def setUp(self): self.year97 = timetools.Date('01.11.1996') self.year98 = timetools.Date('01.11.1997') self.oneday = timetools.Period('1d') self.onehour = timetools.Period('1h') self.timegrid = timetools.Timegrid(self.year97, self.year98, self.oneday)
def __call__(self, *args, **kwargs): try: super().__call__(*args, **kwargs) except NotImplementedError: try: tal = float(kwargs["tal"]) hot = float(kwargs["hot"]) hut = float(kwargs["hut"]) except KeyError: raise ValueError( "For the alternative calculation of parameter `tind`, " "values for all three keyword keyword arguments `tal`, " "`hot`, and `hut` must be given.") from None if (tal <= 0.0) or (hot <= hut): raise ValueError( f"For the alternative calculation of parameter `tind`, " f"the value assigned to keyword argument `tal` must be " f"greater then zero and the one of `hot` must be greater " f"than the one of `hut`. However, for element " f"{objecttools.devicename(self)}, the values `{tal}`, " f"`{hot}` and `{hut}` were given respectively.") from None self.value = (0.868 * tal**3 / (hot - hut))**0.385 if (self > 1000.0) or (self < 0.001): warnings.warn( f"Due to the given values for the keyword arguments " f"`tal` ({tal}), `hot` ({hot}) and `hut` ({hut}), " f"parameter `tind` of element " f"`{objecttools.devicename(self)}` has been set to an " f"unrealistic value of {objecttools.repr_(self.value)} " f"hours.") self.value *= timetools.Period( "1h") / hydpy.pub.options.simulationstep
def __call__(self, *args, **kwargs): """The prefered way to pass values to |TInd| instances within parameter control files. """ try: super().__call__(*args, **kwargs) except NotImplementedError: try: tal = float(kwargs['tal']) hot = float(kwargs['hot']) hut = float(kwargs['hut']) except KeyError: raise ValueError( 'For the alternative calculation of parameter `tind`, ' 'values for all three keyword keyword arguments `tal`, ' '`hot`, and `hut` must be given.') if (tal <= 0.) or (hot <= hut): raise ValueError( 'For the alternative calculation of parameter ' '`tind`, the value assigned to keyword argument ' '`tal` must be greater then zero and the one of ' '`hot` must be greater than the one of `hut`. ' 'However, for element %s, the values `%s`, `%s` ' 'and `%s` were given respectively.' % (objecttools.devicename(self), tal, hot, hut)) self.value = (.868 * tal**3 / (hot - hut))**.385 if (self > 1000.) or (self < .001): warnings.warn( 'Due to the given values for the keyword arguments ' '`tal` (%s), `hot` (%s) and `hut` (%s), parameter ' '`tind` of element `%s` has been set to an ' 'unrealistic value of `%s hours`.' % (tal, hot, hut, objecttools.devicename(self), objecttools.repr_(self.value))) self.value *= timetools.Period('1h') / self.simulationstep
def _prepare_shape(self) -> None: """Private on purpose.""" nmb_weights = timetools.Period( "366d") / hydpy.pub.options.simulationstep nmb_weights = int(numpy.ceil(round(nmb_weights, 10))) shape = (nmb_weights, self._seasonalinterpolator.nmb_algorithms) getattr(self.fastaccess, self.name).ratios = numpy.zeros(shape, dtype=float)
def test_02_wrong(self): with self.assertRaises(ValueError): timetools.Timegrid(self.year97, self.year97, self.oneday) with self.assertRaises(ValueError): timetools.Timegrid(self.year98, self.year97, self.oneday) with self.assertRaises(ValueError): timetools.Timegrid(self.year97, self.year98, timetools.Period('360d'))
def prepare_model( module: Union[types.ModuleType, str], timestep: Optional[timetools.PeriodConstrArg] = None, ) -> modeltools.Model: """Prepare and return the model of the given module. In usual *HydPy* projects, each control file prepares an individual model instance only, which allows for "polluting" the namespace with different model attributes. There is no danger of name conflicts, as long as we do not perform other (wildcard) imports. However, there are situations where we need to load different models into the same namespace. Then it is advisable to use function |prepare_model|, which returns a reference to the model and nothing else. See the documentation of |dam_v001| on how to apply function |prepare_model| properly. """ if timestep is not None: hydpy.pub.options.parameterstep = timetools.Period(timestep) try: model = module.Model() except AttributeError: module = importlib.import_module(f"hydpy.models.{module}") model = module.Model() if hydpy.pub.options.usecython and hasattr(module, "cythonizer"): cymodule = module.cythonizer.cymodule cymodel = cymodule.Model() if hasattr(cymodule, "Parameters"): cymodel.parameters = cymodule.Parameters() cymodel.sequences = cymodule.Sequences() model.cymodel = cymodel for numpars_name in ("NumConsts", "NumVars"): if hasattr(cymodule, numpars_name): numpars_new = getattr(cymodule, numpars_name)() numpars_old = getattr(model, numpars_name.lower()) for (name_numpar, numpar) in vars(numpars_old).items(): setattr(numpars_new, name_numpar, numpar) setattr(cymodel, numpars_name.lower(), numpars_new) for name in dir(cymodel): if (not name.startswith("_")) and hasattr(model, name): setattr(model, name, getattr(cymodel, name)) dict_ = {"cythonmodule": cymodule, "cymodel": cymodel} else: dict_ = {} dict_.update(vars(module)) dict_["model"] = model model.parameters = prepare_parameters(dict_) model.sequences = prepare_sequences(dict_) if hasattr(module, "Masks"): model.masks = module.Masks() else: model.masks = masktools.Masks() for submodelclass in module.Model.SUBMODELS: submodel = submodelclass(model) setattr(model, submodel.name, submodel) return model
def parameterstep(timestep=None): """ Define a parameter time step size within a parameter control file. Argument: * timestep(:class:`~hydpy.core.timetools.Period`): Time step size. Function :func:`parameterstep` should usually be be applied in a line immediately behind the model import. Defining the step size of time dependent parameters is a prerequisite to access any model specific parameter. Note that :func:`parameterstep` implements some namespace magic by means of the module :mod:`inspect`. This makes things a little complicated for framework developers, but it eases the definition of parameter control files for framework users. """ if timestep is not None: parametertools.Parameter._parameterstep = timetools.Period(timestep) namespace = inspect.currentframe().f_back.f_locals model = namespace.get('model') if model is None: model = namespace['Model']() namespace['model'] = model if pub.options.usecython and 'cythonizer' in namespace: cythonizer = namespace['cythonizer'] namespace['cythonmodule'] = cythonizer.cymodule model.cymodel = cythonizer.cymodule.Model() namespace['cymodel'] = model.cymodel for (name, func) in cythonizer.pyxwriter.listofmodeluserfunctions: setattr(model, name, getattr(model.cymodel, name)) for func in ('doit', 'new2old', 'openfiles', 'closefiles', 'loaddata', 'savedata'): if hasattr(model.cymodel, func): setattr(model, func, getattr(model.cymodel, func)) model.parameters = namespace['Parameters'](namespace) model.sequences = namespace['Sequences'](namespace) namespace['parameters'] = model.parameters for (name, pars) in model.parameters: namespace[name] = pars namespace['sequences'] = model.sequences for (name, seqs) in model.sequences: namespace[name] = seqs try: namespace.update(namespace['CONSTANTS']) except KeyError: pass focus = namespace.get('focus') for (name, par) in model.parameters.control: try: if (focus is None) or (par is focus): namespace[par.name] = par else: namespace[par.name] = lambda *args, **kwargs: None except AttributeError: pass
def __call__(self, *args, **kwargs): try: args = [timetools.Period(args[0]).seconds] except BaseException: objecttools.augment_excmessage( 'While trying the set the value of parameter `maxdt` ' 'of the lake model handled by element `%s`' % objecttools.devicename(self), '(An example: set `max dt` to 3600 seconds by writing ' '`maxdt("1h"))') super().__call__(*args, **kwargs)
def prepare_model(module, timestep=None): """Prepare and return the model of the given module. In usual HydPy projects, each hydrological model instance is prepared in an individual control file. This allows for "polluting" the namespace with different model attributes. There is no danger of name conflicts, as long as no other (wildcard) imports are performed. However, there are situations when different models are to be loaded into the same namespace. Then it is advisable to use function |prepare_model|, which just returns a reference to the model and nothing else. See the documentation of |dam_v001| on how to apply function |prepare_model| properly. """ if timestep is not None: parametertools.Parameter.parameterstep(timetools.Period(timestep)) model = module.Model() if pub.options.usecython and hasattr(module, 'cythonizer'): cymodule = module.cythonizer.cymodule cymodel = cymodule.Model() cymodel.parameters = cymodule.Parameters() cymodel.sequences = cymodule.Sequences() model.cymodel = cymodel for numpars_name in ('NumConsts', 'NumVars'): if hasattr(cymodule, numpars_name): numpars_new = getattr(cymodule, numpars_name)() numpars_old = getattr(model, numpars_name.lower()) for (name_numpar, numpar) in vars(numpars_old).items(): setattr(numpars_new, name_numpar, numpar) setattr(cymodel, numpars_name.lower(), numpars_new) for name in dir(cymodel): if (not name.startswith('_')) and hasattr(model, name): setattr(model, name, getattr(cymodel, name)) dict_ = {'cythonmodule': cymodule, 'cymodel': cymodel} else: dict_ = {} dict_.update(vars(module)) dict_['model'] = model if hasattr(module, 'Parameters'): model.parameters = module.Parameters(dict_) else: model.parameters = parametertools.Parameters(dict_) if hasattr(module, 'Sequences'): model.sequences = module.Sequences(**dict_) else: model.sequences = sequencetools.Sequences(**dict_) return model
def __call__(self, *args, **kwargs): """The prefered way to pass values to :class:`TInd` instances within parameter control files. """ try: parametertools.SingleParameter.__call__(self, *args, **kwargs) except NotImplementedError: counter = ('tal' in kwargs) + ('hot' in kwargs) + ('hut' in kwargs) if counter == 0: raise ValueError('For parameter `tind` a value can be set ' 'directly by passing a single value or ' 'indirectly by using the keyword arguments ' '`tal`, `hot`, and `hut`.') elif counter < 3: raise ValueError('For the alternative calculation of ' 'parameter `tind`, values for all three ' 'keyword keyword arguments `tal`, `hot`, ' 'and `hut` must be given.') else: tal = float(kwargs['tal']) hot = float(kwargs['hot']) hut = float(kwargs['hut']) if (tal <= 0.) or (hot <= hut): raise ValueError( 'For the alternative calculation of ' 'parameter `tind`, the value assigned to ' 'keyword argument `tal` must be greater ' 'then zero and the one of `hot` must be ' 'greater than the one of `hut`. ' 'However, for element %s, the values ' '`%s`, `%s` and `%s` were given ' 'respectively.' % (objecttools.devicename(self), tal, hot, hut)) self.value = (.868 * tal**3 / (hot - hut))**.385 if (self > 1000.) or (self < .001): warnings.warn('Due to the given values for the keyword ' 'arguments `tal` (%s), `hot` (%s) and `hut` ' '(%s), parameter `tind` of element `%s` has ' 'been set to an unrealistic value of `%s ' 'hours`.' % (tal, hot, hut, objecttools.devicename(self), round(self.value, 6))) self.value *= timetools.Period('1h') / self.simulationstep
def simulationstep(timestep): """ Define a simulation time step size for testing purposes within a parameter control file. Using |simulationstep| only affects the values of time dependent parameters, when `pub.timegrids.stepsize` is not defined. It thus has no influence on usual hydpy simulations at all. Use it just to check your parameter control files. Write it in a line immediately behind the one calling |parameterstep|. """ if pub.options.warnsimulationstep: warnings.warn( 'Note that the applied function `simulationstep` is inteded for ' 'testing purposes only. When doing a hydpy simulation, parameter ' 'values are initialized based on the actual simulation time step ' 'as defined under `pub.timegrids.stepsize` and the value given ' 'to `simulationstep` is ignored.') parametertools.Parameter.simulationstep(timetools.Period(timestep))
def simulationstep(timestep): """ Define a simulation time step size for testing purposes within a parameter control file. Argument: * timestep(:class:`~hydpy.core.timetools.Period`): Time step size. Using :func:`simulationstep` only affects the values of time dependent parameters, when `pub.timegrids.stepsize` is not defined. It thus has no influence on usual hydpy simulations at all. Use it just to check your parameter control files. Write it in a line immediately behind the one calling :func:`parameterstep`. """ if pub.options.warnsimulationstep: warnings.warn('Note that the applied function `simulationstep` is ' 'inteded for testing purposes only. When doing a ' 'hydpy simulation, parameter values are initialized ' 'based on the actual simulation time step as defined ' 'under `pub.timegrids.stepsize` and the value given ' 'to `simulationstep` is ignored.') parametertools.Parameter._simulationstep = timetools.Period(timestep)
def parameterstep(timestep=None): """Define a parameter time step size within a parameter control file. Argument: * timestep(|Period|): Time step size. Function parameterstep should usually be be applied in a line immediately behind the model import. Defining the step size of time dependent parameters is a prerequisite to access any model specific parameter. Note that parameterstep implements some namespace magic by means of the module |inspect|. This makes things a little complicated for framework developers, but it eases the definition of parameter control files for framework users. """ if timestep is not None: parametertools.Parameter.parameterstep(timetools.Period(timestep)) namespace = inspect.currentframe().f_back.f_locals model = namespace.get('model') if model is None: model = namespace['Model']() namespace['model'] = model if pub.options.usecython and 'cythonizer' in namespace: cythonizer = namespace['cythonizer'] namespace['cythonmodule'] = cythonizer.cymodule model.cymodel = cythonizer.cymodule.Model() namespace['cymodel'] = model.cymodel model.cymodel.parameters = cythonizer.cymodule.Parameters() model.cymodel.sequences = cythonizer.cymodule.Sequences() for numpars_name in ('NumConsts', 'NumVars'): if hasattr(cythonizer.cymodule, numpars_name): numpars_new = getattr(cythonizer.cymodule, numpars_name)() numpars_old = getattr(model, numpars_name.lower()) for (name_numpar, numpar) in vars(numpars_old).items(): setattr(numpars_new, name_numpar, numpar) setattr(model.cymodel, numpars_name.lower(), numpars_new) for name in dir(model.cymodel): if (not name.startswith('_')) and hasattr(model, name): setattr(model, name, getattr(model.cymodel, name)) if 'Parameters' not in namespace: namespace['Parameters'] = parametertools.Parameters model.parameters = namespace['Parameters'](namespace) if 'Sequences' not in namespace: namespace['Sequences'] = sequencetools.Sequences model.sequences = namespace['Sequences'](**namespace) namespace['parameters'] = model.parameters for pars in model.parameters: namespace[pars.name] = pars namespace['sequences'] = model.sequences for seqs in model.sequences: namespace[seqs.name] = seqs try: namespace.update(namespace['CONSTANTS']) except KeyError: pass focus = namespace.get('focus') for par in model.parameters.control: try: if (focus is None) or (par is focus): namespace[par.name] = par else: namespace[par.name] = lambda *args, **kwargs: None except AttributeError: pass
def test_02_hour(self): self.assertEqual(timetools.Period('25h').unit, 'h') self.assertEqual(timetools.Period('1h').unit, 'h') self.assertEqual(timetools.Period('60m').unit, 'h') self.assertEqual(timetools.Period('3600s').unit, 'h')
def test_04_string_second(self): self.assertEqual(datetime.timedelta(0, 1), timetools.Period('1s').timedelta)
def test_05_timedelta(self): timedelta = datetime.timedelta(365) self.assertEqual(timedelta, timetools.Period(timedelta).timedelta)
def test_01_day(self): self.assertEqual(timetools.Period('365d').unit, 'd') self.assertEqual(timetools.Period('1d').unit, 'd') self.assertEqual(timetools.Period('24h').unit, 'd') self.assertEqual(timetools.Period('1440m').unit, 'd') self.assertEqual(timetools.Period('86400m').unit, 'd')
def test_03_minute(self): self.assertEqual(timetools.Period('777m').unit, 'm') self.assertEqual(timetools.Period('1m').unit, 'm') self.assertEqual(timetools.Period('60s').unit, 'm')
def test_03_string_minute(self): self.assertEqual(datetime.timedelta(0, 60), timetools.Period('1m').timedelta)
def test_02_iadd(self): self.oneyear += self.oneday self.assertEqual(self.oneyear, timetools.Period('366d'))
def test_01_add(self): testdate = self.oneyear + self.year97 self.assertEqual(self.year98, testdate) self.assertEqual(testdate.style, 'din') self.assertEqual(self.oneyear + self.oneday, timetools.Period('366d'))
def setUp(self): self.short1 = timetools.Period('1h') self.short2 = timetools.Period('1h') self.long = timetools.Period('1d')
def setUp(self): self.period = timetools.Period('1d')
def test_04_second(self): self.assertEqual(timetools.Period('999s').unit, 's') self.assertEqual(timetools.Period('1s').unit, 's')
def controlcheck( controldir: str = "default", projectdir: Optional[str] = None, controlfile: Optional[str] = None, firstdate: Optional[timetools.DateConstrArg] = None, stepsize: Optional[timetools.PeriodConstrArg] = None, ) -> None: """Define the corresponding control file within a condition file. Function |controlcheck| serves similar purposes as function |parameterstep|. It is the reason why one can interactively access the state and the log sequences within condition files as `land_dill.py` of the example project `LahnH`. It is called `controlcheck` due to its feature to check for possible inconsistencies between control and condition files. The following test, where we write a number of soil moisture values (|hland_states.SM|) into condition file `land_dill.py`, which does not agree with the number of hydrological response units (|hland_control.NmbZones|) defined in control file `land_dill.py`, verifies that this, in fact, works within a separate Python process: >>> from hydpy.examples import prepare_full_example_1 >>> prepare_full_example_1() >>> import os >>> from hydpy import run_subprocess, TestIO >>> cwd = os.path.join("LahnH", "conditions", "init_1996_01_01_00_00_00") >>> with TestIO(): # doctest: +ELLIPSIS ... os.chdir(cwd) ... with open("land_dill.py") as file_: ... lines = file_.readlines() ... lines[10:12] = "sm(185.13164, 181.18755)", "" ... with open("land_dill.py", "w") as file_: ... _ = file_.write("\\n".join(lines)) ... print() ... result = run_subprocess("hyd.py exec_script land_dill.py") <BLANKLINE> ... While trying to set the value(s) of variable `sm`, the following error \ occurred: While trying to convert the value(s) `(185.13164, 181.18755)` to \ a numpy ndarray with shape `(12,)` and type `float`, the following error \ occurred: could not broadcast input array from shape (2...) into shape (12...) ... With a little trick, we can fake to be "inside" condition file `land_dill.py`. Calling |controlcheck| then, for example, prepares the shape of sequence |hland_states.Ic| as specified by the value of parameter |hland_control.NmbZones| given in the corresponding control file: >>> from hydpy.models.hland_v1 import * >>> __file__ = "land_dill.py" >>> with TestIO(): ... os.chdir(cwd) ... controlcheck(firstdate="1996-01-01", stepsize="1d") >>> ic.shape (12,) In the above example, we use the default names for the project directory (the one containing the executed condition file) and the control directory (`default`). The following example shows how to change them: >>> del model >>> with TestIO(): # doctest: +ELLIPSIS ... os.chdir(cwd) ... controlcheck(projectdir="somewhere", controldir="nowhere") Traceback (most recent call last): ... FileNotFoundError: While trying to load the control file `land_dill.py` \ from directory `...hydpy/tests/iotesting/somewhere/control/nowhere`, \ the following error occurred: ... For some models, the suitable states may depend on the initialisation date. One example is the interception storage (|lland_states.Inzp|) of application model |lland_v1|, which should not exceed the interception capacity (|lland_derived.KInz|). However, |lland_derived.KInz| itself depends on the leaf area index parameter |lland_control.LAI|, which offers varying values both for different land-use types and months. Hence, one can assign higher values to state |lland_states.Inzp| during periods with high leaf area indices than during periods with small leaf area indices. To show the related functionalities, we first replace the |hland_v1| application model of element `land_dill` with a |lland_v1| model object, define some of its parameter values, and write its control and condition files. Note that the |lland_control.LAI| value of the only relevant land-use (|lland_constants.ACKER|) is 0.5 during January and 5.0 during July: >>> from hydpy import HydPy, prepare_model, pub >>> from hydpy.models.lland_v1 import ACKER >>> pub.timegrids = "2000-06-01", "2000-07-01", "1d" >>> with TestIO(): ... hp = HydPy("LahnH") ... hp.prepare_network() ... land_dill = hp.elements["land_dill"] ... with pub.options.usedefaultvalues(True): ... land_dill.model = prepare_model("lland_v1") ... control = land_dill.model.parameters.control ... control.nhru(2) ... control.ft(1.0) ... control.fhru(0.5) ... control.hnn(100.0) ... control.lnk(ACKER) ... control.lai.acker_jan = 0.5 ... control.lai.acker_jul = 5.0 ... land_dill.model.parameters.update() ... land_dill.model.sequences.states.inzp(1.0) ... land_dill.model.parameters.save_controls() ... land_dill.model.sequences.save_conditions() Unfortunately, state |lland_states.Inzp| does not define a |trim| method taking the actual value of parameter |lland_derived.KInz| into account (due to compatibility with the original LARSIM model). As an auxiliary solution, we define such a function within the `land_dill.py` condition file (and additionally modify some warning settings in favour of the next examples): >>> cwd = os.path.join("LahnH", "conditions", "init_2000_07_01_00_00_00") >>> with TestIO(): ... os.chdir(cwd) ... with open("land_dill.py") as file_: ... lines = file_.readlines() ... with open("land_dill.py", "w") as file_: ... file_.writelines([ ... "from hydpy import pub\\n", ... "pub.options.warnsimulationstep = False\\n", ... "import warnings\\n", ... 'warnings.filterwarnings("error", message="For variable")\\n']) ... file_.writelines(lines[:5]) ... file_.writelines([ ... "from hydpy.core.variabletools import trim as trim_\\n", ... "def trim(self, lower=None, upper=None):\\n", ... " der = self.subseqs.seqs.model.parameters.derived\\n", ... " trim_(self, 0.0, der.kinz.acker[der.moy[0]])\\n", ... "type(inzp).trim = trim\\n"]) ... file_.writelines(lines[5:]) Now, executing the condition file (and thereby calling function |controlcheck|) does not raise any warnings due to extracting the initialisation date from the name of the condition directory: >>> with TestIO(): ... os.chdir(cwd) ... result = run_subprocess("hyd.py exec_script land_dill.py") If the directory name does imply the initialisation date to be within January 2000 instead of July 2000, we correctly get the following warning: >>> cwd_old = cwd >>> cwd_new = os.path.join("LahnH", "conditions", "init_2000_01_01") >>> with TestIO(): # doctest: +ELLIPSIS ... os.rename(cwd_old, cwd_new) ... os.chdir(cwd_new) ... result = run_subprocess("hyd.py exec_script land_dill.py") Invoking hyd.py with arguments `exec_script, land_dill.py` resulted \ in the following error: For variable `inzp` at least one value needed to be trimmed. \ The old and the new value(s) are `1.0, 1.0` and `0.1, 0.1`, respectively. ... One can define an alternative initialisation date via argument `firstdate`: >>> text_old = ('controlcheck(projectdir=r"LahnH", ' ... 'controldir="default", stepsize="1d")') >>> text_new = ('controlcheck(projectdir=r"LahnH", controldir="default", ' ... 'firstdate="2100-07-15", stepsize="1d")') >>> with TestIO(): ... os.chdir(cwd_new) ... with open("land_dill.py") as file_: ... text = file_.read() ... text = text.replace(text_old, text_new) ... with open("land_dill.py", "w") as file_: ... _ = file_.write(text) ... result = run_subprocess("hyd.py exec_script land_dill.py") Default condition directory names do not contain any information about the simulation step size. Hence, one needs to define it explicitly for all application modelsrelying on the functionalities of class |Indexer|: >>> with TestIO(): # doctest: +ELLIPSIS ... os.chdir(cwd_new) ... with open("land_dill.py") as file_: ... text = file_.read() ... text = text.replace('stepsize="1d"', "") ... with open("land_dill.py", "w") as file_: ... _ = file_.write(text) ... result = run_subprocess("hyd.py exec_script land_dill.py") Invoking hyd.py with arguments `exec_script, land_dill.py` resulted \ in the following error: To apply function `controlcheck` requires time information for some \ model types. Please define the `Timegrids` object of module `pub` manually \ or pass the required information (`stepsize` and eventually `firstdate`) \ as function arguments. ... The same error occurs we do not use the argument `firstdate` to define the initialisation time point, and method |controlcheck| cannot extract it from the directory name: >>> cwd_old = cwd_new >>> cwd_new = os.path.join("LahnH", "conditions", "init") >>> with TestIO(): # doctest: +ELLIPSIS ... os.rename(cwd_old, cwd_new) ... os.chdir(cwd_new) ... with open("land_dill.py") as file_: ... text = file_.read() ... text = text.replace('firstdate="2100-07-15"', 'stepsize="1d"') ... with open("land_dill.py", "w") as file_: ... _ = file_.write(text) ... result = run_subprocess("hyd.py exec_script land_dill.py") Invoking hyd.py with arguments `exec_script, land_dill.py` resulted \ in the following error: To apply function `controlcheck` requires time information for some \ model types. Please define the `Timegrids` object of module `pub` manually \ or pass the required information (`stepsize` and eventually `firstdate`) \ as function arguments. ... Note that the functionalities of function |controlcheck| do not come into action if there is a `model` variable in the namespace, which is the case when a condition file is executed within the context of a complete *HydPy* project. """ namespace = inspect.currentframe().f_back.f_locals model = namespace.get("model") if model is None: if not controlfile: controlfile = os.path.split(namespace["__file__"])[-1] if projectdir is None: projectdir = os.path.split( os.path.split(os.path.split(os.getcwd())[0])[0])[-1] dirpath = os.path.abspath( os.path.join("..", "..", "..", projectdir, "control", controldir)) if not (exceptiontools.attrready(hydpy.pub, "timegrids") or (stepsize is None)): if firstdate is None: try: firstdate = timetools.Date.from_string( os.path.split(os.getcwd())[-1].partition("_")[-1]) except (ValueError, TypeError): pass else: firstdate = timetools.Date(firstdate) if firstdate is not None: stepsize = timetools.Period(stepsize) hydpy.pub.timegrids = (firstdate, firstdate + 1000 * stepsize, stepsize) class CM(filetools.ControlManager): """Tempory |ControlManager| class.""" currentpath = dirpath cwd = os.getcwd() try: os.chdir(dirpath) model = CM().load_file(filename=controlfile)["model"] except BaseException: objecttools.augment_excmessage( f"While trying to load the control file `{controlfile}` " f"from directory `{objecttools.repr_(dirpath)}`") finally: os.chdir(cwd) try: model.parameters.update() except exceptiontools.AttributeNotReady as exc: raise RuntimeError( "To apply function `controlcheck` requires time " "information for some model types. Please define " "the `Timegrids` object of module `pub` manually " "or pass the required information (`stepsize` and " "eventually `firstdate`) as function arguments.") from exc namespace["model"] = model for name in ("states", "logs"): subseqs = getattr(model.sequences, name, None) if subseqs is not None: for seq in subseqs: namespace[seq.name] = seq
def test_10_mod(self): self.assertFalse(self.oneyear % self.oneday) self.assertTrue(self.oneyear % timetools.Period('360d'))
def test_11_floordiv(self): self.assertTrue(self.oneyear // self.oneday) self.assertFalse(self.oneyear // timetools.Period('360d'))
def setUp(self): self.year97 = timetools.Date('01.11.1996') self.year98 = timetools.Date('01.11.1997') self.oneday = timetools.Period('1d')
def test_04_isub(self): self.oneyear -= self.oneday self.assertEqual(self.oneyear, timetools.Period('364d'))
def setUp(self): seconds = int(60 * 60 * 24 * 365 * 3.2) self.refperiod = datetime.timedelta(0, seconds) self.testperiod = timetools.Period('%ds' % seconds)