示例#1
0
    def __init__(self,
                 pgen,
                 pcpy,
                 ptop,
                 soildata,
                 gisdata,
                 cpy_outputs=False,
                 bu_outputs=False,
                 top_outputs=False,
                 flatten=True):

        self.dt = pgen['dt']  # s
        self.id = pgen['catchment_id']
        self.spinup_end = pgen['spinup_end']
        self.pgen = pgen
        self.step_nr = 0
        self.ncf_file = pgen['ncf_file']

        self.GisData = gisdata
        self.cmask = self.GisData['cmask']
        self.gridshape = np.shape(self.cmask)
        cmask = self.cmask.copy()

        flowacc = gisdata['flowacc'].copy()
        slope = gisdata['slope'].copy()
        """
        flatten=True omits cells outside catchment
        """
        if flatten:
            ix = np.where(np.isfinite(cmask))
            cmask = cmask[ix].copy()
            flowacc = flowacc[ix].copy()
            slope = slope[ix].copy()

            for key in pcpy['state']:
                pcpy['state'][key] = pcpy['state'][key][ix].copy()

            for key in soildata:
                soildata[key] = soildata[key][ix].copy()

            self.ix = ix  # indices to locate back to 2d grid
        """--- initialize CanopyGrid ---"""
        self.cpy = CanopyGrid(pcpy, pcpy['state'], outputs=cpy_outputs)
        """--- initialize BucketGrid ---"""
        self.bu = BucketGrid(spara=soildata, outputs=bu_outputs)
        """ --- initialize Topmodel --- """
        self.top = Topmodel(ptop,
                            self.GisData['cellsize']**2,
                            cmask,
                            flowacc,
                            slope,
                            outputs=top_outputs)
示例#2
0
    def __init__(self,
                 pgen,
                 pcpy,
                 pbu,
                 FORC,
                 cmask=np.ones(1),
                 cpy_outputs=True,
                 bu_outputs=True):
        """
        creates SpaFHy_point -object
        Args:
            pgen - parameter dict
            pcpy - canopy parameter dict
            pbu - bucket model parameter dict
            FORC - forcing data (pd.DataFrame)
            cmask - catchment mask; in case multiple cells are simulated. np.array
            cpy_outputs - saves canopy outputs within self.cpy.results
            bu_outputs - saves bucket outputs within self.cpy.results
        Returns:
            object
        """
        self.dt = pgen['dt']  # s
        self.id = pgen['catchment_id']
        self.spinup_end = pgen['spinup_end']
        self.pgen = pgen

        self.FORC = FORC
        self.Nsteps = len(self.FORC)
        """--- initialize CanopyGrid and BucketGrid ---"""

        # sub-models require states as np.array; so multiply with 'cmask'
        cstate = pcpy['state'].copy()

        for key in cstate.keys():
            cstate[key] *= cmask

        self.cpy = CanopyGrid(pcpy, cstate, outputs=cpy_outputs)

        for key in pbu.keys():
            pbu[key] *= cmask

        self.bu = BucketGrid(pbu, outputs=bu_outputs)
示例#3
0
class SpaFHy():
    """
    SpaFHy model class
    """
    def __init__(self, pgen, pcpy, ptop, soildata, gisdata, cpy_outputs=False,
                 bu_outputs=False, top_outputs=False, flatten=False):

        self.dt = pgen['dt']  # s
        self.id = pgen['catchment_id']
        self.spinup_end = pgen['spinup_end']
        self.pgen = pgen
        self.step_nr = 0
        self.ncf_file = pgen['ncf_file']

        self.GisData = gisdata
        self.cmask = self.GisData['cmask']
        self.gridshape = np.shape(self.cmask)
        cmask= self.cmask.copy()

        flowacc = gisdata['flowacc'].copy()
        slope = gisdata['slope'].copy()        
        
        """
        flatten=True omits cells outside catchment
        """
        if flatten:
            ix = np.where(np.isfinite(cmask))
            cmask = cmask[ix].copy()
            # sdata = sdata[ix].copy()
            flowacc = flowacc[ix].copy()
            slope = slope[ix].copy()
            
            for key in pcpy['state']:
                pcpy['state'][key] = pcpy['state'][key][ix].copy()
                        
            for key in soildata:
                soildata[key] = soildata[key][ix].copy()
                
            self.ix = ix  # indices to locate back to 2d grid

        """--- initialize CanopyGrid ---"""
        self.cpy = CanopyGrid(pcpy, pcpy['state'], outputs=cpy_outputs)

        """--- initialize BucketGrid ---"""
        self.bu = BucketGrid(spara=soildata, outputs=bu_outputs)

        """ --- initialize Topmodel --- """
        self.top=Topmodel(ptop, self.GisData['cellsize']**2, cmask,
                          flowacc, slope, outputs=top_outputs)

    def run_timestep(self, forc, ncf=False, flx=False, ave_flx=False):
        """ 
        Runs SpaFHy for one timestep starting from current state
        Args:
            forc - dictionary or pd.DataFrame containing forcing values for the timestep
            ncf - netCDF -file handle, for outputs
            flx - returns flux and state grids to caller as dict
            ave_flx - returns averaged fluxes and states to caller as dict
        Returns:
            optional
        """
        doy = forc['doy']
        ta = forc['T']
        vpd = forc['VPD'] + eps
        rg = forc['Rg']
        par = forc['Par'] + eps
        prec = forc['Prec']
        co2 = forc['CO2']
        u = forc['U'] + eps

        # run Topmodel
        # catchment average ground water recharge [m per unit area]
        RR = self.bu._drainage_to_gw * self.top.CellArea / self.top.CatchmentArea
        qb, _, qr, fsat = self.top.run_timestep(RR)

        # run CanopyGrid
        potinf, trfall, interc, evap, et, transpi, efloor, mbe = \
            self.cpy.run_timestep(doy, self.dt, ta, prec, rg, par, vpd, U=u, CO2=co2,
                                  beta=self.bu.Ree, Rew=self.bu.Rew, P=101300.0)

        # run BucketGrid water balance
        infi, infi_ex, drain, tr, eva, mbes = self.bu.watbal(dt=self.dt, rr=1e-3*potinf, tr=1e-3*transpi,
                                                       evap=1e-3*efloor, retflow=qr)

        # catchment average [m per unit area] saturation excess --> goes to stream
        # as surface runoff
        qs = np.nansum(infi_ex)*self.top.CellArea / self.top.CatchmentArea


        """ outputs """
        # updates state and returns results as dict
        if hasattr(self.top, 'results'):
            self.top.results['Qt'].append(qb + qs + eps)  # total runoff

        if ncf:
            # writes to netCDF -file at every timestep; bit slow - should
            # accumulate into temporary variables and save every 10 days? 
            # for netCDF output, must run in Flatten=True              
            k = self.step_nr
            
            # canopygrid
            ncf['cpy']['W'][k,:,:] = self._to_grid(self.cpy.W)
            ncf['cpy']['SWE'][k,:,:] = self._to_grid(self.cpy.SWE)
            ncf['cpy']['Trfall'][k,:,:] = self._to_grid(trfall) 
            ncf['cpy']['Potinf'][k,:,:] = self._to_grid(potinf)
            ncf['cpy']['ET'][k,:,:] = self._to_grid(et)
            ncf['cpy']['Transpi'][k,:,:] = self._to_grid(transpi)
            ncf['cpy']['Efloor'][k,:,:] = self._to_grid(efloor)            
            ncf['cpy']['Evap'][k,:,:] = self._to_grid(evap)
            ncf['cpy']['Inter'][k,:,:] = self._to_grid(interc)
            ncf['cpy']['Mbe'][k,:,:] = self._to_grid(mbe)              

            # bucketgrid
            ncf['bu']['Drain'][k,:,:] = self._to_grid(drain)
            ncf['bu']['Infil'][k,:,:] = self._to_grid(infi)
            ncf['bu']['Wliq'][k,:,:] = self._to_grid(self.bu.Wliq)
            ncf['bu']['Wliq_top'][k,:,:] = self._to_grid(self.bu.Wliq_top)            
            ncf['bu']['PondSto'][k,:,:] = self._to_grid(self.bu.PondSto)
            ncf['bu']['Mbe'][k,:,:] = self._to_grid(mbes)              

            # topmodel
            ncf['top']['Qb'][k] = qb
            ncf['top']['Qs'][k] = qs
            ncf['top']['Qt'][k] = qb + qs  # total runoff
            ncf['top']['R'][k] = RR
            ncf['top']['fsat'][k] = fsat
            ncf['top']['S'][k] = self.top.S
            ss = self.top.local_s(self.top.S)
            ss[ss < 0] = 0.0
            ncf['top']['Sloc'][k,:,:] = self._to_grid(ss)
            del ss

        # update step number
        self.step_nr += 1
        
        if flx:  # returns flux and state variables as grids
            flx = {'cpy': {'ET': et, 'Transpi': transpi, 'Evap': evap,
                           'Efloor': efloor, 'Inter': interc, 'Trfall': trfall,
                           'Potinf': potinf},
                   'bu': {'Infil': infi, 'Drain': drain},
                   'top': {'Qt': qb + qs, 'Qb': qb, 'Qs': qs, 'fsat': fsat}
                  }
            return flx        

        if ave_flx: # returns average fluxes and state variables
            flx = {
                    'ET': np.nanmean(et),
                    'E': np.nanmean(evap),
                    'Ef': np.nanmean(efloor),
                    'Tr': np.nanmean(transpi),
                    'SWE': np.nanmean(self.cpy.SWE),
                    'Drain': 1e3*RR,
                    'Qt': 1e3 * (qb + qs),
                    'S': self.top.S,
                    'fsat': fsat,
                    'Prec': prec * self.dt,
                    'Rg': rg,
                    'Ta': ta,
                    'VPD': vpd
                   }
            return flx
                         
    def _to_grid(self, x):
        """
        converts variable x back to original grid for NetCDF outputs
        """
        if self.ix:
            a = np.full(self.gridshape, np.NaN)
            a[self.ix] = x
        else: # for non-flattened, return
            a = x
        return a
示例#4
0
class SpaFHy_point():
    """
    SpaFHy for point-scale simulation. Couples Canopygrid and Bucketdrid -classes
    """
    def __init__(self,
                 pgen,
                 pcpy,
                 pbu,
                 FORC,
                 cmask=np.ones(1),
                 cpy_outputs=True,
                 bu_outputs=True):
        """
        creates SpaFHy_point -object
        Args:
            pgen - parameter dict
            pcpy - canopy parameter dict
            pbu - bucket model parameter dict
            FORC - forcing data (pd.DataFrame)
            cmask - catchment mask; in case multiple cells are simulated. np.array
            cpy_outputs - saves canopy outputs within self.cpy.results
            bu_outputs - saves bucket outputs within self.cpy.results
        Returns:
            object
        """
        self.dt = pgen['dt']  # s
        self.id = pgen['catchment_id']
        self.spinup_end = pgen['spinup_end']
        self.pgen = pgen

        self.FORC = FORC
        self.Nsteps = len(self.FORC)
        """--- initialize CanopyGrid and BucketGrid ---"""

        # sub-models require states as np.array; so multiply with 'cmask'
        cstate = pcpy['state'].copy()

        for key in cstate.keys():
            cstate[key] *= cmask

        self.cpy = CanopyGrid(pcpy, cstate, outputs=cpy_outputs)

        for key in pbu.keys():
            pbu[key] *= cmask

        self.bu = BucketGrid(pbu, outputs=bu_outputs)

    def _run(self, fstep, Nsteps, soil_feedbacks=True, results=False):
        """ 
        Runs SpaFHy_point
        IN:
            fstep - index of starting point [int]
            Nsteps - number of timesteps [int]
            soil_feedbacks - False sets REW and REE = 1 and ignores feedback 
                        from soil state to Transpi and Efloor
            results - True returns results dict
        OUT:
            updated state,  optionally saves results within self.cpy.results and
            self.bu.results and/or returns at each timestep as dict 'res'
        """
        dt = self.dt

        for k in range(fstep, fstep + Nsteps):
            print('k=' + str(k))

            # forcing
            doy = self.FORC['doy'].iloc[k]
            ta = self.FORC['T'].iloc[k]
            vpd = self.FORC['VPD'].iloc[k]
            rg = self.FORC['Rg'].iloc[k]
            par = self.FORC['Par'].iloc[k]
            prec = self.FORC['Prec'].iloc[k]
            co2 = self.FORC['CO2'].iloc[k]
            u = self.FORC['U'].iloc[k]
            if not np.isfinite(u):
                u = 2.0

            if soil_feedbacks:
                beta0 = self.bu.Ree  # affects surface evaporation
                rew0 = self.bu.Rew  # affects transpiration
            else:
                beta0 = 1.0
                rew0 = 1.0

            # run CanopyGrid
            potinf, trfall, interc, evap, et, transpi, efloor, mbe = \
                self.cpy.run_timestep(doy, dt, ta, prec, rg, par, vpd, U=u, CO2=co2,
                                      beta=beta0, Rew=rew0, P=101300.0)

            # run BucketGrid water balance
            infi, infi_ex, drain, tr, eva, mbes = self.bu.watbal(
                dt=dt,
                rr=1e-3 * potinf,
                tr=1e-3 * transpi,
                evap=1e-3 * efloor,
                retflow=0.0)

            if results == True:
                # returns fluxes and and state in dictionary
                res = {
                    'Wliq': self.bu.Wliq,
                    'Wliq_top': self.bu.Wliq_top,
                    'Evap': evap,
                    'Transpi': transpi,
                    'Efloor': efloor,
                    'Interc': interc,
                    'Drain': 1e3 * drain,
                    'Infil': 1e3 * infi,
                    'Qs': 1e3 * infi_ex
                }
                return res