示例#1
0
def main(zGr, c, kD, S, t, rWell, zWell, Q):
    '''Run axial fdm model and return results.
    parameters
    ----------
        zGr : ndarray(nLay)
            z values of layer interfaces
        c : ndarray(naquitard)
            resistances [d] of aquitards
        kD : ndarray(naquifer)
            tranmissivities of aquifers
        S : ndarray(naquitard + naquifer)
            strorage coefficients of all aquitards and aquifers in order
        t : ndarray(nt)
            times when output is wanted
        rWell : float
            well radius
        zWell : tuple of 2 floats
            top and bottom of well screen
        Q : float
            if neg. extraction from screen of positive injection
    '''
    gr = grid(rWell, zGr)  # use default x and y coordinates
    kh, kv, ss = k_s(gr, c=c, kD=kD, S=S)
    FQ, Iw = get_FQ(gr, z=zWell, Q=Q, kh=kh)
    HI = gr.const(0.)
    IBOUND = gr.const(1, dtype=int)
    IBOUND[0] = -1

    kh.ravel()[Iw] = 1000.  # hard wired, gravel pack
    if np.all(IBOUND[0] == -1):
        kv[0] /= 2.0  # top layer resistance with centered heads

    kwargs = {
        'gr': gr,
        't': t,
        'kxyz': (kh, kh, kv),
        'Ss': ss,
        'FQ': FQ,
        'HI': HI,
        'IBOUND': IBOUND,
        'epsilon': 1.0
    }

    return fdm3t.fdm3t(**kwargs)
示例#2
0
文件: ptest.py 项目: yon23/tools
    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)
示例#3
0
文件: ptest.py 项目: yon23/tools
    def __init__(self,
                 gr=None,
                 kD=None,
                 c=None,
                 S=None,
                 top_aquitard=False,
                 t=None,
                 Q=None,
                 obswells=None,
                 **kwargs):
        '''Create a Pumptest object and simulate it with fdm and hantushn.

        'rw and R are assumed to be gr.x[0] and gr.x[-1]

        parameters
        ----------
            kD : sequence of floats
                transmissivities of aquifers [L2/T]
            S  : tuple (Saq, Sat) | sequence Saq
                Saq : squence of floats
                    storage coefficients of aquifers
                Sat : sequence of floats
                    storage coefficients of aquitards
                if not a tuplbe with two sequences of floats, then
                S is assumed Saq for aquifers with all Sat = 0
            c  : sequence of floats
                hydraulic resistances of aquitards [T]
            top_aquitard : bool
                whether top layer is an aquitard
            t : sequence of floats
                times to compute heads
            Q : sequence fo floats
                discharge from each aquifier
        '''

        gr.axial = True
        self.t = np.array(t)
        self.Q = np.array(Q)
        self.gr = gr
        self.gr.Axial = True
        self.top_aquitard = top_aquitard

        assert self.gr.nz == len(kD) + len(c),\
            "len(kD) <{}> + len(c) <{}> != gr.nz <{}>"\
            .format(len(kD), len(c), gr.nz)
        if isinstance(S, tuple):
            assert len(kD) == len(S[0]),\
                'len(kD) <{}> != len(S[0]) <{}>'.format(len(kD), len(S[0]))
            assert len(c)  == len(S[1]),\
                'len(c) <{}> != len(S[[1]) <{}>'.format(len(c), len(S[1]))
        else:  # if not a sequence, then S is Saq
            assert len(kD) == len(S),\
                "len(kD) <{}> != len(S) <{}>".format(len(kD), len(S))

        if len(c) > len(kD):
            top_aquitard = True

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

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

        self.iatard = np.logical_not(self.iaquif)

        # conductivities
        kh = np.zeros(self.gr.nz)
        kh[self.iaquif] = np.array(kD) / self.gr.dz[self.iaquif]
        kv = np.ones(self.gr.nz) * 1e6  # just large
        kv[self.iatard] = self.gr.dz[self.iatard] / np.array(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

        # aquitards and aquifers can both have storage
        ss = np.zeros(self.gr.nz)
        if isinstance(S, tuple):
            Saq = S[0]
            Sat = S[1]
            assert len(Saq) == len(kD), 'len(Saq) <{}> != len(kD)<{}>'\
                .format(len(Saq), len(kD))
            assert len(Sat) == len(c), 'len(Sat) <{}> != len(kD) <{}>'\
                .format(len(Sat), len(kD))
            ss[self.iaquif] = Saq / self.gr.dz[self.iaquif]
            ss[self.iatard] = Sat / self.gr.dz[self.iatard]
        else:  # S applies to only aquifers
            Saq = S
            Sat = np.zeros_like(c)
            assert len(Saq) == len(S), 'len(Saq) <{}> != len(kD) <{}>'\
                .format(len(Saq), len(kD))
            ss[self.iaquif] = S / self.gr.dz[self.iaquif]

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

        # Make sure t starts at zero to include initial heads.
        self.t = np.unique(np.hstack((0., np.array(t))))
        assert np.all(t) >= 0, "All times must be > zero."

        # Discharge must be given for each aquifer
        assert len(Q) == len(kD), "len(Q) <{}> != len(kD) <{}>," +\
                    "specify a discharge for each aqufier."\
                    .format(len(Q), len(kD))

        # Boundary and initial conditions
        self.FQ = self.gr.const(0)
        self.FQ[self.iaquif, 0, 0] = self.Q

        # Initial condition all heads zero (always in pumping test)
        self.HI = self.gr.const(0.)

        # Boundary array (Modflow-like)
        self.IBOUND = self.gr.const(1, dtype=int)
        # Only prescribe heads to be fixed if aquitard on top and or bottom
        # Just make sure that the radius of the model is large enough.

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

        # Simulate using FDM
        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)

        # Also compute Hantush. Hantush computes at observation distances.
        # For this we need the observation points
        self.names = list()
        self.r_ow = list()
        self.z_ow = list()
        assert obswells is not None, "obswells == None, specify obswells as [(name, r, z), ..]"
        for ow in obswells:
            self.names.append(ow[0])
            self.r_ow.append(ow[1])
            self.z_ow.append(ow[2])

        # store layer nr of each obswell
        self.layNr = self.gr.lrc(self.r_ow, np.zeros(len(self.r_ow)),
                                 self.z_ow)[:, 0]
        # get and store aquifer number of each obswell
        aqNr = np.zeros(self.gr.nz, dtype=int) - 1
        k = 0
        for i, ia in enumerate(self.iaquif):
            if ia:
                aqNr[i] = k
                k += 1
        self.aqNr = aqNr[self.layNr]
        assert np.all(self.aqNr) > -1, "one or more obswells not in aquifer"

        self.dd = hantushn(Q=self.Q,
                           r=self.r_ow,
                           t=self.t[1:],
                           Saq=Saq,
                           Sat=Sat,
                           c=c,
                           T=kD,
                           N=8)
示例#4
0
# specify observation points [(anme, r, iaquifer), ...]
points = [('well',    0.5*(rwell[0] + rwell[1]), -40.),
          ('TT-001 ',   1., -40.),
          ('TT-050' ,  50., -40.),
          ('TT-070' ,  70., -40.),
          ('TT-120' , 120., -40.),
          ('TT-175' , 175., -40.),
          ('TT-350' , 350., -40.),
          ('TT-700' , 700., -40.),
          ('TO-001',    1., -50.),
          ('TO-050',   50., -50.),
          ('TO-080',   70., -50.),
          ('TO-120',  120., -50.),
          ('TO-175',  175., -50.),
          ('TO-350',  350., -50.),
          ('TO-700',  700., -50.),
          ('BO-001',   1.,  -15.)]

points = [points[i] for i in [0, 1, 2, 8]]

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


show(gr, t, out, points, xscale='log', grid=True)


C = contour(gr, out, dphi=0.25, dpsi=10, xlim=(0, 150))
示例#5
0
文件: hantushn.py 项目: yon23/tools
def compare_hant_fdm(aqSys, obsWells, t=None, Q=None, epsilon=1.0, **kwargs):
    '''Compare hantushn vor r's and all t with fdm3t
    obsWells : dictionarary with keyys ['name', 'r', 'layer')

    Input prerequisites
    aqSys : Aquifer_system
    epsilon : float
        implicitness, use value between 0.5 to 1 (Modflow uses 1.0)
    '''

    N = kwargs.pop('N', 10)

    # simulate analytically using Hantushn
    dd = hantushn(Q=Q,
                  r=obsWells.r,
                  t=t,
                  Sat=aqSys.Sat,
                  Saq=aqSys.Saq,
                  c=aqSys.c,
                  T=aqSys.kD,
                  N=N)

    dd = dd[:, obsWells.aquifer, np.arange(dd.shape[-1], dtype=int)]

    # simulate numerically using fdm3t
    FQ = aqSys.gr.const(0.)
    FQ[1::2, 0, 0] = Q

    HI = aqSys.gr.const(0.)

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

    Kh = aqSys.gr.const(aqSys.kh)
    Kv = aqSys.gr.const(aqSys.kv)
    Ss = aqSys.gr.const(aqSys.Ss)

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

    phi = out['Phi'][:, :, 0, :]  # squeeze y (axis 2)

    # interpolator
    interpolator = interp1d(aqSys.gr.xm, phi, axis=2)

    phi = interpolator(obsWells.r)  # shape [Nt, Nz, len(obsWells)]

    # select using fancy indexing for last two axes
    phi = phi[:, obsWells.layer, np.arange(phi.shape[-1])]

    # plot the results of both Hantush and fdm3t
    ax = kwargs.pop('ax', None)
    if ax is None:
        fig, ax = plt.subplots()
        ax.set_title(
            kwargs.pop('title',
                       'Hantushn versus fdm3 for a set of observatio points'))
        ax.set_xlabel(kwargs.pop('xlabel', 't [d]'))
        ax.set_ylabel(kwargs.pop('ylabel', 's [m]'))
        ax.set_xscale(kwargs.pop('xscale', 'log'))
        ax.set_yscale(kwargs.pop('yscale', 'linear'))
        ax.grid(True)

    xlim = kwargs.pop('xlim', None)
    ylim = kwargs.pop('ylim', None)

    if xlim is not None: ax.set_xlim(xlim)
    if ylim is not None: ax.set_ylim(ylim)

    for i, name in enumerate(obsWells.names):
        ax.plot(t,
                phi[:, i],
                label='fdm ' + name,
                color=colors[i],
                ls='-',
                lw=2)
        ax.plot(t, dd[:, i], label='han ' + name, color=colors[i], ls='--')
    ax.legend(loc='best')

    return ax