def __call__(self, days=7): self.c.vegetation.LAI = 7 self.c.vegetation.height = 10 self.c.vegetation.CanopyClosure = 0.1 l = self.c.layers[0] self.c.surfacewater.depth = 0.05 l.soil.Ksat = 0.02 l.volume = 100 self.c.canopy.volume = self.c.vegetation.LAI * self.c.vegetation.CanopyCapacityPerLAI self.c.set_uptakestress(cmf.VolumeStress(10, 0)) Vc0 = self.c.canopy.volume Vl0 = self.c.layers[0].volume Vs0 = self.c.surfacewater.volume solver = cmf.CVodeIntegrator(self.p, 1e-9) vol = [] flux = [] resistance = [] mpot = [] self.et.refresh(cmf.Time()) for t in solver.run(cmf.Time(), cmf.day * days, cmf.min * 6): #print(f'{t}: {self.c.surfacewater.depth:0.3f}m') vol.append( (self.c.canopy.volume / Vc0, self.c.surfacewater.volume / Vs0, self.c.layers[0].volume / Vl0)) flux.append(( self.c.canopy.flux_to(self.c.evaporation, t), self.c.surfacewater.flux_to(self.c.evaporation, t), self.c.layers[0].flux_to(self.c.evaporation, t), self.c.layers[0].flux_to(self.c.transpiration, t), self.c.surfacewater.flux_to(self.c.layers[0], t), )) resistance.append((self.et.RAA, self.et.RAC, self.et.RAS, self.et.RSC, self.et.RSS)) mpot.append(self.c.surface_water_coverage()) return vol, flux, resistance, mpot
def solve(self, cmf_project, tolerance): """Solves the model""" # Create solver, set time and set up results solver = cmf.CVodeIntegrator(cmf_project, tolerance) solver.t = cmf.Time(1, 1, 2017) self.config_outputs(cmf_project) # Save initial conditions to results self.gather_results(cmf_project, solver.t) # Set timer start_time = datetime.now() step = 0 last = start_time # Run solver and save results at each time step for t in solver.run( solver.t, solver.t + timedelta(hours=self.solver_settings['analysis_length']), timedelta(hours=float(self.solver_settings['time_step']))): self.gather_results(cmf_project, t) last = self.print_solver_time(t, start_time, last, step) step += 1 self.solved = True return True
def runmodel(self, verbose=False): """ Runs the model and saves the results """ solver = cmf.CVodeIntegrator(self.project, 1e-9) c = self.project[0] # result timeseries res_q = cmf.timeseries(self.begin, cmf.day) tstart = datetime.datetime.now() # start solver and calculate in daily steps for t in solver.run(self.data.begin, self.end, cmf.day): if t > self.begin: # append results, when spin up time is over res_q.add(self.outlet.waterbalance(t)) # Give the status the screen to let us know what is going on if verbose: print(t, 'P={:5.3f}'.format(c.get_rainfall(t))) if datetime.datetime.now() - tstart > datetime.timedelta(minutes=self.max_run_minutes): print('Cancelled, since it took more than {} minutes'.format(self.max_run_minutes)) for t in cmf.timerange(solver.t, self.end, cmf.day): res_q.add(np.nan) return res_q
def run_model(self): """ Starts the model. Used by spotpy """ try: # Create a solver for differential equations solver = cmf.CVodeIntegrator(self.project, 1e-8) # New time series for model results resQ = cmf.timeseries(self.begin, cmf.day) # starts the solver and calculates the daily time steps end = self.end for t in solver.run(self.project.meteo_stations[0].T.begin, end, cmf.day): # Fill the results (first year is included but not used to # calculate the NS) if t >= self.begin: resQ.add(self.outlet.waterbalance(t)) return resQ # Return an nan - array when a runtime error occurs except RuntimeError: return np.array(self.Q[self.begin:self.end + datetime.timedelta(days=1)]) * np.nan
def __init__(self, par): cmf.set_parallel_threads(1) # run the model self.project = cmf.project() self.cell = self.project.NewCell(x=0, y=0, z=238.628, area=1000, with_surfacewater=True) c = self.cell r_curve = cmf.VanGenuchtenMualem(Ksat=10**par.pKsat, phi=par.porosity, alpha=par.alpha, n=par.n) # Make the layer boundaries and create soil layers lthickness = [.01] * 5 + [0.025] * 6 + [0.05] * 6 + [0.1] * 5 ldepth = np.cumsum(lthickness) # Create soil layers and pick the new soil layers if they are inside of the evaluation depth's for d in ldepth: c.add_layer(d, r_curve) # Use a Richards model c.install_connection(cmf.Richards) # Use shuttleworth wallace self.ET = c.install_connection(cmf.ShuttleworthWallace) c.saturated_depth = 0.5 self.gw = self.project.NewOutlet('groundwater', x=0, y=0, z=.9) cmf.Richards(c.layers[-1], self.gw) self.gw.potential = c.z - 0.5 #IMPORTANT self.gw.is_source = True self.gwhead = cmf.timeseries.from_scalar(c.z - 0.5) self.solver = cmf.CVodeIntegrator(self.project, 1e-9)
def canopyStorage(): import cmf import pylab as plt p = cmf.project() c = p.NewCell(0, 0, 0, 1000, True) # Add a single layer of 1 m depth l = c.add_layer(1.0, cmf.VanGenuchtenMualem()) # Use GreenAmpt infiltration from surface water c.install_connection(cmf.GreenAmptInfiltration) # Add a groundwater boundary condition gw = p.NewOutlet('gw', 0, 0, -2) # Use a free drainage connection to the groundwater cmf.FreeDrainagePercolation(l, gw) # Add some rainfall c.set_rainfall(5.0) # Make c.canopy a water storage c.add_storage('Canopy', 'C') # Split the rainfall from the rain source (RS) between # intercepted rainfall (RS->canopy) and throughfall (RS-surface) cmf.Rainfall(c.canopy, c, False, True) # RS->canopy, only intercepted rain cmf.Rainfall(c.surfacewater, c, True, False) # RS->surface, only throughfall # Use an overflow mechanism, eg. the famous Rutter-Interception Model cmf.RutterInterception(c.canopy, c.surfacewater, c) # And now the evaporation from the wet canopy (using a classical Penman equation) cmf.CanopyStorageEvaporation(c.canopy, c.evaporation, c) solver = cmf.CVodeIntegrator(p, 1e-9) res = [l.volume for t in solver.run(solver.t, solver.t + cmf.day, cmf.min * 15)] plt.figure() plt.plot(res) plt.show()
def run_model(self): """ Starts the model. Used by spotpy """ print("Start running model") try: # Create a solver for differential equations solver = cmf.CVodeIntegrator(self.project, 1e-9) solver.LinearSolver = 0 self.solver = solver # New time series for model results resQ = cmf.timeseries(self.begin, cmf.day) # starts the solver and calculates the daily time steps end = self.end # datetime.datetime(1979,1,7,9) tstart = time.time() tmax = 300 for t in solver.run(self.project.meteo_stations[0].T.begin, end, cmf.day): # Fill the results (first year is included but not used to # calculate the NS) print(t) if t >= self.begin: resQ.add(self.outlet.waterbalance(t)) if time.time() - tstart > tmax: raise RuntimeError( 'Took more than {:0.1f}min to run'.format(tmax / 60)) print("Finished running model") return resQ # Return an nan - array when a runtime error occurs except RuntimeError as error: print(error) print("FInished running model") return np.array(self.Q[self.begin:self.end + datetime.timedelta(days=1)]) * np.nan
def runmodel(self, verbose=False): """ starts the model if verboose = True --> give something out for every day """ try: # Creates a solver for the differential equations solver = cmf.CVodeIntegrator(self.project, 1e-8) solver.LinearSolver = 0 solver.max_step = cmf.h # New time series for model results (res - result) sim_dis = cmf.timeseries(self.begin, cmf.day) # starts the solver and calculates the daily time steps end = self.end if verbose: print("Start running") for t in solver.run(self.project.meteo_stations[0].T.begin, end, cmf.day): # Fill the results # print(t) if t >= self.begin: sim_dis.add(self.outlet.waterbalance(t)) # Return the filled result time series if verbose: print("Finished running") return sim_dis except RuntimeError: return np.array(self.Q[self.begin:self.end]) * np.nan
def make_integrator(self): """ Create the solver :return: """ winteg = cmf.CVodeIntegrator(1e-9) sinteg = cmf.HeunIntegrator() integ = cmf.SoluteWaterIntegrator(self.project.solutes, winteg, sinteg, self.project) return integ
def iterate(self, p=None): """ Calls `create_connections` and `inital_values` to shape the model using the parameter set `p` and returns an iterator that advances the model over the whole data period """ self.create_connections(p) self.initial_values(p) solver = cmf.CVodeIntegrator(self.project, 1e-9) solver.use_OpenMP = False return solver.run(self.data.begin, self.data.end, cmf.day)
def run(self, begin=None, end=None): begin = begin or self.rainstation.data.begin end = end or self.rainstation.data.end solver = cmf.CVodeIntegrator(self.project, 1e-9) outlet = cmf.timeseries(begin, cmf.day) outlet.add(self.outlet(begin)) for t in solver.run(begin, end, cmf.day): outlet.add(self.outlet.add) print(t) return outlet
def __init__(self, subsurface_lateral_connection, surface_lateral_connection=None, layercount=0): """ Creates the cmf project :param subsurface_lateral_connection: Type of lateral subsurface connection, eg. cmf.Darcy :param surface_lateral_connection: Type of lateral surface flux connection, eg. cmf.KinematicSurfaceRunoff or None :param layercount: Number of layers in the subsurface :return: """ p = cmf.project() shp = Shapefile('data/vollnkirchner_bach_cells.shp') # Create cells self.outlet_cells = [] for feature in shp: # Create a cell for each feature in the shape file c = cmf.geometry.create_cell(p, feature.shape, feature.HEIGHT, feature.OID, with_surfacewater=False) # If it is an outlet feature, add cell to the list of outletcells if feature.LANDUSE_CU.startswith('outlet'): self.outlet_cells.append(c) else: # If it is a normal upload cell, add layers self.build_cell(c, layercount) # Build topology cmf.geometry.mesh_project(p, verbose=True) # Connect cells with fluxes cmf.connect_cells_with_flux(p, subsurface_lateral_connection) if surface_lateral_connection: cmf.connect_cells_with_flux(p, surface_lateral_connection) # Connect outlets with neighbor cells for o_cell in self.outlet_cells: self.connect_outlet_cell(o_cell, subsurface_lateral_connection, surface_lateral_connection) # Load driver data load_meteo(p) self.project = p self.solver = cmf.CVodeIntegrator(p, 1e-9) self.solver.t = p.meteo_stations[0].T.begin
def runmodel(self, verbose=False): """ starts the model if verboose = True --> give something out for every day """ try: # Creates a solver for the differential equations #solver = cmf.ImplicitEuler(self.project,1e-8) solver = cmf.CVodeIntegrator(self.project, 1e-8) # usually the CVodeIntegrator computes the jakobi matrix only # partially to save computation time. But in models with low spatial # complexity this leads to a longer computational time # therefore the jakob matrix is computed completely to speed things up # this is done by LinearSolver = 0 solver.LinearSolver = 0 c = self.project[0] solver.max_step = cmf.h # New time series for model results (res - result) resQ = cmf.timeseries(self.begin, cmf.day) # starts the solver and calculates the daily time steps end = self.end if self.with_valid_data: end = datetime.datetime(1988, 12, 31) for t in solver.run(self.project.meteo_stations[0].T.begin, end, cmf.day): # Fill the results if t >= self.begin: resQ.add(self.outlet.waterbalance(t)) # Print a status report if verbose: print(t, 'Q=%5.3f, P=%5.3f' % (resQ[t], c.get_rainfall(t))) # Print that one year was calculated, so one knows the model is still working #### comment this out if run on supercomputer to avoid spam ###### #if t % cmf.year == cmf.year - cmf.year: # print("Finished one year") # Return the filled result time series return resQ except RuntimeError: return np.array(self.Q[self.begin:self.end + datetime.timedelta(days=1)]) * np.nan
def plot_Vt(self, label=None): """ Plots an integration of the Volume over 1 week starting with a volume of 2 m³ in W1 and an empty W2 """ self.w1.volume = 2.0 self.w2.volume = 0.0 label = label or self.con.to_string() solver = cmf.CVodeIntegrator(self.p, 1e-9) V0 = self.w1.volume t, vol = zip(*[(0, V0)] + [(t / cmf.day, self.w1.volume) for t in solver.run(cmf.Time(), cmf.week, cmf.h)]) plt.plot(t, vol, label=label) plt.xlabel(r'$t\ in\ days$') plt.ylabel(r'$V\ in\ m^3$') plt.yticks([0, 1, 2], ['0', '$V_0$', '$V(t_0)$']) plt.grid(True)
def run(self, verbose=False): """ Runs the model. Parameters ---------- verbose : bool, optional Whether progress is printed. The default is False. Returns ------- resdf : pd.DataFrame Model results provided as time series (DatetimeIndex) Column 0 ('Darcy flow'): Modelled outflow (Darcy flow) [mm/min]. Column 1 ('Surface runoff'): Modelled outflow (Surface runoff) [mm/min]. Column 2 ('Water level'): Time series of lists including the water level along horizontal axis [m]. Column 3 ('Ponding'): Time series of lists including the ponding on the surface along horizontal axis [m]. """ solver = cmf.CVodeIntegrator(self, 1e-9) list_t = list() list_q = list() list_qs = list() list_wlevel = list() list_sd = list() for t in solver.run(self.tstart, self.tstart + self.duration, self.dt): if verbose: print(t) list_q.append(self._to_liters_per_timestep(self.outlet(t))) list_qs.append(self._to_liters_per_timestep(self.outlet_s(t))) list_t.append(t.as_datetime()) wlevel = np.zeros(self.ncell) sd = np.zeros(self.ncell) for ii in range(len(self.cells)): wlevel[ii] = self.bottom[ii]+max(0,self.depth-self.cells[ii].layers[0].get_saturated_depth()) sd[ii] = self.cells[ii].surfacewater.depth list_wlevel.append(wlevel) list_sd.append(sd) resdf = pd.DataFrame(index=list_t, data={'Darcy flow':list_q, 'Surface runoff':list_qs, 'Water level':list_wlevel, 'Ponding':list_sd}) return resdf
def test_Q_t(self): """ Tests if the linear storage connection behaves similar to the analytical solution """ p, w1, w2 = create_project_with_2_storages() q = cmf.LinearStorageConnection(w1, w2, 1) # Loop over several scales for residence time for res_t in 10**np.arange(-3, 3, 0.5): q.residencetime = res_t w1.volume = 1.0 w2.volume = 0.0 solver = cmf.CVodeIntegrator(p, 1e-9) solver.integrate_until(cmf.day) self.assertAlmostEqual( w1.volume, np.exp(-1 / res_t), 5, 'LinearStorage fails to reproduce analytical solution for t_r={:0.5g}' .format(res_t))
def runmodel(self): """ Runs the models and saves the results. :return: Simulated discharge """ solver = cmf.CVodeIntegrator(self.project, 1e-9) # Result timeseries res_q = cmf.timeseries(self.begin, cmf.day) try: # Start solver and calculate in daily steps for t in solver.run(self.data.begin, self.end, cmf.day): res_q.add(self.outlet.waterbalance(t)) except RuntimeError: return np.array(self.data.Q[self.data.begin:self.data.end + datetime.timedelta(days=1)]) * np.nan return res_q
def solve_project(cmf_project: cmf.project, solver_settings: dict, outputs: dict) -> dict: """Solves the model""" logger.info('Initializing solving of CMF project') # Create solver, set time and set up results solver = cmf.CVodeIntegrator(cmf_project, solver_settings['tolerance']) solver.t = cmf.Time(solver_settings['start_time']['day'], solver_settings['start_time']['month'], solver_settings['start_time']['year']) logger.debug(f'Solver start time: {solver.t}') results = config_outputs(cmf_project, outputs) # Save initial conditions to results gather_results(cmf_project, results, solver.t) analysis_length = get_analysis_length(solver_settings['analysis_length']) time_step = get_time_step(solver_settings['time_step']) number_of_steps = analysis_length.total_seconds( ) / time_step.total_seconds() # Run solver and save results at each time step widgets = [ ' [', progressbar.Timer(), '] ', progressbar.Bar(), ' [', progressbar.AdaptiveETA(), ' ]' ] bar = progressbar.ProgressBar(max_value=number_of_steps, widgets=widgets) for index, time_ in enumerate( solver.run(solver.t, solver.t + analysis_length, time_step)): gather_results(cmf_project, results, time_) bar.update(index) logger.info('Solved CMF project!') return results
def run_model(self, verbose = True): """ Starts the model. Used by spotpy """ cell = self.project[0] try: # Create a solver for differential equations solver = cmf.CVodeIntegrator(self.project, 1e-8) # New time series for model results resQ = cmf.timeseries(self.begin_calibration, cmf.day) # starts the solver and calculates the daily time steps end = self.end_validation for t in solver.run(self.project.meteo_stations[0].T.begin, end, cmf.day): # Fill the results (first year is included but not used to # calculate the NS) if verbose: print(t) print("storages") storages = get_storages_and_fluxes.storages_of_cell( cell.rain_source, cell) fluxes = get_storages_and_fluxes.flux_of_all_nodes_of_cell( cell.rain_source, cell, t) fluxes = \ get_storages_and_fluxes.convert_fluxes_for_fluxogram( fluxes) print(storages) print("Fluxes") print(fluxes) print("\n") if t >= self.begin_calibration: resQ.add(self.outlet.waterbalance(t)) return resQ # Return an nan - array when a runtime error occurs except RuntimeError: print("Runtime Error") return np.array(self.obs_discharge[ self.begin_calibration:self.end_validation + datetime.timedelta(days=1)])*np.nan
def simple1D(): from matplotlib import pyplot as plt import cmf from datetime import datetime, timedelta project = cmf.project() # Add one cell at position (0,0,0), Area=1000m2 cell = project.NewCell(0, 0, 0, 1000, with_surfacewater=True) # Create a retention curve r_curve = cmf.VanGenuchtenMualem(Ksat=1, phi=0.5, alpha=0.01, n=2.0) # Add ten layers of 10cm thickness for i in range(10): depth = (i + 1) * 0.1 cell.add_layer(depth, r_curve) # Connect layers with Richards perc. # this can be shorten as cell.install_connection(cmf.Richards) # Create solver solver = cmf.CVodeIntegrator(project, 1e-6) solver.t = cmf.Time(1, 1, 2011) # Create groundwater boundary (uncomment to use it) # Create the boundary condition gw = project.NewOutlet('groundwater', x=0, y=0, z=-1.1) # Set the potential gw.potential = -2 # Connect the lowest layer to the groundwater using Richards percolation gw_flux=cmf.Richards(cell.layers[-1],gw) # Set inital conditions # Set all layers to a potential of -2 m cell.saturated_depth = 2. # 100 mm water in the surface water storage cell.surfacewater.depth = 0.1 # The run time loop, run for 72 hours # Save potential and soil moisture for each layer potential = [cell.layers.potential] moisture = [cell.layers.theta] for t in solver.run(solver.t, solver.t + timedelta(days=7), timedelta(hours=1)): potential.append(cell.layers.potential) moisture.append(cell.layers.theta) """ # Plot results plt.subplot(211) plt.plot(moisture) plt.ylabel(r'Soil moisture $\theta [m^3/m^3]$') plt.xlabel(r'$time [h]$') plt.grid() plt.subplot(212) plt.plot(potential) plt.ylabel(r'Water head $\Psi_{tot} [m]$') plt.xlabel(r'$time [h]$') plt.grid() plt.show() """ print(cell.vegetation)
cmf.kinematic_wave(c.layers[0], outlet, 3) # create artificial rain data begin = datetime.datetime(1979, 1, 1) end = begin + 15 * datetime.timedelta(days=1) step = datetime.timedelta(days=1) P = cmf.timeseries(begin, step) P.extend(prec for prec in np.random.randint(0, high=30, size=15)) # add a rainstation rainstation = p.rainfall_stations.add("Rain", P, (0, 0, 0)) p.use_nearest_rainfall() # create a solver solver = cmf.CVodeIntegrator(p, 1e-8) # create lists to store the results of the fluxes and storages timeseries_fluxes = [] timeseries_storages = [] # let the solver run for our timeperiod for t in solver.run(begin, end, cmf.day): fluxes_raw = flux_of_all_nodes_of_cell(c.rain_source, c, t) # to get an easier to grasp of the output of the fluxes it can be # converted using the following function fluxes_nicer = convert_fluxes_for_fluxogram(fluxes_raw) timeseries_fluxes.append(fluxes_nicer) timeseries_storages.append(storages_of_cell(c.rain_source, c)) # due to the way CMF constructs models and how this program searches
cmf.FreundlichAdsorbtion(2., .5, 1.0, 1e-9)) l.Solute(Y).state = 1. # Tracer Y has a Langmuir isotherm xa/m=Kc/(1+Kc), # with K = 1 and sorbent mass m = 1 l.Solute(Z).set_adsorption(cmf.LangmuirAdsorption(1., 5.)) l.Solute(Z).state = 1. # Use Richards equation c.install_connection(cmf.Richards) # Make a groundwater boundary condition gw = p.NewOutlet('gw', 0, 0, -1.5) cmf.Richards(c.layers[-1], gw) # Template for the water solver wsolver = cmf.CVodeIntegrator(1e-9) # Template for the solute solver ssolver = cmf.ImplicitEuler(1e-9) # Creating the SWI, the storage objects of the project are internally assigned to the correct solver solver = cmf.SoluteWaterIntegrator(p.solutes, wsolver, ssolver, p) c.saturated_depth = 1.5 # Now we put a constant clean water flux into the storage inflow = cmf.NeumannBoundary.create(c.surfacewater) inflow.flux = 100.0 # 100 mm/day for s in p.solutes: inflow.concentration[s] = 0.0 # Save wetness and concentration of all layers conc = []
def _run(self, alpha=None, n=None, porosity=None, ksat=None): #return alpha,n,porosity,ksat ''' Runs the model instance Input: Parameter set (in this case VAN-Genuchten Parameter alpha,n,porosity,ksat) Output: Simulated values on given observation days ''' #Check if given parameter set is in realistic boundaries if alpha<self.bound[0][0] or alpha>self.bound[0][1] or ksat<self.bound[1][0] \ or ksat>self.bound[1][1] or n<self.bound[2][0] or n>self.bound[2][1] or \ porosity<self.bound[3][0] or porosity>self.bound[3][1]: print('The following combination was ignored') text = 'n= ' + str(n) print(text) text = 'alpha=' + str(alpha) print(text) text = 'ksat= ' + str(ksat) print(text) text = 'porosity= ' + str(porosity) print(text) print('##############################') return self.observations * -np.inf else: project = cmf.project() cell = project.NewCell(x=0, y=0, z=0, area=1000, with_surfacewater=True) text = 'n= ' + str(n) print(text) text = 'alpha=' + str(alpha) print(text) text = 'ksat= ' + str(ksat) print(text) text = 'porosity= ' + str(porosity) print(text) print('##############################') r_curve = cmf.VanGenuchtenMualem(Ksat=ksat, phi=porosity, alpha=alpha, n=n) layers = 5 ldepth = .01 for i in range(layers): depth = (i + 1) * ldepth cell.add_layer(depth, r_curve) cell.install_connection(cmf.Richards) cell.install_connection(cmf.ShuttleworthWallace) cell.saturated_depth = .5 solver = cmf.CVodeIntegrator(project, 1e-6) self._load_meteo(project) gw = project.NewOutlet('groundwater', x=0, y=0, z=.9) #layers*ldepth) cmf.Richards(cell.layers[-1], gw) gw.potential = -.5 #IMPORTANT gw.is_source = True solver.t = self.datastart Evalstep, evallist = 0, [] rundays = (self.dataend - self.datastart).days for t in solver.run(solver.t, solver.t + timedelta(days=rundays), timedelta(hours=1)): if self.gw_array['Date'].__contains__(t) == True: Gw_Index = np.where(self.gw_array['Date'] == t) gw.potential = self.gw_array[self.piezometer][Gw_Index] print(gw.potential ) #TO DO: CHECK IF SOMETHING HAPPENS HERE!!!! if t > self.analysestart: if Evalstep != len(self.eval_dates ) and t == self.eval_dates[Evalstep]: evallist.append(cell.layers.wetness[0] * cell.layers.porosity[0] * 100) Evalstep += 1 return evallist