Skip to content

Commit

Permalink
#617 add tests for user 2D mesh
Browse files Browse the repository at this point in the history
  • Loading branch information
rtimms committed Sep 27, 2019
1 parent 817ef9b commit 71c7ed0
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 30 deletions.
1 change: 1 addition & 0 deletions pybamm/meshes/two_dimensional_meshes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from .chebyshev_scikit_fem_submesh import ScikitChebyshev2DSubMesh
from .exponential_scikit_fem_submesh import ScikitTopExponential2DSubMesh
from .uniform_scikit_fem_submesh import ScikitUniform2DSubMesh
from .user_supplied_submesh import GetUserSupplied2DSubMesh, UserSupplied2DSubMesh
72 changes: 42 additions & 30 deletions pybamm/meshes/two_dimensional_meshes/user_supplied_submesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ class GetUserSupplied2DSubMesh:
A class to generate a tensor product submesh on a 2D domain by using two user
supplied vectors of edges: one for the y-direction and one for the z-direction.
----------
edges : array_like
The array of points which correspond to the edges of the mesh.
y_edges : array_like
The array of points which correspond to the edges in the y direction
of the mesh.
z_edges : array_like
The array of points which correspond to the edges in the z direction
of the mesh.
"""

def __init__(self, nodes):
self.nodes = nodes
def __init__(self, y_edges, z_edges):
self.y_edges = y_edges
self.z_edges = z_edges

def __call__(self, lims, npts, tabs=None):
return UserSupplied2DSubMesh(lims, npts, tabs, self.nodes)
return UserSupplied2DSubMesh(lims, npts, tabs, self.y_edges, self.z_edges)


class UserSupplied2DSubMesh(ScikitSubMesh2D):
Expand All @@ -37,11 +42,15 @@ class UserSupplied2DSubMesh(ScikitSubMesh2D):
tabs : dict
A dictionary that contains information about the size and location of
the tabs
edges : array_like
The array of points which correspond to the edges of the mesh.
y_edges : array_like
The array of points which correspond to the edges in the y direction
of the mesh.
z_edges : array_like
The array of points which correspond to the edges in the z direction
of the mesh.
"""

def __init__(self, lims, npts, tabs, edges):
def __init__(self, lims, npts, tabs, y_edges, z_edges):

# check that two variables have been passed in
if len(lims) != 2:
Expand All @@ -63,31 +72,34 @@ def __init__(self, lims, npts, tabs, edges):
)
)

# check that npts equals number of user-supplied edges
if npts != len(edges):
raise pybamm.GeometryError(
"""User-suppled edges has should have length npts but has length {}.
Number of points (npts) for domain {} is {}.""".format(
len(edges), spatial_var.domain, npts
# check and store edges
edges = {"y": y_edges, "z": z_edges}
for var in spatial_vars:

# check that npts equals number of user-supplied edges
if npts[var.id] != len(edges[var.name]):
raise pybamm.GeometryError(
"""User-suppled edges has should have length npts but has length {}.
Number of points (npts) for variable {} in
domain {} is {}.""".format(
len(edges[var.name]), var.name, var.domain, npts[var.id]
)
)
)

# check end points of edges agree with spatial_lims
if edges[0] != spatial_lims["min"]:
raise pybamm.GeometryError(
"""First entry of edges is {}, but should be equal to {}
for domain {}.""".format(
edges[0], spatial_lims["min"], spatial_var.domain
# check end points of edges agree with spatial_lims
if edges[var.name][0] != lims[var]["min"]:
raise pybamm.GeometryError(
"""First entry of edges is {}, but should be equal to {}
for variable {} in domain {}.""".format(
edges[var.name][0], lims[var]["min"], var.name, var.domain
)
)
)
if edges[-1] != spatial_lims["max"]:
raise pybamm.GeometryError(
"""Last entry of edges is {}, but should be equal to {}
for domain {}.""".format(
edges[-1], spatial_lims["max"], spatial_var.domain
if edges[var.name][-1] != lims[var]["max"]:
raise pybamm.GeometryError(
"""Last entry of edges is {}, but should be equal to {}
for variable {} in domain {}.""".format(
edges[var.name][-1], lims[var]["max"], var.name, var.domain
)
)
)

coord_sys = spatial_var.coord_sys

super().__init__(edges, coord_sys=coord_sys, tabs=tabs)
180 changes: 180 additions & 0 deletions tests/unit/test_meshes/test_scikit_fem_submesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#
import pybamm
import unittest
import numpy as np


class TestScikitFiniteElement2DSubMesh(unittest.TestCase):
Expand Down Expand Up @@ -256,6 +257,185 @@ def test_init_failure(self):
pybamm.two_dimensional_meshes.ScikitChebyshev2DSubMesh(lims, None, None)


class TestScikitTopExponential2DSubMesh(unittest.TestCase):
def test_mesh_creation(self):
param = pybamm.ParameterValues(
base_parameters={
"Electrode width [m]": 0.4,
"Electrode height [m]": 0.5,
"Negative tab width [m]": 0.1,
"Negative tab centre y-coordinate [m]": 0.1,
"Negative tab centre z-coordinate [m]": 0.5,
"Positive tab width [m]": 0.1,
"Positive tab centre y-coordinate [m]": 0.3,
"Positive tab centre z-coordinate [m]": 0.5,
"Negative electrode thickness [m]": 0.3,
"Separator thickness [m]": 0.3,
"Positive electrode thickness [m]": 0.3,
}
)

geometry = pybamm.Geometryxp1DMacro(cc_dimension=2)
param.process_geometry(geometry)

var = pybamm.standard_spatial_vars
var_pts = {var.x_n: 10, var.x_s: 7, var.x_p: 12, var.y: 16, var.z: 24}

submesh_types = {
"negative electrode": pybamm.one_dimensional_meshes.Uniform1DSubMesh,
"separator": pybamm.one_dimensional_meshes.Uniform1DSubMesh,
"positive electrode": pybamm.one_dimensional_meshes.Uniform1DSubMesh,
"current collector": pybamm.two_dimensional_meshes.ScikitTopExponential2DSubMesh,
}

mesh_type = pybamm.Mesh

# create mesh
mesh = mesh_type(geometry, submesh_types, var_pts)

# check boundary locations
self.assertEqual(mesh["negative electrode"][0].edges[0], 0)
self.assertEqual(mesh["positive electrode"][0].edges[-1], 1)

# check internal boundary locations
self.assertEqual(
mesh["negative electrode"][0].edges[-1], mesh["separator"][0].edges[0]
)
self.assertEqual(
mesh["positive electrode"][0].edges[0], mesh["separator"][0].edges[-1]
)
for domain in mesh:
if domain == "current collector":
# NOTE: only for degree 1
npts = var_pts[var.y] * var_pts[var.z]
self.assertEqual(mesh[domain][0].npts, npts)
else:
self.assertEqual(
len(mesh[domain][0].edges), len(mesh[domain][0].nodes) + 1
)

def test_init_failure(self):
var = pybamm.standard_spatial_vars

# only one lim
lims = {var.x_n: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}
with self.assertRaises(pybamm.GeometryError):
pybamm.two_dimensional_meshes.ScikitTopExponential2DSubMesh(
lims, None, None
)

# different coord_sys
lims = {
var.r_n: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)},
var.z: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)},
}
with self.assertRaises(pybamm.DomainError):
pybamm.two_dimensional_meshes.ScikitTopExponential2DSubMesh(
lims, None, None
)

# not y and z
lims = {
var.x_n: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)},
var.z: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)},
}
with self.assertRaises(pybamm.DomainError):
pybamm.two_dimensional_meshes.ScikitTopExponential2DSubMesh(
lims, None, None
)


class TestScikitUser2DSubMesh(unittest.TestCase):
def test_mesh_creation(self):
param = pybamm.ParameterValues(
base_parameters={
"Electrode width [m]": 0.4,
"Electrode height [m]": 0.5,
"Negative tab width [m]": 0.1,
"Negative tab centre y-coordinate [m]": 0.1,
"Negative tab centre z-coordinate [m]": 0.5,
"Positive tab width [m]": 0.1,
"Positive tab centre y-coordinate [m]": 0.3,
"Positive tab centre z-coordinate [m]": 0.5,
"Negative electrode thickness [m]": 0.3,
"Separator thickness [m]": 0.3,
"Positive electrode thickness [m]": 0.3,
}
)

geometry = pybamm.Geometryxp1DMacro(cc_dimension=2)
param.process_geometry(geometry)

var = pybamm.standard_spatial_vars
var_pts = {var.x_n: 10, var.x_s: 7, var.x_p: 12, var.y: 16, var.z: 24}

y_edges = np.linspace(0, 0.8, 16)
z_edges = np.linspace(0, 1, 24)

submesh_types = {
"negative electrode": pybamm.one_dimensional_meshes.Uniform1DSubMesh,
"separator": pybamm.one_dimensional_meshes.Uniform1DSubMesh,
"positive electrode": pybamm.one_dimensional_meshes.Uniform1DSubMesh,
"current collector": pybamm.two_dimensional_meshes.GetUserSupplied2DSubMesh(
y_edges, z_edges
),
}

mesh_type = pybamm.Mesh

# create mesh
mesh = mesh_type(geometry, submesh_types, var_pts)

# check boundary locations
self.assertEqual(mesh["negative electrode"][0].edges[0], 0)
self.assertEqual(mesh["positive electrode"][0].edges[-1], 1)

# check internal boundary locations
self.assertEqual(
mesh["negative electrode"][0].edges[-1], mesh["separator"][0].edges[0]
)
self.assertEqual(
mesh["positive electrode"][0].edges[0], mesh["separator"][0].edges[-1]
)
for domain in mesh:
if domain == "current collector":
# NOTE: only for degree 1
npts = var_pts[var.y] * var_pts[var.z]
self.assertEqual(mesh[domain][0].npts, npts)
else:
self.assertEqual(
len(mesh[domain][0].edges), len(mesh[domain][0].nodes) + 1
)

def test_exceptions(self):
var = pybamm.standard_spatial_vars
lims = {var.y: {"min": 0, "max": 1}}
y_edges = np.array([0, 0.3, 1])
z_edges = np.array([0, 0.3, 1])
mesh = pybamm.two_dimensional_meshes.GetUserSupplied2DSubMesh(y_edges, z_edges)
# test not enough lims
with self.assertRaises(pybamm.GeometryError):
mesh(lims, None)
lims = {var.y: {"min": 0, "max": 1}, var.z: {"min": 0, "max": 1}}

# error if len(edges) != npts
npts = {var.y.id: 10, var.z.id: 3}
with self.assertRaises(pybamm.GeometryError):
mesh(lims, npts)

# error if lims[0] not equal to edges[0]
lims = {var.y: {"min": 0.1, "max": 1}, var.z: {"min": 0, "max": 1}}
npts = {var.y.id: 3, var.z.id: 3}
with self.assertRaises(pybamm.GeometryError):
mesh(lims, npts)

# error if lims[-1] not equal to edges[-1]
lims = {var.y: {"min": 0, "max": 1}, var.z: {"min": 0, "max": 1.3}}
npts = {var.y.id: 3, var.z.id: 3}
with self.assertRaises(pybamm.GeometryError):
mesh(lims, npts)


if __name__ == "__main__":
print("Add -v for more debug output")
import sys
Expand Down

0 comments on commit 71c7ed0

Please sign in to comment.