diff --git a/CHANGELOG.md b/CHANGELOG.md index c6f57ddeb8..852cadcc0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ -# Unreleased +# [Unreleased](https://github.com/pybamm-team/PyBaMM) ## Features +- Add averaging in secondary dimensions ([#1057](https://github.com/pybamm-team/PyBaMM/pull/1057)) + ## Optimizations ## Bug fixes diff --git a/examples/notebooks/models/compare-lithium-ion.ipynb b/examples/notebooks/models/compare-lithium-ion.ipynb index b94e62c8ce..266775d351 100644 --- a/examples/notebooks/models/compare-lithium-ion.ipynb +++ b/examples/notebooks/models/compare-lithium-ion.ipynb @@ -102,7 +102,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 4, @@ -247,9 +247,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "Solved the Doyle-Fuller-Newman model in 0.567 seconds\n", - "Solved the Single Particle Model in 0.115 seconds\n", - "Solved the Single Particle Model with electrolyte in 0.172 seconds\n" + "Solved the Doyle-Fuller-Newman model in 0.420 seconds\n", + "Solved the Single Particle Model in 0.071 seconds\n", + "Solved the Single Particle Model with electrolyte in 0.190 seconds\n" ] } ], @@ -287,7 +287,7 @@ "outputs": [ { "data": { - "image/png": "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Styq31VM+T0NFOTllpC74tFGo4Zw8eJFgoKCiqQXDEDkqAuePzSwYMECmjRpgsViITExkYsXL9rV88MPP3Dvvffi5eVFq1at+Pvf/050dDRJSUnFynXixAkSExMJCAjAx8eH++67z2FAp5Lw9fWlZcuWHD9+HDACI40ZM4bQ0FC8vb1p2bIlzz77LL/++msRfVetWsXIkSOpW7cu/fv3p1mzZpw/f56ZM2fahoTyn8AcdfvXr19Phw4d8Pb2JjAwkD59+tgi4zniwoULjBs3joYNG+Ll5cW9997Lzp3FbWzwGwMGDODKlSts3frbbjmpqal06dLFLtxuPseOHWPQoEH4+/vj5+dH//79i2wRf/HiRe6//358fX0JDg62C1xVkIpoq9jYWMaNG2f7vHnzZpRSdsOk69atw9PTk2vXrgH2w1NJSUmsW7eOL774wtY2hYd3Vq9eze23346/vz+9e/fm5MmTJcpVVt1ef/11WrVqhdlsJiQkhDlz5hTJ8+WXX9KtWzd8fX257bbbiIuL4/vvv2fFihU8+uijADZd4uLigN+GNb/66ivat2+Pl5cXa9euBVxr04K88sor+Pr62sI6e7obqzO++mY3yj+IvXv3FnvP5+Xl8dJLL3H77bdjNptp2bIlK1euLPG7cUbVR/DQlInIyEgWLVpE06ZN6devny3qnCusWbOGNm3asHTpUk6ePMnEiRN55plneOWVVwC4du0a9913H0FBQbz77rvcuHGDJ554gv/85z9OI+uB8efZpUsXAgMDefXVV/Hx8eGll16iR48eHD58uFTBfnJzc/n5559t1zt37hwBAQH8+c9/xmKxcPjwYWbMmEFWVhavvfaaXdlJkybx3//936xduxZ3d3csFgvdunVj6NChjB07FjDiojvi7bffZuTIkSQmJjJt2jREhM8//5ysrCxCQkKK5M/OzqZHjx5cvHiRuXPn0qBBA5YsWUKPHj04cuSIQ8NeEF9fX/r168e7775Ljx6Go2BqaiqTJ08u8seRnZ1NfHw8JpOJZcuW4eHhQUpKCrGxsezbt8+2Pfro0aPZtm0bCxYsICgoiHnz5nH06FG78LkV1VYxMTGsW7fO9vnLL7/Ey8uL7du326VFRkYWiekBMG3aNE6cOMHFixdt91+TJk1s53fu3MmpU6eYP38+169fZ8KECYwbN46///3vTmUq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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -340,7 +340,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "b6b2e717c7b54c29b0833c8dcd6edc47", + "model_id": "94384243ffee420db59217c59b2dcf6e", "version_major": 2, "version_minor": 0 }, @@ -373,13 +373,13 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "7ff6db1636a842ea9a8afa205201744c", + "model_id": "380e2f7a84974c6fa04c382c17e7dba8", "version_major": 2, "version_minor": 0 }, @@ -442,7 +442,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.9" + "version": "3.7.7" } }, "nbformat": 4, diff --git a/examples/notebooks/models/lead-acid.ipynb b/examples/notebooks/models/lead-acid.ipynb index 76db95b3fc..9e47df0ec1 100644 --- a/examples/notebooks/models/lead-acid.ipynb +++ b/examples/notebooks/models/lead-acid.ipynb @@ -265,9 +265,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "Solved the LOQS model in 0.271 seconds\n", - "Solved the Composite model in 4.829 seconds\n", - "Solved the Full model in 2.230 seconds\n" + "Solved the LOQS model in 0.239 seconds\n", + "Solved the Composite model in 4.143 seconds\n", + "Solved the Full model in 1.681 seconds\n" ] } ], @@ -305,7 +305,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -336,18 +336,18 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "df420d47c9254fff897a100245fea07d", + "model_id": "2f4c688019294c788d8c314e2944cd79", "version_major": 2, "version_minor": 0 }, "text/plain": [ - "interactive(children=(FloatSlider(value=0.0, description='t', max=17.000000000000004, step=0.17000000000000004…" + "interactive(children=(FloatSlider(value=0.0, description='t', max=17.0, step=0.17), Output()), _dom_classes=('…" ] }, "metadata": {}, @@ -369,7 +369,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": { "scrolled": false }, @@ -377,7 +377,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "e6364fa83f8145bb840de1a4a71f7797", + "model_id": "aeef3a8d9cd1429a8324182274ac46d2", "version_major": 2, "version_minor": 0 }, @@ -424,7 +424,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.9" + "version": "3.7.7" } }, "nbformat": 4, diff --git a/examples/scripts/compare_lead_acid.py b/examples/scripts/compare_lead_acid.py index c0a7cf99fb..334788b8d4 100644 --- a/examples/scripts/compare_lead_acid.py +++ b/examples/scripts/compare_lead_acid.py @@ -9,7 +9,7 @@ models = [ pybamm.lead_acid.LOQS(), pybamm.lead_acid.FOQS(), - pybamm.lead_acid.CompositeExtended(), + pybamm.lead_acid.Composite(), pybamm.lead_acid.Full(), ] diff --git a/examples/scripts/compare_lithium_ion_2D.py b/examples/scripts/compare_lithium_ion_2D.py index a6813942e3..4d92dd9430 100644 --- a/examples/scripts/compare_lithium_ion_2D.py +++ b/examples/scripts/compare_lithium_ion_2D.py @@ -18,10 +18,10 @@ # load models models = [ pybamm.lithium_ion.SPM( - {"current collector": "potential pair", "dimensionality": 1}, name="2+1D SPM" + {"current collector": "potential pair", "dimensionality": 1}, name="1+1D SPM" ), pybamm.lithium_ion.SPMe( - {"current collector": "potential pair", "dimensionality": 1}, name="2+1D SPMe" + {"current collector": "potential pair", "dimensionality": 1}, name="1+1D SPMe" ), ] diff --git a/pybamm/discretisations/discretisation.py b/pybamm/discretisations/discretisation.py index 59a61ad4d0..2afdb91020 100644 --- a/pybamm/discretisations/discretisation.py +++ b/pybamm/discretisations/discretisation.py @@ -47,8 +47,18 @@ def __init__(self, mesh=None, spatial_methods=None): spatial_methods["positive electrode"] = method self._spatial_methods = spatial_methods - for method in self._spatial_methods.values(): + for domain, method in self._spatial_methods.items(): method.build(mesh) + # Check zero-dimensional methods are only applied to zero-dimensional + # meshes + if isinstance(method, pybamm.ZeroDimensionalSpatialMethod): + if not isinstance(mesh[domain], pybamm.SubMesh0D): + raise pybamm.DiscretisationError( + "Zero-dimensional spatial method for the " + "{} domain requires a zero-dimensional submesh".format( + domain + ) + ) self.bcs = {} self.y_slices = {} @@ -852,13 +862,18 @@ def _process_symbol(self, symbol): ) elif isinstance(symbol, pybamm.Integral): - out = child_spatial_method.integral(child, disc_child) + integral_spatial_method = self.spatial_methods[ + symbol.integration_variable[0].domain[0] + ] + out = integral_spatial_method.integral( + child, disc_child, symbol._integration_dimension + ) out.copy_domains(symbol) return out elif isinstance(symbol, pybamm.DefiniteIntegralVector): return child_spatial_method.definite_integral_matrix( - child.domains, vector_type=symbol.vector_type + child, vector_type=symbol.vector_type ) elif isinstance(symbol, pybamm.BoundaryIntegral): @@ -934,7 +949,7 @@ def _process_symbol(self, symbol): domain=parent.domain, auxiliary_domains=parent.auxiliary_domains, ) - out = ext[slice(start, end)] + out = pybamm.Index(ext, slice(start, end)) out.domain = symbol.domain return out @@ -1104,10 +1119,9 @@ def check_initial_conditions_rhs(self, model): assert ( model.rhs[var].shape == model.initial_conditions[var].shape ), pybamm.ModelError( - """ - rhs and initial_conditions must have the same shape after discretisation - but rhs.shape = {} and initial_conditions.shape = {} for variable '{}'. - """.format( + "rhs and initial_conditions must have the same shape after " + "discretisation but rhs.shape = " + "{} and initial_conditions.shape = {} for variable '{}'.".format( model.rhs[var].shape, model.initial_conditions[var].shape, var ) ) @@ -1145,17 +1159,20 @@ def check_variables(self, model): not_concatenation = not isinstance(var, pybamm.Concatenation) not_mult_by_one_vec = not ( - isinstance(var, pybamm.Multiplication) - and isinstance(var.right, pybamm.Vector) - and np.all(var.right.entries == 1) + isinstance( + var, (pybamm.Multiplication, pybamm.MatrixMultiplication) + ) + and ( + pybamm.is_matrix_one(var.left) + or pybamm.is_matrix_one(var.right) + ) ) if different_shapes and not_concatenation and not_mult_by_one_vec: raise pybamm.ModelError( - """ - variable and its eqn must have the same shape after discretisation - but variable.shape = {} and rhs.shape = {} for variable '{}'. - """.format( + "variable and its eqn must have the same shape after " + "discretisation but variable.shape = " + "{} and rhs.shape = {} for variable '{}'. ".format( var.shape, model.rhs[rhs_var].shape, var ) ) diff --git a/pybamm/expression_tree/binary_operators.py b/pybamm/expression_tree/binary_operators.py index cc85897df9..f76e4ac7cf 100644 --- a/pybamm/expression_tree/binary_operators.py +++ b/pybamm/expression_tree/binary_operators.py @@ -43,6 +43,19 @@ def is_scalar_one(expr): return False +def is_matrix_one(expr): + """ + Utility function to test if an expression evaluates to a constant matrix one + """ + if expr.is_constant(): + result = expr.evaluate_ignoring_errors(t=None) + return (issparse(result) and np.all(result.toarray() == 1)) or ( + isinstance(result, np.ndarray) and np.all(result == 1) + ) + else: + return False + + def zeros_of_shape(shape): """ Utility function to create a scalar zero, or a vector or matrix of zeros of @@ -199,9 +212,11 @@ def _binary_evaluate(self, left, right): """ Perform binary operation on nodes 'left' and 'right'. """ raise NotImplementedError - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ - return self.left.evaluates_on_edges() or self.right.evaluates_on_edges() + return self.left.evaluates_on_edges(dimension) or self.right.evaluates_on_edges( + dimension + ) class Power(BinaryOperator): @@ -635,7 +650,7 @@ def _binary_simplify(self, left, right): return pybamm.simplify_multiplication_division(self.__class__, left, right) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return False diff --git a/pybamm/expression_tree/broadcasts.py b/pybamm/expression_tree/broadcasts.py index 052b76cba7..fa13b74bc7 100644 --- a/pybamm/expression_tree/broadcasts.py +++ b/pybamm/expression_tree/broadcasts.py @@ -150,7 +150,7 @@ def __init__(self, child, broadcast_domain, name=None): super().__init__(child, broadcast_domain, name) self.broadcast_type = "primary to edges" - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): return True @@ -244,7 +244,7 @@ def __init__(self, child, broadcast_domain, name=None): super().__init__(child, broadcast_domain, name) self.broadcast_type = "secondary to edges" - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): return True @@ -305,7 +305,7 @@ def __init__(self, child, broadcast_domain, auxiliary_domains, name=None): super().__init__(child, broadcast_domain, auxiliary_domains, name) self.broadcast_type = "full to edges" - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): return True diff --git a/pybamm/expression_tree/concatenations.py b/pybamm/expression_tree/concatenations.py index dd5fe4607a..611b45773b 100644 --- a/pybamm/expression_tree/concatenations.py +++ b/pybamm/expression_tree/concatenations.py @@ -294,7 +294,7 @@ def _concatenation_jac(self, children_jacs): a single domain""" ) child_slice = next(iter(slices.values())) - jacs.append(child_jac[child_slice[i]]) + jacs.append(pybamm.Index(child_jac, child_slice[i])) return SparseStack(*jacs) def _concatenation_new_copy(self, children): diff --git a/pybamm/expression_tree/functions.py b/pybamm/expression_tree/functions.py index ce1d58c7d6..a8eadd22dd 100644 --- a/pybamm/expression_tree/functions.py +++ b/pybamm/expression_tree/functions.py @@ -169,9 +169,9 @@ def evaluate(self, t=None, y=None, y_dot=None, inputs=None, known_evals=None): ] return self._function_evaluate(evaluated_children) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ - return any(child.evaluates_on_edges() for child in self.children) + return any(child.evaluates_on_edges(dimension) for child in self.children) def _evaluate_for_shape(self): """ @@ -450,5 +450,3 @@ def _function_diff(self, children, idx): def arctan(child): " Returns hyperbolic tan function of child. " return pybamm.simplify_if_constant(Arctan(child), keep_domains=True) - - diff --git a/pybamm/expression_tree/independent_variable.py b/pybamm/expression_tree/independent_variable.py index bce3153ee3..bb4dca0817 100644 --- a/pybamm/expression_tree/independent_variable.py +++ b/pybamm/expression_tree/independent_variable.py @@ -127,7 +127,7 @@ class SpatialVariableEdge(SpatialVariable): def __init__(self, name, domain=None, auxiliary_domains=None, coord_sys=None): super().__init__(name, domain, auxiliary_domains, coord_sys) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): return True diff --git a/pybamm/expression_tree/input_parameter.py b/pybamm/expression_tree/input_parameter.py index e12b12565d..e63242cf81 100644 --- a/pybamm/expression_tree/input_parameter.py +++ b/pybamm/expression_tree/input_parameter.py @@ -41,7 +41,7 @@ def _evaluate_for_shape(self): Returns the scalar 'NaN' to represent the shape of a parameter. See :meth:`pybamm.Symbol.evaluate_for_shape()` """ - return np.nan * np.ones_like(self._expected_size) + return np.nan * np.ones((self._expected_size, 1)) def _jac(self, variable): """ See :meth:`pybamm.Symbol._jac()`. """ @@ -55,7 +55,7 @@ def _base_evaluate(self, t=None, y=None, y_dot=None, inputs=None): if not isinstance(inputs, dict): # if the special input "shape test" is passed, just return 1 if inputs == "shape test": - return np.ones_like(self._expected_size) + return np.ones((self._expected_size, 1)) raise TypeError("inputs should be a dictionary") try: input_eval = inputs[self.name] @@ -64,15 +64,20 @@ def _base_evaluate(self, t=None, y=None, y_dot=None, inputs=None): raise KeyError("Input parameter '{}' not found".format(self.name)) if isinstance(input_eval, numbers.Number): - input_shape = 1 + input_size = 1 + input_ndim = 0 else: - input_shape = input_eval.shape[0] - if input_shape == self._expected_size: - return input_eval + input_size = input_eval.shape[0] + input_ndim = len(input_eval.shape) + if input_size == self._expected_size: + if input_ndim == 1: + return input_eval[:, np.newaxis] + else: + return input_eval else: raise ValueError( "Input parameter '{}' was given an object of size '{}'".format( - self.name, input_shape + self.name, input_size ) + " but was expecting an object of size '{}'.".format( self._expected_size diff --git a/pybamm/expression_tree/operations/simplify.py b/pybamm/expression_tree/operations/simplify.py index 60282c893e..37ff117cee 100644 --- a/pybamm/expression_tree/operations/simplify.py +++ b/pybamm/expression_tree/operations/simplify.py @@ -611,7 +611,9 @@ def _simplify(self, symbol, clear_domains=True): elif isinstance(symbol, pybamm.UnaryOperator): # Reassign domain for gradient and divergence - if isinstance(symbol, (pybamm.Gradient, pybamm.Divergence)): + if isinstance( + symbol, (pybamm.Gradient, pybamm.Divergence, pybamm.Integral) + ): new_child = self.simplify(symbol.child, clear_domains=False) else: new_child = self.simplify(symbol.child) diff --git a/pybamm/expression_tree/symbol.py b/pybamm/expression_tree/symbol.py index 635521b751..6693d22acd 100644 --- a/pybamm/expression_tree/symbol.py +++ b/pybamm/expression_tree/symbol.py @@ -467,10 +467,6 @@ def __abs__(self): pybamm.AbsoluteValue(self), keep_domains=True ) - def __getitem__(self, key): - """return a :class:`Index` object""" - return pybamm.simplify_if_constant(pybamm.Index(self, key), keep_domains=True) - def diff(self, variable): """ Differentiate a symbol with respect to a variable. For any symbol that can be @@ -670,16 +666,28 @@ def evaluates_to_number(self): result = self.evaluate_ignoring_errors() if isinstance(result, numbers.Number) or ( - isinstance(result, np.ndarray) and result.shape == () + isinstance(result, np.ndarray) and np.prod(result.shape) == 1 ): return True else: return False - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ Returns True if a symbol evaluates on an edge, i.e. symbol contains a gradient operator, but not a divergence operator, and is not an IndefiniteIntegral. + + Parameters + ---------- + dimension : str + The dimension (primary, secondary, etc) in which to query evaluation on + edges + + Returns + ------- + bool + Whether the symbol evaluates on edges (in the finite volume discretisation + sense) """ # Default behaviour: return False return False diff --git a/pybamm/expression_tree/unary_operators.py b/pybamm/expression_tree/unary_operators.py index 78a08181a0..7c7e0e6a9a 100644 --- a/pybamm/expression_tree/unary_operators.py +++ b/pybamm/expression_tree/unary_operators.py @@ -83,9 +83,9 @@ def _evaluate_for_shape(self): """ return self.children[0].evaluate_for_shape() - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ - return self.child.evaluates_on_edges() + return self.child.evaluates_on_edges(dimension) class Negate(UnaryOperator): @@ -188,7 +188,7 @@ class Index(UnaryOperator): def __init__(self, child, index, name=None, check_size=True): self.index = index if index == -1: - self.slice = slice(index, None) + self.slice = slice(-1, None) if name is None: name = "Index[-1]" elif isinstance(index, int): @@ -255,7 +255,7 @@ def _unary_new_copy(self, child): def _evaluate_for_shape(self): return self._unary_evaluate(self.children[0].evaluate_for_shape()) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return False @@ -316,13 +316,13 @@ def __init__(self, child): + "Try broadcasting the object first, e.g.\n\n" "\tpybamm.grad(pybamm.PrimaryBroadcast(symbol, 'domain'))" ) - if child.evaluates_on_edges() is True: + if child.evaluates_on_edges("primary") is True: raise TypeError( "Cannot take gradient of '{}' since it evaluates on edges".format(child) ) super().__init__("grad", child) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return True @@ -342,7 +342,7 @@ def __init__(self, child): + "Try broadcasting the object first, e.g.\n\n" "\tpybamm.div(pybamm.PrimaryBroadcast(symbol, 'domain'))" ) - if child.evaluates_on_edges() is False: + if child.evaluates_on_edges("primary") is False: raise TypeError( "Cannot take divergence of '{}' since it does not ".format(child) + "evaluates on nodes. Usually, a gradient should be taken before the " @@ -350,7 +350,7 @@ def __init__(self, child): ) super().__init__("div", child) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return False @@ -365,7 +365,7 @@ class Laplacian(SpatialOperator): def __init__(self, child): super().__init__("laplacian", child) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return False @@ -381,7 +381,7 @@ class Gradient_Squared(SpatialOperator): def __init__(self, child): super().__init__("grad squared", child) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return True @@ -421,7 +421,6 @@ class Integral(SpatialOperator): where :math:`a` and :math:`b` are the left-hand and right-hand boundaries of the domain respectively, and :math:`u\\in\\text{domain}`. - Can be integration with respect to time or space. Parameters ---------- @@ -437,34 +436,61 @@ def __init__(self, child, integration_variable): if not isinstance(integration_variable, list): integration_variable = [integration_variable] - # integral of a child takes the domain from auxiliary domain of the child - if child.auxiliary_domains != {}: - domain = child.auxiliary_domains["secondary"] - try: - auxiliary_domains = {"secondary": child.auxiliary_domains["tertiary"]} - except KeyError: - auxiliary_domains = {} - # if child has no auxiliary domain, integral removes domain - else: - domain = [] - auxiliary_domains = {} name = "integral" for var in integration_variable: if isinstance(var, pybamm.SpatialVariable): # Check that child and integration_variable domains agree - if child.domain != var.domain: + if var.domain == child.domain: + self._integration_dimension = "primary" + elif ( + "secondary" in child.auxiliary_domains + and var.domain == child.auxiliary_domains["secondary"] + ): + self._integration_dimension = "secondary" + elif ( + "tertiary" in child.auxiliary_domains + and var.domain == child.auxiliary_domains["tertiary"] + ): + self._integration_dimension = "tertiary" + else: raise pybamm.DomainError( - "child and integration_variable must have the same domain" - ) - elif not isinstance(var, pybamm.IndependentVariable): - raise ValueError( - """integration_variable must be of type pybamm.IndependentVariable, - not {}""".format( - type(var) + "integration_variable must be the same as child domain or " + "an auxiliary domain" ) + else: + raise TypeError( + "integration_variable must be of type pybamm.SpatialVariable, " + "not {}".format(type(var)) ) name += " d{}".format(var.name) + if self._integration_dimension == "primary": + # integral of a child takes the domain from auxiliary domain of the child + if child.auxiliary_domains != {}: + domain = child.auxiliary_domains["secondary"] + if "tertiary" in child.auxiliary_domains: + auxiliary_domains = { + "secondary": child.auxiliary_domains["tertiary"] + } + else: + auxiliary_domains = {} + # if child has no auxiliary domain, integral removes domain + else: + domain = [] + auxiliary_domains = {} + elif self._integration_dimension == "secondary": + # integral in the secondary dimension keeps the same domain, moves tertiary + # domain to secondary domain + domain = child.domain + if "tertiary" in child.auxiliary_domains: + auxiliary_domains = {"secondary": child.auxiliary_domains["tertiary"]} + else: + auxiliary_domains = {} + elif self._integration_dimension == "tertiary": + # integral in the tertiary dimension keeps the domain and secondary domain + domain = child.domain + auxiliary_domains = {"secondary": child.auxiliary_domains["secondary"]} + if any(isinstance(var, pybamm.SpatialVariable) for var in integration_variable): name += " {}".format(child.domain) @@ -505,7 +531,7 @@ def _evaluate_for_shape(self): """ See :meth:`pybamm.Symbol.evaluate_for_shape_using_domain()` """ return pybamm.evaluate_for_shape_using_domain(self.domain) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return False @@ -538,10 +564,10 @@ def __init__(self, child, integration_variable): def _evaluate_for_shape(self): return self.children[0].evaluate_for_shape() - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): # If child evaluates on edges, indefinite integral doesn't # If child doesn't evaluate on edges, indefinite integral does - return not self.child.evaluates_on_edges() + return not self.child.evaluates_on_edges(dimension) class IndefiniteIntegral(BaseIndefiniteIntegral): @@ -713,7 +739,7 @@ def _evaluate_for_shape(self): """ See :meth:`pybamm.Symbol.evaluate_for_shape_using_domain()` """ return pybamm.evaluate_for_shape_using_domain(self.domain) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return False @@ -749,7 +775,7 @@ def set_id(self): + tuple([(k, tuple(v)) for k, v in self.auxiliary_domains.items()]) ) - def evaluates_on_edges(self): + def evaluates_on_edges(self, dimension): """ See :meth:`pybamm.Symbol.evaluates_on_edges()`. """ return False @@ -997,7 +1023,7 @@ def x_average(symbol): the new averaged symbol """ # Can't take average if the symbol evaluates on edges - if symbol.evaluates_on_edges(): + if symbol.evaluates_on_edges("primary"): raise ValueError("Can't take the x-average of a symbol that evaluates on edges") # If symbol doesn't have a domain, its average value is itself if symbol.domain in [[], ["current collector"]]: @@ -1062,7 +1088,7 @@ def z_average(symbol): the new averaged symbol """ # Can't take average if the symbol evaluates on edges - if symbol.evaluates_on_edges(): + if symbol.evaluates_on_edges("primary"): raise ValueError("Can't take the z-average of a symbol that evaluates on edges") # Symbol must have domain [] or ["current collector"] if symbol.domain not in [[], ["current collector"]]: @@ -1139,7 +1165,7 @@ def r_average(symbol): the new averaged symbol """ # Can't take average if the symbol evaluates on edges - if symbol.evaluates_on_edges(): + if symbol.evaluates_on_edges("primary"): raise ValueError("Can't take the r-average of a symbol that evaluates on edges") # If symbol doesn't have a particle domain, its r-averaged value is itself if symbol.domain not in [["positive particle"], ["negative particle"]]: diff --git a/pybamm/meshes/zero_dimensional_submesh.py b/pybamm/meshes/zero_dimensional_submesh.py index bf14954390..c443add1b1 100644 --- a/pybamm/meshes/zero_dimensional_submesh.py +++ b/pybamm/meshes/zero_dimensional_submesh.py @@ -32,7 +32,9 @@ def __init__(self, position, npts=None): if len(position) != 1: raise pybamm.GeometryError("position should only contain a single variable") - spatial_position = list(position.values())[0] + # extract the position + position = list(position.values())[0] + spatial_position = position["position"] self.nodes = np.array([spatial_position]) self.edges = np.array([spatial_position]) self.coord_sys = None diff --git a/pybamm/models/submodels/interface/diffusion_limited.py b/pybamm/models/submodels/interface/diffusion_limited.py index 6de23c2789..2f2890000f 100644 --- a/pybamm/models/submodels/interface/diffusion_limited.py +++ b/pybamm/models/submodels/interface/diffusion_limited.py @@ -145,7 +145,7 @@ def _get_j_diffusion_limited_first_order(self, variables): param = self.param if self.domain == "Negative": N_ox_s_p = variables["Oxygen flux"].orphans[1] - N_ox_neg_sep_interface = N_ox_s_p[0] + N_ox_neg_sep_interface = pybamm.Index(N_ox_s_p, slice(0, 1)) j = -N_ox_neg_sep_interface / param.C_e / -param.s_ox_Ox / param.l_n diff --git a/pybamm/models/submodels/particle/base_particle.py b/pybamm/models/submodels/particle/base_particle.py index e9b2e2e732..28a696f3c6 100644 --- a/pybamm/models/submodels/particle/base_particle.py +++ b/pybamm/models/submodels/particle/base_particle.py @@ -34,8 +34,8 @@ def _get_standard_concentration_variables(self, c_s, c_s_xav): elif self.domain == "Positive": c_scale = self.param.c_p_max active_volume = geo_param.a_p_dim * geo_param.R_p / 3 - c_s_r_av = pybamm.r_average(c_s_xav) - c_s_r_av_vol = active_volume * c_s_r_av + c_s_av = pybamm.r_average(c_s_xav) + c_s_av_vol = active_volume * c_s_av variables = { self.domain + " particle concentration": c_s, self.domain + " particle concentration [mol.m-3]": c_s * c_scale, @@ -53,11 +53,11 @@ def _get_standard_concentration_variables(self, c_s, c_s_xav): + self.domain.lower() + " particle surface concentration [mol.m-3]": c_scale * c_s_surf_av, self.domain + " electrode active volume fraction": active_volume, - self.domain + " electrode volume-averaged concentration": c_s_r_av_vol, + self.domain + " electrode volume-averaged concentration": c_s_av_vol, self.domain + " electrode " - + "volume-averaged concentration [mol.m-3]": c_s_r_av_vol * c_scale, - self.domain + " electrode average extent of lithiation": c_s_r_av, + + "volume-averaged concentration [mol.m-3]": c_s_av_vol * c_scale, + self.domain + " electrode average extent of lithiation": c_s_av, } return variables diff --git a/pybamm/models/submodels/particle/fickian_many_particles.py b/pybamm/models/submodels/particle/fickian_many_particles.py index 3cb2a639ac..a2515c1491 100644 --- a/pybamm/models/submodels/particle/fickian_many_particles.py +++ b/pybamm/models/submodels/particle/fickian_many_particles.py @@ -30,9 +30,8 @@ def get_fundamental_variables(self): elif self.domain == "Positive": c_s = pybamm.standard_variables.c_s_p - # TODO: implement c_s_xav for Fickian many particles (tricky because this - # requires averaging a secondary domain) - variables = self._get_standard_concentration_variables(c_s, c_s) + c_s_xav = pybamm.x_average(c_s) + variables = self._get_standard_concentration_variables(c_s, c_s_xav) return variables diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 292b66a34d..4a3c5db8f2 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -255,9 +255,7 @@ def _yz_average(self, var): "Computes the y-z average" # TODO: change the behaviour of z_average and yz_average so the if statement # can be removed - if self.cc_dimension == 0: - return var - elif self.cc_dimension == 1: + if self.cc_dimension in [0, 1]: return pybamm.z_average(var) elif self.cc_dimension == 2: return pybamm.yz_average(var) diff --git a/pybamm/spatial_methods/finite_volume.py b/pybamm/spatial_methods/finite_volume.py index dedabadda0..c2e9683cbd 100644 --- a/pybamm/spatial_methods/finite_volume.py +++ b/pybamm/spatial_methods/finite_volume.py @@ -59,7 +59,7 @@ def spatial_variable(self, symbol): """ symbol_mesh = self.mesh.combine_submeshes(*symbol.domain) repeats = self._get_auxiliary_domain_repeats(symbol.auxiliary_domains) - if symbol.evaluates_on_edges(): + if symbol.evaluates_on_edges("primary"): entries = np.tile(symbol_mesh.edges, repeats) else: entries = np.tile(symbol_mesh.nodes, repeats) @@ -229,13 +229,15 @@ def laplacian(self, symbol, discretised_symbol, boundary_conditions): grad = self.gradient(symbol, discretised_symbol, boundary_conditions) return self.divergence(grad, grad, boundary_conditions) - def integral(self, child, discretised_child): + def integral(self, child, discretised_child, integration_dimension): """Vector-vector dot product to implement the integral operator. """ - # Calculate integration vector - integration_vector = self.definite_integral_matrix(child.domains) + integration_vector = self.definite_integral_matrix( + child, integration_dimension=integration_dimension + ) # Check for spherical domains - submesh = self.mesh.combine_submeshes(*child.domain) + domain = child.domains[integration_dimension] + submesh = self.mesh.combine_submeshes(*domain) if submesh.coord_sys == "spherical polar": second_dim_repeats = self._get_auxiliary_domain_repeats(child.domains) r_numpy = np.kron(np.ones(second_dim_repeats), submesh.nodes) @@ -244,11 +246,11 @@ def integral(self, child, discretised_child): else: out = integration_vector @ discretised_child - out.copy_domains(child) - return out - def definite_integral_matrix(self, domains, vector_type="row"): + def definite_integral_matrix( + self, child, vector_type="row", integration_dimension="primary" + ): """ Matrix for finite-volume implementation of the definite integral in the primary dimension @@ -261,54 +263,94 @@ def definite_integral_matrix(self, domains, vector_type="row"): Parameters ---------- - domains : dict - The domain(s) and auxiliary domains of integration + child : :class:`pybamm.Symbol` + The symbol being integrated + vector_type : str, optional + Whether to return a row or column vector in the primary dimension + (default is row) + integration_dimension : str, optional + The dimension in which to integrate (default is "primary") Returns ------- :class:`pybamm.Matrix` The finite volume integral matrix for the domain - vector_type : str, optional - Whether to return a row or column vector in the primary dimension - (default is row) """ - # Create appropriate submesh by combining submeshes in domain - submesh = self.mesh.combine_submeshes(*domains["primary"]) - - # Create vector of ones for primary domain submesh - vector = submesh.d_edges - - if vector_type == "row": - vector = vector[np.newaxis, :] - elif vector_type == "column": - vector = vector[:, np.newaxis] + domains = child.domains + if integration_dimension == "primary": + # Create appropriate submesh by combining submeshes in domain + submesh = self.mesh.combine_submeshes(*domains["primary"]) + + # Create vector of ones for primary domain submesh + vector = submesh.d_edges + + if vector_type == "row": + vector = vector[np.newaxis, :] + elif vector_type == "column": + vector = vector[:, np.newaxis] + + # repeat matrix for each node in secondary dimensions + second_dim_repeats = self._get_auxiliary_domain_repeats(domains) + # generate full matrix from the submatrix + matrix = kron(eye(second_dim_repeats), vector) + elif integration_dimension == "secondary": + if vector_type != "row": + raise NotImplementedError( + "Integral in secondary vector only implemented in 'row' form" + ) + # Create appropriate submesh by combining submeshes in domain + primary_submesh = self.mesh.combine_submeshes(*domains["primary"]) + secondary_submesh = self.mesh.combine_submeshes(*domains["secondary"]) + + # Create matrix which integrates in the secondary dimension + d_edges = secondary_submesh.d_edges + # Different number of edges depending on whether child evaluates on edges + # in the primary dimensions + if child.evaluates_on_edges("primary"): + n_primary_pts = primary_submesh.npts + 1 + else: + n_primary_pts = primary_submesh.npts + int_matrix = hstack([d_edge * eye(n_primary_pts) for d_edge in d_edges]) - # repeat matrix for each node in secondary dimensions - second_dim_repeats = self._get_auxiliary_domain_repeats(domains) + # repeat matrix for each node in secondary dimensions + third_dim_repeats = self._get_auxiliary_domain_repeats( + domains, tertiary_only=True + ) + # generate full matrix from the submatrix + matrix = kron(eye(third_dim_repeats), int_matrix) # generate full matrix from the submatrix # Convert to csr_matrix so that we can take the index (row-slicing), which is # not supported by the default kron format # Note that this makes column-slicing inefficient, but this should not be an # issue - matrix = csr_matrix(kron(eye(second_dim_repeats), vector)) - return pybamm.Matrix(matrix) + return pybamm.Matrix(csr_matrix(matrix)) def indefinite_integral(self, child, discretised_child, direction): """Implementation of the indefinite integral operator. """ # Different integral matrix depending on whether the integrand evaluates on # edges or nodes - if child.evaluates_on_edges(): + if child.evaluates_on_edges("primary"): integration_matrix = self.indefinite_integral_matrix_edges( child.domains, direction ) else: + # Check coordinate system is not spherical polar for the case where child + # evaluates on edges + # If it becomes necessary to implement this, will need to think about what + # the spherical polar indefinite integral should be + submesh = self.mesh.combine_submeshes(*child.domain) + if submesh.coord_sys == "spherical polar": + raise NotImplementedError( + "Indefinite integral on a spherical polar domain is not implemented" + ) integration_matrix = self.indefinite_integral_matrix_nodes( child.domains, direction ) - # Don't need to check for spherical domains as spherical polars - # only change the diveregence (childs here have grad and no div) + # Don't need to check for spherical domains as we have ruled out spherical + # polars in the case that involves integrating a divergence + # (child evaluates on nodes) out = integration_matrix @ discretised_child out.copy_domains(child) @@ -1054,8 +1096,8 @@ def process_binary_operators(self, bin_op, left, right, disc_left, disc_right): """ # Post-processing to make sure discretised dimensions match - left_evaluates_on_edges = left.evaluates_on_edges() - right_evaluates_on_edges = right.evaluates_on_edges() + left_evaluates_on_edges = left.evaluates_on_edges("primary") + right_evaluates_on_edges = right.evaluates_on_edges("primary") # inner product takes fluxes from edges to nodes if isinstance(bin_op, pybamm.Inner): diff --git a/pybamm/spatial_methods/scikit_finite_element.py b/pybamm/spatial_methods/scikit_finite_element.py index fc8055d453..2b6457b3c6 100644 --- a/pybamm/spatial_methods/scikit_finite_element.py +++ b/pybamm/spatial_methods/scikit_finite_element.py @@ -292,18 +292,18 @@ def stiffness_form(u, du, v, dv, w): return pybamm.Matrix(stiffness) - def integral(self, child, discretised_child): + def integral(self, child, discretised_child, integration_dimension): """Vector-vector dot product to implement the integral operator. See :meth:`pybamm.SpatialMethod.integral` """ # Calculate integration vector - integration_vector = self.definite_integral_matrix(child.domains) + integration_vector = self.definite_integral_matrix(child) out = integration_vector @ discretised_child return out - def definite_integral_matrix(self, domains, vector_type="row"): + def definite_integral_matrix(self, child, vector_type="row"): """ Matrix for finite-element implementation of the definite integral over the entire domain @@ -315,8 +315,8 @@ def definite_integral_matrix(self, domains, vector_type="row"): Parameters ---------- - domains : dict - The domain(s) of integration + child : :class:`pybamm.Symbol` + The symbol being integrated vector_type : str, optional Whether to return a row or column vector (default is row) @@ -326,7 +326,7 @@ def definite_integral_matrix(self, domains, vector_type="row"): The finite element integral vector for the domain """ # get primary domain mesh - domain = domains["primary"] + domain = child.domains["primary"] if isinstance(domain, list): domain = domain[0] mesh = self.mesh[domain] @@ -344,7 +344,7 @@ def integral_form(v, dv, w): elif vector_type == "column": return pybamm.Matrix(vector[:, np.newaxis]) - def indefinite_integral(self, child, discretised_child): + def indefinite_integral(self, child, discretised_child, direction): """Implementation of the indefinite integral operator. The input discretised child must be defined on the internal mesh edges. See :meth:`pybamm.SpatialMethod.indefinite_integral` diff --git a/pybamm/spatial_methods/spatial_method.py b/pybamm/spatial_methods/spatial_method.py index 9a33901ae2..e5d4605e86 100644 --- a/pybamm/spatial_methods/spatial_method.py +++ b/pybamm/spatial_methods/spatial_method.py @@ -40,11 +40,11 @@ def build(self, mesh): mesh[dom].npts_for_broadcast_to_nodes = mesh[dom].npts self._mesh = mesh - def _get_auxiliary_domain_repeats(self, auxiliary_domains): + def _get_auxiliary_domain_repeats(self, auxiliary_domains, tertiary_only=False): """ Helper method to read the 'auxiliary_domain' meshes """ - if "secondary" in auxiliary_domains: + if tertiary_only is False and "secondary" in auxiliary_domains: sec_mesh_npts = self.mesh.combine_submeshes( *auxiliary_domains["secondary"] ).npts @@ -80,7 +80,7 @@ def spatial_variable(self, symbol): """ symbol_mesh = self.mesh.combine_submeshes(*symbol.domain) repeats = self._get_auxiliary_domain_repeats(symbol.auxiliary_domains) - if symbol.evaluates_on_edges(): + if symbol.evaluates_on_edges("primary"): entries = np.tile(symbol_mesh.edges, repeats) else: entries = np.tile(symbol_mesh.nodes, repeats) @@ -231,7 +231,7 @@ def gradient_squared(self, symbol, discretised_symbol, boundary_conditions): """ raise NotImplementedError - def integral(self, child, discretised_child): + def integral(self, child, discretised_child, integration_dimension): """ Implements the integral for a spatial method. @@ -241,6 +241,8 @@ def integral(self, child, discretised_child): The symbol to which is being integrated discretised_child: :class:`pybamm.Symbol` The discretised symbol of the correct size + integration_dimension : str, optional + The dimension in which to integrate (default is "primary") Returns ------- diff --git a/pybamm/spatial_methods/zero_dimensional_method.py b/pybamm/spatial_methods/zero_dimensional_method.py index 8452700993..e91ffd4045 100644 --- a/pybamm/spatial_methods/zero_dimensional_method.py +++ b/pybamm/spatial_methods/zero_dimensional_method.py @@ -48,7 +48,7 @@ def indefinite_integral(self, child, discretised_child, direction): elif direction == "backward": return -discretised_child - def integral(self, child, discretised_child): + def integral(self, child, discretised_child, integration_dimension): """ Calculates the zero-dimensional integral, i.e. the identity operator """ diff --git a/tests/shared.py b/tests/shared.py index 17f47df37b..e366526a8b 100644 --- a/tests/shared.py +++ b/tests/shared.py @@ -99,16 +99,20 @@ def get_p2d_mesh_for_testing(xpts=None, rpts=10): def get_1p1d_mesh_for_testing( - xpts=None, zpts=15, cc_submesh=pybamm.MeshGenerator(pybamm.Uniform1DSubMesh) + xpts=None, + rpts=10, + zpts=15, + cc_submesh=pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), ): geometry = pybamm.battery_geometry(current_collector_dimension=1) return get_mesh_for_testing( - xpts=xpts, zpts=zpts, geometry=geometry, cc_submesh=cc_submesh + xpts=xpts, rpts=rpts, zpts=zpts, geometry=geometry, cc_submesh=cc_submesh ) def get_2p1d_mesh_for_testing( xpts=None, + rpts=10, ypts=15, zpts=15, include_particles=True, @@ -118,7 +122,12 @@ def get_2p1d_mesh_for_testing( include_particles=include_particles, current_collector_dimension=2 ) return get_mesh_for_testing( - xpts=xpts, zpts=zpts, geometry=geometry, cc_submesh=cc_submesh + xpts=xpts, + rpts=rpts, + ypts=ypts, + zpts=zpts, + geometry=geometry, + cc_submesh=cc_submesh, ) @@ -175,14 +184,16 @@ def get_p2d_discretisation_for_testing(xpts=None, rpts=10): return get_discretisation_for_testing(mesh=get_p2d_mesh_for_testing(xpts, rpts)) -def get_1p1d_discretisation_for_testing(xpts=None, zpts=15): - return get_discretisation_for_testing(mesh=get_1p1d_mesh_for_testing(xpts, zpts)) +def get_1p1d_discretisation_for_testing(xpts=None, rpts=10, zpts=15): + return get_discretisation_for_testing( + mesh=get_1p1d_mesh_for_testing(xpts, rpts, zpts) + ) def get_2p1d_discretisation_for_testing( - xpts=None, ypts=15, zpts=15, include_particles=True + xpts=None, rpts=10, ypts=15, zpts=15, include_particles=True ): return get_discretisation_for_testing( - mesh=get_2p1d_mesh_for_testing(xpts, ypts, zpts, include_particles), + mesh=get_2p1d_mesh_for_testing(xpts, rpts, ypts, zpts, include_particles), cc_method=pybamm.ScikitFiniteElement, ) diff --git a/tests/unit/test_discretisations/test_discretisation.py b/tests/unit/test_discretisations/test_discretisation.py index 1508ffc379..f827a5a135 100644 --- a/tests/unit/test_discretisations/test_discretisation.py +++ b/tests/unit/test_discretisations/test_discretisation.py @@ -1124,6 +1124,18 @@ def test_exceptions(self): } disc.process_model(model) + # Check setting up a 0D spatial method with 1D mesh raises error + mesh = get_mesh_for_testing() + spatial_methods = { + "macroscale": pybamm.FiniteVolume(), + "negative particle": pybamm.FiniteVolume(), + "positive particle": pybamm.ZeroDimensionalSpatialMethod(), + } + with self.assertRaisesRegex( + pybamm.DiscretisationError, "Zero-dimensional spatial method for the " + ): + pybamm.Discretisation(mesh, spatial_methods) + def test_check_tab_bcs_error(self): a = pybamm.Variable("a", domain=["current collector"]) b = pybamm.Variable("b", domain=["negative electrode"]) @@ -1164,7 +1176,11 @@ def test_mass_matrix_inverse(self): "current collector": pybamm.ScikitFiniteElement(), } # create model - a = pybamm.Variable("a", domain="negative electrode") + a = pybamm.Variable( + "a", + domain="negative electrode", + auxiliary_domains={"secondary": "current collector"}, + ) b = pybamm.Variable("b", domain="current collector") model = pybamm.BaseModel() model.rhs = {a: pybamm.Laplacian(a), b: 4 * pybamm.Laplacian(b)} diff --git a/tests/unit/test_expression_tree/test_binary_operators.py b/tests/unit/test_expression_tree/test_binary_operators.py index e6c8dc26b0..02a4b5ceab 100644 --- a/tests/unit/test_expression_tree/test_binary_operators.py +++ b/tests/unit/test_expression_tree/test_binary_operators.py @@ -270,7 +270,7 @@ def test_inner(self): disc.process_model(model) # check doesn't evaluate on edges anymore - self.assertEqual(model.variables["inner"].evaluates_on_edges(), False) + self.assertEqual(model.variables["inner"].evaluates_on_edges("primary"), False) def test_source(self): u = pybamm.Variable("u", domain="current collector") diff --git a/tests/unit/test_expression_tree/test_broadcasts.py b/tests/unit/test_expression_tree/test_broadcasts.py index d666f67e12..db62712e26 100644 --- a/tests/unit/test_expression_tree/test_broadcasts.py +++ b/tests/unit/test_expression_tree/test_broadcasts.py @@ -118,7 +118,7 @@ def test_broadcast_to_edges(self): self.assertEqual(broad_a.name, "broadcast to edges") self.assertEqual(broad_a.children[0].name, a.name) self.assertEqual(broad_a.domain, ["negative electrode"]) - self.assertTrue(broad_a.evaluates_on_edges()) + self.assertTrue(broad_a.evaluates_on_edges("primary")) a = pybamm.Symbol( "a", @@ -131,7 +131,7 @@ def test_broadcast_to_edges(self): broad_a.auxiliary_domains, {"secondary": ["negative electrode"], "tertiary": ["current collector"]}, ) - self.assertTrue(broad_a.evaluates_on_edges()) + self.assertTrue(broad_a.evaluates_on_edges("primary")) a = pybamm.Symbol("a") broad_a = pybamm.FullBroadcastToEdges( @@ -139,7 +139,7 @@ def test_broadcast_to_edges(self): ) self.assertEqual(broad_a.domain, ["negative electrode"]) self.assertEqual(broad_a.auxiliary_domains["secondary"], ["current collector"]) - self.assertTrue(broad_a.evaluates_on_edges()) + self.assertTrue(broad_a.evaluates_on_edges("primary")) if __name__ == "__main__": diff --git a/tests/unit/test_expression_tree/test_independent_variable.py b/tests/unit/test_expression_tree/test_independent_variable.py index a00fa9079d..01b554f2e8 100644 --- a/tests/unit/test_expression_tree/test_independent_variable.py +++ b/tests/unit/test_expression_tree/test_independent_variable.py @@ -36,7 +36,7 @@ def test_time(self): def test_spatial_variable(self): x = pybamm.SpatialVariable("x", "negative electrode") self.assertEqual(x.name, "x") - self.assertFalse(x.evaluates_on_edges()) + self.assertFalse(x.evaluates_on_edges("primary")) y = pybamm.SpatialVariable("y", "separator") self.assertEqual(y.name, "y") z = pybamm.SpatialVariable("z", "positive electrode") @@ -60,7 +60,7 @@ def test_spatial_variable(self): def test_spatial_variable_edge(self): x = pybamm.SpatialVariableEdge("x", "negative electrode") self.assertEqual(x.name, "x") - self.assertTrue(x.evaluates_on_edges()) + self.assertTrue(x.evaluates_on_edges("primary")) if __name__ == "__main__": diff --git a/tests/unit/test_expression_tree/test_input_parameter.py b/tests/unit/test_expression_tree/test_input_parameter.py index f2d1e3b176..d41c40673e 100644 --- a/tests/unit/test_expression_tree/test_input_parameter.py +++ b/tests/unit/test_expression_tree/test_input_parameter.py @@ -17,8 +17,9 @@ def test_set_expected_size(self): a = pybamm.InputParameter("a") a.set_expected_size(10) self.assertEqual(a._expected_size, 10) + np.testing.assert_array_equal(a.evaluate(inputs="shape test"), np.ones((10, 1))) y = np.linspace(0, 1, 10) - np.testing.assert_array_equal(a.evaluate(inputs={"a": y}), y) + np.testing.assert_array_equal(a.evaluate(inputs={"a": y}), y[:, np.newaxis]) with self.assertRaisesRegex( ValueError, "Input parameter 'a' was given an object of size '1' but was expecting an " @@ -29,6 +30,10 @@ def test_set_expected_size(self): def test_evaluate_for_shape(self): a = pybamm.InputParameter("a") self.assertTrue(np.isnan(a.evaluate_for_shape())) + self.assertEqual(a.shape, (1, 1)) + + a.set_expected_size(10) + self.assertEqual(a.shape, (10, 1)) def test_errors(self): a = pybamm.InputParameter("a") diff --git a/tests/unit/test_expression_tree/test_operations/test_copy.py b/tests/unit/test_expression_tree/test_operations/test_copy.py index e7ddbf3057..ef6d3a0638 100644 --- a/tests/unit/test_expression_tree/test_operations/test_copy.py +++ b/tests/unit/test_expression_tree/test_operations/test_copy.py @@ -29,7 +29,6 @@ def test_symbol_new_copy(self): pybamm.FunctionParameter("function", {"a": a}), pybamm.grad(v_n), pybamm.div(pybamm.grad(v_n)), - pybamm.Integral(a, pybamm.t), pybamm.IndefiniteIntegral(v_n, x_n), pybamm.BackwardIndefiniteIntegral(v_n, x_n), pybamm.BoundaryValue(v_n, "right"), diff --git a/tests/unit/test_expression_tree/test_operations/test_simplify.py b/tests/unit/test_expression_tree/test_operations/test_simplify.py index fe9b327892..b74259d89a 100644 --- a/tests/unit/test_expression_tree/test_operations/test_simplify.py +++ b/tests/unit/test_expression_tree/test_operations/test_simplify.py @@ -72,9 +72,20 @@ def myfunction(x, y): # Integral self.assertIsInstance( - (pybamm.Integral(a, pybamm.t)).simplify(), pybamm.Integral + ( + pybamm.Integral(a, pybamm.SpatialVariable("x", domain="domain")) + ).simplify(), + pybamm.Integral, ) + def_int = (pybamm.DefiniteIntegralVector(a, vector_type="column")).simplify() + self.assertIsInstance(def_int, pybamm.DefiniteIntegralVector) + self.assertEqual(def_int.vector_type, "column") + + bound_int = (pybamm.BoundaryIntegral(a, region="negative tab")).simplify() + self.assertIsInstance(bound_int, pybamm.BoundaryIntegral) + self.assertEqual(bound_int.region, "negative tab") + # BoundaryValue v_neg = pybamm.Variable("v", domain=["negative electrode"]) self.assertIsInstance( diff --git a/tests/unit/test_expression_tree/test_unary_operators.py b/tests/unit/test_expression_tree/test_unary_operators.py index 030deaa73d..3ba42e9325 100644 --- a/tests/unit/test_expression_tree/test_unary_operators.py +++ b/tests/unit/test_expression_tree/test_unary_operators.py @@ -106,16 +106,6 @@ def test_div(self): self.assertEqual(div.domain, a.domain) def test_integral(self): - # time integral - a = pybamm.Symbol("a") - t = pybamm.t - inta = pybamm.Integral(a, t) - self.assertEqual(inta.name, "integral dtime") - # self.assertTrue(inta.definite) - self.assertEqual(inta.children[0].name, a.name) - self.assertEqual(inta.integration_variable[0], t) - self.assertEqual(inta.domain, []) - # space integral a = pybamm.Symbol("a", domain=["negative electrode"]) x = pybamm.SpatialVariable("x", ["negative electrode"]) @@ -135,7 +125,7 @@ def test_integral(self): inta_sec = pybamm.Integral(a_sec, x) self.assertEqual(inta_sec.domain, ["current collector"]) self.assertEqual(inta_sec.auxiliary_domains, {}) - # space integral with secondary domain + # space integral with tertiary domain a_tert = pybamm.Symbol( "a", domain=["negative electrode"], @@ -151,6 +141,27 @@ def test_integral(self): inta_tert.auxiliary_domains, {"secondary": ["some extra domain"]} ) + # space integral *in* secondary domain + y = pybamm.SpatialVariable("y", ["current collector"]) + # without a tertiary domain + inta_sec_y = pybamm.Integral(a_sec, y) + self.assertEqual(inta_sec_y.domain, ["negative electrode"]) + self.assertEqual(inta_sec_y.auxiliary_domains, {}) + # with a tertiary domain + inta_tert_y = pybamm.Integral(a_tert, y) + self.assertEqual(inta_tert_y.domain, ["negative electrode"]) + self.assertEqual( + inta_tert_y.auxiliary_domains, {"secondary": ["some extra domain"]} + ) + + # space integral *in* tertiary domain + z = pybamm.SpatialVariable("z", ["some extra domain"]) + inta_tert_z = pybamm.Integral(a_tert, z) + self.assertEqual(inta_tert_z.domain, ["negative electrode"]) + self.assertEqual( + inta_tert_z.auxiliary_domains, {"secondary": ["current collector"]} + ) + # space integral over two variables b = pybamm.Symbol("b", domain=["current collector"]) y = pybamm.SpatialVariable("y", ["current collector"]) @@ -186,24 +197,35 @@ def test_integral(self): z = pybamm.SpatialVariable("z", ["negative electrode"]) with self.assertRaises(pybamm.DomainError): pybamm.Integral(a, x) - with self.assertRaises(ValueError): + with self.assertRaisesRegex(TypeError, "integration_variable must be"): pybamm.Integral(a, y) + with self.assertRaisesRegex( + NotImplementedError, + "Indefinite integral only implemeted w.r.t. one variable", + ): + pybamm.IndefiniteIntegral(a, [x, y]) def test_index(self): vec = pybamm.StateVector(slice(0, 5)) y_test = np.array([1, 2, 3, 4, 5]) # with integer - ind = vec[3] + ind = pybamm.Index(vec, 3) self.assertIsInstance(ind, pybamm.Index) self.assertEqual(ind.slice, slice(3, 4)) self.assertEqual(ind.evaluate(y=y_test), 4) + # with -1 + ind = pybamm.Index(vec, -1) + self.assertIsInstance(ind, pybamm.Index) + self.assertEqual(ind.slice, slice(-1, None)) + self.assertEqual(ind.evaluate(y=y_test), 5) + self.assertEqual(ind.name, "Index[-1]") # with slice - ind = vec[1:3] + ind = pybamm.Index(vec, slice(1, 3)) self.assertIsInstance(ind, pybamm.Index) self.assertEqual(ind.slice, slice(1, 3)) np.testing.assert_array_equal(ind.evaluate(y=y_test), np.array([[2], [3]])) # with only stop slice - ind = vec[:3] + ind = pybamm.Index(vec, slice(3)) self.assertIsInstance(ind, pybamm.Index) self.assertEqual(ind.slice, slice(3)) np.testing.assert_array_equal(ind.evaluate(y=y_test), np.array([[1], [2], [3]])) @@ -265,7 +287,7 @@ def test_delta_function(self): delta_a = pybamm.DeltaFunction(a, "right", "some domain") self.assertEqual(delta_a.side, "right") self.assertEqual(delta_a.child.id, a.id) - self.assertFalse(delta_a.evaluates_on_edges()) + self.assertFalse(delta_a.evaluates_on_edges("primary")) with self.assertRaisesRegex( pybamm.DomainError, "Delta function domain cannot be None" ): @@ -279,8 +301,10 @@ def test_boundary_operators(self): def test_evaluates_on_edges(self): a = pybamm.StateVector(slice(0, 10)) - self.assertFalse(a[1].evaluates_on_edges()) - self.assertFalse(pybamm.Laplacian(a).evaluates_on_edges()) + self.assertFalse(pybamm.Index(a, slice(1)).evaluates_on_edges("primary")) + self.assertFalse(pybamm.Laplacian(a).evaluates_on_edges("primary")) + self.assertTrue(pybamm.Gradient_Squared(a).evaluates_on_edges("primary")) + self.assertFalse(pybamm.BoundaryIntegral(a).evaluates_on_edges("primary")) def test_boundary_value(self): a = pybamm.Scalar(1) @@ -372,6 +396,29 @@ def test_x_average(self): ): pybamm.x_average(symbol_on_edges) + # Particle domains + a = pybamm.Symbol( + "a", + domain="negative particle", + auxiliary_domains={"secondary": "negative electrode"}, + ) + av_a = pybamm.x_average(a) + self.assertEqual(a.domain, ["negative particle"]) + self.assertIsInstance(av_a, pybamm.Division) + self.assertIsInstance(av_a.children[0], pybamm.Integral) + self.assertEqual(av_a.children[1].id, pybamm.geometric_parameters.l_n.id) + + a = pybamm.Symbol( + "a", + domain="positive particle", + auxiliary_domains={"secondary": "positive electrode"}, + ) + av_a = pybamm.x_average(a) + self.assertEqual(a.domain, ["positive particle"]) + self.assertIsInstance(av_a, pybamm.Division) + self.assertIsInstance(av_a.children[0], pybamm.Integral) + self.assertEqual(av_a.children[1].id, pybamm.geometric_parameters.l_p.id) + def test_r_average(self): a = pybamm.Scalar(1) average_a = pybamm.r_average(a) diff --git a/tests/unit/test_meshes/test_zero_dimensional_submesh.py b/tests/unit/test_meshes/test_zero_dimensional_submesh.py index ace1c01230..df663bdf06 100644 --- a/tests/unit/test_meshes/test_zero_dimensional_submesh.py +++ b/tests/unit/test_meshes/test_zero_dimensional_submesh.py @@ -4,12 +4,12 @@ class TestSubMesh0D(unittest.TestCase): def test_exceptions(self): - position = {"x": 0, "y": 0} + position = {"x": {"position": 0}, "y": {"position": 0}} with self.assertRaises(pybamm.GeometryError): pybamm.SubMesh0D(position) def test_init(self): - position = {"x": 1} + position = {"x": {"position": 1}} generator = pybamm.MeshGenerator(pybamm.SubMesh0D) mesh = generator(position, None) mesh.add_ghost_meshes() diff --git a/tests/unit/test_simulation.py b/tests/unit/test_simulation.py index 65215239b8..3222383c74 100644 --- a/tests/unit/test_simulation.py +++ b/tests/unit/test_simulation.py @@ -143,7 +143,8 @@ def test_reuse_commands(self): def test_specs(self): # test can rebuild after setting specs - sim = pybamm.Simulation(pybamm.lithium_ion.SPM()) + model = pybamm.lithium_ion.SPM() + sim = pybamm.Simulation(model) sim.build() model_options = {"thermal": "lumped"} @@ -161,7 +162,17 @@ def test_specs(self): ) sim.build() - sim.specs(geometry=pybamm.battery_geometry(current_collector_dimension=1)) + sim.specs( + geometry=pybamm.battery_geometry(current_collector_dimension=1), + submesh_types={ + **model.default_submesh_types, + "current collector": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), + }, + spatial_methods={ + **model.default_spatial_methods, + "current collector": pybamm.FiniteVolume(), + }, + ) sim.build() var_pts = sim.var_pts diff --git a/tests/unit/test_spatial_methods/test_base_spatial_method.py b/tests/unit/test_spatial_methods/test_base_spatial_method.py index 83051b8f41..324ad098ab 100644 --- a/tests/unit/test_spatial_methods/test_base_spatial_method.py +++ b/tests/unit/test_spatial_methods/test_base_spatial_method.py @@ -22,7 +22,7 @@ def test_basics(self): with self.assertRaises(NotImplementedError): spatial_method.gradient_squared(None, None, None) with self.assertRaises(NotImplementedError): - spatial_method.integral(None, None) + spatial_method.integral(None, None, None) with self.assertRaises(NotImplementedError): spatial_method.indefinite_integral(None, None, None) with self.assertRaises(NotImplementedError): @@ -55,7 +55,7 @@ def test_get_auxiliary_domain_repeats(self): repeats, mesh["negative electrode"].npts + mesh["separator"].npts ) - # Just tertiary domain + # With tertiary domain repeats = spatial_method._get_auxiliary_domain_repeats( { "secondary": ["negative electrode", "separator"], @@ -68,6 +68,16 @@ def test_get_auxiliary_domain_repeats(self): * mesh["current collector"].npts, ) + # Just tertiary domain + repeats = spatial_method._get_auxiliary_domain_repeats( + { + "secondary": ["negative electrode", "separator"], + "tertiary": ["current collector"], + }, + tertiary_only=True, + ) + self.assertEqual(repeats, mesh["current collector"].npts) + def test_discretise_spatial_variable(self): # create discretisation mesh = get_mesh_for_testing() diff --git a/tests/unit/test_spatial_methods/test_finite_volume/test_finite_volume.py b/tests/unit/test_spatial_methods/test_finite_volume/test_finite_volume.py index 965892d891..1c9f6e593e 100644 --- a/tests/unit/test_spatial_methods/test_finite_volume/test_finite_volume.py +++ b/tests/unit/test_spatial_methods/test_finite_volume/test_finite_volume.py @@ -247,15 +247,22 @@ def test_spherical_grad_div_shapes_Dirichlet_bcs(self): Test grad and div with Dirichlet boundary conditions (applied by grad on var) """ # create discretisation - mesh = get_mesh_for_testing() + mesh = get_1p1d_mesh_for_testing() spatial_methods = {"negative particle": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) - combined_submesh = mesh.combine_submeshes("negative particle") + submesh = mesh["negative particle"] # grad # grad(r) == 1 - var = pybamm.Variable("var", domain=["negative particle"]) + var = pybamm.Variable( + "var", + domain=["negative particle"], + auxiliary_domains={ + "secondary": "negative electrode", + "tertiary": "current collector", + }, + ) grad_eqn = pybamm.grad(var) boundary_conditions = { var.id: { @@ -269,10 +276,19 @@ def test_spherical_grad_div_shapes_Dirichlet_bcs(self): disc.set_variable_slices([var]) grad_eqn_disc = disc.process_symbol(grad_eqn) - constant_y = np.ones_like(combined_submesh.nodes[:, np.newaxis]) + total_npts = ( + submesh.npts + * mesh["negative electrode"].npts + * mesh["current collector"].npts + ) + total_npts_edges = ( + (submesh.npts + 1) + * mesh["negative electrode"].npts + * mesh["current collector"].npts + ) + constant_y = np.ones((total_npts, 1)) np.testing.assert_array_equal( - grad_eqn_disc.evaluate(None, constant_y), - np.zeros_like(combined_submesh.edges[:, np.newaxis]), + grad_eqn_disc.evaluate(None, constant_y), np.zeros((total_npts_edges, 1)) ) boundary_conditions = { @@ -283,16 +299,18 @@ def test_spherical_grad_div_shapes_Dirichlet_bcs(self): } disc.bcs = boundary_conditions - y_linear = combined_submesh.nodes + y_linear = np.tile( + submesh.nodes, + mesh["negative electrode"].npts * mesh["current collector"].npts, + ) grad_eqn_disc = disc.process_symbol(grad_eqn) np.testing.assert_array_almost_equal( - grad_eqn_disc.evaluate(None, y_linear), - np.ones_like(combined_submesh.edges[:, np.newaxis]), + grad_eqn_disc.evaluate(None, y_linear), np.ones((total_npts_edges, 1)) ) # div: test on linear r^2 # div (grad r^2) = 6 - const = 6 * np.ones(combined_submesh.npts) + const = 6 * np.ones((total_npts, 1)) N = pybamm.grad(var) div_eqn = pybamm.div(N) boundary_conditions = { @@ -305,7 +323,15 @@ def test_spherical_grad_div_shapes_Dirichlet_bcs(self): div_eqn_disc = disc.process_symbol(div_eqn) np.testing.assert_array_almost_equal( - div_eqn_disc.evaluate(None, const), np.zeros((combined_submesh.npts, 1)) + div_eqn_disc.evaluate(None, const), + np.zeros( + ( + submesh.npts + * mesh["negative electrode"].npts + * mesh["current collector"].npts, + 1, + ) + ), ) def test_p2d_spherical_grad_div_shapes_Dirichlet_bcs(self): @@ -710,6 +736,164 @@ def test_definite_integral(self): integral_eqn_disc.evaluate(None, one_over_y), 4 * np.pi ** 2 ) + # test failure for secondary dimension column form + finite_volume = pybamm.FiniteVolume() + finite_volume.build(mesh) + with self.assertRaisesRegex( + NotImplementedError, + "Integral in secondary vector only implemented in 'row' form", + ): + finite_volume.definite_integral_matrix(var, "column", "secondary") + + def test_integral_secondary_domain(self): + # create discretisation + mesh = get_1p1d_mesh_for_testing() + spatial_methods = { + "macroscale": pybamm.FiniteVolume(), + "negative particle": pybamm.FiniteVolume(), + "positive particle": pybamm.FiniteVolume(), + "current collector": pybamm.FiniteVolume(), + } + disc = pybamm.Discretisation(mesh, spatial_methods) + # lengths + ln = mesh["negative electrode"].edges[-1] + ls = mesh["separator"].edges[-1] - ln + lp = 1 - (ln + ls) + + var = pybamm.Variable( + "var", + domain="positive particle", + auxiliary_domains={ + "secondary": "positive electrode", + "tertiary": "current collector", + }, + ) + x = pybamm.SpatialVariable("x", "positive electrode") + integral_eqn = pybamm.Integral(var, x) + disc.set_variable_slices([var]) + integral_eqn_disc = disc.process_symbol(integral_eqn) + + submesh = mesh["positive particle"] + constant_y = np.ones( + ( + submesh.npts + * mesh["positive electrode"].npts + * mesh["current collector"].npts, + 1, + ) + ) + np.testing.assert_array_almost_equal( + integral_eqn_disc.evaluate(None, constant_y), + lp * np.ones((submesh.npts * mesh["current collector"].npts, 1)), + ) + linear_in_x = np.tile( + np.repeat(mesh["positive electrode"].nodes, submesh.npts), + mesh["current collector"].npts, + ) + np.testing.assert_array_almost_equal( + integral_eqn_disc.evaluate(None, linear_in_x), + (1 - (ln + ls) ** 2) + / 2 + * np.ones((submesh.npts * mesh["current collector"].npts, 1)), + ) + linear_in_r = np.tile( + submesh.nodes, + mesh["positive electrode"].npts * mesh["current collector"].npts, + ) + np.testing.assert_array_almost_equal( + integral_eqn_disc.evaluate(None, linear_in_r).flatten(), + lp * np.tile(submesh.nodes, mesh["current collector"].npts), + ) + cos_y = np.cos(linear_in_x) + np.testing.assert_array_almost_equal( + integral_eqn_disc.evaluate(None, cos_y), + (np.sin(1) - np.sin(ln + ls)) + * np.ones((submesh.npts * mesh["current collector"].npts, 1)), + decimal=4, + ) + + def test_integral_primary_then_secondary_same_result(self): + # Test that integrating in r then in x gives the same result as integrating in + # x then in r + # create discretisation + mesh = get_1p1d_mesh_for_testing() + spatial_methods = { + "macroscale": pybamm.FiniteVolume(), + "negative particle": pybamm.FiniteVolume(), + "positive particle": pybamm.FiniteVolume(), + "current collector": pybamm.FiniteVolume(), + } + disc = pybamm.Discretisation(mesh, spatial_methods) + + var = pybamm.Variable( + "var", + domain="positive particle", + auxiliary_domains={ + "secondary": "positive electrode", + "tertiary": "current collector", + }, + ) + x = pybamm.SpatialVariable("x", "positive electrode") + r = pybamm.SpatialVariable("r", "positive particle") + integral_eqn_x_then_r = pybamm.Integral(pybamm.Integral(var, x), r) + integral_eqn_r_then_x = pybamm.Integral(pybamm.Integral(var, r), x) + + # discretise + disc.set_variable_slices([var]) + integral_eqn_x_then_r_disc = disc.process_symbol(integral_eqn_x_then_r) + integral_eqn_r_then_x_disc = disc.process_symbol(integral_eqn_r_then_x) + + # test + submesh = mesh["positive particle"] + cos_y = np.cos( + np.tile( + submesh.nodes, + mesh["positive electrode"].npts * mesh["current collector"].npts, + ) + ) + np.testing.assert_array_almost_equal( + integral_eqn_x_then_r_disc.evaluate(None, cos_y), + integral_eqn_r_then_x_disc.evaluate(None, cos_y), + decimal=4, + ) + + def test_integral_secondary_domain_on_edges_in_primary_domain(self): + # create discretisation + mesh = get_1p1d_mesh_for_testing() + spatial_methods = { + "macroscale": pybamm.FiniteVolume(), + "negative particle": pybamm.FiniteVolume(), + "positive particle": pybamm.FiniteVolume(), + "current collector": pybamm.FiniteVolume(), + } + disc = pybamm.Discretisation(mesh, spatial_methods) + # lengths + ln = mesh["negative electrode"].edges[-1] + ls = mesh["separator"].edges[-1] - ln + lp = 1 - (ln + ls) + + r_edge = pybamm.SpatialVariableEdge( + "r_p", + domain="positive particle", + auxiliary_domains={ + "secondary": "positive electrode", + "tertiary": "current collector", + }, + ) + + x = pybamm.SpatialVariable("x", "positive electrode") + integral_eqn = pybamm.Integral(r_edge, x) + integral_eqn_disc = disc.process_symbol(integral_eqn) + + submesh = mesh["positive particle"] + np.testing.assert_array_almost_equal( + integral_eqn_disc.evaluate().flatten(), + lp + * np.tile( + np.linspace(0, 1, submesh.npts + 1), mesh["current collector"].npts + ), + ) + def test_definite_integral_vector(self): mesh = get_mesh_for_testing() spatial_methods = { @@ -850,7 +1034,7 @@ def test_indefinite_integral(self): # -------------------------------------------------------------------- # micrsoscale case c = pybamm.Variable("c", domain=["negative particle"]) - N = pybamm.grad(c) # create test current (variable on edges) + N = pybamm.grad(c) # create test flux (variable on edges) r_n = pybamm.SpatialVariable("r_n", ["negative particle"]) c_integral = pybamm.IndefiniteIntegral(N, r_n) disc.set_variable_slices([c]) # N is not a fundamental variable @@ -1004,6 +1188,22 @@ def test_indefinite_integral_on_nodes(self): int_phi_approx = int_phi_disc.evaluate(None, phi_exact).flatten() np.testing.assert_array_almost_equal(int_phi_exact, int_phi_approx, decimal=5) + # microscale case should fail + mesh = get_mesh_for_testing() + spatial_methods = {"negative particle": pybamm.FiniteVolume()} + disc = pybamm.Discretisation(mesh, spatial_methods) + + c = pybamm.Variable("c", domain=["negative particle"]) + r = pybamm.SpatialVariable("r", ["negative particle"]) + + int_c = pybamm.IndefiniteIntegral(c, r) + disc.set_variable_slices([c]) + with self.assertRaisesRegex( + NotImplementedError, + "Indefinite integral on a spherical polar domain is not implemented", + ): + disc.process_symbol(int_c) + def test_backward_indefinite_integral_on_nodes(self): mesh = get_mesh_for_testing() spatial_methods = {"macroscale": pybamm.FiniteVolume()} diff --git a/tests/unit/test_spatial_methods/test_scikit_finite_element.py b/tests/unit/test_spatial_methods/test_scikit_finite_element.py index d02f307ba3..683d1627da 100644 --- a/tests/unit/test_spatial_methods/test_scikit_finite_element.py +++ b/tests/unit/test_spatial_methods/test_scikit_finite_element.py @@ -16,7 +16,7 @@ def test_not_implemented(self): with self.assertRaises(NotImplementedError): spatial_method.divergence(None, None, None) with self.assertRaises(NotImplementedError): - spatial_method.indefinite_integral(None, None) + spatial_method.indefinite_integral(None, None, None) def test_discretise_equations(self): # get mesh diff --git a/tests/unit/test_spatial_methods/test_zero_dimensional_method.py b/tests/unit/test_spatial_methods/test_zero_dimensional_method.py index b4e2128009..bf827a6204 100644 --- a/tests/unit/test_spatial_methods/test_zero_dimensional_method.py +++ b/tests/unit/test_spatial_methods/test_zero_dimensional_method.py @@ -15,7 +15,7 @@ def test_identity_ops(self): np.testing.assert_array_equal(spatial_method._mesh, test_mesh) a = pybamm.Symbol("a") - self.assertEqual(a, spatial_method.integral(None, a)) + self.assertEqual(a, spatial_method.integral(None, a, "primary")) self.assertEqual(a, spatial_method.indefinite_integral(None, a, "forward")) self.assertEqual(a, spatial_method.boundary_value_or_flux(None, a)) self.assertEqual(