/* ************************************************************************* */ int fill_array_3d(N_array_3d * a) { int rows, cols, depths, type; int i, j, k, res = 0; cols = a->cols; rows = a->rows; depths = a->depths; type = N_get_array_3d_type(a); #pragma omp parallel for private (i, j, k) shared (depths, rows, cols, type, a) reduction(+:res) for (k = 0; k < depths; k++) { for (j = 0; j < rows; j++) { for (i = 0; i < cols; i++) { if (type == FCELL_TYPE) { N_put_array_3d_f_value(a, i, j, k, (float)i * (float)j * (float)k); if (N_get_array_3d_f_value(a, i, j, k) != (float)i * (float)j * (float)k) res++; } if (type == DCELL_TYPE) { N_put_array_3d_d_value(a, i, j, k, (double)i * (double)j * (double)k); if (N_get_array_3d_d_value(a, i, j, k) != (double)i * (double)j * (double)k) res++; } } } } return res; }
/*! * \brief Compute the dispersivity tensor based on the solute transport data in 3d * * The dispersivity tensor is stored in the data structure. * To compute the dispersivity tensor, the dispersivity lentghs and the gradient field * must be present. * * This is just a simple tensor computation which should be extended. * * \todo Change the tensor calculation to a mor realistic algorithm * * \param data N_solute_transport_data3d * * \return void * * */ void N_calc_solute_transport_disptensor_3d(N_solute_transport_data3d * data) { int i, j, k; int cols, rows, depths; double vx, vy, vz, vv; double disp_xx, disp_yy, disp_zz, disp_xy, disp_xz, disp_yz; N_gradient_3d grad; cols = data->grad->cols; rows = data->grad->rows; depths = data->grad->depths; G_debug(2, "N_calc_solute_transport_disptensor_3d: calculating the dispersivity tensor"); for (k = 0; k < depths; k++) { for (j = 0; j < rows; j++) { for (i = 0; i < cols; i++) { disp_xx = 0; disp_yy = 0; disp_zz = 0; disp_xy = 0; disp_xz = 0; disp_yz = 0; /*get the gradient neighbours */ N_get_gradient_3d(data->grad, &grad, i, j, k); vx = (grad.WC + grad.EC) / 2; vy = (grad.NC + grad.SC) / 2; vz = (grad.BC + grad.TC) / 2; vv = sqrt(vx * vx + vy * vy + vz * vz); if (vv != 0) { disp_xx = data->al * vx * vx / vv + data->at * vy * vy / vv + data->at * vz * vz / vv; disp_yy = data->at * vx * vx / vv + data->al * vy * vy / vv + data->at * vz * vz / vv; disp_zz = data->at * vx * vx / vv + data->at * vy * vy / vv + data->al * vz * vz / vv; disp_xy = (data->al - data->at) * vx * vy / vv; disp_xz = (data->al - data->at) * vx * vz / vv; disp_yz = (data->al - data->at) * vy * vz / vv; } G_debug(5, "N_calc_solute_transport_disptensor_3d: [%i][%i][%i] disp_xx %g disp_yy %g disp_zz %g disp_xy %g disp_xz %g disp_yz %g ", i, j, k, disp_xx, disp_yy, disp_zz, disp_xy, disp_xz, disp_yz); N_put_array_3d_d_value(data->disp_xx, i, j, k, disp_xx); N_put_array_3d_d_value(data->disp_yy, i, j, k, disp_yy); N_put_array_3d_d_value(data->disp_zz, i, j, k, disp_zz); N_put_array_3d_d_value(data->disp_xy, i, j, k, disp_xy); N_put_array_3d_d_value(data->disp_xz, i, j, k, disp_xz); N_put_array_3d_d_value(data->disp_yz, i, j, k, disp_yz); } } } return; }
/* *************************************************************** */ N_solute_transport_data3d *create_solute_transport_data_3d(void) { N_solute_transport_data3d *data; int i, j, k; data = N_alloc_solute_transport_data3d(TEST_N_NUM_COLS_LOCAL, TEST_N_NUM_ROWS_LOCAL, TEST_N_NUM_DEPTHS_LOCAL); #pragma omp parallel for private (i, j, k) shared (data) for (k = 0; k < TEST_N_NUM_DEPTHS_LOCAL; k++) for (j = 0; j < TEST_N_NUM_ROWS_LOCAL; j++) { for (i = 0; i < TEST_N_NUM_COLS_LOCAL; i++) { if (j == 0) { N_put_array_3d_d_value(data->c, i, j, k, 1); N_put_array_3d_d_value(data->c_start, i, j, k, 1); N_put_array_3d_d_value(data->status, i, j, k, 3); } else { N_put_array_3d_d_value(data->c, i, j, k, 0); N_put_array_3d_d_value(data->c_start, i, j, k, 0); N_put_array_3d_d_value(data->status, i, j, k, 1); } N_put_array_3d_d_value(data->diff_x, i, j, k, 0.000001); N_put_array_3d_d_value(data->diff_y, i, j, k, 0.000001); N_put_array_3d_d_value(data->diff_z, i, j, k, 0.000001); N_put_array_3d_d_value(data->q, i, j, k, 0.0); N_put_array_3d_d_value(data->cs, i, j, k, 0.0); N_put_array_3d_d_value(data->R, i, j, k, 1.0); N_put_array_3d_d_value(data->nf, i, j, k, 0.1); if (j == 1 && i == 1 && k == 1) N_put_array_3d_d_value(data->cs, i, j, k, 5.0); } } return data; }
/*! * \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; }