From bdca62377a662c6d42b54792c3d7c233520d1c2e Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 19 Aug 2020 17:15:39 -0400 Subject: [PATCH 01/88] get simple multiplication working --- pybamm/__init__.py | 5 +- .../operations/evaluate_julia.py | 322 ++++++++++++++++++ .../{evaluate.py => evaluate_python.py} | 0 .../test_operations/test_evaluate_julia.py | 191 +++++++++++ ...st_evaluate.py => test_evaluate_python.py} | 2 +- 5 files changed, 517 insertions(+), 3 deletions(-) create mode 100644 pybamm/expression_tree/operations/evaluate_julia.py rename pybamm/expression_tree/operations/{evaluate.py => evaluate_python.py} (100%) create mode 100644 tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py rename tests/unit/test_expression_tree/test_operations/{test_evaluate.py => test_evaluate_python.py} (99%) diff --git a/pybamm/__init__.py b/pybamm/__init__.py index 8fb1d06f41..b29483b071 100644 --- a/pybamm/__init__.py +++ b/pybamm/__init__.py @@ -102,7 +102,7 @@ def version(formatted=False): simplify_multiplication_division, ) -from .expression_tree.operations.evaluate import ( +from .expression_tree.operations.evaluate_python import ( find_symbols, id_to_python_variable, to_python, @@ -110,11 +110,12 @@ def version(formatted=False): ) if system() != "Windows": - from .expression_tree.operations.evaluate import EvaluatorJax + from .expression_tree.operations.evaluate_python import EvaluatorJax from .expression_tree.operations.jacobian import Jacobian from .expression_tree.operations.convert_to_casadi import CasadiConverter from .expression_tree.operations.unpack_symbols import SymbolUnpacker +from .expression_tree.operations.evaluate_julia import get_julia_function # # Model classes diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py new file mode 100644 index 0000000000..361e912e8d --- /dev/null +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -0,0 +1,322 @@ +# +# Write a symbol to Julia +# +import pybamm + +import numpy as np +import scipy.sparse +from collections import OrderedDict + +import numbers + + +def id_to_julia_variable(symbol_id, constant=False): + """ + This function defines the format for the julia variable names used in find_symbols + and to_julia. Variable names are based on a nodes' id to make them unique + """ + + if constant: + var_format = "const_{:05d}" + else: + var_format = "var_{:05d}" + + # Need to replace "-" character to make them valid julia variable names + return var_format.format(symbol_id).replace("-", "m") + + +def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): + """ + This function converts an expression tree to a dictionary of node id's and strings + specifying valid julia code to calculate that nodes value, given y and t. + + The function distinguishes between nodes that represent constant nodes in the tree + (e.g. a pybamm.Matrix), and those that are variable (e.g. subtrees that contain + pybamm.StateVector). The former are put in `constant_symbols`, the latter in + `variable_symbols` + + Note that it is important that the arguments `constant_symbols` and + `variable_symbols` be and *ordered* dict, since the final ordering of the code lines + are important for the calculations. A dict is specified rather than a list so that + identical subtrees (which give identical id's) are not recalculated in the code + + Parameters + ---------- + symbol : :class:`pybamm.Symbol` + The symbol or expression tree to convert + + constant_symbol: collections.OrderedDict + The output dictionary of constant symbol ids to lines of code + + variable_symbol: collections.OrderedDict + The output dictionary of variable (with y or t) symbol ids to lines of code + + to_dense: bool + If True, all constants and expressions are converted to using dense matrices + + """ + if symbol.is_constant(): + value = symbol.evaluate() + if not isinstance(value, numbers.Number): + if to_dense and scipy.sparse.issparse(value): + constant_symbols[symbol.id] = value.toarray() + else: + constant_symbols[symbol.id] = value + return + + # process children recursively + for child in symbol.children: + find_symbols(child, constant_symbols, variable_symbols, to_dense) + + # calculate the variable names that will hold the result of calculating the + # children variables + children_vars = [] + for child in symbol.children: + if child.is_constant(): + child_eval = child.evaluate() + if isinstance(child_eval, numbers.Number): + children_vars.append(str(child_eval)) + else: + children_vars.append(id_to_julia_variable(child.id, True)) + else: + children_vars.append(id_to_julia_variable(child.id, False)) + + if isinstance(symbol, pybamm.BinaryOperator): + # Multiplication and Division need special handling for scipy sparse matrices + # TODO: we can pass through a dummy y and t to get the type and then hardcode + # the right line, avoiding these checks + if isinstance(symbol, pybamm.Multiplication): + dummy_eval_left = symbol.children[0].evaluate_for_shape() + dummy_eval_right = symbol.children[1].evaluate_for_shape() + if not to_dense and scipy.sparse.issparse(dummy_eval_left): + symbol_str = "{0}.multiply({1})".format( + children_vars[0], children_vars[1] + ) + elif not to_dense and scipy.sparse.issparse(dummy_eval_right): + symbol_str = "{1}.multiply({0})".format( + children_vars[0], children_vars[1] + ) + else: + symbol_str = "{0} .* {1}".format(children_vars[0], children_vars[1]) + elif isinstance(symbol, pybamm.Division): + dummy_eval_left = symbol.children[0].evaluate_for_shape() + if not to_dense and scipy.sparse.issparse(dummy_eval_left): + symbol_str = "{0}.multiply(1/{1})".format( + children_vars[0], children_vars[1] + ) + else: + symbol_str = "{0} / {1}".format(children_vars[0], children_vars[1]) + + elif isinstance(symbol, pybamm.Inner): + dummy_eval_left = symbol.children[0].evaluate_for_shape() + dummy_eval_right = symbol.children[1].evaluate_for_shape() + if not to_dense and scipy.sparse.issparse(dummy_eval_left): + symbol_str = "{0}.multiply({1})".format( + children_vars[0], children_vars[1] + ) + elif not to_dense and scipy.sparse.issparse(dummy_eval_right): + symbol_str = "{1}.multiply({0})".format( + children_vars[0], children_vars[1] + ) + else: + symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) + + elif isinstance(symbol, pybamm.Minimum): + symbol_str = "np.minimum({},{})".format(children_vars[0], children_vars[1]) + elif isinstance(symbol, pybamm.Maximum): + symbol_str = "np.maximum({},{})".format(children_vars[0], children_vars[1]) + else: + symbol_str = children_vars[0] + " " + symbol.name + " " + children_vars[1] + + elif isinstance(symbol, pybamm.UnaryOperator): + # Index has a different syntax than other univariate operations + if isinstance(symbol, pybamm.Index): + symbol_str = "{}[{}:{}]".format( + children_vars[0], symbol.slice.start, symbol.slice.stop + ) + else: + symbol_str = symbol.name + children_vars[0] + + elif isinstance(symbol, pybamm.Function): + children_str = "" + for child_var in children_vars: + if children_str == "": + children_str = child_var + else: + children_str += ", " + child_var + if isinstance(symbol.function, np.ufunc): + # write any numpy functions directly + symbol_str = "np.{}({})".format(symbol.function.__name__, children_str) + else: + # unknown function, store it as a constant and call this in the + # generated code + constant_symbols[symbol.id] = symbol.function + funct_var = id_to_julia_variable(symbol.id, True) + symbol_str = "{}({})".format(funct_var, children_str) + + elif isinstance(symbol, pybamm.Concatenation): + + # don't bother to concatenate if there is only a single child + if isinstance(symbol, pybamm.NumpyConcatenation): + if len(children_vars) > 1: + symbol_str = "np.concatenate(({}))".format(",".join(children_vars)) + else: + symbol_str = "{}".format(",".join(children_vars)) + + elif isinstance(symbol, pybamm.SparseStack): + if not to_dense and len(children_vars) > 1: + symbol_str = "scipy.sparse.vstack(({}))".format(",".join(children_vars)) + elif len(children_vars) > 1: + symbol_str = "np.vstack(({}))".format(",".join(children_vars)) + else: + symbol_str = "{}".format(",".join(children_vars)) + + # DomainConcatenation specifies a particular ordering for the concatenation, + # which we must follow + elif isinstance(symbol, pybamm.DomainConcatenation): + slice_starts = [] + all_child_vectors = [] + for i in range(symbol.secondary_dimensions_npts): + child_vectors = [] + for child_var, slices in zip(children_vars, symbol._children_slices): + for child_dom, child_slice in slices.items(): + slice_starts.append(symbol._slices[child_dom][i].start) + child_vectors.append( + "{}[{}:{}]".format( + child_var, child_slice[i].start, child_slice[i].stop + ) + ) + all_child_vectors.extend( + [v for _, v in sorted(zip(slice_starts, child_vectors))] + ) + if len(children_vars) > 1 or symbol.secondary_dimensions_npts > 1: + symbol_str = "np.concatenate(({}))".format(",".join(all_child_vectors)) + else: + symbol_str = "{}".format(",".join(children_vars)) + else: + raise NotImplementedError + + # Note: we assume that y is being passed as a column vector + elif isinstance(symbol, pybamm.StateVector): + indices = np.argwhere(symbol.evaluation_array).reshape(-1).astype(np.int32) + # add 1 since julia uses 1-indexing + indices += 1 + consecutive = np.all(indices[1:] - indices[:-1] == 1) + if len(indices) == 1: + symbol_str = "y[{}]".format(indices[0]) + elif consecutive: + # julia does include the final value + symbol_str = "y[{}:{}]".format(indices[0], indices[-1]) + else: + indices_array = pybamm.Array(indices) + constant_symbols[indices_array.id] = indices + index_name = id_to_julia_variable(indices_array.id, True) + symbol_str = "y[{}]".format(index_name) + + elif isinstance(symbol, pybamm.Time): + symbol_str = "t" + + elif isinstance(symbol, pybamm.InputParameter): + symbol_str = "inputs['{}']".format(symbol.name) + + else: + raise NotImplementedError( + "Not implemented for a symbol of type '{}'".format(type(symbol)) + ) + + variable_symbols[symbol.id] = symbol_str + + +def to_julia(symbol, debug=False, to_dense=False): + """ + This function converts an expression tree into a dict of constant input values, and + valid julia code that acts like the tree's :func:`pybamm.Symbol.evaluate` function + + Parameters + ---------- + symbol : :class:`pybamm.Symbol` + The symbol to convert to julia code + + debug : bool + If set to True, the function also emits debug code + + Returns + ------- + collections.OrderedDict: + dict mapping node id to a constant value. Represents all the constant nodes in + the expression tree + str: + valid julia code that will evaluate all the variable nodes in the tree. + to_dense: bool + If True, all constants and expressions are converted to using dense matrices + + """ + + constant_values = OrderedDict() + variable_symbols = OrderedDict() + find_symbols(symbol, constant_values, variable_symbols, to_dense) + + line_format = "{} = {}" + + if debug: + variable_lines = [ + "print('{}'); ".format( + line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) + ) + + line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) + + "; print(type({0}),{0}.shape)".format( + id_to_julia_variable(symbol_id, False) + ) + for symbol_id, symbol_line in variable_symbols.items() + ] + else: + variable_lines = [ + line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) + for symbol_id, symbol_line in variable_symbols.items() + ] + + return constant_values, "\n".join(variable_lines) + + +def get_julia_function(symbol): + """ + Converts a pybamm expression tree into pure julia code that will calculate the + result of calling `evaluate(t, y)` on the given expression tree. + + Parameters + ---------- + symbol : :class:`pybamm.Symbol` + The symbol to convert to julia code + + Returns + ------- + julia_str : str + String of julia code, to be evaluated by ``julia.Main.eval`` + + """ + + constants, julia_str = to_julia(symbol, debug=False) + + # extract constants in generated function + for i, symbol_id in enumerate(constants.keys()): + const_name = id_to_julia_variable(symbol_id, True) + julia_str = "{} = constants[{}]\n".format(const_name, i) + julia_str + + # constants passed in as an ordered dict, convert to list + constants = list(constants.values()) + + # indent code + julia_str = " " + julia_str + julia_str = julia_str.replace("\n", "\n ") + + # add function def to first line + julia_str = "function f(t, y, p)\n" + julia_str + + # calculate the final variable that will output the result of calling the function + result_var = id_to_julia_variable(symbol.id, symbol.is_constant()) + + # add return line + julia_str = julia_str + "\n return " + result_var + "\n end" + + return julia_str + diff --git a/pybamm/expression_tree/operations/evaluate.py b/pybamm/expression_tree/operations/evaluate_python.py similarity index 100% rename from pybamm/expression_tree/operations/evaluate.py rename to pybamm/expression_tree/operations/evaluate_python.py diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py new file mode 100644 index 0000000000..740440013e --- /dev/null +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -0,0 +1,191 @@ +# +# Test for the evaluate-to-Julia functions +# +import pybamm + +from tests import get_discretisation_for_testing, get_1p1d_discretisation_for_testing +import unittest +import numpy as np +import scipy.sparse +from collections import OrderedDict + +from julia import Main + + +def test_function(arg): + return arg + arg + + +def test_function2(arg1, arg2): + return arg1 + arg2 + + +class TestEvaluate(unittest.TestCase): + def test_evaluator_julia(self): + a = pybamm.StateVector(slice(0, 1)) + b = pybamm.StateVector(slice(1, 2)) + + y_tests = [np.array([[2], [3]]), np.array([[1], [3]])] + t_tests = [1, 2] + + # test a * b + expr = a * b + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + result = evaluator(None, [2, 3], None) + self.assertEqual(result, 6) + result = evaluator(None, [1, 3], None) + self.assertEqual(result, 3) + + # # test function(a*b) + # expr = pybamm.Function(test_function, a * b) + # evaluator = pybamm.EvaluatorPython(expr) + # result = evaluator.evaluate(t=None, y=np.array([[2], [3]])) + # self.assertEqual(result, 12) + + # expr = pybamm.Function(test_function2, a, b) + # evaluator = pybamm.EvaluatorPython(expr) + # result = evaluator.evaluate(t=None, y=np.array([[2], [3]])) + # self.assertEqual(result, 5) + + # # test a constant expression + # expr = pybamm.Scalar(2) * pybamm.Scalar(3) + # evaluator = pybamm.EvaluatorPython(expr) + # result = evaluator.evaluate() + # self.assertEqual(result, 6) + + # # test a larger expression + # expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 + # evaluator = pybamm.EvaluatorPython(expr) + # for y in y_tests: + # result = evaluator.evaluate(t=None, y=y) + # self.assertEqual(result, expr.evaluate(t=None, y=y)) + + # # test something with time + # expr = a * pybamm.t + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # self.assertEqual(result, expr.evaluate(t=t, y=y)) + + # # test something with a matrix multiplication + # A = pybamm.Matrix([[1, 2], [3, 4]]) + # expr = A @ pybamm.StateVector(slice(0, 2)) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # # test something with a heaviside + # a = pybamm.Vector([1, 2]) + # expr = a <= pybamm.StateVector(slice(0, 2)) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # expr = a > pybamm.StateVector(slice(0, 2)) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # # test something with a minimum or maximum + # a = pybamm.Vector([1, 2]) + # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # # test something with an index + # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # self.assertEqual(result, expr.evaluate(t=t, y=y)) + + # # test something with a sparse matrix multiplication + # A = pybamm.Matrix([[1, 2], [3, 4]]) + # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) + # expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # expr = B @ pybamm.StateVector(slice(0, 2)) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # # test numpy concatenation + # a = pybamm.StateVector(slice(0, 1)) + # b = pybamm.StateVector(slice(1, 2)) + # c = pybamm.StateVector(slice(2, 3)) + + # y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] + # t_tests = [1, 2] + # expr = pybamm.NumpyConcatenation(a, b) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # expr = pybamm.NumpyConcatenation(a, c) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # # test sparse stack + # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) + # a = pybamm.StateVector(slice(0, 1)) + # expr = pybamm.SparseStack(A, a * B) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y).toarray() + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) + + # # test Inner + # expr = pybamm.Inner(a, b) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + # v = pybamm.StateVector(slice(0, 2)) + # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # expr = pybamm.Inner(A, v) + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y).toarray() + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) + + # y_tests = [np.array([[2], [3], [4], [5]]), np.array([[1], [3], [2], [1]])] + # t_tests = [1, 2] + # a = pybamm.StateVector(slice(0, 1), slice(3, 4)) + # b = pybamm.StateVector(slice(1, 3)) + # expr = a * b + # evaluator = pybamm.EvaluatorPython(expr) + # for t, y in zip(t_tests, y_tests): + # result = evaluator.evaluate(t=t, y=y) + # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + + +if __name__ == "__main__": + print("Add -v for more debug output") + import sys + + if "-v" in sys.argv: + debug = True + pybamm.settings.debug_mode = True + unittest.main() diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py similarity index 99% rename from tests/unit/test_expression_tree/test_operations/test_evaluate.py rename to tests/unit/test_expression_tree/test_operations/test_evaluate_python.py index 0e4e4b177f..4d18a722f1 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py @@ -1,5 +1,5 @@ # -# Test for the evaluate functions +# Test for the evaluate-to-python functions # import pybamm From d2ad43a05b9ce795090b5c312f0adf6435e987bd Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 19 Aug 2020 19:19:48 -0400 Subject: [PATCH 02/88] #1129 get more simple scalars and functions working --- pybamm/expression_tree/functions.py | 24 +++++++ .../operations/evaluate_julia.py | 23 +++---- .../test_operations/test_evaluate_julia.py | 63 ++++++++++++------- 3 files changed, 78 insertions(+), 32 deletions(-) diff --git a/pybamm/expression_tree/functions.py b/pybamm/expression_tree/functions.py index a8eadd22dd..86d0e62d05 100644 --- a/pybamm/expression_tree/functions.py +++ b/pybamm/expression_tree/functions.py @@ -226,6 +226,13 @@ def _function_simplify(self, simplified_children): """ return self._function_new_copy(simplified_children) + @property + def julia_name(self): + "Return the name of the equivalent Julia function, for generating Julia code" + raise NotImplementedError( + "No julia name defined for function {}".format(self.function) + ) + class SpecificFunction(Function): """ @@ -252,6 +259,13 @@ def _function_simplify(self, simplified_children): """ See :meth:`pybamm.Function._function_simplify()` """ return self.__class__(*simplified_children) + @property + def julia_name(self): + """ See :meth:`pybamm.Function.julia_name` """ + # By default, the julia name for a specific function is the function's name + # Some functions may overwrite this + return self.function.__name__ + class Arcsinh(SpecificFunction): """ Arcsinh function """ @@ -263,6 +277,11 @@ def _function_diff(self, children, idx): """ See :meth:`pybamm.Symbol._function_diff()`. """ return 1 / Sqrt(children[0] ** 2 + 1) + @property + def julia_name(self): + """ See :meth:`pybamm.Function.julia_name` """ + return "asinh" + def arcsinh(child): " Returns arcsinh function of child. " @@ -446,6 +465,11 @@ def _function_diff(self, children, idx): """ See :meth:`pybamm.Function._function_diff()`. """ return 1 / (children[0] ** 2 + 1) + @property + def julia_name(self): + """ See :meth:`pybamm.Function.julia_name` """ + return "atan" + def arctan(child): " Returns hyperbolic tan function of child. " diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 361e912e8d..f1e41e496c 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -125,6 +125,8 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): symbol_str = "np.minimum({},{})".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Maximum): symbol_str = "np.maximum({},{})".format(children_vars[0], children_vars[1]) + elif isinstance(symbol, pybamm.Power): + symbol_str = children_vars[0] + " ^ " + children_vars[1] else: symbol_str = children_vars[0] + " " + symbol.name + " " + children_vars[1] @@ -144,15 +146,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): children_str = child_var else: children_str += ", " + child_var - if isinstance(symbol.function, np.ufunc): - # write any numpy functions directly - symbol_str = "np.{}({})".format(symbol.function.__name__, children_str) - else: - # unknown function, store it as a constant and call this in the - # generated code - constant_symbols[symbol.id] = symbol.function - funct_var = id_to_julia_variable(symbol.id, True) - symbol_str = "{}({})".format(funct_var, children_str) + # write functions directly + julia_name = symbol.julia_name + symbol_str = "{}({})".format(julia_name, children_str) elif isinstance(symbol, pybamm.Concatenation): @@ -312,11 +308,16 @@ def get_julia_function(symbol): # add function def to first line julia_str = "function f(t, y, p)\n" + julia_str - # calculate the final variable that will output the result of calling the function + # calculate the final variable that will output the result result_var = id_to_julia_variable(symbol.id, symbol.is_constant()) + if symbol.is_constant(): + result_value = symbol.evaluate() # add return line - julia_str = julia_str + "\n return " + result_var + "\n end" + if symbol.is_constant() and isinstance(result_value, numbers.Number): + julia_str = julia_str + "\n return " + str(result_value) + "\n end" + else: + julia_str = julia_str + "\n return " + result_var + "\n end" return julia_str diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 740440013e..e95c27046b 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -37,29 +37,27 @@ def test_evaluator_julia(self): result = evaluator(None, [1, 3], None) self.assertEqual(result, 3) - # # test function(a*b) - # expr = pybamm.Function(test_function, a * b) - # evaluator = pybamm.EvaluatorPython(expr) - # result = evaluator.evaluate(t=None, y=np.array([[2], [3]])) - # self.assertEqual(result, 12) - - # expr = pybamm.Function(test_function2, a, b) - # evaluator = pybamm.EvaluatorPython(expr) - # result = evaluator.evaluate(t=None, y=np.array([[2], [3]])) - # self.assertEqual(result, 5) + # test function(a*b) + expr = pybamm.cos(a * b) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + result = evaluator(None, np.array([[2], [3]]), None) + self.assertAlmostEqual(result, np.cos(6)) - # # test a constant expression - # expr = pybamm.Scalar(2) * pybamm.Scalar(3) - # evaluator = pybamm.EvaluatorPython(expr) - # result = evaluator.evaluate() - # self.assertEqual(result, 6) + # test a constant expression + expr = pybamm.Scalar(2) * pybamm.Scalar(3) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + result = evaluator(None, None, None) + self.assertEqual(result, 6) - # # test a larger expression - # expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 - # evaluator = pybamm.EvaluatorPython(expr) - # for y in y_tests: - # result = evaluator.evaluate(t=None, y=y) - # self.assertEqual(result, expr.evaluate(t=None, y=y)) + # test a larger expression + expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for y in y_tests: + result = evaluator(None, y, None) + self.assertEqual(result, expr.evaluate(t=None, y=y)) # # test something with time # expr = a * pybamm.t @@ -180,6 +178,29 @@ def test_evaluator_julia(self): # result = evaluator.evaluate(t=t, y=y) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + def test_evaluator_julia_all_functions(self): + a = pybamm.StateVector(slice(0, 1)) + y_test = np.array([1]) + + for function in [ + pybamm.arcsinh, + pybamm.cos, + pybamm.cosh, + pybamm.exp, + pybamm.log, + pybamm.log10, + pybamm.sin, + pybamm.sinh, + pybamm.sqrt, + pybamm.tanh, + pybamm.arctan, + ]: + expr = function(a) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + result = evaluator(None, [1], None) + self.assertAlmostEqual(result, expr.evaluate(y=y_test)) + if __name__ == "__main__": print("Add -v for more debug output") From aa0b0b4ae851b890d5d6ccc1b06a00cea779f185 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 19 Aug 2020 20:15:36 -0400 Subject: [PATCH 03/88] #1129 start matrix operations --- .../operations/evaluate_julia.py | 73 +++------- .../operations/evaluate_python.py | 93 +++++++------ .../test_operations/test_evaluate_julia.py | 129 +++++++++--------- 3 files changed, 135 insertions(+), 160 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index f1e41e496c..27f6168719 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -85,41 +85,12 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): # Multiplication and Division need special handling for scipy sparse matrices # TODO: we can pass through a dummy y and t to get the type and then hardcode # the right line, avoiding these checks - if isinstance(symbol, pybamm.Multiplication): - dummy_eval_left = symbol.children[0].evaluate_for_shape() - dummy_eval_right = symbol.children[1].evaluate_for_shape() - if not to_dense and scipy.sparse.issparse(dummy_eval_left): - symbol_str = "{0}.multiply({1})".format( - children_vars[0], children_vars[1] - ) - elif not to_dense and scipy.sparse.issparse(dummy_eval_right): - symbol_str = "{1}.multiply({0})".format( - children_vars[0], children_vars[1] - ) - else: - symbol_str = "{0} .* {1}".format(children_vars[0], children_vars[1]) + if isinstance(symbol, (pybamm.Multiplication, pybamm.Inner)): + symbol_str = "{0} .* {1}".format(children_vars[0], children_vars[1]) + if isinstance(symbol, pybamm.MatrixMultiplication): + symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Division): - dummy_eval_left = symbol.children[0].evaluate_for_shape() - if not to_dense and scipy.sparse.issparse(dummy_eval_left): - symbol_str = "{0}.multiply(1/{1})".format( - children_vars[0], children_vars[1] - ) - else: - symbol_str = "{0} / {1}".format(children_vars[0], children_vars[1]) - - elif isinstance(symbol, pybamm.Inner): - dummy_eval_left = symbol.children[0].evaluate_for_shape() - dummy_eval_right = symbol.children[1].evaluate_for_shape() - if not to_dense and scipy.sparse.issparse(dummy_eval_left): - symbol_str = "{0}.multiply({1})".format( - children_vars[0], children_vars[1] - ) - elif not to_dense and scipy.sparse.issparse(dummy_eval_right): - symbol_str = "{1}.multiply({0})".format( - children_vars[0], children_vars[1] - ) - else: - symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) + symbol_str = "{0} ./ {1}".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Minimum): symbol_str = "np.minimum({},{})".format(children_vars[0], children_vars[1]) @@ -133,8 +104,10 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): elif isinstance(symbol, pybamm.UnaryOperator): # Index has a different syntax than other univariate operations if isinstance(symbol, pybamm.Index): + # Because of how julia indexing works, add 1 to the start, but not to the + # stop symbol_str = "{}[{}:{}]".format( - children_vars[0], symbol.slice.start, symbol.slice.stop + children_vars[0], symbol.slice.start + 1, symbol.slice.stop ) else: symbol_str = symbol.name + children_vars[0] @@ -148,24 +121,17 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): children_str += ", " + child_var # write functions directly julia_name = symbol.julia_name - symbol_str = "{}({})".format(julia_name, children_str) + # add a . to allow elementwise operations + symbol_str = "{}.({})".format(julia_name, children_str) elif isinstance(symbol, pybamm.Concatenation): # don't bother to concatenate if there is only a single child - if isinstance(symbol, pybamm.NumpyConcatenation): - if len(children_vars) > 1: - symbol_str = "np.concatenate(({}))".format(",".join(children_vars)) + if isinstance(symbol, (pybamm.NumpyConcatenation, pybamm.SparseStack)): + if len(children_vars) == 1: + symbol_str = children_vars else: - symbol_str = "{}".format(",".join(children_vars)) - - elif isinstance(symbol, pybamm.SparseStack): - if not to_dense and len(children_vars) > 1: - symbol_str = "scipy.sparse.vstack(({}))".format(",".join(children_vars)) - elif len(children_vars) > 1: - symbol_str = "np.vstack(({}))".format(",".join(children_vars)) - else: - symbol_str = "{}".format(",".join(children_vars)) + symbol_str = "vcat({})".format(",".join(children_vars)) # DomainConcatenation specifies a particular ordering for the concatenation, # which we must follow @@ -217,7 +183,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): else: raise NotImplementedError( - "Not implemented for a symbol of type '{}'".format(type(symbol)) + "Conversion to Julia not implemented for a symbol of type '{}'".format( + type(symbol) + ) ) variable_symbols[symbol.id] = symbol_str @@ -294,12 +262,9 @@ def get_julia_function(symbol): constants, julia_str = to_julia(symbol, debug=False) # extract constants in generated function - for i, symbol_id in enumerate(constants.keys()): + for symbol_id, const_value in constants.items(): const_name = id_to_julia_variable(symbol_id, True) - julia_str = "{} = constants[{}]\n".format(const_name, i) + julia_str - - # constants passed in as an ordered dict, convert to list - constants = list(constants.values()) + julia_str = "{} = {}\n".format(const_name, const_value) + julia_str # indent code julia_str = " " + julia_str diff --git a/pybamm/expression_tree/operations/evaluate_python.py b/pybamm/expression_tree/operations/evaluate_python.py index 7aa14e60ac..903c8f6268 100644 --- a/pybamm/expression_tree/operations/evaluate_python.py +++ b/pybamm/expression_tree/operations/evaluate_python.py @@ -9,10 +9,12 @@ import numbers from platform import system + if system() != "Windows": import jax from jax.config import config + config.update("jax_enable_x64", True) @@ -95,18 +97,21 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): dummy_eval_left = symbol.children[0].evaluate_for_shape() dummy_eval_right = symbol.children[1].evaluate_for_shape() if not to_dense and scipy.sparse.issparse(dummy_eval_left): - symbol_str = "{0}.multiply({1})"\ - .format(children_vars[0], children_vars[1]) + symbol_str = "{0}.multiply({1})".format( + children_vars[0], children_vars[1] + ) elif not to_dense and scipy.sparse.issparse(dummy_eval_right): - symbol_str = "{1}.multiply({0})"\ - .format(children_vars[0], children_vars[1]) + symbol_str = "{1}.multiply({0})".format( + children_vars[0], children_vars[1] + ) else: symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Division): dummy_eval_left = symbol.children[0].evaluate_for_shape() if not to_dense and scipy.sparse.issparse(dummy_eval_left): - symbol_str = "{0}.multiply(1/{1})"\ - .format(children_vars[0], children_vars[1]) + symbol_str = "{0}.multiply(1/{1})".format( + children_vars[0], children_vars[1] + ) else: symbol_str = "{0} / {1}".format(children_vars[0], children_vars[1]) @@ -114,11 +119,13 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): dummy_eval_left = symbol.children[0].evaluate_for_shape() dummy_eval_right = symbol.children[1].evaluate_for_shape() if not to_dense and scipy.sparse.issparse(dummy_eval_left): - symbol_str = "{0}.multiply({1})"\ - .format(children_vars[0], children_vars[1]) + symbol_str = "{0}.multiply({1})".format( + children_vars[0], children_vars[1] + ) elif not to_dense and scipy.sparse.issparse(dummy_eval_right): - symbol_str = "{1}.multiply({0})"\ - .format(children_vars[0], children_vars[1]) + symbol_str = "{1}.multiply({0})".format( + children_vars[0], children_vars[1] + ) else: symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) @@ -159,18 +166,18 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): # don't bother to concatenate if there is only a single child if isinstance(symbol, pybamm.NumpyConcatenation): - if len(children_vars) > 1: - symbol_str = "np.concatenate(({}))".format(",".join(children_vars)) + if len(children_vars) == 1: + symbol_str = children_vars else: - symbol_str = "{}".format(",".join(children_vars)) + symbol_str = "np.concatenate(({}))".format(",".join(children_vars)) elif isinstance(symbol, pybamm.SparseStack): - if not to_dense and len(children_vars) > 1: + if len(children_vars) == 1: + symbol_str = children_vars + elif not to_dense: symbol_str = "scipy.sparse.vstack(({}))".format(",".join(children_vars)) - elif len(children_vars) > 1: - symbol_str = "np.vstack(({}))".format(",".join(children_vars)) else: - symbol_str = "{}".format(",".join(children_vars)) + symbol_str = "np.vstack(({}))".format(",".join(children_vars)) # DomainConcatenation specifies a particular ordering for the concatenation, # which we must follow @@ -217,7 +224,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): else: raise NotImplementedError( - "Not implemented for a symbol of type '{}'".format(type(symbol)) + "Conversion to python not implemented for a symbol of type '{}'".format( + type(symbol) + ) ) variable_symbols[symbol.id] = symbol_str @@ -294,18 +303,20 @@ def __init__(self, symbol): # extract constants in generated function for i, symbol_id in enumerate(constants.keys()): const_name = id_to_python_variable(symbol_id, True) - python_str = '{} = constants[{}]\n'.format(const_name, i) + python_str + python_str = "{} = constants[{}]\n".format(const_name, i) + python_str # constants passed in as an ordered dict, convert to list self._constants = list(constants.values()) # indent code - python_str = ' ' + python_str - python_str = python_str.replace('\n', '\n ') + python_str = " " + python_str + python_str = python_str.replace("\n", "\n ") # add function def to first line - python_str = 'def evaluate(constants, t=None, y=None, '\ - 'y_dot=None, inputs=None, known_evals=None):\n' + python_str + python_str = ( + "def evaluate(constants, t=None, y=None, " + "y_dot=None, inputs=None, known_evals=None):\n" + python_str + ) # calculate the final variable that will output the result of calling `evaluate` # on `symbol` @@ -315,21 +326,18 @@ def __init__(self, symbol): # add return line if symbol.is_constant() and isinstance(result_value, numbers.Number): - python_str = python_str + '\n return ' + str(result_value) + python_str = python_str + "\n return " + str(result_value) else: - python_str = python_str + '\n return ' + result_var + python_str = python_str + "\n return " + result_var # store a copy of examine_jaxpr - python_str = python_str + \ - '\nself._evaluate = evaluate' + python_str = python_str + "\nself._evaluate = evaluate" self._python_str = python_str self._symbol = symbol # compile and run the generated python code, - compiled_function = compile( - python_str, result_var, "exec" - ) + compiled_function = compile(python_str, result_var, "exec") exec(compiled_function) def evaluate(self, t=None, y=None, y_dot=None, inputs=None, known_evals=None): @@ -377,7 +385,7 @@ def __init__(self, symbol): constants, python_str = pybamm.to_python(symbol, debug=False, to_dense=True) # replace numpy function calls to jax numpy calls - python_str = python_str.replace('np.', 'jax.numpy.') + python_str = python_str.replace("np.", "jax.numpy.") # convert all numpy constants to device vectors for symbol_id in constants: @@ -387,18 +395,20 @@ def __init__(self, symbol): # extract constants in generated function for i, symbol_id in enumerate(constants.keys()): const_name = id_to_python_variable(symbol_id, True) - python_str = '{} = constants[{}]\n'.format(const_name, i) + python_str + python_str = "{} = constants[{}]\n".format(const_name, i) + python_str # constants passed in as an ordered dict, convert to list self._constants = list(constants.values()) # indent code - python_str = ' ' + python_str - python_str = python_str.replace('\n', '\n ') + python_str = " " + python_str + python_str = python_str.replace("\n", "\n ") # add function def to first line - python_str = 'def evaluate_jax(constants, t=None, y=None, '\ - 'y_dot=None, inputs=None, known_evals=None):\n' + python_str + python_str = ( + "def evaluate_jax(constants, t=None, y=None, " + "y_dot=None, inputs=None, known_evals=None):\n" + python_str + ) # calculate the final variable that will output the result of calling `evaluate` # on `symbol` @@ -408,18 +418,15 @@ def __init__(self, symbol): # add return line if symbol.is_constant() and isinstance(result_value, numbers.Number): - python_str = python_str + '\n return ' + str(result_value) + python_str = python_str + "\n return " + str(result_value) else: - python_str = python_str + '\n return ' + result_var + python_str = python_str + "\n return " + result_var # store a copy of examine_jaxpr - python_str = python_str + \ - '\nself._evaluate_jax = evaluate_jax' + python_str = python_str + "\nself._evaluate_jax = evaluate_jax" # compile and run the generated python code, - compiled_function = compile( - python_str, result_var, "exec" - ) + compiled_function = compile(python_str, result_var, "exec") exec(compiled_function) self._jit_evaluate = jax.jit(self._evaluate_jax, static_argnums=(0, 4, 5)) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index e95c27046b..a7e818cefd 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -12,14 +12,6 @@ from julia import Main -def test_function(arg): - return arg + arg - - -def test_function2(arg1, arg2): - return arg1 + arg2 - - class TestEvaluate(unittest.TestCase): def test_evaluator_julia(self): a = pybamm.StateVector(slice(0, 1)) @@ -59,54 +51,59 @@ def test_evaluator_julia(self): result = evaluator(None, y, None) self.assertEqual(result, expr.evaluate(t=None, y=y)) - # # test something with time - # expr = a * pybamm.t - # evaluator = pybamm.EvaluatorPython(expr) - # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) - # self.assertEqual(result, expr.evaluate(t=t, y=y)) - - # # test something with a matrix multiplication - # A = pybamm.Matrix([[1, 2], [3, 4]]) - # expr = A @ pybamm.StateVector(slice(0, 2)) - # evaluator = pybamm.EvaluatorPython(expr) - # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # test something with time + expr = a * pybamm.t + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + self.assertEqual(result, expr.evaluate(t=t, y=y)) - # # test something with a heaviside - # a = pybamm.Vector([1, 2]) - # expr = a <= pybamm.StateVector(slice(0, 2)) - # evaluator = pybamm.EvaluatorPython(expr) - # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # test something with a matrix multiplication + A = pybamm.Matrix([[1, 2], [3, 4]]) + expr = A @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + + # test something with a heaviside + a = pybamm.Vector([1, 2]) + expr = a <= pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - # expr = a > pybamm.StateVector(slice(0, 2)) - # evaluator = pybamm.EvaluatorPython(expr) - # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + expr = a > pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) # # test something with a minimum or maximum # a = pybamm.Vector([1, 2]) # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) + # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) + # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) # # test something with an index # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) + # result = evaluator(t,y,None) # self.assertEqual(result, expr.evaluate(t=t, y=y)) # # test something with a sparse matrix multiplication @@ -116,32 +113,38 @@ def test_evaluator_julia(self): # expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) + # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) # expr = B @ pybamm.StateVector(slice(0, 2)) # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) + # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - # # test numpy concatenation - # a = pybamm.StateVector(slice(0, 1)) - # b = pybamm.StateVector(slice(1, 2)) - # c = pybamm.StateVector(slice(2, 3)) + # test numpy concatenation + a = pybamm.StateVector(slice(0, 1)) + b = pybamm.StateVector(slice(1, 2)) + c = pybamm.StateVector(slice(2, 3)) - # y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] - # t_tests = [1, 2] - # expr = pybamm.NumpyConcatenation(a, b) - # evaluator = pybamm.EvaluatorPython(expr) - # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - # expr = pybamm.NumpyConcatenation(a, c) - # evaluator = pybamm.EvaluatorPython(expr) - # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] + t_tests = [1, 2] + + expr = pybamm.NumpyConcatenation(a, b) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + + expr = pybamm.NumpyConcatenation(a, c) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) # # test sparse stack # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) @@ -150,14 +153,14 @@ def test_evaluator_julia(self): # expr = pybamm.SparseStack(A, a * B) # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y).toarray() + # result = evaluator(t,y,None).toarray() # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) # # test Inner # expr = pybamm.Inner(a, b) # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) + # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) # v = pybamm.StateVector(slice(0, 2)) @@ -165,7 +168,7 @@ def test_evaluator_julia(self): # expr = pybamm.Inner(A, v) # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y).toarray() + # result = evaluator(t,y,None).toarray() # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) # y_tests = [np.array([[2], [3], [4], [5]]), np.array([[1], [3], [2], [1]])] @@ -175,12 +178,12 @@ def test_evaluator_julia(self): # expr = a * b # evaluator = pybamm.EvaluatorPython(expr) # for t, y in zip(t_tests, y_tests): - # result = evaluator.evaluate(t=t, y=y) + # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) def test_evaluator_julia_all_functions(self): - a = pybamm.StateVector(slice(0, 1)) - y_test = np.array([1]) + a = pybamm.StateVector(slice(0, 3)) + y_test = np.array([1, 2, 3]) for function in [ pybamm.arcsinh, @@ -198,8 +201,8 @@ def test_evaluator_julia_all_functions(self): expr = function(a) evaluator_str = pybamm.get_julia_function(expr) evaluator = Main.eval(evaluator_str) - result = evaluator(None, [1], None) - self.assertAlmostEqual(result, expr.evaluate(y=y_test)) + result = evaluator(None, y_test, None) + np.testing.assert_almost_equal(result, expr.evaluate(y=y_test).flatten()) if __name__ == "__main__": From f613bc24d0884c361d3497bf1688eeae667249b8 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 19 Aug 2020 23:56:32 -0400 Subject: [PATCH 04/88] #1129 add sparse arrays --- examples/scripts/SPMe.py | 58 +++++---- .../operations/evaluate_julia.py | 24 +++- .../test_operations/test_evaluate_julia.py | 117 ++++++++++++++---- 3 files changed, 147 insertions(+), 52 deletions(-) diff --git a/examples/scripts/SPMe.py b/examples/scripts/SPMe.py index 75921b13d2..e4001f7c33 100644 --- a/examples/scripts/SPMe.py +++ b/examples/scripts/SPMe.py @@ -8,7 +8,7 @@ pybamm.set_logging_level("INFO") # load model -model = pybamm.lithium_ion.SPMe() +model = pybamm.lithium_ion.SPM() model.convert_to_format = "python" # create geometry @@ -20,30 +20,40 @@ param.process_geometry(geometry) # set mesh -mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts) +var = pybamm.standard_spatial_vars +var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 5, var.r_p: 5} + +mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) # discretise model disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) - -# solve model for 1 hour -t_eval = np.linspace(0, 3600, 100) -solution = model.default_solver.solve(model, t_eval) - -# plot -plot = pybamm.QuickPlot( - solution, - [ - "Negative particle concentration [mol.m-3]", - "Electrolyte concentration [mol.m-3]", - "Positive particle concentration [mol.m-3]", - "Current [A]", - "Negative electrode potential [V]", - "Electrolyte potential [V]", - "Positive electrode potential [V]", - "Terminal voltage [V]", - ], - time_unit="seconds", - spatial_unit="um", -) -plot.dynamic_plot() +rhs = pybamm.get_julia_function(model.concatenated_rhs.simplify()) + +from julia import Main + +rhs_eval = Main.eval(rhs) +n = 1 + + +# # solve model for 1 hour +# t_eval = np.linspace(0, 3600, 100) +# solution = model.default_solver.solve(model, t_eval) + +# # plot +# plot = pybamm.QuickPlot( +# solution, +# [ +# "Negative particle concentration [mol.m-3]", +# "Electrolyte concentration [mol.m-3]", +# "Positive particle concentration [mol.m-3]", +# "Current [A]", +# "Negative electrode potential [V]", +# "Electrolyte potential [V]", +# "Positive electrode potential [V]", +# "Terminal voltage [V]", +# ], +# time_unit="seconds", +# spatial_unit="um", +# ) +# plot.dynamic_plot() diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 27f6168719..661056d243 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -58,8 +58,19 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): if symbol.is_constant(): value = symbol.evaluate() if not isinstance(value, numbers.Number): - if to_dense and scipy.sparse.issparse(value): - constant_symbols[symbol.id] = value.toarray() + if scipy.sparse.issparse(value): + # Create Julia SparseArray + row, col, data = scipy.sparse.find(value) + m, n = value.shape + # add 1 to correct for 1-indexing in Julia + # use array2string so that commas are included + constant_symbols[symbol.id] = "sparse({}, {}, {}, {}, {})".format( + np.array2string(row + 1, separator=","), + np.array2string(col + 1, separator=","), + np.array2string(data, separator=","), + m, + n, + ) else: constant_symbols[symbol.id] = value return @@ -270,8 +281,9 @@ def get_julia_function(symbol): julia_str = " " + julia_str julia_str = julia_str.replace("\n", "\n ") - # add function def to first line - julia_str = "function f(t, y, p)\n" + julia_str + # add function def and sparse arrays to first line + imports = "using SparseArrays\n" + julia_str = imports + "function f_pybamm(t, y, p)\n" + julia_str # calculate the final variable that will output the result result_var = id_to_julia_variable(symbol.id, symbol.is_constant()) @@ -280,9 +292,9 @@ def get_julia_function(symbol): # add return line if symbol.is_constant() and isinstance(result_value, numbers.Number): - julia_str = julia_str + "\n return " + str(result_value) + "\n end" + julia_str = julia_str + "\n return " + str(result_value) + "\nend" else: - julia_str = julia_str + "\n return " + result_var + "\n end" + julia_str = julia_str + "\n return " + result_var + "\nend" return julia_str diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index a7e818cefd..4edbba72e2 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -3,7 +3,11 @@ # import pybamm -from tests import get_discretisation_for_testing, get_1p1d_discretisation_for_testing +from tests import ( + get_mesh_for_testing, + get_discretisation_for_testing, + get_1p1d_discretisation_for_testing, +) import unittest import numpy as np import scipy.sparse @@ -88,39 +92,46 @@ def test_evaluator_julia(self): # # test something with a minimum or maximum # a = pybamm.Vector([1, 2]) # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) - # evaluator = pybamm.EvaluatorPython(expr) + # evaluator_str = pybamm.get_julia_function(expr) + # evaluator = Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) - # evaluator = pybamm.EvaluatorPython(expr) + # evaluator_str = pybamm.get_julia_function(expr) + # evaluator = Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) # # test something with an index # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) - # evaluator = pybamm.EvaluatorPython(expr) + # evaluator_str = pybamm.get_julia_function(expr) + # evaluator = Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): # result = evaluator(t,y,None) # self.assertEqual(result, expr.evaluate(t=t, y=y)) - # # test something with a sparse matrix multiplication - # A = pybamm.Matrix([[1, 2], [3, 4]]) - # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) - # expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) - # evaluator = pybamm.EvaluatorPython(expr) - # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # test something with a sparse matrix multiplication + A = pybamm.Matrix([[1, 2], [3, 4]]) + B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) + expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - # expr = B @ pybamm.StateVector(slice(0, 2)) - # evaluator = pybamm.EvaluatorPython(expr) - # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + expr = B @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) # test numpy concatenation a = pybamm.StateVector(slice(0, 1)) @@ -151,14 +162,16 @@ def test_evaluator_julia(self): # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) # a = pybamm.StateVector(slice(0, 1)) # expr = pybamm.SparseStack(A, a * B) - # evaluator = pybamm.EvaluatorPython(expr) + # evaluator_str = pybamm.get_julia_function(expr) + # evaluator = Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): # result = evaluator(t,y,None).toarray() # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) # # test Inner # expr = pybamm.Inner(a, b) - # evaluator = pybamm.EvaluatorPython(expr) + # evaluator_str = pybamm.get_julia_function(expr) + # evaluator = Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) @@ -166,7 +179,8 @@ def test_evaluator_julia(self): # v = pybamm.StateVector(slice(0, 2)) # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) # expr = pybamm.Inner(A, v) - # evaluator = pybamm.EvaluatorPython(expr) + # evaluator_str = pybamm.get_julia_function(expr) + # evaluator = Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): # result = evaluator(t,y,None).toarray() # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) @@ -176,7 +190,8 @@ def test_evaluator_julia(self): # a = pybamm.StateVector(slice(0, 1), slice(3, 4)) # b = pybamm.StateVector(slice(1, 3)) # expr = a * b - # evaluator = pybamm.EvaluatorPython(expr) + # evaluator_str = pybamm.get_julia_function(expr) + # evaluator = Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) @@ -204,6 +219,64 @@ def test_evaluator_julia_all_functions(self): result = evaluator(None, y_test, None) np.testing.assert_almost_equal(result, expr.evaluate(y=y_test).flatten()) + def test_evaluator_julia_discretised_operators(self): + whole_cell = ["negative electrode", "separator", "positive electrode"] + # create discretisation + mesh = get_mesh_for_testing() + spatial_methods = {"macroscale": pybamm.FiniteVolume()} + disc = pybamm.Discretisation(mesh, spatial_methods) + + combined_submesh = mesh.combine_submeshes(*whole_cell) + + # grad + var = pybamm.Variable("var", domain=whole_cell) + grad_eqn = pybamm.grad(var) + boundary_conditions = { + var.id: { + "left": (pybamm.Scalar(1), "Dirichlet"), + "right": (pybamm.Scalar(1), "Dirichlet"), + } + } + disc.bcs = boundary_conditions + + disc.set_variable_slices([var]) + grad_eqn_disc = disc.process_symbol(grad_eqn) + + # test + constant_y = np.ones_like(combined_submesh.nodes[:, np.newaxis]) + + evaluator_str = pybamm.get_julia_function(grad_eqn_disc) + evaluator = Main.eval(evaluator_str) + result = evaluator(None, constant_y, None) + np.testing.assert_almost_equal( + result, grad_eqn_disc.evaluate(y=constant_y).flatten() + ) + + # # div: test on linear y (should have laplacian zero) so change bcs + # linear_y = combined_submesh.nodes + # N = pybamm.grad(var) + # div_eqn = pybamm.div(N) + # boundary_conditions = { + # var.id: { + # "left": (pybamm.Scalar(0), "Dirichlet"), + # "right": (pybamm.Scalar(1), "Dirichlet"), + # } + # } + + # disc.bcs = boundary_conditions + + # grad_eqn_disc = disc.process_symbol(grad_eqn) + # np.testing.assert_array_almost_equal( + # grad_eqn_disc.evaluate(None, linear_y), + # np.ones_like(combined_submesh.edges[:, np.newaxis]), + # ) + + # div_eqn_disc = disc.process_symbol(div_eqn) + # np.testing.assert_array_almost_equal( + # div_eqn_disc.evaluate(None, linear_y), + # np.zeros_like(combined_submesh.nodes[:, np.newaxis]), + # ) + if __name__ == "__main__": print("Add -v for more debug output") From 0e3d72eca18a5a1b433fe7b57b3be92addbcf9c0 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 20 Aug 2020 00:34:19 -0400 Subject: [PATCH 05/88] #1129 test div and grad --- examples/scripts/SPMe.py | 1 + .../operations/evaluate_julia.py | 20 ++-- .../test_operations/test_evaluate_julia.py | 97 +++++++++++++------ 3 files changed, 80 insertions(+), 38 deletions(-) diff --git a/examples/scripts/SPMe.py b/examples/scripts/SPMe.py index e4001f7c33..64da6f0140 100644 --- a/examples/scripts/SPMe.py +++ b/examples/scripts/SPMe.py @@ -33,6 +33,7 @@ from julia import Main rhs_eval = Main.eval(rhs) +rhs_eval(0, model.concatenated_initial_conditions.evaluate(), None) n = 1 diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 661056d243..5292d0fa73 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -62,6 +62,11 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): # Create Julia SparseArray row, col, data = scipy.sparse.find(value) m, n = value.shape + # Set print options large enough to avoid ellipsis + # at least as big is len(row) = len(col) = len(data) + np.set_printoptions( + threshold=max(np.get_printoptions()["threshold"], len(row) + 10) + ) # add 1 to correct for 1-indexing in Julia # use array2string so that commas are included constant_symbols[symbol.id] = "sparse({}, {}, {}, {}, {})".format( @@ -96,21 +101,22 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): # Multiplication and Division need special handling for scipy sparse matrices # TODO: we can pass through a dummy y and t to get the type and then hardcode # the right line, avoiding these checks - if isinstance(symbol, (pybamm.Multiplication, pybamm.Inner)): - symbol_str = "{0} .* {1}".format(children_vars[0], children_vars[1]) if isinstance(symbol, pybamm.MatrixMultiplication): symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) - elif isinstance(symbol, pybamm.Division): - symbol_str = "{0} ./ {1}".format(children_vars[0], children_vars[1]) - + elif isinstance(symbol, pybamm.Inner): + symbol_str = "{0} .* {1}".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Minimum): symbol_str = "np.minimum({},{})".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Maximum): symbol_str = "np.maximum({},{})".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Power): - symbol_str = children_vars[0] + " ^ " + children_vars[1] + # julia uses ^ instead of ** for power + # include dot for elementwise operations + symbol_str = children_vars[0] + " .^ " + children_vars[1] else: - symbol_str = children_vars[0] + " " + symbol.name + " " + children_vars[1] + # all other operations use the same symbol + # include dot: all other operations should be elementwise + symbol_str = children_vars[0] + " ." + symbol.name + " " + children_vars[1] elif isinstance(symbol, pybamm.UnaryOperator): # Index has a different syntax than other univariate operations diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 4edbba72e2..dd245d7208 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -5,6 +5,7 @@ from tests import ( get_mesh_for_testing, + get_1p1d_mesh_for_testing, get_discretisation_for_testing, get_1p1d_discretisation_for_testing, ) @@ -234,7 +235,7 @@ def test_evaluator_julia_discretised_operators(self): boundary_conditions = { var.id: { "left": (pybamm.Scalar(1), "Dirichlet"), - "right": (pybamm.Scalar(1), "Dirichlet"), + "right": (pybamm.Scalar(2), "Neumann"), } } disc.bcs = boundary_conditions @@ -242,40 +243,74 @@ def test_evaluator_julia_discretised_operators(self): disc.set_variable_slices([var]) grad_eqn_disc = disc.process_symbol(grad_eqn) + # div: test on linear y (should have laplacian zero) so change bcs + div_eqn = pybamm.div(var * grad_eqn) + + div_eqn_disc = disc.process_symbol(div_eqn) + # test - constant_y = np.ones_like(combined_submesh.nodes[:, np.newaxis]) + nodes = combined_submesh.nodes + y_tests = [nodes ** 2 + 1, np.cos(nodes)] + + for expr in [grad_eqn_disc, div_eqn_disc]: + for y_test in y_tests: + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + result = evaluator(None, y_test, None) + np.testing.assert_almost_equal( + result, expr.evaluate(y=y_test).flatten() + ) + + def test_evaluator_julia_discretised_microscale(self): + # create discretisation + mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) + spatial_methods = {"negative particle": pybamm.FiniteVolume()} + disc = pybamm.Discretisation(mesh, spatial_methods) - evaluator_str = pybamm.get_julia_function(grad_eqn_disc) - evaluator = Main.eval(evaluator_str) - result = evaluator(None, constant_y, None) - np.testing.assert_almost_equal( - result, grad_eqn_disc.evaluate(y=constant_y).flatten() + submesh = mesh["negative particle"] + + # grad + # grad(r) == 1 + var = pybamm.Variable( + "var", + domain=["negative particle"], + auxiliary_domains={ + "secondary": "negative electrode", + "tertiary": "current collector", + }, ) + grad_eqn = pybamm.grad(var) + div_eqn = pybamm.div(var * grad_eqn) - # # div: test on linear y (should have laplacian zero) so change bcs - # linear_y = combined_submesh.nodes - # N = pybamm.grad(var) - # div_eqn = pybamm.div(N) - # boundary_conditions = { - # var.id: { - # "left": (pybamm.Scalar(0), "Dirichlet"), - # "right": (pybamm.Scalar(1), "Dirichlet"), - # } - # } - - # disc.bcs = boundary_conditions - - # grad_eqn_disc = disc.process_symbol(grad_eqn) - # np.testing.assert_array_almost_equal( - # grad_eqn_disc.evaluate(None, linear_y), - # np.ones_like(combined_submesh.edges[:, np.newaxis]), - # ) - - # div_eqn_disc = disc.process_symbol(div_eqn) - # np.testing.assert_array_almost_equal( - # div_eqn_disc.evaluate(None, linear_y), - # np.zeros_like(combined_submesh.nodes[:, np.newaxis]), - # ) + boundary_conditions = { + var.id: { + "left": (pybamm.Scalar(1), "Dirichlet"), + "right": (pybamm.Scalar(2), "Neumann"), + } + } + + disc.bcs = boundary_conditions + + disc.set_variable_slices([var]) + grad_eqn_disc = disc.process_symbol(grad_eqn) + div_eqn_disc = disc.process_symbol(div_eqn) + + # test + total_npts = ( + submesh.npts + * mesh["negative electrode"].npts + * mesh["current collector"].npts + ) + y_tests = [np.linspace(0, 1, total_npts) ** 2] + + for expr in [div_eqn_disc]: + for y_test in y_tests: + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + result = evaluator(None, y_test, None) + np.testing.assert_almost_equal( + result, expr.evaluate(y=y_test).flatten() + ) if __name__ == "__main__": From 7c7cd6aa226b03c2659dbb200d4edc572829d0ee Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 20 Aug 2020 14:27:38 -0400 Subject: [PATCH 06/88] #1129 flatten column vectors --- examples/scripts/SPMe.py | 59 ++++++++----------- .../operations/evaluate_julia.py | 22 ++++++- .../test_operations/test_evaluate_julia.py | 6 +- 3 files changed, 47 insertions(+), 40 deletions(-) diff --git a/examples/scripts/SPMe.py b/examples/scripts/SPMe.py index 64da6f0140..75921b13d2 100644 --- a/examples/scripts/SPMe.py +++ b/examples/scripts/SPMe.py @@ -8,7 +8,7 @@ pybamm.set_logging_level("INFO") # load model -model = pybamm.lithium_ion.SPM() +model = pybamm.lithium_ion.SPMe() model.convert_to_format = "python" # create geometry @@ -20,41 +20,30 @@ param.process_geometry(geometry) # set mesh -var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 5, var.r_p: 5} - -mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) +mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts) # discretise model disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) -rhs = pybamm.get_julia_function(model.concatenated_rhs.simplify()) - -from julia import Main - -rhs_eval = Main.eval(rhs) -rhs_eval(0, model.concatenated_initial_conditions.evaluate(), None) -n = 1 - - -# # solve model for 1 hour -# t_eval = np.linspace(0, 3600, 100) -# solution = model.default_solver.solve(model, t_eval) - -# # plot -# plot = pybamm.QuickPlot( -# solution, -# [ -# "Negative particle concentration [mol.m-3]", -# "Electrolyte concentration [mol.m-3]", -# "Positive particle concentration [mol.m-3]", -# "Current [A]", -# "Negative electrode potential [V]", -# "Electrolyte potential [V]", -# "Positive electrode potential [V]", -# "Terminal voltage [V]", -# ], -# time_unit="seconds", -# spatial_unit="um", -# ) -# plot.dynamic_plot() + +# solve model for 1 hour +t_eval = np.linspace(0, 3600, 100) +solution = model.default_solver.solve(model, t_eval) + +# plot +plot = pybamm.QuickPlot( + solution, + [ + "Negative particle concentration [mol.m-3]", + "Electrolyte concentration [mol.m-3]", + "Positive particle concentration [mol.m-3]", + "Current [A]", + "Negative electrode potential [V]", + "Electrolyte potential [V]", + "Positive electrode potential [V]", + "Terminal voltage [V]", + ], + time_unit="seconds", + spatial_unit="um", +) +plot.dynamic_plot() diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 5292d0fa73..eb5562aef9 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -76,6 +76,21 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): m, n, ) + elif value.shape == (1, 1): + # Extract value if array has only one entry + constant_symbols[symbol.id] = value[0, 0] + elif value.shape[1] == 1: + # Set print options large enough to avoid ellipsis + # at least as big is len(row) = len(col) = len(data) + np.set_printoptions( + threshold=max( + np.get_printoptions()["threshold"], value.shape[0] + 10 + ) + ) + # Flatten a 1D array + constant_symbols[symbol.id] = np.array2string( + value.flatten(), separator="," + ) else: constant_symbols[symbol.id] = value return @@ -288,7 +303,7 @@ def get_julia_function(symbol): julia_str = julia_str.replace("\n", "\n ") # add function def and sparse arrays to first line - imports = "using SparseArrays\n" + imports = "begin\nusing SparseArrays\n" julia_str = imports + "function f_pybamm(t, y, p)\n" + julia_str # calculate the final variable that will output the result @@ -297,10 +312,11 @@ def get_julia_function(symbol): result_value = symbol.evaluate() # add return line + # two "end"s: one to close the function, one to close the "begin" if symbol.is_constant() and isinstance(result_value, numbers.Number): - julia_str = julia_str + "\n return " + str(result_value) + "\nend" + julia_str = julia_str + "\n return " + str(result_value) + "\nend\nend" else: - julia_str = julia_str + "\n return " + result_var + "\nend" + julia_str = julia_str + "\n return " + result_var + "\nend\nend" return julia_str diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index dd245d7208..597455d1b5 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -81,14 +81,16 @@ def test_evaluator_julia(self): evaluator = Main.eval(evaluator_str) for t, y in zip(t_tests, y_tests): result = evaluator(t, y, None) - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) expr = a > pybamm.StateVector(slice(0, 2)) evaluator_str = pybamm.get_julia_function(expr) evaluator = Main.eval(evaluator_str) for t, y in zip(t_tests, y_tests): result = evaluator(t, y, None) - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) # # test something with a minimum or maximum # a = pybamm.Vector([1, 2]) From 7b8d093b740412685ecc751a57f120c3dc21734b Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 27 Aug 2020 21:58:26 -0400 Subject: [PATCH 07/88] #1129 tests --- .../test_operations/test_evaluate_julia.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 597455d1b5..65d82a27bf 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -108,13 +108,13 @@ def test_evaluator_julia(self): # result = evaluator(t,y,None) # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - # # test something with an index - # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) - # evaluator_str = pybamm.get_julia_function(expr) - # evaluator = Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None) - # self.assertEqual(result, expr.evaluate(t=t, y=y)) + # test something with an index + expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) + evaluator_str = pybamm.get_julia_function(expr) + evaluator = Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + result = evaluator(t, y, None) + self.assertEqual(result, expr.evaluate(t=t, y=y)) # test something with a sparse matrix multiplication A = pybamm.Matrix([[1, 2], [3, 4]]) @@ -168,7 +168,7 @@ def test_evaluator_julia(self): # evaluator_str = pybamm.get_julia_function(expr) # evaluator = Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None).toarray() + # result = evaluator(t, y, None).toarray() # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) # # test Inner From 21b9f99cc2c6cd5d8688eb47f64adc9844f208b8 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 1 Oct 2020 23:24:22 -0400 Subject: [PATCH 08/88] test notebook --- Untitled.ipynb | 2513 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2513 insertions(+) create mode 100644 Untitled.ipynb diff --git a/Untitled.ipynb b/Untitled.ipynb new file mode 100644 index 0000000000..8a73a21698 --- /dev/null +++ b/Untitled.ipynb @@ -0,0 +1,2513 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m registry at `~/.julia/registries/General`\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[?25l " + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m git-repo `https://github.com/JuliaRegistries/General.git`\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [> ] 0.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 2.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 2.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 2.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 2.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 2.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 2.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 2.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 7.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 7.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 7.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 7.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 7.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 7.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 7.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 7.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 10.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 12.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 12.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 12.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 12.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 12.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 12.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 12.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=======> ] 16.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 17.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 17.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 17.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 17.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 17.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 17.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 17.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 17.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 20.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 22.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 22.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 22.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 22.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 22.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 22.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 22.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 27.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 27.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 27.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 27.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 27.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 27.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 27.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 27.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 30.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.1 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.4 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.8 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 32.0 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 32.2 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 32.3 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 32.5 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==============> ] 32.6 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==============> ] 32.7 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==============> ] 32.9 %\r", + " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==============> ] " + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2K\u001b[?25h[1mFetching:\u001b[22m\u001b[39m [========================================>] 100.0 % ] 52.4 % [============================> ] 69.0 %] 85.4 %\u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======================================> ] 97.2 %" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Adapt ────────────────── v2.3.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ArrayInterface ───────── v2.13.3\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m FillArrays ───────────── v0.8.14\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m DiffEqJump ───────────── v6.10.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m FiniteDiff ───────────── v2.7.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m OrderedCollections ───── v1.3.1\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Unitful ──────────────── v1.4.1\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m OrdinaryDiffEq ───────── v5.42.3\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Showoff ──────────────── v0.3.2\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m HTTP ─────────────────── v0.8.19\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ProgressMeter ────────── v1.4.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m DiffEqNoiseProcess ───── v5.3.1\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Grisu ────────────────── v1.0.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Compat ───────────────── v3.17.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Requires ─────────────── v1.1.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ChainRulesCore ───────── v0.9.10\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m RecipesBase ──────────── v1.1.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m SIMDPirates ──────────── v0.8.25\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m PlotUtils ────────────── v1.0.7\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m PDMats ───────────────── v0.10.1\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m OffsetArrays ─────────── v1.3.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m RecipesPipeline ──────── v0.1.13\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m RecursiveArrayTools ──── v2.7.1\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m LoopVectorization ────── v0.8.26\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Contour ──────────────── v0.5.5\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m LaTeXStrings ─────────── v1.2.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ParameterizedFunctions ─ v5.6.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m JSON ─────────────────── v0.21.1\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m StochasticDiffEq ─────── v6.25.0\n", + "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ColorSchemes ─────────── v3.10.1\n", + "\u001b[32m\u001b[1mUpdating\u001b[22m\u001b[39m `~/.julia/environments/v1.5/Project.toml`\n", + " \u001b[90m [1dea7af3] \u001b[39m\u001b[92m+ OrdinaryDiffEq v5.42.3\u001b[39m\n", + "\u001b[32m\u001b[1mUpdating\u001b[22m\u001b[39m `~/.julia/environments/v1.5/Manifest.toml`\n", + " \u001b[90m [79e6a3ab] \u001b[39m\u001b[93m↑ Adapt v2.0.2 ⇒ v2.3.0\u001b[39m\n", + " \u001b[90m [4fba245c] \u001b[39m\u001b[93m↑ ArrayInterface v2.11.0 ⇒ v2.13.3\u001b[39m\n", + " \u001b[90m [6e34b625] \u001b[39m\u001b[93m↑ Bzip2_jll v1.0.6+3 ⇒ v1.0.6+4\u001b[39m\n", + " \u001b[90m [a603d957] \u001b[39m\u001b[93m↑ CanonicalTraits v0.1.0 ⇒ v0.2.2\u001b[39m\n", + " \u001b[90m [d360d2e6] \u001b[39m\u001b[93m↑ ChainRulesCore v0.9.5 ⇒ v0.9.10\u001b[39m\n", + " \u001b[90m [35d6a980] \u001b[39m\u001b[93m↑ ColorSchemes v3.9.0 ⇒ v3.10.1\u001b[39m\n", + " \u001b[90m [3da002f7] \u001b[39m\u001b[93m↑ ColorTypes v0.10.8 ⇒ v0.10.9\u001b[39m\n", + " \u001b[90m [5ae59095] \u001b[39m\u001b[93m↑ Colors v0.12.3 ⇒ v0.12.4\u001b[39m\n", + " \u001b[90m [34da2185] \u001b[39m\u001b[93m↑ Compat v3.13.0 ⇒ v3.17.0\u001b[39m\n", + " \u001b[90m [d38c429a] \u001b[39m\u001b[93m↑ Contour v0.5.4 ⇒ v0.5.5\u001b[39m\n", + " \u001b[90m [c894b116] \u001b[39m\u001b[93m↑ DiffEqJump v6.9.3 ⇒ v6.10.0\u001b[39m\n", + " \u001b[90m [77a26b50] \u001b[39m\u001b[93m↑ DiffEqNoiseProcess v4.3.0 ⇒ v5.3.1\u001b[39m\n", + " \u001b[90m [055956cb] \u001b[39m\u001b[93m↑ DiffEqPhysics v3.2.0 ⇒ v3.6.0\u001b[39m\n", + " \u001b[90m [ffbed154] \u001b[39m\u001b[93m↑ DocStringExtensions v0.8.2 ⇒ v0.8.3\u001b[39m\n", + " \u001b[90m [d4d017d3] \u001b[39m\u001b[93m↑ ExponentialUtilities v1.7.0 ⇒ v1.8.0\u001b[39m\n", + " \u001b[90m [b22a6f82] \u001b[39m\u001b[93m↑ FFMPEG_jll v4.3.1+1 ⇒ v4.3.1+2\u001b[39m\n", + " \u001b[90m [1a297f60] \u001b[39m\u001b[93m↑ FillArrays v0.8.13 ⇒ v0.8.14\u001b[39m\n", + " \u001b[90m [6a86dc24] \u001b[39m\u001b[93m↑ FiniteDiff v2.5.2 ⇒ v2.7.0\u001b[39m\n", + " \u001b[90m [d7e528f0] \u001b[39m\u001b[93m↑ FreeType2_jll v2.10.1+3 ⇒ v2.10.1+4\u001b[39m\n", + " \u001b[90m [559328eb] \u001b[39m\u001b[93m↑ FriBidi_jll v1.0.5+4 ⇒ v1.0.5+5\u001b[39m\n", + " \u001b[90m [6b9d7cbe] \u001b[39m\u001b[93m↑ GeneralizedGenerated v0.2.5 ⇒ v0.2.7\u001b[39m\n", + " \u001b[90m [42e2da0e] \u001b[39m\u001b[92m+ Grisu v1.0.0\u001b[39m\n", + " \u001b[90m [cd3eb016] \u001b[39m\u001b[93m↑ HTTP v0.8.17 ⇒ v0.8.19\u001b[39m\n", + " \u001b[90m [682c06a0] \u001b[39m\u001b[93m↑ JSON v0.21.0 ⇒ v0.21.1\u001b[39m\n", + " \u001b[90m [b964fa9f] \u001b[39m\u001b[93m↑ LaTeXStrings v1.1.0 ⇒ v1.2.0\u001b[39m\n", + " \u001b[90m [d3d80556] \u001b[39m\u001b[93m↑ LineSearches v7.0.1 ⇒ v7.1.0\u001b[39m\n", + " \u001b[90m [bdcacae8] \u001b[39m\u001b[93m↑ LoopVectorization v0.8.22 ⇒ v0.8.26\u001b[39m\n", + " \u001b[90m [d8e11817] \u001b[39m\u001b[93m↑ MLStyle v0.4.3 ⇒ v0.4.6\u001b[39m\n", + " \u001b[90m [c8ffd9c3] \u001b[39m\u001b[93m↑ MbedTLS_jll v2.16.6+1 ⇒ v2.16.8+0\u001b[39m\n", + " \u001b[90m [e1d29d7a] \u001b[39m\u001b[93m↑ Missings v0.4.3 ⇒ v0.4.4\u001b[39m\n", + " \u001b[90m [d41bc354] \u001b[39m\u001b[93m↑ NLSolversBase v7.6.1 ⇒ v7.7.0\u001b[39m\n", + " \u001b[90m [2774e3e8] \u001b[39m\u001b[93m↑ NLsolve v4.4.0 ⇒ v4.4.1\u001b[39m\n", + " \u001b[90m [71a1bf82] \u001b[39m\u001b[93m↑ NameResolution v0.1.4 ⇒ v0.1.5\u001b[39m\n", + " \u001b[90m [6fe1bfb0] \u001b[39m\u001b[93m↑ OffsetArrays v1.1.2 ⇒ v1.3.0\u001b[39m\n", + " \u001b[90m [4536629a] \u001b[39m\u001b[93m↑ OpenBLAS_jll v0.3.9+5 ⇒ v0.3.10+0\u001b[39m\n", + " \u001b[90m [bac558e1] \u001b[39m\u001b[93m↑ OrderedCollections v1.3.0 ⇒ v1.3.1\u001b[39m\n", + " \u001b[90m [1dea7af3] \u001b[39m\u001b[93m↑ OrdinaryDiffEq v5.42.1 ⇒ v5.42.3\u001b[39m\n", + " \u001b[90m [90014a1f] \u001b[39m\u001b[93m↑ PDMats v0.10.0 ⇒ v0.10.1\u001b[39m\n", + " \u001b[90m [65888b18] \u001b[39m\u001b[93m↑ ParameterizedFunctions v5.4.0 ⇒ v5.6.0\u001b[39m\n", + " \u001b[90m [69de0a69] \u001b[39m\u001b[93m↑ Parsers v1.0.7 ⇒ v1.0.10\u001b[39m\n", + " \u001b[90m [995b91a9] \u001b[39m\u001b[93m↑ PlotUtils v1.0.5 ⇒ v1.0.7\u001b[39m\n", + " \u001b[90m [92933f4c] \u001b[39m\u001b[93m↑ ProgressMeter v1.3.2 ⇒ v1.4.0\u001b[39m\n", + " \u001b[90m [1fd47b50] \u001b[39m\u001b[93m↑ QuadGK v2.4.0 ⇒ v2.4.1\u001b[39m\n", + " \u001b[90m [3cdcf5f2] \u001b[39m\u001b[93m↑ RecipesBase v1.0.2 ⇒ v1.1.0\u001b[39m\n", + " \u001b[90m [01d81517] \u001b[39m\u001b[93m↑ RecipesPipeline v0.1.12 ⇒ v0.1.13\u001b[39m\n", + " \u001b[90m [731186ca] \u001b[39m\u001b[93m↑ RecursiveArrayTools v2.5.0 ⇒ v2.7.1\u001b[39m\n", + " \u001b[90m [ae029012] \u001b[39m\u001b[93m↑ Requires v1.0.1 ⇒ v1.1.0\u001b[39m\n", + " \u001b[90m [f2b01f46] \u001b[39m\u001b[93m↑ Roots v1.0.4 ⇒ v1.0.5\u001b[39m\n", + " \u001b[90m [21efa798] \u001b[39m\u001b[93m↑ SIMDPirates v0.8.21 ⇒ v0.8.25\u001b[39m\n", + " \u001b[90m [992d4aef] \u001b[39m\u001b[93m↑ Showoff v0.3.1 ⇒ v0.3.2\u001b[39m\n", + " \u001b[90m [699a6c99] \u001b[39m\u001b[93m↑ SimpleTraits v0.9.2 ⇒ v0.9.3\u001b[39m\n", + " \u001b[90m [47a9eef4] \u001b[39m\u001b[93m↑ SparseDiffTools v1.9.1 ⇒ v1.10.0\u001b[39m\n", + " \u001b[90m [2913bbd2] \u001b[39m\u001b[93m↑ StatsBase v0.33.0 ⇒ v0.33.1\u001b[39m\n", + " \u001b[90m [789caeaf] \u001b[39m\u001b[93m↑ StochasticDiffEq v6.23.1 ⇒ v6.25.0\u001b[39m\n", + " \u001b[90m [c3572dad] \u001b[39m\u001b[93m↑ Sundials v4.2.5 ⇒ v4.2.6\u001b[39m\n", + " \u001b[90m [fb77eaff] \u001b[39m\u001b[93m↑ Sundials_jll v5.2.0+0 ⇒ v5.2.0+1\u001b[39m\n", + " \u001b[90m [3a884ed6] \u001b[39m\u001b[93m↑ UnPack v1.0.1 ⇒ v1.0.2\u001b[39m\n", + " \u001b[90m [1986cc42] \u001b[39m\u001b[93m↑ Unitful v1.3.0 ⇒ v1.4.1\u001b[39m\n", + " \u001b[90m [3d5dd08c] \u001b[39m\u001b[93m↑ VectorizationBase v0.12.30 ⇒ v0.12.33\u001b[39m\n", + " \u001b[90m [83775a58] \u001b[39m\u001b[93m↑ Zlib_jll v1.2.11+15 ⇒ v1.2.11+16\u001b[39m\n", + "┌ Info: Precompiling OrdinaryDiffEq [1dea7af3-3e70-54e6-95c3-0bf5283fa5ed]\n", + "└ @ Base loading.jl:1278\n" + ] + } + ], + "source": [ + "import Pkg; Pkg.add(\"OrdinaryDiffEq\")\n", + "using ModelingToolkit, OrdinaryDiffEq" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "ename": "LoadError", + "evalue": "ArgumentError: reducing over an empty collection is not allowed", + "output_type": "error", + "traceback": [ + "ArgumentError: reducing over an empty collection is not allowed", + "", + "Stacktrace:", + " [1] _empty_reduce_error() at ./reduce.jl:299", + " [2] reduce_empty(::Function, ::Type{Any}) at ./reduce.jl:309", + " [3] mapreduce_empty(::typeof(identity), ::Function, ::Type{T} where T) at ./reduce.jl:343", + " [4] reduce_empty(::Base.MappingRF{typeof(identity),typeof(max)}, ::Type{Any}) at ./reduce.jl:329", + " [5] reduce_empty_iter at ./reduce.jl:355 [inlined]", + " [6] mapreduce_empty_iter(::Function, ::Function, ::Array{Any,1}, ::Base.HasEltype) at ./reduce.jl:351", + " [7] _mapreduce(::typeof(identity), ::typeof(max), ::IndexLinear, ::Array{Any,1}) at ./reduce.jl:400", + " [8] _mapreduce_dim at ./reducedim.jl:318 [inlined]", + " [9] #mapreduce#620 at ./reducedim.jl:310 [inlined]", + " [10] mapreduce at ./reducedim.jl:310 [inlined]", + " [11] _maximum at ./reducedim.jl:727 [inlined]", + " [12] _maximum at ./reducedim.jl:726 [inlined]", + " [13] #maximum#631 at ./reducedim.jl:722 [inlined]", + " [14] maximum(::Array{Any,1}) at ./reducedim.jl:722", + " [15] numargs(::Array{Equation,1}) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/utils.jl:13", + " [16] isinplace(::Array{Equation,1}, ::Int64) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/utils.jl:42", + " [17] ODEFunction(::Array{Equation,1}; kwargs::Base.Iterators.Pairs{Symbol,Nothing,NTuple{10,Symbol},NamedTuple{(:analytic, :tgrad, :jac, :jvp, :vjp, :Wfact, :Wfact_t, :paramjac, :syms, :colorvec),NTuple{10,Nothing}}}) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/diffeqfunction.jl:391", + " [18] convert at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/diffeqfunction.jl:1083 [inlined]", + " [19] ODEProblem(::Array{Equation,1}, ::Array{Pair{Operation,Float64},1}, ::Tuple{Float64,Float64}, ::Array{Pair{Operation,Float64},1}; kwargs::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/problems/ode_problems.jl:76", + " [20] ODEProblem(::Array{Equation,1}, ::Array{Pair{Operation,Float64},1}, ::Tuple{Float64,Float64}, ::Array{Pair{Operation,Float64},1}) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/problems/ode_problems.jl:76", + " [21] top-level scope at In[11]:20", + " [22] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091" + ] + } + ], + "source": [ + "@parameters t σ ρ β\n", + "@variables x(t) y(t) z(t)\n", + "@derivatives D'~t\n", + "\n", + "eqs = [D(x) ~ σ*(y-x),\n", + " D(y) ~ x*(ρ-z)-y,\n", + " D(z) ~ x*y - β*z]\n", + "\n", + "u0 = [x => 1.0,\n", + " y => 0.0,\n", + " z => 0.0,\n", + " ]\n", + "\n", + "p = [σ => 10.0,\n", + " ρ => 28.0,\n", + " β => 8/3,\n", + " ]\n", + "\n", + "tspan = (0.0,100.0)\n", + "prob = ODEProblem(eqs,u0,tspan,p)\n", + "sol = solve(prob,Rodas5())\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: Precompiling Plots [91a5bcdd-55d7-5caf-9e0b-520d859cae80]\n", + "└ @ Base loading.jl:1278\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "using Plots; plot(sol,vars=(a,lorenz1.x,lorenz2.z))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "using ModelingToolkit, OrdinaryDiffEq, Plots\n", + "# t = Variable{Float64}(:t)()\n", + "# σ = Variable{Float64}(:σ)()\n", + "# x = Variable{Float64}(:x)(t)\n", + "# D = Differential(t)\n", + "\n", + "@variables t, x(t)\n", + "# @parameters σ\n", + "@derivatives D'~t\n", + "\n", + "eqs = [D(x) ~ -2.0 * x]\n", + "sys = ODESystem(eqs,t)\n", + "u0 = [x => 1.0]\n", + "p = [σ => 2.0]\n", + "tspan = (0.0,1.0)\n", + "prob = ODEProblem(sys,u0,tspan)\n", + "sol = solve(prob, Tsit5())\n", + "plot(sol)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.5.0", + "language": "julia", + "name": "julia-1.5" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.5.1" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From bb6295371e19087360b35d9fc65c363b4e168c97 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 15 Oct 2020 10:03:38 -0400 Subject: [PATCH 09/88] #1129 generating MTK model --- Untitled.ipynb | 2501 ++--------------- pybamm/__init__.py | 5 +- .../operations/evaluate_julia.py | 130 +- .../test_operations/test_evaluate_julia.py | 13 + 4 files changed, 410 insertions(+), 2239 deletions(-) diff --git a/Untitled.ipynb b/Untitled.ipynb index 8a73a21698..c458565364 100644 --- a/Untitled.ipynb +++ b/Untitled.ipynb @@ -2,2237 +2,253 @@ "cells": [ { "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m registry at `~/.julia/registries/General`\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[?25l " - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m git-repo `https://github.com/JuliaRegistries/General.git`\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [> ] 0.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 0.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 1.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 2.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 2.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 2.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=> ] 2.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 2.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 2.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 2.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 3.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==> ] 4.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 5.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 6.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 7.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 7.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 7.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===> ] 7.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 7.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 7.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 7.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 7.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 8.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 9.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [====> ] 10.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 10.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 11.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 12.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 12.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 12.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=====> ] 12.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 12.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 12.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 12.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 13.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [======> ] 14.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 15.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "=======> ] 16.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 16.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 17.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 17.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 17.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======> ] 17.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 17.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 17.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 17.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 17.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 18.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 19.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [========> ] 20.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 20.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 21.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 22.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 22.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 22.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=========> ] 22.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 22.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 22.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 22.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 23.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==========> ] 24.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 25.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 26.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 27.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 27.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 27.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [===========> ] 27.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 27.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 27.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 27.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 27.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 28.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 29.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [============> ] 30.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 30.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.1 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.4 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.8 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 31.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 32.0 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 32.2 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 32.3 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=============> ] 32.5 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==============> ] 32.6 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==============> ] 32.7 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==============> ] 32.9 %\r", - " \u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [==============> ] " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[2K\u001b[?25h[1mFetching:\u001b[22m\u001b[39m [========================================>] 100.0 % ] 52.4 % [============================> ] 69.0 %] 85.4 %\u001b[36m\u001b[1mFetching:\u001b[22m\u001b[39m [=======================================> ] 97.2 %" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Adapt ────────────────── v2.3.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ArrayInterface ───────── v2.13.3\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m FillArrays ───────────── v0.8.14\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m DiffEqJump ───────────── v6.10.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m FiniteDiff ───────────── v2.7.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m OrderedCollections ───── v1.3.1\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Unitful ──────────────── v1.4.1\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m OrdinaryDiffEq ───────── v5.42.3\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Showoff ──────────────── v0.3.2\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m HTTP ─────────────────── v0.8.19\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ProgressMeter ────────── v1.4.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m DiffEqNoiseProcess ───── v5.3.1\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Grisu ────────────────── v1.0.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Compat ───────────────── v3.17.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Requires ─────────────── v1.1.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ChainRulesCore ───────── v0.9.10\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m RecipesBase ──────────── v1.1.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m SIMDPirates ──────────── v0.8.25\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m PlotUtils ────────────── v1.0.7\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m PDMats ───────────────── v0.10.1\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m OffsetArrays ─────────── v1.3.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m RecipesPipeline ──────── v0.1.13\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m RecursiveArrayTools ──── v2.7.1\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m LoopVectorization ────── v0.8.26\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m Contour ──────────────── v0.5.5\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m LaTeXStrings ─────────── v1.2.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ParameterizedFunctions ─ v5.6.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m JSON ─────────────────── v0.21.1\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m StochasticDiffEq ─────── v6.25.0\n", - "\u001b[32m\u001b[1m Installed\u001b[22m\u001b[39m ColorSchemes ─────────── v3.10.1\n", - "\u001b[32m\u001b[1mUpdating\u001b[22m\u001b[39m `~/.julia/environments/v1.5/Project.toml`\n", - " \u001b[90m [1dea7af3] \u001b[39m\u001b[92m+ OrdinaryDiffEq v5.42.3\u001b[39m\n", - "\u001b[32m\u001b[1mUpdating\u001b[22m\u001b[39m `~/.julia/environments/v1.5/Manifest.toml`\n", - " \u001b[90m [79e6a3ab] \u001b[39m\u001b[93m↑ Adapt v2.0.2 ⇒ v2.3.0\u001b[39m\n", - " \u001b[90m [4fba245c] \u001b[39m\u001b[93m↑ ArrayInterface v2.11.0 ⇒ v2.13.3\u001b[39m\n", - " \u001b[90m [6e34b625] \u001b[39m\u001b[93m↑ Bzip2_jll v1.0.6+3 ⇒ v1.0.6+4\u001b[39m\n", - " \u001b[90m [a603d957] \u001b[39m\u001b[93m↑ CanonicalTraits v0.1.0 ⇒ v0.2.2\u001b[39m\n", - " \u001b[90m [d360d2e6] \u001b[39m\u001b[93m↑ ChainRulesCore v0.9.5 ⇒ v0.9.10\u001b[39m\n", - " \u001b[90m [35d6a980] \u001b[39m\u001b[93m↑ ColorSchemes v3.9.0 ⇒ v3.10.1\u001b[39m\n", - " \u001b[90m [3da002f7] \u001b[39m\u001b[93m↑ ColorTypes v0.10.8 ⇒ v0.10.9\u001b[39m\n", - " \u001b[90m [5ae59095] \u001b[39m\u001b[93m↑ Colors v0.12.3 ⇒ v0.12.4\u001b[39m\n", - " \u001b[90m [34da2185] \u001b[39m\u001b[93m↑ Compat v3.13.0 ⇒ v3.17.0\u001b[39m\n", - " \u001b[90m [d38c429a] \u001b[39m\u001b[93m↑ Contour v0.5.4 ⇒ v0.5.5\u001b[39m\n", - " \u001b[90m [c894b116] \u001b[39m\u001b[93m↑ DiffEqJump v6.9.3 ⇒ v6.10.0\u001b[39m\n", - " \u001b[90m [77a26b50] \u001b[39m\u001b[93m↑ DiffEqNoiseProcess v4.3.0 ⇒ v5.3.1\u001b[39m\n", - " \u001b[90m [055956cb] \u001b[39m\u001b[93m↑ DiffEqPhysics v3.2.0 ⇒ v3.6.0\u001b[39m\n", - " \u001b[90m [ffbed154] \u001b[39m\u001b[93m↑ DocStringExtensions v0.8.2 ⇒ v0.8.3\u001b[39m\n", - " \u001b[90m [d4d017d3] \u001b[39m\u001b[93m↑ ExponentialUtilities v1.7.0 ⇒ v1.8.0\u001b[39m\n", - " \u001b[90m [b22a6f82] \u001b[39m\u001b[93m↑ FFMPEG_jll v4.3.1+1 ⇒ v4.3.1+2\u001b[39m\n", - " \u001b[90m [1a297f60] \u001b[39m\u001b[93m↑ FillArrays v0.8.13 ⇒ v0.8.14\u001b[39m\n", - " \u001b[90m [6a86dc24] \u001b[39m\u001b[93m↑ FiniteDiff v2.5.2 ⇒ v2.7.0\u001b[39m\n", - " \u001b[90m [d7e528f0] \u001b[39m\u001b[93m↑ FreeType2_jll v2.10.1+3 ⇒ v2.10.1+4\u001b[39m\n", - " \u001b[90m [559328eb] \u001b[39m\u001b[93m↑ FriBidi_jll v1.0.5+4 ⇒ v1.0.5+5\u001b[39m\n", - " \u001b[90m [6b9d7cbe] \u001b[39m\u001b[93m↑ GeneralizedGenerated v0.2.5 ⇒ v0.2.7\u001b[39m\n", - " \u001b[90m [42e2da0e] \u001b[39m\u001b[92m+ Grisu v1.0.0\u001b[39m\n", - " \u001b[90m [cd3eb016] \u001b[39m\u001b[93m↑ HTTP v0.8.17 ⇒ v0.8.19\u001b[39m\n", - " \u001b[90m [682c06a0] \u001b[39m\u001b[93m↑ JSON v0.21.0 ⇒ v0.21.1\u001b[39m\n", - " \u001b[90m [b964fa9f] \u001b[39m\u001b[93m↑ LaTeXStrings v1.1.0 ⇒ v1.2.0\u001b[39m\n", - " \u001b[90m [d3d80556] \u001b[39m\u001b[93m↑ LineSearches v7.0.1 ⇒ v7.1.0\u001b[39m\n", - " \u001b[90m [bdcacae8] \u001b[39m\u001b[93m↑ LoopVectorization v0.8.22 ⇒ v0.8.26\u001b[39m\n", - " \u001b[90m [d8e11817] \u001b[39m\u001b[93m↑ MLStyle v0.4.3 ⇒ v0.4.6\u001b[39m\n", - " \u001b[90m [c8ffd9c3] \u001b[39m\u001b[93m↑ MbedTLS_jll v2.16.6+1 ⇒ v2.16.8+0\u001b[39m\n", - " \u001b[90m [e1d29d7a] \u001b[39m\u001b[93m↑ Missings v0.4.3 ⇒ v0.4.4\u001b[39m\n", - " \u001b[90m [d41bc354] \u001b[39m\u001b[93m↑ NLSolversBase v7.6.1 ⇒ v7.7.0\u001b[39m\n", - " \u001b[90m [2774e3e8] \u001b[39m\u001b[93m↑ NLsolve v4.4.0 ⇒ v4.4.1\u001b[39m\n", - " \u001b[90m [71a1bf82] \u001b[39m\u001b[93m↑ NameResolution v0.1.4 ⇒ v0.1.5\u001b[39m\n", - " \u001b[90m [6fe1bfb0] \u001b[39m\u001b[93m↑ OffsetArrays v1.1.2 ⇒ v1.3.0\u001b[39m\n", - " \u001b[90m [4536629a] \u001b[39m\u001b[93m↑ OpenBLAS_jll v0.3.9+5 ⇒ v0.3.10+0\u001b[39m\n", - " \u001b[90m [bac558e1] \u001b[39m\u001b[93m↑ OrderedCollections v1.3.0 ⇒ v1.3.1\u001b[39m\n", - " \u001b[90m [1dea7af3] \u001b[39m\u001b[93m↑ OrdinaryDiffEq v5.42.1 ⇒ v5.42.3\u001b[39m\n", - " \u001b[90m [90014a1f] \u001b[39m\u001b[93m↑ PDMats v0.10.0 ⇒ v0.10.1\u001b[39m\n", - " \u001b[90m [65888b18] \u001b[39m\u001b[93m↑ ParameterizedFunctions v5.4.0 ⇒ v5.6.0\u001b[39m\n", - " \u001b[90m [69de0a69] \u001b[39m\u001b[93m↑ Parsers v1.0.7 ⇒ v1.0.10\u001b[39m\n", - " \u001b[90m [995b91a9] \u001b[39m\u001b[93m↑ PlotUtils v1.0.5 ⇒ v1.0.7\u001b[39m\n", - " \u001b[90m [92933f4c] \u001b[39m\u001b[93m↑ ProgressMeter v1.3.2 ⇒ v1.4.0\u001b[39m\n", - " \u001b[90m [1fd47b50] \u001b[39m\u001b[93m↑ QuadGK v2.4.0 ⇒ v2.4.1\u001b[39m\n", - " \u001b[90m [3cdcf5f2] \u001b[39m\u001b[93m↑ RecipesBase v1.0.2 ⇒ v1.1.0\u001b[39m\n", - " \u001b[90m [01d81517] \u001b[39m\u001b[93m↑ RecipesPipeline v0.1.12 ⇒ v0.1.13\u001b[39m\n", - " \u001b[90m [731186ca] \u001b[39m\u001b[93m↑ RecursiveArrayTools v2.5.0 ⇒ v2.7.1\u001b[39m\n", - " \u001b[90m [ae029012] \u001b[39m\u001b[93m↑ Requires v1.0.1 ⇒ v1.1.0\u001b[39m\n", - " \u001b[90m [f2b01f46] \u001b[39m\u001b[93m↑ Roots v1.0.4 ⇒ v1.0.5\u001b[39m\n", - " \u001b[90m [21efa798] \u001b[39m\u001b[93m↑ SIMDPirates v0.8.21 ⇒ v0.8.25\u001b[39m\n", - " \u001b[90m [992d4aef] \u001b[39m\u001b[93m↑ Showoff v0.3.1 ⇒ v0.3.2\u001b[39m\n", - " \u001b[90m [699a6c99] \u001b[39m\u001b[93m↑ SimpleTraits v0.9.2 ⇒ v0.9.3\u001b[39m\n", - " \u001b[90m [47a9eef4] \u001b[39m\u001b[93m↑ SparseDiffTools v1.9.1 ⇒ v1.10.0\u001b[39m\n", - " \u001b[90m [2913bbd2] \u001b[39m\u001b[93m↑ StatsBase v0.33.0 ⇒ v0.33.1\u001b[39m\n", - " \u001b[90m [789caeaf] \u001b[39m\u001b[93m↑ StochasticDiffEq v6.23.1 ⇒ v6.25.0\u001b[39m\n", - " \u001b[90m [c3572dad] \u001b[39m\u001b[93m↑ Sundials v4.2.5 ⇒ v4.2.6\u001b[39m\n", - " \u001b[90m [fb77eaff] \u001b[39m\u001b[93m↑ Sundials_jll v5.2.0+0 ⇒ v5.2.0+1\u001b[39m\n", - " \u001b[90m [3a884ed6] \u001b[39m\u001b[93m↑ UnPack v1.0.1 ⇒ v1.0.2\u001b[39m\n", - " \u001b[90m [1986cc42] \u001b[39m\u001b[93m↑ Unitful v1.3.0 ⇒ v1.4.1\u001b[39m\n", - " \u001b[90m [3d5dd08c] \u001b[39m\u001b[93m↑ VectorizationBase v0.12.30 ⇒ v0.12.33\u001b[39m\n", - " \u001b[90m [83775a58] \u001b[39m\u001b[93m↑ Zlib_jll v1.2.11+15 ⇒ v1.2.11+16\u001b[39m\n", - "┌ Info: Precompiling OrdinaryDiffEq [1dea7af3-3e70-54e6-95c3-0bf5283fa5ed]\n", - "└ @ Base loading.jl:1278\n" - ] - } - ], - "source": [ - "import Pkg; Pkg.add(\"OrdinaryDiffEq\")\n", - "using ModelingToolkit, OrdinaryDiffEq" - ] - }, - { - "cell_type": "code", - "execution_count": 11, + "execution_count": 1, "metadata": {}, "outputs": [ - { - "ename": "LoadError", - "evalue": "ArgumentError: reducing over an empty collection is not allowed", - "output_type": "error", - "traceback": [ - "ArgumentError: reducing over an empty collection is not allowed", - "", - "Stacktrace:", - " [1] _empty_reduce_error() at ./reduce.jl:299", - " [2] reduce_empty(::Function, ::Type{Any}) at ./reduce.jl:309", - " [3] mapreduce_empty(::typeof(identity), ::Function, ::Type{T} where T) at ./reduce.jl:343", - " [4] reduce_empty(::Base.MappingRF{typeof(identity),typeof(max)}, ::Type{Any}) at ./reduce.jl:329", - " [5] reduce_empty_iter at ./reduce.jl:355 [inlined]", - " [6] mapreduce_empty_iter(::Function, ::Function, ::Array{Any,1}, ::Base.HasEltype) at ./reduce.jl:351", - " [7] _mapreduce(::typeof(identity), ::typeof(max), ::IndexLinear, ::Array{Any,1}) at ./reduce.jl:400", - " [8] _mapreduce_dim at ./reducedim.jl:318 [inlined]", - " [9] #mapreduce#620 at ./reducedim.jl:310 [inlined]", - " [10] mapreduce at ./reducedim.jl:310 [inlined]", - " [11] _maximum at ./reducedim.jl:727 [inlined]", - " [12] _maximum at ./reducedim.jl:726 [inlined]", - " [13] #maximum#631 at ./reducedim.jl:722 [inlined]", - " [14] maximum(::Array{Any,1}) at ./reducedim.jl:722", - " [15] numargs(::Array{Equation,1}) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/utils.jl:13", - " [16] isinplace(::Array{Equation,1}, ::Int64) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/utils.jl:42", - " [17] ODEFunction(::Array{Equation,1}; kwargs::Base.Iterators.Pairs{Symbol,Nothing,NTuple{10,Symbol},NamedTuple{(:analytic, :tgrad, :jac, :jvp, :vjp, :Wfact, :Wfact_t, :paramjac, :syms, :colorvec),NTuple{10,Nothing}}}) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/diffeqfunction.jl:391", - " [18] convert at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/diffeqfunction.jl:1083 [inlined]", - " [19] ODEProblem(::Array{Equation,1}, ::Array{Pair{Operation,Float64},1}, ::Tuple{Float64,Float64}, ::Array{Pair{Operation,Float64},1}; kwargs::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/problems/ode_problems.jl:76", - " [20] ODEProblem(::Array{Equation,1}, ::Array{Pair{Operation,Float64},1}, ::Tuple{Float64,Float64}, ::Array{Pair{Operation,Float64},1}) at /Users/vsulzer/.julia/packages/DiffEqBase/T5smF/src/problems/ode_problems.jl:76", - " [21] top-level scope at In[11]:20", - " [22] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091" - ] - } - ], - "source": [ - "@parameters t σ ρ β\n", - "@variables x(t) y(t) z(t)\n", - "@derivatives D'~t\n", - "\n", - "eqs = [D(x) ~ σ*(y-x),\n", - " D(y) ~ x*(ρ-z)-y,\n", - " D(z) ~ x*y - β*z]\n", - "\n", - "u0 = [x => 1.0,\n", - " y => 0.0,\n", - " z => 0.0,\n", - " ]\n", - "\n", - "p = [σ => 10.0,\n", - " ρ => 28.0,\n", - " β => 8/3,\n", - " ]\n", - "\n", - "tspan = (0.0,100.0)\n", - "prob = ODEProblem(eqs,u0,tspan,p)\n", - "sol = solve(prob,Rodas5())\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "┌ Info: Precompiling Plots [91a5bcdd-55d7-5caf-9e0b-520d859cae80]\n", - "└ @ Base loading.jl:1278\n" - ] - }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", - " \n", + " \n", " \n", " \n", "\n", - "\n", "\n", - " \n", + " \n", " \n", " \n", "\n", + "\n", "\n", - " \n", - " \n", + " \n", + " \n", " \n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" + "\n" ] }, - "execution_count": 4, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "using Plots; plot(sol,vars=(a,lorenz1.x,lorenz2.z))" + "using ModelingToolkit, OrdinaryDiffEq, Plots\n", + "# t = Variable{Float64}(:t)()\n", + "# σ = Variable{Float64}(:σ)()\n", + "# x = Variable{Float64}(:x)(t)\n", + "# D = Differential(t)\n", + "\n", + "@variables t, x(t)\n", + "# @parameters σ\n", + "@derivatives D'~t\n", + "\n", + "constant = 2.0\n", + "eq = - constant * x\n", + "eqs = [D(x) ~ eq]\n", + "sys = ODESystem(eqs,t)\n", + "u0 = [x => 1.0]\n", + "# p = [σ => 2.0]\n", + "tspan = (0.0,1.0)\n", + "prob = ODEProblem(sys,u0,tspan)\n", + "sol = solve(prob, Tsit5())\n", + "plot(sol)" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -2241,99 +257,99 @@ "\n", "\n", "\n", - " \n", + " \n", " \n", " \n", "\n", - "\n", "\n", - " \n", + " \n", " \n", " \n", "\n", - "\n", "\n", - " \n", + " \n", " \n", " \n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" + "\n" ] }, - "execution_count": 16, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "using ModelingToolkit, OrdinaryDiffEq, Plots\n", - "# t = Variable{Float64}(:t)()\n", - "# σ = Variable{Float64}(:σ)()\n", - "# x = Variable{Float64}(:x)(t)\n", - "# D = Differential(t)\n", + "eval(Meta.parse(\n", + " \"\"\"\n", + " begin\n", + " @variables t, x1(t)\n", "\n", - "@variables t, x(t)\n", - "# @parameters σ\n", - "@derivatives D'~t\n", + " @derivatives D'~t\n", "\n", - "eqs = [D(x) ~ -2.0 * x]\n", - "sys = ODESystem(eqs,t)\n", - "u0 = [x => 1.0]\n", - "p = [σ => 2.0]\n", + " # 'v' equation\n", + " var_m2727759585034929413 = -2.0 .* x1\n", + "\n", + " eqs = [\n", + " D(x1) ~ var_m2727759585034929413,\n", + " ]\n", + " sys = ODESystem(eqs, t)\n", + " # 'v' initial conditions\n", + "\n", + "\n", + " u0 = [\n", + " x1 => 1.0,\n", + " ]\n", + " end\n", + " \"\"\"\n", + "))\n", + "# p = [σ => 2.0]\n", "tspan = (0.0,1.0)\n", "prob = ODEProblem(sys,u0,tspan)\n", "sol = solve(prob, Tsit5())\n", "plot(sol)" ] }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "ename": "LoadError", + "evalue": "PyError ($(Expr(:escape, :(ccall(#= /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:38 =# @pysym(:PyEval_EvalCode), PyPtr, (PyPtr, PyPtr, PyPtr), o, globals, locals))))) \nModuleNotFoundError(\"No module named 'pybamm'\")\n File \"/Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl\", line 1, in \n const Py_single_input = 256 # from Python.h\n", + "output_type": "error", + "traceback": [ + "PyError ($(Expr(:escape, :(ccall(#= /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:38 =# @pysym(:PyEval_EvalCode), PyPtr, (PyPtr, PyPtr, PyPtr), o, globals, locals))))) \nModuleNotFoundError(\"No module named 'pybamm'\")\n File \"/Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl\", line 1, in \n const Py_single_input = 256 # from Python.h\n", + "", + "Stacktrace:", + " [1] pyerr_check at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/exception.jl:60 [inlined]", + " [2] pyerr_check at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/exception.jl:64 [inlined]", + " [3] _handle_error(::String) at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/exception.jl:81", + " [4] macro expansion at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/exception.jl:95 [inlined]", + " [5] #120 at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:38 [inlined]", + " [6] disable_sigint at ./c.jl:446 [inlined]", + " [7] pyeval_(::String, ::PyDict{String,PyObject,true}, ::PyDict{String,PyObject,true}, ::Int64, ::String) at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:37", + " [8] top-level scope at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:230", + " [9] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091" + ] + } + ], + "source": [ + "using PyCall\n", + "\n", + "py\"\"\"\n", + "import pybamm\n", + "\"\"\"" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/pybamm/__init__.py b/pybamm/__init__.py index b29483b071..ced00595da 100644 --- a/pybamm/__init__.py +++ b/pybamm/__init__.py @@ -115,7 +115,10 @@ def version(formatted=False): from .expression_tree.operations.jacobian import Jacobian from .expression_tree.operations.convert_to_casadi import CasadiConverter from .expression_tree.operations.unpack_symbols import SymbolUnpacker -from .expression_tree.operations.evaluate_julia import get_julia_function +from .expression_tree.operations.evaluate_julia import ( + get_julia_function, + get_julia_mtk_model, +) # # Model classes diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index eb5562aef9..e5dc563013 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -25,7 +25,7 @@ def id_to_julia_variable(symbol_id, constant=False): return var_format.format(symbol_id).replace("-", "m") -def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): +def find_symbols(symbol, constant_symbols, variable_symbols): """ This function converts an expression tree to a dictionary of node id's and strings specifying valid julia code to calculate that nodes value, given y and t. @@ -45,15 +45,12 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): symbol : :class:`pybamm.Symbol` The symbol or expression tree to convert - constant_symbol: collections.OrderedDict + constant_symbol : collections.OrderedDict The output dictionary of constant symbol ids to lines of code - variable_symbol: collections.OrderedDict + variable_symbol : collections.OrderedDict The output dictionary of variable (with y or t) symbol ids to lines of code - to_dense: bool - If True, all constants and expressions are converted to using dense matrices - """ if symbol.is_constant(): value = symbol.evaluate() @@ -81,7 +78,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): constant_symbols[symbol.id] = value[0, 0] elif value.shape[1] == 1: # Set print options large enough to avoid ellipsis - # at least as big is len(row) = len(col) = len(data) + # at least as big as len(row) = len(col) = len(data) np.set_printoptions( threshold=max( np.get_printoptions()["threshold"], value.shape[0] + 10 @@ -97,7 +94,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): # process children recursively for child in symbol.children: - find_symbols(child, constant_symbols, variable_symbols, to_dense) + find_symbols(child, constant_symbols, variable_symbols) # calculate the variable names that will hold the result of calculating the # children variables @@ -213,6 +210,10 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): elif isinstance(symbol, pybamm.InputParameter): symbol_str = "inputs['{}']".format(symbol.name) + elif isinstance(symbol, pybamm.Variable): + # No need to do anything if a Variable is found + return + else: raise NotImplementedError( "Conversion to Julia not implemented for a symbol of type '{}'".format( @@ -223,7 +224,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols, to_dense=False): variable_symbols[symbol.id] = symbol_str -def to_julia(symbol, debug=False, to_dense=False): +def to_julia(symbol, debug=False): """ This function converts an expression tree into a dict of constant input values, and valid julia code that acts like the tree's :func:`pybamm.Symbol.evaluate` function @@ -233,24 +234,19 @@ def to_julia(symbol, debug=False, to_dense=False): symbol : :class:`pybamm.Symbol` The symbol to convert to julia code - debug : bool - If set to True, the function also emits debug code - Returns ------- - collections.OrderedDict: + constant_values : collections.OrderedDict dict mapping node id to a constant value. Represents all the constant nodes in the expression tree - str: + str valid julia code that will evaluate all the variable nodes in the tree. - to_dense: bool - If True, all constants and expressions are converted to using dense matrices """ constant_values = OrderedDict() variable_symbols = OrderedDict() - find_symbols(symbol, constant_values, variable_symbols, to_dense) + find_symbols(symbol, constant_values, variable_symbols) line_format = "{} = {}" @@ -320,3 +316,103 @@ def get_julia_function(symbol): return julia_str + +def get_julia_mtk_model(model): + """ + Converts a pybamm model into a Julia ModelingToolkit model + + Parameters + ---------- + model : :class:`pybamm.BaseModel` + The model to be converted + + Returns + ------- + mtk_str : str + String of julia code representing a model in MTK, + to be evaluated by ``julia.Main.eval`` + """ + + # Define variables + # Returns something like "@variables t, x1(t), x2(t)" + variables = {var.id: f"x{i+1}" for i, var in enumerate(model.rhs.keys())} + mtk_str = "@variables t" + for var in variables.values(): + mtk_str += f", {var}(t)" + mtk_str += "\n\n" + + # Define derivatives + mtk_str += "@derivatives D'~t\n\n" + + # Define equations + all_eqns_str = "" + all_constants_str = "" + all_julia_str = "" + for var, eqn in model.rhs.items(): + constants, julia_str = to_julia(eqn, debug=False) + + # extract constants in generated function + for eqn_id, const_value in constants.items(): + const_name = id_to_julia_variable(eqn_id, True) + all_constants_str += "{} = {}\n".format(const_name, const_value) + + # add a comment labeling the equation, and the equation itself + all_julia_str += f"# '{var.name}' equation\n" + julia_str + "\n" + + # calculate the final variable that will output the result + result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) + if eqn.is_constant(): + result_value = eqn.evaluate() + + # define the variable that goes into the equation + if eqn.is_constant() and isinstance(result_value, numbers.Number): + eqn_str = str(result_value) + else: + eqn_str = result_var + + all_eqns_str += f"\tD({variables[var.id]}) ~ {eqn_str},\n" + + # Replace variables in the julia strings that correspond to pybamm variables with + # their julia equivalent + for var_id, julia_id in variables.items(): + all_julia_str = all_julia_str.replace( + id_to_julia_variable(var_id, False), julia_id + ) + + # Update the MTK string + mtk_str += all_constants_str + all_julia_str + "\n" + f"eqs = [\n{all_eqns_str}]\n" + + # Create ODESystem + mtk_str += "sys = ODESystem(eqs, t)\n" + + # Create initial conditions + all_ics_str = "" + all_constants_str = "" + all_julia_str = "" + for var, eqn in model.initial_conditions.items(): + constants, julia_str = to_julia(eqn, debug=False) + + # extract constants in generated function + for eqn_id, const_value in constants.items(): + const_name = id_to_julia_variable(eqn_id, True) + all_constants_str += "{} = {}\n".format(const_name, const_value) + + # add a comment labeling the equation, and the equation itself + all_julia_str += f"# '{var.name}' initial conditions\n" + julia_str + "\n" + + # calculate the final variable that will output the result + result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) + if eqn.is_constant(): + result_value = eqn.evaluate() + + # define the variable that goes into the equation + if eqn.is_constant() and isinstance(result_value, numbers.Number): + eqn_str = str(result_value) + else: + raise pybamm.ModelError + + all_ics_str += f"\t{variables[var.id]} => {eqn_str},\n" + + mtk_str += all_constants_str + all_julia_str + "\n" + f"u0 = [\n{all_ics_str}]\n" + + return mtk_str \ No newline at end of file diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 65d82a27bf..e7cbe34156 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -17,6 +17,7 @@ from julia import Main +@unittest.skip("") class TestEvaluate(unittest.TestCase): def test_evaluator_julia(self): a = pybamm.StateVector(slice(0, 1)) @@ -315,6 +316,18 @@ def test_evaluator_julia_discretised_microscale(self): ) +class TestEvaluateMTKModel(unittest.TestCase): + def test_exponential_decay_model(self): + model = pybamm.BaseModel() + v = pybamm.Variable("v") + model.rhs = {v: -2 * v} + model.initial_conditions = {v: 1} + + mtk_str = pybamm.get_julia_mtk_model(model) + + print(mtk_str) + + if __name__ == "__main__": print("Add -v for more debug output") import sys From 5494ea394b990eacfc114fa48f26218c022ffecf Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 15 Oct 2020 11:57:12 -0400 Subject: [PATCH 10/88] #1129 cleaning up a bit --- .../operations/evaluate_julia.py | 30 +++++++++++++------ pybamm/solvers/idaklu_solver.py | 7 +++-- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index e5dc563013..aed984d1d9 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -332,14 +332,18 @@ def get_julia_mtk_model(model): String of julia code representing a model in MTK, to be evaluated by ``julia.Main.eval`` """ - + mtk_str = "begin\n" # Define variables - # Returns something like "@variables t, x1(t), x2(t)" variables = {var.id: f"x{i+1}" for i, var in enumerate(model.rhs.keys())} - mtk_str = "@variables t" + + # Add a comment with the variable names + for var in model.rhs.keys(): + mtk_str += f"# {var.name} -> {variables[var.id]}\n" + # Returns something like "@variables t, x1(t), x2(t)" + mtk_str += "@variables t" for var in variables.values(): mtk_str += f", {var}(t)" - mtk_str += "\n\n" + mtk_str += "\n" # Define derivatives mtk_str += "@derivatives D'~t\n\n" @@ -357,7 +361,10 @@ def get_julia_mtk_model(model): all_constants_str += "{} = {}\n".format(const_name, const_value) # add a comment labeling the equation, and the equation itself - all_julia_str += f"# '{var.name}' equation\n" + julia_str + "\n" + if julia_str == "": + all_julia_str = "" + else: + all_julia_str += f"# '{var.name}' equation\n" + julia_str + "\n" # calculate the final variable that will output the result result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) @@ -370,7 +377,7 @@ def get_julia_mtk_model(model): else: eqn_str = result_var - all_eqns_str += f"\tD({variables[var.id]}) ~ {eqn_str},\n" + all_eqns_str += f" D({variables[var.id]}) ~ {eqn_str},\n" # Replace variables in the julia strings that correspond to pybamm variables with # their julia equivalent @@ -383,7 +390,7 @@ def get_julia_mtk_model(model): mtk_str += all_constants_str + all_julia_str + "\n" + f"eqs = [\n{all_eqns_str}]\n" # Create ODESystem - mtk_str += "sys = ODESystem(eqs, t)\n" + mtk_str += "sys = ODESystem(eqs, t)\n\n" # Create initial conditions all_ics_str = "" @@ -398,7 +405,10 @@ def get_julia_mtk_model(model): all_constants_str += "{} = {}\n".format(const_name, const_value) # add a comment labeling the equation, and the equation itself - all_julia_str += f"# '{var.name}' initial conditions\n" + julia_str + "\n" + if julia_str == "": + all_julia_str = "" + else: + all_julia_str += f"# '{var.name}' initial conditions\n" + julia_str + "\n" # calculate the final variable that will output the result result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) @@ -411,8 +421,10 @@ def get_julia_mtk_model(model): else: raise pybamm.ModelError - all_ics_str += f"\t{variables[var.id]} => {eqn_str},\n" + all_ics_str += f" {variables[var.id]} => {eqn_str},\n" mtk_str += all_constants_str + all_julia_str + "\n" + f"u0 = [\n{all_ics_str}]\n" + mtk_str += "end\n" + return mtk_str \ No newline at end of file diff --git a/pybamm/solvers/idaklu_solver.py b/pybamm/solvers/idaklu_solver.py index 6e7cc7fcc3..a777cd78ab 100644 --- a/pybamm/solvers/idaklu_solver.py +++ b/pybamm/solvers/idaklu_solver.py @@ -10,8 +10,11 @@ idaklu_spec = importlib.util.find_spec("idaklu") if idaklu_spec is not None: - idaklu = importlib.util.module_from_spec(idaklu_spec) - idaklu_spec.loader.exec_module(idaklu) + try: + idaklu = importlib.util.module_from_spec(idaklu_spec) + idaklu_spec.loader.exec_module(idaklu) + except ImportError: + idaklu_spec = None def have_idaklu(): From cbf7acbb0ed4da097d99ac97bc3808db429deba3 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 15 Oct 2020 13:05:38 -0400 Subject: [PATCH 11/88] #1129 adding tests --- .../test_operations/test_evaluate_julia.py | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index e7cbe34156..de2ad85947 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -14,7 +14,8 @@ import scipy.sparse from collections import OrderedDict -from julia import Main +from julia import Main, ModelingToolkit +from diffeqpy import de @unittest.skip("") @@ -326,6 +327,39 @@ def test_exponential_decay_model(self): mtk_str = pybamm.get_julia_mtk_model(model) print(mtk_str) + Main.eval("using ModelingToolkit") + Main.eval(mtk_str) + + tspan = (0, 10) + prob = de.ODEProblem(Main.sys, Main.u0, tspan) + sol = de.solve(prob, de.Tsit5()) + print(sol) + + Main.eval( + """ + begin + # v -> x1 + @variables t, x1(t) + @derivatives D'~t + + # 'v' equation + var_4375622258206212481 = -2.0 .* x1 + + eqs = [ + D(x1) ~ var_4375622258206212481, + ] + sys = ODESystem(eqs, t) + + + u0 = [ + x1 => 1.0, + ] + + prob = ODEProblem(sys, u0, (0.0,10.0)) + sol = solve(prob) + end + """ + ) if __name__ == "__main__": From 88c217f8a6911584fbd84dcc82ec399caf032044 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 16 Oct 2020 10:54:34 -0400 Subject: [PATCH 12/88] #1129 add a test using parameters --- .../operations/evaluate_julia.py | 20 ++++- .../test_operations/test_evaluate_julia.py | 49 +---------- tests/unit/test_solvers/test_julia_mtk.py | 85 +++++++++++++++++++ 3 files changed, 105 insertions(+), 49 deletions(-) create mode 100644 tests/unit/test_solvers/test_julia_mtk.py diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index aed984d1d9..00883e52f0 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -342,7 +342,13 @@ def get_julia_mtk_model(model): # Returns something like "@variables t, x1(t), x2(t)" mtk_str += "@variables t" for var in variables.values(): - mtk_str += f", {var}(t)" + mtk_str += f" {var}(t)" + mtk_str += "\n" + + # Define parameters + mtk_str += "@parameters" + for param in model.input_parameters: + mtk_str += f" {param.name}" mtk_str += "\n" # Define derivatives @@ -386,6 +392,18 @@ def get_julia_mtk_model(model): id_to_julia_variable(var_id, False), julia_id ) + # Replace parameters in the julia strings in the form "inputs[name]" + # with just "name" + for param in model.input_parameters: + # Replace 'var_id' with 'paran.name' + all_julia_str = all_julia_str.replace( + id_to_julia_variable(param.id, False), param.name + ) + # Remove the line where the variable is re-defined + all_julia_str = all_julia_str.replace( + f"{param.name} = inputs['{param.name}']\n", "" + ) + # Update the MTK string mtk_str += all_constants_str + all_julia_str + "\n" + f"eqs = [\n{all_eqns_str}]\n" diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index de2ad85947..65d82a27bf 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -14,11 +14,9 @@ import scipy.sparse from collections import OrderedDict -from julia import Main, ModelingToolkit -from diffeqpy import de +from julia import Main -@unittest.skip("") class TestEvaluate(unittest.TestCase): def test_evaluator_julia(self): a = pybamm.StateVector(slice(0, 1)) @@ -317,51 +315,6 @@ def test_evaluator_julia_discretised_microscale(self): ) -class TestEvaluateMTKModel(unittest.TestCase): - def test_exponential_decay_model(self): - model = pybamm.BaseModel() - v = pybamm.Variable("v") - model.rhs = {v: -2 * v} - model.initial_conditions = {v: 1} - - mtk_str = pybamm.get_julia_mtk_model(model) - - print(mtk_str) - Main.eval("using ModelingToolkit") - Main.eval(mtk_str) - - tspan = (0, 10) - prob = de.ODEProblem(Main.sys, Main.u0, tspan) - sol = de.solve(prob, de.Tsit5()) - print(sol) - - Main.eval( - """ - begin - # v -> x1 - @variables t, x1(t) - @derivatives D'~t - - # 'v' equation - var_4375622258206212481 = -2.0 .* x1 - - eqs = [ - D(x1) ~ var_4375622258206212481, - ] - sys = ODESystem(eqs, t) - - - u0 = [ - x1 => 1.0, - ] - - prob = ODEProblem(sys, u0, (0.0,10.0)) - sol = solve(prob) - end - """ - ) - - if __name__ == "__main__": print("Add -v for more debug output") import sys diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py new file mode 100644 index 0000000000..975d1861d2 --- /dev/null +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -0,0 +1,85 @@ +# +# Test for the evaluate-to-Julia functions +# +import pybamm + +from tests import ( + get_mesh_for_testing, + get_1p1d_mesh_for_testing, + get_discretisation_for_testing, + get_1p1d_discretisation_for_testing, +) +import unittest +import numpy as np +import scipy.sparse +from collections import OrderedDict + +from julia import Main +from diffeqpy import de + + +class TestCreateSolveMTKModel(unittest.TestCase): + # def test_exponential_decay_model(self): + # model = pybamm.BaseModel() + # v = pybamm.Variable("v") + # model.rhs = {v: -2 * v} + # model.initial_conditions = {v: 0.5} + + # mtk_str = pybamm.get_julia_mtk_model(model) + + # Main.eval("using ModelingToolkit, DifferentialEquations") + # Main.eval(mtk_str) + + # Main.tspan = (0.0, 10.0) + # # this definition of prob doesn't work, so we use Main.eval instead + # # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) + + # Main.eval( "prob = ODEProblem(sys, u0, tspan)" ) + # sol = de.solve(Main.prob, de.Tsit5()) + + # y_sol = np.concatenate(sol.u) + # y_exact = 0.5 * np.exp(-2 * sol.t) + # np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) + + def test_lotka_volterra_model(self): + model = pybamm.BaseModel() + a = pybamm.InputParameter("a") + b = pybamm.InputParameter("b") + c = pybamm.InputParameter("c") + d = pybamm.InputParameter("d") + x = pybamm.Variable("x") + y = pybamm.Variable("y") + + model.rhs = {x: a * x - b * x * y, y: c * x * y - d * y} + model.initial_conditions = {x: 1.0, y: 1.0} + + mtk_str = pybamm.get_julia_mtk_model(model) + + # Solve using julia + Main.eval("using ModelingToolkit, DifferentialEquations") + Main.eval(mtk_str) + + Main.tspan = (0.0, 10.0) + Main.eval("p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0]") + Main.eval("prob = ODEProblem(sys, u0, tspan, p)") + sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) + + y_sol_julia = np.vstack(sol_julia.u).T + + # Solve using pybamm + sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve( + model, sol_julia.t, inputs={"a": 1.5, "b": 1.0, "c": 3.0, "d": 1.0} + ) + + # Compare + np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + + +if __name__ == "__main__": + print("Add -v for more debug output") + import sys + + if "-v" in sys.argv: + debug = True + pybamm.settings.debug_mode = True + unittest.main() From 831fe2e1beaa26f9136d8f881c887a5c9af93333 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 16 Oct 2020 12:08:25 -0400 Subject: [PATCH 13/88] #1129 add support for DAE model --- .../operations/evaluate_julia.py | 37 +++++----- tests/unit/test_solvers/test_julia_mtk.py | 71 ++++++++++++++----- 2 files changed, 73 insertions(+), 35 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 00883e52f0..0c56488d36 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -333,24 +333,26 @@ def get_julia_mtk_model(model): to be evaluated by ``julia.Main.eval`` """ mtk_str = "begin\n" + # Define parameters + # Makes a line of the form '@parameters t a b c d' + mtk_str += "@parameters t" + for param in model.input_parameters: + mtk_str += f" {param.name}" + mtk_str += "\n" + # Define variables - variables = {var.id: f"x{i+1}" for i, var in enumerate(model.rhs.keys())} + variables = {**model.rhs, **model.algebraic}.keys() + variable_id_to_number = {var.id: f"x{i+1}" for i, var in enumerate(variables)} # Add a comment with the variable names - for var in model.rhs.keys(): - mtk_str += f"# {var.name} -> {variables[var.id]}\n" - # Returns something like "@variables t, x1(t), x2(t)" - mtk_str += "@variables t" - for var in variables.values(): + for var in variables: + mtk_str += f"# {var.name} -> {variable_id_to_number[var.id]}\n" + # Makes a line of the form '@variables x1(t) x2(t)' + mtk_str += "@variables" + for var in variable_id_to_number.values(): mtk_str += f" {var}(t)" mtk_str += "\n" - # Define parameters - mtk_str += "@parameters" - for param in model.input_parameters: - mtk_str += f" {param.name}" - mtk_str += "\n" - # Define derivatives mtk_str += "@derivatives D'~t\n\n" @@ -358,7 +360,7 @@ def get_julia_mtk_model(model): all_eqns_str = "" all_constants_str = "" all_julia_str = "" - for var, eqn in model.rhs.items(): + for var, eqn in {**model.rhs, **model.algebraic}.items(): constants, julia_str = to_julia(eqn, debug=False) # extract constants in generated function @@ -383,11 +385,14 @@ def get_julia_mtk_model(model): else: eqn_str = result_var - all_eqns_str += f" D({variables[var.id]}) ~ {eqn_str},\n" + if var in model.rhs: + all_eqns_str += f" D({variable_id_to_number[var.id]}) ~ {eqn_str},\n" + elif var in model.algebraic: + all_eqns_str += f" 0 ~ {eqn_str},\n" # Replace variables in the julia strings that correspond to pybamm variables with # their julia equivalent - for var_id, julia_id in variables.items(): + for var_id, julia_id in variable_id_to_number.items(): all_julia_str = all_julia_str.replace( id_to_julia_variable(var_id, False), julia_id ) @@ -439,7 +444,7 @@ def get_julia_mtk_model(model): else: raise pybamm.ModelError - all_ics_str += f" {variables[var.id]} => {eqn_str},\n" + all_ics_str += f" {variable_id_to_number[var.id]} => {eqn_str},\n" mtk_str += all_constants_str + all_julia_str + "\n" + f"u0 = [\n{all_ics_str}]\n" diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 975d1861d2..5fb653fd1c 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -19,27 +19,27 @@ class TestCreateSolveMTKModel(unittest.TestCase): - # def test_exponential_decay_model(self): - # model = pybamm.BaseModel() - # v = pybamm.Variable("v") - # model.rhs = {v: -2 * v} - # model.initial_conditions = {v: 0.5} + def test_exponential_decay_model(self): + model = pybamm.BaseModel() + v = pybamm.Variable("v") + model.rhs = {v: -2 * v} + model.initial_conditions = {v: 0.5} - # mtk_str = pybamm.get_julia_mtk_model(model) + mtk_str = pybamm.get_julia_mtk_model(model) - # Main.eval("using ModelingToolkit, DifferentialEquations") - # Main.eval(mtk_str) + Main.eval("using ModelingToolkit") + Main.eval(mtk_str) - # Main.tspan = (0.0, 10.0) - # # this definition of prob doesn't work, so we use Main.eval instead - # # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) + Main.tspan = (0.0, 10.0) + # this definition of prob doesn't work, so we use Main.eval instead + # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) - # Main.eval( "prob = ODEProblem(sys, u0, tspan)" ) - # sol = de.solve(Main.prob, de.Tsit5()) + Main.eval("prob = ODEProblem(sys, u0, tspan)") + sol = de.solve(Main.prob, de.Tsit5()) - # y_sol = np.concatenate(sol.u) - # y_exact = 0.5 * np.exp(-2 * sol.t) - # np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) + y_sol = np.concatenate(sol.u) + y_exact = 0.5 * np.exp(-2 * sol.t) + np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) def test_lotka_volterra_model(self): model = pybamm.BaseModel() @@ -56,12 +56,18 @@ def test_lotka_volterra_model(self): mtk_str = pybamm.get_julia_mtk_model(model) # Solve using julia - Main.eval("using ModelingToolkit, DifferentialEquations") + Main.eval("using ModelingToolkit") Main.eval(mtk_str) Main.tspan = (0.0, 10.0) - Main.eval("p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0]") - Main.eval("prob = ODEProblem(sys, u0, tspan, p)") + Main.eval( + """ + begin + p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0] + prob = ODEProblem(sys, u0, tspan, p) + end + """ + ) sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) y_sol_julia = np.vstack(sol_julia.u).T @@ -74,6 +80,33 @@ def test_lotka_volterra_model(self): # Compare np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + def test_dae_model(self): + model = pybamm.BaseModel() + x = pybamm.Variable("x") + y = pybamm.Variable("y") + + model.rhs = {x: -2 * x} + model.algebraic = {y: x - y} + model.initial_conditions = {x: 1.0, y: 1.0} + + mtk_str = pybamm.get_julia_mtk_model(model) + + # Solve using julia + Main.eval("using ModelingToolkit") + Main.eval(mtk_str) + + Main.tspan = (0.0, 10.0) + Main.eval("prob = ODEProblem(sys, u0, tspan)") + sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) + + y_sol_julia = np.vstack(sol_julia.u).T + + # Solve using pybamm + sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, sol_julia.t) + + # Compare + np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + if __name__ == "__main__": print("Add -v for more debug output") From e40104fe0d075c0481e4d875ae4d0d100d036a36 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 16 Oct 2020 14:24:02 -0400 Subject: [PATCH 14/88] #1129 flake8 --- pybamm/expression_tree/operations/evaluate_julia.py | 2 +- tests/unit/test_solvers/test_julia_mtk.py | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 0c56488d36..30d24e77d1 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -450,4 +450,4 @@ def get_julia_mtk_model(model): mtk_str += "end\n" - return mtk_str \ No newline at end of file + return mtk_str diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 5fb653fd1c..0fed2881b4 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -3,16 +3,8 @@ # import pybamm -from tests import ( - get_mesh_for_testing, - get_1p1d_mesh_for_testing, - get_discretisation_for_testing, - get_1p1d_discretisation_for_testing, -) import unittest import numpy as np -import scipy.sparse -from collections import OrderedDict from julia import Main from diffeqpy import de From 449699313ac2c40043c2c966bf0c01c21a5ce8ed Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 23 Oct 2020 11:50:27 -0400 Subject: [PATCH 15/88] #1129 move constants outside of function --- .../operations/evaluate_julia.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 30d24e77d1..615f3a20b2 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -173,7 +173,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols): for child_dom, child_slice in slices.items(): slice_starts.append(symbol._slices[child_dom][i].start) child_vectors.append( - "{}[{}:{}]".format( + "@view {}[{}:{}]".format( child_var, child_slice[i].start, child_slice[i].stop ) ) @@ -194,15 +194,15 @@ def find_symbols(symbol, constant_symbols, variable_symbols): indices += 1 consecutive = np.all(indices[1:] - indices[:-1] == 1) if len(indices) == 1: - symbol_str = "y[{}]".format(indices[0]) + symbol_str = "@view y[{}]".format(indices[0]) elif consecutive: # julia does include the final value - symbol_str = "y[{}:{}]".format(indices[0], indices[-1]) + symbol_str = "@view y[{}:{}]".format(indices[0], indices[-1]) else: indices_array = pybamm.Array(indices) constant_symbols[indices_array.id] = indices index_name = id_to_julia_variable(indices_array.id, True) - symbol_str = "y[{}]".format(index_name) + symbol_str = "@view y[{}]".format(index_name) elif isinstance(symbol, pybamm.Time): symbol_str = "t" @@ -287,20 +287,21 @@ def get_julia_function(symbol): """ - constants, julia_str = to_julia(symbol, debug=False) + constants, var_str = to_julia(symbol, debug=False) # extract constants in generated function + const_str = "" for symbol_id, const_value in constants.items(): const_name = id_to_julia_variable(symbol_id, True) - julia_str = "{} = {}\n".format(const_name, const_value) + julia_str + const_str = const_str + "{} = {}\n".format(const_name, const_value) # indent code - julia_str = " " + julia_str - julia_str = julia_str.replace("\n", "\n ") + var_str = " " + var_str + var_str = var_str.replace("\n", "\n ") # add function def and sparse arrays to first line imports = "begin\nusing SparseArrays\n" - julia_str = imports + "function f_pybamm(t, y, p)\n" + julia_str + julia_str = imports + const_str + "\nfunction f_pybamm(t, y, p)\n" + var_str # calculate the final variable that will output the result result_var = id_to_julia_variable(symbol.id, symbol.is_constant()) From 3dff3bb45ea2d713cbc3c0385258aeb8241e21bf Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 28 Oct 2020 12:27:31 -0400 Subject: [PATCH 16/88] #1129 starting to optimize generated function --- .../operations/evaluate_julia.py | 28 ++- .../test_operations/quick_julia_test.py | 160 ++++++++++++++++++ .../test_operations/test.py | 25 +++ 3 files changed, 205 insertions(+), 8 deletions(-) create mode 100644 tests/unit/test_expression_tree/test_operations/quick_julia_test.py create mode 100644 tests/unit/test_expression_tree/test_operations/test.py diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 615f3a20b2..d3b2607e91 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -270,7 +270,7 @@ def to_julia(symbol, debug=False): return constant_values, "\n".join(variable_lines) -def get_julia_function(symbol): +def get_julia_function(symbol, funcname="f"): """ Converts a pybamm expression tree into pure julia code that will calculate the result of calling `evaluate(t, y)` on the given expression tree. @@ -290,18 +290,26 @@ def get_julia_function(symbol): constants, var_str = to_julia(symbol, debug=False) # extract constants in generated function - const_str = "" + const_str = "const cs=(\n" for symbol_id, const_value in constants.items(): const_name = id_to_julia_variable(symbol_id, True) - const_str = const_str + "{} = {}\n".format(const_name, const_value) + const_str += " {} = {},\n".format(const_name, const_value) + const_str += ")\n" # indent code var_str = " " + var_str var_str = var_str.replace("\n", "\n ") + # add "c." to constant names + var_str = var_str.replace("const", "c.const") # add function def and sparse arrays to first line - imports = "begin\nusing SparseArrays\n" - julia_str = imports + const_str + "\nfunction f_pybamm(t, y, p)\n" + var_str + imports = "begin\nusing SparseArrays, LinearAlgebra\n" + julia_str = ( + imports + + const_str + + f"\nfunction {funcname}_with_consts(dy, y, p, t, c)\n" + + var_str + ) # calculate the final variable that will output the result result_var = id_to_julia_variable(symbol.id, symbol.is_constant()) @@ -309,11 +317,15 @@ def get_julia_function(symbol): result_value = symbol.evaluate() # add return line - # two "end"s: one to close the function, one to close the "begin" if symbol.is_constant() and isinstance(result_value, numbers.Number): - julia_str = julia_str + "\n return " + str(result_value) + "\nend\nend" + julia_str = julia_str + "\n return " + str(result_value) + "\nend\n" else: - julia_str = julia_str + "\n return " + result_var + "\nend\nend" + julia_str = julia_str + "\n return " + result_var + "\nend\n" + + julia_str += f"{funcname}(dy, y, p, t) = {funcname}_with_consts(dy, y, p, t, cs)\n" + + # close the "begin" + julia_str += "end" return julia_str diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py new file mode 100644 index 0000000000..2629f773af --- /dev/null +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -0,0 +1,160 @@ +# +# Test for the evaluate-to-Julia functions +# +import pybamm + +from tests import ( + get_mesh_for_testing, + get_1p1d_mesh_for_testing, + get_discretisation_for_testing, + get_1p1d_discretisation_for_testing, +) +import unittest +import numpy as np +import scipy.sparse +from collections import OrderedDict + +from julia import Main + + +a = pybamm.StateVector(slice(0, 1)) +b = pybamm.StateVector(slice(1, 2)) + +y_tests = [np.array([[2], [3]]), np.array([[1], [3]])] +t_tests = [1, 2] + +# test a * b +# expr = a * b +# evaluator_str = pybamm.get_julia_function(expr) +# print(evaluator_str) + +# test something with a matrix multiplication +A = pybamm.Matrix([[1, 2], [3, 4]]) +expr = A @ pybamm.StateVector(slice(0, 2)) +evaluator_str = pybamm.get_julia_function(expr) +print(evaluator_str) + +# # test something with a heaviside +# a = pybamm.Vector([1, 2]) +# expr = a <= pybamm.StateVector(slice(0, 2)) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t, y, None) +# # note 1D arrays are flattened in Julia +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + +# expr = a > pybamm.StateVector(slice(0, 2)) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t, y, None) +# # note 1D arrays are flattened in Julia +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + +# # # test something with a minimum or maximum +# # a = pybamm.Vector([1, 2]) +# # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) +# # evaluator_str = pybamm.get_julia_function(expr) +# # evaluator = Main.eval(evaluator_str) +# # for t, y in zip(t_tests, y_tests): +# # result = evaluator(t,y,None) +# # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + +# # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) +# # evaluator_str = pybamm.get_julia_function(expr) +# # evaluator = Main.eval(evaluator_str) +# # for t, y in zip(t_tests, y_tests): +# # result = evaluator(t,y,None) +# # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + +# # test something with an index +# expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t, y, None) +# self.assertEqual(result, expr.evaluate(t=t, y=y)) + +# # test something with a sparse matrix multiplication +# A = pybamm.Matrix([[1, 2], [3, 4]]) +# B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) +# C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) +# expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t, y, None) +# # note 1D arrays are flattened in Julia +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + +# expr = B @ pybamm.StateVector(slice(0, 2)) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t, y, None) +# # note 1D arrays are flattened in Julia +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + +# # test numpy concatenation +# a = pybamm.StateVector(slice(0, 1)) +# b = pybamm.StateVector(slice(1, 2)) +# c = pybamm.StateVector(slice(2, 3)) + +# y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] +# t_tests = [1, 2] + +# expr = pybamm.NumpyConcatenation(a, b) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t, y, None) +# # note 1D arrays are flattened in Julia +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + +# expr = pybamm.NumpyConcatenation(a, c) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t, y, None) +# # note 1D arrays are flattened in Julia +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + +# # test sparse stack +# A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) +# B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) +# a = pybamm.StateVector(slice(0, 1)) +# expr = pybamm.SparseStack(A, a * B) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t, y, None).toarray() +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) + +# # test Inner +# expr = pybamm.Inner(a, b) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t,y,None) +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + +# v = pybamm.StateVector(slice(0, 2)) +# A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) +# expr = pybamm.Inner(A, v) +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t,y,None).toarray() +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) + +# y_tests = [np.array([[2], [3], [4], [5]]), np.array([[1], [3], [2], [1]])] +# t_tests = [1, 2] +# a = pybamm.StateVector(slice(0, 1), slice(3, 4)) +# b = pybamm.StateVector(slice(1, 3)) +# expr = a * b +# evaluator_str = pybamm.get_julia_function(expr) +# evaluator = Main.eval(evaluator_str) +# for t, y in zip(t_tests, y_tests): +# result = evaluator(t,y,None) +# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) diff --git a/tests/unit/test_expression_tree/test_operations/test.py b/tests/unit/test_expression_tree/test_operations/test.py new file mode 100644 index 0000000000..58554252ae --- /dev/null +++ b/tests/unit/test_expression_tree/test_operations/test.py @@ -0,0 +1,25 @@ +from julia import Main +import numpy as np + +f_b = Main.eval( + """ +begin +function f_b(dy,y,a,b) + dy[1] = a*y[1] + dy[2] = b*y[2] + dy +end +end +""" +) +dy = [0, 0] +y = [1, 3] +print(dy) # returns [0 0] +print(f_b(dy, y, 5, 3)) # returns [5 9] +print(dy) # returns [0 0] (expected [5 9]) + +Main.dy = [0, 0] +Main.y = [1, 3] +print(Main.dy) # returns [0 0] +print(Main.f_b(Main.dy, Main.y, 5, 3)) # returns [5 9] +print(Main.dy) # returns [0 0] (expected [5 9]) From b71ee4629d5925b219f53a4218c598952f089137 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 28 Oct 2020 12:35:33 -0400 Subject: [PATCH 17/88] #1129 testing some inplace stuff --- .../test_operations/test.jl | 10 ++++ .../test_operations/test.py | 54 ++++++++++++------- 2 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 tests/unit/test_expression_tree/test_operations/test.jl diff --git a/tests/unit/test_expression_tree/test_operations/test.jl b/tests/unit/test_expression_tree/test_operations/test.jl new file mode 100644 index 0000000000..7a998c7c6a --- /dev/null +++ b/tests/unit/test_expression_tree/test_operations/test.jl @@ -0,0 +1,10 @@ +function f_b(dy, y, a, b) + dy[1] = a * y[1] + dy[2] = b * y[2] + dy +end +dy = [0, 0] +y = [1, 3] +println(dy) # returns [0 0] +println(f_b(dy, y, 5, 3)) # returns [5 9] +println(dy) # returns [5 9] \ No newline at end of file diff --git a/tests/unit/test_expression_tree/test_operations/test.py b/tests/unit/test_expression_tree/test_operations/test.py index 58554252ae..ee1014c03e 100644 --- a/tests/unit/test_expression_tree/test_operations/test.py +++ b/tests/unit/test_expression_tree/test_operations/test.py @@ -1,25 +1,39 @@ -from julia import Main -import numpy as np +# from julia import Main +# import numpy as np + +# f_b = Main.eval( +# """ +# begin +# function f_b(dy,y,a,b) +# dy[1] = a*y[1] +# dy[2] = b*y[2] +# dy +# end +# end +# """ +# ) +# dy = [0, 0] +# y = [1, 3] +# print(dy) # returns [0 0] +# print(f_b(dy, y, 5, 3)) # returns [5 9] +# dy = f_b(dy, y, 5, 3) +# print(dy) # returns [0 0] (expected [5 9]) + +# Main.dy = [0, 0] +# Main.y = [1, 3] +# print(Main.dy) # returns [0 0] +# print(Main.f_b(Main.dy, Main.y, 5, 3)) # returns [5 9] +# print(Main.dy) # returns [0 0] (expected [5 9]) + + +def f_b(dy, y, a, b): + dy[0] = a * y[0] + dy[1] = b * y[1] + return dy + -f_b = Main.eval( - """ -begin -function f_b(dy,y,a,b) - dy[1] = a*y[1] - dy[2] = b*y[2] - dy -end -end -""" -) dy = [0, 0] y = [1, 3] print(dy) # returns [0 0] print(f_b(dy, y, 5, 3)) # returns [5 9] -print(dy) # returns [0 0] (expected [5 9]) - -Main.dy = [0, 0] -Main.y = [1, 3] -print(Main.dy) # returns [0 0] -print(Main.f_b(Main.dy, Main.y, 5, 3)) # returns [5 9] -print(Main.dy) # returns [0 0] (expected [5 9]) +print(dy) # returns [5 9] \ No newline at end of file From 60db48008dff601eb4c3629700cbdda0c6e2f465 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 28 Oct 2020 13:26:47 -0400 Subject: [PATCH 18/88] #1129 investigating pyjulia issue --- .../test_operations/test.py | 79 +++++++++++-------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/tests/unit/test_expression_tree/test_operations/test.py b/tests/unit/test_expression_tree/test_operations/test.py index ee1014c03e..510723cf03 100644 --- a/tests/unit/test_expression_tree/test_operations/test.py +++ b/tests/unit/test_expression_tree/test_operations/test.py @@ -1,39 +1,52 @@ -# from julia import Main -# import numpy as np +from julia import Main +import numpy as np -# f_b = Main.eval( -# """ -# begin -# function f_b(dy,y,a,b) -# dy[1] = a*y[1] -# dy[2] = b*y[2] -# dy -# end -# end -# """ -# ) -# dy = [0, 0] -# y = [1, 3] -# print(dy) # returns [0 0] -# print(f_b(dy, y, 5, 3)) # returns [5 9] -# dy = f_b(dy, y, 5, 3) -# print(dy) # returns [0 0] (expected [5 9]) +f_b = Main.eval( + """ +begin +function f_b(dy,y,a,b) + dy[1] = a*y[1] + dy[2] = b*y[2] + dy +end +end +""" +) +dy = np.array([0, 0]) +y = np.array([1, 3]) +print(dy) # returns [0 0] +print(f_b(dy, y, 5, 3)) # returns [5 9] +print(dy) # returns [0 0] (expected [5 9]) -# Main.dy = [0, 0] -# Main.y = [1, 3] -# print(Main.dy) # returns [0 0] +Main.dy = [0, 0] +Main.y = [1, 3] +print(Main.dy) # returns [0 0] +Main.eval("println(f_b(dy, y, 5, 3))") # print(Main.f_b(Main.dy, Main.y, 5, 3)) # returns [5 9] -# print(Main.dy) # returns [0 0] (expected [5 9]) - - -def f_b(dy, y, a, b): - dy[0] = a * y[0] - dy[1] = b * y[1] - return dy - +print(Main.dy) # returns [0 0] (expected [5 9]) +Main.eval( + """ +function f_b(dy, y, a, b) + dy[1] = a * y[1] + dy[2] = b * y[2] + dy +end dy = [0, 0] y = [1, 3] -print(dy) # returns [0 0] -print(f_b(dy, y, 5, 3)) # returns [5 9] -print(dy) # returns [5 9] \ No newline at end of file +println(dy) # returns [0 0] +println(f_b(dy, y, 5, 3)) # returns [5 9] +println(dy) +""" +) +# def f_b(dy, y, a, b): +# dy[0] = a * y[0] +# dy[1] = b * y[1] +# return dy + + +# dy = [0, 0] +# y = [1, 3] +# print(dy) # returns [0 0] +# print(f_b(dy, y, 5, 3)) # returns [5 9] +# print(dy) # returns [5 9] \ No newline at end of file From c7d17531d6faa898b2d7fb71a2f46bff867a728c Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 29 Oct 2020 13:32:42 -0400 Subject: [PATCH 19/88] #1129 use mul! and cache variables --- .../operations/evaluate_julia.py | 64 ++++++++++++++----- .../test_operations/quick_julia_test.py | 6 +- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index d3b2607e91..4e8b19d73f 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -5,6 +5,7 @@ import numpy as np import scipy.sparse +import re from collections import OrderedDict import numbers @@ -19,13 +20,13 @@ def id_to_julia_variable(symbol_id, constant=False): if constant: var_format = "const_{:05d}" else: - var_format = "var_{:05d}" + var_format = "cache_{:05d}" # Need to replace "-" character to make them valid julia variable names return var_format.format(symbol_id).replace("-", "m") -def find_symbols(symbol, constant_symbols, variable_symbols): +def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_sizes): """ This function converts an expression tree to a dictionary of node id's and strings specifying valid julia code to calculate that nodes value, given y and t. @@ -51,6 +52,10 @@ def find_symbols(symbol, constant_symbols, variable_symbols): variable_symbol : collections.OrderedDict The output dictionary of variable (with y or t) symbol ids to lines of code + variable_symbol_sizes : collections.OrderedDict + The output dictionary of variable (with y or t) symbol ids to size of that + variable, for caching + """ if symbol.is_constant(): value = symbol.evaluate() @@ -94,7 +99,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols): # process children recursively for child in symbol.children: - find_symbols(child, constant_symbols, variable_symbols) + find_symbols(child, constant_symbols, variable_symbols, variable_symbol_sizes) # calculate the variable names that will hold the result of calculating the # children variables @@ -223,6 +228,12 @@ def find_symbols(symbol, constant_symbols, variable_symbols): variable_symbols[symbol.id] = symbol_str + # Save the size of the variable + symbol_shape = symbol.shape + if symbol_shape[1] != 1: + raise ValueError("expected column vector") + variable_symbol_sizes[symbol.id] = symbol_shape[0] + def to_julia(symbol, debug=False): """ @@ -246,9 +257,10 @@ def to_julia(symbol, debug=False): constant_values = OrderedDict() variable_symbols = OrderedDict() - find_symbols(symbol, constant_values, variable_symbols) + variable_symbol_sizes = OrderedDict() + find_symbols(symbol, constant_values, variable_symbols, variable_symbol_sizes) - line_format = "{} = {}" + line_format = "{} .= {}" if debug: variable_lines = [ @@ -267,7 +279,7 @@ def to_julia(symbol, debug=False): for symbol_id, symbol_line in variable_symbols.items() ] - return constant_values, "\n".join(variable_lines) + return constant_values, "\n".join(variable_lines), variable_symbol_sizes def get_julia_function(symbol, funcname="f"): @@ -287,26 +299,40 @@ def get_julia_function(symbol, funcname="f"): """ - constants, var_str = to_julia(symbol, debug=False) + constants, var_str, var_symbol_sizes = to_julia(symbol, debug=False) # extract constants in generated function - const_str = "const cs=(\n" + const_and_cache_str = "const cs=(\n" for symbol_id, const_value in constants.items(): const_name = id_to_julia_variable(symbol_id, True) - const_str += " {} = {},\n".format(const_name, const_value) - const_str += ")\n" + const_and_cache_str += " {} = {},\n".format(const_name, const_value) + # add "c." to constant and cache names + var_str = var_str.replace("const", "c.const") + var_str = var_str.replace("cache", "c.cache") + # replace matrix multiplications with mul! (requires LinearAlgebra library) + var_str = re.sub("(.+) .= (.+) \* (.+)", r"mul!(\1, \2, \3)", var_str) # indent code var_str = " " + var_str var_str = var_str.replace("\n", "\n ") - # add "c." to constant names - var_str = var_str.replace("const", "c.const") + + # add the cache variables to the cache NamedTuple + for var_symbol_id, var_symbol_size in var_symbol_sizes.items(): + # Skip caching the result variable since this is provided as dy + if var_symbol_id != symbol.id: + cache_name = id_to_julia_variable(var_symbol_id, False) + const_and_cache_str += " {} = zeros({}),\n".format( + cache_name, var_symbol_size + ) + + # close the constants and cache string + const_and_cache_str += ")\n" # add function def and sparse arrays to first line - imports = "begin\nusing SparseArrays, LinearAlgebra\n" + imports = "begin\nusing SparseArrays, LinearAlgebra\n\n" julia_str = ( imports - + const_str + + const_and_cache_str + f"\nfunction {funcname}_with_consts(dy, y, p, t, c)\n" + var_str ) @@ -316,12 +342,16 @@ def get_julia_function(symbol, funcname="f"): if symbol.is_constant(): result_value = symbol.evaluate() - # add return line + # assign the return variable if symbol.is_constant() and isinstance(result_value, numbers.Number): - julia_str = julia_str + "\n return " + str(result_value) + "\nend\n" + julia_str = julia_str + "\n return " + str(result_value) else: - julia_str = julia_str + "\n return " + result_var + "\nend\n" + julia_str = julia_str.replace("c." + result_var, "dy") + + # close the function + julia_str += "\nend\n\n" + # Return the function with the cached variables passed in julia_str += f"{funcname}(dy, y, p, t) = {funcname}_with_consts(dy, y, p, t, cs)\n" # close the "begin" diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index 2629f773af..a61a0d453a 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -33,7 +33,11 @@ expr = A @ pybamm.StateVector(slice(0, 2)) evaluator_str = pybamm.get_julia_function(expr) print(evaluator_str) - +Main.eval(evaluator_str) +Main.dy = [0, 0] +Main.y = [2, 3] +print(Main.eval("f(dy,y,0,0)")) +print(Main.dy) # # test something with a heaviside # a = pybamm.Vector([1, 2]) # expr = a <= pybamm.StateVector(slice(0, 2)) From 90861481918b04e4576cc767285d7169b678d2c1 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 29 Oct 2020 18:44:21 -0400 Subject: [PATCH 20/88] #1129 inlining operations and starting vcat alternative --- .../operations/evaluate_julia.py | 85 ++++-- .../expression_tree/operations/spm_julia.jl | 274 ++++++++++++++++++ pybamm/solvers/base_solver.py | 44 +-- pybamm/solvers/casadi_solver.py | 6 +- .../test_operations/quick_julia_test.py | 18 +- .../test_operations/test.py | 82 +++--- 6 files changed, 394 insertions(+), 115 deletions(-) create mode 100644 pybamm/expression_tree/operations/spm_julia.jl diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 4e8b19d73f..b50a4bfc18 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -162,10 +162,13 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # don't bother to concatenate if there is only a single child if isinstance(symbol, (pybamm.NumpyConcatenation, pybamm.SparseStack)): - if len(children_vars) == 1: - symbol_str = children_vars - else: - symbol_str = "vcat({})".format(",".join(children_vars)) + # return a list of the children variables, which will be converted to a + # line by line assignment + symbol_str = children_vars + # if len(children_vars) == 1: + # symbol_str = children_vars[0] + # else: + # symbol_str = "vcat({})".format(",".join(children_vars)) # DomainConcatenation specifies a particular ordering for the concatenation, # which we must follow @@ -260,26 +263,26 @@ def to_julia(symbol, debug=False): variable_symbol_sizes = OrderedDict() find_symbols(symbol, constant_values, variable_symbols, variable_symbol_sizes) - line_format = "{} .= {}" + # line_format = "{} .= {}" - if debug: - variable_lines = [ - "print('{}'); ".format( - line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) - ) - + line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) - + "; print(type({0}),{0}.shape)".format( - id_to_julia_variable(symbol_id, False) - ) - for symbol_id, symbol_line in variable_symbols.items() - ] - else: - variable_lines = [ - line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) - for symbol_id, symbol_line in variable_symbols.items() - ] + # if debug: + # variable_lines = [ + # "print('{}'); ".format( + # line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) + # ) + # + line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) + # + "; print(type({0}),{0}.shape)".format( + # id_to_julia_variable(symbol_id, False) + # ) + # for symbol_id, symbol_line in variable_symbols.items() + # ] + # else: + # variable_lines = [ + # line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) + # for symbol_id, symbol_line in variable_symbols.items() + # ] - return constant_values, "\n".join(variable_lines), variable_symbol_sizes + return constant_values, variable_symbols, variable_symbol_sizes def get_julia_function(symbol, funcname="f"): @@ -299,7 +302,7 @@ def get_julia_function(symbol, funcname="f"): """ - constants, var_str, var_symbol_sizes = to_julia(symbol, debug=False) + constants, var_symbols, var_symbol_sizes = to_julia(symbol, debug=False) # extract constants in generated function const_and_cache_str = "const cs=(\n" @@ -307,11 +310,33 @@ def get_julia_function(symbol, funcname="f"): const_name = id_to_julia_variable(symbol_id, True) const_and_cache_str += " {} = {},\n".format(const_name, const_value) + # Pop (get and remove) items from the dictionary of symbols one by one + # If they are simple operations (@view, .+, .-, .*, ./), replace all future + # occurences instead of assigning them. This "inlining" speeds up the computation + inlineable_symbols = ["@view", ".+", ".-", ".*", "./"] + var_str = "" + while var_symbols: + var_symbol_id, symbol_line = var_symbols.popitem(last=False) + julia_var = id_to_julia_variable(var_symbol_id, False) + # use mul! for matrix multiplications (requires LinearAlgebra library) + if " * " in symbol_line: + symbol_line = symbol_line.replace(" * ", ", ") + var_str += "mul!({}, {})\n".format(julia_var, symbol_line) + else: + # inline operation if it can be inlined + if any(x in symbol_line for x in inlineable_symbols): + # replace all other occurrences of the variable + # in the dictionary with the symbol line + for key, value in var_symbols.items(): + if not ("mul!" in value and not "@view" in symbol_line): + var_symbols[key] = value.replace(julia_var, symbol_line) + + # otherwise assign + else: + var_str += "{} .= {}\n".format(julia_var, symbol_line) # add "c." to constant and cache names var_str = var_str.replace("const", "c.const") var_str = var_str.replace("cache", "c.cache") - # replace matrix multiplications with mul! (requires LinearAlgebra library) - var_str = re.sub("(.+) .= (.+) \* (.+)", r"mul!(\1, \2, \3)", var_str) # indent code var_str = " " + var_str var_str = var_str.replace("\n", "\n ") @@ -319,7 +344,10 @@ def get_julia_function(symbol, funcname="f"): # add the cache variables to the cache NamedTuple for var_symbol_id, var_symbol_size in var_symbol_sizes.items(): # Skip caching the result variable since this is provided as dy - if var_symbol_id != symbol.id: + # Also skip caching the result variable if it doesn't appear in the var_str, + # since it has been inlined and does not need to be assigned to + julia_var = id_to_julia_variable(var_symbol_id, False) + if var_symbol_id != symbol.id and julia_var in var_str: cache_name = id_to_julia_variable(var_symbol_id, False) const_and_cache_str += " {} = zeros({}),\n".format( cache_name, var_symbol_size @@ -344,12 +372,13 @@ def get_julia_function(symbol, funcname="f"): # assign the return variable if symbol.is_constant() and isinstance(result_value, numbers.Number): - julia_str = julia_str + "\n return " + str(result_value) + julia_str = julia_str + "\n dy .= " + str(result_value) + "\n" else: julia_str = julia_str.replace("c." + result_var, "dy") # close the function - julia_str += "\nend\n\n" + julia_str += "end\n\n" + julia_str = julia_str.replace("\n end", "\nend") # Return the function with the cached variables passed in julia_str += f"{funcname}(dy, y, p, t) = {funcname}_with_consts(dy, y, p, t, cs)\n" diff --git a/pybamm/expression_tree/operations/spm_julia.jl b/pybamm/expression_tree/operations/spm_julia.jl new file mode 100644 index 0000000000..6a26341d42 --- /dev/null +++ b/pybamm/expression_tree/operations/spm_julia.jl @@ -0,0 +1,274 @@ +using BenchmarkTools, OrdinaryDiffEq, Sundials, SparseArrays, LinearAlgebra +using BenchmarkTools, LinearAlgebra + +A = rand(100, 100) +B = rand(100, 100) +C = rand(100, 100) +D = rand(100, 100) + +function twomuls_assign(A, B, C, D) + C .= A .* B + mul!(D, A, C) +end +function twomuls_noassign(A, B, C, D) + mul!(D, A, A .* B) +end + +function mymul(c1, c2, C, A, B) + c1 .= A + c2 .= B + mul!(D, c1, c2) +end +c1 = rand(100, 100) +c2 = rand(100, 100) +function twomuls_noassign_mymul(A, B, C, D, c1, c2) + mymul(c1, c2, D, A, A .* B) +end + +@btime twomuls_assign(A, B, C, D) +@btime twomuls_noassign(A, B, C, D) +@btime twomuls_noassign_mymul(A, B, C, D, c1, c2) + +const cs = (const_m5042476316481538586 = [[0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0. ] + [0.03237701]], + const_m1664908561639471167 = [[-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.]], + const_m1742632654512844898 = [[ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [ 0. ] + [-0.14182856]], + const_6902631343103379854 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, + 25,25,26,26,27,27,28,28,29,29], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, + 25,26,26,27,27,28,28,29,29,30], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.], 29, 30), + const_m2887110228888269587 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, + 26,27,28,29,30], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.], 31, 29), + const_948199332974845790 = [[-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.] + [-1.]], + const_m3416783780236702828 = [[0. ] + [0.00111111] + [0.00444444] + [0.01 ] + [0.01777778] + [0.02777778] + [0.04 ] + [0.05444444] + [0.07111111] + [0.09 ] + [0.11111111] + [0.13444444] + [0.16 ] + [0.18777778] + [0.21777778] + [0.25 ] + [0.28444444] + [0.32111111] + [0.36 ] + [0.40111111] + [0.44444444] + [0.49 ] + [0.53777778] + [0.58777778] + [0.64 ] + [0.69444444] + [0.75111111] + [0.81 ] + [0.87111111] + [0.93444444] + [1. ]], + const_m4709902773269181539 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, + 25,25,26,26,27,27,28,28,29,29,30,30], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, + 25,26,26,27,27,28,28,29,29,30,30,31], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.], 30, 31), + const_m6560247611775222723 = [[3.60000000e+03] + [4.00000000e+02] + [1.44000000e+02] + [7.34693878e+01] + [4.44444444e+01] + [2.97520661e+01] + [2.13017751e+01] + [1.60000000e+01] + [1.24567474e+01] + [9.97229917e+00] + [8.16326531e+00] + [6.80529301e+00] + [5.76000000e+00] + [4.93827160e+00] + [4.28061831e+00] + [3.74609781e+00] + [3.30578512e+00] + [2.93877551e+00] + [2.62965668e+00] + [2.36686391e+00] + [2.14158239e+00] + [1.94699838e+00] + [1.77777778e+00] + [1.62969670e+00] + [1.49937526e+00] + [1.38408304e+00] + [1.28159487e+00] + [1.19008264e+00] + [1.10803324e+00] + [1.03418558e+00]], + const_7523862830560677743 = 4.272493084154669, + cache = zeros(29), + cache2 = zeros(31), + cache3 = zeros(30),) +function f_pybamm(dy, y, p, t, c) + dy[1] = c.const_7523862830560677743 + mul!(c.cache, c.const_6902631343103379854, @view y[2:31]) + mul!(c.cache2, c.const_m2887110228888269587, c.cache) + # c.cache2 .= + mul!(c.cache3, c.const_m4709902773269181539, c.const_m3416783780236702828 .* c.const_948199332974845790 .* c.cache2 .+ c.const_m1742632654512844898) + dy[2:31] .= -8.813457647415214 .* c.const_m6560247611775222723 .* c.cache3 + mul!(c.cache, c.const_6902631343103379854, @view y[32:61]) + mul!(c.cache2, c.const_m2887110228888269587, c.cache) + # c.cache2 .= + mul!(c.cache3, c.const_m4709902773269181539, c.const_m3416783780236702828 .* c.const_948199332974845790 .* c.cache2 .+ c.const_m1742632654512844898) + dy[32:61] .= -22.598609352346706 .* c.const_m6560247611775222723 .* c.cache3 +end +f(dy,y,p,t) = f_pybamm(dy, y, p, t, cs) +u0 = [0.0; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6] +tspan = (0.0, 0.15) +prob = ODEProblem(f, u0, tspan) +@btime solve(prob, KenCarp47(autodiff=false), reltol=1e-6, abstol=1e-6, saveat=0.15 / 100); +@btime solve(prob, CVODE_BDF(), reltol=1e-6, abstol=1e-6, saveat=0.15 / 100); +solve(prob, CVODE_BDF(), reltol=1e-8, abstol=1e-8, saveat=0.15 / 100); +# # Before +# 2.527 ms (13965 allocations: 1.62 MiB) +# # After w/ Sundials +# 1.145 ms (3235 allocations: 188.14 KiB) +# # After with OrdinaryDiffEq KenCarp47 +# 743.099 μs (493 allocations: 155.91 KiB) +# using Profile +# @profile for i in 1:1000 solve(prob, KenCarp47(), reltol=1e-8, abstol=1e-8, saveat=0.15 / 100) end +# Juno.profiler() +# Profile.clear() +rand(10) +@btime rand(10); \ No newline at end of file diff --git a/pybamm/solvers/base_solver.py b/pybamm/solvers/base_solver.py index fb1d1c9c09..d6034155ed 100644 --- a/pybamm/solvers/base_solver.py +++ b/pybamm/solvers/base_solver.py @@ -165,12 +165,14 @@ def set_up(self, model, inputs=None, t_eval=None): inputs = inputs or {} # Set model timescale - model.timescale_eval = model.timescale.evaluate(inputs=inputs) - # Set model lengthscales - model.length_scales_eval = { - domain: scale.evaluate(inputs=inputs) - for domain, scale in model.length_scales.items() - } + try: + model.timescale_eval = model.timescale.evaluate() + except KeyError as e: + raise pybamm.SolverError( + "The model timescale is a function of an input parameter " + "(original error: {})".format(e) + ) + if ( isinstance(self, (pybamm.CasadiSolver, pybamm.CasadiAlgebraicSolver)) ) and model.convert_to_format != "casadi": @@ -685,10 +687,6 @@ def solve(self, model, t_eval=None, external_variables=None, inputs=None): solution.model = model solution.inputs = ext_and_inputs - # Copy the timescale_eval and lengthscale_evals - solution.timescale_eval = model.timescale_eval - solution.length_scales_eval = model.length_scales_eval - # Identify the event that caused termination termination = self.get_termination_reason(solution, model.events) @@ -777,28 +775,6 @@ def step( inputs = inputs or {} ext_and_inputs = {**external_variables, **inputs} - # Check that any inputs that may affect the scaling have not changed - # Set model timescale - temp_timescale_eval = model.timescale.evaluate(inputs=inputs) - # Set model lengthscales - temp_length_scales_eval = { - domain: scale.evaluate(inputs=inputs) - for domain, scale in model.length_scales.items() - } - if old_solution is not None: - if temp_timescale_eval != old_solution.timescale_eval: - raise pybamm.SolverError( - "The model timescale is a function of an input parameter " - "and the value has changed between steps!" - ) - for domain in temp_length_scales_eval.keys(): - old_dom_eval = old_solution.length_scales_eval[domain] - if temp_length_scales_eval[domain] != old_dom_eval: - pybamm.logger.error( - "The {} domain lengthscale is a function of an input " - "parameter and the value has changed between " - "steps!".format(domain) - ) # Run set up on first step if old_solution is None: pybamm.logger.info( @@ -833,10 +809,6 @@ def step( solution.model = model solution.inputs = ext_and_inputs - # Copy the timescale_eval and lengthscale_evals - solution.timescale_eval = temp_timescale_eval - solution.length_scales_eval = temp_length_scales_eval - # Identify the event that caused termination termination = self.get_termination_reason(solution, model.events) diff --git a/pybamm/solvers/casadi_solver.py b/pybamm/solvers/casadi_solver.py index d13af9785d..7d9fbc29fd 100644 --- a/pybamm/solvers/casadi_solver.py +++ b/pybamm/solvers/casadi_solver.py @@ -274,11 +274,7 @@ def event_fun(t): # assign temporary solve time current_step_sol.solve_time = np.nan # append solution from the current step to solution - if solution is None: - solution = current_step_sol - else: - # append solution from the current step to solution - solution.append(current_step_sol) + solution.append(current_step_sol) solution.termination = "event" solution.t_event = t_event solution.y_event = y_event diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index a61a0d453a..f8d06c9495 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -17,11 +17,11 @@ from julia import Main -a = pybamm.StateVector(slice(0, 1)) -b = pybamm.StateVector(slice(1, 2)) +a = pybamm.StateVector(slice(0, 3)) +b = pybamm.StateVector(slice(3, 6)) -y_tests = [np.array([[2], [3]]), np.array([[1], [3]])] -t_tests = [1, 2] +y_tests = np.array([[2], [3], [4]]) +t_tests = 1 # test a * b # expr = a * b @@ -29,13 +29,15 @@ # print(evaluator_str) # test something with a matrix multiplication -A = pybamm.Matrix([[1, 2], [3, 4]]) -expr = A @ pybamm.StateVector(slice(0, 2)) +A = pybamm.Matrix([[1, 2, 3], [3, 4, 5], [6, 7, 8]]) +B = pybamm.Matrix([[11, 12, 13], [13, 14, 15], [16, 17, 18]]) +C = pybamm.Vector([[21], [22], [23]]) +expr = A @ (B @ pybamm.StateVector(slice(0, 3)) + C) evaluator_str = pybamm.get_julia_function(expr) print(evaluator_str) Main.eval(evaluator_str) -Main.dy = [0, 0] -Main.y = [2, 3] +Main.dy = [0, 0, 0] +Main.y = [2, 3, 4] print(Main.eval("f(dy,y,0,0)")) print(Main.dy) # # test something with a heaviside diff --git a/tests/unit/test_expression_tree/test_operations/test.py b/tests/unit/test_expression_tree/test_operations/test.py index 510723cf03..5f2791b875 100644 --- a/tests/unit/test_expression_tree/test_operations/test.py +++ b/tests/unit/test_expression_tree/test_operations/test.py @@ -1,44 +1,50 @@ -from julia import Main -import numpy as np - -f_b = Main.eval( - """ -begin -function f_b(dy,y,a,b) - dy[1] = a*y[1] - dy[2] = b*y[2] - dy -end -end +s = """ +var1 .= @view y[1:10] +var2 .= @view y[10:20] +mul!(dy, var1, var2) """ -) -dy = np.array([0, 0]) -y = np.array([1, 3]) -print(dy) # returns [0 0] -print(f_b(dy, y, 5, 3)) # returns [5 9] -print(dy) # returns [0 0] (expected [5 9]) -Main.dy = [0, 0] -Main.y = [1, 3] -print(Main.dy) # returns [0 0] -Main.eval("println(f_b(dy, y, 5, 3))") -# print(Main.f_b(Main.dy, Main.y, 5, 3)) # returns [5 9] -print(Main.dy) # returns [0 0] (expected [5 9]) +# from julia import Main +# import numpy as np -Main.eval( - """ -function f_b(dy, y, a, b) - dy[1] = a * y[1] - dy[2] = b * y[2] - dy -end -dy = [0, 0] -y = [1, 3] -println(dy) # returns [0 0] -println(f_b(dy, y, 5, 3)) # returns [5 9] -println(dy) -""" -) +# f_b = Main.eval( +# """ +# begin +# function f_b(dy,y,a,b) +# dy[1] = a*y[1] +# dy[2] = b*y[2] +# dy +# end +# end +# """ +# ) +# dy = np.array([0, 0]) +# y = np.array([1, 3]) +# print(dy) # returns [0 0] +# print(f_b(dy, y, 5, 3)) # returns [5 9] +# print(dy) # returns [0 0] (expected [5 9]) + +# Main.dy = [0, 0] +# Main.y = [1, 3] +# print(Main.dy) # returns [0 0] +# Main.eval("println(f_b(dy, y, 5, 3))") +# # print(Main.f_b(Main.dy, Main.y, 5, 3)) # returns [5 9] +# print(Main.dy) # returns [0 0] (expected [5 9]) + +# Main.eval( +# """ +# function f_b(dy, y, a, b) +# dy[1] = a * y[1] +# dy[2] = b * y[2] +# dy +# end +# dy = [0, 0] +# y = [1, 3] +# println(dy) # returns [0 0] +# println(f_b(dy, y, 5, 3)) # returns [5 9] +# println(dy) +# """ +# ) # def f_b(dy, y, a, b): # dy[0] = a * y[0] # dy[1] = b * y[1] From da47078cc25b2e6921b428bac3ae2f18a4a07366 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 30 Oct 2020 00:58:24 -0400 Subject: [PATCH 21/88] #1129 fix concatenations, start adding tests --- .../operations/evaluate_julia.py | 80 ++- .../expression_tree/operations/spm_julia.jl | 11 +- .../test_operations/quick_julia_test.py | 16 +- .../test_operations/test_evaluate_julia.py | 475 +++++++++--------- 4 files changed, 324 insertions(+), 258 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index b50a4bfc18..fd86e9ad8a 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -162,13 +162,19 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # don't bother to concatenate if there is only a single child if isinstance(symbol, (pybamm.NumpyConcatenation, pybamm.SparseStack)): - # return a list of the children variables, which will be converted to a - # line by line assignment - symbol_str = children_vars - # if len(children_vars) == 1: - # symbol_str = children_vars[0] - # else: - # symbol_str = "vcat({})".format(",".join(children_vars)) + if len(children_vars) == 1: + symbol_str = children_vars[0] + else: + # return a list of the children variables, which will be converted to a + # line by line assignment + # return this as a string so that other functionality still works + # also save sizes + symbol_str = "[" + for child in children_vars: + child_id = child[6:].replace("m", "-") + size = variable_symbol_sizes[int(child_id)] + symbol_str += "{}::{}, ".format(size, child) + symbol_str = symbol_str[:-2] + "]" # DomainConcatenation specifies a particular ordering for the concatenation, # which we must follow @@ -318,18 +324,46 @@ def get_julia_function(symbol, funcname="f"): while var_symbols: var_symbol_id, symbol_line = var_symbols.popitem(last=False) julia_var = id_to_julia_variable(var_symbol_id, False) + # Look for lists in the variable symbols. These correpsond to concatenations, so + # assign the children to the right parts of the vector + if symbol_line[0] == "[" and symbol_line[-1] == "]": + # convert to actual list + symbol_line = symbol_line[1:-1].split(", ") + start = 0 + for child_size_and_name in symbol_line: + child_size, child_name = child_size_and_name.split("::") + end = start + int(child_size) + # add 1 to start to account for julia 1-indexing + var_str += "{}[{}:{}] .= {}\n".format( + julia_var, start + 1, end, child_name + ) + start = end # use mul! for matrix multiplications (requires LinearAlgebra library) - if " * " in symbol_line: + elif " * " in symbol_line: symbol_line = symbol_line.replace(" * ", ", ") var_str += "mul!({}, {})\n".format(julia_var, symbol_line) else: # inline operation if it can be inlined if any(x in symbol_line for x in inlineable_symbols): + found_replacement = False # replace all other occurrences of the variable # in the dictionary with the symbol line - for key, value in var_symbols.items(): - if not ("mul!" in value and not "@view" in symbol_line): - var_symbols[key] = value.replace(julia_var, symbol_line) + for next_var_id, next_symbol_line in var_symbols.items(): + # don't replace the matrix multiplication cases (which will be + # turned into a mul!), since it is faster to assign to a cache array + # first in that case, unless it is a @view in which case we don't + # need to cache + if julia_var in next_symbol_line and not ( + " * " in next_symbol_line + and not symbol_line.startswith("@view") + ): + # add brackets so that the order of operations is maintained + var_symbols[next_var_id] = next_symbol_line.replace( + julia_var, "({})".format(symbol_line) + ) + found_replacement = True + if not found_replacement: + var_str += "{} .= {}\n".format(julia_var, symbol_line) # otherwise assign else: @@ -356,14 +390,20 @@ def get_julia_function(symbol, funcname="f"): # close the constants and cache string const_and_cache_str += ")\n" + # remove the constant and cache sring if it is empty + const_and_cache_str = const_and_cache_str.replace("const cs=(\n)\n", "") + # add function def and sparse arrays to first line imports = "begin\nusing SparseArrays, LinearAlgebra\n\n" - julia_str = ( - imports - + const_and_cache_str - + f"\nfunction {funcname}_with_consts(dy, y, p, t, c)\n" - + var_str - ) + if const_and_cache_str == "": + julia_str = imports + f"\nfunction {funcname}(dy, y, p, t)\n" + var_str + else: + julia_str = ( + imports + + const_and_cache_str + + f"\nfunction {funcname}_with_consts(dy, y, p, t, c)\n" + + var_str + ) # calculate the final variable that will output the result result_var = id_to_julia_variable(symbol.id, symbol.is_constant()) @@ -379,9 +419,13 @@ def get_julia_function(symbol, funcname="f"): # close the function julia_str += "end\n\n" julia_str = julia_str.replace("\n end", "\nend") + julia_str = julia_str.replace("\n \n", "\n") # Return the function with the cached variables passed in - julia_str += f"{funcname}(dy, y, p, t) = {funcname}_with_consts(dy, y, p, t, cs)\n" + if const_and_cache_str != "": + julia_str += ( + f"{funcname}(dy, y, p, t) = {funcname}_with_consts(dy, y, p, t, cs)\n" + ) # close the "begin" julia_str += "end" diff --git a/pybamm/expression_tree/operations/spm_julia.jl b/pybamm/expression_tree/operations/spm_julia.jl index 6a26341d42..40e880265f 100644 --- a/pybamm/expression_tree/operations/spm_julia.jl +++ b/pybamm/expression_tree/operations/spm_julia.jl @@ -1,5 +1,14 @@ using BenchmarkTools, OrdinaryDiffEq, Sundials, SparseArrays, LinearAlgebra -using BenchmarkTools, LinearAlgebra + +function f(dy, y) + dy .= @view y[1] .* y[2] +end +y = [2.0,3.0] +dy = [0.0] +f(dy,y) +dy + +(@view y[1]) .* (@view y[2]) A = rand(100, 100) B = rand(100, 100) diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index f8d06c9495..54efe690a5 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -20,7 +20,7 @@ a = pybamm.StateVector(slice(0, 3)) b = pybamm.StateVector(slice(3, 6)) -y_tests = np.array([[2], [3], [4]]) +y_tests = np.array([[2], [3], [4], [5], [6], [7]]) t_tests = 1 # test a * b @@ -29,17 +29,19 @@ # print(evaluator_str) # test something with a matrix multiplication -A = pybamm.Matrix([[1, 2, 3], [3, 4, 5], [6, 7, 8]]) -B = pybamm.Matrix([[11, 12, 13], [13, 14, 15], [16, 17, 18]]) -C = pybamm.Vector([[21], [22], [23]]) -expr = A @ (B @ pybamm.StateVector(slice(0, 3)) + C) +# A = pybamm.Matrix([[1, 2, 3], [3, 4, 5], [6, 7, 8]]) +# B = pybamm.Matrix([[11, 12, 13], [13, 14, 15], [16, 17, 18]]) +# C = pybamm.Vector([[21], [22], [23]]) +# expr = A @ (B @ (C * (C + pybamm.StateVector(slice(0, 3)))) + C) +expr = pybamm.NumpyConcatenation(a, b) evaluator_str = pybamm.get_julia_function(expr) print(evaluator_str) Main.eval(evaluator_str) -Main.dy = [0, 0, 0] -Main.y = [2, 3, 4] +Main.dy = [0, 0, 0, 0, 0, 0] +Main.y = [2, 3, 4, 5, 6, 7] print(Main.eval("f(dy,y,0,0)")) print(Main.dy) +print(expr.evaluate(y=Main.y)) # # test something with a heaviside # a = pybamm.Vector([1, 2]) # expr = a <= pybamm.StateVector(slice(0, 2)) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 65d82a27bf..067a0922cb 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -28,176 +28,185 @@ def test_evaluator_julia(self): # test a * b expr = a * b evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - result = evaluator(None, [2, 3], None) - self.assertEqual(result, 6) - result = evaluator(None, [1, 3], None) - self.assertEqual(result, 3) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = np.array([2.0, 3.0]) + Main.eval("f(dy,y,0,0)") + self.assertEqual(Main.dy, 6) + Main.dy = [0.0] + Main.y = np.array([1.0, 3.0]) + Main.eval("f(dy,y,0,0)") + self.assertEqual(Main.dy, 3) # test function(a*b) expr = pybamm.cos(a * b) evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - result = evaluator(None, np.array([[2], [3]]), None) - self.assertAlmostEqual(result, np.cos(6)) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = np.array([2.0, 3.0]) + Main.eval("f(dy,y,0,0)") + self.assertAlmostEqual(Main.dy[0], np.cos(6)) # test a constant expression expr = pybamm.Scalar(2) * pybamm.Scalar(3) evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - result = evaluator(None, None, None) - self.assertEqual(result, 6) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.eval("f(dy,y,0,0)") + self.assertEqual(Main.dy, 6) # test a larger expression expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) + Main.eval(evaluator_str) for y in y_tests: - result = evaluator(None, y, None) - self.assertEqual(result, expr.evaluate(t=None, y=y)) + Main.dy = 0.0 * y + Main, y = y + Main.eval("f(dy,y,0,0)") + self.assertEqual(Main.dy, expr.evaluate(t=None, y=y)) - # test something with time - expr = a * pybamm.t - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - self.assertEqual(result, expr.evaluate(t=t, y=y)) - - # test something with a matrix multiplication - A = pybamm.Matrix([[1, 2], [3, 4]]) - expr = A @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - - # test something with a heaviside - a = pybamm.Vector([1, 2]) - expr = a <= pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + # # test something with time + # expr = a * pybamm.t + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for t, y in zip(t_tests, y_tests): + # result = evaluator(t, y, None) + # self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) - expr = a > pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) + # # test something with a matrix multiplication + # A = pybamm.Matrix([[1, 2], [3, 4]]) + # expr = A @ pybamm.StateVector(slice(0, 2)) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for t, y in zip(t_tests, y_tests): + # result = evaluator(t, y, None) + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) - # # test something with a minimum or maximum + # # test something with a heaviside # a = pybamm.Vector([1, 2]) - # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) + # expr = a <= pybamm.StateVector(slice(0, 2)) # evaluator_str = pybamm.get_julia_function(expr) - # evaluator = Main.eval(evaluator_str) + # Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # result = evaluator(t, y, None) + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) - # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) + # expr = a > pybamm.StateVector(slice(0, 2)) # evaluator_str = pybamm.get_julia_function(expr) - # evaluator = Main.eval(evaluator_str) + # Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - - # test something with an index - expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - self.assertEqual(result, expr.evaluate(t=t, y=y)) - - # test something with a sparse matrix multiplication - A = pybamm.Matrix([[1, 2], [3, 4]]) - B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) - expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - - expr = B @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - - # test numpy concatenation - a = pybamm.StateVector(slice(0, 1)) - b = pybamm.StateVector(slice(1, 2)) - c = pybamm.StateVector(slice(2, 3)) - - y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] - t_tests = [1, 2] - - expr = pybamm.NumpyConcatenation(a, b) - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - - expr = pybamm.NumpyConcatenation(a, c) - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - result = evaluator(t, y, None) - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - - # # test sparse stack - # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) - # a = pybamm.StateVector(slice(0, 1)) - # expr = pybamm.SparseStack(A, a * B) + # result = evaluator(t, y, None) + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + + # # # test something with a minimum or maximum + # # a = pybamm.Vector([1, 2]) + # # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) + # # evaluator_str = pybamm.get_julia_function(expr) + # # Main.eval(evaluator_str) + # # for t, y in zip(t_tests, y_tests): + # # result = evaluator(t,y,None) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y)) + + # # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) + # # evaluator_str = pybamm.get_julia_function(expr) + # # Main.eval(evaluator_str) + # # for t, y in zip(t_tests, y_tests): + # # result = evaluator(t,y,None) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y)) + + # # test something with an index + # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) # evaluator_str = pybamm.get_julia_function(expr) - # evaluator = Main.eval(evaluator_str) + # Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): - # result = evaluator(t, y, None).toarray() - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) - - # # test Inner - # expr = pybamm.Inner(a, b) + # result = evaluator(t, y, None) + # self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) + + # # test something with a sparse matrix multiplication + # A = pybamm.Matrix([[1, 2], [3, 4]]) + # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) + # expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) # evaluator_str = pybamm.get_julia_function(expr) - # evaluator = Main.eval(evaluator_str) + # Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # result = evaluator(t, y, None) + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) - # v = pybamm.StateVector(slice(0, 2)) - # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # expr = pybamm.Inner(A, v) + # expr = B @ pybamm.StateVector(slice(0, 2)) # evaluator_str = pybamm.get_julia_function(expr) - # evaluator = Main.eval(evaluator_str) + # Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None).toarray() - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) + # result = evaluator(t, y, None) + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + + # # test numpy concatenation + # a = pybamm.StateVector(slice(0, 1)) + # b = pybamm.StateVector(slice(1, 2)) + # c = pybamm.StateVector(slice(2, 3)) - # y_tests = [np.array([[2], [3], [4], [5]]), np.array([[1], [3], [2], [1]])] + # y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] # t_tests = [1, 2] - # a = pybamm.StateVector(slice(0, 1), slice(3, 4)) - # b = pybamm.StateVector(slice(1, 3)) - # expr = a * b + + # expr = pybamm.NumpyConcatenation(a, b) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for t, y in zip(t_tests, y_tests): + # result = evaluator(t, y, None) + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + + # expr = pybamm.NumpyConcatenation(a, c) # evaluator_str = pybamm.get_julia_function(expr) - # evaluator = Main.eval(evaluator_str) + # Main.eval(evaluator_str) # for t, y in zip(t_tests, y_tests): - # result = evaluator(t,y,None) - # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) + # result = evaluator(t, y, None) + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + + # # # test sparse stack + # # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) + # # a = pybamm.StateVector(slice(0, 1)) + # # expr = pybamm.SparseStack(A, a * B) + # # evaluator_str = pybamm.get_julia_function(expr) + # # Main.eval(evaluator_str) + # # for t, y in zip(t_tests, y_tests): + # # result = evaluator(t, y, None).toarray() + # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).toarray()) + + # # # test Inner + # # expr = pybamm.Inner(a, b) + # # evaluator_str = pybamm.get_julia_function(expr) + # # Main.eval(evaluator_str) + # # for t, y in zip(t_tests, y_tests): + # # result = evaluator(t,y,None) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y)) + + # # v = pybamm.StateVector(slice(0, 2)) + # # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # # expr = pybamm.Inner(A, v) + # # evaluator_str = pybamm.get_julia_function(expr) + # # Main.eval(evaluator_str) + # # for t, y in zip(t_tests, y_tests): + # # result = evaluator(t,y,None).toarray() + # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).toarray()) + + # # y_tests = [np.array([[2], [3], [4], [5]]), np.array([[1], [3], [2], [1]])] + # # t_tests = [1, 2] + # # a = pybamm.StateVector(slice(0, 1), slice(3, 4)) + # # b = pybamm.StateVector(slice(1, 3)) + # # expr = a * b + # # evaluator_str = pybamm.get_julia_function(expr) + # # Main.eval(evaluator_str) + # # for t, y in zip(t_tests, y_tests): + # # result = evaluator(t,y,None) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y)) def test_evaluator_julia_all_functions(self): a = pybamm.StateVector(slice(0, 3)) @@ -218,101 +227,103 @@ def test_evaluator_julia_all_functions(self): ]: expr = function(a) evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - result = evaluator(None, y_test, None) - np.testing.assert_almost_equal(result, expr.evaluate(y=y_test).flatten()) - - def test_evaluator_julia_discretised_operators(self): - whole_cell = ["negative electrode", "separator", "positive electrode"] - # create discretisation - mesh = get_mesh_for_testing() - spatial_methods = {"macroscale": pybamm.FiniteVolume()} - disc = pybamm.Discretisation(mesh, spatial_methods) - - combined_submesh = mesh.combine_submeshes(*whole_cell) - - # grad - var = pybamm.Variable("var", domain=whole_cell) - grad_eqn = pybamm.grad(var) - boundary_conditions = { - var.id: { - "left": (pybamm.Scalar(1), "Dirichlet"), - "right": (pybamm.Scalar(2), "Neumann"), - } - } - disc.bcs = boundary_conditions - - disc.set_variable_slices([var]) - grad_eqn_disc = disc.process_symbol(grad_eqn) - - # div: test on linear y (should have laplacian zero) so change bcs - div_eqn = pybamm.div(var * grad_eqn) - - div_eqn_disc = disc.process_symbol(div_eqn) - - # test - nodes = combined_submesh.nodes - y_tests = [nodes ** 2 + 1, np.cos(nodes)] - - for expr in [grad_eqn_disc, div_eqn_disc]: - for y_test in y_tests: - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - result = evaluator(None, y_test, None) - np.testing.assert_almost_equal( - result, expr.evaluate(y=y_test).flatten() - ) - - def test_evaluator_julia_discretised_microscale(self): - # create discretisation - mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) - spatial_methods = {"negative particle": pybamm.FiniteVolume()} - disc = pybamm.Discretisation(mesh, spatial_methods) - - submesh = mesh["negative particle"] - - # grad - # grad(r) == 1 - var = pybamm.Variable( - "var", - domain=["negative particle"], - auxiliary_domains={ - "secondary": "negative electrode", - "tertiary": "current collector", - }, - ) - grad_eqn = pybamm.grad(var) - div_eqn = pybamm.div(var * grad_eqn) - - boundary_conditions = { - var.id: { - "left": (pybamm.Scalar(1), "Dirichlet"), - "right": (pybamm.Scalar(2), "Neumann"), - } - } - - disc.bcs = boundary_conditions - - disc.set_variable_slices([var]) - grad_eqn_disc = disc.process_symbol(grad_eqn) - div_eqn_disc = disc.process_symbol(div_eqn) - - # test - total_npts = ( - submesh.npts - * mesh["negative electrode"].npts - * mesh["current collector"].npts - ) - y_tests = [np.linspace(0, 1, total_npts) ** 2] - - for expr in [div_eqn_disc]: - for y_test in y_tests: - evaluator_str = pybamm.get_julia_function(expr) - evaluator = Main.eval(evaluator_str) - result = evaluator(None, y_test, None) - np.testing.assert_almost_equal( - result, expr.evaluate(y=y_test).flatten() - ) + Main.eval(evaluator_str) + Main.dy = 0.0 * y_test + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + + # def test_evaluator_julia_discretised_operators(self): + # whole_cell = ["negative electrode", "separator", "positive electrode"] + # # create discretisation + # mesh = get_mesh_for_testing() + # spatial_methods = {"macroscale": pybamm.FiniteVolume()} + # disc = pybamm.Discretisation(mesh, spatial_methods) + + # combined_submesh = mesh.combine_submeshes(*whole_cell) + + # # grad + # var = pybamm.Variable("var", domain=whole_cell) + # grad_eqn = pybamm.grad(var) + # boundary_conditions = { + # var.id: { + # "left": (pybamm.Scalar(1), "Dirichlet"), + # "right": (pybamm.Scalar(2), "Neumann"), + # } + # } + # disc.bcs = boundary_conditions + + # disc.set_variable_slices([var]) + # grad_eqn_disc = disc.process_symbol(grad_eqn) + + # # div: test on linear y (should have laplacian zero) so change bcs + # div_eqn = pybamm.div(var * grad_eqn) + + # div_eqn_disc = disc.process_symbol(div_eqn) + + # # test + # nodes = combined_submesh.nodes + # y_tests = [nodes ** 2 + 1, np.cos(nodes)] + + # for expr in [grad_eqn_disc, div_eqn_disc]: + # for y_test in y_tests: + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # result = evaluator(None, y_test, None) + # np.testing.assert_almost_equal( + # result, expr.evaluate(y=y_test).flatten() + # ) + + # def test_evaluator_julia_discretised_microscale(self): + # # create discretisation + # mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) + # spatial_methods = {"negative particle": pybamm.FiniteVolume()} + # disc = pybamm.Discretisation(mesh, spatial_methods) + + # submesh = mesh["negative particle"] + + # # grad + # # grad(r) == 1 + # var = pybamm.Variable( + # "var", + # domain=["negative particle"], + # auxiliary_domains={ + # "secondary": "negative electrode", + # "tertiary": "current collector", + # }, + # ) + # grad_eqn = pybamm.grad(var) + # div_eqn = pybamm.div(var * grad_eqn) + + # boundary_conditions = { + # var.id: { + # "left": (pybamm.Scalar(1), "Dirichlet"), + # "right": (pybamm.Scalar(2), "Neumann"), + # } + # } + + # disc.bcs = boundary_conditions + + # disc.set_variable_slices([var]) + # grad_eqn_disc = disc.process_symbol(grad_eqn) + # div_eqn_disc = disc.process_symbol(div_eqn) + + # # test + # total_npts = ( + # submesh.npts + # * mesh["negative electrode"].npts + # * mesh["current collector"].npts + # ) + # y_tests = [np.linspace(0, 1, total_npts) ** 2] + + # for expr in [div_eqn_disc]: + # for y_test in y_tests: + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # result = evaluator(None, y_test, None) + # np.testing.assert_almost_equal( + # result, expr.evaluate(y=y_test).flatten() + # ) if __name__ == "__main__": From af06122563db3c28bb7e5dc53a7d0919dcf62690 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 30 Oct 2020 15:24:03 -0400 Subject: [PATCH 22/88] #1129 working through more cases --- .../operations/evaluate_julia.py | 25 ++-- pybamm/solvers/casadi_solver.py | 22 ++-- .../test_operations/test_evaluate_julia.py | 112 ++++++++++-------- 3 files changed, 88 insertions(+), 71 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index fd86e9ad8a..0296ed83df 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -239,9 +239,12 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # Save the size of the variable symbol_shape = symbol.shape - if symbol_shape[1] != 1: - raise ValueError("expected column vector") - variable_symbol_sizes[symbol.id] = symbol_shape[0] + if symbol_shape == (): + variable_symbol_sizes[symbol.id] = 1 + elif symbol_shape[1] == 1: + variable_symbol_sizes[symbol.id] = symbol_shape[0] + else: + raise ValueError("expected scalar or column vector") def to_julia(symbol, debug=False): @@ -344,7 +347,7 @@ def get_julia_function(symbol, funcname="f"): var_str += "mul!({}, {})\n".format(julia_var, symbol_line) else: # inline operation if it can be inlined - if any(x in symbol_line for x in inlineable_symbols): + if any(x in symbol_line for x in inlineable_symbols) or symbol_line == "t": found_replacement = False # replace all other occurrences of the variable # in the dictionary with the symbol line @@ -357,10 +360,16 @@ def get_julia_function(symbol, funcname="f"): " * " in next_symbol_line and not symbol_line.startswith("@view") ): - # add brackets so that the order of operations is maintained - var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, "({})".format(symbol_line) - ) + if symbol_line != "t": + # add brackets so that the order of operations is maintained + var_symbols[next_var_id] = next_symbol_line.replace( + julia_var, "({})".format(symbol_line) + ) + else: + # add brackets so that the order of operations is maintained + var_symbols[next_var_id] = next_symbol_line.replace( + julia_var, symbol_line + ) found_replacement = True if not found_replacement: var_str += "{} .= {}\n".format(julia_var, symbol_line) diff --git a/pybamm/solvers/casadi_solver.py b/pybamm/solvers/casadi_solver.py index 7d9fbc29fd..d724be4035 100644 --- a/pybamm/solvers/casadi_solver.py +++ b/pybamm/solvers/casadi_solver.py @@ -16,17 +16,17 @@ class CasadiSolver(pybamm.BaseSolver): Parameters ---------- mode : str - How to solve the model (default is "safe"): - - - "fast": perform direct integration, without accounting for events. \ - Recommended when simulating a drive cycle or other simulation where \ - no events should be triggered. - - "safe": perform step-and-check integration in global steps of size \ - dt_max, checking whether events have been triggered. Recommended for \ - simulations of a full charge or discharge. - - "safe without grid": perform step-and-check integration step-by-step. \ - Takes more steps than "safe" mode, but doesn't require creating the grid \ - each time, so may be faster. Experimental only. + How to solve the model (default is "safe"): + + - "fast": perform direct integration, without accounting for events. \ + Recommended when simulating a drive cycle or other simulation where \ + no events should be triggered. + - "safe": perform step-and-check integration in global steps of size \ + dt_max, checking whether events have been triggered. Recommended for \ + simulations of a full charge or discharge. + - "safe without grid": perform step-and-check integration step-by-step. \ + Takes more steps than "safe" mode, but doesn't require creating the grid \ + each time, so may be faster. Experimental only. rtol : float, optional The relative tolerance for the solver (default is 1e-6). atol : float, optional diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 067a0922cb..4f304caf98 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -60,70 +60,78 @@ def test_evaluator_julia(self): evaluator_str = pybamm.get_julia_function(expr) Main.eval(evaluator_str) for y in y_tests: - Main.dy = 0.0 * y - Main, y = y + Main.dy = [0.0] + Main.y = y Main.eval("f(dy,y,0,0)") self.assertEqual(Main.dy, expr.evaluate(t=None, y=y)) - # # test something with time - # expr = a * pybamm.t - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): - # result = evaluator(t, y, None) - # self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) - - # # test something with a matrix multiplication - # A = pybamm.Matrix([[1, 2], [3, 4]]) - # expr = A @ pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): - # result = evaluator(t, y, None) - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + # test something with time + expr = a * pybamm.t + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + Main.dy = [0.0] + Main.y = y + Main.t = t + Main.eval("f(dy,y,0,t)") + self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) + + # test something with a matrix multiplication + A = pybamm.Matrix([[1, 2], [3, 4]]) + expr = A @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - # # test something with a heaviside - # a = pybamm.Vector([1, 2]) - # expr = a <= pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): - # result = evaluator(t, y, None) - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + # test something with a heaviside + a = pybamm.Vector([1, 2]) + expr = a <= pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + print(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) # expr = a > pybamm.StateVector(slice(0, 2)) # evaluator_str = pybamm.get_julia_function(expr) # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): + # for y in y_tests: # result = evaluator(t, y, None) # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) # # # test something with a minimum or maximum # # a = pybamm.Vector([1, 2]) # # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) # # evaluator_str = pybamm.get_julia_function(expr) # # Main.eval(evaluator_str) - # # for t, y in zip(t_tests, y_tests): + # # for y in y_tests: # # result = evaluator(t,y,None) - # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y)) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y)) # # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) # # evaluator_str = pybamm.get_julia_function(expr) # # Main.eval(evaluator_str) - # # for t, y in zip(t_tests, y_tests): + # # for y in y_tests: # # result = evaluator(t,y,None) - # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y)) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y)) # # test something with an index # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) # evaluator_str = pybamm.get_julia_function(expr) # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): + # for y in y_tests: # result = evaluator(t, y, None) - # self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) + # self.assertEqual(Main.dy, expr.evaluate(y=y)) # # test something with a sparse matrix multiplication # A = pybamm.Matrix([[1, 2], [3, 4]]) @@ -132,18 +140,18 @@ def test_evaluator_julia(self): # expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) # evaluator_str = pybamm.get_julia_function(expr) # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): + # for y in y_tests: # result = evaluator(t, y, None) # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) # expr = B @ pybamm.StateVector(slice(0, 2)) # evaluator_str = pybamm.get_julia_function(expr) # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): + # for y in y_tests: # result = evaluator(t, y, None) # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) # # test numpy concatenation # a = pybamm.StateVector(slice(0, 1)) @@ -156,18 +164,18 @@ def test_evaluator_julia(self): # expr = pybamm.NumpyConcatenation(a, b) # evaluator_str = pybamm.get_julia_function(expr) # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): + # for y in y_tests: # result = evaluator(t, y, None) # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) # expr = pybamm.NumpyConcatenation(a, c) # evaluator_str = pybamm.get_julia_function(expr) # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): + # for y in y_tests: # result = evaluator(t, y, None) # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).flatten()) + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) # # # test sparse stack # # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) @@ -176,26 +184,26 @@ def test_evaluator_julia(self): # # expr = pybamm.SparseStack(A, a * B) # # evaluator_str = pybamm.get_julia_function(expr) # # Main.eval(evaluator_str) - # # for t, y in zip(t_tests, y_tests): + # # for y in y_tests: # # result = evaluator(t, y, None).toarray() - # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).toarray()) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).toarray()) # # # test Inner # # expr = pybamm.Inner(a, b) # # evaluator_str = pybamm.get_julia_function(expr) # # Main.eval(evaluator_str) - # # for t, y in zip(t_tests, y_tests): + # # for y in y_tests: # # result = evaluator(t,y,None) - # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y)) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y)) # # v = pybamm.StateVector(slice(0, 2)) # # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) # # expr = pybamm.Inner(A, v) # # evaluator_str = pybamm.get_julia_function(expr) # # Main.eval(evaluator_str) - # # for t, y in zip(t_tests, y_tests): + # # for y in y_tests: # # result = evaluator(t,y,None).toarray() - # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y).toarray()) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).toarray()) # # y_tests = [np.array([[2], [3], [4], [5]]), np.array([[1], [3], [2], [1]])] # # t_tests = [1, 2] @@ -204,9 +212,9 @@ def test_evaluator_julia(self): # # expr = a * b # # evaluator_str = pybamm.get_julia_function(expr) # # Main.eval(evaluator_str) - # # for t, y in zip(t_tests, y_tests): + # # for y in y_tests: # # result = evaluator(t,y,None) - # # np.testing.assert_allclose(Main.dy, expr.evaluate(t=t, y=y)) + # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y)) def test_evaluator_julia_all_functions(self): a = pybamm.StateVector(slice(0, 3)) From 08a94150bd954bbfab99f808a59cb7277d9f0b83 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 3 Nov 2020 16:32:17 -0500 Subject: [PATCH 23/88] #1219 fix basic tests --- pybamm/expression_tree/functions.py | 28 ++- .../operations/evaluate_julia.py | 58 ++--- .../expression_tree/operations/spm_julia.jl | 23 +- .../test_operations/quick_julia_test.py | 2 +- .../test_operations/test_evaluate_julia.py | 208 +++++++++--------- 5 files changed, 180 insertions(+), 139 deletions(-) diff --git a/pybamm/expression_tree/functions.py b/pybamm/expression_tree/functions.py index 04fed5c08b..ebaaab9dba 100644 --- a/pybamm/expression_tree/functions.py +++ b/pybamm/expression_tree/functions.py @@ -378,12 +378,36 @@ def log10(child): return log(child, base=10) +class Max(SpecificFunction): + """ Max function """ + + def __init__(self, child): + super().__init__(np.max, child) + + @property + def julia_name(self): + """ See :meth:`pybamm.Function.julia_name` """ + return "maximum" + + def max(child): """ Returns max function of child. Not to be confused with :meth:`pybamm.maximum`, which returns the larger of two objects. """ - return pybamm.simplify_if_constant(Function(np.max, child), keep_domains=True) + return pybamm.simplify_if_constant(Max(child), keep_domains=True) + + +class Min(SpecificFunction): + """ Min function """ + + def __init__(self, child): + super().__init__(np.min, child) + + @property + def julia_name(self): + """ See :meth:`pybamm.Function.julia_name` """ + return "minimum" def min(child): @@ -391,7 +415,7 @@ def min(child): Returns min function of child. Not to be confused with :meth:`pybamm.minimum`, which returns the smaller of two objects. """ - return pybamm.simplify_if_constant(Function(np.min, child), keep_domains=True) + return pybamm.simplify_if_constant(Min(child), keep_domains=True) def sech(child): diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 0296ed83df..dca987aed6 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -123,9 +123,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz elif isinstance(symbol, pybamm.Inner): symbol_str = "{0} .* {1}".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Minimum): - symbol_str = "np.minimum({},{})".format(children_vars[0], children_vars[1]) + symbol_str = "min.({},{})".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Maximum): - symbol_str = "np.maximum({},{})".format(children_vars[0], children_vars[1]) + symbol_str = "max.({},{})".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Power): # julia uses ^ instead of ** for power # include dot for elementwise operations @@ -156,7 +156,10 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # write functions directly julia_name = symbol.julia_name # add a . to allow elementwise operations - symbol_str = "{}.({})".format(julia_name, children_str) + if isinstance(symbol, (pybamm.Min, pybamm.Max)): + symbol_str = "{}({})".format(julia_name, children_str) + else: + symbol_str = "{}.({})".format(julia_name, children_str) elif isinstance(symbol, pybamm.Concatenation): @@ -238,11 +241,10 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz variable_symbols[symbol.id] = symbol_str # Save the size of the variable - symbol_shape = symbol.shape - if symbol_shape == (): + if symbol.shape == (): variable_symbol_sizes[symbol.id] = 1 - elif symbol_shape[1] == 1: - variable_symbol_sizes[symbol.id] = symbol_shape[0] + elif symbol.shape[1] == 1: + variable_symbol_sizes[symbol.id] = symbol.shape[0] else: raise ValueError("expected scalar or column vector") @@ -314,7 +316,7 @@ def get_julia_function(symbol, funcname="f"): constants, var_symbols, var_symbol_sizes = to_julia(symbol, debug=False) # extract constants in generated function - const_and_cache_str = "const cs=(\n" + const_and_cache_str = "cs = (\n" for symbol_id, const_value in constants.items(): const_name = id_to_julia_variable(symbol_id, True) const_and_cache_str += " {} = {},\n".format(const_name, const_value) @@ -357,7 +359,7 @@ def get_julia_function(symbol, funcname="f"): # first in that case, unless it is a @view in which case we don't # need to cache if julia_var in next_symbol_line and not ( - " * " in next_symbol_line + [" * " in next_symbol_line or "mul!" in next_symbol_line] and not symbol_line.startswith("@view") ): if symbol_line != "t": @@ -377,9 +379,9 @@ def get_julia_function(symbol, funcname="f"): # otherwise assign else: var_str += "{} .= {}\n".format(julia_var, symbol_line) - # add "c." to constant and cache names - var_str = var_str.replace("const", "c.const") - var_str = var_str.replace("cache", "c.cache") + # add "cs." to constant and cache names + var_str = var_str.replace("const", "cs.const") + var_str = var_str.replace("cache", "cs.cache") # indent code var_str = " " + var_str var_str = var_str.replace("\n", "\n ") @@ -400,19 +402,16 @@ def get_julia_function(symbol, funcname="f"): const_and_cache_str += ")\n" # remove the constant and cache sring if it is empty - const_and_cache_str = const_and_cache_str.replace("const cs=(\n)\n", "") + const_and_cache_str = const_and_cache_str.replace("cs = (\n)\n", "") # add function def and sparse arrays to first line imports = "begin\nusing SparseArrays, LinearAlgebra\n\n" - if const_and_cache_str == "": - julia_str = imports + f"\nfunction {funcname}(dy, y, p, t)\n" + var_str - else: - julia_str = ( - imports - + const_and_cache_str - + f"\nfunction {funcname}_with_consts(dy, y, p, t, c)\n" - + var_str - ) + julia_str = ( + imports + + const_and_cache_str + + f"\nfunction {funcname}_with_consts(dy, y, p, t)\n" + + var_str + ) # calculate the final variable that will output the result result_var = id_to_julia_variable(symbol.id, symbol.is_constant()) @@ -423,18 +422,21 @@ def get_julia_function(symbol, funcname="f"): if symbol.is_constant() and isinstance(result_value, numbers.Number): julia_str = julia_str + "\n dy .= " + str(result_value) + "\n" else: - julia_str = julia_str.replace("c." + result_var, "dy") + julia_str = julia_str.replace("cs." + result_var, "dy") # close the function julia_str += "end\n\n" julia_str = julia_str.replace("\n end", "\nend") julia_str = julia_str.replace("\n \n", "\n") - # Return the function with the cached variables passed in - if const_and_cache_str != "": - julia_str += ( - f"{funcname}(dy, y, p, t) = {funcname}_with_consts(dy, y, p, t, cs)\n" - ) + if const_and_cache_str == "": + julia_str += f"{funcname} = {funcname}_with_consts\n" + else: + # Use a let block for the cached variables + # open the let block + julia_str = julia_str.replace("cs = (", f"{funcname} = let cs = (") + # close the let block + julia_str += "end\n" # close the "begin" julia_str += "end" diff --git a/pybamm/expression_tree/operations/spm_julia.jl b/pybamm/expression_tree/operations/spm_julia.jl index 40e880265f..5b59544de6 100644 --- a/pybamm/expression_tree/operations/spm_julia.jl +++ b/pybamm/expression_tree/operations/spm_julia.jl @@ -280,4 +280,25 @@ solve(prob, CVODE_BDF(), reltol=1e-8, abstol=1e-8, saveat=0.15 / 100); # Juno.profiler() # Profile.clear() rand(10) -@btime rand(10); \ No newline at end of file +@btime rand(10); + +hh = let es = (x1 = [1,2,3,4,5], x2 = 1) + function g_inner(dy, y, p, t, c) + dy .= c.x1 .* y + end + g(dy, y, p, t) = g_inner(dy, y, p, t, es) +end +u0 = [1,1,1,1,1] +tspan = (0, 1) +prob = ODEProblem(hh, u0, tspan) +@btime solve(prob, KenCarp47(autodiff=false), reltol=1e-6, abstol=1e-6, saveat=0.1); + +function aaa() + return 2 +end +bbb = aaa +bbb = let xxx = 2 + xxx^2 +end +xxx +bbb() diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index 54efe690a5..fffba405ff 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -33,7 +33,7 @@ # B = pybamm.Matrix([[11, 12, 13], [13, 14, 15], [16, 17, 18]]) # C = pybamm.Vector([[21], [22], [23]]) # expr = A @ (B @ (C * (C + pybamm.StateVector(slice(0, 3)))) + C) -expr = pybamm.NumpyConcatenation(a, b) +expr = pybamm.Vector([1, 2, 3, 4, 5, 6]) * pybamm.NumpyConcatenation(a, b) evaluator_str = pybamm.get_julia_function(expr) print(evaluator_str) Main.eval(evaluator_str) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 4f304caf98..cb467e2431 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -93,7 +93,6 @@ def test_evaluator_julia(self): expr = a <= pybamm.StateVector(slice(0, 2)) evaluator_str = pybamm.get_julia_function(expr) Main.eval(evaluator_str) - print(evaluator_str) for y in y_tests: Main.dy = [0.0, 0.0] Main.y = y @@ -101,120 +100,103 @@ def test_evaluator_julia(self): # note 1D arrays are flattened in Julia np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - # expr = a > pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # result = evaluator(t, y, None) - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # # test something with a minimum or maximum - # # a = pybamm.Vector([1, 2]) - # # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) - # # evaluator_str = pybamm.get_julia_function(expr) - # # Main.eval(evaluator_str) - # # for y in y_tests: - # # result = evaluator(t,y,None) - # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y)) - - # # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) - # # evaluator_str = pybamm.get_julia_function(expr) - # # Main.eval(evaluator_str) - # # for y in y_tests: - # # result = evaluator(t,y,None) - # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y)) - - # # test something with an index - # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # result = evaluator(t, y, None) - # self.assertEqual(Main.dy, expr.evaluate(y=y)) - - # # test something with a sparse matrix multiplication - # A = pybamm.Matrix([[1, 2], [3, 4]]) - # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) - # expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # result = evaluator(t, y, None) - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + # test something with a minimum or maximum + a = pybamm.Vector([1, 2]) + for expr in [ + pybamm.minimum(a, pybamm.StateVector(slice(0, 2))), + pybamm.maximum(a, pybamm.StateVector(slice(0, 2))), + ]: + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # test something with an index + expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - # expr = B @ pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # result = evaluator(t, y, None) - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + # test something with a sparse matrix multiplication + A = pybamm.Matrix([[1, 2], [3, 4]]) + B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) + expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + expr = B @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - # # test numpy concatenation - # a = pybamm.StateVector(slice(0, 1)) - # b = pybamm.StateVector(slice(1, 2)) - # c = pybamm.StateVector(slice(2, 3)) + # test numpy concatenation + a = pybamm.StateVector(slice(0, 1)) + b = pybamm.StateVector(slice(1, 2)) + c = pybamm.StateVector(slice(2, 3)) - # y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] - # t_tests = [1, 2] + y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] + t_tests = [1, 2] - # expr = pybamm.NumpyConcatenation(a, b) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # result = evaluator(t, y, None) - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + expr = pybamm.NumpyConcatenation(a, b) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - # expr = pybamm.NumpyConcatenation(a, c) + expr = pybamm.NumpyConcatenation(a, c) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # test sparse stack + # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) + # expr = pybamm.SparseStack(A, B) # evaluator_str = pybamm.get_julia_function(expr) # Main.eval(evaluator_str) # for y in y_tests: - # result = evaluator(t, y, None) - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # # test sparse stack - # # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) - # # a = pybamm.StateVector(slice(0, 1)) - # # expr = pybamm.SparseStack(A, a * B) - # # evaluator_str = pybamm.get_julia_function(expr) - # # Main.eval(evaluator_str) - # # for y in y_tests: - # # result = evaluator(t, y, None).toarray() - # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).toarray()) - - # # # test Inner - # # expr = pybamm.Inner(a, b) - # # evaluator_str = pybamm.get_julia_function(expr) - # # Main.eval(evaluator_str) - # # for y in y_tests: - # # result = evaluator(t,y,None) - # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y)) - - # # v = pybamm.StateVector(slice(0, 2)) - # # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # # expr = pybamm.Inner(A, v) - # # evaluator_str = pybamm.get_julia_function(expr) - # # Main.eval(evaluator_str) - # # for y in y_tests: - # # result = evaluator(t,y,None).toarray() - # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).toarray()) - - # # y_tests = [np.array([[2], [3], [4], [5]]), np.array([[1], [3], [2], [1]])] - # # t_tests = [1, 2] - # # a = pybamm.StateVector(slice(0, 1), slice(3, 4)) - # # b = pybamm.StateVector(slice(1, 3)) - # # expr = a * b - # # evaluator_str = pybamm.get_julia_function(expr) - # # Main.eval(evaluator_str) - # # for y in y_tests: - # # result = evaluator(t,y,None) - # # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y)) + # Main.dy = [0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).toarray()) + + # test Inner + expr = pybamm.Inner(a, b) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) def test_evaluator_julia_all_functions(self): a = pybamm.StateVector(slice(0, 3)) @@ -241,6 +223,18 @@ def test_evaluator_julia_all_functions(self): Main.eval("f(dy,y,0,0)") np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + for function in [ + pybamm.min, + pybamm.max, + ]: + expr = function(a) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + # def test_evaluator_julia_discretised_operators(self): # whole_cell = ["negative electrode", "separator", "positive electrode"] # # create discretisation From 6929b320e7e3cb9f10ced8ff0d49df53dec6bea6 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 3 Nov 2020 16:55:23 -0500 Subject: [PATCH 24/88] #1129 all tests pass but not simplifying enough --- .../test_operations/test_evaluate_julia.py | 123 +++++++++--------- 1 file changed, 64 insertions(+), 59 deletions(-) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index cb467e2431..8d48bf4fb9 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -177,16 +177,17 @@ def test_evaluator_julia(self): np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) # test sparse stack - # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) - # expr = pybamm.SparseStack(A, B) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).toarray()) + A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) + c = pybamm.StateVector(slice(0, 2)) + expr = pybamm.SparseStack(A, B) @ c + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0, 0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) # test Inner expr = pybamm.Inner(a, b) @@ -198,42 +199,42 @@ def test_evaluator_julia(self): Main.eval("f(dy,y,0,0)") np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - def test_evaluator_julia_all_functions(self): - a = pybamm.StateVector(slice(0, 3)) - y_test = np.array([1, 2, 3]) - - for function in [ - pybamm.arcsinh, - pybamm.cos, - pybamm.cosh, - pybamm.exp, - pybamm.log, - pybamm.log10, - pybamm.sin, - pybamm.sinh, - pybamm.sqrt, - pybamm.tanh, - pybamm.arctan, - ]: - expr = function(a) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = 0.0 * y_test - Main.y = y_test - Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) - - for function in [ - pybamm.min, - pybamm.max, - ]: - expr = function(a) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.y = y_test - Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + # def test_evaluator_julia_all_functions(self): + # a = pybamm.StateVector(slice(0, 3)) + # y_test = np.array([1, 2, 3]) + + # for function in [ + # pybamm.arcsinh, + # pybamm.cos, + # pybamm.cosh, + # pybamm.exp, + # pybamm.log, + # pybamm.log10, + # pybamm.sin, + # pybamm.sinh, + # pybamm.sqrt, + # pybamm.tanh, + # pybamm.arctan, + # ]: + # expr = function(a) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # Main.dy = 0.0 * y_test + # Main.y = y_test + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + + # for function in [ + # pybamm.min, + # pybamm.max, + # ]: + # expr = function(a) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # Main.dy = [0.0] + # Main.y = y_test + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) # def test_evaluator_julia_discretised_operators(self): # whole_cell = ["negative electrode", "separator", "positive electrode"] @@ -268,13 +269,15 @@ def test_evaluator_julia_all_functions(self): # y_tests = [nodes ** 2 + 1, np.cos(nodes)] # for expr in [grad_eqn_disc, div_eqn_disc]: + # evaluator_str = pybamm.get_julia_function(expr) + # print(evaluator_str) + # Main.eval(evaluator_str) # for y_test in y_tests: - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # result = evaluator(None, y_test, None) - # np.testing.assert_almost_equal( - # result, expr.evaluate(y=y_test).flatten() - # ) + # pybamm_eval = expr.evaluate(y=y_test).flatten() + # Main.dy = np.zeros_like(pybamm_eval) + # Main.y = y_test + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_almost_equal(Main.dy, pybamm_eval) # def test_evaluator_julia_discretised_microscale(self): # # create discretisation @@ -318,14 +321,16 @@ def test_evaluator_julia_all_functions(self): # ) # y_tests = [np.linspace(0, 1, total_npts) ** 2] - # for expr in [div_eqn_disc]: + # for expr in [grad_eqn_disc, div_eqn_disc]: + # evaluator_str = pybamm.get_julia_function(expr) + # print(evaluator_str) + # Main.eval(evaluator_str) # for y_test in y_tests: - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # result = evaluator(None, y_test, None) - # np.testing.assert_almost_equal( - # result, expr.evaluate(y=y_test).flatten() - # ) + # pybamm_eval = expr.evaluate(y=y_test).flatten() + # Main.dy = np.zeros_like(pybamm_eval) + # Main.y = y_test + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_almost_equal(Main.dy, pybamm_eval) if __name__ == "__main__": From 5fa4f8d060511722a9c42cbf771c811eac5dd56a Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 3 Nov 2020 18:16:25 -0500 Subject: [PATCH 25/88] #1129 all evaluate_julia tests passing --- .../operations/evaluate_julia.py | 2 +- .../test_operations/quick_julia_test.py | 3 +- .../test_operations/test_evaluate_julia.py | 262 +++++++++--------- 3 files changed, 133 insertions(+), 134 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index dca987aed6..ba8a2fa0f5 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -359,7 +359,7 @@ def get_julia_function(symbol, funcname="f"): # first in that case, unless it is a @view in which case we don't # need to cache if julia_var in next_symbol_line and not ( - [" * " in next_symbol_line or "mul!" in next_symbol_line] + (" * " in next_symbol_line or "mul!" in next_symbol_line) and not symbol_line.startswith("@view") ): if symbol_line != "t": diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index fffba405ff..6e41fcd40f 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -33,7 +33,8 @@ # B = pybamm.Matrix([[11, 12, 13], [13, 14, 15], [16, 17, 18]]) # C = pybamm.Vector([[21], [22], [23]]) # expr = A @ (B @ (C * (C + pybamm.StateVector(slice(0, 3)))) + C) -expr = pybamm.Vector([1, 2, 3, 4, 5, 6]) * pybamm.NumpyConcatenation(a, b) +v = pybamm.StateVector(slice(0, 6)) +expr = (v * v * v * (v + v)) * pybamm.NumpyConcatenation(a, b) evaluator_str = pybamm.get_julia_function(expr) print(evaluator_str) Main.eval(evaluator_str) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 8d48bf4fb9..590d872b9e 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -199,138 +199,136 @@ def test_evaluator_julia(self): Main.eval("f(dy,y,0,0)") np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - # def test_evaluator_julia_all_functions(self): - # a = pybamm.StateVector(slice(0, 3)) - # y_test = np.array([1, 2, 3]) - - # for function in [ - # pybamm.arcsinh, - # pybamm.cos, - # pybamm.cosh, - # pybamm.exp, - # pybamm.log, - # pybamm.log10, - # pybamm.sin, - # pybamm.sinh, - # pybamm.sqrt, - # pybamm.tanh, - # pybamm.arctan, - # ]: - # expr = function(a) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # Main.dy = 0.0 * y_test - # Main.y = y_test - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) - - # for function in [ - # pybamm.min, - # pybamm.max, - # ]: - # expr = function(a) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # Main.dy = [0.0] - # Main.y = y_test - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) - - # def test_evaluator_julia_discretised_operators(self): - # whole_cell = ["negative electrode", "separator", "positive electrode"] - # # create discretisation - # mesh = get_mesh_for_testing() - # spatial_methods = {"macroscale": pybamm.FiniteVolume()} - # disc = pybamm.Discretisation(mesh, spatial_methods) - - # combined_submesh = mesh.combine_submeshes(*whole_cell) - - # # grad - # var = pybamm.Variable("var", domain=whole_cell) - # grad_eqn = pybamm.grad(var) - # boundary_conditions = { - # var.id: { - # "left": (pybamm.Scalar(1), "Dirichlet"), - # "right": (pybamm.Scalar(2), "Neumann"), - # } - # } - # disc.bcs = boundary_conditions - - # disc.set_variable_slices([var]) - # grad_eqn_disc = disc.process_symbol(grad_eqn) - - # # div: test on linear y (should have laplacian zero) so change bcs - # div_eqn = pybamm.div(var * grad_eqn) - - # div_eqn_disc = disc.process_symbol(div_eqn) - - # # test - # nodes = combined_submesh.nodes - # y_tests = [nodes ** 2 + 1, np.cos(nodes)] - - # for expr in [grad_eqn_disc, div_eqn_disc]: - # evaluator_str = pybamm.get_julia_function(expr) - # print(evaluator_str) - # Main.eval(evaluator_str) - # for y_test in y_tests: - # pybamm_eval = expr.evaluate(y=y_test).flatten() - # Main.dy = np.zeros_like(pybamm_eval) - # Main.y = y_test - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_almost_equal(Main.dy, pybamm_eval) - - # def test_evaluator_julia_discretised_microscale(self): - # # create discretisation - # mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) - # spatial_methods = {"negative particle": pybamm.FiniteVolume()} - # disc = pybamm.Discretisation(mesh, spatial_methods) - - # submesh = mesh["negative particle"] - - # # grad - # # grad(r) == 1 - # var = pybamm.Variable( - # "var", - # domain=["negative particle"], - # auxiliary_domains={ - # "secondary": "negative electrode", - # "tertiary": "current collector", - # }, - # ) - # grad_eqn = pybamm.grad(var) - # div_eqn = pybamm.div(var * grad_eqn) - - # boundary_conditions = { - # var.id: { - # "left": (pybamm.Scalar(1), "Dirichlet"), - # "right": (pybamm.Scalar(2), "Neumann"), - # } - # } - - # disc.bcs = boundary_conditions - - # disc.set_variable_slices([var]) - # grad_eqn_disc = disc.process_symbol(grad_eqn) - # div_eqn_disc = disc.process_symbol(div_eqn) - - # # test - # total_npts = ( - # submesh.npts - # * mesh["negative electrode"].npts - # * mesh["current collector"].npts - # ) - # y_tests = [np.linspace(0, 1, total_npts) ** 2] - - # for expr in [grad_eqn_disc, div_eqn_disc]: - # evaluator_str = pybamm.get_julia_function(expr) - # print(evaluator_str) - # Main.eval(evaluator_str) - # for y_test in y_tests: - # pybamm_eval = expr.evaluate(y=y_test).flatten() - # Main.dy = np.zeros_like(pybamm_eval) - # Main.y = y_test - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_almost_equal(Main.dy, pybamm_eval) + def test_evaluator_julia_all_functions(self): + a = pybamm.StateVector(slice(0, 3)) + y_test = np.array([1, 2, 3]) + + for function in [ + pybamm.arcsinh, + pybamm.cos, + pybamm.cosh, + pybamm.exp, + pybamm.log, + pybamm.log10, + pybamm.sin, + pybamm.sinh, + pybamm.sqrt, + pybamm.tanh, + pybamm.arctan, + ]: + expr = function(a) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = 0.0 * y_test + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + + for function in [ + pybamm.min, + pybamm.max, + ]: + expr = function(a) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + + def test_evaluator_julia_discretised_operators(self): + whole_cell = ["negative electrode", "separator", "positive electrode"] + # create discretisation + mesh = get_mesh_for_testing() + spatial_methods = {"macroscale": pybamm.FiniteVolume()} + disc = pybamm.Discretisation(mesh, spatial_methods) + + combined_submesh = mesh.combine_submeshes(*whole_cell) + + # grad + var = pybamm.Variable("var", domain=whole_cell) + grad_eqn = pybamm.grad(var) + boundary_conditions = { + var.id: { + "left": (pybamm.Scalar(1), "Dirichlet"), + "right": (pybamm.Scalar(2), "Neumann"), + } + } + disc.bcs = boundary_conditions + + disc.set_variable_slices([var]) + grad_eqn_disc = disc.process_symbol(grad_eqn) + + # div: test on linear y (should have laplacian zero) so change bcs + div_eqn = pybamm.div(var * grad_eqn) + + div_eqn_disc = disc.process_symbol(div_eqn) + + # test + nodes = combined_submesh.nodes + y_tests = [nodes ** 2 + 1, np.cos(nodes)] + + for expr in [grad_eqn_disc, div_eqn_disc]: + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y_test in y_tests: + pybamm_eval = expr.evaluate(y=y_test).flatten() + Main.dy = np.zeros_like(pybamm_eval) + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal(Main.dy, pybamm_eval) + + def test_evaluator_julia_discretised_microscale(self): + # create discretisation + mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) + spatial_methods = {"negative particle": pybamm.FiniteVolume()} + disc = pybamm.Discretisation(mesh, spatial_methods) + + submesh = mesh["negative particle"] + + # grad + # grad(r) == 1 + var = pybamm.Variable( + "var", + domain=["negative particle"], + auxiliary_domains={ + "secondary": "negative electrode", + "tertiary": "current collector", + }, + ) + grad_eqn = pybamm.grad(var) + div_eqn = pybamm.div(var * grad_eqn) + + boundary_conditions = { + var.id: { + "left": (pybamm.Scalar(1), "Dirichlet"), + "right": (pybamm.Scalar(2), "Neumann"), + } + } + + disc.bcs = boundary_conditions + + disc.set_variable_slices([var]) + grad_eqn_disc = disc.process_symbol(grad_eqn) + div_eqn_disc = disc.process_symbol(div_eqn) + + # test + total_npts = ( + submesh.npts + * mesh["negative electrode"].npts + * mesh["current collector"].npts + ) + y_tests = [np.linspace(0, 1, total_npts) ** 2] + + for expr in [grad_eqn_disc, div_eqn_disc]: + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y_test in y_tests: + pybamm_eval = expr.evaluate(y=y_test).flatten() + Main.dy = np.zeros_like(pybamm_eval) + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal(Main.dy, pybamm_eval) if __name__ == "__main__": From f595ae2113eaad5feaed890589bc1fd1b458545b Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 4 Nov 2020 00:46:00 -0500 Subject: [PATCH 26/88] #1129 working on battery models --- .../operations/evaluate_julia.py | 72 +- .../expression_tree/operations/spm_julia.jl | 83 +++ .../test_operations/quick_julia_test.py | 53 +- .../test_operations/test_evaluate_julia.py | 665 ++++++++++-------- 4 files changed, 532 insertions(+), 341 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index ba8a2fa0f5..6ef81d70a0 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -81,6 +81,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz elif value.shape == (1, 1): # Extract value if array has only one entry constant_symbols[symbol.id] = value[0, 0] + variable_symbol_sizes[symbol.id] = 1 elif value.shape[1] == 1: # Set print options large enough to avoid ellipsis # at least as big as len(row) = len(col) = len(data) @@ -93,8 +94,10 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz constant_symbols[symbol.id] = np.array2string( value.flatten(), separator="," ) + variable_symbol_sizes[symbol.id] = symbol.shape[0] else: constant_symbols[symbol.id] = value + # No need to save the size as it will not need to be used return # process children recursively @@ -182,27 +185,52 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # DomainConcatenation specifies a particular ordering for the concatenation, # which we must follow elif isinstance(symbol, pybamm.DomainConcatenation): - slice_starts = [] - all_child_vectors = [] - for i in range(symbol.secondary_dimensions_npts): - child_vectors = [] - for child_var, slices in zip(children_vars, symbol._children_slices): - for child_dom, child_slice in slices.items(): - slice_starts.append(symbol._slices[child_dom][i].start) - child_vectors.append( - "@view {}[{}:{}]".format( - child_var, child_slice[i].start, child_slice[i].stop + if symbol.secondary_dimensions_npts == 1: + all_child_vectors = children_vars + all_child_sizes = [ + variable_symbol_sizes[int(child[6:].replace("m", "-"))] + for child in children_vars + ] + else: + slice_starts = [] + all_child_vectors = [] + all_child_sizes = [] + for i in range(symbol.secondary_dimensions_npts): + child_vectors = [] + child_sizes = [] + for child_var, slices in zip( + children_vars, symbol._children_slices + ): + for child_dom, child_slice in slices.items(): + slice_starts.append(symbol._slices[child_dom][i].start) + # add 1 to slice start to account for julia indexing + child_vectors.append( + "@view {}[{}:{}]".format( + child_var, + child_slice[i].start + 1, + child_slice[i].stop, + ) ) - ) - all_child_vectors.extend( - [v for _, v in sorted(zip(slice_starts, child_vectors))] - ) + child_sizes.append( + child_slice[i].stop - child_slice[i].start + ) + all_child_vectors.extend( + [v for _, v in sorted(zip(slice_starts, child_vectors))] + ) + all_child_sizes.extend( + [v for _, v in sorted(zip(slice_starts, child_sizes))] + ) if len(children_vars) > 1 or symbol.secondary_dimensions_npts > 1: - symbol_str = "np.concatenate(({}))".format(",".join(all_child_vectors)) + # return a list of the children variables, which will be converted to a + # line by line assignment + # return this as a string so that other functionality still works + # also save sizes + symbol_str = "[" + for child, size in zip(all_child_vectors, all_child_sizes): + symbol_str += "{}::{}, ".format(size, child) + symbol_str = symbol_str[:-2] + "]" else: - symbol_str = "{}".format(",".join(children_vars)) - else: - raise NotImplementedError + raise NotImplementedError # Note: we assume that y is being passed as a column vector elif isinstance(symbol, pybamm.StateVector): @@ -217,7 +245,13 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz symbol_str = "@view y[{}:{}]".format(indices[0], indices[-1]) else: indices_array = pybamm.Array(indices) - constant_symbols[indices_array.id] = indices + # Save the indices as constant by printing to a string + # Set print options large enough to avoid ellipsis + # at least as big as len(row) = len(col) = len(data) + np.set_printoptions( + threshold=max(np.get_printoptions()["threshold"], indices.shape[0] + 10) + ) + constant_symbols[indices_array.id] = np.array2string(indices, separator=",") index_name = id_to_julia_variable(indices_array.id, True) symbol_str = "@view y[{}]".format(index_name) diff --git a/pybamm/expression_tree/operations/spm_julia.jl b/pybamm/expression_tree/operations/spm_julia.jl index 5b59544de6..ce13db5dd3 100644 --- a/pybamm/expression_tree/operations/spm_julia.jl +++ b/pybamm/expression_tree/operations/spm_julia.jl @@ -302,3 +302,86 @@ bbb = let xxx = 2 end xxx bbb() + +hhh = let cs = (const_5942506679108712033 = 4.272493084154669, + const_8746997338028787016 = [3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00], + const_3581012719263669839 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, + 25,25,26,26,27,27,28,28,29,29,30,30], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, + 25,26,26,27,27,28,28,29,29,30,30,31], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.], 30, 31), + const_m2612367405192523296 = [0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, + 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, + 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, + 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, + 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, + 1. ], + const_5069055130374487851 = [-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.], + const_4295227685794622472 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, + 26,27,28,29,30], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.], 31, 29), + const_6338892525200127145 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, + 25,25,26,26,27,27,28,28,29,29], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, + 25,26,26,27,27,28,28,29,29,30], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.], 29, 30), + const_m959842512278567774 = [ 0. , 0. , 0. , 0. , 0. , 0. , + 0. , 0. , 0. , 0. , 0. , 0. , + 0. , 0. , 0. , 0. , 0. , 0. , + 0. , 0. , 0. , 0. , 0. , 0. , + 0. , 0. , 0. , 0. , 0. , 0. , + -0.14182856], + const_8156332566672787077 = [-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.], + const_1625589959595150026 = [0. ,0. ,0. ,0. ,0. ,0. , + 0. ,0. ,0. ,0. ,0. ,0. , + 0. ,0. ,0. ,0. ,0. ,0. , + 0. ,0. ,0. ,0. ,0. ,0. , + 0. ,0. ,0. ,0. ,0. ,0. , + 0.03237701], + cache_3388063050425235652 = zeros(29), + cache_m1158339372614150244 = zeros(31), + cache_5740054478049714480 = zeros(31), + cache_6789881747970529275 = zeros(30), + cache_7402273518711947758 = zeros(29), + cache_1263431425114534989 = zeros(31), + cache_5253382333075143204 = zeros(31), + cache_5015266301979111956 = zeros(30),) + + function f_with_consts(dy, y, p, t) + mul!(cs.cache_3388063050425235652, cs.const_6338892525200127145, (@view y[2:31])) + mul!(cs.cache_m1158339372614150244, cs.const_4295227685794622472, cs.cache_3388063050425235652) + cs.cache_5740054478049714480 .= cs.const_m2612367405192523296 .* (cs.const_5069055130374487851 .* (cs.cache_m1158339372614150244 .+ cs.const_m959842512278567774)) + mul!(cs.cache_6789881747970529275, cs.const_3581012719263669839, cs.cache_5740054478049714480) + mul!(cs.cache_7402273518711947758, cs.const_6338892525200127145, (@view y[32:61])) + mul!(cs.cache_1263431425114534989, cs.const_4295227685794622472, cs.cache_7402273518711947758) + cs.cache_5253382333075143204 .= cs.const_m2612367405192523296 .* (cs.const_8156332566672787077 .* (cs.cache_1263431425114534989 .+ cs.const_1625589959595150026)) + mul!(cs.cache_5015266301979111956, cs.const_3581012719263669839, cs.cache_5253382333075143204) + dy[1:1] .= cs.const_5942506679108712033 + dy[2:31] .= (-8.813457647415214 .* (cs.const_8746997338028787016 .* cs.cache_6789881747970529275)) + dy[32:61] .= (-22.598609352346706 .* (cs.const_8746997338028787016 .* cs.cache_5015266301979111956)) + end + +end +u0 = [0.0; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6] +tspan = (0.0, 0.15) +prob = ODEProblem(hhh, u0, tspan) +@btime solve(prob, KenCarp47(autodiff=false), reltol=1e-6, abstol=1e-6, saveat=0.15 / 100); +@btime solve(prob, CVODE_BDF(), reltol=1e-6, abstol=1e-6, saveat=0.15 / 100); \ No newline at end of file diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index 6e41fcd40f..bfea95df22 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -14,35 +14,38 @@ import scipy.sparse from collections import OrderedDict -from julia import Main +# from julia import Main -a = pybamm.StateVector(slice(0, 3)) -b = pybamm.StateVector(slice(3, 6)) +model = pybamm.lithium_ion.SPM() +sim = pybamm.Simulation(model, solver=pybamm.CasadiSolver(mode="fast")) +sim.solve([0, 3600]) +sol = sim.solve([0, 3600]) +print(sol.integration_time) +# sim.build(check_model=False) +# expr = sim.built_model.concatenated_rhs -y_tests = np.array([[2], [3], [4], [5], [6], [7]]) -t_tests = 1 - -# test a * b -# expr = a * b # evaluator_str = pybamm.get_julia_function(expr) -# print(evaluator_str) - -# test something with a matrix multiplication -# A = pybamm.Matrix([[1, 2, 3], [3, 4, 5], [6, 7, 8]]) -# B = pybamm.Matrix([[11, 12, 13], [13, 14, 15], [16, 17, 18]]) -# C = pybamm.Vector([[21], [22], [23]]) -# expr = A @ (B @ (C * (C + pybamm.StateVector(slice(0, 3)))) + C) -v = pybamm.StateVector(slice(0, 6)) -expr = (v * v * v * (v + v)) * pybamm.NumpyConcatenation(a, b) -evaluator_str = pybamm.get_julia_function(expr) -print(evaluator_str) -Main.eval(evaluator_str) -Main.dy = [0, 0, 0, 0, 0, 0] -Main.y = [2, 3, 4, 5, 6, 7] -print(Main.eval("f(dy,y,0,0)")) -print(Main.dy) -print(expr.evaluate(y=Main.y)) +# np.set_printoptions( +# threshold=max( +# np.get_printoptions()["threshold"], +# sim.built_model.concatenated_initial_conditions.evaluate().flatten().size, +# ) +# ) +# with open("tmp.txt", "w") as f: +# f.write(evaluator_str) +# f.write( +# np.array2string( +# sim.built_model.concatenated_initial_conditions.evaluate().flatten(), +# separator=",", +# ) +# ) +# Main.eval(evaluator_str) +# Main.dy = [0, 0, 0, 0, 0, 0] +# Main.y = [2, 3, 4, 5, 6, 7] +# print(Main.eval("f(dy,y,0,0)")) +# print(Main.dy) +# print(expr.evaluate(y=Main.y)) # # test something with a heaviside # a = pybamm.Vector([1, 2]) # expr = a <= pybamm.StateVector(slice(0, 2)) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 590d872b9e..f4f8e93309 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -18,317 +18,388 @@ class TestEvaluate(unittest.TestCase): - def test_evaluator_julia(self): - a = pybamm.StateVector(slice(0, 1)) - b = pybamm.StateVector(slice(1, 2)) - - y_tests = [np.array([[2], [3]]), np.array([[1], [3]])] - t_tests = [1, 2] - - # test a * b - expr = a * b - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.y = np.array([2.0, 3.0]) - Main.eval("f(dy,y,0,0)") - self.assertEqual(Main.dy, 6) - Main.dy = [0.0] - Main.y = np.array([1.0, 3.0]) - Main.eval("f(dy,y,0,0)") - self.assertEqual(Main.dy, 3) - - # test function(a*b) - expr = pybamm.cos(a * b) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.y = np.array([2.0, 3.0]) - Main.eval("f(dy,y,0,0)") - self.assertAlmostEqual(Main.dy[0], np.cos(6)) - - # test a constant expression - expr = pybamm.Scalar(2) * pybamm.Scalar(3) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.eval("f(dy,y,0,0)") - self.assertEqual(Main.dy, 6) - - # test a larger expression - expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - self.assertEqual(Main.dy, expr.evaluate(t=None, y=y)) - - # test something with time - expr = a * pybamm.t - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - Main.dy = [0.0] - Main.y = y - Main.t = t - Main.eval("f(dy,y,0,t)") - self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) - - # test something with a matrix multiplication - A = pybamm.Matrix([[1, 2], [3, 4]]) - expr = A @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # test something with a heaviside - a = pybamm.Vector([1, 2]) - expr = a <= pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # test something with a minimum or maximum - a = pybamm.Vector([1, 2]) - for expr in [ - pybamm.minimum(a, pybamm.StateVector(slice(0, 2))), - pybamm.maximum(a, pybamm.StateVector(slice(0, 2))), - ]: - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # test something with an index - expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # test something with a sparse matrix multiplication - A = pybamm.Matrix([[1, 2], [3, 4]]) - B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) - expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - expr = B @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # test numpy concatenation - a = pybamm.StateVector(slice(0, 1)) - b = pybamm.StateVector(slice(1, 2)) - c = pybamm.StateVector(slice(2, 3)) - - y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] - t_tests = [1, 2] + # def test_evaluator_julia(self): + # a = pybamm.StateVector(slice(0, 1)) + # b = pybamm.StateVector(slice(1, 2)) + + # y_tests = [np.array([[2], [3]]), np.array([[1], [3]])] + # t_tests = [1, 2] + + # # test a * b + # expr = a * b + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # Main.dy = [0.0] + # Main.y = np.array([2.0, 3.0]) + # Main.eval("f(dy,y,0,0)") + # self.assertEqual(Main.dy, 6) + # Main.dy = [0.0] + # Main.y = np.array([1.0, 3.0]) + # Main.eval("f(dy,y,0,0)") + # self.assertEqual(Main.dy, 3) + + # # test function(a*b) + # expr = pybamm.cos(a * b) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # Main.dy = [0.0] + # Main.y = np.array([2.0, 3.0]) + # Main.eval("f(dy,y,0,0)") + # self.assertAlmostEqual(Main.dy[0], np.cos(6)) + + # # test a constant expression + # expr = pybamm.Scalar(2) * pybamm.Scalar(3) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # Main.dy = [0.0] + # Main.eval("f(dy,y,0,0)") + # self.assertEqual(Main.dy, 6) + + # # test a larger expression + # expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # self.assertEqual(Main.dy, expr.evaluate(t=None, y=y)) + + # # test something with time + # expr = a * pybamm.t + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for t, y in zip(t_tests, y_tests): + # Main.dy = [0.0] + # Main.y = y + # Main.t = t + # Main.eval("f(dy,y,0,t)") + # self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) + + # # test something with a matrix multiplication + # A = pybamm.Matrix([[1, 2], [3, 4]]) + # expr = A @ pybamm.StateVector(slice(0, 2)) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # # test something with a heaviside + # a = pybamm.Vector([1, 2]) + # expr = a <= pybamm.StateVector(slice(0, 2)) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # # test something with a minimum or maximum + # a = pybamm.Vector([1, 2]) + # for expr in [ + # pybamm.minimum(a, pybamm.StateVector(slice(0, 2))), + # pybamm.maximum(a, pybamm.StateVector(slice(0, 2))), + # ]: + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # # test something with an index + # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # # test something with a sparse matrix multiplication + # A = pybamm.Matrix([[1, 2], [3, 4]]) + # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) + # expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # expr = B @ pybamm.StateVector(slice(0, 2)) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # # test numpy concatenation + # a = pybamm.StateVector(slice(0, 3)) + # b = pybamm.Vector([2, 3, 4]) + # c = pybamm.Vector([5]) + + # y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] + # t_tests = [1, 2] + + # expr = pybamm.NumpyConcatenation(a, b, c) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # expr = pybamm.NumpyConcatenation(a, c) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0, 0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # # note 1D arrays are flattened in Julia + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # # test sparse stack + # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) + # c = pybamm.StateVector(slice(0, 2)) + # expr = pybamm.SparseStack(A, B) @ c + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0, 0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # # test Inner + # expr = pybamm.Inner(pybamm.Vector([1, 2]), pybamm.StateVector(slice(0, 2))) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y in y_tests: + # Main.dy = [0.0, 0.0] + # Main.y = y + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + + # def test_evaluator_julia_all_functions(self): + # a = pybamm.StateVector(slice(0, 3)) + # y_test = np.array([1, 2, 3]) + + # for function in [ + # pybamm.arcsinh, + # pybamm.cos, + # pybamm.cosh, + # pybamm.exp, + # pybamm.log, + # pybamm.log10, + # pybamm.sin, + # pybamm.sinh, + # pybamm.sqrt, + # pybamm.tanh, + # pybamm.arctan, + # ]: + # expr = function(a) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # Main.dy = 0.0 * y_test + # Main.y = y_test + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + + # for function in [ + # pybamm.min, + # pybamm.max, + # ]: + # expr = function(a) + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # Main.dy = [0.0] + # Main.y = y_test + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + + def test_evaluator_julia_domain_concatenation(self): + c_n = pybamm.Variable("c_n", domain="negative electrode") + c_s = pybamm.Variable("c_s", domain="separator") + c_p = pybamm.Variable("c_p", domain="positive electrode") + c = pybamm.Concatenation(c_n, c_s, c_p) + # create discretisation + mesh = get_mesh_for_testing() + spatial_methods = { + "macroscale": pybamm.FiniteVolume(), + "current collector": pybamm.FiniteVolume(), + } + disc = pybamm.Discretisation(mesh, spatial_methods) - expr = pybamm.NumpyConcatenation(a, b) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + combined_submesh = mesh.combine_submeshes(*c.domain) + nodes = combined_submesh.nodes + y_tests = [nodes ** 2 + 1, np.cos(nodes)] - expr = pybamm.NumpyConcatenation(a, c) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # test sparse stack - A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) - c = pybamm.StateVector(slice(0, 2)) - expr = pybamm.SparseStack(A, B) @ c - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0, 0.0, 0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) + # discretise and evaluate the variable + disc.set_variable_slices([c]) + c_disc = disc.process_symbol(c) - # test Inner - expr = pybamm.Inner(a, b) - evaluator_str = pybamm.get_julia_function(expr) + evaluator_str = pybamm.get_julia_function(c_disc) Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0] - Main.y = y - Main.eval("f(dy,y,0,0)") - np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - def test_evaluator_julia_all_functions(self): - a = pybamm.StateVector(slice(0, 3)) - y_test = np.array([1, 2, 3]) - - for function in [ - pybamm.arcsinh, - pybamm.cos, - pybamm.cosh, - pybamm.exp, - pybamm.log, - pybamm.log10, - pybamm.sin, - pybamm.sinh, - pybamm.sqrt, - pybamm.tanh, - pybamm.arctan, - ]: - expr = function(a) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = 0.0 * y_test - Main.y = y_test - Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) - - for function in [ - pybamm.min, - pybamm.max, - ]: - expr = function(a) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] + for y_test in y_tests: + pybamm_eval = c_disc.evaluate(y=y_test).flatten() + Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + np.testing.assert_almost_equal(Main.dy, pybamm_eval) - def test_evaluator_julia_discretised_operators(self): - whole_cell = ["negative electrode", "separator", "positive electrode"] + def test_evaluator_julia_domain_concatenation_2D(self): + c_n = pybamm.Variable( + "c_n", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + c_s = pybamm.Variable( + "c_s", + domain="separator", + auxiliary_domains={"secondary": "current collector"}, + ) + c_p = pybamm.Variable( + "c_p", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + c = pybamm.Concatenation(c_n, c_s, c_p) # create discretisation - mesh = get_mesh_for_testing() + mesh = get_1p1d_mesh_for_testing() spatial_methods = {"macroscale": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) - combined_submesh = mesh.combine_submeshes(*whole_cell) - - # grad - var = pybamm.Variable("var", domain=whole_cell) - grad_eqn = pybamm.grad(var) - boundary_conditions = { - var.id: { - "left": (pybamm.Scalar(1), "Dirichlet"), - "right": (pybamm.Scalar(2), "Neumann"), - } - } - disc.bcs = boundary_conditions - - disc.set_variable_slices([var]) - grad_eqn_disc = disc.process_symbol(grad_eqn) - - # div: test on linear y (should have laplacian zero) so change bcs - div_eqn = pybamm.div(var * grad_eqn) - - div_eqn_disc = disc.process_symbol(div_eqn) - - # test - nodes = combined_submesh.nodes - y_tests = [nodes ** 2 + 1, np.cos(nodes)] - - for expr in [grad_eqn_disc, div_eqn_disc]: - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y_test in y_tests: - pybamm_eval = expr.evaluate(y=y_test).flatten() - Main.dy = np.zeros_like(pybamm_eval) - Main.y = y_test - Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, pybamm_eval) - - def test_evaluator_julia_discretised_microscale(self): - # create discretisation - mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) - spatial_methods = {"negative particle": pybamm.FiniteVolume()} - disc = pybamm.Discretisation(mesh, spatial_methods) - - submesh = mesh["negative particle"] - - # grad - # grad(r) == 1 - var = pybamm.Variable( - "var", - domain=["negative particle"], - auxiliary_domains={ - "secondary": "negative electrode", - "tertiary": "current collector", - }, + combined_submesh = mesh.combine_submeshes(*c.domain) + nodes = np.linspace( + 0, 1, combined_submesh.npts * mesh["current collector"].npts ) - grad_eqn = pybamm.grad(var) - div_eqn = pybamm.div(var * grad_eqn) - - boundary_conditions = { - var.id: { - "left": (pybamm.Scalar(1), "Dirichlet"), - "right": (pybamm.Scalar(2), "Neumann"), - } - } - - disc.bcs = boundary_conditions + y_tests = [nodes ** 2 + 1, np.cos(nodes)] - disc.set_variable_slices([var]) - grad_eqn_disc = disc.process_symbol(grad_eqn) - div_eqn_disc = disc.process_symbol(div_eqn) + # discretise and evaluate the variable + disc.set_variable_slices([c]) + c_disc = disc.process_symbol(c) - # test - total_npts = ( - submesh.npts - * mesh["negative electrode"].npts - * mesh["current collector"].npts - ) - y_tests = [np.linspace(0, 1, total_npts) ** 2] - - for expr in [grad_eqn_disc, div_eqn_disc]: - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y_test in y_tests: - pybamm_eval = expr.evaluate(y=y_test).flatten() - Main.dy = np.zeros_like(pybamm_eval) - Main.y = y_test - Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, pybamm_eval) + evaluator_str = pybamm.get_julia_function(c_disc) + Main.eval(evaluator_str) + for y_test in y_tests: + pybamm_eval = c_disc.evaluate(y=y_test).flatten() + Main.dy = np.zeros_like(pybamm_eval) + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal(Main.dy, pybamm_eval) + + # def test_evaluator_julia_discretised_operators(self): + # whole_cell = ["negative electrode", "separator", "positive electrode"] + # # create discretisation + # mesh = get_mesh_for_testing() + # spatial_methods = {"macroscale": pybamm.FiniteVolume()} + # disc = pybamm.Discretisation(mesh, spatial_methods) + + # combined_submesh = mesh.combine_submeshes(*whole_cell) + + # # grad + # var = pybamm.Variable("var", domain=whole_cell) + # grad_eqn = pybamm.grad(var) + # boundary_conditions = { + # var.id: { + # "left": (pybamm.Scalar(1), "Dirichlet"), + # "right": (pybamm.Scalar(2), "Neumann"), + # } + # } + # disc.bcs = boundary_conditions + + # disc.set_variable_slices([var]) + # grad_eqn_disc = disc.process_symbol(grad_eqn) + + # # div: test on linear y (should have laplacian zero) so change bcs + # div_eqn = pybamm.div(var * grad_eqn) + + # div_eqn_disc = disc.process_symbol(div_eqn) + + # # test + # nodes = combined_submesh.nodes + # y_tests = [nodes ** 2 + 1, np.cos(nodes)] + + # for expr in [grad_eqn_disc, div_eqn_disc]: + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y_test in y_tests: + # pybamm_eval = expr.evaluate(y=y_test).flatten() + # Main.dy = np.zeros_like(pybamm_eval) + # Main.y = y_test + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_almost_equal(Main.dy, pybamm_eval) + + # def test_evaluator_julia_discretised_microscale(self): + # # create discretisation + # mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) + # spatial_methods = {"negative particle": pybamm.FiniteVolume()} + # disc = pybamm.Discretisation(mesh, spatial_methods) + + # submesh = mesh["negative particle"] + + # # grad + # # grad(r) == 1 + # var = pybamm.Variable( + # "var", + # domain=["negative particle"], + # auxiliary_domains={ + # "secondary": "negative electrode", + # "tertiary": "current collector", + # }, + # ) + # grad_eqn = pybamm.grad(var) + # div_eqn = pybamm.div(var * grad_eqn) + + # boundary_conditions = { + # var.id: { + # "left": (pybamm.Scalar(1), "Dirichlet"), + # "right": (pybamm.Scalar(2), "Neumann"), + # } + # } + + # disc.bcs = boundary_conditions + + # disc.set_variable_slices([var]) + # grad_eqn_disc = disc.process_symbol(grad_eqn) + # div_eqn_disc = disc.process_symbol(div_eqn) + + # # test + # total_npts = ( + # submesh.npts + # * mesh["negative electrode"].npts + # * mesh["current collector"].npts + # ) + # y_tests = [np.linspace(0, 1, total_npts) ** 2] + + # for expr in [grad_eqn_disc, div_eqn_disc]: + # evaluator_str = pybamm.get_julia_function(expr) + # Main.eval(evaluator_str) + # for y_test in y_tests: + # pybamm_eval = expr.evaluate(y=y_test).flatten() + # Main.dy = np.zeros_like(pybamm_eval) + # Main.y = y_test + # Main.eval("f(dy,y,0,0)") + # np.testing.assert_almost_equal(Main.dy, pybamm_eval) if __name__ == "__main__": From f415d556352797e3d2052ba7a1b330ef362eed54 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 4 Nov 2020 12:05:28 -0500 Subject: [PATCH 27/88] #1129 debugging julia models --- .../test_operations/quick_julia_test.py | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index bfea95df22..caa516e4c8 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -17,29 +17,39 @@ # from julia import Main -model = pybamm.lithium_ion.SPM() +model = pybamm.lithium_ion.SPMe() sim = pybamm.Simulation(model, solver=pybamm.CasadiSolver(mode="fast")) sim.solve([0, 3600]) -sol = sim.solve([0, 3600]) +param = model.default_parameter_values +timescale = param.evaluate(model.timescale) +sol = sim.solve(np.linspace(0, 0.15 * timescale, 100)) +print(sol.y[:, -1]) print(sol.integration_time) -# sim.build(check_model=False) -# expr = sim.built_model.concatenated_rhs +# expr = pybamm.NumpyConcatenation( +# sim.built_model.concatenated_rhs, sim.built_model.concatenated_algebraic +# ) +expr = sim.built_model.concatenated_rhs -# evaluator_str = pybamm.get_julia_function(expr) +evaluator_str = pybamm.get_julia_function(expr) +n_rhs = sim.built_model.concatenated_rhs.size +n_alg = sim.built_model.concatenated_algebraic.size # np.set_printoptions( # threshold=max( # np.get_printoptions()["threshold"], -# sim.built_model.concatenated_initial_conditions.evaluate().flatten().size, +# n_rhs + n_alg, # ) # ) -# with open("tmp.txt", "w") as f: -# f.write(evaluator_str) -# f.write( -# np.array2string( -# sim.built_model.concatenated_initial_conditions.evaluate().flatten(), -# separator=",", -# ) -# ) +with open("tmp.txt", "w") as f: + f.write(evaluator_str + "\n\n") + # f.write(f"u0 = {np.array2string(sol.model.y0, separator=',')}\n") + # f.write(f"du0 = zeros({n_rhs + n_alg})\n") + # f.write(f"differential_vars=[zeros({n_rhs});zeros({n_alg})]\n") + +expr2 = sim.built_model.variables["Terminal voltage [V]"] +evaluator_str2 = pybamm.get_julia_function(expr2) +with open("tmp2.txt", "w") as f: + f.write(evaluator_str2 + "\n\n") + # Main.eval(evaluator_str) # Main.dy = [0, 0, 0, 0, 0, 0] # Main.y = [2, 3, 4, 5, 6, 7] From bec5ce3cdd2fcff2dd51190f9ef30eef11285d3e Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 11 Nov 2020 09:25:23 -0500 Subject: [PATCH 28/88] #1129 running more tests, DFN is wrong --- examples/scripts/DFN.py | 12 +++--- .../test_operations/quick_julia_test.py | 41 ++++++++++--------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/examples/scripts/DFN.py b/examples/scripts/DFN.py index 9c50dbc7ef..24fa10751d 100644 --- a/examples/scripts/DFN.py +++ b/examples/scripts/DFN.py @@ -9,7 +9,7 @@ # load model -model = pybamm.lithium_ion.DFN() +model = pybamm.lithium_ion.SPMe() # create geometry geometry = model.default_geometry @@ -20,9 +20,9 @@ param.process_geometry(geometry) # set mesh -var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} -mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) +# var = pybamm.standard_spatial_vars +# var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} +mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts) # discretise model disc = pybamm.Discretisation(mesh, model.default_spatial_methods) @@ -30,8 +30,10 @@ # solve model t_eval = np.linspace(0, 3600, 100) -solver = pybamm.CasadiSolver(mode="fast", atol=1e-6, rtol=1e-3) +solver = pybamm.CasadiSolver(mode="fast", atol=1e-6, rtol=1e-6) solution = solver.solve(model, t_eval) +solution = solver.solve(model, t_eval) +print(solution.integration_time) # plot plot = pybamm.QuickPlot( diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index caa516e4c8..f0c3c5cd7a 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -14,10 +14,10 @@ import scipy.sparse from collections import OrderedDict -# from julia import Main +from julia import Main -model = pybamm.lithium_ion.SPMe() +model = pybamm.lithium_ion.DFN() sim = pybamm.Simulation(model, solver=pybamm.CasadiSolver(mode="fast")) sim.solve([0, 3600]) param = model.default_parameter_values @@ -25,10 +25,10 @@ sol = sim.solve(np.linspace(0, 0.15 * timescale, 100)) print(sol.y[:, -1]) print(sol.integration_time) -# expr = pybamm.NumpyConcatenation( -# sim.built_model.concatenated_rhs, sim.built_model.concatenated_algebraic -# ) -expr = sim.built_model.concatenated_rhs +expr = pybamm.NumpyConcatenation( + sim.built_model.concatenated_rhs, sim.built_model.concatenated_algebraic +).simplify() +# expr = sim.built_model.concatenated_rhs.simplify() evaluator_str = pybamm.get_julia_function(expr) n_rhs = sim.built_model.concatenated_rhs.size @@ -41,20 +41,21 @@ # ) with open("tmp.txt", "w") as f: f.write(evaluator_str + "\n\n") - # f.write(f"u0 = {np.array2string(sol.model.y0, separator=',')}\n") - # f.write(f"du0 = zeros({n_rhs + n_alg})\n") - # f.write(f"differential_vars=[zeros({n_rhs});zeros({n_alg})]\n") - -expr2 = sim.built_model.variables["Terminal voltage [V]"] -evaluator_str2 = pybamm.get_julia_function(expr2) -with open("tmp2.txt", "w") as f: - f.write(evaluator_str2 + "\n\n") - -# Main.eval(evaluator_str) -# Main.dy = [0, 0, 0, 0, 0, 0] -# Main.y = [2, 3, 4, 5, 6, 7] -# print(Main.eval("f(dy,y,0,0)")) -# print(Main.dy) + f.write(f"u0 = {np.array2string(sol.model.y0, separator=',')}\n") + f.write(f"du0 = zeros({n_rhs + n_alg})\n") + f.write(f"differential_vars=[ones({n_rhs});zeros({n_alg})]\n") + +# expr2 = sim.built_model.variables["Terminal voltage [V]"] +# evaluator_str2 = pybamm.get_julia_function(expr2) +# with open("tmp2.txt", "w") as f: +# f.write(evaluator_str2 + "\n\n") + +Main.eval(evaluator_str) +Main.dy = np.zeros(n_rhs + n_alg) +Main.y = sol.model.y0 +Main.eval("f(dy,y,0,0)") +print(Main.dy) +expr.evaluate(y=sol.model.y0) # print(expr.evaluate(y=Main.y)) # # test something with a heaviside # a = pybamm.Vector([1, 2]) From f3e4936b332e14b842460718f6084d186d6b6b0f Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 11 Nov 2020 13:19:46 -0500 Subject: [PATCH 29/88] #1129 running more julia tests --- examples/scripts/DFN.py | 41 ++++++++++--------- .../test_operations/quick_julia_test.py | 40 ++++++++++-------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/examples/scripts/DFN.py b/examples/scripts/DFN.py index 24fa10751d..fc23f22fc5 100644 --- a/examples/scripts/DFN.py +++ b/examples/scripts/DFN.py @@ -20,9 +20,10 @@ param.process_geometry(geometry) # set mesh -# var = pybamm.standard_spatial_vars -# var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} -mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts) +var = pybamm.standard_spatial_vars +var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} +# var_pts = model.default_var_pts +mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) # discretise model disc = pybamm.Discretisation(mesh, model.default_spatial_methods) @@ -33,22 +34,22 @@ solver = pybamm.CasadiSolver(mode="fast", atol=1e-6, rtol=1e-6) solution = solver.solve(model, t_eval) solution = solver.solve(model, t_eval) -print(solution.integration_time) +print(pybamm.Timer().format(solution.integration_time)) # plot -plot = pybamm.QuickPlot( - solution, - [ - "Negative particle concentration [mol.m-3]", - "Electrolyte concentration [mol.m-3]", - "Positive particle concentration [mol.m-3]", - "Current [A]", - "Negative electrode potential [V]", - "Electrolyte potential [V]", - "Positive electrode potential [V]", - "Terminal voltage [V]", - ], - time_unit="seconds", - spatial_unit="um", -) -plot.dynamic_plot() +# plot = pybamm.QuickPlot( +# solution, +# [ +# "Negative particle concentration [mol.m-3]", +# "Electrolyte concentration [mol.m-3]", +# "Positive particle concentration [mol.m-3]", +# "Current [A]", +# "Negative electrode potential [V]", +# "Electrolyte potential [V]", +# "Positive electrode potential [V]", +# "Terminal voltage [V]", +# ], +# time_unit="seconds", +# spatial_unit="um", +# ) +# plot.dynamic_plot() diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index f0c3c5cd7a..5e79b07e3b 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -17,33 +17,37 @@ from julia import Main -model = pybamm.lithium_ion.DFN() -sim = pybamm.Simulation(model, solver=pybamm.CasadiSolver(mode="fast")) +model = pybamm.lithium_ion.SPM() +# var = pybamm.standard_spatial_vars +# var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} +var_pts = model.default_var_pts +sim = pybamm.Simulation(model, solver=pybamm.CasadiSolver(mode="fast"), var_pts=var_pts) sim.solve([0, 3600]) param = model.default_parameter_values timescale = param.evaluate(model.timescale) sol = sim.solve(np.linspace(0, 0.15 * timescale, 100)) print(sol.y[:, -1]) print(sol.integration_time) -expr = pybamm.NumpyConcatenation( - sim.built_model.concatenated_rhs, sim.built_model.concatenated_algebraic -).simplify() -# expr = sim.built_model.concatenated_rhs.simplify() +# expr = pybamm.NumpyConcatenation( +# sim.built_model.concatenated_rhs, sim.built_model.concatenated_algebraic +# ).simplify() +expr = sim.built_model.concatenated_rhs.simplify() evaluator_str = pybamm.get_julia_function(expr) n_rhs = sim.built_model.concatenated_rhs.size n_alg = sim.built_model.concatenated_algebraic.size # np.set_printoptions( -# threshold=max( -# np.get_printoptions()["threshold"], -# n_rhs + n_alg, -# ) +# threshold=100 +# # max( +# # np.get_printoptions()["threshold"], +# # n_rhs + n_alg, +# # ) # ) -with open("tmp.txt", "w") as f: +with open("tmp_SPM_30.txt", "w") as f: f.write(evaluator_str + "\n\n") - f.write(f"u0 = {np.array2string(sol.model.y0, separator=',')}\n") - f.write(f"du0 = zeros({n_rhs + n_alg})\n") - f.write(f"differential_vars=[ones({n_rhs});zeros({n_alg})]\n") + f.write(f"u0 = {np.array2string(sol.model.y0.full().flatten(), separator=',')}\n") + # f.write(f"du0 = zeros({n_rhs + n_alg})\n") + # f.write(f"differential_vars=[ones({n_rhs});zeros({n_alg})]\n") # expr2 = sim.built_model.variables["Terminal voltage [V]"] # evaluator_str2 = pybamm.get_julia_function(expr2) @@ -52,10 +56,12 @@ Main.eval(evaluator_str) Main.dy = np.zeros(n_rhs + n_alg) -Main.y = sol.model.y0 +Main.y = sol.model.y0.full().flatten() Main.eval("f(dy,y,0,0)") -print(Main.dy) -expr.evaluate(y=sol.model.y0) +# print(Main.dy) +# expr.evaluate(y=sol.model.y0) + +print(Main.dy - expr.evaluate(y=Main.y).T) # print(expr.evaluate(y=Main.y)) # # test something with a heaviside # a = pybamm.Vector([1, 2]) From fef5d0c8a77d78de3858a7a5b5f82923263929f9 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 18 Nov 2020 12:37:43 -0500 Subject: [PATCH 30/88] #1129 debugging DFN --- .../test_operations/quick_julia_test.py | 45 +- .../test_operations/test_evaluate_julia.py | 628 +++--- tmp_debug.jl | 1780 +++++++++++++++++ 3 files changed, 2113 insertions(+), 340 deletions(-) create mode 100644 tmp_debug.jl diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index 5e79b07e3b..f5205d2cf6 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -3,21 +3,12 @@ # import pybamm -from tests import ( - get_mesh_for_testing, - get_1p1d_mesh_for_testing, - get_discretisation_for_testing, - get_1p1d_discretisation_for_testing, -) -import unittest import numpy as np -import scipy.sparse -from collections import OrderedDict from julia import Main -model = pybamm.lithium_ion.SPM() +model = pybamm.lithium_ion.DFN() # var = pybamm.standard_spatial_vars # var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} var_pts = model.default_var_pts @@ -28,25 +19,25 @@ sol = sim.solve(np.linspace(0, 0.15 * timescale, 100)) print(sol.y[:, -1]) print(sol.integration_time) -# expr = pybamm.NumpyConcatenation( -# sim.built_model.concatenated_rhs, sim.built_model.concatenated_algebraic -# ).simplify() -expr = sim.built_model.concatenated_rhs.simplify() +expr = pybamm.NumpyConcatenation( + sim.built_model.concatenated_rhs, sim.built_model.concatenated_algebraic +) # .simplify() +# expr = sim.built_model.concatenated_rhs.simplify() +expr = sim.built_model.concatenated_algebraic # .children[-1] evaluator_str = pybamm.get_julia_function(expr) n_rhs = sim.built_model.concatenated_rhs.size n_alg = sim.built_model.concatenated_algebraic.size -# np.set_printoptions( -# threshold=100 -# # max( -# # np.get_printoptions()["threshold"], -# # n_rhs + n_alg, -# # ) -# ) -with open("tmp_SPM_30.txt", "w") as f: - f.write(evaluator_str + "\n\n") - f.write(f"u0 = {np.array2string(sol.model.y0.full().flatten(), separator=',')}\n") - # f.write(f"du0 = zeros({n_rhs + n_alg})\n") +np.set_printoptions( + threshold=max( + np.get_printoptions()["threshold"], + n_rhs + n_alg, + ) +) +with open("tmp_debug.jl", "w") as f: + f.write(evaluator_str) + f.write(f"u0 = {np.array2string(sol.model.y0, separator=',')}\n") + f.write(f"du0 = zeros({n_rhs + n_alg})\n") # f.write(f"differential_vars=[ones({n_rhs});zeros({n_alg})]\n") # expr2 = sim.built_model.variables["Terminal voltage [V]"] @@ -55,8 +46,8 @@ # f.write(evaluator_str2 + "\n\n") Main.eval(evaluator_str) -Main.dy = np.zeros(n_rhs + n_alg) -Main.y = sol.model.y0.full().flatten() +Main.dy = np.zeros(expr.shape[0]) +Main.y = sol.model.y0 Main.eval("f(dy,y,0,0)") # print(Main.dy) # expr.evaluate(y=sol.model.y0) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index f4f8e93309..f32660203e 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -18,223 +18,225 @@ class TestEvaluate(unittest.TestCase): - # def test_evaluator_julia(self): - # a = pybamm.StateVector(slice(0, 1)) - # b = pybamm.StateVector(slice(1, 2)) - - # y_tests = [np.array([[2], [3]]), np.array([[1], [3]])] - # t_tests = [1, 2] - - # # test a * b - # expr = a * b - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # Main.dy = [0.0] - # Main.y = np.array([2.0, 3.0]) - # Main.eval("f(dy,y,0,0)") - # self.assertEqual(Main.dy, 6) - # Main.dy = [0.0] - # Main.y = np.array([1.0, 3.0]) - # Main.eval("f(dy,y,0,0)") - # self.assertEqual(Main.dy, 3) - - # # test function(a*b) - # expr = pybamm.cos(a * b) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # Main.dy = [0.0] - # Main.y = np.array([2.0, 3.0]) - # Main.eval("f(dy,y,0,0)") - # self.assertAlmostEqual(Main.dy[0], np.cos(6)) - - # # test a constant expression - # expr = pybamm.Scalar(2) * pybamm.Scalar(3) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # Main.dy = [0.0] - # Main.eval("f(dy,y,0,0)") - # self.assertEqual(Main.dy, 6) - - # # test a larger expression - # expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # self.assertEqual(Main.dy, expr.evaluate(t=None, y=y)) - - # # test something with time - # expr = a * pybamm.t - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for t, y in zip(t_tests, y_tests): - # Main.dy = [0.0] - # Main.y = y - # Main.t = t - # Main.eval("f(dy,y,0,t)") - # self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) - - # # test something with a matrix multiplication - # A = pybamm.Matrix([[1, 2], [3, 4]]) - # expr = A @ pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # test something with a heaviside - # a = pybamm.Vector([1, 2]) - # expr = a <= pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # test something with a minimum or maximum - # a = pybamm.Vector([1, 2]) - # for expr in [ - # pybamm.minimum(a, pybamm.StateVector(slice(0, 2))), - # pybamm.maximum(a, pybamm.StateVector(slice(0, 2))), - # ]: - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # test something with an index - # expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # test something with a sparse matrix multiplication - # A = pybamm.Matrix([[1, 2], [3, 4]]) - # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) - # expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # expr = B @ pybamm.StateVector(slice(0, 2)) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # test numpy concatenation - # a = pybamm.StateVector(slice(0, 3)) - # b = pybamm.Vector([2, 3, 4]) - # c = pybamm.Vector([5]) - - # y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] - # t_tests = [1, 2] - - # expr = pybamm.NumpyConcatenation(a, b, c) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # expr = pybamm.NumpyConcatenation(a, c) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0, 0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # # note 1D arrays are flattened in Julia - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # test sparse stack - # A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - # B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) - # c = pybamm.StateVector(slice(0, 2)) - # expr = pybamm.SparseStack(A, B) @ c - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0, 0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # # test Inner - # expr = pybamm.Inner(pybamm.Vector([1, 2]), pybamm.StateVector(slice(0, 2))) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y in y_tests: - # Main.dy = [0.0, 0.0] - # Main.y = y - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_allclose(Main.dy, expr.evaluate(y=y).flatten()) - - # def test_evaluator_julia_all_functions(self): - # a = pybamm.StateVector(slice(0, 3)) - # y_test = np.array([1, 2, 3]) - - # for function in [ - # pybamm.arcsinh, - # pybamm.cos, - # pybamm.cosh, - # pybamm.exp, - # pybamm.log, - # pybamm.log10, - # pybamm.sin, - # pybamm.sinh, - # pybamm.sqrt, - # pybamm.tanh, - # pybamm.arctan, - # ]: - # expr = function(a) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # Main.dy = 0.0 * y_test - # Main.y = y_test - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) - - # for function in [ - # pybamm.min, - # pybamm.max, - # ]: - # expr = function(a) - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # Main.dy = [0.0] - # Main.y = y_test - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_almost_equal(Main.dy, expr.evaluate(y=y_test).flatten()) + def test_evaluator_julia(self): + a = pybamm.StateVector(slice(0, 1)) + b = pybamm.StateVector(slice(1, 2)) + + y_tests = [np.array([[2], [3]]), np.array([[1], [3]])] + t_tests = [1, 2] + + # test a * b + expr = a * b + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = np.array([2.0, 3.0]) + Main.eval("f(dy,y,0,0)") + self.assertEqual(Main.dy, 6) + Main.dy = [0.0] + Main.y = np.array([1.0, 3.0]) + Main.eval("f(dy,y,0,0)") + self.assertEqual(Main.dy, 3) + + # test function(a*b) + expr = pybamm.cos(a * b) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = np.array([2.0, 3.0]) + Main.eval("f(dy,y,0,0)") + self.assertAlmostEqual(Main.dy[0], np.cos(6), places=15) + + # test a constant expression + expr = pybamm.Scalar(2) * pybamm.Scalar(3) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.eval("f(dy,y,0,0)") + self.assertEqual(Main.dy, 6) + + # test a larger expression + expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + self.assertEqual(Main.dy, expr.evaluate(t=None, y=y)) + + # test something with time + expr = a * pybamm.t + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for t, y in zip(t_tests, y_tests): + Main.dy = [0.0] + Main.y = y + Main.t = t + Main.eval("f(dy,y,0,t)") + self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) + + # test something with a matrix multiplication + A = pybamm.Matrix([[1, 2], [3, 4]]) + expr = A @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + # test something with a heaviside + a = pybamm.Vector([1, 2]) + expr = a <= pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + # test something with a minimum or maximum + a = pybamm.Vector([1, 2]) + for expr in [ + pybamm.minimum(a, pybamm.StateVector(slice(0, 2))), + pybamm.maximum(a, pybamm.StateVector(slice(0, 2))), + ]: + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + # test something with an index + expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + # test something with a sparse matrix multiplication + A = pybamm.Matrix([[1, 2], [3, 4]]) + B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) + expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + expr = B @ pybamm.StateVector(slice(0, 2)) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + # test numpy concatenation + a = pybamm.StateVector(slice(0, 3)) + b = pybamm.Vector([2, 3, 4]) + c = pybamm.Vector([5]) + + y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] + t_tests = [1, 2] + + expr = pybamm.NumpyConcatenation(a, b, c) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + expr = pybamm.NumpyConcatenation(a, c) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0, 0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + # note 1D arrays are flattened in Julia + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + # test sparse stack + A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) + B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) + c = pybamm.StateVector(slice(0, 2)) + expr = pybamm.SparseStack(A, B) @ c + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0, 0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + # test Inner + expr = pybamm.Inner(pybamm.Vector([1, 2]), pybamm.StateVector(slice(0, 2))) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y in y_tests: + Main.dy = [0.0, 0.0] + Main.y = y + Main.eval("f(dy,y,0,0)") + np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + + def test_evaluator_julia_all_functions(self): + a = pybamm.StateVector(slice(0, 3)) + y_test = np.array([1, 2, 3]) + + for function in [ + pybamm.arcsinh, + pybamm.cos, + pybamm.cosh, + pybamm.exp, + pybamm.log, + pybamm.log10, + pybamm.sin, + pybamm.sinh, + pybamm.sqrt, + pybamm.tanh, + pybamm.arctan, + ]: + expr = function(a) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = 0.0 * y_test + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal( + Main.dy, expr.evaluate(y=y_test).flatten(), decimal=15 + ) + + for function in [ + pybamm.min, + pybamm.max, + ]: + expr = function(a) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_equal(Main.dy, expr.evaluate(y=y_test).flatten()) def test_evaluator_julia_domain_concatenation(self): c_n = pybamm.Variable("c_n", domain="negative electrode") @@ -264,7 +266,7 @@ def test_evaluator_julia_domain_concatenation(self): Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, pybamm_eval) + np.testing.assert_equal(Main.dy, pybamm_eval) def test_evaluator_julia_domain_concatenation_2D(self): c_n = pybamm.Variable( @@ -305,101 +307,101 @@ def test_evaluator_julia_domain_concatenation_2D(self): Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, pybamm_eval) - - # def test_evaluator_julia_discretised_operators(self): - # whole_cell = ["negative electrode", "separator", "positive electrode"] - # # create discretisation - # mesh = get_mesh_for_testing() - # spatial_methods = {"macroscale": pybamm.FiniteVolume()} - # disc = pybamm.Discretisation(mesh, spatial_methods) - - # combined_submesh = mesh.combine_submeshes(*whole_cell) - - # # grad - # var = pybamm.Variable("var", domain=whole_cell) - # grad_eqn = pybamm.grad(var) - # boundary_conditions = { - # var.id: { - # "left": (pybamm.Scalar(1), "Dirichlet"), - # "right": (pybamm.Scalar(2), "Neumann"), - # } - # } - # disc.bcs = boundary_conditions - - # disc.set_variable_slices([var]) - # grad_eqn_disc = disc.process_symbol(grad_eqn) - - # # div: test on linear y (should have laplacian zero) so change bcs - # div_eqn = pybamm.div(var * grad_eqn) - - # div_eqn_disc = disc.process_symbol(div_eqn) - - # # test - # nodes = combined_submesh.nodes - # y_tests = [nodes ** 2 + 1, np.cos(nodes)] - - # for expr in [grad_eqn_disc, div_eqn_disc]: - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y_test in y_tests: - # pybamm_eval = expr.evaluate(y=y_test).flatten() - # Main.dy = np.zeros_like(pybamm_eval) - # Main.y = y_test - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_almost_equal(Main.dy, pybamm_eval) - - # def test_evaluator_julia_discretised_microscale(self): - # # create discretisation - # mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) - # spatial_methods = {"negative particle": pybamm.FiniteVolume()} - # disc = pybamm.Discretisation(mesh, spatial_methods) - - # submesh = mesh["negative particle"] - - # # grad - # # grad(r) == 1 - # var = pybamm.Variable( - # "var", - # domain=["negative particle"], - # auxiliary_domains={ - # "secondary": "negative electrode", - # "tertiary": "current collector", - # }, - # ) - # grad_eqn = pybamm.grad(var) - # div_eqn = pybamm.div(var * grad_eqn) - - # boundary_conditions = { - # var.id: { - # "left": (pybamm.Scalar(1), "Dirichlet"), - # "right": (pybamm.Scalar(2), "Neumann"), - # } - # } - - # disc.bcs = boundary_conditions - - # disc.set_variable_slices([var]) - # grad_eqn_disc = disc.process_symbol(grad_eqn) - # div_eqn_disc = disc.process_symbol(div_eqn) - - # # test - # total_npts = ( - # submesh.npts - # * mesh["negative electrode"].npts - # * mesh["current collector"].npts - # ) - # y_tests = [np.linspace(0, 1, total_npts) ** 2] - - # for expr in [grad_eqn_disc, div_eqn_disc]: - # evaluator_str = pybamm.get_julia_function(expr) - # Main.eval(evaluator_str) - # for y_test in y_tests: - # pybamm_eval = expr.evaluate(y=y_test).flatten() - # Main.dy = np.zeros_like(pybamm_eval) - # Main.y = y_test - # Main.eval("f(dy,y,0,0)") - # np.testing.assert_almost_equal(Main.dy, pybamm_eval) + np.testing.assert_equal(Main.dy, pybamm_eval) + + def test_evaluator_julia_discretised_operators(self): + whole_cell = ["negative electrode", "separator", "positive electrode"] + # create discretisation + mesh = get_mesh_for_testing() + spatial_methods = {"macroscale": pybamm.FiniteVolume()} + disc = pybamm.Discretisation(mesh, spatial_methods) + + combined_submesh = mesh.combine_submeshes(*whole_cell) + + # grad + var = pybamm.Variable("var", domain=whole_cell) + grad_eqn = pybamm.grad(var) + boundary_conditions = { + var.id: { + "left": (pybamm.Scalar(1), "Dirichlet"), + "right": (pybamm.Scalar(2), "Neumann"), + } + } + disc.bcs = boundary_conditions + + disc.set_variable_slices([var]) + grad_eqn_disc = disc.process_symbol(grad_eqn) + + # div: test on linear y (should have laplacian zero) so change bcs + div_eqn = pybamm.div(var * grad_eqn) + + div_eqn_disc = disc.process_symbol(div_eqn) + + # test + nodes = combined_submesh.nodes + y_tests = [nodes ** 2 + 1, np.cos(nodes)] + + for expr in [grad_eqn_disc, div_eqn_disc]: + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y_test in y_tests: + pybamm_eval = expr.evaluate(y=y_test).flatten() + Main.dy = np.zeros_like(pybamm_eval) + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_equal(Main.dy, pybamm_eval) + + def test_evaluator_julia_discretised_microscale(self): + # create discretisation + mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) + spatial_methods = {"negative particle": pybamm.FiniteVolume()} + disc = pybamm.Discretisation(mesh, spatial_methods) + + submesh = mesh["negative particle"] + + # grad + # grad(r) == 1 + var = pybamm.Variable( + "var", + domain=["negative particle"], + auxiliary_domains={ + "secondary": "negative electrode", + "tertiary": "current collector", + }, + ) + grad_eqn = pybamm.grad(var) + div_eqn = pybamm.div(var * grad_eqn) + + boundary_conditions = { + var.id: { + "left": (pybamm.Scalar(1), "Dirichlet"), + "right": (pybamm.Scalar(2), "Neumann"), + } + } + + disc.bcs = boundary_conditions + + disc.set_variable_slices([var]) + grad_eqn_disc = disc.process_symbol(grad_eqn) + div_eqn_disc = disc.process_symbol(div_eqn) + + # test + total_npts = ( + submesh.npts + * mesh["negative electrode"].npts + * mesh["current collector"].npts + ) + y_tests = [np.linspace(0, 1, total_npts) ** 2] + + for expr in [grad_eqn_disc, div_eqn_disc]: + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + for y_test in y_tests: + pybamm_eval = expr.evaluate(y=y_test).flatten() + Main.dy = np.zeros_like(pybamm_eval) + Main.y = y_test + Main.eval("f(dy,y,0,0)") + np.testing.assert_almost_equal(Main.dy, pybamm_eval, decimal=15) if __name__ == "__main__": diff --git a/tmp_debug.jl b/tmp_debug.jl new file mode 100644 index 0000000000..4f989db900 --- /dev/null +++ b/tmp_debug.jl @@ -0,0 +1,1780 @@ +begin + using SparseArrays, LinearAlgebra + + f = let cs = (const_m1032606879019717969 = 4.272493084154669, + const_m6466908670533079333 = [-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, + -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765], + const_m919967631435488369 = [3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, + 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, + 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, + 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, + 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, + 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, + 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, + 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, + 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, + 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, + 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, + 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, + 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, + 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, + 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, + 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00], + const_1477443756317609848 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, + 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, + 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, + 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, + 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, + 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, + 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, + 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, + 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, + 100,100,101,101,102,102,103,103,104,104,105,105,106,106,107,107,108,108, + 109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117, + 118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126, + 127,127,128,128,129,129,130,130,131,131,132,132,133,133,134,134,135,135, + 136,136,137,137,138,138,139,139,140,140,141,141,142,142,143,143,144,144, + 145,145,146,146,147,147,148,148,149,149,150,150,151,151,152,152,153,153, + 154,154,155,155,156,156,157,157,158,158,159,159,160,160,161,161,162,162, + 163,163,164,164,165,165,166,166,167,167,168,168,169,169,170,170,171,171, + 172,172,173,173,174,174,175,175,176,176,177,177,178,178,179,179,180,180, + 181,181,182,182,183,183,184,184,185,185,186,186,187,187,188,188,189,189, + 190,190,191,191,192,192,193,193,194,194,195,195,196,196,197,197,198,198, + 199,199,200,200,201,201,202,202,203,203,204,204,205,205,206,206,207,207, + 208,208,209,209,210,210,211,211,212,212,213,213,214,214,215,215,216,216, + 217,217,218,218,219,219,220,220,221,221,222,222,223,223,224,224,225,225, + 226,226,227,227,228,228,229,229,230,230,231,231,232,232,233,233,234,234, + 235,235,236,236,237,237,238,238,239,239,240,240,241,241,242,242,243,243, + 244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252, + 253,253,254,254,255,255,256,256,257,257,258,258,259,259,260,260,261,261, + 262,262,263,263,264,264,265,265,266,266,267,267,268,268,269,269,270,270, + 271,271,272,272,273,273,274,274,275,275,276,276,277,277,278,278,279,279, + 280,280,281,281,282,282,283,283,284,284,285,285,286,286,287,287,288,288, + 289,289,290,290,291,291,292,292,293,293,294,294,295,295,296,296,297,297, + 298,298,299,299,300,300,301,301,302,302,303,303,304,304,305,305,306,306, + 307,307,308,308,309,309,310,310,311,311,312,312,313,313,314,314,315,315, + 316,316,317,317,318,318,319,319,320,320,321,321,322,322,323,323,324,324, + 325,325,326,326,327,327,328,328,329,329,330,330,331,331,332,332,333,333, + 334,334,335,335,336,336,337,337,338,338,339,339,340,340,341,341,342,342, + 343,343,344,344,345,345,346,346,347,347,348,348,349,349,350,350,351,351, + 352,352,353,353,354,354,355,355,356,356,357,357,358,358,359,359,360,360, + 361,361,362,362,363,363,364,364,365,365,366,366,367,367,368,368,369,369, + 370,370,371,371,372,372,373,373,374,374,375,375,376,376,377,377,378,378, + 379,379,380,380,381,381,382,382,383,383,384,384,385,385,386,386,387,387, + 388,388,389,389,390,390,391,391,392,392,393,393,394,394,395,395,396,396, + 397,397,398,398,399,399,400,400,401,401,402,402,403,403,404,404,405,405, + 406,406,407,407,408,408,409,409,410,410,411,411,412,412,413,413,414,414, + 415,415,416,416,417,417,418,418,419,419,420,420,421,421,422,422,423,423, + 424,424,425,425,426,426,427,427,428,428,429,429,430,430,431,431,432,432, + 433,433,434,434,435,435,436,436,437,437,438,438,439,439,440,440,441,441, + 442,442,443,443,444,444,445,445,446,446,447,447,448,448,449,449,450,450, + 451,451,452,452,453,453,454,454,455,455,456,456,457,457,458,458,459,459, + 460,460,461,461,462,462,463,463,464,464,465,465,466,466,467,467,468,468, + 469,469,470,470,471,471,472,472,473,473,474,474,475,475,476,476,477,477, + 478,478,479,479,480,480,481,481,482,482,483,483,484,484,485,485,486,486, + 487,487,488,488,489,489,490,490,491,491,492,492,493,493,494,494,495,495, + 496,496,497,497,498,498,499,499,500,500,501,501,502,502,503,503,504,504, + 505,505,506,506,507,507,508,508,509,509,510,510,511,511,512,512,513,513, + 514,514,515,515,516,516,517,517,518,518,519,519,520,520,521,521,522,522, + 523,523,524,524,525,525,526,526,527,527,528,528,529,529,530,530,531,531, + 532,532,533,533,534,534,535,535,536,536,537,537,538,538,539,539,540,540, + 541,541,542,542,543,543,544,544,545,545,546,546,547,547,548,548,549,549, + 550,550,551,551,552,552,553,553,554,554,555,555,556,556,557,557,558,558, + 559,559,560,560,561,561,562,562,563,563,564,564,565,565,566,566,567,567, + 568,568,569,569,570,570,571,571,572,572,573,573,574,574,575,575,576,576, + 577,577,578,578,579,579,580,580,581,581,582,582,583,583,584,584,585,585, + 586,586,587,587,588,588,589,589,590,590,591,591,592,592,593,593,594,594, + 595,595,596,596,597,597,598,598,599,599,600,600], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, + 28, 29, 29, 30, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, + 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, + 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, + 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 63, 64, 64, 65, 65, 66, + 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, + 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, + 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, + 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99,100,100,101,101,102,102,103, + 103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112, + 112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121, + 121,122,122,123,123,124,125,126,126,127,127,128,128,129,129,130,130,131, + 131,132,132,133,133,134,134,135,135,136,136,137,137,138,138,139,139,140, + 140,141,141,142,142,143,143,144,144,145,145,146,146,147,147,148,148,149, + 149,150,150,151,151,152,152,153,153,154,154,155,156,157,157,158,158,159, + 159,160,160,161,161,162,162,163,163,164,164,165,165,166,166,167,167,168, + 168,169,169,170,170,171,171,172,172,173,173,174,174,175,175,176,176,177, + 177,178,178,179,179,180,180,181,181,182,182,183,183,184,184,185,185,186, + 187,188,188,189,189,190,190,191,191,192,192,193,193,194,194,195,195,196, + 196,197,197,198,198,199,199,200,200,201,201,202,202,203,203,204,204,205, + 205,206,206,207,207,208,208,209,209,210,210,211,211,212,212,213,213,214, + 214,215,215,216,216,217,218,219,219,220,220,221,221,222,222,223,223,224, + 224,225,225,226,226,227,227,228,228,229,229,230,230,231,231,232,232,233, + 233,234,234,235,235,236,236,237,237,238,238,239,239,240,240,241,241,242, + 242,243,243,244,244,245,245,246,246,247,247,248,249,250,250,251,251,252, + 252,253,253,254,254,255,255,256,256,257,257,258,258,259,259,260,260,261, + 261,262,262,263,263,264,264,265,265,266,266,267,267,268,268,269,269,270, + 270,271,271,272,272,273,273,274,274,275,275,276,276,277,277,278,278,279, + 280,281,281,282,282,283,283,284,284,285,285,286,286,287,287,288,288,289, + 289,290,290,291,291,292,292,293,293,294,294,295,295,296,296,297,297,298, + 298,299,299,300,300,301,301,302,302,303,303,304,304,305,305,306,306,307, + 307,308,308,309,309,310,311,312,312,313,313,314,314,315,315,316,316,317, + 317,318,318,319,319,320,320,321,321,322,322,323,323,324,324,325,325,326, + 326,327,327,328,328,329,329,330,330,331,331,332,332,333,333,334,334,335, + 335,336,336,337,337,338,338,339,339,340,340,341,342,343,343,344,344,345, + 345,346,346,347,347,348,348,349,349,350,350,351,351,352,352,353,353,354, + 354,355,355,356,356,357,357,358,358,359,359,360,360,361,361,362,362,363, + 363,364,364,365,365,366,366,367,367,368,368,369,369,370,370,371,371,372, + 373,374,374,375,375,376,376,377,377,378,378,379,379,380,380,381,381,382, + 382,383,383,384,384,385,385,386,386,387,387,388,388,389,389,390,390,391, + 391,392,392,393,393,394,394,395,395,396,396,397,397,398,398,399,399,400, + 400,401,401,402,402,403,404,405,405,406,406,407,407,408,408,409,409,410, + 410,411,411,412,412,413,413,414,414,415,415,416,416,417,417,418,418,419, + 419,420,420,421,421,422,422,423,423,424,424,425,425,426,426,427,427,428, + 428,429,429,430,430,431,431,432,432,433,433,434,435,436,436,437,437,438, + 438,439,439,440,440,441,441,442,442,443,443,444,444,445,445,446,446,447, + 447,448,448,449,449,450,450,451,451,452,452,453,453,454,454,455,455,456, + 456,457,457,458,458,459,459,460,460,461,461,462,462,463,463,464,464,465, + 466,467,467,468,468,469,469,470,470,471,471,472,472,473,473,474,474,475, + 475,476,476,477,477,478,478,479,479,480,480,481,481,482,482,483,483,484, + 484,485,485,486,486,487,487,488,488,489,489,490,490,491,491,492,492,493, + 493,494,494,495,495,496,497,498,498,499,499,500,500,501,501,502,502,503, + 503,504,504,505,505,506,506,507,507,508,508,509,509,510,510,511,511,512, + 512,513,513,514,514,515,515,516,516,517,517,518,518,519,519,520,520,521, + 521,522,522,523,523,524,524,525,525,526,526,527,528,529,529,530,530,531, + 531,532,532,533,533,534,534,535,535,536,536,537,537,538,538,539,539,540, + 540,541,541,542,542,543,543,544,544,545,545,546,546,547,547,548,548,549, + 549,550,550,551,551,552,552,553,553,554,554,555,555,556,556,557,557,558, + 559,560,560,561,561,562,562,563,563,564,564,565,565,566,566,567,567,568, + 568,569,569,570,570,571,571,572,572,573,573,574,574,575,575,576,576,577, + 577,578,578,579,579,580,580,581,581,582,582,583,583,584,584,585,585,586, + 586,587,587,588,588,589,590,591,591,592,592,593,593,594,594,595,595,596, + 596,597,597,598,598,599,599,600,600,601,601,602,602,603,603,604,604,605, + 605,606,606,607,607,608,608,609,609,610,610,611,611,612,612,613,613,614, + 614,615,615,616,616,617,617,618,618,619,619,620], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.], 600, 620), + const_m6370830283027149840 = [0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, + 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, + 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, + 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, + 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, + 1. ,0. ,0.00111111,0.00444444,0.01 ,0.01777778, + 0.02777778,0.04 ,0.05444444,0.07111111,0.09 ,0.11111111, + 0.13444444,0.16 ,0.18777778,0.21777778,0.25 ,0.28444444, + 0.32111111,0.36 ,0.40111111,0.44444444,0.49 ,0.53777778, + 0.58777778,0.64 ,0.69444444,0.75111111,0.81 ,0.87111111, + 0.93444444,1. ,0. ,0.00111111,0.00444444,0.01 , + 0.01777778,0.02777778,0.04 ,0.05444444,0.07111111,0.09 , + 0.11111111,0.13444444,0.16 ,0.18777778,0.21777778,0.25 , + 0.28444444,0.32111111,0.36 ,0.40111111,0.44444444,0.49 , + 0.53777778,0.58777778,0.64 ,0.69444444,0.75111111,0.81 , + 0.87111111,0.93444444,1. ,0. ,0.00111111,0.00444444, + 0.01 ,0.01777778,0.02777778,0.04 ,0.05444444,0.07111111, + 0.09 ,0.11111111,0.13444444,0.16 ,0.18777778,0.21777778, + 0.25 ,0.28444444,0.32111111,0.36 ,0.40111111,0.44444444, + 0.49 ,0.53777778,0.58777778,0.64 ,0.69444444,0.75111111, + 0.81 ,0.87111111,0.93444444,1. ,0. ,0.00111111, + 0.00444444,0.01 ,0.01777778,0.02777778,0.04 ,0.05444444, + 0.07111111,0.09 ,0.11111111,0.13444444,0.16 ,0.18777778, + 0.21777778,0.25 ,0.28444444,0.32111111,0.36 ,0.40111111, + 0.44444444,0.49 ,0.53777778,0.58777778,0.64 ,0.69444444, + 0.75111111,0.81 ,0.87111111,0.93444444,1. ,0. , + 0.00111111,0.00444444,0.01 ,0.01777778,0.02777778,0.04 , + 0.05444444,0.07111111,0.09 ,0.11111111,0.13444444,0.16 , + 0.18777778,0.21777778,0.25 ,0.28444444,0.32111111,0.36 , + 0.40111111,0.44444444,0.49 ,0.53777778,0.58777778,0.64 , + 0.69444444,0.75111111,0.81 ,0.87111111,0.93444444,1. , + 0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, + 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, + 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, + 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, + 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, + 1. ,0. ,0.00111111,0.00444444,0.01 ,0.01777778, + 0.02777778,0.04 ,0.05444444,0.07111111,0.09 ,0.11111111, + 0.13444444,0.16 ,0.18777778,0.21777778,0.25 ,0.28444444, + 0.32111111,0.36 ,0.40111111,0.44444444,0.49 ,0.53777778, + 0.58777778,0.64 ,0.69444444,0.75111111,0.81 ,0.87111111, + 0.93444444,1. ,0. ,0.00111111,0.00444444,0.01 , + 0.01777778,0.02777778,0.04 ,0.05444444,0.07111111,0.09 , + 0.11111111,0.13444444,0.16 ,0.18777778,0.21777778,0.25 , + 0.28444444,0.32111111,0.36 ,0.40111111,0.44444444,0.49 , + 0.53777778,0.58777778,0.64 ,0.69444444,0.75111111,0.81 , + 0.87111111,0.93444444,1. ,0. ,0.00111111,0.00444444, + 0.01 ,0.01777778,0.02777778,0.04 ,0.05444444,0.07111111, + 0.09 ,0.11111111,0.13444444,0.16 ,0.18777778,0.21777778, + 0.25 ,0.28444444,0.32111111,0.36 ,0.40111111,0.44444444, + 0.49 ,0.53777778,0.58777778,0.64 ,0.69444444,0.75111111, + 0.81 ,0.87111111,0.93444444,1. ,0. ,0.00111111, + 0.00444444,0.01 ,0.01777778,0.02777778,0.04 ,0.05444444, + 0.07111111,0.09 ,0.11111111,0.13444444,0.16 ,0.18777778, + 0.21777778,0.25 ,0.28444444,0.32111111,0.36 ,0.40111111, + 0.44444444,0.49 ,0.53777778,0.58777778,0.64 ,0.69444444, + 0.75111111,0.81 ,0.87111111,0.93444444,1. ,0. , + 0.00111111,0.00444444,0.01 ,0.01777778,0.02777778,0.04 , + 0.05444444,0.07111111,0.09 ,0.11111111,0.13444444,0.16 , + 0.18777778,0.21777778,0.25 ,0.28444444,0.32111111,0.36 , + 0.40111111,0.44444444,0.49 ,0.53777778,0.58777778,0.64 , + 0.69444444,0.75111111,0.81 ,0.87111111,0.93444444,1. , + 0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, + 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, + 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, + 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, + 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, + 1. ,0. ,0.00111111,0.00444444,0.01 ,0.01777778, + 0.02777778,0.04 ,0.05444444,0.07111111,0.09 ,0.11111111, + 0.13444444,0.16 ,0.18777778,0.21777778,0.25 ,0.28444444, + 0.32111111,0.36 ,0.40111111,0.44444444,0.49 ,0.53777778, + 0.58777778,0.64 ,0.69444444,0.75111111,0.81 ,0.87111111, + 0.93444444,1. ,0. ,0.00111111,0.00444444,0.01 , + 0.01777778,0.02777778,0.04 ,0.05444444,0.07111111,0.09 , + 0.11111111,0.13444444,0.16 ,0.18777778,0.21777778,0.25 , + 0.28444444,0.32111111,0.36 ,0.40111111,0.44444444,0.49 , + 0.53777778,0.58777778,0.64 ,0.69444444,0.75111111,0.81 , + 0.87111111,0.93444444,1. ,0. ,0.00111111,0.00444444, + 0.01 ,0.01777778,0.02777778,0.04 ,0.05444444,0.07111111, + 0.09 ,0.11111111,0.13444444,0.16 ,0.18777778,0.21777778, + 0.25 ,0.28444444,0.32111111,0.36 ,0.40111111,0.44444444, + 0.49 ,0.53777778,0.58777778,0.64 ,0.69444444,0.75111111, + 0.81 ,0.87111111,0.93444444,1. ,0. ,0.00111111, + 0.00444444,0.01 ,0.01777778,0.02777778,0.04 ,0.05444444, + 0.07111111,0.09 ,0.11111111,0.13444444,0.16 ,0.18777778, + 0.21777778,0.25 ,0.28444444,0.32111111,0.36 ,0.40111111, + 0.44444444,0.49 ,0.53777778,0.58777778,0.64 ,0.69444444, + 0.75111111,0.81 ,0.87111111,0.93444444,1. ,0. , + 0.00111111,0.00444444,0.01 ,0.01777778,0.02777778,0.04 , + 0.05444444,0.07111111,0.09 ,0.11111111,0.13444444,0.16 , + 0.18777778,0.21777778,0.25 ,0.28444444,0.32111111,0.36 , + 0.40111111,0.44444444,0.49 ,0.53777778,0.58777778,0.64 , + 0.69444444,0.75111111,0.81 ,0.87111111,0.93444444,1. , + 0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, + 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, + 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, + 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, + 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, + 1. ,0. ,0.00111111,0.00444444,0.01 ,0.01777778, + 0.02777778,0.04 ,0.05444444,0.07111111,0.09 ,0.11111111, + 0.13444444,0.16 ,0.18777778,0.21777778,0.25 ,0.28444444, + 0.32111111,0.36 ,0.40111111,0.44444444,0.49 ,0.53777778, + 0.58777778,0.64 ,0.69444444,0.75111111,0.81 ,0.87111111, + 0.93444444,1. ], + const_5256068128236031296 = [-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.], + const_m810426824042609992 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 95, 96, 97, + 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115, + 116,117,118,119,120,121,122,123,126,127,128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153, + 154,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173, + 174,175,176,177,178,179,180,181,182,183,184,185,188,189,190,191,192,193, + 194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211, + 212,213,214,215,216,219,220,221,222,223,224,225,226,227,228,229,230,231, + 232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,250,251, + 252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269, + 270,271,272,273,274,275,276,277,278,281,282,283,284,285,286,287,288,289, + 290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307, + 308,309,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327, + 328,329,330,331,332,333,334,335,336,337,338,339,340,343,344,345,346,347, + 348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365, + 366,367,368,369,370,371,374,375,376,377,378,379,380,381,382,383,384,385, + 386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,405, + 406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423, + 424,425,426,427,428,429,430,431,432,433,436,437,438,439,440,441,442,443, + 444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461, + 462,463,464,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481, + 482,483,484,485,486,487,488,489,490,491,492,493,494,495,498,499,500,501, + 502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519, + 520,521,522,523,524,525,526,529,530,531,532,533,534,535,536,537,538,539, + 540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557, + 560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577, + 578,579,580,581,582,583,584,585,586,587,588,591,592,593,594,595,596,597, + 598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615, + 616,617,618,619], [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108, + 109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126, + 127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144, + 145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162, + 163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180, + 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198, + 199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216, + 217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234, + 235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252, + 253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270, + 271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288, + 289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306, + 307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324, + 325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342, + 343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360, + 361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378, + 379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396, + 397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414, + 415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432, + 433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450, + 451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468, + 469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486, + 487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504, + 505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522, + 523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540, + 541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558, + 559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576, + 577,578,579,580], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.], 620, 580), + const_m3854548607110444668 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, + 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, + 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, + 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, + 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, + 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, + 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, + 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, + 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, + 100,100,101,101,102,102,103,103,104,104,105,105,106,106,107,107,108,108, + 109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117, + 118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126, + 127,127,128,128,129,129,130,130,131,131,132,132,133,133,134,134,135,135, + 136,136,137,137,138,138,139,139,140,140,141,141,142,142,143,143,144,144, + 145,145,146,146,147,147,148,148,149,149,150,150,151,151,152,152,153,153, + 154,154,155,155,156,156,157,157,158,158,159,159,160,160,161,161,162,162, + 163,163,164,164,165,165,166,166,167,167,168,168,169,169,170,170,171,171, + 172,172,173,173,174,174,175,175,176,176,177,177,178,178,179,179,180,180, + 181,181,182,182,183,183,184,184,185,185,186,186,187,187,188,188,189,189, + 190,190,191,191,192,192,193,193,194,194,195,195,196,196,197,197,198,198, + 199,199,200,200,201,201,202,202,203,203,204,204,205,205,206,206,207,207, + 208,208,209,209,210,210,211,211,212,212,213,213,214,214,215,215,216,216, + 217,217,218,218,219,219,220,220,221,221,222,222,223,223,224,224,225,225, + 226,226,227,227,228,228,229,229,230,230,231,231,232,232,233,233,234,234, + 235,235,236,236,237,237,238,238,239,239,240,240,241,241,242,242,243,243, + 244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252, + 253,253,254,254,255,255,256,256,257,257,258,258,259,259,260,260,261,261, + 262,262,263,263,264,264,265,265,266,266,267,267,268,268,269,269,270,270, + 271,271,272,272,273,273,274,274,275,275,276,276,277,277,278,278,279,279, + 280,280,281,281,282,282,283,283,284,284,285,285,286,286,287,287,288,288, + 289,289,290,290,291,291,292,292,293,293,294,294,295,295,296,296,297,297, + 298,298,299,299,300,300,301,301,302,302,303,303,304,304,305,305,306,306, + 307,307,308,308,309,309,310,310,311,311,312,312,313,313,314,314,315,315, + 316,316,317,317,318,318,319,319,320,320,321,321,322,322,323,323,324,324, + 325,325,326,326,327,327,328,328,329,329,330,330,331,331,332,332,333,333, + 334,334,335,335,336,336,337,337,338,338,339,339,340,340,341,341,342,342, + 343,343,344,344,345,345,346,346,347,347,348,348,349,349,350,350,351,351, + 352,352,353,353,354,354,355,355,356,356,357,357,358,358,359,359,360,360, + 361,361,362,362,363,363,364,364,365,365,366,366,367,367,368,368,369,369, + 370,370,371,371,372,372,373,373,374,374,375,375,376,376,377,377,378,378, + 379,379,380,380,381,381,382,382,383,383,384,384,385,385,386,386,387,387, + 388,388,389,389,390,390,391,391,392,392,393,393,394,394,395,395,396,396, + 397,397,398,398,399,399,400,400,401,401,402,402,403,403,404,404,405,405, + 406,406,407,407,408,408,409,409,410,410,411,411,412,412,413,413,414,414, + 415,415,416,416,417,417,418,418,419,419,420,420,421,421,422,422,423,423, + 424,424,425,425,426,426,427,427,428,428,429,429,430,430,431,431,432,432, + 433,433,434,434,435,435,436,436,437,437,438,438,439,439,440,440,441,441, + 442,442,443,443,444,444,445,445,446,446,447,447,448,448,449,449,450,450, + 451,451,452,452,453,453,454,454,455,455,456,456,457,457,458,458,459,459, + 460,460,461,461,462,462,463,463,464,464,465,465,466,466,467,467,468,468, + 469,469,470,470,471,471,472,472,473,473,474,474,475,475,476,476,477,477, + 478,478,479,479,480,480,481,481,482,482,483,483,484,484,485,485,486,486, + 487,487,488,488,489,489,490,490,491,491,492,492,493,493,494,494,495,495, + 496,496,497,497,498,498,499,499,500,500,501,501,502,502,503,503,504,504, + 505,505,506,506,507,507,508,508,509,509,510,510,511,511,512,512,513,513, + 514,514,515,515,516,516,517,517,518,518,519,519,520,520,521,521,522,522, + 523,523,524,524,525,525,526,526,527,527,528,528,529,529,530,530,531,531, + 532,532,533,533,534,534,535,535,536,536,537,537,538,538,539,539,540,540, + 541,541,542,542,543,543,544,544,545,545,546,546,547,547,548,548,549,549, + 550,550,551,551,552,552,553,553,554,554,555,555,556,556,557,557,558,558, + 559,559,560,560,561,561,562,562,563,563,564,564,565,565,566,566,567,567, + 568,568,569,569,570,570,571,571,572,572,573,573,574,574,575,575,576,576, + 577,577,578,578,579,579,580,580], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, + 28, 29, 29, 30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, + 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, + 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, + 56, 57, 57, 58, 58, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, + 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, + 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, + 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 91, 92, 92, 93, 93, 94, + 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99,100,100,101,101,102,102,103, + 103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112, + 112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,121,122, + 122,123,123,124,124,125,125,126,126,127,127,128,128,129,129,130,130,131, + 131,132,132,133,133,134,134,135,135,136,136,137,137,138,138,139,139,140, + 140,141,141,142,142,143,143,144,144,145,145,146,146,147,147,148,148,149, + 149,150,151,152,152,153,153,154,154,155,155,156,156,157,157,158,158,159, + 159,160,160,161,161,162,162,163,163,164,164,165,165,166,166,167,167,168, + 168,169,169,170,170,171,171,172,172,173,173,174,174,175,175,176,176,177, + 177,178,178,179,179,180,181,182,182,183,183,184,184,185,185,186,186,187, + 187,188,188,189,189,190,190,191,191,192,192,193,193,194,194,195,195,196, + 196,197,197,198,198,199,199,200,200,201,201,202,202,203,203,204,204,205, + 205,206,206,207,207,208,208,209,209,210,211,212,212,213,213,214,214,215, + 215,216,216,217,217,218,218,219,219,220,220,221,221,222,222,223,223,224, + 224,225,225,226,226,227,227,228,228,229,229,230,230,231,231,232,232,233, + 233,234,234,235,235,236,236,237,237,238,238,239,239,240,241,242,242,243, + 243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252, + 252,253,253,254,254,255,255,256,256,257,257,258,258,259,259,260,260,261, + 261,262,262,263,263,264,264,265,265,266,266,267,267,268,268,269,269,270, + 271,272,272,273,273,274,274,275,275,276,276,277,277,278,278,279,279,280, + 280,281,281,282,282,283,283,284,284,285,285,286,286,287,287,288,288,289, + 289,290,290,291,291,292,292,293,293,294,294,295,295,296,296,297,297,298, + 298,299,299,300,301,302,302,303,303,304,304,305,305,306,306,307,307,308, + 308,309,309,310,310,311,311,312,312,313,313,314,314,315,315,316,316,317, + 317,318,318,319,319,320,320,321,321,322,322,323,323,324,324,325,325,326, + 326,327,327,328,328,329,329,330,331,332,332,333,333,334,334,335,335,336, + 336,337,337,338,338,339,339,340,340,341,341,342,342,343,343,344,344,345, + 345,346,346,347,347,348,348,349,349,350,350,351,351,352,352,353,353,354, + 354,355,355,356,356,357,357,358,358,359,359,360,361,362,362,363,363,364, + 364,365,365,366,366,367,367,368,368,369,369,370,370,371,371,372,372,373, + 373,374,374,375,375,376,376,377,377,378,378,379,379,380,380,381,381,382, + 382,383,383,384,384,385,385,386,386,387,387,388,388,389,389,390,391,392, + 392,393,393,394,394,395,395,396,396,397,397,398,398,399,399,400,400,401, + 401,402,402,403,403,404,404,405,405,406,406,407,407,408,408,409,409,410, + 410,411,411,412,412,413,413,414,414,415,415,416,416,417,417,418,418,419, + 419,420,421,422,422,423,423,424,424,425,425,426,426,427,427,428,428,429, + 429,430,430,431,431,432,432,433,433,434,434,435,435,436,436,437,437,438, + 438,439,439,440,440,441,441,442,442,443,443,444,444,445,445,446,446,447, + 447,448,448,449,449,450,451,452,452,453,453,454,454,455,455,456,456,457, + 457,458,458,459,459,460,460,461,461,462,462,463,463,464,464,465,465,466, + 466,467,467,468,468,469,469,470,470,471,471,472,472,473,473,474,474,475, + 475,476,476,477,477,478,478,479,479,480,481,482,482,483,483,484,484,485, + 485,486,486,487,487,488,488,489,489,490,490,491,491,492,492,493,493,494, + 494,495,495,496,496,497,497,498,498,499,499,500,500,501,501,502,502,503, + 503,504,504,505,505,506,506,507,507,508,508,509,509,510,511,512,512,513, + 513,514,514,515,515,516,516,517,517,518,518,519,519,520,520,521,521,522, + 522,523,523,524,524,525,525,526,526,527,527,528,528,529,529,530,530,531, + 531,532,532,533,533,534,534,535,535,536,536,537,537,538,538,539,539,540, + 541,542,542,543,543,544,544,545,545,546,546,547,547,548,548,549,549,550, + 550,551,551,552,552,553,553,554,554,555,555,556,556,557,557,558,558,559, + 559,560,560,561,561,562,562,563,563,564,564,565,565,566,566,567,567,568, + 568,569,569,570,571,572,572,573,573,574,574,575,575,576,576,577,577,578, + 578,579,579,580,580,581,581,582,582,583,583,584,584,585,585,586,586,587, + 587,588,588,589,589,590,590,591,591,592,592,593,593,594,594,595,595,596, + 596,597,597,598,598,599,599,600], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., + -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.], 580, 600), + const_419985987929628265 = sparse([ 31, 62, 93,124,155,186,217,248,279,310,341,372,403,434,465,496,527,558, + 589,620], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 620, 20), + const_m9126168015536320261 = [2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05, + 2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05], + const_83118777604549222 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20], [ 29, 30, 59, 60, 89, 90,119,120,149,150,179,180,209,210,239,240,269,270, + 299,300,329,330,359,360,389,390,419,420,449,450,479,480,509,510,539,540, + 569,570,599,600], [-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5, + -0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5, + -0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5], 20, 600), + const_1845266373960578514 = [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, + 0.5,0.5], + const_6438113274932828980 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], + const_6284853627393591686 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], + const_844432128953615761 = [-22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, + -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935], + const_3206463238628087733 = [-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.], + const_7674564103979747454 = [6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07, + 6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07], + const_1237538932840516848 = [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, + 0.5,0.5], + const_m8218000856912416174 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], + const_m8371260504451653468 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], + const_5356335722306557041 = [3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, + 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, + 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, + 3.33333333,3.33333333,1. ,1. ,1. ,1. , + 1. ,1. ,1. ,1. ,1. ,1. , + 1. ,1. ,1. ,1. ,1. ,1. , + 1. ,1. ,1. ,1. ,3.33333333,3.33333333, + 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, + 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, + 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333], + const_2155620181971259577 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, + 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36, + 37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48, + 49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,60], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, + 25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36,37, + 37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49, + 49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,60,61], [ -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45.,-180., 180.,-180., 180.,-180., 180.,-180., 180., + -180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180., + -180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180., + -180., 180.,-180., 180.,-180., 180.,-180., 180., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45.], 60, 61), + const_m6406009788656677430 = sparse([ 1, 1,61,61], [ 1, 2,59,60], [ 1.5,-0.5,-0.5, 1.5], 61, 60), + const_4910271190053899160 = [-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, + -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, + -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, + -0.16431677,-0.16431677,-1. ,-1. ,-1. ,-1. , + -1. ,-1. ,-1. ,-1. ,-1. ,-1. , + -1. ,-1. ,-1. ,-1. ,-1. ,-1. , + -1. ,-1. ,-1. ,-1. ,-0.16431677,-0.16431677, + -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, + -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, + -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677], + const_m1615735228018878911 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], + const_m2239172306025069482 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, + 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49, + 50,51,52,53,54,55,56,57,58,59,60], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, + 49,50,51,52,53,54,55,56,57,58,59], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 61, 59), + const_7492635389435296866 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, + 49,50,51,52,53,54,55,56,57,58,59], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, + 49,50,51,52,53,54,55,56,57,58,59], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 59, 60), + const_m2551856243850624398 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, + 49,50,51,52,53,54,55,56,57,58,59], [ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, + 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49, + 50,51,52,53,54,55,56,57,58,59,60], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 59, 60), + const_8229859839001814964 = [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, + 0.5,0.8,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, + 0.5,0.5,0.5,0.2,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, + 0.5,0.5,0.5,0.5,0.5], + const_m8826988669266821604 = [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, + 0.5,0.2,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, + 0.5,0.5,0.5,0.8,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, + 0.5,0.5,0.5,0.5,0.5], + const_4742260312915039474 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, + 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36, + 37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48, + 49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, + 25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36,37, + 37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49, + 49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60], [ -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -72., 72.,-180., 180.,-180., 180.,-180., 180.,-180., 180., + -180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180., + -180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180., + -180., 180.,-180., 180.,-180., 180., -72., 72., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., + -45., 45., -45., 45., -45., 45., -45., 45., -45., 45.], 59, 60), + const_m344729034815622734 = [0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, + 0.00321435], + const_4022673044584674996 = sparse([ 1, 2, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, + 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36, + 37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48, + 49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,61, + 60,61], [ 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24, + 24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36, + 36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48, + 48,49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,59, + 60,60], [ 1.5, 0.5,-0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,-0.5, 0.5, 1.5], 61, 60), + const_1871829889889080582 = [0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, + 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, + 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, + 0.16431677,0.16431677,1. ,1. ,1. ,1. , + 1. ,1. ,1. ,1. ,1. ,1. , + 1. ,1. ,1. ,1. ,1. ,1. , + 1. ,1. ,1. ,1. ,0.16431677,0.16431677, + 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, + 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, + 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677], + const_m6293037495340517372 = [1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2, + 1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2, + 1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2, + 1.2,1.2,1.2,1.2,1.2,1.2,1.2], + const_7749124486072430752 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], + const_2100260670751548208 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], + const_m3704159319882291581 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], + const_2673546356631690987 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], + const_9168352019723563689 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21], [-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45., + -45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45., + -45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.], 20, 21), + const_m4831381568644549996 = [-221.12651346,-221.12651346,-221.12651346,-221.12651346,-221.12651346, + -221.12651346,-221.12651346,-221.12651346,-221.12651346,-221.12651346, + -221.12651346,-221.12651346,-221.12651346,-221.12651346,-221.12651346, + -221.12651346,-221.12651346,-221.12651346,-221.12651346,-221.12651346, + -221.12651346], + const_m6337143657829181592 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 21, 20), + const_1509603028080037696 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21], [ 1, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [-1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1.], 21, 20), + const_m1453791953686693439 = [-16.82166382,-16.82166382,-16.82166382,-16.82166382,-16.82166382, + -16.82166382,-16.82166382,-16.82166382,-16.82166382,-16.82166382, + -16.82166382,-16.82166382,-16.82166382,-16.82166382,-16.82166382, + -16.82166382,-16.82166382,-16.82166382,-16.82166382,-16.82166382, + -16.82166382], + const_m6076020440529072554 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 21, 19), + const_6715966457835164428 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, + 13,13,14,14,15,15,16,16,17,17,18,18,19,19], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,16,16,17,17,18,18,19,19,20], [-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45., + -45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45., + -45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.], 19, 20), + const_8366588851195495623 = [ 0. , 0. , 0. , 0. , 0. , 0. , + 0. , 0. , 0. , 0. , 0. , 0. , + 0. , 0. , 0. , 0. , 0. , 0. , + 0. , 0. ,-0.05944715], + const_m2268798281525233596 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], + cache_m8690271296156904125 = zeros(580), + cache_7735162028737694396 = zeros(620), + cache_m4432716267967134655 = zeros(20), + cache_1416156281203053579 = zeros(20), + cache_3837998097161001762 = zeros(620), + cache_m2349735126975898980 = zeros(620), + cache_3559064883010407825 = zeros(600), + cache_m5236042054648721177 = zeros(580), + cache_4552822235374881625 = zeros(620), + cache_6385594400131391611 = zeros(20), + cache_3669255876411325857 = zeros(20), + cache_m5979984690307217085 = zeros(620), + cache_4085014493431324638 = zeros(620), + cache_m4186862615729982588 = zeros(600), + cache_7729892376240732805 = zeros(60), + cache_m5983176047089085323 = zeros(60), + cache_m7220358040310595472 = zeros(61), + cache_2958147717725554841 = zeros(59), + cache_6584089953429348159 = zeros(59), + cache_m2205063840212872182 = zeros(59), + cache_774339592884572080 = zeros(61), + cache_956044674773232170 = zeros(59), + cache_m1168385265453438253 = zeros(61), + cache_7084643733393507988 = zeros(60), + cache_6377132265167146240 = zeros(61), + cache_m6244145936812788240 = zeros(61), + cache_1105677131701825845 = zeros(60), + cache_m4559336614180109070 = zeros(59), + cache_5964596193839440387 = zeros(61), + cache_6730866441417284015 = zeros(61), + cache_6453636296210224079 = zeros(60), + cache_m7958094614900297101 = zeros(61), + cache_8188036567708323486 = zeros(61), + cache_m6645337912123003706 = zeros(60), + cache_m1572333326302305327 = zeros(60), + cache_4444843852540613429 = zeros(60), + cache_8316190851790556232 = zeros(1261), + cache_6281528158126438668 = zeros(21), + cache_244133575886292095 = zeros(20), + cache_1480199951838108910 = zeros(21), + cache_m8825037627629645404 = zeros(21), + cache_m4463903973878375467 = zeros(20), + cache_m5204106969040429111 = zeros(19), + cache_m8118013018143870756 = zeros(21), + cache_7899744126569850954 = zeros(21), + cache_m8486204412392847702 = zeros(20), + cache_6953277061565774920 = zeros(60), + cache_7545625011893614278 = zeros(100),) + + function f_with_consts(dy, y, p, t) + mul!(cs.cache_m8690271296156904125, cs.const_m3854548607110444668, (@view y[2:601])) + mul!(cs.cache_7735162028737694396, cs.const_m810426824042609992, cs.cache_m8690271296156904125) + mul!(cs.cache_m4432716267967134655, cs.const_83118777604549222, (@view y[2:601])) + cs.cache_1416156281203053579 .= (((-0.11346284738694776 .* ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725))))))) .* cs.const_6284853627393591686) ./ 1.7999999999999998) ./ cs.const_6284853627393591686 + mul!(cs.cache_3837998097161001762, cs.const_419985987929628265, cs.cache_1416156281203053579) + cs.cache_m2349735126975898980 .= cs.const_m6370830283027149840 .* (cs.const_5256068128236031296 .* (cs.cache_7735162028737694396 .+ cs.cache_3837998097161001762)) + mul!(cs.cache_3559064883010407825, cs.const_1477443756317609848, cs.cache_m2349735126975898980) + mul!(cs.cache_m5236042054648721177, cs.const_m3854548607110444668, (@view y[602:1201])) + mul!(cs.cache_4552822235374881625, cs.const_m810426824042609992, cs.cache_m5236042054648721177) + mul!(cs.cache_6385594400131391611, cs.const_83118777604549222, (@view y[602:1201])) + cs.cache_3669255876411325857 .= ((((-0.04425051048090962 .* ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725))))))) .* cs.const_m8371260504451653468) ./ 1.5000000000000002) ./ 2.05008960573477) ./ cs.const_m8371260504451653468 + mul!(cs.cache_m5979984690307217085, cs.const_419985987929628265, cs.cache_3669255876411325857) + cs.cache_4085014493431324638 .= cs.const_m6370830283027149840 .* (cs.const_3206463238628087733 .* (cs.cache_4552822235374881625 .+ cs.cache_m5979984690307217085)) + mul!(cs.cache_m4186862615729982588, cs.const_1477443756317609848, cs.cache_4085014493431324638) + cs.cache_7729892376240732805[1:20] .= (@view y[1202:1221]) + cs.cache_7729892376240732805[21:40] .= (@view y[1222:1241]) + cs.cache_7729892376240732805[41:60] .= (@view y[1242:1261]) + cs.cache_m5983176047089085323 .= cs.const_4910271190053899160 .* (((5.34e-10 .* (exp.(((-0.65 .* (cs.cache_7729892376240732805 .* 1000.0)) ./ 1000.0)))) .* cs.const_m1615735228018878911) ./ 2.7877244479038255e-10) + mul!(cs.cache_m7220358040310595472, cs.const_m6406009788656677430, cs.cache_m5983176047089085323) + mul!(cs.cache_2958147717725554841, cs.const_7492635389435296866, cs.cache_m5983176047089085323) + mul!(cs.cache_6584089953429348159, cs.const_m2551856243850624398, cs.cache_m5983176047089085323) + cs.cache_m2205063840212872182 .= (cs.cache_2958147717725554841 .* cs.cache_6584089953429348159) ./ (((cs.cache_6584089953429348159 .* cs.const_8229859839001814964) .+ (cs.cache_2958147717725554841 .* cs.const_m8826988669266821604)) .+ 1e-16) + mul!(cs.cache_774339592884572080, cs.const_m2239172306025069482, cs.cache_m2205063840212872182) + mul!(cs.cache_956044674773232170, cs.const_4742260312915039474, cs.cache_7729892376240732805) + mul!(cs.cache_m1168385265453438253, cs.const_m2239172306025069482, cs.cache_956044674773232170) + cs.cache_7084643733393507988 .= (((((((0.0911 .+ (1.9101 .* ((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0).^2.0))) .+ (0.1554 .* (((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0).^3.0))) .* cs.const_m1615735228018878911) ./ 1.0468957512717258) .* cs.const_1871829889889080582) .* 0.04002679875215723) ./ 0.008035880643729008 + mul!(cs.cache_6377132265167146240, cs.const_4022673044584674996, cs.cache_7084643733393507988) + mul!(cs.cache_m6244145936812788240, cs.const_4022673044584674996, cs.cache_7729892376240732805) + cs.cache_1105677131701825845[1:20] .= (@view y[1302:1321]) + cs.cache_1105677131701825845[21:40] .= (@view y[1322:1341]) + cs.cache_1105677131701825845[41:60] .= (@view y[1342:1361]) + mul!(cs.cache_m4559336614180109070, cs.const_4742260312915039474, cs.cache_1105677131701825845) + mul!(cs.cache_5964596193839440387, cs.const_m2239172306025069482, cs.cache_m4559336614180109070) + cs.cache_6453636296210224079 .= (0.008035880643729008 .* cs.cache_7729892376240732805) .* cs.const_7749124486072430752 + mul!(cs.cache_m7958094614900297101, cs.const_4022673044584674996, cs.cache_6453636296210224079) + cs.cache_8188036567708323486 .= (((cs.cache_m7220358040310595472 .+ cs.cache_774339592884572080) .* cs.cache_m1168385265453438253) .+ ((cs.const_m344729034815622734 .* (cs.cache_6377132265167146240 .* (((cs.const_m6293037495340517372 .* cs.cache_m1168385265453438253) ./ cs.cache_m6244145936812788240) .- cs.cache_5964596193839440387))) ./ 0.04002679875215723)) .+ cs.cache_m7958094614900297101 + mul!(cs.cache_m6645337912123003706, cs.const_2155620181971259577, cs.cache_8188036567708323486) + cs.cache_m1572333326302305327 .= -cs.cache_m6645337912123003706 + cs.cache_4444843852540613429[1:20] .= ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725)))))) + cs.cache_4444843852540613429[21:40] .= cs.const_2673546356631690987 + cs.cache_4444843852540613429[41:60] .= ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725)))))) + cs.cache_8316190851790556232[1:1] .= cs.const_m1032606879019717969 + cs.cache_8316190851790556232[2:601] .= (cs.const_m6466908670533079333 .* (cs.const_m919967631435488369 .* cs.cache_3559064883010407825)) + cs.cache_8316190851790556232[602:1201] .= (cs.const_844432128953615761 .* (cs.const_m919967631435488369 .* cs.cache_m4186862615729982588)) + cs.cache_8316190851790556232[1202:1261] .= (cs.const_5356335722306557041 .* ((((cs.cache_m1572333326302305327 ./ 0.008035880643729008) .+ (((cs.const_2100260670751548208 .+ (cs.const_m3704159319882291581 .* cs.cache_4444843852540613429)) .+ cs.const_2100260670751548208) ./ 0.04002679875215723)) .- (cs.cache_7729892376240732805 .* cs.const_7749124486072430752)) .- (cs.cache_7729892376240732805 .* cs.const_7749124486072430752))) + mul!(cs.cache_6281528158126438668, cs.const_1509603028080037696, (@view y[1262:1281])) + mul!(cs.cache_244133575886292095, cs.const_9168352019723563689, cs.cache_6281528158126438668) + mul!(cs.cache_1480199951838108910, cs.const_m6337143657829181592, cs.cache_244133575886292095) + cs.cache_m8825037627629645404 .= cs.const_m4831381568644549996 .* cs.cache_1480199951838108910 + mul!(cs.cache_m4463903973878375467, cs.const_9168352019723563689, cs.cache_m8825037627629645404) + mul!(cs.cache_m5204106969040429111, cs.const_6715966457835164428, (@view y[1282:1301])) + mul!(cs.cache_m8118013018143870756, cs.const_m6076020440529072554, cs.cache_m5204106969040429111) + cs.cache_7899744126569850954 .= cs.const_m1453791953686693439 .* (cs.cache_m8118013018143870756 .+ cs.const_8366588851195495623) + mul!(cs.cache_m8486204412392847702, cs.const_9168352019723563689, cs.cache_7899744126569850954) + mul!(cs.cache_6953277061565774920, cs.const_2155620181971259577, cs.cache_6730866441417284015) + cs.cache_7545625011893614278[1:20] .= (cs.cache_m4463903973878375467 .+ (cs.const_6284853627393591686 .* ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725)))))))) + cs.cache_7545625011893614278[21:40] .= (cs.cache_m8486204412392847702 .+ (cs.const_m8371260504451653468 .* ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725)))))))) + cs.cache_7545625011893614278[41:100] .= (cs.cache_6953277061565774920 .- (cs.const_m2268798281525233596 .* ((cs.const_7749124486072430752 .+ cs.cache_4444843852540613429) .+ cs.const_7749124486072430752))) + dy[1:1261] .= cs.cache_8316190851790556232 + dy[1262:1361] .= cs.cache_7545625011893614278 + end + + end +end +u0 = [ 0.00000000e+00, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, + 8.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, + 6.00000000e-01, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, + 1.00000000e+00,-5.02477561e-05,-1.47288017e-04,-2.40854214e-04, + -3.30906208e-04,-4.17382278e-04,-5.00198739e-04,-5.79249418e-04, + -6.54404992e-04,-7.25512172e-04,-7.92392744e-04,-8.54842448e-04, + -9.12629680e-04,-9.65494034e-04,-1.01314463e-03,-1.05525828e-03, + -1.09147734e-03,-1.12140750e-03,-1.14461508e-03,-1.16062427e-03, + -1.16891389e-03,-3.10835420e+00,-3.10842621e+00,-3.10856924e+00, + -3.10878237e+00,-3.10906475e+00,-3.10941558e+00,-3.10983414e+00, + -3.11031975e+00,-3.11087180e+00,-3.11148975e+00,-3.11217308e+00, + -3.11292135e+00,-3.11373418e+00,-3.11461121e+00,-3.11555215e+00, + -3.11655676e+00,-3.11762485e+00,-3.11875628e+00,-3.11995094e+00, + -3.12120879e+00,-1.44988336e-01,-1.45873084e-01,-1.47647397e-01, + -1.50321554e-01,-1.53911357e-01,-1.58438237e-01,-1.63929378e-01, + -1.70417896e-01,-1.77943041e-01,-1.86550447e-01,-1.96292417e-01, + -2.07228254e-01,-2.19424638e-01,-2.32956051e-01,-2.47905251e-01, + -2.64363809e-01,-2.82432701e-01,-3.02222966e-01,-3.23856445e-01, + -3.47466589e-01,-3.52006083e-01,-3.53063164e-01,-3.54120246e-01, + -3.55177327e-01,-3.56234409e-01,-3.57291491e-01,-3.58348572e-01, + -3.59405654e-01,-3.60462735e-01,-3.61519817e-01,-3.62576899e-01, + -3.63633980e-01,-3.64691062e-01,-3.65748143e-01,-3.66805225e-01, + -3.67862307e-01,-3.68919388e-01,-3.69976470e-01,-3.71033551e-01, + -3.72090633e-01,-3.76630126e-01,-4.00960204e-01,-4.23906866e-01, + -4.45488050e-01,-4.65720405e-01,-4.84619335e-01,-5.02199042e-01, + -5.18472566e-01,-5.33451820e-01,-5.47147616e-01,-5.59569701e-01, + -5.70726774e-01,-5.80626515e-01,-5.89275599e-01,-5.96679715e-01, + -6.02843579e-01,-6.07770949e-01,-6.11464627e-01,-6.13926473e-01, + -6.15157406e-01] +du0 = zeros(1361) +f(du0,u0,0,0) +du0 + + +mul!(cs.cache_m8690271296156904125, cs.const_m3854548607110444668, (@view y[2:601])) +mul!(cs.cache_7735162028737694396, cs.const_m810426824042609992, cs.cache_m8690271296156904125) +mul!(cs.cache_m4432716267967134655, cs.const_83118777604549222, (@view y[2:601])) +cs.cache_1416156281203053579 .= (((-0.11346284738694776 .* ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725))))))) .* cs.const_6284853627393591686) ./ 1.7999999999999998) ./ cs.const_6284853627393591686 +mul!(cs.cache_3837998097161001762, cs.const_419985987929628265, cs.cache_1416156281203053579) +cs.cache_m2349735126975898980 .= cs.const_m6370830283027149840 .* (cs.const_5256068128236031296 .* (cs.cache_7735162028737694396 .+ cs.cache_3837998097161001762)) +mul!(cs.cache_3559064883010407825, cs.const_1477443756317609848, cs.cache_m2349735126975898980) +mul!(cs.cache_m5236042054648721177, cs.const_m3854548607110444668, (@view y[602:1201])) +mul!(cs.cache_4552822235374881625, cs.const_m810426824042609992, cs.cache_m5236042054648721177) +mul!(cs.cache_6385594400131391611, cs.const_83118777604549222, (@view y[602:1201])) +cs.cache_3669255876411325857 .= ((((-0.04425051048090962 .* ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725))))))) .* cs.const_m8371260504451653468) ./ 1.5000000000000002) ./ 2.05008960573477) ./ cs.const_m8371260504451653468 +mul!(cs.cache_m5979984690307217085, cs.const_419985987929628265, cs.cache_3669255876411325857) +cs.cache_4085014493431324638 .= cs.const_m6370830283027149840 .* (cs.const_3206463238628087733 .* (cs.cache_4552822235374881625 .+ cs.cache_m5979984690307217085)) +mul!(cs.cache_m4186862615729982588, cs.const_1477443756317609848, cs.cache_4085014493431324638) +cs.cache_7729892376240732805[1:20] .= (@view y[1202:1221]) +cs.cache_7729892376240732805[21:40] .= (@view y[1222:1241]) +cs.cache_7729892376240732805[41:60] .= (@view y[1242:1261]) +cs.cache_m5983176047089085323 .= cs.const_4910271190053899160 .* (((5.34e-10 .* (exp.(((-0.65 .* (cs.cache_7729892376240732805 .* 1000.0)) ./ 1000.0)))) .* cs.const_m1615735228018878911) ./ 2.7877244479038255e-10) +mul!(cs.cache_m7220358040310595472, cs.const_m6406009788656677430, cs.cache_m5983176047089085323) +mul!(cs.cache_2958147717725554841, cs.const_7492635389435296866, cs.cache_m5983176047089085323) +mul!(cs.cache_6584089953429348159, cs.const_m2551856243850624398, cs.cache_m5983176047089085323) +cs.cache_m2205063840212872182 .= (cs.cache_2958147717725554841 .* cs.cache_6584089953429348159) ./ (((cs.cache_6584089953429348159 .* cs.const_8229859839001814964) .+ (cs.cache_2958147717725554841 .* cs.const_m8826988669266821604)) .+ 1e-16) +mul!(cs.cache_774339592884572080, cs.const_m2239172306025069482, cs.cache_m2205063840212872182) +mul!(cs.cache_956044674773232170, cs.const_4742260312915039474, cs.cache_7729892376240732805) +mul!(cs.cache_m1168385265453438253, cs.const_m2239172306025069482, cs.cache_956044674773232170) +cs.cache_7084643733393507988 .= (((((((0.0911 .+ (1.9101 .* ((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0).^2.0))) .+ (0.1554 .* (((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0).^3.0))) .* cs.const_m1615735228018878911) ./ 1.0468957512717258) .* cs.const_1871829889889080582) .* 0.04002679875215723) ./ 0.008035880643729008 +mul!(cs.cache_6377132265167146240, cs.const_4022673044584674996, cs.cache_7084643733393507988) +mul!(cs.cache_m6244145936812788240, cs.const_4022673044584674996, cs.cache_7729892376240732805) +cs.cache_1105677131701825845[1:20] .= (@view y[1302:1321]) +cs.cache_1105677131701825845[21:40] .= (@view y[1322:1341]) +cs.cache_1105677131701825845[41:60] .= (@view y[1342:1361]) +mul!(cs.cache_m4559336614180109070, cs.const_4742260312915039474, cs.cache_1105677131701825845) +mul!(cs.cache_5964596193839440387, cs.const_m2239172306025069482, cs.cache_m4559336614180109070) +cs.cache_6453636296210224079 .= (0.008035880643729008 .* cs.cache_7729892376240732805) .* cs.const_7749124486072430752 +mul!(cs.cache_m7958094614900297101, cs.const_4022673044584674996, cs.cache_6453636296210224079) +cs.cache_8188036567708323486 .= (((cs.cache_m7220358040310595472 .+ cs.cache_774339592884572080) .* cs.cache_m1168385265453438253) .+ ((cs.const_m344729034815622734 .* (cs.cache_6377132265167146240 .* (((cs.const_m6293037495340517372 .* cs.cache_m1168385265453438253) ./ cs.cache_m6244145936812788240) .- cs.cache_5964596193839440387))) ./ 0.04002679875215723)) .+ cs.cache_m7958094614900297101 +mul!(cs.cache_m6645337912123003706, cs.const_2155620181971259577, cs.cache_8188036567708323486) +cs.cache_m1572333326302305327 .= -cs.cache_m6645337912123003706 +cs.cache_4444843852540613429[1:20] .= ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725)))))) +cs.cache_4444843852540613429[21:40] .= cs.const_2673546356631690987 +cs.cache_4444843852540613429[41:60] .= ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725)))))) +cs.cache_8316190851790556232[1:1] .= cs.const_m1032606879019717969 +cs.cache_8316190851790556232[2:601] .= (cs.const_m6466908670533079333 .* (cs.const_m919967631435488369 .* cs.cache_3559064883010407825)) +cs.cache_8316190851790556232[602:1201] .= (cs.const_844432128953615761 .* (cs.const_m919967631435488369 .* cs.cache_m4186862615729982588)) +cs.cache_8316190851790556232[1202:1261] .= (cs.const_5356335722306557041 .* ((((cs.cache_m1572333326302305327 ./ 0.008035880643729008) .+ (((cs.const_2100260670751548208 .+ (cs.const_m3704159319882291581 .* cs.cache_4444843852540613429)) .+ cs.const_2100260670751548208) ./ 0.04002679875215723)) .- (cs.cache_7729892376240732805 .* cs.const_7749124486072430752)) .- (cs.cache_7729892376240732805 .* cs.const_7749124486072430752))) +mul!(cs.cache_6281528158126438668, cs.const_1509603028080037696, (@view y[1262:1281])) +mul!(cs.cache_244133575886292095, cs.const_9168352019723563689, cs.cache_6281528158126438668) +mul!(cs.cache_1480199951838108910, cs.const_m6337143657829181592, cs.cache_244133575886292095) +cs.cache_m8825037627629645404 .= cs.const_m4831381568644549996 .* cs.cache_1480199951838108910 +mul!(cs.cache_m4463903973878375467, cs.const_9168352019723563689, cs.cache_m8825037627629645404) +mul!(cs.cache_m5204106969040429111, cs.const_6715966457835164428, (@view y[1282:1301])) +mul!(cs.cache_m8118013018143870756, cs.const_m6076020440529072554, cs.cache_m5204106969040429111) +cs.cache_7899744126569850954 .= cs.const_m1453791953686693439 .* (cs.cache_m8118013018143870756 .+ cs.const_8366588851195495623) +mul!(cs.cache_m8486204412392847702, cs.const_9168352019723563689, cs.cache_7899744126569850954) +mul!(cs.cache_6953277061565774920, cs.const_2155620181971259577, cs.cache_6730866441417284015) +cs.cache_7545625011893614278[1:20] .= (cs.cache_m4463903973878375467 .+ (cs.const_6284853627393591686 .* ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725)))))))) +cs.cache_7545625011893614278[21:40] .= (cs.cache_m8486204412392847702 .+ (cs.const_m8371260504451653468 .* ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725)))))))) +cs.cache_7545625011893614278[41:100] .= (cs.cache_6953277061565774920 .- (cs.const_m2268798281525233596 .* ((cs.const_7749124486072430752 .+ cs.cache_4444843852540613429) .+ cs.const_7749124486072430752))) +dy[1:1261] .= cs.cache_8316190851790556232 +dy[1262:1361] .= cs.cache_7545625011893614278 \ No newline at end of file From dbeab17e7a572a2bd2e45e195bc1c0752bdce359 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 18 Nov 2020 15:44:37 -0500 Subject: [PATCH 31/88] #1129 fix typos --- pybamm/spatial_methods/finite_volume.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pybamm/spatial_methods/finite_volume.py b/pybamm/spatial_methods/finite_volume.py index 269e5f6d03..9458918f1d 100644 --- a/pybamm/spatial_methods/finite_volume.py +++ b/pybamm/spatial_methods/finite_volume.py @@ -815,13 +815,12 @@ def add_neumann_values(self, symbol, discretised_gradient, bcs, domain): # Need to match the domain. E.g. in the case of the boundary condition # on the particle, the gradient has domain particle but the bcs_vector # has domain electrode, since it is a function of the macroscopic variables - bcs_vector.domain = discretised_gradient.domain - bcs_vector.auxiliary_domains = discretised_gradient.auxiliary_domains + bcs_vector.copy_domains(discretised_gradient) # Make matrix which makes "gaps" in the the discretised gradient into # which the known Neumann values will be added. E.g. in 1D if the left # boundary condition is Dirichlet and the right Neumann, this matrix will - # act to append a zero to the end of the discretsied gradient + # act to append a zero to the end of the discretised gradient if lbc_type == "Neumann": left_vector = csr_matrix((1, n)) else: From e78e988ddd30e59f376e6b96fafdd40095075a9f Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 20 Nov 2020 14:51:16 -0500 Subject: [PATCH 32/88] #1129 working on MTK PDEs --- examples/scripts/DFN.py | 11 +- .../operations/evaluate_julia.py | 161 +- test.jl | 137 ++ .../test_operations/quick_julia_test.py | 29 +- .../test_operations/test_evaluate_julia.py | 11 +- tests/unit/test_solvers/test_julia_mtk.py | 148 +- tmp_debug.jl | 1891 +---------------- 7 files changed, 492 insertions(+), 1896 deletions(-) create mode 100644 test.jl diff --git a/examples/scripts/DFN.py b/examples/scripts/DFN.py index fc23f22fc5..c73e467484 100644 --- a/examples/scripts/DFN.py +++ b/examples/scripts/DFN.py @@ -9,7 +9,7 @@ # load model -model = pybamm.lithium_ion.SPMe() +model = pybamm.lithium_ion.DFN() # create geometry geometry = model.default_geometry @@ -21,7 +21,7 @@ # set mesh var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} +var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} # var_pts = model.default_var_pts mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) @@ -33,8 +33,11 @@ t_eval = np.linspace(0, 3600, 100) solver = pybamm.CasadiSolver(mode="fast", atol=1e-6, rtol=1e-6) solution = solver.solve(model, t_eval) -solution = solver.solve(model, t_eval) -print(pybamm.Timer().format(solution.integration_time)) +tot = 0 +for i in range(100): + solution = solver.solve(model, t_eval) + tot += solution.solve_time +print(tot / 100) # plot # plot = pybamm.QuickPlot( diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 6ef81d70a0..4927d40dd7 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -146,6 +146,8 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz symbol_str = "{}[{}:{}]".format( children_vars[0], symbol.slice.start + 1, symbol.slice.stop ) + elif isinstance(symbol, (pybamm.Gradient, pybamm.Divergence)): + symbol_str = "D'{}'({})".format(symbol.domain[0], children_vars[0]) else: symbol_str = symbol.name + children_vars[0] @@ -274,16 +276,19 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz variable_symbols[symbol.id] = symbol_str - # Save the size of the variable - if symbol.shape == (): - variable_symbol_sizes[symbol.id] = 1 - elif symbol.shape[1] == 1: - variable_symbol_sizes[symbol.id] = symbol.shape[0] - else: - raise ValueError("expected scalar or column vector") + # Save the size of the symbol + try: + if symbol.shape == (): + variable_symbol_sizes[symbol.id] = 1 + elif symbol.shape[1] == 1: + variable_symbol_sizes[symbol.id] = symbol.shape[0] + else: + raise ValueError("expected scalar or column vector") + except NotImplementedError: + pass -def to_julia(symbol, debug=False): +def to_julia(symbol): """ This function converts an expression tree into a dict of constant input values, and valid julia code that acts like the tree's :func:`pybamm.Symbol.evaluate` function @@ -308,25 +313,6 @@ def to_julia(symbol, debug=False): variable_symbol_sizes = OrderedDict() find_symbols(symbol, constant_values, variable_symbols, variable_symbol_sizes) - # line_format = "{} .= {}" - - # if debug: - # variable_lines = [ - # "print('{}'); ".format( - # line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) - # ) - # + line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) - # + "; print(type({0}),{0}.shape)".format( - # id_to_julia_variable(symbol_id, False) - # ) - # for symbol_id, symbol_line in variable_symbols.items() - # ] - # else: - # variable_lines = [ - # line_format.format(id_to_julia_variable(symbol_id, False), symbol_line) - # for symbol_id, symbol_line in variable_symbols.items() - # ] - return constant_values, variable_symbols, variable_symbol_sizes @@ -347,7 +333,7 @@ def get_julia_function(symbol, funcname="f"): """ - constants, var_symbols, var_symbol_sizes = to_julia(symbol, debug=False) + constants, var_symbols, var_symbol_sizes = to_julia(symbol) # extract constants in generated function const_and_cache_str = "cs = (\n" @@ -453,8 +439,11 @@ def get_julia_function(symbol, funcname="f"): result_value = symbol.evaluate() # assign the return variable - if symbol.is_constant() and isinstance(result_value, numbers.Number): - julia_str = julia_str + "\n dy .= " + str(result_value) + "\n" + if symbol.is_constant(): + if isinstance(result_value, numbers.Number): + julia_str = julia_str + "\n dy .= " + str(result_value) + "\n" + else: + julia_str = julia_str + "\n dy .= cs." + result_var + "\n" else: julia_str = julia_str.replace("cs." + result_var, "dy") @@ -478,7 +467,7 @@ def get_julia_function(symbol, funcname="f"): return julia_str -def get_julia_mtk_model(model): +def get_julia_mtk_model(model, geometry=None, tspan=None): """ Converts a pybamm model into a Julia ModelingToolkit model @@ -486,6 +475,10 @@ def get_julia_mtk_model(model): ---------- model : :class:`pybamm.BaseModel` The model to be converted + geometry : dict, optional + Dictionary defining the geometry. Must be provided if the model is a PDE model + tspan : array-like, optional + Time for which to solve the model. Must be provided if the model is a PDE model Returns ------- @@ -493,36 +486,77 @@ def get_julia_mtk_model(model): String of julia code representing a model in MTK, to be evaluated by ``julia.Main.eval`` """ + # Extract variables + variables = {**model.rhs, **model.algebraic}.keys() + variable_id_to_number = {var.id: f"u{i+1}" for i, var in enumerate(variables)} + all_domains = list(set([dom for var in variables for dom in var.domain])) + + is_pde = bool(all_domains) + + # Check geometry and tspan have been provided if a PDE + if is_pde: + if geometry is None: + raise ValueError("must provide geometry if the model is a PDE model") + if tspan is None: + raise ValueError("must provide tspan if the model is a PDE model") + + domain_name_to_symbol = { + dom: list(geometry[dom].keys())[0].name for i, dom in enumerate(all_domains) + } + mtk_str = "begin\n" - # Define parameters - # Makes a line of the form '@parameters t a b c d' - mtk_str += "@parameters t" + # Define parameters (including independent variables) + # Makes a line of the form '@parameters t x1 x2 x3 a b c d' + ind_vars = ["t"] + list(domain_name_to_symbol.values()) + for dom, number in domain_name_to_symbol.items(): + mtk_str += f"# '{dom}' -> {number}\n" + mtk_str += "@parameters " + " ".join(ind_vars) for param in model.input_parameters: mtk_str += f" {param.name}" mtk_str += "\n" - # Define variables - variables = {**model.rhs, **model.algebraic}.keys() - variable_id_to_number = {var.id: f"x{i+1}" for i, var in enumerate(variables)} - # Add a comment with the variable names for var in variables: - mtk_str += f"# {var.name} -> {variable_id_to_number[var.id]}\n" - # Makes a line of the form '@variables x1(t) x2(t)' + mtk_str += f"# '{var.name}' -> {variable_id_to_number[var.id]}\n" + # Makes a line of the form '@variables u1(t) u2(t)' + dep_vars = list(variable_id_to_number.values()) mtk_str += "@variables" - for var in variable_id_to_number.values(): - mtk_str += f" {var}(t)" + for var in variables: + if var.domain == []: + var_ind_vars = "(t)" + else: + var_ind_vars = ( + "(t, " + + ", ".join([domain_name_to_symbol[dom] for dom in var.domain]) + + ")" + ) + mtk_str += f" {variable_id_to_number[var.id]}{var_ind_vars}" mtk_str += "\n" # Define derivatives - mtk_str += "@derivatives D'~t\n\n" + + mtk_str += "@derivatives Dt'~t\n" + if is_pde: + mtk_str += "@derivatives " + for domain_symbol in domain_name_to_symbol.values(): + mtk_str += f"D{domain_symbol}'~{domain_symbol}" + mtk_str += "\n" + mtk_str += "\n" # Define equations all_eqns_str = "" all_constants_str = "" all_julia_str = "" for var, eqn in {**model.rhs, **model.algebraic}.items(): - constants, julia_str = to_julia(eqn, debug=False) + constants, variable_symbols = to_julia(eqn)[:2] + line_format = "{} .= {}" + + julia_str = "\n".join( + [ + f"{id_to_julia_variable(symbol_id)} = {symbol_line}" + for symbol_id, symbol_line in variable_symbols.items() + ] + ) # extract constants in generated function for eqn_id, const_value in constants.items(): @@ -547,7 +581,7 @@ def get_julia_mtk_model(model): eqn_str = result_var if var in model.rhs: - all_eqns_str += f" D({variable_id_to_number[var.id]}) ~ {eqn_str},\n" + all_eqns_str += f" Dt({variable_id_to_number[var.id]}) ~ {eqn_str},\n" elif var in model.algebraic: all_eqns_str += f" 0 ~ {eqn_str},\n" @@ -558,6 +592,11 @@ def get_julia_mtk_model(model): id_to_julia_variable(var_id, False), julia_id ) + # Replace independent variables (domain names) in julia strings with the + # corresponding symbol + for domain, symbol in domain_name_to_symbol.items(): + all_julia_str = all_julia_str.replace(f"'{domain}'", symbol) + # Replace parameters in the julia strings in the form "inputs[name]" # with just "name" for param in model.input_parameters: @@ -573,15 +612,41 @@ def get_julia_mtk_model(model): # Update the MTK string mtk_str += all_constants_str + all_julia_str + "\n" + f"eqs = [\n{all_eqns_str}]\n" - # Create ODESystem - mtk_str += "sys = ODESystem(eqs, t)\n\n" + # Create ODESystem or PDESystem + if not is_pde: + mtk_str += "sys = ODESystem(eqs, t)\n\n" + else: + # Create domains + mtk_str += "\n" + mtk_str += f"t_domain = IntervalDomain({tspan[0]}, {tspan[1]})\n" + domains = f"domains = [\n t in t_domain,\n" + for domain, symbol in domain_name_to_symbol.items(): + dom_limits = list(geometry[domain].values())[0] + dom_min, dom_max = dom_limits.values() + mtk_str += f"{symbol}_domain = IntervalDomain({dom_min}, {dom_max})\n" + domains += f" {symbol} in {symbol}_domain,\n" + domains += "]\n" + + mtk_str += "\n" + mtk_str += domains + mtk_str += "ind_vars = [{}]\n".format(", ".join(ind_vars)) + mtk_str += "dep_vars = [{}]\n\n".format(", ".join(dep_vars)) + + mtk_str += "sys = PDESystem(eqs, bcs, domains, ind_vars, dep_vars)\n\n" # Create initial conditions all_ics_str = "" all_constants_str = "" all_julia_str = "" for var, eqn in model.initial_conditions.items(): - constants, julia_str = to_julia(eqn, debug=False) + constants, variable_symbols = to_julia(eqn)[:2] + + julia_str = "\n".join( + [ + f"{id_to_julia_variable(symbol_id)} = {symbol_line}" + for symbol_id, symbol_line in variable_symbols.items() + ] + ) # extract constants in generated function for eqn_id, const_value in constants.items(): diff --git a/test.jl b/test.jl new file mode 100644 index 0000000000..2f570678b2 --- /dev/null +++ b/test.jl @@ -0,0 +1,137 @@ +using SparseArrays, LinearAlgebra + +cs = (const_m6820315422816856576 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99,100], [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99,100], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., + 1.,1.,1.,1.], 101, 100), + const_m6249938662719198354 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, + 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, + 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, + 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, + 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, + 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, + 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, + 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, + 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, + 100,100], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, + 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, + 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, + 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, + 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, + 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, + 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, + 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, + 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99,100, + 100,101], [-120. , 120. ,-120. , 120. ,-120. , + 120. ,-120. , 120. ,-120. , 120. , + -120. , 120. ,-120. , 120. ,-120. , + 120. ,-120. , 120. ,-120. , 120. , + -120. , 120. ,-120. , 120. ,-120. , + 120. ,-120. , 120. ,-120. , 120. , + -120. , 120. ,-120. , 120. ,-120. , + 120. ,-120. , 120. ,-120. , 120. , + -120. , 120. ,-120. , 120. ,-120. , + 120. ,-120. , 120. ,-120. , 120. , + -120. , 120. ,-120. , 120. ,-120. , + 120. ,-120. , 120. ,-120. , 120. , + -120. , 120. ,-120. , 120. ,-120. , + 120. ,-120. , 120. ,-120. , 120. , + -120. , 120. ,-120. , 120. ,-120. , + 120. ,-120. , 120. ,-120. , 120. , + -92.30769231, 92.30769231, -75. , 75. , -75. , + 75. , -75. , 75. , -75. , 75. , + -75. , 75. , -75. , 75. , -75. , + 75. , -75. , 75. , -75. , 75. , + -75. , 75. , -75. , 75. , -75. , + 75. , -75. , 75. , -75. , 75. , + -75. , 75. , -75. , 75. , -75. , + 75. , -75. , 75. , -75. , 75. , + -75. , 75. , -75. , 75. , -75. , + 75. , -75. , 75. , -75. , 75. , + -87.5 , 87.5 ,-105. , 105. ,-105. , + 105. ,-105. , 105. ,-105. , 105. , + -105. , 105. ,-105. , 105. ,-105. , + 105. ,-105. , 105. ,-105. , 105. , + -105. , 105. ,-105. , 105. ,-105. , + 105. ,-105. , 105. ,-105. , 105. , + -105. , 105. ,-105. , 105. ,-105. , + 105. ,-105. , 105. ,-105. , 105. , + -105. , 105. ,-105. , 105. ,-105. , + 105. ,-105. , 105. ,-105. , 105. , + -105. , 105. ,-105. , 105. ,-105. , + 105. ,-105. , 105. ,-105. , 105. , + -105. , 105. ,-105. , 105. ,-105. , + 105. ,-105. , 105. ,-105. , 105. ], 100, 101), + const_79228066988392040 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101], [ 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100], [-1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.], 101, 100), + const_m2973107757891108131 = [2.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.], + const_m3631117290644352711 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., + 0.,0.,0.,0.,2.], + cache_5378890746278984336 = zeros(101), + cache_m2599068943850039371 = zeros(101), + cache_m7992824528112566971 = zeros(100), + cache_m5645790295110124696 = zeros(101),) + +y = [1.00001736, 1.00015625, 1.00043403, 1.00085069, 1.00140625, +1.00210069, 1.00293403, 1.00390625, 1.00501736, 1.00626736, +1.00765625, 1.00918403, 1.01085069, 1.01265625, 1.01460069, +1.01668403, 1.01890625, 1.02126736, 1.02376736, 1.02640625, +1.02918403, 1.03210069, 1.03515625, 1.03835069, 1.04168403, +1.04515625, 1.04876736, 1.05251736, 1.05640625, 1.06043403, +1.06460069, 1.06890625, 1.07335069, 1.07793403, 1.08265625, +1.08751736, 1.09251736, 1.09765625, 1.10293403, 1.10835069, +1.1156 , 1.12484444, 1.13444444, 1.1444 , 1.15471111, +1.16537778, 1.1764 , 1.18777778, 1.19951111, 1.2116 , +1.22404444, 1.23684444, 1.25 , 1.26351111, 1.27737778, +1.2916 , 1.30617778, 1.32111111, 1.3364 , 1.35204444, +1.36804444, 1.3844 , 1.40111111, 1.41817778, 1.4356 , +1.45081633, 1.46369615, 1.47675737, 1.49 , 1.50342404, +1.51702948, 1.53081633, 1.54478458, 1.55893424, 1.57326531, +1.58777778, 1.60247166, 1.61734694, 1.63240363, 1.64764172, +1.66306122, 1.67866213, 1.69444444, 1.71040816, 1.72655329, +1.74287982, 1.75938776, 1.7760771 , 1.79294785, 1.81 , +1.82723356, 1.84464853, 1.8622449 , 1.88002268, 1.89798186, +1.91612245, 1.93444444, 1.95294785, 1.97163265, 1.99049887] +dy = similar(y) + +mul!(cs.cache_5378890746278984336, cs.const_79228066988392040, (@view y[1:100])) +cs.cache_m2599068943850039371 .= cs.cache_5378890746278984336 .+ cs.const_m2973107757891108131 +mul!(cs.cache_m7992824528112566971, cs.const_m6249938662719198354, cs.cache_m2599068943850039371) +mul!(cs.cache_m5645790295110124696, cs.const_m6820315422816856576, cs.cache_m7992824528112566971) +dy .= cs.cache_m5645790295110124696 .+ cs.const_m3631117290644352711 diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py index f5205d2cf6..9aebbcb7a5 100644 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py @@ -8,9 +8,9 @@ from julia import Main -model = pybamm.lithium_ion.DFN() +model = pybamm.lithium_ion.SPMe() # var = pybamm.standard_spatial_vars -# var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} +# var_pts = {var.x_n: 3, var.x_s: 3, var.x_p: 3, var.r_n: 3, var.r_p: 3} var_pts = model.default_var_pts sim = pybamm.Simulation(model, solver=pybamm.CasadiSolver(mode="fast"), var_pts=var_pts) sim.solve([0, 3600]) @@ -24,21 +24,23 @@ ) # .simplify() # expr = sim.built_model.concatenated_rhs.simplify() -expr = sim.built_model.concatenated_algebraic # .children[-1] +expr = sol["Terminal voltage [V]"].base_variable + +# expr = sim.built_model.concatenated_algebraic # .children[-1] evaluator_str = pybamm.get_julia_function(expr) n_rhs = sim.built_model.concatenated_rhs.size n_alg = sim.built_model.concatenated_algebraic.size -np.set_printoptions( - threshold=max( - np.get_printoptions()["threshold"], - n_rhs + n_alg, - ) -) +# np.set_printoptions( +# threshold=max( +# np.get_printoptions()["threshold"], +# n_rhs + n_alg, +# ) +# ) with open("tmp_debug.jl", "w") as f: f.write(evaluator_str) - f.write(f"u0 = {np.array2string(sol.model.y0, separator=',')}\n") - f.write(f"du0 = zeros({n_rhs + n_alg})\n") - # f.write(f"differential_vars=[ones({n_rhs});zeros({n_alg})]\n") +# f.write(f"u0 = {np.array2string(sol.model.y0, separator=',')}\n") +# f.write(f"du0 = zeros({n_rhs + n_alg})\n") +# f.write(f"differential_vars=[ones({n_rhs});zeros({n_alg})]\n") # expr2 = sim.built_model.variables["Terminal voltage [V]"] # evaluator_str2 = pybamm.get_julia_function(expr2) @@ -47,7 +49,8 @@ Main.eval(evaluator_str) Main.dy = np.zeros(expr.shape[0]) -Main.y = sol.model.y0 +Main.y = sol.model.y0 + 1e-3 +# Main.y = sim.built_model.concatenated_initial_conditions.evaluate() ** 2 Main.eval("f(dy,y,0,0)") # print(Main.dy) # expr.evaluate(y=sol.model.y0) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index f32660203e..7d8be25a6b 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -55,6 +55,13 @@ def test_evaluator_julia(self): Main.eval("f(dy,y,0,0)") self.assertEqual(Main.dy, 6) + expr = pybamm.Scalar(2) * pybamm.Vector([1, 2, 3]) + evaluator_str = pybamm.get_julia_function(expr) + Main.eval(evaluator_str) + Main.dy = [0.0] * 3 + Main.eval("f(dy,y,0,0)") + np.testing.assert_array_equal(Main.dy, [2, 4, 6]) + # test a larger expression expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 evaluator_str = pybamm.get_julia_function(expr) @@ -349,7 +356,7 @@ def test_evaluator_julia_discretised_operators(self): Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test Main.eval("f(dy,y,0,0)") - np.testing.assert_equal(Main.dy, pybamm_eval) + np.testing.assert_almost_equal(Main.dy, pybamm_eval, decimal=7) def test_evaluator_julia_discretised_microscale(self): # create discretisation @@ -401,7 +408,7 @@ def test_evaluator_julia_discretised_microscale(self): Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test Main.eval("f(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, pybamm_eval, decimal=15) + np.testing.assert_almost_equal(Main.dy, pybamm_eval, decimal=7) if __name__ == "__main__": diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 0fed2881b4..86df4aa6dc 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -6,82 +6,118 @@ import unittest import numpy as np -from julia import Main -from diffeqpy import de +# from julia import Main +# from diffeqpy import de class TestCreateSolveMTKModel(unittest.TestCase): - def test_exponential_decay_model(self): - model = pybamm.BaseModel() - v = pybamm.Variable("v") - model.rhs = {v: -2 * v} - model.initial_conditions = {v: 0.5} + # def test_exponential_decay_model(self): + # model = pybamm.BaseModel() + # v = pybamm.Variable("v") + # model.rhs = {v: -2 * v} + # model.initial_conditions = {v: 0.5} - mtk_str = pybamm.get_julia_mtk_model(model) + # mtk_str = pybamm.get_julia_mtk_model(model) + # print(mtk_str) - Main.eval("using ModelingToolkit") - Main.eval(mtk_str) + # Main.eval("using ModelingToolkit") + # Main.eval(mtk_str) - Main.tspan = (0.0, 10.0) - # this definition of prob doesn't work, so we use Main.eval instead - # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) + # Main.tspan = (0.0, 10.0) + # # this definition of prob doesn't work, so we use Main.eval instead + # # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) - Main.eval("prob = ODEProblem(sys, u0, tspan)") - sol = de.solve(Main.prob, de.Tsit5()) + # Main.eval("prob = ODEProblem(sys, u0, tspan)") + # sol = de.solve(Main.prob, de.Tsit5()) - y_sol = np.concatenate(sol.u) - y_exact = 0.5 * np.exp(-2 * sol.t) - np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) + # y_sol = np.concatenate(sol.u) + # y_exact = 0.5 * np.exp(-2 * sol.t) + # np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) - def test_lotka_volterra_model(self): - model = pybamm.BaseModel() - a = pybamm.InputParameter("a") - b = pybamm.InputParameter("b") - c = pybamm.InputParameter("c") - d = pybamm.InputParameter("d") - x = pybamm.Variable("x") - y = pybamm.Variable("y") + # def test_lotka_volterra_model(self): + # model = pybamm.BaseModel() + # a = pybamm.InputParameter("a") + # b = pybamm.InputParameter("b") + # c = pybamm.InputParameter("c") + # d = pybamm.InputParameter("d") + # x = pybamm.Variable("x") + # y = pybamm.Variable("y") - model.rhs = {x: a * x - b * x * y, y: c * x * y - d * y} - model.initial_conditions = {x: 1.0, y: 1.0} + # model.rhs = {x: a * x - b * x * y, y: c * x * y - d * y} + # model.initial_conditions = {x: 1.0, y: 1.0} - mtk_str = pybamm.get_julia_mtk_model(model) + # mtk_str = pybamm.get_julia_mtk_model(model) - # Solve using julia - Main.eval("using ModelingToolkit") - Main.eval(mtk_str) + # # Solve using julia + # Main.eval("using ModelingToolkit") + # Main.eval(mtk_str) - Main.tspan = (0.0, 10.0) - Main.eval( - """ - begin - p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0] - prob = ODEProblem(sys, u0, tspan, p) - end - """ - ) - sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) + # Main.tspan = (0.0, 10.0) + # Main.eval( + # """ + # begin + # p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0] + # prob = ODEProblem(sys, u0, tspan, p) + # end + # """ + # ) + # sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) - y_sol_julia = np.vstack(sol_julia.u).T + # y_sol_julia = np.vstack(sol_julia.u).T - # Solve using pybamm - sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve( - model, sol_julia.t, inputs={"a": 1.5, "b": 1.0, "c": 3.0, "d": 1.0} - ) + # # Solve using pybamm + # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve( + # model, sol_julia.t, inputs={"a": 1.5, "b": 1.0, "c": 3.0, "d": 1.0} + # ) - # Compare - np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + # # Compare + # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + + # def test_dae_model(self): + # model = pybamm.BaseModel() + # x = pybamm.Variable("x") + # y = pybamm.Variable("y") + + # model.rhs = {x: -2 * x} + # model.algebraic = {y: x - y} + # model.initial_conditions = {x: 1.0, y: 1.0} + + # mtk_str = pybamm.get_julia_mtk_model(model) + # print(mtk_str) + + # # Solve using julia + # Main.eval("using ModelingToolkit") + # Main.eval(mtk_str) - def test_dae_model(self): + # Main.tspan = (0.0, 10.0) + # Main.eval("prob = ODEProblem(sys, u0, tspan)") + # sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) + + # y_sol_julia = np.vstack(sol_julia.u).T + + # # Solve using pybamm + # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, sol_julia.t) + + # # Compare + # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + + def test_pde_model(self): model = pybamm.BaseModel() - x = pybamm.Variable("x") - y = pybamm.Variable("y") + x = pybamm.Variable("x", domain="line") + + model.rhs = {x: pybamm.div(pybamm.grad(x))} + model.initial_conditions = {x: 1.0} + model.boundary_conditions = { + x: {"left": (-1, "Neumann"), "right": (1, "Dirichlet")} + } - model.rhs = {x: -2 * x} - model.algebraic = {y: x - y} - model.initial_conditions = {x: 1.0, y: 1.0} + x = pybamm.SpatialVariable("x", domain="line", coord_sys="cartesian") + geometry = {"line": {x: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}} - mtk_str = pybamm.get_julia_mtk_model(model) + mtk_str = pybamm.get_julia_mtk_model( + model, geometry=geometry, tspan=(0.0, 10.0) + ) + print(mtk_str) # Solve using julia Main.eval("using ModelingToolkit") diff --git a/tmp_debug.jl b/tmp_debug.jl index 4f989db900..2e7df21f68 100644 --- a/tmp_debug.jl +++ b/tmp_debug.jl @@ -1,1780 +1,125 @@ begin - using SparseArrays, LinearAlgebra +using SparseArrays, LinearAlgebra - f = let cs = (const_m1032606879019717969 = 4.272493084154669, - const_m6466908670533079333 = [-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765, - -8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765,-8.81345765], - const_m919967631435488369 = [3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00, - 3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00,3.60000000e+03,4.00000000e+02, - 1.44000000e+02,7.34693878e+01,4.44444444e+01,2.97520661e+01, - 2.13017751e+01,1.60000000e+01,1.24567474e+01,9.97229917e+00, - 8.16326531e+00,6.80529301e+00,5.76000000e+00,4.93827160e+00, - 4.28061831e+00,3.74609781e+00,3.30578512e+00,2.93877551e+00, - 2.62965668e+00,2.36686391e+00,2.14158239e+00,1.94699838e+00, - 1.77777778e+00,1.62969670e+00,1.49937526e+00,1.38408304e+00, - 1.28159487e+00,1.19008264e+00,1.10803324e+00,1.03418558e+00], - const_1477443756317609848 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, - 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, - 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, - 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, - 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, - 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, - 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, - 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, - 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, - 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, - 100,100,101,101,102,102,103,103,104,104,105,105,106,106,107,107,108,108, - 109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117, - 118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126, - 127,127,128,128,129,129,130,130,131,131,132,132,133,133,134,134,135,135, - 136,136,137,137,138,138,139,139,140,140,141,141,142,142,143,143,144,144, - 145,145,146,146,147,147,148,148,149,149,150,150,151,151,152,152,153,153, - 154,154,155,155,156,156,157,157,158,158,159,159,160,160,161,161,162,162, - 163,163,164,164,165,165,166,166,167,167,168,168,169,169,170,170,171,171, - 172,172,173,173,174,174,175,175,176,176,177,177,178,178,179,179,180,180, - 181,181,182,182,183,183,184,184,185,185,186,186,187,187,188,188,189,189, - 190,190,191,191,192,192,193,193,194,194,195,195,196,196,197,197,198,198, - 199,199,200,200,201,201,202,202,203,203,204,204,205,205,206,206,207,207, - 208,208,209,209,210,210,211,211,212,212,213,213,214,214,215,215,216,216, - 217,217,218,218,219,219,220,220,221,221,222,222,223,223,224,224,225,225, - 226,226,227,227,228,228,229,229,230,230,231,231,232,232,233,233,234,234, - 235,235,236,236,237,237,238,238,239,239,240,240,241,241,242,242,243,243, - 244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252, - 253,253,254,254,255,255,256,256,257,257,258,258,259,259,260,260,261,261, - 262,262,263,263,264,264,265,265,266,266,267,267,268,268,269,269,270,270, - 271,271,272,272,273,273,274,274,275,275,276,276,277,277,278,278,279,279, - 280,280,281,281,282,282,283,283,284,284,285,285,286,286,287,287,288,288, - 289,289,290,290,291,291,292,292,293,293,294,294,295,295,296,296,297,297, - 298,298,299,299,300,300,301,301,302,302,303,303,304,304,305,305,306,306, - 307,307,308,308,309,309,310,310,311,311,312,312,313,313,314,314,315,315, - 316,316,317,317,318,318,319,319,320,320,321,321,322,322,323,323,324,324, - 325,325,326,326,327,327,328,328,329,329,330,330,331,331,332,332,333,333, - 334,334,335,335,336,336,337,337,338,338,339,339,340,340,341,341,342,342, - 343,343,344,344,345,345,346,346,347,347,348,348,349,349,350,350,351,351, - 352,352,353,353,354,354,355,355,356,356,357,357,358,358,359,359,360,360, - 361,361,362,362,363,363,364,364,365,365,366,366,367,367,368,368,369,369, - 370,370,371,371,372,372,373,373,374,374,375,375,376,376,377,377,378,378, - 379,379,380,380,381,381,382,382,383,383,384,384,385,385,386,386,387,387, - 388,388,389,389,390,390,391,391,392,392,393,393,394,394,395,395,396,396, - 397,397,398,398,399,399,400,400,401,401,402,402,403,403,404,404,405,405, - 406,406,407,407,408,408,409,409,410,410,411,411,412,412,413,413,414,414, - 415,415,416,416,417,417,418,418,419,419,420,420,421,421,422,422,423,423, - 424,424,425,425,426,426,427,427,428,428,429,429,430,430,431,431,432,432, - 433,433,434,434,435,435,436,436,437,437,438,438,439,439,440,440,441,441, - 442,442,443,443,444,444,445,445,446,446,447,447,448,448,449,449,450,450, - 451,451,452,452,453,453,454,454,455,455,456,456,457,457,458,458,459,459, - 460,460,461,461,462,462,463,463,464,464,465,465,466,466,467,467,468,468, - 469,469,470,470,471,471,472,472,473,473,474,474,475,475,476,476,477,477, - 478,478,479,479,480,480,481,481,482,482,483,483,484,484,485,485,486,486, - 487,487,488,488,489,489,490,490,491,491,492,492,493,493,494,494,495,495, - 496,496,497,497,498,498,499,499,500,500,501,501,502,502,503,503,504,504, - 505,505,506,506,507,507,508,508,509,509,510,510,511,511,512,512,513,513, - 514,514,515,515,516,516,517,517,518,518,519,519,520,520,521,521,522,522, - 523,523,524,524,525,525,526,526,527,527,528,528,529,529,530,530,531,531, - 532,532,533,533,534,534,535,535,536,536,537,537,538,538,539,539,540,540, - 541,541,542,542,543,543,544,544,545,545,546,546,547,547,548,548,549,549, - 550,550,551,551,552,552,553,553,554,554,555,555,556,556,557,557,558,558, - 559,559,560,560,561,561,562,562,563,563,564,564,565,565,566,566,567,567, - 568,568,569,569,570,570,571,571,572,572,573,573,574,574,575,575,576,576, - 577,577,578,578,579,579,580,580,581,581,582,582,583,583,584,584,585,585, - 586,586,587,587,588,588,589,589,590,590,591,591,592,592,593,593,594,594, - 595,595,596,596,597,597,598,598,599,599,600,600], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, - 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, - 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, - 28, 29, 29, 30, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, - 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, - 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, - 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 63, 64, 64, 65, 65, 66, - 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, - 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, - 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, - 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99,100,100,101,101,102,102,103, - 103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112, - 112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121, - 121,122,122,123,123,124,125,126,126,127,127,128,128,129,129,130,130,131, - 131,132,132,133,133,134,134,135,135,136,136,137,137,138,138,139,139,140, - 140,141,141,142,142,143,143,144,144,145,145,146,146,147,147,148,148,149, - 149,150,150,151,151,152,152,153,153,154,154,155,156,157,157,158,158,159, - 159,160,160,161,161,162,162,163,163,164,164,165,165,166,166,167,167,168, - 168,169,169,170,170,171,171,172,172,173,173,174,174,175,175,176,176,177, - 177,178,178,179,179,180,180,181,181,182,182,183,183,184,184,185,185,186, - 187,188,188,189,189,190,190,191,191,192,192,193,193,194,194,195,195,196, - 196,197,197,198,198,199,199,200,200,201,201,202,202,203,203,204,204,205, - 205,206,206,207,207,208,208,209,209,210,210,211,211,212,212,213,213,214, - 214,215,215,216,216,217,218,219,219,220,220,221,221,222,222,223,223,224, - 224,225,225,226,226,227,227,228,228,229,229,230,230,231,231,232,232,233, - 233,234,234,235,235,236,236,237,237,238,238,239,239,240,240,241,241,242, - 242,243,243,244,244,245,245,246,246,247,247,248,249,250,250,251,251,252, - 252,253,253,254,254,255,255,256,256,257,257,258,258,259,259,260,260,261, - 261,262,262,263,263,264,264,265,265,266,266,267,267,268,268,269,269,270, - 270,271,271,272,272,273,273,274,274,275,275,276,276,277,277,278,278,279, - 280,281,281,282,282,283,283,284,284,285,285,286,286,287,287,288,288,289, - 289,290,290,291,291,292,292,293,293,294,294,295,295,296,296,297,297,298, - 298,299,299,300,300,301,301,302,302,303,303,304,304,305,305,306,306,307, - 307,308,308,309,309,310,311,312,312,313,313,314,314,315,315,316,316,317, - 317,318,318,319,319,320,320,321,321,322,322,323,323,324,324,325,325,326, - 326,327,327,328,328,329,329,330,330,331,331,332,332,333,333,334,334,335, - 335,336,336,337,337,338,338,339,339,340,340,341,342,343,343,344,344,345, - 345,346,346,347,347,348,348,349,349,350,350,351,351,352,352,353,353,354, - 354,355,355,356,356,357,357,358,358,359,359,360,360,361,361,362,362,363, - 363,364,364,365,365,366,366,367,367,368,368,369,369,370,370,371,371,372, - 373,374,374,375,375,376,376,377,377,378,378,379,379,380,380,381,381,382, - 382,383,383,384,384,385,385,386,386,387,387,388,388,389,389,390,390,391, - 391,392,392,393,393,394,394,395,395,396,396,397,397,398,398,399,399,400, - 400,401,401,402,402,403,404,405,405,406,406,407,407,408,408,409,409,410, - 410,411,411,412,412,413,413,414,414,415,415,416,416,417,417,418,418,419, - 419,420,420,421,421,422,422,423,423,424,424,425,425,426,426,427,427,428, - 428,429,429,430,430,431,431,432,432,433,433,434,435,436,436,437,437,438, - 438,439,439,440,440,441,441,442,442,443,443,444,444,445,445,446,446,447, - 447,448,448,449,449,450,450,451,451,452,452,453,453,454,454,455,455,456, - 456,457,457,458,458,459,459,460,460,461,461,462,462,463,463,464,464,465, - 466,467,467,468,468,469,469,470,470,471,471,472,472,473,473,474,474,475, - 475,476,476,477,477,478,478,479,479,480,480,481,481,482,482,483,483,484, - 484,485,485,486,486,487,487,488,488,489,489,490,490,491,491,492,492,493, - 493,494,494,495,495,496,497,498,498,499,499,500,500,501,501,502,502,503, - 503,504,504,505,505,506,506,507,507,508,508,509,509,510,510,511,511,512, - 512,513,513,514,514,515,515,516,516,517,517,518,518,519,519,520,520,521, - 521,522,522,523,523,524,524,525,525,526,526,527,528,529,529,530,530,531, - 531,532,532,533,533,534,534,535,535,536,536,537,537,538,538,539,539,540, - 540,541,541,542,542,543,543,544,544,545,545,546,546,547,547,548,548,549, - 549,550,550,551,551,552,552,553,553,554,554,555,555,556,556,557,557,558, - 559,560,560,561,561,562,562,563,563,564,564,565,565,566,566,567,567,568, - 568,569,569,570,570,571,571,572,572,573,573,574,574,575,575,576,576,577, - 577,578,578,579,579,580,580,581,581,582,582,583,583,584,584,585,585,586, - 586,587,587,588,588,589,590,591,591,592,592,593,593,594,594,595,595,596, - 596,597,597,598,598,599,599,600,600,601,601,602,602,603,603,604,604,605, - 605,606,606,607,607,608,608,609,609,610,610,611,611,612,612,613,613,614, - 614,615,615,616,616,617,617,618,618,619,619,620], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.], 600, 620), - const_m6370830283027149840 = [0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, - 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, - 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, - 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, - 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, - 1. ,0. ,0.00111111,0.00444444,0.01 ,0.01777778, - 0.02777778,0.04 ,0.05444444,0.07111111,0.09 ,0.11111111, - 0.13444444,0.16 ,0.18777778,0.21777778,0.25 ,0.28444444, - 0.32111111,0.36 ,0.40111111,0.44444444,0.49 ,0.53777778, - 0.58777778,0.64 ,0.69444444,0.75111111,0.81 ,0.87111111, - 0.93444444,1. ,0. ,0.00111111,0.00444444,0.01 , - 0.01777778,0.02777778,0.04 ,0.05444444,0.07111111,0.09 , - 0.11111111,0.13444444,0.16 ,0.18777778,0.21777778,0.25 , - 0.28444444,0.32111111,0.36 ,0.40111111,0.44444444,0.49 , - 0.53777778,0.58777778,0.64 ,0.69444444,0.75111111,0.81 , - 0.87111111,0.93444444,1. ,0. ,0.00111111,0.00444444, - 0.01 ,0.01777778,0.02777778,0.04 ,0.05444444,0.07111111, - 0.09 ,0.11111111,0.13444444,0.16 ,0.18777778,0.21777778, - 0.25 ,0.28444444,0.32111111,0.36 ,0.40111111,0.44444444, - 0.49 ,0.53777778,0.58777778,0.64 ,0.69444444,0.75111111, - 0.81 ,0.87111111,0.93444444,1. ,0. ,0.00111111, - 0.00444444,0.01 ,0.01777778,0.02777778,0.04 ,0.05444444, - 0.07111111,0.09 ,0.11111111,0.13444444,0.16 ,0.18777778, - 0.21777778,0.25 ,0.28444444,0.32111111,0.36 ,0.40111111, - 0.44444444,0.49 ,0.53777778,0.58777778,0.64 ,0.69444444, - 0.75111111,0.81 ,0.87111111,0.93444444,1. ,0. , - 0.00111111,0.00444444,0.01 ,0.01777778,0.02777778,0.04 , - 0.05444444,0.07111111,0.09 ,0.11111111,0.13444444,0.16 , - 0.18777778,0.21777778,0.25 ,0.28444444,0.32111111,0.36 , - 0.40111111,0.44444444,0.49 ,0.53777778,0.58777778,0.64 , - 0.69444444,0.75111111,0.81 ,0.87111111,0.93444444,1. , - 0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, - 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, - 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, - 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, - 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, - 1. ,0. ,0.00111111,0.00444444,0.01 ,0.01777778, - 0.02777778,0.04 ,0.05444444,0.07111111,0.09 ,0.11111111, - 0.13444444,0.16 ,0.18777778,0.21777778,0.25 ,0.28444444, - 0.32111111,0.36 ,0.40111111,0.44444444,0.49 ,0.53777778, - 0.58777778,0.64 ,0.69444444,0.75111111,0.81 ,0.87111111, - 0.93444444,1. ,0. ,0.00111111,0.00444444,0.01 , - 0.01777778,0.02777778,0.04 ,0.05444444,0.07111111,0.09 , - 0.11111111,0.13444444,0.16 ,0.18777778,0.21777778,0.25 , - 0.28444444,0.32111111,0.36 ,0.40111111,0.44444444,0.49 , - 0.53777778,0.58777778,0.64 ,0.69444444,0.75111111,0.81 , - 0.87111111,0.93444444,1. ,0. ,0.00111111,0.00444444, - 0.01 ,0.01777778,0.02777778,0.04 ,0.05444444,0.07111111, - 0.09 ,0.11111111,0.13444444,0.16 ,0.18777778,0.21777778, - 0.25 ,0.28444444,0.32111111,0.36 ,0.40111111,0.44444444, - 0.49 ,0.53777778,0.58777778,0.64 ,0.69444444,0.75111111, - 0.81 ,0.87111111,0.93444444,1. ,0. ,0.00111111, - 0.00444444,0.01 ,0.01777778,0.02777778,0.04 ,0.05444444, - 0.07111111,0.09 ,0.11111111,0.13444444,0.16 ,0.18777778, - 0.21777778,0.25 ,0.28444444,0.32111111,0.36 ,0.40111111, - 0.44444444,0.49 ,0.53777778,0.58777778,0.64 ,0.69444444, - 0.75111111,0.81 ,0.87111111,0.93444444,1. ,0. , - 0.00111111,0.00444444,0.01 ,0.01777778,0.02777778,0.04 , - 0.05444444,0.07111111,0.09 ,0.11111111,0.13444444,0.16 , - 0.18777778,0.21777778,0.25 ,0.28444444,0.32111111,0.36 , - 0.40111111,0.44444444,0.49 ,0.53777778,0.58777778,0.64 , - 0.69444444,0.75111111,0.81 ,0.87111111,0.93444444,1. , - 0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, - 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, - 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, - 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, - 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, - 1. ,0. ,0.00111111,0.00444444,0.01 ,0.01777778, - 0.02777778,0.04 ,0.05444444,0.07111111,0.09 ,0.11111111, - 0.13444444,0.16 ,0.18777778,0.21777778,0.25 ,0.28444444, - 0.32111111,0.36 ,0.40111111,0.44444444,0.49 ,0.53777778, - 0.58777778,0.64 ,0.69444444,0.75111111,0.81 ,0.87111111, - 0.93444444,1. ,0. ,0.00111111,0.00444444,0.01 , - 0.01777778,0.02777778,0.04 ,0.05444444,0.07111111,0.09 , - 0.11111111,0.13444444,0.16 ,0.18777778,0.21777778,0.25 , - 0.28444444,0.32111111,0.36 ,0.40111111,0.44444444,0.49 , - 0.53777778,0.58777778,0.64 ,0.69444444,0.75111111,0.81 , - 0.87111111,0.93444444,1. ,0. ,0.00111111,0.00444444, - 0.01 ,0.01777778,0.02777778,0.04 ,0.05444444,0.07111111, - 0.09 ,0.11111111,0.13444444,0.16 ,0.18777778,0.21777778, - 0.25 ,0.28444444,0.32111111,0.36 ,0.40111111,0.44444444, - 0.49 ,0.53777778,0.58777778,0.64 ,0.69444444,0.75111111, - 0.81 ,0.87111111,0.93444444,1. ,0. ,0.00111111, - 0.00444444,0.01 ,0.01777778,0.02777778,0.04 ,0.05444444, - 0.07111111,0.09 ,0.11111111,0.13444444,0.16 ,0.18777778, - 0.21777778,0.25 ,0.28444444,0.32111111,0.36 ,0.40111111, - 0.44444444,0.49 ,0.53777778,0.58777778,0.64 ,0.69444444, - 0.75111111,0.81 ,0.87111111,0.93444444,1. ,0. , - 0.00111111,0.00444444,0.01 ,0.01777778,0.02777778,0.04 , - 0.05444444,0.07111111,0.09 ,0.11111111,0.13444444,0.16 , - 0.18777778,0.21777778,0.25 ,0.28444444,0.32111111,0.36 , - 0.40111111,0.44444444,0.49 ,0.53777778,0.58777778,0.64 , - 0.69444444,0.75111111,0.81 ,0.87111111,0.93444444,1. , - 0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, - 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, - 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, - 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, - 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, - 1. ,0. ,0.00111111,0.00444444,0.01 ,0.01777778, - 0.02777778,0.04 ,0.05444444,0.07111111,0.09 ,0.11111111, - 0.13444444,0.16 ,0.18777778,0.21777778,0.25 ,0.28444444, - 0.32111111,0.36 ,0.40111111,0.44444444,0.49 ,0.53777778, - 0.58777778,0.64 ,0.69444444,0.75111111,0.81 ,0.87111111, - 0.93444444,1. ], - const_5256068128236031296 = [-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.], - const_m810426824042609992 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 95, 96, 97, - 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115, - 116,117,118,119,120,121,122,123,126,127,128,129,130,131,132,133,134,135, - 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153, - 154,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173, - 174,175,176,177,178,179,180,181,182,183,184,185,188,189,190,191,192,193, - 194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211, - 212,213,214,215,216,219,220,221,222,223,224,225,226,227,228,229,230,231, - 232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,250,251, - 252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269, - 270,271,272,273,274,275,276,277,278,281,282,283,284,285,286,287,288,289, - 290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307, - 308,309,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327, - 328,329,330,331,332,333,334,335,336,337,338,339,340,343,344,345,346,347, - 348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365, - 366,367,368,369,370,371,374,375,376,377,378,379,380,381,382,383,384,385, - 386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,405, - 406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423, - 424,425,426,427,428,429,430,431,432,433,436,437,438,439,440,441,442,443, - 444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461, - 462,463,464,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481, - 482,483,484,485,486,487,488,489,490,491,492,493,494,495,498,499,500,501, - 502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519, - 520,521,522,523,524,525,526,529,530,531,532,533,534,535,536,537,538,539, - 540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557, - 560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577, - 578,579,580,581,582,583,584,585,586,587,588,591,592,593,594,595,596,597, - 598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615, - 616,617,618,619], [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108, - 109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126, - 127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144, - 145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162, - 163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180, - 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198, - 199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216, - 217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234, - 235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252, - 253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270, - 271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288, - 289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306, - 307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324, - 325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342, - 343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360, - 361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378, - 379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396, - 397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414, - 415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432, - 433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450, - 451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468, - 469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486, - 487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504, - 505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522, - 523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540, - 541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558, - 559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576, - 577,578,579,580], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.], 620, 580), - const_m3854548607110444668 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, - 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, - 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, - 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, - 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, - 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, - 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, - 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, - 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, - 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, - 100,100,101,101,102,102,103,103,104,104,105,105,106,106,107,107,108,108, - 109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117, - 118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126, - 127,127,128,128,129,129,130,130,131,131,132,132,133,133,134,134,135,135, - 136,136,137,137,138,138,139,139,140,140,141,141,142,142,143,143,144,144, - 145,145,146,146,147,147,148,148,149,149,150,150,151,151,152,152,153,153, - 154,154,155,155,156,156,157,157,158,158,159,159,160,160,161,161,162,162, - 163,163,164,164,165,165,166,166,167,167,168,168,169,169,170,170,171,171, - 172,172,173,173,174,174,175,175,176,176,177,177,178,178,179,179,180,180, - 181,181,182,182,183,183,184,184,185,185,186,186,187,187,188,188,189,189, - 190,190,191,191,192,192,193,193,194,194,195,195,196,196,197,197,198,198, - 199,199,200,200,201,201,202,202,203,203,204,204,205,205,206,206,207,207, - 208,208,209,209,210,210,211,211,212,212,213,213,214,214,215,215,216,216, - 217,217,218,218,219,219,220,220,221,221,222,222,223,223,224,224,225,225, - 226,226,227,227,228,228,229,229,230,230,231,231,232,232,233,233,234,234, - 235,235,236,236,237,237,238,238,239,239,240,240,241,241,242,242,243,243, - 244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252, - 253,253,254,254,255,255,256,256,257,257,258,258,259,259,260,260,261,261, - 262,262,263,263,264,264,265,265,266,266,267,267,268,268,269,269,270,270, - 271,271,272,272,273,273,274,274,275,275,276,276,277,277,278,278,279,279, - 280,280,281,281,282,282,283,283,284,284,285,285,286,286,287,287,288,288, - 289,289,290,290,291,291,292,292,293,293,294,294,295,295,296,296,297,297, - 298,298,299,299,300,300,301,301,302,302,303,303,304,304,305,305,306,306, - 307,307,308,308,309,309,310,310,311,311,312,312,313,313,314,314,315,315, - 316,316,317,317,318,318,319,319,320,320,321,321,322,322,323,323,324,324, - 325,325,326,326,327,327,328,328,329,329,330,330,331,331,332,332,333,333, - 334,334,335,335,336,336,337,337,338,338,339,339,340,340,341,341,342,342, - 343,343,344,344,345,345,346,346,347,347,348,348,349,349,350,350,351,351, - 352,352,353,353,354,354,355,355,356,356,357,357,358,358,359,359,360,360, - 361,361,362,362,363,363,364,364,365,365,366,366,367,367,368,368,369,369, - 370,370,371,371,372,372,373,373,374,374,375,375,376,376,377,377,378,378, - 379,379,380,380,381,381,382,382,383,383,384,384,385,385,386,386,387,387, - 388,388,389,389,390,390,391,391,392,392,393,393,394,394,395,395,396,396, - 397,397,398,398,399,399,400,400,401,401,402,402,403,403,404,404,405,405, - 406,406,407,407,408,408,409,409,410,410,411,411,412,412,413,413,414,414, - 415,415,416,416,417,417,418,418,419,419,420,420,421,421,422,422,423,423, - 424,424,425,425,426,426,427,427,428,428,429,429,430,430,431,431,432,432, - 433,433,434,434,435,435,436,436,437,437,438,438,439,439,440,440,441,441, - 442,442,443,443,444,444,445,445,446,446,447,447,448,448,449,449,450,450, - 451,451,452,452,453,453,454,454,455,455,456,456,457,457,458,458,459,459, - 460,460,461,461,462,462,463,463,464,464,465,465,466,466,467,467,468,468, - 469,469,470,470,471,471,472,472,473,473,474,474,475,475,476,476,477,477, - 478,478,479,479,480,480,481,481,482,482,483,483,484,484,485,485,486,486, - 487,487,488,488,489,489,490,490,491,491,492,492,493,493,494,494,495,495, - 496,496,497,497,498,498,499,499,500,500,501,501,502,502,503,503,504,504, - 505,505,506,506,507,507,508,508,509,509,510,510,511,511,512,512,513,513, - 514,514,515,515,516,516,517,517,518,518,519,519,520,520,521,521,522,522, - 523,523,524,524,525,525,526,526,527,527,528,528,529,529,530,530,531,531, - 532,532,533,533,534,534,535,535,536,536,537,537,538,538,539,539,540,540, - 541,541,542,542,543,543,544,544,545,545,546,546,547,547,548,548,549,549, - 550,550,551,551,552,552,553,553,554,554,555,555,556,556,557,557,558,558, - 559,559,560,560,561,561,562,562,563,563,564,564,565,565,566,566,567,567, - 568,568,569,569,570,570,571,571,572,572,573,573,574,574,575,575,576,576, - 577,577,578,578,579,579,580,580], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, - 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, - 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, - 28, 29, 29, 30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, - 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, - 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, - 56, 57, 57, 58, 58, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, - 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, - 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, - 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 91, 92, 92, 93, 93, 94, - 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99,100,100,101,101,102,102,103, - 103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112, - 112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,121,122, - 122,123,123,124,124,125,125,126,126,127,127,128,128,129,129,130,130,131, - 131,132,132,133,133,134,134,135,135,136,136,137,137,138,138,139,139,140, - 140,141,141,142,142,143,143,144,144,145,145,146,146,147,147,148,148,149, - 149,150,151,152,152,153,153,154,154,155,155,156,156,157,157,158,158,159, - 159,160,160,161,161,162,162,163,163,164,164,165,165,166,166,167,167,168, - 168,169,169,170,170,171,171,172,172,173,173,174,174,175,175,176,176,177, - 177,178,178,179,179,180,181,182,182,183,183,184,184,185,185,186,186,187, - 187,188,188,189,189,190,190,191,191,192,192,193,193,194,194,195,195,196, - 196,197,197,198,198,199,199,200,200,201,201,202,202,203,203,204,204,205, - 205,206,206,207,207,208,208,209,209,210,211,212,212,213,213,214,214,215, - 215,216,216,217,217,218,218,219,219,220,220,221,221,222,222,223,223,224, - 224,225,225,226,226,227,227,228,228,229,229,230,230,231,231,232,232,233, - 233,234,234,235,235,236,236,237,237,238,238,239,239,240,241,242,242,243, - 243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252, - 252,253,253,254,254,255,255,256,256,257,257,258,258,259,259,260,260,261, - 261,262,262,263,263,264,264,265,265,266,266,267,267,268,268,269,269,270, - 271,272,272,273,273,274,274,275,275,276,276,277,277,278,278,279,279,280, - 280,281,281,282,282,283,283,284,284,285,285,286,286,287,287,288,288,289, - 289,290,290,291,291,292,292,293,293,294,294,295,295,296,296,297,297,298, - 298,299,299,300,301,302,302,303,303,304,304,305,305,306,306,307,307,308, - 308,309,309,310,310,311,311,312,312,313,313,314,314,315,315,316,316,317, - 317,318,318,319,319,320,320,321,321,322,322,323,323,324,324,325,325,326, - 326,327,327,328,328,329,329,330,331,332,332,333,333,334,334,335,335,336, - 336,337,337,338,338,339,339,340,340,341,341,342,342,343,343,344,344,345, - 345,346,346,347,347,348,348,349,349,350,350,351,351,352,352,353,353,354, - 354,355,355,356,356,357,357,358,358,359,359,360,361,362,362,363,363,364, - 364,365,365,366,366,367,367,368,368,369,369,370,370,371,371,372,372,373, - 373,374,374,375,375,376,376,377,377,378,378,379,379,380,380,381,381,382, - 382,383,383,384,384,385,385,386,386,387,387,388,388,389,389,390,391,392, - 392,393,393,394,394,395,395,396,396,397,397,398,398,399,399,400,400,401, - 401,402,402,403,403,404,404,405,405,406,406,407,407,408,408,409,409,410, - 410,411,411,412,412,413,413,414,414,415,415,416,416,417,417,418,418,419, - 419,420,421,422,422,423,423,424,424,425,425,426,426,427,427,428,428,429, - 429,430,430,431,431,432,432,433,433,434,434,435,435,436,436,437,437,438, - 438,439,439,440,440,441,441,442,442,443,443,444,444,445,445,446,446,447, - 447,448,448,449,449,450,451,452,452,453,453,454,454,455,455,456,456,457, - 457,458,458,459,459,460,460,461,461,462,462,463,463,464,464,465,465,466, - 466,467,467,468,468,469,469,470,470,471,471,472,472,473,473,474,474,475, - 475,476,476,477,477,478,478,479,479,480,481,482,482,483,483,484,484,485, - 485,486,486,487,487,488,488,489,489,490,490,491,491,492,492,493,493,494, - 494,495,495,496,496,497,497,498,498,499,499,500,500,501,501,502,502,503, - 503,504,504,505,505,506,506,507,507,508,508,509,509,510,511,512,512,513, - 513,514,514,515,515,516,516,517,517,518,518,519,519,520,520,521,521,522, - 522,523,523,524,524,525,525,526,526,527,527,528,528,529,529,530,530,531, - 531,532,532,533,533,534,534,535,535,536,536,537,537,538,538,539,539,540, - 541,542,542,543,543,544,544,545,545,546,546,547,547,548,548,549,549,550, - 550,551,551,552,552,553,553,554,554,555,555,556,556,557,557,558,558,559, - 559,560,560,561,561,562,562,563,563,564,564,565,565,566,566,567,567,568, - 568,569,569,570,571,572,572,573,573,574,574,575,575,576,576,577,577,578, - 578,579,579,580,580,581,581,582,582,583,583,584,584,585,585,586,586,587, - 587,588,588,589,589,590,590,591,591,592,592,593,593,594,594,595,595,596, - 596,597,597,598,598,599,599,600], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.], 580, 600), - const_419985987929628265 = sparse([ 31, 62, 93,124,155,186,217,248,279,310,341,372,403,434,465,496,527,558, - 589,620], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 620, 20), - const_m9126168015536320261 = [2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05, - 2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05], - const_83118777604549222 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20], [ 29, 30, 59, 60, 89, 90,119,120,149,150,179,180,209,210,239,240,269,270, - 299,300,329,330,359,360,389,390,419,420,449,450,479,480,509,510,539,540, - 569,570,599,600], [-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5, - -0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5, - -0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5,-0.5, 1.5], 20, 600), - const_1845266373960578514 = [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, - 0.5,0.5], - const_6438113274932828980 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], - const_6284853627393591686 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], - const_844432128953615761 = [-22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935, - -22.59860935,-22.59860935,-22.59860935,-22.59860935,-22.59860935], - const_3206463238628087733 = [-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.], - const_7674564103979747454 = [6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07, +f = let cs = ( + const_m4822311374121275919 = sparse([1,1], [19,20], [-0.5, 1.5], 1, 20), + const_1744480757062911249 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 20, 1), + const_m8518220820285355445 = sparse([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, + 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, + 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, + 0.02222222,0.02222222], 1, 20), + const_m2794236520912209521 = [2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.], + const_m942165513388665034 = [-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25, + -2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25], + const_m1232301553800524044 = [6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07, 6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07], - const_1237538932840516848 = [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, - 0.5,0.5], - const_m8218000856912416174 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], - const_m8371260504451653468 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], - const_5356335722306557041 = [3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, - 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, - 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, - 3.33333333,3.33333333,1. ,1. ,1. ,1. , - 1. ,1. ,1. ,1. ,1. ,1. , - 1. ,1. ,1. ,1. ,1. ,1. , - 1. ,1. ,1. ,1. ,3.33333333,3.33333333, - 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, - 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333, - 3.33333333,3.33333333,3.33333333,3.33333333,3.33333333,3.33333333], - const_2155620181971259577 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, - 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36, - 37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48, - 49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,60], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, - 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, - 25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36,37, - 37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49, - 49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,60,61], [ -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45.,-180., 180.,-180., 180.,-180., 180.,-180., 180., - -180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180., - -180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180., - -180., 180.,-180., 180.,-180., 180.,-180., 180., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45.], 60, 61), - const_m6406009788656677430 = sparse([ 1, 1,61,61], [ 1, 2,59,60], [ 1.5,-0.5,-0.5, 1.5], 61, 60), - const_4910271190053899160 = [-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, - -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, - -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, - -0.16431677,-0.16431677,-1. ,-1. ,-1. ,-1. , - -1. ,-1. ,-1. ,-1. ,-1. ,-1. , - -1. ,-1. ,-1. ,-1. ,-1. ,-1. , - -1. ,-1. ,-1. ,-1. ,-0.16431677,-0.16431677, - -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, - -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677, - -0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677,-0.16431677], - const_m1615735228018878911 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], - const_m2239172306025069482 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, - 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49, - 50,51,52,53,54,55,56,57,58,59,60], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, - 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, - 49,50,51,52,53,54,55,56,57,58,59], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 61, 59), - const_7492635389435296866 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, - 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, - 49,50,51,52,53,54,55,56,57,58,59], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, - 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, - 49,50,51,52,53,54,55,56,57,58,59], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 59, 60), - const_m2551856243850624398 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + const_1388564590504212564 = sparse([1,1], [29,30], [-0.5, 1.5], 1, 30), + const_8752233790552333983 = 0.0, + const_m6459359983097884347 = [2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.], + const_8416676264869710905 = [2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25, + 2.25,2.25,2.25,2.25,2.25,2.25], + const_m2775764531995498168 = [2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05, + 2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05], + const_m3780420342443263966 = -0.0006701794467029256, + const_m3587115650644734227 = 1.2, + const_m4908013908935754244 = sparse([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, - 49,50,51,52,53,54,55,56,57,58,59], [ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, - 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49, - 50,51,52,53,54,55,56,57,58,59,60], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 59, 60), - const_8229859839001814964 = [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, - 0.5,0.8,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, - 0.5,0.5,0.5,0.2,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, - 0.5,0.5,0.5,0.5,0.5], - const_m8826988669266821604 = [0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, - 0.5,0.2,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, - 0.5,0.5,0.5,0.8,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5, - 0.5,0.5,0.5,0.5,0.5], - const_4742260312915039474 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, - 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36, - 37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48, - 49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, - 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, - 25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36,37, - 37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49, - 49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60], [ -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -72., 72.,-180., 180.,-180., 180.,-180., 180.,-180., 180., - -180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180., - -180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180.,-180., 180., - -180., 180.,-180., 180.,-180., 180., -72., 72., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., -45., 45., - -45., 45., -45., 45., -45., 45., -45., 45., -45., 45.], 59, 60), - const_m344729034815622734 = [0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435,0.00321435,0.00321435,0.00321435,0.00321435,0.00321435, - 0.00321435], - const_4022673044584674996 = sparse([ 1, 2, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, - 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36, - 37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48, - 49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,61, - 60,61], [ 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12, - 12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24, - 24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36, - 36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48, - 48,49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,59, - 60,60], [ 1.5, 0.5,-0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,-0.5, 0.5, 1.5], 61, 60), - const_1871829889889080582 = [0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, - 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, - 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, - 0.16431677,0.16431677,1. ,1. ,1. ,1. , - 1. ,1. ,1. ,1. ,1. ,1. , - 1. ,1. ,1. ,1. ,1. ,1. , - 1. ,1. ,1. ,1. ,0.16431677,0.16431677, - 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, - 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677, - 0.16431677,0.16431677,0.16431677,0.16431677,0.16431677,0.16431677], - const_m6293037495340517372 = [1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2, - 1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2, - 1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2, - 1.2,1.2,1.2,1.2,1.2,1.2,1.2], - const_7749124486072430752 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], - const_2100260670751548208 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], - const_m3704159319882291581 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], - const_2673546356631690987 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.], - const_9168352019723563689 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, - 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21], [-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45., - -45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45., - -45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.], 20, 21), - const_m4831381568644549996 = [-221.12651346,-221.12651346,-221.12651346,-221.12651346,-221.12651346, - -221.12651346,-221.12651346,-221.12651346,-221.12651346,-221.12651346, - -221.12651346,-221.12651346,-221.12651346,-221.12651346,-221.12651346, - -221.12651346,-221.12651346,-221.12651346,-221.12651346,-221.12651346, - -221.12651346], - const_m6337143657829181592 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 21, 20), - const_1509603028080037696 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21], [ 1, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [-1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1.], 21, 20), - const_m1453791953686693439 = [-16.82166382,-16.82166382,-16.82166382,-16.82166382,-16.82166382, - -16.82166382,-16.82166382,-16.82166382,-16.82166382,-16.82166382, - -16.82166382,-16.82166382,-16.82166382,-16.82166382,-16.82166382, - -16.82166382,-16.82166382,-16.82166382,-16.82166382,-16.82166382, - -16.82166382], - const_m6076020440529072554 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 21, 19), - const_6715966457835164428 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, - 13,14,14,15,15,16,16,17,17,18,18,19,19,20], [-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45., - -45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45., - -45., 45.,-45., 45.,-45., 45.,-45., 45.,-45., 45.], 19, 20), - const_8366588851195495623 = [ 0. , 0. , 0. , 0. , 0. , 0. , - 0. , 0. , 0. , 0. , 0. , 0. , - 0. , 0. , 0. , 0. , 0. , 0. , - 0. , 0. ,-0.05944715], - const_m2268798281525233596 = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], - cache_m8690271296156904125 = zeros(580), - cache_7735162028737694396 = zeros(620), - cache_m4432716267967134655 = zeros(20), - cache_1416156281203053579 = zeros(20), - cache_3837998097161001762 = zeros(620), - cache_m2349735126975898980 = zeros(620), - cache_3559064883010407825 = zeros(600), - cache_m5236042054648721177 = zeros(580), - cache_4552822235374881625 = zeros(620), - cache_6385594400131391611 = zeros(20), - cache_3669255876411325857 = zeros(20), - cache_m5979984690307217085 = zeros(620), - cache_4085014493431324638 = zeros(620), - cache_m4186862615729982588 = zeros(600), - cache_7729892376240732805 = zeros(60), - cache_m5983176047089085323 = zeros(60), - cache_m7220358040310595472 = zeros(61), - cache_2958147717725554841 = zeros(59), - cache_6584089953429348159 = zeros(59), - cache_m2205063840212872182 = zeros(59), - cache_774339592884572080 = zeros(61), - cache_956044674773232170 = zeros(59), - cache_m1168385265453438253 = zeros(61), - cache_7084643733393507988 = zeros(60), - cache_6377132265167146240 = zeros(61), - cache_m6244145936812788240 = zeros(61), - cache_1105677131701825845 = zeros(60), - cache_m4559336614180109070 = zeros(59), - cache_5964596193839440387 = zeros(61), - cache_6730866441417284015 = zeros(61), - cache_6453636296210224079 = zeros(60), - cache_m7958094614900297101 = zeros(61), - cache_8188036567708323486 = zeros(61), - cache_m6645337912123003706 = zeros(60), - cache_m1572333326302305327 = zeros(60), - cache_4444843852540613429 = zeros(60), - cache_8316190851790556232 = zeros(1261), - cache_6281528158126438668 = zeros(21), - cache_244133575886292095 = zeros(20), - cache_1480199951838108910 = zeros(21), - cache_m8825037627629645404 = zeros(21), - cache_m4463903973878375467 = zeros(20), - cache_m5204106969040429111 = zeros(19), - cache_m8118013018143870756 = zeros(21), - cache_7899744126569850954 = zeros(21), - cache_m8486204412392847702 = zeros(20), - cache_6953277061565774920 = zeros(60), - cache_7545625011893614278 = zeros(100),) - - function f_with_consts(dy, y, p, t) - mul!(cs.cache_m8690271296156904125, cs.const_m3854548607110444668, (@view y[2:601])) - mul!(cs.cache_7735162028737694396, cs.const_m810426824042609992, cs.cache_m8690271296156904125) - mul!(cs.cache_m4432716267967134655, cs.const_83118777604549222, (@view y[2:601])) - cs.cache_1416156281203053579 .= (((-0.11346284738694776 .* ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725))))))) .* cs.const_6284853627393591686) ./ 1.7999999999999998) ./ cs.const_6284853627393591686 - mul!(cs.cache_3837998097161001762, cs.const_419985987929628265, cs.cache_1416156281203053579) - cs.cache_m2349735126975898980 .= cs.const_m6370830283027149840 .* (cs.const_5256068128236031296 .* (cs.cache_7735162028737694396 .+ cs.cache_3837998097161001762)) - mul!(cs.cache_3559064883010407825, cs.const_1477443756317609848, cs.cache_m2349735126975898980) - mul!(cs.cache_m5236042054648721177, cs.const_m3854548607110444668, (@view y[602:1201])) - mul!(cs.cache_4552822235374881625, cs.const_m810426824042609992, cs.cache_m5236042054648721177) - mul!(cs.cache_6385594400131391611, cs.const_83118777604549222, (@view y[602:1201])) - cs.cache_3669255876411325857 .= ((((-0.04425051048090962 .* ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725))))))) .* cs.const_m8371260504451653468) ./ 1.5000000000000002) ./ 2.05008960573477) ./ cs.const_m8371260504451653468 - mul!(cs.cache_m5979984690307217085, cs.const_419985987929628265, cs.cache_3669255876411325857) - cs.cache_4085014493431324638 .= cs.const_m6370830283027149840 .* (cs.const_3206463238628087733 .* (cs.cache_4552822235374881625 .+ cs.cache_m5979984690307217085)) - mul!(cs.cache_m4186862615729982588, cs.const_1477443756317609848, cs.cache_4085014493431324638) - cs.cache_7729892376240732805[1:20] .= (@view y[1202:1221]) - cs.cache_7729892376240732805[21:40] .= (@view y[1222:1241]) - cs.cache_7729892376240732805[41:60] .= (@view y[1242:1261]) - cs.cache_m5983176047089085323 .= cs.const_4910271190053899160 .* (((5.34e-10 .* (exp.(((-0.65 .* (cs.cache_7729892376240732805 .* 1000.0)) ./ 1000.0)))) .* cs.const_m1615735228018878911) ./ 2.7877244479038255e-10) - mul!(cs.cache_m7220358040310595472, cs.const_m6406009788656677430, cs.cache_m5983176047089085323) - mul!(cs.cache_2958147717725554841, cs.const_7492635389435296866, cs.cache_m5983176047089085323) - mul!(cs.cache_6584089953429348159, cs.const_m2551856243850624398, cs.cache_m5983176047089085323) - cs.cache_m2205063840212872182 .= (cs.cache_2958147717725554841 .* cs.cache_6584089953429348159) ./ (((cs.cache_6584089953429348159 .* cs.const_8229859839001814964) .+ (cs.cache_2958147717725554841 .* cs.const_m8826988669266821604)) .+ 1e-16) - mul!(cs.cache_774339592884572080, cs.const_m2239172306025069482, cs.cache_m2205063840212872182) - mul!(cs.cache_956044674773232170, cs.const_4742260312915039474, cs.cache_7729892376240732805) - mul!(cs.cache_m1168385265453438253, cs.const_m2239172306025069482, cs.cache_956044674773232170) - cs.cache_7084643733393507988 .= (((((((0.0911 .+ (1.9101 .* ((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0).^2.0))) .+ (0.1554 .* (((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0).^3.0))) .* cs.const_m1615735228018878911) ./ 1.0468957512717258) .* cs.const_1871829889889080582) .* 0.04002679875215723) ./ 0.008035880643729008 - mul!(cs.cache_6377132265167146240, cs.const_4022673044584674996, cs.cache_7084643733393507988) - mul!(cs.cache_m6244145936812788240, cs.const_4022673044584674996, cs.cache_7729892376240732805) - cs.cache_1105677131701825845[1:20] .= (@view y[1302:1321]) - cs.cache_1105677131701825845[21:40] .= (@view y[1322:1341]) - cs.cache_1105677131701825845[41:60] .= (@view y[1342:1361]) - mul!(cs.cache_m4559336614180109070, cs.const_4742260312915039474, cs.cache_1105677131701825845) - mul!(cs.cache_5964596193839440387, cs.const_m2239172306025069482, cs.cache_m4559336614180109070) - cs.cache_6453636296210224079 .= (0.008035880643729008 .* cs.cache_7729892376240732805) .* cs.const_7749124486072430752 - mul!(cs.cache_m7958094614900297101, cs.const_4022673044584674996, cs.cache_6453636296210224079) - cs.cache_8188036567708323486 .= (((cs.cache_m7220358040310595472 .+ cs.cache_774339592884572080) .* cs.cache_m1168385265453438253) .+ ((cs.const_m344729034815622734 .* (cs.cache_6377132265167146240 .* (((cs.const_m6293037495340517372 .* cs.cache_m1168385265453438253) ./ cs.cache_m6244145936812788240) .- cs.cache_5964596193839440387))) ./ 0.04002679875215723)) .+ cs.cache_m7958094614900297101 - mul!(cs.cache_m6645337912123003706, cs.const_2155620181971259577, cs.cache_8188036567708323486) - cs.cache_m1572333326302305327 .= -cs.cache_m6645337912123003706 - cs.cache_4444843852540613429[1:20] .= ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725)))))) - cs.cache_4444843852540613429[21:40] .= cs.const_2673546356631690987 - cs.cache_4444843852540613429[41:60] .= ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725)))))) - cs.cache_8316190851790556232[1:1] .= cs.const_m1032606879019717969 - cs.cache_8316190851790556232[2:601] .= (cs.const_m6466908670533079333 .* (cs.const_m919967631435488369 .* cs.cache_3559064883010407825)) - cs.cache_8316190851790556232[602:1201] .= (cs.const_844432128953615761 .* (cs.const_m919967631435488369 .* cs.cache_m4186862615729982588)) - cs.cache_8316190851790556232[1202:1261] .= (cs.const_5356335722306557041 .* ((((cs.cache_m1572333326302305327 ./ 0.008035880643729008) .+ (((cs.const_2100260670751548208 .+ (cs.const_m3704159319882291581 .* cs.cache_4444843852540613429)) .+ cs.const_2100260670751548208) ./ 0.04002679875215723)) .- (cs.cache_7729892376240732805 .* cs.const_7749124486072430752)) .- (cs.cache_7729892376240732805 .* cs.const_7749124486072430752))) - mul!(cs.cache_6281528158126438668, cs.const_1509603028080037696, (@view y[1262:1281])) - mul!(cs.cache_244133575886292095, cs.const_9168352019723563689, cs.cache_6281528158126438668) - mul!(cs.cache_1480199951838108910, cs.const_m6337143657829181592, cs.cache_244133575886292095) - cs.cache_m8825037627629645404 .= cs.const_m4831381568644549996 .* cs.cache_1480199951838108910 - mul!(cs.cache_m4463903973878375467, cs.const_9168352019723563689, cs.cache_m8825037627629645404) - mul!(cs.cache_m5204106969040429111, cs.const_6715966457835164428, (@view y[1282:1301])) - mul!(cs.cache_m8118013018143870756, cs.const_m6076020440529072554, cs.cache_m5204106969040429111) - cs.cache_7899744126569850954 .= cs.const_m1453791953686693439 .* (cs.cache_m8118013018143870756 .+ cs.const_8366588851195495623) - mul!(cs.cache_m8486204412392847702, cs.const_9168352019723563689, cs.cache_7899744126569850954) - mul!(cs.cache_6953277061565774920, cs.const_2155620181971259577, cs.cache_6730866441417284015) - cs.cache_7545625011893614278[1:20] .= (cs.cache_m4463903973878375467 .+ (cs.const_6284853627393591686 .* ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725)))))))) - cs.cache_7545625011893614278[21:40] .= (cs.cache_m8486204412392847702 .+ (cs.const_m8371260504451653468 .* ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725)))))))) - cs.cache_7545625011893614278[41:100] .= (cs.cache_6953277061565774920 .- (cs.const_m2268798281525233596 .* ((cs.const_7749124486072430752 .+ cs.cache_4444843852540613429) .+ cs.const_7749124486072430752))) - dy[1:1261] .= cs.cache_8316190851790556232 - dy[1262:1361] .= cs.cache_7545625011893614278 - end + 49,50,51,52,53,54,55,56,57,58,59,60], [0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, + 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, + 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, + 0.02222222,0.02222222,0.00555556,0.00555556,0.00555556,0.00555556, + 0.00555556,0.00555556,0.00555556,0.00555556,0.00555556,0.00555556, + 0.00555556,0.00555556,0.00555556,0.00555556,0.00555556,0.00555556, + 0.00555556,0.00555556,0.00555556,0.00555556,0.02222222,0.02222222, + 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, + 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, + 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222], 1, 60), + const_m836363707967227454 = 0.08922778287712851, + const_m2099015146737727157 = 1.0, + const_m3731019977586676618 = 0.1643167672515498, + const_9098493608742964394 = 0.9999999999999999, + const_6560875588504410658 = [1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2, + 1.2,1.2], + const_m8721193489185815234 = 0.20076251147353916, + const_m887411406143043211 = 0.16431676725154978, + const_m7098007253014595426 = [0.00975309,0.02851852,0.0462963 ,0.06308642,0.07888889,0.0937037 , + 0.10753086,0.12037037,0.13222222,0.14308642,0.15296296,0.16185185, + 0.16975309,0.17666667,0.18259259,0.18753086,0.19148148,0.19444444, + 0.19641975,0.19740741], + const_6638868103325447887 = 0.11153472859641064, + const_m358324611044111996 = 0.05064016622195792, + const_m5057362321874500390 = [0.04624493,0.04631098,0.04644309,0.04664124,0.04690545,0.04723572, + 0.04763203,0.0480944 ,0.04862282,0.04921729,0.04987781,0.05060439, + 0.05139702,0.0522557 ,0.05318043,0.05417122,0.05522806,0.05635095, + 0.05753989,0.05879488], + cache_3915606029483975135 = zeros(1), + cache_959261321572005728 = zeros(20), + cache_m3206663273767608132 = zeros(1), + cache_8147124925464309775 = zeros(20), + cache_m7276528384970331289 = zeros(20), + cache_m1499541469728327654 = zeros(1), + cache_m2825253393613765537 = zeros(1), + cache_640754690756395244 = zeros(20), + cache_6711155880308569207 = zeros(1), + cache_m8191789462605491070 = zeros(20), + cache_m735068602063420310 = zeros(20), + cache_m2737248814353521814 = zeros(1), + cache_m8937655955816370474 = zeros(60), + cache_m7903676841323904382 = zeros(1), + cache_4951424073511713159 = zeros(20), + cache_m3708658618337972127 = zeros(20), + cache_m821629956291150857 = zeros(1), + cache_m2710349119673370670 = zeros(1), + cache_m5408670181879547603 = zeros(20), + cache_8616547535697387985 = zeros(20), + cache_3928631964573574281 = zeros(1), + cache_8080731599320426571 = zeros(20), + cache_m1569211042726296739 = zeros(1), + cache_6958716317680719368 = zeros(20), + cache_m3159910331817368091 = zeros(20), + cache_7491403280521532656 = zeros(1), + cache_2097128636677903600 = zeros(1), + cache_5746692283934222791 = zeros(20), + cache_4358330042817845608 = zeros(20), + cache_m5214664370647379083 = zeros(1), +) - end +function f_with_consts(dy, y, p, t) + mul!(cs.cache_3915606029483975135, cs.const_1388564590504212564, (@view y[32:61])) + mul!(cs.cache_959261321572005728, cs.const_1744480757062911249, cs.cache_3915606029483975135) + cs.cache_m3206663273767608132 .= ((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_3915606029483975135))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_3915606029483975135))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_3915606029483975135))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_3915606029483975135))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_3915606029483975135)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_3915606029483975135) .- 0.525) ./ 0.006))))) .+ (cs.const_8752233790552333983 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_3915606029483975135)))))) .^ 2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_3915606029483975135))))) .^ -2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_3915606029483975135))))) .^ -2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_3915606029483975135))))) .^ -2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_3915606029483975135)) .+ 0.56478) ./ 0.1316))) .^ -2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_3915606029483975135) .- 0.525) ./ 0.006))) .^ -2.0))))) .- 4.027013847342062) ./ 0.025692579121493725 + mul!(cs.cache_8147124925464309775, cs.const_1744480757062911249, cs.cache_m3206663273767608132) + cs.cache_m7276528384970331289 .= (cs.const_m2794236520912209521 .* (asinh.((cs.const_m942165513388665034 ./ (2.0 .* ((2.05008960573477 .* ((((cs.const_m1232301553800524044 .* (((@view y[102:121]) .* 1000.0) .^ 0.5)) .* ((cs.cache_959261321572005728 .* 51217.9257309275) .^ 0.5)) .* ((51217.9257309275 .- (cs.cache_959261321572005728 .* 51217.9257309275)) .^ 0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)))))) .+ cs.cache_8147124925464309775 + mul!(cs.cache_m1499541469728327654, cs.const_m8518220820285355445, cs.cache_m7276528384970331289) + mul!(cs.cache_m2825253393613765537, cs.const_1388564590504212564, (@view y[2:31])) + mul!(cs.cache_640754690756395244, cs.const_1744480757062911249, cs.cache_m2825253393613765537) + cs.cache_6711155880308569207 .= (((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m2825253393613765537))))) .+ (0.0351 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.105) ./ 0.029))))) .+ (cs.const_8752233790552333983 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m2825253393613765537)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.286) ./ 0.083))) .^ -2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.849) ./ 0.119))) .^ -2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.9233) ./ 0.05))) .^ -2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.5) ./ 0.034))) .^ -2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.194) ./ 0.142))) .^ -2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.9) ./ 0.0164))) .^ -2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.124) ./ 0.0226))) .^ -2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.105) ./ 0.029))) .^ -2.0))))) .- 0.175193184028335) ./ 0.025692579121493725 + mul!(cs.cache_m8191789462605491070, cs.const_1744480757062911249, cs.cache_6711155880308569207) + cs.cache_m735068602063420310 .= (cs.const_m6459359983097884347 .* (asinh.((cs.const_8416676264869710905 ./ (2.0 .* (((((cs.const_m2775764531995498168 .* (((@view y[62:81]) .* 1000.0) .^ 0.5)) .* ((cs.cache_640754690756395244 .* 24983.2619938437) .^ 0.5)) .* ((24983.2619938437 .- (cs.cache_640754690756395244 .* 24983.2619938437)) .^ 0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)))))) .+ cs.cache_m8191789462605491070 + mul!(cs.cache_m2737248814353521814, cs.const_m8518220820285355445, cs.cache_m735068602063420310) + cs.cache_m8937655955816370474[1:20] .= (@view y[62:81]) + cs.cache_m8937655955816370474[21:40] .= (@view y[82:101]) + cs.cache_m8937655955816370474[41:60] .= (@view y[102:121]) + mul!(cs.cache_m7903676841323904382, cs.const_m4908013908935754244, cs.cache_m8937655955816370474) + mul!(cs.cache_4951424073511713159, cs.const_1744480757062911249, cs.cache_m7903676841323904382) + cs.cache_m3708658618337972127 .= log.(((@view y[62:81]) ./ cs.cache_4951424073511713159)) + mul!(cs.cache_m821629956291150857, cs.const_m8518220820285355445, cs.cache_m3708658618337972127) + cs.cache_m2710349119673370670 .= (((-(cs.cache_m2737248814353521814 ./ 0.4444444444444445)) .+ cs.const_m3780420342443263966) .- (cs.const_m3587115650644734227 .* (cs.cache_m821629956291150857 ./ 0.4444444444444445))) .- (cs.const_m836363707967227454 .* ((1.0 ./ (3.0 .* ((((((0.0911 .+ (1.9101 .* ((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 2.0))) .+ (0.1554 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 3.0))) .* cs.const_m2099015146737727157) ./ 1.0468957512717258) .* cs.const_m3731019977586676618))) .- (1.0 ./ ((((((0.0911 .+ (1.9101 .* ((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 2.0))) .+ (0.1554 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 3.0))) .* cs.const_m2099015146737727157) ./ 1.0468957512717258) .* cs.const_9098493608742964394)))) + mul!(cs.cache_m5408670181879547603, cs.const_1744480757062911249, cs.cache_m2710349119673370670) + mul!(cs.cache_8616547535697387985, cs.const_1744480757062911249, cs.cache_m7903676841323904382) + cs.cache_3928631964573574281 .= cs.const_m8721193489185815234 ./ ((((((0.0911 .+ (1.9101 .* ((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 2.0))) .+ (0.1554 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 3.0))) .* cs.const_m2099015146737727157) ./ 1.0468957512717258) .* cs.const_m887411406143043211) + mul!(cs.cache_8080731599320426571, cs.const_1744480757062911249, cs.cache_3928631964573574281) + cs.cache_m1569211042726296739 .= cs.const_6638868103325447887 ./ ((((((0.0911 .+ (1.9101 .* ((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 2.0))) .+ (0.1554 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 3.0))) .* cs.const_m2099015146737727157) ./ 1.0468957512717258) .* cs.const_9098493608742964394) + mul!(cs.cache_6958716317680719368, cs.const_1744480757062911249, cs.cache_m1569211042726296739) + cs.cache_m3159910331817368091 .= ((cs.cache_m5408670181879547603 .+ (cs.const_6560875588504410658 .* (log.(((@view y[102:121]) ./ cs.cache_8616547535697387985))))) .- ((cs.cache_8080731599320426571 .* cs.const_m7098007253014595426) ./ 0.888888888888889)) .- cs.cache_6958716317680719368 + mul!(cs.cache_7491403280521532656, cs.const_m8518220820285355445, cs.cache_m3159910331817368091) + cs.cache_2097128636677903600 .= ((cs.cache_m1499541469728327654 ./ 0.4444444444444445) .+ (cs.cache_7491403280521532656 ./ 0.4444444444444445)) .+ cs.const_m358324611044111996 + mul!(cs.cache_5746692283934222791, cs.const_1744480757062911249, cs.cache_2097128636677903600) + cs.cache_4358330042817845608 .= cs.cache_5746692283934222791 .- cs.const_m5057362321874500390 + mul!(cs.cache_m5214664370647379083, cs.const_m4822311374121275919, cs.cache_4358330042817845608) + dy .= 3.8518206633137266 .+ (cs.cache_m5214664370647379083 .* 0.025692579121493725) end -u0 = [ 0.00000000e+00, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, 8.00000000e-01, - 8.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, 6.00000000e-01, - 6.00000000e-01, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00,-5.02477561e-05,-1.47288017e-04,-2.40854214e-04, - -3.30906208e-04,-4.17382278e-04,-5.00198739e-04,-5.79249418e-04, - -6.54404992e-04,-7.25512172e-04,-7.92392744e-04,-8.54842448e-04, - -9.12629680e-04,-9.65494034e-04,-1.01314463e-03,-1.05525828e-03, - -1.09147734e-03,-1.12140750e-03,-1.14461508e-03,-1.16062427e-03, - -1.16891389e-03,-3.10835420e+00,-3.10842621e+00,-3.10856924e+00, - -3.10878237e+00,-3.10906475e+00,-3.10941558e+00,-3.10983414e+00, - -3.11031975e+00,-3.11087180e+00,-3.11148975e+00,-3.11217308e+00, - -3.11292135e+00,-3.11373418e+00,-3.11461121e+00,-3.11555215e+00, - -3.11655676e+00,-3.11762485e+00,-3.11875628e+00,-3.11995094e+00, - -3.12120879e+00,-1.44988336e-01,-1.45873084e-01,-1.47647397e-01, - -1.50321554e-01,-1.53911357e-01,-1.58438237e-01,-1.63929378e-01, - -1.70417896e-01,-1.77943041e-01,-1.86550447e-01,-1.96292417e-01, - -2.07228254e-01,-2.19424638e-01,-2.32956051e-01,-2.47905251e-01, - -2.64363809e-01,-2.82432701e-01,-3.02222966e-01,-3.23856445e-01, - -3.47466589e-01,-3.52006083e-01,-3.53063164e-01,-3.54120246e-01, - -3.55177327e-01,-3.56234409e-01,-3.57291491e-01,-3.58348572e-01, - -3.59405654e-01,-3.60462735e-01,-3.61519817e-01,-3.62576899e-01, - -3.63633980e-01,-3.64691062e-01,-3.65748143e-01,-3.66805225e-01, - -3.67862307e-01,-3.68919388e-01,-3.69976470e-01,-3.71033551e-01, - -3.72090633e-01,-3.76630126e-01,-4.00960204e-01,-4.23906866e-01, - -4.45488050e-01,-4.65720405e-01,-4.84619335e-01,-5.02199042e-01, - -5.18472566e-01,-5.33451820e-01,-5.47147616e-01,-5.59569701e-01, - -5.70726774e-01,-5.80626515e-01,-5.89275599e-01,-5.96679715e-01, - -6.02843579e-01,-6.07770949e-01,-6.11464627e-01,-6.13926473e-01, - -6.15157406e-01] -du0 = zeros(1361) -f(du0,u0,0,0) -du0 - -mul!(cs.cache_m8690271296156904125, cs.const_m3854548607110444668, (@view y[2:601])) -mul!(cs.cache_7735162028737694396, cs.const_m810426824042609992, cs.cache_m8690271296156904125) -mul!(cs.cache_m4432716267967134655, cs.const_83118777604549222, (@view y[2:601])) -cs.cache_1416156281203053579 .= (((-0.11346284738694776 .* ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725))))))) .* cs.const_6284853627393591686) ./ 1.7999999999999998) ./ cs.const_6284853627393591686 -mul!(cs.cache_3837998097161001762, cs.const_419985987929628265, cs.cache_1416156281203053579) -cs.cache_m2349735126975898980 .= cs.const_m6370830283027149840 .* (cs.const_5256068128236031296 .* (cs.cache_7735162028737694396 .+ cs.cache_3837998097161001762)) -mul!(cs.cache_3559064883010407825, cs.const_1477443756317609848, cs.cache_m2349735126975898980) -mul!(cs.cache_m5236042054648721177, cs.const_m3854548607110444668, (@view y[602:1201])) -mul!(cs.cache_4552822235374881625, cs.const_m810426824042609992, cs.cache_m5236042054648721177) -mul!(cs.cache_6385594400131391611, cs.const_83118777604549222, (@view y[602:1201])) -cs.cache_3669255876411325857 .= ((((-0.04425051048090962 .* ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725))))))) .* cs.const_m8371260504451653468) ./ 1.5000000000000002) ./ 2.05008960573477) ./ cs.const_m8371260504451653468 -mul!(cs.cache_m5979984690307217085, cs.const_419985987929628265, cs.cache_3669255876411325857) -cs.cache_4085014493431324638 .= cs.const_m6370830283027149840 .* (cs.const_3206463238628087733 .* (cs.cache_4552822235374881625 .+ cs.cache_m5979984690307217085)) -mul!(cs.cache_m4186862615729982588, cs.const_1477443756317609848, cs.cache_4085014493431324638) -cs.cache_7729892376240732805[1:20] .= (@view y[1202:1221]) -cs.cache_7729892376240732805[21:40] .= (@view y[1222:1241]) -cs.cache_7729892376240732805[41:60] .= (@view y[1242:1261]) -cs.cache_m5983176047089085323 .= cs.const_4910271190053899160 .* (((5.34e-10 .* (exp.(((-0.65 .* (cs.cache_7729892376240732805 .* 1000.0)) ./ 1000.0)))) .* cs.const_m1615735228018878911) ./ 2.7877244479038255e-10) -mul!(cs.cache_m7220358040310595472, cs.const_m6406009788656677430, cs.cache_m5983176047089085323) -mul!(cs.cache_2958147717725554841, cs.const_7492635389435296866, cs.cache_m5983176047089085323) -mul!(cs.cache_6584089953429348159, cs.const_m2551856243850624398, cs.cache_m5983176047089085323) -cs.cache_m2205063840212872182 .= (cs.cache_2958147717725554841 .* cs.cache_6584089953429348159) ./ (((cs.cache_6584089953429348159 .* cs.const_8229859839001814964) .+ (cs.cache_2958147717725554841 .* cs.const_m8826988669266821604)) .+ 1e-16) -mul!(cs.cache_774339592884572080, cs.const_m2239172306025069482, cs.cache_m2205063840212872182) -mul!(cs.cache_956044674773232170, cs.const_4742260312915039474, cs.cache_7729892376240732805) -mul!(cs.cache_m1168385265453438253, cs.const_m2239172306025069482, cs.cache_956044674773232170) -cs.cache_7084643733393507988 .= (((((((0.0911 .+ (1.9101 .* ((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0).^2.0))) .+ (0.1554 .* (((cs.cache_7729892376240732805 .* 1000.0) ./ 1000.0).^3.0))) .* cs.const_m1615735228018878911) ./ 1.0468957512717258) .* cs.const_1871829889889080582) .* 0.04002679875215723) ./ 0.008035880643729008 -mul!(cs.cache_6377132265167146240, cs.const_4022673044584674996, cs.cache_7084643733393507988) -mul!(cs.cache_m6244145936812788240, cs.const_4022673044584674996, cs.cache_7729892376240732805) -cs.cache_1105677131701825845[1:20] .= (@view y[1302:1321]) -cs.cache_1105677131701825845[21:40] .= (@view y[1322:1341]) -cs.cache_1105677131701825845[41:60] .= (@view y[1342:1361]) -mul!(cs.cache_m4559336614180109070, cs.const_4742260312915039474, cs.cache_1105677131701825845) -mul!(cs.cache_5964596193839440387, cs.const_m2239172306025069482, cs.cache_m4559336614180109070) -cs.cache_6453636296210224079 .= (0.008035880643729008 .* cs.cache_7729892376240732805) .* cs.const_7749124486072430752 -mul!(cs.cache_m7958094614900297101, cs.const_4022673044584674996, cs.cache_6453636296210224079) -cs.cache_8188036567708323486 .= (((cs.cache_m7220358040310595472 .+ cs.cache_774339592884572080) .* cs.cache_m1168385265453438253) .+ ((cs.const_m344729034815622734 .* (cs.cache_6377132265167146240 .* (((cs.const_m6293037495340517372 .* cs.cache_m1168385265453438253) ./ cs.cache_m6244145936812788240) .- cs.cache_5964596193839440387))) ./ 0.04002679875215723)) .+ cs.cache_m7958094614900297101 -mul!(cs.cache_m6645337912123003706, cs.const_2155620181971259577, cs.cache_8188036567708323486) -cs.cache_m1572333326302305327 .= -cs.cache_m6645337912123003706 -cs.cache_4444843852540613429[1:20] .= ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725)))))) -cs.cache_4444843852540613429[21:40] .= cs.const_2673546356631690987 -cs.cache_4444843852540613429[41:60] .= ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725)))))) -cs.cache_8316190851790556232[1:1] .= cs.const_m1032606879019717969 -cs.cache_8316190851790556232[2:601] .= (cs.const_m6466908670533079333 .* (cs.const_m919967631435488369 .* cs.cache_3559064883010407825)) -cs.cache_8316190851790556232[602:1201] .= (cs.const_844432128953615761 .* (cs.const_m919967631435488369 .* cs.cache_m4186862615729982588)) -cs.cache_8316190851790556232[1202:1261] .= (cs.const_5356335722306557041 .* ((((cs.cache_m1572333326302305327 ./ 0.008035880643729008) .+ (((cs.const_2100260670751548208 .+ (cs.const_m3704159319882291581 .* cs.cache_4444843852540613429)) .+ cs.const_2100260670751548208) ./ 0.04002679875215723)) .- (cs.cache_7729892376240732805 .* cs.const_7749124486072430752)) .- (cs.cache_7729892376240732805 .* cs.const_7749124486072430752))) -mul!(cs.cache_6281528158126438668, cs.const_1509603028080037696, (@view y[1262:1281])) -mul!(cs.cache_244133575886292095, cs.const_9168352019723563689, cs.cache_6281528158126438668) -mul!(cs.cache_1480199951838108910, cs.const_m6337143657829181592, cs.cache_244133575886292095) -cs.cache_m8825037627629645404 .= cs.const_m4831381568644549996 .* cs.cache_1480199951838108910 -mul!(cs.cache_m4463903973878375467, cs.const_9168352019723563689, cs.cache_m8825037627629645404) -mul!(cs.cache_m5204106969040429111, cs.const_6715966457835164428, (@view y[1282:1301])) -mul!(cs.cache_m8118013018143870756, cs.const_m6076020440529072554, cs.cache_m5204106969040429111) -cs.cache_7899744126569850954 .= cs.const_m1453791953686693439 .* (cs.cache_m8118013018143870756 .+ cs.const_8366588851195495623) -mul!(cs.cache_m8486204412392847702, cs.const_9168352019723563689, cs.cache_7899744126569850954) -mul!(cs.cache_6953277061565774920, cs.const_2155620181971259577, cs.cache_6730866441417284015) -cs.cache_7545625011893614278[1:20] .= (cs.cache_m4463903973878375467 .+ (cs.const_6284853627393591686 .* ((2.0 .* (((((cs.const_m9126168015536320261 .* (((@view y[1202:1221]) .* 1000.0).^0.5)) .* ((cs.cache_m4432716267967134655 .* 24983.2619938437).^0.5)) .* ((24983.2619938437 .- (cs.cache_m4432716267967134655 .* 24983.2619938437)).^0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)) .* (sinh.((cs.const_1845266373960578514 .* (((@view y[1262:1281]) .- (@view y[1302:1321])) .- ((((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m4432716267967134655))))) .+ (0.0351 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))))) .+ (cs.const_6438113274932828980 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m4432716267967134655)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.286) ./ 0.083))).^-2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.849) ./ 0.119))).^-2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9233) ./ 0.05))).^-2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.5) ./ 0.034))).^-2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.194) ./ 0.142))).^-2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.9) ./ 0.0164))).^-2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.124) ./ 0.0226))).^-2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m4432716267967134655 .- 0.105) ./ 0.029))).^-2.0))))) .- 0.175193184028335) ./ 0.025692579121493725)))))))) -cs.cache_7545625011893614278[21:40] .= (cs.cache_m8486204412392847702 .+ (cs.const_m8371260504451653468 .* ((2.0 .* ((2.05008960573477 .* ((((cs.const_7674564103979747454 .* (((@view y[1242:1261]) .* 1000.0).^0.5)) .* ((cs.cache_6385594400131391611 .* 51217.9257309275).^0.5)) .* ((51217.9257309275 .- (cs.cache_6385594400131391611 .* 51217.9257309275)).^0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)) .* (sinh.((cs.const_1237538932840516848 .* (((@view y[1282:1301]) .- (@view y[1342:1361])) .- (((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))))) .+ (cs.const_m8218000856912416174 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_6385594400131391611)))))).^2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_6385594400131391611))))).^-2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_6385594400131391611)) .+ 0.56478) ./ 0.1316))).^-2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_6385594400131391611) .- 0.525) ./ 0.006))).^-2.0))))) .- 4.027013847342062) ./ 0.025692579121493725)))))))) -cs.cache_7545625011893614278[41:100] .= (cs.cache_6953277061565774920 .- (cs.const_m2268798281525233596 .* ((cs.const_7749124486072430752 .+ cs.cache_4444843852540613429) .+ cs.const_7749124486072430752))) -dy[1:1261] .= cs.cache_8316190851790556232 -dy[1262:1361] .= cs.cache_7545625011893614278 \ No newline at end of file +end +end \ No newline at end of file From f379a38312c7c920acc8ded36316e44b605991f9 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 2 Dec 2020 15:02:31 -0500 Subject: [PATCH 33/88] #1129 get simple heat equation working --- .gitignore | 3 + Project.toml | 4 + .../operations/evaluate_julia.py | 229 ++++++++++++------ test.jl | 198 +++++---------- tests/unit/test_solvers/test_julia_mtk.py | 33 ++- 5 files changed, 245 insertions(+), 222 deletions(-) create mode 100644 Project.toml diff --git a/.gitignore b/.gitignore index 45764bf036..cf1bfd4ad1 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,6 @@ setup.log # tox .tox/ +# Julia +Manifest.toml + diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000000..e628883af2 --- /dev/null +++ b/Project.toml @@ -0,0 +1,4 @@ +[deps] +DiffEqOperators = "9fdde737-9c7f-55bf-ade8-46b3f136cc48" +DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 4927d40dd7..7dc2a391d5 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -467,6 +467,71 @@ def get_julia_function(symbol, funcname="f"): return julia_str +def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, typ): + """ + Converts a variable and its equation to a julia string + + Parameters + ---------- + var : :class:`pybamm.Symbol` + The variable (key in the dictionary of rhs/algebraic/initial conditions) + eqn : :class:`pybamm.Symbol` + The equation (value in the dictionary of rhs/algebraic/initial conditions) + all_constants_str : str + String containing all the constants defined so far + all_variables_str : str + String containing all the variables defined so far + typ : str + The type of the variable/equation pair being converted ("equation", "initial + condition", or "boundary condition") + + Returns + ------- + all_constants_str : str + Updated string of all constants + all_variables_str : str + Updated string of all variables + eqn_str : str + The string describing the final equation result, perhaps as a function of some + variables and/or constants in all_constants_str and all_variables_str + + """ + constants, variable_symbols = to_julia(eqn)[:2] + line_format = "{} .= {}" + + variables_str = "\n".join( + [ + f"{id_to_julia_variable(symbol_id)} = {symbol_line}" + for symbol_id, symbol_line in variable_symbols.items() + ] + ) + + # extract constants in generated function + for eqn_id, const_value in constants.items(): + const_name = id_to_julia_variable(eqn_id, True) + all_constants_str += "{} = {}\n".format(const_name, const_value) + # TODO: avoid repeated constants definitions + + # add a comment labeling the equation, and the equation itself + if variables_str == "": + all_variables_str += "" + else: + all_variables_str += f"# '{var.name}' {typ}\n" + variables_str + "\n" + + # calculate the final variable that will output the result + result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) + if eqn.is_constant(): + result_value = eqn.evaluate() + + # define the variable that goes into the equation + if eqn.is_constant() and isinstance(result_value, numbers.Number): + eqn_str = str(result_value) + else: + eqn_str = result_var + + return all_constants_str, all_variables_str, eqn_str + + def get_julia_mtk_model(model, geometry=None, tspan=None): """ Converts a pybamm model into a Julia ModelingToolkit model @@ -521,16 +586,17 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Makes a line of the form '@variables u1(t) u2(t)' dep_vars = list(variable_id_to_number.values()) mtk_str += "@variables" + var_to_ind_vars = {} for var in variables: if var.domain == []: - var_ind_vars = "(t)" + var_to_ind_vars[var.id] = "(t)" else: - var_ind_vars = ( + var_to_ind_vars[var.id] = ( "(t, " + ", ".join([domain_name_to_symbol[dom] for dom in var.domain]) + ")" ) - mtk_str += f" {variable_id_to_number[var.id]}{var_ind_vars}" + mtk_str += f" {variable_id_to_number[var.id]}(..)" mtk_str += "\n" # Define derivatives @@ -548,48 +614,25 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): all_constants_str = "" all_julia_str = "" for var, eqn in {**model.rhs, **model.algebraic}.items(): - constants, variable_symbols = to_julia(eqn)[:2] - line_format = "{} .= {}" - - julia_str = "\n".join( - [ - f"{id_to_julia_variable(symbol_id)} = {symbol_line}" - for symbol_id, symbol_line in variable_symbols.items() - ] + all_constants_str, all_julia_str, eqn_str = convert_var_and_eqn_to_str( + var, eqn, all_constants_str, all_julia_str, "equation" ) - - # extract constants in generated function - for eqn_id, const_value in constants.items(): - const_name = id_to_julia_variable(eqn_id, True) - all_constants_str += "{} = {}\n".format(const_name, const_value) - - # add a comment labeling the equation, and the equation itself - if julia_str == "": - all_julia_str = "" - else: - all_julia_str += f"# '{var.name}' equation\n" + julia_str + "\n" - - # calculate the final variable that will output the result - result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) - if eqn.is_constant(): - result_value = eqn.evaluate() - - # define the variable that goes into the equation - if eqn.is_constant() and isinstance(result_value, numbers.Number): - eqn_str = str(result_value) - else: - eqn_str = result_var + # add if var in model.rhs: - all_eqns_str += f" Dt({variable_id_to_number[var.id]}) ~ {eqn_str},\n" + all_eqns_str += ( + f" Dt({variable_id_to_number[var.id]}{var_to_ind_vars[var.id]}) " + + f"~ {eqn_str},\n" + ) elif var in model.algebraic: all_eqns_str += f" 0 ~ {eqn_str},\n" # Replace variables in the julia strings that correspond to pybamm variables with # their julia equivalent + # e.g. cache_123456789 gets replaced with u1(t, x) for var_id, julia_id in variable_id_to_number.items(): all_julia_str = all_julia_str.replace( - id_to_julia_variable(var_id, False), julia_id + id_to_julia_variable(var_id, False), julia_id + var_to_ind_vars[var_id] ) # Replace independent variables (domain names) in julia strings with the @@ -600,7 +643,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Replace parameters in the julia strings in the form "inputs[name]" # with just "name" for param in model.input_parameters: - # Replace 'var_id' with 'paran.name' + # Replace 'var_id' with 'param.name' all_julia_str = all_julia_str.replace( id_to_julia_variable(param.id, False), param.name ) @@ -612,11 +655,79 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Update the MTK string mtk_str += all_constants_str + all_julia_str + "\n" + f"eqs = [\n{all_eqns_str}]\n" + #################################################################################### + # Initial and boundary conditions + #################################################################################### + # Initial conditions + all_ic_bc_str = "" + all_ic_bc_constants_str = "" + all_ic_bc_julia_str = "" + for var, eqn in model.initial_conditions.items(): + ( + all_ic_bc_constants_str, + all_ic_bc_julia_str, + eqn_str, + ) = convert_var_and_eqn_to_str( + var, eqn, all_ic_bc_constants_str, all_ic_bc_julia_str, "initial condition" + ) + + if not is_pde: + all_ic_bc_str += f" {variable_id_to_number[var.id]}(t) => {eqn_str},\n" + else: + doms = ", ".join([domain_name_to_symbol[dom] for dom in var.domain]) + all_ic_bc_str += ( + f" {variable_id_to_number[var.id]}(0, {doms}) ~ {eqn_str},\n" + ) + # Boundary conditions + if is_pde: + for var, eqn_side in model.boundary_conditions.items(): + for side, (eqn, typ) in eqn_side.items(): + ( + all_ic_bc_constants_str, + all_ic_bc_julia_str, + eqn_str, + ) = convert_var_and_eqn_to_str( + var, + eqn, + all_ic_bc_constants_str, + all_ic_bc_julia_str, + "boundary condition", + ) + + geom = list(geometry[var.domain[0]].values())[0] + if side == "left": + limit = geom["min"] + elif side == "right": + limit = geom["max"] + if typ == "Dirichlet": + pass + elif typ == "Neumann": + raise NotImplementedError + all_ic_bc_str += ( + f" {variable_id_to_number[var.id]}(t, {limit}) ~ {eqn_str},\n" + ) + + #################################################################################### + # Create ODESystem or PDESystem if not is_pde: mtk_str += "sys = ODESystem(eqs, t)\n\n" + mtk_str += ( + all_ic_bc_constants_str + + all_ic_bc_julia_str + + "\n" + + f"u0 = [\n{all_ic_bc_str}]\n" + ) else: - # Create domains + # Initial and boundary conditions + mtk_str += ( + all_ic_bc_constants_str + + all_ic_bc_julia_str + + "\n" + + f"ics_bcs = [\n{all_ic_bc_str}]\n" + ) + + # Domains mtk_str += "\n" mtk_str += f"t_domain = IntervalDomain({tspan[0]}, {tspan[1]})\n" domains = f"domains = [\n t in t_domain,\n" @@ -629,51 +740,15 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str += "\n" mtk_str += domains + + # Independent and dependent variables mtk_str += "ind_vars = [{}]\n".format(", ".join(ind_vars)) mtk_str += "dep_vars = [{}]\n\n".format(", ".join(dep_vars)) - mtk_str += "sys = PDESystem(eqs, bcs, domains, ind_vars, dep_vars)\n\n" - - # Create initial conditions - all_ics_str = "" - all_constants_str = "" - all_julia_str = "" - for var, eqn in model.initial_conditions.items(): - constants, variable_symbols = to_julia(eqn)[:2] - - julia_str = "\n".join( - [ - f"{id_to_julia_variable(symbol_id)} = {symbol_line}" - for symbol_id, symbol_line in variable_symbols.items() - ] + mtk_str += ( + "pde_system = PDESystem(eqs, ics_bcs, domains, ind_vars, dep_vars)\n\n" ) - # extract constants in generated function - for eqn_id, const_value in constants.items(): - const_name = id_to_julia_variable(eqn_id, True) - all_constants_str += "{} = {}\n".format(const_name, const_value) - - # add a comment labeling the equation, and the equation itself - if julia_str == "": - all_julia_str = "" - else: - all_julia_str += f"# '{var.name}' initial conditions\n" + julia_str + "\n" - - # calculate the final variable that will output the result - result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) - if eqn.is_constant(): - result_value = eqn.evaluate() - - # define the variable that goes into the equation - if eqn.is_constant() and isinstance(result_value, numbers.Number): - eqn_str = str(result_value) - else: - raise pybamm.ModelError - - all_ics_str += f" {variable_id_to_number[var.id]} => {eqn_str},\n" - - mtk_str += all_constants_str + all_julia_str + "\n" + f"u0 = [\n{all_ics_str}]\n" - mtk_str += "end\n" return mtk_str diff --git a/test.jl b/test.jl index 2f570678b2..d9f62fd10d 100644 --- a/test.jl +++ b/test.jl @@ -1,137 +1,67 @@ -using SparseArrays, LinearAlgebra +using ModelingToolkit, DiffEqOperators -cs = (const_m6820315422816856576 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99,100], [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99,100], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.], 101, 100), - const_m6249938662719198354 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, - 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, - 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, - 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, - 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, - 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, - 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, - 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, - 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, - 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, - 100,100], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, - 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, - 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, - 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, - 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, - 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, - 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, - 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, - 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, - 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, - 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99,100, - 100,101], [-120. , 120. ,-120. , 120. ,-120. , - 120. ,-120. , 120. ,-120. , 120. , - -120. , 120. ,-120. , 120. ,-120. , - 120. ,-120. , 120. ,-120. , 120. , - -120. , 120. ,-120. , 120. ,-120. , - 120. ,-120. , 120. ,-120. , 120. , - -120. , 120. ,-120. , 120. ,-120. , - 120. ,-120. , 120. ,-120. , 120. , - -120. , 120. ,-120. , 120. ,-120. , - 120. ,-120. , 120. ,-120. , 120. , - -120. , 120. ,-120. , 120. ,-120. , - 120. ,-120. , 120. ,-120. , 120. , - -120. , 120. ,-120. , 120. ,-120. , - 120. ,-120. , 120. ,-120. , 120. , - -120. , 120. ,-120. , 120. ,-120. , - 120. ,-120. , 120. ,-120. , 120. , - -92.30769231, 92.30769231, -75. , 75. , -75. , - 75. , -75. , 75. , -75. , 75. , - -75. , 75. , -75. , 75. , -75. , - 75. , -75. , 75. , -75. , 75. , - -75. , 75. , -75. , 75. , -75. , - 75. , -75. , 75. , -75. , 75. , - -75. , 75. , -75. , 75. , -75. , - 75. , -75. , 75. , -75. , 75. , - -75. , 75. , -75. , 75. , -75. , - 75. , -75. , 75. , -75. , 75. , - -87.5 , 87.5 ,-105. , 105. ,-105. , - 105. ,-105. , 105. ,-105. , 105. , - -105. , 105. ,-105. , 105. ,-105. , - 105. ,-105. , 105. ,-105. , 105. , - -105. , 105. ,-105. , 105. ,-105. , - 105. ,-105. , 105. ,-105. , 105. , - -105. , 105. ,-105. , 105. ,-105. , - 105. ,-105. , 105. ,-105. , 105. , - -105. , 105. ,-105. , 105. ,-105. , - 105. ,-105. , 105. ,-105. , 105. , - -105. , 105. ,-105. , 105. ,-105. , - 105. ,-105. , 105. ,-105. , 105. , - -105. , 105. ,-105. , 105. ,-105. , - 105. ,-105. , 105. ,-105. , 105. ], 100, 101), - const_79228066988392040 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101], [ 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100], [-1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.], 101, 100), - const_m2973107757891108131 = [2.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.], - const_m3631117290644352711 = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., - 0.,0.,0.,0.,2.], - cache_5378890746278984336 = zeros(101), - cache_m2599068943850039371 = zeros(101), - cache_m7992824528112566971 = zeros(100), - cache_m5645790295110124696 = zeros(101),) +# # 'line' -> x +# @parameters t +# # 'x' -> u1 +# @variables u1(..) +# # @variables u1(t) +# @derivatives Dt'~t -y = [1.00001736, 1.00015625, 1.00043403, 1.00085069, 1.00140625, -1.00210069, 1.00293403, 1.00390625, 1.00501736, 1.00626736, -1.00765625, 1.00918403, 1.01085069, 1.01265625, 1.01460069, -1.01668403, 1.01890625, 1.02126736, 1.02376736, 1.02640625, -1.02918403, 1.03210069, 1.03515625, 1.03835069, 1.04168403, -1.04515625, 1.04876736, 1.05251736, 1.05640625, 1.06043403, -1.06460069, 1.06890625, 1.07335069, 1.07793403, 1.08265625, -1.08751736, 1.09251736, 1.09765625, 1.10293403, 1.10835069, -1.1156 , 1.12484444, 1.13444444, 1.1444 , 1.15471111, -1.16537778, 1.1764 , 1.18777778, 1.19951111, 1.2116 , -1.22404444, 1.23684444, 1.25 , 1.26351111, 1.27737778, -1.2916 , 1.30617778, 1.32111111, 1.3364 , 1.35204444, -1.36804444, 1.3844 , 1.40111111, 1.41817778, 1.4356 , -1.45081633, 1.46369615, 1.47675737, 1.49 , 1.50342404, -1.51702948, 1.53081633, 1.54478458, 1.55893424, 1.57326531, -1.58777778, 1.60247166, 1.61734694, 1.63240363, 1.64764172, -1.66306122, 1.67866213, 1.69444444, 1.71040816, 1.72655329, -1.74287982, 1.75938776, 1.7760771 , 1.79294785, 1.81 , -1.82723356, 1.84464853, 1.8622449 , 1.88002268, 1.89798186, -1.91612245, 1.93444444, 1.95294785, 1.97163265, 1.99049887] -dy = similar(y) +# eqs = [ +# Dt(u1(t)) ~ -1, +# # Dt(u1) ~ -1, +# ] -mul!(cs.cache_5378890746278984336, cs.const_79228066988392040, (@view y[1:100])) -cs.cache_m2599068943850039371 .= cs.cache_5378890746278984336 .+ cs.const_m2973107757891108131 -mul!(cs.cache_m7992824528112566971, cs.const_m6249938662719198354, cs.cache_m2599068943850039371) -mul!(cs.cache_m5645790295110124696, cs.const_m6820315422816856576, cs.cache_m7992824528112566971) -dy .= cs.cache_m5645790295110124696 .+ cs.const_m3631117290644352711 +# # ics = [u1(0) ~ 1] +# ics = [u1(t) => 1] + +# sys = ODESystem(eqs, t) + +# # Convert the PDE problem into an ODE problem +# prob = ODEProblem(sys, ics, (0.0, 10.0)) + +# # Solve ODE problem +# using OrdinaryDiffEq +# sol = solve(prob,Tsit5(),saveat=0.1) +# 'line' -> x +@parameters t x +# 'x' -> u1 +@variables u1(..) +@derivatives Dt'~t +@derivatives Dx'~x + +# 'x' equation +cache_4964620357949541853 = Dx(u1(t,x)) +cache_m2869545278201409051 = Dx(cache_4964620357949541853) + +eqs = [ + Dt(u1(t,x)) ~ cache_m2869545278201409051, +] + +ics_bcs = [u1(0,x) ~ -x*(x-1)*sin(x), +u1(t,0) ~ 0.0, +u1(t,1) ~ 0.0] + +t_domain = IntervalDomain(0.0, 10.0) +x_domain = IntervalDomain(0.0, 1.0) + +domains = [ + t in t_domain, + x in x_domain, +] +ind_vars = [t, x] +dep_vars = [u1] + +pde_system = PDESystem(eqs, ics_bcs, domains, ind_vars, dep_vars) + +# Method of lines discretization +dx = 0.1 +order = 2 +discretization = MOLFiniteDifference(dx,order) + +# Convert the PDE problem into an ODE problem +prob = DiffEqOperators.discretize(pde_system,discretization) + +# Solve ODE problem +using OrdinaryDiffEq +sol = solve(prob,saveat=0.1) \ No newline at end of file diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 86df4aa6dc..d11e3c8686 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -6,8 +6,13 @@ import unittest import numpy as np -# from julia import Main -# from diffeqpy import de +# julia imports +from julia import Main +from julia import Pkg + +Pkg.activate(".") + +from diffeqpy import de class TestCreateSolveMTKModel(unittest.TestCase): @@ -18,7 +23,6 @@ class TestCreateSolveMTKModel(unittest.TestCase): # model.initial_conditions = {v: 0.5} # mtk_str = pybamm.get_julia_mtk_model(model) - # print(mtk_str) # Main.eval("using ModelingToolkit") # Main.eval(mtk_str) @@ -83,7 +87,6 @@ class TestCreateSolveMTKModel(unittest.TestCase): # model.initial_conditions = {x: 1.0, y: 1.0} # mtk_str = pybamm.get_julia_mtk_model(model) - # print(mtk_str) # # Solve using julia # Main.eval("using ModelingToolkit") @@ -108,7 +111,7 @@ def test_pde_model(self): model.rhs = {x: pybamm.div(pybamm.grad(x))} model.initial_conditions = {x: 1.0} model.boundary_conditions = { - x: {"left": (-1, "Neumann"), "right": (1, "Dirichlet")} + x: {"left": (1, "Dirichlet"), "right": (1, "Dirichlet")} } x = pybamm.SpatialVariable("x", domain="line", coord_sys="cartesian") @@ -120,20 +123,28 @@ def test_pde_model(self): print(mtk_str) # Solve using julia - Main.eval("using ModelingToolkit") + Main.eval("using ModelingToolkit, DiffEqOperators") Main.eval(mtk_str) Main.tspan = (0.0, 10.0) - Main.eval("prob = ODEProblem(sys, u0, tspan)") + # Method of lines discretization + Main.dx = 0.1 + Main.order = 2 + Main.eval("discretization = MOLFiniteDifference(dx,order)") + + # Convert the PDE problem into an ODE problem + Main.eval("prob = ModelingToolkit.discretize(pde_system,discretization)") + + # Solve PDE problem sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) y_sol_julia = np.vstack(sol_julia.u).T - # Solve using pybamm - sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, sol_julia.t) + # # Solve using pybamm + # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, sol_julia.t) - # Compare - np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + # # Compare + # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) if __name__ == "__main__": From 28f68ad4714fd0469ad1f8506782bd834597b4c2 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 8 Dec 2020 20:09:44 -0500 Subject: [PATCH 34/88] #1129 get all mtk tests working --- Project.toml | 30 ++++ .../operations/evaluate_julia.py | 4 +- tests/unit/test_solvers/test_julia_mtk.py | 145 +++++++++--------- 3 files changed, 104 insertions(+), 75 deletions(-) diff --git a/Project.toml b/Project.toml index e628883af2..47d61820db 100644 --- a/Project.toml +++ b/Project.toml @@ -1,4 +1,34 @@ [deps] +BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" +CatViews = "81a5f4ea-a946-549a-aa7e-2a7f63a27d31" +ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +DiffEqFlux = "aae7a2af-3d4f-5e19-a356-7da93b79d9d0" DiffEqOperators = "9fdde737-9c7f-55bf-ade8-46b3f136cc48" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" +GalacticOptim = "a75be94c-b780-496d-a8a9-0878b188d577" +IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" +Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +NeuralPDE = "315f7962-48a3-4962-8226-d0f33b1235f0" +Optim = "429524aa-4258-5aef-a3af-852621145aeb" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" +Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +UnitfulRecipes = "42071c24-d89e-48dd-8a24-8a12d9b8861f" diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 7dc2a391d5..2c235f8312 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -749,6 +749,8 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): "pde_system = PDESystem(eqs, ics_bcs, domains, ind_vars, dep_vars)\n\n" ) - mtk_str += "end\n" + # Need to add 'nothing' to the end of the mtk string to avoid errors in MTK v4 + # See https://github.com/SciML/diffeqpy/issues/82 + mtk_str += "nothing\nend\n" return mtk_str diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index d11e3c8686..00446e9393 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -16,93 +16,93 @@ class TestCreateSolveMTKModel(unittest.TestCase): - # def test_exponential_decay_model(self): - # model = pybamm.BaseModel() - # v = pybamm.Variable("v") - # model.rhs = {v: -2 * v} - # model.initial_conditions = {v: 0.5} + def test_exponential_decay_model(self): + model = pybamm.BaseModel() + v = pybamm.Variable("v") + model.rhs = {v: -2 * v} + model.initial_conditions = {v: 0.5} - # mtk_str = pybamm.get_julia_mtk_model(model) + mtk_str = pybamm.get_julia_mtk_model(model) - # Main.eval("using ModelingToolkit") - # Main.eval(mtk_str) + Main.eval("using ModelingToolkit") + Main.eval(mtk_str) - # Main.tspan = (0.0, 10.0) - # # this definition of prob doesn't work, so we use Main.eval instead - # # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) + Main.tspan = (0.0, 10.0) + # this definition of prob doesn't work, so we use Main.eval instead + # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) - # Main.eval("prob = ODEProblem(sys, u0, tspan)") - # sol = de.solve(Main.prob, de.Tsit5()) + Main.eval("prob = ODEProblem(sys, u0, tspan)") + sol = de.solve(Main.prob, de.Tsit5()) - # y_sol = np.concatenate(sol.u) - # y_exact = 0.5 * np.exp(-2 * sol.t) - # np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) + y_sol = np.concatenate(sol.u) + y_exact = 0.5 * np.exp(-2 * sol.t) + np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) - # def test_lotka_volterra_model(self): - # model = pybamm.BaseModel() - # a = pybamm.InputParameter("a") - # b = pybamm.InputParameter("b") - # c = pybamm.InputParameter("c") - # d = pybamm.InputParameter("d") - # x = pybamm.Variable("x") - # y = pybamm.Variable("y") + def test_lotka_volterra_model(self): + model = pybamm.BaseModel() + a = pybamm.InputParameter("a") + b = pybamm.InputParameter("b") + c = pybamm.InputParameter("c") + d = pybamm.InputParameter("d") + x = pybamm.Variable("x") + y = pybamm.Variable("y") - # model.rhs = {x: a * x - b * x * y, y: c * x * y - d * y} - # model.initial_conditions = {x: 1.0, y: 1.0} + model.rhs = {x: a * x - b * x * y, y: c * x * y - d * y} + model.initial_conditions = {x: 1.0, y: 1.0} - # mtk_str = pybamm.get_julia_mtk_model(model) + mtk_str = pybamm.get_julia_mtk_model(model) - # # Solve using julia - # Main.eval("using ModelingToolkit") - # Main.eval(mtk_str) + # Solve using julia + Main.eval("using ModelingToolkit") + Main.eval(mtk_str) - # Main.tspan = (0.0, 10.0) - # Main.eval( - # """ - # begin - # p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0] - # prob = ODEProblem(sys, u0, tspan, p) - # end - # """ - # ) - # sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) + Main.tspan = (0.0, 10.0) + Main.eval( + """ + begin + p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0] + prob = ODEProblem(sys, u0, tspan, p) + end + """ + ) + sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) - # y_sol_julia = np.vstack(sol_julia.u).T + y_sol_julia = np.vstack(sol_julia.u).T - # # Solve using pybamm - # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve( - # model, sol_julia.t, inputs={"a": 1.5, "b": 1.0, "c": 3.0, "d": 1.0} - # ) + # Solve using pybamm + sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve( + model, sol_julia.t, inputs={"a": 1.5, "b": 1.0, "c": 3.0, "d": 1.0} + ) - # # Compare - # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + # Compare + np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) - # def test_dae_model(self): - # model = pybamm.BaseModel() - # x = pybamm.Variable("x") - # y = pybamm.Variable("y") + def test_dae_model(self): + model = pybamm.BaseModel() + x = pybamm.Variable("x") + y = pybamm.Variable("y") - # model.rhs = {x: -2 * x} - # model.algebraic = {y: x - y} - # model.initial_conditions = {x: 1.0, y: 1.0} + model.rhs = {x: -2 * x} + model.algebraic = {y: x - y} + model.initial_conditions = {x: 1.0, y: 1.0} - # mtk_str = pybamm.get_julia_mtk_model(model) + mtk_str = pybamm.get_julia_mtk_model(model) - # # Solve using julia - # Main.eval("using ModelingToolkit") - # Main.eval(mtk_str) + # Solve using julia + Main.eval("using ModelingToolkit") + Main.eval(mtk_str) - # Main.tspan = (0.0, 10.0) - # Main.eval("prob = ODEProblem(sys, u0, tspan)") - # sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) + Main.tspan = (0.0, 10.0) + Main.eval("prob = ODEProblem(sys, u0, tspan)") + sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) - # y_sol_julia = np.vstack(sol_julia.u).T + y_sol_julia = np.vstack(sol_julia.u).T - # # Solve using pybamm - # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, sol_julia.t) + # Solve using pybamm + sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, sol_julia.t) - # # Compare - # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + # Compare + np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) def test_pde_model(self): model = pybamm.BaseModel() @@ -120,7 +120,6 @@ def test_pde_model(self): mtk_str = pybamm.get_julia_mtk_model( model, geometry=geometry, tspan=(0.0, 10.0) ) - print(mtk_str) # Solve using julia Main.eval("using ModelingToolkit, DiffEqOperators") @@ -133,18 +132,16 @@ def test_pde_model(self): Main.eval("discretization = MOLFiniteDifference(dx,order)") # Convert the PDE problem into an ODE problem - Main.eval("prob = ModelingToolkit.discretize(pde_system,discretization)") + Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") # Solve PDE problem sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) - y_sol_julia = np.vstack(sol_julia.u).T - - # # Solve using pybamm - # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, sol_julia.t) + y_sol_julia = np.hstack(sol_julia.u) - # # Compare - # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + # Check everything is equal to 1 + # Just a simple test for now to get started + np.testing.assert_equal(y_sol_julia, 1) if __name__ == "__main__": From 64dfc8e7c24e2ff3d4d7336f3b565cfc51072086 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 8 Dec 2020 20:52:43 -0500 Subject: [PATCH 35/88] #1129 add spherical coordinates and input parameters --- .../operations/evaluate_julia.py | 53 ++++++++++++++++--- .../test_operations/test_evaluate_julia.py | 18 +++++++ tests/unit/test_solvers/test_julia_mtk.py | 49 +++++++++++++++-- 3 files changed, 107 insertions(+), 13 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 2c235f8312..1d60ca2030 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -146,8 +146,10 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz symbol_str = "{}[{}:{}]".format( children_vars[0], symbol.slice.start + 1, symbol.slice.stop ) - elif isinstance(symbol, (pybamm.Gradient, pybamm.Divergence)): - symbol_str = "D'{}'({})".format(symbol.domain[0], children_vars[0]) + elif isinstance(symbol, pybamm.Gradient): + symbol_str = "grad_{}({})".format(symbol.domain[0], children_vars[0]) + elif isinstance(symbol, pybamm.Divergence): + symbol_str = "div_{}({})".format(symbol.domain[0], children_vars[0]) else: symbol_str = symbol.name + children_vars[0] @@ -316,7 +318,7 @@ def to_julia(symbol): return constant_values, variable_symbols, variable_symbol_sizes -def get_julia_function(symbol, funcname="f"): +def get_julia_function(symbol, funcname="f", input_parameter_order=None): """ Converts a pybamm expression tree into pure julia code that will calculate the result of calling `evaluate(t, y)` on the given expression tree. @@ -325,6 +327,11 @@ def get_julia_function(symbol, funcname="f"): ---------- symbol : :class:`pybamm.Symbol` The symbol to convert to julia code + funcname : str, optional + The name to give to the function (default 'f') + input_parameter_order : list, optional + List of input parameter names. Defines the order in which the input parameters + are extracted from 'p' in the julia function that is created Returns ------- @@ -346,6 +353,7 @@ def get_julia_function(symbol, funcname="f"): # occurences instead of assigning them. This "inlining" speeds up the computation inlineable_symbols = ["@view", ".+", ".-", ".*", "./"] var_str = "" + input_parameters = {} while var_symbols: var_symbol_id, symbol_line = var_symbols.popitem(last=False) julia_var = id_to_julia_variable(var_symbol_id, False) @@ -367,6 +375,9 @@ def get_julia_function(symbol, funcname="f"): elif " * " in symbol_line: symbol_line = symbol_line.replace(" * ", ", ") var_str += "mul!({}, {})\n".format(julia_var, symbol_line) + # find input parameters + elif symbol_line.startswith("inputs"): + input_parameters[julia_var] = symbol_line[8:-2] else: # inline operation if it can be inlined if any(x in symbol_line for x in inlineable_symbols) or symbol_line == "t": @@ -399,6 +410,9 @@ def get_julia_function(symbol, funcname="f"): # otherwise assign else: var_str += "{} .= {}\n".format(julia_var, symbol_line) + # Replace all input parameter names + for input_parameter_id, input_parameter_name in input_parameters.items(): + var_str = var_str.replace(input_parameter_id, input_parameter_name) # add "cs." to constant and cache names var_str = var_str.replace("const", "cs.const") var_str = var_str.replace("cache", "cs.cache") @@ -424,12 +438,19 @@ def get_julia_function(symbol, funcname="f"): # remove the constant and cache sring if it is empty const_and_cache_str = const_and_cache_str.replace("cs = (\n)\n", "") + # line that extracts the input parameters in the right order + if input_parameter_order is None: + input_parameter_extraction = "" + else: + input_parameter_extraction = " " + ", ".join(input_parameter_order) + " = p\n" + # add function def and sparse arrays to first line imports = "begin\nusing SparseArrays, LinearAlgebra\n\n" julia_str = ( imports + const_and_cache_str + f"\nfunction {funcname}_with_consts(dy, y, p, t)\n" + + input_parameter_extraction + var_str ) @@ -568,13 +589,17 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): domain_name_to_symbol = { dom: list(geometry[dom].keys())[0].name for i, dom in enumerate(all_domains) } + domain_name_to_coord_sys = { + dom: list(geometry[dom].keys())[0].coord_sys + for i, dom in enumerate(all_domains) + } mtk_str = "begin\n" # Define parameters (including independent variables) # Makes a line of the form '@parameters t x1 x2 x3 a b c d' ind_vars = ["t"] + list(domain_name_to_symbol.values()) - for dom, number in domain_name_to_symbol.items(): - mtk_str += f"# '{dom}' -> {number}\n" + for domain_name, domain_symbol in domain_name_to_symbol.items(): + mtk_str += f"# '{domain_name}' -> {domain_symbol}\n" mtk_str += "@parameters " + " ".join(ind_vars) for param in model.input_parameters: mtk_str += f" {param.name}" @@ -617,7 +642,6 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): all_constants_str, all_julia_str, eqn_str = convert_var_and_eqn_to_str( var, eqn, all_constants_str, all_julia_str, "equation" ) - # add if var in model.rhs: all_eqns_str += ( @@ -637,8 +661,21 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Replace independent variables (domain names) in julia strings with the # corresponding symbol - for domain, symbol in domain_name_to_symbol.items(): - all_julia_str = all_julia_str.replace(f"'{domain}'", symbol) + for domain_name, domain_symbol in domain_name_to_symbol.items(): + all_julia_str = all_julia_str.replace( + f"grad_{domain_name}", f"D{domain_symbol}" + ) + # Different divergence depending on the coordinate system + coord_sys = domain_name_to_coord_sys[domain_name] + if coord_sys == "cartesian": + all_julia_str = all_julia_str.replace( + f"div_{domain_name}", f"D{domain_symbol}" + ) + elif coord_sys == "spherical polar": + all_julia_str = all_julia_str.replace( + f"div_{domain_name}(", + f"1 / {domain_symbol}^2 * D{domain_symbol}({domain_symbol}^2 * ", + ) # Replace parameters in the julia strings in the form "inputs[name]" # with just "name" diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 7d8be25a6b..6449ff4260 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -206,6 +206,24 @@ def test_evaluator_julia(self): Main.eval("f(dy,y,0,0)") np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) + def test_evaluator_julia_input_parameters(self): + a = pybamm.StateVector(slice(0, 1)) + b = pybamm.StateVector(slice(1, 2)) + c = pybamm.InputParameter("c") + d = pybamm.InputParameter("d") + + # test a * c + b * d + expr = a * c + b * d + evaluator_str = pybamm.get_julia_function( + expr, input_parameter_order=["c", "d"] + ) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = np.array([2.0, 3.0]) + Main.p = [5, 6] + Main.eval("f(dy,y,p,0)") + self.assertEqual(Main.dy, 28) + def test_evaluator_julia_all_functions(self): a = pybamm.StateVector(slice(0, 3)) y_test = np.array([1, 2, 3]) diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 00446e9393..635a5757eb 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -106,12 +106,12 @@ def test_dae_model(self): def test_pde_model(self): model = pybamm.BaseModel() - x = pybamm.Variable("x", domain="line") + var = pybamm.Variable("var", domain="line") - model.rhs = {x: pybamm.div(pybamm.grad(x))} - model.initial_conditions = {x: 1.0} + model.rhs = {var: pybamm.div(pybamm.grad(var))} + model.initial_conditions = {var: 1.0} model.boundary_conditions = { - x: {"left": (1, "Dirichlet"), "right": (1, "Dirichlet")} + var: {"left": (1, "Dirichlet"), "right": (1, "Dirichlet")} } x = pybamm.SpatialVariable("x", domain="line", coord_sys="cartesian") @@ -135,7 +135,46 @@ def test_pde_model(self): Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") # Solve PDE problem - sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) + sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) + + y_sol_julia = np.hstack(sol_julia.u) + + # Check everything is equal to 1 + # Just a simple test for now to get started + np.testing.assert_equal(y_sol_julia, 1) + + def test_pde_model_spherical_polar(self): + model = pybamm.BaseModel() + var = pybamm.Variable("var", domain="particle") + + model.rhs = {var: pybamm.div(pybamm.grad(var))} + model.initial_conditions = {var: 1.0} + model.boundary_conditions = { + var: {"left": (1, "Dirichlet"), "right": (1, "Dirichlet")} + } + + r = pybamm.SpatialVariable("r", domain="particle", coord_sys="spherical polar") + geometry = {"particle": {r: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}} + + mtk_str = pybamm.get_julia_mtk_model( + model, geometry=geometry, tspan=(0.0, 10.0) + ) + + # Solve using julia + Main.eval("using ModelingToolkit, DiffEqOperators") + Main.eval(mtk_str) + + Main.tspan = (0.0, 10.0) + # Method of lines discretization + Main.dx = 0.1 + Main.order = 2 + Main.eval("discretization = MOLFiniteDifference(dx,order)") + + # Convert the PDE problem into an ODE problem + Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") + + # Solve PDE problem + sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) y_sol_julia = np.hstack(sol_julia.u) From 90b4fb3368632ebea3f815e2cc094b1e74d1fa04 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 8 Dec 2020 21:08:36 -0500 Subject: [PATCH 36/88] #1129 fix flake8 and start setting up workflow --- .github/workflows/test_on_push.yml | 5 + Untitled.ipynb | 572 ------------------ .../operations/evaluate_julia.py | 4 +- requirements.txt | 1 + setup.py | 1 + test.jl | 67 -- .../test_operations/test.jl | 10 - .../test_operations/test.py | 58 -- .../test_operations/test_evaluate_julia.py | 8 +- tests/unit/test_solvers/test_julia_mtk.py | 3 +- tmp_debug.jl | 125 ---- 11 files changed, 10 insertions(+), 844 deletions(-) delete mode 100644 Untitled.ipynb delete mode 100644 test.jl delete mode 100644 tests/unit/test_expression_tree/test_operations/test.jl delete mode 100644 tests/unit/test_expression_tree/test_operations/test.py delete mode 100644 tmp_debug.jl diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 9f724371a3..472b08f5fd 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -40,6 +40,11 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} + + - name: Set up Julia 1.5 + uses: julia-actions/setup-julia@v1.5 + with: + version: 1.5 - name: Install Linux system dependencies if: matrix.os == 'ubuntu-latest' diff --git a/Untitled.ipynb b/Untitled.ipynb deleted file mode 100644 index c458565364..0000000000 --- a/Untitled.ipynb +++ /dev/null @@ -1,572 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using ModelingToolkit, OrdinaryDiffEq, Plots\n", - "# t = Variable{Float64}(:t)()\n", - "# σ = Variable{Float64}(:σ)()\n", - "# x = Variable{Float64}(:x)(t)\n", - "# D = Differential(t)\n", - "\n", - "@variables t, x(t)\n", - "# @parameters σ\n", - "@derivatives D'~t\n", - "\n", - "constant = 2.0\n", - "eq = - constant * x\n", - "eqs = [D(x) ~ eq]\n", - "sys = ODESystem(eqs,t)\n", - "u0 = [x => 1.0]\n", - "# p = [σ => 2.0]\n", - "tspan = (0.0,1.0)\n", - "prob = ODEProblem(sys,u0,tspan)\n", - "sol = solve(prob, Tsit5())\n", - "plot(sol)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "eval(Meta.parse(\n", - " \"\"\"\n", - " begin\n", - " @variables t, x1(t)\n", - "\n", - " @derivatives D'~t\n", - "\n", - " # 'v' equation\n", - " var_m2727759585034929413 = -2.0 .* x1\n", - "\n", - " eqs = [\n", - " D(x1) ~ var_m2727759585034929413,\n", - " ]\n", - " sys = ODESystem(eqs, t)\n", - " # 'v' initial conditions\n", - "\n", - "\n", - " u0 = [\n", - " x1 => 1.0,\n", - " ]\n", - " end\n", - " \"\"\"\n", - "))\n", - "# p = [σ => 2.0]\n", - "tspan = (0.0,1.0)\n", - "prob = ODEProblem(sys,u0,tspan)\n", - "sol = solve(prob, Tsit5())\n", - "plot(sol)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "ename": "LoadError", - "evalue": "PyError ($(Expr(:escape, :(ccall(#= /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:38 =# @pysym(:PyEval_EvalCode), PyPtr, (PyPtr, PyPtr, PyPtr), o, globals, locals))))) \nModuleNotFoundError(\"No module named 'pybamm'\")\n File \"/Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl\", line 1, in \n const Py_single_input = 256 # from Python.h\n", - "output_type": "error", - "traceback": [ - "PyError ($(Expr(:escape, :(ccall(#= /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:38 =# @pysym(:PyEval_EvalCode), PyPtr, (PyPtr, PyPtr, PyPtr), o, globals, locals))))) \nModuleNotFoundError(\"No module named 'pybamm'\")\n File \"/Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl\", line 1, in \n const Py_single_input = 256 # from Python.h\n", - "", - "Stacktrace:", - " [1] pyerr_check at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/exception.jl:60 [inlined]", - " [2] pyerr_check at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/exception.jl:64 [inlined]", - " [3] _handle_error(::String) at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/exception.jl:81", - " [4] macro expansion at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/exception.jl:95 [inlined]", - " [5] #120 at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:38 [inlined]", - " [6] disable_sigint at ./c.jl:446 [inlined]", - " [7] pyeval_(::String, ::PyDict{String,PyObject,true}, ::PyDict{String,PyObject,true}, ::Int64, ::String) at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:37", - " [8] top-level scope at /Users/vsulzer/.julia/packages/PyCall/zqDXB/src/pyeval.jl:230", - " [9] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091" - ] - } - ], - "source": [ - "using PyCall\n", - "\n", - "py\"\"\"\n", - "import pybamm\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.5.0", - "language": "julia", - "name": "julia-1.5" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.5.1" - }, - "toc": { - "base_numbering": 1, - "nav_menu": {}, - "number_sections": true, - "sideBar": true, - "skip_h1_title": false, - "title_cell": "Table of Contents", - "title_sidebar": "Contents", - "toc_cell": false, - "toc_position": {}, - "toc_section_display": true, - "toc_window_display": true - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 1d60ca2030..0c041871d7 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -5,7 +5,6 @@ import numpy as np import scipy.sparse -import re from collections import OrderedDict import numbers @@ -518,7 +517,6 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t """ constants, variable_symbols = to_julia(eqn)[:2] - line_format = "{} .= {}" variables_str = "\n".join( [ @@ -767,7 +765,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Domains mtk_str += "\n" mtk_str += f"t_domain = IntervalDomain({tspan[0]}, {tspan[1]})\n" - domains = f"domains = [\n t in t_domain,\n" + domains = "domains = [\n t in t_domain,\n" for domain, symbol in domain_name_to_symbol.items(): dom_limits = list(geometry[domain].values())[0] dom_min, dom_max = dom_limits.values() diff --git a/requirements.txt b/requirements.txt index 7527da77b4..8b94aaf9db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ scikit-fem >= 0.2.0 casadi >= 3.5.0 jax==0.1.75 jaxlib==0.1.52 +diffeqpy>=1.1.0 jupyter # For example notebooks # Note: Matplotlib is loaded for debug plots but to ensure pybamm runs # on systems without an attached display it should never be imported diff --git a/setup.py b/setup.py index 1a1e81d73b..79048c1945 100644 --- a/setup.py +++ b/setup.py @@ -197,6 +197,7 @@ def compile_KLU(): "scikit-fem>=0.2.0", "casadi>=3.5.0", *jax_dependencies, + "diffeqpy", "jupyter", # For example notebooks # Note: Matplotlib is loaded for debug plots, but to ensure pybamm runs # on systems without an attached display, it should never be imported diff --git a/test.jl b/test.jl deleted file mode 100644 index d9f62fd10d..0000000000 --- a/test.jl +++ /dev/null @@ -1,67 +0,0 @@ -using ModelingToolkit, DiffEqOperators - -# # 'line' -> x -# @parameters t -# # 'x' -> u1 -# @variables u1(..) -# # @variables u1(t) -# @derivatives Dt'~t - -# eqs = [ -# Dt(u1(t)) ~ -1, -# # Dt(u1) ~ -1, -# ] - -# # ics = [u1(0) ~ 1] -# ics = [u1(t) => 1] - -# sys = ODESystem(eqs, t) - -# # Convert the PDE problem into an ODE problem -# prob = ODEProblem(sys, ics, (0.0, 10.0)) - -# # Solve ODE problem -# using OrdinaryDiffEq -# sol = solve(prob,Tsit5(),saveat=0.1) -# 'line' -> x -@parameters t x -# 'x' -> u1 -@variables u1(..) -@derivatives Dt'~t -@derivatives Dx'~x - -# 'x' equation -cache_4964620357949541853 = Dx(u1(t,x)) -cache_m2869545278201409051 = Dx(cache_4964620357949541853) - -eqs = [ - Dt(u1(t,x)) ~ cache_m2869545278201409051, -] - -ics_bcs = [u1(0,x) ~ -x*(x-1)*sin(x), -u1(t,0) ~ 0.0, -u1(t,1) ~ 0.0] - -t_domain = IntervalDomain(0.0, 10.0) -x_domain = IntervalDomain(0.0, 1.0) - -domains = [ - t in t_domain, - x in x_domain, -] -ind_vars = [t, x] -dep_vars = [u1] - -pde_system = PDESystem(eqs, ics_bcs, domains, ind_vars, dep_vars) - -# Method of lines discretization -dx = 0.1 -order = 2 -discretization = MOLFiniteDifference(dx,order) - -# Convert the PDE problem into an ODE problem -prob = DiffEqOperators.discretize(pde_system,discretization) - -# Solve ODE problem -using OrdinaryDiffEq -sol = solve(prob,saveat=0.1) \ No newline at end of file diff --git a/tests/unit/test_expression_tree/test_operations/test.jl b/tests/unit/test_expression_tree/test_operations/test.jl deleted file mode 100644 index 7a998c7c6a..0000000000 --- a/tests/unit/test_expression_tree/test_operations/test.jl +++ /dev/null @@ -1,10 +0,0 @@ -function f_b(dy, y, a, b) - dy[1] = a * y[1] - dy[2] = b * y[2] - dy -end -dy = [0, 0] -y = [1, 3] -println(dy) # returns [0 0] -println(f_b(dy, y, 5, 3)) # returns [5 9] -println(dy) # returns [5 9] \ No newline at end of file diff --git a/tests/unit/test_expression_tree/test_operations/test.py b/tests/unit/test_expression_tree/test_operations/test.py deleted file mode 100644 index 5f2791b875..0000000000 --- a/tests/unit/test_expression_tree/test_operations/test.py +++ /dev/null @@ -1,58 +0,0 @@ -s = """ -var1 .= @view y[1:10] -var2 .= @view y[10:20] -mul!(dy, var1, var2) -""" - -# from julia import Main -# import numpy as np - -# f_b = Main.eval( -# """ -# begin -# function f_b(dy,y,a,b) -# dy[1] = a*y[1] -# dy[2] = b*y[2] -# dy -# end -# end -# """ -# ) -# dy = np.array([0, 0]) -# y = np.array([1, 3]) -# print(dy) # returns [0 0] -# print(f_b(dy, y, 5, 3)) # returns [5 9] -# print(dy) # returns [0 0] (expected [5 9]) - -# Main.dy = [0, 0] -# Main.y = [1, 3] -# print(Main.dy) # returns [0 0] -# Main.eval("println(f_b(dy, y, 5, 3))") -# # print(Main.f_b(Main.dy, Main.y, 5, 3)) # returns [5 9] -# print(Main.dy) # returns [0 0] (expected [5 9]) - -# Main.eval( -# """ -# function f_b(dy, y, a, b) -# dy[1] = a * y[1] -# dy[2] = b * y[2] -# dy -# end -# dy = [0, 0] -# y = [1, 3] -# println(dy) # returns [0 0] -# println(f_b(dy, y, 5, 3)) # returns [5 9] -# println(dy) -# """ -# ) -# def f_b(dy, y, a, b): -# dy[0] = a * y[0] -# dy[1] = b * y[1] -# return dy - - -# dy = [0, 0] -# y = [1, 3] -# print(dy) # returns [0 0] -# print(f_b(dy, y, 5, 3)) # returns [5 9] -# print(dy) # returns [5 9] \ No newline at end of file diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 6449ff4260..af8b3cb3e8 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -3,16 +3,10 @@ # import pybamm -from tests import ( - get_mesh_for_testing, - get_1p1d_mesh_for_testing, - get_discretisation_for_testing, - get_1p1d_discretisation_for_testing, -) +from tests import get_mesh_for_testing, get_1p1d_mesh_for_testing import unittest import numpy as np import scipy.sparse -from collections import OrderedDict from julia import Main diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 635a5757eb..310029a4ec 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -9,11 +9,10 @@ # julia imports from julia import Main from julia import Pkg +from diffeqpy import de Pkg.activate(".") -from diffeqpy import de - class TestCreateSolveMTKModel(unittest.TestCase): def test_exponential_decay_model(self): diff --git a/tmp_debug.jl b/tmp_debug.jl deleted file mode 100644 index 2e7df21f68..0000000000 --- a/tmp_debug.jl +++ /dev/null @@ -1,125 +0,0 @@ -begin -using SparseArrays, LinearAlgebra - -f = let cs = ( - const_m4822311374121275919 = sparse([1,1], [19,20], [-0.5, 1.5], 1, 20), - const_1744480757062911249 = sparse([ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.], 20, 1), - const_m8518220820285355445 = sparse([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20], [0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, - 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, - 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, - 0.02222222,0.02222222], 1, 20), - const_m2794236520912209521 = [2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.], - const_m942165513388665034 = [-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25, - -2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25,-2.25], - const_m1232301553800524044 = [6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07, - 6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07,6.e-07], - const_1388564590504212564 = sparse([1,1], [29,30], [-0.5, 1.5], 1, 30), - const_8752233790552333983 = 0.0, - const_m6459359983097884347 = [2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.,2.], - const_8416676264869710905 = [2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25,2.25, - 2.25,2.25,2.25,2.25,2.25,2.25], - const_m2775764531995498168 = [2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05, - 2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05,2.e-05], - const_m3780420342443263966 = -0.0006701794467029256, - const_m3587115650644734227 = 1.2, - const_m4908013908935754244 = sparse([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, - 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, - 49,50,51,52,53,54,55,56,57,58,59,60], [0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, - 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, - 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, - 0.02222222,0.02222222,0.00555556,0.00555556,0.00555556,0.00555556, - 0.00555556,0.00555556,0.00555556,0.00555556,0.00555556,0.00555556, - 0.00555556,0.00555556,0.00555556,0.00555556,0.00555556,0.00555556, - 0.00555556,0.00555556,0.00555556,0.00555556,0.02222222,0.02222222, - 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, - 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222, - 0.02222222,0.02222222,0.02222222,0.02222222,0.02222222,0.02222222], 1, 60), - const_m836363707967227454 = 0.08922778287712851, - const_m2099015146737727157 = 1.0, - const_m3731019977586676618 = 0.1643167672515498, - const_9098493608742964394 = 0.9999999999999999, - const_6560875588504410658 = [1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2, - 1.2,1.2], - const_m8721193489185815234 = 0.20076251147353916, - const_m887411406143043211 = 0.16431676725154978, - const_m7098007253014595426 = [0.00975309,0.02851852,0.0462963 ,0.06308642,0.07888889,0.0937037 , - 0.10753086,0.12037037,0.13222222,0.14308642,0.15296296,0.16185185, - 0.16975309,0.17666667,0.18259259,0.18753086,0.19148148,0.19444444, - 0.19641975,0.19740741], - const_6638868103325447887 = 0.11153472859641064, - const_m358324611044111996 = 0.05064016622195792, - const_m5057362321874500390 = [0.04624493,0.04631098,0.04644309,0.04664124,0.04690545,0.04723572, - 0.04763203,0.0480944 ,0.04862282,0.04921729,0.04987781,0.05060439, - 0.05139702,0.0522557 ,0.05318043,0.05417122,0.05522806,0.05635095, - 0.05753989,0.05879488], - cache_3915606029483975135 = zeros(1), - cache_959261321572005728 = zeros(20), - cache_m3206663273767608132 = zeros(1), - cache_8147124925464309775 = zeros(20), - cache_m7276528384970331289 = zeros(20), - cache_m1499541469728327654 = zeros(1), - cache_m2825253393613765537 = zeros(1), - cache_640754690756395244 = zeros(20), - cache_6711155880308569207 = zeros(1), - cache_m8191789462605491070 = zeros(20), - cache_m735068602063420310 = zeros(20), - cache_m2737248814353521814 = zeros(1), - cache_m8937655955816370474 = zeros(60), - cache_m7903676841323904382 = zeros(1), - cache_4951424073511713159 = zeros(20), - cache_m3708658618337972127 = zeros(20), - cache_m821629956291150857 = zeros(1), - cache_m2710349119673370670 = zeros(1), - cache_m5408670181879547603 = zeros(20), - cache_8616547535697387985 = zeros(20), - cache_3928631964573574281 = zeros(1), - cache_8080731599320426571 = zeros(20), - cache_m1569211042726296739 = zeros(1), - cache_6958716317680719368 = zeros(20), - cache_m3159910331817368091 = zeros(20), - cache_7491403280521532656 = zeros(1), - cache_2097128636677903600 = zeros(1), - cache_5746692283934222791 = zeros(20), - cache_4358330042817845608 = zeros(20), - cache_m5214664370647379083 = zeros(1), -) - -function f_with_consts(dy, y, p, t) - mul!(cs.cache_3915606029483975135, cs.const_1388564590504212564, (@view y[32:61])) - mul!(cs.cache_959261321572005728, cs.const_1744480757062911249, cs.cache_3915606029483975135) - cs.cache_m3206663273767608132 .= ((((((((2.16216 .+ (0.07645 .* (tanh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_3915606029483975135))))))) .+ (2.1581 .* (tanh.((52.294 .- (50.294 .* (1.062 .* cs.cache_3915606029483975135))))))) .- (0.14169 .* (tanh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_3915606029483975135))))))) .+ (0.2051 .* (tanh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_3915606029483975135))))))) .+ (0.2531 .* (tanh.((((-(1.062 .* cs.cache_3915606029483975135)) .+ 0.56478) ./ 0.1316))))) .- (0.02167 .* (tanh.((((1.062 .* cs.cache_3915606029483975135) .- 0.525) ./ 0.006))))) .+ (cs.const_8752233790552333983 .* ((((((-8.132000292009045e-05 .* ((1.0 ./ (cosh.((30.834 .- (54.4806 .* (1.062 .* cs.cache_3915606029483975135)))))) .^ 2.0)) .+ (-0.0021191697994606485 .* ((cosh.((52.294 .- (50.294 .* (1.062 .* cs.cache_3915606029483975135))))) .^ -2.0))) .+ (5.492438867553213e-05 .* ((cosh.((11.0923 .- (19.8543 .* (1.062 .* cs.cache_3915606029483975135))))) .^ -2.0))) .- (2.1979665594310157e-05 .* ((cosh.((1.4684 .- (5.4888 .* (1.062 .* cs.cache_3915606029483975135))))) .^ -2.0))) .- (3.755037425254259e-05 .* ((cosh.((((-(1.062 .* cs.cache_3915606029483975135)) .+ 0.56478) ./ 0.1316))) .^ -2.0))) .- (7.051567620368884e-05 .* ((cosh.((((1.062 .* cs.cache_3915606029483975135) .- 0.525) ./ 0.006))) .^ -2.0))))) .- 4.027013847342062) ./ 0.025692579121493725 - mul!(cs.cache_8147124925464309775, cs.const_1744480757062911249, cs.cache_m3206663273767608132) - cs.cache_m7276528384970331289 .= (cs.const_m2794236520912209521 .* (asinh.((cs.const_m942165513388665034 ./ (2.0 .* ((2.05008960573477 .* ((((cs.const_m1232301553800524044 .* (((@view y[102:121]) .* 1000.0) .^ 0.5)) .* ((cs.cache_959261321572005728 .* 51217.9257309275) .^ 0.5)) .* ((51217.9257309275 .- (cs.cache_959261321572005728 .* 51217.9257309275)) .^ 0.5)) ./ 0.9717918140344515)) ./ 1.5001582400237319)))))) .+ cs.cache_8147124925464309775 - mul!(cs.cache_m1499541469728327654, cs.const_m8518220820285355445, cs.cache_m7276528384970331289) - mul!(cs.cache_m2825253393613765537, cs.const_1388564590504212564, (@view y[2:31])) - mul!(cs.cache_640754690756395244, cs.const_1744480757062911249, cs.cache_m2825253393613765537) - cs.cache_6711155880308569207 .= (((((((((((0.194 .+ (1.5 .* (exp.((-120.0 .* cs.cache_m2825253393613765537))))) .+ (0.0351 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.286) ./ 0.083))))) .- (0.0045 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.849) ./ 0.119))))) .- (0.035 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.9233) ./ 0.05))))) .- (0.0147 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.5) ./ 0.034))))) .- (0.102 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.194) ./ 0.142))))) .- (0.022 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.9) ./ 0.0164))))) .- (0.011 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.124) ./ 0.0226))))) .+ (0.0155 .* (tanh.(((cs.cache_m2825253393613765537 .- 0.105) ./ 0.029))))) .+ (cs.const_8752233790552333983 .* (((((((((-0.007204823775388301 .* (exp.((-120.0 .* cs.cache_m2825253393613765537)))) .+ (1.6926995616876127e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.286) ./ 0.083))) .^ -2.0))) .- (1.5136184402076262e-06 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.849) ./ 0.119))) .^ -2.0))) .- (2.801875912651006e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.9233) ./ 0.05))) .^ -2.0))) .- (1.730570416637386e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.5) ./ 0.034))) .^ -2.0))) .- (2.8751644174084767e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.194) ./ 0.142))) .^ -2.0))) .- (5.3694486130942614e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.9) ./ 0.0164))) .^ -2.0))) .- (1.9482070189103072e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.124) ./ 0.0226))) .^ -2.0))) .+ (2.139363381580817e-05 .* ((cosh.(((cs.cache_m2825253393613765537 .- 0.105) ./ 0.029))) .^ -2.0))))) .- 0.175193184028335) ./ 0.025692579121493725 - mul!(cs.cache_m8191789462605491070, cs.const_1744480757062911249, cs.cache_6711155880308569207) - cs.cache_m735068602063420310 .= (cs.const_m6459359983097884347 .* (asinh.((cs.const_8416676264869710905 ./ (2.0 .* (((((cs.const_m2775764531995498168 .* (((@view y[62:81]) .* 1000.0) .^ 0.5)) .* ((cs.cache_640754690756395244 .* 24983.2619938437) .^ 0.5)) .* ((24983.2619938437 .- (cs.cache_640754690756395244 .* 24983.2619938437)) .^ 0.5)) ./ 15.800802256253133) ./ 0.037503956000593294)))))) .+ cs.cache_m8191789462605491070 - mul!(cs.cache_m2737248814353521814, cs.const_m8518220820285355445, cs.cache_m735068602063420310) - cs.cache_m8937655955816370474[1:20] .= (@view y[62:81]) - cs.cache_m8937655955816370474[21:40] .= (@view y[82:101]) - cs.cache_m8937655955816370474[41:60] .= (@view y[102:121]) - mul!(cs.cache_m7903676841323904382, cs.const_m4908013908935754244, cs.cache_m8937655955816370474) - mul!(cs.cache_4951424073511713159, cs.const_1744480757062911249, cs.cache_m7903676841323904382) - cs.cache_m3708658618337972127 .= log.(((@view y[62:81]) ./ cs.cache_4951424073511713159)) - mul!(cs.cache_m821629956291150857, cs.const_m8518220820285355445, cs.cache_m3708658618337972127) - cs.cache_m2710349119673370670 .= (((-(cs.cache_m2737248814353521814 ./ 0.4444444444444445)) .+ cs.const_m3780420342443263966) .- (cs.const_m3587115650644734227 .* (cs.cache_m821629956291150857 ./ 0.4444444444444445))) .- (cs.const_m836363707967227454 .* ((1.0 ./ (3.0 .* ((((((0.0911 .+ (1.9101 .* ((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 2.0))) .+ (0.1554 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 3.0))) .* cs.const_m2099015146737727157) ./ 1.0468957512717258) .* cs.const_m3731019977586676618))) .- (1.0 ./ ((((((0.0911 .+ (1.9101 .* ((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 2.0))) .+ (0.1554 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 3.0))) .* cs.const_m2099015146737727157) ./ 1.0468957512717258) .* cs.const_9098493608742964394)))) - mul!(cs.cache_m5408670181879547603, cs.const_1744480757062911249, cs.cache_m2710349119673370670) - mul!(cs.cache_8616547535697387985, cs.const_1744480757062911249, cs.cache_m7903676841323904382) - cs.cache_3928631964573574281 .= cs.const_m8721193489185815234 ./ ((((((0.0911 .+ (1.9101 .* ((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 2.0))) .+ (0.1554 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 3.0))) .* cs.const_m2099015146737727157) ./ 1.0468957512717258) .* cs.const_m887411406143043211) - mul!(cs.cache_8080731599320426571, cs.const_1744480757062911249, cs.cache_3928631964573574281) - cs.cache_m1569211042726296739 .= cs.const_6638868103325447887 ./ ((((((0.0911 .+ (1.9101 .* ((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0))) .- (1.052 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 2.0))) .+ (0.1554 .* (((cs.cache_m7903676841323904382 .* 1000.0) ./ 1000.0) .^ 3.0))) .* cs.const_m2099015146737727157) ./ 1.0468957512717258) .* cs.const_9098493608742964394) - mul!(cs.cache_6958716317680719368, cs.const_1744480757062911249, cs.cache_m1569211042726296739) - cs.cache_m3159910331817368091 .= ((cs.cache_m5408670181879547603 .+ (cs.const_6560875588504410658 .* (log.(((@view y[102:121]) ./ cs.cache_8616547535697387985))))) .- ((cs.cache_8080731599320426571 .* cs.const_m7098007253014595426) ./ 0.888888888888889)) .- cs.cache_6958716317680719368 - mul!(cs.cache_7491403280521532656, cs.const_m8518220820285355445, cs.cache_m3159910331817368091) - cs.cache_2097128636677903600 .= ((cs.cache_m1499541469728327654 ./ 0.4444444444444445) .+ (cs.cache_7491403280521532656 ./ 0.4444444444444445)) .+ cs.const_m358324611044111996 - mul!(cs.cache_5746692283934222791, cs.const_1744480757062911249, cs.cache_2097128636677903600) - cs.cache_4358330042817845608 .= cs.cache_5746692283934222791 .- cs.const_m5057362321874500390 - mul!(cs.cache_m5214664370647379083, cs.const_m4822311374121275919, cs.cache_4358330042817845608) - dy .= 3.8518206633137266 .+ (cs.cache_m5214664370647379083 .* 0.025692579121493725) -end - -end -end \ No newline at end of file From 5b53a11f6fd3cb12bfa243043c7f46784071fdac Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 8 Dec 2020 21:47:17 -0500 Subject: [PATCH 37/88] #1129 update workflow --- .github/workflows/test_on_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 472b08f5fd..6cfdbbdd85 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -42,7 +42,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Set up Julia 1.5 - uses: julia-actions/setup-julia@v1.5 + uses: julia-actions/setup-julia@v1 with: version: 1.5 From 3b1c0670fffbee755aa7dea7a671f259c363f67f Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 10 Dec 2020 11:39:00 -0500 Subject: [PATCH 38/88] #1129 try julia install --- .github/workflows/test_on_push.yml | 3 +++ pybamm/__init__.py | 1 + pybamm/util.py | 15 +++++++++++++++ setup.py | 4 ++-- .../test_operations/test_evaluate_julia.py | 5 ++++- tests/unit/test_solvers/test_julia_mtk.py | 11 +++++++---- tox.ini | 17 +++++++++-------- 7 files changed, 41 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 6cfdbbdd85..20436fce3d 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -72,6 +72,9 @@ jobs: if: matrix.os != 'windows-latest' run: tox -e pybamm-requires + - name: Install pyjulia + run: tox -e julia + - name: Run unit tests for GNU/Linux and MacOS if: matrix.os != 'windows-latest' run: python -m tox -e tests diff --git a/pybamm/__init__.py b/pybamm/__init__.py index 8f1565ea35..789db42f14 100644 --- a/pybamm/__init__.py +++ b/pybamm/__init__.py @@ -66,6 +66,7 @@ def version(formatted=False): from .util import Timer, TimerTime, FuzzyDict from .util import root_dir, load_function, rmse, get_infinite_nested_dict, load from .util import get_parameters_filepath +from .util import have_julia from .logger import logger, set_logging_level from .settings import settings from .citations import Citations, citations, print_citations diff --git a/pybamm/util.py b/pybamm/util.py index 43d6988ace..c5a2a4bcdb 100644 --- a/pybamm/util.py +++ b/pybamm/util.py @@ -348,3 +348,18 @@ def get_parameters_filepath(path): return path else: return os.path.join(pybamm.__path__[0], path) + + +def have_julia(): + """ + Checks whether the Julia programming language has been installed + """ + import subprocess + + # Try reading the julia version quietly to see whether julia is installed + FNULL = open(os.devnull, "w") + try: + subprocess.call(["julia", "--version"], stdout=FNULL, stderr=subprocess.STDOUT) + return True + except subprocess.CalledProcessError: + return False \ No newline at end of file diff --git a/setup.py b/setup.py index 79048c1945..38e14f036d 100644 --- a/setup.py +++ b/setup.py @@ -165,7 +165,6 @@ def compile_KLU(): "jaxlib==0.1.57", ] - # Load text for description and license with open("README.md", encoding="utf-8") as f: readme = f.read() @@ -197,7 +196,8 @@ def compile_KLU(): "scikit-fem>=0.2.0", "casadi>=3.5.0", *jax_dependencies, - "diffeqpy", + "diffeqpy>=1.1.0", # For julia differential equations, also installs pyjulia. + # Can be installed even if julia is not installed "jupyter", # For example notebooks # Note: Matplotlib is loaded for debug plots, but to ensure pybamm runs # on systems without an attached display, it should never be imported diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index af8b3cb3e8..8195e0a49e 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -8,9 +8,12 @@ import numpy as np import scipy.sparse -from julia import Main +have_julia = pybamm.have_julia() +if have_julia: + from julia import Main +@unittest.skipIf(not have_julia, "Julia not installed") class TestEvaluate(unittest.TestCase): def test_evaluator_julia(self): a = pybamm.StateVector(slice(0, 1)) diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 310029a4ec..82807ea91d 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -7,13 +7,16 @@ import numpy as np # julia imports -from julia import Main -from julia import Pkg -from diffeqpy import de +have_julia = pybamm.have_julia() +if have_julia: + from julia import Main + from julia import Pkg + from diffeqpy import de -Pkg.activate(".") + Pkg.activate(".") +@unittest.skipIf(not have_julia, "Julia not installed") class TestCreateSolveMTKModel(unittest.TestCase): def test_exponential_decay_model(self): model = pybamm.BaseModel() diff --git a/tox.ini b/tox.ini index 4e90a958c3..9bae321d86 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {windows}-{tests,quick,dev},tests,quick,dev +envlist = {windows}-{tests,quick,dev},tests,quick,dev,julia [testenv] platform = !windows: [linux,darwin] @@ -21,11 +21,12 @@ deps = !windows: scikits.odes commands = - tests: python run-tests.py --unit --folder all - quick: python run-tests.py --unit - examples: python run-tests.py --examples - dev-!windows: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" - doctests: python run-tests.py --doctest + tests: python run-tests.py --unit --folder all + quick: python run-tests.py --unit + examples: python run-tests.py --examples + dev-!windows: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" + doctests: python run-tests.py --doctest + julia: python -c "import julia; julia.install()" [testenv:pybamm-requires] platform = [linux,darwin] @@ -36,8 +37,8 @@ deps = wget cmake commands = - python {toxinidir}/scripts/install_KLU_Sundials.py - - git clone https://github.com/pybind/pybind11.git {toxinidir}/pybind11 + python {toxinidir}/scripts/install_KLU_Sundials.py + - git clone https://github.com/pybind/pybind11.git {toxinidir}/pybind11 [testenv:flake8] skip_install = true From 7d74c2a2ff4fb497d1d70d2ca8d73944d5a22248 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 10 Dec 2020 12:06:01 -0500 Subject: [PATCH 39/88] #1129 fix evaluator_python --- pybamm/expression_tree/operations/evaluate_python.py | 6 +++--- pybamm/util.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_python.py b/pybamm/expression_tree/operations/evaluate_python.py index 306eb58478..93d2200dfe 100644 --- a/pybamm/expression_tree/operations/evaluate_python.py +++ b/pybamm/expression_tree/operations/evaluate_python.py @@ -313,16 +313,16 @@ def find_symbols(symbol, constant_symbols, variable_symbols, output_jax=False): elif isinstance(symbol, pybamm.Concatenation): - # don't bother to concatenate if there is only a single child + # no need to concatenate if there is only a single child if isinstance(symbol, pybamm.NumpyConcatenation): if len(children_vars) == 1: - symbol_str = children_vars + symbol_str = children_vars[0] else: symbol_str = "np.concatenate(({}))".format(",".join(children_vars)) elif isinstance(symbol, pybamm.SparseStack): if len(children_vars) == 1: - symbol_str = children_vars + symbol_str = children_vars[0] else: if output_jax: raise NotImplementedError diff --git a/pybamm/util.py b/pybamm/util.py index c5a2a4bcdb..b965789f6e 100644 --- a/pybamm/util.py +++ b/pybamm/util.py @@ -362,4 +362,4 @@ def have_julia(): subprocess.call(["julia", "--version"], stdout=FNULL, stderr=subprocess.STDOUT) return True except subprocess.CalledProcessError: - return False \ No newline at end of file + return False From 60bde7d435d9a8cf1a409866cfaaf6e0be8700ad Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 10 Dec 2020 12:55:24 -0500 Subject: [PATCH 40/88] #1129 remove temp files and fix overwritten commits --- examples/scripts/DFN.py | 42 +- .../expression_tree/operations/spm_julia.jl | 387 ------------------ pybamm/solvers/base_solver.py | 44 +- pybamm/solvers/casadi_solver.py | 24 +- .../test_operations/quick_julia_test.py | 183 --------- 5 files changed, 68 insertions(+), 612 deletions(-) delete mode 100644 pybamm/expression_tree/operations/spm_julia.jl delete mode 100644 tests/unit/test_expression_tree/test_operations/quick_julia_test.py diff --git a/examples/scripts/DFN.py b/examples/scripts/DFN.py index c73e467484..9c50dbc7ef 100644 --- a/examples/scripts/DFN.py +++ b/examples/scripts/DFN.py @@ -21,8 +21,7 @@ # set mesh var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} -# var_pts = model.default_var_pts +var_pts = {var.x_n: 30, var.x_s: 30, var.x_p: 30, var.r_n: 10, var.r_p: 10} mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) # discretise model @@ -31,28 +30,23 @@ # solve model t_eval = np.linspace(0, 3600, 100) -solver = pybamm.CasadiSolver(mode="fast", atol=1e-6, rtol=1e-6) +solver = pybamm.CasadiSolver(mode="fast", atol=1e-6, rtol=1e-3) solution = solver.solve(model, t_eval) -tot = 0 -for i in range(100): - solution = solver.solve(model, t_eval) - tot += solution.solve_time -print(tot / 100) # plot -# plot = pybamm.QuickPlot( -# solution, -# [ -# "Negative particle concentration [mol.m-3]", -# "Electrolyte concentration [mol.m-3]", -# "Positive particle concentration [mol.m-3]", -# "Current [A]", -# "Negative electrode potential [V]", -# "Electrolyte potential [V]", -# "Positive electrode potential [V]", -# "Terminal voltage [V]", -# ], -# time_unit="seconds", -# spatial_unit="um", -# ) -# plot.dynamic_plot() +plot = pybamm.QuickPlot( + solution, + [ + "Negative particle concentration [mol.m-3]", + "Electrolyte concentration [mol.m-3]", + "Positive particle concentration [mol.m-3]", + "Current [A]", + "Negative electrode potential [V]", + "Electrolyte potential [V]", + "Positive electrode potential [V]", + "Terminal voltage [V]", + ], + time_unit="seconds", + spatial_unit="um", +) +plot.dynamic_plot() diff --git a/pybamm/expression_tree/operations/spm_julia.jl b/pybamm/expression_tree/operations/spm_julia.jl deleted file mode 100644 index ce13db5dd3..0000000000 --- a/pybamm/expression_tree/operations/spm_julia.jl +++ /dev/null @@ -1,387 +0,0 @@ -using BenchmarkTools, OrdinaryDiffEq, Sundials, SparseArrays, LinearAlgebra - -function f(dy, y) - dy .= @view y[1] .* y[2] -end -y = [2.0,3.0] -dy = [0.0] -f(dy,y) -dy - -(@view y[1]) .* (@view y[2]) - -A = rand(100, 100) -B = rand(100, 100) -C = rand(100, 100) -D = rand(100, 100) - -function twomuls_assign(A, B, C, D) - C .= A .* B - mul!(D, A, C) -end -function twomuls_noassign(A, B, C, D) - mul!(D, A, A .* B) -end - -function mymul(c1, c2, C, A, B) - c1 .= A - c2 .= B - mul!(D, c1, c2) -end -c1 = rand(100, 100) -c2 = rand(100, 100) -function twomuls_noassign_mymul(A, B, C, D, c1, c2) - mymul(c1, c2, D, A, A .* B) -end - -@btime twomuls_assign(A, B, C, D) -@btime twomuls_noassign(A, B, C, D) -@btime twomuls_noassign_mymul(A, B, C, D, c1, c2) - -const cs = (const_m5042476316481538586 = [[0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0. ] - [0.03237701]], - const_m1664908561639471167 = [[-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.]], - const_m1742632654512844898 = [[ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [ 0. ] - [-0.14182856]], - const_6902631343103379854 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, - 25,25,26,26,27,27,28,28,29,29], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, - 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, - 25,26,26,27,27,28,28,29,29,30], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.], 29, 30), - const_m2887110228888269587 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, - 26,27,28,29,30], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, - 25,26,27,28,29], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.], 31, 29), - const_948199332974845790 = [[-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.] - [-1.]], - const_m3416783780236702828 = [[0. ] - [0.00111111] - [0.00444444] - [0.01 ] - [0.01777778] - [0.02777778] - [0.04 ] - [0.05444444] - [0.07111111] - [0.09 ] - [0.11111111] - [0.13444444] - [0.16 ] - [0.18777778] - [0.21777778] - [0.25 ] - [0.28444444] - [0.32111111] - [0.36 ] - [0.40111111] - [0.44444444] - [0.49 ] - [0.53777778] - [0.58777778] - [0.64 ] - [0.69444444] - [0.75111111] - [0.81 ] - [0.87111111] - [0.93444444] - [1. ]], - const_m4709902773269181539 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, - 25,25,26,26,27,27,28,28,29,29,30,30], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, - 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, - 25,26,26,27,27,28,28,29,29,30,30,31], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.], 30, 31), - const_m6560247611775222723 = [[3.60000000e+03] - [4.00000000e+02] - [1.44000000e+02] - [7.34693878e+01] - [4.44444444e+01] - [2.97520661e+01] - [2.13017751e+01] - [1.60000000e+01] - [1.24567474e+01] - [9.97229917e+00] - [8.16326531e+00] - [6.80529301e+00] - [5.76000000e+00] - [4.93827160e+00] - [4.28061831e+00] - [3.74609781e+00] - [3.30578512e+00] - [2.93877551e+00] - [2.62965668e+00] - [2.36686391e+00] - [2.14158239e+00] - [1.94699838e+00] - [1.77777778e+00] - [1.62969670e+00] - [1.49937526e+00] - [1.38408304e+00] - [1.28159487e+00] - [1.19008264e+00] - [1.10803324e+00] - [1.03418558e+00]], - const_7523862830560677743 = 4.272493084154669, - cache = zeros(29), - cache2 = zeros(31), - cache3 = zeros(30),) -function f_pybamm(dy, y, p, t, c) - dy[1] = c.const_7523862830560677743 - mul!(c.cache, c.const_6902631343103379854, @view y[2:31]) - mul!(c.cache2, c.const_m2887110228888269587, c.cache) - # c.cache2 .= - mul!(c.cache3, c.const_m4709902773269181539, c.const_m3416783780236702828 .* c.const_948199332974845790 .* c.cache2 .+ c.const_m1742632654512844898) - dy[2:31] .= -8.813457647415214 .* c.const_m6560247611775222723 .* c.cache3 - mul!(c.cache, c.const_6902631343103379854, @view y[32:61]) - mul!(c.cache2, c.const_m2887110228888269587, c.cache) - # c.cache2 .= - mul!(c.cache3, c.const_m4709902773269181539, c.const_m3416783780236702828 .* c.const_948199332974845790 .* c.cache2 .+ c.const_m1742632654512844898) - dy[32:61] .= -22.598609352346706 .* c.const_m6560247611775222723 .* c.cache3 -end -f(dy,y,p,t) = f_pybamm(dy, y, p, t, cs) -u0 = [0.0; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6] -tspan = (0.0, 0.15) -prob = ODEProblem(f, u0, tspan) -@btime solve(prob, KenCarp47(autodiff=false), reltol=1e-6, abstol=1e-6, saveat=0.15 / 100); -@btime solve(prob, CVODE_BDF(), reltol=1e-6, abstol=1e-6, saveat=0.15 / 100); -solve(prob, CVODE_BDF(), reltol=1e-8, abstol=1e-8, saveat=0.15 / 100); -# # Before -# 2.527 ms (13965 allocations: 1.62 MiB) -# # After w/ Sundials -# 1.145 ms (3235 allocations: 188.14 KiB) -# # After with OrdinaryDiffEq KenCarp47 -# 743.099 μs (493 allocations: 155.91 KiB) -# using Profile -# @profile for i in 1:1000 solve(prob, KenCarp47(), reltol=1e-8, abstol=1e-8, saveat=0.15 / 100) end -# Juno.profiler() -# Profile.clear() -rand(10) -@btime rand(10); - -hh = let es = (x1 = [1,2,3,4,5], x2 = 1) - function g_inner(dy, y, p, t, c) - dy .= c.x1 .* y - end - g(dy, y, p, t) = g_inner(dy, y, p, t, es) -end -u0 = [1,1,1,1,1] -tspan = (0, 1) -prob = ODEProblem(hh, u0, tspan) -@btime solve(prob, KenCarp47(autodiff=false), reltol=1e-6, abstol=1e-6, saveat=0.1); - -function aaa() - return 2 -end -bbb = aaa -bbb = let xxx = 2 - xxx^2 -end -xxx -bbb() - -hhh = let cs = (const_5942506679108712033 = 4.272493084154669, - const_8746997338028787016 = [3.60000000e+03,4.00000000e+02,1.44000000e+02,7.34693878e+01, - 4.44444444e+01,2.97520661e+01,2.13017751e+01,1.60000000e+01, - 1.24567474e+01,9.97229917e+00,8.16326531e+00,6.80529301e+00, - 5.76000000e+00,4.93827160e+00,4.28061831e+00,3.74609781e+00, - 3.30578512e+00,2.93877551e+00,2.62965668e+00,2.36686391e+00, - 2.14158239e+00,1.94699838e+00,1.77777778e+00,1.62969670e+00, - 1.49937526e+00,1.38408304e+00,1.28159487e+00,1.19008264e+00, - 1.10803324e+00,1.03418558e+00], - const_3581012719263669839 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, - 25,25,26,26,27,27,28,28,29,29,30,30], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, - 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, - 25,26,26,27,27,28,28,29,29,30,30,31], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.], 30, 31), - const_m2612367405192523296 = [0. ,0.00111111,0.00444444,0.01 ,0.01777778,0.02777778, - 0.04 ,0.05444444,0.07111111,0.09 ,0.11111111,0.13444444, - 0.16 ,0.18777778,0.21777778,0.25 ,0.28444444,0.32111111, - 0.36 ,0.40111111,0.44444444,0.49 ,0.53777778,0.58777778, - 0.64 ,0.69444444,0.75111111,0.81 ,0.87111111,0.93444444, - 1. ], - const_5069055130374487851 = [-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.], - const_4295227685794622472 = sparse([ 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, - 26,27,28,29,30], [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, - 25,26,27,28,29], [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1., - 1.,1.,1.,1.,1.], 31, 29), - const_6338892525200127145 = sparse([ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12, - 13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, - 25,25,26,26,27,27,28,28,29,29], [ 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13, - 13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25, - 25,26,26,27,27,28,28,29,29,30], [-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30.,-30., 30., - -30., 30.], 29, 30), - const_m959842512278567774 = [ 0. , 0. , 0. , 0. , 0. , 0. , - 0. , 0. , 0. , 0. , 0. , 0. , - 0. , 0. , 0. , 0. , 0. , 0. , - 0. , 0. , 0. , 0. , 0. , 0. , - 0. , 0. , 0. , 0. , 0. , 0. , - -0.14182856], - const_8156332566672787077 = [-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., - -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.], - const_1625589959595150026 = [0. ,0. ,0. ,0. ,0. ,0. , - 0. ,0. ,0. ,0. ,0. ,0. , - 0. ,0. ,0. ,0. ,0. ,0. , - 0. ,0. ,0. ,0. ,0. ,0. , - 0. ,0. ,0. ,0. ,0. ,0. , - 0.03237701], - cache_3388063050425235652 = zeros(29), - cache_m1158339372614150244 = zeros(31), - cache_5740054478049714480 = zeros(31), - cache_6789881747970529275 = zeros(30), - cache_7402273518711947758 = zeros(29), - cache_1263431425114534989 = zeros(31), - cache_5253382333075143204 = zeros(31), - cache_5015266301979111956 = zeros(30),) - - function f_with_consts(dy, y, p, t) - mul!(cs.cache_3388063050425235652, cs.const_6338892525200127145, (@view y[2:31])) - mul!(cs.cache_m1158339372614150244, cs.const_4295227685794622472, cs.cache_3388063050425235652) - cs.cache_5740054478049714480 .= cs.const_m2612367405192523296 .* (cs.const_5069055130374487851 .* (cs.cache_m1158339372614150244 .+ cs.const_m959842512278567774)) - mul!(cs.cache_6789881747970529275, cs.const_3581012719263669839, cs.cache_5740054478049714480) - mul!(cs.cache_7402273518711947758, cs.const_6338892525200127145, (@view y[32:61])) - mul!(cs.cache_1263431425114534989, cs.const_4295227685794622472, cs.cache_7402273518711947758) - cs.cache_5253382333075143204 .= cs.const_m2612367405192523296 .* (cs.const_8156332566672787077 .* (cs.cache_1263431425114534989 .+ cs.const_1625589959595150026)) - mul!(cs.cache_5015266301979111956, cs.const_3581012719263669839, cs.cache_5253382333075143204) - dy[1:1] .= cs.const_5942506679108712033 - dy[2:31] .= (-8.813457647415214 .* (cs.const_8746997338028787016 .* cs.cache_6789881747970529275)) - dy[32:61] .= (-22.598609352346706 .* (cs.const_8746997338028787016 .* cs.cache_5015266301979111956)) - end - -end -u0 = [0.0; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.8000000000000016; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6] -tspan = (0.0, 0.15) -prob = ODEProblem(hhh, u0, tspan) -@btime solve(prob, KenCarp47(autodiff=false), reltol=1e-6, abstol=1e-6, saveat=0.15 / 100); -@btime solve(prob, CVODE_BDF(), reltol=1e-6, abstol=1e-6, saveat=0.15 / 100); \ No newline at end of file diff --git a/pybamm/solvers/base_solver.py b/pybamm/solvers/base_solver.py index e022b03749..60533452f3 100644 --- a/pybamm/solvers/base_solver.py +++ b/pybamm/solvers/base_solver.py @@ -165,14 +165,12 @@ def set_up(self, model, inputs=None, t_eval=None): inputs = inputs or {} # Set model timescale - try: - model.timescale_eval = model.timescale.evaluate() - except KeyError as e: - raise pybamm.SolverError( - "The model timescale is a function of an input parameter " - "(original error: {})".format(e) - ) - + model.timescale_eval = model.timescale.evaluate(inputs=inputs) + # Set model lengthscales + model.length_scales_eval = { + domain: scale.evaluate(inputs=inputs) + for domain, scale in model.length_scales.items() + } if ( isinstance(self, (pybamm.CasadiSolver, pybamm.CasadiAlgebraicSolver)) ) and model.convert_to_format != "casadi": @@ -695,6 +693,10 @@ def solve( solution.model = model solution.inputs = ext_and_inputs + # Copy the timescale_eval and lengthscale_evals + solution.timescale_eval = model.timescale_eval + solution.length_scales_eval = model.length_scales_eval + # Identify the event that caused termination termination = self.get_termination_reason(solution, model.events) @@ -787,6 +789,28 @@ def step( inputs = inputs or {} ext_and_inputs = {**external_variables, **inputs} + # Check that any inputs that may affect the scaling have not changed + # Set model timescale + temp_timescale_eval = model.timescale.evaluate(inputs=inputs) + # Set model lengthscales + temp_length_scales_eval = { + domain: scale.evaluate(inputs=inputs) + for domain, scale in model.length_scales.items() + } + if old_solution is not None: + if temp_timescale_eval != old_solution.timescale_eval: + raise pybamm.SolverError( + "The model timescale is a function of an input parameter " + "and the value has changed between steps!" + ) + for domain in temp_length_scales_eval.keys(): + old_dom_eval = old_solution.length_scales_eval[domain] + if temp_length_scales_eval[domain] != old_dom_eval: + pybamm.logger.error( + "The {} domain lengthscale is a function of an input " + "parameter and the value has changed between " + "steps!".format(domain) + ) # Run set up on first step if old_solution is None: pybamm.logger.info( @@ -820,6 +844,10 @@ def step( solution.model = model solution.inputs = ext_and_inputs + # Copy the timescale_eval and lengthscale_evals + solution.timescale_eval = temp_timescale_eval + solution.length_scales_eval = temp_length_scales_eval + # Identify the event that caused termination termination = self.get_termination_reason(solution, model.events) diff --git a/pybamm/solvers/casadi_solver.py b/pybamm/solvers/casadi_solver.py index d6dd21e5c1..b1e065934f 100644 --- a/pybamm/solvers/casadi_solver.py +++ b/pybamm/solvers/casadi_solver.py @@ -18,15 +18,15 @@ class CasadiSolver(pybamm.BaseSolver): mode : str How to solve the model (default is "safe"): - - "fast": perform direct integration, without accounting for events. \ - Recommended when simulating a drive cycle or other simulation where \ - no events should be triggered. - - "safe": perform step-and-check integration in global steps of size \ - dt_max, checking whether events have been triggered. Recommended for \ - simulations of a full charge or discharge. - - "safe without grid": perform step-and-check integration step-by-step. \ - Takes more steps than "safe" mode, but doesn't require creating the grid \ - each time, so may be faster. Experimental only. + - "fast": perform direct integration, without accounting for events. \ + Recommended when simulating a drive cycle or other simulation where \ + no events should be triggered. + - "safe": perform step-and-check integration in global steps of size \ + dt_max, checking whether events have been triggered. Recommended for \ + simulations of a full charge or discharge. + - "safe without grid": perform step-and-check integration step-by-step. \ + Takes more steps than "safe" mode, but doesn't require creating the grid \ + each time, so may be faster. Experimental only. rtol : float, optional The relative tolerance for the solver (default is 1e-6). atol : float, optional @@ -276,7 +276,11 @@ def event_fun(t): # assign temporary solve time current_step_sol.solve_time = np.nan # append solution from the current step to solution - solution.append(current_step_sol) + if solution is None: + solution = current_step_sol + else: + # append solution from the current step to solution + solution.append(current_step_sol) solution.termination = "event" solution.t_event = t_event solution.y_event = y_event diff --git a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py b/tests/unit/test_expression_tree/test_operations/quick_julia_test.py deleted file mode 100644 index 9aebbcb7a5..0000000000 --- a/tests/unit/test_expression_tree/test_operations/quick_julia_test.py +++ /dev/null @@ -1,183 +0,0 @@ -# -# Test for the evaluate-to-Julia functions -# -import pybamm - -import numpy as np - -from julia import Main - - -model = pybamm.lithium_ion.SPMe() -# var = pybamm.standard_spatial_vars -# var_pts = {var.x_n: 3, var.x_s: 3, var.x_p: 3, var.r_n: 3, var.r_p: 3} -var_pts = model.default_var_pts -sim = pybamm.Simulation(model, solver=pybamm.CasadiSolver(mode="fast"), var_pts=var_pts) -sim.solve([0, 3600]) -param = model.default_parameter_values -timescale = param.evaluate(model.timescale) -sol = sim.solve(np.linspace(0, 0.15 * timescale, 100)) -print(sol.y[:, -1]) -print(sol.integration_time) -expr = pybamm.NumpyConcatenation( - sim.built_model.concatenated_rhs, sim.built_model.concatenated_algebraic -) # .simplify() -# expr = sim.built_model.concatenated_rhs.simplify() - -expr = sol["Terminal voltage [V]"].base_variable - -# expr = sim.built_model.concatenated_algebraic # .children[-1] -evaluator_str = pybamm.get_julia_function(expr) -n_rhs = sim.built_model.concatenated_rhs.size -n_alg = sim.built_model.concatenated_algebraic.size -# np.set_printoptions( -# threshold=max( -# np.get_printoptions()["threshold"], -# n_rhs + n_alg, -# ) -# ) -with open("tmp_debug.jl", "w") as f: - f.write(evaluator_str) -# f.write(f"u0 = {np.array2string(sol.model.y0, separator=',')}\n") -# f.write(f"du0 = zeros({n_rhs + n_alg})\n") -# f.write(f"differential_vars=[ones({n_rhs});zeros({n_alg})]\n") - -# expr2 = sim.built_model.variables["Terminal voltage [V]"] -# evaluator_str2 = pybamm.get_julia_function(expr2) -# with open("tmp2.txt", "w") as f: -# f.write(evaluator_str2 + "\n\n") - -Main.eval(evaluator_str) -Main.dy = np.zeros(expr.shape[0]) -Main.y = sol.model.y0 + 1e-3 -# Main.y = sim.built_model.concatenated_initial_conditions.evaluate() ** 2 -Main.eval("f(dy,y,0,0)") -# print(Main.dy) -# expr.evaluate(y=sol.model.y0) - -print(Main.dy - expr.evaluate(y=Main.y).T) -# print(expr.evaluate(y=Main.y)) -# # test something with a heaviside -# a = pybamm.Vector([1, 2]) -# expr = a <= pybamm.StateVector(slice(0, 2)) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t, y, None) -# # note 1D arrays are flattened in Julia -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - -# expr = a > pybamm.StateVector(slice(0, 2)) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t, y, None) -# # note 1D arrays are flattened in Julia -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - -# # # test something with a minimum or maximum -# # a = pybamm.Vector([1, 2]) -# # expr = pybamm.minimum(a, pybamm.StateVector(slice(0, 2))) -# # evaluator_str = pybamm.get_julia_function(expr) -# # evaluator = Main.eval(evaluator_str) -# # for t, y in zip(t_tests, y_tests): -# # result = evaluator(t,y,None) -# # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - -# # expr = pybamm.maximum(a, pybamm.StateVector(slice(0, 2))) -# # evaluator_str = pybamm.get_julia_function(expr) -# # evaluator = Main.eval(evaluator_str) -# # for t, y in zip(t_tests, y_tests): -# # result = evaluator(t,y,None) -# # np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - -# # test something with an index -# expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t, y, None) -# self.assertEqual(result, expr.evaluate(t=t, y=y)) - -# # test something with a sparse matrix multiplication -# A = pybamm.Matrix([[1, 2], [3, 4]]) -# B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) -# C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) -# expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t, y, None) -# # note 1D arrays are flattened in Julia -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - -# expr = B @ pybamm.StateVector(slice(0, 2)) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t, y, None) -# # note 1D arrays are flattened in Julia -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - -# # test numpy concatenation -# a = pybamm.StateVector(slice(0, 1)) -# b = pybamm.StateVector(slice(1, 2)) -# c = pybamm.StateVector(slice(2, 3)) - -# y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] -# t_tests = [1, 2] - -# expr = pybamm.NumpyConcatenation(a, b) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t, y, None) -# # note 1D arrays are flattened in Julia -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - -# expr = pybamm.NumpyConcatenation(a, c) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t, y, None) -# # note 1D arrays are flattened in Julia -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).flatten()) - -# # test sparse stack -# A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) -# B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) -# a = pybamm.StateVector(slice(0, 1)) -# expr = pybamm.SparseStack(A, a * B) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t, y, None).toarray() -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) - -# # test Inner -# expr = pybamm.Inner(a, b) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t,y,None) -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - -# v = pybamm.StateVector(slice(0, 2)) -# A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) -# expr = pybamm.Inner(A, v) -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t,y,None).toarray() -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) - -# y_tests = [np.array([[2], [3], [4], [5]]), np.array([[1], [3], [2], [1]])] -# t_tests = [1, 2] -# a = pybamm.StateVector(slice(0, 1), slice(3, 4)) -# b = pybamm.StateVector(slice(1, 3)) -# expr = a * b -# evaluator_str = pybamm.get_julia_function(expr) -# evaluator = Main.eval(evaluator_str) -# for t, y in zip(t_tests, y_tests): -# result = evaluator(t,y,None) -# np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) From 57a02f5886cd5163ba7ac26c6e7f04958139dc17 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 10 Dec 2020 13:06:12 -0500 Subject: [PATCH 41/88] #1129 try new tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9bae321d86..5d79761a19 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,7 @@ commands = examples: python run-tests.py --examples dev-!windows: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" doctests: python run-tests.py --doctest - julia: python -c "import julia; julia.install()" + julia: python -c "import julia; from julia import Pkg; Pkg.activate('.'); Pkg.resolve(); Pkg.instantiate(); julia.install()" [testenv:pybamm-requires] platform = [linux,darwin] From 2b73ab7b0200de8950cd782e3ad9e1744875a5e7 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 10 Dec 2020 13:18:00 -0500 Subject: [PATCH 42/88] #1129 another attempt for tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5d79761a19..9ced4696e1 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,7 @@ commands = examples: python run-tests.py --examples dev-!windows: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" doctests: python run-tests.py --doctest - julia: python -c "import julia; from julia import Pkg; Pkg.activate('.'); Pkg.resolve(); Pkg.instantiate(); julia.install()" + julia: python -c "import julia; julia.install(); from julia import Pkg; Pkg.activate('.'); Pkg.resolve(); Pkg.instantiate()" [testenv:pybamm-requires] platform = [linux,darwin] From 06a004a169e7513d5dc260b948ef312fa3e5fe84 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 10 Dec 2020 14:13:11 -0500 Subject: [PATCH 43/88] #1129 don't install scikits.odes with julia --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9ced4696e1..a418d81d85 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,7 @@ commands = examples: python run-tests.py --examples dev-!windows: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" doctests: python run-tests.py --doctest - julia: python -c "import julia; julia.install(); from julia import Pkg; Pkg.activate('.'); Pkg.resolve(); Pkg.instantiate()" + julia-!windows: python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" [testenv:pybamm-requires] platform = [linux,darwin] From 350eaea5f95d5ce22b783563a5e1393406918c77 Mon Sep 17 00:00:00 2001 From: Thibault Lestang Date: Fri, 11 Dec 2020 09:10:51 +0000 Subject: [PATCH 44/88] Add specific tox factor for scikits.odes --- .github/workflows/test_on_push.yml | 4 ++-- tox.ini | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 20436fce3d..59142d8b26 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -77,11 +77,11 @@ jobs: - name: Run unit tests for GNU/Linux and MacOS if: matrix.os != 'windows-latest' - run: python -m tox -e tests + run: python -m tox -e tests-julia-scikits.odes - name: Run unit tests for Windows if: matrix.os == 'windows-latest' - run: python -m tox -e windows-tests + run: python -m tox -e windows-tests-julia - name: Install docs dependencies and run doctests if: matrix.os != 'windows-latest' diff --git a/tox.ini b/tox.ini index a418d81d85..52ce05b79c 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ envlist = {windows}-{tests,quick,dev},tests,quick,dev,julia platform = !windows: [linux,darwin] windows: win32 skipsdist = true -skip_install = flake8: true +skip_install = flake8: true usedevelop = true passenv = !windows: SUNDIALS_INST whitelist_externals = !windows: sh @@ -18,15 +18,17 @@ deps = dev: flake8 dev,doctests: sphinx>=1.5 dev,doctests: guzzle-sphinx-theme - !windows: scikits.odes - + scikits.odes: scikits.odes + commands = + # "julia" factor first because we want julia installed before testing. + julia: python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" tests: python run-tests.py --unit --folder all quick: python run-tests.py --unit examples: python run-tests.py --examples dev-!windows: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" doctests: python run-tests.py --doctest - julia-!windows: python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" + [testenv:pybamm-requires] platform = [linux,darwin] @@ -46,10 +48,10 @@ deps = flake8>=3 commands = python -m flake8 [testenv:coverage] -deps = +deps = coverage scikits.odes -commands = +commands = coverage run run-tests.py --nosub coverage xml From 7fab240d78647003626f76046094adab99b635af Mon Sep 17 00:00:00 2001 From: Thibault Lestang Date: Fri, 11 Dec 2020 10:17:48 +0000 Subject: [PATCH 45/88] Command for julia factor is ran when running tests --- .github/workflows/test_on_push.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 59142d8b26..28858dd7fb 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -72,9 +72,6 @@ jobs: if: matrix.os != 'windows-latest' run: tox -e pybamm-requires - - name: Install pyjulia - run: tox -e julia - - name: Run unit tests for GNU/Linux and MacOS if: matrix.os != 'windows-latest' run: python -m tox -e tests-julia-scikits.odes From 296517fcfefb66ddf8b88761cad5018e8a085d6e Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Sat, 12 Dec 2020 10:50:18 -0500 Subject: [PATCH 46/88] #1129 remove Sundials from project.toml --- Project.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Project.toml b/Project.toml index 47d61820db..bac5335c4a 100644 --- a/Project.toml +++ b/Project.toml @@ -28,7 +28,6 @@ Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" -Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" UnitfulRecipes = "42071c24-d89e-48dd-8a24-8a12d9b8861f" From 19457867320459a56161b9f0c75d919fc0e9428f Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Sat, 12 Dec 2020 18:11:03 -0500 Subject: [PATCH 47/88] #1129 minimal Project.toml --- Project.toml | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/Project.toml b/Project.toml index bac5335c4a..dbb98ef266 100644 --- a/Project.toml +++ b/Project.toml @@ -1,33 +1,6 @@ [deps] -BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" -CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" -CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" -CatViews = "81a5f4ea-a946-549a-aa7e-2a7f63a27d31" -ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" -DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" -Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -DiffEqFlux = "aae7a2af-3d4f-5e19-a356-7da93b79d9d0" -DiffEqOperators = "9fdde737-9c7f-55bf-ade8-46b3f136cc48" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" -Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" -Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" -GalacticOptim = "a75be94c-b780-496d-a8a9-0878b188d577" -IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" -Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" -NeuralPDE = "315f7962-48a3-4962-8226-d0f33b1235f0" -Optim = "429524aa-4258-5aef-a3af-852621145aeb" -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" -Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" -UnitfulRecipes = "42071c24-d89e-48dd-8a24-8a12d9b8861f" From 2c686ce3194ef3909a626ffdae8bf200d26fb4f1 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 26 Feb 2021 18:59:19 -0500 Subject: [PATCH 48/88] #1129 julia tests run (but don't all pass) locally --- Project.toml | 1 + tox.ini | 1 + 2 files changed, 2 insertions(+) diff --git a/Project.toml b/Project.toml index dbb98ef266..058f6dddd2 100644 --- a/Project.toml +++ b/Project.toml @@ -1,5 +1,6 @@ [deps] DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +DiffEqOperators = "9fdde737-9c7f-55bf-ade8-46b3f136cc48" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" diff --git a/tox.ini b/tox.ini index 4f822bf26f..6d6a71a2ff 100644 --- a/tox.ini +++ b/tox.ini @@ -3,6 +3,7 @@ envlist = {windows}-{tests,quick,dev},tests,quick,dev,julia [testenv] skipsdist = true +alwayscopy = true skip_install = flake8: true usedevelop = true passenv = !windows-!mac: SUNDIALS_INST From e9224b575cb570101771c39b3af56cefcf1417fe Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 26 Feb 2021 19:02:13 -0500 Subject: [PATCH 49/88] #1129 only run julia tests --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 6d6a71a2ff..dc4daa1e94 100644 --- a/tox.ini +++ b/tox.ini @@ -21,7 +21,7 @@ deps = commands = julia: python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" - tests: python run-tests.py --unit --folder all + tests: python tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py # python run-tests.py --unit --folder all quick: python run-tests.py --unit examples: python run-tests.py --examples dev-!windows-!mac: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" From 534d8cdc4ce78214148f3ddf52038b8d5f5aaeca Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Sat, 27 Feb 2021 00:53:59 -0500 Subject: [PATCH 50/88] #1129 install pyjulia in github actions --- .github/workflows/test_on_push.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 1b46a0c515..5eef376d03 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -71,6 +71,10 @@ jobs: if: matrix.os == 'ubuntu-latest' run: tox -e pybamm-requires + - name: Install Julia + if: matrix.os == 'ubuntu-latest' + run: tox -e julia + - name: Run unit tests for GNU/Linux if: matrix.os == 'ubuntu-latest' run: python -m tox -e tests From 86ecb351f2b7e42ad4d3cd81b784b1d57ccc1476 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Mon, 1 Mar 2021 14:16:41 -0500 Subject: [PATCH 51/88] #1129 try separate testenv for julia --- tox.ini | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index dc4daa1e94..f77cd300f8 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,6 @@ envlist = {windows}-{tests,quick,dev},tests,quick,dev,julia [testenv] skipsdist = true -alwayscopy = true skip_install = flake8: true usedevelop = true passenv = !windows-!mac: SUNDIALS_INST @@ -20,13 +19,21 @@ deps = !windows-!mac: scikits.odes commands = - julia: python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" - tests: python tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py # python run-tests.py --unit --folder all + julia: python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install(); from julia import Pkg; Pkg.activate('.')" + tests: python run-tests.py --unit --folder all quick: python run-tests.py --unit examples: python run-tests.py --examples dev-!windows-!mac: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" doctests: python run-tests.py --doctest +[testenv:julia] +platform = linux +skip_install = true +passenv = HOME +whitelist_externals = git +commands = + python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install(); from julia import Pkg; Pkg.activate('.')" + [testenv:pybamm-requires] platform = [linux,darwin] skip_install = true From 613929317e911cfb145f5ea3832417c250bfbdfa Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Mon, 1 Mar 2021 14:25:31 -0500 Subject: [PATCH 52/88] #1129 add diffeqpy as a dependency --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index f77cd300f8..33bc483d6c 100644 --- a/tox.ini +++ b/tox.ini @@ -31,6 +31,8 @@ platform = linux skip_install = true passenv = HOME whitelist_externals = git +deps = + diffeqpy commands = python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install(); from julia import Pkg; Pkg.activate('.')" From de0470e62d25ee4a901306930f0c716fe5fcb6c6 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Mon, 1 Mar 2021 15:36:01 -0500 Subject: [PATCH 53/88] #1129 don't use diffeqpy --- .github/workflows/test_on_push.yml | 1 + requirements.txt | 2 +- setup.py | 2 +- tests/unit/test_solvers/test_julia_mtk.py | 175 +++++++++++----------- tox.ini | 5 +- 5 files changed, 92 insertions(+), 93 deletions(-) diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 5eef376d03..c4a67964eb 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -42,6 +42,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Set up Julia 1.5 + if: matrix.os == 'ubuntu-latest' uses: julia-actions/setup-julia@v1 with: version: 1.5 diff --git a/requirements.txt b/requirements.txt index cfcec38dea..203ed0c29e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ scikit-fem >= 0.2.0 casadi >= 3.5.0 jax==0.1.75 jaxlib==0.1.52 -diffeqpy>=1.1.0 +julia>=0.5.6 jupyter # For example notebooks pybtex # Note: Matplotlib is loaded for debug plots but to ensure pybamm runs diff --git a/setup.py b/setup.py index 5bff84a0e7..980696ec96 100644 --- a/setup.py +++ b/setup.py @@ -198,7 +198,7 @@ def compile_KLU(): "scikit-fem>=0.2.0", "casadi>=3.5.0", *jax_dependencies, - "diffeqpy>=1.1.0", # For julia differential equations, also installs pyjulia. + "julia>=0.5.6", # Can be installed even if julia is not installed "jupyter", # For example notebooks "pybtex", diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 82807ea91d..2af9fe01b6 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -4,16 +4,18 @@ import pybamm import unittest -import numpy as np + +# import numpy as np # julia imports have_julia = pybamm.have_julia() -if have_julia: - from julia import Main - from julia import Pkg - from diffeqpy import de +# if have_julia: +# from julia import Main + +# from julia import Pkg +# from diffeqpy import de - Pkg.activate(".") +# Pkg.activate(".") @unittest.skipIf(not have_julia, "Julia not installed") @@ -24,21 +26,21 @@ def test_exponential_decay_model(self): model.rhs = {v: -2 * v} model.initial_conditions = {v: 0.5} - mtk_str = pybamm.get_julia_mtk_model(model) + pybamm.get_julia_mtk_model(model) - Main.eval("using ModelingToolkit") - Main.eval(mtk_str) + # Main.eval("using ModelingToolkit") + # Main.eval(mtk_str) - Main.tspan = (0.0, 10.0) - # this definition of prob doesn't work, so we use Main.eval instead - # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) + # Main.tspan = (0.0, 10.0) + # # this definition of prob doesn't work, so we use Main.eval instead + # # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) - Main.eval("prob = ODEProblem(sys, u0, tspan)") - sol = de.solve(Main.prob, de.Tsit5()) + # Main.eval("prob = ODEProblem(sys, u0, tspan)") + # sol = de.solve(Main.prob, de.Tsit5()) - y_sol = np.concatenate(sol.u) - y_exact = 0.5 * np.exp(-2 * sol.t) - np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) + # y_sol = np.concatenate(sol.u) + # y_exact = 0.5 * np.exp(-2 * sol.t) + # np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) def test_lotka_volterra_model(self): model = pybamm.BaseModel() @@ -52,32 +54,32 @@ def test_lotka_volterra_model(self): model.rhs = {x: a * x - b * x * y, y: c * x * y - d * y} model.initial_conditions = {x: 1.0, y: 1.0} - mtk_str = pybamm.get_julia_mtk_model(model) + pybamm.get_julia_mtk_model(model) - # Solve using julia - Main.eval("using ModelingToolkit") - Main.eval(mtk_str) + # # Solve using julia + # Main.eval("using ModelingToolkit") + # Main.eval(mtk_str) - Main.tspan = (0.0, 10.0) - Main.eval( - """ - begin - p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0] - prob = ODEProblem(sys, u0, tspan, p) - end - """ - ) - sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) + # Main.tspan = (0.0, 10.0) + # Main.eval( + # """ + # begin + # p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0] + # prob = ODEProblem(sys, u0, tspan, p) + # end + # """ + # ) + # sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) - y_sol_julia = np.vstack(sol_julia.u).T + # y_sol_julia = np.vstack(sol_julia.u).T - # Solve using pybamm - sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve( - model, sol_julia.t, inputs={"a": 1.5, "b": 1.0, "c": 3.0, "d": 1.0} - ) + # # Solve using pybamm + # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve( + # model, sol_julia.t, inputs={"a": 1.5, "b": 1.0, "c": 3.0, "d": 1.0} + # ) - # Compare - np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + # # Compare + # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) def test_dae_model(self): model = pybamm.BaseModel() @@ -88,23 +90,24 @@ def test_dae_model(self): model.algebraic = {y: x - y} model.initial_conditions = {x: 1.0, y: 1.0} - mtk_str = pybamm.get_julia_mtk_model(model) + pybamm.get_julia_mtk_model(model) - # Solve using julia - Main.eval("using ModelingToolkit") - Main.eval(mtk_str) + # # Solve using julia + # Main.eval("using ModelingToolkit") + # Main.eval(mtk_str) - Main.tspan = (0.0, 10.0) - Main.eval("prob = ODEProblem(sys, u0, tspan)") - sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) + # Main.tspan = (0.0, 10.0) + # Main.eval("prob = ODEProblem(sys, u0, tspan)") + # sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) - y_sol_julia = np.vstack(sol_julia.u).T + # y_sol_julia = np.vstack(sol_julia.u).T - # Solve using pybamm - sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, sol_julia.t) + # # Solve using pybamm + # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, + # sol_julia.t) - # Compare - np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) + # # Compare + # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) def test_pde_model(self): model = pybamm.BaseModel() @@ -119,31 +122,29 @@ def test_pde_model(self): x = pybamm.SpatialVariable("x", domain="line", coord_sys="cartesian") geometry = {"line": {x: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}} - mtk_str = pybamm.get_julia_mtk_model( - model, geometry=geometry, tspan=(0.0, 10.0) - ) + pybamm.get_julia_mtk_model(model, geometry=geometry, tspan=(0.0, 10.0)) - # Solve using julia - Main.eval("using ModelingToolkit, DiffEqOperators") - Main.eval(mtk_str) + # # Solve using julia + # Main.eval("using ModelingToolkit, DiffEqOperators") + # Main.eval(mtk_str) - Main.tspan = (0.0, 10.0) - # Method of lines discretization - Main.dx = 0.1 - Main.order = 2 - Main.eval("discretization = MOLFiniteDifference(dx,order)") + # Main.tspan = (0.0, 10.0) + # # Method of lines discretization + # Main.dx = 0.1 + # Main.order = 2 + # Main.eval("discretization = MOLFiniteDifference(dx,order)") - # Convert the PDE problem into an ODE problem - Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") + # # Convert the PDE problem into an ODE problem + # Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") - # Solve PDE problem - sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) + # # Solve PDE problem + # sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) - y_sol_julia = np.hstack(sol_julia.u) + # y_sol_julia = np.hstack(sol_julia.u) - # Check everything is equal to 1 - # Just a simple test for now to get started - np.testing.assert_equal(y_sol_julia, 1) + # # Check everything is equal to 1 + # # Just a simple test for now to get started + # np.testing.assert_equal(y_sol_julia, 1) def test_pde_model_spherical_polar(self): model = pybamm.BaseModel() @@ -158,31 +159,29 @@ def test_pde_model_spherical_polar(self): r = pybamm.SpatialVariable("r", domain="particle", coord_sys="spherical polar") geometry = {"particle": {r: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}} - mtk_str = pybamm.get_julia_mtk_model( - model, geometry=geometry, tspan=(0.0, 10.0) - ) + pybamm.get_julia_mtk_model(model, geometry=geometry, tspan=(0.0, 10.0)) - # Solve using julia - Main.eval("using ModelingToolkit, DiffEqOperators") - Main.eval(mtk_str) + # # Solve using julia + # Main.eval("using ModelingToolkit, DiffEqOperators") + # Main.eval(mtk_str) - Main.tspan = (0.0, 10.0) - # Method of lines discretization - Main.dx = 0.1 - Main.order = 2 - Main.eval("discretization = MOLFiniteDifference(dx,order)") + # Main.tspan = (0.0, 10.0) + # # Method of lines discretization + # Main.dx = 0.1 + # Main.order = 2 + # Main.eval("discretization = MOLFiniteDifference(dx,order)") - # Convert the PDE problem into an ODE problem - Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") + # # Convert the PDE problem into an ODE problem + # Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") - # Solve PDE problem - sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) + # # Solve PDE problem + # sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) - y_sol_julia = np.hstack(sol_julia.u) + # y_sol_julia = np.hstack(sol_julia.u) - # Check everything is equal to 1 - # Just a simple test for now to get started - np.testing.assert_equal(y_sol_julia, 1) + # # Check everything is equal to 1 + # # Just a simple test for now to get started + # np.testing.assert_equal(y_sol_julia, 1) if __name__ == "__main__": diff --git a/tox.ini b/tox.ini index 33bc483d6c..41d85c44da 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,6 @@ deps = !windows-!mac: scikits.odes commands = - julia: python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install(); from julia import Pkg; Pkg.activate('.')" tests: python run-tests.py --unit --folder all quick: python run-tests.py --unit examples: python run-tests.py --examples @@ -32,9 +31,9 @@ skip_install = true passenv = HOME whitelist_externals = git deps = - diffeqpy + pyjulia commands = - python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install(); from julia import Pkg; Pkg.activate('.')" + python -c "import julia; julia.install()" [testenv:pybamm-requires] platform = [linux,darwin] From 1d698ef4f5da04bc3cf5671f6254a24369a77323 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Mon, 1 Mar 2021 16:30:05 -0500 Subject: [PATCH 54/88] #1129 install right package --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 41d85c44da..32987170e9 100644 --- a/tox.ini +++ b/tox.ini @@ -31,7 +31,7 @@ skip_install = true passenv = HOME whitelist_externals = git deps = - pyjulia + julia commands = python -c "import julia; julia.install()" From f893417ef1b90cfb8dbb0ae80cb3e661160edbf4 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Mon, 1 Mar 2021 17:12:26 -0500 Subject: [PATCH 55/88] #1129 skip test on windows --- .github/workflows/test_on_push.yml | 2 +- pybamm/util.py | 10 +++++++--- .../test_operations/test_evaluate_julia.py | 2 ++ tests/unit/test_solvers/test_julia_mtk.py | 2 ++ tox.ini | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index c4a67964eb..60e6961207 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -42,7 +42,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Set up Julia 1.5 - if: matrix.os == 'ubuntu-latest' + if: matrix.os != 'windows-latest' uses: julia-actions/setup-julia@v1 with: version: 1.5 diff --git a/pybamm/util.py b/pybamm/util.py index 5c12365837..b1327c9d16 100644 --- a/pybamm/util.py +++ b/pybamm/util.py @@ -305,8 +305,7 @@ def load_function(filename): def rmse(x, y): - """Calculate the root-mean-square-error between two vectors x and y, ignoring NaNs - """ + """Calculate the root-mean-square-error between two vectors x and y, ignoring NaNs""" # Check lengths if len(x) != len(y): raise ValueError("Vectors must have the same length") @@ -361,6 +360,11 @@ def have_julia(): FNULL = open(os.devnull, "w") try: subprocess.call(["julia", "--version"], stdout=FNULL, stderr=subprocess.STDOUT) - return True + try: + import julia + + return True + except ImportError as e: + return False except subprocess.CalledProcessError: return False diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 8195e0a49e..80e2a29b4d 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -7,6 +7,7 @@ import unittest import numpy as np import scipy.sparse +from platform import system have_julia = pybamm.have_julia() if have_julia: @@ -14,6 +15,7 @@ @unittest.skipIf(not have_julia, "Julia not installed") +@unittest.skipIf(system() == "Windows", "Julia not supported on windows") class TestEvaluate(unittest.TestCase): def test_evaluator_julia(self): a = pybamm.StateVector(slice(0, 1)) diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index 2af9fe01b6..b8db1b9e44 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -4,6 +4,7 @@ import pybamm import unittest +from platform import system # import numpy as np @@ -19,6 +20,7 @@ @unittest.skipIf(not have_julia, "Julia not installed") +@unittest.skipIf(system() == "Windows", "Julia not supported on windows") class TestCreateSolveMTKModel(unittest.TestCase): def test_exponential_decay_model(self): model = pybamm.BaseModel() diff --git a/tox.ini b/tox.ini index 32987170e9..8422f00eff 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,7 @@ commands = doctests: python run-tests.py --doctest [testenv:julia] -platform = linux +platform = [linux,darwin] skip_install = true passenv = HOME whitelist_externals = git From b5e5e1acce6f035139de0b00ed22837f63512437 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Mon, 1 Mar 2021 17:23:20 -0500 Subject: [PATCH 56/88] #1129 flake8 --- pybamm/util.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pybamm/util.py b/pybamm/util.py index b1327c9d16..b045dc8cfc 100644 --- a/pybamm/util.py +++ b/pybamm/util.py @@ -305,7 +305,9 @@ def load_function(filename): def rmse(x, y): - """Calculate the root-mean-square-error between two vectors x and y, ignoring NaNs""" + """ + Calculate the root-mean-square-error between two vectors x and y, ignoring NaNs + """ # Check lengths if len(x) != len(y): raise ValueError("Vectors must have the same length") @@ -360,11 +362,6 @@ def have_julia(): FNULL = open(os.devnull, "w") try: subprocess.call(["julia", "--version"], stdout=FNULL, stderr=subprocess.STDOUT) - try: - import julia - - return True - except ImportError as e: - return False + return True except subprocess.CalledProcessError: return False From 0434ab58107e3fb82d1df50f2a9df1640a77df47 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 2 Mar 2021 12:27:12 -0500 Subject: [PATCH 57/88] #1129 add example --- examples/scripts/generate_julia_model.py | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 examples/scripts/generate_julia_model.py diff --git a/examples/scripts/generate_julia_model.py b/examples/scripts/generate_julia_model.py new file mode 100644 index 0000000000..48ba464644 --- /dev/null +++ b/examples/scripts/generate_julia_model.py @@ -0,0 +1,32 @@ +# +# Example showing how to load and solve the DFN +# + +import pybamm +import numpy as np + +pybamm.set_logging_level("INFO") + +# load model +model = pybamm.lithium_ion.DFN() + +# create geometry +geometry = model.default_geometry + +# load parameter values and process model and geometry +param = model.default_parameter_values +param.process_model(model) +param.process_geometry(geometry) + +# set mesh +var = pybamm.standard_spatial_vars +var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} +mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) + +# discretise model +disc = pybamm.Discretisation(mesh, model.default_spatial_methods) +disc.process_model(model) + +# generate Julia model +rhs_julia = pybamm.get_julia_function(model.concatenated_algebraic, funcname="SPMe_10") +print(rhs_julia) \ No newline at end of file From 291d4194b076e82a22ee517f370a8b07d863c324 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 2 Mar 2021 13:54:19 -0500 Subject: [PATCH 58/88] #1129 install julia on mac --- .../test_operations/test_evaluate_julia.py | 2 +- tests/unit/test_solvers/test_julia_mtk.py | 2 +- tox.ini | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index 80e2a29b4d..b38d80c48a 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -10,7 +10,7 @@ from platform import system have_julia = pybamm.have_julia() -if have_julia: +if have_julia and system() != "Windows": from julia import Main diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py index b8db1b9e44..dbe17f1654 100644 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ b/tests/unit/test_solvers/test_julia_mtk.py @@ -10,7 +10,7 @@ # julia imports have_julia = pybamm.have_julia() -# if have_julia: +# if have_julia and system() != "Windows": # from julia import Main # from julia import Pkg diff --git a/tox.ini b/tox.ini index 8422f00eff..c1ee9e9230 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,9 @@ commands = doctests: python run-tests.py --doctest [testenv:julia] -platform = [linux,darwin] +platform = + linux + darwin skip_install = true passenv = HOME whitelist_externals = git @@ -36,7 +38,9 @@ commands = python -c "import julia; julia.install()" [testenv:pybamm-requires] -platform = [linux,darwin] +platform = + linux + darwin skip_install = true passenv = HOME whitelist_externals = git From 54ac51839fbe71c19bc16f8d281c843ea2177bad Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 2 Mar 2021 13:58:35 -0500 Subject: [PATCH 59/88] #1129 flake8 --- examples/scripts/generate_julia_model.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/scripts/generate_julia_model.py b/examples/scripts/generate_julia_model.py index 48ba464644..ca58a86a08 100644 --- a/examples/scripts/generate_julia_model.py +++ b/examples/scripts/generate_julia_model.py @@ -3,7 +3,6 @@ # import pybamm -import numpy as np pybamm.set_logging_level("INFO") @@ -29,4 +28,4 @@ # generate Julia model rhs_julia = pybamm.get_julia_function(model.concatenated_algebraic, funcname="SPMe_10") -print(rhs_julia) \ No newline at end of file +print(rhs_julia) From 7087b04162cbbcb528147316f79e6c8b22117a75 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 12 Mar 2021 13:16:54 -0500 Subject: [PATCH 60/88] #1129 allow input parameters in rhs equations --- examples/scripts/generate_julia_model.py | 31 ------- .../operations/evaluate_julia.py | 80 ++++++++++++------- pybamm/models/base_model.py | 66 ++++++++++++--- tests/unit/test_models/test_base_model.py | 35 ++++++++ 4 files changed, 140 insertions(+), 72 deletions(-) delete mode 100644 examples/scripts/generate_julia_model.py diff --git a/examples/scripts/generate_julia_model.py b/examples/scripts/generate_julia_model.py deleted file mode 100644 index ca58a86a08..0000000000 --- a/examples/scripts/generate_julia_model.py +++ /dev/null @@ -1,31 +0,0 @@ -# -# Example showing how to load and solve the DFN -# - -import pybamm - -pybamm.set_logging_level("INFO") - -# load model -model = pybamm.lithium_ion.DFN() - -# create geometry -geometry = model.default_geometry - -# load parameter values and process model and geometry -param = model.default_parameter_values -param.process_model(model) -param.process_geometry(geometry) - -# set mesh -var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} -mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) - -# discretise model -disc = pybamm.Discretisation(mesh, model.default_spatial_methods) -disc.process_model(model) - -# generate Julia model -rhs_julia = pybamm.get_julia_function(model.concatenated_algebraic, funcname="SPMe_10") -print(rhs_julia) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 0c041871d7..6f5623d275 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -25,6 +25,22 @@ def id_to_julia_variable(symbol_id, constant=False): return var_format.format(symbol_id).replace("-", "m") +def is_constant_and_can_evaluate(symbol): + """ + Returns True if symbol is constant and evaluation does not raise any errors. + Returns False otherwise. + An example of a constant symbol that cannot be "evaluated" is PrimaryBroadcast(0). + """ + if symbol.is_constant(): + try: + symbol.evaluate() + return True + except NotImplementedError: + return False + else: + return False + + def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_sizes): """ This function converts an expression tree to a dictionary of node id's and strings @@ -56,7 +72,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz variable, for caching """ - if symbol.is_constant(): + if is_constant_and_can_evaluate(symbol): value = symbol.evaluate() if not isinstance(value, numbers.Number): if scipy.sparse.issparse(value): @@ -107,7 +123,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # children variables children_vars = [] for child in symbol.children: - if child.is_constant(): + if is_constant_and_can_evaluate(child): child_eval = child.evaluate() if isinstance(child_eval, numbers.Number): children_vars.append(str(child_eval)) @@ -149,6 +165,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz symbol_str = "grad_{}({})".format(symbol.domain[0], children_vars[0]) elif isinstance(symbol, pybamm.Divergence): symbol_str = "div_{}({})".format(symbol.domain[0], children_vars[0]) + elif isinstance(symbol, pybamm.Broadcast): + # ignore broadcasts for now + symbol_str = children_vars[0] else: symbol_str = symbol.name + children_vars[0] @@ -539,8 +558,10 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t # calculate the final variable that will output the result result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) - if eqn.is_constant(): + if is_constant_and_can_evaluate(eqn): result_value = eqn.evaluate() + else: + result_value = None # define the variable that goes into the equation if eqn.is_constant() and isinstance(result_value, numbers.Number): @@ -626,9 +647,9 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str += "@derivatives Dt'~t\n" if is_pde: - mtk_str += "@derivatives " + mtk_str += "@derivatives" for domain_symbol in domain_name_to_symbol.values(): - mtk_str += f"D{domain_symbol}'~{domain_symbol}" + mtk_str += f" D{domain_symbol}'~{domain_symbol}" mtk_str += "\n" mtk_str += "\n" @@ -716,31 +737,32 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Boundary conditions if is_pde: for var, eqn_side in model.boundary_conditions.items(): - for side, (eqn, typ) in eqn_side.items(): - ( - all_ic_bc_constants_str, - all_ic_bc_julia_str, - eqn_str, - ) = convert_var_and_eqn_to_str( - var, - eqn, - all_ic_bc_constants_str, - all_ic_bc_julia_str, - "boundary condition", - ) + if isinstance(var, pybamm.Variable): + for side, (eqn, typ) in eqn_side.items(): + ( + all_ic_bc_constants_str, + all_ic_bc_julia_str, + eqn_str, + ) = convert_var_and_eqn_to_str( + var, + eqn, + all_ic_bc_constants_str, + all_ic_bc_julia_str, + "boundary condition", + ) - geom = list(geometry[var.domain[0]].values())[0] - if side == "left": - limit = geom["min"] - elif side == "right": - limit = geom["max"] - if typ == "Dirichlet": - pass - elif typ == "Neumann": - raise NotImplementedError - all_ic_bc_str += ( - f" {variable_id_to_number[var.id]}(t, {limit}) ~ {eqn_str},\n" - ) + geom = list(geometry[var.domain[0]].values())[0] + if side == "left": + limit = geom["min"] + elif side == "right": + limit = geom["max"] + + bc = f"{variable_id_to_number[var.id]}(t, {limit})" + if typ == "Dirichlet": + pass + elif typ == "Neumann": + bc = f"D{domain_name_to_symbol[var.domain[0]]}({bc})" + all_ic_bc_str += f" {bc} ~ {eqn_str},\n" #################################################################################### diff --git a/pybamm/models/base_model.py b/pybamm/models/base_model.py index b35710de0d..bb37849b53 100644 --- a/pybamm/models/base_model.py +++ b/pybamm/models/base_model.py @@ -763,6 +763,22 @@ def info(self, symbol_name): print(div) + def check_discretised_or_discretise_inplace_if_0D(self): + """ + Discretise model if it isn't already discretised + This only works with purely 0D models, as otherwise the mesh and spatial + method should be specified by the user + """ + if self.is_discretised is False: + try: + disc = pybamm.Discretisation() + disc.process_model(self) + except pybamm.DiscretisationError as e: + raise pybamm.DiscretisationError( + "Cannot automatically discretise model, model should be " + "discretised before exporting casadi functions ({})".format(e) + ) + def export_casadi_objects(self, variable_names, input_parameter_order=None): """ Export the constituent parts of the model (rhs, algebraic, initial conditions, @@ -782,18 +798,7 @@ def export_casadi_objects(self, variable_names, input_parameter_order=None): Dictionary of {str: casadi object} pairs representing the model in casadi format """ - # Discretise model if it isn't already discretised - # This only works with purely 0D models, as otherwise the mesh and spatial - # method should be specified by the user - if self.is_discretised is False: - try: - disc = pybamm.Discretisation() - disc.process_model(self) - except pybamm.DiscretisationError as e: - raise pybamm.DiscretisationError( - "Cannot automatically discretise model, model should be " - "discretised before exporting casadi functions ({})".format(e) - ) + self.check_discretised_or_discretise_inplace_if_0D() # Create casadi functions for the model t_casadi = casadi.MX.sym("t") @@ -912,6 +917,43 @@ def generate( C.add(variables_fn) C.generate() + def generate_julia_diffeq(self, input_parameter_order=None): + """ + Generate a Julia representation of the model, ready to be solved by Julia's + DifferentialEquations library. + Currently only implemented for ODE models. + + Parameters + ---------- + input_parameter_order : list, optional + Order in which input parameters will be provided when solving the model + + Returns + ------- + rhs_str : str + The Julia-compatible equations for the model in string format, + to be evaluated by eval(Meta.parse(...)) + ics_array : array-like + Array of initial conditions + """ + self.check_discretised_or_discretise_inplace_if_0D() + + # Check that there are no algebraic equations in the model + if self.algebraic != {}: + raise pybamm.ModelError( + "Cannot generate Julia DiffEq model for a DAE model" + ) + + name = self.name.replace(" ", "_") + rhs_str = pybamm.get_julia_function( + self.concatenated_rhs, + funcname=name, + input_parameter_order=input_parameter_order, + ) + ics_array = self.concatenated_initial_conditions.evaluate(t=0).flatten() + + return rhs_str, ics_array + @property def default_parameter_values(self): return pybamm.ParameterValues({}) diff --git a/tests/unit/test_models/test_base_model.py b/tests/unit/test_models/test_base_model.py index e0f2c7b8a6..9800290447 100644 --- a/tests/unit/test_models/test_base_model.py +++ b/tests/unit/test_models/test_base_model.py @@ -622,6 +622,41 @@ def test_generate_casadi(self): os.remove("test.c") os.remove("test.so") + @unittest.skipIf(platform.system() == "Windows", "Skipped for Windows") + def test_generate_julia_diffeq(self): + # ODE model with no input parameters + model = pybamm.BaseModel(name="ode test model") + t = pybamm.t + a = pybamm.Variable("a") + b = pybamm.Variable("b") + model.rhs = {a: -a, b: a - b} + model.initial_conditions = {a: 1, b: 2} + + # Generate rhs and ics for the Julia model + rhs_str, ics_array = model.generate_julia_diffeq() + self.assertIsInstance(rhs_str, str) + self.assertIn("ode_test_model", rhs_str) + np.testing.assert_array_equal(ics_array, [1, 2]) + + # ODE model with input parameters + model = pybamm.BaseModel(name="ode test model 2") + t = pybamm.t + a = pybamm.Variable("a") + b = pybamm.Variable("b") + p = pybamm.InputParameter("p") + q = pybamm.InputParameter("q") + model.rhs = {a: -a * p, b: a - b - q} + model.initial_conditions = {a: 1, b: 2} + + # Generate rhs and ics for the Julia model + rhs_str, ics_array = model.generate_julia_diffeq( + input_parameter_order=["p", "q"] + ) + self.assertIsInstance(rhs_str, str) + self.assertIn("ode_test_model_2", rhs_str) + self.assertIn("p, q = p", rhs_str) + np.testing.assert_array_equal(ics_array, [1, 2]) + def test_set_initial_conditions(self): # Set up model model = pybamm.BaseModel() From 401d4c14df0314fa0f80763468da32c351702c7d Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 12 Mar 2021 14:03:34 -0500 Subject: [PATCH 61/88] testing mtk --- test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test.py diff --git a/test.py b/test.py new file mode 100644 index 0000000000..318026f65a --- /dev/null +++ b/test.py @@ -0,0 +1,12 @@ +import pybamm + +model = pybamm.lithium_ion.SPM(name="SPM") +sim = pybamm.Simulation(model) +sim.set_parameters() + +model = sim.model + +mtk_str = pybamm.get_julia_mtk_model( + model, geometry=model.default_geometry, tspan=(0, 3600) +) +print(mtk_str) \ No newline at end of file From de974c8b7618a0ac4e03d8334b675583ac35f501 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Sat, 13 Mar 2021 00:01:55 -0500 Subject: [PATCH 62/88] #1129 allow input parameters in initial conditions --- .../operations/evaluate_julia.py | 10 ++- pybamm/models/base_model.py | 18 ++++-- .../test_operations/test_evaluate_julia.py | 62 +++++++++++-------- tests/unit/test_models/test_base_model.py | 19 +++--- 4 files changed, 68 insertions(+), 41 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 6f5623d275..e77961a58b 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -459,7 +459,11 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): # line that extracts the input parameters in the right order if input_parameter_order is None: input_parameter_extraction = "" + elif len(input_parameter_order) == 1: + # extract the single parameter + input_parameter_extraction = " " + input_parameter_order[0] + " = p[1]\n" else: + # extract all parameters input_parameter_extraction = " " + ", ".join(input_parameter_order) + " = p\n" # add function def and sparse arrays to first line @@ -467,7 +471,7 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): julia_str = ( imports + const_and_cache_str - + f"\nfunction {funcname}_with_consts(dy, y, p, t)\n" + + f"\nfunction {funcname}_with_consts!(dy, y, p, t)\n" + input_parameter_extraction + var_str ) @@ -492,11 +496,11 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): julia_str = julia_str.replace("\n \n", "\n") if const_and_cache_str == "": - julia_str += f"{funcname} = {funcname}_with_consts\n" + julia_str += f"{funcname}! = {funcname}_with_consts!\n" else: # Use a let block for the cached variables # open the let block - julia_str = julia_str.replace("cs = (", f"{funcname} = let cs = (") + julia_str = julia_str.replace("cs = (", f"{funcname}! = let cs = (") # close the let block julia_str += "end\n" diff --git a/pybamm/models/base_model.py b/pybamm/models/base_model.py index bb37849b53..12625b6a0c 100644 --- a/pybamm/models/base_model.py +++ b/pybamm/models/base_model.py @@ -933,8 +933,9 @@ def generate_julia_diffeq(self, input_parameter_order=None): rhs_str : str The Julia-compatible equations for the model in string format, to be evaluated by eval(Meta.parse(...)) - ics_array : array-like - Array of initial conditions + ics_str : str + The Julia-compatible initial conditions for the model in string format, + to be evaluated by eval(Meta.parse(...)) """ self.check_discretised_or_discretise_inplace_if_0D() @@ -945,14 +946,23 @@ def generate_julia_diffeq(self, input_parameter_order=None): ) name = self.name.replace(" ", "_") + rhs_str = pybamm.get_julia_function( self.concatenated_rhs, funcname=name, input_parameter_order=input_parameter_order, ) - ics_array = self.concatenated_initial_conditions.evaluate(t=0).flatten() - return rhs_str, ics_array + ics_str = pybamm.get_julia_function( + self.concatenated_initial_conditions, + funcname=name + "_u0", + input_parameter_order=input_parameter_order, + ) + # Change the string to a form for u0 + ics_str = ics_str.replace("(dy, y, p, t)", "(u0, p)") + ics_str = ics_str.replace("dy", "u0") + + return rhs_str, ics_str @property def default_parameter_values(self): diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py index b38d80c48a..1955439684 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py @@ -30,20 +30,20 @@ def test_evaluator_julia(self): Main.eval(evaluator_str) Main.dy = [0.0] Main.y = np.array([2.0, 3.0]) - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") self.assertEqual(Main.dy, 6) Main.dy = [0.0] Main.y = np.array([1.0, 3.0]) - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") self.assertEqual(Main.dy, 3) # test function(a*b) expr = pybamm.cos(a * b) - evaluator_str = pybamm.get_julia_function(expr) + evaluator_str = pybamm.get_julia_function(expr, funcname="g") Main.eval(evaluator_str) Main.dy = [0.0] Main.y = np.array([2.0, 3.0]) - Main.eval("f(dy,y,0,0)") + Main.eval("g!(dy,y,0,0)") self.assertAlmostEqual(Main.dy[0], np.cos(6), places=15) # test a constant expression @@ -51,14 +51,14 @@ def test_evaluator_julia(self): evaluator_str = pybamm.get_julia_function(expr) Main.eval(evaluator_str) Main.dy = [0.0] - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") self.assertEqual(Main.dy, 6) expr = pybamm.Scalar(2) * pybamm.Vector([1, 2, 3]) evaluator_str = pybamm.get_julia_function(expr) Main.eval(evaluator_str) Main.dy = [0.0] * 3 - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_array_equal(Main.dy, [2, 4, 6]) # test a larger expression @@ -68,7 +68,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") self.assertEqual(Main.dy, expr.evaluate(t=None, y=y)) # test something with time @@ -79,7 +79,7 @@ def test_evaluator_julia(self): Main.dy = [0.0] Main.y = y Main.t = t - Main.eval("f(dy,y,0,t)") + Main.eval("f!(dy,y,0,t)") self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) # test something with a matrix multiplication @@ -90,7 +90,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") # note 1D arrays are flattened in Julia np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) @@ -102,7 +102,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") # note 1D arrays are flattened in Julia np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) @@ -117,7 +117,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) # test something with an index @@ -127,7 +127,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) # test something with a sparse matrix multiplication @@ -140,7 +140,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") # note 1D arrays are flattened in Julia np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) @@ -150,7 +150,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") # note 1D arrays are flattened in Julia np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) @@ -168,7 +168,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") # note 1D arrays are flattened in Julia np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) @@ -178,7 +178,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0, 0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") # note 1D arrays are flattened in Julia np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) @@ -192,7 +192,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0, 0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) # test Inner @@ -202,7 +202,7 @@ def test_evaluator_julia(self): for y in y_tests: Main.dy = [0.0, 0.0] Main.y = y - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) def test_evaluator_julia_input_parameters(self): @@ -211,7 +211,17 @@ def test_evaluator_julia_input_parameters(self): c = pybamm.InputParameter("c") d = pybamm.InputParameter("d") - # test a * c + b * d + # test one input parameter: a * c + expr = a * c + evaluator_str = pybamm.get_julia_function(expr, input_parameter_order=["c"]) + Main.eval(evaluator_str) + Main.dy = [0.0] + Main.y = np.array([2.0, 3.0]) + Main.p = [5] + Main.eval("f!(dy,y,p,0)") + self.assertEqual(Main.dy, 10) + + # test several input parameters: a * c + b * d expr = a * c + b * d evaluator_str = pybamm.get_julia_function( expr, input_parameter_order=["c", "d"] @@ -220,7 +230,7 @@ def test_evaluator_julia_input_parameters(self): Main.dy = [0.0] Main.y = np.array([2.0, 3.0]) Main.p = [5, 6] - Main.eval("f(dy,y,p,0)") + Main.eval("f!(dy,y,p,0)") self.assertEqual(Main.dy, 28) def test_evaluator_julia_all_functions(self): @@ -245,7 +255,7 @@ def test_evaluator_julia_all_functions(self): Main.eval(evaluator_str) Main.dy = 0.0 * y_test Main.y = y_test - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_almost_equal( Main.dy, expr.evaluate(y=y_test).flatten(), decimal=15 ) @@ -259,7 +269,7 @@ def test_evaluator_julia_all_functions(self): Main.eval(evaluator_str) Main.dy = [0.0] Main.y = y_test - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_equal(Main.dy, expr.evaluate(y=y_test).flatten()) def test_evaluator_julia_domain_concatenation(self): @@ -289,7 +299,7 @@ def test_evaluator_julia_domain_concatenation(self): pybamm_eval = c_disc.evaluate(y=y_test).flatten() Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_equal(Main.dy, pybamm_eval) def test_evaluator_julia_domain_concatenation_2D(self): @@ -330,7 +340,7 @@ def test_evaluator_julia_domain_concatenation_2D(self): pybamm_eval = c_disc.evaluate(y=y_test).flatten() Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_equal(Main.dy, pybamm_eval) def test_evaluator_julia_discretised_operators(self): @@ -372,7 +382,7 @@ def test_evaluator_julia_discretised_operators(self): pybamm_eval = expr.evaluate(y=y_test).flatten() Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_almost_equal(Main.dy, pybamm_eval, decimal=7) def test_evaluator_julia_discretised_microscale(self): @@ -424,7 +434,7 @@ def test_evaluator_julia_discretised_microscale(self): pybamm_eval = expr.evaluate(y=y_test).flatten() Main.dy = np.zeros_like(pybamm_eval) Main.y = y_test - Main.eval("f(dy,y,0,0)") + Main.eval("f!(dy,y,0,0)") np.testing.assert_almost_equal(Main.dy, pybamm_eval, decimal=7) diff --git a/tests/unit/test_models/test_base_model.py b/tests/unit/test_models/test_base_model.py index 9800290447..6ef33315d3 100644 --- a/tests/unit/test_models/test_base_model.py +++ b/tests/unit/test_models/test_base_model.py @@ -633,10 +633,12 @@ def test_generate_julia_diffeq(self): model.initial_conditions = {a: 1, b: 2} # Generate rhs and ics for the Julia model - rhs_str, ics_array = model.generate_julia_diffeq() + rhs_str, ics_str = model.generate_julia_diffeq() self.assertIsInstance(rhs_str, str) self.assertIn("ode_test_model", rhs_str) - np.testing.assert_array_equal(ics_array, [1, 2]) + self.assertIsInstance(ics_str, str) + self.assertIn("ode_test_model_u0", ics_str) + self.assertIn("(u0, p)", ics_str) # ODE model with input parameters model = pybamm.BaseModel(name="ode test model 2") @@ -645,17 +647,18 @@ def test_generate_julia_diffeq(self): b = pybamm.Variable("b") p = pybamm.InputParameter("p") q = pybamm.InputParameter("q") - model.rhs = {a: -a * p, b: a - b - q} - model.initial_conditions = {a: 1, b: 2} + model.rhs = {a: -a * p, b: a - b} + model.initial_conditions = {a: q, b: 2} # Generate rhs and ics for the Julia model - rhs_str, ics_array = model.generate_julia_diffeq( - input_parameter_order=["p", "q"] - ) + rhs_str, ics_str = model.generate_julia_diffeq(input_parameter_order=["p", "q"]) self.assertIsInstance(rhs_str, str) self.assertIn("ode_test_model_2", rhs_str) self.assertIn("p, q = p", rhs_str) - np.testing.assert_array_equal(ics_array, [1, 2]) + + self.assertIsInstance(ics_str, str) + self.assertIn("ode_test_model_2_u0", ics_str) + self.assertIn("p, q = p", ics_str) def test_set_initial_conditions(self): # Set up model From cb0e4b6d049641071bb2be2690f81870cde6e5b7 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 17 Mar 2021 18:38:20 -0400 Subject: [PATCH 63/88] #1129 ignore Broadcast and fix 0D ics --- .../expression_tree/operations/evaluate_julia.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index e77961a58b..09d5c943f3 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -357,7 +357,6 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): String of julia code, to be evaluated by ``julia.Main.eval`` """ - constants, var_symbols, var_symbol_sizes = to_julia(symbol) # extract constants in generated function @@ -539,6 +538,10 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t variables and/or constants in all_constants_str and all_variables_str """ + if isinstance(eqn, pybamm.Broadcast): + # ignore broadcasts for now + eqn = eqn.child + constants, variable_symbols = to_julia(eqn)[:2] variables_str = "\n".join( @@ -734,9 +737,14 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): if not is_pde: all_ic_bc_str += f" {variable_id_to_number[var.id]}(t) => {eqn_str},\n" else: - doms = ", ".join([domain_name_to_symbol[dom] for dom in var.domain]) + if var.domain == []: + doms = "" + else: + doms = ", " + ", ".join( + [domain_name_to_symbol[dom] for dom in var.domain] + ) all_ic_bc_str += ( - f" {variable_id_to_number[var.id]}(0, {doms}) ~ {eqn_str},\n" + f" {variable_id_to_number[var.id]}(0{doms}) ~ {eqn_str},\n" ) # Boundary conditions if is_pde: @@ -763,7 +771,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): bc = f"{variable_id_to_number[var.id]}(t, {limit})" if typ == "Dirichlet": - pass + bc = bc elif typ == "Neumann": bc = f"D{domain_name_to_symbol[var.domain[0]]}({bc})" all_ic_bc_str += f" {bc} ~ {eqn_str},\n" From b7a27d3da0b1b2037a1b91d0fd0e357e511f42a7 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 17 Mar 2021 20:08:50 -0400 Subject: [PATCH 64/88] #1129 running some tests --- examples/scripts/SPMe.py | 11 ++++++++--- test.py | 19 ++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/examples/scripts/SPMe.py b/examples/scripts/SPMe.py index 75921b13d2..4ee61e5203 100644 --- a/examples/scripts/SPMe.py +++ b/examples/scripts/SPMe.py @@ -9,18 +9,21 @@ # load model model = pybamm.lithium_ion.SPMe() -model.convert_to_format = "python" +# model.convert_to_format = "python" # create geometry geometry = model.default_geometry # load parameter values and process model and geometry param = model.default_parameter_values +param["Electrolyte diffusivity [m2.s-1]"] = 1e-10 param.process_model(model) param.process_geometry(geometry) # set mesh -mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts) +var = pybamm.standard_spatial_vars +var_pts = {var.x_n: 20, var.x_s: 20, var.x_p: 20, var.r_n: 30, var.r_p: 30} +mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) # discretise model disc = pybamm.Discretisation(mesh, model.default_spatial_methods) @@ -28,7 +31,9 @@ # solve model for 1 hour t_eval = np.linspace(0, 3600, 100) -solution = model.default_solver.solve(model, t_eval) +solver = pybamm.CasadiSolver(mode="fast", rtol=1e-6, atol=1e-6) +solution = solver.solve(model, t_eval) +solution = solver.solve(model, t_eval) # plot plot = pybamm.QuickPlot( diff --git a/test.py b/test.py index 318026f65a..88826479db 100644 --- a/test.py +++ b/test.py @@ -1,12 +1,17 @@ import pybamm -model = pybamm.lithium_ion.SPM(name="SPM") +model = pybamm.lithium_ion.SPMe(name="SPM") sim = pybamm.Simulation(model) -sim.set_parameters() +# sim.set_parameters() -model = sim.model +# model = sim.model -mtk_str = pybamm.get_julia_mtk_model( - model, geometry=model.default_geometry, tspan=(0, 3600) -) -print(mtk_str) \ No newline at end of file +# mtk_str = pybamm.get_julia_mtk_model( +# model, geometry=model.default_geometry, tspan=(0, 3600) +# ) +# print(mtk_str) + +sim.build() + +rhs_str, u0_str = sim.built_model.generate_julia_diffeq() +print(rhs_str) \ No newline at end of file From 0b0d795733253e5dddbce853b9e21fadd4d12a90 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 17 Mar 2021 20:35:12 -0400 Subject: [PATCH 65/88] #1129 SPM -> MTK now working --- .../operations/evaluate_julia.py | 22 +++++++++---------- test.py | 20 ++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 09d5c943f3..aa0b496c2d 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -544,12 +544,13 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t constants, variable_symbols = to_julia(eqn)[:2] - variables_str = "\n".join( - [ - f"{id_to_julia_variable(symbol_id)} = {symbol_line}" - for symbol_id, symbol_line in variable_symbols.items() - ] - ) + # Replace .+, .* etc with regular +, *, etc + replace_ops = ["+", "-", "*", "/"] + variables_str = "" + for symbol_id, symbol_line in variable_symbols.items(): + for op in replace_ops: + symbol_line = symbol_line.replace("." + op, op) + variables_str += f"{id_to_julia_variable(symbol_id)} = {symbol_line}\n" # extract constants in generated function for eqn_id, const_value in constants.items(): @@ -613,7 +614,8 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): raise ValueError("must provide tspan if the model is a PDE model") domain_name_to_symbol = { - dom: list(geometry[dom].keys())[0].name for i, dom in enumerate(all_domains) + dom: list(geometry[dom].keys())[0].name.replace("_", "") + for i, dom in enumerate(all_domains) } domain_name_to_coord_sys = { dom: list(geometry[dom].keys())[0].coord_sys @@ -652,12 +654,10 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Define derivatives - mtk_str += "@derivatives Dt'~t\n" + mtk_str += "Dt = Derivative(t)\n" if is_pde: - mtk_str += "@derivatives" for domain_symbol in domain_name_to_symbol.values(): - mtk_str += f" D{domain_symbol}'~{domain_symbol}" - mtk_str += "\n" + mtk_str += f"D{domain_symbol} = Derivative({domain_symbol})\n" mtk_str += "\n" # Define equations diff --git a/test.py b/test.py index 88826479db..eff0e47e58 100644 --- a/test.py +++ b/test.py @@ -1,17 +1,17 @@ import pybamm -model = pybamm.lithium_ion.SPMe(name="SPM") +model = pybamm.lithium_ion.SPM(name="SPM") sim = pybamm.Simulation(model) -# sim.set_parameters() +sim.set_parameters() -# model = sim.model +model = sim.model -# mtk_str = pybamm.get_julia_mtk_model( -# model, geometry=model.default_geometry, tspan=(0, 3600) -# ) -# print(mtk_str) +mtk_str = pybamm.get_julia_mtk_model( + model, geometry=model.default_geometry, tspan=(0, 3600) +) +print(mtk_str) -sim.build() +# sim.build() -rhs_str, u0_str = sim.built_model.generate_julia_diffeq() -print(rhs_str) \ No newline at end of file +# rhs_str, u0_str = sim.built_model.generate_julia_diffeq() +# print(rhs_str) \ No newline at end of file From ca9cac3bd56f8e9da5ab24652f411f3b1df05766 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 17 Mar 2021 20:49:01 -0400 Subject: [PATCH 66/88] #1129 SPMe -> MTK works but needs fine tuning --- pybamm/expression_tree/operations/evaluate_julia.py | 8 ++++++++ test.py | 6 ++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index aa0b496c2d..a4715bbc1a 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -254,6 +254,11 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz else: raise NotImplementedError + else: + # A regular Concatenation for the MTK model + # Not sure how to deal with this yet so leaving as a "concatenation" + symbol_str = "concatenation(" + ", ".join(children_vars) + ")" + # Note: we assume that y is being passed as a column vector elif isinstance(symbol, pybamm.StateVector): indices = np.argwhere(symbol.evaluation_array).reshape(-1).astype(np.int32) @@ -287,6 +292,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # No need to do anything if a Variable is found return + elif isinstance(symbol, pybamm.SpatialVariable): + symbol_str = symbol.name.replace("_", "") + else: raise NotImplementedError( "Conversion to Julia not implemented for a symbol of type '{}'".format( diff --git a/test.py b/test.py index eff0e47e58..9074f62955 100644 --- a/test.py +++ b/test.py @@ -1,14 +1,12 @@ import pybamm -model = pybamm.lithium_ion.SPM(name="SPM") +model = pybamm.lithium_ion.SPMe(name="SPM") sim = pybamm.Simulation(model) sim.set_parameters() model = sim.model -mtk_str = pybamm.get_julia_mtk_model( - model, geometry=model.default_geometry, tspan=(0, 3600) -) +mtk_str = pybamm.get_julia_mtk_model(model, geometry=sim.geometry, tspan=(0, 3600)) print(mtk_str) # sim.build() From 6da520b674f0f37f59f59acf57a988c4a3000ec5 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Sun, 21 Mar 2021 18:08:44 -0400 Subject: [PATCH 67/88] #1129 allow dae model --- examples/scripts/SPMe.py | 15 ++- .../operations/evaluate_julia.py | 98 +++++++++---------- pybamm/models/base_model.py | 30 +++--- test.py | 24 +++-- 4 files changed, 88 insertions(+), 79 deletions(-) diff --git a/examples/scripts/SPMe.py b/examples/scripts/SPMe.py index 4ee61e5203..50fd726db1 100644 --- a/examples/scripts/SPMe.py +++ b/examples/scripts/SPMe.py @@ -5,7 +5,7 @@ import pybamm import numpy as np -pybamm.set_logging_level("INFO") +# pybamm.set_logging_level("INFO") # load model model = pybamm.lithium_ion.SPMe() @@ -22,7 +22,7 @@ # set mesh var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 20, var.x_s: 20, var.x_p: 20, var.r_n: 30, var.r_p: 30} +var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) # discretise model @@ -33,7 +33,14 @@ t_eval = np.linspace(0, 3600, 100) solver = pybamm.CasadiSolver(mode="fast", rtol=1e-6, atol=1e-6) solution = solver.solve(model, t_eval) -solution = solver.solve(model, t_eval) +solve_time = 0 +int_time = 0 +for _ in range(1000): + solution = solver.solve(model, t_eval) + solve_time += solution.solve_time + int_time += solution.integration_time + +print(str(solve_time / 1000) + " (" + str(int_time / 1000) + ")") # plot plot = pybamm.QuickPlot( @@ -51,4 +58,4 @@ time_unit="seconds", spatial_unit="um", ) -plot.dynamic_plot() +# plot.dynamic_plot() diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index a4715bbc1a..a5554b215c 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -137,21 +137,20 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # TODO: we can pass through a dummy y and t to get the type and then hardcode # the right line, avoiding these checks if isinstance(symbol, pybamm.MatrixMultiplication): - symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) + symbol_str = "{0} @ {1}".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Inner): - symbol_str = "{0} .* {1}".format(children_vars[0], children_vars[1]) + symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Minimum): - symbol_str = "min.({},{})".format(children_vars[0], children_vars[1]) + symbol_str = "min({},{})".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Maximum): - symbol_str = "max.({},{})".format(children_vars[0], children_vars[1]) + symbol_str = "max({},{})".format(children_vars[0], children_vars[1]) elif isinstance(symbol, pybamm.Power): # julia uses ^ instead of ** for power # include dot for elementwise operations - symbol_str = children_vars[0] + " .^ " + children_vars[1] + symbol_str = children_vars[0] + " ^ " + children_vars[1] else: # all other operations use the same symbol - # include dot: all other operations should be elementwise - symbol_str = children_vars[0] + " ." + symbol.name + " " + children_vars[1] + symbol_str = children_vars[0] + " " + symbol.name + " " + children_vars[1] elif isinstance(symbol, pybamm.UnaryOperator): # Index has a different syntax than other univariate operations @@ -162,9 +161,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz children_vars[0], symbol.slice.start + 1, symbol.slice.stop ) elif isinstance(symbol, pybamm.Gradient): - symbol_str = "grad_{}({})".format(symbol.domain[0], children_vars[0]) + symbol_str = "grad_{}({})".format(tuple(symbol.domain), children_vars[0]) elif isinstance(symbol, pybamm.Divergence): - symbol_str = "div_{}({})".format(symbol.domain[0], children_vars[0]) + symbol_str = "div_{}({})".format(tuple(symbol.domain), children_vars[0]) elif isinstance(symbol, pybamm.Broadcast): # ignore broadcasts for now symbol_str = children_vars[0] @@ -180,11 +179,11 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz children_str += ", " + child_var # write functions directly julia_name = symbol.julia_name - # add a . to allow elementwise operations - if isinstance(symbol, (pybamm.Min, pybamm.Max)): - symbol_str = "{}({})".format(julia_name, children_str) - else: - symbol_str = "{}.({})".format(julia_name, children_str) + symbol_str = "{}({})".format(julia_name, children_str) + + elif isinstance(symbol, (pybamm.Variable, pybamm.ConcatenationVariable)): + # No need to do anything if a Variable is found + return elif isinstance(symbol, pybamm.Concatenation): @@ -288,10 +287,6 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz elif isinstance(symbol, pybamm.InputParameter): symbol_str = "inputs['{}']".format(symbol.name) - elif isinstance(symbol, pybamm.Variable): - # No need to do anything if a Variable is found - return - elif isinstance(symbol, pybamm.SpatialVariable): symbol_str = symbol.name.replace("_", "") @@ -376,7 +371,7 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): # Pop (get and remove) items from the dictionary of symbols one by one # If they are simple operations (@view, .+, .-, .*, ./), replace all future # occurences instead of assigning them. This "inlining" speeds up the computation - inlineable_symbols = ["@view", ".+", ".-", ".*", "./"] + inlineable_symbols = ["@view", "+", "-", "*", "/"] var_str = "" input_parameters = {} while var_symbols: @@ -392,13 +387,13 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): child_size, child_name = child_size_and_name.split("::") end = start + int(child_size) # add 1 to start to account for julia 1-indexing - var_str += "{}[{}:{}] .= {}\n".format( + var_str += "@. {}[{}:{}] = {}\n".format( julia_var, start + 1, end, child_name ) start = end # use mul! for matrix multiplications (requires LinearAlgebra library) - elif " * " in symbol_line: - symbol_line = symbol_line.replace(" * ", ", ") + elif " @ " in symbol_line: + symbol_line = symbol_line.replace(" @ ", ", ") var_str += "mul!({}, {})\n".format(julia_var, symbol_line) # find input parameters elif symbol_line.startswith("inputs"): @@ -415,7 +410,7 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): # first in that case, unless it is a @view in which case we don't # need to cache if julia_var in next_symbol_line and not ( - (" * " in next_symbol_line or "mul!" in next_symbol_line) + (" @ " in next_symbol_line or "mul!" in next_symbol_line) and not symbol_line.startswith("@view") ): if symbol_line != "t": @@ -430,11 +425,11 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): ) found_replacement = True if not found_replacement: - var_str += "{} .= {}\n".format(julia_var, symbol_line) + var_str += "@. {} = {}\n".format(julia_var, symbol_line) # otherwise assign else: - var_str += "{} .= {}\n".format(julia_var, symbol_line) + var_str += "@. {} = {}\n".format(julia_var, symbol_line) # Replace all input parameter names for input_parameter_id, input_parameter_name in input_parameters.items(): var_str = var_str.replace(input_parameter_id, input_parameter_name) @@ -497,9 +492,8 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): else: julia_str = julia_str.replace("cs." + result_var, "dy") - # close the function - julia_str += "end\n\n" - julia_str = julia_str.replace("\n end", "\nend") + # close the function, with a 'nothing' to avoid allocations + julia_str += "nothing\nend\n\n" julia_str = julia_str.replace("\n \n", "\n") if const_and_cache_str == "": @@ -552,12 +546,8 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t constants, variable_symbols = to_julia(eqn)[:2] - # Replace .+, .* etc with regular +, *, etc - replace_ops = ["+", "-", "*", "/"] variables_str = "" for symbol_id, symbol_line in variable_symbols.items(): - for op in replace_ops: - symbol_line = symbol_line.replace("." + op, op) variables_str += f"{id_to_julia_variable(symbol_id)} = {symbol_line}\n" # extract constants in generated function @@ -610,7 +600,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Extract variables variables = {**model.rhs, **model.algebraic}.keys() variable_id_to_number = {var.id: f"u{i+1}" for i, var in enumerate(variables)} - all_domains = list(set([dom for var in variables for dom in var.domain])) + all_domains = [var.domain for var in variables if var.domain != []] is_pde = bool(all_domains) @@ -621,13 +611,19 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): if tspan is None: raise ValueError("must provide tspan if the model is a PDE model") - domain_name_to_symbol = { - dom: list(geometry[dom].keys())[0].name.replace("_", "") - for i, dom in enumerate(all_domains) - } + domain_name_to_symbol = {} + for dom in all_domains: + # Read domain name from geometry + domain_symbol = list(geometry[dom[0]].keys())[0].name.replace("_", "") + if len(dom) > 1: + # For multi-domain variables keep only the first letter of the domain + domain_name_to_symbol[tuple(dom)] = domain_symbol[0] + else: + # Otherwise keep the whole domain + domain_name_to_symbol[tuple(dom)] = domain_symbol + domain_name_to_coord_sys = { - dom: list(geometry[dom].keys())[0].coord_sys - for i, dom in enumerate(all_domains) + tuple(dom): list(geometry[dom[0]].keys())[0].coord_sys for dom in all_domains } mtk_str = "begin\n" @@ -652,16 +648,11 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): if var.domain == []: var_to_ind_vars[var.id] = "(t)" else: - var_to_ind_vars[var.id] = ( - "(t, " - + ", ".join([domain_name_to_symbol[dom] for dom in var.domain]) - + ")" - ) + var_to_ind_vars[var.id] = f"(t, {domain_name_to_symbol[tuple(var.domain)]})" mtk_str += f" {variable_id_to_number[var.id]}(..)" mtk_str += "\n" # Define derivatives - mtk_str += "Dt = Derivative(t)\n" if is_pde: for domain_symbol in domain_name_to_symbol.values(): @@ -748,16 +739,15 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): if var.domain == []: doms = "" else: - doms = ", " + ", ".join( - [domain_name_to_symbol[dom] for dom in var.domain] - ) + doms = ", " + domain_name_to_symbol[tuple(var.domain)] + all_ic_bc_str += ( f" {variable_id_to_number[var.id]}(0{doms}) ~ {eqn_str},\n" ) # Boundary conditions if is_pde: for var, eqn_side in model.boundary_conditions.items(): - if isinstance(var, pybamm.Variable): + if isinstance(var, (pybamm.Variable, pybamm.ConcatenationVariable)): for side, (eqn, typ) in eqn_side.items(): ( all_ic_bc_constants_str, @@ -771,17 +761,18 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): "boundary condition", ) - geom = list(geometry[var.domain[0]].values())[0] if side == "left": + geom = list(geometry[var.domain[0]].values())[0] limit = geom["min"] elif side == "right": + geom = list(geometry[var.domain[-1]].values())[0] limit = geom["max"] bc = f"{variable_id_to_number[var.id]}(t, {limit})" if typ == "Dirichlet": bc = bc elif typ == "Neumann": - bc = f"D{domain_name_to_symbol[var.domain[0]]}({bc})" + bc = f"D{domain_name_to_symbol[tuple(var.domain)]}({bc})" all_ic_bc_str += f" {bc} ~ {eqn_str},\n" #################################################################################### @@ -809,8 +800,9 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str += f"t_domain = IntervalDomain({tspan[0]}, {tspan[1]})\n" domains = "domains = [\n t in t_domain,\n" for domain, symbol in domain_name_to_symbol.items(): - dom_limits = list(geometry[domain].values())[0] - dom_min, dom_max = dom_limits.values() + dom_min, _ = list(geometry[domain[0]].values())[0].values() + _, dom_max = list(geometry[domain[-1]].values())[0].values() + mtk_str += f"{symbol}_domain = IntervalDomain({dom_min}, {dom_max})\n" domains += f" {symbol} in {symbol}_domain,\n" domains += "]\n" diff --git a/pybamm/models/base_model.py b/pybamm/models/base_model.py index 12625b6a0c..661d64336a 100644 --- a/pybamm/models/base_model.py +++ b/pybamm/models/base_model.py @@ -917,11 +917,12 @@ def generate( C.add(variables_fn) C.generate() - def generate_julia_diffeq(self, input_parameter_order=None): + def generate_julia_diffeq( + self, input_parameter_order=None, get_consistent_ics_solver=None + ): """ Generate a Julia representation of the model, ready to be solved by Julia's DifferentialEquations library. - Currently only implemented for ODE models. Parameters ---------- @@ -930,7 +931,7 @@ def generate_julia_diffeq(self, input_parameter_order=None): Returns ------- - rhs_str : str + eqn_str : str The Julia-compatible equations for the model in string format, to be evaluated by eval(Meta.parse(...)) ics_str : str @@ -939,22 +940,25 @@ def generate_julia_diffeq(self, input_parameter_order=None): """ self.check_discretised_or_discretise_inplace_if_0D() - # Check that there are no algebraic equations in the model - if self.algebraic != {}: - raise pybamm.ModelError( - "Cannot generate Julia DiffEq model for a DAE model" - ) - name = self.name.replace(" ", "_") - rhs_str = pybamm.get_julia_function( - self.concatenated_rhs, + eqn_str = pybamm.get_julia_function( + pybamm.numpy_concatenation( + self.concatenated_rhs, self.concatenated_algebraic + ), funcname=name, input_parameter_order=input_parameter_order, ) + if get_consistent_ics_solver is None or self.algebraic == {}: + ics = self.concatenated_initial_conditions + else: + get_consistent_ics_solver.set_up(self) + get_consistent_ics_solver._set_initial_conditions(self, {}, False) + ics = pybamm.Vector(self.y0.full()) + ics_str = pybamm.get_julia_function( - self.concatenated_initial_conditions, + ics, funcname=name + "_u0", input_parameter_order=input_parameter_order, ) @@ -962,7 +966,7 @@ def generate_julia_diffeq(self, input_parameter_order=None): ics_str = ics_str.replace("(dy, y, p, t)", "(u0, p)") ics_str = ics_str.replace("dy", "u0") - return rhs_str, ics_str + return eqn_str, ics_str @property def default_parameter_values(self): diff --git a/test.py b/test.py index 9074f62955..39b7760143 100644 --- a/test.py +++ b/test.py @@ -1,15 +1,21 @@ import pybamm -model = pybamm.lithium_ion.SPMe(name="SPM") -sim = pybamm.Simulation(model) -sim.set_parameters() +model = pybamm.lithium_ion.DFN(name="DFN") +var = pybamm.standard_spatial_vars +var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} +sim = pybamm.Simulation(model, var_pts=var_pts) +# sim.set_parameters() -model = sim.model +# model = sim.model +# list(model.rhs.values())[-1].render() -mtk_str = pybamm.get_julia_mtk_model(model, geometry=sim.geometry, tspan=(0, 3600)) -print(mtk_str) +# mtk_str = pybamm.get_julia_mtk_model(model, geometry=sim.geometry, tspan=(0, 3600)) +# print(mtk_str) -# sim.build() +sim.build() -# rhs_str, u0_str = sim.built_model.generate_julia_diffeq() -# print(rhs_str) \ No newline at end of file +rhs_str, u0_str = sim.built_model.generate_julia_diffeq( + get_consistent_ics_solver=pybamm.CasadiSolver() +) +print(rhs_str) +print(u0_str) \ No newline at end of file From 911f41fe946319f20389f3903781e2af131fbb55 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 24 Mar 2021 13:36:16 -0400 Subject: [PATCH 68/88] #1129 generate SPMe in MTK --- .../operations/evaluate_julia.py | 104 +++++++++++++++--- test.py | 21 ++-- 2 files changed, 101 insertions(+), 24 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index a5554b215c..a53512ef40 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -72,6 +72,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz variable, for caching """ + # ignore broadcasts for now + if isinstance(symbol, pybamm.Broadcast): + symbol = symbol.child if is_constant_and_can_evaluate(symbol): value = symbol.evaluate() if not isinstance(value, numbers.Number): @@ -123,6 +126,8 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz # children variables children_vars = [] for child in symbol.children: + if isinstance(child, pybamm.Broadcast): + child = child.child if is_constant_and_can_evaluate(child): child_eval = child.evaluate() if isinstance(child_eval, numbers.Number): @@ -255,7 +260,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz else: # A regular Concatenation for the MTK model - # Not sure how to deal with this yet so leaving as a "concatenation" + # We will define the concatenation function separately symbol_str = "concatenation(" + ", ".join(children_vars) + ")" # Note: we assume that y is being passed as a column vector @@ -369,7 +374,7 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): const_and_cache_str += " {} = {},\n".format(const_name, const_value) # Pop (get and remove) items from the dictionary of symbols one by one - # If they are simple operations (@view, .+, .-, .*, ./), replace all future + # If they are simple operations (@view, +, -, *, /), replace all future # occurences instead of assigning them. This "inlining" speeds up the computation inlineable_symbols = ["@view", "+", "-", "*", "/"] var_str = "" @@ -413,15 +418,15 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): (" @ " in next_symbol_line or "mul!" in next_symbol_line) and not symbol_line.startswith("@view") ): - if symbol_line != "t": - # add brackets so that the order of operations is maintained + if symbol_line == "t": + # no brackets needed var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, "({})".format(symbol_line) + julia_var, symbol_line ) else: # add brackets so that the order of operations is maintained var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, symbol_line + julia_var, "({})".format(symbol_line) ) found_replacement = True if not found_replacement: @@ -544,11 +549,49 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t # ignore broadcasts for now eqn = eqn.child - constants, variable_symbols = to_julia(eqn)[:2] + constants, var_symbols = to_julia(eqn)[:2] - variables_str = "" - for symbol_id, symbol_line in variable_symbols.items(): - variables_str += f"{id_to_julia_variable(symbol_id)} = {symbol_line}\n" + # var_str = "" + # for symbol_id, symbol_line in var_symbols.items(): + # var_str += f"{id_to_julia_variable(symbol_id)} = {symbol_line}\n" + # Pop (get and remove) items from the dictionary of symbols one by one + # If they are simple operations (+, -, *, /), replace all future + # occurences instead of assigning them. + inlineable_symbols = [" + ", " - ", " * ", " / "] + var_str = "" + input_parameters = {} + while var_symbols: + var_symbol_id, symbol_line = var_symbols.popitem(last=False) + julia_var = id_to_julia_variable(var_symbol_id, False) + # inline operation if it can be inlined + if "concatenation" not in symbol_line: + found_replacement = False + # replace all other occurrences of the variable + # in the dictionary with the symbol line + for next_var_id, next_symbol_line in var_symbols.items(): + if ( + symbol_line == "t" + or " " not in symbol_line + or symbol_line.startswith("grad") + or next_symbol_line.startswith("concatenation") + or not any(x in next_symbol_line for x in inlineable_symbols) + ): + # cases that don't need brackets + var_symbols[next_var_id] = next_symbol_line.replace( + julia_var, symbol_line + ) + else: + # add brackets so that the order of operations is maintained + var_symbols[next_var_id] = next_symbol_line.replace( + julia_var, "({})".format(symbol_line) + ) + found_replacement = True + if not found_replacement: + var_str += "{} = {}\n".format(julia_var, symbol_line) + + # otherwise assign + else: + var_str += "{} = {}\n".format(julia_var, symbol_line) # extract constants in generated function for eqn_id, const_value in constants.items(): @@ -556,11 +599,26 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t all_constants_str += "{} = {}\n".format(const_name, const_value) # TODO: avoid repeated constants definitions + # If we have created a concatenation we need to define it + # Hardcoded to the negative electrode, separator, positive electrode case for now + if "concatenation" in var_str and "function concatenation" not in all_variables_str: + concatenation_def = ( + "\nfunction concatenation(n, s, p)\n" + + " # A concatenation in the electrolyte domain\n" + + " IfElse.ifelse(\n" + + " x < neg_width, n, IfElse.ifelse(\n" + + " x < neg_plus_sep_width, s, p\n" + + " )\n" + + " )\n" + + "end\n\n" + ) + var_str = concatenation_def + var_str + # add a comment labeling the equation, and the equation itself - if variables_str == "": + if var_str == "": all_variables_str += "" else: - all_variables_str += f"# '{var.name}' {typ}\n" + variables_str + "\n" + all_variables_str += f"# '{var.name}' {typ}\n" + var_str + "\n" # calculate the final variable that will output the result result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) @@ -612,12 +670,18 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): raise ValueError("must provide tspan if the model is a PDE model") domain_name_to_symbol = {} + long_domain_symbol_to_short = {} for dom in all_domains: # Read domain name from geometry domain_symbol = list(geometry[dom[0]].keys())[0].name.replace("_", "") if len(dom) > 1: + domain_symbol = domain_symbol[0] # For multi-domain variables keep only the first letter of the domain - domain_name_to_symbol[tuple(dom)] = domain_symbol[0] + domain_name_to_symbol[tuple(dom)] = domain_symbol + # Record which domain symbols we shortened + for d in dom: + long = list(geometry[d].keys())[0].name.replace("_", "") + long_domain_symbol_to_short[long] = domain_symbol else: # Otherwise keep the whole domain domain_name_to_symbol[tuple(dom)] = domain_symbol @@ -702,6 +766,20 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): f"1 / {domain_symbol}^2 * D{domain_symbol}({domain_symbol}^2 * ", ) + # Replace any long domain symbols with the short version + # e.g. "xn" gets replaced with "x" + for long, short in long_domain_symbol_to_short.items(): + # we need to add a space to avoid accidentally replacing 'exp' with 'ex' + all_julia_str = all_julia_str.replace(" " + long, " " + short) + + # Replace the thicknesses in the concatenation with the actual thickness from the + # geometrt + var = pybamm.standard_spatial_vars + x_n = geometry["negative electrode"][var.x_n]["max"].evaluate() + x_s = geometry["separator"][var.x_s]["max"].evaluate() + all_julia_str = all_julia_str.replace("neg_width", str(x_n)) + all_julia_str = all_julia_str.replace("neg_plus_sep_width", str(x_s)) + # Replace parameters in the julia strings in the form "inputs[name]" # with just "name" for param in model.input_parameters: diff --git a/test.py b/test.py index 39b7760143..a1b3076919 100644 --- a/test.py +++ b/test.py @@ -4,18 +4,17 @@ var = pybamm.standard_spatial_vars var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} sim = pybamm.Simulation(model, var_pts=var_pts) -# sim.set_parameters() +sim.set_parameters() -# model = sim.model -# list(model.rhs.values())[-1].render() +# list(sim.model.rhs.values())[-1].render() -# mtk_str = pybamm.get_julia_mtk_model(model, geometry=sim.geometry, tspan=(0, 3600)) -# print(mtk_str) +mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) +print(mtk_str) -sim.build() +# sim.build() -rhs_str, u0_str = sim.built_model.generate_julia_diffeq( - get_consistent_ics_solver=pybamm.CasadiSolver() -) -print(rhs_str) -print(u0_str) \ No newline at end of file +# rhs_str, u0_str = sim.built_model.generate_julia_diffeq( +# get_consistent_ics_solver=pybamm.CasadiSolver() +# ) +# print(rhs_str) +# print(u0_str) \ No newline at end of file From 05688e0ff706938b44785d76d04cf271f9221eb1 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 25 Mar 2021 12:39:49 -0400 Subject: [PATCH 69/88] #1129 working on DFN to MTK --- examples/scripts/SPMe.py | 1 - pybamm/expression_tree/operations/evaluate_julia.py | 6 ++++-- test.py | 10 ++++------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/examples/scripts/SPMe.py b/examples/scripts/SPMe.py index 50fd726db1..5eb274ae74 100644 --- a/examples/scripts/SPMe.py +++ b/examples/scripts/SPMe.py @@ -16,7 +16,6 @@ # load parameter values and process model and geometry param = model.default_parameter_values -param["Electrolyte diffusivity [m2.s-1]"] = 1e-10 param.process_model(model) param.process_geometry(geometry) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index a53512ef40..16e17bc8a9 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -172,6 +172,8 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz elif isinstance(symbol, pybamm.Broadcast): # ignore broadcasts for now symbol_str = children_vars[0] + elif isinstance(symbol, pybamm.BoundaryValue): + symbol_str = "boundary_value_{}({})".format(symbol.side, children_vars[0]) else: symbol_str = symbol.name + children_vars[0] @@ -717,10 +719,10 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str += "\n" # Define derivatives - mtk_str += "Dt = Derivative(t)\n" + mtk_str += "Dt = Differential(t)\n" if is_pde: for domain_symbol in domain_name_to_symbol.values(): - mtk_str += f"D{domain_symbol} = Derivative({domain_symbol})\n" + mtk_str += f"D{domain_symbol} = Differential({domain_symbol})\n" mtk_str += "\n" # Define equations diff --git a/test.py b/test.py index a1b3076919..ab6aa2da48 100644 --- a/test.py +++ b/test.py @@ -1,16 +1,14 @@ import pybamm -model = pybamm.lithium_ion.DFN(name="DFN") -var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} -sim = pybamm.Simulation(model, var_pts=var_pts) +model = pybamm.lithium_ion.DFN() +sim = pybamm.Simulation(model) sim.set_parameters() +mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) -# list(sim.model.rhs.values())[-1].render() -mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) print(mtk_str) +# list(sim.model.rhs.values())[1].render() # sim.build() # rhs_str, u0_str = sim.built_model.generate_julia_diffeq( From 432851fe9804d6f57948a8d55d080f5856d058d9 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 25 Mar 2021 23:18:53 -0400 Subject: [PATCH 70/88] #1229 working on dfn to mtk --- .../operations/evaluate_julia.py | 154 ++++++++++++++---- pybamm/expression_tree/parameter.py | 18 +- pybamm/parameters/parameter_values.py | 23 ++- test.py | 6 +- .../test_expression_tree/test_parameter.py | 19 +++ 5 files changed, 180 insertions(+), 40 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 16e17bc8a9..240f03ce29 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -178,15 +178,8 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz symbol_str = symbol.name + children_vars[0] elif isinstance(symbol, pybamm.Function): - children_str = "" - for child_var in children_vars: - if children_str == "": - children_str = child_var - else: - children_str += ", " + child_var # write functions directly - julia_name = symbol.julia_name - symbol_str = "{}({})".format(julia_name, children_str) + symbol_str = "{}({})".format(symbol.julia_name, ", ".join(children_vars)) elif isinstance(symbol, (pybamm.Variable, pybamm.ConcatenationVariable)): # No need to do anything if a Variable is found @@ -297,6 +290,9 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz elif isinstance(symbol, pybamm.SpatialVariable): symbol_str = symbol.name.replace("_", "") + elif isinstance(symbol, pybamm.FunctionParameter): + symbol_str = "{}({})".format(symbol.name, ", ".join(children_vars)) + else: raise NotImplementedError( "Conversion to Julia not implemented for a symbol of type '{}'".format( @@ -659,9 +655,26 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): """ # Extract variables variables = {**model.rhs, **model.algebraic}.keys() - variable_id_to_number = {var.id: f"u{i+1}" for i, var in enumerate(variables)} - all_domains = [var.domain for var in variables if var.domain != []] - + variable_id_to_number = {} + for i, var in enumerate(variables): + variable_id_to_number[var.id] = f"u{i+1}" + if isinstance(var, pybamm.ConcatenationVariable): + for child in var.children: + variable_id_to_number[child.id] = f"u{i+1}" + + # Extract domain and auxiliary domains + all_domains = set([tuple(var.domain) for var in variables if var.domain != []]) + for aux_dim in ["secondary", "tertiary"]: + all_domains.update( + set( + [ + tuple(var.auxiliary_domains[aux_dim]) + for var in variables + if aux_dim in var.auxiliary_domains + and var.auxiliary_domains[aux_dim] != [] + ] + ) + ) is_pde = bool(all_domains) # Check geometry and tspan have been provided if a PDE @@ -671,6 +684,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): if tspan is None: raise ValueError("must provide tspan if the model is a PDE model") + # Read domain names domain_name_to_symbol = {} long_domain_symbol_to_short = {} for dom in all_domains: @@ -688,10 +702,63 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Otherwise keep the whole domain domain_name_to_symbol[tuple(dom)] = domain_symbol + # Read coordinate systems domain_name_to_coord_sys = { tuple(dom): list(geometry[dom[0]].keys())[0].coord_sys for dom in all_domains } + # Read domain limits + domain_name_to_limits = {} + for dom in all_domains: + limits = list(geometry[dom[0]].values())[0].values() + if len(limits) > 1: + lower_limit, _ = list(geometry[dom[0]].values())[0].values() + _, upper_limit = list(geometry[dom[-1]].values())[0].values() + domain_name_to_limits[tuple(dom)] = ( + lower_limit.evaluate(), + upper_limit.evaluate(), + ) + else: + # Don't record limits for variables that have "limits" of length 1 i.e. + # a zero-dimensional domain + domain_name_to_limits[tuple(dom)] = None + + # Define independent variables for each variable + var_to_ind_vars = {} + var_to_ind_vars_left_boundary = {} + var_to_ind_vars_right_boundary = {} + for var in variables: + if var.domain == []: + var_to_ind_vars[var.id] = "(t)" + else: + # all independent variables e.g. (t, x) or (t, rn, xn) + domain_symbols = ", ".join( + domain_name_to_symbol[tuple(dom)] + for dom in var.domains.values() + if domain_name_to_limits[tuple(dom)] is not None + ) + var_to_ind_vars[var.id] = f"(t, {domain_symbols})" + if isinstance(var, pybamm.ConcatenationVariable): + for child in var.children: + var_to_ind_vars[child.id] = f"(t, {domain_symbols})" + aux_domain_symbols = ", ".join( + domain_name_to_symbol[tuple(dom)] + for dom in var.auxiliary_domains.values() + if domain_name_to_limits[tuple(dom)] is not None + ) + if aux_domain_symbols != "": + aux_domain_symbols = ", " + aux_domain_symbols + + limits = domain_name_to_limits[tuple(var.domain)] + # left bc e.g. (t, 0) or (t, 0, xn) + var_to_ind_vars_left_boundary[ + var.id + ] = f"(t, {limits[0]}{aux_domain_symbols})" + # right bc e.g. (t, 1) or (t, 1, xn) + var_to_ind_vars_right_boundary[ + var.id + ] = f"(t, {limits[1]}{aux_domain_symbols})" + mtk_str = "begin\n" # Define parameters (including independent variables) # Makes a line of the form '@parameters t x1 x2 x3 a b c d' @@ -707,15 +774,11 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): for var in variables: mtk_str += f"# '{var.name}' -> {variable_id_to_number[var.id]}\n" # Makes a line of the form '@variables u1(t) u2(t)' - dep_vars = list(variable_id_to_number.values()) + dep_vars = [] mtk_str += "@variables" - var_to_ind_vars = {} for var in variables: - if var.domain == []: - var_to_ind_vars[var.id] = "(t)" - else: - var_to_ind_vars[var.id] = f"(t, {domain_name_to_symbol[tuple(var.domain)]})" mtk_str += f" {variable_id_to_number[var.id]}(..)" + dep_vars.append(variable_id_to_number[var.id]) mtk_str += "\n" # Define derivatives @@ -742,12 +805,25 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): elif var in model.algebraic: all_eqns_str += f" 0 ~ {eqn_str},\n" + # Replace any long domain symbols with the short version + # e.g. "xn" gets replaced with "x" + for long, short in long_domain_symbol_to_short.items(): + # we need to add a space to avoid accidentally replacing 'exp' with 'ex' + all_julia_str = all_julia_str.replace(" " + long, " " + short) + # Replace variables in the julia strings that correspond to pybamm variables with # their julia equivalent - # e.g. cache_123456789 gets replaced with u1(t, x) for var_id, julia_id in variable_id_to_number.items(): + # e.g. boundary_value_right(cache_123456789) gets replaced with u1(t, 1) + cache_var_id = id_to_julia_variable(var_id, False) + if f"boundary_value_right({cache_var_id})" in all_julia_str: + all_julia_str = all_julia_str.replace( + f"boundary_value_right({cache_var_id})", + julia_id + var_to_ind_vars_right_boundary[var_id], + ) + # e.g. cache_123456789 gets replaced with u1(t, x) all_julia_str = all_julia_str.replace( - id_to_julia_variable(var_id, False), julia_id + var_to_ind_vars[var_id] + cache_var_id, julia_id + var_to_ind_vars[var_id] ) # Replace independent variables (domain names) in julia strings with the @@ -768,14 +844,8 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): f"1 / {domain_symbol}^2 * D{domain_symbol}({domain_symbol}^2 * ", ) - # Replace any long domain symbols with the short version - # e.g. "xn" gets replaced with "x" - for long, short in long_domain_symbol_to_short.items(): - # we need to add a space to avoid accidentally replacing 'exp' with 'ex' - all_julia_str = all_julia_str.replace(" " + long, " " + short) - # Replace the thicknesses in the concatenation with the actual thickness from the - # geometrt + # geometry var = pybamm.standard_spatial_vars x_n = geometry["negative electrode"][var.x_n]["max"].evaluate() x_s = geometry["separator"][var.x_s]["max"].evaluate() @@ -842,19 +912,32 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): ) if side == "left": - geom = list(geometry[var.domain[0]].values())[0] - limit = geom["min"] + limit = var_to_ind_vars_left_boundary[var.id] elif side == "right": - geom = list(geometry[var.domain[-1]].values())[0] - limit = geom["max"] + limit = var_to_ind_vars_right_boundary[var.id] - bc = f"{variable_id_to_number[var.id]}(t, {limit})" + bc = f"{variable_id_to_number[var.id]}{limit}" if typ == "Dirichlet": bc = bc elif typ == "Neumann": bc = f"D{domain_name_to_symbol[tuple(var.domain)]}({bc})" all_ic_bc_str += f" {bc} ~ {eqn_str},\n" + # Replace variables in the julia strings that correspond to pybamm variables with + # their julia equivalent + for var_id, julia_id in variable_id_to_number.items(): + # e.g. boundary_value_right(cache_123456789) gets replaced with u1(t, 1) + cache_var_id = id_to_julia_variable(var_id, False) + if f"boundary_value_right({cache_var_id})" in all_ic_bc_julia_str: + all_ic_bc_julia_str = all_ic_bc_julia_str.replace( + f"boundary_value_right({cache_var_id})", + julia_id + var_to_ind_vars_right_boundary[var_id], + ) + # e.g. cache_123456789 gets replaced with u1(t, x) + all_ic_bc_julia_str = all_ic_bc_julia_str.replace( + cache_var_id, julia_id + var_to_ind_vars[var_id] + ) + #################################################################################### # Create ODESystem or PDESystem @@ -880,11 +963,10 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str += f"t_domain = IntervalDomain({tspan[0]}, {tspan[1]})\n" domains = "domains = [\n t in t_domain,\n" for domain, symbol in domain_name_to_symbol.items(): - dom_min, _ = list(geometry[domain[0]].values())[0].values() - _, dom_max = list(geometry[domain[-1]].values())[0].values() - - mtk_str += f"{symbol}_domain = IntervalDomain({dom_min}, {dom_max})\n" - domains += f" {symbol} in {symbol}_domain,\n" + limits = domain_name_to_limits[tuple(domain)] + if limits is not None: + mtk_str += f"{symbol}_domain = IntervalDomain{limits}\n" + domains += f" {symbol} in {symbol}_domain,\n" domains += "]\n" mtk_str += "\n" diff --git a/pybamm/expression_tree/parameter.py b/pybamm/expression_tree/parameter.py index f38b03e7fc..1121d31377 100644 --- a/pybamm/expression_tree/parameter.py +++ b/pybamm/expression_tree/parameter.py @@ -4,6 +4,7 @@ import numbers import numpy as np import pybamm +import inspect class Parameter(pybamm.Symbol): @@ -90,6 +91,19 @@ def __init__( self.input_names = list(inputs.keys()) + # Use the inspect module to find the function's "short name" from the + # Parameters module that called it + short_name = inspect.stack()[1][3] + if short_name.startswith("_"): + self.short_name = None + else: + if short_name.endswith("_dimensional"): + self.short_name = short_name[: -len("_dimensional")] + elif short_name.endswith("_dim"): + self.short_name = short_name[: -len("_dim")] + else: + self.short_name = short_name + @property def input_names(self): return self._input_names @@ -159,7 +173,9 @@ def diff(self, variable): def new_copy(self): """ See :meth:`pybamm.Symbol.new_copy()`. """ - return self._function_parameter_new_copy(self._input_names, self.orphans) + out = self._function_parameter_new_copy(self._input_names, self.orphans) + out.short_name = self.short_name + return out def _function_parameter_new_copy(self, input_names, children): """Returns a new copy of the function parameter. diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py index 56cc7c86fc..f406cfc348 100644 --- a/pybamm/parameters/parameter_values.py +++ b/pybamm/parameters/parameter_values.py @@ -87,6 +87,10 @@ def __init__(self, values=None, chemistry=None): self._processed_symbols = {} self.parameter_events = [] + # Don't touch this parameter unless you know what you are doing + # This is for the conversion to Julia (ModelingToolkit) + self._replace_callable_function_parameters = True + def __getitem__(self, key): return self._dict_items[key] @@ -122,7 +126,11 @@ def items(self): def copy(self): """Returns a copy of the parameter values. Makes sure to copy the internal dictionary.""" - return ParameterValues(values=self._dict_items.copy()) + new_copy = ParameterValues(values=self._dict_items.copy()) + new_copy._replace_callable_function_parameters = ( + self._replace_callable_function_parameters + ) + return new_copy def search(self, key, print_values=True): """ @@ -570,6 +578,8 @@ def process_geometry(self, geometry): geometry[domain][spatial_variable][ lim ] = self.process_symbol(sym) + elif isinstance(sym, numbers.Number): + geometry[domain][spatial_variable][lim] = pybamm.Scalar(sym) def process_symbol(self, symbol): """Walk through the symbol and replace any Parameter with a Value. @@ -668,6 +678,17 @@ def _process_symbol(self, symbol): elif callable(function_name): # otherwise evaluate the function to create a new PyBaMM object function = function_name(*new_children) + if ( + self._replace_callable_function_parameters is False + and not isinstance( + self.process_symbol(function), (pybamm.Scalar, pybamm.Broadcast) + ) + and symbol.short_name is not None + and symbol.diff_variable is None + ): + return pybamm.FunctionParameter( + symbol.short_name, dict(zip(symbol.input_names, new_children)) + ) elif isinstance(function_name, pybamm.Interpolant): function = function_name else: diff --git a/test.py b/test.py index ab6aa2da48..1b82684e15 100644 --- a/test.py +++ b/test.py @@ -1,14 +1,16 @@ import pybamm model = pybamm.lithium_ion.DFN() -sim = pybamm.Simulation(model) +parameter_values = model.default_parameter_values +parameter_values._replace_callable_function_parameters = False +sim = pybamm.Simulation(model, parameter_values=parameter_values) sim.set_parameters() mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) print(mtk_str) -# list(sim.model.rhs.values())[1].render() +list(sim.model.rhs.values())[3].render() # sim.build() # rhs_str, u0_str = sim.built_model.generate_julia_diffeq( diff --git a/tests/unit/test_expression_tree/test_parameter.py b/tests/unit/test_expression_tree/test_parameter.py index ee3231a0d8..db839f7c2a 100644 --- a/tests/unit/test_expression_tree/test_parameter.py +++ b/tests/unit/test_expression_tree/test_parameter.py @@ -74,6 +74,25 @@ def test_set_input_names(self): new_input_names = [var] func.input_names = new_input_names + def test_short_name(self): + def myfun(x): + return pybamm.FunctionParameter("my function", {"x": x}) + + def myfun_dim(x): + return pybamm.FunctionParameter("my function", {"x": x}) + + def myfun_dimensional(x): + return pybamm.FunctionParameter("my function", {"x": x}) + + def _myfun(x): + return pybamm.FunctionParameter("my function", {"x": x}) + + x = pybamm.Scalar(1) + self.assertEqual(myfun(x).short_name, "myfun") + self.assertEqual(myfun_dim(x).short_name, "myfun") + self.assertEqual(myfun_dimensional(x).short_name, "myfun") + self.assertEqual(_myfun(x).short_name, None) + if __name__ == "__main__": print("Add -v for more debug output") From 3b54890aaa1a94590ebbd9d31f72611f1b54774c Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 26 Mar 2021 00:26:11 -0400 Subject: [PATCH 71/88] #1129 working on DFN to MTK --- pybamm/__init__.py | 2 +- pybamm/expression_tree/concatenations.py | 7 + .../operations/evaluate_julia.py | 70 ++- pybamm/expression_tree/scalar.py | 3 + pybamm/expression_tree/variable.py | 5 +- pybamm/models/standard_variables.py | 545 +++++++++--------- .../external_circuit/base_external_circuit.py | 2 +- pybamm/parameters/parameter_values.py | 20 +- test.py | 2 +- 9 files changed, 373 insertions(+), 283 deletions(-) diff --git a/pybamm/__init__.py b/pybamm/__init__.py index 1aed1be474..866c92fe4d 100644 --- a/pybamm/__init__.py +++ b/pybamm/__init__.py @@ -120,7 +120,7 @@ def version(formatted=False): # Model classes # from .models.base_model import BaseModel -from .models import standard_variables +from .models.standard_variables import standard_variables from .models.event import Event from .models.event import EventType diff --git a/pybamm/expression_tree/concatenations.py b/pybamm/expression_tree/concatenations.py index 77839640b4..f3d71a2be8 100644 --- a/pybamm/expression_tree/concatenations.py +++ b/pybamm/expression_tree/concatenations.py @@ -341,6 +341,13 @@ def __init__(self, *children): np.min([child.bounds[1] for child in children]), ) + short_name = intersect(children[0].short_name, children[1].short_name) + for child in children[2:]: + short_name = intersect(short_name, child.short_name) + if short_name.endswith("_"): + short_name = short_name[:-1] + self.short_name = short_name + def substrings(s): for i in range(len(s)): diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 240f03ce29..fe91feaf7f 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -571,13 +571,21 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t symbol_line == "t" or " " not in symbol_line or symbol_line.startswith("grad") - or next_symbol_line.startswith("concatenation") or not any(x in next_symbol_line for x in inlineable_symbols) ): # cases that don't need brackets var_symbols[next_var_id] = next_symbol_line.replace( julia_var, symbol_line ) + elif next_symbol_line.startswith("concatenation"): + if len(symbol_line) < 20: + var_symbols[next_var_id] = next_symbol_line.replace( + julia_var, symbol_line + ) + else: + var_symbols[next_var_id] = next_symbol_line.replace( + julia_var, f"\n {symbol_line}\n" + ) else: # add brackets so that the order of operations is maintained var_symbols[next_var_id] = next_symbol_line.replace( @@ -608,9 +616,33 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t + " x < neg_plus_sep_width, s, p\n" + " )\n" + " )\n" - + "end\n\n" + + "end\n" ) - var_str = concatenation_def + var_str + else: + concatenation_def = "" + + # Define the FunctionParameter objects that have not yet been defined + function_defs = "" + for x in eqn.pre_order(): + if ( + isinstance(x, pybamm.FunctionParameter) + and f"function {x.name}" not in all_variables_str + and typ == "equation" + ): + range_children = range(len(x.children)) + function_def = ( + f"\nfunction {x.name}(" + + ", ".join(x.arg_names) + + ")\n" + + " {}\n".format(str(x.callable).replace("**", "^")) + + "end\n" + ) + function_defs += function_def + + if concatenation_def + function_defs != "": + function_defs += "\n" + + var_str = concatenation_def + function_defs + var_str # add a comment labeling the equation, and the equation itself if var_str == "": @@ -655,12 +687,16 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): """ # Extract variables variables = {**model.rhs, **model.algebraic}.keys() - variable_id_to_number = {} + variable_id_to_short_name = {} for i, var in enumerate(variables): - variable_id_to_number[var.id] = f"u{i+1}" + if var.short_name is not None: + short_name = var.short_name + else: + short_name = f"u{i+1}" + variable_id_to_short_name[var.id] = short_name if isinstance(var, pybamm.ConcatenationVariable): for child in var.children: - variable_id_to_number[child.id] = f"u{i+1}" + variable_id_to_short_name[child.id] = short_name # Extract domain and auxiliary domains all_domains = set([tuple(var.domain) for var in variables if var.domain != []]) @@ -764,7 +800,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Makes a line of the form '@parameters t x1 x2 x3 a b c d' ind_vars = ["t"] + list(domain_name_to_symbol.values()) for domain_name, domain_symbol in domain_name_to_symbol.items(): - mtk_str += f"# '{domain_name}' -> {domain_symbol}\n" + mtk_str += f"# {domain_name} -> {domain_symbol}\n" mtk_str += "@parameters " + " ".join(ind_vars) for param in model.input_parameters: mtk_str += f" {param.name}" @@ -772,13 +808,13 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Add a comment with the variable names for var in variables: - mtk_str += f"# '{var.name}' -> {variable_id_to_number[var.id]}\n" + mtk_str += f"# '{var.name}' -> {variable_id_to_short_name[var.id]}\n" # Makes a line of the form '@variables u1(t) u2(t)' dep_vars = [] mtk_str += "@variables" for var in variables: - mtk_str += f" {variable_id_to_number[var.id]}(..)" - dep_vars.append(variable_id_to_number[var.id]) + mtk_str += f" {variable_id_to_short_name[var.id]}(..)" + dep_vars.append(variable_id_to_short_name[var.id]) mtk_str += "\n" # Define derivatives @@ -799,7 +835,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): if var in model.rhs: all_eqns_str += ( - f" Dt({variable_id_to_number[var.id]}{var_to_ind_vars[var.id]}) " + f" Dt({variable_id_to_short_name[var.id]}{var_to_ind_vars[var.id]}) " + f"~ {eqn_str},\n" ) elif var in model.algebraic: @@ -813,7 +849,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Replace variables in the julia strings that correspond to pybamm variables with # their julia equivalent - for var_id, julia_id in variable_id_to_number.items(): + for var_id, julia_id in variable_id_to_short_name.items(): # e.g. boundary_value_right(cache_123456789) gets replaced with u1(t, 1) cache_var_id = id_to_julia_variable(var_id, False) if f"boundary_value_right({cache_var_id})" in all_julia_str: @@ -884,7 +920,9 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): ) if not is_pde: - all_ic_bc_str += f" {variable_id_to_number[var.id]}(t) => {eqn_str},\n" + all_ic_bc_str += ( + f" {variable_id_to_short_name[var.id]}(t) => {eqn_str},\n" + ) else: if var.domain == []: doms = "" @@ -892,7 +930,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): doms = ", " + domain_name_to_symbol[tuple(var.domain)] all_ic_bc_str += ( - f" {variable_id_to_number[var.id]}(0{doms}) ~ {eqn_str},\n" + f" {variable_id_to_short_name[var.id]}(0{doms}) ~ {eqn_str},\n" ) # Boundary conditions if is_pde: @@ -916,7 +954,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): elif side == "right": limit = var_to_ind_vars_right_boundary[var.id] - bc = f"{variable_id_to_number[var.id]}{limit}" + bc = f"{variable_id_to_short_name[var.id]}{limit}" if typ == "Dirichlet": bc = bc elif typ == "Neumann": @@ -925,7 +963,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Replace variables in the julia strings that correspond to pybamm variables with # their julia equivalent - for var_id, julia_id in variable_id_to_number.items(): + for var_id, julia_id in variable_id_to_short_name.items(): # e.g. boundary_value_right(cache_123456789) gets replaced with u1(t, 1) cache_var_id = id_to_julia_variable(var_id, False) if f"boundary_value_right({cache_var_id})" in all_ic_bc_julia_str: diff --git a/pybamm/expression_tree/scalar.py b/pybamm/expression_tree/scalar.py index 5bde1f147e..333844fcdb 100644 --- a/pybamm/expression_tree/scalar.py +++ b/pybamm/expression_tree/scalar.py @@ -31,6 +31,9 @@ def __init__(self, value, name=None, domain=[]): super().__init__(name, domain=domain) + def __str__(self): + return str(self.value) + @property def value(self): """the value returned by the node when evaluated""" diff --git a/pybamm/expression_tree/variable.py b/pybamm/expression_tree/variable.py index ee54d7eda8..b3b31c0b66 100644 --- a/pybamm/expression_tree/variable.py +++ b/pybamm/expression_tree/variable.py @@ -47,13 +47,16 @@ def __init__(self, name, domain=None, auxiliary_domains=None, bounds=None): + "Lower bound should be strictly less than upper bound." ) self.bounds = bounds + self.short_name = None def new_copy(self): """ See :meth:`pybamm.Symbol.new_copy()`. """ - return self.__class__( + out = self.__class__( self.name, self.domain, self.auxiliary_domains, self.bounds ) + out.short_name = self.short_name + return out def _evaluate_for_shape(self): """ See :meth:`pybamm.Symbol.evaluate_for_shape_using_domain()` """ diff --git a/pybamm/models/standard_variables.py b/pybamm/models/standard_variables.py index ed9f8f4a47..9e9b4d908d 100644 --- a/pybamm/models/standard_variables.py +++ b/pybamm/models/standard_variables.py @@ -4,279 +4,300 @@ import pybamm import numpy as np -# Electrolyte concentration -c_e_n = pybamm.Variable( - "Negative electrolyte concentration", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, np.inf), -) -c_e_s = pybamm.Variable( - "Separator electrolyte concentration", - domain="separator", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, np.inf), -) -c_e_p = pybamm.Variable( - "Positive electrolyte concentration", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, np.inf), -) -c_e = pybamm.concatenation(c_e_n, c_e_s, c_e_p) -c_e_av = pybamm.Variable( - "X-averaged electrolyte concentration", - domain="current collector", - bounds=(0, np.inf), -) +class StandardVariables: + def __init__(self): + # Discharge capacity + self.Q = pybamm.Variable("Discharge capacity [A.h]") -# Electrolyte potential -phi_e_n = pybamm.Variable( - "Negative electrolyte potential", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, -) -phi_e_s = pybamm.Variable( - "Separator electrolyte potential", - domain="separator", - auxiliary_domains={"secondary": "current collector"}, -) -phi_e_p = pybamm.Variable( - "Positive electrolyte potential", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, -) -phi_e = pybamm.concatenation(phi_e_n, phi_e_s, phi_e_p) + # Electrolyte concentration + self.c_e_n = pybamm.Variable( + "Negative electrolyte concentration", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, np.inf), + ) + self.c_e_s = pybamm.Variable( + "Separator electrolyte concentration", + domain="separator", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, np.inf), + ) + self.c_e_p = pybamm.Variable( + "Positive electrolyte concentration", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, np.inf), + ) + # self.c_e = pybamm.concatenation(c_e_n, c_e_s, c_e_p) -# Electrode potential -phi_s_n = pybamm.Variable( - "Negative electrode potential", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, -) -phi_s_p = pybamm.Variable( - "Positive electrode potential", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, -) + self.c_e_av = pybamm.Variable( + "X-averaged electrolyte concentration", + domain="current collector", + bounds=(0, np.inf), + ) -# Potential difference -delta_phi_n = pybamm.Variable( - "Negative electrode surface potential difference", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, -) -delta_phi_p = pybamm.Variable( - "Positive electrode surface potential difference", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, -) + # Electrolyte potential + self.phi_e_n = pybamm.Variable( + "Negative electrolyte potential", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + self.phi_e_s = pybamm.Variable( + "Separator electrolyte potential", + domain="separator", + auxiliary_domains={"secondary": "current collector"}, + ) + self.phi_e_p = pybamm.Variable( + "Positive electrolyte potential", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + # self.phi_e = pybamm.concatenation(phi_e_n, phi_e_s, phi_e_p) -delta_phi_n_av = pybamm.Variable( - "X-averaged negative electrode surface potential difference", - domain="current collector", -) -delta_phi_p_av = pybamm.Variable( - "X-averaged positive electrode surface potential difference", - domain="current collector", -) + # Electrode potential + self.phi_s_n = pybamm.Variable( + "Negative electrode potential", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + self.phi_s_p = pybamm.Variable( + "Positive electrode potential", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + ) -# current collector variables -phi_s_cn = pybamm.Variable( - "Negative current collector potential", domain="current collector" -) -phi_s_cp = pybamm.Variable( - "Positive current collector potential", domain="current collector" -) -i_boundary_cc = pybamm.Variable( - "Current collector current density", domain="current collector" -) -phi_s_cn_composite = pybamm.Variable( - "Composite negative current collector potential", domain="current collector" -) -phi_s_cp_composite = pybamm.Variable( - "Composite positive current collector potential", domain="current collector" -) -i_boundary_cc_composite = pybamm.Variable( - "Composite current collector current density", domain="current collector" -) + # Potential difference + self.delta_phi_n = pybamm.Variable( + "Negative electrode surface potential difference", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + self.delta_phi_p = pybamm.Variable( + "Positive electrode surface potential difference", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + self.delta_phi_n_av = pybamm.Variable( + "X-averaged negative electrode surface potential difference", + domain="current collector", + ) + self.delta_phi_p_av = pybamm.Variable( + "X-averaged positive electrode surface potential difference", + domain="current collector", + ) -# Particle concentration -c_s_n = pybamm.Variable( - "Negative particle concentration", - domain="negative particle", - auxiliary_domains={ - "secondary": "negative electrode", - "tertiary": "current collector", - }, - bounds=(0, 1), -) -c_s_p = pybamm.Variable( - "Positive particle concentration", - domain="positive particle", - auxiliary_domains={ - "secondary": "positive electrode", - "tertiary": "current collector", - }, - bounds=(0, 1), -) -c_s_n_xav = pybamm.Variable( - "X-averaged negative particle concentration", - domain="negative particle", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -c_s_p_xav = pybamm.Variable( - "X-averaged positive particle concentration", - domain="positive particle", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -c_s_n_rav = pybamm.Variable( - "R-averaged negative particle concentration", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -c_s_p_rav = pybamm.Variable( - "R-averaged positive particle concentration", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -c_s_n_rxav = pybamm.Variable( - "R-X-averaged negative particle concentration", - domain="current collector", - bounds=(0, 1), -) -c_s_p_rxav = pybamm.Variable( - "R-X-averaged positive particle concentration", - domain="current collector", - bounds=(0, 1), -) -c_s_n_surf = pybamm.Variable( - "Negative particle surface concentration", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -c_s_p_surf = pybamm.Variable( - "Positive particle surface concentration", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -c_s_n_surf_xav = pybamm.Variable( - "X-averaged negative particle surface concentration", - domain="current collector", - bounds=(0, 1), -) -c_s_p_surf_xav = pybamm.Variable( - "X-averaged positive particle surface concentration", - domain="current collector", - bounds=(0, 1), -) -# Average particle concentration gradient (for polynomial particle concentration -# models). Note: we make the distinction here between the flux defined as -# N = -D*dc/dr and the concentration gradient q = dc/dr -q_s_n_rav = pybamm.Variable( - "R-averaged negative particle concentration gradient", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, -) -q_s_p_rav = pybamm.Variable( - "R-averaged positive particle concentration gradient", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, -) -q_s_n_rxav = pybamm.Variable( - "R-X-averaged negative particle concentration gradient", domain="current collector" -) -q_s_p_rxav = pybamm.Variable( - "R-X-averaged positive particle concentration gradient", domain="current collector" -) + # current collector variables + self.phi_s_cn = pybamm.Variable( + "Negative current collector potential", domain="current collector" + ) + self.phi_s_cp = pybamm.Variable( + "Positive current collector potential", domain="current collector" + ) + self.i_boundary_cc = pybamm.Variable( + "Current collector current density", domain="current collector" + ) + self.phi_s_cn_composite = pybamm.Variable( + "Composite negative current collector potential", domain="current collector" + ) + self.phi_s_cp_composite = pybamm.Variable( + "Composite positive current collector potential", domain="current collector" + ) + self.i_boundary_cc_composite = pybamm.Variable( + "Composite current collector current density", domain="current collector" + ) -# Porosity -eps_n = pybamm.Variable( - "Negative electrode porosity", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -eps_s = pybamm.Variable( - "Separator porosity", - domain="separator", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -eps_p = pybamm.Variable( - "Positive electrode porosity", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, - bounds=(0, 1), -) -eps = pybamm.concatenation(eps_n, eps_s, eps_p) + # Particle concentration + self.c_s_n = pybamm.Variable( + "Negative particle concentration", + domain="negative particle", + auxiliary_domains={ + "secondary": "negative electrode", + "tertiary": "current collector", + }, + bounds=(0, 1), + ) + self.c_s_p = pybamm.Variable( + "Positive particle concentration", + domain="positive particle", + auxiliary_domains={ + "secondary": "positive electrode", + "tertiary": "current collector", + }, + bounds=(0, 1), + ) + self.c_s_n_xav = pybamm.Variable( + "X-averaged negative particle concentration", + domain="negative particle", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + self.c_s_p_xav = pybamm.Variable( + "X-averaged positive particle concentration", + domain="positive particle", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + self.c_s_n_rav = pybamm.Variable( + "R-averaged negative particle concentration", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + self.c_s_p_rav = pybamm.Variable( + "R-averaged positive particle concentration", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + self.c_s_n_rxav = pybamm.Variable( + "R-X-averaged negative particle concentration", + domain="current collector", + bounds=(0, 1), + ) + self.c_s_p_rxav = pybamm.Variable( + "R-X-averaged positive particle concentration", + domain="current collector", + bounds=(0, 1), + ) + self.c_s_n_surf = pybamm.Variable( + "Negative particle surface concentration", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + self.c_s_p_surf = pybamm.Variable( + "Positive particle surface concentration", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + self.c_s_n_surf_xav = pybamm.Variable( + "X-averaged negative particle surface concentration", + domain="current collector", + bounds=(0, 1), + ) + self.c_s_p_surf_xav = pybamm.Variable( + "X-averaged positive particle surface concentration", + domain="current collector", + bounds=(0, 1), + ) + # Average particle concentration gradient (for polynomial particle concentration + # models). Note: we make the distinction here between the flux defined as + # N = -D*dc/dr and the concentration gradient q = dc/dr + self.q_s_n_rav = pybamm.Variable( + "R-averaged negative particle concentration gradient", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + self.q_s_p_rav = pybamm.Variable( + "R-averaged positive particle concentration gradient", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + self.q_s_n_rxav = pybamm.Variable( + "R-X-averaged negative particle concentration gradient", + domain="current collector", + ) + self.q_s_p_rxav = pybamm.Variable( + "R-X-averaged positive particle concentration gradient", + domain="current collector", + ) -# Piecewise constant (for asymptotic models) -eps_n_pc = pybamm.Variable( - "X-averaged negative electrode porosity", domain="current collector", bounds=(0, 1) -) -eps_s_pc = pybamm.Variable( - "X-averaged separator porosity", domain="current collector", bounds=(0, 1) -) -eps_p_pc = pybamm.Variable( - "X-averaged positive electrode porosity", domain="current collector", bounds=(0, 1) -) + # Porosity + self.eps_n = pybamm.Variable( + "Negative electrode porosity", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + self.eps_s = pybamm.Variable( + "Separator porosity", + domain="separator", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + self.eps_p = pybamm.Variable( + "Positive electrode porosity", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + bounds=(0, 1), + ) + # self.eps = pybamm.concatenation(eps_n, eps_s, eps_p) -eps_piecewise_constant = pybamm.concatenation( - pybamm.PrimaryBroadcast(eps_n_pc, "negative electrode"), - pybamm.PrimaryBroadcast(eps_s_pc, "separator"), - pybamm.PrimaryBroadcast(eps_p_pc, "positive electrode"), -) + # Piecewise constant (for asymptotic models) + self.eps_n_pc = pybamm.Variable( + "X-averaged negative electrode porosity", + domain="current collector", + bounds=(0, 1), + ) + self.eps_s_pc = pybamm.Variable( + "X-averaged separator porosity", domain="current collector", bounds=(0, 1) + ) + self.eps_p_pc = pybamm.Variable( + "X-averaged positive electrode porosity", + domain="current collector", + bounds=(0, 1), + ) -# Temperature -T_cn = pybamm.Variable( - "Negative currents collector temperature", domain="current collector" -) -T_n = pybamm.Variable( - "Negative electrode temperature", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, -) -T_s = pybamm.Variable( - "Separator temperature", - domain="separator", - auxiliary_domains={"secondary": "current collector"}, -) -T_p = pybamm.Variable( - "Positive electrode temperature", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, -) -T_cp = pybamm.Variable( - "Positive currents collector temperature", domain="current collector" -) -T = pybamm.concatenation(T_n, T_s, T_p) -T_av = pybamm.Variable("X-averaged cell temperature", domain="current collector") -T_vol_av = pybamm.Variable("Volume-averaged cell temperature") + # self.eps_piecewise_constant = pybamm.concatenation( + # pybamm.PrimaryBroadcast(eps_n_pc, "negative electrode"), + # pybamm.PrimaryBroadcast(eps_s_pc, "separator"), + # pybamm.PrimaryBroadcast(eps_p_pc, "positive electrode"), + # ) + # Temperature + self.T_cn = pybamm.Variable( + "Negative currents collector temperature", domain="current collector" + ) + self.T_n = pybamm.Variable( + "Negative electrode temperature", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + self.T_s = pybamm.Variable( + "Separator temperature", + domain="separator", + auxiliary_domains={"secondary": "current collector"}, + ) + self.T_p = pybamm.Variable( + "Positive electrode temperature", + domain="positive electrode", + auxiliary_domains={"secondary": "current collector"}, + ) + self.T_cp = pybamm.Variable( + "Positive currents collector temperature", domain="current collector" + ) + # self.T = pybamm.concatenation(T_n, T_s, T_p) + self.T_av = pybamm.Variable( + "X-averaged cell temperature", domain="current collector" + ) + self.T_vol_av = pybamm.Variable("Volume-averaged cell temperature") -# SEI variables -L_inner_av = pybamm.Variable( - "X-averaged inner negative electrode SEI thickness", domain="current collector" -) -L_inner = pybamm.Variable( - "Inner negative electrode SEI thickness", - domain=["negative electrode"], - auxiliary_domains={"secondary": "current collector"}, -) -L_outer_av = pybamm.Variable( - "X-averaged outer negative electrode SEI thickness", domain="current collector" -) -L_outer = pybamm.Variable( - "Outer negative electrode SEI thickness", - domain=["negative electrode"], - auxiliary_domains={"secondary": "current collector"}, -) + # SEI variables + self.L_inner_av = pybamm.Variable( + "X-averaged inner negative electrode SEI thickness", + domain="current collector", + ) + self.L_inner = pybamm.Variable( + "Inner negative electrode SEI thickness", + domain=["negative electrode"], + auxiliary_domains={"secondary": "current collector"}, + ) + self.L_outer_av = pybamm.Variable( + "X-averaged outer negative electrode SEI thickness", + domain="current collector", + ) + self.L_outer = pybamm.Variable( + "Outer negative electrode SEI thickness", + domain=["negative electrode"], + auxiliary_domains={"secondary": "current collector"}, + ) + + def __setattr__(self, name, value): + value.short_name = name + super().__setattr__(name, value) + + +standard_variables = StandardVariables() \ No newline at end of file diff --git a/pybamm/models/submodels/external_circuit/base_external_circuit.py b/pybamm/models/submodels/external_circuit/base_external_circuit.py index cd37a82a6f..95df5b7582 100644 --- a/pybamm/models/submodels/external_circuit/base_external_circuit.py +++ b/pybamm/models/submodels/external_circuit/base_external_circuit.py @@ -11,7 +11,7 @@ def __init__(self, param): super().__init__(param) def get_fundamental_variables(self): - Q = pybamm.Variable("Discharge capacity [A.h]") + Q = pybamm.standard_variables.Q variables = {"Discharge capacity [A.h]": Q} return variables diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py index 1db9e923bb..4575377eec 100644 --- a/pybamm/parameters/parameter_values.py +++ b/pybamm/parameters/parameter_values.py @@ -8,6 +8,7 @@ import warnings from pprint import pformat from collections import defaultdict +import inspect class ParameterValues: @@ -686,9 +687,26 @@ def _process_symbol(self, symbol): and symbol.short_name is not None and symbol.diff_variable is None ): - return pybamm.FunctionParameter( + # Special trick for printing in Julia ModelingToolkit format + out = pybamm.FunctionParameter( symbol.short_name, dict(zip(symbol.input_names, new_children)) ) + + out.arg_names = inspect.getfullargspec(function_name)[0] + out.callable = self.process_symbol( + function_name( + *[ + pybamm.Variable( + arg_name, + domain=child.domain, + auxiliary_domains=child.auxiliary_domains, + ) + for arg_name, child in zip(out.arg_names, new_children) + ] + ) + ) + + return out elif isinstance(function_name, pybamm.Interpolant): function = function_name else: diff --git a/test.py b/test.py index 1b82684e15..be1600e40b 100644 --- a/test.py +++ b/test.py @@ -10,7 +10,7 @@ print(mtk_str) -list(sim.model.rhs.values())[3].render() +# list(sim.model.rhs.values())[3].render() # sim.build() # rhs_str, u0_str = sim.built_model.generate_julia_diffeq( From 24516ff7895ee80cd711a14c2ab6f6f1b4bd1794 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 26 Mar 2021 15:41:53 -0400 Subject: [PATCH 72/88] #1129 more dfn mtk --- .../operations/evaluate_julia.py | 19 ++++++++++++------- test.py | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index fe91feaf7f..af09fc4be8 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -798,9 +798,14 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str = "begin\n" # Define parameters (including independent variables) # Makes a line of the form '@parameters t x1 x2 x3 a b c d' - ind_vars = ["t"] + list(domain_name_to_symbol.values()) + ind_vars = ["t"] + [ + sym + for dom, sym in domain_name_to_symbol.items() + if domain_name_to_limits[dom] is not None + ] for domain_name, domain_symbol in domain_name_to_symbol.items(): - mtk_str += f"# {domain_name} -> {domain_symbol}\n" + if domain_name_to_limits[domain_name] is not None: + mtk_str += f"# {domain_name} -> {domain_symbol}\n" mtk_str += "@parameters " + " ".join(ind_vars) for param in model.input_parameters: mtk_str += f" {param.name}" @@ -818,10 +823,8 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str += "\n" # Define derivatives - mtk_str += "Dt = Differential(t)\n" - if is_pde: - for domain_symbol in domain_name_to_symbol.values(): - mtk_str += f"D{domain_symbol} = Differential({domain_symbol})\n" + for domain_symbol in ind_vars: + mtk_str += f"D{domain_symbol} = Differential({domain_symbol})\n" mtk_str += "\n" # Define equations @@ -1014,8 +1017,10 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str += "ind_vars = [{}]\n".format(", ".join(ind_vars)) mtk_str += "dep_vars = [{}]\n\n".format(", ".join(dep_vars)) + name = model.name.replace(" ", "_").replace("-", "_") mtk_str += ( - "pde_system = PDESystem(eqs, ics_bcs, domains, ind_vars, dep_vars)\n\n" + name + + "_pde_system = PDESystem(eqs, ics_bcs, domains, ind_vars, dep_vars)\n\n" ) # Need to add 'nothing' to the end of the mtk string to avoid errors in MTK v4 diff --git a/test.py b/test.py index be1600e40b..93bffe4f85 100644 --- a/test.py +++ b/test.py @@ -1,6 +1,6 @@ import pybamm -model = pybamm.lithium_ion.DFN() +model = pybamm.lithium_ion.SPMe(name="SPMe") parameter_values = model.default_parameter_values parameter_values._replace_callable_function_parameters = False sim = pybamm.Simulation(model, parameter_values=parameter_values) From df3da7cea7a2b64b5d35ad2d185ea9f81aeec326 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 26 Mar 2021 20:24:59 -0400 Subject: [PATCH 73/88] #1129 reformat for daes --- .../operations/evaluate_julia.py | 46 +++++++++++++++---- pybamm/models/base_model.py | 24 +++++++--- test.py | 34 ++++++++------ 3 files changed, 75 insertions(+), 29 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index af09fc4be8..3a1e4afe92 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -259,16 +259,20 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz symbol_str = "concatenation(" + ", ".join(children_vars) + ")" # Note: we assume that y is being passed as a column vector - elif isinstance(symbol, pybamm.StateVector): + elif isinstance(symbol, pybamm.StateVectorBase): + if isinstance(symbol, pybamm.StateVector): + name = "@view y" + elif isinstance(symbol, pybamm.StateVectorDot): + name = "@view dy" indices = np.argwhere(symbol.evaluation_array).reshape(-1).astype(np.int32) # add 1 since julia uses 1-indexing indices += 1 consecutive = np.all(indices[1:] - indices[:-1] == 1) if len(indices) == 1: - symbol_str = "@view y[{}]".format(indices[0]) + symbol_str = "{}[{}]".format(name, indices[0]) elif consecutive: # julia does include the final value - symbol_str = "@view y[{}:{}]".format(indices[0], indices[-1]) + symbol_str = "{}[{}:{}]".format(name, indices[0], indices[-1]) else: indices_array = pybamm.Array(indices) # Save the indices as constant by printing to a string @@ -279,7 +283,7 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz ) constant_symbols[indices_array.id] = np.array2string(indices, separator=",") index_name = id_to_julia_variable(indices_array.id, True) - symbol_str = "@view y[{}]".format(index_name) + symbol_str = "{}[{}]".format(name, index_name) elif isinstance(symbol, pybamm.Time): symbol_str = "t" @@ -342,7 +346,7 @@ def to_julia(symbol): return constant_values, variable_symbols, variable_symbol_sizes -def get_julia_function(symbol, funcname="f", input_parameter_order=None): +def get_julia_function(symbol, funcname="f", input_parameter_order=None, len_rhs=None): """ Converts a pybamm expression tree into pure julia code that will calculate the result of calling `evaluate(t, y)` on the given expression tree. @@ -363,6 +367,24 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): String of julia code, to be evaluated by ``julia.Main.eval`` """ + if len_rhs is None: + typ = "ode" + else: + typ = "dae" + # Take away dy from the differential states + # we will return a function of the form + # out[] = .. - dy[] for the differential states + # out[] = .. for the algebraic states + symbol_minus_dy = [] + end = 0 + for child in symbol.orphans: + start = end + end += child.size + if end <= len_rhs: + symbol_minus_dy.append(child - pybamm.StateVectorDot(slice(start, end))) + else: + symbol_minus_dy.append(child) + symbol = pybamm.numpy_concatenation(*symbol_minus_dy) constants, var_symbols, var_symbol_sizes = to_julia(symbol) # extract constants in generated function @@ -473,10 +495,14 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): # add function def and sparse arrays to first line imports = "begin\nusing SparseArrays, LinearAlgebra\n\n" + if typ == "ode": + function_def = f"\nfunction {funcname}_with_consts!(dy, y, p, t)\n" + elif typ == "dae": + function_def = f"\nfunction {funcname}_with_consts!(out, dy, y, p, t)\n" julia_str = ( imports + const_and_cache_str - + f"\nfunction {funcname}_with_consts!(dy, y, p, t)\n" + + function_def + input_parameter_extraction + var_str ) @@ -493,7 +519,10 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None): else: julia_str = julia_str + "\n dy .= cs." + result_var + "\n" else: - julia_str = julia_str.replace("cs." + result_var, "dy") + if typ == "ode": + julia_str = julia_str.replace("cs." + result_var, "dy") + elif typ == "dae": + julia_str = julia_str.replace("cs." + result_var, "out") # close the function, with a 'nothing' to avoid allocations julia_str += "nothing\nend\n\n" @@ -910,7 +939,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Initial and boundary conditions #################################################################################### # Initial conditions - all_ic_bc_str = "" + all_ic_bc_str = " # initial conditions\n" all_ic_bc_constants_str = "" all_ic_bc_julia_str = "" for var, eqn in model.initial_conditions.items(): @@ -937,6 +966,7 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): ) # Boundary conditions if is_pde: + all_ic_bc_str += " # boundary conditions\n" for var, eqn_side in model.boundary_conditions.items(): if isinstance(var, (pybamm.Variable, pybamm.ConcatenationVariable)): for side, (eqn, typ) in eqn_side.items(): diff --git a/pybamm/models/base_model.py b/pybamm/models/base_model.py index 661d64336a..720de8fb44 100644 --- a/pybamm/models/base_model.py +++ b/pybamm/models/base_model.py @@ -942,13 +942,23 @@ def generate_julia_diffeq( name = self.name.replace(" ", "_") - eqn_str = pybamm.get_julia_function( - pybamm.numpy_concatenation( - self.concatenated_rhs, self.concatenated_algebraic - ), - funcname=name, - input_parameter_order=input_parameter_order, - ) + if self.algebraic == {}: + # ODE model: form dy[] = ... + eqn_str = pybamm.get_julia_function( + self.concatenated_rhs, + funcname=name, + input_parameter_order=input_parameter_order, + ) + else: + # DAE model: form out[] = ... - dy[] + eqn_str = pybamm.get_julia_function( + pybamm.numpy_concatenation( + self.concatenated_rhs, self.concatenated_algebraic + ), + funcname=name, + input_parameter_order=input_parameter_order, + len_rhs=self.concatenated_rhs.size, + ) if get_consistent_ics_solver is None or self.algebraic == {}: ics = self.concatenated_initial_conditions diff --git a/test.py b/test.py index 93bffe4f85..bf589539da 100644 --- a/test.py +++ b/test.py @@ -1,20 +1,26 @@ import pybamm -model = pybamm.lithium_ion.SPMe(name="SPMe") -parameter_values = model.default_parameter_values -parameter_values._replace_callable_function_parameters = False -sim = pybamm.Simulation(model, parameter_values=parameter_values) -sim.set_parameters() -mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) +model = pybamm.lithium_ion.DFN({"particle": "uniform profile"}, name="DFN_no_r") +# model = pybamm.BaseModel(name="DFN_no_r") +# var1 = pybamm.Variable("var1") +# var2 = pybamm.Variable("var2") +# model.rhs = {var1: 0.1 * var1} +# model.algebraic = {var2: 2 * var1 - var2} +# model.initial_conditions = {var1: 1, var2: 2} +# parameter_values = model.default_parameter_values +# parameter_values._replace_callable_function_parameters = False +sim = pybamm.Simulation(model) +# sim.set_parameters() +# mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) -print(mtk_str) - +# print(mtk_str) # list(sim.model.rhs.values())[3].render() -# sim.build() -# rhs_str, u0_str = sim.built_model.generate_julia_diffeq( -# get_consistent_ics_solver=pybamm.CasadiSolver() -# ) -# print(rhs_str) -# print(u0_str) \ No newline at end of file +sim.build() + +rhs_str, u0_str = sim.built_model.generate_julia_diffeq( + get_consistent_ics_solver=pybamm.CasadiSolver() +) +print(rhs_str) +print(u0_str) \ No newline at end of file From ae96e84da4722b6df32c00a70eea050fd9359359 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 26 Mar 2021 22:22:03 -0400 Subject: [PATCH 74/88] #1129 debugging dfn --- pybamm/expression_tree/operations/evaluate_julia.py | 2 ++ test.py | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 3a1e4afe92..a2ce3fa5b5 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -87,6 +87,8 @@ def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_siz np.set_printoptions( threshold=max(np.get_printoptions()["threshold"], len(row) + 10) ) + # increase precision for printing + np.set_printoptions(precision=20) # add 1 to correct for 1-indexing in Julia # use array2string so that commas are included constant_symbols[symbol.id] = "sparse({}, {}, {}, {}, {})".format( diff --git a/test.py b/test.py index bf589539da..e0f9bd687e 100644 --- a/test.py +++ b/test.py @@ -7,9 +7,17 @@ # model.rhs = {var1: 0.1 * var1} # model.algebraic = {var2: 2 * var1 - var2} # model.initial_conditions = {var1: 1, var2: 2} -# parameter_values = model.default_parameter_values +parameter_values = model.default_parameter_values +parameter_values["Electrolyte diffusivity [m2.s-1]"] = 1e-10 +# parameter_values["Electrolyte conductivity [S.m-1]"] = 1 +parameter_values["Negative electrode OCP [V]"] = 0.5 +parameter_values["Positive electrode OCP [V]"] = 4 # parameter_values._replace_callable_function_parameters = False -sim = pybamm.Simulation(model) + +var = pybamm.standard_spatial_vars +var_pts = {var.x_n: 3, var.x_s: 3, var.x_p: 3, var.r_n: 3, var.r_p: 3} + +sim = pybamm.Simulation(model, var_pts=var_pts, parameter_values=parameter_values) # sim.set_parameters() # mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) From ac31d01f02bc0165e5ab629d0724af33db92631f Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Sat, 27 Mar 2021 12:00:05 -0400 Subject: [PATCH 75/88] #1129 fix DFN model generation, now runs (but slow) --- .../operations/evaluate_julia.py | 37 ++++++++++++++----- test.py | 19 +++++++--- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index a2ce3fa5b5..bb74a6a4b2 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -362,6 +362,11 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None, len_rhs input_parameter_order : list, optional List of input parameter names. Defines the order in which the input parameters are extracted from 'p' in the julia function that is created + len_rhs : int, optional + The number of ODEs in the discretized differential equations. This also + determines whether the model has any algebraic equations: if None (default), + the model is assume to have no algebraic parts and ``julia_str`` is compatible + with an ODE solver. If not None, ``julia_str`` is compatible with a DAE solver Returns ------- @@ -426,20 +431,27 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None, len_rhs elif symbol_line.startswith("inputs"): input_parameters[julia_var] = symbol_line[8:-2] else: + # don't replace the matrix multiplication cases (which will be + # turned into a mul!), since it is faster to assign to a cache array + # first in that case, unless it is a @view in which case we don't + # need to cache + any_matmuls = any( + julia_var in next_symbol_line + and ( + (" @ " in next_symbol_line or "mul!" in next_symbol_line) + and not symbol_line.startswith("@view") + ) + for next_symbol_line in var_symbols.values() + ) # inline operation if it can be inlined - if any(x in symbol_line for x in inlineable_symbols) or symbol_line == "t": + if ( + any(x in symbol_line for x in inlineable_symbols) or symbol_line == "t" + ) and not any_matmuls: found_replacement = False # replace all other occurrences of the variable # in the dictionary with the symbol line for next_var_id, next_symbol_line in var_symbols.items(): - # don't replace the matrix multiplication cases (which will be - # turned into a mul!), since it is faster to assign to a cache array - # first in that case, unless it is a @view in which case we don't - # need to cache - if julia_var in next_symbol_line and not ( - (" @ " in next_symbol_line or "mul!" in next_symbol_line) - and not symbol_line.startswith("@view") - ): + if julia_var in next_symbol_line: if symbol_line == "t": # no brackets needed var_symbols[next_var_id] = next_symbol_line.replace( @@ -472,8 +484,13 @@ def get_julia_function(symbol, funcname="f", input_parameter_order=None, len_rhs # Skip caching the result variable since this is provided as dy # Also skip caching the result variable if it doesn't appear in the var_str, # since it has been inlined and does not need to be assigned to + # make sure that the variable appears at the start of a line in var_str julia_var = id_to_julia_variable(var_symbol_id, False) - if var_symbol_id != symbol.id and julia_var in var_str: + if ( + var_symbol_id != symbol.id + and "mul!(cs." + julia_var in var_str + or "@. cs." + julia_var in var_str + ): cache_name = id_to_julia_variable(var_symbol_id, False) const_and_cache_str += " {} = zeros({}),\n".format( cache_name, var_symbol_size diff --git a/test.py b/test.py index e0f9bd687e..ee9280a2fa 100644 --- a/test.py +++ b/test.py @@ -1,6 +1,6 @@ import pybamm -model = pybamm.lithium_ion.DFN({"particle": "uniform profile"}, name="DFN_no_r") +model = pybamm.lithium_ion.DFN(name="DFN") # model = pybamm.BaseModel(name="DFN_no_r") # var1 = pybamm.Variable("var1") # var2 = pybamm.Variable("var2") @@ -8,14 +8,16 @@ # model.algebraic = {var2: 2 * var1 - var2} # model.initial_conditions = {var1: 1, var2: 2} parameter_values = model.default_parameter_values -parameter_values["Electrolyte diffusivity [m2.s-1]"] = 1e-10 +# parameter_values["Electrolyte diffusivity [m2.s-1]"] = 1e-10 # parameter_values["Electrolyte conductivity [S.m-1]"] = 1 -parameter_values["Negative electrode OCP [V]"] = 0.5 -parameter_values["Positive electrode OCP [V]"] = 4 +# parameter_values["Negative electrode exchange-current density [A.m-2]"] = 1e-6 +# parameter_values["Positive electrode exchange-current density [A.m-2]"] = 1e-6 +# parameter_values["Negative electrode OCP [V]"] = 0.5 +# parameter_values["Positive electrode OCP [V]"] = 4 # parameter_values._replace_callable_function_parameters = False var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 3, var.x_s: 3, var.x_p: 3, var.r_n: 3, var.r_p: 3} +var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} sim = pybamm.Simulation(model, var_pts=var_pts, parameter_values=parameter_values) # sim.set_parameters() @@ -31,4 +33,9 @@ get_consistent_ics_solver=pybamm.CasadiSolver() ) print(rhs_str) -print(u0_str) \ No newline at end of file +print(u0_str) + +V_str = pybamm.get_julia_function( + sim.built_model.variables["Terminal voltage [V]"], funcname="V" +) +print(V_str) From a896a17754049cc08085eae83654e387be3b70f6 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 16 Apr 2021 16:28:47 -0400 Subject: [PATCH 76/88] #1129 merge develop, run flake8 --- .github/workflows/test_on_push.yml | 2 +- pybamm/expression_tree/operations/evaluate_julia.py | 2 -- pybamm/models/standard_variables.py | 2 +- test.py | 3 ++- tests/unit/test_models/test_base_model.py | 2 -- 5 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 0b23d3bf97..8f6fa153ac 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -45,7 +45,7 @@ jobs: if: matrix.os != 'windows-latest' uses: julia-actions/setup-julia@v1 with: - version: 1.5 + version: 1.6 - name: Install Linux system dependencies if: matrix.os == 'ubuntu-latest' diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index bb74a6a4b2..52430c407c 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -605,7 +605,6 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t # occurences instead of assigning them. inlineable_symbols = [" + ", " - ", " * ", " / "] var_str = "" - input_parameters = {} while var_symbols: var_symbol_id, symbol_line = var_symbols.popitem(last=False) julia_var = id_to_julia_variable(var_symbol_id, False) @@ -677,7 +676,6 @@ def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, t and f"function {x.name}" not in all_variables_str and typ == "equation" ): - range_children = range(len(x.children)) function_def = ( f"\nfunction {x.name}(" + ", ".join(x.arg_names) diff --git a/pybamm/models/standard_variables.py b/pybamm/models/standard_variables.py index 9e9b4d908d..9b88c7f6b7 100644 --- a/pybamm/models/standard_variables.py +++ b/pybamm/models/standard_variables.py @@ -300,4 +300,4 @@ def __setattr__(self, name, value): super().__setattr__(name, value) -standard_variables = StandardVariables() \ No newline at end of file +standard_variables = StandardVariables() diff --git a/test.py b/test.py index ee9280a2fa..a53df30840 100644 --- a/test.py +++ b/test.py @@ -21,7 +21,8 @@ sim = pybamm.Simulation(model, var_pts=var_pts, parameter_values=parameter_values) # sim.set_parameters() -# mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) +# mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, +# tspan=(0, 3600)) # print(mtk_str) diff --git a/tests/unit/test_models/test_base_model.py b/tests/unit/test_models/test_base_model.py index 90475ff6df..4f34a81ce7 100644 --- a/tests/unit/test_models/test_base_model.py +++ b/tests/unit/test_models/test_base_model.py @@ -626,7 +626,6 @@ def test_generate_casadi(self): def test_generate_julia_diffeq(self): # ODE model with no input parameters model = pybamm.BaseModel(name="ode test model") - t = pybamm.t a = pybamm.Variable("a") b = pybamm.Variable("b") model.rhs = {a: -a, b: a - b} @@ -642,7 +641,6 @@ def test_generate_julia_diffeq(self): # ODE model with input parameters model = pybamm.BaseModel(name="ode test model 2") - t = pybamm.t a = pybamm.Variable("a") b = pybamm.Variable("b") p = pybamm.InputParameter("p") From c7032505a337839ff834a1139de297ae18ae4690 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Mon, 19 Apr 2021 12:30:05 -0400 Subject: [PATCH 77/88] #1129 testing --- test.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/test.py b/test.py index a53df30840..b68745fe53 100644 --- a/test.py +++ b/test.py @@ -1,6 +1,6 @@ import pybamm -model = pybamm.lithium_ion.DFN(name="DFN") +model = pybamm.lithium_ion.SPM(name="SPM") # model = pybamm.BaseModel(name="DFN_no_r") # var1 = pybamm.Variable("var1") # var2 = pybamm.Variable("var2") @@ -20,23 +20,22 @@ var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} sim = pybamm.Simulation(model, var_pts=var_pts, parameter_values=parameter_values) -# sim.set_parameters() -# mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, -# tspan=(0, 3600)) +sim.set_parameters() +mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) -# print(mtk_str) +print(mtk_str) # list(sim.model.rhs.values())[3].render() -sim.build() +# sim.build() -rhs_str, u0_str = sim.built_model.generate_julia_diffeq( - get_consistent_ics_solver=pybamm.CasadiSolver() -) -print(rhs_str) -print(u0_str) +# rhs_str, u0_str = sim.built_model.generate_julia_diffeq( +# get_consistent_ics_solver=pybamm.CasadiSolver() +# ) +# print(rhs_str) +# print(u0_str) -V_str = pybamm.get_julia_function( - sim.built_model.variables["Terminal voltage [V]"], funcname="V" -) -print(V_str) +# V_str = pybamm.get_julia_function( +# sim.built_model.variables["Terminal voltage [V]"], funcname="V" +# ) +# print(V_str) From a6e8080b185accf3f235581c6a4e74e61666624b Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 29 Apr 2021 18:42:05 -0400 Subject: [PATCH 78/88] #1129 minor fixes --- pybamm/expression_tree/operations/evaluate_julia.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py index 52430c407c..90b9580cf1 100644 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ b/pybamm/expression_tree/operations/evaluate_julia.py @@ -865,7 +865,8 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): mtk_str += "@variables" for var in variables: mtk_str += f" {variable_id_to_short_name[var.id]}(..)" - dep_vars.append(variable_id_to_short_name[var.id]) + dep_var = variable_id_to_short_name[var.id] + var_to_ind_vars[var.id] + dep_vars.append(dep_var) mtk_str += "\n" # Define derivatives @@ -1048,7 +1049,10 @@ def get_julia_mtk_model(model, geometry=None, tspan=None): # Domains mtk_str += "\n" - mtk_str += f"t_domain = IntervalDomain({tspan[0]}, {tspan[1]})\n" + tpsan_str = ",".join( + map(lambda x: f"{x / model.timescale.evaluate():.3f}", tspan) + ) + mtk_str += f"t_domain = IntervalDomain({tpsan_str})\n" domains = "domains = [\n t in t_domain,\n" for domain, symbol in domain_name_to_symbol.items(): limits = domain_name_to_limits[tuple(domain)] From 2d991354b687f79cabf755372afdc18a4710fa56 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Wed, 26 May 2021 12:40:21 -0400 Subject: [PATCH 79/88] #1129 fix windows test --- pybamm/expression_tree/concatenations.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pybamm/expression_tree/concatenations.py b/pybamm/expression_tree/concatenations.py index aeac676968..fe1356d38c 100644 --- a/pybamm/expression_tree/concatenations.py +++ b/pybamm/expression_tree/concatenations.py @@ -349,11 +349,14 @@ def __init__(self, *children): np.min([child.bounds[1] for child in children]), ) - short_name = intersect(children[0].short_name, children[1].short_name) - for child in children[2:]: - short_name = intersect(short_name, child.short_name) - if short_name.endswith("_"): - short_name = short_name[:-1] + if not any(c.short_name is None for c in children): + short_name = intersect(children[0].short_name, children[1].short_name) + for child in children[2:]: + short_name = intersect(short_name, child.short_name) + if short_name.endswith("_"): + short_name = short_name[:-1] + else: + short_name = None self.short_name = short_name From a8beb0ee6f891e3bdde1e7c1d8fd2e12f7a6b26c Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 28 May 2021 15:00:56 -0400 Subject: [PATCH 80/88] remove Julia for now --- .github/workflows/test_on_push.yml | 10 - pybamm/__init__.py | 5 - pybamm/expression_tree/concatenations.py | 14 +- pybamm/expression_tree/functions.py | 34 - .../operations/evaluate_julia.py | 1081 ----------------- pybamm/expression_tree/parameter.py | 18 +- pybamm/expression_tree/variable.py | 4 +- pybamm/models/base_model.py | 61 - pybamm/models/standard_variables.py | 2 +- pybamm/parameters/parameter_values.py | 4 +- pybamm/util.py | 15 - requirements.txt | 1 - setup.py | 2 - test.py | 41 - .../test_operations/test_evaluate_julia.py | 448 ------- .../test_expression_tree/test_parameter.py | 10 +- tests/unit/test_models/test_base_model.py | 36 - tests/unit/test_solvers/test_julia_mtk.py | 196 --- tox.ini | 14 +- 19 files changed, 27 insertions(+), 1969 deletions(-) delete mode 100644 pybamm/expression_tree/operations/evaluate_julia.py delete mode 100644 test.py delete mode 100644 tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py delete mode 100644 tests/unit/test_solvers/test_julia_mtk.py diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index 8f6fa153ac..385914bc3a 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -41,12 +41,6 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Set up Julia 1.5 - if: matrix.os != 'windows-latest' - uses: julia-actions/setup-julia@v1 - with: - version: 1.6 - - name: Install Linux system dependencies if: matrix.os == 'ubuntu-latest' run: | @@ -72,10 +66,6 @@ jobs: if: matrix.os == 'ubuntu-latest' run: tox -e pybamm-requires - - name: Install Julia - if: matrix.os == 'ubuntu-latest' - run: tox -e julia - - name: Run unit tests for GNU/Linux if: matrix.os == 'ubuntu-latest' run: python -m tox -e tests diff --git a/pybamm/__init__.py b/pybamm/__init__.py index ef87373a83..e5f476195a 100644 --- a/pybamm/__init__.py +++ b/pybamm/__init__.py @@ -67,7 +67,6 @@ def version(formatted=False): from .util import Timer, TimerTime, FuzzyDict from .util import root_dir, load_function, rmse, get_infinite_nested_dict, load from .util import get_parameters_filepath -from .util import have_julia from .logger import logger, set_logging_level from .settings import settings from .citations import Citations, citations, print_citations @@ -111,10 +110,6 @@ def version(formatted=False): from .expression_tree.operations.convert_to_casadi import CasadiConverter from .expression_tree.operations.unpack_symbols import SymbolUnpacker from .expression_tree.operations.replace_symbols import SymbolReplacer -from .expression_tree.operations.evaluate_julia import ( - get_julia_function, - get_julia_mtk_model, -) # # Model classes diff --git a/pybamm/expression_tree/concatenations.py b/pybamm/expression_tree/concatenations.py index fe1356d38c..2d72b0efcc 100644 --- a/pybamm/expression_tree/concatenations.py +++ b/pybamm/expression_tree/concatenations.py @@ -349,15 +349,15 @@ def __init__(self, *children): np.min([child.bounds[1] for child in children]), ) - if not any(c.short_name is None for c in children): - short_name = intersect(children[0].short_name, children[1].short_name) + if not any(c.print_name is None for c in children): + print_name = intersect(children[0].print_name, children[1].print_name) for child in children[2:]: - short_name = intersect(short_name, child.short_name) - if short_name.endswith("_"): - short_name = short_name[:-1] + print_name = intersect(print_name, child.print_name) + if print_name.endswith("_"): + print_name = print_name[:-1] else: - short_name = None - self.short_name = short_name + print_name = None + self.print_name = print_name def substrings(s): diff --git a/pybamm/expression_tree/functions.py b/pybamm/expression_tree/functions.py index f2b9296976..e1da19b902 100644 --- a/pybamm/expression_tree/functions.py +++ b/pybamm/expression_tree/functions.py @@ -225,13 +225,6 @@ def _function_new_copy(self, children): ), ) - @property - def julia_name(self): - "Return the name of the equivalent Julia function, for generating Julia code" - raise NotImplementedError( - "No julia name defined for function {}".format(self.function) - ) - def simplified_function(func_class, child): """ @@ -270,13 +263,6 @@ def _function_new_copy(self, children): """ See :meth:`pybamm.Function._function_new_copy()` """ return pybamm.simplify_if_constant(self.__class__(*children)) - @property - def julia_name(self): - """ See :meth:`pybamm.Function.julia_name` """ - # By default, the julia name for a specific function is the function's name - # Some functions may overwrite this - return self.function.__name__ - class Arcsinh(SpecificFunction): """Arcsinh function.""" @@ -288,11 +274,6 @@ def _function_diff(self, children, idx): """ See :meth:`pybamm.Symbol._function_diff()`. """ return 1 / Sqrt(children[0] ** 2 + 1) - @property - def julia_name(self): - """ See :meth:`pybamm.Function.julia_name` """ - return "asinh" - def arcsinh(child): """Returns arcsinh function of child.""" @@ -383,11 +364,6 @@ class Max(SpecificFunction): def __init__(self, child): super().__init__(np.max, child) - @property - def julia_name(self): - """ See :meth:`pybamm.Function.julia_name` """ - return "maximum" - def max(child): """ @@ -403,11 +379,6 @@ class Min(SpecificFunction): def __init__(self, child): super().__init__(np.min, child) - @property - def julia_name(self): - """ See :meth:`pybamm.Function.julia_name` """ - return "minimum" - def min(child): """ @@ -501,11 +472,6 @@ def _function_diff(self, children, idx): """ See :meth:`pybamm.Function._function_diff()`. """ return 1 / (children[0] ** 2 + 1) - @property - def julia_name(self): - """ See :meth:`pybamm.Function.julia_name` """ - return "atan" - def arctan(child): """Returns hyperbolic tan function of child.""" diff --git a/pybamm/expression_tree/operations/evaluate_julia.py b/pybamm/expression_tree/operations/evaluate_julia.py deleted file mode 100644 index 90b9580cf1..0000000000 --- a/pybamm/expression_tree/operations/evaluate_julia.py +++ /dev/null @@ -1,1081 +0,0 @@ -# -# Write a symbol to Julia -# -import pybamm - -import numpy as np -import scipy.sparse -from collections import OrderedDict - -import numbers - - -def id_to_julia_variable(symbol_id, constant=False): - """ - This function defines the format for the julia variable names used in find_symbols - and to_julia. Variable names are based on a nodes' id to make them unique - """ - - if constant: - var_format = "const_{:05d}" - else: - var_format = "cache_{:05d}" - - # Need to replace "-" character to make them valid julia variable names - return var_format.format(symbol_id).replace("-", "m") - - -def is_constant_and_can_evaluate(symbol): - """ - Returns True if symbol is constant and evaluation does not raise any errors. - Returns False otherwise. - An example of a constant symbol that cannot be "evaluated" is PrimaryBroadcast(0). - """ - if symbol.is_constant(): - try: - symbol.evaluate() - return True - except NotImplementedError: - return False - else: - return False - - -def find_symbols(symbol, constant_symbols, variable_symbols, variable_symbol_sizes): - """ - This function converts an expression tree to a dictionary of node id's and strings - specifying valid julia code to calculate that nodes value, given y and t. - - The function distinguishes between nodes that represent constant nodes in the tree - (e.g. a pybamm.Matrix), and those that are variable (e.g. subtrees that contain - pybamm.StateVector). The former are put in `constant_symbols`, the latter in - `variable_symbols` - - Note that it is important that the arguments `constant_symbols` and - `variable_symbols` be and *ordered* dict, since the final ordering of the code lines - are important for the calculations. A dict is specified rather than a list so that - identical subtrees (which give identical id's) are not recalculated in the code - - Parameters - ---------- - symbol : :class:`pybamm.Symbol` - The symbol or expression tree to convert - - constant_symbol : collections.OrderedDict - The output dictionary of constant symbol ids to lines of code - - variable_symbol : collections.OrderedDict - The output dictionary of variable (with y or t) symbol ids to lines of code - - variable_symbol_sizes : collections.OrderedDict - The output dictionary of variable (with y or t) symbol ids to size of that - variable, for caching - - """ - # ignore broadcasts for now - if isinstance(symbol, pybamm.Broadcast): - symbol = symbol.child - if is_constant_and_can_evaluate(symbol): - value = symbol.evaluate() - if not isinstance(value, numbers.Number): - if scipy.sparse.issparse(value): - # Create Julia SparseArray - row, col, data = scipy.sparse.find(value) - m, n = value.shape - # Set print options large enough to avoid ellipsis - # at least as big is len(row) = len(col) = len(data) - np.set_printoptions( - threshold=max(np.get_printoptions()["threshold"], len(row) + 10) - ) - # increase precision for printing - np.set_printoptions(precision=20) - # add 1 to correct for 1-indexing in Julia - # use array2string so that commas are included - constant_symbols[symbol.id] = "sparse({}, {}, {}, {}, {})".format( - np.array2string(row + 1, separator=","), - np.array2string(col + 1, separator=","), - np.array2string(data, separator=","), - m, - n, - ) - elif value.shape == (1, 1): - # Extract value if array has only one entry - constant_symbols[symbol.id] = value[0, 0] - variable_symbol_sizes[symbol.id] = 1 - elif value.shape[1] == 1: - # Set print options large enough to avoid ellipsis - # at least as big as len(row) = len(col) = len(data) - np.set_printoptions( - threshold=max( - np.get_printoptions()["threshold"], value.shape[0] + 10 - ) - ) - # Flatten a 1D array - constant_symbols[symbol.id] = np.array2string( - value.flatten(), separator="," - ) - variable_symbol_sizes[symbol.id] = symbol.shape[0] - else: - constant_symbols[symbol.id] = value - # No need to save the size as it will not need to be used - return - - # process children recursively - for child in symbol.children: - find_symbols(child, constant_symbols, variable_symbols, variable_symbol_sizes) - - # calculate the variable names that will hold the result of calculating the - # children variables - children_vars = [] - for child in symbol.children: - if isinstance(child, pybamm.Broadcast): - child = child.child - if is_constant_and_can_evaluate(child): - child_eval = child.evaluate() - if isinstance(child_eval, numbers.Number): - children_vars.append(str(child_eval)) - else: - children_vars.append(id_to_julia_variable(child.id, True)) - else: - children_vars.append(id_to_julia_variable(child.id, False)) - - if isinstance(symbol, pybamm.BinaryOperator): - # Multiplication and Division need special handling for scipy sparse matrices - # TODO: we can pass through a dummy y and t to get the type and then hardcode - # the right line, avoiding these checks - if isinstance(symbol, pybamm.MatrixMultiplication): - symbol_str = "{0} @ {1}".format(children_vars[0], children_vars[1]) - elif isinstance(symbol, pybamm.Inner): - symbol_str = "{0} * {1}".format(children_vars[0], children_vars[1]) - elif isinstance(symbol, pybamm.Minimum): - symbol_str = "min({},{})".format(children_vars[0], children_vars[1]) - elif isinstance(symbol, pybamm.Maximum): - symbol_str = "max({},{})".format(children_vars[0], children_vars[1]) - elif isinstance(symbol, pybamm.Power): - # julia uses ^ instead of ** for power - # include dot for elementwise operations - symbol_str = children_vars[0] + " ^ " + children_vars[1] - else: - # all other operations use the same symbol - symbol_str = children_vars[0] + " " + symbol.name + " " + children_vars[1] - - elif isinstance(symbol, pybamm.UnaryOperator): - # Index has a different syntax than other univariate operations - if isinstance(symbol, pybamm.Index): - # Because of how julia indexing works, add 1 to the start, but not to the - # stop - symbol_str = "{}[{}:{}]".format( - children_vars[0], symbol.slice.start + 1, symbol.slice.stop - ) - elif isinstance(symbol, pybamm.Gradient): - symbol_str = "grad_{}({})".format(tuple(symbol.domain), children_vars[0]) - elif isinstance(symbol, pybamm.Divergence): - symbol_str = "div_{}({})".format(tuple(symbol.domain), children_vars[0]) - elif isinstance(symbol, pybamm.Broadcast): - # ignore broadcasts for now - symbol_str = children_vars[0] - elif isinstance(symbol, pybamm.BoundaryValue): - symbol_str = "boundary_value_{}({})".format(symbol.side, children_vars[0]) - else: - symbol_str = symbol.name + children_vars[0] - - elif isinstance(symbol, pybamm.Function): - # write functions directly - symbol_str = "{}({})".format(symbol.julia_name, ", ".join(children_vars)) - - elif isinstance(symbol, (pybamm.Variable, pybamm.ConcatenationVariable)): - # No need to do anything if a Variable is found - return - - elif isinstance(symbol, pybamm.Concatenation): - - # don't bother to concatenate if there is only a single child - if isinstance(symbol, (pybamm.NumpyConcatenation, pybamm.SparseStack)): - if len(children_vars) == 1: - symbol_str = children_vars[0] - else: - # return a list of the children variables, which will be converted to a - # line by line assignment - # return this as a string so that other functionality still works - # also save sizes - symbol_str = "[" - for child in children_vars: - child_id = child[6:].replace("m", "-") - size = variable_symbol_sizes[int(child_id)] - symbol_str += "{}::{}, ".format(size, child) - symbol_str = symbol_str[:-2] + "]" - - # DomainConcatenation specifies a particular ordering for the concatenation, - # which we must follow - elif isinstance(symbol, pybamm.DomainConcatenation): - if symbol.secondary_dimensions_npts == 1: - all_child_vectors = children_vars - all_child_sizes = [ - variable_symbol_sizes[int(child[6:].replace("m", "-"))] - for child in children_vars - ] - else: - slice_starts = [] - all_child_vectors = [] - all_child_sizes = [] - for i in range(symbol.secondary_dimensions_npts): - child_vectors = [] - child_sizes = [] - for child_var, slices in zip( - children_vars, symbol._children_slices - ): - for child_dom, child_slice in slices.items(): - slice_starts.append(symbol._slices[child_dom][i].start) - # add 1 to slice start to account for julia indexing - child_vectors.append( - "@view {}[{}:{}]".format( - child_var, - child_slice[i].start + 1, - child_slice[i].stop, - ) - ) - child_sizes.append( - child_slice[i].stop - child_slice[i].start - ) - all_child_vectors.extend( - [v for _, v in sorted(zip(slice_starts, child_vectors))] - ) - all_child_sizes.extend( - [v for _, v in sorted(zip(slice_starts, child_sizes))] - ) - if len(children_vars) > 1 or symbol.secondary_dimensions_npts > 1: - # return a list of the children variables, which will be converted to a - # line by line assignment - # return this as a string so that other functionality still works - # also save sizes - symbol_str = "[" - for child, size in zip(all_child_vectors, all_child_sizes): - symbol_str += "{}::{}, ".format(size, child) - symbol_str = symbol_str[:-2] + "]" - else: - raise NotImplementedError - - else: - # A regular Concatenation for the MTK model - # We will define the concatenation function separately - symbol_str = "concatenation(" + ", ".join(children_vars) + ")" - - # Note: we assume that y is being passed as a column vector - elif isinstance(symbol, pybamm.StateVectorBase): - if isinstance(symbol, pybamm.StateVector): - name = "@view y" - elif isinstance(symbol, pybamm.StateVectorDot): - name = "@view dy" - indices = np.argwhere(symbol.evaluation_array).reshape(-1).astype(np.int32) - # add 1 since julia uses 1-indexing - indices += 1 - consecutive = np.all(indices[1:] - indices[:-1] == 1) - if len(indices) == 1: - symbol_str = "{}[{}]".format(name, indices[0]) - elif consecutive: - # julia does include the final value - symbol_str = "{}[{}:{}]".format(name, indices[0], indices[-1]) - else: - indices_array = pybamm.Array(indices) - # Save the indices as constant by printing to a string - # Set print options large enough to avoid ellipsis - # at least as big as len(row) = len(col) = len(data) - np.set_printoptions( - threshold=max(np.get_printoptions()["threshold"], indices.shape[0] + 10) - ) - constant_symbols[indices_array.id] = np.array2string(indices, separator=",") - index_name = id_to_julia_variable(indices_array.id, True) - symbol_str = "{}[{}]".format(name, index_name) - - elif isinstance(symbol, pybamm.Time): - symbol_str = "t" - - elif isinstance(symbol, pybamm.InputParameter): - symbol_str = "inputs['{}']".format(symbol.name) - - elif isinstance(symbol, pybamm.SpatialVariable): - symbol_str = symbol.name.replace("_", "") - - elif isinstance(symbol, pybamm.FunctionParameter): - symbol_str = "{}({})".format(symbol.name, ", ".join(children_vars)) - - else: - raise NotImplementedError( - "Conversion to Julia not implemented for a symbol of type '{}'".format( - type(symbol) - ) - ) - - variable_symbols[symbol.id] = symbol_str - - # Save the size of the symbol - try: - if symbol.shape == (): - variable_symbol_sizes[symbol.id] = 1 - elif symbol.shape[1] == 1: - variable_symbol_sizes[symbol.id] = symbol.shape[0] - else: - raise ValueError("expected scalar or column vector") - except NotImplementedError: - pass - - -def to_julia(symbol): - """ - This function converts an expression tree into a dict of constant input values, and - valid julia code that acts like the tree's :func:`pybamm.Symbol.evaluate` function - - Parameters - ---------- - symbol : :class:`pybamm.Symbol` - The symbol to convert to julia code - - Returns - ------- - constant_values : collections.OrderedDict - dict mapping node id to a constant value. Represents all the constant nodes in - the expression tree - str - valid julia code that will evaluate all the variable nodes in the tree. - - """ - - constant_values = OrderedDict() - variable_symbols = OrderedDict() - variable_symbol_sizes = OrderedDict() - find_symbols(symbol, constant_values, variable_symbols, variable_symbol_sizes) - - return constant_values, variable_symbols, variable_symbol_sizes - - -def get_julia_function(symbol, funcname="f", input_parameter_order=None, len_rhs=None): - """ - Converts a pybamm expression tree into pure julia code that will calculate the - result of calling `evaluate(t, y)` on the given expression tree. - - Parameters - ---------- - symbol : :class:`pybamm.Symbol` - The symbol to convert to julia code - funcname : str, optional - The name to give to the function (default 'f') - input_parameter_order : list, optional - List of input parameter names. Defines the order in which the input parameters - are extracted from 'p' in the julia function that is created - len_rhs : int, optional - The number of ODEs in the discretized differential equations. This also - determines whether the model has any algebraic equations: if None (default), - the model is assume to have no algebraic parts and ``julia_str`` is compatible - with an ODE solver. If not None, ``julia_str`` is compatible with a DAE solver - - Returns - ------- - julia_str : str - String of julia code, to be evaluated by ``julia.Main.eval`` - - """ - if len_rhs is None: - typ = "ode" - else: - typ = "dae" - # Take away dy from the differential states - # we will return a function of the form - # out[] = .. - dy[] for the differential states - # out[] = .. for the algebraic states - symbol_minus_dy = [] - end = 0 - for child in symbol.orphans: - start = end - end += child.size - if end <= len_rhs: - symbol_minus_dy.append(child - pybamm.StateVectorDot(slice(start, end))) - else: - symbol_minus_dy.append(child) - symbol = pybamm.numpy_concatenation(*symbol_minus_dy) - constants, var_symbols, var_symbol_sizes = to_julia(symbol) - - # extract constants in generated function - const_and_cache_str = "cs = (\n" - for symbol_id, const_value in constants.items(): - const_name = id_to_julia_variable(symbol_id, True) - const_and_cache_str += " {} = {},\n".format(const_name, const_value) - - # Pop (get and remove) items from the dictionary of symbols one by one - # If they are simple operations (@view, +, -, *, /), replace all future - # occurences instead of assigning them. This "inlining" speeds up the computation - inlineable_symbols = ["@view", "+", "-", "*", "/"] - var_str = "" - input_parameters = {} - while var_symbols: - var_symbol_id, symbol_line = var_symbols.popitem(last=False) - julia_var = id_to_julia_variable(var_symbol_id, False) - # Look for lists in the variable symbols. These correpsond to concatenations, so - # assign the children to the right parts of the vector - if symbol_line[0] == "[" and symbol_line[-1] == "]": - # convert to actual list - symbol_line = symbol_line[1:-1].split(", ") - start = 0 - for child_size_and_name in symbol_line: - child_size, child_name = child_size_and_name.split("::") - end = start + int(child_size) - # add 1 to start to account for julia 1-indexing - var_str += "@. {}[{}:{}] = {}\n".format( - julia_var, start + 1, end, child_name - ) - start = end - # use mul! for matrix multiplications (requires LinearAlgebra library) - elif " @ " in symbol_line: - symbol_line = symbol_line.replace(" @ ", ", ") - var_str += "mul!({}, {})\n".format(julia_var, symbol_line) - # find input parameters - elif symbol_line.startswith("inputs"): - input_parameters[julia_var] = symbol_line[8:-2] - else: - # don't replace the matrix multiplication cases (which will be - # turned into a mul!), since it is faster to assign to a cache array - # first in that case, unless it is a @view in which case we don't - # need to cache - any_matmuls = any( - julia_var in next_symbol_line - and ( - (" @ " in next_symbol_line or "mul!" in next_symbol_line) - and not symbol_line.startswith("@view") - ) - for next_symbol_line in var_symbols.values() - ) - # inline operation if it can be inlined - if ( - any(x in symbol_line for x in inlineable_symbols) or symbol_line == "t" - ) and not any_matmuls: - found_replacement = False - # replace all other occurrences of the variable - # in the dictionary with the symbol line - for next_var_id, next_symbol_line in var_symbols.items(): - if julia_var in next_symbol_line: - if symbol_line == "t": - # no brackets needed - var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, symbol_line - ) - else: - # add brackets so that the order of operations is maintained - var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, "({})".format(symbol_line) - ) - found_replacement = True - if not found_replacement: - var_str += "@. {} = {}\n".format(julia_var, symbol_line) - - # otherwise assign - else: - var_str += "@. {} = {}\n".format(julia_var, symbol_line) - # Replace all input parameter names - for input_parameter_id, input_parameter_name in input_parameters.items(): - var_str = var_str.replace(input_parameter_id, input_parameter_name) - # add "cs." to constant and cache names - var_str = var_str.replace("const", "cs.const") - var_str = var_str.replace("cache", "cs.cache") - # indent code - var_str = " " + var_str - var_str = var_str.replace("\n", "\n ") - - # add the cache variables to the cache NamedTuple - for var_symbol_id, var_symbol_size in var_symbol_sizes.items(): - # Skip caching the result variable since this is provided as dy - # Also skip caching the result variable if it doesn't appear in the var_str, - # since it has been inlined and does not need to be assigned to - # make sure that the variable appears at the start of a line in var_str - julia_var = id_to_julia_variable(var_symbol_id, False) - if ( - var_symbol_id != symbol.id - and "mul!(cs." + julia_var in var_str - or "@. cs." + julia_var in var_str - ): - cache_name = id_to_julia_variable(var_symbol_id, False) - const_and_cache_str += " {} = zeros({}),\n".format( - cache_name, var_symbol_size - ) - - # close the constants and cache string - const_and_cache_str += ")\n" - - # remove the constant and cache sring if it is empty - const_and_cache_str = const_and_cache_str.replace("cs = (\n)\n", "") - - # line that extracts the input parameters in the right order - if input_parameter_order is None: - input_parameter_extraction = "" - elif len(input_parameter_order) == 1: - # extract the single parameter - input_parameter_extraction = " " + input_parameter_order[0] + " = p[1]\n" - else: - # extract all parameters - input_parameter_extraction = " " + ", ".join(input_parameter_order) + " = p\n" - - # add function def and sparse arrays to first line - imports = "begin\nusing SparseArrays, LinearAlgebra\n\n" - if typ == "ode": - function_def = f"\nfunction {funcname}_with_consts!(dy, y, p, t)\n" - elif typ == "dae": - function_def = f"\nfunction {funcname}_with_consts!(out, dy, y, p, t)\n" - julia_str = ( - imports - + const_and_cache_str - + function_def - + input_parameter_extraction - + var_str - ) - - # calculate the final variable that will output the result - result_var = id_to_julia_variable(symbol.id, symbol.is_constant()) - if symbol.is_constant(): - result_value = symbol.evaluate() - - # assign the return variable - if symbol.is_constant(): - if isinstance(result_value, numbers.Number): - julia_str = julia_str + "\n dy .= " + str(result_value) + "\n" - else: - julia_str = julia_str + "\n dy .= cs." + result_var + "\n" - else: - if typ == "ode": - julia_str = julia_str.replace("cs." + result_var, "dy") - elif typ == "dae": - julia_str = julia_str.replace("cs." + result_var, "out") - - # close the function, with a 'nothing' to avoid allocations - julia_str += "nothing\nend\n\n" - julia_str = julia_str.replace("\n \n", "\n") - - if const_and_cache_str == "": - julia_str += f"{funcname}! = {funcname}_with_consts!\n" - else: - # Use a let block for the cached variables - # open the let block - julia_str = julia_str.replace("cs = (", f"{funcname}! = let cs = (") - # close the let block - julia_str += "end\n" - - # close the "begin" - julia_str += "end" - - return julia_str - - -def convert_var_and_eqn_to_str(var, eqn, all_constants_str, all_variables_str, typ): - """ - Converts a variable and its equation to a julia string - - Parameters - ---------- - var : :class:`pybamm.Symbol` - The variable (key in the dictionary of rhs/algebraic/initial conditions) - eqn : :class:`pybamm.Symbol` - The equation (value in the dictionary of rhs/algebraic/initial conditions) - all_constants_str : str - String containing all the constants defined so far - all_variables_str : str - String containing all the variables defined so far - typ : str - The type of the variable/equation pair being converted ("equation", "initial - condition", or "boundary condition") - - Returns - ------- - all_constants_str : str - Updated string of all constants - all_variables_str : str - Updated string of all variables - eqn_str : str - The string describing the final equation result, perhaps as a function of some - variables and/or constants in all_constants_str and all_variables_str - - """ - if isinstance(eqn, pybamm.Broadcast): - # ignore broadcasts for now - eqn = eqn.child - - constants, var_symbols = to_julia(eqn)[:2] - - # var_str = "" - # for symbol_id, symbol_line in var_symbols.items(): - # var_str += f"{id_to_julia_variable(symbol_id)} = {symbol_line}\n" - # Pop (get and remove) items from the dictionary of symbols one by one - # If they are simple operations (+, -, *, /), replace all future - # occurences instead of assigning them. - inlineable_symbols = [" + ", " - ", " * ", " / "] - var_str = "" - while var_symbols: - var_symbol_id, symbol_line = var_symbols.popitem(last=False) - julia_var = id_to_julia_variable(var_symbol_id, False) - # inline operation if it can be inlined - if "concatenation" not in symbol_line: - found_replacement = False - # replace all other occurrences of the variable - # in the dictionary with the symbol line - for next_var_id, next_symbol_line in var_symbols.items(): - if ( - symbol_line == "t" - or " " not in symbol_line - or symbol_line.startswith("grad") - or not any(x in next_symbol_line for x in inlineable_symbols) - ): - # cases that don't need brackets - var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, symbol_line - ) - elif next_symbol_line.startswith("concatenation"): - if len(symbol_line) < 20: - var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, symbol_line - ) - else: - var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, f"\n {symbol_line}\n" - ) - else: - # add brackets so that the order of operations is maintained - var_symbols[next_var_id] = next_symbol_line.replace( - julia_var, "({})".format(symbol_line) - ) - found_replacement = True - if not found_replacement: - var_str += "{} = {}\n".format(julia_var, symbol_line) - - # otherwise assign - else: - var_str += "{} = {}\n".format(julia_var, symbol_line) - - # extract constants in generated function - for eqn_id, const_value in constants.items(): - const_name = id_to_julia_variable(eqn_id, True) - all_constants_str += "{} = {}\n".format(const_name, const_value) - # TODO: avoid repeated constants definitions - - # If we have created a concatenation we need to define it - # Hardcoded to the negative electrode, separator, positive electrode case for now - if "concatenation" in var_str and "function concatenation" not in all_variables_str: - concatenation_def = ( - "\nfunction concatenation(n, s, p)\n" - + " # A concatenation in the electrolyte domain\n" - + " IfElse.ifelse(\n" - + " x < neg_width, n, IfElse.ifelse(\n" - + " x < neg_plus_sep_width, s, p\n" - + " )\n" - + " )\n" - + "end\n" - ) - else: - concatenation_def = "" - - # Define the FunctionParameter objects that have not yet been defined - function_defs = "" - for x in eqn.pre_order(): - if ( - isinstance(x, pybamm.FunctionParameter) - and f"function {x.name}" not in all_variables_str - and typ == "equation" - ): - function_def = ( - f"\nfunction {x.name}(" - + ", ".join(x.arg_names) - + ")\n" - + " {}\n".format(str(x.callable).replace("**", "^")) - + "end\n" - ) - function_defs += function_def - - if concatenation_def + function_defs != "": - function_defs += "\n" - - var_str = concatenation_def + function_defs + var_str - - # add a comment labeling the equation, and the equation itself - if var_str == "": - all_variables_str += "" - else: - all_variables_str += f"# '{var.name}' {typ}\n" + var_str + "\n" - - # calculate the final variable that will output the result - result_var = id_to_julia_variable(eqn.id, eqn.is_constant()) - if is_constant_and_can_evaluate(eqn): - result_value = eqn.evaluate() - else: - result_value = None - - # define the variable that goes into the equation - if eqn.is_constant() and isinstance(result_value, numbers.Number): - eqn_str = str(result_value) - else: - eqn_str = result_var - - return all_constants_str, all_variables_str, eqn_str - - -def get_julia_mtk_model(model, geometry=None, tspan=None): - """ - Converts a pybamm model into a Julia ModelingToolkit model - - Parameters - ---------- - model : :class:`pybamm.BaseModel` - The model to be converted - geometry : dict, optional - Dictionary defining the geometry. Must be provided if the model is a PDE model - tspan : array-like, optional - Time for which to solve the model. Must be provided if the model is a PDE model - - Returns - ------- - mtk_str : str - String of julia code representing a model in MTK, - to be evaluated by ``julia.Main.eval`` - """ - # Extract variables - variables = {**model.rhs, **model.algebraic}.keys() - variable_id_to_short_name = {} - for i, var in enumerate(variables): - if var.short_name is not None: - short_name = var.short_name - else: - short_name = f"u{i+1}" - variable_id_to_short_name[var.id] = short_name - if isinstance(var, pybamm.ConcatenationVariable): - for child in var.children: - variable_id_to_short_name[child.id] = short_name - - # Extract domain and auxiliary domains - all_domains = set([tuple(var.domain) for var in variables if var.domain != []]) - for aux_dim in ["secondary", "tertiary"]: - all_domains.update( - set( - [ - tuple(var.auxiliary_domains[aux_dim]) - for var in variables - if aux_dim in var.auxiliary_domains - and var.auxiliary_domains[aux_dim] != [] - ] - ) - ) - is_pde = bool(all_domains) - - # Check geometry and tspan have been provided if a PDE - if is_pde: - if geometry is None: - raise ValueError("must provide geometry if the model is a PDE model") - if tspan is None: - raise ValueError("must provide tspan if the model is a PDE model") - - # Read domain names - domain_name_to_symbol = {} - long_domain_symbol_to_short = {} - for dom in all_domains: - # Read domain name from geometry - domain_symbol = list(geometry[dom[0]].keys())[0].name.replace("_", "") - if len(dom) > 1: - domain_symbol = domain_symbol[0] - # For multi-domain variables keep only the first letter of the domain - domain_name_to_symbol[tuple(dom)] = domain_symbol - # Record which domain symbols we shortened - for d in dom: - long = list(geometry[d].keys())[0].name.replace("_", "") - long_domain_symbol_to_short[long] = domain_symbol - else: - # Otherwise keep the whole domain - domain_name_to_symbol[tuple(dom)] = domain_symbol - - # Read coordinate systems - domain_name_to_coord_sys = { - tuple(dom): list(geometry[dom[0]].keys())[0].coord_sys for dom in all_domains - } - - # Read domain limits - domain_name_to_limits = {} - for dom in all_domains: - limits = list(geometry[dom[0]].values())[0].values() - if len(limits) > 1: - lower_limit, _ = list(geometry[dom[0]].values())[0].values() - _, upper_limit = list(geometry[dom[-1]].values())[0].values() - domain_name_to_limits[tuple(dom)] = ( - lower_limit.evaluate(), - upper_limit.evaluate(), - ) - else: - # Don't record limits for variables that have "limits" of length 1 i.e. - # a zero-dimensional domain - domain_name_to_limits[tuple(dom)] = None - - # Define independent variables for each variable - var_to_ind_vars = {} - var_to_ind_vars_left_boundary = {} - var_to_ind_vars_right_boundary = {} - for var in variables: - if var.domain == []: - var_to_ind_vars[var.id] = "(t)" - else: - # all independent variables e.g. (t, x) or (t, rn, xn) - domain_symbols = ", ".join( - domain_name_to_symbol[tuple(dom)] - for dom in var.domains.values() - if domain_name_to_limits[tuple(dom)] is not None - ) - var_to_ind_vars[var.id] = f"(t, {domain_symbols})" - if isinstance(var, pybamm.ConcatenationVariable): - for child in var.children: - var_to_ind_vars[child.id] = f"(t, {domain_symbols})" - aux_domain_symbols = ", ".join( - domain_name_to_symbol[tuple(dom)] - for dom in var.auxiliary_domains.values() - if domain_name_to_limits[tuple(dom)] is not None - ) - if aux_domain_symbols != "": - aux_domain_symbols = ", " + aux_domain_symbols - - limits = domain_name_to_limits[tuple(var.domain)] - # left bc e.g. (t, 0) or (t, 0, xn) - var_to_ind_vars_left_boundary[ - var.id - ] = f"(t, {limits[0]}{aux_domain_symbols})" - # right bc e.g. (t, 1) or (t, 1, xn) - var_to_ind_vars_right_boundary[ - var.id - ] = f"(t, {limits[1]}{aux_domain_symbols})" - - mtk_str = "begin\n" - # Define parameters (including independent variables) - # Makes a line of the form '@parameters t x1 x2 x3 a b c d' - ind_vars = ["t"] + [ - sym - for dom, sym in domain_name_to_symbol.items() - if domain_name_to_limits[dom] is not None - ] - for domain_name, domain_symbol in domain_name_to_symbol.items(): - if domain_name_to_limits[domain_name] is not None: - mtk_str += f"# {domain_name} -> {domain_symbol}\n" - mtk_str += "@parameters " + " ".join(ind_vars) - for param in model.input_parameters: - mtk_str += f" {param.name}" - mtk_str += "\n" - - # Add a comment with the variable names - for var in variables: - mtk_str += f"# '{var.name}' -> {variable_id_to_short_name[var.id]}\n" - # Makes a line of the form '@variables u1(t) u2(t)' - dep_vars = [] - mtk_str += "@variables" - for var in variables: - mtk_str += f" {variable_id_to_short_name[var.id]}(..)" - dep_var = variable_id_to_short_name[var.id] + var_to_ind_vars[var.id] - dep_vars.append(dep_var) - mtk_str += "\n" - - # Define derivatives - for domain_symbol in ind_vars: - mtk_str += f"D{domain_symbol} = Differential({domain_symbol})\n" - mtk_str += "\n" - - # Define equations - all_eqns_str = "" - all_constants_str = "" - all_julia_str = "" - for var, eqn in {**model.rhs, **model.algebraic}.items(): - all_constants_str, all_julia_str, eqn_str = convert_var_and_eqn_to_str( - var, eqn, all_constants_str, all_julia_str, "equation" - ) - - if var in model.rhs: - all_eqns_str += ( - f" Dt({variable_id_to_short_name[var.id]}{var_to_ind_vars[var.id]}) " - + f"~ {eqn_str},\n" - ) - elif var in model.algebraic: - all_eqns_str += f" 0 ~ {eqn_str},\n" - - # Replace any long domain symbols with the short version - # e.g. "xn" gets replaced with "x" - for long, short in long_domain_symbol_to_short.items(): - # we need to add a space to avoid accidentally replacing 'exp' with 'ex' - all_julia_str = all_julia_str.replace(" " + long, " " + short) - - # Replace variables in the julia strings that correspond to pybamm variables with - # their julia equivalent - for var_id, julia_id in variable_id_to_short_name.items(): - # e.g. boundary_value_right(cache_123456789) gets replaced with u1(t, 1) - cache_var_id = id_to_julia_variable(var_id, False) - if f"boundary_value_right({cache_var_id})" in all_julia_str: - all_julia_str = all_julia_str.replace( - f"boundary_value_right({cache_var_id})", - julia_id + var_to_ind_vars_right_boundary[var_id], - ) - # e.g. cache_123456789 gets replaced with u1(t, x) - all_julia_str = all_julia_str.replace( - cache_var_id, julia_id + var_to_ind_vars[var_id] - ) - - # Replace independent variables (domain names) in julia strings with the - # corresponding symbol - for domain_name, domain_symbol in domain_name_to_symbol.items(): - all_julia_str = all_julia_str.replace( - f"grad_{domain_name}", f"D{domain_symbol}" - ) - # Different divergence depending on the coordinate system - coord_sys = domain_name_to_coord_sys[domain_name] - if coord_sys == "cartesian": - all_julia_str = all_julia_str.replace( - f"div_{domain_name}", f"D{domain_symbol}" - ) - elif coord_sys == "spherical polar": - all_julia_str = all_julia_str.replace( - f"div_{domain_name}(", - f"1 / {domain_symbol}^2 * D{domain_symbol}({domain_symbol}^2 * ", - ) - - # Replace the thicknesses in the concatenation with the actual thickness from the - # geometry - var = pybamm.standard_spatial_vars - x_n = geometry["negative electrode"][var.x_n]["max"].evaluate() - x_s = geometry["separator"][var.x_s]["max"].evaluate() - all_julia_str = all_julia_str.replace("neg_width", str(x_n)) - all_julia_str = all_julia_str.replace("neg_plus_sep_width", str(x_s)) - - # Replace parameters in the julia strings in the form "inputs[name]" - # with just "name" - for param in model.input_parameters: - # Replace 'var_id' with 'param.name' - all_julia_str = all_julia_str.replace( - id_to_julia_variable(param.id, False), param.name - ) - # Remove the line where the variable is re-defined - all_julia_str = all_julia_str.replace( - f"{param.name} = inputs['{param.name}']\n", "" - ) - - # Update the MTK string - mtk_str += all_constants_str + all_julia_str + "\n" + f"eqs = [\n{all_eqns_str}]\n" - - #################################################################################### - # Initial and boundary conditions - #################################################################################### - # Initial conditions - all_ic_bc_str = " # initial conditions\n" - all_ic_bc_constants_str = "" - all_ic_bc_julia_str = "" - for var, eqn in model.initial_conditions.items(): - ( - all_ic_bc_constants_str, - all_ic_bc_julia_str, - eqn_str, - ) = convert_var_and_eqn_to_str( - var, eqn, all_ic_bc_constants_str, all_ic_bc_julia_str, "initial condition" - ) - - if not is_pde: - all_ic_bc_str += ( - f" {variable_id_to_short_name[var.id]}(t) => {eqn_str},\n" - ) - else: - if var.domain == []: - doms = "" - else: - doms = ", " + domain_name_to_symbol[tuple(var.domain)] - - all_ic_bc_str += ( - f" {variable_id_to_short_name[var.id]}(0{doms}) ~ {eqn_str},\n" - ) - # Boundary conditions - if is_pde: - all_ic_bc_str += " # boundary conditions\n" - for var, eqn_side in model.boundary_conditions.items(): - if isinstance(var, (pybamm.Variable, pybamm.ConcatenationVariable)): - for side, (eqn, typ) in eqn_side.items(): - ( - all_ic_bc_constants_str, - all_ic_bc_julia_str, - eqn_str, - ) = convert_var_and_eqn_to_str( - var, - eqn, - all_ic_bc_constants_str, - all_ic_bc_julia_str, - "boundary condition", - ) - - if side == "left": - limit = var_to_ind_vars_left_boundary[var.id] - elif side == "right": - limit = var_to_ind_vars_right_boundary[var.id] - - bc = f"{variable_id_to_short_name[var.id]}{limit}" - if typ == "Dirichlet": - bc = bc - elif typ == "Neumann": - bc = f"D{domain_name_to_symbol[tuple(var.domain)]}({bc})" - all_ic_bc_str += f" {bc} ~ {eqn_str},\n" - - # Replace variables in the julia strings that correspond to pybamm variables with - # their julia equivalent - for var_id, julia_id in variable_id_to_short_name.items(): - # e.g. boundary_value_right(cache_123456789) gets replaced with u1(t, 1) - cache_var_id = id_to_julia_variable(var_id, False) - if f"boundary_value_right({cache_var_id})" in all_ic_bc_julia_str: - all_ic_bc_julia_str = all_ic_bc_julia_str.replace( - f"boundary_value_right({cache_var_id})", - julia_id + var_to_ind_vars_right_boundary[var_id], - ) - # e.g. cache_123456789 gets replaced with u1(t, x) - all_ic_bc_julia_str = all_ic_bc_julia_str.replace( - cache_var_id, julia_id + var_to_ind_vars[var_id] - ) - - #################################################################################### - - # Create ODESystem or PDESystem - if not is_pde: - mtk_str += "sys = ODESystem(eqs, t)\n\n" - mtk_str += ( - all_ic_bc_constants_str - + all_ic_bc_julia_str - + "\n" - + f"u0 = [\n{all_ic_bc_str}]\n" - ) - else: - # Initial and boundary conditions - mtk_str += ( - all_ic_bc_constants_str - + all_ic_bc_julia_str - + "\n" - + f"ics_bcs = [\n{all_ic_bc_str}]\n" - ) - - # Domains - mtk_str += "\n" - tpsan_str = ",".join( - map(lambda x: f"{x / model.timescale.evaluate():.3f}", tspan) - ) - mtk_str += f"t_domain = IntervalDomain({tpsan_str})\n" - domains = "domains = [\n t in t_domain,\n" - for domain, symbol in domain_name_to_symbol.items(): - limits = domain_name_to_limits[tuple(domain)] - if limits is not None: - mtk_str += f"{symbol}_domain = IntervalDomain{limits}\n" - domains += f" {symbol} in {symbol}_domain,\n" - domains += "]\n" - - mtk_str += "\n" - mtk_str += domains - - # Independent and dependent variables - mtk_str += "ind_vars = [{}]\n".format(", ".join(ind_vars)) - mtk_str += "dep_vars = [{}]\n\n".format(", ".join(dep_vars)) - - name = model.name.replace(" ", "_").replace("-", "_") - mtk_str += ( - name - + "_pde_system = PDESystem(eqs, ics_bcs, domains, ind_vars, dep_vars)\n\n" - ) - - # Need to add 'nothing' to the end of the mtk string to avoid errors in MTK v4 - # See https://github.com/SciML/diffeqpy/issues/82 - mtk_str += "nothing\nend\n" - - return mtk_str diff --git a/pybamm/expression_tree/parameter.py b/pybamm/expression_tree/parameter.py index 1121d31377..27ec0ada35 100644 --- a/pybamm/expression_tree/parameter.py +++ b/pybamm/expression_tree/parameter.py @@ -93,16 +93,16 @@ def __init__( # Use the inspect module to find the function's "short name" from the # Parameters module that called it - short_name = inspect.stack()[1][3] - if short_name.startswith("_"): - self.short_name = None + print_name = inspect.stack()[1][3] + if print_name.startswith("_"): + self.print_name = None else: - if short_name.endswith("_dimensional"): - self.short_name = short_name[: -len("_dimensional")] - elif short_name.endswith("_dim"): - self.short_name = short_name[: -len("_dim")] + if print_name.endswith("_dimensional"): + self.print_name = print_name[: -len("_dimensional")] + elif print_name.endswith("_dim"): + self.print_name = print_name[: -len("_dim")] else: - self.short_name = short_name + self.print_name = print_name @property def input_names(self): @@ -174,7 +174,7 @@ def diff(self, variable): def new_copy(self): """ See :meth:`pybamm.Symbol.new_copy()`. """ out = self._function_parameter_new_copy(self._input_names, self.orphans) - out.short_name = self.short_name + out.print_name = self.print_name return out def _function_parameter_new_copy(self, input_names, children): diff --git a/pybamm/expression_tree/variable.py b/pybamm/expression_tree/variable.py index b3b31c0b66..c38dd50c63 100644 --- a/pybamm/expression_tree/variable.py +++ b/pybamm/expression_tree/variable.py @@ -47,7 +47,7 @@ def __init__(self, name, domain=None, auxiliary_domains=None, bounds=None): + "Lower bound should be strictly less than upper bound." ) self.bounds = bounds - self.short_name = None + self.print_name = None def new_copy(self): """ See :meth:`pybamm.Symbol.new_copy()`. """ @@ -55,7 +55,7 @@ def new_copy(self): out = self.__class__( self.name, self.domain, self.auxiliary_domains, self.bounds ) - out.short_name = self.short_name + out.print_name = self.print_name return out def _evaluate_for_shape(self): diff --git a/pybamm/models/base_model.py b/pybamm/models/base_model.py index 26facdf3b3..36bd5b862e 100644 --- a/pybamm/models/base_model.py +++ b/pybamm/models/base_model.py @@ -928,67 +928,6 @@ def generate( C.add(variables_fn) C.generate() - def generate_julia_diffeq( - self, input_parameter_order=None, get_consistent_ics_solver=None - ): - """ - Generate a Julia representation of the model, ready to be solved by Julia's - DifferentialEquations library. - - Parameters - ---------- - input_parameter_order : list, optional - Order in which input parameters will be provided when solving the model - - Returns - ------- - eqn_str : str - The Julia-compatible equations for the model in string format, - to be evaluated by eval(Meta.parse(...)) - ics_str : str - The Julia-compatible initial conditions for the model in string format, - to be evaluated by eval(Meta.parse(...)) - """ - self.check_discretised_or_discretise_inplace_if_0D() - - name = self.name.replace(" ", "_") - - if self.algebraic == {}: - # ODE model: form dy[] = ... - eqn_str = pybamm.get_julia_function( - self.concatenated_rhs, - funcname=name, - input_parameter_order=input_parameter_order, - ) - else: - # DAE model: form out[] = ... - dy[] - eqn_str = pybamm.get_julia_function( - pybamm.numpy_concatenation( - self.concatenated_rhs, self.concatenated_algebraic - ), - funcname=name, - input_parameter_order=input_parameter_order, - len_rhs=self.concatenated_rhs.size, - ) - - if get_consistent_ics_solver is None or self.algebraic == {}: - ics = self.concatenated_initial_conditions - else: - get_consistent_ics_solver.set_up(self) - get_consistent_ics_solver._set_initial_conditions(self, {}, False) - ics = pybamm.Vector(self.y0.full()) - - ics_str = pybamm.get_julia_function( - ics, - funcname=name + "_u0", - input_parameter_order=input_parameter_order, - ) - # Change the string to a form for u0 - ics_str = ics_str.replace("(dy, y, p, t)", "(u0, p)") - ics_str = ics_str.replace("dy", "u0") - - return eqn_str, ics_str - @property def default_parameter_values(self): return pybamm.ParameterValues({}) diff --git a/pybamm/models/standard_variables.py b/pybamm/models/standard_variables.py index d436317464..e862e2dc57 100644 --- a/pybamm/models/standard_variables.py +++ b/pybamm/models/standard_variables.py @@ -321,7 +321,7 @@ def __init__(self): ) def __setattr__(self, name, value): - value.short_name = name + value.print_name = name super().__setattr__(name, value) diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py index f2ff69f103..23f244fb13 100644 --- a/pybamm/parameters/parameter_values.py +++ b/pybamm/parameters/parameter_values.py @@ -684,12 +684,12 @@ def _process_symbol(self, symbol): and not isinstance( self.process_symbol(function), (pybamm.Scalar, pybamm.Broadcast) ) - and symbol.short_name is not None + and symbol.print_name is not None and symbol.diff_variable is None ): # Special trick for printing in Julia ModelingToolkit format out = pybamm.FunctionParameter( - symbol.short_name, dict(zip(symbol.input_names, new_children)) + symbol.print_name, dict(zip(symbol.input_names, new_children)) ) out.arg_names = inspect.getfullargspec(function_name)[0] diff --git a/pybamm/util.py b/pybamm/util.py index 0dcb5e19cd..27ff4a88cc 100644 --- a/pybamm/util.py +++ b/pybamm/util.py @@ -321,18 +321,3 @@ def get_parameters_filepath(path): return path else: return os.path.join(pybamm.__path__[0], path) - - -def have_julia(): - """ - Checks whether the Julia programming language has been installed - """ - import subprocess - - # Try reading the julia version quietly to see whether julia is installed - FNULL = open(os.devnull, "w") - try: - subprocess.call(["julia", "--version"], stdout=FNULL, stderr=subprocess.STDOUT) - return True - except subprocess.CalledProcessError: - return False diff --git a/requirements.txt b/requirements.txt index 5150a3d95e..711d81b4f5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,6 @@ scikit-fem >= 0.2.0 casadi >= 3.5.0 jax==0.1.75 jaxlib==0.1.52 -julia>=0.5.6 jupyter # For example notebooks pybtex sympy==1.8 diff --git a/setup.py b/setup.py index 57151dce32..fe9d385dfe 100644 --- a/setup.py +++ b/setup.py @@ -196,8 +196,6 @@ def compile_KLU(): "scikit-fem>=0.2.0", "casadi>=3.5.0", *jax_dependencies, - "julia>=0.5.6", - # Can be installed even if julia is not installed "jupyter", # For example notebooks "pybtex", "sympy==1.8", diff --git a/test.py b/test.py deleted file mode 100644 index b68745fe53..0000000000 --- a/test.py +++ /dev/null @@ -1,41 +0,0 @@ -import pybamm - -model = pybamm.lithium_ion.SPM(name="SPM") -# model = pybamm.BaseModel(name="DFN_no_r") -# var1 = pybamm.Variable("var1") -# var2 = pybamm.Variable("var2") -# model.rhs = {var1: 0.1 * var1} -# model.algebraic = {var2: 2 * var1 - var2} -# model.initial_conditions = {var1: 1, var2: 2} -parameter_values = model.default_parameter_values -# parameter_values["Electrolyte diffusivity [m2.s-1]"] = 1e-10 -# parameter_values["Electrolyte conductivity [S.m-1]"] = 1 -# parameter_values["Negative electrode exchange-current density [A.m-2]"] = 1e-6 -# parameter_values["Positive electrode exchange-current density [A.m-2]"] = 1e-6 -# parameter_values["Negative electrode OCP [V]"] = 0.5 -# parameter_values["Positive electrode OCP [V]"] = 4 -# parameter_values._replace_callable_function_parameters = False - -var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} - -sim = pybamm.Simulation(model, var_pts=var_pts, parameter_values=parameter_values) -sim.set_parameters() -mtk_str = pybamm.get_julia_mtk_model(sim.model, geometry=sim.geometry, tspan=(0, 3600)) - - -print(mtk_str) -# list(sim.model.rhs.values())[3].render() - -# sim.build() - -# rhs_str, u0_str = sim.built_model.generate_julia_diffeq( -# get_consistent_ics_solver=pybamm.CasadiSolver() -# ) -# print(rhs_str) -# print(u0_str) - -# V_str = pybamm.get_julia_function( -# sim.built_model.variables["Terminal voltage [V]"], funcname="V" -# ) -# print(V_str) diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py deleted file mode 100644 index 1955439684..0000000000 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_julia.py +++ /dev/null @@ -1,448 +0,0 @@ -# -# Test for the evaluate-to-Julia functions -# -import pybamm - -from tests import get_mesh_for_testing, get_1p1d_mesh_for_testing -import unittest -import numpy as np -import scipy.sparse -from platform import system - -have_julia = pybamm.have_julia() -if have_julia and system() != "Windows": - from julia import Main - - -@unittest.skipIf(not have_julia, "Julia not installed") -@unittest.skipIf(system() == "Windows", "Julia not supported on windows") -class TestEvaluate(unittest.TestCase): - def test_evaluator_julia(self): - a = pybamm.StateVector(slice(0, 1)) - b = pybamm.StateVector(slice(1, 2)) - - y_tests = [np.array([[2], [3]]), np.array([[1], [3]])] - t_tests = [1, 2] - - # test a * b - expr = a * b - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.y = np.array([2.0, 3.0]) - Main.eval("f!(dy,y,0,0)") - self.assertEqual(Main.dy, 6) - Main.dy = [0.0] - Main.y = np.array([1.0, 3.0]) - Main.eval("f!(dy,y,0,0)") - self.assertEqual(Main.dy, 3) - - # test function(a*b) - expr = pybamm.cos(a * b) - evaluator_str = pybamm.get_julia_function(expr, funcname="g") - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.y = np.array([2.0, 3.0]) - Main.eval("g!(dy,y,0,0)") - self.assertAlmostEqual(Main.dy[0], np.cos(6), places=15) - - # test a constant expression - expr = pybamm.Scalar(2) * pybamm.Scalar(3) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.eval("f!(dy,y,0,0)") - self.assertEqual(Main.dy, 6) - - expr = pybamm.Scalar(2) * pybamm.Vector([1, 2, 3]) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] * 3 - Main.eval("f!(dy,y,0,0)") - np.testing.assert_array_equal(Main.dy, [2, 4, 6]) - - # test a larger expression - expr = a * b + b + a ** 2 / b + 2 * a + b / 2 + 4 - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - self.assertEqual(Main.dy, expr.evaluate(t=None, y=y)) - - # test something with time - expr = a * pybamm.t - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for t, y in zip(t_tests, y_tests): - Main.dy = [0.0] - Main.y = y - Main.t = t - Main.eval("f!(dy,y,0,t)") - self.assertEqual(Main.dy, expr.evaluate(t=t, y=y)) - - # test something with a matrix multiplication - A = pybamm.Matrix([[1, 2], [3, 4]]) - expr = A @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - # test something with a heaviside - a = pybamm.Vector([1, 2]) - expr = a <= pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - # test something with a minimum or maximum - a = pybamm.Vector([1, 2]) - for expr in [ - pybamm.minimum(a, pybamm.StateVector(slice(0, 2))), - pybamm.maximum(a, pybamm.StateVector(slice(0, 2))), - ]: - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - # test something with an index - expr = pybamm.Index(A @ pybamm.StateVector(slice(0, 2)), 0) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - # test something with a sparse matrix multiplication - A = pybamm.Matrix([[1, 2], [3, 4]]) - B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - C = pybamm.Matrix(scipy.sparse.coo_matrix(np.array([[1, 0], [0, 4]]))) - expr = A @ B @ C @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - expr = B @ pybamm.StateVector(slice(0, 2)) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - # test numpy concatenation - a = pybamm.StateVector(slice(0, 3)) - b = pybamm.Vector([2, 3, 4]) - c = pybamm.Vector([5]) - - y_tests = [np.array([[2], [3], [4]]), np.array([[1], [3], [2]])] - t_tests = [1, 2] - - expr = pybamm.NumpyConcatenation(a, b, c) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - expr = pybamm.NumpyConcatenation(a, c) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0, 0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - # note 1D arrays are flattened in Julia - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - # test sparse stack - A = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[1, 0], [0, 4]]))) - B = pybamm.Matrix(scipy.sparse.csr_matrix(np.array([[2, 0], [5, 0]]))) - c = pybamm.StateVector(slice(0, 2)) - expr = pybamm.SparseStack(A, B) @ c - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0, 0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - # test Inner - expr = pybamm.Inner(pybamm.Vector([1, 2]), pybamm.StateVector(slice(0, 2))) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y in y_tests: - Main.dy = [0.0, 0.0] - Main.y = y - Main.eval("f!(dy,y,0,0)") - np.testing.assert_array_equal(Main.dy, expr.evaluate(y=y).flatten()) - - def test_evaluator_julia_input_parameters(self): - a = pybamm.StateVector(slice(0, 1)) - b = pybamm.StateVector(slice(1, 2)) - c = pybamm.InputParameter("c") - d = pybamm.InputParameter("d") - - # test one input parameter: a * c - expr = a * c - evaluator_str = pybamm.get_julia_function(expr, input_parameter_order=["c"]) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.y = np.array([2.0, 3.0]) - Main.p = [5] - Main.eval("f!(dy,y,p,0)") - self.assertEqual(Main.dy, 10) - - # test several input parameters: a * c + b * d - expr = a * c + b * d - evaluator_str = pybamm.get_julia_function( - expr, input_parameter_order=["c", "d"] - ) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.y = np.array([2.0, 3.0]) - Main.p = [5, 6] - Main.eval("f!(dy,y,p,0)") - self.assertEqual(Main.dy, 28) - - def test_evaluator_julia_all_functions(self): - a = pybamm.StateVector(slice(0, 3)) - y_test = np.array([1, 2, 3]) - - for function in [ - pybamm.arcsinh, - pybamm.cos, - pybamm.cosh, - pybamm.exp, - pybamm.log, - pybamm.log10, - pybamm.sin, - pybamm.sinh, - pybamm.sqrt, - pybamm.tanh, - pybamm.arctan, - ]: - expr = function(a) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = 0.0 * y_test - Main.y = y_test - Main.eval("f!(dy,y,0,0)") - np.testing.assert_almost_equal( - Main.dy, expr.evaluate(y=y_test).flatten(), decimal=15 - ) - - for function in [ - pybamm.min, - pybamm.max, - ]: - expr = function(a) - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - Main.dy = [0.0] - Main.y = y_test - Main.eval("f!(dy,y,0,0)") - np.testing.assert_equal(Main.dy, expr.evaluate(y=y_test).flatten()) - - def test_evaluator_julia_domain_concatenation(self): - c_n = pybamm.Variable("c_n", domain="negative electrode") - c_s = pybamm.Variable("c_s", domain="separator") - c_p = pybamm.Variable("c_p", domain="positive electrode") - c = pybamm.Concatenation(c_n, c_s, c_p) - # create discretisation - mesh = get_mesh_for_testing() - spatial_methods = { - "macroscale": pybamm.FiniteVolume(), - "current collector": pybamm.FiniteVolume(), - } - disc = pybamm.Discretisation(mesh, spatial_methods) - - combined_submesh = mesh.combine_submeshes(*c.domain) - nodes = combined_submesh.nodes - y_tests = [nodes ** 2 + 1, np.cos(nodes)] - - # discretise and evaluate the variable - disc.set_variable_slices([c]) - c_disc = disc.process_symbol(c) - - evaluator_str = pybamm.get_julia_function(c_disc) - Main.eval(evaluator_str) - for y_test in y_tests: - pybamm_eval = c_disc.evaluate(y=y_test).flatten() - Main.dy = np.zeros_like(pybamm_eval) - Main.y = y_test - Main.eval("f!(dy,y,0,0)") - np.testing.assert_equal(Main.dy, pybamm_eval) - - def test_evaluator_julia_domain_concatenation_2D(self): - c_n = pybamm.Variable( - "c_n", - domain="negative electrode", - auxiliary_domains={"secondary": "current collector"}, - ) - c_s = pybamm.Variable( - "c_s", - domain="separator", - auxiliary_domains={"secondary": "current collector"}, - ) - c_p = pybamm.Variable( - "c_p", - domain="positive electrode", - auxiliary_domains={"secondary": "current collector"}, - ) - c = pybamm.Concatenation(c_n, c_s, c_p) - # create discretisation - mesh = get_1p1d_mesh_for_testing() - spatial_methods = {"macroscale": pybamm.FiniteVolume()} - disc = pybamm.Discretisation(mesh, spatial_methods) - - combined_submesh = mesh.combine_submeshes(*c.domain) - nodes = np.linspace( - 0, 1, combined_submesh.npts * mesh["current collector"].npts - ) - y_tests = [nodes ** 2 + 1, np.cos(nodes)] - - # discretise and evaluate the variable - disc.set_variable_slices([c]) - c_disc = disc.process_symbol(c) - - evaluator_str = pybamm.get_julia_function(c_disc) - Main.eval(evaluator_str) - for y_test in y_tests: - pybamm_eval = c_disc.evaluate(y=y_test).flatten() - Main.dy = np.zeros_like(pybamm_eval) - Main.y = y_test - Main.eval("f!(dy,y,0,0)") - np.testing.assert_equal(Main.dy, pybamm_eval) - - def test_evaluator_julia_discretised_operators(self): - whole_cell = ["negative electrode", "separator", "positive electrode"] - # create discretisation - mesh = get_mesh_for_testing() - spatial_methods = {"macroscale": pybamm.FiniteVolume()} - disc = pybamm.Discretisation(mesh, spatial_methods) - - combined_submesh = mesh.combine_submeshes(*whole_cell) - - # grad - var = pybamm.Variable("var", domain=whole_cell) - grad_eqn = pybamm.grad(var) - boundary_conditions = { - var.id: { - "left": (pybamm.Scalar(1), "Dirichlet"), - "right": (pybamm.Scalar(2), "Neumann"), - } - } - disc.bcs = boundary_conditions - - disc.set_variable_slices([var]) - grad_eqn_disc = disc.process_symbol(grad_eqn) - - # div: test on linear y (should have laplacian zero) so change bcs - div_eqn = pybamm.div(var * grad_eqn) - - div_eqn_disc = disc.process_symbol(div_eqn) - - # test - nodes = combined_submesh.nodes - y_tests = [nodes ** 2 + 1, np.cos(nodes)] - - for expr in [grad_eqn_disc, div_eqn_disc]: - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y_test in y_tests: - pybamm_eval = expr.evaluate(y=y_test).flatten() - Main.dy = np.zeros_like(pybamm_eval) - Main.y = y_test - Main.eval("f!(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, pybamm_eval, decimal=7) - - def test_evaluator_julia_discretised_microscale(self): - # create discretisation - mesh = get_1p1d_mesh_for_testing(xpts=5, rpts=5, zpts=2) - spatial_methods = {"negative particle": pybamm.FiniteVolume()} - disc = pybamm.Discretisation(mesh, spatial_methods) - - submesh = mesh["negative particle"] - - # grad - # grad(r) == 1 - var = pybamm.Variable( - "var", - domain=["negative particle"], - auxiliary_domains={ - "secondary": "negative electrode", - "tertiary": "current collector", - }, - ) - grad_eqn = pybamm.grad(var) - div_eqn = pybamm.div(var * grad_eqn) - - boundary_conditions = { - var.id: { - "left": (pybamm.Scalar(1), "Dirichlet"), - "right": (pybamm.Scalar(2), "Neumann"), - } - } - - disc.bcs = boundary_conditions - - disc.set_variable_slices([var]) - grad_eqn_disc = disc.process_symbol(grad_eqn) - div_eqn_disc = disc.process_symbol(div_eqn) - - # test - total_npts = ( - submesh.npts - * mesh["negative electrode"].npts - * mesh["current collector"].npts - ) - y_tests = [np.linspace(0, 1, total_npts) ** 2] - - for expr in [grad_eqn_disc, div_eqn_disc]: - evaluator_str = pybamm.get_julia_function(expr) - Main.eval(evaluator_str) - for y_test in y_tests: - pybamm_eval = expr.evaluate(y=y_test).flatten() - Main.dy = np.zeros_like(pybamm_eval) - Main.y = y_test - Main.eval("f!(dy,y,0,0)") - np.testing.assert_almost_equal(Main.dy, pybamm_eval, decimal=7) - - -if __name__ == "__main__": - print("Add -v for more debug output") - import sys - - if "-v" in sys.argv: - debug = True - pybamm.settings.debug_mode = True - unittest.main() diff --git a/tests/unit/test_expression_tree/test_parameter.py b/tests/unit/test_expression_tree/test_parameter.py index db839f7c2a..6f51624b55 100644 --- a/tests/unit/test_expression_tree/test_parameter.py +++ b/tests/unit/test_expression_tree/test_parameter.py @@ -74,7 +74,7 @@ def test_set_input_names(self): new_input_names = [var] func.input_names = new_input_names - def test_short_name(self): + def test_print_name(self): def myfun(x): return pybamm.FunctionParameter("my function", {"x": x}) @@ -88,10 +88,10 @@ def _myfun(x): return pybamm.FunctionParameter("my function", {"x": x}) x = pybamm.Scalar(1) - self.assertEqual(myfun(x).short_name, "myfun") - self.assertEqual(myfun_dim(x).short_name, "myfun") - self.assertEqual(myfun_dimensional(x).short_name, "myfun") - self.assertEqual(_myfun(x).short_name, None) + self.assertEqual(myfun(x).print_name, "myfun") + self.assertEqual(myfun_dim(x).print_name, "myfun") + self.assertEqual(myfun_dimensional(x).print_name, "myfun") + self.assertEqual(_myfun(x).print_name, None) if __name__ == "__main__": diff --git a/tests/unit/test_models/test_base_model.py b/tests/unit/test_models/test_base_model.py index 8f2828632e..9ad1ce6cc4 100644 --- a/tests/unit/test_models/test_base_model.py +++ b/tests/unit/test_models/test_base_model.py @@ -614,42 +614,6 @@ def test_generate_casadi(self): os.remove("test.c") os.remove("test.so") - @unittest.skipIf(platform.system() == "Windows", "Skipped for Windows") - def test_generate_julia_diffeq(self): - # ODE model with no input parameters - model = pybamm.BaseModel(name="ode test model") - a = pybamm.Variable("a") - b = pybamm.Variable("b") - model.rhs = {a: -a, b: a - b} - model.initial_conditions = {a: 1, b: 2} - - # Generate rhs and ics for the Julia model - rhs_str, ics_str = model.generate_julia_diffeq() - self.assertIsInstance(rhs_str, str) - self.assertIn("ode_test_model", rhs_str) - self.assertIsInstance(ics_str, str) - self.assertIn("ode_test_model_u0", ics_str) - self.assertIn("(u0, p)", ics_str) - - # ODE model with input parameters - model = pybamm.BaseModel(name="ode test model 2") - a = pybamm.Variable("a") - b = pybamm.Variable("b") - p = pybamm.InputParameter("p") - q = pybamm.InputParameter("q") - model.rhs = {a: -a * p, b: a - b} - model.initial_conditions = {a: q, b: 2} - - # Generate rhs and ics for the Julia model - rhs_str, ics_str = model.generate_julia_diffeq(input_parameter_order=["p", "q"]) - self.assertIsInstance(rhs_str, str) - self.assertIn("ode_test_model_2", rhs_str) - self.assertIn("p, q = p", rhs_str) - - self.assertIsInstance(ics_str, str) - self.assertIn("ode_test_model_2_u0", ics_str) - self.assertIn("p, q = p", ics_str) - def test_set_initial_conditions(self): # Set up model model = pybamm.BaseModel() diff --git a/tests/unit/test_solvers/test_julia_mtk.py b/tests/unit/test_solvers/test_julia_mtk.py deleted file mode 100644 index dbe17f1654..0000000000 --- a/tests/unit/test_solvers/test_julia_mtk.py +++ /dev/null @@ -1,196 +0,0 @@ -# -# Test for the evaluate-to-Julia functions -# -import pybamm - -import unittest -from platform import system - -# import numpy as np - -# julia imports -have_julia = pybamm.have_julia() -# if have_julia and system() != "Windows": -# from julia import Main - -# from julia import Pkg -# from diffeqpy import de - -# Pkg.activate(".") - - -@unittest.skipIf(not have_julia, "Julia not installed") -@unittest.skipIf(system() == "Windows", "Julia not supported on windows") -class TestCreateSolveMTKModel(unittest.TestCase): - def test_exponential_decay_model(self): - model = pybamm.BaseModel() - v = pybamm.Variable("v") - model.rhs = {v: -2 * v} - model.initial_conditions = {v: 0.5} - - pybamm.get_julia_mtk_model(model) - - # Main.eval("using ModelingToolkit") - # Main.eval(mtk_str) - - # Main.tspan = (0.0, 10.0) - # # this definition of prob doesn't work, so we use Main.eval instead - # # prob = de.ODEProblem(Main.sys, Main.u0, Main.tspan) - - # Main.eval("prob = ODEProblem(sys, u0, tspan)") - # sol = de.solve(Main.prob, de.Tsit5()) - - # y_sol = np.concatenate(sol.u) - # y_exact = 0.5 * np.exp(-2 * sol.t) - # np.testing.assert_almost_equal(y_sol, y_exact, decimal=6) - - def test_lotka_volterra_model(self): - model = pybamm.BaseModel() - a = pybamm.InputParameter("a") - b = pybamm.InputParameter("b") - c = pybamm.InputParameter("c") - d = pybamm.InputParameter("d") - x = pybamm.Variable("x") - y = pybamm.Variable("y") - - model.rhs = {x: a * x - b * x * y, y: c * x * y - d * y} - model.initial_conditions = {x: 1.0, y: 1.0} - - pybamm.get_julia_mtk_model(model) - - # # Solve using julia - # Main.eval("using ModelingToolkit") - # Main.eval(mtk_str) - - # Main.tspan = (0.0, 10.0) - # Main.eval( - # """ - # begin - # p = [a => 1.5, b => 1.0, c => 3.0, d => 1.0] - # prob = ODEProblem(sys, u0, tspan, p) - # end - # """ - # ) - # sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) - - # y_sol_julia = np.vstack(sol_julia.u).T - - # # Solve using pybamm - # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve( - # model, sol_julia.t, inputs={"a": 1.5, "b": 1.0, "c": 3.0, "d": 1.0} - # ) - - # # Compare - # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) - - def test_dae_model(self): - model = pybamm.BaseModel() - x = pybamm.Variable("x") - y = pybamm.Variable("y") - - model.rhs = {x: -2 * x} - model.algebraic = {y: x - y} - model.initial_conditions = {x: 1.0, y: 1.0} - - pybamm.get_julia_mtk_model(model) - - # # Solve using julia - # Main.eval("using ModelingToolkit") - # Main.eval(mtk_str) - - # Main.tspan = (0.0, 10.0) - # Main.eval("prob = ODEProblem(sys, u0, tspan)") - # sol_julia = de.solve(Main.prob, de.Rodas5(), reltol=1e-8, abstol=1e-8) - - # y_sol_julia = np.vstack(sol_julia.u).T - - # # Solve using pybamm - # sol_pybamm = pybamm.CasadiSolver(rtol=1e-8, atol=1e-8).solve(model, - # sol_julia.t) - - # # Compare - # np.testing.assert_almost_equal(y_sol_julia, sol_pybamm.y, decimal=5) - - def test_pde_model(self): - model = pybamm.BaseModel() - var = pybamm.Variable("var", domain="line") - - model.rhs = {var: pybamm.div(pybamm.grad(var))} - model.initial_conditions = {var: 1.0} - model.boundary_conditions = { - var: {"left": (1, "Dirichlet"), "right": (1, "Dirichlet")} - } - - x = pybamm.SpatialVariable("x", domain="line", coord_sys="cartesian") - geometry = {"line": {x: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}} - - pybamm.get_julia_mtk_model(model, geometry=geometry, tspan=(0.0, 10.0)) - - # # Solve using julia - # Main.eval("using ModelingToolkit, DiffEqOperators") - # Main.eval(mtk_str) - - # Main.tspan = (0.0, 10.0) - # # Method of lines discretization - # Main.dx = 0.1 - # Main.order = 2 - # Main.eval("discretization = MOLFiniteDifference(dx,order)") - - # # Convert the PDE problem into an ODE problem - # Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") - - # # Solve PDE problem - # sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) - - # y_sol_julia = np.hstack(sol_julia.u) - - # # Check everything is equal to 1 - # # Just a simple test for now to get started - # np.testing.assert_equal(y_sol_julia, 1) - - def test_pde_model_spherical_polar(self): - model = pybamm.BaseModel() - var = pybamm.Variable("var", domain="particle") - - model.rhs = {var: pybamm.div(pybamm.grad(var))} - model.initial_conditions = {var: 1.0} - model.boundary_conditions = { - var: {"left": (1, "Dirichlet"), "right": (1, "Dirichlet")} - } - - r = pybamm.SpatialVariable("r", domain="particle", coord_sys="spherical polar") - geometry = {"particle": {r: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}} - - pybamm.get_julia_mtk_model(model, geometry=geometry, tspan=(0.0, 10.0)) - - # # Solve using julia - # Main.eval("using ModelingToolkit, DiffEqOperators") - # Main.eval(mtk_str) - - # Main.tspan = (0.0, 10.0) - # # Method of lines discretization - # Main.dx = 0.1 - # Main.order = 2 - # Main.eval("discretization = MOLFiniteDifference(dx,order)") - - # # Convert the PDE problem into an ODE problem - # Main.eval("prob = DiffEqOperators.discretize(pde_system,discretization)") - - # # Solve PDE problem - # sol_julia = de.solve(Main.prob, de.Tsit5(), reltol=1e-8, abstol=1e-8) - - # y_sol_julia = np.hstack(sol_julia.u) - - # # Check everything is equal to 1 - # # Just a simple test for now to get started - # np.testing.assert_equal(y_sol_julia, 1) - - -if __name__ == "__main__": - print("Add -v for more debug output") - import sys - - if "-v" in sys.argv: - debug = True - pybamm.settings.debug_mode = True - unittest.main() diff --git a/tox.ini b/tox.ini index c1ee9e9230..08f8df148d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {windows}-{tests,quick,dev},tests,quick,dev,julia +envlist = {windows}-{tests,quick,dev},tests,quick,dev [testenv] skipsdist = true @@ -25,18 +25,6 @@ commands = dev-!windows-!mac: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" doctests: python run-tests.py --doctest -[testenv:julia] -platform = - linux - darwin -skip_install = true -passenv = HOME -whitelist_externals = git -deps = - julia -commands = - python -c "import julia; julia.install()" - [testenv:pybamm-requires] platform = linux From 5916134d2d0be8855f52e73b4966aea54b8ce2de Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 28 May 2021 15:03:52 -0400 Subject: [PATCH 81/88] use tox.ini and setup.py from develop branch --- setup.py | 1 + tox.ini | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/setup.py b/setup.py index fe9d385dfe..e455058478 100644 --- a/setup.py +++ b/setup.py @@ -165,6 +165,7 @@ def compile_KLU(): if system() != "Windows": jax_dependencies = ["jax==0.2.12", "jaxlib==0.1.65"] + # Load text for description and license with open("README.md", encoding="utf-8") as f: readme = f.read() diff --git a/tox.ini b/tox.ini index 08f8df148d..1501988e90 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ envlist = {windows}-{tests,quick,dev},tests,quick,dev [testenv] skipsdist = true -skip_install = flake8: true +skip_install = flake8: true usedevelop = true passenv = !windows-!mac: SUNDIALS_INST whitelist_externals = !windows-!mac: sh @@ -19,16 +19,14 @@ deps = !windows-!mac: scikits.odes commands = - tests: python run-tests.py --unit --folder all - quick: python run-tests.py --unit - examples: python run-tests.py --examples - dev-!windows-!mac: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" - doctests: python run-tests.py --doctest + tests: python run-tests.py --unit --folder all + quick: python run-tests.py --unit + examples: python run-tests.py --examples + dev-!windows-!mac: sh -c "echo export LD_LIBRARY_PATH={env:LD_LIBRARY_PATH} >> {envbindir}/activate" + doctests: python run-tests.py --doctest [testenv:pybamm-requires] -platform = - linux - darwin +platform = [linux,darwin] skip_install = true passenv = HOME whitelist_externals = git @@ -36,8 +34,8 @@ deps = wget cmake commands = - python {toxinidir}/scripts/install_KLU_Sundials.py - - git clone https://github.com/pybind/pybind11.git {toxinidir}/pybind11 + python {toxinidir}/scripts/install_KLU_Sundials.py + - git clone https://github.com/pybind/pybind11.git {toxinidir}/pybind11 [testenv:flake8] skip_install = true @@ -45,10 +43,10 @@ deps = flake8>=3 commands = python -m flake8 [testenv:coverage] -deps = +deps = coverage scikits.odes -commands = +commands = coverage run run-tests.py --nosub # Some tests make use of multiple processes through # multiprocessing. Coverage data is then generated for each From ec6aaa64d4c7aa5c59e8dfb39edeef6eb8f8f2fd Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 28 May 2021 15:06:05 -0400 Subject: [PATCH 82/88] revert SPMe example changes --- examples/scripts/SPMe.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/examples/scripts/SPMe.py b/examples/scripts/SPMe.py index 5eb274ae74..75921b13d2 100644 --- a/examples/scripts/SPMe.py +++ b/examples/scripts/SPMe.py @@ -5,11 +5,11 @@ import pybamm import numpy as np -# pybamm.set_logging_level("INFO") +pybamm.set_logging_level("INFO") # load model model = pybamm.lithium_ion.SPMe() -# model.convert_to_format = "python" +model.convert_to_format = "python" # create geometry geometry = model.default_geometry @@ -20,9 +20,7 @@ param.process_geometry(geometry) # set mesh -var = pybamm.standard_spatial_vars -var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.r_n: 10, var.r_p: 10} -mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) +mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts) # discretise model disc = pybamm.Discretisation(mesh, model.default_spatial_methods) @@ -30,16 +28,7 @@ # solve model for 1 hour t_eval = np.linspace(0, 3600, 100) -solver = pybamm.CasadiSolver(mode="fast", rtol=1e-6, atol=1e-6) -solution = solver.solve(model, t_eval) -solve_time = 0 -int_time = 0 -for _ in range(1000): - solution = solver.solve(model, t_eval) - solve_time += solution.solve_time - int_time += solution.integration_time - -print(str(solve_time / 1000) + " (" + str(int_time / 1000) + ")") +solution = model.default_solver.solve(model, t_eval) # plot plot = pybamm.QuickPlot( @@ -57,4 +46,4 @@ time_unit="seconds", spatial_unit="um", ) -# plot.dynamic_plot() +plot.dynamic_plot() From fc1fda98e4d1914fc0fba94b09a0bee09c36a36e Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Mon, 31 May 2021 14:29:20 -0400 Subject: [PATCH 83/88] coverage --- .gitignore | 3 -- Project.toml | 7 ---- pybamm/parameters/parameter_values.py | 38 +------------------ pybamm/solvers/idaklu_solver.py | 2 +- .../test_operations/test_evaluate_python.py | 4 ++ 5 files changed, 6 insertions(+), 48 deletions(-) delete mode 100644 Project.toml diff --git a/.gitignore b/.gitignore index 576a29f621..adf3743680 100644 --- a/.gitignore +++ b/.gitignore @@ -110,8 +110,5 @@ test.c # tox .tox/ -# Julia -Manifest.toml - # vcpkg vcpkg_installed/ diff --git a/Project.toml b/Project.toml deleted file mode 100644 index 058f6dddd2..0000000000 --- a/Project.toml +++ /dev/null @@ -1,7 +0,0 @@ -[deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -DiffEqOperators = "9fdde737-9c7f-55bf-ade8-46b3f136cc48" -DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" -ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" -PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" -Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py index 23f244fb13..b262589168 100644 --- a/pybamm/parameters/parameter_values.py +++ b/pybamm/parameters/parameter_values.py @@ -88,10 +88,6 @@ def __init__(self, values=None, chemistry=None): self._processed_symbols = {} self.parameter_events = [] - # Don't touch this parameter unless you know what you are doing - # This is for the conversion to Julia (ModelingToolkit) - self._replace_callable_function_parameters = True - def __getitem__(self, key): return self._dict_items[key] @@ -127,11 +123,7 @@ def items(self): def copy(self): """Returns a copy of the parameter values. Makes sure to copy the internal dictionary.""" - new_copy = ParameterValues(values=self._dict_items.copy()) - new_copy._replace_callable_function_parameters = ( - self._replace_callable_function_parameters - ) - return new_copy + return ParameterValues(values=self._dict_items.copy()) def search(self, key, print_values=True): """ @@ -679,34 +671,6 @@ def _process_symbol(self, symbol): elif callable(function_name): # otherwise evaluate the function to create a new PyBaMM object function = function_name(*new_children) - if ( - self._replace_callable_function_parameters is False - and not isinstance( - self.process_symbol(function), (pybamm.Scalar, pybamm.Broadcast) - ) - and symbol.print_name is not None - and symbol.diff_variable is None - ): - # Special trick for printing in Julia ModelingToolkit format - out = pybamm.FunctionParameter( - symbol.print_name, dict(zip(symbol.input_names, new_children)) - ) - - out.arg_names = inspect.getfullargspec(function_name)[0] - out.callable = self.process_symbol( - function_name( - *[ - pybamm.Variable( - arg_name, - domain=child.domain, - auxiliary_domains=child.auxiliary_domains, - ) - for arg_name, child in zip(out.arg_names, new_children) - ] - ) - ) - - return out elif isinstance(function_name, pybamm.Interpolant): function = function_name else: diff --git a/pybamm/solvers/idaklu_solver.py b/pybamm/solvers/idaklu_solver.py index f255380fb7..f6b8362702 100644 --- a/pybamm/solvers/idaklu_solver.py +++ b/pybamm/solvers/idaklu_solver.py @@ -13,7 +13,7 @@ try: idaklu = importlib.util.module_from_spec(idaklu_spec) idaklu_spec.loader.exec_module(idaklu) - except ImportError: + except ImportError: # pragma: no cover idaklu_spec = None diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py index ed907ec4bd..3907470234 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py @@ -427,6 +427,10 @@ def test_evaluator_python(self): for t, y in zip(t_tests, y_tests): result = evaluator.evaluate(t=t, y=y).toarray() np.testing.assert_allclose(result, expr.evaluate(t=t, y=y).toarray()) + expr = pybamm.SparseStack(A) + evaluator = pybamm.EvaluatorPython(expr) + result = evaluator.evaluate().toarray() + np.testing.assert_allclose(result, expr.evaluate().toarray()) # test Inner expr = pybamm.Inner(a, b) From d06e77b638dd62039d23a57aba1e29def192e138 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 1 Jun 2021 11:24:44 -0400 Subject: [PATCH 84/88] flake8 --- pybamm/parameters/parameter_values.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py index b262589168..c8b1a7ba77 100644 --- a/pybamm/parameters/parameter_values.py +++ b/pybamm/parameters/parameter_values.py @@ -8,7 +8,6 @@ import warnings from pprint import pformat from collections import defaultdict -import inspect class ParameterValues: From 02e261d5f3a57af0768f5c9c9b2876a8b3d5e6de Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 1 Jun 2021 11:36:40 -0400 Subject: [PATCH 85/88] try removing print name for benchmarks --- pybamm/expression_tree/parameter.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/pybamm/expression_tree/parameter.py b/pybamm/expression_tree/parameter.py index 27ec0ada35..d417a358c1 100644 --- a/pybamm/expression_tree/parameter.py +++ b/pybamm/expression_tree/parameter.py @@ -4,7 +4,6 @@ import numbers import numpy as np import pybamm -import inspect class Parameter(pybamm.Symbol): @@ -90,19 +89,7 @@ def __init__( ) self.input_names = list(inputs.keys()) - - # Use the inspect module to find the function's "short name" from the - # Parameters module that called it - print_name = inspect.stack()[1][3] - if print_name.startswith("_"): - self.print_name = None - else: - if print_name.endswith("_dimensional"): - self.print_name = print_name[: -len("_dimensional")] - elif print_name.endswith("_dim"): - self.print_name = print_name[: -len("_dim")] - else: - self.print_name = print_name + self.print_name = None @property def input_names(self): From 7136cc7ce3bb60ed9ed6e458458660e52e8c197e Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 1 Jun 2021 12:25:51 -0400 Subject: [PATCH 86/88] try faster inspect --- pybamm/expression_tree/parameter.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pybamm/expression_tree/parameter.py b/pybamm/expression_tree/parameter.py index d417a358c1..92a50931bb 100644 --- a/pybamm/expression_tree/parameter.py +++ b/pybamm/expression_tree/parameter.py @@ -4,6 +4,7 @@ import numbers import numpy as np import pybamm +import sys class Parameter(pybamm.Symbol): @@ -89,7 +90,20 @@ def __init__( ) self.input_names = list(inputs.keys()) - self.print_name = None + + # Use the inspect module to find the function's "short name" from the + # Parameters module that called it + frame = sys._getframe().f_back + print_name = frame.f_code.co_name + if print_name.startswith("_"): + self.print_name = None + else: + if print_name.endswith("_dimensional"): + self.print_name = print_name[: -len("_dimensional")] + elif print_name.endswith("_dim"): + self.print_name = print_name[: -len("_dim")] + else: + self.print_name = print_name @property def input_names(self): From 6454df35595cde33a74efdd3990725f6acadf5ad Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 1 Jun 2021 12:40:21 -0400 Subject: [PATCH 87/88] don't recalculate print name if not needed --- pybamm/expression_tree/parameter.py | 41 +++++++++++++++++++---------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/pybamm/expression_tree/parameter.py b/pybamm/expression_tree/parameter.py index 92a50931bb..d7b885e9ae 100644 --- a/pybamm/expression_tree/parameter.py +++ b/pybamm/expression_tree/parameter.py @@ -63,6 +63,9 @@ class FunctionParameter(pybamm.Symbol): if diff_variable is specified, the FunctionParameter node will be replaced by a :class:`pybamm.Function` and then differentiated with respect to diff_variable. Default is None. + print_name : str, optional + The name to show when printing. Default is 'calculate', in which case the name + is calculated using sys._getframe(). """ def __init__( @@ -70,6 +73,7 @@ def __init__( name, inputs, diff_variable=None, + print_name="calculate", ): # assign diff variable self.diff_variable = diff_variable @@ -93,17 +97,20 @@ def __init__( # Use the inspect module to find the function's "short name" from the # Parameters module that called it - frame = sys._getframe().f_back - print_name = frame.f_code.co_name - if print_name.startswith("_"): - self.print_name = None + if print_name != "calculate": + self.print_name = print_name else: - if print_name.endswith("_dimensional"): - self.print_name = print_name[: -len("_dimensional")] - elif print_name.endswith("_dim"): - self.print_name = print_name[: -len("_dim")] + frame = sys._getframe().f_back + print_name = frame.f_code.co_name + if print_name.startswith("_"): + self.print_name = None else: - self.print_name = print_name + if print_name.endswith("_dimensional"): + self.print_name = print_name[: -len("_dimensional")] + elif print_name.endswith("_dim"): + self.print_name = print_name[: -len("_dim")] + else: + self.print_name = print_name @property def input_names(self): @@ -174,11 +181,14 @@ def diff(self, variable): def new_copy(self): """ See :meth:`pybamm.Symbol.new_copy()`. """ - out = self._function_parameter_new_copy(self._input_names, self.orphans) - out.print_name = self.print_name + out = self._function_parameter_new_copy( + self._input_names, self.orphans, print_name=self.print_name + ) return out - def _function_parameter_new_copy(self, input_names, children): + def _function_parameter_new_copy( + self, input_names, children, print_name="calculate" + ): """Returns a new copy of the function parameter. Inputs @@ -190,14 +200,17 @@ def _function_parameter_new_copy(self, input_names, children): Returns ------- - : :pybamm.FunctionParameter + :class:`pybamm.FunctionParameter` A new copy of the function parameter """ input_dict = {input_names[i]: children[i] for i in range(len(input_names))} return FunctionParameter( - self.name, input_dict, diff_variable=self.diff_variable + self.name, + input_dict, + diff_variable=self.diff_variable, + print_name=print_name, ) def _evaluate_for_shape(self): From 2e4f5e474578fe767a2ff3ab91145a7f62d5a3f1 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Thu, 3 Jun 2021 10:05:00 -0400 Subject: [PATCH 88/88] review comments --- CHANGELOG.md | 1 + pybamm/models/standard_variables.py | 9 --------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76f036cef7..60fb615ad1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Features +- Added `print_name` to some symbols ([#1495](https://github.com/pybamm-team/PyBaMM/pull/1497), [#1495](https://github.com/pybamm-team/PyBaMM/pull/1497)) - Added Base Parameters class and SymPy in dependencies ([#1495](https://github.com/pybamm-team/PyBaMM/pull/1495)) - Added a new "reaction-driven" model for LAM from Reniers et al (2019) ([#1490](https://github.com/pybamm-team/PyBaMM/pull/1490)) - Some features ("loss of active material" and "particle mechanics") can now be specified separately for the negative electrode and positive electrode by passing a 2-tuple ([#1490](https://github.com/pybamm-team/PyBaMM/pull/1490)) diff --git a/pybamm/models/standard_variables.py b/pybamm/models/standard_variables.py index e862e2dc57..ea1e4e4391 100644 --- a/pybamm/models/standard_variables.py +++ b/pybamm/models/standard_variables.py @@ -78,7 +78,6 @@ def __init__(self): domain="positive electrode", auxiliary_domains={"secondary": "current collector"}, ) - # self.phi_e = pybamm.concatenation(phi_e_n, phi_e_s, phi_e_p) # Electrode potential self.phi_s_n = pybamm.Variable( @@ -249,7 +248,6 @@ def __init__(self): auxiliary_domains={"secondary": "current collector"}, bounds=(0, 1), ) - # self.eps = pybamm.concatenation(eps_n, eps_s, eps_p) # Piecewise constant (for asymptotic models) self.eps_n_pc = pybamm.Variable( @@ -266,12 +264,6 @@ def __init__(self): bounds=(0, 1), ) - # self.eps_piecewise_constant = pybamm.concatenation( - # pybamm.PrimaryBroadcast(eps_n_pc, "negative electrode"), - # pybamm.PrimaryBroadcast(eps_s_pc, "separator"), - # pybamm.PrimaryBroadcast(eps_p_pc, "positive electrode"), - # ) - # Temperature self.T_cn = pybamm.Variable( "Negative currents collector temperature", domain="current collector" @@ -294,7 +286,6 @@ def __init__(self): self.T_cp = pybamm.Variable( "Positive currents collector temperature", domain="current collector" ) - # self.T = pybamm.concatenation(T_n, T_s, T_p) self.T_av = pybamm.Variable( "X-averaged cell temperature", domain="current collector" )