/*! * \brief Assemble a linear equation system (les) based on 2d location data (raster) * * * The linear equation system type can be set to N_NORMAL_LES to create a regular * matrix, or to N_SPARSE_LES to create a sparse matrix. This function returns * a new created linear equation system which can be solved with * linear equation solvers. An 2d array with start values and an 2d status array * must be provided as well as the location geometry and a void pointer to data * passed to the callback which creates the les row entries. This callback * must be defined in the N_les_callback_2d strcuture. * * The creation of the les is parallelized with OpenMP. * If you implement new callbacks, please make sure that the * function calls are thread safe. * * * the les can be created in two ways, with dirichlet and similar cells and without them, * to spare some memory. If the les is created with dirichlet cell, the dirichlet boundary condition * must be added. * * \param les_type int * \param geom N_geom_data* * \param status N_array_2d * * \param start_val N_array_2d * * \param data void * * \param cell_type int -- les assemble based on N_CELL_ACTIVE or N_CELL_DIRICHLET * \param call N_les_callback_2d * * \return N_les * * */ 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) { int i, j, count = 0, pos = 0; int cell_type_count = 0; int **index_ij; N_array_2d *cell_count; N_les *les = NULL; G_debug(2, "N_assemble_les_2d: starting to assemble the linear equation system"); /* At first count the number of valid cells and save * each number in a new 2d array. Those numbers are used * to create the linear equation system. * */ cell_count = N_alloc_array_2d(geom->cols, geom->rows, 1, CELL_TYPE); /* include dirichlet cells in the les */ if (cell_type == N_CELL_DIRICHLET) { for (j = 0; j < geom->rows; j++) { for (i = 0; i < geom->cols; i++) { /*use all non-inactive cells for les creation */ if (N_CELL_INACTIVE < N_get_array_2d_c_value(status, i, j) && N_get_array_2d_c_value(status, i, j) < N_MAX_CELL_STATE) cell_type_count++; } } } /*use only active cell in the les */ if (cell_type == N_CELL_ACTIVE) { for (j = 0; j < geom->rows; j++) { for (i = 0; i < geom->cols; i++) { /*count only active cells */ if (N_CELL_ACTIVE == N_get_array_2d_d_value(status, i, j)) cell_type_count++; } } } G_debug(2, "N_assemble_les_2d: number of used cells %i\n", cell_type_count); if (cell_type_count == 0) G_fatal_error ("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.", cell_type_count); /* Then allocate the memory for the linear equation system (les). * Only valid cells are used to create the les. */ index_ij = (int **)G_calloc(cell_type_count, sizeof(int *)); for (i = 0; i < cell_type_count; i++) index_ij[i] = (int *)G_calloc(2, sizeof(int)); les = N_alloc_les_Ax_b(cell_type_count, les_type); count = 0; /*count the number of cells which should be used to create the linear equation system */ /*save the i and j indices and create a ordered numbering */ for (j = 0; j < geom->rows; j++) { for (i = 0; i < geom->cols; i++) { /*count every non-inactive cell */ if (cell_type == N_CELL_DIRICHLET) { if (N_CELL_INACTIVE < N_get_array_2d_c_value(status, i, j) && N_get_array_2d_c_value(status, i, j) < N_MAX_CELL_STATE) { N_put_array_2d_c_value(cell_count, i, j, count); index_ij[count][0] = i; index_ij[count][1] = j; count++; G_debug(5, "N_assemble_les_2d: non-inactive cells count %i at pos x[%i] y[%i]\n", count, i, j); } /*count every active cell */ } else if (N_CELL_ACTIVE == N_get_array_2d_c_value(status, i, j)) { N_put_array_2d_c_value(cell_count, i, j, count); index_ij[count][0] = i; index_ij[count][1] = j; count++; G_debug(5, "N_assemble_les_2d: active cells count %i at pos x[%i] y[%i]\n", count, i, j); } } } G_debug(2, "N_assemble_les_2d: starting the parallel assemble loop"); /* Assemble the matrix in parallel */ #pragma omp parallel for private(i, j, pos, count) schedule(static) for (count = 0; count < cell_type_count; count++) { i = index_ij[count][0]; j = index_ij[count][1]; /*create the entries for the */ N_data_star *items = call->callback(data, geom, i, j); /* we need a sparse vector pointer anytime */ G_math_spvector *spvect = NULL; /*allocate a sprase vector */ if (les_type == N_SPARSE_LES) { spvect = G_math_alloc_spvector(items->count); } /* initial conditions */ les->x[count] = N_get_array_2d_d_value(start_val, i, j); /* the entry in the vector b */ les->b[count] = items->V; /* pos describes the position in the sparse vector. * the first entry is always the diagonal entry of the matrix*/ pos = 0; if (les_type == N_SPARSE_LES) { spvect->index[pos] = count; spvect->values[pos] = items->C; } else { les->A[count][count] = items->C; } /* western neighbour, entry is col - 1 */ if (i > 0) { pos = make_les_entry_2d(i, j, -1, 0, count, pos, les, spvect, cell_count, status, start_val, items->W, cell_type); } /* eastern neighbour, entry col + 1 */ if (i < geom->cols - 1) { pos = make_les_entry_2d(i, j, 1, 0, count, pos, les, spvect, cell_count, status, start_val, items->E, cell_type); } /* northern neighbour, entry row - 1 */ if (j > 0) { pos = make_les_entry_2d(i, j, 0, -1, count, pos, les, spvect, cell_count, status, start_val, items->N, cell_type); } /* southern neighbour, entry row + 1 */ if (j < geom->rows - 1) { pos = make_les_entry_2d(i, j, 0, 1, count, pos, les, spvect, cell_count, status, start_val, items->S, cell_type); } /*in case of a nine point star, we have additional entries */ if (items->type == N_9_POINT_STAR) { /* north-western neighbour, entry is col - 1 row - 1 */ if (i > 0 && j > 0) { pos = make_les_entry_2d(i, j, -1, -1, count, pos, les, spvect, cell_count, status, start_val, items->NW, cell_type); } /* north-eastern neighbour, entry col + 1 row - 1 */ if (i < geom->cols - 1 && j > 0) { pos = make_les_entry_2d(i, j, 1, -1, count, pos, les, spvect, cell_count, status, start_val, items->NE, cell_type); } /* south-western neighbour, entry is col - 1 row + 1 */ if (i > 0 && j < geom->rows - 1) { pos = make_les_entry_2d(i, j, -1, 1, count, pos, les, spvect, cell_count, status, start_val, items->SW, cell_type); } /* south-eastern neighbour, entry col + 1 row + 1 */ if (i < geom->cols - 1 && j < geom->rows - 1) { pos = make_les_entry_2d(i, j, 1, 1, count, pos, les, spvect, cell_count, status, start_val, items->SE, cell_type); } } /*How many entries in the les */ if (les->type == N_SPARSE_LES) { spvect->cols = pos + 1; G_math_add_spvector(les->Asp, spvect, count); } if (items) G_free(items); } /*release memory */ N_free_array_2d(cell_count); for (i = 0; i < cell_type_count; i++) G_free(index_ij[i]); G_free(index_ij); return les; }
/* *************************************************************** */ int test_les(void) { N_spvector *spvector = NULL; N_les *les = NULL; N_les *sples = NULL; int i, j; les = N_alloc_les(TEST_N_NUM_ROWS, N_NORMAL_LES); N_print_les(les); N_free_les(les); les = N_alloc_les_A(TEST_N_NUM_ROWS, N_NORMAL_LES); N_print_les(les); N_free_les(les); les = N_alloc_les_Ax(TEST_N_NUM_ROWS, N_NORMAL_LES); N_print_les(les); N_free_les(les); les = N_alloc_les_Ax_b(TEST_N_NUM_ROWS, N_NORMAL_LES); N_print_les(les); N_free_les(les); les = N_alloc_nquad_les(6, 3, N_NORMAL_LES); N_print_les(les); N_free_les(les); les = N_alloc_nquad_les_A(6, 3, N_NORMAL_LES); N_print_les(les); N_free_les(les); les = N_alloc_nquad_les_Ax(6, 3, N_NORMAL_LES); N_print_les(les); N_free_les(les); les = N_alloc_nquad_les_Ax_b(6, 3, N_NORMAL_LES); N_print_les(les); N_free_les(les); les = N_alloc_les(TEST_N_NUM_ROWS, N_NORMAL_LES); sples = N_alloc_les(TEST_N_NUM_ROWS, N_SPARSE_LES); G_message(_("\t * testing les creation in parallel\n")); #pragma omp parallel for private(i, j) shared(les) for (i = 0; i < TEST_N_NUM_ROWS; i++) { for (j = 0; j < TEST_N_NUM_ROWS; j++) { if (i != j) les->A[i][j] = 2e-2; les->A[i][i] = -1e2 - i; } les->x[i] = 273.15 + i; les->b[i] = 1e2 - i; } #pragma omp parallel for private(i, j) shared(sples, spvector) for (i = 0; i < TEST_N_NUM_ROWS; i++) { spvector = N_alloc_spvector(TEST_N_NUM_ROWS); for (j = 0; j < TEST_N_NUM_ROWS; j++) if (i != j) spvector->index[j] = 2e-2; spvector->index[0] = i; spvector->values[0] = -1e2 - i; N_add_spvector_to_les(sples, spvector, i); sples->x[i] = 273.15 + i; sples->b[i] = 1e2 - i; } N_free_les(les); N_free_les(sples); G_message(_("\t * testing les creation in serial\n")); les = N_alloc_les(TEST_N_NUM_ROWS, N_NORMAL_LES); sples = N_alloc_les(TEST_N_NUM_ROWS, N_SPARSE_LES); for (i = 0; i < TEST_N_NUM_ROWS; i++) { for (j = 0; j < TEST_N_NUM_ROWS; j++) { if (i != j) les->A[i][j] = 2e-2; les->A[i][i] = -1e2 - i; } les->x[i] = 273.15 + i; les->b[i] = 1e2 - i; } for (i = 0; i < TEST_N_NUM_ROWS; i++) { spvector = N_alloc_spvector(TEST_N_NUM_ROWS); for (j = 0; j < TEST_N_NUM_ROWS; j++) if (i != j) spvector->index[j] = 2e-2; spvector->index[0] = i; spvector->values[0] = -1e2 - i; N_add_spvector_to_les(sples, spvector, i); sples->x[i] = 273.15 + i; sples->b[i] = 1e2 - i; } N_free_les(les); N_free_les(sples); return 0; }
/*! * \brief Assemble a linear equation system (les) based on 3d location data (g3d) * * The linear equation system type can be set to N_NORMAL_LES to create a regular * matrix, or to N_SPARSE_LES to create a sparse matrix. This function returns * a new created linear equation system which can be solved with * linear equation solvers. An 3d array with start values and an 3d status array * must be provided as well as the location geometry and a void pointer to data * passed to the callback which creates the les row entries. This callback * must be defined in the N_les_callback_3d structure. * * The creation of the les is parallelized with OpenMP. * If you implement new callbacks, please make sure that the * function calls are thread safe. * * the les can be created in two ways, with dirichlet and similar cells and without them, * to spare some memory. If the les is created with dirichlet cell, the dirichlet boundary condition * must be added. * * \param les_type int * \param geom N_geom_data* * \param status N_array_3d * * \param start_val N_array_3d * * \param data void * * \param call N_les_callback_3d * * \param cell_type int -- les assemble based on N_CELL_ACTIVE or N_CELL_DIRICHLET * \return N_les * * */ 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) { int i, j, k, count = 0, pos = 0; int cell_type_count = 0; N_array_3d *cell_count; N_les *les = NULL; int **index_ij; G_debug(2, "N_assemble_les_3d: starting to assemble the linear equation system"); cell_count = N_alloc_array_3d(geom->cols, geom->rows, geom->depths, 1, DCELL_TYPE); /* First count the number of valid cells and save * each number in a new 3d array. Those numbers are used * to create the linear equation system.*/ if (cell_type == N_CELL_DIRICHLET) { /* include dirichlet cells in the les */ for (k = 0; k < geom->depths; k++) { for (j = 0; j < geom->rows; j++) { for (i = 0; i < geom->cols; i++) { /*use all non-inactive cells for les creation */ if (N_CELL_INACTIVE < (int)N_get_array_3d_d_value(status, i, j, k) && (int)N_get_array_3d_d_value(status, i, j, k) < N_MAX_CELL_STATE) cell_type_count++; } } } } else { /*use only active cell in the les */ for (k = 0; k < geom->depths; k++) { for (j = 0; j < geom->rows; j++) { for (i = 0; i < geom->cols; i++) { /*count only active cells */ if (N_CELL_ACTIVE == (int)N_get_array_3d_d_value(status, i, j, k)) cell_type_count++; } } } } G_debug(2, "N_assemble_les_3d: number of used cells %i\n", cell_type_count); if (cell_type_count == 0.0) G_fatal_error ("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.", cell_type_count); /* allocate the memory for the linear equation system (les). * Only valid cells are used to create the les. */ les = N_alloc_les_Ax_b(cell_type_count, les_type); index_ij = (int **)G_calloc(cell_type_count, sizeof(int *)); for (i = 0; i < cell_type_count; i++) index_ij[i] = (int *)G_calloc(3, sizeof(int)); count = 0; /*count the number of cells which should be used to create the linear equation system */ /*save the k, i and j indices and create a ordered numbering */ for (k = 0; k < geom->depths; k++) { for (j = 0; j < geom->rows; j++) { for (i = 0; i < geom->cols; i++) { if (cell_type == N_CELL_DIRICHLET) { if (N_CELL_INACTIVE < (int)N_get_array_3d_d_value(status, i, j, k) && (int)N_get_array_3d_d_value(status, i, j, k) < N_MAX_CELL_STATE) { N_put_array_3d_d_value(cell_count, i, j, k, count); index_ij[count][0] = i; index_ij[count][1] = j; index_ij[count][2] = k; count++; G_debug(5, "N_assemble_les_3d: non-inactive cells count %i at pos x[%i] y[%i] z[%i]\n", count, i, j, k); } } else if (N_CELL_ACTIVE == (int)N_get_array_3d_d_value(status, i, j, k)) { N_put_array_3d_d_value(cell_count, i, j, k, count); index_ij[count][0] = i; index_ij[count][1] = j; index_ij[count][2] = k; count++; G_debug(5, "N_assemble_les_3d: active cells count %i at pos x[%i] y[%i] z[%i]\n", count, i, j, k); } } } } G_debug(2, "N_assemble_les_3d: starting the parallel assemble loop"); #pragma omp parallel for private(i, j, k, pos, count) schedule(static) for (count = 0; count < cell_type_count; count++) { i = index_ij[count][0]; j = index_ij[count][1]; k = index_ij[count][2]; /*create the entries for the */ N_data_star *items = call->callback(data, geom, i, j, k); G_math_spvector *spvect = NULL; /*allocate a sprase vector */ if (les_type == N_SPARSE_LES) spvect = G_math_alloc_spvector(items->count); /* initial conditions */ les->x[count] = N_get_array_3d_d_value(start_val, i, j, k); /* the entry in the vector b */ les->b[count] = items->V; /* pos describes the position in the sparse vector. * the first entry is always the diagonal entry of the matrix*/ pos = 0; if (les_type == N_SPARSE_LES) { spvect->index[pos] = count; spvect->values[pos] = items->C; } else { les->A[count][count] = items->C; } /* western neighbour, entry is col - 1 */ if (i > 0) { pos = make_les_entry_3d(i, j, k, -1, 0, 0, count, pos, les, spvect, cell_count, status, start_val, items->W, cell_type); } /* eastern neighbour, entry col + 1 */ if (i < geom->cols - 1) { pos = make_les_entry_3d(i, j, k, 1, 0, 0, count, pos, les, spvect, cell_count, status, start_val, items->E, cell_type); } /* northern neighbour, entry row -1 */ if (j > 0) { pos = make_les_entry_3d(i, j, k, 0, -1, 0, count, pos, les, spvect, cell_count, status, start_val, items->N, cell_type); } /* southern neighbour, entry row +1 */ if (j < geom->rows - 1) { pos = make_les_entry_3d(i, j, k, 0, 1, 0, count, pos, les, spvect, cell_count, status, start_val, items->S, cell_type); } /*only for a 7 star entry needed */ if (items->type == N_7_POINT_STAR || items->type == N_27_POINT_STAR) { /* the upper cell (top), entry depth + 1 */ if (k < geom->depths - 1) { pos = make_les_entry_3d(i, j, k, 0, 0, 1, count, pos, les, spvect, cell_count, status, start_val, items->T, cell_type); } /* the lower cell (bottom), entry depth - 1 */ if (k > 0) { pos = make_les_entry_3d(i, j, k, 0, 0, -1, count, pos, les, spvect, cell_count, status, start_val, items->B, cell_type); } } /*How many entries in the les */ if (les->type == N_SPARSE_LES) { spvect->cols = pos + 1; G_math_add_spvector(les->Asp, spvect, count); } if (items) G_free(items); } N_free_array_3d(cell_count); for (i = 0; i < cell_type_count; i++) G_free(index_ij[i]); G_free(index_ij); return les; }