Esempio n. 1
0
    def test_processed_variable_1D(self):
        var = pybamm.Variable("var", domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"])
        eqn = var + x

        # On nodes
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        eqn_sol = disc.process_symbol(eqn)

        # With scalar t_sol
        t_sol = [0]
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)
        np.testing.assert_array_equal(
            processed_eqn.value(), y_sol + x_sol[:, np.newaxis]
        )

        # With vector t_sol
        t_sol = np.linspace(0, 1)
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * np.linspace(0, 5)
        sol = pybamm.Solution(t_sol, y_sol)
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)
        np.testing.assert_array_equal(
            processed_eqn.value(), (y_sol + x_sol[:, np.newaxis]).T.reshape(-1, 1)
        )
    def test_processed_variable_1D_with_scalar_inputs(self):
        var = pybamm.Variable("var", domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"])
        p = pybamm.InputParameter("p")
        q = pybamm.InputParameter("q")
        eqn = var * p + 2 * q

        # On nodes
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        eqn_sol = disc.process_symbol(eqn)

        # Scalar t
        t_sol = [0]
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5

        sol = pybamm.Solution(t_sol, y_sol)
        sol.inputs = {"p": casadi.MX.sym("p"), "q": casadi.MX.sym("q")}
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)

        # Test values
        np.testing.assert_array_equal(
            processed_eqn.value({"p": 27, "q": -42}), 27 * y_sol - 84,
        )

        # Test sensitivities
        np.testing.assert_array_equal(
            processed_eqn.sensitivity({"p": 27, "q": -84}),
            np.c_[y_sol, 2 * np.ones_like(y_sol)],
        )

        ################################################################################
        # Vector t
        t_sol = np.linspace(0, 1)
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * np.linspace(0, 5)

        sol = pybamm.Solution(t_sol, y_sol)
        sol.inputs = {"p": casadi.MX.sym("p"), "q": casadi.MX.sym("q")}
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)

        # Test values
        np.testing.assert_array_equal(
            processed_eqn.value({"p": 27, "q": -42}),
            (27 * y_sol - 84).T.reshape(-1, 1),
        )

        # Test sensitivities
        np.testing.assert_array_equal(
            processed_eqn.sensitivity({"p": 27, "q": -42}),
            np.c_[y_sol.T.flatten(), 2 * np.ones_like(y_sol.T.flatten())],
        )
Esempio n. 3
0
    def test_processed_variable_0D_with_inputs(self):
        # with symbolic inputs
        y = pybamm.StateVector(slice(0, 1))
        p = pybamm.InputParameter("p")
        q = pybamm.InputParameter("q")
        var = p * y + q
        var.mesh = None

        t_sol = np.linspace(0, 1)
        y_sol = np.array([np.linspace(0, 5)])
        solution = pybamm.Solution(t_sol, y_sol)
        solution.inputs = {"p": casadi.MX.sym("p"), "q": casadi.MX.sym("q")}
        processed_var = pybamm.ProcessedSymbolicVariable(var, solution)
        np.testing.assert_array_equal(
            processed_var.value({"p": 3, "q": 4}).full(), 3 * y_sol + 4
        )
        np.testing.assert_array_equal(
            processed_var.sensitivity({"p": 3, "q": 4}).full(),
            np.c_[y_sol.T, np.ones_like(y_sol).T],
        )

        # via value_and_sensitivity
        val, sens = processed_var.value_and_sensitivity({"p": 3, "q": 4})
        np.testing.assert_array_equal(val.full(), 3 * y_sol + 4)
        np.testing.assert_array_equal(
            sens.full(), np.c_[y_sol.T, np.ones_like(y_sol).T]
        )

        # Test bad inputs
        with self.assertRaisesRegex(TypeError, "inputs should be 'dict'"):
            processed_var.value(1)
        with self.assertRaisesRegex(KeyError, "Inconsistent input keys"):
            processed_var.value({"not p": 3})
Esempio n. 4
0
    def update(self, variables):
        """Add ProcessedVariables to the dictionary of variables in the solution"""
        # Convert single entry to list
        if isinstance(variables, str):
            variables = [variables]
        # Process
        for key in variables:
            pybamm.logger.debug("Post-processing {}".format(key))
            # If there are symbolic inputs then we need to make a
            # ProcessedSymbolicVariable
            if self.has_symbolic_inputs is True:
                var = pybamm.ProcessedSymbolicVariable(
                    self.model.variables[key], self)

            # Otherwise a standard ProcessedVariable is ok
            else:
                var = pybamm.ProcessedVariable(self.model.variables[key], self,
                                               self._known_evals)

                # Update known_evals in order to process any other variables faster
                for t in var.known_evals:
                    self._known_evals[t].update(var.known_evals[t])

            # Save variable and data
            self._variables[key] = var
            self.data[key] = var.data
Esempio n. 5
0
    def update(self, variables):
        """Add ProcessedVariables to the dictionary of variables in the solution"""
        # Convert single entry to list
        if isinstance(variables, str):
            variables = [variables]
        # Process
        for key in variables:
            pybamm.logger.debug("Post-processing {}".format(key))
            # If there are symbolic inputs then we need to make a
            # ProcessedSymbolicVariable
            if self.has_symbolic_inputs is True:
                var = pybamm.ProcessedSymbolicVariable(
                    self.all_models[0].variables[key], self
                )

            # Otherwise a standard ProcessedVariable is ok
            else:
                vars_pybamm = [model.variables[key] for model in self.all_models]

                # Iterate through all models, some may be in the list several times and
                # therefore only get set up once
                vars_casadi = []
                for model, ys, inputs, var_pybamm in zip(
                    self.all_models, self.all_ys, self.all_inputs, vars_pybamm
                ):
                    if key in model._variables_casadi:
                        var_casadi = model._variables_casadi[key]
                    else:
                        t_MX = casadi.MX.sym("t")
                        y_MX = casadi.MX.sym("y", ys.shape[0])
                        symbolic_inputs_dict = {
                            key: casadi.MX.sym("input", value.shape[0])
                            for key, value in inputs.items()
                        }
                        symbolic_inputs = casadi.vertcat(
                            *[p for p in symbolic_inputs_dict.values()]
                        )

                        # Convert variable to casadi
                        # Make all inputs symbolic first for converting to casadi
                        var_sym = var_pybamm.to_casadi(
                            t_MX, y_MX, inputs=symbolic_inputs_dict
                        )

                        var_casadi = casadi.Function(
                            "variable", [t_MX, y_MX, symbolic_inputs], [var_sym]
                        )
                        model._variables_casadi[key] = var_casadi
                    vars_casadi.append(var_casadi)

                var = pybamm.ProcessedVariable(vars_pybamm, vars_casadi, self)

            # Save variable and data
            self._variables[key] = var
            self.data[key] = var.data
Esempio n. 6
0
    def test_processed_variable_1D_with_vector_inputs(self):
        var = pybamm.Variable("var", domain=["negative electrode", "separator"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"])
        p = pybamm.InputParameter("p", domain=["negative electrode", "separator"])
        p.set_expected_size(65)
        q = pybamm.InputParameter("q")
        eqn = (var * p) ** 2 + 2 * q

        # On nodes
        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        n = x_sol.size
        eqn_sol = disc.process_symbol(eqn)

        # Scalar t
        t_sol = [0]
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        sol.inputs = {"p": casadi.MX.sym("p", n), "q": casadi.MX.sym("q")}
        processed_eqn = pybamm.ProcessedSymbolicVariable(eqn_sol, sol)

        # Test values - constant p
        np.testing.assert_array_equal(
            processed_eqn.value({"p": 27 * np.ones(n), "q": -42}),
            (27 * y_sol) ** 2 - 84,
        )
        # Test values - varying p
        p = np.linspace(0, 1, n)
        np.testing.assert_array_equal(
            processed_eqn.value({"p": p, "q": 3}), (p[:, np.newaxis] * y_sol) ** 2 + 6
        )

        # Test sensitivities - constant p
        np.testing.assert_array_equal(
            processed_eqn.sensitivity({"p": 2 * np.ones(n), "q": -84}),
            np.c_[100 * np.eye(y_sol.size), 2 * np.ones(n)],
        )
        # Test sensitivities - varying p
        # d/dy((py)**2) = (2*p*y) * y
        np.testing.assert_array_equal(
            processed_eqn.sensitivity({"p": p, "q": -84}),
            np.c_[
                np.diag((2 * p[:, np.newaxis] * y_sol ** 2).flatten()), 2 * np.ones(n)
            ],
        )

        # Bad shape
        with self.assertRaisesRegex(
            ValueError, "Wrong shape for input 'p': expected 65, actual 5"
        ):
            processed_eqn.value({"p": casadi.MX.sym("p", 5), "q": 1})
Esempio n. 7
0
    def test_processed_variable_0D(self):
        # without inputs
        y = pybamm.StateVector(slice(0, 1))
        var = 2 * y
        var.mesh = None

        t_sol = np.linspace(0, 1)
        y_sol = np.array([np.linspace(0, 5)])
        solution = pybamm.Solution(t_sol, y_sol)
        processed_var = pybamm.ProcessedSymbolicVariable(var, solution)
        np.testing.assert_array_equal(processed_var.value(), 2 * y_sol)

        # No sensitivity as variable is not symbolic
        with self.assertRaisesRegex(ValueError, "Variable is not symbolic"):
            processed_var.sensitivity()
Esempio n. 8
0
    def test_processed_variable_0D_some_inputs(self):
        # with some symbolic inputs and some non-symbolic inputs
        y = pybamm.StateVector(slice(0, 1))
        p = pybamm.InputParameter("p")
        q = pybamm.InputParameter("q")
        var = p * y - q
        var.mesh = None

        t_sol = np.linspace(0, 1)
        y_sol = np.array([np.linspace(0, 5)])
        solution = pybamm.Solution(t_sol, y_sol)
        solution.inputs = {"p": casadi.MX.sym("p"), "q": 2}
        processed_var = pybamm.ProcessedSymbolicVariable(var, solution)
        np.testing.assert_array_equal(
            processed_var.value({"p": 3}).full(), 3 * y_sol - 2
        )
        np.testing.assert_array_equal(
            processed_var.sensitivity({"p": 3}).full(), y_sol.T
        )
Esempio n. 9
0
    def test_1D_different_domains(self):
        # Negative electrode domain
        var = pybamm.Variable("var", domain=["negative electrode"])
        x = pybamm.SpatialVariable("x", domain=["negative electrode"])

        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        var_sol = disc.process_symbol(var)

        t_sol = [0]
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        pybamm.ProcessedSymbolicVariable(var_sol, sol)

        # Particle domain
        var = pybamm.Variable("var", domain=["negative particle"])
        r = pybamm.SpatialVariable("r", domain=["negative particle"])

        disc = tests.get_discretisation_for_testing()
        disc.set_variable_slices([var])
        r_sol = disc.process_symbol(r).entries[:, 0]
        var_sol = disc.process_symbol(var)

        t_sol = [0]
        y_sol = np.ones_like(r_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        pybamm.ProcessedSymbolicVariable(var_sol, sol)

        # Current collector domain
        var = pybamm.Variable("var", domain=["current collector"])
        z = pybamm.SpatialVariable("z", domain=["current collector"])

        disc = tests.get_1p1d_discretisation_for_testing()
        disc.set_variable_slices([var])
        z_sol = disc.process_symbol(z).entries[:, 0]
        var_sol = disc.process_symbol(var)

        t_sol = [0]
        y_sol = np.ones_like(z_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        pybamm.ProcessedSymbolicVariable(var_sol, sol)

        # Other domain
        var = pybamm.Variable("var", domain=["line"])
        x = pybamm.SpatialVariable("x", domain=["line"])

        geometry = pybamm.Geometry(
            {"line": {x: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}}
        )
        submesh_types = {"line": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)}
        var_pts = {x: 10}
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)
        disc = pybamm.Discretisation(mesh, {"line": pybamm.FiniteVolume()})
        disc.set_variable_slices([var])
        x_sol = disc.process_symbol(x).entries[:, 0]
        var_sol = disc.process_symbol(var)

        t_sol = [0]
        y_sol = np.ones_like(x_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        pybamm.ProcessedSymbolicVariable(var_sol, sol)

        # 2D fails
        var = pybamm.Variable(
            "var",
            domain=["negative particle"],
            auxiliary_domains={"secondary": "negative electrode"},
        )
        r = pybamm.SpatialVariable(
            "r",
            domain=["negative particle"],
            auxiliary_domains={"secondary": "negative electrode"},
        )

        disc = tests.get_p2d_discretisation_for_testing()
        disc.set_variable_slices([var])
        r_sol = disc.process_symbol(r).entries[:, 0]
        var_sol = disc.process_symbol(var)

        t_sol = [0]
        y_sol = np.ones_like(r_sol)[:, np.newaxis] * 5
        sol = pybamm.Solution(t_sol, y_sol)
        with self.assertRaisesRegex(NotImplementedError, "Shape not recognized"):
            pybamm.ProcessedSymbolicVariable(var_sol, sol)