Skip to content

Commit

Permalink
Resolved bug for zero-valued differential equations declared in eleme…
Browse files Browse the repository at this point in the history
…ntary form, by creating an dummy constant-like enode
  • Loading branch information
hfsf committed Jan 19, 2020
1 parent 6ec558f commit 48cd054
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 31 deletions.
40 changes: 28 additions & 12 deletions src/sloth/core/equation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""

from .expression_evaluation import EquationNode
from .template_units import dimless
from .error_definitions import UnexpectedValueError, AbsentRequiredObjectError, UnresolvedPanicError
import sympy as sp

Expand All @@ -28,7 +29,7 @@ class Equation:
Definition of Equation class. Process the ExpressionNode into one resultant node, which can be evaluated.
"""

def __init__(self, name, description, fast_expr = None, owner_model_name=""):
def __init__(self, name, description, fast_expr=None, owner_model_name=""):

"""
Istantiate Equation.
Expand All @@ -51,6 +52,8 @@ def __init__(self, name, description, fast_expr = None, owner_model_name=""):

name = gen_rnd_str()

#print("===> fast_expr = ", fast_expr,", owner_model_name = ", owner_model_name)

self.name = name

self.description = description
Expand All @@ -67,9 +70,9 @@ def __init__(self, name, description, fast_expr = None, owner_model_name=""):

self.objects_declared = {}

if fast_expr != None:
if fast_expr is not None:

self.setResidual( fast_expr )
self.setResidual(fast_expr)

self.owner_model_name = owner_model_name

Expand Down Expand Up @@ -346,15 +349,30 @@ def setResidual(self, equation_expression):
"""

if isinstance(equation_expression, tuple) and \
isinstance(equation_expression[0],EquationNode) and \
isinstance(equation_expression[1], EquationNode):
if isinstance(equation_expression, tuple) and isinstance(equation_expression[0], EquationNode):

# The equation expression is in the elementary form

self.elementary_equation_expression = tuple([equation_expression[0], equation_expression[1]])
if isinstance(equation_expression[1], EquationNode):

#If the RHS is an ENODE, pass it directly

self.elementary_equation_expression = tuple([equation_expression[0], equation_expression[1]])

self.equation_expression = equation_expression[0] - equation_expression[1]

if isinstance(equation_expression[1], float) or isinstance(equation_expression[1], int):

self.equation_expression = equation_expression[0] - equation_expression[1]
#If the RHS is a float or an int, convert it to ENODE previously

equation_expression1_as_enode = EquationNode(name='constant'+gen_rnd_str(),
symbolic_object=equation_expression[1],
unit_object=equation_expression[0].unit_object,
repr_symbolic=equation_expression[1])

self.elementary_equation_expression = tuple([equation_expression[0], equation_expression1_as_enode])

self.equation_expression = equation_expression[0] - equation_expression1_as_enode

self.equation_form = 'elementary'

Expand Down Expand Up @@ -410,7 +428,7 @@ def eval(self, symbolic_map=None, side=None):

if symbolic_map == None:

symbolic_map = self.equation_expression.symbolic_map
symbolic_map_ = self.equation_expression.symbolic_map

else:

Expand All @@ -422,9 +440,7 @@ def eval(self, symbolic_map=None, side=None):

eval_map = dict( ( (i,j) for i, j in zip(eq_keys,eq_values) ) )

#Check if the equation expression is a float. If so, returns it directly

if isinstance(equation_expression_.symbolic_object, float):
if isinstance(equation_expression_.symbolic_object, float) or isinstance(equation_expression_.symbolic_object, int):

res = equation_expression_.symbolic_object

Expand Down
2 changes: 2 additions & 0 deletions src/sloth/core/error_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ def __str__(self):

msg = "Unexpected value error. A %s was expected, but one divergent type was supplied." % (self.expected_type)

return msg

class UnresolvedPanicError(Exception):

"""
Expand Down
11 changes: 6 additions & 5 deletions src/sloth/core/expression_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class EquationNode:
Eg: IfThen(CONDITION, [THEN_CLAUSE,ELSE_CAUSE])
"""

def __init__(self, name='', symbolic_object=None, symbolic_map={}, variable_map={}, is_linear=True, is_nonlinear=False, is_differential=False, unit_object=None, args=[], latex_text='', repr_symbolic=None):
def __init__(self, name='', symbolic_object=None, symbolic_map={}, variable_map={}, is_linear=True, is_nonlinear=False,
is_differential=False, unit_object=None, args=[], latex_text='', repr_symbolic=None):

"""
Instantiate EquationNode
Expand Down Expand Up @@ -65,8 +66,8 @@ def __init__(self, name='', symbolic_object=None, symbolic_map={}, variable_map=

self.variable_map = variable_map

self.equation_type = {'is_linear':is_linear, \
'is_nonlinear':is_nonlinear, \
self.equation_type = {'is_linear':is_linear,
'is_nonlinear':is_nonlinear,
'is_differential':is_differential
}

Expand Down Expand Up @@ -139,13 +140,13 @@ def __eq__(self, other_obj):
:rtype tuple(EquationNode, EquationNode):
"""

if isinstance(other_obj, self.__class__):
if isinstance(other_obj, self.__class__) or isinstance(other_obj, int) or isinstance(other_obj, float):

return tuple([self, other_obj])

else:

return UnexpectedValueError("EquationNode")
raise UnexpectedValueError("EquationNode")

def __add__(self, other_obj):

Expand Down
2 changes: 1 addition & 1 deletion src/sloth/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ def createEquation(self, name, description="", expr=None, check_equation=True):
"""

eq = Equation(name, description, expr, owner_model_name=self.name)
eq.setResidual(expr) # I DON'T UNDERSTAND WHY THIS NEED TO BE HERE! x)
#eq.setResidual(expr) # I DON'T UNDERSTAND WHY THIS NEED TO BE HERE! x)

eq.name=eq.name+'_'+self.name

Expand Down
22 changes: 14 additions & 8 deletions tests/test_differential_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def DeclareEquations(self):

expr2 = self.v.Diff(self.t) == self.d()*self.b()*self.u()*self.v() -self.c()*self.v()

expr3 = self.y.Diff(self.t) == self.z()
expr3 = self.y.Diff(self.t) == 0.

self.eq1 = self.createEquation("eq1", "Equation 1", expr1)
self.eq2 = self.createEquation("eq2", "Equation 2", expr2)
Expand Down Expand Up @@ -266,18 +266,24 @@ def test_equation_zero_variable(mod_zero, prob, sim, compile_equations):

result = sim.getResults('dict')

#assert result['t_D0']['Time(t)'][0] == pytest.approx(0.)
assert result['t_D0']['Time(t)'][0] == pytest.approx(0.)

#assert result['t_D0']['Time(t)'][-1] == pytest.approx(16.)
assert result['t_D0']['Time(t)'][-1] == pytest.approx(16.)

#assert result['t_D0']['Preys(u)'][0] == pytest.approx(10.)
assert result['t_D0']['Scum(y)'][0] == pytest.approx(0.)

#assert result['t_D0']['Preys(u)'][-1] == pytest.approx(8.38505427)
assert result['t_D0']['Scum(y)'][-1] == pytest.approx(0.)

#assert result['t_D0']['Predators(v)'][0] == pytest.approx(5.)
assert result['t_D0']['Preys(u)'][0] == pytest.approx(10.)

#assert result['t_D0']['Predators(v)'][-1] == pytest.approx(7.1602100083)
assert result['t_D0']['Preys(u)'][-1] == pytest.approx(8.38505427)

assert result['t_D0']['Predators(v)'][0] == pytest.approx(5.)

assert result['t_D0']['Predators(v)'][-1] == pytest.approx(7.1602100083)

sim.showResults()

assert False
#assert False

#Removed ridiculously wrong test for zero-valued differential equations
10 changes: 5 additions & 5 deletions tests/test_linear_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ def __init__(self, name, description):

super().__init__(name, description)

self.a = self.createVariable("a", kg, "A")
self.b = self.createVariable("b", kg, "B")
self.c = self.createVariable("c", kg, "C", is_exposed=True, type='output')
self.d = self.createVariable("d", kg, "D", is_exposed=True, type='output')
self.a = self.createVariable("a", kg, "A")
self.b = self.createVariable("b", kg, "B")
self.c = self.createVariable("c", kg, "C", is_exposed=True, type='output')
self.d = self.createVariable("d", kg, "D", is_exposed=True, type='output')

def DeclareEquations(self):

Expand Down Expand Up @@ -117,7 +117,7 @@ def __init__(self, name, description):

def test_model_properties(mod1):

mod=mod1
mod = mod1

assert mod.name == "L0"

Expand Down

0 comments on commit 48cd054

Please sign in to comment.