GRASS 8 Programmer's Manual 8.6.0dev(2026)-4bb960b182
Loading...
Searching...
No Matches
n_solute_transport.c
Go to the documentation of this file.
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: solute transport in porous media
8 * part of the gpde library
9 *
10 * SPDX-FileCopyrightText: 2007 GRASS Development Team
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 *
13 *****************************************************************************/
14
15#include <math.h>
16#include <grass/N_solute_transport.h>
17
18/* ************************************************************************* *
19 * ************************************************************************* *
20 * ************************************************************************* */
21/*! \brief This is just a placeholder
22 *
23 * */
25 int col, int row, int depth)
26{
27 double Df_e = 0, Df_w = 0, Df_n = 0, Df_s = 0, Df_t = 0, Df_b = 0;
28 double dx, dy, dz, Az;
29 double diff_x, diff_y, diff_z;
30 double diff_xw, diff_yn;
31 double diff_xe, diff_ys;
32 double diff_zt, diff_zb;
33 double cin = 0, /* cg, */ cg_start;
34 double R, nf, cs, q;
35 double C, W, E, N, S, T, B, V;
36 double vw = 0, ve = 0, vn = 0, vs = 0, vt = 0, vb = 0;
37 double Ds_w = 0, Ds_e = 0, Ds_n = 0, Ds_s = 0, Ds_t = 0, Ds_b = 0;
38 double Dw = 0, De = 0, Dn = 0, Ds = 0, Dt = 0, Db = 0;
39 double rw = 0.5, re = 0.5, rn = 0.5, rs = 0.5, rt = 0.5, rb = 0.5;
40
43 N_gradient_3d grad;
44
45 /*cast the void pointer to the right data structure */
47
48 N_get_gradient_3d(data->grad, &grad, col, row, depth);
49
50 dx = geom->dx;
51 dy = geom->dy;
52 dz = geom->dz;
54
55 /*read the data from the arrays */
56 cg_start = N_get_array_3d_d_value(data->c_start, col, row, depth);
57 /* cg = N_get_array_3d_d_value(data->c, col, row, depth); */
58
59 /*get the surrounding diffusion tensor entries */
60 diff_x = N_get_array_3d_d_value(data->diff_x, col, row, depth);
61 diff_y = N_get_array_3d_d_value(data->diff_y, col, row, depth);
62 diff_z = N_get_array_3d_d_value(data->diff_z, col, row, depth);
63 diff_xw = N_get_array_3d_d_value(data->diff_x, col - 1, row, depth);
64 diff_xe = N_get_array_3d_d_value(data->diff_x, col + 1, row, depth);
65 diff_yn = N_get_array_3d_d_value(data->diff_y, col, row - 1, depth);
66 diff_ys = N_get_array_3d_d_value(data->diff_y, col, row + 1, depth);
67 diff_zt = N_get_array_3d_d_value(data->diff_z, col, row, depth + 1);
68 diff_zb = N_get_array_3d_d_value(data->diff_z, col, row, depth - 1);
69
70 /* calculate the diffusion on the cell borders using the harmonical mean */
77
78 /* calculate the dispersion */
79 /*todo */
80
81 /* calculate the velocity parts with full upwinding scheme */
82 vw = grad.WC;
83 ve = grad.EC;
84 vn = grad.NC;
85 vs = grad.SC;
86 vt = grad.TC;
87 vb = grad.BC;
88
89 /* put the diffusion and dispersion together */
90 Dw = ((Df_w + Ds_w)) / dx;
91 De = ((Df_e + Ds_e)) / dx;
92 Dn = ((Df_n + Ds_n)) / dy;
93 Ds = ((Df_s + Ds_s)) / dy;
94 Dt = ((Df_t + Ds_t)) / dz;
95 Db = ((Df_b + Ds_b)) / dz;
96
97 rw = N_exp_upwinding(-1 * vw, dx, Dw);
98 re = N_exp_upwinding(ve, dx, De);
99 rs = N_exp_upwinding(-1 * vs, dy, Ds);
100 rn = N_exp_upwinding(vn, dy, Dn);
101 rb = N_exp_upwinding(-1 * vb, dz, Dn);
102 rt = N_exp_upwinding(vt, dz, Dn);
103
104 /*mass balance center cell to western cell */
105 W = -1 * (Dw)*dy * dz - vw * (1 - rw) * dy * dz;
106 /*mass balance center cell to eastern cell */
107 E = -1 * (De)*dy * dz + ve * (1 - re) * dy * dz;
108 /*mass balance center cell to southern cell */
109 S = -1 * (Ds)*dx * dz - vs * (1 - rs) * dx * dz;
110 /*mass balance center cell to northern cell */
111 N = -1 * (Dn)*dx * dz + vn * (1 - rn) * dx * dz;
112 /*mass balance center cell to bottom cell */
113 B = -1 * (Db)*Az - vb * (1 - rb) * Az;
114 /*mass balance center cell to top cell */
115 T = -1 * (Dt)*Az + vt * (1 - rt) * Az;
116
117 /* Retardation */
118 R = N_get_array_3d_d_value(data->R, col, row, depth);
119 /* Inner sources */
120 cs = N_get_array_3d_d_value(data->cs, col, row, depth);
121 /* effective porosity */
122 nf = N_get_array_3d_d_value(data->nf, col, row, depth);
123 /* groundwater sources and sinks */
124 q = N_get_array_3d_d_value(data->q, col, row, depth);
125 /* concentration of influent water */
126 cin = N_get_array_3d_d_value(data->cin, col, row, depth);
127
128 /*the diagonal entry of the matrix */
129 C = ((Dw - vw) * dy * dz + (De + ve) * dy * dz + (Ds - vs) * dx * dz +
130 (Dn + vn) * dx * dz + (Db - vb) * Az + (Dt + vt) * Az +
131 Az * dz * R / data->dt - q / nf);
132
133 /*the entry in the right side b of Ax = b */
134 V = (cs + cg_start * Az * dz * R / data->dt - q / nf * cin);
135
136 /*
137 * printf("nf %g\n", nf);
138 * printf("q %g\n", q);
139 * printf("cs %g\n", cs);
140 * printf("cin %g\n", cin);
141 * printf("cg %g\n", cg);
142 * printf("cg_start %g\n", cg_start);
143 * printf("Az %g\n", Az);
144 * printf("z %g\n", z);
145 * printf("R %g\n", R);
146 * printf("dt %g\n", data->dt);
147 */
148 G_debug(6, "N_callback_solute_transport_3d: called [%i][%i][%i]", row, col,
149 depth);
150
151 /*create the 7 point star entries */
152 mat_pos = N_create_7star(C, W, E, N, S, T, B, V);
153
154 return mat_pos;
155}
156
157/* ************************************************************************* *
158 * ************************************************************************* *
159 * ************************************************************************* */
160/*!
161 * \brief This callback function creates the mass balance of a 5 point star
162 *
163 * The mass balance is based on the common solute transport equation:
164 *
165 * \f[\frac{\partial c_g}{\partial t} R = \nabla \cdot ({\bf D} \nabla c_g -
166 * {\bf u} c_g) + \sigma + \frac{q}{n_f}(c_g - c_in) \f]
167 *
168 * This equation is discretizised with the finite volume method in two
169 * dimensions.
170 *
171 *
172 * \param solutedata * N_solute_transport_data2d - a void pointer to the data
173 * structure \param geom N_geom_data * \param col int \param row int \return
174 * N_data_star * - a five point data star
175 *
176 * */
178 int col, int row)
179{
180 double Df_e = 0, Df_w = 0, Df_n = 0, Df_s = 0;
181 double z_e = 0, z_w = 0, z_n = 0, z_s = 0;
182 double dx, dy, Az;
183 double diff_x, diff_y;
184 double disp_x, disp_y;
185 double z;
186 double diff_xw, diff_yn;
187 double disp_xw, disp_yn;
188 double z_xw, z_yn;
189 double diff_xe, diff_ys;
190 double disp_xe, disp_ys;
191 double z_xe, z_ys;
192 double cin = 0, /* cg, */ cg_start;
193 double R, nf, cs, q;
194 double C, W, E, N, S, V, NE, NW, SW, SE;
195 double vw = 0, ve = 0, vn = 0, vs = 0;
196 double Ds_w = 0, Ds_e = 0, Ds_n = 0, Ds_s = 0;
197 double Dw = 0, De = 0, Dn = 0, Ds = 0;
198 double rw = 0.5, re = 0.5, rn = 0.5, rs = 0.5;
199
202 N_gradient_2d grad;
203
204 /*cast the void pointer to the right data structure */
206
207 N_get_gradient_2d(data->grad, &grad, col, row);
208
209 dx = geom->dx;
210 dy = geom->dy;
212
213 /*read the data from the arrays */
215 /* cg = N_get_array_2d_d_value(data->c, col, row); */
216
217 /* calculate the cell height */
218 z = N_get_array_2d_d_value(data->top, col, row) -
219 N_get_array_2d_d_value(data->bottom, col, row);
220 z_xw = N_get_array_2d_d_value(data->top, col - 1, row) -
221 N_get_array_2d_d_value(data->bottom, col - 1, row);
222 z_xe = N_get_array_2d_d_value(data->top, col + 1, row) -
223 N_get_array_2d_d_value(data->bottom, col + 1, row);
224 z_yn = N_get_array_2d_d_value(data->top, col, row - 1) -
225 N_get_array_2d_d_value(data->bottom, col, row - 1);
226 z_ys = N_get_array_2d_d_value(data->top, col, row + 1) -
227 N_get_array_2d_d_value(data->bottom, col, row + 1);
228
229 /*geometrical mean of cell height */
234
235 /*get the surrounding diffusion tensor entries */
236 diff_x = N_get_array_2d_d_value(data->diff_x, col, row);
237 diff_y = N_get_array_2d_d_value(data->diff_y, col, row);
238 diff_xw = N_get_array_2d_d_value(data->diff_x, col - 1, row);
239 diff_xe = N_get_array_2d_d_value(data->diff_x, col + 1, row);
240 diff_yn = N_get_array_2d_d_value(data->diff_y, col, row - 1);
241 diff_ys = N_get_array_2d_d_value(data->diff_y, col, row + 1);
242
243 /* calculate the diffusion at the cell borders using the harmonical mean */
248
249 /* calculate the dispersion */
250 /*get the surrounding dispersion tensor entries */
253 if (N_get_array_2d_d_value(data->status, col - 1, row) ==
255 disp_xw = disp_x;
256 }
257 else {
258 disp_xw = N_get_array_2d_d_value(data->disp_xx, col - 1, row);
259 }
260 if (N_get_array_2d_d_value(data->status, col + 1, row) ==
262 disp_xe = disp_x;
263 }
264 else {
265 disp_xe = N_get_array_2d_d_value(data->disp_xx, col + 1, row);
266 }
267 if (N_get_array_2d_d_value(data->status, col, row - 1) ==
269 disp_yn = disp_y;
270 }
271 else {
272 disp_yn = N_get_array_2d_d_value(data->disp_yy, col, row - 1);
273 }
274 if (N_get_array_2d_d_value(data->status, col, row + 1) ==
276 disp_ys = disp_y;
277 }
278 else {
279 disp_ys = N_get_array_2d_d_value(data->disp_yy, col, row + 1);
280 }
281
282 /* calculate the dispersion at the cell borders using the harmonical mean */
287
288 /* put the diffusion and dispersion together */
289 Dw = ((Df_w + Ds_w)) / dx;
290 De = ((Df_e + Ds_e)) / dx;
291 Ds = ((Df_s + Ds_s)) / dy;
292 Dn = ((Df_n + Ds_n)) / dy;
293
294 vw = -1.0 * grad.WC;
295 ve = grad.EC;
296 vs = -1.0 * grad.SC;
297 vn = grad.NC;
298
299 if (data->stab == N_UPWIND_FULL) {
300 rw = N_full_upwinding(vw, dx, Dw);
301 re = N_full_upwinding(ve, dx, De);
302 rs = N_full_upwinding(vs, dy, Ds);
303 rn = N_full_upwinding(vn, dy, Dn);
304 }
305 else if (data->stab == N_UPWIND_EXP) {
306 rw = N_exp_upwinding(vw, dx, Dw);
307 re = N_exp_upwinding(ve, dx, De);
308 rs = N_exp_upwinding(vs, dy, Ds);
309 rn = N_exp_upwinding(vn, dy, Dn);
310 }
311
312 /*mass balance center cell to western cell */
313 W = -1 * (Dw)*dy * z_w + vw * (1 - rw) * dy * z_w;
314 /*mass balance center cell to eastern cell */
315 E = -1 * (De)*dy * z_e + ve * (1 - re) * dy * z_e;
316 /*mass balance center cell to southern cell */
317 S = -1 * (Ds)*dx * z_s + vs * (1 - rs) * dx * z_s;
318 /*mass balance center cell to northern cell */
319 N = -1 * (Dn)*dx * z_n + vn * (1 - rn) * dx * z_n;
320
321 NW = 0.0;
322 SW = 0.0;
323 NE = 0.0;
324 SE = 0.0;
325
326 /* Retardation */
327 R = N_get_array_2d_d_value(data->R, col, row);
328 /* Inner sources */
329 cs = N_get_array_2d_d_value(data->cs, col, row);
330 /* effective porosity */
331 nf = N_get_array_2d_d_value(data->nf, col, row);
332 /* groundwater sources and sinks */
333 q = N_get_array_2d_d_value(data->q, col, row);
334 /* concentration of influent water */
335 cin = N_get_array_2d_d_value(data->cin, col, row);
336
337 /*the diagonal entry of the matrix */
338 C = (Dw + vw * rw) * dy * z_w + (De + ve * re) * dy * z_e +
339 (Ds + vs * rs) * dx * z_s + (Dn + vn * rn) * dx * z_n +
340 Az * z * R / data->dt - q / nf;
341
342 /*the entry in the right side b of Ax = b */
343 V = (cs + cg_start * Az * z * R / data->dt + q / nf * cin);
344
345 /*
346 fprintf(stderr, "nf %g\n", nf);
347 fprintf(stderr, "q %g\n", q);
348 fprintf(stderr, "cs %g\n", cs);
349 fprintf(stderr, "cin %g\n", cin);
350 fprintf(stderr, "cg %g\n", cg);
351 fprintf(stderr, "cg_start %g\n", cg_start);
352 fprintf(stderr, "Az %g\n", Az);
353 fprintf(stderr, "z %g\n", z);
354 fprintf(stderr, "R %g\n", R);
355 fprintf(stderr, "dt %g\n", data->dt);
356 */
357
358 G_debug(6, "N_callback_solute_transport_2d: called [%i][%i]", row, col);
359
360 /*create the 9 point star entries */
361 mat_pos = N_create_9star(C, W, E, N, S, NW, SW, NE, SE, V);
362
363 return mat_pos;
364}
365
366/* ************************************************************************* *
367 * ************************************************************************* *
368 * ************************************************************************* */
369/*!
370 * \brief Allocate memory for the solute transport data structure in three
371 * dimensions
372 *
373 * The solute transport data structure will be allocated including
374 * all appendant 3d arrays. The offset for the 3d arrays is one
375 * to establish homogeneous Neumann boundary conditions at the calculation area
376 * border. This data structure is used to create a linear equation system based
377 * on the computation of solute transport in porous media with the finite volume
378 * method.
379 *
380 * \param cols int
381 * \param rows int
382 * \param depths int
383 * \return N_solute_transport_data3d *
384 * */
385
387 int depths)
388{
390
392 1, sizeof(N_solute_transport_data3d));
393
394 data->c = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
395 data->c_start = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
396 data->status = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
397 data->diff_x = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
398 data->diff_y = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
399 data->diff_z = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
400 data->q = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
401 data->cs = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
402 data->R = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
403 data->nf = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
404 data->cin = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
405
406 /*Allocate the dispersivity tensor */
407 data->disp_xx = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
408 data->disp_yy = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
409 data->disp_zz = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
410 data->disp_xy = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
411 data->disp_xz = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
412 data->disp_yz = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
413
414 data->grad = N_alloc_gradient_field_3d(cols, rows, depths);
415 data->stab = N_UPWIND_EXP;
416
417 return data;
418}
419
420/* ************************************************************************* *
421 * ************************************************************************* *
422 * ************************************************************************* */
423/*!
424 * \brief Allocate memory for the solute transport data structure in two
425 * dimensions
426 *
427 * The solute transport data structure will be allocated including
428 * all appendant 2d arrays. The offset for the 2d arrays is one
429 * to establish homogeneous Neumann boundary conditions at the calculation area
430 * border. This data structure is used to create a linear equation system based
431 * on the computation of solute transport in porous media with the finite volume
432 * method.
433 *
434 * \param cols int
435 * \param rows int
436 * \return N_solute_transport_data2d *
437 * */
438
440{
442
444 1, sizeof(N_solute_transport_data2d));
445
446 data->c = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
447 data->c_start = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
448 data->status = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
449 data->diff_x = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
450 data->diff_y = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
451 data->q = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
452 data->cs = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
453 data->R = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
454 data->nf = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
455 data->cin = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
456 data->top = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
457 data->bottom = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
458
459 /*Allocate the dispersivity tensor */
460 data->disp_xx = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
461 data->disp_yy = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
462 data->disp_xy = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
463
464 data->grad = N_alloc_gradient_field_2d(cols, rows);
465 data->stab = N_UPWIND_EXP;
466
467 return data;
468}
469
470/* ************************************************************************* *
471 * ************************************************************************* *
472 * ************************************************************************* */
473/*!
474 * \brief Release the memory of the solute transport data structure in three
475 * dimensions
476 *
477 * \param data N_solute_transport_data2d *
478 * \return void *
479 * */
481{
482 N_free_array_3d(data->c);
484 N_free_array_3d(data->status);
485 N_free_array_3d(data->diff_x);
486 N_free_array_3d(data->diff_y);
487 N_free_array_3d(data->diff_z);
488 N_free_array_3d(data->q);
489 N_free_array_3d(data->cs);
490 N_free_array_3d(data->R);
491 N_free_array_3d(data->nf);
492 N_free_array_3d(data->cin);
493
500
501 G_free(data);
502
503 data = NULL;
504
505 return;
506}
507
508/* ************************************************************************* *
509 * ************************************************************************* *
510 * ************************************************************************* */
511/*!
512 * \brief Release the memory of the solute transport data structure in two
513 * dimensions
514 *
515 * \param data N_solute_transport_data2d *
516 * \return void *
517 * */
519{
520 N_free_array_2d(data->c);
522 N_free_array_2d(data->status);
523 N_free_array_2d(data->diff_x);
524 N_free_array_2d(data->diff_y);
525 N_free_array_2d(data->q);
526 N_free_array_2d(data->cs);
527 N_free_array_2d(data->R);
528 N_free_array_2d(data->nf);
529 N_free_array_2d(data->cin);
530 N_free_array_2d(data->top);
531 N_free_array_2d(data->bottom);
532
536
537 G_free(data);
538
539 data = NULL;
540
541 return;
542}
543
544/*!
545 * \brief Compute the transmission boundary condition in 2d
546 *
547 * This function calculates the transmission boundary condition
548 * for each cell with status N_CELL_TRANSMISSION. The surrounding
549 * gradient field is used to verify the flow direction. If a flow
550 * goes into a cell, the concentration (data->c) from the neighbour cell is
551 * added to the transmission cell. If the flow from several neighbour
552 * cells goes into the cell, the concentration mean is calculated.
553 *
554 * The new concentrations are written into the data->c_start array,
555 * so they can be handled by the matrix assembling function.
556 *
557 * \param data N_solute_transport_data2d *
558 * \return void *
559 * */
561{
562 int i, j, count = 1;
563 int cols, rows;
564 double c;
565 N_gradient_2d grad;
566
567 cols = data->grad->cols;
568 rows = data->grad->rows;
569
570 G_debug(2, "N_calc_solute_transport_transmission_2d: calculating "
571 "transmission boundary");
572
573 for (j = 0; j < rows; j++) {
574 for (i = 0; i < cols; i++) {
575 if (N_get_array_2d_d_value(data->status, i, j) ==
577 count = 0;
578 /*get the gradient neighbours */
579 N_get_gradient_2d(data->grad, &grad, i, j);
580 c = 0;
581 /*
582 c = N_get_array_2d_d_value(data->c_start, i, j);
583 if(c > 0)
584 count++;
585 */
586
587 if (grad.WC > 0 &&
588 !N_is_array_2d_value_null(data->c, i - 1, j)) {
589 c += N_get_array_2d_d_value(data->c, i - 1, j);
590 count++;
591 }
592 if (grad.EC < 0 &&
593 !N_is_array_2d_value_null(data->c, i + 1, j)) {
594 c += N_get_array_2d_d_value(data->c, i + 1, j);
595 count++;
596 }
597 if (grad.NC < 0 &&
598 !N_is_array_2d_value_null(data->c, i, j - 1)) {
599 c += N_get_array_2d_d_value(data->c, i, j - 1);
600 count++;
601 }
602 if (grad.SC > 0 &&
603 !N_is_array_2d_value_null(data->c, i, j + 1)) {
604 c += N_get_array_2d_d_value(data->c, i, j + 1);
605 count++;
606 }
607 if (count != 0)
608 c = c / (double)count;
609 /*make sure it is not NAN */
610 if (c > 0 || c == 0 || c < 0)
611 N_put_array_2d_d_value(data->c_start, i, j, c);
612 }
613 }
614 }
615
616 return;
617}
618
619/*!
620 * \brief Compute the dispersivity tensor based on the solute transport data in
621 * 2d
622 *
623 * The dispersivity tensor is stored in the data structure.
624 * To compute the dispersivity tensor, the dispersivity lengths and the gradient
625 * field must be present.
626 *
627 * This is just a simple tensor computation which should be extended.
628 *
629 * \todo Change the tensor calculation to a more realistic algorithm
630 *
631 * \param data N_solute_transport_data2d *
632 * \return void *
633 * */
635{
636 int i, j;
637 int cols, rows;
638 double vx, vy, vv;
639 double disp_xx, disp_yy, disp_xy;
640 N_gradient_2d grad;
641
642 cols = data->grad->cols;
643 rows = data->grad->rows;
644
645 G_debug(2, "N_calc_solute_transport_disptensor_2d: calculating the "
646 "dispersivity tensor");
647
648 for (j = 0; j < rows; j++) {
649 for (i = 0; i < cols; i++) {
650
651 disp_xx = 0;
652 disp_yy = 0;
653 disp_xy = 0;
654
655 /*get the gradient neighbours */
656 N_get_gradient_2d(data->grad, &grad, i, j);
657 vx = (grad.WC + grad.EC) / 2;
658 vy = (grad.NC + grad.SC) / 2;
659 vv = sqrt(vx * vx + vy * vy);
660
661 if (vv != 0) {
662 disp_xx = data->al * vx * vx / vv + data->at * vy * vy / vv;
663 disp_yy = data->at * vx * vx / vv + data->al * vy * vy / vv;
664 disp_xy = (data->al - data->at) * vx * vy / vv;
665 }
666
667 G_debug(5,
668 "N_calc_solute_transport_disptensor_2d: [%i][%i] disp_xx "
669 "%g disp_yy %g disp_xy %g",
670 i, j, disp_xx, disp_yy, disp_xy);
671 N_put_array_2d_d_value(data->disp_xx, i, j, disp_xx);
672 N_put_array_2d_d_value(data->disp_yy, i, j, disp_yy);
673 N_put_array_2d_d_value(data->disp_xy, i, j, disp_xy);
674 }
675 }
676
677 return;
678}
679
680/*!
681 * \brief Compute the dispersivity tensor based on the solute transport data in
682 * 3d
683 *
684 * The dispersivity tensor is stored in the data structure.
685 * To compute the dispersivity tensor, the dispersivity lengths and the gradient
686 * field must be present.
687 *
688 * This is just a simple tensor computation which should be extended.
689 *
690 * \todo Change the tensor calculation to a more realistic algorithm
691 *
692 * \param data N_solute_transport_data3d *
693 * \return void *
694 * */
696{
697 int i, j, k;
698 int cols, rows, depths;
699 double vx, vy, vz, vv;
700 double disp_xx, disp_yy, disp_zz, disp_xy, disp_xz, disp_yz;
701 N_gradient_3d grad;
702
703 cols = data->grad->cols;
704 rows = data->grad->rows;
705 depths = data->grad->depths;
706
707 G_debug(2, "N_calc_solute_transport_disptensor_3d: calculating the "
708 "dispersivity tensor");
709
710 for (k = 0; k < depths; k++) {
711 for (j = 0; j < rows; j++) {
712 for (i = 0; i < cols; i++) {
713 disp_xx = 0;
714 disp_yy = 0;
715 disp_zz = 0;
716 disp_xy = 0;
717 disp_xz = 0;
718 disp_yz = 0;
719
720 /*get the gradient neighbours */
721 N_get_gradient_3d(data->grad, &grad, i, j, k);
722 vx = (grad.WC + grad.EC) / 2;
723 vy = (grad.NC + grad.SC) / 2;
724 vz = (grad.BC + grad.TC) / 2;
725 vv = sqrt(vx * vx + vy * vy + vz * vz);
726
727 if (vv != 0) {
728 disp_xx = data->al * vx * vx / vv +
729 data->at * vy * vy / vv + data->at * vz * vz / vv;
730 disp_yy = data->at * vx * vx / vv +
731 data->al * vy * vy / vv + data->at * vz * vz / vv;
732 disp_zz = data->at * vx * vx / vv +
733 data->at * vy * vy / vv + data->al * vz * vz / vv;
734 disp_xy = (data->al - data->at) * vx * vy / vv;
735 disp_xz = (data->al - data->at) * vx * vz / vv;
736 disp_yz = (data->al - data->at) * vy * vz / vv;
737 }
738
739 G_debug(5,
740 "N_calc_solute_transport_disptensor_3d: [%i][%i][%i] "
741 "disp_xx %g disp_yy %g disp_zz %g disp_xy %g disp_xz "
742 "%g disp_yz %g ",
743 i, j, k, disp_xx, disp_yy, disp_zz, disp_xy, disp_xz,
744 disp_yz);
745 N_put_array_3d_d_value(data->disp_xx, i, j, k, disp_xx);
746 N_put_array_3d_d_value(data->disp_yy, i, j, k, disp_yy);
747 N_put_array_3d_d_value(data->disp_zz, i, j, k, disp_zz);
748 N_put_array_3d_d_value(data->disp_xy, i, j, k, disp_xy);
749 N_put_array_3d_d_value(data->disp_xz, i, j, k, disp_xz);
750 N_put_array_3d_d_value(data->disp_yz, i, j, k, disp_yz);
751 }
752 }
753 }
754
755 return;
756}
#define N_UPWIND_FULL
Definition N_pde.h:51
#define N_CELL_TRANSMISSION
Definition N_pde.h:30
double N_exp_upwinding(double sprod, double distance, double D)
exponential upwinding stabilization algorithm
Definition n_upwind.c:60
double N_calc_geom_mean(double a, double b)
Calculate the geometrical mean of values a and b.
Definition n_tools.c:70
double N_full_upwinding(double sprod, double distance, double D)
full upwinding stabilization algorithm
Definition n_upwind.c:29
#define N_UPWIND_EXP
Definition N_pde.h:52
double N_calc_harmonic_mean(double a, double b)
Calculate the harmonical mean of values a and b.
Definition n_tools.c:112
#define NULL
Definition ccmath.h:32
#define SE
Definition dataquad.h:27
#define SW
Definition dataquad.h:26
#define NE
Definition dataquad.h:25
#define NW
Definition dataquad.h:24
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
#define G_calloc(m, n)
Definition defs/gis.h:137
int G_debug(int, const char *,...) __attribute__((format(printf
#define N
int count
N_array_3d * N_alloc_array_3d(int cols, int rows, int depths, int offset, int type)
Allocate memory for a N_array_3d data structure.
Definition n_arrays.c:716
void N_free_array_3d(N_array_3d *data)
Release the memory of a N_array_3d.
Definition n_arrays.c:771
DCELL N_get_array_2d_d_value(N_array_2d *data, int col, int row)
Returns the value of type DCELL at position col, row.
Definition n_arrays.c:377
int N_is_array_2d_value_null(N_array_2d *data, int col, int row)
Returns 1 if the value of N_array_2d struct at position col, row is of type null, otherwise 0.
Definition n_arrays.c:228
void N_free_array_2d(N_array_2d *data)
Release the memory of a N_array_2d structure.
Definition n_arrays.c:129
void N_put_array_3d_d_value(N_array_3d *data, int col, int row, int depth, double value)
Writes a double value to the N_array_3d struct at position col, row, depth.
Definition n_arrays.c:1145
N_array_2d * N_alloc_array_2d(int cols, int rows, int offset, int type)
Allocate memory for a N_array_2d data structure.
Definition n_arrays.c:72
double N_get_array_3d_d_value(N_array_3d *data, int col, int row, int depth)
This function returns the value of type float at position col, row, depth.
Definition n_arrays.c:976
void N_put_array_2d_d_value(N_array_2d *data, int col, int row, DCELL value)
Writes a DCELL value to the N_array_2d struct at position col, row.
Definition n_arrays.c:573
double N_get_geom_data_area_of_cell(N_geom_data *geom, int row)
Get the areay size in square meter of one cell (x*y) at row.
Definition n_geom.c:193
N_gradient_field_2d * N_alloc_gradient_field_2d(int cols, int rows)
Allocate a N_gradient_field_2d.
Definition n_gradient.c:893
N_gradient_field_3d * N_alloc_gradient_field_3d(int cols, int rows, int depths)
Allocate a N_gradient_field_3d.
Definition n_gradient.c:990
N_gradient_2d * N_get_gradient_2d(N_gradient_field_2d *field, N_gradient_2d *gradient, int col, int row)
Return a N_gradient_2d structure calculated from the input gradient field at position [row][col].
Definition n_gradient.c:111
N_gradient_3d * N_get_gradient_3d(N_gradient_field_3d *field, N_gradient_3d *gradient, int col, int row, int depth)
Return a N_gradient_3d structure calculated from the input gradient field at position [depth][row][co...
Definition n_gradient.c:243
N_data_star * N_create_9star(double C, double W, double E, double N, double S, double NW, double SW, double NE, double SE, double V)
allocate and initialize a 9 point star data structure
N_data_star * N_create_7star(double C, double W, double E, double N, double S, double T, double B, double V)
allocate and initialize a 7 point star data structure
N_solute_transport_data2d * N_alloc_solute_transport_data2d(int cols, int rows)
Allocate memory for the solute transport data structure in two dimensions.
void N_calc_solute_transport_disptensor_2d(N_solute_transport_data2d *data)
Compute the dispersivity tensor based on the solute transport data in 2d.
void N_free_solute_transport_data2d(N_solute_transport_data2d *data)
Release the memory of the solute transport data structure in two dimensions.
N_solute_transport_data3d * N_alloc_solute_transport_data3d(int cols, int rows, int depths)
Allocate memory for the solute transport data structure in three dimensions.
void N_free_solute_transport_data3d(N_solute_transport_data3d *data)
Release the memory of the solute transport data structure in three dimensions.
N_data_star * N_callback_solute_transport_2d(void *solutedata, N_geom_data *geom, int col, int row)
This callback function creates the mass balance of a 5 point star.
N_data_star * N_callback_solute_transport_3d(void *solutedata, N_geom_data *geom, int col, int row, int depth)
This is just a placeholder.
void N_calc_solute_transport_transmission_2d(N_solute_transport_data2d *data)
Compute the transmission boundary condition in 2d.
void N_calc_solute_transport_disptensor_3d(N_solute_transport_data3d *data)
Compute the dispersivity tensor based on the solute transport data in 3d.
#define W
Definition ogsf.h:144
#define DCELL_TYPE
Definition raster.h:13
Matrix entries for a mass balance 5/7/9 star system.
Definition N_pde.h:292
Geometric information about the structured grid.
Definition N_pde.h:98
Gradient between the cells in X and Y direction.
Definition N_pde.h:454
double EC
Definition N_pde.h:456
double SC
Definition N_pde.h:456
double WC
Definition N_pde.h:456
double NC
Definition N_pde.h:456
Gradient between the cells in X, Y and Z direction.
Definition N_pde.h:461
double WC
Definition N_pde.h:463
double NC
Definition N_pde.h:463
double EC
Definition N_pde.h:463
double SC
Definition N_pde.h:463
double BC
Definition N_pde.h:463
double TC
Definition N_pde.h:463
N_gradient_field_2d * grad
N_gradient_field_3d * grad