2
/*****************************************************************************
4
* MODULE: Grass PDE Numerical Library
5
* AUTHOR(S): Soeren Gebbert, Berlin (GER) Dec 2006
6
* soerengebbert <at> gmx <dot> de
8
* PURPOSE: functions to assemble a linear equation system
9
* part of the gpde library
11
* COPYRIGHT: (C) 2000 by the GRASS Development Team
13
* This program is free software under the GNU General Public
14
* License (>=v2). Read the file COPYING that comes with GRASS
17
*****************************************************************************/
21
#include "grass/N_pde.h"
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
N_spvector * spvect, N_array_2d * cell_count,
27
N_array_2d * status, N_array_2d * start_val,
28
double entry, int cell_type);
30
static int make_les_entry_3d(int i, int j, int k, int offset_i, int offset_j,
31
int offset_k, int count, int pos, N_les * les,
32
N_spvector * spvect, N_array_3d * cell_count,
33
N_array_3d * status, N_array_3d * start_val,
34
double entry, int cell_type);
36
/* *************************************************************** *
37
* ********************** N_alloc_5star ************************** *
38
* *************************************************************** */
40
* \brief allocate a 5 point star data structure
42
* \return N_data_star *
44
N_data_star *N_alloc_5star(void)
46
N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
48
star->type = N_5_POINT_STAR;
53
/* *************************************************************** *
54
* ********************* N_alloc_7star *************************** *
55
* *************************************************************** */
57
* \brief allocate a 7 point star data structure
59
* \return N_data_star *
61
N_data_star *N_alloc_7star(void)
63
N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
65
star->type = N_7_POINT_STAR;
70
/* *************************************************************** *
71
* ********************* N_alloc_9star *************************** *
72
* *************************************************************** */
74
* \brief allocate a 9 point star data structure
76
* \return N_data_star *
78
* \attention The 9 point start is not yet implemented in the matrix assembling function
81
N_data_star *N_alloc_9star(void)
83
N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
85
star->type = N_9_POINT_STAR;
90
/* *************************************************************** *
91
* ********************* N_alloc_27star ************************** *
92
* *************************************************************** */
94
* \brief allocate a 27 point star data structure
96
* \return N_data_star *
98
* \attention The 27 point start is not yet implemented in the matrix assembling function
101
N_data_star *N_alloc_27star(void)
103
N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
105
star->type = N_27_POINT_STAR;
110
/* *************************************************************** *
111
* ********************** N_create_5star ************************* *
112
* *************************************************************** */
114
* \brief allocate and initialize a 5 point star data structure
122
* \return N_data_star *
124
N_data_star *N_create_5star(double C, double W, double E, double N,
127
N_data_star *star = N_alloc_5star();
137
G_debug(5, "N_create_5star: w %g e %g n %g s %g c %g v %g\n", star->W,
138
star->E, star->N, star->S, star->C, star->V);
143
/* *************************************************************** *
144
* ************************* N_create_7star ********************** *
145
* *************************************************************** */
147
* \brief allocate and initialize a 7 point star data structure
157
* \return N_data_star *
159
N_data_star *N_create_7star(double C, double W, double E, double N,
160
double S, double T, double B, double V)
162
N_data_star *star = N_alloc_7star();
175
G_debug(5, "N_create_7star: w %g e %g n %g s %g t %g b %g c %g v %g\n",
176
star->W, star->E, star->N, star->S, star->T, star->B, star->C,
182
/* *************************************************************** *
183
* ************************ N_create_9star *********************** *
184
* *************************************************************** */
186
* \brief allocate and initialize a 9 point star data structure
198
* \return N_data_star *
200
N_data_star *N_create_9star(double C, double W, double E, double N,
201
double S, double NW, double SW, double NE,
204
N_data_star *star = N_alloc_9star();
220
"N_create_9star: w %g e %g n %g s %g nw %g sw %g ne %g se %g c %g v %g\n",
221
star->W, star->E, star->N, star->S, star->NW, star->SW, star->NE,
222
star->SE, star->C, star->V);
227
/* *************************************************************** *
228
* ************************ N_create_27star *********************** *
229
* *************************************************************** */
231
* \brief allocate and initialize a 27 point star data structure
261
* \return N_data_star *
263
N_data_star *N_create_27star(double C, double W, double E, double N, double S,
264
double NW, double SW, double NE, double SE,
265
double T, double W_T, double E_T, double N_T,
266
double S_T, double NW_T, double SW_T,
267
double NE_T, double SE_T, double B, double W_B,
268
double E_B, double N_B, double S_B, double NW_B,
269
double SW_B, double NE_B, double SE_B, double V)
271
N_data_star *star = N_alloc_27star();
309
"N_create_27star: w %g e %g n %g s %g nw %g sw %g ne %g se %g c %g v %g\n",
310
star->W, star->E, star->N, star->S, star->NW, star->SW, star->NE,
311
star->SE, star->C, star->V);
314
"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",
315
star->W_T, star->E_T, star->N_T, star->S_T, star->NW_T,
316
star->SW_T, star->NE_T, star->SE_T, star->T);
319
"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",
320
star->W_B, star->E_B, star->N_B, star->S_B, star->NW_B,
321
star->SW_B, star->NE_B, star->SE_B, star->B);
329
/* *************************************************************** *
330
* ****************** N_set_les_callback_3d_func ***************** *
331
* *************************************************************** */
333
* \brief Set the callback function which is called while assembling the les in 3d
335
* \param data N_les_callback_3d *
336
* \param callback_func_3d N_data_star *
340
N_set_les_callback_3d_func(N_les_callback_3d * data,
341
N_data_star * (*callback_func_3d) ())
343
data->callback = callback_func_3d;
346
/* *************************************************************** *
347
* *************** N_set_les_callback_2d_func ******************** *
348
* *************************************************************** */
350
* \brief Set the callback function which is called while assembling the les in 2d
352
* \param data N_les_callback_2d *
353
* \param callback_func_2d N_data_star *
357
N_set_les_callback_2d_func(N_les_callback_2d * data,
358
N_data_star * (*callback_func_2d) ())
360
data->callback = callback_func_2d;
363
/* *************************************************************** *
364
* ************** N_alloc_les_callback_3d ************************ *
365
* *************************************************************** */
367
* \brief Allocate the structure holding the callback function
369
* A template callback is set. Use N_set_les_callback_3d_func
370
* to set up a specific function.
372
* \return N_les_callback_3d *
374
N_les_callback_3d *N_alloc_les_callback_3d(void)
376
N_les_callback_3d *call;
378
call = (N_les_callback_3d *) G_calloc(1, sizeof(N_les_callback_3d *));
379
call->callback = N_callback_template_3d;
384
/* *************************************************************** *
385
* *************** N_alloc_les_callback_2d *********************** *
386
* *************************************************************** */
388
* \brief Allocate the structure holding the callback function
390
* A template callback is set. Use N_set_les_callback_2d_func
391
* to set up a specific function.
393
* \return N_les_callback_2d *
395
N_les_callback_2d *N_alloc_les_callback_2d(void)
397
N_les_callback_2d *call;
399
call = (N_les_callback_2d *) G_calloc(1, sizeof(N_les_callback_2d *));
400
call->callback = N_callback_template_2d;
405
/* *************************************************************** *
406
* ******************** N_callback_template_3d ******************* *
407
* *************************************************************** */
409
* \brief A callback template creates a 7 point star structure
411
* This is a template callback for mass balance calculation with 7 point stars
412
* based on 3d data (g3d).
415
* \param geom N_geom_data *
419
* \return N_data_star *
422
N_data_star *N_callback_template_3d(void *data, N_geom_data * geom, int col,
425
N_data_star *star = N_alloc_7star();
427
star->E = 1 / geom->dx;
428
star->W = 1 / geom->dx;
429
star->N = 1 / geom->dy;
430
star->S = 1 / geom->dy;
431
star->T = 1 / geom->dz;
432
star->B = 1 / geom->dz;
433
star->C = -1 * (2 / geom->dx + 2 / geom->dy + 2 / geom->dz);
437
"N_callback_template_3d: w %g e %g n %g s %g t %g b %g c %g v %g\n",
438
star->W, star->E, star->N, star->S, star->T, star->B, star->C,
445
/* *************************************************************** *
446
* ********************* N_callback_template_2d ****************** *
447
* *************************************************************** */
449
* \brief A callback template creates a 9 point star structure
451
* This is a template callback for mass balance calculation with 9 point stars
452
* based on 2d data (raster).
455
* \param geom N_geom_data *
458
* \return N_data_star *
461
N_data_star *N_callback_template_2d(void *data, N_geom_data * geom, int col,
464
N_data_star *star = N_alloc_9star();
466
star->E = 1 / geom->dx;
467
star->NE = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
468
star->SE = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
469
star->W = 1 / geom->dx;
470
star->NW = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
471
star->SW = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
472
star->N = 1 / geom->dy;
473
star->S = 1 / geom->dy;
475
-1 * (star->E + star->NE + star->SE + star->W + star->NW + star->SW +
482
/* *************************************************************** *
483
* ******************** N_assemble_les_2d ************************ *
484
* *************************************************************** */
486
* \brief Assemble a linear equation system (les) based on 2d location data (raster) and active cells
488
* This function calls #N_assemble_les_2d_param
491
N_les *N_assemble_les_2d(int les_type, N_geom_data * geom,
492
N_array_2d * status, N_array_2d * start_val,
493
void *data, N_les_callback_2d * call)
495
return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
496
call, N_CELL_ACTIVE);
500
* \brief Assemble a linear equation system (les) based on 2d location data (raster) and active cells
502
* This function calls #N_assemble_les_2d_param
505
N_les *N_assemble_les_2d_active(int les_type, N_geom_data * geom,
506
N_array_2d * status, N_array_2d * start_val,
507
void *data, N_les_callback_2d * call)
509
return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
510
call, N_CELL_ACTIVE);
514
* \brief Assemble a linear equation system (les) based on 2d location data (raster) and active and dirichlet cells
516
* This function calls #N_assemble_les_2d_param
519
N_les *N_assemble_les_2d_dirichlet(int les_type, N_geom_data * geom,
521
N_array_2d * start_val, void *data,
522
N_les_callback_2d * call)
524
return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
525
call, N_CELL_DIRICHLET);
529
* \brief Assemble a linear equation system (les) based on 2d location data (raster)
532
* The linear equation system type can be set to N_NORMAL_LES to create a regular
533
* matrix, or to N_SPARSE_LES to create a sparse matrix. This function returns
534
* a new created linear equation system which can be solved with
535
* linear equation solvers. An 2d array with start values and an 2d status array
536
* must be provided as well as the location geometry and a void pointer to data
537
* passed to the callback which creates the les row entries. This callback
538
* must be defined in the N_les_callback_2d strcuture.
540
* The creation of the les is parallelized with OpenMP.
541
* If you implement new callbacks, please make sure that the
542
* function calls are thread safe.
545
* the les can be created in two ways, with dirichlet and similar cells and without them,
546
* to spare some memory. If the les is created with dirichlet cell, the dirichlet boundary condition
549
* \param les_type int
550
* \param geom N_geom_data*
551
* \param status N_array_2d *
552
* \param start_val N_array_2d *
554
* \param cell_type int -- les assemble based on N_CELL_ACTIVE or N_CELL_DIRICHLET
555
* \param call N_les_callback_2d *
558
N_les *N_assemble_les_2d_param(int les_type, N_geom_data * geom,
559
N_array_2d * status, N_array_2d * start_val,
560
void *data, N_les_callback_2d * call,
563
int i, j, count = 0, pos = 0;
564
int cell_type_count = 0;
566
N_array_2d *cell_count;
570
"N_assemble_les_2d: starting to assemble the linear equation system");
572
/* At first count the number of valid cells and save the
573
* each number in a new 2d array. Those numbers are used
574
* to create the linear equation system.
577
cell_count = N_alloc_array_2d(geom->cols, geom->rows, 1, CELL_TYPE);
579
/* include dirichlet cells in the les */
580
if (cell_type == N_CELL_DIRICHLET) {
581
for (j = 0; j < geom->rows; j++) {
582
for (i = 0; i < geom->cols; i++) {
583
/*use all non-inactive cells for les creation */
584
if (N_CELL_INACTIVE < N_get_array_2d_c_value(status, i, j) &&
585
N_get_array_2d_c_value(status, i, j) < N_MAX_CELL_STATE)
590
/*use only active cell in the les */
591
if (cell_type == N_CELL_ACTIVE) {
592
for (j = 0; j < geom->rows; j++) {
593
for (i = 0; i < geom->cols; i++) {
594
/*count only active cells */
595
if (N_CELL_ACTIVE == N_get_array_2d_d_value(status, i, j))
601
G_debug(2, "N_assemble_les_2d: number of used cells %i\n",
604
if (cell_type_count == 0)
606
("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.",
609
/* Then allocate the memory for the linear equation system (les).
610
* Only valid cells are used to create the les. */
611
index_ij = (int **)G_calloc(cell_type_count, sizeof(int *));
612
for (i = 0; i < cell_type_count; i++)
613
index_ij[i] = (int *)G_calloc(2, sizeof(int));
615
les = N_alloc_les_Ax_b(cell_type_count, les_type);
619
/*count the number of cells which should be used to create the linear equation system */
620
/*save the i and j indices and create a ordered numbering */
621
for (j = 0; j < geom->rows; j++) {
622
for (i = 0; i < geom->cols; i++) {
623
/*count every non-inactive cell */
624
if (cell_type == N_CELL_DIRICHLET) {
625
if (N_CELL_INACTIVE < N_get_array_2d_c_value(status, i, j) &&
626
N_get_array_2d_c_value(status, i, j) < N_MAX_CELL_STATE) {
627
N_put_array_2d_c_value(cell_count, i, j, count);
628
index_ij[count][0] = i;
629
index_ij[count][1] = j;
632
"N_assemble_les_2d: non-inactive cells count %i at pos x[%i] y[%i]\n",
635
/*count every active cell */
637
else if (N_CELL_ACTIVE == N_get_array_2d_c_value(status, i, j)) {
638
N_put_array_2d_c_value(cell_count, i, j, count);
639
index_ij[count][0] = i;
640
index_ij[count][1] = j;
643
"N_assemble_les_2d: active cells count %i at pos x[%i] y[%i]\n",
649
G_debug(2, "N_assemble_les_2d: starting the parallel assemble loop");
651
/* Assemble the matrix in parallel */
652
#pragma omp parallel for private(i, j, pos, count) schedule(static)
653
for (count = 0; count < cell_type_count; count++) {
654
i = index_ij[count][0];
655
j = index_ij[count][1];
657
/*create the entries for the */
658
N_data_star *items = call->callback(data, geom, i, j);
660
/* we need a sparse vector pointer anytime */
661
N_spvector *spvect = NULL;
663
/*allocate a sprase vector */
664
if (les_type == N_SPARSE_LES) {
665
spvect = N_alloc_spvector(items->count);
667
/* initial conditions */
668
les->x[count] = N_get_array_2d_d_value(start_val, i, j);
670
/* the entry in the vector b */
671
les->b[count] = items->V;
673
/* pos describes the position in the sparse vector.
674
* the first entry is always the diagonal entry of the matrix*/
677
if (les_type == N_SPARSE_LES) {
678
spvect->index[pos] = count;
679
spvect->values[pos] = items->C;
682
les->A[count][count] = items->C;
684
/* western neighbour, entry is col - 1 */
686
pos = make_les_entry_2d(i, j, -1, 0, count, pos, les, spvect,
687
cell_count, status, start_val, items->W,
690
/* eastern neighbour, entry col + 1 */
691
if (i < geom->cols - 1) {
692
pos = make_les_entry_2d(i, j, 1, 0, count, pos, les, spvect,
693
cell_count, status, start_val, items->E,
696
/* northern neighbour, entry row - 1 */
699
make_les_entry_2d(i, j, 0, -1, count, pos, les, spvect,
700
cell_count, status, start_val, items->N,
703
/* southern neighbour, entry row + 1 */
704
if (j < geom->rows - 1) {
705
pos = make_les_entry_2d(i, j, 0, 1, count, pos, les, spvect,
706
cell_count, status, start_val, items->S,
709
/*in case of a nine point star, we have additional entries */
710
if (items->type == N_9_POINT_STAR) {
711
/* north-western neighbour, entry is col - 1 row - 1 */
712
if (i > 0 && j > 0) {
713
pos = make_les_entry_2d(i, j, -1, -1, count, pos, les, spvect,
714
cell_count, status, start_val,
715
items->NW, cell_type);
717
/* north-eastern neighbour, entry col + 1 row - 1 */
718
if (i < geom->cols - 1 && j > 0) {
719
pos = make_les_entry_2d(i, j, 1, -1, count, pos, les, spvect,
720
cell_count, status, start_val,
721
items->NE, cell_type);
723
/* south-western neighbour, entry is col - 1 row + 1 */
724
if (i > 0 && j < geom->rows - 1) {
725
pos = make_les_entry_2d(i, j, -1, 1, count, pos, les, spvect,
726
cell_count, status, start_val,
727
items->SW, cell_type);
729
/* south-eastern neighbour, entry col + 1 row + 1 */
730
if (i < geom->cols - 1 && 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->SE, cell_type);
737
/*How many entries in the les */
738
if (les->type == N_SPARSE_LES) {
739
spvect->cols = pos + 1;
740
N_add_spvector_to_les(les, spvect, count);
748
N_free_array_2d(cell_count);
750
for (i = 0; i < cell_type_count; i++)
759
* \brief Integrate Dirichlet or Transmission boundary conditions into the les (2s)
761
* Dirichlet and Transmission boundary conditions will be integrated into
762
* the provided linear equation system. This is meaningfull if
763
* the les was created with #N_assemble_les_2d_dirichlet, because in
764
* this case Dirichlet boundary conditions are not automatically included.
766
* The provided les will be modified:
768
* Ax = b will be splitted into Ax_u + Ax_d = b
771
* x_d - the Dirichlet cells
773
* Ax_u = b -Ax_d will be computed. Then the matrix A will be modified to
778
* \param les N_les* -- the linear equation system
779
* \param geom N_geom_data* -- geometrical data information
780
* \param status N_array_2d* -- the status array containing the cell types
781
* \param start_val N_array_2d* -- an array with start values
782
* \return int -- 1 = success, 0 = failure
784
int N_les_integrate_dirichlet_2d(N_les * les, N_geom_data * geom,
785
N_array_2d * status, N_array_2d * start_val)
789
int i, j, x, y, stat;
794
"N_les_integrate_dirichlet_2d: integrating the dirichlet boundary condition");
799
/*we nned to additional vectors */
800
dvect1 = (double *)G_calloc(les->cols, sizeof(double));
801
dvect2 = (double *)G_calloc(les->cols, sizeof(double));
803
/*fill the first one with the x vector data of Dirichlet cells */
805
for (y = 0; y < rows; y++) {
806
for (x = 0; x < cols; x++) {
807
stat = N_get_array_2d_c_value(status, x, y);
808
if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
809
dvect1[count] = N_get_array_2d_d_value(start_val, x, y);
812
else if (stat == N_CELL_ACTIVE) {
819
#pragma omp parallel default(shared)
821
/*performe the matrix vector product */
822
if (les->type == N_SPARSE_LES)
823
N_sparse_matrix_vector_product(les, dvect1, dvect2);
825
N_matrix_vector_product(les, dvect1, dvect2);
826
#pragma omp for schedule (static) private(i)
827
for (i = 0; i < les->cols; i++)
828
les->b[i] = les->b[i] - dvect2[i];
831
/*now set the Dirichlet cell rows and cols to zero and the
832
* diagonal entry to 1*/
834
for (y = 0; y < rows; y++) {
835
for (x = 0; x < cols; x++) {
836
stat = N_get_array_2d_c_value(status, x, y);
837
if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
838
if (les->type == N_SPARSE_LES) {
839
/*set the rows to zero */
840
for (i = 0; i < les->Asp[count]->cols; i++)
841
les->Asp[count]->values[i] = 0.0;
842
/*set the cols to zero */
843
for (i = 0; i < les->rows; i++) {
844
for (j = 0; j < les->Asp[i]->cols; j++) {
845
if (les->Asp[i]->index[j] == count)
846
les->Asp[i]->values[j] = 0.0;
850
/*entry on the diagonal */
851
les->Asp[count]->values[0] = 1.0;
855
/*set the rows to zero */
856
for (i = 0; i < les->cols; i++)
857
les->A[count][i] = 0.0;
858
/*set the cols to zero */
859
for (i = 0; i < les->rows; i++)
860
les->A[i][count] = 0.0;
862
/*entry on the diagonal */
863
les->A[count][count] = 1.0;
866
if (stat >= N_CELL_ACTIVE)
875
/* **************************************************************** */
876
/* **** make an entry in the les (2d) ***************************** */
877
/* **************************************************************** */
878
int make_les_entry_2d(int i, int j, int offset_i, int offset_j, int count,
879
int pos, N_les * les, N_spvector * spvect,
880
N_array_2d * cell_count, N_array_2d * status,
881
N_array_2d * start_val, double entry, int cell_type)
887
K = N_get_array_2d_c_value(cell_count, i + di, j + dj) -
888
N_get_array_2d_c_value(cell_count, i, j);
890
/* active cells build the linear equation system */
891
if (cell_type == N_CELL_ACTIVE) {
892
/* dirichlet or transmission cells must be handled like this */
893
if (N_get_array_2d_c_value(status, i + di, j + dj) > N_CELL_ACTIVE &&
894
N_get_array_2d_c_value(status, i + di, j + dj) < N_MAX_CELL_STATE)
896
N_get_array_2d_d_value(start_val, i + di, j + dj) * entry;
897
else if (N_get_array_2d_c_value(status, i + di, j + dj) ==
899
if ((count + K) >= 0 && (count + K) < les->cols) {
901
" make_les_entry_2d: (N_CELL_ACTIVE) create matrix entry at row[%i] col[%i] value %g\n",
902
count, count + K, entry);
904
if (les->type == N_SPARSE_LES) {
905
spvect->index[pos] = count + K;
906
spvect->values[pos] = entry;
909
les->A[count][count + K] = entry;
913
} /* if dirichlet cells should be used then check for all valid cell neighbours */
914
else if (cell_type == N_CELL_DIRICHLET) {
915
/* all valid cells */
916
if (N_get_array_2d_c_value(status, i + di, j + dj) > N_CELL_INACTIVE
917
&& N_get_array_2d_c_value(status, i + di,
918
j + dj) < N_MAX_CELL_STATE) {
919
if ((count + K) >= 0 && (count + K) < les->cols) {
921
" make_les_entry_2d: (N_CELL_DIRICHLET) create matrix entry at row[%i] col[%i] value %g\n",
922
count, count + K, entry);
924
if (les->type == N_SPARSE_LES) {
925
spvect->index[pos] = count + K;
926
spvect->values[pos] = entry;
929
les->A[count][count + K] = entry;
939
/* *************************************************************** *
940
* ******************** N_assemble_les_3d ************************ *
941
* *************************************************************** */
943
* \brief Assemble a linear equation system (les) based on 3d location data (g3d) active cells
945
* This function calls #N_assemble_les_3d_param
947
N_les *N_assemble_les_3d(int les_type, N_geom_data * geom,
948
N_array_3d * status, N_array_3d * start_val,
949
void *data, N_les_callback_3d * call)
951
return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
952
call, N_CELL_ACTIVE);
956
* \brief Assemble a linear equation system (les) based on 3d location data (g3d) active cells
958
* This function calls #N_assemble_les_3d_param
960
N_les *N_assemble_les_3d_active(int les_type, N_geom_data * geom,
961
N_array_3d * status, N_array_3d * start_val,
962
void *data, N_les_callback_3d * call)
964
return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
965
call, N_CELL_ACTIVE);
969
* \brief Assemble a linear equation system (les) based on 3d location data (g3d) active and dirichlet cells
971
* This function calls #N_assemble_les_3d_param
973
N_les *N_assemble_les_3d_dirichlet(int les_type, N_geom_data * geom,
975
N_array_3d * start_val, void *data,
976
N_les_callback_3d * call)
978
return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
979
call, N_CELL_DIRICHLET);
983
* \brief Assemble a linear equation system (les) based on 3d location data (g3d)
985
* The linear equation system type can be set to N_NORMAL_LES to create a regular
986
* matrix, or to N_SPARSE_LES to create a sparse matrix. This function returns
987
* a new created linear equation system which can be solved with
988
* linear equation solvers. An 3d array with start values and an 3d status array
989
* must be provided as well as the location geometry and a void pointer to data
990
* passed to the callback which creates the les row entries. This callback
991
* must be defined in the N_les_callback_3d structure.
993
* The creation of the les is parallelized with OpenMP.
994
* If you implement new callbacks, please make sure that the
995
* function calls are thread safe.
997
* the les can be created in two ways, with dirichlet and similar cells and without them,
998
* to spare some memory. If the les is created with dirichlet cell, the dirichlet boundary condition
1001
* \param les_type int
1002
* \param geom N_geom_data*
1003
* \param status N_array_3d *
1004
* \param start_val N_array_3d *
1005
* \param data void *
1006
* \param call N_les_callback_3d *
1007
* \param cell_type int -- les assemble based on N_CELL_ACTIVE or N_CELL_DIRICHLET
1010
N_les *N_assemble_les_3d_param(int les_type, N_geom_data * geom,
1011
N_array_3d * status, N_array_3d * start_val,
1012
void *data, N_les_callback_3d * call,
1015
int i, j, k, count = 0, pos = 0;
1016
int cell_type_count = 0;
1017
N_array_3d *cell_count;
1022
"N_assemble_les_3d: starting to assemble the linear equation system");
1025
N_alloc_array_3d(geom->cols, geom->rows, geom->depths, 1, DCELL_TYPE);
1027
/* First count the number of valid cells and save
1028
* each number in a new 3d array. Those numbers are used
1029
* to create the linear equation system.*/
1031
if (cell_type == N_CELL_DIRICHLET) {
1032
/* include dirichlet cells in the les */
1033
for (k = 0; k < geom->depths; k++) {
1034
for (j = 0; j < geom->rows; j++) {
1035
for (i = 0; i < geom->cols; i++) {
1036
/*use all non-inactive cells for les creation */
1037
if (N_CELL_INACTIVE <
1038
(int)N_get_array_3d_d_value(status, i, j, k) &&
1039
(int)N_get_array_3d_d_value(status, i, j,
1040
k) < N_MAX_CELL_STATE)
1047
/*use only active cell in the les */
1048
for (k = 0; k < geom->depths; k++) {
1049
for (j = 0; j < geom->rows; j++) {
1050
for (i = 0; i < geom->cols; i++) {
1051
/*count only active cells */
1053
== (int)N_get_array_3d_d_value(status, i, j, k))
1062
"N_assemble_les_3d: number of used cells %i\n", cell_type_count);
1064
if (cell_type_count == 0.0)
1066
("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.",
1069
/* allocate the memory for the linear equation system (les).
1070
* Only valid cells are used to create the les. */
1071
les = N_alloc_les_Ax_b(cell_type_count, les_type);
1073
index_ij = (int **)G_calloc(cell_type_count, sizeof(int *));
1074
for (i = 0; i < cell_type_count; i++)
1075
index_ij[i] = (int *)G_calloc(3, sizeof(int));
1078
/*count the number of cells which should be used to create the linear equation system */
1079
/*save the k, i and j indices and create a ordered numbering */
1080
for (k = 0; k < geom->depths; k++) {
1081
for (j = 0; j < geom->rows; j++) {
1082
for (i = 0; i < geom->cols; i++) {
1083
if (cell_type == N_CELL_DIRICHLET) {
1084
if (N_CELL_INACTIVE <
1085
(int)N_get_array_3d_d_value(status, i, j, k) &&
1086
(int)N_get_array_3d_d_value(status, i, j,
1087
k) < N_MAX_CELL_STATE) {
1088
N_put_array_3d_d_value(cell_count, i, j, k, count);
1089
index_ij[count][0] = i;
1090
index_ij[count][1] = j;
1091
index_ij[count][2] = k;
1094
"N_assemble_les_3d: non-inactive cells count %i at pos x[%i] y[%i] z[%i]\n",
1098
else if (N_CELL_ACTIVE ==
1099
(int)N_get_array_3d_d_value(status, i, j, k)) {
1100
N_put_array_3d_d_value(cell_count, i, j, k, count);
1101
index_ij[count][0] = i;
1102
index_ij[count][1] = j;
1103
index_ij[count][2] = k;
1106
"N_assemble_les_3d: active cells count %i at pos x[%i] y[%i] z[%i]\n",
1113
G_debug(2, "N_assemble_les_3d: starting the parallel assemble loop");
1115
#pragma omp parallel for private(i, j, k, pos, count) schedule(static)
1116
for (count = 0; count < cell_type_count; count++) {
1117
i = index_ij[count][0];
1118
j = index_ij[count][1];
1119
k = index_ij[count][2];
1121
/*create the entries for the */
1122
N_data_star *items = call->callback(data, geom, i, j, k);
1124
N_spvector *spvect = NULL;
1126
/*allocate a sprase vector */
1127
if (les_type == N_SPARSE_LES)
1128
spvect = N_alloc_spvector(items->count);
1129
/* initial conditions */
1131
les->x[count] = N_get_array_3d_d_value(start_val, i, j, k);
1133
/* the entry in the vector b */
1134
les->b[count] = items->V;
1136
/* pos describes the position in the sparse vector.
1137
* the first entry is always the diagonal entry of the matrix*/
1140
if (les_type == N_SPARSE_LES) {
1141
spvect->index[pos] = count;
1142
spvect->values[pos] = items->C;
1145
les->A[count][count] = items->C;
1147
/* western neighbour, entry is col - 1 */
1150
make_les_entry_3d(i, j, k, -1, 0, 0, count, pos, les, spvect,
1151
cell_count, status, start_val, items->W,
1154
/* eastern neighbour, entry col + 1 */
1155
if (i < geom->cols - 1) {
1156
pos = make_les_entry_3d(i, j, k, 1, 0, 0, count, pos, les, spvect,
1157
cell_count, status, start_val, items->E,
1160
/* northern neighbour, entry row -1 */
1163
make_les_entry_3d(i, j, k, 0, -1, 0, count, pos, les, spvect,
1164
cell_count, status, start_val, items->N,
1167
/* southern neighbour, entry row +1 */
1168
if (j < geom->rows - 1) {
1169
pos = make_les_entry_3d(i, j, k, 0, 1, 0, count, pos, les, spvect,
1170
cell_count, status, start_val, items->S,
1173
/*only for a 7 star entry needed */
1174
if (items->type == N_7_POINT_STAR || items->type == N_27_POINT_STAR) {
1175
/* the upper cell (top), entry depth + 1 */
1176
if (k < geom->depths - 1) {
1178
make_les_entry_3d(i, j, k, 0, 0, 1, count, pos, les,
1179
spvect, cell_count, status, start_val,
1180
items->T, cell_type);
1182
/* the lower cell (bottom), entry depth - 1 */
1185
make_les_entry_3d(i, j, k, 0, 0, -1, count, pos, les,
1186
spvect, cell_count, status, start_val,
1187
items->B, cell_type);
1191
/*How many entries in the les */
1192
if (les->type == N_SPARSE_LES) {
1193
spvect->cols = pos + 1;
1194
N_add_spvector_to_les(les, spvect, count);
1201
N_free_array_3d(cell_count);
1203
for (i = 0; i < cell_type_count; i++)
1204
G_free(index_ij[i]);
1212
* \brief Integrate Dirichlet or Transmission boundary conditions into the les (3d)
1214
* Dirichlet and Transmission boundary conditions will be integrated into
1215
* the provided linear equation system. This is meaningfull if
1216
* the les was created with #N_assemble_les_2d_dirichlet, because in
1217
* this case Dirichlet boundary conditions are not automatically included.
1219
* The provided les will be modified:
1221
* Ax = b will be splitted into Ax_u + Ax_d = b
1223
* x_u - the unknowns
1224
* x_d - the Dirichlet cells
1226
* Ax_u = b -Ax_d will be computed. Then the matrix A will be modified to
1231
* \param les N_les* -- the linear equation system
1232
* \param geom N_geom_data* -- geometrical data information
1233
* \param status N_array_2d* -- the status array containing the cell types
1234
* \param start_val N_array_2d* -- an array with start values
1235
* \return int -- 1 = success, 0 = failure
1237
int N_les_integrate_dirichlet_3d(N_les * les, N_geom_data * geom,
1238
N_array_3d * status, N_array_3d * start_val)
1240
int rows, cols, depths;
1242
int i, j, x, y, z, stat;
1247
"N_les_integrate_dirichlet_3d: integrating the dirichlet boundary condition");
1251
depths = geom->depths;
1253
/*we nned to additional vectors */
1254
dvect1 = (double *)G_calloc(les->cols, sizeof(double));
1255
dvect2 = (double *)G_calloc(les->cols, sizeof(double));
1257
/*fill the first one with the x vector data of Dirichlet cells */
1259
for (z = 0; z < depths; z++) {
1260
for (y = 0; y < rows; y++) {
1261
for (x = 0; x < cols; x++) {
1262
stat = (int)N_get_array_3d_d_value(status, x, y, z);
1263
if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
1265
N_get_array_3d_d_value(start_val, x, y, z);
1268
else if (stat == N_CELL_ACTIVE) {
1269
dvect1[count] = 0.0;
1276
#pragma omp parallel default(shared)
1278
/*performe the matrix vector product and */
1279
if (les->type == N_SPARSE_LES)
1280
N_sparse_matrix_vector_product(les, dvect1, dvect2);
1282
N_matrix_vector_product(les, dvect1, dvect2);
1283
#pragma omp for schedule (static) private(i)
1284
for (i = 0; i < les->cols; i++)
1285
les->b[i] = les->b[i] - dvect2[i];
1288
/*now set the Dirichlet cell rows and cols to zero and the
1289
* diagonal entry to 1*/
1291
for (z = 0; z < depths; z++) {
1292
for (y = 0; y < rows; y++) {
1293
for (x = 0; x < cols; x++) {
1294
stat = (int)N_get_array_3d_d_value(status, x, y, z);
1295
if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
1296
if (les->type == N_SPARSE_LES) {
1297
/*set the rows to zero */
1298
for (i = 0; i < les->Asp[count]->cols; i++)
1299
les->Asp[count]->values[i] = 0.0;
1300
/*set the cols to zero */
1301
for (i = 0; i < les->rows; i++) {
1302
for (j = 0; j < les->Asp[i]->cols; j++) {
1303
if (les->Asp[i]->index[j] == count)
1304
les->Asp[i]->values[j] = 0.0;
1308
/*entry on the diagonal */
1309
les->Asp[count]->values[0] = 1.0;
1313
/*set the rows to zero */
1314
for (i = 0; i < les->cols; i++)
1315
les->A[count][i] = 0.0;
1316
/*set the cols to zero */
1317
for (i = 0; i < les->rows; i++)
1318
les->A[i][count] = 0.0;
1320
/*entry on the diagonal */
1321
les->A[count][count] = 1.0;
1333
/* **************************************************************** */
1334
/* **** make an entry in the les (3d) ***************************** */
1335
/* **************************************************************** */
1336
int make_les_entry_3d(int i, int j, int k, int offset_i, int offset_j,
1337
int offset_k, int count, int pos, N_les * les,
1338
N_spvector * spvect, N_array_3d * cell_count,
1339
N_array_3d * status, N_array_3d * start_val,
1340
double entry, int cell_type)
1347
K = N_get_array_3d_d_value(cell_count, i + di, j + dj, k + dk) -
1348
N_get_array_3d_d_value(cell_count, i, j, k);
1350
if (cell_type == N_CELL_ACTIVE) {
1351
if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk) >
1353
(int)N_get_array_3d_d_value(status, i + di, j + dj,
1354
k + dk) < N_MAX_CELL_STATE)
1356
N_get_array_3d_d_value(start_val, i + di, j + dj,
1358
else if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk)
1360
if ((count + K) >= 0 && (count + K) < les->cols) {
1362
" make_les_entry_3d: (N_CELL_ACTIVE) create matrix entry at row[%i] col[%i] value %g\n",
1363
count, count + K, entry);
1365
if (les->type == N_SPARSE_LES) {
1366
spvect->index[pos] = count + K;
1367
spvect->values[pos] = entry;
1370
les->A[count][count + K] = entry;
1375
else if (cell_type == N_CELL_DIRICHLET) {
1376
if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk)
1377
!= N_CELL_INACTIVE) {
1378
if ((count + K) >= 0 && (count + K) < les->cols) {
1380
" make_les_entry_3d: (N_CELL_DIRICHLET) create matrix entry at row[%i] col[%i] value %g\n",
1381
count, count + K, entry);
1383
if (les->type == N_SPARSE_LES) {
1384
spvect->index[pos] = count + K;
1385
spvect->values[pos] = entry;
1388
les->A[count][count + K] = entry;