Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
*.png
*.gif
/local/
.local
*.DS_Store
*.mat
*.csv
*.hidden
*.pkl
.claude

# don't ignore important .txt and .csv files
!requirements*
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

## Features

- Added uniform grid sizing across subdomains in the x-dimension, ensuring consistent grid spacing when geometries have varying lengths. ([#5253](https://github.com/pybamm-team/PyBaMM/pull/5253))
- Added the `electrode_phases` kwarg to `plot_voltage_components()` which allows choosing between plotting primary or secondary phase overpotentials. ([#5229](https://github.com/pybamm-team/PyBaMM/pull/5229))
- Added the `num_steps_no_progress` and `t_no_progress` options in the `IDAKLUSolver` to early terminate the simulation if little progress is detected. ([#5201](https://github.com/pybamm-team/PyBaMM/pull/5201))
- EvaluateAt symbol: add support for children evaluated at edges ([#5190](https://github.com/pybamm-team/PyBaMM/pull/5190))
Expand Down
711 changes: 606 additions & 105 deletions src/pybamm/expression_tree/operations/serialise.py

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions src/pybamm/meshes/meshes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,39 @@
import pybamm


def compute_var_pts_from_thicknesses(electrode_thicknesses, grid_size):
"""
Compute a ``var_pts`` dictionary using electrode thicknesses and a target cell size (dx).

Added as per maintainer feedback in issue #<your-issue-number> to make mesh generation
explicit — ``grid_size`` now represents the mesh cell size in metres.

Parameters
----------
electrode_thicknesses : dict
Domain thicknesses in metres.
grid_size : float
Desired uniform mesh cell size (m).

Returns
-------
dict
Mapping of each domain to its computed grid points.
"""
if not isinstance(electrode_thicknesses, dict):
raise TypeError("electrode_thicknesses must be a dictionary")

if not isinstance(grid_size, (int | float)) or grid_size <= 0:
raise ValueError("grid_size must be a positive number")

var_pts = {}
for domain, thickness in electrode_thicknesses.items():
npts = max(round(thickness / grid_size), 2)
var_pts[domain] = {f"x_{domain[0]}": npts}

return var_pts


class Mesh(dict):
"""
Mesh contains a list of submeshes on each subdomain.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class SymmetricButlerVolmer(BaseKinetics):
Submodel which implements the symmetric forward Butler-Volmer equation:

.. math::
j = 2 * j_0(c) * \\sinh(ne * F * \\eta_r(c) / RT)
j = 2 * j_0(c) * \\sinh(ne * F * \\eta_r(c) / 2RT)

Parameters
----------
Expand Down
21 changes: 17 additions & 4 deletions src/pybamm/parameters/parameter_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,10 @@ def _process_symbol(self, symbol):
# Unary operators
elif isinstance(symbol, pybamm.UnaryOperator):
new_child = self.process_symbol(symbol.child)
new_symbol = symbol.create_copy(new_children=[new_child])
# Don't perform simplifications during parameter processing
new_symbol = symbol.create_copy(
new_children=[new_child], perform_simplifications=False
)
# x_average can sometimes create a new symbol with electrode thickness
# parameters, so we process again to make sure these parameters are set
if isinstance(symbol, pybamm.XAverage) and not isinstance(
Expand Down Expand Up @@ -822,16 +825,22 @@ def _process_symbol(self, symbol):
or isinstance(symbol, pybamm.BinaryOperator)
):
new_children = [self.process_symbol(child) for child in symbol.children]
return symbol.create_copy(new_children)
# Don't perform simplifications during parameter processing to avoid
# evaluation errors (e.g., ZeroDivisionError) when creating copies
return symbol.create_copy(new_children, perform_simplifications=False)

elif isinstance(symbol, pybamm.VectorField):
left_symbol = self.process_symbol(symbol.lr_field)
right_symbol = self.process_symbol(symbol.tb_field)
return symbol.create_copy(new_children=[left_symbol, right_symbol])
# Don't perform simplifications during parameter processing
return symbol.create_copy(
new_children=[left_symbol, right_symbol], perform_simplifications=False
)

# Variables: update scale
elif isinstance(symbol, pybamm.Variable):
new_symbol = symbol.create_copy()
# Don't perform simplifications during parameter processing
new_symbol = symbol.create_copy(perform_simplifications=False)
new_symbol._scale = self.process_symbol(symbol.scale)
reference = self.process_symbol(symbol.reference)
if isinstance(reference, pybamm.Vector):
Expand Down Expand Up @@ -1403,6 +1412,10 @@ def convert_parameter_values_to_json(parameter_values, filename=None):
The filename to save the JSON file to. If not provided, the dictionary is
not saved.
"""
# Reset caches for a clean serialization
from pybamm.expression_tree.operations.serialise import _reset_serialization_caches

_reset_serialization_caches()
parameter_values_dict = {}

for k, v in parameter_values.items():
Expand Down
31 changes: 31 additions & 0 deletions tests/unit/test_meshes/test_meshes.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,37 @@ def test_to_json(self):

assert mesh_json == expected_json

def test_compute_var_pts_from_thicknesses_cell_size(self):
from pybamm.meshes.meshes import compute_var_pts_from_thicknesses

electrode_thicknesses = {
"negative electrode": 100e-6,
"separator": 25e-6,
"positive electrode": 100e-6,
}

cell_size = 5e-6 # 5 micrometres per cell
var_pts = compute_var_pts_from_thicknesses(electrode_thicknesses, cell_size)

assert isinstance(var_pts, dict)
assert all(isinstance(v, dict) for v in var_pts.values())
assert var_pts["negative electrode"]["x_n"] == 20
assert var_pts["separator"]["x_s"] == 5
assert var_pts["positive electrode"]["x_p"] == 20

def test_compute_var_pts_from_thicknesses_invalid_thickness_type(self):
from pybamm.meshes.meshes import compute_var_pts_from_thicknesses

with pytest.raises(TypeError):
compute_var_pts_from_thicknesses(["not", "a", "dict"], 1e-6)

def test_compute_var_pts_from_thicknesses_invalid_grid_size(self):
from pybamm.meshes.meshes import compute_var_pts_from_thicknesses

electrode_thicknesses = {"negative electrode": 100e-6}
with pytest.raises(ValueError):
compute_var_pts_from_thicknesses(electrode_thicknesses, -1e-6)


class TestMeshGenerator:
def test_init_name(self):
Expand Down
Loading
Loading