class DeterministicRunner(DynamicModel): def __init__(self, configuration, modelTime, initialState = None): DynamicModel.__init__(self) self.modelTime = modelTime self.model = PCRGlobWB(configuration, modelTime, initialState) self.reporting = Reporting(configuration, self.model, modelTime) def initial(self): pass def dynamic(self): # re-calculate current model time using current pcraster timestep value self.modelTime.update(self.currentTimeStep()) # update model (will pick up current model time from model time object) self.model.read_forcings() self.model.update(report_water_balance=True) #do any needed reporting for this time step self.reporting.report()
class DeterministicRunner(DynamicModel): def __init__(self, configuration, modelTime, initialState = None): DynamicModel.__init__(self) self.modelTime = modelTime self.model = PCRGlobWB(configuration, modelTime, initialState) self.reporting = Reporting(configuration, self.model, modelTime) def initial(self): pass def dynamic(self): # re-calculate current model time using current pcraster timestep value self.modelTime.update(self.currentTimeStep()) self.model.read_forcings() self.model.update(report_water_balance=True) # get observation data sattelite_satDegUpp000005 = self.get_satDegUpp000005_from_observation() # set upper soil moisture state based on observation data self.set_satDegUpp000005(sattelite_satDegUpp000005) # do any needed reporting for this time step self.reporting.report() def get_satDegUpp000005_from_observation(self): # assumption for observation values # - this should be replaced by values from the ECV soil moisture value (sattelite data) # - uncertainty should be included here # - note that the value should be between 0.0 and 1.0 observed_satDegUpp000005 = pcr.min(1.0,\ pcr.max(0.0,\ pcr.normal(pcr.boolean(1)) + 1.0)) return observed_satDegUpp000005 def set_satDegUpp000005(self, observed_satDegUpp000005): # ratio between observation and model ratio_between_observation_and_model = pcr.ifthenelse(self.model.landSurface.satDegUpp000005> 0.0, observed_satDegUpp000005 / \ self.model.landSurface.satDegUpp000005, 0.0) # updating upper soil states for all lad cover types for coverType in self.model.landSurface.coverTypes: # correcting upper soil state (storUpp000005) self.model.landSurface.landCoverObj[coverType].storUpp000005 *= ratio_between_observation_and_model # if model value = 0.0, storUpp000005 is calculated based on storage capacity (model parameter) and observed saturation degree self.model.landSurface.landCoverObj[coverType].storUpp000005 = pcr.ifthenelse(self.model.landSurface.satDegUpp000005 > 0.0,\ self.model.landSurface.landCoverObj[coverType].storUpp000005,\ observed_satDegUpp000005 * self.model.landSurface.parameters.storCapUpp000005)
class DeterministicRunner(DynamicModel): def __init__(self, configuration, modelTime): DynamicModel.__init__(self) self.modelTime = modelTime self.model = ModflowOfflineCoupling(configuration, modelTime) self.reporting = Reporting(configuration, self.model, modelTime) def initial(self): # get or prepare the initial condition for groundwater head self.model.get_initial_heads() def dynamic(self): # re-calculate current model time using current pcraster timestep value self.modelTime.update(self.currentTimeStep()) # update model (It will pick up current model time from the modelTime object) self.model.update() # do any needed reporting for this time step self.reporting.report()
class DeterministicRunner(DynamicModel): def __init__(self, configuration, modelTime, initialState=None, system_argument=None): DynamicModel.__init__(self) self.modelTime = modelTime self.model = PCRGlobWB(configuration, modelTime, initialState) self.reporting = Reporting(configuration, self.model, modelTime) # the model will set paramaters based on global pre-multipliers given in the argument: if system_argument != None: self.adusting_parameters(configuration, system_argument) # option to include merging processes for pcraster maps and netcdf files: self.with_merging = True if ('with_merging' in configuration.globalOptions.keys()) and ( configuration.globalOptions['with_merging'] == "False"): self.with_merging = False # make the configuration available for the other method/function self.configuration = configuration def adusting_parameters(self, configuration, system_argument): # global pre-multipliers given in the argument: if len(system_argument) > 4: logger.info( "Adjusting some model parameters based on given values in the system argument." ) # pre-multipliers for minSoilDepthFrac, kSat, recessionCoeff, storCap and degreeDayFactor multiplier_for_minSoilDepthFrac = float( system_argument[4] ) # linear scale # Note that this one does NOT work for the changing WMIN or Joyce land cover options. multiplier_for_kSat = float(system_argument[5]) # log scale multiplier_for_recessionCoeff = float( system_argument[6]) # log scale multiplier_for_storCap = float(system_argument[7]) # linear scale multiplier_for_degreeDayFactor = float( system_argument[8]) # linear scale # pre-multiplier for the reference potential ET self.multiplier_for_refPotET = float( system_argument[9]) # linear scale # it is also possible to define prefactors via the ini/configuration file: # - this will be overwrite any previous given pre-multipliers if 'prefactorOptions' in configuration.allSections: logger.info( "Adjusting some model parameters based on given values in the ini/configuration file." ) self.multiplier_for_refPotET = float( configuration. prefactorOptions['linear_multiplier_for_refPotET'] ) # linear scale # Note that this one does NOT work for the changing WMIN or Joyce land cover options. multiplier_for_degreeDayFactor = float( configuration.prefactorOptions[ 'linear_multiplier_for_degreeDayFactor']) # linear scale multiplier_for_minSoilDepthFrac = float( configuration.prefactorOptions[ 'linear_multiplier_for_minSoilDepthFrac']) # linear scale multiplier_for_kSat = float( configuration.prefactorOptions['log_10_multiplier_for_kSat'] ) # log scale multiplier_for_storCap = float( configuration.prefactorOptions['linear_multiplier_for_storCap'] ) # linear scale multiplier_for_recessionCoeff = float( configuration.prefactorOptions[ 'log_10_multiplier_for_recessionCoeff']) # log scale # saving global pre-multipliers to the log file: msg = "\n" msg += "\n" msg += "Multiplier values used: " + "\n" msg += "For minSoilDepthFrac : " + str( multiplier_for_minSoilDepthFrac) + "\n" msg += "For kSat (log-scale) : " + str( multiplier_for_kSat) + "\n" msg += "For recessionCoeff (log-scale) : " + str( multiplier_for_recessionCoeff) + "\n" msg += "For storCap : " + str( multiplier_for_storCap) + "\n" msg += "For degreeDayFactor : " + str( multiplier_for_degreeDayFactor) + "\n" msg += "For refPotET : " + str( self.multiplier_for_refPotET) + "\n" logger.info(msg) # - also to a txt file f = open( "multiplier.txt", "w" ) # this will be stored in the "map" folder of the 'outputDir' (as we set the current working directory to this "map" folder, see configuration.py) f.write(msg) f.close() # set parameter "recessionCoeff" based on the given pre-multiplier # - also saving the adjusted parameter maps to pcraster files # - these will be stored in the "map" folder of the 'outputDir' (as we set the current working directory to this "map" folder, see configuration.py) # "recessionCoeff" # minimum value is zero and using log-scale self.model.groundwater.recessionCoeff = pcr.max( 0.0, (10**(multiplier_for_recessionCoeff)) * self.model.groundwater.recessionCoeff) self.model.groundwater.recessionCoeff = pcr.min( 1.0, self.model.groundwater.recessionCoeff) # report the map pcr.report(self.model.groundwater.recessionCoeff, "recessionCoeff.map") # set parameters "kSat", "storCap", "minSoilDepthFrac", and "degreeDayFactor" based on the given pre-multipliers for coverType in self.model.landSurface.coverTypes: # "degreeDayFactor" self.model.landSurface.landCoverObj[coverType].degreeDayFactor = pcr.max(0.0, multiplier_for_degreeDayFactor *\ self.model.landSurface.landCoverObj[coverType].degreeDayFactor) # report the map pcraster_filename = "degreeDayFactor" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].degreeDayFactor, pcraster_filename) # "kSat" and "storCap" for 2 layer model if self.model.landSurface.numberOfSoilLayers == 2: # "kSat" # minimum value is zero and using-log-scale self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp) self.model.landSurface.landCoverObj[coverType].parameters.kSatLow = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatLow) # report the maps pcraster_filename = "kSatUpp" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. kSatUpp, pcraster_filename) pcraster_filename = "kSatLow" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. kSatLow, pcraster_filename) # "storCap" # minimum value is zero self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp) self.model.landSurface.landCoverObj[coverType].parameters.storCapLow = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.landCoverObj[coverType].parameters.storCapLow) # report the maps pcraster_filename = "storCapUpp" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. storCapUpp, pcraster_filename) pcraster_filename = "storCapLow" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. storCapLow, pcraster_filename) # "kSat" and "storCap" for 3 layer model if self.model.landSurface.numberOfSoilLayers == 3: # "kSat" # minimum value is zero and using-log-scale self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp000005 = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp000005) self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp005030 = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp005030) self.model.landSurface.landCoverObj[coverType].parameters.kSatLow030150 = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatLow030150) # report the maps pcraster_filename = "kSatUpp000005" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. kSatUpp000005, pcraster_filename) pcraster_filename = "kSatUpp005030" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. kSatUpp005030, pcraster_filename) pcraster_filename = "kSatLow030150" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. kSatLow030150, pcraster_filename) # "storCap" # minimum value is zero self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005 = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005) self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030 = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030) self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150 = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150) # report the maps pcraster_filename = "storCapUpp000005" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. storCapUpp000005, pcraster_filename) pcraster_filename = "storCapUpp005030" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. storCapUpp005030, pcraster_filename) pcraster_filename = "storCapLow030150" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. storCapLow030150, pcraster_filename) # re-calculate rootZoneWaterStorageCap as the consequence of the modification of "storCap" # This is WMAX in the oldcalc script. if self.model.landSurface.numberOfSoilLayers == 2: self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap = self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp +\ self.model.landSurface.landCoverObj[coverType].parameters.storCapLow if self.model.landSurface.numberOfSoilLayers == 3: self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap = self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005 +\ self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030 +\ self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150 # report the map pcraster_filename = "rootZoneWaterStorageCap" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. rootZoneWaterStorageCap, pcraster_filename) # "minSoilDepthFrac" if multiplier_for_minSoilDepthFrac != 1.0: # minimum value is zero self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac = pcr.max(0.0, multiplier_for_minSoilDepthFrac*\ self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac) # for minSoilDepthFrac - values will be limited by maxSoilDepthFrac self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac = pcr.min(\ self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac,\ self.model.landSurface.landCoverObj[coverType].maxSoilDepthFrac) # maximum value is 1.0 self.model.landSurface.landCoverObj[ coverType].minSoilDepthFrac = pcr.min( 1.0, self.model.landSurface.landCoverObj[coverType]. minSoilDepthFrac) # report the map pcraster_filename = "minSoilDepthFrac" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType]. minSoilDepthFrac, pcraster_filename) # re-calculate arnoBeta (as the consequence of the modification of minSoilDepthFrac) self.model.landSurface.landCoverObj[coverType].arnoBeta = pcr.max(0.001,\ (self.model.landSurface.landCoverObj[coverType].maxSoilDepthFrac-1.)/(1.-self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac)+\ self.model.landSurface.landCoverObj[coverType].parameters.orographyBeta-0.01) self.model.landSurface.landCoverObj[coverType].arnoBeta = pcr.cover(pcr.max(0.001,\ self.model.landSurface.landCoverObj[coverType].arnoBeta), 0.001) # report the map pcraster_filename = "arnoBeta" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].arnoBeta, pcraster_filename) # re-calculate rootZoneWaterStorageMin (as the consequence of the modification of minSoilDepthFrac) # This is WMIN in the oldcalc script. # WMIN (unit: m): minimum local soil water capacity within the grid-cell self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageMin = self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac *\ self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap # report the map pcraster_filename = "rootZoneWaterStorageMin" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType]. rootZoneWaterStorageMin, pcraster_filename) # re-calculate rootZoneWaterStorageRange (as the consequence of the modification of rootZoneWaterStorageRange and minSoilDepthFrac) # WMAX - WMIN (unit: m) self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageRange = self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap -\ self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageMin # report the map pcraster_filename = "rootZoneWaterStorageRange" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType]. rootZoneWaterStorageRange, pcraster_filename) def initial(self): pass def dynamic(self): # re-calculate current model time using current pcraster timestep value self.modelTime.update(self.currentTimeStep()) # read model forcing (will pick up current model time from model time object) self.model.read_forcings() # adjust the reference potential ET according to the given pre-multiplier self.model.meteo.referencePotET = self.model.meteo.referencePotET * self.multiplier_for_refPotET # update model (will pick up current model time from model time object) # - for a run coupled to MODFLOW, water balance checks are not valid due to lateral flow. if self.configuration.online_coupling_between_pcrglobwb_and_modflow: self.model.update(report_water_balance=False) else: self.model.update(report_water_balance=True) # do any needed reporting for this time step self.reporting.report() # at the last day of the month, stop calculation until modflow and related merging process are ready (only for a run with modflow) if self.modelTime.isLastDayOfMonth() and (self.configuration.online_coupling_between_pcrglobwb_and_modflow or\ self.with_merging): # wait until modflow files are ready if self.configuration.online_coupling_between_pcrglobwb_and_modflow: modflow_is_ready = False self.count_check = 0 while modflow_is_ready == False: if datetime.datetime.now().second == 14 or\ datetime.datetime.now().second == 29 or\ datetime.datetime.now().second == 34 or\ datetime.datetime.now().second == 59: \ modflow_is_ready = self.check_modflow_status() # wait until merged files are ready merged_files_are_ready = False while merged_files_are_ready == False: self.count_check = 0 if datetime.datetime.now().second == 14 or\ datetime.datetime.now().second == 29 or\ datetime.datetime.now().second == 34 or\ datetime.datetime.now().second == 59: \ merged_files_are_ready = self.check_merging_status() def check_modflow_status(self): status_file = str( self.configuration.main_output_directory ) + "/modflow/transient/maps/modflow_files_for_" + str( self.modelTime.fulldate) + "_are_ready.txt" msg = 'Waiting for the file: ' + status_file if self.count_check == 1: logger.info(msg) if self.count_check < 7: #~ logger.debug(msg) # INACTIVATE THIS AS THIS MAKE A HUGE DEBUG (dbg) FILE self.count_check += 1 status = os.path.exists(status_file) if status == False: return status if status: self.count_check = 0 return status def check_merging_status(self): status_file = str(self.configuration.main_output_directory ) + "/global/maps/merged_files_for_" + str( self.modelTime.fulldate) + "_are_ready.txt" msg = 'Waiting for the file: ' + status_file if self.count_check == 1: logger.info(msg) if self.count_check < 7: #~ logger.debug(msg) # INACTIVATE THIS AS THIS MAKE A HUGE DEBUG (dbg) FILE self.count_check += 1 status = os.path.exists(status_file) if status == False: return status if status: self.count_check = 0 return status
class DeterministicRunner(DynamicModel): def __init__(self, configuration, modelTime, initialState=None, system_argument=None): DynamicModel.__init__(self) self.modelTime = modelTime self.model = PCRGlobWB(configuration, modelTime, initialState) self.reporting = Reporting(configuration, self.model, modelTime) # the model will set paramaters based on global pre-multipliers given in the argument: self.adusting_parameters(configuration, system_argument) # make the configuration available for the other method/function self.configuration = configuration def adusting_parameters(self, configuration, system_argument): # it is also possible to define prefactors via the ini/configuration file: # - this will be overwrite any previous given pre-multipliers if 'prefactorOptions' in configuration.allSections: logger.info( "Adjusting some model parameters based on given values in the ini/configuration file." ) self.multiplier_for_refPotET = float( configuration. prefactorOptions['linear_multiplier_for_refPotET'] ) # linear scale # Note that this one does NOT work for the changing WMIN or Joyce land cover options. multiplier_for_degreeDayFactor = float( configuration.prefactorOptions[ 'linear_multiplier_for_degreeDayFactor']) # linear scale multiplier_for_minSoilDepthFrac = float( configuration.prefactorOptions[ 'linear_multiplier_for_minSoilDepthFrac']) # linear scale multiplier_for_kSat = float( configuration.prefactorOptions['log_10_multiplier_for_kSat'] ) # log scale multiplier_for_storCap = float( configuration.prefactorOptions['linear_multiplier_for_storCap'] ) # linear scale multiplier_for_recessionCoeff = float( configuration.prefactorOptions[ 'log_10_multiplier_for_recessionCoeff']) # log scale # saving global pre-multipliers to the log file: msg = "\n" msg += "\n" msg += "Multiplier values used: " + "\n" msg += "For minSoilDepthFrac : " + str( multiplier_for_minSoilDepthFrac) + "\n" msg += "For kSat (log-scale) : " + str( multiplier_for_kSat) + "\n" msg += "For recessionCoeff (log-scale) : " + str( multiplier_for_recessionCoeff) + "\n" msg += "For storCap : " + str( multiplier_for_storCap) + "\n" msg += "For degreeDayFactor : " + str( multiplier_for_degreeDayFactor) + "\n" msg += "For refPotET : " + str( self.multiplier_for_refPotET) + "\n" logger.info(msg) # - also to a txt file f = open( "multiplier.txt", "w" ) # this will be stored in the "map" folder of the 'outputDir' (as we set the current working directory to this "map" folder, see configuration.py) f.write(msg) f.close() # set parameter "recessionCoeff" based on the given pre-multiplier # - also saving the adjusted parameter maps to pcraster files # - these will be stored in the "map" folder of the 'outputDir' (as we set the current working directory to this "map" folder, see configuration.py) # "recessionCoeff" # minimum value is zero and using log-scale self.model.groundwater.recessionCoeff = pcr.max( 0.0, (10**(multiplier_for_recessionCoeff)) * self.model.groundwater.recessionCoeff) self.model.groundwater.recessionCoeff = pcr.min( 1.0, self.model.groundwater.recessionCoeff) # report the map pcr.report(self.model.groundwater.recessionCoeff, "recessionCoeff.map") # set parameters "kSat", "storCap", "minSoilDepthFrac", and "degreeDayFactor" based on the given pre-multipliers for coverType in self.model.landSurface.coverTypes: # "degreeDayFactor" self.model.landSurface.landCoverObj[coverType].degreeDayFactor = pcr.max(0.0, multiplier_for_degreeDayFactor *\ self.model.landSurface.landCoverObj[coverType].degreeDayFactor) # report the map pcraster_filename = "degreeDayFactor" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].degreeDayFactor, pcraster_filename) # "kSat" and "storCap" for 2 layer model if self.model.landSurface.numberOfSoilLayers == 2: # "kSat" # minimum value is zero and using-log-scale self.model.landSurface.parameters.kSatUpp = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.parameters.kSatUpp) self.model.landSurface.parameters.kSatLow = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.parameters.kSatLow) # report the maps (for debugging) #pcraster_filename = "kSatUpp"+ "_" + coverType + ".map" #pcr.report(self.model.landSurface.parameters.kSatUpp, pcraster_filename) #pcraster_filename = "kSatLow"+ "_" + coverType + ".map" #pcr.report(self.model.landSurface.parameters.kSatLow, pcraster_filename) # "storCap" # minimum value is zero self.model.landSurface.parameters.storCapUpp = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.parameters.storCapUpp) self.model.landSurface.parameters.storCapLow = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.parameters.storCapLow) # report the maps (for debugging) #pcraster_filename = "storCapUpp"+ "_" + coverType + ".map" #pcr.report(self.model.landSurface.parameters.storCapUpp, pcraster_filename) #pcraster_filename = "storCapLow"+ "_" + coverType + ".map" #pcr.report(self.model.landSurface.parameters.storCapLow, pcraster_filename) # "kSat" and "storCap" for 3 layer model if self.model.landSurface.numberOfSoilLayers == 3: # "kSat" # minimum value is zero and using-log-scale self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp000005 = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp000005) self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp005030 = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp005030) self.model.landSurface.landCoverObj[coverType].parameters.kSatLow030150 = \ pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatLow030150) # report the maps pcraster_filename = "kSatUpp000005" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. kSatUpp000005, pcraster_filename) pcraster_filename = "kSatUpp005030" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. kSatUpp005030, pcraster_filename) pcraster_filename = "kSatLow030150" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. kSatLow030150, pcraster_filename) # "storCap" # minimum value is zero self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005 = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005) self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030 = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030) self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150 = pcr.max(0.0, multiplier_for_storCap*\ self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150) # report the maps pcraster_filename = "storCapUpp000005" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. storCapUpp000005, pcraster_filename) pcraster_filename = "storCapUpp005030" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. storCapUpp005030, pcraster_filename) pcraster_filename = "storCapLow030150" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].parameters. storCapLow030150, pcraster_filename) # re-calculate rootZoneWaterStorageCap as the consequence of the modification of "storCap" # This is WMAX in the oldcalc script. if self.model.landSurface.numberOfSoilLayers == 2: self.model.landSurface.parameters.rootZoneWaterStorageCap = self.model.landSurface.parameters.storCapUpp +\ self.model.landSurface.parameters.storCapLow if self.model.landSurface.numberOfSoilLayers == 3: self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap = self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005 +\ self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030 +\ self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150 # report the map #pcraster_filename = "rootZoneWaterStorageCap"+ "_" + coverType + ".map" #pcr.report(self.model.landSurface.parameters.rootZoneWaterStorageCap, pcraster_filename) # "minSoilDepthFrac" if multiplier_for_minSoilDepthFrac != 1.0: for coverType in self.model.landSurface.coverTypes: # minimum value is zero self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac = pcr.max(0.0, multiplier_for_minSoilDepthFrac*\ self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac) # for minSoilDepthFrac - values will be limited by maxSoilDepthFrac self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac = pcr.min(\ self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac,\ self.model.landSurface.landCoverObj[coverType].maxSoilDepthFrac) # maximum value is 1.0 self.model.landSurface.landCoverObj[ coverType].minSoilDepthFrac = pcr.min( 1.0, self.model.landSurface.landCoverObj[coverType]. minSoilDepthFrac) # report the map pcraster_filename = "minSoilDepthFrac" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType]. minSoilDepthFrac, pcraster_filename) # re-calculate arnoBeta (as the consequence of the modification of minSoilDepthFrac) self.model.landSurface.landCoverObj[coverType].arnoBeta = pcr.max(0.001,\ (self.model.landSurface.landCoverObj[coverType].maxSoilDepthFrac-1.)/(1.-self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac)+\ self.model.landSurface.parameters.orographyBeta-0.01) self.model.landSurface.landCoverObj[coverType].arnoBeta = pcr.cover(pcr.max(0.001,\ self.model.landSurface.landCoverObj[coverType].arnoBeta), 0.001) # report the map pcraster_filename = "arnoBeta" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType].arnoBeta, pcraster_filename) # re-calculate rootZoneWaterStorageMin (as the consequence of the modification of minSoilDepthFrac) # This is WMIN in the oldcalc script. # WMIN (unit: m): minimum local soil water capacity within the grid-cell self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageMin = self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac *\ self.model.landSurface.parameters.rootZoneWaterStorageCap # report the map pcraster_filename = "rootZoneWaterStorageMin" + "_" + coverType + ".map" pcr.report( self.model.landSurface.landCoverObj[coverType]. rootZoneWaterStorageMin, pcraster_filename) # re-calculate rootZoneWaterStorageRange (as the consequence of the modification of rootZoneWaterStorageRange and minSoilDepthFrac) # WMAX - WMIN (unit: m) self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageRange = self.model.landSurface.parameters.rootZoneWaterStorageCap -\ self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageMin # report the map #pcraster_filename = "rootZoneWaterStorageRange"+ "_" + coverType + ".map" #pcr.report(self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageRange, pcraster_filename) def initial(self): pass def dynamic(self): # re-calculate current model time using current pcraster timestep value self.modelTime.update(self.currentTimeStep()) # update model (will pick up current model time from model time object) self.model.read_forcings() self.model.update(report_water_balance=True) #do any needed reporting for this time step self.reporting.report()
class BmiPCRGlobWB(EBmi): #we use the same epoch as pcrglobwb netcdf reporting def days_since_industry_epoch(self, modeltime): return (modeltime - datetime.date(1901, 1, 1)).days def in_modeltime(self, days_since_industry_epoch): return (datetime.datetime(1901, 1, 1) + datetime.timedelta(days=days_since_industry_epoch)).date() def calculate_shape(self): # return pcr.pcr2numpy(self.model.landmask, 1e20).shape return (pcr.clone().nrRows(), pcr.clone().nrCols()) #BMI initialize (as a single step) def initialize(self, fileName): self.initialize_config(fileName) self.initialize_model() #EBMI initialize (first step of two) def initialize_config(self, fileName): logger.info("PCRGlobWB: initialize_config") try: self.configuration = Configuration(fileName, relative_ini_meteo_paths=True) pcr.setclone(self.configuration.cloneMap) # set start and end time based on configuration self.model_time = ModelTime() self.model_time.getStartEndTimeSteps( self.configuration.globalOptions['startTime'], self.configuration.globalOptions['endTime']) self.model_time.update(0) self.shape = self.calculate_shape() logger.info("Shape of maps is %s", str(self.shape)) self.model = None except: import traceback traceback.print_exc() raise #EBMI initialize (second step of two) def initialize_model(self): if self.model is not None: #already initialized return try: logger.info("PCRGlobWB: initialize_model") initial_state = None self.model = PCRGlobWB(self.configuration, self.model_time, initial_state) self.reporting = Reporting(self.configuration, self.model, self.model_time) logger.info("Shape of maps is %s", str(self.shape)) logger.info("PCRGlobWB Initialized") except: import traceback traceback.print_exc() raise def update(self): timestep = self.model_time.timeStepPCR self.model_time.update(timestep + 1) self.model.read_forcings() self.model.update(report_water_balance=True) self.reporting.report() # #numpy = pcr.pcr2numpy(self.model.landSurface.satDegUpp000005, 1e20) # numpy = pcr.pcr2numpy(self.model.landSurface.satDegUpp000005, np.NaN) # print numpy.shape # print numpy def update_until(self, time): while self.get_current_time() + 0.001 < time: self.update() def update_frac(self, time_frac): raise NotImplementedError def finalize(self): pass def get_component_name(self): return "pcrglobwb" def get_input_var_names(self): return ["top_layer_soil_saturation"] def get_output_var_names(self): return ["top_layer_soil_saturation"] def get_var_type(self, long_var_name): return 'float64' def get_var_units(self, long_var_name): #TODO: this is not a proper unit return '1' def get_var_rank(self, long_var_name): return 0 def get_var_size(self, long_var_name): return np.prod(self.get_grid_shape(long_var_name)) def get_var_nbytes(self, long_var_name): return self.get_var_size(long_var_name) * np.float64.itemsize def get_start_time(self): return self.days_since_industry_epoch(self.model_time.startTime) def get_current_time(self): return self.days_since_industry_epoch(self.model_time.currTime) def get_end_time(self): return self.days_since_industry_epoch(self.model_time.endTime) def get_time_step(self): return 1 def get_time_units(self): return "Days since 1901-01-01" def get_value(self, long_var_name): logger.info("getting value for var %s", long_var_name) if (long_var_name == "top_layer_soil_saturation"): if self.model is not None and hasattr(self.model.landSurface, 'satDegUpp000005'): #first make all NanS into 0.0 with cover, then cut out the model using the landmask. # This should not actually make a difference. remasked = pcr.ifthen( self.model.landmask, pcr.cover(self.model.landSurface.satDegUpp000005, 0.0)) pcr.report(self.model.landSurface.satDegUpp000005, "value.map") pcr.report(remasked, "remasked.map") value = pcr.pcr2numpy(remasked, np.NaN) else: logger.info( "model has not run yet, returning empty state for top_layer_soil_saturation" ) value = pcr.pcr2numpy(pcr.scalar(0.0), np.NaN) # print "getting var", value # sys.stdout.flush() doubles = value.astype(np.float64) # print "getting var as doubles!!!!", doubles result = np.flipud(doubles) # print "getting var as doubles flipped!!!!", result # sys.stdout.flush() return result else: raise Exception("unknown var name" + long_var_name) def get_value_at_indices(self, long_var_name, inds): raise NotImplementedError # def get_satDegUpp000005_from_observation(self): # # # assumption for observation values # # - this should be replaced by values from the ECV soil moisture value (sattelite data) # # - uncertainty should be included here # # - note that the value should be between 0.0 and 1.0 # observed_satDegUpp000005 = pcr.min(1.0,\ # pcr.max(0.0,\ # pcr.normal(pcr.boolean(1)) + 1.0)) # return observed_satDegUpp000005 def set_satDegUpp000005(self, src): mask = np.isnan(src) src[mask] = 1e20 observed_satDegUpp000005 = pcr.numpy2pcr(pcr.Scalar, src, 1e20) pcr.report(observed_satDegUpp000005, "observed.map") constrained_satDegUpp000005 = pcr.min( 1.0, pcr.max(0.0, observed_satDegUpp000005)) pcr.report(constrained_satDegUpp000005, "constrained.map") pcr.report(self.model.landSurface.satDegUpp000005, "origmap.map") diffmap = constrained_satDegUpp000005 - self.model.landSurface.satDegUpp000005 pcr.report(diffmap, "diffmap.map") # ratio between observation and model ratio_between_observation_and_model = pcr.ifthenelse(self.model.landSurface.satDegUpp000005 > 0.0, constrained_satDegUpp000005 / \ self.model.landSurface.satDegUpp000005, 0.0) # updating upper soil states for all lad cover types for coverType in self.model.landSurface.coverTypes: # correcting upper soil state (storUpp000005) self.model.landSurface.landCoverObj[ coverType].storUpp000005 *= ratio_between_observation_and_model # if model value = 0.0, storUpp000005 is calculated based on storage capacity (model parameter) and observed saturation degree self.model.landSurface.landCoverObj[coverType].storUpp000005 = pcr.ifthenelse( self.model.landSurface.satDegUpp000005 > 0.0, \ self.model.landSurface.landCoverObj[coverType].storUpp000005, \ constrained_satDegUpp000005 * self.model.landSurface.parameters.storCapUpp000005) # correct for any scaling issues (value < 0 or > 1 do not make sense self.model.landSurface.landCoverObj[ coverType].storUpp000005 = pcr.min( 1.0, pcr.max( 0.0, self.model.landSurface.landCoverObj[coverType]. storUpp000005)) def set_value(self, long_var_name, src): if self.model is None or not hasattr(self.model.landSurface, 'satDegUpp000005'): logger.info("cannot set value for %s, as model has not run yet.", long_var_name) return logger.info("setting value for %s", long_var_name) # logger.info("dumping state to %s", self.configuration.endStateDir) # self.model.dumpStateDir(self.configuration.endStateDir + "/pre/") # print "got value to set", src # make sure the raster is the right side up src = np.flipud(src) # print "flipped", src # cast to pcraster precision src = src.astype(np.float32) # print "as float 32", src sys.stdout.flush() logger.info("setting value shape %s", src.shape) if (long_var_name == "top_layer_soil_saturation"): self.set_satDegUpp000005(src) else: raise Exception("unknown var name" + long_var_name) # write state here to facilitate restarting tomorrow # logger.info("dumping state to %s", self.configuration.endStateDir) # self.model.dumpStateDir(self.configuration.endStateDir + "/post/") def set_value_at_indices(self, long_var_name, inds, src): raise NotImplementedError def get_grid_type(self, long_var_name): return BmiGridType.UNIFORM def get_grid_shape(self, long_var_name): return def get_grid_shape(self, long_var_name): return self.shape def get_grid_spacing(self, long_var_name): cellsize = pcr.clone().cellSize() return np.array([cellsize, cellsize]) def get_grid_origin(self, long_var_name): north = pcr.clone().north() cellSize = pcr.clone().cellSize() nrRows = pcr.clone().nrRows() south = north - (cellSize * nrRows) west = pcr.clone().west() return np.array([south, west]) def get_grid_x(self, long_var_name): raise ValueError def get_grid_y(self, long_var_name): raise ValueError def get_grid_z(self, long_var_name): raise ValueError def get_grid_connectivity(self, long_var_name): raise ValueError def get_grid_offset(self, long_var_name): raise ValueError #EBMI functions def set_start_time(self, start_time): self.model_time.setStartTime(self.in_modeltime(start_time)) def set_end_time(self, end_time): self.model_time.setEndTime(self.in_modeltime(end_time)) def get_attribute_names(self): raise NotImplementedError def get_attribute_value(self, attribute_name): raise NotImplementedError def set_attribute_value(self, attribute_name, attribute_value): raise NotImplementedError def save_state(self, destination_directory): logger.info("saving state to %s", destination_directory) self.model.dumpStateDir(destination_directory) def load_state(self, source_directory): raise NotImplementedError