def setup_and_run_fdm(gridpar, k, rch, axis=1): Lx, wx, Ly, wy, D, d = gridpar x = np.linspace(-Lx, Lx, int(2 * Lx / wx) + 1) y = np.linspace(-Ly, Ly, int(2 * Ly / wy) + 1) z = np.linspace(-D, D, int(2 * D / d) + 1) gr = mfgrid.Grid(x, y, z) K = gr.const(k) FH = gr.const(0.) FQ = gr.Volume * rch IBOUND = gr.const(1) if axis == 0: IBOUND[[0, -1], :, :] = -1 elif axis == 1: IBOUND[:, [0, -1], :] = -1 elif axis == 2: IBOUND[:, :, [0, -1]] = -1 else: print("axis must be 0, 1, or 2, not {}".format(axis)) # Solve for the heads: Out = fdm.fdm3(gr, (K, K, K), FQ, FH, IBOUND) return Out, gr, IBOUND
def setup_and_run_fdm(gridpar, k, Q): Lx, wx, Ly, wy, D, d = gridpar x = np.linspace(-Lx, Lx, int(2 * Lx / wx) + 1) y = np.linspace(-Ly, Ly, int(2 * Ly / wy) + 1) z = np.linspace(-D, D, int(2 * D / d) + 1) gr = mfgrid.Grid(x, y, z) K = gr.const(k) # * np.random.rand(gr.Nod).reshape(gr.shape) FH = gr.const(0.) FQ = gr.const(0.) IBOUND = gr.const(1) IBOUND[[0, -1], :, :] = -1 IBOUND[:, [0, -1], :] = -1 IBOUND[:, :, [0, -1]] = -1 icx, icy, icz = gr.ixyz(0., 0., 0.) FQ[icy, icx, icz] = Q # Solve for the heads: Out = fdm.fdm3(gr, (K, K, K), FQ, FH, IBOUND) return Out, gr, IBOUND
def set_up_and_run_fdm(gridpar, k, hbound, axis=None): Lx, wx, Ly, wy, D, d = gridpar x = np.linspace(-Lx, Lx, int(2 * Lx / wx) + 1) y = np.linspace(-Ly, Ly, int(2 * Ly / wy) + 1) z = np.linspace(-D , D, int(2 * D / d) + 1) gr = mfgrid.Grid(x, y, z) K = gr.const(k) # * np.random.rand(gr.Nod).reshape(gr.shape) FH = gr.const(0.) FQ = gr.const(0.) IBOUND = gr.const(1) if axis == 0: IBOUND[[0, -1], :, :] = -1 FH[0, :, :] = hbound[0] FH[-1, :,:] = hbound[1] elif axis == 1: IBOUND[:,[0, -1], :] = -1 FH[:, 0, :] = hbound[0] FH[:, -1, :] = hbound[1] elif axis == 2: IBOUND[:, :, [0, -1]] = -1 FH[:, :, 0] = hbound[0] FH[:, :, -1] = hbound[1] else: print("axis must be 0, 1, or to, not {}".format(axis)) raise ValueError() # Solve for the heads: Out = fdm.fdm3(gr, (K, K, K), FQ, FH, IBOUND) return Out, gr, IBOUND
def example_De_Glee(): """Axial symmetric example, well in semi-confined aquifer (De Glee case) De Glee was a Dutch engineer/groundwater hydrologist and later the first director of the water company of the province of Groningen. His PhD (1930) solved the axial symmetric steady state flow to a well in a semi confined aquifer using the Besselfunctions of the second kind, known as K0 and K1. The example computes the heads in the regional aquifer below a semi confining layer with a fixed head above. It uses two model layers a confining one in which the heads are fixed and a semi-confined aquifer with a prescribed extraction at r=r0. If r0>>0, both K0 and K1 Bessel functions are needed. The grid is signaled to use inteprete the grid as axially symmetric. """ K0 = lambda x: scipy.special.kn(0, x ) # Bessel function second kind, order 0 K1 = lambda x: scipy.special.kn(1, x ) # Bessel function second kind, order 1 Q = -1200.0 # m3/d, well extraction r0 = 100. # m, well radius R = 2500. # m, outer radius of model d = 10. # m, thickness of confining top layer D = 50. # m, thickness of regional aquifer c = 250 # d, vertical resistance of confining top layer k1 = d / c # m/d conductivity of confining top layer k2 = 10. # m/d conductivity of regional aquifer kD = k2 * D # m2/d, transmissivity of regional aquifer lam = np.sqrt(kD * c) # spreading length of regional aquifer r = np.hstack((r0 + 0.001, np.logspace(np.log10(r0), np.log10(R), 41))) # distance to well center y = None # dummy, ignored because problem is axially symmetric z = np.array([0, -d, -d - D]) # m, elevation of tops and bottoms of model layers gr = mfgrid.Grid(r, y, z, axial=True) # generate grid FQ = gr.const(0.) FQ[-1, 0, 0] = Q # m3/d fixed flows IH = gr.const(0.) # m, initial heads IBOUND = gr.const(1) IBOUND[0, :, :] = -1 # modflow like boundary array K = gr.const([k1 / 2., k2]) # full 3D array of conductivities Out = fdm3(gr, K, FQ, IH, IBOUND) # run model plt.figure() plt.setp(plt.gca(), 'xlabel', 'r [m]', 'ylabel', 'head [m]',\ 'title', 'De Glee, well extraction, axially symmetric', 'xscale', 'log', 'xlim', [1.0, R]) plt.plot(gr.xm, Out.Phi[-1, 0, :], 'ro-', label='fdm3') plt.plot(gr.x, Q / (2 * np.pi * kD) * K0(gr.x / lam) / (r0 / lam * K1(r0 / lam)), 'bx-', label='analytic') plt.legend()
def set_up_and_run_fdm(gridpar, k, Q, well_axis): Lx, wx, Ly, wy, D, d = gridpar x = np.linspace(-Lx, Lx, int(2 * Lx / wx) + 1) y = np.linspace(-Ly, Ly, int(2 * Ly / wy) + 1) z = np.linspace(-D , D, int(2 * D / d) + 1) gr = mfgrid.Grid(x, y, z) K = gr.const(k) # * np.random.rand(gr.Nod).reshape(gr.shape) FH = gr.const(0.) FQ = gr.const(0.) # Cell indices of center of model: hard wired here x0, y0, z0 = 0., 0., 0. icx, icy, icz = gr.ixyz(x0, y0, z0) # Covner to int to prevent shape errors with FQ below icx = int(icx); icy=int(icy); icz=int(icz) if well_axis == 2: # i.e. z # screen in z direction, flow in xy plane IBOUND = gr.const(1) IBOUND[[0,-1], :, :] = -1 IBOUND[:, [0,-1], :] = -1 FQ[icy, icx, :] = Q * gr.dz / np.sum(gr.dz) elif well_axis == 0: # i.e. y # screen in x direction, flow in zx plane IBOUND = gr.const(1) IBOUND[:, [0,-1], :] = -1 IBOUND[:, :, [0,-1]] = -1 FQ[:, icx, icz] = Q * gr.dy / np.sum(gr.dy) elif well_axis == 1: # i.e. x # screen in y direction, flow in yz plane IBOUND = gr.const(1) IBOUND[[0,-1], :, :] = -1 IBOUND[:, :, [0,-1]] = -1 FQ[icy, :, icz] = Q * gr.dx / np.sum(gr.dx) else: print("well_axis must be 0, 1, or 2, not {}".format(well_axis)) # Solve for the heads: Out = fdm.fdm3(gr, (K, K, K), FQ, FH, IBOUND) return Out, gr, IBOUND
def example_mazure(): """1D flow in semi-confined aquifer example Mazure was Dutch professor in the 1930s, concerned with leakage from polders that were pumped dry. His situation is a cross section perpendicular to the dike of a regional aquifer covered by a semi-confining layer with a maintained head in it. The head in the regional aquifer at the dike was given as well. The head obeys the following analytical expression phi(x) - hp = (phi(0)-hp) * exp(-x/lam), lam = sqrt(kDc) To compute we use 2 model layers and define the values such that we obtain the Mazure result. """ x = np.hstack((0.001, np.linspace(0., 2000., 101))) # column coordinates y = np.array([-0.5, 0.5]) # m, model is 1 m thick d = 10. # m, thickness of confining top layer D = 50. # m, thickness of regional aquifer z = np.array([0, -d, -d - D]) # tops and bottoms of layers gr = mfgrid.Grid(x, y, z, axial=False) c = 250 # d, vertical resistance of semi-confining layer k1 = d / c # m/d conductivity of the top layer k2 = 10. # m/d conductivity of the regional aquifer kD = k2 * D # m2/d, transmissivity of regional aquifer K = gr.const([k1 / 2., k2]) # k1 = 0.5 d/c because conductance from layer center FQ = gr.const(0) # prescribed flows s0 = 2.0 # head in aquifer at x=0 IH = gr.const(0) IH[:, 0, -1] = s0 # prescribed heads IBOUND = gr.const(1) IBOUND[:, :, 0] = -1 IBOUND[:, 0, -1] = -1 out = fdm.fdm3(gr, K, FQ, IH, IBOUND) # compute heads, run model numerical = out.Phi[0, :, -1] analytic = vanMarzure(s0, kD, c, gr.xm) #============================================================================== # plt.figure() # plt.setp(plt.gca(), 'xlabel','x [m]', 'ylabel', 'head [m]', 'title', 'Mazure 1D flow') # plt.plot(gr.xm, numerical, 'ro-', label='fdm3') # numeric solution # plt.plot(gr.xm, analytic ,'bx-', label='analytic') # analytic solution # plt.legend() # #============================================================================== return numerical, analytic, out
def setupAndRunFDM_model(gridpar, k, hbound): Lx, wx, Ly, wy, D, d = gridpar hW, hE, hN, hS, hT, hB = hbound x = np.linspace(-Lx, Lx, int(2 * Lx / wx) + 1) y = np.linspace(-Ly, Ly, int(2 * Ly / wy) + 1) z = np.linspace(0, -D, int(D / d) + 1) gr = mfgrid.Grid(x, y, z) K = gr.const(k) # * np.random.rand(gr.Nod).reshape(gr.shape) FH = gr.const(0.) FQ = gr.const(0.) IBOUND = gr.const(1) if not (hW is None): IBOUND[:, 0, :] = -1 FH[:, 0, :] = hW if not hE is None: IBOUND[:, -1, :] = -1 FH[:, -1, :] = hE if not hN is None: IBOUND[0, :, :] = -1 FH[0, :, :] = hN if not hS is None: IBOUND[-1, :, :] = -1 FH[-1, :, :] = hS if not hT is None: IBOUND[:, :, 0] = -1 FH[:, :, 0] = hT if not hB is None: IBOUND[:, :, -1] = -1 FH[:, :, -1] = hB # Solve for the heads: Out = fdm.fdm3(gr, (K, K, K), FQ, FH, IBOUND) return Out, gr, IBOUND
def normGrid(gr): up = np.arange(0., gr.Nx + 1) vp = np.arange(0., gr.Ny + 1) wp = np.arange(0., gr.Nz + 1) return mfgrid.Grid(up, vp, wp)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Mon Nov 14 18:03:45 2016 @author: Theo """ #from mpl_toolkits.mplot3d import axes3d import matplotlib.pyplot as plt import numpy as np import mfgrid fig = plt.figure() ax1 = fig.add_subplot(111, projection='3d') Np = 11 x = np.arange(Np, dtype=float) y = np.arange(Np, dtype=float) z = np.arange(Np, dtype=float) gr = mfgrid.Grid(x, y, z) gr.plot_grid3d('gbr', alpha=0.5) plt.show()
def setUp(self): global gr, grn, tol, xTest, yTest,\ xp, yp, zp, xpm, ypm, zpm,\ up, vp, wp, upm, vpm, wpm,\ U, iu, V, iv, W, iw, mustSkip mustSkip = False tol = 1e-5 digits = int(abs(np.log10(tol))) x = np.array( [0, 6, 3.000001, -2, -1e-6, 3e-6, 4.00001, 7, 8, 11, -3, -4]) y = x[:] xTest = np.unique(np.round(x, digits)) yTest = xTest[::-1] Nx = len(np.unique(np.round(np.array(x), digits))) - 1 Ny = len(np.unique(np.round(np.array(y), digits))) - 1 # Generate a full fledged Z array with different Z in ever iy,ix # combination z = np.arange(5) * -10 Z = np.ones((Ny, Nx, 1)) * z.reshape((1, 1, len(z))) Z = Z * (np.random.rand(len(z)) + 0.5).reshape((1, 1, len(z))) min_dz = 0.1 gr = mfgrid.Grid(x, y, Z, min_dz=min_dz, tol=tol) Nz = gr.Nz grn = gr.norm_grid() Lam = lambda a, b: np.hstack((np.array(a), np.array(b))) """ # Generate trial points that include all special cases like # points outside the model, points at grid lines and points # at the boundary edges of the model, next to ordinary # points falling within model cells. """ # outside and inside the model up = np.array([]) vp = np.array([]) wp = np.array([]) up = Lam(up, -0.5 + np.array([0., 1., 0., 0., 1., 1., 0., 1.])) vp = Lam(vp, -0.5 + np.array([0., 0., 1., 0., 1., 0., 1., 1.])) wp = Lam(wp, -0.5 + np.array([0., 0., 0., 1., 0., 1., 1., 1.])) up = Lam(up, Nx - 0.5 + np.array([0., 1., 0., 0., 1., 1., 0., 1.])) vp = Lam(vp, Ny - 0.5 + np.array([0., 0., 1., 0., 1., 0., 1., 1.])) wp = Lam(wp, Nz - 0.5 + np.array([0., 0., 0., 1., 0., 1., 1., 1.])) # points on grid lines, including all corner cases up = Lam(up, [0., 1., 0., 0., 1., 1., 0., 1.]) vp = Lam(vp, [0., 0., 1., 0., 1., 0., 1., 1.]) wp = Lam(wp, [0., 0., 0., 1., 0., 1., 1., 1.]) up = Lam(up, Nx - np.array([0., 1., 0., 0., 1., 1., 0., 1.])) vp = Lam(vp, Ny - np.array([0., 0., 1., 0., 1., 0., 1., 1.])) wp = Lam(wp, Nz - np.array([0., 0., 0., 1., 0., 1., 1., 1.])) # not at grid lines, i.e. ordinary points up = Lam(up, np.pi / 10. * Nx + np.array([0., 1., 0., 0., 1., 1., 0., 1.])) vp = Lam(vp, np.pi / 10. * Ny + np.array([0., 0., 1., 0., 1., 0., 1., 1.])) wp = Lam(wp, np.pi / 10. * Nz + np.array([0., 0., 0., 1., 0., 1., 1., 1.])) # convert these ponts to grid coordinates xp, yp, zp = gr.uvw2xyz(up, vp, wp) # verify by showing the location of these points in the two grids U, iu = gr.U(xp) V, iv = gr.V(yp) W, iw = gr.W(xp, yp, zp) up = gr.up(xp) vp = gr.vp(yp) wp = gr.wp(xp, yp, zp)
import numpy as np import matplotlib.pylab as plt import mfgrid import fdm import mfpath import pdb axial = False Q = -2400 if axial else -240. # m3/d if axial else m2/ por = 0.35 # [-], effective porosity xGr = np.logspace(-1, 4, 51) xGr = np.linspace(0, 2000, 101) yGr = np.array([-0.5, 0.5]) zGr = np.array([0., -5, -50, -60, -100]) gr = mfgrid.Grid(xGr, yGr, zGr, axial) IBOUND = gr.const(1) IBOUND[:, :, 0] = -1 # head in top confining unit fixed k = gr.const(np.array([0.01, 10., 0.01, 20.])) FH = gr.const(0.) FQ = gr.const(0.) FQ[0, 0, 1] = Q # insecond layer # run flow model Out = fdm.fdm3(gr, (k, k, k), FQ, FH, IBOUND) Psi = fdm.psi(Out.Qx) #pdb.set_trace()