GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
N_les_assemble.c
Go to the documentation of this file.
1 
2 /*****************************************************************************
3 *
4 * MODULE: Grass PDE Numerical Library
5 * AUTHOR(S): Soeren Gebbert, Berlin (GER) Dec 2006
6 * soerengebbert <at> gmx <dot> de
7 *
8 * PURPOSE: functions to assemble a linear equation system
9 * part of the gpde library
10 *
11 * COPYRIGHT: (C) 2000 by the GRASS Development Team
12 *
13 * This program is free software under the GNU General Public
14 * License (>=v2). Read the file COPYING that comes with GRASS
15 * for details.
16 *
17 *****************************************************************************/
18 
19 
20 #include <math.h>
21 #include "grass/N_pde.h"
22 
23 /* local protos */
24 static int make_les_entry_2d(int i, int j, int offset_i, int offset_j,
25  int count, int pos, N_les * les,
26  G_math_spvector * spvect,
27  N_array_2d * cell_count, N_array_2d * status,
28  N_array_2d * start_val, double entry,
29  int cell_type);
30 
31 static int make_les_entry_3d(int i, int j, int k, int offset_i, int offset_j,
32  int offset_k, int count, int pos, N_les * les,
33  G_math_spvector * spvect,
34  N_array_3d * cell_count, N_array_3d * status,
35  N_array_3d * start_val, double entry,
36  int cell_type);
37 
38 /* *************************************************************** *
39  * ********************** N_alloc_5star ************************** *
40  * *************************************************************** */
47 {
48  N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
49 
50  star->type = N_5_POINT_STAR;
51  star->count = 5;
52  return star;
53 }
54 
55 /* *************************************************************** *
56  * ********************* N_alloc_7star *************************** *
57  * *************************************************************** */
64 {
65  N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
66 
67  star->type = N_7_POINT_STAR;
68  star->count = 7;
69  return star;
70 }
71 
72 /* *************************************************************** *
73  * ********************* N_alloc_9star *************************** *
74  * *************************************************************** */
84 {
85  N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
86 
87  star->type = N_9_POINT_STAR;
88  star->count = 9;
89  return star;
90 }
91 
92 /* *************************************************************** *
93  * ********************* N_alloc_27star ************************** *
94  * *************************************************************** */
104 {
105  N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
106 
107  star->type = N_27_POINT_STAR;
108  star->count = 27;
109  return star;
110 }
111 
112 /* *************************************************************** *
113  * ********************** N_create_5star ************************* *
114  * *************************************************************** */
126 N_data_star *N_create_5star(double C, double W, double E, double N,
127  double S, double V)
128 {
129  N_data_star *star = N_alloc_5star();
130 
131  star->C = C;
132  star->W = W;
133  star->E = E;
134  star->N = N;
135  star->S = S;
136 
137  star->V = V;
138 
139  G_debug(5, "N_create_5star: w %g e %g n %g s %g c %g v %g\n", star->W,
140  star->E, star->N, star->S, star->C, star->V);
141 
142  return star;
143 }
144 
145 /* *************************************************************** *
146  * ************************* N_create_7star ********************** *
147  * *************************************************************** */
161 N_data_star *N_create_7star(double C, double W, double E, double N,
162  double S, double T, double B, double V)
163 {
164  N_data_star *star = N_alloc_7star();
165 
166  star->C = C;
167  star->W = W;
168  star->E = E;
169  star->N = N;
170  star->S = S;
171 
172  star->T = T;
173  star->B = B;
174 
175  star->V = V;
176 
177  G_debug(5, "N_create_7star: w %g e %g n %g s %g t %g b %g c %g v %g\n",
178  star->W, star->E, star->N, star->S, star->T, star->B, star->C,
179  star->V);
180 
181  return star;
182 }
183 
184 /* *************************************************************** *
185  * ************************ N_create_9star *********************** *
186  * *************************************************************** */
202 N_data_star *N_create_9star(double C, double W, double E, double N,
203  double S, double NW, double SW, double NE,
204  double SE, double V)
205 {
206  N_data_star *star = N_alloc_9star();
207 
208  star->C = C;
209  star->W = W;
210  star->E = E;
211  star->N = N;
212  star->S = S;
213 
214  star->NW = NW;
215  star->SW = SW;
216  star->NE = NE;
217  star->SE = SE;
218 
219  star->V = V;
220 
221  G_debug(5,
222  "N_create_9star: w %g e %g n %g s %g nw %g sw %g ne %g se %g c %g v %g\n",
223  star->W, star->E, star->N, star->S, star->NW, star->SW, star->NE,
224  star->SE, star->C, star->V);
225 
226  return star;
227 }
228 
229 /* *************************************************************** *
230  * ************************ N_create_27star *********************** *
231  * *************************************************************** */
265 N_data_star *N_create_27star(double C, double W, double E, double N, double S,
266  double NW, double SW, double NE, double SE,
267  double T, double W_T, double E_T, double N_T,
268  double S_T, double NW_T, double SW_T,
269  double NE_T, double SE_T, double B, double W_B,
270  double E_B, double N_B, double S_B, double NW_B,
271  double SW_B, double NE_B, double SE_B, double V)
272 {
273  N_data_star *star = N_alloc_27star();
274 
275  star->C = C;
276  star->W = W;
277  star->E = E;
278  star->N = N;
279  star->S = S;
280 
281  star->NW = NW;
282  star->SW = SW;
283  star->NE = NE;
284  star->SE = SE;
285 
286  star->T = T;
287  star->W_T = W_T;
288  star->E_T = E_T;
289  star->N_T = N_T;
290  star->S_T = S_T;
291 
292  star->NW_T = NW_T;
293  star->SW_T = SW_T;
294  star->NE_T = NE_T;
295  star->SE_T = SE_T;
296 
297  star->B = B;
298  star->W_B = W_B;
299  star->E_B = E_B;
300  star->N_B = N_B;
301  star->S_B = S_B;
302 
303  star->NW_B = NW_B;
304  star->SW_B = SW_B;
305  star->NE_B = NE_B;
306  star->SE_B = SE_B;
307 
308  star->V = V;
309 
310  G_debug(5,
311  "N_create_27star: w %g e %g n %g s %g nw %g sw %g ne %g se %g c %g v %g\n",
312  star->W, star->E, star->N, star->S, star->NW, star->SW, star->NE,
313  star->SE, star->C, star->V);
314 
315  G_debug(5,
316  "N_create_27star: w_t %g e_t %g n_t %g s_t %g nw_t %g sw_t %g ne_t %g se_t %g t %g \n",
317  star->W_T, star->E_T, star->N_T, star->S_T, star->NW_T,
318  star->SW_T, star->NE_T, star->SE_T, star->T);
319 
320  G_debug(5,
321  "N_create_27star: w_b %g e_b %g n_b %g s_b %g nw_b %g sw_b %g ne_b %g se_B %g b %g\n",
322  star->W_B, star->E_B, star->N_B, star->S_B, star->NW_B,
323  star->SW_B, star->NE_B, star->SE_B, star->B);
324 
325 
326 
327  return star;
328 }
329 
330 
331 /* *************************************************************** *
332  * ****************** N_set_les_callback_3d_func ***************** *
333  * *************************************************************** */
341 void
343  N_data_star * (*callback_func_3d) ())
344 {
345  data->callback = callback_func_3d;
346 }
347 
348 /* *************************************************************** *
349  * *************** N_set_les_callback_2d_func ******************** *
350  * *************************************************************** */
358 void
360  N_data_star * (*callback_func_2d) ())
361 {
362  data->callback = callback_func_2d;
363 }
364 
365 /* *************************************************************** *
366  * ************** N_alloc_les_callback_3d ************************ *
367  * *************************************************************** */
377 {
379 
380  call = (N_les_callback_3d *) G_calloc(1, sizeof(N_les_callback_3d *));
382 
383  return call;
384 }
385 
386 /* *************************************************************** *
387  * *************** N_alloc_les_callback_2d *********************** *
388  * *************************************************************** */
398 {
400 
401  call = (N_les_callback_2d *) G_calloc(1, sizeof(N_les_callback_2d *));
403 
404  return call;
405 }
406 
407 /* *************************************************************** *
408  * ******************** N_callback_template_3d ******************* *
409  * *************************************************************** */
424 N_data_star *N_callback_template_3d(void *data, N_geom_data * geom, int col,
425  int row, int depth)
426 {
427  N_data_star *star = N_alloc_7star();
428 
429  star->E = 1 / geom->dx;
430  star->W = 1 / geom->dx;
431  star->N = 1 / geom->dy;
432  star->S = 1 / geom->dy;
433  star->T = 1 / geom->dz;
434  star->B = 1 / geom->dz;
435  star->C = -1 * (2 / geom->dx + 2 / geom->dy + 2 / geom->dz);
436  star->V = -1;
437 
438  G_debug(5,
439  "N_callback_template_3d: w %g e %g n %g s %g t %g b %g c %g v %g\n",
440  star->W, star->E, star->N, star->S, star->T, star->B, star->C,
441  star->V);
442 
443 
444  return star;
445 }
446 
447 /* *************************************************************** *
448  * ********************* N_callback_template_2d ****************** *
449  * *************************************************************** */
463 N_data_star *N_callback_template_2d(void *data, N_geom_data * geom, int col,
464  int row)
465 {
466  N_data_star *star = N_alloc_9star();
467 
468  star->E = 1 / geom->dx;
469  star->NE = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
470  star->SE = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
471  star->W = 1 / geom->dx;
472  star->NW = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
473  star->SW = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
474  star->N = 1 / geom->dy;
475  star->S = 1 / geom->dy;
476  star->C =
477  -1 * (star->E + star->NE + star->SE + star->W + star->NW + star->SW +
478  star->N + star->S);
479  star->V = 0;
480 
481  return star;
482 }
483 
484 /* *************************************************************** *
485  * ******************** N_assemble_les_2d ************************ *
486  * *************************************************************** */
493 N_les *N_assemble_les_2d(int les_type, N_geom_data * geom,
494  N_array_2d * status, N_array_2d * start_val,
495  void *data, N_les_callback_2d * call)
496 {
497  return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
498  call, N_CELL_ACTIVE);
499 }
500 
508  N_array_2d * status, N_array_2d * start_val,
509  void *data, N_les_callback_2d * call)
510 {
511  return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
512  call, N_CELL_ACTIVE);
513 }
514 
522  N_array_2d * status,
523  N_array_2d * start_val, void *data,
525 {
526  return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
527  call, N_CELL_DIRICHLET);
528 }
529 
561  N_array_2d * status, N_array_2d * start_val,
562  void *data, N_les_callback_2d * call,
563  int cell_type)
564 {
565  int i, j, count = 0, pos = 0;
566 
567  int cell_type_count = 0;
568 
569  int **index_ij;
570 
571  N_array_2d *cell_count;
572 
573  N_les *les = NULL;
574 
575  G_debug(2,
576  "N_assemble_les_2d: starting to assemble the linear equation system");
577 
578  /* At first count the number of valid cells and save the
579  * each number in a new 2d array. Those numbers are used
580  * to create the linear equation system.
581  * */
582 
583  cell_count = N_alloc_array_2d(geom->cols, geom->rows, 1, CELL_TYPE);
584 
585  /* include dirichlet cells in the les */
586  if (cell_type == N_CELL_DIRICHLET) {
587  for (j = 0; j < geom->rows; j++) {
588  for (i = 0; i < geom->cols; i++) {
589  /*use all non-inactive cells for les creation */
590  if (N_CELL_INACTIVE < N_get_array_2d_c_value(status, i, j) &&
592  cell_type_count++;
593  }
594  }
595  }
596  /*use only active cell in the les */
597  if (cell_type == N_CELL_ACTIVE) {
598  for (j = 0; j < geom->rows; j++) {
599  for (i = 0; i < geom->cols; i++) {
600  /*count only active cells */
601  if (N_CELL_ACTIVE == N_get_array_2d_d_value(status, i, j))
602  cell_type_count++;
603  }
604  }
605  }
606 
607  G_debug(2, "N_assemble_les_2d: number of used cells %i\n",
608  cell_type_count);
609 
610  if (cell_type_count == 0)
612  ("Not enough cells [%i] to create the linear equation system. Check the cell status. Only active cells (value = 1) are used to create the equation system.",
613  cell_type_count);
614 
615  /* Then allocate the memory for the linear equation system (les).
616  * Only valid cells are used to create the les. */
617  index_ij = (int **)G_calloc(cell_type_count, sizeof(int *));
618  for (i = 0; i < cell_type_count; i++)
619  index_ij[i] = (int *)G_calloc(2, sizeof(int));
620 
621  les = N_alloc_les_Ax_b(cell_type_count, les_type);
622 
623  count = 0;
624 
625  /*count the number of cells which should be used to create the linear equation system */
626  /*save the i and j indices and create a ordered numbering */
627  for (j = 0; j < geom->rows; j++) {
628  for (i = 0; i < geom->cols; i++) {
629  /*count every non-inactive cell */
630  if (cell_type == N_CELL_DIRICHLET) {
631  if (N_CELL_INACTIVE < N_get_array_2d_c_value(status, i, j) &&
632  N_get_array_2d_c_value(status, i, j) < N_MAX_CELL_STATE) {
633  N_put_array_2d_c_value(cell_count, i, j, count);
634  index_ij[count][0] = i;
635  index_ij[count][1] = j;
636  count++;
637  G_debug(5,
638  "N_assemble_les_2d: non-inactive cells count %i at pos x[%i] y[%i]\n",
639  count, i, j);
640  }
641  /*count every active cell */
642  }
643  else if (N_CELL_ACTIVE == N_get_array_2d_c_value(status, i, j)) {
644  N_put_array_2d_c_value(cell_count, i, j, count);
645  index_ij[count][0] = i;
646  index_ij[count][1] = j;
647  count++;
648  G_debug(5,
649  "N_assemble_les_2d: active cells count %i at pos x[%i] y[%i]\n",
650  count, i, j);
651  }
652  }
653  }
654 
655  G_debug(2, "N_assemble_les_2d: starting the parallel assemble loop");
656 
657  /* Assemble the matrix in parallel */
658 #pragma omp parallel for private(i, j, pos, count) schedule(static)
659  for (count = 0; count < cell_type_count; count++) {
660  i = index_ij[count][0];
661  j = index_ij[count][1];
662 
663  /*create the entries for the */
664  N_data_star *items = call->callback(data, geom, i, j);
665 
666  /* we need a sparse vector pointer anytime */
667  G_math_spvector *spvect = NULL;
668 
669  /*allocate a sprase vector */
670  if (les_type == N_SPARSE_LES) {
671  spvect = G_math_alloc_spvector(items->count);
672  }
673  /* initial conditions */
674  les->x[count] = N_get_array_2d_d_value(start_val, i, j);
675 
676  /* the entry in the vector b */
677  les->b[count] = items->V;
678 
679  /* pos describes the position in the sparse vector.
680  * the first entry is always the diagonal entry of the matrix*/
681  pos = 0;
682 
683  if (les_type == N_SPARSE_LES) {
684  spvect->index[pos] = count;
685  spvect->values[pos] = items->C;
686  }
687  else {
688  les->A[count][count] = items->C;
689  }
690  /* western neighbour, entry is col - 1 */
691  if (i > 0) {
692  pos = make_les_entry_2d(i, j, -1, 0, count, pos, les, spvect,
693  cell_count, status, start_val, items->W,
694  cell_type);
695  }
696  /* eastern neighbour, entry col + 1 */
697  if (i < geom->cols - 1) {
698  pos = make_les_entry_2d(i, j, 1, 0, count, pos, les, spvect,
699  cell_count, status, start_val, items->E,
700  cell_type);
701  }
702  /* northern neighbour, entry row - 1 */
703  if (j > 0) {
704  pos =
705  make_les_entry_2d(i, j, 0, -1, count, pos, les, spvect,
706  cell_count, status, start_val, items->N,
707  cell_type);
708  }
709  /* southern neighbour, entry row + 1 */
710  if (j < geom->rows - 1) {
711  pos = make_les_entry_2d(i, j, 0, 1, count, pos, les, spvect,
712  cell_count, status, start_val, items->S,
713  cell_type);
714  }
715  /*in case of a nine point star, we have additional entries */
716  if (items->type == N_9_POINT_STAR) {
717  /* north-western neighbour, entry is col - 1 row - 1 */
718  if (i > 0 && j > 0) {
719  pos = make_les_entry_2d(i, j, -1, -1, count, pos, les, spvect,
720  cell_count, status, start_val,
721  items->NW, cell_type);
722  }
723  /* north-eastern neighbour, entry col + 1 row - 1 */
724  if (i < geom->cols - 1 && j > 0) {
725  pos = make_les_entry_2d(i, j, 1, -1, count, pos, les, spvect,
726  cell_count, status, start_val,
727  items->NE, cell_type);
728  }
729  /* south-western neighbour, entry is col - 1 row + 1 */
730  if (i > 0 && j < geom->rows - 1) {
731  pos = make_les_entry_2d(i, j, -1, 1, count, pos, les, spvect,
732  cell_count, status, start_val,
733  items->SW, cell_type);
734  }
735  /* south-eastern neighbour, entry col + 1 row + 1 */
736  if (i < geom->cols - 1 && j < geom->rows - 1) {
737  pos = make_les_entry_2d(i, j, 1, 1, count, pos, les, spvect,
738  cell_count, status, start_val,
739  items->SE, cell_type);
740  }
741  }
742 
743  /*How many entries in the les */
744  if (les->type == N_SPARSE_LES) {
745  spvect->cols = pos + 1;
746  G_math_add_spvector(les->Asp, spvect, count);
747  }
748 
749  if (items)
750  G_free(items);
751  }
752 
753  /*release memory */
754  N_free_array_2d(cell_count);
755 
756  for (i = 0; i < cell_type_count; i++)
757  G_free(index_ij[i]);
758 
759  G_free(index_ij);
760 
761  return les;
762 }
763 
791  N_array_2d * status, N_array_2d * start_val)
792 {
793  int rows, cols;
794 
795  int count = 0;
796 
797  int i, j, x, y, stat;
798 
799  double *dvect1;
800 
801  double *dvect2;
802 
803  G_debug(2,
804  "N_les_integrate_dirichlet_2d: integrating the dirichlet boundary condition");
805 
806  rows = geom->rows;
807  cols = geom->cols;
808 
809  /*we nned to additional vectors */
810  dvect1 = (double *)G_calloc(les->cols, sizeof(double));
811  dvect2 = (double *)G_calloc(les->cols, sizeof(double));
812 
813  /*fill the first one with the x vector data of Dirichlet cells */
814  count = 0;
815  for (y = 0; y < rows; y++) {
816  for (x = 0; x < cols; x++) {
817  stat = N_get_array_2d_c_value(status, x, y);
818  if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
819  dvect1[count] = N_get_array_2d_d_value(start_val, x, y);
820  count++;
821  }
822  else if (stat == N_CELL_ACTIVE) {
823  dvect1[count] = 0.0;
824  count++;
825  }
826  }
827  }
828 
829 #pragma omp parallel default(shared)
830  {
831  /*performe the matrix vector product and */
832  if (les->type == N_SPARSE_LES)
833  G_math_Ax_sparse(les->Asp, dvect1, dvect2, les->rows);
834  else
835  G_math_d_Ax(les->A, dvect1, dvect2, les->rows, les->cols);
836 #pragma omp for schedule (static) private(i)
837  for (i = 0; i < les->cols; i++)
838  les->b[i] = les->b[i] - dvect2[i];
839  }
840 
841  /*now set the Dirichlet cell rows and cols to zero and the
842  * diagonal entry to 1*/
843  count = 0;
844  for (y = 0; y < rows; y++) {
845  for (x = 0; x < cols; x++) {
846  stat = N_get_array_2d_c_value(status, x, y);
847  if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
848  if (les->type == N_SPARSE_LES) {
849  /*set the rows to zero */
850  for (i = 0; i < les->Asp[count]->cols; i++)
851  les->Asp[count]->values[i] = 0.0;
852  /*set the cols to zero */
853  for (i = 0; i < les->rows; i++) {
854  for (j = 0; j < les->Asp[i]->cols; j++) {
855  if (les->Asp[i]->index[j] == count)
856  les->Asp[i]->values[j] = 0.0;
857  }
858  }
859 
860  /*entry on the diagonal */
861  les->Asp[count]->values[0] = 1.0;
862 
863  }
864  else {
865  /*set the rows to zero */
866  for (i = 0; i < les->cols; i++)
867  les->A[count][i] = 0.0;
868  /*set the cols to zero */
869  for (i = 0; i < les->rows; i++)
870  les->A[i][count] = 0.0;
871 
872  /*entry on the diagonal */
873  les->A[count][count] = 1.0;
874  }
875  }
876  if (stat >= N_CELL_ACTIVE)
877  count++;
878  }
879  }
880 
881  return 0;
882 
883 }
884 
885 /* **************************************************************** */
886 /* **** make an entry in the les (2d) ***************************** */
887 /* **************************************************************** */
888 int make_les_entry_2d(int i, int j, int offset_i, int offset_j, int count,
889  int pos, N_les * les, G_math_spvector * spvect,
890  N_array_2d * cell_count, N_array_2d * status,
891  N_array_2d * start_val, double entry, int cell_type)
892 {
893  int K;
894 
895  int di = offset_i;
896 
897  int dj = offset_j;
898 
899  K = N_get_array_2d_c_value(cell_count, i + di, j + dj) -
900  N_get_array_2d_c_value(cell_count, i, j);
901 
902  /* active cells build the linear equation system */
903  if (cell_type == N_CELL_ACTIVE) {
904  /* dirichlet or transmission cells must be handled like this */
905  if (N_get_array_2d_c_value(status, i + di, j + dj) > N_CELL_ACTIVE &&
906  N_get_array_2d_c_value(status, i + di, j + dj) < N_MAX_CELL_STATE)
907  les->b[count] -=
908  N_get_array_2d_d_value(start_val, i + di, j + dj) * entry;
909  else if (N_get_array_2d_c_value(status, i + di, j + dj) ==
910  N_CELL_ACTIVE) {
911  if ((count + K) >= 0 && (count + K) < les->cols) {
912  G_debug(5,
913  " make_les_entry_2d: (N_CELL_ACTIVE) create matrix entry at row[%i] col[%i] value %g\n",
914  count, count + K, entry);
915  pos++;
916  if (les->type == N_SPARSE_LES) {
917  spvect->index[pos] = count + K;
918  spvect->values[pos] = entry;
919  }
920  else {
921  les->A[count][count + K] = entry;
922  }
923  }
924  }
925  } /* if dirichlet cells should be used then check for all valid cell neighbours */
926  else if (cell_type == N_CELL_DIRICHLET) {
927  /* all valid cells */
928  if (N_get_array_2d_c_value(status, i + di, j + dj) > N_CELL_INACTIVE
929  && N_get_array_2d_c_value(status, i + di,
930  j + dj) < N_MAX_CELL_STATE) {
931  if ((count + K) >= 0 && (count + K) < les->cols) {
932  G_debug(5,
933  " make_les_entry_2d: (N_CELL_DIRICHLET) create matrix entry at row[%i] col[%i] value %g\n",
934  count, count + K, entry);
935  pos++;
936  if (les->type == N_SPARSE_LES) {
937  spvect->index[pos] = count + K;
938  spvect->values[pos] = entry;
939  }
940  else {
941  les->A[count][count + K] = entry;
942  }
943  }
944  }
945  }
946 
947  return pos;
948 }
949 
950 
951 /* *************************************************************** *
952  * ******************** N_assemble_les_3d ************************ *
953  * *************************************************************** */
959 N_les *N_assemble_les_3d(int les_type, N_geom_data * geom,
960  N_array_3d * status, N_array_3d * start_val,
961  void *data, N_les_callback_3d * call)
962 {
963  return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
964  call, N_CELL_ACTIVE);
965 }
966 
973  N_array_3d * status, N_array_3d * start_val,
974  void *data, N_les_callback_3d * call)
975 {
976  return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
977  call, N_CELL_ACTIVE);
978 }
979 
986  N_array_3d * status,
987  N_array_3d * start_val, void *data,
989 {
990  return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
991  call, N_CELL_DIRICHLET);
992 }
993 
1023  N_array_3d * status, N_array_3d * start_val,
1024  void *data, N_les_callback_3d * call,
1025  int cell_type)
1026 {
1027  int i, j, k, count = 0, pos = 0;
1028 
1029  int cell_type_count = 0;
1030 
1031  N_array_3d *cell_count;
1032 
1033  N_les *les = NULL;
1034 
1035  int **index_ij;
1036 
1037  G_debug(2,
1038  "N_assemble_les_3d: starting to assemble the linear equation system");
1039 
1040  cell_count =
1041  N_alloc_array_3d(geom->cols, geom->rows, geom->depths, 1, DCELL_TYPE);
1042 
1043  /* First count the number of valid cells and save
1044  * each number in a new 3d array. Those numbers are used
1045  * to create the linear equation system.*/
1046 
1047  if (cell_type == N_CELL_DIRICHLET) {
1048  /* include dirichlet cells in the les */
1049  for (k = 0; k < geom->depths; k++) {
1050  for (j = 0; j < geom->rows; j++) {
1051  for (i = 0; i < geom->cols; i++) {
1052  /*use all non-inactive cells for les creation */
1053  if (N_CELL_INACTIVE <
1054  (int)N_get_array_3d_d_value(status, i, j, k) &&
1055  (int)N_get_array_3d_d_value(status, i, j,
1056  k) < N_MAX_CELL_STATE)
1057  cell_type_count++;
1058  }
1059  }
1060  }
1061  }
1062  else {
1063  /*use only active cell in the les */
1064  for (k = 0; k < geom->depths; k++) {
1065  for (j = 0; j < geom->rows; j++) {
1066  for (i = 0; i < geom->cols; i++) {
1067  /*count only active cells */
1068  if (N_CELL_ACTIVE
1069  == (int)N_get_array_3d_d_value(status, i, j, k))
1070  cell_type_count++;
1071 
1072  }
1073  }
1074  }
1075  }
1076 
1077  G_debug(2,
1078  "N_assemble_les_3d: number of used cells %i\n", cell_type_count);
1079 
1080  if (cell_type_count == 0.0)
1082  ("Not enough active cells [%i] to create the linear equation system. Check the cell status. Only active cells (value = 1) are used to create the equation system.",
1083  cell_type_count);
1084 
1085  /* allocate the memory for the linear equation system (les).
1086  * Only valid cells are used to create the les. */
1087  les = N_alloc_les_Ax_b(cell_type_count, les_type);
1088 
1089  index_ij = (int **)G_calloc(cell_type_count, sizeof(int *));
1090  for (i = 0; i < cell_type_count; i++)
1091  index_ij[i] = (int *)G_calloc(3, sizeof(int));
1092 
1093  count = 0;
1094  /*count the number of cells which should be used to create the linear equation system */
1095  /*save the k, i and j indices and create a ordered numbering */
1096  for (k = 0; k < geom->depths; k++) {
1097  for (j = 0; j < geom->rows; j++) {
1098  for (i = 0; i < geom->cols; i++) {
1099  if (cell_type == N_CELL_DIRICHLET) {
1100  if (N_CELL_INACTIVE <
1101  (int)N_get_array_3d_d_value(status, i, j, k) &&
1102  (int)N_get_array_3d_d_value(status, i, j,
1103  k) < N_MAX_CELL_STATE) {
1104  N_put_array_3d_d_value(cell_count, i, j, k, count);
1105  index_ij[count][0] = i;
1106  index_ij[count][1] = j;
1107  index_ij[count][2] = k;
1108  count++;
1109  G_debug(5,
1110  "N_assemble_les_3d: non-inactive cells count %i at pos x[%i] y[%i] z[%i]\n",
1111  count, i, j, k);
1112  }
1113  }
1114  else if (N_CELL_ACTIVE ==
1115  (int)N_get_array_3d_d_value(status, i, j, k)) {
1116  N_put_array_3d_d_value(cell_count, i, j, k, count);
1117  index_ij[count][0] = i;
1118  index_ij[count][1] = j;
1119  index_ij[count][2] = k;
1120  count++;
1121  G_debug(5,
1122  "N_assemble_les_3d: active cells count %i at pos x[%i] y[%i] z[%i]\n",
1123  count, i, j, k);
1124  }
1125  }
1126  }
1127  }
1128 
1129  G_debug(2, "N_assemble_les_3d: starting the parallel assemble loop");
1130 
1131 #pragma omp parallel for private(i, j, k, pos, count) schedule(static)
1132  for (count = 0; count < cell_type_count; count++) {
1133  i = index_ij[count][0];
1134  j = index_ij[count][1];
1135  k = index_ij[count][2];
1136 
1137  /*create the entries for the */
1138  N_data_star *items = call->callback(data, geom, i, j, k);
1139 
1140  G_math_spvector *spvect = NULL;
1141 
1142  /*allocate a sprase vector */
1143  if (les_type == N_SPARSE_LES)
1144  spvect = G_math_alloc_spvector(items->count);
1145  /* initial conditions */
1146 
1147  les->x[count] = N_get_array_3d_d_value(start_val, i, j, k);
1148 
1149  /* the entry in the vector b */
1150  les->b[count] = items->V;
1151 
1152  /* pos describes the position in the sparse vector.
1153  * the first entry is always the diagonal entry of the matrix*/
1154  pos = 0;
1155 
1156  if (les_type == N_SPARSE_LES) {
1157  spvect->index[pos] = count;
1158  spvect->values[pos] = items->C;
1159  }
1160  else {
1161  les->A[count][count] = items->C;
1162  }
1163  /* western neighbour, entry is col - 1 */
1164  if (i > 0) {
1165  pos =
1166  make_les_entry_3d(i, j, k, -1, 0, 0, count, pos, les, spvect,
1167  cell_count, status, start_val, items->W,
1168  cell_type);
1169  }
1170  /* eastern neighbour, entry col + 1 */
1171  if (i < geom->cols - 1) {
1172  pos = make_les_entry_3d(i, j, k, 1, 0, 0, count, pos, les, spvect,
1173  cell_count, status, start_val, items->E,
1174  cell_type);
1175  }
1176  /* northern neighbour, entry row -1 */
1177  if (j > 0) {
1178  pos =
1179  make_les_entry_3d(i, j, k, 0, -1, 0, count, pos, les, spvect,
1180  cell_count, status, start_val, items->N,
1181  cell_type);
1182  }
1183  /* southern neighbour, entry row +1 */
1184  if (j < geom->rows - 1) {
1185  pos = make_les_entry_3d(i, j, k, 0, 1, 0, count, pos, les, spvect,
1186  cell_count, status, start_val, items->S,
1187  cell_type);
1188  }
1189  /*only for a 7 star entry needed */
1190  if (items->type == N_7_POINT_STAR || items->type == N_27_POINT_STAR) {
1191  /* the upper cell (top), entry depth + 1 */
1192  if (k < geom->depths - 1) {
1193  pos =
1194  make_les_entry_3d(i, j, k, 0, 0, 1, count, pos, les,
1195  spvect, cell_count, status, start_val,
1196  items->T, cell_type);
1197  }
1198  /* the lower cell (bottom), entry depth - 1 */
1199  if (k > 0) {
1200  pos =
1201  make_les_entry_3d(i, j, k, 0, 0, -1, count, pos, les,
1202  spvect, cell_count, status, start_val,
1203  items->B, cell_type);
1204  }
1205  }
1206 
1207  /*How many entries in the les */
1208  if (les->type == N_SPARSE_LES) {
1209  spvect->cols = pos + 1;
1210  G_math_add_spvector(les->Asp, spvect, count);
1211  }
1212 
1213  if (items)
1214  G_free(items);
1215  }
1216 
1217  N_free_array_3d(cell_count);
1218 
1219  for (i = 0; i < cell_type_count; i++)
1220  G_free(index_ij[i]);
1221 
1222  G_free(index_ij);
1223 
1224  return les;
1225 }
1226 
1254  N_array_3d * status, N_array_3d * start_val)
1255 {
1256  int rows, cols, depths;
1257 
1258  int count = 0;
1259 
1260  int i, j, x, y, z, stat;
1261 
1262  double *dvect1;
1263 
1264  double *dvect2;
1265 
1266  G_debug(2,
1267  "N_les_integrate_dirichlet_3d: integrating the dirichlet boundary condition");
1268 
1269  rows = geom->rows;
1270  cols = geom->cols;
1271  depths = geom->depths;
1272 
1273  /*we nned to additional vectors */
1274  dvect1 = (double *)G_calloc(les->cols, sizeof(double));
1275  dvect2 = (double *)G_calloc(les->cols, sizeof(double));
1276 
1277  /*fill the first one with the x vector data of Dirichlet cells */
1278  count = 0;
1279  for (z = 0; z < depths; z++) {
1280  for (y = 0; y < rows; y++) {
1281  for (x = 0; x < cols; x++) {
1282  stat = (int)N_get_array_3d_d_value(status, x, y, z);
1283  if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
1284  dvect1[count] =
1285  N_get_array_3d_d_value(start_val, x, y, z);
1286  count++;
1287  }
1288  else if (stat == N_CELL_ACTIVE) {
1289  dvect1[count] = 0.0;
1290  count++;
1291  }
1292  }
1293  }
1294  }
1295 
1296 #pragma omp parallel default(shared)
1297  {
1298  /*performe the matrix vector product and */
1299  if (les->type == N_SPARSE_LES)
1300  G_math_Ax_sparse(les->Asp, dvect1, dvect2, les->rows);
1301  else
1302  G_math_d_Ax(les->A, dvect1, dvect2, les->rows, les->cols);
1303 #pragma omp for schedule (static) private(i)
1304  for (i = 0; i < les->cols; i++)
1305  les->b[i] = les->b[i] - dvect2[i];
1306  }
1307 
1308  /*now set the Dirichlet cell rows and cols to zero and the
1309  * diagonal entry to 1*/
1310  count = 0;
1311  for (z = 0; z < depths; z++) {
1312  for (y = 0; y < rows; y++) {
1313  for (x = 0; x < cols; x++) {
1314  stat = (int)N_get_array_3d_d_value(status, x, y, z);
1315  if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
1316  if (les->type == N_SPARSE_LES) {
1317  /*set the rows to zero */
1318  for (i = 0; i < les->Asp[count]->cols; i++)
1319  les->Asp[count]->values[i] = 0.0;
1320  /*set the cols to zero */
1321  for (i = 0; i < les->rows; i++) {
1322  for (j = 0; j < les->Asp[i]->cols; j++) {
1323  if (les->Asp[i]->index[j] == count)
1324  les->Asp[i]->values[j] = 0.0;
1325  }
1326  }
1327 
1328  /*entry on the diagonal */
1329  les->Asp[count]->values[0] = 1.0;
1330 
1331  }
1332  else {
1333  /*set the rows to zero */
1334  for (i = 0; i < les->cols; i++)
1335  les->A[count][i] = 0.0;
1336  /*set the cols to zero */
1337  for (i = 0; i < les->rows; i++)
1338  les->A[i][count] = 0.0;
1339 
1340  /*entry on the diagonal */
1341  les->A[count][count] = 1.0;
1342  }
1343  }
1344  count++;
1345  }
1346  }
1347  }
1348 
1349  return 0;
1350 
1351 }
1352 
1353 /* **************************************************************** */
1354 /* **** make an entry in the les (3d) ***************************** */
1355 /* **************************************************************** */
1356 int make_les_entry_3d(int i, int j, int k, int offset_i, int offset_j,
1357  int offset_k, int count, int pos, N_les * les,
1358  G_math_spvector * spvect, N_array_3d * cell_count,
1359  N_array_3d * status, N_array_3d * start_val,
1360  double entry, int cell_type)
1361 {
1362  int K;
1363 
1364  int di = offset_i;
1365 
1366  int dj = offset_j;
1367 
1368  int dk = offset_k;
1369 
1370  K = (int)N_get_array_3d_d_value(cell_count, i + di, j + dj, k + dk) -
1371  (int)N_get_array_3d_d_value(cell_count, i, j, k);
1372 
1373  if (cell_type == N_CELL_ACTIVE) {
1374  if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk) >
1375  N_CELL_ACTIVE &&
1376  (int)N_get_array_3d_d_value(status, i + di, j + dj,
1377  k + dk) < N_MAX_CELL_STATE)
1378  les->b[count] -=
1379  N_get_array_3d_d_value(start_val, i + di, j + dj,
1380  k + dk) * entry;
1381  else if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk)
1382  == N_CELL_ACTIVE) {
1383  if ((count + K) >= 0 && (count + K) < les->cols) {
1384  G_debug(5,
1385  " make_les_entry_3d: (N_CELL_ACTIVE) create matrix entry at row[%i] col[%i] value %g\n",
1386  count, count + K, entry);
1387  pos++;
1388  if (les->type == N_SPARSE_LES) {
1389  spvect->index[pos] = count + K;
1390  spvect->values[pos] = entry;
1391  }
1392  else {
1393  les->A[count][count + K] = entry;
1394  }
1395  }
1396  }
1397  }
1398  else if (cell_type == N_CELL_DIRICHLET) {
1399  if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk)
1400  != N_CELL_INACTIVE) {
1401  if ((count + K) >= 0 && (count + K) < les->cols) {
1402  G_debug(5,
1403  " make_les_entry_3d: (N_CELL_DIRICHLET) create matrix entry at row[%i] col[%i] value %g\n",
1404  count, count + K, entry);
1405  pos++;
1406  if (les->type == N_SPARSE_LES) {
1407  spvect->index[pos] = count + K;
1408  spvect->values[pos] = entry;
1409  }
1410  else {
1411  les->A[count][count + K] = entry;
1412  }
1413  }
1414  }
1415  }
1416 
1417  return pos;
1418 }
void N_free_array_2d(N_array_2d *data)
Release the memory of a N_array_2d structure.
Definition: N_arrays.c:127
double S_T
Definition: N_pde.h:348
double SW_T
Definition: N_pde.h:348
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:142
double N
Definition: N_pde.h:346
double S_B
Definition: N_pde.h:350
Matrix entries for a mass balance 5/7/9 star system.
Definition: N_pde.h:342
#define N_27_POINT_STAR
Definition: N_pde.h:57
N_data_star * N_alloc_27star(void)
allocate a 27 point star data structure
N_les_callback_3d * N_alloc_les_callback_3d(void)
Allocate the structure holding the callback function.
double E
Definition: N_pde.h:346
double NW_B
Definition: N_pde.h:350
N_les * N_assemble_les_3d_active(int les_type, N_geom_data *geom, N_array_3d *status, N_array_3d *start_val, void *data, N_les_callback_3d *call)
Assemble a linear equation system (les) based on 3d location data (g3d) active cells.
G_math_spvector * G_math_alloc_spvector(int cols)
Allocate memory for a sparse vector.
Definition: sparse_matrix.c:76
N_les * N_alloc_les_Ax_b(int rows, int type)
Allocate memory for a quadratic linear equation system which includes the Matrix A, vector x and vector b.
Definition: N_les.c:145
void N_free_array_3d(N_array_3d *data)
Release the memory of a N_array_3d.
Definition: N_arrays.c:777
N_les * N_assemble_les_2d(int les_type, N_geom_data *geom, N_array_2d *status, N_array_2d *start_val, void *data, N_les_callback_2d *call)
Assemble a linear equation system (les) based on 2d location data (raster) and active cells...
void G_math_d_Ax(double **A, double *x, double *y, int rows, int cols)
Compute the matrix - vector product of matrix A and vector x.
Definition: blas_level_2.c:79
double C
Definition: N_pde.h:346
int count
tuple pos
Definition: tools.py:1367
#define NE
Definition: dataquad.h:18
#define N_SPARSE_LES
Definition: N_pde.h:43
#define N_MAX_CELL_STATE
the maximum number of available cell states (eg: boundary condition, inactiven active) ...
Definition: N_pde.h:52
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:69
double T
Definition: N_pde.h:348
#define NW
Definition: dataquad.h:17
double * x
Definition: N_pde.h:88
int y
Definition: plot.c:34
int depths
Definition: N_pde.h:139
callback structure for 2d matrix assembling
Definition: N_pde.h:364
#define N_CELL_ACTIVE
Definition: N_pde.h:46
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:723
int count
Definition: N_pde.h:345
double S
Definition: N_pde.h:346
double dy
Definition: N_pde.h:134
N_data_star * N_alloc_5star(void)
allocate a 5 point star data structure
double W_B
Definition: N_pde.h:350
N_data_star * N_alloc_9star(void)
allocate a 9 point star data structure
#define SW
Definition: dataquad.h:19
#define C
Definition: intr_char.c:17
Geometric information about the structured grid.
Definition: N_pde.h:127
double dz
Definition: N_pde.h:135
tuple data
int stat
Definition: g3dcolor.c:369
int rows
Definition: N_pde.h:140
void N_set_les_callback_3d_func(N_les_callback_3d *data, N_data_star *(*callback_func_3d)())
Set the callback function which is called while assembling the les in 3d.
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
double ** A
Definition: N_pde.h:90
N_data_star * N_create_27star(double C, double W, double E, double N, double S, double NW, double SW, double NE, double SE, double T, double W_T, double E_T, double N_T, double S_T, double NW_T, double SW_T, double NE_T, double SE_T, double B, double W_B, double E_B, double N_B, double S_B, double NW_B, double SW_B, double NE_B, double SE_B, double V)
allocate and initialize a 27 point star data structure
double E_T
Definition: N_pde.h:348
def call
Definition: core.py:71
double V
Definition: N_pde.h:346
double W_T
Definition: N_pde.h:348
double N_B
Definition: N_pde.h:350
double SE_B
Definition: N_pde.h:350
N_les * N_assemble_les_2d_param(int les_type, N_geom_data *geom, N_array_2d *status, N_array_2d *start_val, void *data, N_les_callback_2d *call, int cell_type)
Assemble a linear equation system (les) based on 2d location data (raster)
G_math_spvector ** Asp
Definition: N_pde.h:91
#define N_CELL_DIRICHLET
Definition: N_pde.h:47
void N_put_array_2d_c_value(N_array_2d *data, int col, int row, CELL value)
Writes a CELL value to the N_array_2d struct at position col, row.
Definition: N_arrays.c:521
#define N_CELL_INACTIVE
Definition: N_pde.h:45
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
int
Definition: g3dcolor.c:48
N_les * N_assemble_les_2d_dirichlet(int les_type, N_geom_data *geom, N_array_2d *status, N_array_2d *start_val, void *data, N_les_callback_2d *call)
Assemble a linear equation system (les) based on 2d location data (raster) and active and dirichlet c...
int N_les_integrate_dirichlet_3d(N_les *les, N_geom_data *geom, N_array_3d *status, N_array_3d *start_val)
Integrate Dirichlet or Transmission boundary conditions into the les (3d)
N_les * N_assemble_les_3d(int les_type, N_geom_data *geom, N_array_3d *status, N_array_3d *start_val, void *data, N_les_callback_3d *call)
Assemble a linear equation system (les) based on 3d location data (g3d) active cells.
N_data_star * N_create_5star(double C, double W, double E, double N, double S, double V)
allocate and initialize a 5 point star data structure
int cols
Definition: N_pde.h:141
N_data_star * N_callback_template_3d(void *data, N_geom_data *geom, int col, int row, int depth)
A callback template creates a 7 point star structure.
#define N_5_POINT_STAR
Definition: N_pde.h:54
int type
Definition: N_pde.h:344
N_data_star *(* callback)()
Definition: N_pde.h:366
#define SE
Definition: dataquad.h:20
double NE_B
Definition: N_pde.h:350
double SE
Definition: N_pde.h:346
double SW
Definition: N_pde.h:346
void N_set_les_callback_2d_func(N_les_callback_2d *data, N_data_star *(*callback_func_2d)())
Set the callback function which is called while assembling the les in 2d.
N_les * N_assemble_les_3d_param(int les_type, N_geom_data *geom, N_array_3d *status, N_array_3d *start_val, void *data, N_les_callback_3d *call, int cell_type)
Assemble a linear equation system (les) based on 3d location data (g3d)
double NW_T
Definition: N_pde.h:348
N_data_star * N_alloc_7star(void)
allocate a 7 point star data structure
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:987
return NULL
Definition: dbfopen.c:1394
double NW
Definition: N_pde.h:346
int cols
Definition: N_pde.h:93
double N_T
Definition: N_pde.h:348
tuple cols
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: gis/debug.c:51
void G_math_Ax_sparse(G_math_spvector **Asp, double *x, double *y, int rows)
Compute the matrix - vector product of sparse matrix **Asp and vector x.
Definition: blas_level_2.c:45
double SW_B
Definition: N_pde.h:350
double NE
Definition: N_pde.h:346
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:375
double E_B
Definition: N_pde.h:350
N_data_star * N_callback_template_2d(void *data, N_geom_data *geom, int col, int row)
A callback template creates a 9 point star structure.
double NE_T
Definition: N_pde.h:348
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:1172
#define N
Definition: inverse.c:8
for(cat=0;;cat++)
Definition: g3dcats.c:140
double * b
Definition: N_pde.h:89
double B
Definition: N_pde.h:350
N_data_star *(* callback)()
Definition: N_pde.h:358
#define N_7_POINT_STAR
Definition: N_pde.h:55
CELL N_get_array_2d_c_value(N_array_2d *data, int col, int row)
Returns the value of type CELL at position col, row.
Definition: N_arrays.c:311
callback structure for 3d matrix assembling
Definition: N_pde.h:356
double SE_T
Definition: N_pde.h:348
int G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
double W
Definition: N_pde.h:346
int N_les_integrate_dirichlet_2d(N_les *les, N_geom_data *geom, N_array_2d *status, N_array_2d *start_val)
Integrate Dirichlet or Transmission boundary conditions into the les (2s)
double dx
Definition: N_pde.h:133
int rows
Definition: N_pde.h:92
#define N_9_POINT_STAR
Definition: N_pde.h:56
N_les * N_assemble_les_3d_dirichlet(int les_type, N_geom_data *geom, N_array_3d *status, N_array_3d *start_val, void *data, N_les_callback_3d *call)
Assemble a linear equation system (les) based on 3d location data (g3d) active and dirichlet cells...
int G_math_add_spvector(G_math_spvector **Asp, G_math_spvector *spvector, int row)
Adds a sparse vector to a sparse linear equation system at position row.
Definition: sparse_matrix.c:35
N_les * N_assemble_les_2d_active(int les_type, N_geom_data *geom, N_array_2d *status, N_array_2d *start_val, void *data, N_les_callback_2d *call)
Assemble a linear equation system (les) based on 2d location data (raster) and active cells...
The linear equation system (les) structure.
Definition: N_pde.h:86
int type
Definition: N_pde.h:95
N_les_callback_2d * N_alloc_les_callback_2d(void)
Allocate the structure holding the callback function.