/* *************************************************************** */ int test_array_3d(void) { int sum = 0, res = 0; char buff[1024]; RASTER3D_Region region; N_array_3d *data1; N_array_3d *data11; N_array_3d *data2; N_array_3d *data22; N_array_3d *tmp; double min, max, ssum; int nonzero; /*Alloacte memory for all arrays */ data1 = N_alloc_array_3d(TEST_N_NUM_COLS, TEST_N_NUM_ROWS, TEST_N_NUM_DEPTHS, 2, FCELL_TYPE); N_print_array_3d_info(data1); data11 = N_alloc_array_3d(TEST_N_NUM_COLS, TEST_N_NUM_ROWS, TEST_N_NUM_DEPTHS, 2, FCELL_TYPE); data2 = N_alloc_array_3d(TEST_N_NUM_COLS, TEST_N_NUM_ROWS, TEST_N_NUM_DEPTHS, 2, DCELL_TYPE); N_print_array_3d_info(data2); data22 = N_alloc_array_3d(TEST_N_NUM_COLS, TEST_N_NUM_ROWS, TEST_N_NUM_DEPTHS, 2, DCELL_TYPE); /*Fill the first arrays with data */ res = fill_array_3d(data1); if (res != 0) G_warning("test_array_3d: error while filling array with values"); sum += res; res = fill_array_3d(data2); if (res != 0) G_warning("test_array_3d: error while filling array with values"); sum += res; /*Copy the data */ N_copy_array_3d(data1, data11); N_copy_array_3d(data2, data22); /*Compare the data */ res = compare_array_3d(data1, data11); if (res != 0) G_warning("test_array_3d: error in N_copy_array_2d"); sum += res; res = compare_array_3d(data1, data11); if (res != 0) G_warning("test_array_3d: error in N_copy_array_2d"); sum += res; /*compute statistics */ N_calc_array_3d_stats(data1, &min, &max, &ssum, &nonzero, 0); G_message("FELL Min %g Max %g Sum %g nonzero %i\n", min, max, ssum, nonzero); if (min != 0 || max != 729 || ssum != 91125 || nonzero != 1000) { G_warning("test_array_3d: error in N_calc_array_3d_stats"); sum++; } N_calc_array_3d_stats(data1, &min, &max, &ssum, &nonzero, 1); G_message("FELL Min %g Max %g Sum %g nonzero %i\n", min, max, ssum, nonzero); if (min != 0 || max != 729 || ssum != 91125 || nonzero != 2744) { G_warning("test_array_3d: error in N_calc_array_3d_stats"); sum++; } N_calc_array_3d_stats(data2, &min, &max, &ssum, &nonzero, 0); G_message("DCELL Min %g Max %g Sum %g nonzero %i\n", min, max, ssum, nonzero); if (min != 0 || max != 729 || ssum != 91125 || nonzero != 1000) { G_warning("test_array_3d: error in N_calc_array_3d_stats"); sum++; } N_calc_array_3d_stats(data2, &min, &max, &ssum, &nonzero, 1); G_message("DCELL Min %g Max %g Sum %g nonzero %i\n", min, max, ssum, nonzero); if (min != 0 || max != 729 || ssum != 91125 || nonzero != 2744) { G_warning("test_array_3d: error in N_calc_array_3d_stats"); sum++; } /*test the array math functions */ tmp = N_math_array_3d(data1, data2, NULL, N_ARRAY_SUM); N_math_array_3d(data2, data2, tmp, N_ARRAY_SUM); res = N_convert_array_3d_null_to_zero(tmp); if (res != 0) G_warning("test_array_3d: error in N_convert_array_3d_null_to_zero"); sum = res; N_free_array_3d(tmp); tmp = N_math_array_3d(data2, data1, NULL, N_ARRAY_DIF); N_math_array_3d(data1, data2, tmp, N_ARRAY_DIF); res = N_convert_array_3d_null_to_zero(tmp); if (res != 0) G_warning("test_array_3d: error in N_convert_array_3d_null_to_zero"); sum = res; N_free_array_3d(tmp); tmp = N_math_array_3d(data1, data1, NULL, N_ARRAY_MUL); N_math_array_3d(data1, data1, tmp, N_ARRAY_MUL); res = N_convert_array_3d_null_to_zero(tmp); if (res != 0) G_warning("test_array_3d: error in N_convert_array_3d_null_to_zero"); sum = res; N_free_array_3d(tmp); tmp = N_math_array_3d(data2, data1, NULL, N_ARRAY_DIV); N_math_array_3d(data1, data2, tmp, N_ARRAY_DIV); res = N_convert_array_3d_null_to_zero(tmp); if (res == 0) { /* if a division with zero is detected, the value is set to null, not to nan */ G_warning("test_array_3d: error in N_convert_array_3d_null_to_zero"); sum++; } N_free_array_3d(tmp); /*check for correct norm calculation */ if (N_norm_array_3d(data1, data11, N_EUKLID_NORM) != 0.0) { G_warning("test_array_3d: error in N_norm_array_3d"); sum++; } if (N_norm_array_3d(data1, data11, N_MAXIMUM_NORM) != 0.0) { G_warning("test_array_3d: error in N_norm_array_3d"); sum++; } if (N_norm_array_3d(data1, data2, N_EUKLID_NORM) != 0.0) { G_warning("test_array_3d: error in N_norm_array_3d"); sum++; } if (N_norm_array_3d(data1, data2, N_MAXIMUM_NORM) != 0.0) { G_warning("test_array_3d: error in N_norm_array_3d"); sum++; } /*fill arrays with null values */ res = fill_array_3d_null(data1); if (res != 0) G_warning ("test_array_3d: error while filling array with float null values"); sum += res; res = fill_array_3d_null(data2); if (res != 0) G_warning ("test_array_3d: error while filling array with double null values"); sum += res; /*Copy the data */ N_copy_array_3d(data1, data11); N_copy_array_3d(data2, data22); /*Compare the data */ compare_array_3d(data1, data11); compare_array_3d(data2, data22); /*test the array math functions */ tmp = N_math_array_3d(data1, data2, NULL, N_ARRAY_SUM); N_math_array_3d(data2, data2, tmp, N_ARRAY_SUM); res = N_convert_array_3d_null_to_zero(tmp); if (res == 0) { G_warning("test_array_3d: error in N_convert_array_3d_null_to_zero"); sum++; } N_free_array_3d(tmp); tmp = N_math_array_3d(data2, data1, NULL, N_ARRAY_DIF); N_math_array_3d(data1, data2, tmp, N_ARRAY_DIF); res = N_convert_array_3d_null_to_zero(tmp); if (res == 0) { G_warning("test_array_3d: error in N_convert_array_3d_null_to_zero"); sum++; } N_free_array_3d(tmp); tmp = N_math_array_3d(data1, data1, NULL, N_ARRAY_MUL); N_math_array_3d(data1, data1, tmp, N_ARRAY_MUL); res = N_convert_array_3d_null_to_zero(tmp); if (res == 0) { G_warning("test_array_3d: error in N_convert_array_3d_null_to_zero"); sum++; } N_free_array_3d(tmp); tmp = N_math_array_3d(data2, data1, NULL, N_ARRAY_DIV); N_math_array_3d(data1, data2, tmp, N_ARRAY_DIV); res = N_convert_array_3d_null_to_zero(tmp); if (res == 0) { G_warning("test_array_3d: error in N_convert_array_3d_null_to_zero"); sum++; } N_free_array_3d(tmp); /*check for correct norm calculation in case of null values */ if (N_norm_array_3d(data1, data11, N_EUKLID_NORM) != 0.0) { G_warning("test_array_3d: error in N_norm_array_3d"); sum++; } if (N_norm_array_3d(data1, data11, N_MAXIMUM_NORM) != 0.0) { G_warning("test_array_3d: error in N_norm_array_3d"); sum++; } if (N_norm_array_3d(data1, data2, N_EUKLID_NORM) != 0.0) { G_warning("test_array_3d: error in N_norm_array_3d"); sum++; } if (N_norm_array_3d(data1, data2, N_MAXIMUM_NORM) != 0.0) { G_warning("test_array_3d: error in N_norm_array_3d"); sum++; } N_free_array_3d(data1); N_free_array_3d(data2); /*Set the defaults */ Rast3d_init_defaults(); Rast3d_get_window(®ion); data1 = N_alloc_array_3d(region.cols, region.rows, region.depths, 0, FCELL_TYPE); data2 = N_alloc_array_3d(region.cols, region.rows, region.depths, 0, DCELL_TYPE); fill_array_3d(data1); fill_array_3d(data2); /*Volume IO methods */ N_write_array_3d_to_rast3d(data1, "gpde_lib_test_volume_1", 1); N_write_array_3d_to_rast3d(data2, "gpde_lib_test_volume_2", 1); tmp = N_read_rast3d_to_array_3d("gpde_lib_test_volume_1", NULL, 1); N_read_rast3d_to_array_3d("gpde_lib_test_volume_1", tmp, 1); N_free_array_3d(tmp); tmp = N_read_rast3d_to_array_3d("gpde_lib_test_volume_2", NULL, 1); N_read_rast3d_to_array_3d("gpde_lib_test_volume_2", tmp, 1); N_free_array_3d(tmp); sprintf(buff, "g.remove rast3d=gpde_lib_test_volume_1,gpde_lib_test_volume_2"); system(buff); N_free_array_3d(data1); N_free_array_3d(data11); N_free_array_3d(data2); N_free_array_3d(data22); return sum; }
/*! * \brief Release the memory of the solute transport data structure in three dimensions * * \param data N_solute_transport_data2d * * \return void * * */ void N_free_solute_transport_data3d(N_solute_transport_data3d * data) { N_free_array_3d(data->c); N_free_array_3d(data->c_start); N_free_array_3d(data->status); N_free_array_3d(data->diff_x); N_free_array_3d(data->diff_y); N_free_array_3d(data->diff_z); N_free_array_3d(data->q); N_free_array_3d(data->cs); N_free_array_3d(data->R); N_free_array_3d(data->nf); N_free_array_3d(data->cin); N_free_array_3d(data->disp_xx); N_free_array_3d(data->disp_yy); N_free_array_3d(data->disp_zz); N_free_array_3d(data->disp_xy); N_free_array_3d(data->disp_xz); N_free_array_3d(data->disp_yz); G_free(data); data = NULL; return; }
/*! * \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; }