n_gradient_calc.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /*****************************************************************************
  2. *
  3. * MODULE: Grass PDE Numerical Library
  4. * AUTHOR(S): Soeren Gebbert, Berlin (GER) Dec 2006
  5. * soerengebbert <at> gmx <dot> de
  6. *
  7. * PURPOSE: gradient management functions
  8. * part of the gpde library
  9. *
  10. * COPYRIGHT: (C) 2000 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. *****************************************************************************/
  17. #include <grass/N_pde.h>
  18. /*! \brief Calculate basic statistics of a gradient field
  19. *
  20. * The statistic is stored in the gradient field struct
  21. *
  22. * \param field N_gradient_2d_field *
  23. * \return void
  24. *
  25. * */
  26. void N_calc_gradient_field_2d_stats(N_gradient_field_2d * field)
  27. {
  28. double minx, miny;
  29. double maxx, maxy;
  30. double sumx, sumy;
  31. int nonullx, nonully;
  32. G_debug(3,
  33. "N_calc_gradient_field_2d_stats: compute gradient field stats");
  34. N_calc_array_2d_stats(field->x_array, &minx, &maxx, &sumx, &nonullx, 0);
  35. N_calc_array_2d_stats(field->y_array, &miny, &maxy, &sumy, &nonully, 0);
  36. if (minx < miny)
  37. field->min = minx;
  38. else
  39. field->min = miny;
  40. if (maxx > maxy)
  41. field->max = maxx;
  42. else
  43. field->max = maxy;
  44. field->sum = sumx + sumy;
  45. field->nonull = nonullx + nonully;
  46. field->mean = field->sum / (double)field->nonull;
  47. return;
  48. }
  49. /*!
  50. * \brief This function computes the gradient based on the input N_array_2d pot
  51. * (potential), a weighting factor N_array_2d named weight and the distance between two cells
  52. * saved in the N_geom_data struct.
  53. *
  54. * The gradient is calculated between cells for each cell and direction.
  55. * An existing gradient field can be filled with new data or, if a NULL pointer is
  56. * given, a new gradient field will be allocated with the appropriate size.
  57. *
  58. *
  59. \verbatim
  60. ______________
  61. | | | |
  62. | | | |
  63. |----|-NC-|----|
  64. | | | |
  65. | WC EC |
  66. | | | |
  67. |----|-SC-|----|
  68. | | | |
  69. |____|____|____|
  70. x - direction:
  71. r = 2 * weight[row][col]*weight[row][col + 1] / (weight[row][col]*weight[row][col + 1])
  72. EC = r * (pot[row][col] - pot[row][col + 1])/dx
  73. y - direction:
  74. r = 2 * weight[row][col]*weight[row + 1][col] / (weight[row][col]*weight[row + 1][col])
  75. SC = r * (pot[row][col] - pot[row + 1][col])/dy
  76. the values SC and EC are the values of the next row/col
  77. \endverbatim
  78. * \param pot N_array_2d * - the potential N_array_2d
  79. * \param weight_x N_array_2d * - the weighting factor N_array_2d used to modify the gradient in x-direction
  80. * \param weight_y N_array_2d * - the weighting factor N_array_2d used to modify the gradient in y-direction
  81. * \param geom N_geom_data * - geometry data structure
  82. * \param gradfield N_gradient_field_2d * - a gradient field of the correct size, if a NULL pointer is provided this gradient field will be new allocated
  83. * \return N_gradient_field_2d * - the pointer to the computed gradient field
  84. *
  85. * */
  86. N_gradient_field_2d *N_compute_gradient_field_2d(N_array_2d * pot,
  87. N_array_2d * weight_x,
  88. N_array_2d * weight_y,
  89. N_geom_data * geom,
  90. N_gradient_field_2d *
  91. gradfield)
  92. {
  93. int i, j;
  94. int rows, cols;
  95. double dx, dy, p1, p2, r1, r2, mean, grad, res;
  96. N_gradient_field_2d *field = gradfield;
  97. if (pot->cols != weight_x->cols || pot->cols != weight_y->cols)
  98. G_fatal_error
  99. ("N_compute_gradient_field_2d: the arrays are not of equal size");
  100. if (pot->rows != weight_x->rows || pot->rows != weight_y->rows)
  101. G_fatal_error
  102. ("N_compute_gradient_field_2d: the arrays are not of equal size");
  103. if (pot->cols != geom->cols || pot->rows != geom->rows)
  104. G_fatal_error
  105. ("N_compute_gradient_field_2d: array sizes and geometry data are different");
  106. G_debug(3, "N_compute_gradient_field_2d: compute gradient field");
  107. rows = pot->rows;
  108. cols = pot->cols;
  109. dx = geom->dx;
  110. dy = geom->dy;
  111. if (field == NULL) {
  112. field = N_alloc_gradient_field_2d(cols, rows);
  113. }
  114. else {
  115. if (field->cols != geom->cols || field->rows != geom->rows)
  116. G_fatal_error
  117. ("N_compute_gradient_field_2d: gradient field sizes and geometry data are different");
  118. }
  119. for (j = 0; j < rows; j++)
  120. for (i = 0; i < cols - 1; i++) {
  121. grad = 0;
  122. mean = 0;
  123. /* Only compute if the arrays are not null */
  124. if (!N_is_array_2d_value_null(pot, i, j) &&
  125. !N_is_array_2d_value_null(pot, i + 1, j)) {
  126. p1 = N_get_array_2d_d_value(pot, i, j);
  127. p2 = N_get_array_2d_d_value(pot, i + 1, j);
  128. grad = (p1 - p2) / dx; /* gradient */
  129. }
  130. if (!N_is_array_2d_value_null(weight_x, i, j) &&
  131. !N_is_array_2d_value_null(weight_x, i + 1, j)) {
  132. r1 = N_get_array_2d_d_value(weight_x, i, j);
  133. r2 = N_get_array_2d_d_value(weight_x, i + 1, j);
  134. mean = N_calc_harmonic_mean(r1, r2); /*harmonical mean */
  135. }
  136. res = mean * grad;
  137. N_put_array_2d_d_value(field->x_array, i + 1, j, res);
  138. }
  139. for (j = 0; j < rows - 1; j++)
  140. for (i = 0; i < cols; i++) {
  141. grad = 0;
  142. mean = 0;
  143. /* Only compute if the arrays are not null */
  144. if (!N_is_array_2d_value_null(pot, i, j) &&
  145. !N_is_array_2d_value_null(pot, i, j + 1)) {
  146. p1 = N_get_array_2d_d_value(pot, i, j);
  147. p2 = N_get_array_2d_d_value(pot, i, j + 1);
  148. grad = (p1 - p2) / dy; /* gradient */
  149. }
  150. if (!N_is_array_2d_value_null(weight_y, i, j) &&
  151. !N_is_array_2d_value_null(weight_y, i, j + 1)) {
  152. r1 = N_get_array_2d_d_value(weight_y, i, j);
  153. r2 = N_get_array_2d_d_value(weight_y, i, j + 1);
  154. mean = N_calc_harmonic_mean(r1, r2); /*harmonical mean */
  155. }
  156. res = -1 * mean * grad;
  157. N_put_array_2d_d_value(field->y_array, i, j + 1, res);
  158. }
  159. /*Compute gradient field statistics */
  160. N_calc_gradient_field_2d_stats(field);
  161. return field;
  162. }
  163. /*!
  164. * \brief Calculate the x and y vector components from a gradient field for each
  165. * cell and stores them in the provided N_array_2d structures
  166. *
  167. * The arrays must have the same size as the gradient field.
  168. \verbatim
  169. Based on this storages scheme the gradient vector for each cell is
  170. calculated and stored in the provided N_array_2d structures
  171. ______________
  172. | | | |
  173. | | | |
  174. |----|-NC-|----|
  175. | | | |
  176. | WC EC |
  177. | | | |
  178. |----|-SC-|----|
  179. | | | |
  180. |____|____|____|
  181. x vector component:
  182. x = (WC + EC) / 2
  183. y vector component:
  184. y = (NC + SC) / 2
  185. \endverbatim
  186. *
  187. * \param field N_gradient_field_2d *
  188. * \param x_comp N_array_2d * - the array in which the x component will be written
  189. * \param y_comp N_array_2d * - the array in which the y component will be written
  190. *
  191. * \return void
  192. * */
  193. void
  194. N_compute_gradient_field_components_2d(N_gradient_field_2d * field,
  195. N_array_2d * x_comp,
  196. N_array_2d * y_comp)
  197. {
  198. int i, j;
  199. int rows, cols;
  200. double vx, vy;
  201. N_array_2d *x = x_comp;
  202. N_array_2d *y = y_comp;
  203. N_gradient_2d grad;
  204. if (!x)
  205. G_fatal_error("N_compute_gradient_components_2d: x array is empty");
  206. if (!y)
  207. G_fatal_error("N_compute_gradient_components_2d: y array is empty");
  208. cols = field->x_array->cols;
  209. rows = field->x_array->rows;
  210. /*Check the array sizes */
  211. if (x->cols != cols || x->rows != rows)
  212. G_fatal_error
  213. ("N_compute_gradient_components_2d: the size of the x array doesn't fit the gradient field size");
  214. if (y->cols != cols || y->rows != rows)
  215. G_fatal_error
  216. ("N_compute_gradient_components_2d: the size of the y array doesn't fit the gradient field size");
  217. for (j = 0; j < rows; j++)
  218. for (i = 0; i < cols; i++) {
  219. N_get_gradient_2d(field, &grad, i, j);
  220. /* in case a gradient is zero, we expect a no flow boundary */
  221. if (grad.WC == 0.0 || grad.EC == 0.0)
  222. vx = (grad.WC + grad.EC);
  223. else
  224. vx = (grad.WC + grad.EC) / 2;
  225. if (grad.NC == 0.0 || grad.SC == 0.0)
  226. vy = (grad.NC + grad.SC);
  227. else
  228. vy = (grad.NC + grad.SC) / 2;
  229. N_put_array_2d_d_value(x, i, j, vx);
  230. N_put_array_2d_d_value(y, i, j, vy);
  231. }
  232. return;
  233. }
  234. /*! \brief Calculate basic statistics of a gradient field
  235. *
  236. * The statistic is stored in the gradient field struct
  237. *
  238. * \param field N_gradient_3d_field *
  239. * \return void
  240. *
  241. * */
  242. void N_calc_gradient_field_3d_stats(N_gradient_field_3d * field)
  243. {
  244. double minx, miny, minz;
  245. double maxx, maxy, maxz;
  246. double sumx, sumy, sumz;
  247. int nonullx, nonully, nonullz;
  248. G_debug(3,
  249. "N_calc_gradient_field_3d_stats: compute gradient field stats");
  250. N_calc_array_3d_stats(field->x_array, &minx, &maxx, &sumx, &nonullx, 0);
  251. N_calc_array_3d_stats(field->y_array, &miny, &maxy, &sumy, &nonully, 0);
  252. N_calc_array_3d_stats(field->z_array, &minz, &maxz, &sumz, &nonullz, 0);
  253. if (minx <= minz && minx <= miny)
  254. field->min = minx;
  255. if (miny <= minz && miny <= minx)
  256. field->min = miny;
  257. if (minz <= minx && minz <= miny)
  258. field->min = minz;
  259. if (maxx >= maxz && maxx >= maxy)
  260. field->max = maxx;
  261. if (maxy >= maxz && maxy >= maxx)
  262. field->max = maxy;
  263. if (maxz >= maxx && maxz >= maxy)
  264. field->max = maxz;
  265. field->sum = sumx + sumy + sumz;
  266. field->nonull = nonullx + nonully + nonullz;
  267. field->mean = field->sum / (double)field->nonull;
  268. return;
  269. }
  270. /*!
  271. * \brief This function computes the gradient based on the input N_array_3d pot
  272. * (that means potential), a weighting factor N_array_3d named weight and the distance between two cells
  273. * saved in the N_geom_data struct.
  274. *
  275. * The gradient is calculated between cells for each cell and direction.
  276. * An existing gradient field can be filled with new data or, if a NULL pointer is
  277. * given, a new gradient field will be allocated with the appropriate size.
  278. *
  279. *
  280. *
  281. *
  282. \verbatim
  283. | /
  284. TC NC
  285. |/
  286. --WC-----EC--
  287. /|
  288. SC BC
  289. / |
  290. x - direction:
  291. r = 2 * weight_x[depth][row][col]*weight_x[depth][row][col + 1] / (weight_X[depth][row][col]*weight_x[depth][row][col + 1])
  292. EC = r * (pot[depth][row][col] - pot[depth][row][col + 1])/dx
  293. y - direction:
  294. r = 2 * weight_y[depth][row][col]*weight_y[depth][row + 1][col] / (weight_y[depth][row][col]*weight_y[depth][row + 1][col])
  295. SC = r * (pot[depth][row][col] - pot[depth][row + 1][col])/dy
  296. z - direction:
  297. r = 2 * weight_z[depth][row][col]*weight_z[depth + 1][row][col] / (weight_z[depth][row][col]*weight_z[depth + 1][row][col])
  298. TC = r * (pot[depth][row][col] - pot[depth + 1][row][col])/dy
  299. the values BC, NC, WC are the values of the next depth/row/col
  300. \endverbatim
  301. * \param pot N_array_3d * - the potential N_array_2d
  302. * \param weight_x N_array_3d * - the weighting factor N_array_3d used to modify the gradient in x-direction
  303. * \param weight_y N_array_3d * - the weighting factor N_array_3d used to modify the gradient in y-direction
  304. * \param weight_z N_array_3d * - the weighting factor N_array_3d used to modify the gradient in z-direction
  305. * \param geom N_geom_data * - geometry data structure
  306. * \param gradfield N_gradient_field_3d * - a gradient field of the correct size, if a NULL pointer is provided this gradient field will be new allocated
  307. * \return N_gradient_field_3d * - the pointer to the computed gradient field
  308. *
  309. * */
  310. N_gradient_field_3d *N_compute_gradient_field_3d(N_array_3d * pot,
  311. N_array_3d * weight_x,
  312. N_array_3d * weight_y,
  313. N_array_3d * weight_z,
  314. N_geom_data * geom,
  315. N_gradient_field_3d *
  316. gradfield)
  317. {
  318. int i, j, k;
  319. int cols, rows, depths;
  320. double dx, dy, dz, p1, p2, r1, r2, mean, grad, res;
  321. N_gradient_field_3d *field = gradfield;
  322. if (pot->cols != weight_x->cols || pot->cols != weight_y->cols ||
  323. pot->cols != weight_z->cols)
  324. G_fatal_error
  325. ("N_compute_gradient_field_3d: the arrays are not of equal size");
  326. if (pot->rows != weight_x->rows || pot->rows != weight_y->rows ||
  327. pot->rows != weight_z->rows)
  328. G_fatal_error
  329. ("N_compute_gradient_field_3d: the arrays are not of equal size");
  330. if (pot->depths != weight_x->depths || pot->depths != weight_y->depths ||
  331. pot->depths != weight_z->depths)
  332. G_fatal_error
  333. ("N_compute_gradient_field_3d: the arrays are not of equal size");
  334. if (pot->cols != geom->cols || pot->rows != geom->rows ||
  335. pot->depths != geom->depths)
  336. G_fatal_error
  337. ("N_compute_gradient_field_3d: array sizes and geometry data are different");
  338. G_debug(3, "N_compute_gradient_field_3d: compute gradient field");
  339. cols = geom->cols;
  340. rows = geom->rows;
  341. depths = geom->depths;
  342. dx = geom->dx;
  343. dy = geom->dy;
  344. dz = geom->dz;
  345. if (gradfield == NULL) {
  346. field = N_alloc_gradient_field_3d(cols, rows, depths);
  347. }
  348. else {
  349. if (field->cols != geom->cols || field->rows != geom->rows ||
  350. field->depths != geom->depths)
  351. G_fatal_error
  352. ("N_compute_gradient_field_3d: gradient field sizes and geometry data are different");
  353. }
  354. for (k = 0; k < depths; k++)
  355. for (j = 0; j < rows; j++)
  356. for (i = 0; i < cols - 1; i++) {
  357. grad = 0;
  358. mean = 0;
  359. /*Only compute if the arrays are not null */
  360. if (!N_is_array_3d_value_null(pot, i, j, k) &&
  361. !N_is_array_3d_value_null(pot, i + 1, j, k)) {
  362. p1 = N_get_array_3d_d_value(pot, i, j, k);
  363. p2 = N_get_array_3d_d_value(pot, i + 1, j, k);
  364. grad = (p1 - p2) / dx; /* gradient */
  365. }
  366. if (!N_is_array_3d_value_null(weight_x, i, j, k) &&
  367. !N_is_array_3d_value_null(weight_x, i + 1, j, k)) {
  368. r1 = N_get_array_3d_d_value(weight_x, i, j, k);
  369. r2 = N_get_array_3d_d_value(weight_x, i + 1, j, k);
  370. mean = N_calc_harmonic_mean(r1, r2); /*harmonical mean */
  371. }
  372. res = mean * grad;
  373. G_debug(6,
  374. "N_compute_gradient_field_3d: X-direction insert value %6.5g at %i %i %i ",
  375. res, k, j, i + 1);
  376. N_put_array_3d_d_value(field->x_array, i + 1, j, k, res);
  377. }
  378. for (k = 0; k < depths; k++)
  379. for (j = 0; j < rows - 1; j++)
  380. for (i = 0; i < cols; i++) {
  381. grad = 0;
  382. mean = 0;
  383. /* Only compute if the arrays are not null */
  384. if (!N_is_array_3d_value_null(pot, i, j, k) &&
  385. !N_is_array_3d_value_null(pot, i, j + 1, k)) {
  386. p1 = N_get_array_3d_d_value(pot, i, j, k);
  387. p2 = N_get_array_3d_d_value(pot, i, j + 1, k);
  388. grad = (p1 - p2) / dy; /* gradient */
  389. }
  390. if (!N_is_array_3d_value_null(weight_y, i, j, k) &&
  391. !N_is_array_3d_value_null(weight_y, i, j + 1, k)) {
  392. r1 = N_get_array_3d_d_value(weight_y, i, j, k);
  393. r2 = N_get_array_3d_d_value(weight_y, i, j + 1, k);
  394. mean = N_calc_harmonic_mean(r1, r2); /*harmonical mean */
  395. }
  396. res = -1 * mean * grad; /*invert the direction, because we count from north to south,
  397. * but the gradient is defined in y direction */
  398. G_debug(6,
  399. "N_compute_gradient_field_3d: Y-direction insert value %6.5g at %i %i %i ",
  400. res, k, j + 1, i);
  401. N_put_array_3d_d_value(field->y_array, i, j + 1, k, res);
  402. }
  403. for (k = 0; k < depths - 1; k++)
  404. for (j = 0; j < rows; j++)
  405. for (i = 0; i < cols; i++) {
  406. grad = 0;
  407. mean = 0;
  408. /* Only compute if the arrays are not null */
  409. if (!N_is_array_3d_value_null(pot, i, j, k) &&
  410. !N_is_array_3d_value_null(pot, i, j, k + 1)) {
  411. p1 = N_get_array_3d_d_value(pot, i, j, k);
  412. p2 = N_get_array_3d_d_value(pot, i, j, k + 1);
  413. grad = (p1 - p2) / dz; /* gradient */
  414. }
  415. if (!N_is_array_3d_value_null(weight_z, i, j, k) &&
  416. !N_is_array_3d_value_null(weight_z, i, j, k + 1)) {
  417. r1 = N_get_array_3d_d_value(weight_z, i, j, k);
  418. r2 = N_get_array_3d_d_value(weight_z, i, j, k + 1);
  419. mean = N_calc_harmonic_mean(r1, r2); /*harmonical mean */
  420. }
  421. res = mean * grad;
  422. G_debug(6,
  423. "N_compute_gradient_field_3d: Z-direction insert value %6.5g at %i %i %i ",
  424. res, k + 1, j, i);
  425. N_put_array_3d_d_value(field->z_array, i, j, k + 1, res);
  426. }
  427. /*Compute gradient field statistics */
  428. N_calc_gradient_field_3d_stats(field);
  429. return field;
  430. }
  431. /*!
  432. * \brief Calculate the x, y and z vector components from a gradient field for each cell
  433. * and store them in the provided N_array_3d structures
  434. *
  435. * The arrays must have the same size as the gradient field.
  436. *
  437. \verbatim
  438. Based on this storages scheme the gradient vector for each cell is
  439. calculated and stored in the provided N_array_3d structures
  440. | /
  441. TC NC
  442. |/
  443. --WC-----EC--
  444. /|
  445. SC BC
  446. / |
  447. x vector component:
  448. x = (WC + EC) / 2
  449. y vector component:
  450. y = (NC + SC) / 2
  451. z vector component:
  452. z = (TC + BC) / 2
  453. \endverbatim
  454. * \param field N_gradient_field_3d *
  455. * \param x_comp N_array_3d * - the array in which the x component will be written
  456. * \param y_comp N_array_3d * - the array in which the y component will be written
  457. * \param z_comp N_array_3d * - the array in which the z component will be written
  458. *
  459. * \return void
  460. * */
  461. void
  462. N_compute_gradient_field_components_3d(N_gradient_field_3d * field,
  463. N_array_3d * x_comp,
  464. N_array_3d * y_comp,
  465. N_array_3d * z_comp)
  466. {
  467. int i, j, k;
  468. int rows, cols, depths;
  469. double vx, vy, vz;
  470. N_array_3d *x = x_comp;
  471. N_array_3d *y = y_comp;
  472. N_array_3d *z = z_comp;
  473. N_gradient_3d grad;
  474. if (!x)
  475. G_fatal_error("N_compute_gradient_components_3d: x array is empty");
  476. if (!y)
  477. G_fatal_error("N_compute_gradient_components_3d: y array is empty");
  478. if (!z)
  479. G_fatal_error("N_compute_gradient_components_3d: z array is empty");
  480. cols = field->x_array->cols;
  481. rows = field->x_array->rows;
  482. depths = field->x_array->depths;
  483. /*Check the array sizes */
  484. if (x->cols != cols || x->rows != rows || x->depths != depths)
  485. G_fatal_error
  486. ("N_compute_gradient_components_3d: the size of the x array doesn't fit the gradient field size");
  487. if (y->cols != cols || y->rows != rows || y->depths != depths)
  488. G_fatal_error
  489. ("N_compute_gradient_components_3d: the size of the y array doesn't fit the gradient field size");
  490. if (z->cols != cols || z->rows != rows || z->depths != depths)
  491. G_fatal_error
  492. ("N_compute_gradient_components_3d: the size of the z array doesn't fit the gradient field size");
  493. for (k = 0; k < depths; k++)
  494. for (j = 0; j < rows; j++)
  495. for (i = 0; i < cols; i++) {
  496. N_get_gradient_3d(field, &grad, i, j, k);
  497. /* in case a gradient is zero, we expect a no flow boundary */
  498. if (grad.WC == 0.0 || grad.EC == 0.0)
  499. vx = (grad.WC + grad.EC);
  500. else
  501. vx = (grad.WC + grad.EC) / 2;
  502. if (grad.NC == 0.0 || grad.SC == 0.0)
  503. vy = (grad.NC + grad.SC);
  504. else
  505. vy = (grad.NC + grad.SC) / 2;
  506. if (grad.TC == 0.0 || grad.BC == 0.0)
  507. vz = (grad.TC + grad.BC);
  508. else
  509. vz = (grad.TC + grad.BC) / 2;
  510. N_put_array_3d_d_value(x, i, j, k, vx);
  511. N_put_array_3d_d_value(y, i, j, k, vy);
  512. N_put_array_3d_d_value(z, i, j, k, vz);
  513. }
  514. return;
  515. }