/* ************************************************************************* */ int fill_array_2d(N_array_2d * a) { int rows, cols, type; int i, j, res = 0; rows = a->rows; cols = a->cols; type = N_get_array_2d_type(a); #pragma omp parallel for private (i, j) shared (cols, rows, type, a) reduction(+:res) for (j = 0; j < rows; j++) { for (i = 0; i < cols; i++) { if (type == CELL_TYPE) { N_put_array_2d_c_value(a, i, j, (CELL) i * (CELL) j); if (N_get_array_2d_c_value(a, i, j) != (CELL) i * (CELL) j) res++; } if (type == FCELL_TYPE) { N_put_array_2d_f_value(a, i, j, (FCELL) i * (FCELL) j); if (N_get_array_2d_f_value(a, i, j) != (FCELL) i * (FCELL) j) res++; } if (type == DCELL_TYPE) { N_put_array_2d_d_value(a, i, j, (DCELL) i * (DCELL) j); if (N_get_array_2d_d_value(a, i, j) != (DCELL) i * (DCELL) j) res++; } } } return res; }
/* *************************************************************** */ N_array_2d *create_status_array_2d(void) { N_array_2d *data; int i, j; data = N_alloc_array_2d(TEST_N_NUM_COLS, TEST_N_NUM_ROWS, 1, CELL_TYPE); #pragma omp parallel for private (i, j) shared (data) for (j = 0; j < TEST_N_NUM_ROWS; j++) { for (i = 0; i < TEST_N_NUM_COLS; i++) { if (j == 1) { N_put_array_2d_c_value(data, i, j, 2); } else { N_put_array_2d_c_value(data, i, j, 1); } } } return data; }
/*! * \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; }