def test_electrolyte_conductivity(self): root = pybamm.root_dir() p = "pybamm/input/parameters/lithium-ion/electrolytes/lipf6_Landesfeind2019" k_path = os.path.join(root, p) files = [ f for f in os.listdir(k_path) if ".py" in f and "_base" not in f and "conductivity" in f ] files.sort() funcs = [pybamm.load_function(os.path.join(k_path, f)) for f in files] T_ref = 298.15 T = T_ref + 30.0 c = 1000.0 k = [np.around(f(c, T).value, 6) for f in funcs] self.assertEqual(k, [1.839786, 1.361015, 0.750259]) T += 20 k = [np.around(f(c, T).value, 6) for f in funcs] self.assertEqual(k, [2.292425, 1.664438, 0.880755]) chemistry = pybamm.parameter_sets.Chen2020 param = pybamm.ParameterValues(chemistry=chemistry) param["Electrolyte conductivity [S.m-1]"] = funcs[0] model = pybamm.lithium_ion.SPM() sim = pybamm.Simulation(model, parameter_values=param) sim.set_parameters() sim.build()
def test_interpolant_against_function(self): parameter_values = pybamm.ParameterValues({"a": 0.6}) parameter_values.update( { "function": "[function]lico2_ocp_Dualfoil1998", "interpolation": "[data]lico2_data_example", }, path=os.path.join( pybamm.root_dir(), "input", "parameters", "lithium-ion", "cathodes", "lico2_Marquis2019", ), ) a = pybamm.Parameter("a") func = pybamm.FunctionParameter("function", a) interp = pybamm.FunctionParameter("interpolation", a) processed_func = parameter_values.process_symbol(func) processed_interp = parameter_values.process_symbol(interp) np.testing.assert_array_almost_equal(processed_func.evaluate(), processed_interp.evaluate(), decimal=4) # process differentiated function parameter diff_func = func.diff(a) diff_interp = interp.diff(a) processed_diff_func = parameter_values.process_symbol(diff_func) processed_diff_interp = parameter_values.process_symbol(diff_interp) np.testing.assert_array_almost_equal(processed_diff_func.evaluate(), processed_diff_interp.evaluate(), decimal=2)
def __init__(self, filename, units="[]", current_scale=pybamm.electrical_parameters.I_typ): self.parameters = {"Current [A]": current_scale} self.parameters_eval = {"Current [A]": current_scale} # Load data from csv if filename: pybamm_path = pybamm.root_dir() data = pd.read_csv( os.path.join(pybamm_path, "input", "drive_cycles", filename), comment="#", skip_blank_lines=True, ).to_dict("list") self.time = np.array(data["time [s]"]) self.units = units self.current = np.array(data["current " + units]) # If voltage data is present, load it into the class try: self.voltage = np.array(data["voltage [V]"]) except KeyError: self.voltage = None else: raise pybamm.ModelError("No input file provided for current")
def test_electrolyte_diffusivity(self): root = pybamm.root_dir() p = "pybamm/input/parameters/lithium-ion/electrolytes/lipf6_Landesfeind2019" d_path = os.path.join(root, p) files = [ f for f in os.listdir(d_path) if ".py" in f and "_base" not in f and "diffusivity" in f ] files.sort() funcs = [pybamm.load_function(os.path.join(d_path, f)) for f in files] T_ref = 298.15 T = T_ref + 30.0 c = 1000.0 D = [np.around(f(c, T).value, 16) for f in funcs] self.assertEqual(D, [5.796505e-10, 5.417881e-10, 5.608856e-10]) T += 20 D = [np.around(f(c, T).value, 16) for f in funcs] self.assertEqual(D, [8.5992e-10, 7.752815e-10, 7.907549e-10]) chemistry = pybamm.parameter_sets.Chen2020 param = pybamm.ParameterValues(chemistry=chemistry) param["Electrolyte diffusivity [m2.s-1]"] = funcs[0] model = pybamm.lithium_ion.SPM() sim = pybamm.Simulation(model, parameter_values=param) sim.set_parameters() sim.build()
def test_drive_cycle_data(self): model = pybamm.lithium_ion.SPM() param = model.default_parameter_values param["Current function [A]"] = "[current data]US06" drive_cycle = pd.read_csv( os.path.join(pybamm.root_dir(), "input", "drive_cycles", "US06.csv"), comment="#", skip_blank_lines=True, header=None, ) time_data = drive_cycle.values[:, 0] sim = pybamm.Simulation(model, parameter_values=param) # check solution is returned at the times in the data sim.solve() tau = model.timescale.evaluate() np.testing.assert_array_almost_equal(sim.solution.t, time_data / tau) # check warning raised if the largest gap in t_eval is bigger than the # smallest gap in the data sim.reset() with self.assertWarns(pybamm.SolverWarning): sim.solve(t_eval=np.linspace(0, 1, 100)) # check warning raised if t_eval doesnt contain time_data , but has a finer # resolution (can still solve, but good for users to know they dont have # the solution returned at the data points) sim.reset() with self.assertWarns(pybamm.SolverWarning): sim.solve(t_eval=np.linspace(0, time_data[-1], 800))
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 read_citations(self): "Read the citations text file" self._all_citations = {} citations_file = os.path.join(pybamm.root_dir(), "pybamm", "CITATIONS.txt") citation = "" start = True for line in open(citations_file): # if start is true, we need to find the key if start is True: # match everything between { and , in the first line to get the key brace_idx = line.find("{") comma_idx = line.find(",") key = line[brace_idx + 1 : comma_idx] # turn off start as we now have the right key start = False citation += line # blank line means next block, add citation to dictionary and # reset everything if line == "\n": self._all_citations[key] = citation citation = "" start = True # add the final citation self._all_citations[key] = citation
def update_from_chemistry(self, chemistry): """ Load standard set of components from a 'chemistry' dictionary """ base_chemistry = chemistry["chemistry"] # Create path to file path = os.path.join(pybamm.root_dir(), "input", "parameters", base_chemistry) # Load each component name for component_group in [ "cell", "anode", "cathode", "separator", "electrolyte", "experiment", ]: # Make sure component is provided try: component = chemistry[component_group] except KeyError: raise KeyError( "must provide '{}' parameters for {} chemistry".format( component_group, base_chemistry ) ) # Create path to component and load values component_path = os.path.join(path, component_group + "s", component) component_params = self.read_parameters_csv( os.path.join(component_path, "parameters.csv") ) # Update parameters, making sure to check any conflicts self.update(component_params, check_conflict=True, path=component_path)
def update_from_chemistry(self, chemistry): """ Load standard set of components from a 'chemistry' dictionary """ base_chemistry = chemistry["chemistry"] # Create path to file path = os.path.join( pybamm.root_dir(), "pybamm", "input", "parameters", base_chemistry ) # Load each component name component_groups = [ "cell", "anode", "cathode", "separator", "electrolyte", "experiment", ] # add sei parameters if provided if "sei" in chemistry: component_groups += ["sei"] for component_group in component_groups: # Make sure component is provided try: component = chemistry[component_group] except KeyError: raise KeyError( "must provide '{}' parameters for {} chemistry".format( component_group, base_chemistry ) ) # Create path to component and load values component_path = os.path.join(path, component_group + "s", component) component_params = self.read_parameters_csv( pybamm.get_parameters_filepath( os.path.join(component_path, "parameters.csv") ) ) # Update parameters, making sure to check any conflicts self.update( component_params, check_conflict=True, check_already_exists=False, path=component_path, ) # register (list of) citations if "citation" in chemistry: citations = chemistry["citation"] if not isinstance(citations, list): citations = [citations] for citation in citations: pybamm.citations.register(citation)
def test_get_parameters_filepath(self): tempfile_obj = tempfile.NamedTemporaryFile("w", dir=".") self.assertTrue( pybamm.get_parameters_filepath(tempfile_obj.name) == tempfile_obj.name) tempfile_obj.close() package_dir = os.path.join(pybamm.root_dir(), "pybamm") tempfile_obj = tempfile.NamedTemporaryFile("w", dir=package_dir) path = os.path.join(package_dir, tempfile_obj.name) self.assertTrue( pybamm.get_parameters_filepath(tempfile_obj.name) == path)
def test_read_parameters_csv(self): data = pybamm.ParameterValues({}).read_parameters_csv( os.path.join( pybamm.root_dir(), "pybamm", "input", "parameters", "lithium-ion", "cathodes", "lico2_Marquis2019", "parameters.csv", )) self.assertEqual(data["Positive electrode porosity"], "0.3")
def update_doc(generated_doc): """ Opens parameter_sets.py, replaces the docstring and then writes it """ with open( os.path.join(pybamm.root_dir(), "pybamm", "parameters", "parameter_sets.py"), "r+", ) as ps_fp: ps_output = ps_fp.read() ps_output = ps_output.replace(parameter_sets.__doc__, generated_doc) ps_fp.truncate(0) ps_fp.seek(0) ps_fp.write(ps_output)
def generate_ps_doc(parameter_set_dict): """ Generates docstring of parameter_sets.py from the given dictionary """ output_list = [DOC_INTRO] citations_file = os.path.join(pybamm.root_dir(), "pybamm", "CITATIONS.txt") for ps_chemistry in sorted(parameter_set_dict.keys()): output_list.append("") ps_citations = parameter_set_dict[ps_chemistry] chem_name = ps_chemistry.capitalize().replace("_", "-") + " " + "parameter sets" output_list.append(chem_name) dashes = "-" * len(ps_chemistry) + "-" * 15 output_list.append(dashes) for ps_name, ps_citation in sorted(ps_citations): citations = pybtex.format_from_file( citations_file, style="plain", output_backend="plaintext", citations=ps_citation, nocite=True, ) # Remove citation labels "[3]" citations = re.split(r"(?:^|\n)\[\d+\]\s", citations) # Remove empty strings citations = filter(bool, citations) fmt_citations = [] for citation in citations: # Break line at the first space before 80 characters citation_parts = re.findall(r"(.{1,79})(?:\s|$)", citation) # first_line = citation.split('\n') indent_citation_parts = [] for idx, citation_part in enumerate(citation_parts): if idx == 0: citation_part = "- " + citation_part else: citation_part = " " + citation_part indent_citation_parts.append(" " * 7 + citation_part) # Join to create a single citation paragraph citation = "\n".join(indent_citation_parts) fmt_citations.append(citation) fmt_citations = "\n".join(fmt_citations) ps_doc = f" * {ps_name:} :\n{fmt_citations}" output_list.append(ps_doc) output = "\n".join(output_list) output += "\n" return output
def test_load_function(self): # Test filename ends in '.py' with self.assertRaisesRegex( ValueError, "Expected filename.py, but got doesnotendindotpy"): pybamm.load_function("doesnotendindotpy") # Test exception if absolute file not found with self.assertRaisesRegex( ValueError, "is an absolute path, but the file is not found"): nonexistent_abs_file = os.path.join(os.getcwd(), "i_dont_exist.py") pybamm.load_function(nonexistent_abs_file) # Test exception if relative file not found with self.assertRaisesRegex(ValueError, "cannot be found in the PyBaMM directory"): pybamm.load_function("i_dont_exist.py") # Test exception if relative file found more than once with self.assertRaisesRegex( ValueError, "found multiple times in the PyBaMM directory"): pybamm.load_function("__init__.py") # Test exception if no matching function found in module with self.assertRaisesRegex(ValueError, "No function .+ found in module .+"): pybamm.load_function("process_symbol_bad_function.py") # Test function load with absolute path abs_test_path = os.path.join( pybamm.root_dir(), "tests", "unit", "test_parameters", "data", "process_symbol_test_function.py", ) self.assertTrue(os.path.isfile(abs_test_path)) func = pybamm.load_function(abs_test_path) self.assertEqual(func(2), 246) # Test function load with relative path func = pybamm.load_function("process_symbol_test_function.py") self.assertEqual(func(3), 369)
def test_interpolant_against_function(self): parameter_values = pybamm.ParameterValues({}) parameter_values.update( { "function": "[function]lico2_ocp_Dualfoil1998", "interpolation": "[data]lico2_data_example", }, path=os.path.join( pybamm.root_dir(), "pybamm", "input", "parameters", "lithium_ion", "positive_electrodes", "lico2_Marquis2019", ), check_already_exists=False, ) a = pybamm.Scalar(0.6) func = pybamm.FunctionParameter("function", {"a": a}) interp = pybamm.FunctionParameter("interpolation", {"a": a}) processed_func = parameter_values.process_symbol(func) processed_interp = parameter_values.process_symbol(interp) np.testing.assert_array_almost_equal( processed_func.evaluate(), processed_interp.evaluate(), decimal=4, ) # process differentiated function parameter diff_func = func.diff(a) diff_interp = interp.diff(a) processed_diff_func = parameter_values.process_symbol(diff_func) processed_diff_interp = parameter_values.process_symbol(diff_interp) np.testing.assert_array_almost_equal( processed_diff_func.evaluate(), processed_diff_interp.evaluate(), decimal=2, )
def test_load_function(self): # Test replace function and deprecation warning for lithium-ion with self.assertWarns(Warning): warn_path = os.path.join( "pybamm", "input", "parameters", "lithium-ion", "negative_electrodes", "graphite_Chen2020", "graphite_LGM50_electrolyte_exchange_current_density_Chen2020.py", ) pybamm.load_function(warn_path) # Test replace function and deprecation warning for lead-acid with self.assertWarns(Warning): warn_path = os.path.join( "pybamm", "input", "parameters", "lead-acid", "negative_electrodes", "lead_Sulzer2019", "lead_exchange_current_density_Sulzer2019.py", ) pybamm.load_function(warn_path) # Test function load with absolute path abs_test_path = os.path.join( pybamm.root_dir(), "pybamm", "input", "parameters", "lithium_ion", "negative_electrodes", "graphite_Chen2020", "graphite_LGM50_electrolyte_exchange_current_density_Chen2020.py", ) func = pybamm.load_function(abs_test_path) self.assertEqual( func, pybamm.input.parameters.lithium_ion.negative_electrodes. graphite_Chen2020. graphite_LGM50_electrolyte_exchange_current_density_Chen2020. graphite_LGM50_electrolyte_exchange_current_density_Chen2020, # noqa ) # Test function load with relative path rel_test_path = os.path.join( "pybamm", "input", "parameters", "lithium_ion", "negative_electrodes", "graphite_Chen2020", "graphite_LGM50_electrolyte_exchange_current_density_Chen2020.py", ) func = pybamm.load_function(rel_test_path) self.assertEqual( func, pybamm.input.parameters.lithium_ion.negative_electrodes. graphite_Chen2020. graphite_LGM50_electrolyte_exchange_current_density_Chen2020. graphite_LGM50_electrolyte_exchange_current_density_Chen2020, # noqa )
def update(self, values, check_conflict=False, check_already_exists=True, path=""): """ Update parameter dictionary, while also performing some basic checks. Parameters ---------- values : dict Dictionary of parameter values to update parameter dictionary with check_conflict : bool, optional Whether to check that a parameter in `values` has not already been defined in the parameter class when updating it, and if so that its value does not change. This is set to True during initialisation, when parameters are combined from different sources, and is False by default otherwise check_already_exists : bool, optional Whether to check that a parameter in `values` already exists when trying to update it. This is to avoid cases where an intended change in the parameters is ignored due a typo in the parameter name, and is True by default but can be manually overridden. path : string, optional Path from which to load functions """ # check parameter values self.check_parameter_values(values) # update for name, value in values.items(): # check for conflicts if (check_conflict is True and name in self.keys() and not (self[name] == float(value) or self[name] == value)): raise ValueError( "parameter '{}' already defined with value '{}'".format( name, self[name])) # check parameter already exists (for updating parameters) if check_already_exists is True: try: self._dict_items[name] except KeyError as err: raise KeyError( "Cannot update parameter '{}' as it does not ".format( name) + "have a default value. ({}). If you are ".format( err.args[0]) + "sure you want to update this parameter, use " + "param.update({{name: value}}, check_already_exists=False)" ) # if no conflicts, update, loading functions and data if they are specified # Functions are flagged with the string "[function]" if isinstance(value, str): if value.startswith("[function]"): loaded_value = pybamm.load_function( os.path.join(path, value[10:])) self._dict_items[name] = loaded_value values[name] = loaded_value # Data is flagged with the string "[data]" or "[current data]" elif value.startswith("[current data]") or value.startswith( "[data]"): if value.startswith("[current data]"): data_path = os.path.join(pybamm.root_dir(), "pybamm", "input", "drive_cycles") filename = os.path.join(data_path, value[14:] + ".csv") function_name = value[14:] else: filename = os.path.join(path, value[6:] + ".csv") function_name = value[6:] filename = pybamm.get_parameters_filepath(filename) data = pd.read_csv(filename, comment="#", skip_blank_lines=True, header=None).to_numpy() # Save name and data self._dict_items[name] = (function_name, data) values[name] = (function_name, data) elif value == "[input]": self._dict_items[name] = pybamm.InputParameter(name) # Anything else should be a converted to a float else: self._dict_items[name] = float(value) values[name] = float(value) else: self._dict_items[name] = value # reset processed symbols self._processed_symbols = {}
import pybamm import numpy as np import os import pickle import scipy.interpolate as interp # change working directory to the root of pybamm os.chdir(pybamm.root_dir()) "-----------------------------------------------------------------------------" "Pick C_rate and load comsol data" # C_rate # NOTE: the results in pybamm stop when a voltage cutoff is reached, so # for higher C-rate the pybamm solution may stop before the comsol solution C_rates = {"01": 0.1, "05": 0.5, "1": 1, "2": 2, "3": 3} C_rate = "1" # choose the key from the above dictionary of available results # load the comsol results comsol_results_path = pybamm.get_parameters_filepath( "input/comsol_results/comsol_{}C.pickle".format(C_rate)) comsol_variables = pickle.load(open(comsol_results_path, "rb")) "-----------------------------------------------------------------------------" "Create and solve pybamm model" # load model and geometry pybamm.set_logging_level("INFO") pybamm_model = pybamm.lithium_ion.DFN() geometry = pybamm_model.default_geometry
def test_load_params(self): data_D_e = { "EC_DMC_1_1": [1.94664e-10, 1.94233e-10], "EC_EMC_3_7": [2.01038e-10, 1.78391e-10], "EMC_FEC_19_1": [2.16871e-10, 1.8992e-10], } data_sigma_e = { "EC_DMC_1_1": [0.870352, 0.839076], "EC_EMC_3_7": [0.695252, 0.668677], "EMC_FEC_19_1": [0.454054, 0.632419], } data_TDF = { "EC_DMC_1_1": [1.84644, 4.16915], "EC_EMC_3_7": [1.82671, 3.9218], "EMC_FEC_19_1": [0.92532, 3.22481], } data_tplus = { "EC_DMC_1_1": [0.17651, 0.241924], "EC_EMC_3_7": [0.0118815, 0.151879], "EMC_FEC_19_1": [-0.0653014, 0.0416203], } T = [273.15 + 10.0, 273.15 + 30.0] c = [1000.0, 2000.0] for solvent in ["EC_DMC_1_1", "EC_EMC_3_7", "EMC_FEC_19_1"]: root = pybamm.root_dir() p = ("pybamm/input/parameters/lithium-ion/electrolytes/lipf6_" + solvent + "_Landesfeind2019/") k_path = os.path.join(root, p) sigma_e = pybamm.load_function( os.path.join( k_path, "electrolyte_conductivity_" + solvent + "_Landesfeind2019.py", )) D_e = pybamm.load_function( os.path.join( k_path, "electrolyte_diffusivity_" + solvent + "_Landesfeind2019.py")) TDF = pybamm.load_function( os.path.join( k_path, "electrolyte_TDF_" + solvent + "_Landesfeind2019.py")) tplus = pybamm.load_function( os.path.join( k_path, "electrolyte_transference_number_" + solvent + "_Landesfeind2019.py", )) for i, _ in enumerate(T): self.assertAlmostEqual(sigma_e(c[i], T[i]).value, data_sigma_e[solvent][i], places=5) self.assertAlmostEqual(D_e(c[i], T[i]).value, data_D_e[solvent][i], places=5) self.assertAlmostEqual(TDF(c[i], T[i]), data_TDF[solvent][i], places=5) self.assertAlmostEqual(tplus(c[i], T[i]), data_tplus[solvent][i], places=5)
def test_load_function(self): # Test filename ends in '.py' with self.assertRaisesRegex( ValueError, "Expected filename.py, but got doesnotendindotpy"): pybamm.load_function("doesnotendindotpy") # Test replace function and deprecation warning for lithium-ion with self.assertWarns(Warning): warn_path = os.path.join( "pybamm", "input", "parameters", "lithium-ion", "negative_electrodes", "graphite_Chen2020", "graphite_LGM50_electrolyte_exchange_current_density_Chen2020.py", ) pybamm.load_function(warn_path) # Test replace function and deprecation warning for lead-acid with self.assertWarns(Warning): warn_path = os.path.join( "pybamm", "input", "parameters", "lead-acid", "negative_electrodes", "lead_Sulzer2019", "lead_exchange_current_density_Sulzer2019.py", ) pybamm.load_function(warn_path) # Test exception if absolute file not found with self.assertRaisesRegex( ValueError, "is an absolute path, but the file is not found"): nonexistent_abs_file = os.path.join(os.getcwd(), "i_dont_exist.py") pybamm.load_function(nonexistent_abs_file) # Test exception if relative file not found with self.assertRaisesRegex(ValueError, "cannot be found in the PyBaMM directory"): pybamm.load_function("i_dont_exist.py") # Test exception if relative file found more than once with self.assertRaisesRegex( ValueError, "found multiple times in the PyBaMM directory"): pybamm.load_function("__init__.py") # Test exception if no matching function found in module with self.assertRaisesRegex(ValueError, "No function .+ found in module .+"): pybamm.load_function("process_symbol_bad_function.py") # Test function load with absolute path abs_test_path = os.path.join( pybamm.root_dir(), "tests", "unit", "test_parameters", "data", "process_symbol_test_function.py", ) self.assertTrue(os.path.isfile(abs_test_path)) func = pybamm.load_function(abs_test_path) self.assertEqual(func(2), 246) # Test function load with relative path func = pybamm.load_function("process_symbol_test_function.py") self.assertEqual(func(3), 369)
def load_function(filename): """ Load a python function from a file "function_name.py" called "function_name". The filename might either be an absolute path, in which case that specific file will be used, or the file will be searched for relative to PyBaMM root. Arguments --------- filename : str The name of the file containing the function of the same name. Returns ------- function The python function loaded from the file. """ if not filename.endswith(".py"): raise ValueError("Expected filename.py, but got {}".format(filename)) # If it's an absolute path, find that exact file if os.path.isabs(filename): if not os.path.isfile(filename): raise ValueError( "{} is an absolute path, but the file is not found".format(filename) ) valid_filename = filename # Else, search in the whole PyBaMM directory for matches else: search_path = pybamm.root_dir() head, tail = os.path.split(filename) matching_files = [] for root, _, files in os.walk(search_path): for file in files: if file == tail: full_path = os.path.join(root, file) if full_path.endswith(filename): matching_files.append(full_path) if len(matching_files) == 0: raise ValueError( "{} cannot be found in the PyBaMM directory".format(filename) ) elif len(matching_files) > 1: raise ValueError( "{} found multiple times in the PyBaMM directory".format(filename) ) valid_filename = matching_files[0] # Now: we have some /path/to/valid/filename.py # Add "/path/to/vaid" to the python path, and load the module "filename". # Then, check "filename" module contains "filename" function. If it does, return # that function object, or raise an exception valid_path, valid_leaf = os.path.split(valid_filename) sys.path.append(valid_path) # Load the module, which must be the leaf of filename, minus the .py extension valid_module = valid_leaf.replace(".py", "") module_object = importlib.import_module(valid_module) # Check that a function of the same name exists in the loaded module if valid_module not in dir(module_object): raise ValueError( "No function {} found in module {}".format(valid_module, valid_module) ) # Remove valid_path from sys_path to avoid clashes down the line sys.path.remove(valid_path) return getattr(module_object, valid_module)
def test_cycle_summary_variables(self): # Test cycle_summary_variables works for different combinations of data and # function OCPs experiment = pybamm.Experiment([ ( "Discharge at 1C until 3.3V", "Charge at C/3 until 4.0V", "Hold at 4.0V until C/10", ), ] * 5, ) model = pybamm.lithium_ion.SPM() # Chen 2020 plating: pos = function, neg = data param = pybamm.ParameterValues( chemistry=pybamm.parameter_sets.Chen2020_plating) sim = pybamm.Simulation(model, experiment=experiment, parameter_values=param) sim.solve(solver=pybamm.CasadiSolver("fast with events"), save_at_cycles=2) # Chen 2020: pos = function, neg = function param = pybamm.ParameterValues( chemistry=pybamm.parameter_sets.Chen2020) sim = pybamm.Simulation(model, experiment=experiment, parameter_values=param) sim.solve(solver=pybamm.CasadiSolver("fast with events"), save_at_cycles=2) # Chen 2020 with data: pos = data, neg = data # Load negative electrode OCP data filename = os.path.join( pybamm.root_dir(), "pybamm", "input", "parameters", "lithium_ion", "negative_electrodes", "graphite_Chen2020", "graphite_LGM50_ocp_Chen2020.csv", ) function_name = "graphite_Chen2020" filename = pybamm.get_parameters_filepath(filename) data = pd.read_csv(filename, comment="#", skip_blank_lines=True, header=None).to_numpy() param["Negative electrode OCP [V]"] = (function_name, data) # Load positive electrode OCP data filename = os.path.join( pybamm.root_dir(), "pybamm", "input", "parameters", "lithium_ion", "positive_electrodes", "nmc_Chen2020", "nmc_LGM50_ocp_Chen2020.csv", ) function_name = "nmc_LGM50_ocp_Chen2020.csv" filename = pybamm.get_parameters_filepath(filename) data = pd.read_csv(filename, comment="#", skip_blank_lines=True, header=None).to_numpy() param["Positive electrode OCP [V]"] = (function_name, data) sim = pybamm.Simulation(model, experiment=experiment, parameter_values=param) sim.solve(solver=pybamm.CasadiSolver("safe"), save_at_cycles=2)