def ext_theis_tpl_3d( time, rad, storage, cond_gmean, len_scale, hurst, var=None, c=1.0, anis=1, lat_ext=1.0, rate=-1e-4, r_well=0.0, r_bound=np.inf, h_bound=0.0, K_well="KH", prop=1.6, far_err=0.01, struc_grid=True, parts=30, lap_kwargs=None, ): """ The extended Theis solution for truncated power-law fields in 3D. The extended Theis solution for transient flow under a pumping condition in a confined aquifer with anisotropy in 3D. The type curve is describing the effective drawdown in a 3-dimensional statistical framework, where the conductivity distribution is following a log-normal distribution with a truncated power-law correlation function build on superposition of gaussian modes. Parameters ---------- time : :class:`numpy.ndarray` Array with all time-points where the function should be evaluated rad : :class:`numpy.ndarray` Array with all radii where the function should be evaluated storage : :class:`float` Storage of the aquifer. cond_gmean : :class:`float` Geometric-mean conductivity. len_scale : :class:`float` Corralation-length of log-conductivity. hurst: :class:`float` Hurst coefficient of the TPL model. Should be in (0, 1). var : :class:`float` Variance of the log-conductivity. If var is given, c will be calculated accordingly. Default: :any:`None` c : :class:`float`, optional Intensity of variation in the TPL model. Is overwritten if var is given. Default: ``1.0`` anis : :class:`float`, optional Anisotropy-ratio of the vertical and horizontal corralation-lengths. Default: 1.0 lat_ext : :class:`float`, optional Lateral extend of the aquifer (thickness). Default: ``1.0`` rate : :class:`float`, optional Pumpingrate at the well. Default: -1e-4 r_well : :class:`float`, optional Radius of the pumping-well. Default: ``0.0`` r_bound : :class:`float`, optional Radius of the outer boundary of the aquifer. Default: ``np.inf`` h_bound : :class:`float`, optional Reference head at the outer boundary as well as initial condition. Default: ``0.0`` K_well : :class:`float`, optional Explicit conductivity value at the well. One can choose between the harmonic mean (``"KH"``), the arithmetic mean (``"KA"``) or an arbitrary float value. Default: ``"KH"`` prop: :class:`float`, optional Proportionality factor used within the upscaling procedure. Default: ``1.6`` far_err : :class:`float`, optional Relative error for the farfield transmissivity for calculating the cutoff-point of the solution. Default: ``0.01`` struc_grid : :class:`bool`, optional If this is set to ``False``, the `rad` and `time` array will be merged and interpreted as single, r-t points. In this case they need to have the same shapes. Otherwise a structured r-t grid is created. Default: ``True`` parts : :class:`int`, optional Since the solution is calculated by setting the transmissivity to local constant values, one needs to specify the number of partitions of the transmissivity. Default: ``30`` lap_kwargs : :class:`dict` or :any:`None` optional Dictionary for :any:`get_lap_inv` containing `method` and `method_dict`. The default is equivalent to ``lap_kwargs = {"method": "stehfest", "method_dict": None}``. Default: :any:`None` Returns ------- head : :class:`numpy.ndarray` Array with all heads at the given radii and time-points. Notes ----- If you want to use cartesian coordiantes, just use the formula ``r = sqrt(x**2 + y**2)`` """ # check the input if r_well < 0.0: raise ValueError("The wellradius needs to be >= 0") if not r_bound > r_well: raise ValueError("The upper boundary needs to be > well radius") if not storage > 0.0: raise ValueError("The storage needs to be positive.") if not cond_gmean > 0.0: raise ValueError("The gmean conductivity needs to be positive.") if not len_scale > 0.0: raise ValueError("The correlationlength needs to be positive.") if not 0 < hurst < 1: raise ValueError("Hurst coefficient needs to be in (0,1)") if var is not None and var < 0.0: raise ValueError("The variance needs to be positive.") if var is None and not c > 0.0: raise ValueError("The intensity of variation needs to be positive.") if K_well != "KA" and K_well != "KH" and not isinstance(K_well, float): raise ValueError( "The well-conductivity should be given as float or 'KA' resp 'KH'") if isinstance(K_well, float) and not K_well > 0.0: raise ValueError("The well-conductivity needs to be positive.") if not prop > 0.0: raise ValueError("The proportionality factor needs to be positive.") if parts <= 1: raise ValueError("The numbor of partitions needs to be at least 2") if not 0.0 < far_err < 1.0: raise ValueError( "The relative error of Conductivity needs to be within (0,1)") # genearte rlast from a given relativ-error to farfield-conductivity r_last = TPL_CG_error(far_err, cond_gmean, len_scale, hurst, var, c, anis, 3, K_well, prop) # generate the partition points if r_last > r_well: R_part = specialrange_cut(r_well, r_bound, parts + 1, r_last) else: R_part = np.array([r_well, r_bound]) # calculate the harmonic mean conductivity values within each partition K_part = annular_hmean( TPL_CG, R_part, ann_dim=2, cond_gmean=cond_gmean, len_scale=len_scale, hurst=hurst, var=var, c=c, anis=anis, dim=3, K_well=K_well, prop=prop, ) K_well = TPL_CG(r_well, cond_gmean, len_scale, hurst, var, c, anis, 3, K_well, prop) return ext_grf( time=time, rad=rad, S_part=np.full_like(K_part, storage), K_part=K_part, R_part=R_part, dim=2, lat_ext=lat_ext, rate=rate, h_bound=h_bound, K_well=K_well, struc_grid=struc_grid, lap_kwargs=lap_kwargs, )
def ext_theis_2d( time, rad, storage, trans_gmean, var, len_scale, rate=-1e-4, r_well=0.0, r_bound=np.inf, h_bound=0.0, T_well=None, prop=1.6, struc_grid=True, far_err=0.01, parts=30, lap_kwargs=None, ): """ The extended Theis solution in 2D. The extended Theis solution for transient flow under a pumping condition in a confined aquifer. The type curve is describing the effective drawdown in a 2D statistical framework, where the transmissivity distribution is following a log-normal distribution with a gaussian correlation function. Parameters ---------- time : :class:`numpy.ndarray` Array with all time-points where the function should be evaluated rad : :class:`numpy.ndarray` Array with all radii where the function should be evaluated storage : :class:`float` Storage of the aquifer. trans_gmean : :class:`float` Geometric-mean transmissivity. var : :class:`float` Variance of log-transmissivity. len_scale : :class:`float` Correlation-length of log-transmissivity. rate : :class:`float`, optional Pumpingrate at the well. Default: -1e-4 r_well : :class:`float`, optional Radius of the pumping-well. Default: ``0.0`` r_bound : :class:`float`, optional Radius of the outer boundary of the aquifer. Default: ``np.inf`` h_bound : :class:`float`, optional Reference head at the outer boundary as well as initial condition. Default: ``0.0`` T_well : :class:`float`, optional Explicit transmissivity value at the well. Harmonic mean by default. prop: :class:`float`, optional Proportionality factor used within the upscaling procedure. Default: ``1.6`` far_err : :class:`float`, optional Relative error for the farfield transmissivity for calculating the cutoff-point of the solution. Default: ``0.01`` struc_grid : :class:`bool`, optional If this is set to ``False``, the `rad` and `time` array will be merged and interpreted as single, r-t points. In this case they need to have the same shapes. Otherwise a structured r-t grid is created. Default: ``True`` parts : :class:`int`, optional Since the solution is calculated by setting the transmissivity to local constant values, one needs to specify the number of partitions of the transmissivity. Default: ``30`` lap_kwargs : :class:`dict` or :any:`None` optional Dictionary for :any:`get_lap_inv` containing `method` and `method_dict`. The default is equivalent to ``lap_kwargs = {"method": "stehfest", "method_dict": None}``. Default: :any:`None` Returns ------- head : :class:`numpy.ndarray` Array with all heads at the given radii and time-points. Notes ----- If you want to use cartesian coordiantes, just use the formula ``r = sqrt(x**2 + y**2)`` Examples -------- >>> ext_theis_2d([10,100], [1,2,3], 0.001, 0.001, 1, 10, -0.001) array([[-0.33737576, -0.17400123, -0.09489812], [-0.58443489, -0.40847176, -0.31095166]]) """ lap_kwargs = {} if lap_kwargs is None else lap_kwargs # check the input if r_well < 0.0: raise ValueError("The wellradius needs to be >= 0") if not r_bound > r_well: raise ValueError("The upper boundary needs to be > well radius") if not storage > 0.0: raise ValueError("The Storage needs to be positive.") if not trans_gmean > 0.0: raise ValueError("The Transmissivity needs to be positive.") if var < 0.0: raise ValueError("The variance needs to be positive.") if not len_scale > 0.0: raise ValueError("The correlationlength needs to be positive.") if T_well is not None and not T_well > 0.0: raise ValueError("The well Transmissivity needs to be positive.") if not prop > 0.0: raise ValueError("The proportionality factor needs to be positive.") if parts <= 1: raise ValueError("The numbor of partitions needs to be at least 2") if not 0.0 < far_err < 1.0: raise ValueError( "The relative error of Transmissivity needs to be within (0,1)") # genearte rlast from a given relativ-error to farfield-transmissivity r_last = T_CG_error(far_err, trans_gmean, var, len_scale, T_well, prop) # generate the partition points if r_last > r_well: R_part = specialrange_cut(r_well, r_bound, parts + 1, r_last) else: R_part = np.array([r_well, r_bound]) # calculate the harmonic mean transmissivity values within each partition T_part = annular_hmean( T_CG, R_part, trans_gmean=trans_gmean, var=var, len_scale=len_scale, T_well=T_well, prop=prop, ) T_well = T_CG(r_well, trans_gmean, var, len_scale, T_well, prop) return ext_grf( time=time, rad=rad, S_part=np.full_like(T_part, storage), K_part=T_part, R_part=R_part, dim=2, lat_ext=1, rate=rate, h_bound=h_bound, K_well=T_well, struc_grid=struc_grid, lap_kwargs=lap_kwargs, )
def theis( time, rad, storage, transmissivity, rate=-1e-4, r_well=0.0, r_bound=np.inf, h_bound=0.0, struc_grid=True, lap_kwargs=None, ): """ The Theis solution. The Theis solution for transient flow under a pumping condition in a confined and homogeneous aquifer. This solution was presented in [Theis35]_. Parameters ---------- time : :class:`numpy.ndarray` Array with all time-points where the function should be evaluated rad : :class:`numpy.ndarray` Array with all radii where the function should be evaluated storage : :class:`float` Storage coefficient of the aquifer. conductivity : :class:`float` Conductivity of the aquifer. rate : :class:`float`, optional Pumpingrate at the well. Default: -1e-4 r_well : :class:`float`, optional Inner radius of the pumping-well. Default: ``0.0`` r_bound : :class:`float`, optional Radius of the outer boundariy of the aquifer. Default: ``np.inf`` h_bound : :class:`float`, optional Reference head at the outer boundary, as well as initial condition. Default: ``0.0`` struc_grid : :class:`bool`, optional If this is set to ``False``, the `rad` and `time` array will be merged and interpreted as single, r-t points. In this case they need to have the same shapes. Otherwise a structured r-t grid is created. Default: ``True`` lap_kwargs : :class:`dict` or :any:`None` optional Dictionary for :any:`get_lap_inv` containing `method` and `method_dict`. The default is equivalent to ``lap_kwargs = {"method": "stehfest", "method_dict": None}``. Default: :any:`None` Returns ------- head : :class:`numpy.ndarray` Array with all heads at the given radii and time-points. References ---------- .. [Theis35] Theis, C., ''The relation between the lowering of the piezometric surface and the rate and duration of discharge of a well using groundwater storage'', Trans. Am. Geophys. Union, 16, 519-524, 1935 """ if np.isclose(r_well, 0) and np.isposinf(r_bound) and lap_kwargs is None: return well_solution(time, rad, storage, transmissivity, rate) return ext_grf( time=time, rad=rad, S_part=[storage], K_part=[transmissivity], R_part=[r_well, r_bound], dim=2, lat_ext=1, rate=rate, K_well=None, h_bound=h_bound, lap_kwargs=lap_kwargs, struc_grid=struc_grid, )
def neuman2004( time, rad, storage, trans_gmean, var, len_scale, rate=-1e-4, r_well=0.0, r_bound=np.inf, h_bound=0.0, struc_grid=True, parts=30, lap_kwargs=None, ): """ The transient solution for the apparent transmissivity from [Neuman2004]. This solution is build on the apparent transmissivity from Neuman 2004, which represents a mean drawdown in an ensemble of pumping tests in heterogeneous transmissivity fields following an exponential covariance. Parameters ---------- time : :class:`numpy.ndarray` Array with all time-points where the function should be evaluated. rad : :class:`numpy.ndarray` Array with all radii where the function should be evaluated. storage : :class:`float` Storage of the aquifer. trans_gmean : :class:`float` Geometric-mean transmissivity. var : :class:`float` Variance of log-transmissivity. len_scale : :class:`float` Correlation-length of log-transmissivity. rate : :class:`float`, optional Pumpingrate at the well. Default: -1e-4 r_well : :class:`float`, optional Radius of the pumping-well. Default: ``0.0`` r_bound : :class:`float`, optional Radius of the outer boundary of the aquifer. Default: ``np.inf`` h_bound : :class:`float`, optional Reference head at the outer boundary as well as initial condition. Default: ``0.0`` struc_grid : :class:`bool`, optional If this is set to ``False``, the `rad` and `time` array will be merged and interpreted as single, r-t points. In this case they need to have the same shapes. Otherwise a structured r-t grid is created. Default: ``True`` parts : :class:`int`, optional Since the solution is calculated by setting the transmissivity to local constant values, one needs to specify the number of partitions of the transmissivity. Default: ``30`` lap_kwargs : :class:`dict` or :any:`None` optional Dictionary for :any:`get_lap_inv` containing `method` and `method_dict`. The default is equivalent to ``lap_kwargs = {"method": "stehfest", "method_dict": None}``. Default: :any:`None` Returns ------- head : :class:`numpy.ndarray` Array with all heads at the given radii and time-points. References ---------- .. [Neuman2004] Neuman, Shlomo P., Alberto Guadagnini, and Monica Riva. ''Type-curve estimation of statistical heterogeneity.'' Water resources research 40.4, 2004 """ # check the input if r_well < 0.0: raise ValueError("The wellradius needs to be >= 0") if not r_bound > r_well: raise ValueError("The upper boundary needs to be > well radius") if not storage > 0.0: raise ValueError("The Storage needs to be positive.") if not trans_gmean > 0.0: raise ValueError("The Transmissivity needs to be positive.") if var < 0.0: raise ValueError("The variance needs to be positive.") if not len_scale > 0.0: raise ValueError("The correlationlength needs to be positive.") if parts <= 1: raise ValueError("The numbor of partitions needs to be at least 2") # genearte rlast from a given relativ-error to farfield-transmissivity r_last = 2 * len_scale # generate the partition points if r_last > r_well: R_part = specialrange_cut(r_well, r_bound, parts + 1, r_last) else: R_part = np.array([r_well, r_bound]) # calculate the harmonic mean transmissivity values within each partition T_part = annular_hmean( neuman2004_trans, R_part, trans_gmean=trans_gmean, var=var, len_scale=len_scale, ) T_well = neuman2004_trans(r_well, trans_gmean, var, len_scale) return ext_grf( time=time, rad=rad, S_part=np.full_like(T_part, storage), K_part=T_part, R_part=R_part, dim=2, lat_ext=1, rate=rate, h_bound=h_bound, K_well=T_well, struc_grid=struc_grid, lap_kwargs=lap_kwargs, )
def grf( time, rad, storage, conductivity, dim=2, lat_ext=1.0, rate=-1e-4, r_well=0.0, r_bound=np.inf, h_bound=0.0, struc_grid=True, lap_kwargs=None, ): """ The general radial flow (GRF) model for a pumping test. This solution was presented in [Barker88]_. Parameters ---------- time : :class:`numpy.ndarray` Array with all time-points where the function should be evaluated. rad : :class:`numpy.ndarray` Array with all radii where the function should be evaluated. storage : :class:`float` Storage coefficient of the aquifer. conductivity : :class:`float` Conductivity of the aquifer. dim : :class:`float`, optional Fractional dimension of the aquifer. Default: ``2.0`` lat_ext : :class:`float`, optional Lateral extend of the aquifer. Default: ``1.0`` rate : :class:`float`, optional Pumpingrate at the well. Default: -1e-4 r_well : :class:`float`, optional Inner radius of the pumping-well. Default: ``0.0`` r_bound : :class:`float`, optional Radius of the outer boundary of the aquifer. Default: ``np.inf`` h_bound : :class:`float`, optional Reference head at the outer boundary, as well as initial condition. Default: ``0.0`` struc_grid : :class:`bool`, optional If this is set to "False", the "rad" and "time" array will be merged and interpreted as single, r-t points. In this case they need to have the same shapes. Otherwise a structured r-t grid is created. Default: ``True`` lap_kwargs : :class:`dict` or :any:`None` optional Dictionary for :any:`get_lap_inv` containing `method` and `method_dict`. The default is equivalent to ``lap_kwargs = {"method": "stehfest", "method_dict": None}``. Default: :any:`None` Returns ------- head : :class:`numpy.ndarray` Array with all heads at the given radii and time-points. References ---------- .. [Barker88] Barker, J. ''A generalized radial flow model for hydraulic tests in fractured rock.'', Water Resources Research 24.10, 1796-1804, 1988 """ if np.isclose(r_well, 0) and np.isposinf(r_bound) and lap_kwargs is None: return grf_solution( time=time, rad=rad, storage=storage, conductivity=conductivity, dim=dim, lat_ext=lat_ext, rate=rate, h_bound=h_bound, struc_grid=struc_grid, ) return ext_grf( time=time, rad=rad, S_part=[storage], K_part=[conductivity], R_part=[r_well, r_bound], dim=dim, lat_ext=lat_ext, rate=rate, K_well=None, h_bound=h_bound, struc_grid=struc_grid, lap_kwargs=lap_kwargs, )