Пример #1
0
    def __init__(self,
                 z=None,
                 c=None,
                 kD=None,
                 Sat=None,
                 Saq=None,
                 rw=0.1,
                 R=1e4,
                 top_aquitard=True):

        r = np.logspace(np.log10(rw), np.log10(R),
                        int(10 * np.ceil(np.log10(R / rw)) + 1))

        self.gr = Grid(r, [-0.5, 0.5], np.array(z), axial=True)

        self.top_aquitard = top_aquitard
        self.bot_aquitard =\
            (     self.top_aquitard  and len(c) > len(kD)  ) or\
            ((not self.top_aquitard) and len(c) == len(kD) )

        assert self.gr.nz == len(c) + len(kD), 'nz != len(c) + len(kD)'
        assert self.gr.nz == len(Sat) + len(Saq), 'nz = len(Sat)  + len(Saq)'

        self.c = np.array(c)
        self.kD = np.array(kD)
        self.Sat = np.array(Sat)
        self.Saq = np.array(Saq)

        self.kh = np.zeros(self.gr.nz)
        self.kv = np.zeros(self.gr.nz)
        if self.top_aquitard:
            self.kv[::2] = self.gr.dz[::2] / c
            self.kh[::2] = 0.
            self.kh[1::2] = self.kD / self.gr.dz[1::2]
            self.kv[1::2] = np.inf
        else:
            self.kh[::2] = self.kD / self.gr.dz[::2]
            self.kv[::2] = np.inf
            self.kv[1::2] = self.gr.dz[1::2] / c
            self.kh[1::2] = 0.
        if self.top_aquitard: self.kv[0] *= 0.5
        if self.bot_aquitard: self.kv[-1] *= 0.5

        self.iaquif = np.ones(self.gr.nz, dtype=bool)
        if self.top_aquitard:
            self.iaquif[::2] = False
        else:
            self.iaquif[1::2] = False
        self.iatard = np.logical_not(self.iaquif)

        self.Ss = np.zeros(self.gr.nz)
        self.Ss[self.iaquif] = self.Saq / self.gr.dz[self.iaquif]
        self.Ss[self.iatard] = self.Sat / self.gr.dz[self.iatard]
Пример #2
0
#%% Grid

z = [layer[0]['ztop']]
kh = []
kv = []
ss = []
for i in range(len(layer)):
    z.append(layer[i]['zbot'])
    kh.append(layer[i]['kh'])
    kv.append(layer[i]['kv'])
    ss.append(layer[i]['ss'])

y = [-0.5, 0.5]
r = np.hstack((0, *rwell, *rwand, np.logspace(0, 4, 101)))
gr = Grid(r, y, z, axial=True)

wand = np.zeros(gr.shape, dtype=bool)
wand[AND(AND(AND(gr.XM > rwand[0], gr.XM < rwand[1]), gr.ZM < zwand[0]),
         gr.ZM > zwand[1])] = True

well = np.zeros(gr.shape, dtype=bool)
well[AND(AND(AND(gr.XM > rwell[0], gr.XM < rwell[1]), gr.ZM < zwell[0]),
         gr.ZM > zwell[1])] = True

vloer = np.zeros(gr.shape, dtype=bool)
vloer[AND(gr.XM < rwand[0], gr.ZM > -21.9)] = True

#%% parameters
Kh = gr.const(np.array(kh))
Kh[wand] = kwand
Пример #3
0
    def __init__(self, mluxmlfile, tshift=0, Rmax=1e4, **kwargs):
        '''Return MLUtest, pumping test results based on mlu file.

        parameters
        ----------
            tshift : float
                Delay imposed on measurement time (pump upstart delay)
            Rmax: float
                Duter radius of model where head is fixed.

        kwargs
        ------
            Rw : float
                Well radius (not in mlu file) if None, use 2 * screen of well
        '''

        mlu = Mluobj(mluxmlfile)
        aqSys = mlu.aqSys
        self.obswells = mlu.obsWells

        nz = len(aqSys.aquifs) + len(aqSys.atards)
        self.iaquif = np.ones(nz, dtype=bool)
        self.top_aquitard = aqSys.top_aquitard != 'absent'
        if self.top_aquitard:
            self.iaquif[::2] = False
        else:
            self.iaquif[1::2] = False
        self.iatard = np.logical_not(self.iaquif)

        rmin = kwargs.pop('Rw', 2 * mlu.wells[0].screen)

        # Piezometer data from xml file
        tmax = 0
        tmin = np.inf
        x0, y0 = mlu.wells[0].x, mlu.wells[0].y
        r = rmin
        rmax = rmin
        self.names = list()
        self.points = list()
        self.ow_aquif = list()

        for ow in mlu.obsWells:
            self.names.append(ow.name)
            r = max(rmin, np.sqrt((x0 - ow.x)**2 + (y0 - ow.y)**2))
            rmax = max(rmax, r)
            tmin = min(tmin, ow.data[0, 0])
            tmax = max(tmax, ow.data[-1, 0])
            self.ow_aquif.append(ow.layer - 1)
            self.points.append((r, mlu.aqSys.aquifs[ow.layer - 1].zmid))

        # attribute discharge over screened aquifers
        Qs = np.zeros(len(mlu.aqSys.aquifs))
        kDtot = 0.
        for iaq, (screened,
                  aq) in enumerate(zip(mlu.wells[0].screens,
                                       mlu.aqSys.aquifs)):
            if screened == '1':
                kDtot += aq.T
                Qs[iaq] = aq.T
        Qs *= mlu.wells[0].Q / kDtot

        # radial grid, general max r.
        r = np.hstack(
            (0,
             np.logspace(np.log10(rmin), np.log10(Rmax),
                         int(10 * np.ceil(np.log10(Rmax / rmin)) + 1))))

        zf = np.array([(aquif.ztop, aquif.zbot) for aquif in aqSys.aquifs])
        za = np.array([(atard.ztop, atard.zbot) for atard in aqSys.atards])
        z = np.unique(np.hstack((zf[:, 0], zf[:, 1], za[:, 0], za[:, 1])))

        self.gr = Grid(r, [-0.5, 0.5], z, axial=True)

        # sufficiently detailed times for graphs
        self.t = np.logspace(np.log10(tmin), np.log10(tmax), 60)
        self.t = np.unique(np.hstack((0., self.t)))  # start at 0

        # conductivities
        kD = np.array([aq.T for aq in aqSys.aquifs])
        c = np.array([at.c for at in aqSys.atards])
        kh = np.zeros(self.gr.nz)
        kh[self.iaquif] = kD / self.gr.dz[self.iaquif]
        kv = np.ones(self.gr.nz) * 1e6  # just large
        kv[self.iatard] = self.gr.dz[self.iatard] / c

        if self.iatard[0]: kv[0] /= 2.
        if self.iatard[-1]: kv[-1] /= 2.

        self.Kh = self.gr.const(kh)
        self.Kv = self.gr.const(kv)

        self.Kh[self.iaquif, :, 0] = 100.  # no resistance inside well

        # storativities (both aquitards and aquifers)
        Saq = np.array([aq.S for aq in aqSys.aquifs])
        Sat = np.array([at.S for at in aqSys.atards])
        ss = np.zeros(self.gr.nz)
        ss[self.iaquif] = Saq / self.gr.dz[self.iaquif]
        ss[self.iatard] = Sat / self.gr.dz[self.iatard]

        self.Ss = self.gr.const(ss)

        kd_tot = 0.
        kd = np.zeros_like(kD)
        for i, scr in enumerate(mlu.wells[0].screens):
            if scr == '1':
                kd[i] = kD[i]
                kd_tot += kD[i]
        self.Q = mlu.wells[0].Q * kd / kd_tot

        self.FQ = self.gr.const(0)
        self.FQ[self.iaquif, 0, 0] = self.Q
        self.HI = self.gr.const(0.)

        self.IBOUND = self.gr.const(1, dtype=int)
        self.IBOUND[:, :, -1] = -1

        if self.iatard[0]: self.IBOUND[0] = -1
        if self.iatard[-1]: self.IBOUND[-1] = -1

        # TODO: verify that the inflow over the outer boundary is < 5% or so.

        self.out = fdm3t(gr=self.gr,
                         t=self.t,
                         kxyz=(self.Kh, self.Kh, self.Kv),
                         Ss=self.Ss,
                         FQ=self.FQ,
                         HI=self.HI,
                         IBOUND=self.IBOUND,
                         epsilon=1.0)

        ax = mlu.plot_drawdown(mlu.obsNames,
                               tshift=tshift,
                               marker='.',
                               linestyle='none',
                               **kwargs)

        #hantush(...)
        r = np.array(self.points)[:, 0]
        self.dd = hantushn(Q=self.Q,
                           r=r,
                           t=self.t[1:],
                           Saq=Saq,
                           Sat=Sat,
                           c=c,
                           T=kD,
                           N=8)

        self.show(xscale='log', ax=ax, labels=self.names)
Пример #4
0
class MLU_ptest:
    def __init__(self, mluxmlfile, tshift=0, Rmax=1e4, **kwargs):
        '''Return MLUtest, pumping test results based on mlu file.

        parameters
        ----------
            tshift : float
                Delay imposed on measurement time (pump upstart delay)
            Rmax: float
                Duter radius of model where head is fixed.

        kwargs
        ------
            Rw : float
                Well radius (not in mlu file) if None, use 2 * screen of well
        '''

        mlu = Mluobj(mluxmlfile)
        aqSys = mlu.aqSys
        self.obswells = mlu.obsWells

        nz = len(aqSys.aquifs) + len(aqSys.atards)
        self.iaquif = np.ones(nz, dtype=bool)
        self.top_aquitard = aqSys.top_aquitard != 'absent'
        if self.top_aquitard:
            self.iaquif[::2] = False
        else:
            self.iaquif[1::2] = False
        self.iatard = np.logical_not(self.iaquif)

        rmin = kwargs.pop('Rw', 2 * mlu.wells[0].screen)

        # Piezometer data from xml file
        tmax = 0
        tmin = np.inf
        x0, y0 = mlu.wells[0].x, mlu.wells[0].y
        r = rmin
        rmax = rmin
        self.names = list()
        self.points = list()
        self.ow_aquif = list()

        for ow in mlu.obsWells:
            self.names.append(ow.name)
            r = max(rmin, np.sqrt((x0 - ow.x)**2 + (y0 - ow.y)**2))
            rmax = max(rmax, r)
            tmin = min(tmin, ow.data[0, 0])
            tmax = max(tmax, ow.data[-1, 0])
            self.ow_aquif.append(ow.layer - 1)
            self.points.append((r, mlu.aqSys.aquifs[ow.layer - 1].zmid))

        # attribute discharge over screened aquifers
        Qs = np.zeros(len(mlu.aqSys.aquifs))
        kDtot = 0.
        for iaq, (screened,
                  aq) in enumerate(zip(mlu.wells[0].screens,
                                       mlu.aqSys.aquifs)):
            if screened == '1':
                kDtot += aq.T
                Qs[iaq] = aq.T
        Qs *= mlu.wells[0].Q / kDtot

        # radial grid, general max r.
        r = np.hstack(
            (0,
             np.logspace(np.log10(rmin), np.log10(Rmax),
                         int(10 * np.ceil(np.log10(Rmax / rmin)) + 1))))

        zf = np.array([(aquif.ztop, aquif.zbot) for aquif in aqSys.aquifs])
        za = np.array([(atard.ztop, atard.zbot) for atard in aqSys.atards])
        z = np.unique(np.hstack((zf[:, 0], zf[:, 1], za[:, 0], za[:, 1])))

        self.gr = Grid(r, [-0.5, 0.5], z, axial=True)

        # sufficiently detailed times for graphs
        self.t = np.logspace(np.log10(tmin), np.log10(tmax), 60)
        self.t = np.unique(np.hstack((0., self.t)))  # start at 0

        # conductivities
        kD = np.array([aq.T for aq in aqSys.aquifs])
        c = np.array([at.c for at in aqSys.atards])
        kh = np.zeros(self.gr.nz)
        kh[self.iaquif] = kD / self.gr.dz[self.iaquif]
        kv = np.ones(self.gr.nz) * 1e6  # just large
        kv[self.iatard] = self.gr.dz[self.iatard] / c

        if self.iatard[0]: kv[0] /= 2.
        if self.iatard[-1]: kv[-1] /= 2.

        self.Kh = self.gr.const(kh)
        self.Kv = self.gr.const(kv)

        self.Kh[self.iaquif, :, 0] = 100.  # no resistance inside well

        # storativities (both aquitards and aquifers)
        Saq = np.array([aq.S for aq in aqSys.aquifs])
        Sat = np.array([at.S for at in aqSys.atards])
        ss = np.zeros(self.gr.nz)
        ss[self.iaquif] = Saq / self.gr.dz[self.iaquif]
        ss[self.iatard] = Sat / self.gr.dz[self.iatard]

        self.Ss = self.gr.const(ss)

        kd_tot = 0.
        kd = np.zeros_like(kD)
        for i, scr in enumerate(mlu.wells[0].screens):
            if scr == '1':
                kd[i] = kD[i]
                kd_tot += kD[i]
        self.Q = mlu.wells[0].Q * kd / kd_tot

        self.FQ = self.gr.const(0)
        self.FQ[self.iaquif, 0, 0] = self.Q
        self.HI = self.gr.const(0.)

        self.IBOUND = self.gr.const(1, dtype=int)
        self.IBOUND[:, :, -1] = -1

        if self.iatard[0]: self.IBOUND[0] = -1
        if self.iatard[-1]: self.IBOUND[-1] = -1

        # TODO: verify that the inflow over the outer boundary is < 5% or so.

        self.out = fdm3t(gr=self.gr,
                         t=self.t,
                         kxyz=(self.Kh, self.Kh, self.Kv),
                         Ss=self.Ss,
                         FQ=self.FQ,
                         HI=self.HI,
                         IBOUND=self.IBOUND,
                         epsilon=1.0)

        ax = mlu.plot_drawdown(mlu.obsNames,
                               tshift=tshift,
                               marker='.',
                               linestyle='none',
                               **kwargs)

        #hantush(...)
        r = np.array(self.points)[:, 0]
        self.dd = hantushn(Q=self.Q,
                           r=r,
                           t=self.t[1:],
                           Saq=Saq,
                           Sat=Sat,
                           c=c,
                           T=kD,
                           N=8)

        self.show(xscale='log', ax=ax, labels=self.names)

    def show(self, **kwargs):

        #points should be r, z tuples
        rz = np.array(self.points)
        if rz.shape[1] == 2:
            rz = np.hstack((rz[:, 0:1], np.zeros((rz.shape[0], 1)), rz[:,
                                                                       1:2]))

        LRC = self.gr.lrc(rz[:, 0], rz[:, 1], rz[:, -1])

        # squeeze out axis 2 (y)
        interpolator = interp1d(self.gr.xm,
                                self.out['Phi'][:, :, 0, :],
                                axis=2)

        # interpolate for all obswells at once along r-axis
        phi_t = interpolator(rz[:, 0])

        # fancy indexing to select the correct col-row (r-z) combinations
        Ipnt = np.arange(phi_t.shape[-1], dtype=int)
        phi_t = phi_t[:, LRC[:, 0], Ipnt]

        # Add Hantushn points
        aqNr = np.array(self.ow_aquif)
        ddHant = self.dd[:, aqNr, np.arange(self.dd.shape[-1], dtype=int)]

        ax = kwargs.pop('ax', None)
        if ax is None:
            fig, ax = plt.subplots()
            ax.set_title('Ptest testing')
            ax.set_xlabel('t [d]')
            ax.set_ylabel('drawdown [m]')
            ax.grid(True)
            ax.invert_yaxis()

        xscale = kwargs.pop('xscale', None)
        yscale = kwargs.pop('yscale', None)
        grid = kwargs.pop('grid', None)

        if xscale: ax.set_xscale(xscale)
        if yscale: ax.set_yscale(yscale)
        if grid: ax.grid(grid)

        labels = kwargs.pop('labels', [''] * phi_t.shape[1])

        # plot fdm3t lines
        for fi, label, color in zip(phi_t.T, labels, colors):
            ax.plot(self.t[1:],
                    fi[1:],
                    color=color,
                    label=label + ' fdm',
                    ls='--',
                    marker='+',
                    **kwargs)

        # plot hantush lines
        for fi, label, color in zip(ddHant.T, labels, colors):
            ax.plot(self.t[1:],
                    fi,
                    color=color,
                    label=label + ' anal',
                    lw=2,
                    **kwargs)

        ax.legend(loc='best')

        return ax
Пример #5
0
    mptest = MLU_ptest(xml_file, Rw=0.13, tshift=0.)

    #%% from ground up: =gat_boomse_klei using ptest ==========================

    # Firstly define the grid
    Rw = 0.13  # m, well borehole radius
    Rmax = 10000.  # m, extent of model (should be large enough)

    r = np.hstack((0,
                   np.logspace(np.log10(Rw), np.log10(Rmax),
                               int(np.ceil(10 * np.log10(Rmax / Rw) + 1)))))

    dz = np.array(
        [9., 16., 0.01, 3.79, 3.7, 1., 3.7, 1., 3.8, 1., 1.3, 5., 3.4, 6.3])
    z = np.hstack((0, -np.cumsum(dz)))
    gr = Grid(r, [-0.5, 0.5], z, axial=True)

    # Set soil parameters
    kD = np.array([48, 11.37, 0.13, 0.15, 0.16, 0.75, 31.5])
    c = np.array([1500, 1.e-2, 2.85, 12.3, 76., 26., 56.7])
    Sat = np.array([
        0.,
        0.,
        0.,
        0.,
        0.,
        0.,
        0.,
    ])
    Saq = np.array([1.e-04, 1.e-4, 1.e-5, 1.e-5, 1.e-5, 1.e-5, 1.e-5])
    top_aquitard = True  # whether the top layer is a top aquitard
Пример #6
0

top_aquitad = True

kwand = 1e-3  # m/d
rwand = (64.95, 65.05)
zwand = (0., -45.)
rwell = (rwand[0] - 0.5, rwand[0])
zwell = (-36., -42. )
hwell = -20.
#      c1  kD1   c2    kD2   c3    kD3   c4  kD4
z = [0, -2., -22., -36., -42, -42.5, -45, -50, -60]
y = [ -0.5, 0.5]
r = np.hstack((0, *rwell, rwand[0], rwand[1], *rwand, np.logspace(0, 4, 101)))

gr = Grid(r, y, z, axial=True)

wand = np.zeros(gr.shape, dtype=bool)
wand[AND( AND( AND(gr.XM > rwand[0], gr.XM < rwand[1]),
                    gr.ZM < zwand[0]),
                    gr.ZM > zwand[1])] = True

well = np.zeros(gr.shape, dtype=bool)
well[AND( AND( AND(gr.XM > rwell[0], gr.XM < rwell[1]),
                    gr.ZM < zwell[0]),
                    gr.ZM > zwell[1])] = True

vloer = np.zeros(gr.shape, dtype=bool)
vloer[AND(gr.XM < rwand[0], gr.ZM > -22)] = True

Пример #7
0
    east = np.hstack((np.zeros((gr.ny, 1), dtype=bool), west[:,:-1]))
    north= np.vstack((south[1:,:], np.zeros((1, gr.nx), dtype=bool)))

    pairs = np.array([np.hstack((gr.NOD[0][west], gr.NOD[0][north])),
                      np.hstack((gr.NOD[0][east], gr.NOD[0][south]))]).T

    return pairs

if __name__ == '__main__':

    x = np.linspace(-100., 100., 21)
    y = np.linspace(-100., 100., 21)
    z = [0, -10, -20]

    gr = Grid(x, y, z)

    polygon = np.array([(23, 15), (45, 50.), (10., 81.), (-5., 78), (-61., 51.), (-31., 11.),
               (-6., -4.), (-42., -20.), (-50., -63.), (-7., -95.),
               (31., -80.), (60., -71.), (81., -31.), (5., -63.), (25., -15.), (95., 40.),
               (23, 15)])

    pairs = cell_pairs(gr, polygon)


    fig, ax = plt.subplots()
    ax.set_title('Node pairs for the hor. flow-barrier package of Modflow')
    ax.set_xlabel('x [m]')
    ax.set_ylabel('y [m]')
    gr.plot_grid(world=False, ax=ax)
    ax.plot(polygon[:,0], polygon[:,1])