def options(self, extra_options): extra_options = extra_options or {} # Default options options = {"particle shape": "spherical", "particle cracking": None} # All model options get passed to the parameter class, so we just need # to update the options in the default options and ignore the rest for name, opt in extra_options.items(): if name in options: options[name] = opt # Check the options are valid (this check also happens in 'BaseBatteryModel', # but we check here incase the parameter class is instantiated separetly # from the model) if options["particle shape"] not in ["spherical", "user"]: raise pybamm.OptionError( "particle shape '{}' not recognised".format(options["particle shape"]) ) if options["particle cracking"] not in [ None, "no cracking", "cathode", "anode", "both", ]: raise pybamm.OptionError( "particle cracking '{}' not recognised".format( options["particle cracking"] ) ) self._options = options
def set_electrolyte_submodel(self): surf_form = pybamm.electrolyte_conductivity.surface_potential_form if self.options["electrolyte conductivity"] not in [ "default", "leading order" ]: raise pybamm.OptionError( "electrolyte conductivity '{}' not suitable for SPM".format( self.options["electrolyte conductivity"])) if self.options["surface form"] is False: self.submodels[ "leading-order electrolyte conductivity"] = pybamm.electrolyte_conductivity.LeadingOrder( self.param) elif self.options["surface form"] == "differential": for domain in ["Negative", "Separator", "Positive"]: self.submodels[ "leading-order " + domain.lower() + " electrolyte conductivity"] = surf_form.LeadingOrderDifferential( self.param, domain) elif self.options["surface form"] == "algebraic": for domain in ["Negative", "Separator", "Positive"]: self.submodels[ "leading-order " + domain.lower() + " electrolyte conductivity"] = surf_form.LeadingOrderAlgebraic( self.param, domain) self.submodels[ "electrolyte diffusion"] = pybamm.electrolyte_diffusion.ConstantConcentration( self.param)
def set_electrolyte_submodel(self): surf_form = pybamm.electrolyte_conductivity.surface_potential_form self.submodels[ "electrolyte diffusion"] = pybamm.electrolyte_diffusion.Full( self.param) if self.options["electrolyte conductivity"] not in ["default", "full"]: raise pybamm.OptionError( "electrolyte conductivity '{}' not suitable for DFN".format( self.options["electrolyte conductivity"])) if self.options["surface form"] == "false": self.submodels[ "electrolyte conductivity"] = pybamm.electrolyte_conductivity.Full( self.param) elif self.options["surface form"] == "differential": for domain in ["Negative", "Separator", "Positive"]: self.submodels[ domain.lower() + " electrolyte conductivity"] = surf_form.FullDifferential( self.param, domain) elif self.options["surface form"] == "algebraic": for domain in ["Negative", "Separator", "Positive"]: self.submodels[ domain.lower() + " electrolyte conductivity"] = surf_form.FullAlgebraic( self.param, domain)
def set_electrolyte_submodel(self): if self.options["electrolyte conductivity"] not in [ "default", "composite", "integrated", ]: raise pybamm.OptionError( "electrolyte conductivity '{}' not suitable for SPMe".format( self.options["electrolyte conductivity"])) if self.options["surface form"] is False: if self.options["electrolyte conductivity"] in [ "default", "composite" ]: self.submodels[ "electrolyte conductivity"] = pybamm.electrolyte_conductivity.Composite( self.param) elif self.options["electrolyte conductivity"] == "integrated": self.submodels[ "electrolyte conductivity"] = pybamm.electrolyte_conductivity.Integrated( self.param) elif self.options["surface form"] == "differential": raise NotImplementedError( "surface form '{}' has not been implemented for SPMe yet". format(self.options["surface form"])) elif self.options["surface form"] == "algebraic": raise NotImplementedError( "surface form '{}' has not been implemented for SPMe yet". format(self.options["surface form"])) self.submodels[ "electrolyte diffusion"] = pybamm.electrolyte_diffusion.Full( self.param)
def print(self, filename=None, output_format="text"): """Print all citations that were used for running simulations. Parameters ---------- filename : str, optional Filename to which to print citations. If None, citations are printed to the terminal. """ citations = "" citations_file = os.path.join(pybamm.root_dir(), "pybamm", "CITATIONS.txt") if output_format == "text": citations = pybtex.format_from_file( citations_file, "plain", citations=self._papers_to_cite, output_backend="plaintext", ) elif output_format == "bibtex": for key in self._papers_to_cite: citations += self._all_citations[key] + "\n" else: raise pybamm.OptionError( "Output format {} not recognised." "It should be 'text' or 'bibtex'.".format(output_format)) if filename is None: print(citations) else: with open(filename, "w") as f: f.write(citations)
def options(self, extra_options): default_options = {"dimensionality": 1} extra_options = extra_options or {} options = pybamm.FuzzyDict(default_options) # any extra options overwrite the default options for name, opt in extra_options.items(): if name in default_options: options[name] = opt else: raise pybamm.OptionError( "Option '{}' not recognised. Best matches are {}".format( name, options.get_best_matches(name))) if options["dimensionality"] not in [1, 2]: raise pybamm.OptionError( "Dimension of current collectors must be 1 or 2, not {}". format(options["dimensionality"])) self._options = options
def options(self, extra_options): options = Options(extra_options) # Options that are incompatible with models if isinstance(self, pybamm.lithium_ion.BaseModel): if options["convection"] != "none": raise pybamm.OptionError( "convection not implemented for lithium-ion models") if (options["thermal"] in ["x-lumped", "x-full"] and options["cell geometry"] != "pouch"): raise pybamm.OptionError(options["thermal"] + " model must have pouch geometry.") if isinstance(self, pybamm.lead_acid.BaseModel): if options["thermal"] != "isothermal" and options[ "dimensionality"] != 0: raise pybamm.OptionError( "Lead-acid models can only have thermal " "effects if dimensionality is 0.") if options["SEI"] != "none" or options[ "SEI film resistance"] != "none": raise pybamm.OptionError( "Lead-acid models cannot have SEI formation") if options["lithium plating"] != "none": raise pybamm.OptionError( "Lead-acid models cannot have lithium plating") if (isinstance(self, (pybamm.lead_acid.LOQS, pybamm.lead_acid.Composite)) and options["surface form"] == "false"): if len(options["side reactions"]) > 0: raise pybamm.OptionError( """must use surface formulation to solve {!s} with side reactions """.format(self)) self._options = options
def options(self, extra_options): default_options = { "operating mode": "current", "dimensionality": 0, "surface form": False, "convection": False, "side reactions": [], "interfacial surface area": "constant", "current collector": "uniform", "particle": "Fickian diffusion", "particle shape": "spherical", "thermal": "isothermal", "cell geometry": None, "external submodels": [], "sei": None, "sei porosity change": False, "working electrode": None, } # Change the default for cell geometry based on which thermal option is provided extra_options = extra_options or {} thermal_option = extra_options.get( "thermal", None ) # return None if option not given if thermal_option is None or thermal_option in ["isothermal", "lumped"]: default_options["cell geometry"] = "arbitrary" else: default_options["cell geometry"] = "pouch" # The "cell geometry" option will still be overridden by extra_options if # provided # Change the default for SEI film resistance based on which sei option is # provided # extra_options = extra_options or {} sei_option = extra_options.get("sei", None) # return None if option not given if sei_option is None: default_options["sei film resistance"] = None else: default_options["sei film resistance"] = "distributed" # The "sei film resistance" option will still be overridden by extra_options if # provided options = pybamm.FuzzyDict(default_options) # any extra options overwrite the default options for name, opt in extra_options.items(): if name in default_options: options[name] = opt else: raise pybamm.OptionError( "Option '{}' not recognised. Best matches are {}".format( name, options.get_best_matches(name) ) ) # Options that are incompatible with models if isinstance(self, pybamm.lithium_ion.BaseModel): if options["convection"] is not False: raise pybamm.OptionError( "convection not implemented for lithium-ion models" ) if ( options["thermal"] in ["x-lumped", "x-full"] and options["cell geometry"] != "pouch" ): raise pybamm.OptionError( options["thermal"] + " model must have pouch geometry." ) if isinstance(self, pybamm.lead_acid.BaseModel): if options["thermal"] != "isothermal" and options["dimensionality"] != 0: raise pybamm.OptionError( "Lead-acid models can only have thermal " "effects if dimensionality is 0." ) if options["sei"] is not None or options["sei film resistance"] is not None: raise pybamm.OptionError("Lead-acid models cannot have SEI formation") # Some standard checks to make sure options are compatible if not ( options["operating mode"] in ["current", "voltage", "power"] or callable(options["operating mode"]) ): raise pybamm.OptionError( "operating mode '{}' not recognised".format(options["operating mode"]) ) if ( isinstance(self, (pybamm.lead_acid.LOQS, pybamm.lead_acid.Composite)) and options["surface form"] is False ): if len(options["side reactions"]) > 0: raise pybamm.OptionError( """must use surface formulation to solve {!s} with side reactions """.format( self ) ) if options["surface form"] not in [False, "differential", "algebraic"]: raise pybamm.OptionError( "surface form '{}' not recognised".format(options["surface form"]) ) if options["convection"] not in [ False, "uniform transverse", "full transverse", ]: raise pybamm.OptionError( "convection option '{}' not recognised".format(options["convection"]) ) if options["current collector"] not in [ "uniform", "potential pair", "potential pair quite conductive", ]: raise pybamm.OptionError( "current collector model '{}' not recognised".format( options["current collector"] ) ) if options["dimensionality"] not in [0, 1, 2]: raise pybamm.OptionError( "Dimension of current collectors must be 0, 1, or 2, not {}".format( options["dimensionality"] ) ) if options["thermal"] not in ["isothermal", "lumped", "x-lumped", "x-full"]: raise pybamm.OptionError( "Unknown thermal model '{}'".format(options["thermal"]) ) if options["cell geometry"] not in ["arbitrary", "pouch"]: raise pybamm.OptionError( "Unknown geometry '{}'".format(options["cell geometry"]) ) if options["sei"] not in [ None, "constant", "reaction limited", "solvent-diffusion limited", "electron-migration limited", "interstitial-diffusion limited", "ec reaction limited", ]: raise pybamm.OptionError("Unknown sei model '{}'".format(options["sei"])) if options["sei film resistance"] not in [None, "distributed", "average"]: raise pybamm.OptionError( "Unknown sei film resistance model '{}'".format( options["sei film resistance"] ) ) if options["sei porosity change"] not in [True, False]: raise pybamm.OptionError( "Unknown sei porosity change '{}'".format( options["sei porosity change"] ) ) if options["dimensionality"] == 0: if options["current collector"] not in ["uniform"]: raise pybamm.OptionError( "current collector model must be uniform in 0D model" ) if options["convection"] == "full transverse": raise pybamm.OptionError( "cannot have transverse convection in 0D model" ) if options["particle"] not in [ "Fickian diffusion", "fast diffusion", "uniform profile", "quadratic profile", "quartic profile", ]: raise pybamm.OptionError( "particle model '{}' not recognised".format(options["particle"]) ) if options["particle"] == "fast diffusion": raise NotImplementedError( "The 'fast diffusion' option has been renamed. " "Use 'uniform profile' instead." ) if options["particle shape"] not in ["spherical", "user"]: raise pybamm.OptionError( "particle shape '{}' not recognised".format(options["particle shape"]) ) if options["thermal"] == "x-lumped" and options["dimensionality"] == 1: warnings.warn( "1+1D Thermal models are only valid if both tabs are " "placed at the top of the cell." ) self._options = options
def options(self, extra_options): default_options = { "operating mode": "current", "dimensionality": 0, "surface form": False, "convection": False, "side reactions": [], "interfacial surface area": "constant", "current collector": "uniform", "particle": "Fickian diffusion", "thermal": "isothermal", "thermal current collector": False, "external submodels": [], } options = default_options # any extra options overwrite the default options if extra_options is not None: for name, opt in extra_options.items(): if name in default_options: options[name] = opt else: raise pybamm.OptionError( "option {} not recognised".format(name)) # Some standard checks to make sure options are compatible if not (options["operating mode"] in ["current", "voltage", "power"] or callable(options["operating mode"])): raise pybamm.OptionError( "operating mode '{}' not recognised".format( options["operating mode"])) if (isinstance(self, (pybamm.lead_acid.LOQS, pybamm.lead_acid.Composite)) and options["surface form"] is False): if len(options["side reactions"]) > 0: raise pybamm.OptionError(""" must use surface formulation to solve {!s} with side reactions """.format(self)) if options["surface form"] not in [False, "differential", "algebraic"]: raise pybamm.OptionError("surface form '{}' not recognised".format( options["surface form"])) if options["current collector"] not in [ "uniform", "potential pair", "potential pair quite conductive", "set external potential", ]: raise pybamm.OptionError( "current collector model '{}' not recognised".format( options["current collector"])) if options["dimensionality"] not in [0, 1, 2]: raise pybamm.OptionError( "Dimension of current collectors must be 0, 1, or 2, not {}". format(options["dimensionality"])) if options["thermal"] not in [ "isothermal", "x-full", "x-lumped", "xyz-lumped", "lumped", "set external temperature", ]: raise pybamm.OptionError("Unknown thermal model '{}'".format( options["thermal"])) if options["particle"] not in ["Fickian diffusion", "fast diffusion"]: raise pybamm.OptionError( "particle model '{}' not recognised".format( options["particle"])) # Options that are incompatible with models if isinstance(self, pybamm.lithium_ion.BaseModel): # if options["surface form"] is not False: # raise pybamm.OptionError( # "surface form not implemented for lithium-ion models" # ) if options["convection"] is True: raise pybamm.OptionError( "convection not implemented for lithium-ion models") if isinstance(self, pybamm.lead_acid.BaseModel): if options["thermal"] != "isothermal": raise pybamm.OptionError( "thermal effects not implemented for lead-acid models") if options["thermal current collector"] is True: raise pybamm.OptionError( "thermal effects not implemented for lead-acid models") if options[ "current collector"] == "set external potential" and not isinstance( self, pybamm.lithium_ion.SPM): raise pybamm.OptionError( "option {} only compatible with SPM".format( options["current collector"])) self._options = options
def __init__(self, extra_options): self.possible_options = { "surface form": ["false", "differential", "algebraic"], "convection": ["none", "uniform transverse", "full transverse"], "current collector": [ "uniform", "potential pair", "potential pair quite conductive", ], "dimensionality": [0, 1, 2], "interfacial surface area": ["constant", "varying"], "thermal": ["isothermal", "lumped", "x-lumped", "x-full"], "cell geometry": ["arbitrary", "pouch"], "SEI": [ "none", "constant", "reaction limited", "solvent-diffusion limited", "electron-migration limited", "interstitial-diffusion limited", "ec reaction limited", ], "SEI film resistance": ["none", "distributed", "average"], "SEI porosity change": ["true", "false"], "lithium plating": ["none", "reversible", "irreversible"], "loss of active material": ["none", "negative", "positive", "both"], "operating mode": ["current", "voltage", "power"], "particle cracking": [ "none", "no cracking", "negative", "positive", "both", ], "lithium plating porosity change": ["true", "false"], "particle": [ "Fickian diffusion", "fast diffusion", "uniform profile", "quadratic profile", "quartic profile", ], "particle shape": ["spherical", "user", "no particles"], "electrolyte conductivity": [ "default", "full", "leading order", "composite", "integrated", ], "total interfacial current density as a state": ["true", "false"], } default_options = { "operating mode": "current", "dimensionality": 0, "surface form": "false", "convection": "none", "side reactions": [], "interfacial surface area": "constant", "current collector": "uniform", "particle": "Fickian diffusion", "particle shape": "spherical", "electrolyte conductivity": "default", "thermal": "isothermal", "cell geometry": "none", "external submodels": [], "SEI": "none", "lithium plating": "none", "SEI porosity change": "false", "lithium plating porosity change": "false", "loss of active material": "none", "working electrode": "none", "particle cracking": "none", "total interfacial current density as a state": "false", } # Change the default for cell geometry based on which thermal option is provided extra_options = extra_options or {} thermal_option = extra_options.get("thermal", "none") # return "none" if option not given if thermal_option in ["none", "isothermal", "lumped"]: default_options["cell geometry"] = "arbitrary" else: default_options["cell geometry"] = "pouch" # The "cell geometry" option will still be overridden by extra_options if # provided # Change the default for SEI film resistance based on which SEI option is # provided # extra_options = extra_options or {} sei_option = extra_options.get("SEI", "none") # return "none" if option not given if sei_option == "none": default_options["SEI film resistance"] = "none" else: default_options["SEI film resistance"] = "distributed" # The "SEI film resistance" option will still be overridden by extra_options if # provided options = pybamm.FuzzyDict(default_options) # any extra options overwrite the default options for name, opt in extra_options.items(): if name in default_options: options[name] = opt else: raise pybamm.OptionError( "Option '{}' not recognised. Best matches are {}".format( name, options.get_best_matches(name))) # If "SEI film resistance" is "distributed" then "total interfacial current # density as a state" must be "true" if options["SEI film resistance"] == "distributed": options["total interfacial current density as a state"] = "true" # Check that extra_options did not try to provide a clashing option if (extra_options.get( "total interfacial current density as a state") == "false" ): raise pybamm.OptionError( "If 'sei film resistance' is 'distributed' then 'total interfacial " "current density as a state' must be 'true'") # Some standard checks to make sure options are compatible if options["SEI porosity change"] in [True, False]: raise pybamm.OptionError( "SEI porosity change must now be given in string format " "('true' or 'false')") if options["dimensionality"] == 0: if options["current collector"] not in ["uniform"]: raise pybamm.OptionError( "current collector model must be uniform in 0D model") if options["convection"] == "full transverse": raise pybamm.OptionError( "cannot have transverse convection in 0D model") if options["particle"] == "fast diffusion": raise NotImplementedError( "The 'fast diffusion' option has been renamed. " "Use 'uniform profile' instead.") if options["thermal"] == "x-lumped" and options["dimensionality"] == 1: warnings.warn( "1+1D Thermal models are only valid if both tabs are " "placed at the top of the cell.") for option, value in options.items(): if (option == "side reactions" or option == "external submodels" or option == "working electrode"): pass elif value not in self.possible_options[option]: if not (option == "operating mode" and callable(value)): raise pybamm.OptionError( f"\n'{value}' is not recognized in option '{option}'. " f"Possible values are {self.possible_options[option]}") super().__init__(options.items())
def options(self, extra_options): default_options = { "operating mode": "current", "dimensionality": 0, "surface form": False, "convection": False, "side reactions": [], "interfacial surface area": "constant", "current collector": "uniform", "particle": "Fickian diffusion", "thermal": "isothermal", "external submodels": [], "sei": None, } options = pybamm.FuzzyDict(default_options) # any extra options overwrite the default options if extra_options is not None: for name, opt in extra_options.items(): if name in default_options: options[name] = opt else: raise pybamm.OptionError( "Option '{}' not recognised. Best matches are {}". format(name, options.get_best_matches(name))) # Options that are incompatible with models if isinstance(self, pybamm.lithium_ion.BaseModel): if options["convection"] is not False: raise pybamm.OptionError( "convection not implemented for lithium-ion models") if isinstance(self, pybamm.lead_acid.BaseModel): if options["thermal"] != "isothermal" and options[ "dimensionality"] != 0: raise pybamm.OptionError( "Lead-acid models can only have thermal " "effects if dimensionality is 0.") # Some standard checks to make sure options are compatible if not (options["operating mode"] in ["current", "voltage", "power"] or callable(options["operating mode"])): raise pybamm.OptionError( "operating mode '{}' not recognised".format( options["operating mode"])) if (isinstance(self, (pybamm.lead_acid.LOQS, pybamm.lead_acid.Composite)) and options["surface form"] is False): if len(options["side reactions"]) > 0: raise pybamm.OptionError( """must use surface formulation to solve {!s} with side reactions """.format(self)) if options["surface form"] not in [False, "differential", "algebraic"]: raise pybamm.OptionError("surface form '{}' not recognised".format( options["surface form"])) if options["convection"] not in [ False, "uniform transverse", "full transverse", ]: raise pybamm.OptionError( "convection option '{}' not recognised".format( options["convection"])) if options["current collector"] not in [ "uniform", "potential pair", "potential pair quite conductive", ]: raise pybamm.OptionError( "current collector model '{}' not recognised".format( options["current collector"])) if options["dimensionality"] not in [0, 1, 2]: raise pybamm.OptionError( "Dimension of current collectors must be 0, 1, or 2, not {}". format(options["dimensionality"])) if options["thermal"] not in [ "isothermal", "lumped", "x-lumped", "x-full" ]: raise pybamm.OptionError("Unknown thermal model '{}'".format( options["thermal"])) if options["dimensionality"] == 0: if options["current collector"] not in [ "uniform", ]: raise pybamm.OptionError( "current collector model must be uniform in 0D model") if options["convection"] == "full transverse": raise pybamm.OptionError( "cannot have transverse convection in 0D model") if options["particle"] not in ["Fickian diffusion", "fast diffusion"]: raise pybamm.OptionError( "particle model '{}' not recognised".format( options["particle"])) if options["thermal"] == "x-lumped" and options["dimensionality"] == 1: warnings.warn( "1+1D Thermal models are only valid if both tabs are" + "placed at the top of the cell.") self._options = options