def __init__(self, name, domain=None, auxiliary_domains=None, coord_sys=None): self.coord_sys = coord_sys super().__init__(name, domain=domain, auxiliary_domains=auxiliary_domains) domain = self.domain if domain == []: raise ValueError("domain must be provided") # Check symbol name vs domain name if name == "r" and not (len(domain) == 1 and "particle" in domain[0]): raise pybamm.DomainError("domain must be particle if name is 'r'") elif name == "r_n" and domain != ["negative particle"]: raise pybamm.DomainError( "domain must be negative particle if name is 'r_n'") elif name == "r_p" and domain != ["positive particle"]: raise pybamm.DomainError( "domain must be positive particle if name is 'r_p'") elif name in ["x", "y", "z", "x_n", "x_s", "x_p"] and any( ["particle" in dom for dom in domain]): raise pybamm.DomainError( "domain cannot be particle if name is '{}'".format(name))
def __init__(self, lims, npts, tabs): # check that two variables have been passed in if len(lims) != 2: raise pybamm.GeometryError( "lims should contain exactly two variables, not {}".format(len(lims)) ) # get spatial variables spatial_vars = list(lims.keys()) # check coordinate system agrees if spatial_vars[0].coord_sys == spatial_vars[1].coord_sys: coord_sys = spatial_vars[0].coord_sys else: raise pybamm.DomainError( """spatial variables should have the same coordinate system, but have coordinate systems {} and {}""".format( spatial_vars[0].coord_sys, spatial_vars[1].coord_sys ) ) # compute edges edges = {} for var in spatial_vars: if var.name not in ["y", "z"]: raise pybamm.DomainError( "spatial variable must be y or z not {}".format(var.name) ) else: edges[var.name] = np.linspace( lims[var]["min"], lims[var]["max"], npts[var.id] ) super().__init__(edges, coord_sys, tabs)
def combine_submeshes(self, *submeshnames): """Combine submeshes into a new submesh, using self.submeshclass Raises pybamm.DomainError if submeshes to be combined do not match up (edges are not aligned). Parameters ---------- submeshnames: list of str The names of the submeshes to be combined Returns ------- submesh: :class:`self.submeshclass` A new submesh with the class defined by self.submeshclass """ # Check that the final edge of each submesh is the same as the first edge of the # next submesh for i in range(len(submeshnames) - 1): for j in range(len(self[submeshnames[i]])): if (self[submeshnames[i]][j].edges[-1] != self[submeshnames[i + 1]][j].edges[0]): raise pybamm.DomainError("submesh edges are not aligned") coord_sys = self[submeshnames[i]][0].coord_sys coord_sys_r = self[submeshnames[i + 1]][0].coord_sys if coord_sys != coord_sys_r: raise pybamm.DomainError( "trying to combine two meshes in different coordinate systems" ) submeshes = [None] * len(self[submeshnames[0]]) # Hack for the special case of current collector if submeshnames == ("current collector", ) and isinstance( self[submeshnames[0]][0].edges, dict): return self[submeshnames[0]] for i in range(len(self[submeshnames[0]])): combined_submesh_edges = np.concatenate( [self[submeshnames[0]][i].edges] + [ self[submeshname][i].edges[1:] for submeshname in submeshnames[1:] ]) coord_sys = self[submeshnames[0]][i].coord_sys submeshes[i] = pybamm.SubMesh1D(combined_submesh_edges, coord_sys) # add in internal boundaries submeshes[i].internal_boundaries = [ self[submeshname][i].edges[0] for submeshname in submeshnames[1:] ] return submeshes
def __init__(self, lims, npts, tabs, side="top", stretch=2.3): # check side is top if side != "top": raise pybamm.GeometryError( "At present, side can only be 'top', but is set to {}".format(side) ) # check that two variables have been passed in if len(lims) != 2: raise pybamm.GeometryError( "lims should contain exactly two variables, not {}".format(len(lims)) ) # get spatial variables spatial_vars = list(lims.keys()) # check coordinate system agrees if spatial_vars[0].coord_sys == spatial_vars[1].coord_sys: coord_sys = spatial_vars[0].coord_sys else: raise pybamm.DomainError( """spatial variables should have the same coordinate system, but have coordinate systems {} and {}""".format( spatial_vars[0].coord_sys, spatial_vars[1].coord_sys ) ) # compute edges edges = {} for var in spatial_vars: if var.name not in ["y", "z"]: raise pybamm.DomainError( "spatial variable must be y or z not {}".format(var.name) ) elif var.name == "y": edges[var.name] = np.linspace( lims[var]["min"], lims[var]["max"], npts[var.id] ) elif var.name == "z": ii = np.array(range(0, npts[var.id])) a = lims[var]["min"] b = lims[var]["max"] edges[var.name] = (b - a) * ( np.exp(-stretch * ii / (npts[var.id] - 1)) - 1 ) / (np.exp(-stretch) - 1) + a super().__init__(edges, coord_sys, tabs)
def check_and_convert_equations(self, equations): """ Convert any scalar equations in dict to 'pybamm.Scalar' and check that domains are consistent """ # Convert any numbers to a pybamm.Scalar for var, eqn in equations.items(): if isinstance(eqn, numbers.Number): equations[var] = pybamm.Scalar(eqn) if not all([ variable.domain == equation.domain or variable.domain == [] or equation.domain == [] for variable, equation in equations.items() ]): raise pybamm.DomainError( "variable and equation in '{}' must have the same domain". format(self.name)) # For initial conditions, check that the equation doesn't contain any # Variable objects # skip this if the dictionary has no "name" attribute (which will be the case # after pickling) if hasattr(self, "name") and self.name == "initial_conditions": for var, eqn in equations.items(): if eqn.has_symbol_of_classes(pybamm.Variable): unpacker = pybamm.SymbolUnpacker(pybamm.Variable) variable_in_equation = list( unpacker.unpack_symbol(eqn).values())[0] raise TypeError( "Initial conditions cannot contain 'Variable' objects, " "but '{!r}' found in initial conditions for '{}'". format(variable_in_equation, var)) return equations
def get_children_domains(self, children): # combine domains from children domain = [] for child in children: if not isinstance(child, pybamm.Symbol): raise TypeError("{} is not a pybamm symbol".format(child)) child_domain = child.domain if child_domain == []: raise pybamm.DomainError( "Cannot concatenate child '{}' with empty domain".format(child) ) if set(domain).isdisjoint(child_domain): domain += child_domain else: raise pybamm.DomainError("domain of children must be disjoint") return domain
def z_average(symbol): """convenience function for creating an average in the z-direction Parameters ---------- symbol : :class:`pybamm.Symbol` The function to be averaged Returns ------- :class:`Symbol` the new averaged symbol """ # Symbol must have domain [] or ["current collector"] if symbol.domain not in [[], ["current collector"]]: raise pybamm.DomainError( """z-average only implemented in the 'current collector' domain, but symbol has domains {}""".format( symbol.domain ) ) # If symbol doesn't have a domain, its average value is itself if symbol.domain == []: new_symbol = symbol.new_copy() new_symbol.parent = None return new_symbol # If symbol is a Broadcast, its average value is its child elif isinstance(symbol, pybamm.Broadcast): return symbol.orphans[0] # Otherwise, use Integral to calculate average value else: z = pybamm.standard_spatial_vars.z l_z = pybamm.geometric_parameters.l_z return Integral(symbol, z) / l_z
def __init__(self, lims, npts, side="top", stretch=2.3): # check side is top if side != "top": raise pybamm.GeometryError( "At present, side can only be 'top', but is set to {}".format( side)) spatial_vars, tabs = self.read_lims(lims) coord_sys = spatial_vars[0].coord_sys # compute edges edges = {} for var in spatial_vars: if var.name not in ["y", "z"]: raise pybamm.DomainError( "spatial variable must be y or z not {}".format(var.name)) elif var.name == "y": edges[var.name] = np.linspace(lims[var]["min"], lims[var]["max"], npts[var.id]) elif var.name == "z": ii = np.array(range(0, npts[var.id])) a = lims[var]["min"] b = lims[var]["max"] edges[var.name] = (b - a) * (np.exp(-stretch * ii / (npts[var.id] - 1)) - 1) / (np.exp(-stretch) - 1) + a super().__init__(edges, coord_sys, tabs)
def auxiliary_domains(self, auxiliary_domains): # Turn dictionary into appropriate form if auxiliary_domains is None: auxiliary_domains = {} for level, dom in auxiliary_domains.items(): if isinstance(dom, str): auxiliary_domains[level] = [dom] # Check domains don't clash if self.domain in auxiliary_domains.values(): raise pybamm.DomainError("Domain cannot be the same as an auxiliary domain") values = [tuple(val) for val in auxiliary_domains.values()] if len(set(values)) != len(values): raise pybamm.DomainError("All auxiliary domains must be different") self._auxiliary_domains = auxiliary_domains
def __init__(self, lims, npts, tabs, y_edges=None, z_edges=None): # raise error if no edges passed if y_edges is None: raise pybamm.GeometryError("User mesh requires parameter 'y_edges'") if z_edges is None: raise pybamm.GeometryError("User mesh requires parameter 'z_edges'") # check that two variables have been passed in if len(lims) != 2: raise pybamm.GeometryError( "lims should contain exactly two variables, not {}".format(len(lims)) ) # get spatial variables spatial_vars = list(lims.keys()) # check coordinate system agrees if spatial_vars[0].coord_sys == spatial_vars[1].coord_sys: coord_sys = spatial_vars[0].coord_sys else: raise pybamm.DomainError( """spatial variables should have the same coordinate system, but have coordinate systems {} and {}""".format( spatial_vars[0].coord_sys, spatial_vars[1].coord_sys ) ) # 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[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[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 ) ) super().__init__(edges, coord_sys=coord_sys, tabs=tabs)
def x_average(symbol): """convenience function for creating an average in the x-direction Parameters ---------- symbol : :class:`pybamm.Symbol` The function to be averaged Returns ------- :class:`Symbol` the new averaged symbol """ # If symbol doesn't have a domain, its average value is itself if symbol.domain in [[], ["current collector"]]: new_symbol = symbol.new_copy() new_symbol.parent = None return new_symbol # If symbol is a Broadcast, its average value is its child elif isinstance(symbol, pybamm.Broadcast): return symbol.orphans[0] # If symbol is a concatenation of Broadcasts, its average value is its child elif ( isinstance(symbol, pybamm.Concatenation) and all(isinstance(child, pybamm.Broadcast) for child in symbol.children) and symbol.domain == ["negative electrode", "separator", "positive electrode"] ): a, b, c = [orp.orphans[0] for orp in symbol.orphans] if a.id == b.id == c.id: return a else: l_n = pybamm.geometric_parameters.l_n l_s = pybamm.geometric_parameters.l_s l_p = pybamm.geometric_parameters.l_p return (l_n * a + l_s * b + l_p * c) / (l_n + l_s + l_p) # Otherwise, use Integral to calculate average value else: if symbol.domain == ["negative electrode"]: x = pybamm.standard_spatial_vars.x_n l = pybamm.geometric_parameters.l_n elif symbol.domain == ["separator"]: x = pybamm.standard_spatial_vars.x_s l = pybamm.geometric_parameters.l_s elif symbol.domain == ["positive electrode"]: x = pybamm.standard_spatial_vars.x_p l = pybamm.geometric_parameters.l_p elif symbol.domain == ["negative electrode", "separator", "positive electrode"]: x = pybamm.standard_spatial_vars.x l = pybamm.Scalar(1) elif symbol.domain == ["negative particle"]: x = pybamm.standard_spatial_vars.x_n l = pybamm.geometric_parameters.l_n elif symbol.domain == ["positive particle"]: x = pybamm.standard_spatial_vars.x_p l = pybamm.geometric_parameters.l_p else: raise pybamm.DomainError("domain '{}' not recognised".format(symbol.domain)) return Integral(symbol, x) / l
def domain(self, domain): if domain in ["Negative", "Separator", "Positive"]: self._domain = domain elif domain is None: pass else: raise pybamm.DomainError( "Domain must be either 'Negative' or 'Positive' not {}".format( domain))
def __init__(self, child, side, domain): self.side = side if domain is None: raise pybamm.DomainError("Delta function domain cannot be None") if child.domain != []: auxiliary_domains = {"secondary": child.domain} else: auxiliary_domains = {} super().__init__("delta_function", child, domain, auxiliary_domains)
def __init__(self, lims, npts, tabs): # check that two variables have been passed in if len(lims) != 2: raise pybamm.GeometryError( "lims should contain exactly two variables, not {}".format(len(lims)) ) # get spatial variables spatial_vars = list(lims.keys()) # check coordinate system agrees if spatial_vars[0].coord_sys == spatial_vars[1].coord_sys: coord_sys = spatial_vars[0].coord_sys else: raise pybamm.DomainError( """spatial variables should have the same coordinate system, but have coordinate systems {} and {}""".format( spatial_vars[0].coord_sys, spatial_vars[1].coord_sys ) ) # compute edges edges = {} for var in spatial_vars: if var.name not in ["y", "z"]: raise pybamm.DomainError( "spatial variable must be y or z not {}".format(var.name) ) else: # Create N Chebyshev nodes in the interval (a,b) N = npts[var.id] - 2 ii = np.array(range(1, N + 1)) a = lims[var]["min"] b = lims[var]["max"] x_cheb = (a + b) / 2 + (b - a) / 2 * np.cos( (2 * ii - 1) * np.pi / 2 / N ) # Append the boundary nodes. Note: we need to flip the order the # Chebyshev nodes as they are created in descending order. edges[var.name] = np.concatenate(([a], np.flip(x_cheb), [b])) super().__init__(edges, coord_sys, tabs)
def combine_submeshes(self, *submeshnames): """Combine submeshes into a new submesh, using self.submeshclass Raises pybamm.DomainError if submeshes to be combined do not match up (edges are not aligned). Parameters ---------- submeshnames: list of str The names of the submeshes to be combined Returns ------- submesh: :class:`self.submeshclass` A new submesh with the class defined by self.submeshclass """ if submeshnames == (): raise ValueError("Submesh domains being combined cannot be empty") # If there is just a single submesh, we can return it directly if len(submeshnames) == 1: return self[submeshnames[0]] # Check that the final edge of each submesh is the same as the first edge of the # next submesh for i in range(len(submeshnames) - 1): if self[submeshnames[i]].edges[-1] != self[submeshnames[i + 1]].edges[0]: raise pybamm.DomainError("submesh edges are not aligned") coord_sys = self[submeshnames[i]].coord_sys coord_sys_r = self[submeshnames[i + 1]].coord_sys if coord_sys != coord_sys_r: raise pybamm.DomainError( "trying to combine two meshes in different coordinate systems" ) combined_submesh_edges = np.concatenate( [self[submeshnames[0]].edges] + [self[submeshname].edges[1:] for submeshname in submeshnames[1:]] ) coord_sys = self[submeshnames[0]].coord_sys submesh = pybamm.SubMesh1D(combined_submesh_edges, coord_sys) # add in internal boundaries submesh.internal_boundaries = [ self[submeshname].edges[0] for submeshname in submeshnames[1:] ] return submesh
def domain(self, domain): if domain is None: domain = [] elif isinstance(domain, str): domain = [domain] if domain == [] and self.auxiliary_domains != {}: raise pybamm.DomainError( "Domain cannot be empty if auxiliary domains are not empty") if domain in self.auxiliary_domains.values(): raise pybamm.DomainError( "Domain cannot be the same as an auxiliary domain") try: iter(domain) except TypeError: raise TypeError("Domain: argument domain is not iterable") else: self._domain = domain # Update id since domain has changed self.set_id()
def __init__(self, name, child): if child.domain == []: raise pybamm.DomainError( "Cannot upwind '{}' since its domain is empty. ".format( child) + "Try broadcasting the object first, e.g.\n\n" "\tpybamm.div(pybamm.PrimaryBroadcast(symbol, 'domain'))") if child.evaluates_on_edges("primary") is True: raise TypeError( "Cannot upwind '{}' since it does not ".format(child) + "evaluate on nodes.") super().__init__(name, child)
def __init__(self, child): if child.domain == []: raise pybamm.DomainError( "Cannot take gradient of '{}' since its domain is empty. ". format(child) + "Try broadcasting the object first, e.g.\n\n" "\tpybamm.grad(pybamm.PrimaryBroadcast(symbol, 'domain'))") 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 get_children_domains(self, children): # combine domains from children domain = [] for child in children: child_domain = child.domain if set(domain).isdisjoint(child_domain): domain += child_domain else: raise pybamm.DomainError( """domain of children must be disjoint""") return domain
def check_and_set_domains(self, child, broadcast_type, broadcast_domain, broadcast_auxiliary_domains): "See :meth:`Broadcast.check_and_set_domains`" if child.domain == []: raise TypeError( "Cannot take SecondaryBroadcast of an object with empty domain. " "Use PrimaryBroadcast instead.") # Can only do secondary broadcast from particle to electrode or from # electrode to current collector if child.domain[0] in [ "negative particle", "positive particle", ] and broadcast_domain[0] not in [ "negative electrode", "separator", "positive electrode", ]: raise pybamm.DomainError( """Secondary broadcast from particle domain must be to electrode or separator domains""") elif child.domain[0] in [ "negative electrode", "separator", "positive electrode", ] and broadcast_domain != ["current collector"]: raise pybamm.DomainError( """Secondary broadcast from electrode or separator must be to current collector domains""") elif child.domain == ["current collector"]: raise pybamm.DomainError( "Cannot do secondary broadcast from current collector domain") # Domain stays the same as child domain and broadcast domain is secondary # domain domain = child.domain auxiliary_domains = {"secondary": broadcast_domain} # Child's secondary domain becomes tertiary domain if "secondary" in child.auxiliary_domains: auxiliary_domains["tertiary"] = child.auxiliary_domains[ "secondary"] return domain, auxiliary_domains
def check_and_set_domains(self, child, broadcast_type, broadcast_domain, broadcast_auxiliary_domains): "See :meth:`Broadcast.check_and_set_domains`" # Can only do primary broadcast from current collector to electrode or particle # or from electrode to particle. Note current collector to particle *is* allowed if child.domain == []: pass elif child.domain == ["current collector" ] and broadcast_domain[0] not in [ "negative electrode", "separator", "positive electrode", "negative particle", "positive particle", ]: raise pybamm.DomainError( """Primary broadcast from current collector domain must be to electrode or separator or particle domains""") elif child.domain[0] in [ "negative electrode", "separator", "positive electrode", ] and broadcast_domain[0] not in [ "negative particle", "positive particle" ]: raise pybamm.DomainError( """Primary broadcast from electrode or separator must be to particle domains""") elif child.domain[0] in ["negative particle", "positive particle"]: raise pybamm.DomainError( "Cannot do primary broadcast from particle domain") domain = broadcast_domain auxiliary_domains = {} if child.domain != []: auxiliary_domains["secondary"] = child.domain if "secondary" in child.auxiliary_domains: auxiliary_domains["tertiary"] = child.auxiliary_domains[ "secondary"] return domain, auxiliary_domains
def check_and_set_domains(self, child, broadcast_type, broadcast_domain, broadcast_auxiliary_domains): "See :meth:`Broadcast.check_and_set_domains`" # Variables on the current collector can only be broadcast to 'primary' if child.domain == ["current collector"]: raise pybamm.DomainError( "Cannot do full broadcast from current collector domain") domain = broadcast_domain auxiliary_domains = broadcast_auxiliary_domains or {} return domain, auxiliary_domains
def internal_neumann_condition( self, left_symbol_disc, right_symbol_disc, left_mesh, right_mesh ): """ A method to find the internal neumann conditions between two symbols on adjacent subdomains. Parameters ---------- left_symbol_disc : :class:`pybamm.Symbol` The discretised symbol on the left subdomain right_symbol_disc : :class:`pybamm.Symbol` The discretised symbol on the right subdomain left_mesh : list The mesh on the left subdomain right_mesh : list The mesh on the right subdomain """ left_npts = left_mesh[0].npts right_npts = right_mesh[0].npts sec_pts = len(left_mesh) if sec_pts != len(right_mesh): raise pybamm.DomainError( """Number of secondary points in subdomains do not match""" ) left_sub_matrix = np.zeros((1, left_npts)) left_sub_matrix[0][left_npts - 1] = 1 left_matrix = pybamm.Matrix(csr_matrix(kron(eye(sec_pts), left_sub_matrix))) right_sub_matrix = np.zeros((1, right_npts)) right_sub_matrix[0][0] = 1 right_matrix = pybamm.Matrix(csr_matrix(kron(eye(sec_pts), right_sub_matrix))) # Remove domains to avoid clash left_domain = left_symbol_disc.domain right_domain = right_symbol_disc.domain left_symbol_disc.domain = [] right_symbol_disc.domain = [] # Finite volume derivative dy = right_matrix @ right_symbol_disc - left_matrix @ left_symbol_disc dx = right_mesh[0].nodes[0] - left_mesh[0].nodes[-1] # Change domains back left_symbol_disc.domain = left_domain right_symbol_disc.domain = right_domain return dy / dx
def get_children_domains(self, ldomain, rdomain): "Combine domains from children in appropriate way" if ldomain == rdomain: return ldomain elif ldomain == []: return rdomain elif rdomain == []: return ldomain else: raise pybamm.DomainError(""" children must have same (or empty) domains, but left.domain is '{}' and right.domain is '{}' """.format(ldomain, rdomain))
def __init__(self, child): if child.domain == []: raise pybamm.DomainError( "Cannot take divergence of '{}' since its domain is empty. ". format(child) + "Try broadcasting the object first, e.g.\n\n" "\tpybamm.div(pybamm.PrimaryBroadcast(symbol, 'domain'))") if child.evaluates_on_edges("primary") is False: raise TypeError( "Cannot take divergence of '{}' since it does not ".format( child) + "evaluate on edges. Usually, a gradient should be taken before the " "divergence.") super().__init__("div", child)
def __init__(self, lims, npts): spatial_vars, tabs = self.read_lims(lims) coord_sys = spatial_vars[0].coord_sys # compute edges edges = {} for var in spatial_vars: if var.name not in ["y", "z"]: raise pybamm.DomainError( "spatial variable must be y or z not {}".format(var.name)) else: edges[var.name] = np.linspace(lims[var]["min"], lims[var]["max"], npts[var.id]) super().__init__(edges, coord_sys, tabs)
def get_children_auxiliary_domains(self, children): "Combine auxiliary domains from children, at all levels" aux_domains = {} for child in children: for level in child.auxiliary_domains.keys(): if (level not in aux_domains or aux_domains[level] == [] or child.auxiliary_domains[level] == aux_domains[level]): aux_domains[level] = child.auxiliary_domains[level] else: raise pybamm.DomainError( """children must have same or empty auxiliary domains, not {!s} and {!s}""".format( aux_domains[level], child.auxiliary_domains[level])) return aux_domains
def get_children_domains(self, children_list): """Obtains the unique domain of the children. If the children have different domains then raise an error""" domains = [child.domain for child in children_list if child.domain != []] # check that there is one common domain amongst children distinct_domains = set(tuple(dom) for dom in domains) if len(distinct_domains) > 1: raise pybamm.DomainError( "Functions can only be applied to variables on the same domain" ) elif len(distinct_domains) == 0: domain = [] else: domain = domains[0] return domain
def __init__(self, children, full_mesh, copy_this=None): # Convert any constant symbols in children to a Vector of the right size for # concatenation children = list(children) # Allow the base class to sort the domains into the correct order super().__init__(*children, name="domain concatenation") # ensure domain is sorted according to mesh keys domain_dict = {d: full_mesh.domain_order.index(d) for d in self.domain} self.domain = sorted(domain_dict, key=domain_dict.__getitem__) if copy_this is None: # store mesh self._full_mesh = full_mesh # Check that there is a domain, otherwise the functionality won't work # and we should raise a DomainError if self.domain == []: raise pybamm.DomainError( """ domain cannot be empty for a DomainConcatenation. Perhaps the children should have been Broadcasted first? """ ) # create dict of domain => slice of final vector self.secondary_dimensions_npts = len(self.full_mesh[self.domain[0]]) self._slices = self.create_slices(self) # store size of final vector self._size = self._slices[self.domain[-1]][-1].stop # create disc of domain => slice for each child self._children_slices = [ self.create_slices(child) for child in self.cached_children ] else: self._full_mesh = copy.copy(copy_this._full_mesh) self._slices = copy.copy(copy_this._slices) self._size = copy.copy(copy_this._size) self._children_slices = copy.copy(copy_this._children_slices) self.secondary_dimensions_npts = copy_this.secondary_dimensions_npts
def domain(self, domain): ok_domain_list = [ "Negative", "Separator", "Positive", "Negative electrode", "Negative electrolyte", "Separator electrolyte", "Positive electrode", "Positive electrolyte", ] if domain in ok_domain_list: self._domain = domain elif domain is None: pass else: raise pybamm.DomainError( "Domain '{}' not recognised (must be one of {})".format( domain, ok_domain_list))