Exemple #1
0
    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
Exemple #2
0
    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)
Exemple #3
0
    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)
Exemple #4
0
    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)
Exemple #5
0
    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)
Exemple #6
0
    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
Exemple #9
0
    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())
Exemple #11
0
    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