/* ************************************************************************* */ void set_params() { param.c = G_define_standard_option(G_OPT_R_INPUT); param.c->key = "c"; param.c->description = _("The initial concentration in [kg/m^3]"); param.phead = G_define_standard_option(G_OPT_R_INPUT); param.phead->key = "phead"; param.phead->description = _("The piezometric head in [m]"); param.hc_x = G_define_standard_option(G_OPT_R_INPUT); param.hc_x->key = "hc_x"; param.hc_x->description = _("The x-part of the hydraulic conductivity tensor in [m/s]"); param.hc_y = G_define_standard_option(G_OPT_R_INPUT); param.hc_y->key = "hc_y"; param.hc_y->description = _("The y-part of the hydraulic conductivity tensor in [m/s]"); param.status = G_define_standard_option(G_OPT_R_INPUT); param.status->key = "status"; param.status->description = _("The status for each cell, = 0 - inactive cell, 1 - active cell, " "2 - dirichlet- and 3 - transfer boundary condition"); param.diff_x = G_define_standard_option(G_OPT_R_INPUT); param.diff_x->key = "diff_x"; param.diff_x->description = _("The x-part of the diffusion tensor in [m^2/s]"); param.diff_y = G_define_standard_option(G_OPT_R_INPUT); param.diff_y->key = "diff_y"; param.diff_y->description = _("The y-part of the diffusion tensor in [m^2/s]"); param.q = G_define_standard_option(G_OPT_R_INPUT); param.q->key = "q"; param.q->guisection = _("Water flow"); param.q->required = NO; param.q->description = _("Groundwater sources and sinks in [m^3/s]"); param.cin = G_define_standard_option(G_OPT_R_INPUT); param.cin->key = "cin"; param.cin->required = NO; param.cin->gisprompt = "old,raster,raster"; param.cin->guisection = _("Water flow"); param.cin->description = _("Concentration sources and sinks bounded to a " "water source or sink in [kg/s]"); param.cs = G_define_standard_option(G_OPT_R_INPUT); param.cs->key = "cs"; param.cs->type = TYPE_STRING; param.cs->required = YES; param.cs->gisprompt = "old,raster,raster"; param.cs->description = _("Concentration of inner sources and inner sinks in [kg/s] " "(i.e. a chemical reaction)"); param.r = G_define_standard_option(G_OPT_R_INPUT); param.r->key = "rd"; param.r->description = _("Retardation factor [-]"); param.nf = G_define_standard_option(G_OPT_R_INPUT); param.nf->key = "nf"; param.nf->description = _("Effective porosity [-]"); param.top = G_define_standard_option(G_OPT_R_INPUT); param.top->key = "top"; param.top->description = _("Top surface of the aquifer in [m]"); param.bottom = G_define_standard_option(G_OPT_R_INPUT); param.bottom->key = "bottom"; param.bottom->description = _("Bottom surface of the aquifer in [m]"); param.output = G_define_standard_option(G_OPT_R_OUTPUT); param.output->description = _("The resulting concentration of the numerical solute " "transport calculation will be written to this map. [kg/m^3]"); param.vector_x = G_define_standard_option(G_OPT_R_OUTPUT); param.vector_x->key = "vx"; param.vector_x->required = NO; param.vector_x->guisection = _("Water flow"); param.vector_x->description = _("Calculate and store the groundwater filter velocity vector part in x direction [m/s]\n"); param.vector_y = G_define_standard_option(G_OPT_R_OUTPUT); param.vector_y->key = "vy"; param.vector_y->required = NO; param.vector_y->guisection = _("Water flow"); param.vector_y->description = _("Calculate and store the groundwater filter velocity vector part in y direction [m/s]\n"); param.dt = N_define_standard_option(N_OPT_CALC_TIME); param.maxit = N_define_standard_option(N_OPT_MAX_ITERATIONS); param.error = N_define_standard_option(N_OPT_ITERATION_ERROR); param.solver = N_define_standard_option(N_OPT_SOLVER_UNSYMM); param.sor = N_define_standard_option(N_OPT_SOR_VALUE); param.al = G_define_option(); param.al->key = "al"; param.al->type = TYPE_DOUBLE; param.al->required = NO; param.al->answer = "0.0"; param.al->description = _("The longditudinal dispersivity length. [m]"); param.at = G_define_option(); param.at->key = "at"; param.at->type = TYPE_DOUBLE; param.at->required = NO; param.at->answer = "0.0"; param.at->description = _("The transversal dispersivity length. [m]"); param.loops = G_define_option(); param.loops->key = "loops"; param.loops->type = TYPE_DOUBLE; param.loops->required = NO; param.loops->answer = "1"; param.loops->description = _("Use this number of time loops if the CFL flag is off. The timestep will become dt/loops."); param.stab = G_define_option(); param.stab->key = "stab"; param.stab->type = TYPE_STRING; param.stab->required = NO; param.stab->answer = "full"; param.stab->options = "full,exp"; param.stab->guisection = "Stabelization"; param.stab->description = _("Set the flow stabilizing scheme (full or exponential upwinding)."); param.full_les = G_define_flag(); param.full_les->key = 'f'; param.full_les->guisection = "Solver"; param.full_les->description = _("Use a full filled quadratic linear equation system," " default is a sparse linear equation system."); param.cfl = G_define_flag(); param.cfl->key = 'c'; param.cfl->guisection = "Stabelization"; param.cfl->description = _("Use the Courant-Friedrichs-Lewy criteria for time step calculation"); }
/*--------------------------------------------------------------------*/ int main(int argc, char *argv[]) { /* Variable declarations */ int nsply, nsplx, nrows, ncols, nsplx_adj, nsply_adj; int nsubregion_col, nsubregion_row, subregion_row, subregion_col; int subregion = 0, nsubregions = 0; int last_row, last_column, grid, bilin, ext, flag_auxiliar, cross; /* booleans */ double stepN, stepE, lambda, mean; double N_extension, E_extension, edgeE, edgeN; const char *mapset, *drv, *db, *vector, *map; char table_name[GNAME_MAX], title[64]; char xname[GNAME_MAX], xmapset[GMAPSET_MAX]; int dim_vect, nparameters, BW; int *lineVect; /* Vector restoring primitive's ID */ double *TN, *Q, *parVect; /* Interpolating and least-square vectors */ double **N, **obsVect; /* Interpolation and least-square matrix */ SEGMENT out_seg, mask_seg; const char *out_file, *mask_file; int out_fd, mask_fd; double seg_size; int seg_mb, segments_in_memory; int have_mask; /* Structs declarations */ int raster; struct Map_info In, In_ext, Out; struct History history; struct GModule *module; struct Option *in_opt, *in_ext_opt, *out_opt, *out_map_opt, *stepE_opt, *stepN_opt, *lambda_f_opt, *type_opt, *dfield_opt, *col_opt, *mask_opt, *memory_opt, *solver, *error, *iter; struct Flag *cross_corr_flag, *spline_step_flag; struct Reg_dimens dims; struct Cell_head elaboration_reg, original_reg; struct bound_box general_box, overlap_box, original_box; struct Point *observ; struct line_cats *Cats; dbCatValArray cvarr; int with_z; int nrec, ctype = 0; struct field_info *Fi; dbDriver *driver, *driver_cats; /*----------------------------------------------------------------*/ /* Options declarations */ module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("surface")); G_add_keyword(_("interpolation")); G_add_keyword(_("LIDAR")); module->description = _("Performs bicubic or bilinear spline interpolation with Tykhonov regularization."); cross_corr_flag = G_define_flag(); cross_corr_flag->key = 'c'; cross_corr_flag->description = _("Find the best Tykhonov regularizing parameter using a \"leave-one-out\" cross validation method"); spline_step_flag = G_define_flag(); spline_step_flag->key = 'e'; spline_step_flag->label = _("Estimate point density and distance"); spline_step_flag->description = _("Estimate point density and distance for the input vector points within the current region extends and quit"); in_opt = G_define_standard_option(G_OPT_V_INPUT); in_opt->label = _("Name of input vector point map"); dfield_opt = G_define_standard_option(G_OPT_V_FIELD); dfield_opt->guisection = _("Settings"); col_opt = G_define_standard_option(G_OPT_DB_COLUMN); col_opt->required = NO; col_opt->label = _("Name of the attribute column with values to be used for approximation"); col_opt->description = _("If not given and input is 3D vector map then z-coordinates are used."); col_opt->guisection = _("Settings"); in_ext_opt = G_define_standard_option(G_OPT_V_INPUT); in_ext_opt->key = "sparse_input"; in_ext_opt->required = NO; in_ext_opt->label = _("Name of input vector map with sparse points"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->required = NO; out_opt->guisection = _("Outputs"); out_map_opt = G_define_standard_option(G_OPT_R_OUTPUT); out_map_opt->key = "raster_output"; out_map_opt->required = NO; out_map_opt->guisection = _("Outputs"); mask_opt = G_define_standard_option(G_OPT_R_INPUT); mask_opt->key = "mask"; mask_opt->label = _("Raster map to use for masking (applies to raster output only)"); mask_opt->description = _("Only cells that are not NULL and not zero are interpolated"); mask_opt->required = NO; stepE_opt = G_define_option(); stepE_opt->key = "ew_step"; stepE_opt->type = TYPE_DOUBLE; stepE_opt->required = NO; stepE_opt->answer = "4"; stepE_opt->description = _("Length of each spline step in the east-west direction"); stepE_opt->guisection = _("Settings"); stepN_opt = G_define_option(); stepN_opt->key = "ns_step"; stepN_opt->type = TYPE_DOUBLE; stepN_opt->required = NO; stepN_opt->answer = "4"; stepN_opt->description = _("Length of each spline step in the north-south direction"); stepN_opt->guisection = _("Settings"); type_opt = G_define_option(); type_opt->key = "method"; type_opt->description = _("Spline interpolation algorithm"); type_opt->type = TYPE_STRING; type_opt->options = "bilinear,bicubic"; type_opt->answer = "bilinear"; type_opt->guisection = _("Settings"); G_asprintf((char **) &(type_opt->descriptions), "bilinear;%s;bicubic;%s", _("Bilinear interpolation"), _("Bicubic interpolation")); lambda_f_opt = G_define_option(); lambda_f_opt->key = "lambda_i"; lambda_f_opt->type = TYPE_DOUBLE; lambda_f_opt->required = NO; lambda_f_opt->description = _("Tykhonov regularization parameter (affects smoothing)"); lambda_f_opt->answer = "0.01"; lambda_f_opt->guisection = _("Settings"); solver = N_define_standard_option(N_OPT_SOLVER_SYMM); solver->options = "cholesky,cg"; solver->answer = "cholesky"; iter = N_define_standard_option(N_OPT_MAX_ITERATIONS); error = N_define_standard_option(N_OPT_ITERATION_ERROR); memory_opt = G_define_option(); memory_opt->key = "memory"; memory_opt->type = TYPE_INTEGER; memory_opt->required = NO; memory_opt->answer = "300"; memory_opt->label = _("Maximum memory to be used (in MB)"); memory_opt->description = _("Cache size for raster rows"); /*----------------------------------------------------------------*/ /* Parsing */ G_gisinit(argv[0]); if (G_parser(argc, argv)) exit(EXIT_FAILURE); vector = out_opt->answer; map = out_map_opt->answer; if (vector && map) G_fatal_error(_("Choose either vector or raster output, not both")); if (!vector && !map && !cross_corr_flag->answer) G_fatal_error(_("No raster or vector or cross-validation output")); if (!strcmp(type_opt->answer, "linear")) bilin = P_BILINEAR; else bilin = P_BICUBIC; stepN = atof(stepN_opt->answer); stepE = atof(stepE_opt->answer); lambda = atof(lambda_f_opt->answer); flag_auxiliar = FALSE; drv = db_get_default_driver_name(); if (!drv) { if (db_set_default_connection() != DB_OK) G_fatal_error(_("Unable to set default DB connection")); drv = db_get_default_driver_name(); } db = db_get_default_database_name(); if (!db) G_fatal_error(_("No default DB defined")); /* Set auxiliary table's name */ if (vector) { if (G_name_is_fully_qualified(out_opt->answer, xname, xmapset)) { sprintf(table_name, "%s_aux", xname); } else sprintf(table_name, "%s_aux", out_opt->answer); } /* Something went wrong in a previous v.surf.bspline execution */ if (db_table_exists(drv, db, table_name)) { /* Start driver and open db */ driver = db_start_driver_open_database(drv, db); if (driver == NULL) G_fatal_error(_("No database connection for driver <%s> is defined. Run db.connect."), drv); db_set_error_handler_driver(driver); if (P_Drop_Aux_Table(driver, table_name) != DB_OK) G_fatal_error(_("Old auxiliary table could not be dropped")); db_close_database_shutdown_driver(driver); } /* Open input vector */ if ((mapset = G_find_vector2(in_opt->answer, "")) == NULL) G_fatal_error(_("Vector map <%s> not found"), in_opt->answer); Vect_set_open_level(1); /* WITHOUT TOPOLOGY */ if (1 > Vect_open_old(&In, in_opt->answer, mapset)) G_fatal_error(_("Unable to open vector map <%s> at the topological level"), in_opt->answer); bspline_field = 0; /* assume 3D input */ bspline_column = col_opt->answer; with_z = !bspline_column && Vect_is_3d(&In); if (Vect_is_3d(&In)) { if (!with_z) G_verbose_message(_("Input is 3D: using attribute values instead of z-coordinates for approximation")); else G_verbose_message(_("Input is 3D: using z-coordinates for approximation")); } else { /* 2D */ if (!bspline_column) G_fatal_error(_("Input vector map is 2D. Parameter <%s> required."), col_opt->key); } if (!with_z) { bspline_field = Vect_get_field_number(&In, dfield_opt->answer); } /* Estimate point density and mean distance for current region */ if (spline_step_flag->answer) { double dens, dist; if (P_estimate_splinestep(&In, &dens, &dist) == 0) { fprintf(stdout, _("Estimated point density: %.4g"), dens); fprintf(stdout, _("Estimated mean distance between points: %.4g"), dist); } else { fprintf(stdout, _("No points in current region")); } Vect_close(&In); exit(EXIT_SUCCESS); } /*----------------------------------------------------------------*/ /* Cross-correlation begins */ if (cross_corr_flag->answer) { G_debug(1, "CrossCorrelation()"); cross = cross_correlation(&In, stepE, stepN); if (cross != TRUE) G_fatal_error(_("Cross validation didn't finish correctly")); else { G_debug(1, "Cross validation finished correctly"); Vect_close(&In); G_done_msg(_("Cross validation finished for ew_step = %f and ns_step = %f"), stepE, stepN); exit(EXIT_SUCCESS); } } /* Open input ext vector */ ext = FALSE; if (in_ext_opt->answer) { ext = TRUE; G_message(_("Vector map <%s> of sparse points will be interpolated"), in_ext_opt->answer); if ((mapset = G_find_vector2(in_ext_opt->answer, "")) == NULL) G_fatal_error(_("Vector map <%s> not found"), in_ext_opt->answer); Vect_set_open_level(1); /* WITHOUT TOPOLOGY */ if (1 > Vect_open_old(&In_ext, in_ext_opt->answer, mapset)) G_fatal_error(_("Unable to open vector map <%s> at the topological level"), in_opt->answer); } /* Open output map */ /* vector output */ if (vector && !map) { if (strcmp(drv, "dbf") == 0) G_fatal_error(_("Sorry, the <%s> driver is not compatible with " "the vector output of this module. " "Try with raster output or another driver."), drv); Vect_check_input_output_name(in_opt->answer, out_opt->answer, G_FATAL_EXIT); grid = FALSE; if (0 > Vect_open_new(&Out, out_opt->answer, WITH_Z)) G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer); /* Copy vector Head File */ if (ext == FALSE) { Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); } else { Vect_copy_head_data(&In_ext, &Out); Vect_hist_copy(&In_ext, &Out); } Vect_hist_command(&Out); G_verbose_message(_("Points in input vector map <%s> will be interpolated"), vector); } /* read z values from attribute table */ if (bspline_field > 0) { G_message(_("Reading values from attribute table...")); db_CatValArray_init(&cvarr); Fi = Vect_get_field(&In, bspline_field); if (Fi == NULL) G_fatal_error(_("Cannot read layer info")); driver_cats = db_start_driver_open_database(Fi->driver, Fi->database); /*G_debug (0, _("driver=%s db=%s"), Fi->driver, Fi->database); */ if (driver_cats == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Fi->database, Fi->driver); db_set_error_handler_driver(driver_cats); nrec = db_select_CatValArray(driver_cats, Fi->table, Fi->key, col_opt->answer, NULL, &cvarr); G_debug(3, "nrec = %d", nrec); ctype = cvarr.ctype; if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE) G_fatal_error(_("Column type not supported")); if (nrec < 0) G_fatal_error(_("Unable to select data from table")); G_verbose_message(_("%d records selected from table"), nrec); db_close_database_shutdown_driver(driver_cats); } /*----------------------------------------------------------------*/ /* Interpolation begins */ G_debug(1, "Interpolation()"); /* Open driver and database */ driver = db_start_driver_open_database(drv, db); if (driver == NULL) G_fatal_error(_("No database connection for driver <%s> is defined. " "Run db.connect."), drv); db_set_error_handler_driver(driver); /* Create auxiliary table */ if (vector) { if ((flag_auxiliar = P_Create_Aux4_Table(driver, table_name)) == FALSE) { P_Drop_Aux_Table(driver, table_name); G_fatal_error(_("Interpolation: Creating table: " "It was impossible to create table <%s>."), table_name); } /* db_create_index2(driver, table_name, "ID"); */ /* sqlite likes that ??? */ db_close_database_shutdown_driver(driver); driver = db_start_driver_open_database(drv, db); } /* raster output */ raster = -1; Rast_set_fp_type(DCELL_TYPE); if (!vector && map) { grid = TRUE; raster = Rast_open_fp_new(out_map_opt->answer); G_verbose_message(_("Cells for raster map <%s> will be interpolated"), map); } /* Setting regions and boxes */ G_debug(1, "Interpolation: Setting regions and boxes"); G_get_window(&original_reg); G_get_window(&elaboration_reg); Vect_region_box(&original_reg, &original_box); Vect_region_box(&elaboration_reg, &overlap_box); Vect_region_box(&elaboration_reg, &general_box); nrows = Rast_window_rows(); ncols = Rast_window_cols(); /* Alloc raster matrix */ have_mask = 0; out_file = mask_file = NULL; out_fd = mask_fd = -1; if (grid == TRUE) { int row; DCELL *drastbuf; seg_mb = atoi(memory_opt->answer); if (seg_mb < 3) G_fatal_error(_("Memory in MB must be >= 3")); if (mask_opt->answer) seg_size = sizeof(double) + sizeof(char); else seg_size = sizeof(double); seg_size = (seg_size * SEGSIZE * SEGSIZE) / (1 << 20); segments_in_memory = seg_mb / seg_size + 0.5; G_debug(1, "%d %dx%d segments held in memory", segments_in_memory, SEGSIZE, SEGSIZE); out_file = G_tempfile(); out_fd = creat(out_file, 0666); if (Segment_format(out_fd, nrows, ncols, SEGSIZE, SEGSIZE, sizeof(double)) != 1) G_fatal_error(_("Can not create temporary file")); close(out_fd); out_fd = open(out_file, 2); if (Segment_init(&out_seg, out_fd, segments_in_memory) != 1) G_fatal_error(_("Can not initialize temporary file")); /* initialize output */ G_message(_("Initializing output...")); drastbuf = Rast_allocate_buf(DCELL_TYPE); Rast_set_d_null_value(drastbuf, ncols); for (row = 0; row < nrows; row++) { G_percent(row, nrows, 2); Segment_put_row(&out_seg, drastbuf, row); } G_percent(row, nrows, 2); if (mask_opt->answer) { int row, col, maskfd; DCELL dval, *drastbuf; char mask_val; G_message(_("Load masking map")); mask_file = G_tempfile(); mask_fd = creat(mask_file, 0666); if (Segment_format(mask_fd, nrows, ncols, SEGSIZE, SEGSIZE, sizeof(char)) != 1) G_fatal_error(_("Can not create temporary file")); close(mask_fd); mask_fd = open(mask_file, 2); if (Segment_init(&mask_seg, mask_fd, segments_in_memory) != 1) G_fatal_error(_("Can not initialize temporary file")); maskfd = Rast_open_old(mask_opt->answer, ""); drastbuf = Rast_allocate_buf(DCELL_TYPE); for (row = 0; row < nrows; row++) { G_percent(row, nrows, 2); Rast_get_d_row(maskfd, drastbuf, row); for (col = 0; col < ncols; col++) { dval = drastbuf[col]; if (Rast_is_d_null_value(&dval) || dval == 0) mask_val = 0; else mask_val = 1; Segment_put(&mask_seg, &mask_val, row, col); } } G_percent(row, nrows, 2); G_free(drastbuf); Rast_close(maskfd); have_mask = 1; } } /*------------------------------------------------------------------ | Subdividing and working with tiles: | Each original region will be divided into several subregions. | Each one will be overlaped by its neighbouring subregions. | The overlapping is calculated as a fixed OVERLAP_SIZE times | the largest spline step plus 2 * edge ----------------------------------------------------------------*/ /* Fixing parameters of the elaboration region */ P_zero_dim(&dims); /* Set dim struct to zero */ nsplx_adj = NSPLX_MAX; nsply_adj = NSPLY_MAX; if (stepN > stepE) dims.overlap = OVERLAP_SIZE * stepN; else dims.overlap = OVERLAP_SIZE * stepE; P_get_edge(bilin, &dims, stepE, stepN); P_set_dim(&dims, stepE, stepN, &nsplx_adj, &nsply_adj); G_verbose_message(_("Adjusted EW splines %d"), nsplx_adj); G_verbose_message(_("Adjusted NS splines %d"), nsply_adj); /* calculate number of subregions */ edgeE = dims.ew_size - dims.overlap - 2 * dims.edge_v; edgeN = dims.sn_size - dims.overlap - 2 * dims.edge_h; N_extension = original_reg.north - original_reg.south; E_extension = original_reg.east - original_reg.west; nsubregion_col = ceil(E_extension / edgeE) + 0.5; nsubregion_row = ceil(N_extension / edgeN) + 0.5; if (nsubregion_col < 0) nsubregion_col = 0; if (nsubregion_row < 0) nsubregion_row = 0; nsubregions = nsubregion_row * nsubregion_col; /* Creating line and categories structs */ Cats = Vect_new_cats_struct(); Vect_cat_set(Cats, 1, 0); subregion_row = 0; elaboration_reg.south = original_reg.north; last_row = FALSE; while (last_row == FALSE) { /* For each subregion row */ subregion_row++; P_set_regions(&elaboration_reg, &general_box, &overlap_box, dims, GENERAL_ROW); if (elaboration_reg.north > original_reg.north) { /* First row */ P_set_regions(&elaboration_reg, &general_box, &overlap_box, dims, FIRST_ROW); } if (elaboration_reg.south <= original_reg.south) { /* Last row */ P_set_regions(&elaboration_reg, &general_box, &overlap_box, dims, LAST_ROW); last_row = TRUE; } nsply = ceil((elaboration_reg.north - elaboration_reg.south) / stepN) + 0.5; G_debug(1, "Interpolation: nsply = %d", nsply); /* if (nsply > NSPLY_MAX) nsply = NSPLY_MAX; */ elaboration_reg.east = original_reg.west; last_column = FALSE; subregion_col = 0; /* TODO: process each subregion using its own thread (via OpenMP or pthreads) */ /* I'm not sure about pthreads, but you can tell OpenMP to start all at the same time and it will keep num_workers supplied with the next job as free cpus become available */ while (last_column == FALSE) { /* For each subregion column */ int npoints = 0; /* needed for sparse points interpolation */ int npoints_ext, *lineVect_ext = NULL; double **obsVect_ext; /*, mean_ext = .0; */ struct Point *observ_ext; subregion_col++; subregion++; if (nsubregions > 1) G_message(_("Processing subregion %d of %d..."), subregion, nsubregions); P_set_regions(&elaboration_reg, &general_box, &overlap_box, dims, GENERAL_COLUMN); if (elaboration_reg.west < original_reg.west) { /* First column */ P_set_regions(&elaboration_reg, &general_box, &overlap_box, dims, FIRST_COLUMN); } if (elaboration_reg.east >= original_reg.east) { /* Last column */ P_set_regions(&elaboration_reg, &general_box, &overlap_box, dims, LAST_COLUMN); last_column = TRUE; } nsplx = ceil((elaboration_reg.east - elaboration_reg.west) / stepE) + 0.5; G_debug(1, "Interpolation: nsplx = %d", nsplx); /* if (nsplx > NSPLX_MAX) nsplx = NSPLX_MAX; */ G_debug(1, "Interpolation: (%d,%d): subregion bounds", subregion_row, subregion_col); G_debug(1, "Interpolation: \t\tNORTH:%.2f\t", elaboration_reg.north); G_debug(1, "Interpolation: WEST:%.2f\t\tEAST:%.2f", elaboration_reg.west, elaboration_reg.east); G_debug(1, "Interpolation: \t\tSOUTH:%.2f", elaboration_reg.south); #ifdef DEBUG_SUBREGIONS fprintf(stdout, "B 5\n"); fprintf(stdout, " %.11g %.11g\n", elaboration_reg.east, elaboration_reg.north); fprintf(stdout, " %.11g %.11g\n", elaboration_reg.west, elaboration_reg.north); fprintf(stdout, " %.11g %.11g\n", elaboration_reg.west, elaboration_reg.south); fprintf(stdout, " %.11g %.11g\n", elaboration_reg.east, elaboration_reg.south); fprintf(stdout, " %.11g %.11g\n", elaboration_reg.east, elaboration_reg.north); fprintf(stdout, "C 1 1\n"); fprintf(stdout, " %.11g %.11g\n", (elaboration_reg.west + elaboration_reg.east) / 2, (elaboration_reg.south + elaboration_reg.north) / 2); fprintf(stdout, " 1 %d\n", subregion); #endif /* reading points in interpolation region */ dim_vect = nsplx * nsply; observ_ext = NULL; if (grid == FALSE && ext == TRUE) { observ_ext = P_Read_Vector_Region_Map(&In_ext, &elaboration_reg, &npoints_ext, dim_vect, 1); } else npoints_ext = 1; if (grid == TRUE && have_mask) { /* any unmasked cells in general region ? */ mean = 0; observ_ext = P_Read_Raster_Region_masked(&mask_seg, &original_reg, original_box, general_box, &npoints_ext, dim_vect, mean); } observ = NULL; if (npoints_ext > 0) { observ = P_Read_Vector_Region_Map(&In, &elaboration_reg, &npoints, dim_vect, bspline_field); } else npoints = 1; G_debug(1, "Interpolation: (%d,%d): Number of points in <elaboration_box> is %d", subregion_row, subregion_col, npoints); if (npoints > 0) G_verbose_message(_("%d points found in this subregion"), npoints); /* only interpolate if there are any points in current subregion */ if (npoints > 0 && npoints_ext > 0) { int i; nparameters = nsplx * nsply; BW = P_get_BandWidth(bilin, nsply); /* Least Squares system */ N = G_alloc_matrix(nparameters, BW); /* Normal matrix */ TN = G_alloc_vector(nparameters); /* vector */ parVect = G_alloc_vector(nparameters); /* Parameters vector */ obsVect = G_alloc_matrix(npoints, 3); /* Observation vector */ Q = G_alloc_vector(npoints); /* "a priori" var-cov matrix */ lineVect = G_alloc_ivector(npoints); /* */ for (i = 0; i < npoints; i++) { /* Setting obsVect vector & Q matrix */ double dval; Q[i] = 1; /* Q=I */ lineVect[i] = observ[i].lineID; obsVect[i][0] = observ[i].coordX; obsVect[i][1] = observ[i].coordY; /* read z coordinates from attribute table */ if (bspline_field > 0) { int cat, ival, ret; cat = observ[i].cat; if (cat < 0) continue; if (ctype == DB_C_TYPE_INT) { ret = db_CatValArray_get_value_int(&cvarr, cat, &ival); obsVect[i][2] = ival; observ[i].coordZ = ival; } else { /* DB_C_TYPE_DOUBLE */ ret = db_CatValArray_get_value_double(&cvarr, cat, &dval); obsVect[i][2] = dval; observ[i].coordZ = dval; } if (ret != DB_OK) { G_warning(_("Interpolation: (%d,%d): No record for point (cat = %d)"), subregion_row, subregion_col, cat); continue; } } /* use z coordinates of 3D vector */ else { obsVect[i][2] = observ[i].coordZ; } } /* Mean calculation for every point */ mean = P_Mean_Calc(&elaboration_reg, observ, npoints); G_debug(1, "Interpolation: (%d,%d): mean=%lf", subregion_row, subregion_col, mean); G_free(observ); for (i = 0; i < npoints; i++) obsVect[i][2] -= mean; /* Bilinear interpolation */ if (bilin) { G_debug(1, "Interpolation: (%d,%d): Bilinear interpolation...", subregion_row, subregion_col); normalDefBilin(N, TN, Q, obsVect, stepE, stepN, nsplx, nsply, elaboration_reg.west, elaboration_reg.south, npoints, nparameters, BW); nCorrectGrad(N, lambda, nsplx, nsply, stepE, stepN); } /* Bicubic interpolation */ else { G_debug(1, "Interpolation: (%d,%d): Bicubic interpolation...", subregion_row, subregion_col); normalDefBicubic(N, TN, Q, obsVect, stepE, stepN, nsplx, nsply, elaboration_reg.west, elaboration_reg.south, npoints, nparameters, BW); nCorrectGrad(N, lambda, nsplx, nsply, stepE, stepN); } if(G_strncasecmp(solver->answer, "cg", 2) == 0) G_math_solver_cg_sband(N, parVect, TN, nparameters, BW, atoi(iter->answer), atof(error->answer)); else G_math_solver_cholesky_sband(N, parVect, TN, nparameters, BW); G_free_matrix(N); G_free_vector(TN); G_free_vector(Q); if (grid == TRUE) { /* GRID INTERPOLATION ==> INTERPOLATION INTO A RASTER */ G_debug(1, "Interpolation: (%d,%d): Regular_Points...", subregion_row, subregion_col); if (!have_mask) { P_Regular_Points(&elaboration_reg, &original_reg, general_box, overlap_box, &out_seg, parVect, stepN, stepE, dims.overlap, mean, nsplx, nsply, nrows, ncols, bilin); } else { P_Sparse_Raster_Points(&out_seg, &elaboration_reg, &original_reg, general_box, overlap_box, observ_ext, parVect, stepE, stepN, dims.overlap, nsplx, nsply, npoints_ext, bilin, mean); } } else { /* OBSERVATION POINTS INTERPOLATION */ if (ext == FALSE) { G_debug(1, "Interpolation: (%d,%d): Sparse_Points...", subregion_row, subregion_col); P_Sparse_Points(&Out, &elaboration_reg, general_box, overlap_box, obsVect, parVect, lineVect, stepE, stepN, dims.overlap, nsplx, nsply, npoints, bilin, Cats, driver, mean, table_name); } else { /* FLAG_EXT == TRUE */ /* done that earlier */ /* int npoints_ext, *lineVect_ext = NULL; double **obsVect_ext; struct Point *observ_ext; observ_ext = P_Read_Vector_Region_Map(&In_ext, &elaboration_reg, &npoints_ext, dim_vect, 1); */ obsVect_ext = G_alloc_matrix(npoints_ext, 3); /* Observation vector_ext */ lineVect_ext = G_alloc_ivector(npoints_ext); for (i = 0; i < npoints_ext; i++) { /* Setting obsVect_ext vector & Q matrix */ obsVect_ext[i][0] = observ_ext[i].coordX; obsVect_ext[i][1] = observ_ext[i].coordY; obsVect_ext[i][2] = observ_ext[i].coordZ - mean; lineVect_ext[i] = observ_ext[i].lineID; } G_free(observ_ext); G_debug(1, "Interpolation: (%d,%d): Sparse_Points...", subregion_row, subregion_col); P_Sparse_Points(&Out, &elaboration_reg, general_box, overlap_box, obsVect_ext, parVect, lineVect_ext, stepE, stepN, dims.overlap, nsplx, nsply, npoints_ext, bilin, Cats, driver, mean, table_name); G_free_matrix(obsVect_ext); G_free_ivector(lineVect_ext); } /* END FLAG_EXT == TRUE */ } /* END GRID == FALSE */ G_free_vector(parVect); G_free_matrix(obsVect); G_free_ivector(lineVect); } else { if (observ) G_free(observ); if (observ_ext) G_free(observ_ext); if (npoints == 0) G_warning(_("No data within this subregion. " "Consider increasing spline step values.")); } } /*! END WHILE; last_column = TRUE */ } /*! END WHILE; last_row = TRUE */ G_verbose_message(_("Writing output...")); /* Writing the output raster map */ if (grid == TRUE) { int row, col; DCELL *drastbuf, dval; if (have_mask) { Segment_release(&mask_seg); /* release memory */ close(mask_fd); unlink(mask_file); } drastbuf = Rast_allocate_buf(DCELL_TYPE); for (row = 0; row < nrows; row++) { G_percent(row, nrows, 2); for (col = 0; col < ncols; col++) { Segment_get(&out_seg, &dval, row, col); drastbuf[col] = dval; } Rast_put_d_row(raster, drastbuf); } Rast_close(raster); Segment_release(&out_seg); /* release memory */ close(out_fd); unlink(out_file); /* set map title */ sprintf(title, "%s interpolation with Tykhonov regularization", type_opt->answer); Rast_put_cell_title(out_map_opt->answer, title); /* write map history */ Rast_short_history(out_map_opt->answer, "raster", &history); Rast_command_history(&history); Rast_write_history(out_map_opt->answer, &history); } /* Writing to the output vector map the points from the overlapping zones */ else if (flag_auxiliar == TRUE) { if (ext == FALSE) P_Aux_to_Vector(&In, &Out, driver, table_name); else P_Aux_to_Vector(&In_ext, &Out, driver, table_name); /* Drop auxiliary table */ G_debug(1, "%s: Dropping <%s>", argv[0], table_name); if (P_Drop_Aux_Table(driver, table_name) != DB_OK) G_fatal_error(_("Auxiliary table could not be dropped")); } db_close_database_shutdown_driver(driver); Vect_close(&In); if (ext != FALSE) Vect_close(&In_ext); if (vector) Vect_close(&Out); G_done_msg(" "); exit(EXIT_SUCCESS); } /*END MAIN */
/* ************************************************************************* */ void set_params(void) { param.phead = G_define_standard_option(G_OPT_R_INPUT); param.phead->key = "phead"; param.phead->description = _("The initial piezometric head in [m]"); param.status = G_define_standard_option(G_OPT_R_INPUT); param.status->key = "status"; param.status->description = _("Boundary condition status, 0-inactive, 1-active, 2-dirichlet"); param.hc_x = G_define_standard_option(G_OPT_R_INPUT); param.hc_x->key = "hc_x"; param.hc_x->description = _("X-part of the hydraulic conductivity tensor in [m/s]"); param.hc_y = G_define_standard_option(G_OPT_R_INPUT); param.hc_y->key = "hc_y"; param.hc_y->description = _("Y-part of the hydraulic conductivity tensor in [m/s]"); param.q = G_define_standard_option(G_OPT_R_INPUT); param.q->key = "q"; param.q->required = NO; param.q->description = _("Water sources and sinks in [m^3/s]"); param.s = G_define_standard_option(G_OPT_R_INPUT); param.s->key = "s"; param.s->description = _("Specific yield in [1/m]"); param.r = G_define_standard_option(G_OPT_R_INPUT); param.r->key = "r"; param.r->required = NO; param.r->guisection = _("Recharge"); param.r->description = _("Recharge map e.g: 6*10^-9 per cell in [m^3/s*m^2]"); param.top = G_define_standard_option(G_OPT_R_INPUT); param.top->key = "top"; param.top->description = _("Top surface of the aquifer in [m]"); param.bottom = G_define_standard_option(G_OPT_R_INPUT); param.bottom->key = "bottom"; param.bottom->description = _("Bottom surface of the aquifer in [m]"); param.output = G_define_standard_option(G_OPT_R_OUTPUT); param.output->key = "output"; param.output->description = _("The map storing the numerical result [m]"); param.vector = G_define_standard_option(G_OPT_R_OUTPUT); param.vector->key = "velocity"; param.vector->required = NO; param.vector->description = _("Calculate the groundwater filter velocity vector field [m/s]\n" "and write the x, and y components to maps named name_[xy]"); param.type = G_define_option(); param.type->key = "type"; param.type->type = TYPE_STRING; param.type->required = NO; param.type->answer = "confined"; param.type->options = "confined,unconfined"; param.type->description = _("The type of groundwater flow"); /*Variants of the cauchy boundary condition */ param.river_bed = G_define_standard_option(G_OPT_R_INPUT); param.river_bed->key = "river_bed"; param.river_bed->guisection = "River"; param.river_bed->required = NO; param.river_bed->description = _("The height of the river bed in [m]"); param.river_head = G_define_standard_option(G_OPT_R_INPUT); param.river_head->key = "river_head"; param.river_head->guisection = "River"; param.river_head->required = NO; param.river_head->description = _("Water level (head) of the river with leakage connection in [m]"); param.river_leak = G_define_standard_option(G_OPT_R_INPUT); param.river_leak->key = "river_leak"; param.river_leak->guisection = "River"; param.river_leak->required = NO; param.river_leak->description = _("The leakage coefficient of the river bed in [1/s]."); param.drain_bed = G_define_standard_option(G_OPT_R_INPUT); param.drain_bed->key = "drain_bed";; param.drain_bed->guisection = "Drainage"; param.drain_bed->required = NO; param.drain_bed->description = _("The height of the drainage bed in [m]"); param.drain_leak = G_define_standard_option(G_OPT_R_INPUT); param.drain_leak->key = "drain_leak"; param.drain_leak->guisection = "Drainage"; param.drain_leak->required = NO; param.drain_leak->description = _("The leakage coefficient of the drainage bed in [1/s]"); param.dt = N_define_standard_option(N_OPT_CALC_TIME); param.maxit = N_define_standard_option(N_OPT_MAX_ITERATIONS); param.error = N_define_standard_option(N_OPT_ITERATION_ERROR); param.solver = N_define_standard_option(N_OPT_SOLVER_SYMM); param.sor = N_define_standard_option(N_OPT_SOR_VALUE); param.sparse = G_define_flag(); param.sparse->key = 's'; param.sparse->guisection = "Solver"; param.sparse->description = _("Use a sparse matrix, only available with iterative solvers"); }