Skip to content

Commit

Permalink
Release 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Dal Molin committed Sep 7, 2020
1 parent b9614dc commit cd977bf
Show file tree
Hide file tree
Showing 20 changed files with 1,544 additions and 804 deletions.
11 changes: 8 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@

setuptools.setup(
name='superflexpy',
version='0.3.1',
version='0.0.13',
author='Marco Dal Molin',
author_email='[email protected]',
description='Framework for building hydrological models',
long_description='Framework for building hydrological models',
license='Apache Software License',
packages=setuptools.find_packages(),
classifiers=[
'Development Status :: 3 - Alpha' # https://martin-thoma.com/software-development-stages/
]
'Development Status :: 5 - Production/Stable', # https://martin-thoma.com/software-development-stages/
],
install_requires=[
'numpy>=1.16.4',
'numba>=0.49.0',
],
)
71 changes: 39 additions & 32 deletions superflexpy/framework/element.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Copyright 2019 Marco Dal Molin et al.
Copyright 2020 Marco Dal Molin et al.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,7 +37,7 @@ class BaseElement():
"""
Number of downstream elements
"""

_num_upstream = None
"""
Number of upstream elements
Expand Down Expand Up @@ -469,7 +469,7 @@ class ODEsElement(StateParameterizedElement):
dS/dt = input - output
"""

_num_upstream = 1
"""
Number of upstream elements
Expand All @@ -485,7 +485,25 @@ class ODEsElement(StateParameterizedElement):
List of states used by the solver of the differential equation
"""

def __init__(self, parameters, states, solver, id):
_fluxes = []
"""
This attribute contains a list of methods (one per differential equation)
that calculate the values of the fluxes needed to solve the differential
equations that control the element. The single functions must return the
fluxes as a list where incoming fluxes are positive and outgoing are
negative. Here is a list of the required outputs of the single functions:
list(floats)
Values of the fluxes given states, inputs, and parameters.
float
Minimum value of the state. Used, sometimes, by the numerical solver
to search for the solution.
float
Maximum value of the state. Used, sometimes, by the numerical solver
to search for the solution.
"""

def __init__(self, parameters, states, approximation, id):
"""
This is the initializer of the abstract class ODEsElement.
Expand All @@ -498,10 +516,8 @@ def __init__(self, parameters, states, solver, id):
states : dict
Initial states of the element. Depending on the element the states
can be either a float or a numpy.ndarray.
solver : superflexpy.utils.root_finder.RootFinder
Solver used to find the root(s) of the differential equation(s).
Child classes may implement their own solver, therefore the type
of the solver is not enforced.
approximation : superflexpy.utils.numerical_approximation.NumericalApproximator
Numerial method used to approximate the differential equation
id : str
Identifier of the element. All the elements of the framework must
have an id.
Expand All @@ -510,7 +526,7 @@ def __init__(self, parameters, states, solver, id):
StateParameterizedElement.__init__(self, parameters=parameters,
states=states, id=id)

self._solver = solver
self._num_app = approximation

def set_timestep(self, dt):
"""
Expand All @@ -534,7 +550,7 @@ def get_timestep(self):
"""
return self._dt

def define_solver(self, solver):
def define_numerical_approximation(self, approximation):
"""
This method define the solver to use for the differential equation.
Expand All @@ -546,7 +562,7 @@ def define_solver(self, solver):
of the solver is not enforced.
"""

self._solver = solver
self._num_app = approximation

def _solve_differential_equation(self, **kwargs):
"""
Expand All @@ -559,29 +575,20 @@ def _solve_differential_equation(self, **kwargs):
message = '{}the attribute _solver_states must be filled'.format(self._error_message)
raise ValueError(message)

self.state_array = self._solver.solve(fun=self._differential_equation,
S0=self._solver_states,
dt=self._dt,
**self.input,
**{k[len(self._prefix_parameters):]: self._parameters[k] for k in self._parameters},
**kwargs)

def _differential_equation(self):
"""
To be implemented by any child class. This method sets the differential
equation(s) to be solved by the solver. The method must be implemented
in order to satisfy the requirements of the solver.
"""

raise NotImplementedError('The _differential_equation method must be implemented')
self.state_array = self._num_app.solve(fun=self._fluxes,
S0=self._solver_states,
dt=self._dt,
**self.input,
**{k[len(self._prefix_parameters):]: self._parameters[k] for k in self._parameters},
**kwargs)

def __copy__(self):
p = self._parameters # Only the reference
s = deepcopy(self._states) # Create a new dictionary
ele = self.__class__(parameters=p,
states=s,
id=self.id,
solver=self._solver)
approximation=self._num_app)
ele._prefix_states = self._prefix_states
ele._prefix_parameters = self._prefix_parameters
return ele
Expand All @@ -592,7 +599,7 @@ def __deepcopy__(self, memo):
ele = self.__class__(parameters=p,
states=s,
id=self.id,
solver=self._solver)
approximation=self._num_app)
ele._prefix_states = self._prefix_states
ele._prefix_parameters = self._prefix_parameters
return ele
Expand Down Expand Up @@ -728,7 +735,7 @@ def _solve_lag(weight, lag_state, input):
"""
This method distributes the input fluxes according to the weight array
and the initial state.
Parameters
----------
weight : list(numpy.ndarray)
Expand All @@ -737,7 +744,7 @@ def _solve_lag(weight, lag_state, input):
List of the initial states of the lag.
input : list(numpy.ndarray)
List of fluxes
Returns
-------
numpy.ndarray
Expand All @@ -761,12 +768,12 @@ def _init_lag_state(self, lag_time):
"""
This method sets the initial state of the lag to arrays of proper
length.
Parameters
----------
lag_time : list(float)
List of lag times
Returns
-------
list(numpy.ndarray)
Expand Down
30 changes: 23 additions & 7 deletions superflexpy/framework/network.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Copyright 2019 Marco Dal Molin et al.
Copyright 2020 Marco Dal Molin et al.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -23,6 +23,7 @@
"""

from ..utils.generic_component import GenericComponent
from .node import Node


class Network(GenericComponent):
Expand All @@ -47,12 +48,17 @@ def __init__(self, nodes, topography):
be a tree, each key has only one downstream element
"""

self._content = nodes
self._downstream = topography

self._error_message = 'module : superflexPy, Network ,'
self._error_message += ' Error message : '

for n in nodes:
if not isinstance(n, Node):
message = '{}units must be instance of the Unit class'.format(self._error_message)
raise TypeError(message)

self._content = nodes
self._downstream = topography

self._build_network()

# METHODS FOR THE USER
Expand Down Expand Up @@ -146,7 +152,12 @@ def get_internal(self, id, attribute):
cat_num, ele = self._find_attribute_from_name(id)

if ele:
return self._content[cat_num].get_internal(id, attribute)
splitted = id.split('_')
if len(splitted) == 3: # element
ele_id = splitted[1] + '_' + splitted[2]
else: # unit
ele_id = splitted[1]
return self._content[cat_num].get_internal(ele_id, attribute)
else:
try:
method = getattr(self._content[cat_num], attribute)
Expand Down Expand Up @@ -178,7 +189,12 @@ def call_internal(self, id, method, **kwargs):
cat_num, ele = self._find_attribute_from_name(id)

if ele:
return self._content[cat_num].call_internal(id, method, **kwargs)
splitted = id.split('_')
if len(splitted) == 3: # element
ele_id = splitted[1] + '_' + splitted[2]
else: # unit
ele_id = splitted[1]
return self._content[cat_num].call_internal(ele_id, method, **kwargs)
else:
try:
method = getattr(self._content[cat_num], method)
Expand Down Expand Up @@ -264,7 +280,7 @@ def _find_attribute_from_name(self, id):

splitted = id.split('_')

cat_num = self._find_content_from_name(id)
cat_num = self._find_content_from_name(id) # Options: None if cat_id not in id, number otherwise

if len(splitted) >= 2:
return (cat_num, True) # We are looking for a HRU or an element
Expand Down
Loading

0 comments on commit cd977bf

Please sign in to comment.