From 6fb6b6d96af558f722ad19867ff7546d5117879a Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Wed, 17 Jan 2024 16:11:10 +0000 Subject: [PATCH 01/15] Add model.rebuild(), model.copy(), and tests --- pybop/models/base_model.py | 74 ++++++++++++++++++++++++++++++++++++-- tests/unit/test_models.py | 58 ++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index 5e1657d25..70de2fe88 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -1,4 +1,5 @@ import pybamm +import copy import numpy as np @@ -75,7 +76,7 @@ def build( self._model_with_set_params, inplace=False, check_model=check_model ) - # Clear solver + # Clear solver and setup model self._solver._model_set_up = {} def set_init_soc(self, init_soc): @@ -103,14 +104,14 @@ def set_init_soc(self, init_soc): # Save solved initial SOC in case we need to rebuild the model self._built_initial_soc = init_soc - def set_params(self): + def set_params(self, rebuild=False): """ Assign the parameters to the model. This method processes the model with the given parameters, sets up the geometry, and updates the model instance. """ - if self.model_with_set_params: + if self.model_with_set_params and not rebuild: return # Mark any simulation inputs in the parameter set @@ -134,6 +135,62 @@ def set_params(self): self._parameter_set.process_geometry(self.geometry) self.pybamm_model = self._model_with_set_params + def rebuild( + self, + dataset=None, + parameters=None, + parameter_set=None, + check_model=True, + init_soc=None, + ): + """ + Rebuild the PyBaMM model for a given parameter set. + + This method requires the self.build() method to be called first, and + then rebuilds the model for a given parameter set. Specifically, + this method applies the given parameters, sets up the mesh and discretization if needed, and prepares the model + for simulations. + + Parameters + ---------- + dataset : pybamm.Dataset, optional + The dataset to be used in the model construction. + parameters : dict, optional + A dictionary containing parameter values to apply to the model. + parameter_set : pybop.parameter_set, optional + A PyBOP parameter set object or a dictionary containing the parameter values + check_model : bool, optional + If True, the model will be checked for correctness after construction. + init_soc : float, optional + The initial state of charge to be used in simulations. + """ + self.dataset = dataset + self.parameters = parameters + + if parameter_set is not None: + self._parameter_set = parameter_set + self._unprocessed_parameter_set = parameter_set + self.geometry = self.pybamm_model.default_geometry + + if self.parameters is not None: + self.fit_keys = [param.name for param in self.parameters] + + if init_soc is not None: + self.set_init_soc(init_soc) + + if self._built_model is None: + raise ValueError("Model must be built before calling rebuild") + + self.set_params(rebuild=True) + self._mesh = pybamm.Mesh(self.geometry, self.submesh_types, self.var_pts) + self._disc = pybamm.Discretisation(self.mesh, self.spatial_methods) + self._built_model = self._disc.process_model( + self._model_with_set_params, inplace=False, check_model=check_model + ) + + # Clear solver and setup model + self._solver._model_set_up = {} + def simulate(self, inputs, t_eval): """ Execute the forward model simulation and return the result. @@ -316,6 +373,17 @@ def check_params(self, inputs=None): """ return True + def copy(self): + """ + Return a copy of the model. + + Returns + ------- + BaseModel + A copy of the model. + """ + return copy.copy(self) + @property def built_model(self): return self._built_model diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index 6925391de..5c742ba4b 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -59,3 +59,61 @@ def test_build(self): # Test that the model can be built again model.build() assert model.built_model is not None + + @pytest.mark.unit + def test_rebuild(self): + model = pybop.lithium_ion.SPM() + model.build() + initial_built_model = model._built_model + assert model._built_model is not None + + # Test that the model can be built again + model.rebuild() + rebuilt_model = model._built_model + assert rebuilt_model is not None + + # Filter out special and private attributes + attributes_to_compare = [ + "algebraic", + "bcs", + "boundary_conditions", + "mass_matrix", + "parameters", + "submodels", + "summary_variables", + "rhs", + "variables", + "y_slices", + ] + + # Loop through the filtered attributes and compare them + for attribute in attributes_to_compare: + assert getattr(rebuilt_model, attribute) == getattr( + initial_built_model, attribute + ) + + @pytest.mark.unit + def test_rebuild_geometric_parameters(self): + parameter_set = pybop.ParameterSet.pybamm("Chen2020") + model = pybop.lithium_ion.SPM(parameter_set=parameter_set) + model.build() + initial_built_model = model.copy() + assert initial_built_model._built_model is not None + + # Test that the model can be built again + parameter_set.update({"Negative electrode thickness [m]": 4.00e-05}) + model.rebuild(parameter_set=parameter_set) + rebuilt_model = model + assert rebuilt_model._built_model is not None + + with pytest.raises(AssertionError): + assert ( + rebuilt_model._mesh["negative electrode"].nodes[1] + == initial_built_model._mesh["negative electrode"].nodes[1] + ), "Mesh nodes mismatch" + + with pytest.raises(AssertionError): + assert ( + rebuilt_model.geometry["negative electrode"]["x_n"]["max"] + == initial_built_model.geometry["negative electrode"]["x_n"]["max"] + ), "Geometry max mismatch" From c1fd3728a29963e5e729d985cc8d0e5177f8a575 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Wed, 17 Jan 2024 19:18:39 +0000 Subject: [PATCH 02/15] refactor test + add prediction comparison --- tests/unit/test_models.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index 5c742ba4b..45765844d 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -100,20 +100,31 @@ def test_rebuild_geometric_parameters(self): initial_built_model = model.copy() assert initial_built_model._built_model is not None - # Test that the model can be built again + # Run prediction + t_eval = np.linspace(0, 100, 100) + out_init = initial_built_model.predict(t_eval=t_eval) + + # Test that the model can be rebuilt with different geometric parameters parameter_set.update({"Negative electrode thickness [m]": 4.00e-05}) model.rebuild(parameter_set=parameter_set) rebuilt_model = model assert rebuilt_model._built_model is not None + # Test model geometry + assert ( + rebuilt_model._mesh["negative electrode"].nodes[1] + != initial_built_model._mesh["negative electrode"].nodes[1] + ) + assert ( + rebuilt_model.geometry["negative electrode"]["x_n"]["max"] + != initial_built_model.geometry["negative electrode"]["x_n"]["max"] + ) + + # Compare model results + out_rebuild = rebuilt_model.predict(t_eval=t_eval) with pytest.raises(AssertionError): - assert ( - rebuilt_model._mesh["negative electrode"].nodes[1] - == initial_built_model._mesh["negative electrode"].nodes[1] - ), "Mesh nodes mismatch" - - with pytest.raises(AssertionError): - assert ( - rebuilt_model.geometry["negative electrode"]["x_n"]["max"] - == initial_built_model.geometry["negative electrode"]["x_n"]["max"] - ), "Geometry max mismatch" + np.testing.assert_allclose( + out_init["Terminal voltage [V]"].data, + out_rebuild["Terminal voltage [V]"].data, + atol=1e-5, + ) From 6e8d664addfb44ac69cfaabe5f557cd021fa0df0 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Thu, 18 Jan 2024 13:51:09 +0000 Subject: [PATCH 03/15] Add geometric parameter dict, add logic for geometric/non-geometric rebuilding, updt. plot2D --- examples/scripts/spm_geometric_parameters.py | 60 ++++++++++++++++++++ pybop/_problem.py | 12 ++++ pybop/models/base_model.py | 41 ++++++++++--- pybop/models/lithium_ion/echem.py | 52 +++++++++++++++++ pybop/plotting/plot_cost2d.py | 2 +- 5 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 examples/scripts/spm_geometric_parameters.py diff --git a/examples/scripts/spm_geometric_parameters.py b/examples/scripts/spm_geometric_parameters.py new file mode 100644 index 000000000..df38984a0 --- /dev/null +++ b/examples/scripts/spm_geometric_parameters.py @@ -0,0 +1,60 @@ +import pybop +import numpy as np + +# Define model +parameter_set = pybop.ParameterSet.pybamm("Chen2020") +model = pybop.lithium_ion.SPM(parameter_set=parameter_set) + +# Fitting parameters +parameters = [ + pybop.Parameter( + "Positive particle radius [m]", + prior=pybop.Gaussian(5.22e-06, 0.05e-06), + bounds=[4e-06, 6e-06], + ), + pybop.Parameter( + "Positive electrode active material volume fraction", + prior=pybop.Gaussian(0.48, 0.05), + bounds=[0.4, 0.7], + ), +] + +# Generate data +sigma = 0.001 +t_eval = np.arange(0, 900, 2) +values = model.predict(t_eval=t_eval) +corrupt_values = values["Voltage [V]"].data + np.random.normal(0, sigma, len(t_eval)) + +# Form dataset +dataset = pybop.Dataset( + { + "Time [s]": t_eval, + "Current function [A]": values["Current [A]"].data, + "Voltage [V]": corrupt_values, + } +) + +# Generate problem, cost function, and optimisation class +problem = pybop.FittingProblem(model, parameters, dataset) +cost = pybop.SumSquaredError(problem) +optim = pybop.Optimisation(cost, optimiser=pybop.CMAES) +optim.set_max_iterations(100) + +# Run the optimisation +x, final_cost = optim.run() +print("Estimated parameters:", x) + +# Plot the timeseries output +pybop.quick_plot(x, cost, title="Optimised Comparison") + +# Plot convergence +pybop.plot_convergence(optim) + +# Plot the parameter traces +pybop.plot_parameters(optim) + +# Plot the cost landscape +pybop.plot_cost2d(cost, steps=15) + +# Plot the cost landscape with optimisation path and updated bounds +pybop.plot_cost2d(cost, optim=optim, steps=15) diff --git a/pybop/_problem.py b/pybop/_problem.py index 504193874..29690e331 100644 --- a/pybop/_problem.py +++ b/pybop/_problem.py @@ -146,6 +146,7 @@ def __init__( ): super().__init__(parameters, model, check_model, signal, init_soc, x0) self._dataset = dataset.data + self.x = self.x0 # Check that the dataset contains time and current for name in ["Time [s]", "Current function [A]"] + self.signal: @@ -182,6 +183,13 @@ def __init__( check_model=self.check_model, init_soc=self.init_soc, ) + elif self._model.has_predict is True: + self._model.rebuild( + dataset=self._dataset, + parameters=self.parameters, + check_model=self.check_model, + init_soc=self.init_soc, + ) def evaluate(self, x): """ @@ -193,6 +201,10 @@ def evaluate(self, x): Parameter values to evaluate the model at. """ + if (x != self.x).all() and self._model.matched_parameters: + self._model.rebuild(parameters=self.parameters) + self.x = x + y = np.asarray(self._model.simulate(inputs=x, t_eval=self._time_data)) return y diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index 70de2fe88..1ad31a4a9 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -28,6 +28,10 @@ def __init__(self, name="Base Model"): self.parameters = None self.dataset = None self.signal = None + self.init_build_counter = 0 + self.has_predict = False + self.matched_parameters = {} + self.non_matched_parameters = {} def build( self, @@ -57,7 +61,7 @@ def build( self.dataset = dataset self.parameters = parameters if self.parameters is not None: - self.fit_keys = [param.name for param in self.parameters] + self.set_parameter_classification(self.parameters) if init_soc is not None: self.set_init_soc(init_soc) @@ -166,14 +170,8 @@ def rebuild( """ self.dataset = dataset self.parameters = parameters - - if parameter_set is not None: - self._parameter_set = parameter_set - self._unprocessed_parameter_set = parameter_set - self.geometry = self.pybamm_model.default_geometry - - if self.parameters is not None: - self.fit_keys = [param.name for param in self.parameters] + if parameters is not None: + self.set_parameter_classification(parameters) if init_soc is not None: self.set_init_soc(init_soc) @@ -191,6 +189,30 @@ def rebuild( # Clear solver and setup model self._solver._model_set_up = {} + def set_parameter_classification(self, parameters): + """ + Set the parameter classification for the model. + """ + processed_parameters = {param.name: param.value for param in parameters} + + # Iterate over self.rebuild_parameters to separate matched and non-matched parameters + for param in processed_parameters: + if param in self.rebuild_parameters: + self.matched_parameters[param] = processed_parameters[param] + elif self.init_build_counter == 0: + self.non_matched_parameters[param] = processed_parameters[param] + + if self.matched_parameters: + self.parameter_set.update(self.matched_parameters) + self._parameter_set = self.parameter_set + self._unprocessed_parameter_set = self.parameter_set + self.geometry = self.pybamm_model.default_geometry + + if self.non_matched_parameters and self.init_build_counter == 0: + self.fit_keys = [param for param in self.non_matched_parameters] + + self.init_build_counter += 1 + def simulate(self, inputs, t_eval): """ Execute the forward model simulation and return the result. @@ -328,6 +350,7 @@ def predict( if PyBaMM models are not supported by the current simulation method. """ + self.has_predict = True parameter_set = parameter_set or self._parameter_set if inputs is not None: if not isinstance(inputs, dict): diff --git a/pybop/models/lithium_ion/echem.py b/pybop/models/lithium_ion/echem.py index 9ae85ea80..802a3dc57 100644 --- a/pybop/models/lithium_ion/echem.py +++ b/pybop/models/lithium_ion/echem.py @@ -69,6 +69,32 @@ def __init__( self._disc = None self._electrode_soh = pybamm.lithium_ion.electrode_soh + self.rebuild_parameters = self.set_rebuild_parameters() + + def set_rebuild_parameters(self): + """ + Sets the parameters that can be changed when rebuilding the model. + + Returns + ------- + dict + A dictionary of parameters that can be changed when rebuilding the model. + + """ + rebuild_parameters = dict.fromkeys( + [ + "Negative particle radius [m]", + "Negative electrode porosity", + "Negative electrode thickness [m]", + "Positive particle radius [m]", + "Positive electrode porosity", + "Positive electrode thickness [m]", + "Separator porosity", + "Separator thickness [m]", + ] + ) + + return rebuild_parameters def check_params(self, inputs=None): """ @@ -186,6 +212,32 @@ def __init__( self._disc = None self._electrode_soh = pybamm.lithium_ion.electrode_soh + self.rebuild_parameters = self.set_rebuild_parameters() + + def set_rebuild_parameters(self): + """ + Sets the parameters that can be changed when rebuilding the model. + + Returns + ------- + dict + A dictionary of parameters that can be changed when rebuilding the model. + + """ + rebuild_parameters = dict.fromkeys( + [ + "Negative particle radius [m]", + "Negative electrode porosity", + "Negative electrode thickness [m]", + "Positive particle radius [m]", + "Positive electrode porosity", + "Positive electrode thickness [m]", + "Separator porosity", + "Separator thickness [m]", + ] + ) + + return rebuild_parameters def check_params(self, inputs=None): """ diff --git a/pybop/plotting/plot_cost2d.py b/pybop/plotting/plot_cost2d.py index ee43d9d09..1565ed243 100644 --- a/pybop/plotting/plot_cost2d.py +++ b/pybop/plotting/plot_cost2d.py @@ -46,7 +46,7 @@ def plot_cost2d(cost, bounds=None, optim=None, steps=10): # Populate cost matrix for i, xi in enumerate(x): for j, yj in enumerate(y): - costs[j, i] = cost([xi, yj]) + costs[j, i] = cost(np.array([xi, yj])) # Create figure fig = create_figure(x, y, costs, bounds, cost.problem.parameters, optim) From 8356b3a735fe90592ed3f46098054f4368f14cfc Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Thu, 18 Jan 2024 16:00:51 +0000 Subject: [PATCH 04/15] Updt tests, add functionality for simulate() with geometric parameters, add rebuild parameters functionality to problem.evaluate(), updt. example --- examples/scripts/spm_geometric_parameters.py | 10 +++--- pybop/_costs.py | 1 - pybop/_problem.py | 3 ++ pybop/models/base_model.py | 38 ++++++++++---------- tests/unit/test_models.py | 32 +++++++++++++++-- 5 files changed, 56 insertions(+), 28 deletions(-) diff --git a/examples/scripts/spm_geometric_parameters.py b/examples/scripts/spm_geometric_parameters.py index df38984a0..0b6b8726d 100644 --- a/examples/scripts/spm_geometric_parameters.py +++ b/examples/scripts/spm_geometric_parameters.py @@ -10,12 +10,12 @@ pybop.Parameter( "Positive particle radius [m]", prior=pybop.Gaussian(5.22e-06, 0.05e-06), - bounds=[4e-06, 6e-06], + bounds=[5e-06, 6e-06], ), pybop.Parameter( - "Positive electrode active material volume fraction", - prior=pybop.Gaussian(0.48, 0.05), - bounds=[0.4, 0.7], + "Negative particle radius [m]", + prior=pybop.Gaussian(5.9e-06, 0.05e-06), + bounds=[5e-06, 6.5e-06], ), ] @@ -37,7 +37,7 @@ # Generate problem, cost function, and optimisation class problem = pybop.FittingProblem(model, parameters, dataset) cost = pybop.SumSquaredError(problem) -optim = pybop.Optimisation(cost, optimiser=pybop.CMAES) +optim = pybop.Optimisation(cost, optimiser=pybop.SNES) optim.set_max_iterations(100) # Run the optimisation diff --git a/pybop/_costs.py b/pybop/_costs.py index 65bf2662f..99a476306 100644 --- a/pybop/_costs.py +++ b/pybop/_costs.py @@ -169,7 +169,6 @@ def _evaluate(self, x, grad=None): The root mean square error. """ - prediction = self.problem.evaluate(x) if len(prediction) < len(self._target): diff --git a/pybop/_problem.py b/pybop/_problem.py index 29690e331..336ae3d0c 100644 --- a/pybop/_problem.py +++ b/pybop/_problem.py @@ -202,6 +202,9 @@ def evaluate(self, x): """ if (x != self.x).all() and self._model.matched_parameters: + for i, param in enumerate(self.parameters): + param.update(value=x[i]) + self._model.rebuild(parameters=self.parameters) self.x = x diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index 1ad31a4a9..24282d0ff 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -28,10 +28,10 @@ def __init__(self, name="Base Model"): self.parameters = None self.dataset = None self.signal = None - self.init_build_counter = 0 self.has_predict = False self.matched_parameters = {} self.non_matched_parameters = {} + self.fit_keys = [] def build( self, @@ -119,11 +119,11 @@ def set_params(self, rebuild=False): return # Mark any simulation inputs in the parameter set - if self.parameters is not None: + if self.non_matched_parameters: for i in self.fit_keys: self._parameter_set[i] = "[input]" - if self.dataset is not None and self.parameters is not None: + if self.dataset is not None and self.non_matched_parameters: if "Current function [A]" not in self.fit_keys: self.parameter_set["Current function [A]"] = pybamm.Interpolant( self.dataset["Time [s]"], @@ -199,7 +199,7 @@ def set_parameter_classification(self, parameters): for param in processed_parameters: if param in self.rebuild_parameters: self.matched_parameters[param] = processed_parameters[param] - elif self.init_build_counter == 0: + else: self.non_matched_parameters[param] = processed_parameters[param] if self.matched_parameters: @@ -208,11 +208,9 @@ def set_parameter_classification(self, parameters): self._unprocessed_parameter_set = self.parameter_set self.geometry = self.pybamm_model.default_geometry - if self.non_matched_parameters and self.init_build_counter == 0: + if self.non_matched_parameters: self.fit_keys = [param for param in self.non_matched_parameters] - self.init_build_counter += 1 - def simulate(self, inputs, t_eval): """ Execute the forward model simulation and return the result. @@ -235,22 +233,24 @@ def simulate(self, inputs, t_eval): ValueError If the model has not been built before simulation. """ - if self._built_model is None: raise ValueError("Model must be built before calling simulate") else: - if not isinstance(inputs, dict): - inputs = {key: inputs[i] for i, key in enumerate(self.fit_keys)} - - if self.check_params(inputs): - sol = self.solver.solve(self.built_model, inputs=inputs, t_eval=t_eval) - - predictions = [sol[signal].data for signal in self.signal] - - return np.vstack(predictions).T - + if not self.fit_keys and self.matched_parameters: + sol = self.solver.solve(self.built_model, t_eval=t_eval) else: - return [np.inf] + if not isinstance(inputs, dict): + inputs = {key: inputs[i] for i, key in enumerate(self.fit_keys)} + if self.check_params(inputs): + sol = self.solver.solve( + self.built_model, inputs=inputs, t_eval=t_eval + ) + else: + return [np.inf] + + predictions = [sol[signal].data for signal in self.signal] + + return np.vstack(predictions).T def simulateS1(self, inputs, t_eval): """ diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index 45765844d..db639067e 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -95,8 +95,23 @@ def test_rebuild(self): @pytest.mark.unit def test_rebuild_geometric_parameters(self): parameter_set = pybop.ParameterSet.pybamm("Chen2020") + parameters = [ + pybop.Parameter( + "Positive particle radius [m]", + prior=pybop.Gaussian(4.8e-06, 0.05e-06), + bounds=[4e-06, 6e-06], + initial_value=4.8e-06, + ), + pybop.Parameter( + "Negative electrode thickness [m]", + prior=pybop.Gaussian(40e-06, 1e-06), + bounds=[30e-06, 50e-06], + initial_value=48e-06, + ), + ] + model = pybop.lithium_ion.SPM(parameter_set=parameter_set) - model.build() + model.build(parameters=parameters) initial_built_model = model.copy() assert initial_built_model._built_model is not None @@ -105,8 +120,9 @@ def test_rebuild_geometric_parameters(self): out_init = initial_built_model.predict(t_eval=t_eval) # Test that the model can be rebuilt with different geometric parameters - parameter_set.update({"Negative electrode thickness [m]": 4.00e-05}) - model.rebuild(parameter_set=parameter_set) + parameters[0].update(5e-06) + parameters[1].update(45e-06) + model.rebuild(parameters=parameters) rebuilt_model = model assert rebuilt_model._built_model is not None @@ -120,6 +136,16 @@ def test_rebuild_geometric_parameters(self): != initial_built_model.geometry["negative electrode"]["x_n"]["max"] ) + assert ( + rebuilt_model.geometry["positive particle"]["r_p"]["max"] + != initial_built_model.geometry["positive particle"]["r_p"]["max"] + ) + + assert ( + rebuilt_model._mesh["positive particle"].nodes[1] + != initial_built_model._mesh["positive particle"].nodes[1] + ) + # Compare model results out_rebuild = rebuilt_model.predict(t_eval=t_eval) with pytest.raises(AssertionError): From f3204275c904b401f8633cb69b11de1dea54c6f7 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Thu, 18 Jan 2024 18:24:59 +0000 Subject: [PATCH 05/15] Add rebuild_parameters to Thevenin --- pybop/models/empirical/ecm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pybop/models/empirical/ecm.py b/pybop/models/empirical/ecm.py index e6d29c3b0..bd5475e19 100644 --- a/pybop/models/empirical/ecm.py +++ b/pybop/models/empirical/ecm.py @@ -75,3 +75,4 @@ def __init__( self._built_initial_soc = None self._mesh = None self._disc = None + self.rebuild_parameters = {} From d8bd78f75891538c90f9e084c69e174eb82b0ee3 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Fri, 19 Jan 2024 10:54:58 +0000 Subject: [PATCH 06/15] refactor parameter_classification, add model getter to problem class, change private reference to public in design example --- examples/scripts/spm_geometric_parameters.py | 2 +- examples/scripts/spme_max_energy.py | 16 ++++---- pybop/_problem.py | 8 ++++ pybop/models/base_model.py | 39 ++++++++++++++------ 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/examples/scripts/spm_geometric_parameters.py b/examples/scripts/spm_geometric_parameters.py index 0b6b8726d..046f024cd 100644 --- a/examples/scripts/spm_geometric_parameters.py +++ b/examples/scripts/spm_geometric_parameters.py @@ -37,7 +37,7 @@ # Generate problem, cost function, and optimisation class problem = pybop.FittingProblem(model, parameters, dataset) cost = pybop.SumSquaredError(problem) -optim = pybop.Optimisation(cost, optimiser=pybop.SNES) +optim = pybop.Optimisation(cost, optimiser=pybop.CMAES) optim.set_max_iterations(100) # Run the optimisation diff --git a/examples/scripts/spme_max_energy.py b/examples/scripts/spme_max_energy.py index 30a14c001..2ab519076 100644 --- a/examples/scripts/spme_max_energy.py +++ b/examples/scripts/spme_max_energy.py @@ -48,17 +48,17 @@ def nominal_capacity( inputs = { key: x[i] for i, key in enumerate([param.name for param in model.parameters]) } - model._parameter_set.update(inputs) + model.parameter_set.update(inputs) theoretical_energy = model._electrode_soh.calculate_theoretical_energy( # All of the computational time is in this line (~0.7) - model._parameter_set + model.parameter_set ) - average_voltage = model._parameter_set["Positive electrode OCP [V]"]( + average_voltage = model.parameter_set["Positive electrode OCP [V]"]( mean_sto_pos - ) - model._parameter_set["Negative electrode OCP [V]"](mean_sto_neg) + ) - model.parameter_set["Negative electrode OCP [V]"](mean_sto_neg) theoretical_capacity = theoretical_energy / average_voltage - model._parameter_set.update({"Nominal cell capacity [A.h]": theoretical_capacity}) + model.parameter_set.update({"Nominal cell capacity [A.h]": theoretical_capacity}) def cell_mass(parameter_set): # This is very low compute time @@ -153,7 +153,7 @@ def _evaluate(self, x, grad=None): """ with warnings.catch_warnings(record=True) as w: # Update the C-rate and run the simulation - nominal_capacity(x, self.problem._model) + nominal_capacity(x, self.problem.model) sol = self.problem.evaluate(x) if any(w) and issubclass(w[-1].category, UserWarning): @@ -167,7 +167,7 @@ def _evaluate(self, x, grad=None): gravimetric_energy_density = -np.trapz( voltage * current, dx=dt ) / ( # trapz over-estimates compares to pybamm (~0.5%) - 3600 * cell_mass(self.problem._model._parameter_set) + 3600 * cell_mass(self.problem.model.parameter_set) ) # Return the negative energy density, as the optimiser minimises # this function, to carry out maximisation of the energy density @@ -186,7 +186,7 @@ def _evaluate(self, x, grad=None): print(f"Optimised gravimetric energy density: {-final_cost:.2f} Wh.kg-1") # Plot the timeseries output -nominal_capacity(x, cost.problem._model) +nominal_capacity(x, cost.problem.model) pybop.quick_plot(x, cost, title="Optimised Comparison") # Plot the cost landscape with optimisation path diff --git a/pybop/_problem.py b/pybop/_problem.py index 336ae3d0c..845c3e7ff 100644 --- a/pybop/_problem.py +++ b/pybop/_problem.py @@ -221,6 +221,10 @@ def evaluateS1(self, x): x : np.ndarray Parameter values to evaluate the model at. """ + if self._model.matched_parameters: + raise RuntimeError( + "Gradient not available when using geometric parameters." + ) y, dy = self._model.simulateS1( inputs=x, @@ -303,3 +307,7 @@ def evaluate(self, x): predictions = [sol[signal].data for signal in self.signal + ["Time [s]"]] return np.vstack(predictions).T + + @property + def model(self): + return self._model diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index 24282d0ff..3d8eaa614 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -125,7 +125,7 @@ def set_params(self, rebuild=False): if self.dataset is not None and self.non_matched_parameters: if "Current function [A]" not in self.fit_keys: - self.parameter_set["Current function [A]"] = pybamm.Interpolant( + self._parameter_set["Current function [A]"] = pybamm.Interpolant( self.dataset["Time [s]"], self.dataset["Current function [A]"], pybamm.t, @@ -192,24 +192,39 @@ def rebuild( def set_parameter_classification(self, parameters): """ Set the parameter classification for the model. + + Parameters + ---------- + parameters : Pybop.ParameterSet + + Returns + ------- + None + The method updates attributes on self. + """ processed_parameters = {param.name: param.value for param in parameters} - - # Iterate over self.rebuild_parameters to separate matched and non-matched parameters - for param in processed_parameters: - if param in self.rebuild_parameters: - self.matched_parameters[param] = processed_parameters[param] - else: - self.non_matched_parameters[param] = processed_parameters[param] + matched_parameters = { + param: processed_parameters[param] + for param in processed_parameters + if param in self.rebuild_parameters + } + non_matched_parameters = { + param: processed_parameters[param] + for param in processed_parameters + if param not in self.rebuild_parameters + } + + self.matched_parameters.update(matched_parameters) + self.non_matched_parameters.update(non_matched_parameters) if self.matched_parameters: - self.parameter_set.update(self.matched_parameters) - self._parameter_set = self.parameter_set - self._unprocessed_parameter_set = self.parameter_set + self._parameter_set.update(self.matched_parameters) + self._unprocessed_parameter_set = self._parameter_set self.geometry = self.pybamm_model.default_geometry if self.non_matched_parameters: - self.fit_keys = [param for param in self.non_matched_parameters] + self.fit_keys = list(self.non_matched_parameters.keys()) def simulate(self, inputs, t_eval): """ From 44e935ce3da6c99bb0a96e4431e38b57ceb61ce5 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Thu, 8 Feb 2024 17:14:16 +0000 Subject: [PATCH 07/15] Update simulate --- pybop/models/base_model.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index a4bdc1fe8..df62a8f34 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -345,15 +345,16 @@ def simulate(self, inputs, t_eval) -> np.ndarray[np.float64]: else: if not isinstance(inputs, dict): inputs = {key: inputs[i] for i, key in enumerate(self.fit_keys)} - if self.check_params( - inputs=inputs, - allow_infeasible_solutions=self.allow_infeasible_solutions, - ): - sol = self.solver.solve( - self.built_model, inputs=inputs, t_eval=t_eval - ) - else: - return [np.inf] + + if self.check_params( + inputs=inputs, + allow_infeasible_solutions=self.allow_infeasible_solutions, + ): + sol = self.solver.solve( + self.built_model, inputs=inputs, t_eval=t_eval + ) + else: + return [np.inf] predictions = [sol[signal].data for signal in self.signal] From 59aec2be4aaae309c225e213856532bf063b83d1 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Sat, 17 Feb 2024 15:40:07 +0000 Subject: [PATCH 08/15] Merge develop --- .all-contributorsrc | 10 + ...elease-action.yaml => release_action.yaml} | 0 .github/workflows/scheduled_tests.yaml | 57 +- .github/workflows/test_on_push.yaml | 10 + .pre-commit-config.yaml | 2 +- CHANGELOG.md | 6 + README.md | 3 + examples/notebooks/spm_electrode_design.ipynb | 14703 ++++++++++++++++ examples/scripts/spme_max_energy.py | 149 +- examples/standalone/model.py | 1 + noxfile.py | 27 +- pybop/__init__.py | 12 +- pybop/_problem.py | 8 +- pybop/costs/__init__.py | 0 pybop/costs/base_cost.py | 142 + pybop/costs/design_costs.py | 181 + pybop/{_costs.py => costs/fitting_costs.py} | 139 +- pybop/models/base_model.py | 67 +- pybop/models/empirical/ecm.py | 4 +- pybop/models/empirical/ecm_base.py | 29 + pybop/models/lithium_ion/echem.py | 106 +- pybop/models/lithium_ion/echem_base.py | 259 + pybop/parameters/parameter_set.py | 6 + pybop/plotting/quick_plot.py | 13 +- scripts/ci/build_matrix.sh | 43 + tests/unit/test_cost.py | 112 +- tests/unit/test_models.py | 14 + tests/unit/test_parameter_sets.py | 2 +- 28 files changed, 15667 insertions(+), 438 deletions(-) rename .github/workflows/{release-action.yaml => release_action.yaml} (100%) create mode 100644 examples/notebooks/spm_electrode_design.ipynb create mode 100644 pybop/costs/__init__.py create mode 100644 pybop/costs/base_cost.py create mode 100644 pybop/costs/design_costs.py rename pybop/{_costs.py => costs/fitting_costs.py} (60%) create mode 100644 pybop/models/empirical/ecm_base.py create mode 100644 pybop/models/lithium_ion/echem_base.py create mode 100644 scripts/ci/build_matrix.sh diff --git a/.all-contributorsrc b/.all-contributorsrc index 35012fac8..2e8f851d3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -81,6 +81,16 @@ "contributions": [ "financial" ] + }, + { + "login": "agriyakhetarpal", + "name": "Agriya Khetarpal", + "avatar_url": "https://avatars.githubusercontent.com/u/74401230?v=4", + "profile": "https://github.com/agriyakhetarpal", + "contributions": [ + "code", + "infra" + ] } ], "contributorsPerLine": 7, diff --git a/.github/workflows/release-action.yaml b/.github/workflows/release_action.yaml similarity index 100% rename from .github/workflows/release-action.yaml rename to .github/workflows/release_action.yaml diff --git a/.github/workflows/scheduled_tests.yaml b/.github/workflows/scheduled_tests.yaml index 83a0d986b..0bfd6a0ac 100644 --- a/.github/workflows/scheduled_tests.yaml +++ b/.github/workflows/scheduled_tests.yaml @@ -10,38 +10,67 @@ on: schedule: - cron: '0 9 * * *' +# Check noxfile.py for associated environment variables +env: + PYBOP_SCHEDULED: 1 + jobs: + # Dynamically create a matrix of OS, Python, and PyBaMM versions + create_pybamm_matrix: + name: Dynamically create GitHub Actions matrix + runs-on: ubuntu-latest + steps: + - name: Check out PyBOP repository + uses: actions/checkout@v4 + with: + sparse-checkout-cone-mode: false + sparse-checkout: | + scripts/ci/build_matrix.sh + + - name: Run script to create matrix + id: set-matrix + run: | + echo "matrix=$(bash scripts/ci/build_matrix.sh)" >> "$GITHUB_OUTPUT" + outputs: + pybop_matrix: ${{ steps.set-matrix.outputs.matrix }} + build: + needs: [create_pybamm_matrix] + name: Build (${{ matrix.os }}, Python ${{ matrix.python_version }}, PyBaMM ${{ matrix.pybamm_version }}) runs-on: ${{ matrix.os }} strategy: fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.8", "3.9", "3.10", "3.11"] + matrix: ${{fromJson(needs.create_pybamm_matrix.outputs.pybop_matrix)}} + env: + PYBAMM_VERSION: ${{ matrix.pybamm_version }} steps: - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} + - name: Set up Python ${{ matrix.python_version }} uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} + python-version: ${{ matrix.python_version }} + - name: Install dependencies run: | python -m pip install --upgrade pip nox + - name: Unit tests with nox - run: | - python -m nox -s unit - python -m nox -s notebooks + run: python -m nox -s unit + + - name: Run notebooks with nox + run: python -m nox -s notebooks - #M-series Mac Mini + # M-series Mac Mini build-apple-mseries: runs-on: [self-hosted, macOS, ARM64] + if: github.repository == 'pybop-team/PyBOP' env: GITHUB_PATH: ${PYENV_ROOT/bin:$PATH} strategy: fail-fast: false matrix: - python-version: ["3.10"] + python_version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v4 @@ -49,14 +78,14 @@ jobs: shell: bash run: | eval "$(pyenv init -)" - pyenv install ${{ matrix.python-version }} -s - pyenv virtualenv ${{ matrix.python-version }} pybop-${{ matrix.python-version }} + pyenv install ${{ matrix.python_version }} -s + pyenv virtualenv ${{ matrix.python_version }} pybop-${{ matrix.python_version }} - name: Install dependencies & run unit tests shell: bash run: | eval "$(pyenv init -)" - pyenv activate pybop-${{ matrix.python-version }} + pyenv activate pybop-${{ matrix.python_version }} python -m pip install --upgrade pip wheel setuptools nox python -m nox -s unit python -m nox -s notebooks @@ -66,5 +95,5 @@ jobs: shell: bash run: | eval "$(pyenv init -)" - pyenv activate pybop-${{ matrix.python-version }} + pyenv activate pybop-${{ matrix.python_version }} pyenv uninstall -f $( python --version ) diff --git a/.github/workflows/test_on_push.yaml b/.github/workflows/test_on_push.yaml index 688614e4a..a55219bbb 100644 --- a/.github/workflows/test_on_push.yaml +++ b/.github/workflows/test_on_push.yaml @@ -29,12 +29,22 @@ jobs: build: + needs: style runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ["3.8", "3.9", "3.10", "3.11"] + exclude: # We run the coverage tests on Ubuntu with Python 3.11 + - os: ubuntu-latest + python-version: "3.11" + # Include MacOS M-series Runners + include: + - os: macos-14 + python-version: "3.10" + - os: macos-14 + python-version: "3.11" steps: - uses: actions/checkout@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c98de3655..9859cdb12 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.2.0" + rev: "v0.2.1" hooks: - id: ruff args: [--fix, --show-fixes] diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cee3076c..d089db95f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,16 +2,22 @@ ## Features +- [#123](https://github.com/pybop-team/PyBOP/issues/123) - Configures scheduled tests to run against the last three PyPI releases of PyBaMM via dynamic GitHub Actions matrix generation. +- [#187](https://github.com/pybop-team/PyBOP/issues/187) - Adds M1 Github runner to `test_on_push` workflow, updt. self-hosted supported python versions in scheduled tests. - [#118](https://github.com/pybop-team/PyBOP/issues/118) - Adds example jupyter notebooks. - [#151](https://github.com/pybop-team/PyBOP/issues/151) - Adds a standalone version of the Problem class. - [#12](https://github.com/pybop-team/PyBOP/issues/12) - Adds initial implementation of an Observer class and an unscented Kalman filter. +- [#190](https://github.com/pybop-team/PyBOP/issues/190) - Adds a second example design cost, namely the VolumetricEnergyDensity. ## Bug Fixes +- [#123](https://github.com/pybop-team/PyBOP/issues/123) - Reinstates check for availability of parameter sets via PyBaMM upon retrieval by `pybop.ParameterSet.pybamm()`. +- [#196](https://github.com/pybop-team/PyBOP/issues/196) - Fixes failing observer cost tests. - [#63](https://github.com/pybop-team/PyBOP/issues/63) - Removes NLOpt Optimiser from future releases. This is to support deployment to the Apple M-Series platform. - [#164](https://github.com/pybop-team/PyBOP/issues/164) - Fixes convergence issues with gradient-based optimisers, changes default `model.check_params()` to allow infeasible solutions during optimisation iterations. Adds a feasibility check on the optimal parameters. # [v23.12](https://github.com/pybop-team/PyBOP/tree/v23.12) - 2023-12-19 + ## Features - [#141](https://github.com/pybop-team/PyBOP/pull/141) - Adds documentation with Sphinx and PyData Sphinx Theme. Updates docstrings across package, relocates `costs` and `dataset` to top-level of package. Adds noxfile session and deployment workflow for docs. diff --git a/README.md b/README.md index 12b5aad6f..3a3e4881b 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Faraday Institution
Faraday Institution

💵 UK Research and Innovation
UK Research and Innovation

💵 + + Agriya Khetarpal
Agriya Khetarpal

💻 🚇 + diff --git a/examples/notebooks/spm_electrode_design.ipynb b/examples/notebooks/spm_electrode_design.ipynb new file mode 100644 index 000000000..9b378388a --- /dev/null +++ b/examples/notebooks/spm_electrode_design.ipynb @@ -0,0 +1,14703 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "expmkveO04pw" + }, + "source": [ + "## A Electrode Design Optimisation Example\n", + "\n", + "NOTE: This is a brittle example, the classes and methods below will be integrated into PyBOP in a future release.\n", + "\n", + "A design optimisation example loosely based on work by L.D. Couto available at https://doi.org/10.1016/j.energy.2022.125966.\n", + "\n", + "The target is to maximise the gravimetric energy density over a range of possible design parameter values, including for example:\n", + "\n", + "cross-sectional area = height x width (only need change one), electrode widths, particle radii, volume fractions and separator width." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "X87NUGPW04py", + "outputId": "0d785b07-7cff-4aeb-e60a-4ff5a669afbf" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Note: you may need to restart the kernel to use updated packages.\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "%pip install --upgrade pip ipywidgets pybamm -q\n", + "%pip install pybop -q" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jAvD5fk104p0" + }, + "source": [ + "Next, we import the added packages plus any additional dependencies," + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "id": "SQdt4brD04p1" + }, + "outputs": [], + "source": [ + "import pybop" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "X8-tubYY04p_" + }, + "source": [ + "## Optimise the Parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PQqhvSZN04p_" + }, + "source": [ + "First, we define the model to be used for the parameter optimisation," + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "zuvGHWID04p_" + }, + "outputs": [], + "source": [ + "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "model = pybop.lithium_ion.SPMe(parameter_set=parameter_set)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ffS3CF_704qA" + }, + "source": [ + "Next, we define the model parameters for optimisation. Furthermore, PyBOP provides functionality to define a prior for the parameters. The initial parameters values used in the optimisation will be randomly drawn from the prior distribution." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "id": "WPCybXIJ04qA" + }, + "outputs": [], + "source": [ + "parameters = [\n", + " pybop.Parameter(\n", + " \"Positive electrode thickness [m]\",\n", + " prior=pybop.Gaussian(7.56e-05, 0.05e-05),\n", + " bounds=[65e-06, 10e-05],\n", + " ),\n", + " pybop.Parameter(\n", + " \"Positive particle radius [m]\",\n", + " prior=pybop.Gaussian(5.22e-06, 0.05e-06),\n", + " bounds=[2e-06, 9e-06],\n", + " ),\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we construct the experiment for design optimisation and the initial state-of-charge," + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "experiment = pybop.Experiment(\n", + " [\"Discharge at 1C until 2.5 V (5 seconds period)\"],\n", + ")\n", + "init_soc = 1 # start from full charge" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "n4OHa-aF04qA" + }, + "source": [ + "We can now define the output signal, the problem (which combines the model with the dataset) and construct a cost function which in this example is the `GravimetricEnergyDensity()` used to maximise the gravimetric energy density of the cell." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "id": "etMzRtx404qA" + }, + "outputs": [], + "source": [ + "signal = [\"Voltage [V]\", \"Current [A]\"]\n", + "problem = pybop.DesignProblem(\n", + " model, parameters, experiment, signal=signal, init_soc=init_soc\n", + ")\n", + "cost = pybop.GravimetricEnergyDensity(problem)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eQiGurUV04qB" + }, + "source": [ + "Let's construct PyBOP's optimisation class. This class provides the methods needed to fit the forward model. For this example, we use particle swarm optimisation (PSO). Due to the computational requirements of the design optimisation methods, we limit the number of iterations to 5 for this example." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "id": "N3FtAhrT04qB" + }, + "outputs": [], + "source": [ + "optim = pybop.Optimisation(cost, optimiser=pybop.PSO, verbose=True)\n", + "optim.set_max_iterations(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "caprp-bV04qB" + }, + "source": [ + "Finally, we run the optimisation and return the values obtained," + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "id": "-9OVt0EQ04qB" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Halt: Maximum number of iterations (5) reached.\n", + "Estimated parameters: [7.38910820e-05 2.07135001e-06]\n", + "Initial gravimetric energy density: 386.13 Wh.kg-1\n", + "Optimised gravimetric energy density: 397.79 Wh.kg-1\n" + ] + } + ], + "source": [ + "x, final_cost = optim.run()\n", + "print(\"Estimated parameters:\", x)\n", + "print(f\"Initial gravimetric energy density: {-cost(cost.x0):.2f} Wh.kg-1\")\n", + "print(f\"Optimised gravimetric energy density: {-final_cost:.2f} Wh.kg-1\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KxKURtH704qC" + }, + "source": [ + "## Plotting and Visualisation\n", + "\n", + "PyBOP provides various plotting utilities to visualise the results of the optimisation." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-cWCOiqR04qC" + }, + "source": [ + "## Comparing System Response\n", + "\n", + "We can quickly plot the system's response using the estimated parameters compared to the initial parameters:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "id": "ZVfozY0A04qC" + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "fill": "toself", + "fillcolor": "rgba(255,229,204,0.8)", + "hoverinfo": "skip", + "line": { + "color": "rgba(255,255,255,0)" + }, + "showlegend": false, + "type": "scatter", + "x": [ + 0, + 5, + 10, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 65, + 70, + 75, + 80, + 85, + 90, + 95, + 100, + 105, + 110, + 115, + 120, + 125, + 130, + 135, + 140, + 145, + 150, + 155, + 160, + 165, + 170, + 175, + 180, + 185, + 190, + 195, + 200, + 205, + 210, + 215, + 220, + 225, + 230, + 235, + 240, + 245, + 250, + 255, + 260, + 265, + 270, + 275, + 280, + 285, + 290, + 295, + 300, + 305, + 310, + 315, + 320, + 325, + 330, + 335, + 340, + 345, + 350, + 355, + 360, + 365, + 370, + 375, + 380, + 385, + 390, + 395, + 400, + 405, + 410, + 415, + 420, + 425, + 430, + 435, + 440, + 445, + 450, + 455, + 460, + 465, + 470, + 475, + 480, + 485, + 490, + 495, + 500, + 505, + 510, + 515, + 520, + 525, + 530, + 535, + 540, + 545, + 550, + 555, + 560, + 565, + 570, + 575, + 580, + 585, + 590, + 595, + 600, + 605, + 610, + 615, + 620, + 625, + 630, + 635, + 640, + 645, + 650, + 655, + 660, + 665, + 670, + 675, + 680, + 685, + 690, + 695, + 700, + 705, + 710, + 715, + 720, + 725, + 730, + 735, + 740, + 745, + 750, + 755, + 760, + 765, + 770, + 775, + 780, + 785, + 790, + 795, + 800, + 805, + 810, + 815, + 820, + 825, + 830, + 835, + 840, + 845, + 850, + 855, + 860, + 865, + 870, + 875, + 880, + 885, + 890, + 895, + 900, + 905, + 910, + 915, + 920, + 925, + 930, + 935, + 940, + 945, + 950, + 955, + 960, + 965, + 970, + 975, + 980, + 985, + 990, + 995, + 1000, + 1005, + 1010, + 1015, + 1020, + 1025, + 1030, + 1035, + 1040, + 1045, + 1050, + 1055, + 1060, + 1065, + 1070, + 1075, + 1080, + 1085, + 1090, + 1095, + 1100, + 1105, + 1110, + 1115, + 1120, + 1125, + 1130, + 1135, + 1140, + 1145, + 1150, + 1155, + 1160, + 1165, + 1170, + 1175, + 1180, + 1185, + 1190, + 1195, + 1200, + 1205, + 1210, + 1215, + 1220, + 1225, + 1230, + 1235, + 1240, + 1245, + 1250, + 1255, + 1260, + 1265, + 1270, + 1275, + 1280, + 1285, + 1290, + 1295, + 1300, + 1305, + 1310, + 1315, + 1320, + 1325, + 1330, + 1335, + 1340, + 1345, + 1350, + 1355, + 1360, + 1365, + 1370, + 1375, + 1380, + 1385, + 1390, + 1395, + 1400, + 1405, + 1410, + 1415, + 1420, + 1425, + 1430, + 1435, + 1440, + 1445, + 1450, + 1455, + 1460, + 1465, + 1470, + 1475, + 1480, + 1485, + 1490, + 1495, + 1500, + 1505, + 1510, + 1515, + 1520, + 1525, + 1530, + 1535, + 1540, + 1545, + 1550, + 1555, + 1560, + 1565, + 1570, + 1575, + 1580, + 1585, + 1590, + 1595, + 1600, + 1605, + 1610, + 1615, + 1620, + 1625, + 1630, + 1635, + 1640, + 1645, + 1650, + 1655, + 1660, + 1665, + 1670, + 1675, + 1680, + 1685, + 1690, + 1695, + 1700, + 1705, + 1710, + 1715, + 1720, + 1725, + 1730, + 1735, + 1740, + 1745, + 1750, + 1755, + 1760, + 1765, + 1770, + 1775, + 1780, + 1785, + 1790, + 1795, + 1800, + 1805, + 1810, + 1815, + 1820, + 1825, + 1830, + 1835, + 1840, + 1845, + 1850, + 1855, + 1860, + 1865, + 1870, + 1875, + 1880, + 1885, + 1890, + 1895, + 1900, + 1905, + 1910, + 1915, + 1920, + 1925, + 1930, + 1935, + 1940, + 1945, + 1950, + 1955, + 1960, + 1965, + 1970, + 1975, + 1980, + 1985, + 1990, + 1995, + 2000, + 2005, + 2010, + 2015, + 2020, + 2025, + 2030, + 2035, + 2040, + 2045, + 2050, + 2055, + 2060, + 2065, + 2070, + 2075, + 2080, + 2085, + 2090, + 2095, + 2100, + 2105, + 2110, + 2115, + 2120, + 2125, + 2130, + 2135, + 2140, + 2145, + 2150, + 2155, + 2160, + 2165, + 2170, + 2175, + 2180, + 2185, + 2190, + 2195, + 2200, + 2205, + 2210, + 2215, + 2220, + 2225, + 2230, + 2235, + 2240, + 2245, + 2250, + 2255, + 2260, + 2265, + 2270, + 2275, + 2280, + 2285, + 2290, + 2295, + 2300, + 2305, + 2310, + 2315, + 2320, + 2325, + 2330, + 2335, + 2340, + 2345, + 2350, + 2355, + 2360, + 2365, + 2370, + 2375, + 2380, + 2385, + 2390, + 2395, + 2400, + 2405, + 2410, + 2415, + 2420, + 2425, + 2430, + 2435, + 2440, + 2445, + 2450, + 2455, + 2460, + 2465, + 2470, + 2475, + 2480, + 2485, + 2490, + 2495, + 2500, + 2505, + 2510, + 2515, + 2520, + 2525, + 2530, + 2535, + 2540, + 2545, + 2550, + 2555, + 2560, + 2565, + 2570, + 2575, + 2580, + 2585, + 2590, + 2595, + 2600, + 2605, + 2610, + 2615, + 2620, + 2625, + 2630, + 2635, + 2640, + 2645, + 2650, + 2655, + 2660, + 2665, + 2670, + 2675, + 2680, + 2685, + 2690, + 2695, + 2700, + 2705, + 2710, + 2715, + 2720, + 2725, + 2730, + 2735, + 2740, + 2745, + 2750, + 2755, + 2760, + 2765, + 2770, + 2775, + 2780, + 2785, + 2790, + 2795, + 2800, + 2805, + 2810, + 2815, + 2820, + 2825, + 2830, + 2835, + 2840, + 2845, + 2850, + 2855, + 2860, + 2865, + 2870, + 2875, + 2880, + 2885, + 2890, + 2895, + 2900, + 2905, + 2910, + 2915, + 2920, + 2925, + 2930, + 2935, + 2940, + 2945, + 2950, + 2955, + 2960, + 2965, + 2970, + 2975, + 2980, + 2985, + 2990, + 2995, + 3000, + 3005, + 3010, + 3015, + 3020, + 3025, + 3030, + 3035, + 3040, + 3045, + 3050, + 3055, + 3060, + 3065, + 3070, + 3075, + 3080, + 3085, + 3090, + 3095, + 3100, + 3105, + 3110, + 3115, + 3120, + 3125, + 3130, + 3135, + 3140, + 3145, + 3150, + 3155, + 3160, + 3165, + 3170, + 3175, + 3180, + 3185, + 3190, + 3195, + 3200, + 3205, + 3210, + 3215, + 3220, + 3225, + 3230, + 3235, + 3240, + 3245, + 3250, + 3255, + 3260, + 3265, + 3270, + 3275, + 3280, + 3285, + 3290, + 3295, + 3300, + 3305, + 3310, + 3315, + 3320, + 3325, + 3330, + 3335, + 3340, + 3345, + 3350, + 3355, + 3360, + 3365, + 3370, + 3375, + 3380, + 3385, + 3390, + 3395, + 3400, + 3405, + 3410, + 3415, + 3420, + 3425, + 3430, + 3435, + 3440, + 3445, + 3450, + 3455, + 3460, + 3465, + 3470, + 3475, + 3480, + 3485, + 3490, + 3495, + 3500, + 3505, + 3510, + 3510.522507468857, + 3510.522507468857, + 3510, + 3505, + 3500, + 3495, + 3490, + 3485, + 3480, + 3475, + 3470, + 3465, + 3460, + 3455, + 3450, + 3445, + 3440, + 3435, + 3430, + 3425, + 3420, + 3415, + 3410, + 3405, + 3400, + 3395, + 3390, + 3385, + 3380, + 3375, + 3370, + 3365, + 3360, + 3355, + 3350, + 3345, + 3340, + 3335, + 3330, + 3325, + 3320, + 3315, + 3310, + 3305, + 3300, + 3295, + 3290, + 3285, + 3280, + 3275, + 3270, + 3265, + 3260, + 3255, + 3250, + 3245, + 3240, + 3235, + 3230, + 3225, + 3220, + 3215, + 3210, + 3205, + 3200, + 3195, + 3190, + 3185, + 3180, + 3175, + 3170, + 3165, + 3160, + 3155, + 3150, + 3145, + 3140, + 3135, + 3130, + 3125, + 3120, + 3115, + 3110, + 3105, + 3100, + 3095, + 3090, + 3085, + 3080, + 3075, + 3070, + 3065, + 3060, + 3055, + 3050, + 3045, + 3040, + 3035, + 3030, + 3025, + 3020, + 3015, + 3010, + 3005, + 3000, + 2995, + 2990, + 2985, + 2980, + 2975, + 2970, + 2965, + 2960, + 2955, + 2950, + 2945, + 2940, + 2935, + 2930, + 2925, + 2920, + 2915, + 2910, + 2905, + 2900, + 2895, + 2890, + 2885, + 2880, + 2875, + 2870, + 2865, + 2860, + 2855, + 2850, + 2845, + 2840, + 2835, + 2830, + 2825, + 2820, + 2815, + 2810, + 2805, + 2800, + 2795, + 2790, + 2785, + 2780, + 2775, + 2770, + 2765, + 2760, + 2755, + 2750, + 2745, + 2740, + 2735, + 2730, + 2725, + 2720, + 2715, + 2710, + 2705, + 2700, + 2695, + 2690, + 2685, + 2680, + 2675, + 2670, + 2665, + 2660, + 2655, + 2650, + 2645, + 2640, + 2635, + 2630, + 2625, + 2620, + 2615, + 2610, + 2605, + 2600, + 2595, + 2590, + 2585, + 2580, + 2575, + 2570, + 2565, + 2560, + 2555, + 2550, + 2545, + 2540, + 2535, + 2530, + 2525, + 2520, + 2515, + 2510, + 2505, + 2500, + 2495, + 2490, + 2485, + 2480, + 2475, + 2470, + 2465, + 2460, + 2455, + 2450, + 2445, + 2440, + 2435, + 2430, + 2425, + 2420, + 2415, + 2410, + 2405, + 2400, + 2395, + 2390, + 2385, + 2380, + 2375, + 2370, + 2365, + 2360, + 2355, + 2350, + 2345, + 2340, + 2335, + 2330, + 2325, + 2320, + 2315, + 2310, + 2305, + 2300, + 2295, + 2290, + 2285, + 2280, + 2275, + 2270, + 2265, + 2260, + 2255, + 2250, + 2245, + 2240, + 2235, + 2230, + 2225, + 2220, + 2215, + 2210, + 2205, + 2200, + 2195, + 2190, + 2185, + 2180, + 2175, + 2170, + 2165, + 2160, + 2155, + 2150, + 2145, + 2140, + 2135, + 2130, + 2125, + 2120, + 2115, + 2110, + 2105, + 2100, + 2095, + 2090, + 2085, + 2080, + 2075, + 2070, + 2065, + 2060, + 2055, + 2050, + 2045, + 2040, + 2035, + 2030, + 2025, + 2020, + 2015, + 2010, + 2005, + 2000, + 1995, + 1990, + 1985, + 1980, + 1975, + 1970, + 1965, + 1960, + 1955, + 1950, + 1945, + 1940, + 1935, + 1930, + 1925, + 1920, + 1915, + 1910, + 1905, + 1900, + 1895, + 1890, + 1885, + 1880, + 1875, + 1870, + 1865, + 1860, + 1855, + 1850, + 1845, + 1840, + 1835, + 1830, + 1825, + 1820, + 1815, + 1810, + 1805, + 1800, + 1795, + 1790, + 1785, + 1780, + 1775, + 1770, + 1765, + 1760, + 1755, + 1750, + 1745, + 1740, + 1735, + 1730, + 1725, + 1720, + 1715, + 1710, + 1705, + 1700, + 1695, + 1690, + 1685, + 1680, + 1675, + 1670, + 1665, + 1660, + 1655, + 1650, + 1645, + 1640, + 1635, + 1630, + 1625, + 1620, + 1615, + 1610, + 1605, + 1600, + 1595, + 1590, + 1585, + 1580, + 1575, + 1570, + 1565, + 1560, + 1555, + 1550, + 1545, + 1540, + 1535, + 1530, + 1525, + 1520, + 1515, + 1510, + 1505, + 1500, + 1495, + 1490, + 1485, + 1480, + 1475, + 1470, + 1465, + 1460, + 1455, + 1450, + 1445, + 1440, + 1435, + 1430, + 1425, + 1420, + 1415, + 1410, + 1405, + 1400, + 1395, + 1390, + 1385, + 1380, + 1375, + 1370, + 1365, + 1360, + 1355, + 1350, + 1345, + 1340, + 1335, + 1330, + 1325, + 1320, + 1315, + 1310, + 1305, + 1300, + 1295, + 1290, + 1285, + 1280, + 1275, + 1270, + 1265, + 1260, + 1255, + 1250, + 1245, + 1240, + 1235, + 1230, + 1225, + 1220, + 1215, + 1210, + 1205, + 1200, + 1195, + 1190, + 1185, + 1180, + 1175, + 1170, + 1165, + 1160, + 1155, + 1150, + 1145, + 1140, + 1135, + 1130, + 1125, + 1120, + 1115, + 1110, + 1105, + 1100, + 1095, + 1090, + 1085, + 1080, + 1075, + 1070, + 1065, + 1060, + 1055, + 1050, + 1045, + 1040, + 1035, + 1030, + 1025, + 1020, + 1015, + 1010, + 1005, + 1000, + 995, + 990, + 985, + 980, + 975, + 970, + 965, + 960, + 955, + 950, + 945, + 940, + 935, + 930, + 925, + 920, + 915, + 910, + 905, + 900, + 895, + 890, + 885, + 880, + 875, + 870, + 865, + 860, + 855, + 850, + 845, + 840, + 835, + 830, + 825, + 820, + 815, + 810, + 805, + 800, + 795, + 790, + 785, + 780, + 775, + 770, + 765, + 760, + 755, + 750, + 745, + 740, + 735, + 730, + 725, + 720, + 715, + 710, + 705, + 700, + 695, + 690, + 685, + 680, + 675, + 670, + 665, + 660, + 655, + 650, + 645, + 640, + 635, + 630, + 625, + 620, + 615, + 610, + 605, + 600, + 595, + 590, + 585, + 580, + 575, + 570, + 565, + 560, + 555, + 550, + 545, + 540, + 535, + 530, + 525, + 520, + 515, + 510, + 505, + 500, + 495, + 490, + 485, + 480, + 475, + 470, + 465, + 460, + 455, + 450, + 445, + 440, + 435, + 430, + 425, + 420, + 415, + 410, + 405, + 400, + 395, + 390, + 385, + 380, + 375, + 370, + 365, + 360, + 355, + 350, + 345, + 340, + 335, + 330, + 325, + 320, + 315, + 310, + 305, + 300, + 295, + 290, + 285, + 280, + 275, + 270, + 265, + 260, + 255, + 250, + 245, + 240, + 235, + 230, + 225, + 220, + 215, + 210, + 205, + 200, + 195, + 190, + 185, + 180, + 175, + 170, + 165, + 160, + 155, + 150, + 145, + 140, + 135, + 130, + 125, + 120, + 115, + 110, + 105, + 100, + 95, + 90, + 85, + 80, + 75, + 70, + 65, + 60, + 55, + 50, + 45, + 40, + 35, + 30, + 25, + 20, + 15, + 10, + 5, + 0 + ], + "y": [ + 4.0781535600043215, + 4.062128492127174, + 4.052857122903849, + 4.045468006198349, + 4.039164655238445, + 4.033627171418397, + 4.028679583717739, + 4.024206701988653, + 4.020126671141043, + 4.016378976602813, + 4.0129172388855325, + 4.009704860323629, + 4.006712148243633, + 4.003914931880226, + 4.001293401720541, + 3.99883105267252, + 3.996513935514436, + 3.994329756382196, + 3.992268199397369, + 3.990320376053805, + 3.9884786151773146, + 3.9867362494432466, + 3.985087257169886, + 3.983526273017628, + 3.982048410059068, + 3.9806493509083007, + 3.9793252039606934, + 3.978072411222857, + 3.976887703615617, + 3.9757680144916834, + 3.974710494221364, + 3.9737124647122415, + 3.9727714087989336, + 3.9718849370518097, + 3.971050756685545, + 3.970266658014845, + 3.969530495605136, + 3.968840185890992, + 3.9681936922444754, + 3.9675890165982617, + 3.9670241906840658, + 3.966497268901439, + 3.9660063241849626, + 3.9655494426727618, + 3.965124722491505, + 3.9647302700948246, + 3.964364200491103, + 3.96402463621366, + 3.963709707556047, + 3.9634175509708824, + 3.963146309998812, + 3.9628941362300134, + 3.9626591937709392, + 3.962439660679193, + 3.962233730227712, + 3.962039611945965, + 3.9618555334371224, + 3.961679745579746, + 3.961510524327599, + 3.961346175226278, + 3.961185033115423, + 3.961025465675149, + 3.9608658760771354, + 3.960704706406239, + 3.960540438943686, + 3.9603716016500656, + 3.9601967674705296, + 3.9600145563644937, + 3.9598236409958183, + 3.959622743439794, + 3.95941063977861, + 3.9591861609960928, + 3.9589481906857658, + 3.958695677190458, + 3.9584276269293177, + 3.958143105106755, + 3.957841219978721, + 3.9575211653766007, + 3.9571821882635025, + 3.956823597460946, + 3.95644474094881, + 3.9560450489014496, + 3.9556240092170705, + 3.9551811668294734, + 3.954716112093187, + 3.954228495561752, + 3.953718036274191, + 3.9531845023818577, + 3.952627716265804, + 3.952047553288323, + 3.951443940452529, + 3.95081681939006, + 3.9501662187187385, + 3.9494922074961463, + 3.9487948939344584, + 3.9480744285682583, + 3.947331002452851, + 3.946564842068588, + 3.9457761724734417, + 3.944965309992684, + 3.9441325800465257, + 3.9432783377421696, + 3.942402965889137, + 3.941506873027282, + 3.9405904873417623, + 3.939654253971517, + 3.93869865012846, + 3.937724165047615, + 3.9367313037486937, + 3.9357205852191233, + 3.9346925406436792, + 3.933647718924989, + 3.932586674408453, + 3.9315099636900217, + 3.9304181529211393, + 3.929311812830394, + 3.9281915173138953, + 3.9270578420856808, + 3.9259113661614737, + 3.924752671067227, + 3.923582336475441, + 3.922400932133523, + 3.921209026068122, + 3.920007184672868, + 3.9187959711483114, + 3.917575932353624, + 3.916347613554031, + 3.915111551967116, + 3.9138682760725696, + 3.912618304973568, + 3.91136214780803, + 3.9101003032077903, + 3.908833258803867, + 3.9075614907756258, + 3.9062854634420208, + 3.9050056288924857, + 3.903722426655612, + 3.9024362838142888, + 3.9011476169194825, + 3.8998568227693142, + 3.8985642880087874, + 3.8972703855527144, + 3.895975474433693, + 3.8946798996721896, + 3.893383992166422, + 3.8920880685998727, + 3.8907924313642135, + 3.889497368495429, + 3.888203153621002, + 3.88691004591595, + 3.885618290065571, + 3.8843281162328154, + 3.883039740028083, + 3.881753362479445, + 3.880469170001101, + 3.879187334358151, + 3.877908012625472, + 3.8766313471388174, + 3.875357465436043, + 3.874086480186543, + 3.8728184902884193, + 3.871553577419355, + 3.870291808871612, + 3.869033236830797, + 3.867777898016867, + 3.866525813502974, + 3.8652769885098297, + 3.864031412173953, + 3.862789057288426, + 3.8615498800148944, + 3.860313819565679, + 3.8590807978551904, + 3.857850719119923, + 3.856623469506763, + 3.8553989166295626, + 3.8541769090945737, + 3.852957275995444, + 3.851739826379542, + 3.850524348687568, + 3.8493106101695633, + 3.848098356281136, + 3.846887310064644, + 3.845677171521611, + 3.844467616983481, + 3.843258298489774, + 3.8420488431839814, + 3.840838852739704, + 3.839627902831415, + 3.838415542666537, + 3.8372012945979743, + 3.8359846538389095, + 3.834765088304472, + 3.833542038607813, + 3.832314918241333, + 3.831083113976733, + 3.829845986520855, + 3.828602871467264, + 3.827353080586043, + 3.8260959034970865, + 3.8248306097736746, + 3.8235564515767657, + 3.822272666807052, + 3.8209784823430417, + 3.8196731188882183, + 3.818355795729425, + 3.817025736386133, + 3.815682174975635, + 3.8143243633068846, + 3.8129515787012234, + 3.811563132520345, + 3.8101583793612583, + 3.808736726853778, + 3.807297645969768, + 3.8058406817238137, + 3.80436546411492, + 3.802871719126947, + 3.8013592795750033, + 3.799828095556136, + 3.798278244237408, + 3.796709938695079, + 3.795123535506046, + 3.7935195407902023, + 3.791898614409963, + 3.7902615720536934, + 3.788609384963118, + 3.7869431771111666, + 3.7852642196964066, + 3.7835739228902656, + 3.781873824853354, + 3.7801655781220935, + 3.778450933554908, + 3.77673172211256, + 3.775009834826224, + 3.7732872013754, + 3.7715657677511754, + 3.7698474735163607, + 3.7681342291899154, + 3.766427894278298, + 3.764730256450638, + 3.763043012383892, + 3.76136775030427, + 3.759705935267657, + 3.7580588967027095, + 3.756427818706251, + 3.754813733065729, + 3.753217515064813, + 3.7516398818772, + 3.750081393439029, + 3.748542455571776, + 3.747023325098422, + 3.7455241166687054, + 3.744044810994625, + 3.742585264194985, + 3.741145217955012, + 3.7397243102231448, + 3.7383220861894384, + 3.7369380093171713, + 3.735571472229128, + 3.734221807281244, + 3.732888296687621, + 3.731570182090632, + 3.730266673498163, + 3.728976957535277, + 3.727700204980097, + 3.7264355775731017, + 3.7251822341053327, + 3.7239393358039874, + 3.7227060510445447, + 3.7214815594261057, + 3.720265055252273, + 3.7190557504633626, + 3.7178528770675903, + 3.7166556891193983, + 3.7154634642923026, + 3.7142755050922776, + 3.713091139755458, + 3.7119097228712814, + 3.710730635772411, + 3.709553286711547, + 3.708377110886087, + 3.707201570312106, + 3.7060261535853862, + 3.704850375550881, + 3.703673776900308, + 3.7024959237151753, + 3.701316406970347, + 3.7001348420108537, + 3.6989508680127496, + 3.6977641474369536, + 3.696574365483474, + 3.695381229551866, + 3.694184468712492, + 3.692983833192168, + 3.6917790938766006, + 3.6905700418313105, + 3.689356487841866, + 3.6881382619737697, + 3.686915213151619, + 3.6856872087568857, + 3.684454134243129, + 3.6832158927672474, + 3.6819724048350486, + 3.680723607959318, + 3.679469456328282, + 3.6782099204824057, + 3.676944986997304, + 3.675674658170475, + 3.6743989517097777, + 3.673117900421307, + 3.671831551894593, + 3.6705399681830535, + 3.6692432254777265, + 3.6679414137723967, + 3.666634636518434, + 3.665323010267701, + 3.664006664302177, + 3.662685740248972, + 3.661360391679693, + 3.660030783693226, + 3.658697092481317, + 3.657359504876294, + 3.656018217880785, + 3.654673438179195, + 3.6533253816311055, + 3.651974272746874, + 3.650620344145859, + 3.649263835998055, + 3.6479049954498697, + 3.64654407603522, + 3.6451813370730024, + 3.6438170430523886, + 3.642451463007464, + 3.6410848698827625, + 3.63971753989153, + 3.638349751868498, + 3.636981786619237, + 3.6356139262679137, + 3.6342464536056944, + 3.632879651441849, + 3.631513801959559, + 3.6301491860787576, + 3.628786082827955, + 3.627424768727187, + 3.626065517184118, + 3.624708597905212, + 3.623354276323971, + 3.622002813047884, + 3.620654463325893, + 3.6193094765378895, + 3.617968095707732, + 3.6166305570410184, + 3.6152970894888607, + 3.613967914338624, + 3.612643244832525, + 3.611323285814783, + 3.610008233407862, + 3.6086982747181993, + 3.607393587571689, + 3.606094340279004, + 3.6048006914304, + 3.603512789720329, + 3.602230773801203, + 3.6009547721656663, + 3.5996849030565214, + 3.5984212744049477, + 3.597163983794369, + 3.5959131184501274, + 3.5946687552535765, + 3.5934309607795667, + 3.5921997913561636, + 3.590975293145315, + 3.5897575022431543, + 3.5885464447987476, + 3.58734213714977, + 3.5861445859738885, + 3.584953788454368, + 3.5837697324585904, + 3.582592396728057, + 3.581421751078609, + 3.5802577566094453, + 3.579100365919649, + 3.577949523331005, + 3.576805165115871, + 3.575667219728831, + 3.5745356080411113, + 3.573410243576644, + 3.572291032748701, + 3.571177875096211, + 3.5700706635187833, + 3.568969284509659, + 3.567873618385751, + 3.5667835395141276, + 3.5656989165341613, + 3.564619612574924, + 3.5635454854671544, + 3.5624763879494097, + 3.5614121678680313, + 3.5603526683703404, + 3.5592977280912264, + 3.558247181332565, + 3.5572008582352743, + 3.556158584944156, + 3.555120183765203, + 3.5540854733155114, + 3.553054268665782, + 3.552026381475508, + 3.551001620120972, + 3.549979789816222, + 3.548960692727279, + 3.5479441280797843, + 3.5469298922604047, + 3.5459177789123357, + 3.54490757902527, + 3.5438990810201907, + 3.542892070829531, + 3.541886331973032, + 3.5408816456299164, + 3.539877790707815, + 3.5388745439091256, + 3.5378716797952148, + 3.536868970849262, + 3.5358661875382458, + 3.5348630983748404, + 3.5338594699798067, + 3.5328550671457184, + 3.5318496529026273, + 3.530842988586536, + 3.529834833911404, + 3.528824947045443, + 3.5278130846926485, + 3.52679900218025, + 3.525782453553013, + 3.5247631916752344, + 3.523740968341321, + 3.5227155343957404, + 3.52168663986339, + 3.520654034091064, + 3.519617465901109, + 3.5185766837579777, + 3.5175314359486443, + 3.516481470777728, + 3.5154265367780937, + 3.5143663829378275, + 3.513300758944305, + 3.5122294154461127, + 3.511152104333493, + 3.5100685790379904, + 3.508978594851838, + 3.5078819092676476, + 3.5067782823387015, + 3.5056674770604, + 3.504549259772839, + 3.503423400584881, + 3.502289673819573, + 3.5011478584808287, + 3.4999977387411385, + 3.4988391044498233, + 3.4976717516612643, + 3.496495483182384, + 3.495310109138316, + 3.494115447555253, + 3.492911324958987, + 3.491697576987634, + 3.4904740490167594, + 3.48924059679486, + 3.4879970870869235, + 3.486743398323682, + 3.4854794212537072, + 3.4842050595955354, + 3.482920230686549, + 3.4816248661252818, + 3.480318912403507, + 3.4790023315243683, + 3.4776751016025056, + 3.4763372174421123, + 3.4749886910886008, + 3.4736295523495304, + 3.472259849280337, + 3.4708796486302957, + 3.4694890362443003, + 3.4680881174159053, + 3.4666770171871777, + 3.4652558805911324, + 3.463824872832561, + 3.462384179403261, + 3.460934006128083, + 3.459474579138267, + 3.4580061447691928, + 3.4565289693797165, + 3.4550433390910085, + 3.4535495594431485, + 3.4520479549682195, + 3.450538868679267, + 3.449022661475053, + 3.447499711461173, + 3.445970413188571, + 3.4444351768113988, + 3.4428944271664896, + 3.4413486027776026, + 3.4397981547881065, + 3.438243545826284, + 3.4366852488082644, + 3.435123745683842, + 3.4335595261311216, + 3.431993086206317, + 3.4304249269554377, + 3.4288555529948748, + 3.4272854710682346, + 3.4257151885868966, + 3.4241452121619247, + 3.4225760461350117, + 3.4210081911160173, + 3.419442142534674, + 3.4178783892137656, + 3.4163174119708324, + 3.414759682255156, + 3.4132056608263377, + 3.411655796480413, + 3.4101105248288035, + 3.408570267135024, + 3.4070354292132636, + 3.405506400392595, + 3.403983552549601, + 3.4024672392117923, + 3.400957794733415, + 3.399455533544512, + 3.3979607494735324, + 3.39647371514301, + 3.3949946814372924, + 3.3935238770405647, + 3.3920615080428966, + 3.390607757611462, + 3.389162785723548, + 3.3877267289574102, + 3.3862997003367714, + 3.384881789224161, + 3.3834730612579964, + 3.382073558328104, + 3.3806832985838384, + 3.379302276469116, + 3.3779304627780213, + 3.3765678047249033, + 3.375214226022518, + 3.3738696269617083, + 3.372533884486157, + 3.3712068522556384, + 3.369888360691123, + 3.3685782169952594, + 3.3672762051416316, + 3.365982085826301, + 3.3646955963751912, + 3.363416450600904, + 3.3621443386026506, + 3.360878926503067, + 3.359619856115685, + 3.3583667445370065, + 3.3571191836572125, + 3.3558767395835076, + 3.3546389519703874, + 3.353405333251112, + 3.352175367764781, + 3.3509485107736836, + 3.3497241873656023, + 3.3485017912361044, + 3.34728068334599, + 3.346060190449433, + 3.344839603488674, + 3.3436181758516086, + 3.3423951214890755, + 3.3411696128893005, + 3.339940778907851, + 3.3387077024521448, + 3.3374694180208495, + 3.3362249090997276, + 3.334973105417095, + 3.333712880063687, + 3.332443046484157, + 3.3311623553495604, + 3.329869491323346, + 3.328563069736361, + 3.32724163319048, + 3.325903648114467, + 3.3245475013007426, + 3.3231714964572268, + 3.321773850814463, + 3.320352691835222, + 3.3189060540813884, + 3.317431876301088, + 3.3159279988083807, + 3.314392161237326, + 3.312822000763001, + 3.3112150508927645, + 3.3095687409427863, + 3.307880396326462, + 3.306147239793123, + 3.304366393766847, + 3.3025348839458797, + 3.300649644332875, + 3.2987075238735573, + 3.2967052948870874, + 3.294639663473017, + 3.292507282077737, + 3.290304764395832, + 3.288028702768201, + 3.2856756882176765, + 3.2832423332335283, + 3.2807252973771406, + 3.278121315731635, + 3.2754272301574874, + 3.2726400232438095, + 3.269756854760963, + 3.2667751003251047, + 3.2636923918801815, + 3.2605066594903542, + 3.25721617381772, + 3.2538195885414565, + 3.250315981858906, + 3.246704896102827, + 3.242986374418139, + 3.239160993372672, + 3.2352298903369876, + 3.2311947844644098, + 3.227057990140412, + 3.222822421854606, + 3.218491589581512, + 3.214069583938895, + 3.209561050621223, + 3.204971153876343, + 3.2003055290966023, + 3.195570224919974, + 3.1907716355687565, + 3.185916424477614, + 3.1810114405627146, + 3.176063628744403, + 3.1710799365422058, + 3.1660672187022643, + 3.1610321418847236, + 3.155981091428758, + 3.1509200821259715, + 3.145854674774099, + 3.140789900061202, + 3.1357301910580246, + 3.130679325287935, + 3.1256403770153307, + 3.120615680061021, + 3.1156068011316647, + 3.110614523353324, + 3.105638839437114, + 3.1006789536860233, + 3.0957332918802307, + 3.090799517956329, + 3.085874556322205, + 3.0809546186207895, + 3.076035233767983, + 3.0711112801359244, + 3.06617701882649, + 3.061226127073741, + 3.056251730921822, + 3.051246436440277, + 3.0462023588562612, + 3.041111149098527, + 3.035964017357659, + 3.0307517533678836, + 3.025464743206662, + 3.0200929824875216, + 3.0146260858892946, + 3.0090532930207265, + 3.0033634706642856, + 2.9975451114773475, + 2.9915863292539195, + 2.985474850866622, + 2.9791980050182136, + 2.9727427079349993, + 2.966095446132939, + 2.9592422563810845, + 2.952168702977978, + 2.9448598524448917, + 2.937300245726268, + 2.9294738679728756, + 2.92136411596758, + 2.9129537632373315, + 2.9042249228786146, + 2.895159008107192, + 2.8857366905264774, + 2.8759378560928313, + 2.8657415587400674, + 2.8551259716095316, + 2.8440683358167096, + 2.8325449066694137, + 2.820530897237168, + 2.808000419155303, + 2.794926420531019, + 2.781280620801645, + 2.7670334423774694, + 2.752153938882235, + 2.7366097197836883, + 2.7203668711836975, + 2.7033898725116132, + 2.68564150883573, + 2.6670827784741347, + 2.64767279554727, + 2.627368687068769, + 2.60612548411602, + 2.5838960065557774, + 2.547832201997476, + 2.570061679557719, + 2.591304882510468, + 2.6116089909889686, + 2.6310189739158334, + 2.6495777042774287, + 2.667326067953312, + 2.684303066625396, + 2.700545915225387, + 2.7160901343239336, + 2.730969637819168, + 2.7452168162433437, + 2.758862615972718, + 2.771936614597002, + 2.7844670926788666, + 2.7964811021111124, + 2.8080045312584083, + 2.8190621670512304, + 2.829677754181766, + 2.83987405153453, + 2.849672885968176, + 2.8590952035488906, + 2.8681611183203133, + 2.87688995867903, + 2.885300311409279, + 2.8934100634145743, + 2.9012364411679665, + 2.9087960478865904, + 2.9161048984196767, + 2.9231784518227832, + 2.930031641574638, + 2.936678903376698, + 2.9431342004599124, + 2.9494110463083207, + 2.9555225246956183, + 2.961481306919046, + 2.9672996661059843, + 2.9729894884624253, + 2.9785622813309933, + 2.9840291779292203, + 2.9894009386483607, + 2.9946879488095823, + 2.999900212799358, + 3.005047344540226, + 3.01013855429796, + 3.015182631881976, + 3.0201879263635205, + 3.0251623225154396, + 3.0301132142681886, + 3.035047475577623, + 3.0399714292096816, + 3.044890814062488, + 3.049810751763904, + 3.0547357133980277, + 3.0596694873219294, + 3.064615149127722, + 3.0695750348788127, + 3.074550718795023, + 3.0795429965733634, + 3.08455187550272, + 3.0895765724570294, + 3.0946155207296338, + 3.0996663864997234, + 3.104726095502901, + 3.109790870215798, + 3.1148562775676703, + 3.1199172868704568, + 3.1249683373264223, + 3.130003414143963, + 3.1350161319839045, + 3.1399998241861016, + 3.1449476360044133, + 3.149852619919313, + 3.1547078310104553, + 3.1595064203616725, + 3.164241724538301, + 3.1689073493180415, + 3.173497246062922, + 3.1780057793805936, + 3.1824277850232106, + 3.186758617296305, + 3.190994185582111, + 3.1951309799061085, + 3.1991660857786863, + 3.203097188814371, + 3.2069225698598376, + 3.2106410915445256, + 3.2142521773006045, + 3.217755783983155, + 3.2211523692594186, + 3.224442854932053, + 3.22762858732188, + 3.2307112957668034, + 3.233693050202662, + 3.2365762186855083, + 3.239363425599186, + 3.242057511173334, + 3.2446614928188393, + 3.247178528675227, + 3.2496118836593753, + 3.2519648982099, + 3.2542409598375306, + 3.2564434775194355, + 3.258575858914716, + 3.260641490328786, + 3.262643719315256, + 3.2645858397745737, + 3.2664710793875784, + 3.2683025892085458, + 3.2700834352348216, + 3.27181659176816, + 3.273504936384485, + 3.275151246334463, + 3.2767581962046997, + 3.2783283566790247, + 3.2798641942500795, + 3.281368071742787, + 3.282842249523087, + 3.284288887276922, + 3.285710046256162, + 3.2871076918989255, + 3.2884836967424413, + 3.2898398435561655, + 3.2911778286321787, + 3.29249926517806, + 3.2938056867650447, + 3.295098550791259, + 3.2963792419258557, + 3.2976490755053858, + 3.2989093008587935, + 3.3001611045414263, + 3.301405613462548, + 3.3026438978938435, + 3.3038769743495497, + 3.305105808330999, + 3.306331316930774, + 3.3075543712933073, + 3.3087757989303728, + 3.309996385891132, + 3.3112168787876888, + 3.312437986677803, + 3.313660382807301, + 3.3148847062153823, + 3.31611156320648, + 3.3173415286928107, + 3.318575147412086, + 3.3198129350252064, + 3.3210553790989112, + 3.322302939978705, + 3.3235560515573837, + 3.324815121944766, + 3.3260805340443493, + 3.327352646042603, + 3.32863179181689, + 3.3299182812679997, + 3.3312124005833303, + 3.332514412436958, + 3.333824556132822, + 3.335143047697337, + 3.3364700799278557, + 3.337805822403407, + 3.339150421464218, + 3.340504000166602, + 3.34186665821972, + 3.343238471910815, + 3.344619494025537, + 3.3460097537698026, + 3.347409256699695, + 3.34881798466586, + 3.35023589577847, + 3.351662924399109, + 3.353098981165247, + 3.354543953053161, + 3.3559977034845954, + 3.3574600724822634, + 3.358930876878991, + 3.3604099105847087, + 3.361896944915231, + 3.3633917289862105, + 3.364893990175114, + 3.366403434653491, + 3.3679197479912997, + 3.3694425958342937, + 3.3709716246549624, + 3.3725064625767227, + 3.3740467202705022, + 3.3755919919221116, + 3.3771418562680364, + 3.3786958776968548, + 3.380253607412531, + 3.3818145846554644, + 3.3833783379763727, + 3.384944386557716, + 3.3865122415767104, + 3.3880814076036234, + 3.3896513840285953, + 3.3912216665099333, + 3.3927917484365735, + 3.3943611223971364, + 3.395929281648016, + 3.3974957215728203, + 3.399059941125541, + 3.400621444249963, + 3.402179741267983, + 3.403734350229805, + 3.4052847982193013, + 3.4068306226081884, + 3.4083713722530975, + 3.4099066086302696, + 3.411435906902872, + 3.412958856916752, + 3.414475064120966, + 3.415984150409918, + 3.417485754884847, + 3.418979534532707, + 3.4204651648214153, + 3.4219423402108915, + 3.4234107745799656, + 3.4248702015697816, + 3.4263203748449595, + 3.42776106827426, + 3.429192076032831, + 3.4306132126288764, + 3.432024312857604, + 3.433425231685999, + 3.4348158440719945, + 3.4361960447220357, + 3.437565747791229, + 3.4389248865302995, + 3.440273412883811, + 3.4416112970442043, + 3.442938526966067, + 3.4442551078452057, + 3.4455610615669805, + 3.4468564261282477, + 3.448141255037234, + 3.449415616695406, + 3.450679593765381, + 3.451933282528622, + 3.4531767922365586, + 3.454410244458458, + 3.4556337724293327, + 3.456847520400686, + 3.458051642996952, + 3.459246304580015, + 3.460431678624083, + 3.461607947102963, + 3.462775299891522, + 3.4639339341828372, + 3.4650840539225274, + 3.4662258692612715, + 3.4673595960265793, + 3.468485455214538, + 3.4696036725020987, + 3.4707144777804, + 3.4718181047093464, + 3.4729147902935367, + 3.474004774479689, + 3.4750882997751913, + 3.4761656108878114, + 3.4772369543860036, + 3.4783025783795263, + 3.4793627322197924, + 3.480417666219427, + 3.481467631390343, + 3.4825128791996764, + 3.4835536613428073, + 3.484590229532763, + 3.485622835305089, + 3.486651729837439, + 3.4876771637830197, + 3.488699387116933, + 3.4897186489947116, + 3.490735197621949, + 3.4917492801343473, + 3.492761142487142, + 3.493771029353103, + 3.4947791840282347, + 3.495785848344326, + 3.496791262587417, + 3.4977956654215054, + 3.498799293816539, + 3.4998023829799445, + 3.5008051662909607, + 3.5018078752369135, + 3.5028107393508243, + 3.5038139861495137, + 3.504817841071615, + 3.5058225274147308, + 3.5068282662712296, + 3.5078352764618894, + 3.508843774466969, + 3.5098539743540345, + 3.5108660877021034, + 3.511880323521483, + 3.512896888168978, + 3.513915985257921, + 3.514937815562671, + 3.5159625769172065, + 3.5169904641074807, + 3.51802166875721, + 3.519056379206902, + 3.520094780385855, + 3.521137053676973, + 3.522183376774264, + 3.523233923532925, + 3.524288863812039, + 3.52534836330973, + 3.5264125833911084, + 3.527481680908853, + 3.528555808016623, + 3.52963511197586, + 3.5307197349558264, + 3.53180981382745, + 3.5329054799513577, + 3.534006858960482, + 3.53511407053791, + 3.5362272281903997, + 3.537346439018343, + 3.53847180348281, + 3.5396034151705296, + 3.54074136055757, + 3.5418857187727033, + 3.543036561361348, + 3.544193952051144, + 3.5453579465203076, + 3.546528592169756, + 3.547705927900289, + 3.548889983896067, + 3.5500807814155872, + 3.5512783325914685, + 3.5524826402404464, + 3.553693697684853, + 3.5549114885870137, + 3.5561359867978624, + 3.5573671562212654, + 3.5586049506952753, + 3.559849313891826, + 3.561100179236068, + 3.5623574698466465, + 3.56362109849822, + 3.564890967607365, + 3.566166969242902, + 3.5674489851620277, + 3.5687368868720983, + 3.570030535720703, + 3.571329783013388, + 3.572634470159898, + 3.5739444288495608, + 3.575259481256482, + 3.576579440274224, + 3.5779041097803224, + 3.5792332849305595, + 3.580566752482717, + 3.5819042911494305, + 3.583245671979588, + 3.5845906587675915, + 3.5859390084895826, + 3.5872904717656695, + 3.5886447933469108, + 3.590001712625817, + 3.591360964168886, + 3.592722278269654, + 3.5940853815204563, + 3.595449997401258, + 3.5968158468835476, + 3.598182649047393, + 3.599550121709612, + 3.6009179820609356, + 3.6022859473101967, + 3.603653735333229, + 3.605021065324461, + 3.6063876584491625, + 3.6077532384940874, + 3.609117532514701, + 3.610480271476919, + 3.611841190891568, + 3.613200031439754, + 3.6145565395875576, + 3.6159104681885728, + 3.617261577072804, + 3.6186096336208937, + 3.619954413322484, + 3.621295700317993, + 3.622633287923015, + 3.6239669791349254, + 3.625296587121391, + 3.626621935690671, + 3.627942859743875, + 3.629259205709399, + 3.630570831960133, + 3.6318776092140954, + 3.6331794209194257, + 3.634476163624752, + 3.635767747336292, + 3.6370540958630055, + 3.638335147151477, + 3.6396108536121736, + 3.640881182439003, + 3.642146115924104, + 3.6434056517699807, + 3.6446598034010167, + 3.6459086002767473, + 3.647152088208946, + 3.648390329684828, + 3.649623404198584, + 3.6508514085933177, + 3.652074457415469, + 3.653292683283565, + 3.6545062372730097, + 3.6557152893182994, + 3.6569200286338663, + 3.6581206641541906, + 3.659317424993565, + 3.660510560925174, + 3.661700342878652, + 3.662887063454448, + 3.664071037452553, + 3.665252602412046, + 3.666432119156874, + 3.667609972342007, + 3.66878657099258, + 3.6699623490270854, + 3.6711377657538047, + 3.6723133063277857, + 3.673489482153246, + 3.67466683121411, + 3.67584591831298, + 3.677027335197157, + 3.678211700533976, + 3.6793996597340017, + 3.680591884561097, + 3.6817890725092894, + 3.6829919459050617, + 3.684201250693971, + 3.685417754867804, + 3.6866422464862434, + 3.687875531245686, + 3.6891184295470314, + 3.6903717730148, + 3.691636400421795, + 3.692913152976976, + 3.6942028689398616, + 3.695506377532331, + 3.69682449212932, + 3.6981580027229426, + 3.6995076676708263, + 3.70087420475887, + 3.702258281631137, + 3.703660505664843, + 3.705081413396711, + 3.706521459636684, + 3.7079810064363232, + 3.709460312110404, + 3.7109595205401207, + 3.712478651013475, + 3.714017588880728, + 3.7155760773188984, + 3.717153710506511, + 3.718749928507428, + 3.7203640141479504, + 3.721995092144408, + 3.723642130709356, + 3.725303945745969, + 3.726979207825591, + 3.728666451892338, + 3.730364089719997, + 3.732070424631614, + 3.733783668958059, + 3.735501963192874, + 3.737223396817099, + 3.738946030267923, + 3.7406679175542585, + 3.742387128996606, + 3.744101773563792, + 3.745810020295053, + 3.747510118331964, + 3.7492004151381058, + 3.7508793725528657, + 3.7525455804048167, + 3.754197767495392, + 3.7558348098516623, + 3.7574557362319014, + 3.7590597309477447, + 3.7606461341367776, + 3.762214439679107, + 3.7637642909978344, + 3.765295475016702, + 3.7668079145686457, + 3.768301659556619, + 3.769776877165512, + 3.7712338414114663, + 3.772672922295477, + 3.774094574802957, + 3.775499327962044, + 3.776887774142922, + 3.7782605587485834, + 3.7796183704173343, + 3.780961931827832, + 3.7822919911711232, + 3.783609314329917, + 3.78491467778474, + 3.786208862248751, + 3.787492647018464, + 3.788766805215374, + 3.7900320989387857, + 3.791289276027742, + 3.792539066908963, + 3.7937821819625537, + 3.795019309418432, + 3.796251113683032, + 3.797478234049512, + 3.7987012837461704, + 3.799920849280608, + 3.8011374900396735, + 3.802351738108236, + 3.803564098273114, + 3.804775048181402, + 3.80598503862568, + 3.8071944939314726, + 3.80840381242518, + 3.8096133669633097, + 3.810823505506343, + 3.812034551722835, + 3.813246805611262, + 3.8144605441292665, + 3.8156760218212407, + 3.8168934714371425, + 3.818113104536272, + 3.8193351120712618, + 3.8205596649484623, + 3.8217869145616223, + 3.823016993296889, + 3.8242500150073777, + 3.825486075456593, + 3.826725252730124, + 3.8279676076156512, + 3.829213183951528, + 3.830462008944673, + 3.8317140934585656, + 3.832969432272496, + 3.8342280043133106, + 3.835489772861054, + 3.836754685730118, + 3.838022675628242, + 3.8392936608777415, + 3.840567542580516, + 3.841844208067171, + 3.8431235297998496, + 3.844405365442799, + 3.845689557921143, + 3.8469759354697817, + 3.848264311674514, + 3.8495544855072703, + 3.8508462413576487, + 3.8521393490627007, + 3.853433563937127, + 3.854728626805912, + 3.8560242640415714, + 3.8573201876081207, + 3.858616095113888, + 3.859911669875392, + 3.861206580994413, + 3.862500483450486, + 3.8637930182110134, + 3.8650838123611817, + 3.866372479255987, + 3.867658622097311, + 3.868941824334184, + 3.870221658883719, + 3.871497686217325, + 3.8727694542455655, + 3.874036498649489, + 3.875298343249728, + 3.8765545004152666, + 3.877804471514268, + 3.8790477474088143, + 3.88028380899573, + 3.881512127795323, + 3.88273216659001, + 3.883943380114567, + 3.885145221509821, + 3.8863371275752217, + 3.8875185319171393, + 3.8886888665089256, + 3.889847561603172, + 3.890994037527379, + 3.892127712755594, + 3.8932480082720926, + 3.894354348362838, + 3.89544615913172, + 3.896522869850152, + 3.8975839143666873, + 3.898628736085378, + 3.899656780660822, + 3.900667499190392, + 3.9016603604893136, + 3.9026348455701583, + 3.903590449413216, + 3.904526682783461, + 3.9054430684689807, + 3.906339161330836, + 3.907214533183869, + 3.908068775488224, + 3.908901505434383, + 3.909712367915141, + 3.9105010375102864, + 3.9112671978945497, + 3.9120106240099575, + 3.912731089376157, + 3.913428402937845, + 3.914102414160437, + 3.914753014831758, + 3.9153801358942273, + 3.9159837487300218, + 3.916563911707503, + 3.917120697823556, + 3.9176542317158902, + 3.918164691003451, + 3.9186523075348862, + 3.919117362271172, + 3.919560204658769, + 3.919981244343148, + 3.920380936390509, + 3.9207597929026448, + 3.9211183837052017, + 3.921457360818299, + 3.92177741542042, + 3.922079300548454, + 3.922363822371016, + 3.9226318726321567, + 3.922884386127465, + 3.923122356437791, + 3.923346835220309, + 3.923558938881493, + 3.923759836437517, + 3.923950751806192, + 3.924132962912229, + 3.924307797091765, + 3.924476634385384, + 3.924640901847938, + 3.924802071518834, + 3.924961661116848, + 3.9251212285571215, + 3.925282370667978, + 3.925446719769298, + 3.925615941021445, + 3.925791728878821, + 3.925975807387664, + 3.9261699256694103, + 3.9263758561208912, + 3.926595389212638, + 3.926830331671712, + 3.9270825054405103, + 3.927353746412581, + 3.9276459029977455, + 3.9279608316553585, + 3.9283003959328022, + 3.9286664655365233, + 3.929060917933204, + 3.929485638114461, + 3.9299425196266617, + 3.9304334643431376, + 3.930960386125764, + 3.93152521203996, + 3.932129887686174, + 3.9327763813326904, + 3.933466691046835, + 3.934202853456543, + 3.934986952127243, + 3.935821132493508, + 3.936707604240632, + 3.93764866015394, + 3.9386466896630625, + 3.939704209933382, + 3.9408238990573152, + 3.942008606664556, + 3.943261399402392, + 3.944585546349999, + 3.9459846055007666, + 3.9474624684593262, + 3.9490234526115846, + 3.9506724448849457, + 3.952414810619014, + 3.954256571495504, + 3.9562043948390673, + 3.9582659518238943, + 3.960450130956135, + 3.962767248114219, + 3.965229597162239, + 3.967851127321925, + 3.970648343685331, + 3.973641055765328, + 3.976853434327231, + 3.980315172044512, + 3.984062866582742, + 3.988142897430352, + 3.992615779159438, + 3.997563366860096, + 4.003100850680144, + 4.009404201640048, + 4.016793318345548, + 4.026064687568873, + 4.04208975544602 + ] + }, + { + "mode": "markers", + "name": "Initial", + "type": "scatter", + "x": [ + 0, + 5, + 10, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 65, + 70, + 75, + 80, + 85, + 90, + 95, + 100, + 105, + 110, + 115, + 120, + 125, + 130, + 135, + 140, + 145, + 150, + 155, + 160, + 165, + 170, + 175, + 180, + 185, + 190, + 195, + 200, + 205, + 210, + 215, + 220, + 225, + 230, + 235, + 240, + 245, + 250, + 255, + 260, + 265, + 270, + 275, + 280, + 285, + 290, + 295, + 300, + 305, + 310, + 315, + 320, + 325, + 330, + 335, + 340, + 345, + 350, + 355, + 360, + 365, + 370, + 375, + 380, + 385, + 390, + 395, + 400, + 405, + 410, + 415, + 420, + 425, + 430, + 435, + 440, + 445, + 450, + 455, + 460, + 465, + 470, + 475, + 480, + 485, + 490, + 495, + 500, + 505, + 510, + 515, + 520, + 525, + 530, + 535, + 540, + 545, + 550, + 555, + 560, + 565, + 570, + 575, + 580, + 585, + 590, + 595, + 600, + 605, + 610, + 615, + 620, + 625, + 630, + 635, + 640, + 645, + 650, + 655, + 660, + 665, + 670, + 675, + 680, + 685, + 690, + 695, + 700, + 705, + 710, + 715, + 720, + 725, + 730, + 735, + 740, + 745, + 750, + 755, + 760, + 765, + 770, + 775, + 780, + 785, + 790, + 795, + 800, + 805, + 810, + 815, + 820, + 825, + 830, + 835, + 840, + 845, + 850, + 855, + 860, + 865, + 870, + 875, + 880, + 885, + 890, + 895, + 900, + 905, + 910, + 915, + 920, + 925, + 930, + 935, + 940, + 945, + 950, + 955, + 960, + 965, + 970, + 975, + 980, + 985, + 990, + 995, + 1000, + 1005, + 1010, + 1015, + 1020, + 1025, + 1030, + 1035, + 1040, + 1045, + 1050, + 1055, + 1060, + 1065, + 1070, + 1075, + 1080, + 1085, + 1090, + 1095, + 1100, + 1105, + 1110, + 1115, + 1120, + 1125, + 1130, + 1135, + 1140, + 1145, + 1150, + 1155, + 1160, + 1165, + 1170, + 1175, + 1180, + 1185, + 1190, + 1195, + 1200, + 1205, + 1210, + 1215, + 1220, + 1225, + 1230, + 1235, + 1240, + 1245, + 1250, + 1255, + 1260, + 1265, + 1270, + 1275, + 1280, + 1285, + 1290, + 1295, + 1300, + 1305, + 1310, + 1315, + 1320, + 1325, + 1330, + 1335, + 1340, + 1345, + 1350, + 1355, + 1360, + 1365, + 1370, + 1375, + 1380, + 1385, + 1390, + 1395, + 1400, + 1405, + 1410, + 1415, + 1420, + 1425, + 1430, + 1435, + 1440, + 1445, + 1450, + 1455, + 1460, + 1465, + 1470, + 1475, + 1480, + 1485, + 1490, + 1495, + 1500, + 1505, + 1510, + 1515, + 1520, + 1525, + 1530, + 1535, + 1540, + 1545, + 1550, + 1555, + 1560, + 1565, + 1570, + 1575, + 1580, + 1585, + 1590, + 1595, + 1600, + 1605, + 1610, + 1615, + 1620, + 1625, + 1630, + 1635, + 1640, + 1645, + 1650, + 1655, + 1660, + 1665, + 1670, + 1675, + 1680, + 1685, + 1690, + 1695, + 1700, + 1705, + 1710, + 1715, + 1720, + 1725, + 1730, + 1735, + 1740, + 1745, + 1750, + 1755, + 1760, + 1765, + 1770, + 1775, + 1780, + 1785, + 1790, + 1795, + 1800, + 1805, + 1810, + 1815, + 1820, + 1825, + 1830, + 1835, + 1840, + 1845, + 1850, + 1855, + 1860, + 1865, + 1870, + 1875, + 1880, + 1885, + 1890, + 1895, + 1900, + 1905, + 1910, + 1915, + 1920, + 1925, + 1930, + 1935, + 1940, + 1945, + 1950, + 1955, + 1960, + 1965, + 1970, + 1975, + 1980, + 1985, + 1990, + 1995, + 2000, + 2005, + 2010, + 2015, + 2020, + 2025, + 2030, + 2035, + 2040, + 2045, + 2050, + 2055, + 2060, + 2065, + 2070, + 2075, + 2080, + 2085, + 2090, + 2095, + 2100, + 2105, + 2110, + 2115, + 2120, + 2125, + 2130, + 2135, + 2140, + 2145, + 2150, + 2155, + 2160, + 2165, + 2170, + 2175, + 2180, + 2185, + 2190, + 2195, + 2200, + 2205, + 2210, + 2215, + 2220, + 2225, + 2230, + 2235, + 2240, + 2245, + 2250, + 2255, + 2260, + 2265, + 2270, + 2275, + 2280, + 2285, + 2290, + 2295, + 2300, + 2305, + 2310, + 2315, + 2320, + 2325, + 2330, + 2335, + 2340, + 2345, + 2350, + 2355, + 2360, + 2365, + 2370, + 2375, + 2380, + 2385, + 2390, + 2395, + 2400, + 2405, + 2410, + 2415, + 2420, + 2425, + 2430, + 2435, + 2440, + 2445, + 2450, + 2455, + 2460, + 2465, + 2470, + 2475, + 2480, + 2485, + 2490, + 2495, + 2500, + 2505, + 2510, + 2515, + 2520, + 2525, + 2530, + 2535, + 2540, + 2545, + 2550, + 2555, + 2560, + 2565, + 2570, + 2575, + 2580, + 2585, + 2590, + 2595, + 2600, + 2605, + 2610, + 2615, + 2620, + 2625, + 2630, + 2635, + 2640, + 2645, + 2650, + 2655, + 2660, + 2665, + 2670, + 2675, + 2680, + 2685, + 2690, + 2695, + 2700, + 2705, + 2710, + 2715, + 2720, + 2725, + 2730, + 2735, + 2740, + 2745, + 2750, + 2755, + 2760, + 2765, + 2770, + 2775, + 2780, + 2785, + 2790, + 2795, + 2800, + 2805, + 2810, + 2815, + 2820, + 2825, + 2830, + 2835, + 2840, + 2845, + 2850, + 2855, + 2860, + 2865, + 2870, + 2875, + 2880, + 2885, + 2890, + 2895, + 2900, + 2905, + 2910, + 2915, + 2920, + 2925, + 2930, + 2935, + 2940, + 2945, + 2950, + 2955, + 2960, + 2965, + 2970, + 2975, + 2980, + 2985, + 2990, + 2995, + 3000, + 3005, + 3010, + 3015, + 3020, + 3025, + 3030, + 3035, + 3040, + 3045, + 3050, + 3055, + 3060, + 3065, + 3070, + 3075, + 3080, + 3085, + 3090, + 3095, + 3100, + 3105, + 3110, + 3115, + 3120, + 3125, + 3130, + 3135, + 3140, + 3145, + 3150, + 3155, + 3160, + 3165, + 3170, + 3175, + 3180, + 3185, + 3190, + 3195, + 3200, + 3205, + 3210, + 3215, + 3220, + 3225, + 3230, + 3235, + 3240, + 3245, + 3250, + 3255, + 3260, + 3265, + 3270, + 3275, + 3280, + 3285, + 3290, + 3295, + 3300, + 3305, + 3310, + 3315, + 3320, + 3325, + 3330, + 3335, + 3340, + 3345, + 3350, + 3355, + 3360, + 3365, + 3370, + 3375, + 3380, + 3385, + 3390, + 3395, + 3400, + 3405, + 3410, + 3415, + 3420, + 3425, + 3430, + 3435, + 3440, + 3445, + 3450, + 3455, + 3460, + 3465, + 3470, + 3475, + 3480, + 3485, + 3490, + 3495, + 3500, + 3505, + 3510, + 3510.522507468857 + ], + "y": [ + 4.051091197755109, + 4.026475108438385, + 4.008477230182524, + 3.994743960024916, + 3.9838543280120633, + 3.9749913244469983, + 3.9676532382673617, + 3.9615083809432377, + 3.9563232224458926, + 3.951925843627623, + 3.948184747176896, + 3.944995727609847, + 3.942273785922641, + 3.939948635878476, + 3.937961382079423, + 3.936261890108397, + 3.934807038436865, + 3.933559012260305, + 3.9324851327226193, + 3.931556777388467, + 3.9307488615214665, + 3.930039338828893, + 3.9294086705095816, + 3.9288396300260153, + 3.928316953040113, + 3.927827287088335, + 3.927358907257412, + 3.926901554605048, + 3.926446275028168, + 3.925985271887887, + 3.925511816401267, + 3.925020127680449, + 3.924505306614829, + 3.923963235167639, + 3.92339049602856, + 3.922784301368551, + 3.92214242468456, + 3.921463149377828, + 3.920745212041869, + 3.919987756314304, + 3.9191902863636656, + 3.9183526240114017, + 3.91747487089897, + 3.9165573733152192, + 3.915600692297605, + 3.914605573809794, + 3.913572923313997, + 3.9125037831662377, + 3.911399310270373, + 3.9102607556047166, + 3.9090894459581422, + 3.907886767570613, + 3.9066541544107505, + 3.9053930749232113, + 3.9041050217496687, + 3.902791498765284, + 3.9014540120117593, + 3.900094062228471, + 3.898713139278162, + 3.897312716992423, + 3.895894245743106, + 3.894459148584555, + 3.8930088156677343, + 3.891544603279242, + 3.890067830266237, + 3.8885797757484504, + 3.8870816803782287, + 3.88557474089635, + 3.884060108999762, + 3.8825388980826334, + 3.881012166605889, + 3.8794809390568865, + 3.877946178699285, + 3.876408816563815, + 3.874869745029061, + 3.873329814907405, + 3.871789812202043, + 3.8702504832112647, + 3.8687125655143606, + 3.8671767461867, + 3.865643662651416, + 3.8641138779356594, + 3.862587984105185, + 3.861066515208374, + 3.859549972965006, + 3.858038757021709, + 3.856533326009225, + 3.855034079108866, + 3.8535413880321694, + 3.8520555988992906, + 3.85057703381059, + 3.849105979973825, + 3.8476426021317303, + 3.8461872023175623, + 3.844739998262977, + 3.84330118798268, + 3.84187095100722, + 3.8404494495742183, + 3.839036803109904, + 3.837633047858334, + 3.83623833876022, + 3.8348527571203497, + 3.833476369163409, + 3.8321092268344943, + 3.830751368565041, + 3.829402806176272, + 3.8280635288487503, + 3.826733548590174, + 3.825412849161585, + 3.824101403107537, + 3.822799172278868, + 3.821506108327485, + 3.820222167080443, + 3.8189472934050097, + 3.817681406105694, + 3.8164244260533033, + 3.8151762667582303, + 3.813936834750651, + 3.8127060299372175, + 3.8114837495043346, + 3.81027054905092, + 3.8090652828279663, + 3.807868089955092, + 3.806678856713983, + 3.805497534088226, + 3.804323997614932, + 3.803158151099869, + 3.801999650606534, + 3.8008484387023658, + 3.7997044962828057, + 3.798567705214392, + 3.797437943275455, + 3.796315084344113, + 3.7951989985711463, + 3.794088996867595, + 3.7929853416497026, + 3.791887908309829, + 3.7907965552699583, + 3.78971113776844, + 3.788631507942738, + 3.7875573787766825, + 3.786488252006753, + 3.785424306903648, + 3.784365385273782, + 3.783311325912911, + 3.782261964601563, + 3.7812171340859497, + 3.780176392493644, + 3.779139509198147, + 3.778106504048643, + 3.777077198194828, + 3.77605140931841, + 3.775028951519508, + 3.774009635186179, + 3.7729928860143462, + 3.7719787021371074, + 3.770966949011369, + 3.769957421066427, + 3.7689499079884023, + 3.7679441944751497, + 3.7669400162932023, + 3.765936810120639, + 3.764934619510436, + 3.7639332065540065, + 3.762932326696258, + 3.761931728350295, + 3.760931152486282, + 3.759930195333132, + 3.758928452229471, + 3.757925811117531, + 3.7569219784313623, + 3.7559166506091968, + 3.7549095135169104, + 3.7539002418439975, + 3.752888281796543, + 3.7518733326775338, + 3.750855114448382, + 3.7498332501356177, + 3.7488073481150743, + 3.747777001374497, + 3.746741786765226, + 3.745700977649681, + 3.7446543206509846, + 3.743601344306701, + 3.742541552814826, + 3.741474430497341, + 3.740399441150352, + 3.7393159633105344, + 3.738223260991708, + 3.737120883455387, + 3.7360082066211655, + 3.734884583843864, + 3.7337493459344744, + 3.732601801386736, + 3.7314411097545257, + 3.730266510446479, + 3.729077336385026, + 3.7278728136012673, + 3.7266521512996142, + 3.725414544153301, + 3.7241591751054663, + 3.722885033362144, + 3.7215913832968206, + 3.720277424876117, + 3.7189423329676337, + 3.7175852938632454, + 3.716205512017186, + 3.7148021941032567, + 3.713374434277096, + 3.711921675709079, + 3.710443276687608, + 3.708938658096601, + 3.7074073141188975, + 3.705848823306803, + 3.704262785403982, + 3.7026489130296993, + 3.701007194809328, + 3.699337657639283, + 3.69764046691591, + 3.69591593538358, + 3.69416453064445, + 3.6923867580814673, + 3.690583438783865, + 3.688755576600643, + 3.686904295725777, + 3.68503088266543, + 3.6831367801549986, + 3.681223578288515, + 3.679292844367936, + 3.677346528980446, + 3.675386581846091, + 3.673415036909972, + 3.6714339936213336, + 3.6694455951366183, + 3.667452005719403, + 3.665455387859761, + 3.6634578796457022, + 3.661461572908639, + 3.659468493270011, + 3.6574808301781303, + 3.655500141026384, + 3.653528020671549, + 3.651566090477876, + 3.64961591970504, + 3.64767874777366, + 3.645755738233628, + 3.643847926633869, + 3.641956175838086, + 3.6400812044743103, + 3.6382235792075512, + 3.636383729905451, + 3.63456201156556, + 3.632758638178245, + 3.630973719334009, + 3.6292072706146543, + 3.62745922416492, + 3.62572943293978, + 3.624017597023729, + 3.6223235370089006, + 3.620646953545162, + 3.618987512818841, + 3.6173448546654017, + 3.615718599959673, + 3.614108357261962, + 3.6125136404784928, + 3.6109340876597806, + 3.609369325838584, + 3.6078189662453033, + 3.606282630270269, + 3.604759952019108, + 3.603250580329514, + 3.6017541301979135, + 3.6002702598964644, + 3.598798717886237, + 3.5973392233627743, + 3.595891514048498, + 3.59445534601216, + 3.5930304932765877, + 3.5916167256893132, + 3.59021375777888, + 3.588821495027339, + 3.5874397758059207, + 3.5860684525048763, + 3.584707390518293, + 3.5833564672043288, + 3.5820155708364867, + 3.5806845995590013, + 3.579363460357595, + 3.5780520680548618, + 3.5767503443379676, + 3.5754582168247135, + 3.5741756181729234, + 3.5729024852367215, + 3.5716387582723956, + 3.5703843786717067, + 3.569139197397881, + 3.567903239965505, + 3.5666764526754458, + 3.5654587820698236, + 3.564250174448393, + 3.5630505754340014, + 3.5618599295855256, + 3.5606781800562737, + 3.5595052682959345, + 3.558341133793797, + 3.5571857138610103, + 3.556038943449582, + 3.5549007550057468, + 3.5537710783553624, + 3.552649840619015, + 3.551536966154549, + 3.5504323653972203, + 3.549335964261777, + 3.5482476804307517, + 3.5471674270219764, + 3.5460951144407016, + 3.5450306504415687, + 3.5439739402037516, + 3.542924886417629, + 3.54188338938139, + 3.540849347106075, + 3.539822655427651, + 3.5388032081248264, + 3.537790897041368, + 3.53678561221188, + 3.535787241989854, + 3.534795673177249, + 3.533810807152796, + 3.532832522743972, + 3.5318606962228953, + 3.5308952096451365, + 3.529935944152046, + 3.5289827800934086, + 3.5280355971470025, + 3.5270942744345337, + 3.5261586906337223, + 3.5252287240861824, + 3.5243042529008446, + 3.5233851550527304, + 3.522471308476922, + 3.5215625911575374, + 3.5206588812116895, + 3.5197600569683063, + 3.518866008856703, + 3.5179766183813097, + 3.5170917550793694, + 3.5162112990482166, + 3.515335130909995, + 3.514463131859937, + 3.513595183709622, + 3.512731168925286, + 3.5118709706613815, + 3.511014472789345, + 3.5101615599217624, + 3.5093121174320796, + 3.5084660314698612, + 3.507623188971874, + 3.506783477668947, + 3.5059468180895785, + 3.505113070808307, + 3.5042821130253867, + 3.503453839714827, + 3.502628155560913, + 3.5018049461217235, + 3.5009841054208373, + 3.500165530277254, + 3.499349115100144, + 3.4985347554550756, + 3.4977223480154103, + 3.496911790045252, + 3.4961029793646645, + 3.4952958143124095, + 3.494490183046301, + 3.493685963193977, + 3.4928830832865994, + 3.492081443342534, + 3.491280943677112, + 3.4904814848525296, + 3.4896829676259076, + 3.488885292895574, + 3.488088361645684, + 3.487292074889229, + 3.486496333609527, + 3.4857010387002414, + 3.484906090904042, + 3.484111390749972, + 3.483316838489538, + 3.4825223340317217, + 3.481727776876827, + 3.4809330660494093, + 3.4801381000301843, + 3.4793427766871985, + 3.4785469932061286, + 3.4777506460199876, + 3.4769535985941307, + 3.4761557414408126, + 3.4753569991425586, + 3.474557264427684, + 3.4737564289118295, + 3.4729543830256997, + 3.47215101594281, + 3.47134621550744, + 3.4705398681629087, + 3.4697318588802983, + 3.4689220710878637, + 3.4681103866012, + 3.4672966855544183, + 3.46648084633252, + 3.465662745505131, + 3.464842257761884, + 3.4640192558496175, + 3.463193610511731, + 3.4623651904298556, + 3.4615338621682414, + 3.4606994901210815, + 3.4598619364631267, + 3.459021017770725, + 3.458176615144849, + 3.4573285985856432, + 3.4564768209831165, + 3.4556211328223383, + 3.4547613821617738, + 3.453897414617772, + 3.4530290733556592, + 3.4521561990879936, + 3.451278630080486, + 3.4503962021661847, + 3.4495087487685057, + 3.448616100933651, + 3.447718087373124, + 3.446814534516931, + 3.445905266578167, + 3.4449901056296217, + 3.4440688716931342, + 3.443141382842379, + 3.4422074553197946, + 3.4412669036684034, + 3.440319540879151, + 3.439365132738992, + 3.4384035302951923, + 3.437434544014805, + 3.436457982493587, + 3.4354736537702832, + 3.434481365582195, + 3.433480925640874, + 3.432472141928711, + 3.4314548230167956, + 3.430428778404429, + 3.429393818880761, + 3.4283497569087378, + 3.4272964070315592, + 3.426233586301763, + 3.425161114732811, + 3.424078815773117, + 3.4229865168021365, + 3.421884049648113, + 3.4207712511268893, + 3.4196479636009283, + 3.418514035557666, + 3.4173693168017603, + 3.4162136537020302, + 3.4150469354587796, + 3.413869041184869, + 3.4126798592517784, + 3.411479287952255, + 3.410267236169707, + 3.409043624051654, + 3.4078083836842747, + 3.406561459764918, + 3.405302810269166, + 3.4040324071088595, + 3.402750236777333, + 3.4014563009777765, + 3.400150617230701, + 3.398833219456096, + 3.3975041585259453, + 3.396163502782571, + 3.39481133780715, + 3.393447766242977, + 3.392072909628145, + 3.390686911461197, + 3.3892899365425797, + 3.3878821635541785, + 3.386463793818072, + 3.3850350485011735, + 3.383596168626729, + 3.3821474150101456, + 3.380689068116281, + 3.3792214278358483, + 3.377744812537824, + 3.3762595581598513, + 3.3747660228482967, + 3.373264580287283, + 3.3717556212071345, + 3.370239552654385, + 3.3687167971794914, + 3.3671877919443203, + 3.36565298775243, + 3.3641128480057008, + 3.362567847591306, + 3.361018471703969, + 3.359465214608614, + 3.3579085783493814, + 3.3563490714111524, + 3.354787207340347, + 3.35322350333206, + 3.351658478790755, + 3.3500926538722116, + 3.3485265480142403, + 3.3469606741490447, + 3.345395535521542, + 3.3438316543043887, + 3.3422695324177267, + 3.3407096638191893, + 3.3391525331271783, + 3.3375986142843015, + 3.336048369266992, + 3.3345022468468613, + 3.332960681408968, + 3.331424091831286, + 3.3298928804292927, + 3.3283674319687915, + 3.3268481127495177, + 3.325335269761191, + 3.3238292299133545, + 3.3223302993391575, + 3.32083876277302, + 3.319354883001166, + 3.317878900383496, + 3.3164110324446137, + 3.314951473531292, + 3.3135003945330204, + 3.3120579426619097, + 3.310624241287626, + 3.3091993898227643, + 3.307783463653505, + 3.306376514110241, + 3.3049785684724733, + 3.3035896300020595, + 3.302209677998705, + 3.300838667871357, + 3.29947653121914, + 3.298123175915253, + 3.2967784861872893, + 3.2954423226873084, + 3.2941145225450295, + 3.2927948993974967, + 3.291483243388616, + 3.290179300844195, + 3.288882831898938, + 3.2875935578187336, + 3.2863111739368027, + 3.285035351410079, + 3.2837657369016027, + 3.2825019521880026, + 3.2812435936859425, + 3.2799902318915923, + 3.278741410727174, + 3.2774966467888813, + 3.276255428490454, + 3.275017215096959, + 3.2737814356433996, + 3.272547487733064, + 3.2713147362106936, + 3.2700825117058967, + 3.2688501090425017, + 3.2676167855101235, + 3.2663817589945596, + 3.265144205964376, + 3.2639032593117134, + 3.262658006046384, + 3.261407484843172, + 3.2601506834438103, + 3.2588865359163943, + 3.257613919776889, + 3.2563316529794983, + 3.255038490784942, + 3.2537331225187915, + 3.252414168234902, + 3.2510801753030725, + 3.2497296149441044, + 3.248360878740259, + 3.246972275154833, + 3.2455620261003344, + 3.2441282636018673, + 3.242669026609765, + 3.241182256769195, + 3.239665797926234, + 3.2381173938485084, + 3.2365346846230834, + 3.234915206080872, + 3.2332563891572264, + 3.2315555600522883, + 3.2298099413292873, + 3.228016654100678, + 3.2261727214628637, + 3.2242750739602313, + 3.2223205542316817, + 3.2203059267871152, + 3.2182278883766293, + 3.2160830802221567, + 3.2138681010291426, + 3.2115795261840336, + 3.2092139268908633, + 3.2067678927734495, + 3.2042380573190137, + 3.2016211261933103, + 3.198913908397262, + 3.196113350163349, + 3.1932165714062855, + 3.190220904447609, + 3.187123934628521, + 3.183923542311989, + 3.1806179456561554, + 3.177205743420512, + 3.1736859569486833, + 3.170058070362576, + 3.166322064855059, + 3.1624784608556338, + 3.1585283380342344, + 3.1544733594039984, + 3.150315785936714, + 3.146058482389281, + 3.141704913632553, + 3.1372591307225486, + 3.132725746181483, + 3.128109898226134, + 3.1234172039855896, + 3.1186537020771947, + 3.11382578524601, + 3.108940124102552, + 3.104003583300486, + 3.0990231317637873, + 3.0940057487874557, + 3.088958327984548, + 3.0838875811272164, + 3.078799943925715, + 3.0737014857074643, + 3.068597824802668, + 3.063494051222941, + 3.0583946579467725, + 3.0533034818154463, + 3.0482236547113013, + 3.0431575653533103, + 3.0381068317181903, + 3.033072283792399, + 3.0280539560924873, + 3.0230510891662874, + 3.018062139110873, + 3.01308479401631, + 3.0081159961670028, + 3.0031519688011254, + 2.99818824623844, + 2.993219706231952, + 2.988240603471948, + 2.9832446032652142, + 2.978224814520922, + 2.9731738212912053, + 2.968083712233682, + 2.96294610748013, + 2.9577521825067516, + 2.9524926887042353, + 2.9471579704381172, + 2.9417379784707047, + 2.9362222796848605, + 2.9306000631068825, + 2.9248601422714695, + 2.918990954006901, + 2.9129805500974904, + 2.90681659862296, + 2.900486366186482, + 2.8939767029821564, + 2.887274026805922, + 2.880364302902069, + 2.8732330210943173, + 2.865865170306786, + 2.8582452105663556, + 2.8503570425630795, + 2.842183974829324, + 2.833708688581958, + 2.8249132002552466, + 2.8157788217355195, + 2.806286118291993, + 2.7964148641817967, + 2.7861439958911416, + 2.775451562958369, + 2.7643146763089894, + 2.752709454016846, + 2.7406109643896723, + 2.7279931662612316, + 2.714828846355646, + 2.7010895535721993, + 2.6867455300209717, + 2.671765638619922, + 2.656117287043286, + 2.639766347787585, + 2.6226770740957828, + 2.6048120114503917, + 2.586131904312632, + 2.5665955977449313, + 2.5461599335074667, + 2.524779640163713, + 2.5024072166621973, + 2.500010012082775 + ] + }, + { + "line": { + "width": 4 + }, + "mode": "lines", + "name": "Optimised", + "type": "scatter", + "x": [ + 0, + 5, + 10, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 65, + 70, + 75, + 80, + 85, + 90, + 95, + 100, + 105, + 110, + 115, + 120, + 125, + 130, + 135, + 140, + 145, + 150, + 155, + 160, + 165, + 170, + 175, + 180, + 185, + 190, + 195, + 200, + 205, + 210, + 215, + 220, + 225, + 230, + 235, + 240, + 245, + 250, + 255, + 260, + 265, + 270, + 275, + 280, + 285, + 290, + 295, + 300, + 305, + 310, + 315, + 320, + 325, + 330, + 335, + 340, + 345, + 350, + 355, + 360, + 365, + 370, + 375, + 380, + 385, + 390, + 395, + 400, + 405, + 410, + 415, + 420, + 425, + 430, + 435, + 440, + 445, + 450, + 455, + 460, + 465, + 470, + 475, + 480, + 485, + 490, + 495, + 500, + 505, + 510, + 515, + 520, + 525, + 530, + 535, + 540, + 545, + 550, + 555, + 560, + 565, + 570, + 575, + 580, + 585, + 590, + 595, + 600, + 605, + 610, + 615, + 620, + 625, + 630, + 635, + 640, + 645, + 650, + 655, + 660, + 665, + 670, + 675, + 680, + 685, + 690, + 695, + 700, + 705, + 710, + 715, + 720, + 725, + 730, + 735, + 740, + 745, + 750, + 755, + 760, + 765, + 770, + 775, + 780, + 785, + 790, + 795, + 800, + 805, + 810, + 815, + 820, + 825, + 830, + 835, + 840, + 845, + 850, + 855, + 860, + 865, + 870, + 875, + 880, + 885, + 890, + 895, + 900, + 905, + 910, + 915, + 920, + 925, + 930, + 935, + 940, + 945, + 950, + 955, + 960, + 965, + 970, + 975, + 980, + 985, + 990, + 995, + 1000, + 1005, + 1010, + 1015, + 1020, + 1025, + 1030, + 1035, + 1040, + 1045, + 1050, + 1055, + 1060, + 1065, + 1070, + 1075, + 1080, + 1085, + 1090, + 1095, + 1100, + 1105, + 1110, + 1115, + 1120, + 1125, + 1130, + 1135, + 1140, + 1145, + 1150, + 1155, + 1160, + 1165, + 1170, + 1175, + 1180, + 1185, + 1190, + 1195, + 1200, + 1205, + 1210, + 1215, + 1220, + 1225, + 1230, + 1235, + 1240, + 1245, + 1250, + 1255, + 1260, + 1265, + 1270, + 1275, + 1280, + 1285, + 1290, + 1295, + 1300, + 1305, + 1310, + 1315, + 1320, + 1325, + 1330, + 1335, + 1340, + 1345, + 1350, + 1355, + 1360, + 1365, + 1370, + 1375, + 1380, + 1385, + 1390, + 1395, + 1400, + 1405, + 1410, + 1415, + 1420, + 1425, + 1430, + 1435, + 1440, + 1445, + 1450, + 1455, + 1460, + 1465, + 1470, + 1475, + 1480, + 1485, + 1490, + 1495, + 1500, + 1505, + 1510, + 1515, + 1520, + 1525, + 1530, + 1535, + 1540, + 1545, + 1550, + 1555, + 1560, + 1565, + 1570, + 1575, + 1580, + 1585, + 1590, + 1595, + 1600, + 1605, + 1610, + 1615, + 1620, + 1625, + 1630, + 1635, + 1640, + 1645, + 1650, + 1655, + 1660, + 1665, + 1670, + 1675, + 1680, + 1685, + 1690, + 1695, + 1700, + 1705, + 1710, + 1715, + 1720, + 1725, + 1730, + 1735, + 1740, + 1745, + 1750, + 1755, + 1760, + 1765, + 1770, + 1775, + 1780, + 1785, + 1790, + 1795, + 1800, + 1805, + 1810, + 1815, + 1820, + 1825, + 1830, + 1835, + 1840, + 1845, + 1850, + 1855, + 1860, + 1865, + 1870, + 1875, + 1880, + 1885, + 1890, + 1895, + 1900, + 1905, + 1910, + 1915, + 1920, + 1925, + 1930, + 1935, + 1940, + 1945, + 1950, + 1955, + 1960, + 1965, + 1970, + 1975, + 1980, + 1985, + 1990, + 1995, + 2000, + 2005, + 2010, + 2015, + 2020, + 2025, + 2030, + 2035, + 2040, + 2045, + 2050, + 2055, + 2060, + 2065, + 2070, + 2075, + 2080, + 2085, + 2090, + 2095, + 2100, + 2105, + 2110, + 2115, + 2120, + 2125, + 2130, + 2135, + 2140, + 2145, + 2150, + 2155, + 2160, + 2165, + 2170, + 2175, + 2180, + 2185, + 2190, + 2195, + 2200, + 2205, + 2210, + 2215, + 2220, + 2225, + 2230, + 2235, + 2240, + 2245, + 2250, + 2255, + 2260, + 2265, + 2270, + 2275, + 2280, + 2285, + 2290, + 2295, + 2300, + 2305, + 2310, + 2315, + 2320, + 2325, + 2330, + 2335, + 2340, + 2345, + 2350, + 2355, + 2360, + 2365, + 2370, + 2375, + 2380, + 2385, + 2390, + 2395, + 2400, + 2405, + 2410, + 2415, + 2420, + 2425, + 2430, + 2435, + 2440, + 2445, + 2450, + 2455, + 2460, + 2465, + 2470, + 2475, + 2480, + 2485, + 2490, + 2495, + 2500, + 2505, + 2510, + 2515, + 2520, + 2525, + 2530, + 2535, + 2540, + 2545, + 2550, + 2555, + 2560, + 2565, + 2570, + 2575, + 2580, + 2585, + 2590, + 2595, + 2600, + 2605, + 2610, + 2615, + 2620, + 2625, + 2630, + 2635, + 2640, + 2645, + 2650, + 2655, + 2660, + 2665, + 2670, + 2675, + 2680, + 2685, + 2690, + 2695, + 2700, + 2705, + 2710, + 2715, + 2720, + 2725, + 2730, + 2735, + 2740, + 2745, + 2750, + 2755, + 2760, + 2765, + 2770, + 2775, + 2780, + 2785, + 2790, + 2795, + 2800, + 2805, + 2810, + 2815, + 2820, + 2825, + 2830, + 2835, + 2840, + 2845, + 2850, + 2855, + 2860, + 2865, + 2870, + 2875, + 2880, + 2885, + 2890, + 2895, + 2900, + 2905, + 2910, + 2915, + 2920, + 2925, + 2930, + 2935, + 2940, + 2945, + 2950, + 2955, + 2960, + 2965, + 2970, + 2975, + 2980, + 2985, + 2990, + 2995, + 3000, + 3005, + 3010, + 3015, + 3020, + 3025, + 3030, + 3035, + 3040, + 3045, + 3050, + 3055, + 3060, + 3065, + 3070, + 3075, + 3080, + 3085, + 3090, + 3095, + 3100, + 3105, + 3110, + 3115, + 3120, + 3125, + 3130, + 3135, + 3140, + 3145, + 3150, + 3155, + 3160, + 3165, + 3170, + 3175, + 3180, + 3185, + 3190, + 3195, + 3200, + 3205, + 3210, + 3215, + 3220, + 3225, + 3230, + 3235, + 3240, + 3245, + 3250, + 3255, + 3260, + 3265, + 3270, + 3275, + 3280, + 3285, + 3290, + 3295, + 3300, + 3305, + 3310, + 3315, + 3320, + 3325, + 3330, + 3335, + 3340, + 3345, + 3350, + 3355, + 3360, + 3365, + 3370, + 3375, + 3380, + 3385, + 3390, + 3395, + 3400, + 3405, + 3410, + 3415, + 3420, + 3425, + 3430, + 3435, + 3440, + 3445, + 3450, + 3455, + 3460, + 3465, + 3470, + 3475, + 3480, + 3485, + 3490, + 3495, + 3500, + 3505, + 3510, + 3510.522507468857 + ], + "y": [ + 4.060121657725171, + 4.0440965898480234, + 4.034825220624699, + 4.027436103919198, + 4.021132752959295, + 4.015595269139246, + 4.010647681438589, + 4.006174799709503, + 4.002094768861892, + 3.998347074323662, + 3.9948853366063815, + 3.9916729580444783, + 3.9886802459644817, + 3.985883029601075, + 3.9832614994413897, + 3.9807991503933695, + 3.9784820332352857, + 3.976297854103046, + 3.974236297118218, + 3.9722884737746544, + 3.970446712898164, + 3.968704347164096, + 3.9670553548907352, + 3.9654943707384778, + 3.964016507779917, + 3.96261744862915, + 3.961293301681543, + 3.9600405089437065, + 3.958855801336466, + 3.9577361122125327, + 3.956678591942213, + 3.955680562433091, + 3.954739506519783, + 3.9538530347726586, + 3.9530188544063942, + 3.952234755735694, + 3.9514985933259856, + 3.950808283611841, + 3.9501617899653247, + 3.949557114319111, + 3.9489922884049142, + 3.948465366622288, + 3.947974421905812, + 3.947517540393611, + 3.9470928202123545, + 3.946698367815674, + 3.946332298211953, + 3.945992733934509, + 3.945677805276896, + 3.945385648691732, + 3.945114407719662, + 3.9448622339508623, + 3.9446272914917886, + 3.944407758400042, + 3.944201827948562, + 3.9440077096668142, + 3.943823631157972, + 3.943647843300595, + 3.943478622048449, + 3.943314272947128, + 3.943153130836272, + 3.9429935633959983, + 3.9428339737979847, + 3.942672804127088, + 3.9425085366645343, + 3.942339699370915, + 3.942164865191379, + 3.941982654085342, + 3.941791738716668, + 3.941590841160643, + 3.941378737499459, + 3.941154258716942, + 3.940916288406615, + 3.9406637749113074, + 3.940395724650167, + 3.940111202827605, + 3.9398093176995705, + 3.93948926309745, + 3.939150285984352, + 3.9387916951817954, + 3.938412838669659, + 3.938013146622299, + 3.93759210693792, + 3.937149264550323, + 3.936684209814037, + 3.9361965932826015, + 3.935686133995041, + 3.9351526001027066, + 3.9345958139866535, + 3.934015651009173, + 3.933412038173378, + 3.9327849171109097, + 3.932134316439588, + 3.931460305216995, + 3.930762991655308, + 3.930042526289108, + 3.9292991001737, + 3.928532939789437, + 3.927744270194291, + 3.9269334077135336, + 3.926100677767375, + 3.925246435463019, + 3.9243710636099864, + 3.9234749707481313, + 3.922558585062612, + 3.9216223516923665, + 3.92066674784931, + 3.919692262768464, + 3.918699401469542, + 3.9176886829399726, + 3.9166606383645286, + 3.915615816645838, + 3.9145547721293026, + 3.913478061410871, + 3.9123862506419886, + 3.9112799105512432, + 3.9101596150347446, + 3.90902593980653, + 3.907879463882322, + 3.906720768788076, + 3.90555043419629, + 3.904369029854372, + 3.9031771237889714, + 3.9019752823937175, + 3.9007640688691607, + 3.8995440300744737, + 3.898315711274881, + 3.8970796496879654, + 3.895836373793419, + 3.8945864026944177, + 3.8933302455288783, + 3.89206840092864, + 3.890801356524716, + 3.889529588496475, + 3.88825356116287, + 3.886973726613334, + 3.8856905243764617, + 3.884404381535138, + 3.883115714640332, + 3.881824920490164, + 3.8805323857296368, + 3.879238483273564, + 3.8779435721545426, + 3.876647997393039, + 3.8753520898872713, + 3.874056166320722, + 3.872760529085063, + 3.871465466216278, + 3.8701712513418514, + 3.8688781436367994, + 3.867586387786421, + 3.8662962139536647, + 3.865007837748932, + 3.863721460200294, + 3.86243726772195, + 3.861155432079, + 3.8598761103463217, + 3.858599444859667, + 3.857325563156892, + 3.856054577907393, + 3.8547865880092687, + 3.853521675140205, + 3.852259906592461, + 3.8510013345516465, + 3.849745995737716, + 3.848493911223823, + 3.847245086230678, + 3.845999509894802, + 3.8447571550092743, + 3.843517977735744, + 3.842281917286528, + 3.84104889557604, + 3.839818816840773, + 3.838591567227613, + 3.837367014350412, + 3.836145006815423, + 3.834925373716293, + 3.8337079241003913, + 3.832492446408417, + 3.8312787078904127, + 3.8300664540019858, + 3.8288554077854937, + 3.82764526924246, + 3.8264357147043304, + 3.825226396210623, + 3.824016940904831, + 3.8228069504605537, + 3.821596000552264, + 3.8203836403873863, + 3.819169392318824, + 3.817952751559759, + 3.816733186025321, + 3.8155101363286623, + 3.8142830159621823, + 3.8130512116975823, + 3.811814084241704, + 3.8105709691881136, + 3.809321178306893, + 3.808064001217936, + 3.806798707494524, + 3.805524549297614, + 3.8042407645279015, + 3.80294658006389, + 3.801641216609067, + 3.800323893450274, + 3.7989938341069824, + 3.797650272696485, + 3.796292461027734, + 3.7949196764220727, + 3.7935312302411943, + 3.792126477082108, + 3.790704824574627, + 3.789265743690617, + 3.787808779444662, + 3.7863335618357694, + 3.784839816847797, + 3.7833273772958527, + 3.781796193276985, + 3.7802463419582577, + 3.778678036415928, + 3.7770916332268953, + 3.775487638511052, + 3.773866712130813, + 3.7722296697745423, + 3.7705774826839673, + 3.768911274832016, + 3.767232317417256, + 3.765542020611115, + 3.763841922574203, + 3.762133675842943, + 3.7604190312757577, + 3.758699819833409, + 3.756977932547074, + 3.7552552990962496, + 3.7535338654720247, + 3.75181557123721, + 3.7501023269107647, + 3.748395991999147, + 3.746698354171488, + 3.7450111101047416, + 3.743335848025119, + 3.7416740329885063, + 3.740026994423559, + 3.738395916427101, + 3.7367818307865783, + 3.7351856127856617, + 3.733607979598049, + 3.7320494911598785, + 3.7305105532926257, + 3.7289914228192713, + 3.727492214389555, + 3.726012908715474, + 3.7245533619158344, + 3.7231133156758616, + 3.721692407943994, + 3.720290183910288, + 3.7189061070380207, + 3.717539569949978, + 3.716189905002093, + 3.7148563944084705, + 3.7135382798114818, + 3.712234771219012, + 3.7109450552561265, + 3.7096683027009463, + 3.70840367529395, + 3.707150331826182, + 3.7059074335248368, + 3.704674148765394, + 3.7034496571469546, + 3.702233152973122, + 3.701023848184212, + 3.69982097478844, + 3.698623786840248, + 3.697431562013152, + 3.696243602813127, + 3.695059237476307, + 3.693877820592131, + 3.692698733493261, + 3.691521384432397, + 3.690345208606936, + 3.6891696680329553, + 3.687994251306236, + 3.6868184732717304, + 3.6856418746211577, + 3.6844640214360247, + 3.683284504691197, + 3.682102939731703, + 3.680918965733599, + 3.679732245157803, + 3.678542463204324, + 3.677349327272715, + 3.676152566433341, + 3.674951930913017, + 3.67374719159745, + 3.67253813955216, + 3.671324585562715, + 3.670106359694619, + 3.668883310872468, + 3.667655306477734, + 3.6664222319639785, + 3.6651839904880967, + 3.663940502555898, + 3.6626917056801673, + 3.6614375540491313, + 3.660178018203255, + 3.6589130847181535, + 3.657642755891324, + 3.656367049430627, + 3.655085998142156, + 3.6537996496154426, + 3.652508065903903, + 3.651211323198576, + 3.649909511493246, + 3.648602734239283, + 3.6472911079885497, + 3.645974762023026, + 3.6446538379698215, + 3.6433284894005418, + 3.641998881414076, + 3.640665190202166, + 3.639327602597143, + 3.6379863156016343, + 3.636641535900045, + 3.635293479351955, + 3.6339423704677234, + 3.632588441866708, + 3.631231933718905, + 3.629873093170719, + 3.6285121737560697, + 3.627149434793852, + 3.625785140773238, + 3.624419560728313, + 3.623052967603612, + 3.621685637612379, + 3.6203178495893473, + 3.6189498843400862, + 3.6175820239887626, + 3.616214551326544, + 3.6148477491626982, + 3.613481899680409, + 3.612117283799607, + 3.610754180548805, + 3.6093928664480366, + 3.608033614904967, + 3.6066766956260614, + 3.60532237404482, + 3.603970910768733, + 3.602622561046742, + 3.601277574258739, + 3.599936193428581, + 3.598598654761868, + 3.59726518720971, + 3.595936012059473, + 3.5946113425533746, + 3.593291383535633, + 3.5919763311287114, + 3.5906663724390486, + 3.5893616852925385, + 3.5880624379998536, + 3.586768789151249, + 3.5854808874411783, + 3.5841988715220525, + 3.5829228698865156, + 3.581653000777371, + 3.580389372125797, + 3.5791320815152186, + 3.5778812161709768, + 3.576636852974426, + 3.575399058500416, + 3.574167889077013, + 3.5729433908661643, + 3.5717255999640036, + 3.570514542519597, + 3.569310234870619, + 3.568112683694738, + 3.5669218861752174, + 3.56573783017944, + 3.5645604944489064, + 3.563389848799458, + 3.5622258543302947, + 3.5610684636404986, + 3.559917621051854, + 3.558773262836721, + 3.55763531744968, + 3.5565037057619606, + 3.5553783412974935, + 3.5542591304695503, + 3.5531459728170605, + 3.5520387612396327, + 3.5509373822305084, + 3.5498417161066005, + 3.548751637234977, + 3.54766701425501, + 3.5465877102957735, + 3.545513583188004, + 3.544444485670259, + 3.5433802655888806, + 3.5423207660911897, + 3.5412658258120757, + 3.5402152790534145, + 3.5391689559561237, + 3.5381266826650055, + 3.5370882814860525, + 3.5360535710363608, + 3.5350223663866314, + 3.533994479196357, + 3.5329697178418216, + 3.5319478875370716, + 3.530928790448129, + 3.5299122258006337, + 3.528897989981254, + 3.527885876633185, + 3.5268756767461196, + 3.52586717874104, + 3.52486016855038, + 3.5238544296938814, + 3.5228497433507657, + 3.5218458884286643, + 3.520842641629975, + 3.519839777516064, + 3.5188370685701114, + 3.517834285259095, + 3.5168311960956897, + 3.515827567700656, + 3.514823164866568, + 3.5138177506234767, + 3.512811086307386, + 3.5118029316322534, + 3.5107930447662925, + 3.509781182413498, + 3.5087670999010996, + 3.5077505512738623, + 3.506731289396084, + 3.5057090660621704, + 3.5046836321165897, + 3.5036547375842395, + 3.5026221318119135, + 3.501585563621958, + 3.500544781478827, + 3.4994995336694936, + 3.4984495684985775, + 3.497394634498943, + 3.496334480658677, + 3.495268856665154, + 3.494197513166962, + 3.493120202054342, + 3.49203667675884, + 3.4909466925726873, + 3.489850006988497, + 3.488746380059551, + 3.4876355747812493, + 3.4865173574936885, + 3.48539149830573, + 3.484257771540422, + 3.483115956201678, + 3.481965836461988, + 3.4808072021706726, + 3.4796398493821137, + 3.4784635809032336, + 3.4772782068591654, + 3.4760835452761025, + 3.4748794226798365, + 3.4736656747084833, + 3.4724421467376088, + 3.4712086945157092, + 3.469965184807773, + 3.4687114960445316, + 3.4674475189745566, + 3.4661731573163848, + 3.4648883284073984, + 3.463592963846131, + 3.4622870101243564, + 3.4609704292452177, + 3.459643199323355, + 3.4583053151629617, + 3.45695678880945, + 3.45559765007038, + 3.4542279470011863, + 3.452847746351145, + 3.4514571339651496, + 3.450056215136754, + 3.448645114908027, + 3.447223978311982, + 3.4457929705534105, + 3.44435227712411, + 3.442902103848932, + 3.441442676859116, + 3.439974242490042, + 3.438497067100566, + 3.437011436811858, + 3.435517657163998, + 3.434016052689069, + 3.4325069664001164, + 3.4309907591959026, + 3.4294678091820225, + 3.4279385109094203, + 3.426403274532248, + 3.424862524887339, + 3.423316700498452, + 3.421766252508956, + 3.4202116435471335, + 3.418653346529114, + 3.4170918434046915, + 3.415527623851971, + 3.4139611839271664, + 3.412393024676287, + 3.410823650715724, + 3.409253568789084, + 3.407683286307746, + 3.406113309882774, + 3.404544143855861, + 3.402976288836866, + 3.4014102402555233, + 3.399846486934615, + 3.3982855096916817, + 3.3967277799760054, + 3.395173758547187, + 3.393623894201262, + 3.392078622549653, + 3.3905383648558733, + 3.389003526934113, + 3.3874744981134444, + 3.3859516502704503, + 3.3844353369326416, + 3.3829258924542644, + 3.381423631265361, + 3.379928847194382, + 3.3784418128638594, + 3.376962779158142, + 3.375491974761414, + 3.374029605763746, + 3.3725758553323115, + 3.3711308834443976, + 3.3696948266782596, + 3.3682677980576208, + 3.3668498869450105, + 3.3654411589788458, + 3.364041656048953, + 3.362651396304688, + 3.3612703741899654, + 3.3598985604988707, + 3.3585359024457526, + 3.357182323743368, + 3.3558377246825577, + 3.3545019822070063, + 3.353174949976488, + 3.351856458411973, + 3.3505463147161088, + 3.349244302862481, + 3.3479501835471503, + 3.3466636940960406, + 3.3453845483217535, + 3.3441124363235, + 3.342847024223917, + 3.3415879538365343, + 3.340334842257856, + 3.339087281378062, + 3.337844837304357, + 3.336607049691237, + 3.335373430971962, + 3.3341434654856306, + 3.332916608494533, + 3.3316922850864517, + 3.3304698889569537, + 3.3292487810668394, + 3.3280282881702825, + 3.3268077012095234, + 3.325586273572458, + 3.324363219209925, + 3.32313771061015, + 3.3219088766287004, + 3.320675800172994, + 3.319437515741699, + 3.318193006820577, + 3.316941203137944, + 3.3156809777845364, + 3.3144111442050064, + 3.3131304530704098, + 3.3118375890441953, + 3.3105311674572104, + 3.3092097309113293, + 3.307871745835316, + 3.306515599021592, + 3.305139594178076, + 3.303741948535313, + 3.302320789556072, + 3.3008741518022378, + 3.2993999740219375, + 3.29789609652923, + 3.2963602589581753, + 3.2947900984838503, + 3.293183148613614, + 3.2915368386636357, + 3.2898484940473107, + 3.288115337513972, + 3.2863344914876964, + 3.284502981666729, + 3.2826177420537244, + 3.2806756215944066, + 3.2786733926079368, + 3.2766077611938664, + 3.274475379798586, + 3.2722728621166812, + 3.2699968004890505, + 3.267643785938526, + 3.2652104309543777, + 3.26269339509799, + 3.2600894134524845, + 3.2573953278783367, + 3.254608120964659, + 3.251724952481813, + 3.248743198045954, + 3.245660489601031, + 3.2424747572112036, + 3.2391842715385692, + 3.235787686262306, + 3.232284079579755, + 3.228672993823676, + 3.224954472138988, + 3.2211290910935215, + 3.217197988057837, + 3.213162882185259, + 3.2090260878612615, + 3.2047905195754556, + 3.200459687302361, + 3.196037681659744, + 3.1915291483420725, + 3.186939251597192, + 3.1822736268174516, + 3.177538322640823, + 3.172739733289606, + 3.1678845221984635, + 3.162979538283564, + 3.158031726465252, + 3.153048034263055, + 3.1480353164231136, + 3.143000239605573, + 3.1379491891496074, + 3.132888179846821, + 3.127822772494949, + 3.122757997782051, + 3.117698288778874, + 3.1126474230087844, + 3.10760847473618, + 3.1025837777818706, + 3.097574898852514, + 3.0925826210741736, + 3.0876069371579633, + 3.0826470514068727, + 3.07770138960108, + 3.0727676156771784, + 3.0678426540430546, + 3.062922716341639, + 3.058003331488832, + 3.0530793778567737, + 3.048145116547339, + 3.0431942247945902, + 3.038219828642671, + 3.0332145341611265, + 3.0281704565771106, + 3.023079246819377, + 3.017932115078509, + 3.012719851088733, + 3.0074328409275113, + 3.002061080208371, + 2.996594183610144, + 2.991021390741576, + 2.985331568385135, + 2.979513209198197, + 2.973554426974769, + 2.9674429485874714, + 2.961166102739063, + 2.9547108056558486, + 2.9480635438537885, + 2.941210354101934, + 2.9341368006988273, + 2.926827950165741, + 2.919268343447117, + 2.911441965693725, + 2.9033322136884294, + 2.894921860958181, + 2.886193020599464, + 2.877127105828041, + 2.8677047882473268, + 2.8579059538136806, + 2.847709656460917, + 2.837094069330381, + 2.826036433537559, + 2.814513004390263, + 2.8024989949580172, + 2.7899685168761525, + 2.7768945182518685, + 2.7632487185224943, + 2.7490015400983188, + 2.7341220366030843, + 2.7185778175045376, + 2.702334968904547, + 2.6853579702324626, + 2.6676096065565793, + 2.649050876194984, + 2.6296408932681192, + 2.6093367847896185, + 2.5880935818368696, + 2.565864104276627 + ] + } + ], + "layout": { + "autosize": false, + "height": 576, + "legend": { + "font": { + "size": 12 + }, + "x": 1, + "xanchor": "right", + "y": 1, + "yanchor": "top" + }, + "margin": { + "b": 10, + "l": 10, + "pad": 4, + "r": 10, + "t": 75 + }, + "showlegend": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Optimised Comparison", + "x": 0.5 + }, + "width": 1024, + "xaxis": { + "tickfont": { + "size": 12 + }, + "title": { + "font": { + "size": 12 + }, + "text": "Time [s]" + } + }, + "yaxis": { + "tickfont": { + "size": 12 + }, + "title": { + "font": { + "size": 12 + }, + "text": "Voltage [V]" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "fill": "toself", + "fillcolor": "rgba(255,229,204,0.8)", + "hoverinfo": "skip", + "line": { + "color": "rgba(255,255,255,0)" + }, + "showlegend": false, + "type": "scatter", + "x": [ + 0, + 5, + 10, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 65, + 70, + 75, + 80, + 85, + 90, + 95, + 100, + 105, + 110, + 115, + 120, + 125, + 130, + 135, + 140, + 145, + 150, + 155, + 160, + 165, + 170, + 175, + 180, + 185, + 190, + 195, + 200, + 205, + 210, + 215, + 220, + 225, + 230, + 235, + 240, + 245, + 250, + 255, + 260, + 265, + 270, + 275, + 280, + 285, + 290, + 295, + 300, + 305, + 310, + 315, + 320, + 325, + 330, + 335, + 340, + 345, + 350, + 355, + 360, + 365, + 370, + 375, + 380, + 385, + 390, + 395, + 400, + 405, + 410, + 415, + 420, + 425, + 430, + 435, + 440, + 445, + 450, + 455, + 460, + 465, + 470, + 475, + 480, + 485, + 490, + 495, + 500, + 505, + 510, + 515, + 520, + 525, + 530, + 535, + 540, + 545, + 550, + 555, + 560, + 565, + 570, + 575, + 580, + 585, + 590, + 595, + 600, + 605, + 610, + 615, + 620, + 625, + 630, + 635, + 640, + 645, + 650, + 655, + 660, + 665, + 670, + 675, + 680, + 685, + 690, + 695, + 700, + 705, + 710, + 715, + 720, + 725, + 730, + 735, + 740, + 745, + 750, + 755, + 760, + 765, + 770, + 775, + 780, + 785, + 790, + 795, + 800, + 805, + 810, + 815, + 820, + 825, + 830, + 835, + 840, + 845, + 850, + 855, + 860, + 865, + 870, + 875, + 880, + 885, + 890, + 895, + 900, + 905, + 910, + 915, + 920, + 925, + 930, + 935, + 940, + 945, + 950, + 955, + 960, + 965, + 970, + 975, + 980, + 985, + 990, + 995, + 1000, + 1005, + 1010, + 1015, + 1020, + 1025, + 1030, + 1035, + 1040, + 1045, + 1050, + 1055, + 1060, + 1065, + 1070, + 1075, + 1080, + 1085, + 1090, + 1095, + 1100, + 1105, + 1110, + 1115, + 1120, + 1125, + 1130, + 1135, + 1140, + 1145, + 1150, + 1155, + 1160, + 1165, + 1170, + 1175, + 1180, + 1185, + 1190, + 1195, + 1200, + 1205, + 1210, + 1215, + 1220, + 1225, + 1230, + 1235, + 1240, + 1245, + 1250, + 1255, + 1260, + 1265, + 1270, + 1275, + 1280, + 1285, + 1290, + 1295, + 1300, + 1305, + 1310, + 1315, + 1320, + 1325, + 1330, + 1335, + 1340, + 1345, + 1350, + 1355, + 1360, + 1365, + 1370, + 1375, + 1380, + 1385, + 1390, + 1395, + 1400, + 1405, + 1410, + 1415, + 1420, + 1425, + 1430, + 1435, + 1440, + 1445, + 1450, + 1455, + 1460, + 1465, + 1470, + 1475, + 1480, + 1485, + 1490, + 1495, + 1500, + 1505, + 1510, + 1515, + 1520, + 1525, + 1530, + 1535, + 1540, + 1545, + 1550, + 1555, + 1560, + 1565, + 1570, + 1575, + 1580, + 1585, + 1590, + 1595, + 1600, + 1605, + 1610, + 1615, + 1620, + 1625, + 1630, + 1635, + 1640, + 1645, + 1650, + 1655, + 1660, + 1665, + 1670, + 1675, + 1680, + 1685, + 1690, + 1695, + 1700, + 1705, + 1710, + 1715, + 1720, + 1725, + 1730, + 1735, + 1740, + 1745, + 1750, + 1755, + 1760, + 1765, + 1770, + 1775, + 1780, + 1785, + 1790, + 1795, + 1800, + 1805, + 1810, + 1815, + 1820, + 1825, + 1830, + 1835, + 1840, + 1845, + 1850, + 1855, + 1860, + 1865, + 1870, + 1875, + 1880, + 1885, + 1890, + 1895, + 1900, + 1905, + 1910, + 1915, + 1920, + 1925, + 1930, + 1935, + 1940, + 1945, + 1950, + 1955, + 1960, + 1965, + 1970, + 1975, + 1980, + 1985, + 1990, + 1995, + 2000, + 2005, + 2010, + 2015, + 2020, + 2025, + 2030, + 2035, + 2040, + 2045, + 2050, + 2055, + 2060, + 2065, + 2070, + 2075, + 2080, + 2085, + 2090, + 2095, + 2100, + 2105, + 2110, + 2115, + 2120, + 2125, + 2130, + 2135, + 2140, + 2145, + 2150, + 2155, + 2160, + 2165, + 2170, + 2175, + 2180, + 2185, + 2190, + 2195, + 2200, + 2205, + 2210, + 2215, + 2220, + 2225, + 2230, + 2235, + 2240, + 2245, + 2250, + 2255, + 2260, + 2265, + 2270, + 2275, + 2280, + 2285, + 2290, + 2295, + 2300, + 2305, + 2310, + 2315, + 2320, + 2325, + 2330, + 2335, + 2340, + 2345, + 2350, + 2355, + 2360, + 2365, + 2370, + 2375, + 2380, + 2385, + 2390, + 2395, + 2400, + 2405, + 2410, + 2415, + 2420, + 2425, + 2430, + 2435, + 2440, + 2445, + 2450, + 2455, + 2460, + 2465, + 2470, + 2475, + 2480, + 2485, + 2490, + 2495, + 2500, + 2505, + 2510, + 2515, + 2520, + 2525, + 2530, + 2535, + 2540, + 2545, + 2550, + 2555, + 2560, + 2565, + 2570, + 2575, + 2580, + 2585, + 2590, + 2595, + 2600, + 2605, + 2610, + 2615, + 2620, + 2625, + 2630, + 2635, + 2640, + 2645, + 2650, + 2655, + 2660, + 2665, + 2670, + 2675, + 2680, + 2685, + 2690, + 2695, + 2700, + 2705, + 2710, + 2715, + 2720, + 2725, + 2730, + 2735, + 2740, + 2745, + 2750, + 2755, + 2760, + 2765, + 2770, + 2775, + 2780, + 2785, + 2790, + 2795, + 2800, + 2805, + 2810, + 2815, + 2820, + 2825, + 2830, + 2835, + 2840, + 2845, + 2850, + 2855, + 2860, + 2865, + 2870, + 2875, + 2880, + 2885, + 2890, + 2895, + 2900, + 2905, + 2910, + 2915, + 2920, + 2925, + 2930, + 2935, + 2940, + 2945, + 2950, + 2955, + 2960, + 2965, + 2970, + 2975, + 2980, + 2985, + 2990, + 2995, + 3000, + 3005, + 3010, + 3015, + 3020, + 3025, + 3030, + 3035, + 3040, + 3045, + 3050, + 3055, + 3060, + 3065, + 3070, + 3075, + 3080, + 3085, + 3090, + 3095, + 3100, + 3105, + 3110, + 3115, + 3120, + 3125, + 3130, + 3135, + 3140, + 3145, + 3150, + 3155, + 3160, + 3165, + 3170, + 3175, + 3180, + 3185, + 3190, + 3195, + 3200, + 3205, + 3210, + 3215, + 3220, + 3225, + 3230, + 3235, + 3240, + 3245, + 3250, + 3255, + 3260, + 3265, + 3270, + 3275, + 3280, + 3285, + 3290, + 3295, + 3300, + 3305, + 3310, + 3315, + 3320, + 3325, + 3330, + 3335, + 3340, + 3345, + 3350, + 3355, + 3360, + 3365, + 3370, + 3375, + 3380, + 3385, + 3390, + 3395, + 3400, + 3405, + 3410, + 3415, + 3420, + 3425, + 3430, + 3435, + 3440, + 3445, + 3450, + 3455, + 3460, + 3465, + 3470, + 3475, + 3480, + 3485, + 3490, + 3495, + 3500, + 3505, + 3510, + 3510.522507468857, + 3510.522507468857, + 3510, + 3505, + 3500, + 3495, + 3490, + 3485, + 3480, + 3475, + 3470, + 3465, + 3460, + 3455, + 3450, + 3445, + 3440, + 3435, + 3430, + 3425, + 3420, + 3415, + 3410, + 3405, + 3400, + 3395, + 3390, + 3385, + 3380, + 3375, + 3370, + 3365, + 3360, + 3355, + 3350, + 3345, + 3340, + 3335, + 3330, + 3325, + 3320, + 3315, + 3310, + 3305, + 3300, + 3295, + 3290, + 3285, + 3280, + 3275, + 3270, + 3265, + 3260, + 3255, + 3250, + 3245, + 3240, + 3235, + 3230, + 3225, + 3220, + 3215, + 3210, + 3205, + 3200, + 3195, + 3190, + 3185, + 3180, + 3175, + 3170, + 3165, + 3160, + 3155, + 3150, + 3145, + 3140, + 3135, + 3130, + 3125, + 3120, + 3115, + 3110, + 3105, + 3100, + 3095, + 3090, + 3085, + 3080, + 3075, + 3070, + 3065, + 3060, + 3055, + 3050, + 3045, + 3040, + 3035, + 3030, + 3025, + 3020, + 3015, + 3010, + 3005, + 3000, + 2995, + 2990, + 2985, + 2980, + 2975, + 2970, + 2965, + 2960, + 2955, + 2950, + 2945, + 2940, + 2935, + 2930, + 2925, + 2920, + 2915, + 2910, + 2905, + 2900, + 2895, + 2890, + 2885, + 2880, + 2875, + 2870, + 2865, + 2860, + 2855, + 2850, + 2845, + 2840, + 2835, + 2830, + 2825, + 2820, + 2815, + 2810, + 2805, + 2800, + 2795, + 2790, + 2785, + 2780, + 2775, + 2770, + 2765, + 2760, + 2755, + 2750, + 2745, + 2740, + 2735, + 2730, + 2725, + 2720, + 2715, + 2710, + 2705, + 2700, + 2695, + 2690, + 2685, + 2680, + 2675, + 2670, + 2665, + 2660, + 2655, + 2650, + 2645, + 2640, + 2635, + 2630, + 2625, + 2620, + 2615, + 2610, + 2605, + 2600, + 2595, + 2590, + 2585, + 2580, + 2575, + 2570, + 2565, + 2560, + 2555, + 2550, + 2545, + 2540, + 2535, + 2530, + 2525, + 2520, + 2515, + 2510, + 2505, + 2500, + 2495, + 2490, + 2485, + 2480, + 2475, + 2470, + 2465, + 2460, + 2455, + 2450, + 2445, + 2440, + 2435, + 2430, + 2425, + 2420, + 2415, + 2410, + 2405, + 2400, + 2395, + 2390, + 2385, + 2380, + 2375, + 2370, + 2365, + 2360, + 2355, + 2350, + 2345, + 2340, + 2335, + 2330, + 2325, + 2320, + 2315, + 2310, + 2305, + 2300, + 2295, + 2290, + 2285, + 2280, + 2275, + 2270, + 2265, + 2260, + 2255, + 2250, + 2245, + 2240, + 2235, + 2230, + 2225, + 2220, + 2215, + 2210, + 2205, + 2200, + 2195, + 2190, + 2185, + 2180, + 2175, + 2170, + 2165, + 2160, + 2155, + 2150, + 2145, + 2140, + 2135, + 2130, + 2125, + 2120, + 2115, + 2110, + 2105, + 2100, + 2095, + 2090, + 2085, + 2080, + 2075, + 2070, + 2065, + 2060, + 2055, + 2050, + 2045, + 2040, + 2035, + 2030, + 2025, + 2020, + 2015, + 2010, + 2005, + 2000, + 1995, + 1990, + 1985, + 1980, + 1975, + 1970, + 1965, + 1960, + 1955, + 1950, + 1945, + 1940, + 1935, + 1930, + 1925, + 1920, + 1915, + 1910, + 1905, + 1900, + 1895, + 1890, + 1885, + 1880, + 1875, + 1870, + 1865, + 1860, + 1855, + 1850, + 1845, + 1840, + 1835, + 1830, + 1825, + 1820, + 1815, + 1810, + 1805, + 1800, + 1795, + 1790, + 1785, + 1780, + 1775, + 1770, + 1765, + 1760, + 1755, + 1750, + 1745, + 1740, + 1735, + 1730, + 1725, + 1720, + 1715, + 1710, + 1705, + 1700, + 1695, + 1690, + 1685, + 1680, + 1675, + 1670, + 1665, + 1660, + 1655, + 1650, + 1645, + 1640, + 1635, + 1630, + 1625, + 1620, + 1615, + 1610, + 1605, + 1600, + 1595, + 1590, + 1585, + 1580, + 1575, + 1570, + 1565, + 1560, + 1555, + 1550, + 1545, + 1540, + 1535, + 1530, + 1525, + 1520, + 1515, + 1510, + 1505, + 1500, + 1495, + 1490, + 1485, + 1480, + 1475, + 1470, + 1465, + 1460, + 1455, + 1450, + 1445, + 1440, + 1435, + 1430, + 1425, + 1420, + 1415, + 1410, + 1405, + 1400, + 1395, + 1390, + 1385, + 1380, + 1375, + 1370, + 1365, + 1360, + 1355, + 1350, + 1345, + 1340, + 1335, + 1330, + 1325, + 1320, + 1315, + 1310, + 1305, + 1300, + 1295, + 1290, + 1285, + 1280, + 1275, + 1270, + 1265, + 1260, + 1255, + 1250, + 1245, + 1240, + 1235, + 1230, + 1225, + 1220, + 1215, + 1210, + 1205, + 1200, + 1195, + 1190, + 1185, + 1180, + 1175, + 1170, + 1165, + 1160, + 1155, + 1150, + 1145, + 1140, + 1135, + 1130, + 1125, + 1120, + 1115, + 1110, + 1105, + 1100, + 1095, + 1090, + 1085, + 1080, + 1075, + 1070, + 1065, + 1060, + 1055, + 1050, + 1045, + 1040, + 1035, + 1030, + 1025, + 1020, + 1015, + 1010, + 1005, + 1000, + 995, + 990, + 985, + 980, + 975, + 970, + 965, + 960, + 955, + 950, + 945, + 940, + 935, + 930, + 925, + 920, + 915, + 910, + 905, + 900, + 895, + 890, + 885, + 880, + 875, + 870, + 865, + 860, + 855, + 850, + 845, + 840, + 835, + 830, + 825, + 820, + 815, + 810, + 805, + 800, + 795, + 790, + 785, + 780, + 775, + 770, + 765, + 760, + 755, + 750, + 745, + 740, + 735, + 730, + 725, + 720, + 715, + 710, + 705, + 700, + 695, + 690, + 685, + 680, + 675, + 670, + 665, + 660, + 655, + 650, + 645, + 640, + 635, + 630, + 625, + 620, + 615, + 610, + 605, + 600, + 595, + 590, + 585, + 580, + 575, + 570, + 565, + 560, + 555, + 550, + 545, + 540, + 535, + 530, + 525, + 520, + 515, + 510, + 505, + 500, + 495, + 490, + 485, + 480, + 475, + 470, + 465, + 460, + 455, + 450, + 445, + 440, + 435, + 430, + 425, + 420, + 415, + 410, + 405, + 400, + 395, + 390, + 385, + 380, + 375, + 370, + 365, + 360, + 355, + 350, + 345, + 340, + 335, + 330, + 325, + 320, + 315, + 310, + 305, + 300, + 295, + 290, + 285, + 280, + 275, + 270, + 265, + 260, + 255, + 250, + 245, + 240, + 235, + 230, + 225, + 220, + 215, + 210, + 205, + 200, + 195, + 190, + 185, + 180, + 175, + 170, + 165, + 160, + 155, + 150, + 145, + 140, + 135, + 130, + 125, + 120, + 115, + 110, + 105, + 100, + 95, + 90, + 85, + 80, + 75, + 70, + 65, + 60, + 55, + 50, + 45, + 40, + 35, + 30, + 25, + 20, + 15, + 10, + 5, + 0 + ], + "y": [ + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081 + ] + }, + { + "mode": "markers", + "name": "Initial", + "type": "scatter", + "x": [ + 0, + 5, + 10, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 65, + 70, + 75, + 80, + 85, + 90, + 95, + 100, + 105, + 110, + 115, + 120, + 125, + 130, + 135, + 140, + 145, + 150, + 155, + 160, + 165, + 170, + 175, + 180, + 185, + 190, + 195, + 200, + 205, + 210, + 215, + 220, + 225, + 230, + 235, + 240, + 245, + 250, + 255, + 260, + 265, + 270, + 275, + 280, + 285, + 290, + 295, + 300, + 305, + 310, + 315, + 320, + 325, + 330, + 335, + 340, + 345, + 350, + 355, + 360, + 365, + 370, + 375, + 380, + 385, + 390, + 395, + 400, + 405, + 410, + 415, + 420, + 425, + 430, + 435, + 440, + 445, + 450, + 455, + 460, + 465, + 470, + 475, + 480, + 485, + 490, + 495, + 500, + 505, + 510, + 515, + 520, + 525, + 530, + 535, + 540, + 545, + 550, + 555, + 560, + 565, + 570, + 575, + 580, + 585, + 590, + 595, + 600, + 605, + 610, + 615, + 620, + 625, + 630, + 635, + 640, + 645, + 650, + 655, + 660, + 665, + 670, + 675, + 680, + 685, + 690, + 695, + 700, + 705, + 710, + 715, + 720, + 725, + 730, + 735, + 740, + 745, + 750, + 755, + 760, + 765, + 770, + 775, + 780, + 785, + 790, + 795, + 800, + 805, + 810, + 815, + 820, + 825, + 830, + 835, + 840, + 845, + 850, + 855, + 860, + 865, + 870, + 875, + 880, + 885, + 890, + 895, + 900, + 905, + 910, + 915, + 920, + 925, + 930, + 935, + 940, + 945, + 950, + 955, + 960, + 965, + 970, + 975, + 980, + 985, + 990, + 995, + 1000, + 1005, + 1010, + 1015, + 1020, + 1025, + 1030, + 1035, + 1040, + 1045, + 1050, + 1055, + 1060, + 1065, + 1070, + 1075, + 1080, + 1085, + 1090, + 1095, + 1100, + 1105, + 1110, + 1115, + 1120, + 1125, + 1130, + 1135, + 1140, + 1145, + 1150, + 1155, + 1160, + 1165, + 1170, + 1175, + 1180, + 1185, + 1190, + 1195, + 1200, + 1205, + 1210, + 1215, + 1220, + 1225, + 1230, + 1235, + 1240, + 1245, + 1250, + 1255, + 1260, + 1265, + 1270, + 1275, + 1280, + 1285, + 1290, + 1295, + 1300, + 1305, + 1310, + 1315, + 1320, + 1325, + 1330, + 1335, + 1340, + 1345, + 1350, + 1355, + 1360, + 1365, + 1370, + 1375, + 1380, + 1385, + 1390, + 1395, + 1400, + 1405, + 1410, + 1415, + 1420, + 1425, + 1430, + 1435, + 1440, + 1445, + 1450, + 1455, + 1460, + 1465, + 1470, + 1475, + 1480, + 1485, + 1490, + 1495, + 1500, + 1505, + 1510, + 1515, + 1520, + 1525, + 1530, + 1535, + 1540, + 1545, + 1550, + 1555, + 1560, + 1565, + 1570, + 1575, + 1580, + 1585, + 1590, + 1595, + 1600, + 1605, + 1610, + 1615, + 1620, + 1625, + 1630, + 1635, + 1640, + 1645, + 1650, + 1655, + 1660, + 1665, + 1670, + 1675, + 1680, + 1685, + 1690, + 1695, + 1700, + 1705, + 1710, + 1715, + 1720, + 1725, + 1730, + 1735, + 1740, + 1745, + 1750, + 1755, + 1760, + 1765, + 1770, + 1775, + 1780, + 1785, + 1790, + 1795, + 1800, + 1805, + 1810, + 1815, + 1820, + 1825, + 1830, + 1835, + 1840, + 1845, + 1850, + 1855, + 1860, + 1865, + 1870, + 1875, + 1880, + 1885, + 1890, + 1895, + 1900, + 1905, + 1910, + 1915, + 1920, + 1925, + 1930, + 1935, + 1940, + 1945, + 1950, + 1955, + 1960, + 1965, + 1970, + 1975, + 1980, + 1985, + 1990, + 1995, + 2000, + 2005, + 2010, + 2015, + 2020, + 2025, + 2030, + 2035, + 2040, + 2045, + 2050, + 2055, + 2060, + 2065, + 2070, + 2075, + 2080, + 2085, + 2090, + 2095, + 2100, + 2105, + 2110, + 2115, + 2120, + 2125, + 2130, + 2135, + 2140, + 2145, + 2150, + 2155, + 2160, + 2165, + 2170, + 2175, + 2180, + 2185, + 2190, + 2195, + 2200, + 2205, + 2210, + 2215, + 2220, + 2225, + 2230, + 2235, + 2240, + 2245, + 2250, + 2255, + 2260, + 2265, + 2270, + 2275, + 2280, + 2285, + 2290, + 2295, + 2300, + 2305, + 2310, + 2315, + 2320, + 2325, + 2330, + 2335, + 2340, + 2345, + 2350, + 2355, + 2360, + 2365, + 2370, + 2375, + 2380, + 2385, + 2390, + 2395, + 2400, + 2405, + 2410, + 2415, + 2420, + 2425, + 2430, + 2435, + 2440, + 2445, + 2450, + 2455, + 2460, + 2465, + 2470, + 2475, + 2480, + 2485, + 2490, + 2495, + 2500, + 2505, + 2510, + 2515, + 2520, + 2525, + 2530, + 2535, + 2540, + 2545, + 2550, + 2555, + 2560, + 2565, + 2570, + 2575, + 2580, + 2585, + 2590, + 2595, + 2600, + 2605, + 2610, + 2615, + 2620, + 2625, + 2630, + 2635, + 2640, + 2645, + 2650, + 2655, + 2660, + 2665, + 2670, + 2675, + 2680, + 2685, + 2690, + 2695, + 2700, + 2705, + 2710, + 2715, + 2720, + 2725, + 2730, + 2735, + 2740, + 2745, + 2750, + 2755, + 2760, + 2765, + 2770, + 2775, + 2780, + 2785, + 2790, + 2795, + 2800, + 2805, + 2810, + 2815, + 2820, + 2825, + 2830, + 2835, + 2840, + 2845, + 2850, + 2855, + 2860, + 2865, + 2870, + 2875, + 2880, + 2885, + 2890, + 2895, + 2900, + 2905, + 2910, + 2915, + 2920, + 2925, + 2930, + 2935, + 2940, + 2945, + 2950, + 2955, + 2960, + 2965, + 2970, + 2975, + 2980, + 2985, + 2990, + 2995, + 3000, + 3005, + 3010, + 3015, + 3020, + 3025, + 3030, + 3035, + 3040, + 3045, + 3050, + 3055, + 3060, + 3065, + 3070, + 3075, + 3080, + 3085, + 3090, + 3095, + 3100, + 3105, + 3110, + 3115, + 3120, + 3125, + 3130, + 3135, + 3140, + 3145, + 3150, + 3155, + 3160, + 3165, + 3170, + 3175, + 3180, + 3185, + 3190, + 3195, + 3200, + 3205, + 3210, + 3215, + 3220, + 3225, + 3230, + 3235, + 3240, + 3245, + 3250, + 3255, + 3260, + 3265, + 3270, + 3275, + 3280, + 3285, + 3290, + 3295, + 3300, + 3305, + 3310, + 3315, + 3320, + 3325, + 3330, + 3335, + 3340, + 3345, + 3350, + 3355, + 3360, + 3365, + 3370, + 3375, + 3380, + 3385, + 3390, + 3395, + 3400, + 3405, + 3410, + 3415, + 3420, + 3425, + 3430, + 3435, + 3440, + 3445, + 3450, + 3455, + 3460, + 3465, + 3470, + 3475, + 3480, + 3485, + 3490, + 3495, + 3500, + 3505, + 3510, + 3510.522507468857 + ], + "y": [ + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965, + 5.114173249321965 + ] + }, + { + "line": { + "width": 4 + }, + "mode": "lines", + "name": "Optimised", + "type": "scatter", + "x": [ + 0, + 5, + 10, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 65, + 70, + 75, + 80, + 85, + 90, + 95, + 100, + 105, + 110, + 115, + 120, + 125, + 130, + 135, + 140, + 145, + 150, + 155, + 160, + 165, + 170, + 175, + 180, + 185, + 190, + 195, + 200, + 205, + 210, + 215, + 220, + 225, + 230, + 235, + 240, + 245, + 250, + 255, + 260, + 265, + 270, + 275, + 280, + 285, + 290, + 295, + 300, + 305, + 310, + 315, + 320, + 325, + 330, + 335, + 340, + 345, + 350, + 355, + 360, + 365, + 370, + 375, + 380, + 385, + 390, + 395, + 400, + 405, + 410, + 415, + 420, + 425, + 430, + 435, + 440, + 445, + 450, + 455, + 460, + 465, + 470, + 475, + 480, + 485, + 490, + 495, + 500, + 505, + 510, + 515, + 520, + 525, + 530, + 535, + 540, + 545, + 550, + 555, + 560, + 565, + 570, + 575, + 580, + 585, + 590, + 595, + 600, + 605, + 610, + 615, + 620, + 625, + 630, + 635, + 640, + 645, + 650, + 655, + 660, + 665, + 670, + 675, + 680, + 685, + 690, + 695, + 700, + 705, + 710, + 715, + 720, + 725, + 730, + 735, + 740, + 745, + 750, + 755, + 760, + 765, + 770, + 775, + 780, + 785, + 790, + 795, + 800, + 805, + 810, + 815, + 820, + 825, + 830, + 835, + 840, + 845, + 850, + 855, + 860, + 865, + 870, + 875, + 880, + 885, + 890, + 895, + 900, + 905, + 910, + 915, + 920, + 925, + 930, + 935, + 940, + 945, + 950, + 955, + 960, + 965, + 970, + 975, + 980, + 985, + 990, + 995, + 1000, + 1005, + 1010, + 1015, + 1020, + 1025, + 1030, + 1035, + 1040, + 1045, + 1050, + 1055, + 1060, + 1065, + 1070, + 1075, + 1080, + 1085, + 1090, + 1095, + 1100, + 1105, + 1110, + 1115, + 1120, + 1125, + 1130, + 1135, + 1140, + 1145, + 1150, + 1155, + 1160, + 1165, + 1170, + 1175, + 1180, + 1185, + 1190, + 1195, + 1200, + 1205, + 1210, + 1215, + 1220, + 1225, + 1230, + 1235, + 1240, + 1245, + 1250, + 1255, + 1260, + 1265, + 1270, + 1275, + 1280, + 1285, + 1290, + 1295, + 1300, + 1305, + 1310, + 1315, + 1320, + 1325, + 1330, + 1335, + 1340, + 1345, + 1350, + 1355, + 1360, + 1365, + 1370, + 1375, + 1380, + 1385, + 1390, + 1395, + 1400, + 1405, + 1410, + 1415, + 1420, + 1425, + 1430, + 1435, + 1440, + 1445, + 1450, + 1455, + 1460, + 1465, + 1470, + 1475, + 1480, + 1485, + 1490, + 1495, + 1500, + 1505, + 1510, + 1515, + 1520, + 1525, + 1530, + 1535, + 1540, + 1545, + 1550, + 1555, + 1560, + 1565, + 1570, + 1575, + 1580, + 1585, + 1590, + 1595, + 1600, + 1605, + 1610, + 1615, + 1620, + 1625, + 1630, + 1635, + 1640, + 1645, + 1650, + 1655, + 1660, + 1665, + 1670, + 1675, + 1680, + 1685, + 1690, + 1695, + 1700, + 1705, + 1710, + 1715, + 1720, + 1725, + 1730, + 1735, + 1740, + 1745, + 1750, + 1755, + 1760, + 1765, + 1770, + 1775, + 1780, + 1785, + 1790, + 1795, + 1800, + 1805, + 1810, + 1815, + 1820, + 1825, + 1830, + 1835, + 1840, + 1845, + 1850, + 1855, + 1860, + 1865, + 1870, + 1875, + 1880, + 1885, + 1890, + 1895, + 1900, + 1905, + 1910, + 1915, + 1920, + 1925, + 1930, + 1935, + 1940, + 1945, + 1950, + 1955, + 1960, + 1965, + 1970, + 1975, + 1980, + 1985, + 1990, + 1995, + 2000, + 2005, + 2010, + 2015, + 2020, + 2025, + 2030, + 2035, + 2040, + 2045, + 2050, + 2055, + 2060, + 2065, + 2070, + 2075, + 2080, + 2085, + 2090, + 2095, + 2100, + 2105, + 2110, + 2115, + 2120, + 2125, + 2130, + 2135, + 2140, + 2145, + 2150, + 2155, + 2160, + 2165, + 2170, + 2175, + 2180, + 2185, + 2190, + 2195, + 2200, + 2205, + 2210, + 2215, + 2220, + 2225, + 2230, + 2235, + 2240, + 2245, + 2250, + 2255, + 2260, + 2265, + 2270, + 2275, + 2280, + 2285, + 2290, + 2295, + 2300, + 2305, + 2310, + 2315, + 2320, + 2325, + 2330, + 2335, + 2340, + 2345, + 2350, + 2355, + 2360, + 2365, + 2370, + 2375, + 2380, + 2385, + 2390, + 2395, + 2400, + 2405, + 2410, + 2415, + 2420, + 2425, + 2430, + 2435, + 2440, + 2445, + 2450, + 2455, + 2460, + 2465, + 2470, + 2475, + 2480, + 2485, + 2490, + 2495, + 2500, + 2505, + 2510, + 2515, + 2520, + 2525, + 2530, + 2535, + 2540, + 2545, + 2550, + 2555, + 2560, + 2565, + 2570, + 2575, + 2580, + 2585, + 2590, + 2595, + 2600, + 2605, + 2610, + 2615, + 2620, + 2625, + 2630, + 2635, + 2640, + 2645, + 2650, + 2655, + 2660, + 2665, + 2670, + 2675, + 2680, + 2685, + 2690, + 2695, + 2700, + 2705, + 2710, + 2715, + 2720, + 2725, + 2730, + 2735, + 2740, + 2745, + 2750, + 2755, + 2760, + 2765, + 2770, + 2775, + 2780, + 2785, + 2790, + 2795, + 2800, + 2805, + 2810, + 2815, + 2820, + 2825, + 2830, + 2835, + 2840, + 2845, + 2850, + 2855, + 2860, + 2865, + 2870, + 2875, + 2880, + 2885, + 2890, + 2895, + 2900, + 2905, + 2910, + 2915, + 2920, + 2925, + 2930, + 2935, + 2940, + 2945, + 2950, + 2955, + 2960, + 2965, + 2970, + 2975, + 2980, + 2985, + 2990, + 2995, + 3000, + 3005, + 3010, + 3015, + 3020, + 3025, + 3030, + 3035, + 3040, + 3045, + 3050, + 3055, + 3060, + 3065, + 3070, + 3075, + 3080, + 3085, + 3090, + 3095, + 3100, + 3105, + 3110, + 3115, + 3120, + 3125, + 3130, + 3135, + 3140, + 3145, + 3150, + 3155, + 3160, + 3165, + 3170, + 3175, + 3180, + 3185, + 3190, + 3195, + 3200, + 3205, + 3210, + 3215, + 3220, + 3225, + 3230, + 3235, + 3240, + 3245, + 3250, + 3255, + 3260, + 3265, + 3270, + 3275, + 3280, + 3285, + 3290, + 3295, + 3300, + 3305, + 3310, + 3315, + 3320, + 3325, + 3330, + 3335, + 3340, + 3345, + 3350, + 3355, + 3360, + 3365, + 3370, + 3375, + 3380, + 3385, + 3390, + 3395, + 3400, + 3405, + 3410, + 3415, + 3420, + 3425, + 3430, + 3435, + 3440, + 3445, + 3450, + 3455, + 3460, + 3465, + 3470, + 3475, + 3480, + 3485, + 3490, + 3495, + 3500, + 3505, + 3510, + 3510.522507468857 + ], + "y": [ + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081, + 5.106005404082081 + ] + } + ], + "layout": { + "autosize": false, + "height": 576, + "legend": { + "font": { + "size": 12 + }, + "x": 1, + "xanchor": "right", + "y": 1, + "yanchor": "top" + }, + "margin": { + "b": 10, + "l": 10, + "pad": 4, + "r": 10, + "t": 75 + }, + "showlegend": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Optimised Comparison", + "x": 0.5 + }, + "width": 1024, + "xaxis": { + "tickfont": { + "size": 12 + }, + "title": { + "font": { + "size": 12 + }, + "text": "Time [s]" + } + }, + "yaxis": { + "tickfont": { + "size": 12 + }, + "title": { + "font": { + "size": 12 + }, + "text": "Current [A]" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "if cost.update_capacity:\n", + " cost.problem._model.approximate_capacity(x)\n", + "pybop.quick_plot(x, cost, title=\"Optimised Comparison\");" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ntIvAJmA04qD" + }, + "source": [ + "## Cost Landscape\n", + "\n", + "Finally, we can visualise the cost landscape and the path taken by the optimiser:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 467 + }, + "id": "tJUJ80Ve04qD", + "outputId": "855fbaa2-1e09-4935-eb1a-8caf7f99eb75" + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "type": "contour", + "x": [ + 0.000065, + 0.0000825, + 0.0001 + ], + "y": [ + 2e-6, + 5.5e-6, + 9e-6 + ], + "z": [ + [ + -411.2298715307869, + -384.5514548667088, + -360.1243749344209 + ], + [ + -389.45853879647154, + -375.6347882136447, + -353.0562652976013 + ], + [ + -297.51446838856344, + -361.0290869712437, + -342.44425194479135 + ] + ] + }, + { + "marker": { + "color": "red", + "line": { + "color": "midnightblue", + "width": 1 + }, + "showscale": false, + "size": 12, + "symbol": "x" + }, + "mode": "markers", + "showlegend": false, + "type": "scatter", + "x": [ + 0.00007503043032178322 + ], + "y": [ + 5.213989386373176e-6 + ] + }, + { + "marker": { + "color": [ + 0, + 0.034482758620689655, + 0.06896551724137931, + 0.10344827586206896, + 0.13793103448275862, + 0.1724137931034483, + 0.20689655172413793, + 0.2413793103448276, + 0.27586206896551724, + 0.3103448275862069, + 0.3448275862068966, + 0.3793103448275862, + 0.41379310344827586, + 0.4482758620689655, + 0.4827586206896552, + 0.5172413793103449, + 0.5517241379310345, + 0.5862068965517241, + 0.6206896551724138, + 0.6551724137931034, + 0.6896551724137931, + 0.7241379310344828, + 0.7586206896551724, + 0.7931034482758621, + 0.8275862068965517, + 0.8620689655172413, + 0.896551724137931, + 0.9310344827586208, + 0.9655172413793104 + ], + "colorscale": [ + [ + 0, + "rgb(255,255,229)" + ], + [ + 0.125, + "rgb(255,247,188)" + ], + [ + 0.25, + "rgb(254,227,145)" + ], + [ + 0.375, + "rgb(254,196,79)" + ], + [ + 0.5, + "rgb(254,153,41)" + ], + [ + 0.625, + "rgb(236,112,20)" + ], + [ + 0.75, + "rgb(204,76,2)" + ], + [ + 0.875, + "rgb(153,52,4)" + ], + [ + 1, + "rgb(102,37,6)" + ] + ], + "showscale": false + }, + "mode": "markers", + "showlegend": false, + "type": "scatter", + "x": [ + 0.00007503043032178322, + 0.00009802702542268024, + 0.00009961571599618376, + 0.00009696983570692418, + 0.00008395762998574042, + 0.00008911496694118421, + 0.00007515805406653971, + 0.00009204596401393966, + 0.00008057020125259683, + 0.00008386969615225464, + 0.00007254052989342064, + 0.00007935751972288362, + 0.0000750001946075022, + 0.00008577128815953699, + 0.00006982413489087496, + 0.00006640947572511218, + 0.00006612369542972039, + 0.00007061848272252423, + 0.00007472708479047697, + 0.0000738910819935762, + 0.00006523593718322669, + 0.00008483575733667275, + 0.00007033181106801437, + 0.00006562638003355986, + 0.00007040332572662624, + 0.00007229780199113263, + 0.00008264638468653952, + 0.00007440284793077438, + 0.00006533356141242215 + ], + "y": [ + 5.213989386373176e-6, + 6.987440787316741e-6, + 2.64453786570932e-6, + 3.389077859556841e-6, + 3.817668779124727e-6, + 5.687676535722202e-6, + 5.269200008333387e-6, + 5.489880994504372e-6, + 3.4059598243459385e-6, + 5.8057531438234875e-6, + 5.433979620135304e-6, + 5.189789142120092e-6, + 5.197278021663849e-6, + 3.6326734178928816e-6, + 5.035835393184889e-6, + 8.106091461340278e-6, + 6.696212143249081e-6, + 4.942164056645866e-6, + 5.279709597217932e-6, + 2.0713500143226936e-6, + 5.9660067637513625e-6, + 4.586549463916286e-6, + 6.3368993449299045e-6, + 5.485105039355238e-6, + 5.140156754229586e-6, + 5.3613255870193305e-6, + 2.844730658911555e-6, + 3.36938348462524e-6, + 5.694287622969207e-6 + ] + } + ], + "layout": { + "height": 600, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Cost Landscape", + "x": 0.5, + "y": 0.9 + }, + "width": 600, + "xaxis": { + "range": [ + 0.000065, + 0.0001 + ], + "title": { + "text": "Positive electrode thickness [m]" + } + }, + "yaxis": { + "range": [ + 2e-6, + 9e-6 + ], + "title": { + "text": "Positive particle radius [m]" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "if len(x) == 2:\n", + " pybop.plot_cost2d(cost, optim=optim, steps=3)" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "06f2374f91c8455bb63252092512f2ed": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "423bffea3a1c42b49a9ad71218e5811b": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "56ff19291e464d63b23e63b8e2ac9ea3": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "SliderStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "SliderStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "description_width": "", + "handle_color": null + } + }, + "646a8670cb204a31bb56bc2380898093": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "7d46516469314b88be3500e2afcafcf6": { + "model_module": "@jupyter-widgets/output", + "model_module_version": "1.0.0", + "model_name": "OutputModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/output", + "_model_module_version": "1.0.0", + "_model_name": "OutputModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/output", + "_view_module_version": "1.0.0", + "_view_name": "OutputView", + "layout": "IPY_MODEL_646a8670cb204a31bb56bc2380898093", + "msg_id": "", + "outputs": [], + "tabbable": null, + "tooltip": null + } + }, + "8d003c14da5f4fa68284b28c15cee6e6": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "VBoxModel", + "state": { + "_dom_classes": [ + "widget-interact" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_aef2fa7adcc14ad0854b73d5910ae3b4", + "IPY_MODEL_7d46516469314b88be3500e2afcafcf6" + ], + "layout": "IPY_MODEL_423bffea3a1c42b49a9ad71218e5811b", + "tabbable": null, + "tooltip": null + } + }, + "aef2fa7adcc14ad0854b73d5910ae3b4": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "FloatSliderModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "FloatSliderModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "FloatSliderView", + "behavior": "drag-tap", + "continuous_update": true, + "description": "t", + "description_allow_html": false, + "disabled": false, + "layout": "IPY_MODEL_06f2374f91c8455bb63252092512f2ed", + "max": 1.1333333333333333, + "min": 0, + "orientation": "horizontal", + "readout": true, + "readout_format": ".2f", + "step": 0.011333333333333332, + "style": "IPY_MODEL_56ff19291e464d63b23e63b8e2ac9ea3", + "tabbable": null, + "tooltip": null, + "value": 0 + } + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/scripts/spme_max_energy.py b/examples/scripts/spme_max_energy.py index e8410cf6e..ebd5bebfa 100644 --- a/examples/scripts/spme_max_energy.py +++ b/examples/scripts/spme_max_energy.py @@ -1,9 +1,5 @@ import pybop -import numpy as np -import warnings -## NOTE: This is a brittle example, the classes and methods below will be -## integrated into pybop in a future release. # A design optimisation example loosely based on work by L.D. Couto # available at https://doi.org/10.1016/j.energy.2022.125966. @@ -14,6 +10,12 @@ # electrode widths, particle radii, volume fractions and # separator width. +# NOTE: This script can be easily adjusted to consider the volumetric +# (instead of gravimetric) energy density by changing the line which +# defines the cost and changing the output to: +# print(f"Initial volumetric energy density: {-cost(cost.x0):.2f} Wh.m-3") +# print(f"Optimised volumetric energy density: {-final_cost:.2f} Wh.m-3") + # Define parameter set and model parameter_set = pybop.ParameterSet.pybamm("Chen2020") model = pybop.lithium_ion.SPMe(parameter_set=parameter_set) @@ -31,90 +33,6 @@ bounds=[2e-06, 9e-06], ), ] -# Define stoichiometries -sto = model._electrode_soh.get_min_max_stoichiometries(parameter_set) -mean_sto_neg = np.mean(sto[0:2]) -mean_sto_pos = np.mean(sto[2:4]) - - -# Define functions -def nominal_capacity( - x, model -): # > 50% of the simulation time is spent in this function (~0.7 sec per iteration vs ~1.1 for the forward simulation) - """ - Update the nominal capacity based on the theoretical energy density and an - average voltage. - """ - inputs = { - key: x[i] for i, key in enumerate([param.name for param in model.parameters]) - } - model.parameter_set.update(inputs) - - theoretical_energy = model._electrode_soh.calculate_theoretical_energy( # All of the computational time is in this line (~0.7) - model.parameter_set - ) - average_voltage = model.parameter_set["Positive electrode OCP [V]"]( - mean_sto_pos - ) - model.parameter_set["Negative electrode OCP [V]"](mean_sto_neg) - - theoretical_capacity = theoretical_energy / average_voltage - model.parameter_set.update({"Nominal cell capacity [A.h]": theoretical_capacity}) - - -def cell_mass(parameter_set): # This is very low compute time - """ - Compute the total cell mass [kg] for the current parameter set. - """ - - # Approximations due to SPM(e) parameter set limitations - electrolyte_density = parameter_set["Separator density [kg.m-3]"] - - # Electrode mass densities [kg.m-3] - positive_mass_density = ( - parameter_set["Positive electrode active material volume fraction"] - * parameter_set["Positive electrode density [kg.m-3]"] - ) - +(parameter_set["Positive electrode porosity"] * electrolyte_density) - negative_mass_density = ( - parameter_set["Negative electrode active material volume fraction"] - * parameter_set["Negative electrode density [kg.m-3]"] - ) - +(parameter_set["Negative electrode porosity"] * electrolyte_density) - - # Area densities [kg.m-2] - positive_area_density = ( - parameter_set["Positive electrode thickness [m]"] * positive_mass_density - ) - negative_area_density = ( - parameter_set["Negative electrode thickness [m]"] * negative_mass_density - ) - separator_area_density = ( - parameter_set["Separator thickness [m]"] - * parameter_set["Separator porosity"] - * parameter_set["Separator density [kg.m-3]"] - ) - positive_current_collector_area_density = ( - parameter_set["Positive current collector thickness [m]"] - * parameter_set["Positive current collector density [kg.m-3]"] - ) - negative_current_collector_area_density = ( - parameter_set["Negative current collector thickness [m]"] - * parameter_set["Negative current collector density [kg.m-3]"] - ) - - # Cross-sectional area [m2] - cross_sectional_area = ( - parameter_set["Electrode height [m]"] * parameter_set["Electrode width [m]"] - ) - - return cross_sectional_area * ( - positive_area_density - + separator_area_density - + negative_area_density - + positive_current_collector_area_density - + negative_current_collector_area_density - ) - # Define test protocol experiment = pybop.Experiment( @@ -128,58 +46,12 @@ def cell_mass(parameter_set): # This is very low compute time model, parameters, experiment, signal=signal, init_soc=init_soc ) -# Update the C-rate and the example dataset -nominal_capacity(problem.x0, model) -sol = problem.evaluate(problem.x0) -problem._time_data = sol[:, -1] -problem._target = sol[:, 0:-1] -dt = sol[1, -1] - sol[0, -1] - - -# Define cost function as a subclass -class GravimetricEnergyDensity(pybop.BaseCost): - """ - Defines the (negative*) gravimetric energy density corresponding to a - normalised 1C discharge from upper to lower voltage limits. - *The energy density is maximised by minimising the negative energy density. - """ - - def __init__(self, problem): - super().__init__(problem) - - def _evaluate(self, x, grad=None): - """ - Compute the cost - """ - with warnings.catch_warnings(record=True) as w: - # Update the C-rate and run the simulation - nominal_capacity(x, self.problem.model) - sol = self.problem.evaluate(x) - - if any(w) and issubclass(w[-1].category, UserWarning): - # Catch infeasible parameter combinations e.g. E_Li > Q_p - print(f"ignoring this sample due to: {w[-1].message}") - return np.inf - - else: - voltage = sol[:, 0] - current = sol[:, 1] - gravimetric_energy_density = -np.trapz( - voltage * current, dx=dt - ) / ( # trapz over-estimates compares to pybamm (~0.5%) - 3600 * cell_mass(self.problem.model.parameter_set) - ) - # Return the negative energy density, as the optimiser minimises - # this function, to carry out maximisation of the energy density - return gravimetric_energy_density - - -# Generate cost function and optimisation class -cost = GravimetricEnergyDensity(problem) +# Generate cost function and optimisation class: +cost = pybop.GravimetricEnergyDensity(problem) optim = pybop.Optimisation( cost, optimiser=pybop.PSO, verbose=True, allow_infeasible_solutions=False ) -optim.set_max_iterations(5) +optim.set_max_iterations(15) # Run optimisation x, final_cost = optim.run() @@ -188,7 +60,8 @@ def _evaluate(self, x, grad=None): print(f"Optimised gravimetric energy density: {-final_cost:.2f} Wh.kg-1") # Plot the timeseries output -nominal_capacity(x, cost.problem.model) +if cost.update_capacity: + cost.problem._model.approximate_capacity(x) pybop.quick_plot(x, cost, title="Optimised Comparison") # Plot the cost landscape with optimisation path diff --git a/examples/standalone/model.py b/examples/standalone/model.py index 9943ff3d8..2295d080a 100644 --- a/examples/standalone/model.py +++ b/examples/standalone/model.py @@ -56,3 +56,4 @@ def __init__( self._built_initial_soc = None self._mesh = None self._disc = None + self.rebuild_parameters = {} diff --git a/noxfile.py b/noxfile.py index ddb7bd191..c14e5b880 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,20 +1,31 @@ +import os import nox + # nox options nox.options.reuse_existing_virtualenvs = True +nox.options.venv_backend = "virtualenv" + +# Environment variables to control CI behaviour for nox sessions +PYBOP_SCHEDULED = int(os.environ.get("PYBOP_SCHEDULED", 0)) +PYBAMM_VERSION = os.environ.get("PYBAMM_VERSION", None) @nox.session def unit(session): - session.run_always("pip", "install", "-e", ".[all]") - session.install("pytest", "pytest-mock") + session.install("-e", ".[all]", silent=False) + if PYBOP_SCHEDULED: + session.run("pip", "install", f"pybamm=={PYBAMM_VERSION}", silent=False) + session.install("pytest", "pytest-mock", silent=False) session.run("pytest", "--unit") @nox.session def coverage(session): - session.run_always("pip", "install", "-e", ".[all]") - session.install("pytest", "pytest-cov", "pytest-mock") + session.install("-e", ".[all]", silent=False) + if PYBOP_SCHEDULED: + session.run("pip", "install", f"pybamm=={PYBAMM_VERSION}", silent=False) + session.install("pytest", "pytest-cov", "pytest-mock", silent=False) session.run( "pytest", "--unit", @@ -27,8 +38,10 @@ def coverage(session): @nox.session def notebooks(session): """Run the examples tests for Jupyter notebooks.""" - session.run_always("pip", "install", "-e", ".[all]") - session.install("pytest", "nbmake") + session.install("-e", ".[all]", silent=False) + if PYBOP_SCHEDULED: + session.run("pip", "install", f"pybamm=={PYBAMM_VERSION}", silent=False) + session.install("pytest", "nbmake", silent=False) session.run("pytest", "--nbmake", "--examples", "examples/", external=True) @@ -39,7 +52,7 @@ def docs(session): Credit: PyBaMM Team """ envbindir = session.bin - session.install("-e", ".[all,docs]") + session.install("-e", ".[all,docs]", silent=False) session.chdir("docs") # Local development if session.interactive: diff --git a/pybop/__init__.py b/pybop/__init__.py index 8216c2f9d..1e8227101 100644 --- a/pybop/__init__.py +++ b/pybop/__init__.py @@ -26,7 +26,17 @@ # # Cost function class # -from ._costs import BaseCost, RootMeanSquaredError, SumSquaredError, ObserverCost +from .costs.base_cost import BaseCost +from .costs.fitting_costs import ( + RootMeanSquaredError, + SumSquaredError, + ObserverCost, +) +from .costs.design_costs import ( + DesignCost, + GravimetricEnergyDensity, + VolumetricEnergyDensity, +) # # Dataset class diff --git a/pybop/_problem.py b/pybop/_problem.py index 2302c63f1..3f7216222 100644 --- a/pybop/_problem.py +++ b/pybop/_problem.py @@ -118,6 +118,10 @@ def target(self): """ return self._target + @property + def model(self): + return self._model + class FittingProblem(BaseProblem): """ @@ -324,7 +328,3 @@ def evaluate(self, x): predictions = [sol[signal].data for signal in self.signal + ["Time [s]"]] return np.vstack(predictions).T - - @property - def model(self): - return self._model diff --git a/pybop/costs/__init__.py b/pybop/costs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pybop/costs/base_cost.py b/pybop/costs/base_cost.py new file mode 100644 index 000000000..171e09b37 --- /dev/null +++ b/pybop/costs/base_cost.py @@ -0,0 +1,142 @@ +class BaseCost: + """ + Base class for defining cost functions. + + This class is intended to be subclassed to create specific cost functions + for evaluating model predictions against a set of data. The cost function + quantifies the goodness-of-fit between the model predictions and the + observed data, with a lower cost value indicating a better fit. + + Parameters + ---------- + problem : object + A problem instance containing the data and functions necessary for + evaluating the cost function. + _target : array-like + An array containing the target data to fit. + x0 : array-like + The initial guess for the model parameters. + bounds : tuple + The bounds for the model parameters. + n_parameters : int + The number of parameters in the model. + n_outputs : int + The number of outputs in the model. + """ + + def __init__(self, problem): + self.problem = problem + if problem is not None: + self._target = problem._target + self.x0 = problem.x0 + self.bounds = problem.bounds + self.n_parameters = problem.n_parameters + self.n_outputs = problem.n_outputs + + def __call__(self, x, grad=None): + """ + Call the evaluate function for a given set of parameters. + + Parameters + ---------- + x : array-like + The parameters for which to evaluate the cost. + grad : array-like, optional + An array to store the gradient of the cost function with respect + to the parameters. + + Returns + ------- + float + The calculated cost function value. + + Raises + ------ + ValueError + If an error occurs during the calculation of the cost. + """ + try: + return self._evaluate(x, grad) + + except NotImplementedError as e: + raise e + + except Exception as e: + raise ValueError(f"Error in cost calculation: {e}") + + def _evaluate(self, x, grad=None): + """ + Calculate the cost function value for a given set of parameters. + + This method must be implemented by subclasses. + + Parameters + ---------- + x : array-like + The parameters for which to evaluate the cost. + grad : array-like, optional + An array to store the gradient of the cost function with respect + to the parameters. + + Returns + ------- + float + The calculated cost function value. + + Raises + ------ + NotImplementedError + If the method has not been implemented by the subclass. + """ + raise NotImplementedError + + def evaluateS1(self, x): + """ + Call _evaluateS1 for a given set of parameters. + + Parameters + ---------- + x : array-like + The parameters for which to compute the cost and gradient. + + Returns + ------- + tuple + A tuple containing the cost and the gradient. The cost is a float, + and the gradient is an array-like of the same length as `x`. + + Raises + ------ + ValueError + If an error occurs during the calculation of the cost or gradient. + """ + try: + return self._evaluateS1(x) + + except NotImplementedError as e: + raise e + + except Exception as e: + raise ValueError(f"Error in cost calculation: {e}") + + def _evaluateS1(self, x): + """ + Compute the cost and its gradient with respect to the parameters. + + Parameters + ---------- + x : array-like + The parameters for which to compute the cost and gradient. + + Returns + ------- + tuple + A tuple containing the cost and the gradient. The cost is a float, + and the gradient is an array-like of the same length as `x`. + + Raises + ------ + NotImplementedError + If the method has not been implemented by the subclass. + """ + raise NotImplementedError diff --git a/pybop/costs/design_costs.py b/pybop/costs/design_costs.py new file mode 100644 index 000000000..8b02f1f28 --- /dev/null +++ b/pybop/costs/design_costs.py @@ -0,0 +1,181 @@ +import numpy as np +import warnings + +from pybop.costs.base_cost import BaseCost + + +class DesignCost(BaseCost): + """ + Overwrites and extends `BaseCost` class for design-related cost functions. + + Inherits all parameters and attributes from ``BaseCost``. + + Additional Attributes + --------------------- + problem : object + The associated problem containing model and evaluation methods. + parameter_set : object) + The set of parameters from the problem's model. + dt : float + The time step size used in the simulation. + """ + + def __init__(self, problem, update_capacity=False): + """ + Initialises the gravimetric energy density calculator with a problem. + + Parameters + ---------- + problem : object + The problem instance containing the model and data. + """ + super().__init__(problem) + self.problem = problem + if update_capacity is True: + nominal_capacity_warning = ( + "The nominal capacity is approximated for each iteration." + ) + else: + nominal_capacity_warning = ( + "The nominal capacity is fixed at the initial model value." + ) + warnings.warn(nominal_capacity_warning, UserWarning) + self.update_capacity = update_capacity + self.parameter_set = problem.model.parameter_set + self.update_simulation_data(problem.x0) + + def update_simulation_data(self, initial_conditions): + """ + Updates the simulation data based on the initial conditions. + + Parameters + ---------- + initial_conditions : array + The initial conditions for the simulation. + """ + if self.update_capacity: + self.problem.model.approximate_capacity(self.problem.x0) + solution = self.problem.evaluate(initial_conditions) + self.problem._time_data = solution[:, -1] + self.problem._target = solution[:, 0:-1] + self.dt = solution[1, -1] - solution[0, -1] + + def _evaluate(self, x, grad=None): + """ + Computes the value of the cost function. + + This method must be implemented by subclasses. + + Parameters + ---------- + x : array + The parameter set for which to compute the cost. + grad : array, optional + Gradient information, not used in this method. + + Raises + ------ + NotImplementedError + If the method has not been implemented by the subclass. + """ + raise NotImplementedError + + +class GravimetricEnergyDensity(DesignCost): + """ + Represents the gravimetric energy density of a battery cell, calculated based + on a normalised discharge from upper to lower voltage limits. The goal is to + maximise the energy density, which is achieved by minimizing the negative energy + density reported by this class. + + Inherits all parameters and attributes from ``DesignCost``. + """ + + def __init__(self, problem, update_capacity=False): + super().__init__(problem, update_capacity) + + def _evaluate(self, x, grad=None): + """ + Computes the cost function for the energy density. + + Parameters + ---------- + x : array + The parameter set for which to compute the cost. + grad : array, optional + Gradient information, not used in this method. + + Returns + ------- + float + The negative gravimetric energy density or infinity in case of infeasible parameters. + """ + try: + with warnings.catch_warnings(): + # Convert UserWarning to an exception + warnings.filterwarnings("error", category=UserWarning) + + if self.update_capacity: + self.problem.model.approximate_capacity(x) + solution = self.problem.evaluate(x) + + voltage, current = solution[:, 0], solution[:, 1] + negative_energy_density = -np.trapz(voltage * current, dx=self.dt) / ( + 3600 * self.problem.model.cell_mass(self.parameter_set) + ) + + return negative_energy_density + + except UserWarning as e: + print(f"Ignoring this sample due to: {e}") + return np.inf + + +class VolumetricEnergyDensity(DesignCost): + """ + Represents the volumetric energy density of a battery cell, calculated based + on a normalised discharge from upper to lower voltage limits. The goal is to + maximise the energy density, which is achieved by minimizing the negative energy + density reported by this class. + + Inherits all parameters and attributes from ``DesignCost``. + """ + + def __init__(self, problem, update_capacity=False): + super().__init__(problem, update_capacity) + + def _evaluate(self, x, grad=None): + """ + Computes the cost function for the energy density. + + Parameters + ---------- + x : array + The parameter set for which to compute the cost. + grad : array, optional + Gradient information, not used in this method. + + Returns + ------- + float + The negative volumetric energy density or infinity in case of infeasible parameters. + """ + try: + with warnings.catch_warnings(): + # Convert UserWarning to an exception + warnings.filterwarnings("error", category=UserWarning) + + if self.update_capacity: + self.problem.model.approximate_capacity(x) + solution = self.problem.evaluate(x) + + voltage, current = solution[:, 0], solution[:, 1] + negative_energy_density = -np.trapz(voltage * current, dx=self.dt) / ( + 3600 * self.problem.model.cell_volume(self.parameter_set) + ) + + return negative_energy_density + + except UserWarning as e: + print(f"Ignoring this sample due to: {e}") + return np.inf diff --git a/pybop/_costs.py b/pybop/costs/fitting_costs.py similarity index 60% rename from pybop/_costs.py rename to pybop/costs/fitting_costs.py index 926057ea0..2da337f18 100644 --- a/pybop/_costs.py +++ b/pybop/costs/fitting_costs.py @@ -1,146 +1,9 @@ import numpy as np +from pybop.costs.base_cost import BaseCost from pybop.observers.observer import Observer -class BaseCost: - """ - Base class for defining cost functions. - - This class is intended to be subclassed to create specific cost functions - for evaluating model predictions against a set of data. The cost function - quantifies the goodness-of-fit between the model predictions and the - observed data, with a lower cost value indicating a better fit. - - Parameters - ---------- - problem : object - A problem instance containing the data and functions necessary for - evaluating the cost function. - _target : array-like - An array containing the target data to fit. - x0 : array-like - The initial guess for the model parameters. - bounds : tuple - The bounds for the model parameters. - n_parameters : int - The number of parameters in the model. - n_outputs : int - The number of outputs in the model. - """ - - def __init__(self, problem): - self.problem = problem - if problem is not None: - self._target = problem._target - self.x0 = problem.x0 - self.bounds = problem.bounds - self.n_parameters = problem.n_parameters - self.n_outputs = problem.n_outputs - - def __call__(self, x, grad=None): - """ - Call the evaluate function for a given set of parameters. - - Parameters - ---------- - x : array-like - The parameters for which to evaluate the cost. - grad : array-like, optional - An array to store the gradient of the cost function with respect - to the parameters. - - Returns - ------- - float - The calculated cost function value. - - Raises - ------ - ValueError - If an error occurs during the calculation of the cost. - """ - try: - return self._evaluate(x, grad) - - except Exception as e: - raise ValueError(f"Error in cost calculation: {e}") - - def _evaluate(self, x, grad=None): - """ - Calculate the cost function value for a given set of parameters. - - This method must be implemented by subclasses. - - Parameters - ---------- - x : array-like - The parameters for which to evaluate the cost. - grad : array-like, optional - An array to store the gradient of the cost function with respect - to the parameters. - - Returns - ------- - float - The calculated cost function value. - - Raises - ------ - NotImplementedError - If the method has not been implemented by the subclass. - """ - raise NotImplementedError - - def evaluateS1(self, x): - """ - Call _evaluateS1 for a given set of parameters. - - Parameters - ---------- - x : array-like - The parameters for which to compute the cost and gradient. - - Returns - ------- - tuple - A tuple containing the cost and the gradient. The cost is a float, - and the gradient is an array-like of the same length as `x`. - - Raises - ------ - ValueError - If an error occurs during the calculation of the cost or gradient. - """ - try: - return self._evaluateS1(x) - - except Exception as e: - raise ValueError(f"Error in cost calculation: {e}") - - def _evaluateS1(self, x): - """ - Compute the cost and its gradient with respect to the parameters. - - Parameters - ---------- - x : array-like - The parameters for which to compute the cost and gradient. - - Returns - ------- - tuple - A tuple containing the cost and the gradient. The cost is a float, - and the gradient is an array-like of the same length as `x`. - - Raises - ------ - NotImplementedError - If the method has not been implemented by the subclass. - """ - raise NotImplementedError - - class RootMeanSquaredError(BaseCost): """ Root mean square error cost function. diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index df62a8f34..a247ade53 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -514,7 +514,15 @@ def check_params( """ if inputs is not None: if not isinstance(inputs, dict): - inputs = {key: inputs[i] for i, key in enumerate(self.fit_keys)} + if isinstance(inputs, list): + for entry in inputs: + if not isinstance(entry, (int, float)): + raise ValueError( + "Expecting inputs in the form of a dictionary, numeric list" + + f" or None, but received a list with type: {type(inputs)}" + ) + else: + inputs = {key: inputs[i] for i, key in enumerate(self.fit_keys)} return self._check_params( inputs=inputs, allow_infeasible_solutions=allow_infeasible_solutions @@ -550,6 +558,63 @@ def copy(self): """ return copy.copy(self) + def cell_mass(self, parameter_set=None): + """ + Calculate the cell mass in kilograms. + + This method must be implemented by subclasses. + + Parameters + ---------- + parameter_set : dict, optional + A dictionary containing the parameter values necessary for the mass + calculations. + + Raises + ------ + NotImplementedError + If the method has not been implemented by the subclass. + """ + raise NotImplementedError + + def cell_volume(self, parameter_set=None): + """ + Calculate the cell volume in m3. + + This method must be implemented by subclasses. + + Parameters + ---------- + parameter_set : dict, optional + A dictionary containing the parameter values necessary for the volume + calculation. + + Raises + ------ + NotImplementedError + If the method has not been implemented by the subclass. + """ + raise NotImplementedError + + def approximate_capacity(self, x): + """ + Calculate a new estimate for the nominal capacity based on the theoretical energy density + and an average voltage. + + This method must be implemented by subclasses. + + Parameters + ---------- + x : array-like + An array of values representing the model inputs. + + Raises + ------ + NotImplementedError + If the method has not been implemented by the subclass. + """ + raise NotImplementedError + @property def built_model(self): return self._built_model diff --git a/pybop/models/empirical/ecm.py b/pybop/models/empirical/ecm.py index 56354be6d..6c0427c8c 100644 --- a/pybop/models/empirical/ecm.py +++ b/pybop/models/empirical/ecm.py @@ -1,8 +1,8 @@ import pybamm -from ..base_model import BaseModel +from .ecm_base import ECircuitModel -class Thevenin(BaseModel): +class Thevenin(ECircuitModel): """ The Thevenin class represents an equivalent circuit model based on the Thevenin model in PyBaMM. diff --git a/pybop/models/empirical/ecm_base.py b/pybop/models/empirical/ecm_base.py new file mode 100644 index 000000000..b66fb47bf --- /dev/null +++ b/pybop/models/empirical/ecm_base.py @@ -0,0 +1,29 @@ +from ..base_model import BaseModel + + +class ECircuitModel(BaseModel): + """ + Overwrites and extends `BaseModel` class for circuit-based PyBaMM models. + """ + + def __init__(self): + super().__init__() + + def _check_params(self, inputs=None, allow_infeasible_solutions=True): + """ + Check the compatibility of the model parameters. + + Parameters + ---------- + inputs : dict + The input parameters for the simulation. + allow_infeasible_solutions : bool, optional + If True, infeasible parameter values will be allowed in the optimisation (default: True). + + Returns + ------- + bool + A boolean which signifies whether the parameters are compatible. + + """ + return True diff --git a/pybop/models/lithium_ion/echem.py b/pybop/models/lithium_ion/echem.py index b6ea8542f..be411c862 100644 --- a/pybop/models/lithium_ion/echem.py +++ b/pybop/models/lithium_ion/echem.py @@ -1,9 +1,9 @@ import pybamm import warnings -from ..base_model import BaseModel +from .echem_base import EChemBaseModel -class SPM(BaseModel): +class SPM(EChemBaseModel): """ Wraps the Single Particle Model (SPM) for simulating lithium-ion batteries, as implemented in PyBaMM. @@ -72,83 +72,8 @@ def __init__( self._electrode_soh = pybamm.lithium_ion.electrode_soh self.rebuild_parameters = self.set_rebuild_parameters() - def set_rebuild_parameters(self): - """ - Sets the parameters that can be changed when rebuilding the model. - - Returns - ------- - dict - A dictionary of parameters that can be changed when rebuilding the model. - - """ - rebuild_parameters = dict.fromkeys( - [ - "Negative particle radius [m]", - "Negative electrode porosity", - "Negative electrode thickness [m]", - "Positive particle radius [m]", - "Positive electrode porosity", - "Positive electrode thickness [m]", - "Separator porosity", - "Separator thickness [m]", - ] - ) - - return rebuild_parameters - - def _check_params( - self, inputs=None, parameter_set=None, allow_infeasible_solutions=True - ): - """ - Check compatibility of the model parameters. - - Parameters - ---------- - inputs : dict - The input parameters for the simulation. - allow_infeasible_solutions : bool, optional - If True, infeasible parameter values will be allowed in the optimisation (default: True). - - Returns - ------- - bool - A boolean which signifies whether the parameters are compatible. - """ - parameter_set = parameter_set or self._parameter_set - - electrode_params = [ - ( - "Negative electrode active material volume fraction", - "Negative electrode porosity", - ), - ( - "Positive electrode active material volume fraction", - "Positive electrode porosity", - ), - ] - - related_parameters = { - key: inputs.get(key) if inputs and key in inputs else parameter_set[key] - for pair in electrode_params - for key in pair - } - - for material_vol_fraction, porosity in electrode_params: - if ( - related_parameters[material_vol_fraction] + related_parameters[porosity] - > 1 - ): - if self.param_check_counter <= len(electrode_params): - infeasibility_warning = "Non-physical point encountered - [{material_vol_fraction} + {porosity}] > 1.0!" - warnings.warn(infeasibility_warning, UserWarning) - self.param_check_counter += 1 - return allow_infeasible_solutions - return True - - -class SPMe(BaseModel): +class SPMe(EChemBaseModel): """ Represents the Single Particle Model with Electrolyte (SPMe) for lithium-ion batteries. @@ -219,31 +144,6 @@ def __init__( self._electrode_soh = pybamm.lithium_ion.electrode_soh self.rebuild_parameters = self.set_rebuild_parameters() - def set_rebuild_parameters(self): - """ - Sets the parameters that can be changed when rebuilding the model. - - Returns - ------- - dict - A dictionary of parameters that can be changed when rebuilding the model. - - """ - rebuild_parameters = dict.fromkeys( - [ - "Negative particle radius [m]", - "Negative electrode porosity", - "Negative electrode thickness [m]", - "Positive particle radius [m]", - "Positive electrode porosity", - "Positive electrode thickness [m]", - "Separator porosity", - "Separator thickness [m]", - ] - ) - - return rebuild_parameters - def _check_params( self, inputs=None, parameter_set=None, allow_infeasible_solutions=True ): diff --git a/pybop/models/lithium_ion/echem_base.py b/pybop/models/lithium_ion/echem_base.py new file mode 100644 index 000000000..7e5c869fa --- /dev/null +++ b/pybop/models/lithium_ion/echem_base.py @@ -0,0 +1,259 @@ +import warnings +from ..base_model import BaseModel + + +class EChemBaseModel(BaseModel): + """ + Overwrites and extends `BaseModel` class for electrochemical PyBaMM models. + """ + + def __init__(self): + super().__init__() + + def _check_params( + self, inputs=None, parameter_set=None, allow_infeasible_solutions=True + ): + """ + Check compatibility of the model parameters. + + Parameters + ---------- + inputs : dict + The input parameters for the simulation. + allow_infeasible_solutions : bool, optional + If True, infeasible parameter values will be allowed in the optimisation (default: True). + + Returns + ------- + bool + A boolean which signifies whether the parameters are compatible. + """ + parameter_set = parameter_set or self._parameter_set + + electrode_params = [ + ( + "Negative electrode active material volume fraction", + "Negative electrode porosity", + ), + ( + "Positive electrode active material volume fraction", + "Positive electrode porosity", + ), + ] + + related_parameters = { + key: inputs.get(key) if inputs and key in inputs else parameter_set[key] + for pair in electrode_params + for key in pair + } + + for material_vol_fraction, porosity in electrode_params: + if ( + related_parameters[material_vol_fraction] + related_parameters[porosity] + > 1 + ): + if self.param_check_counter <= len(electrode_params): + infeasibility_warning = "Non-physical point encountered - [{material_vol_fraction} + {porosity}] > 1.0!" + warnings.warn(infeasibility_warning, UserWarning) + self.param_check_counter += 1 + return allow_infeasible_solutions + + return True + + def cell_volume(self, parameter_set=None): + """ + Calculate the total cell volume in m3. + + This method uses the provided parameter set to calculate the total thickness + of the cell including electrodes, separator, and current collectors. It then + calculates the volume by multiplying by the cross-sectional area. + + Parameters + ---------- + parameter_set : dict, optional + A dictionary containing the parameter values necessary for the volume + calculation. + + Returns + ------- + float + The total volume of the cell in m3. + """ + parameter_set = parameter_set or self._parameter_set + + # Calculate cell thickness + cell_thickness = ( + parameter_set["Positive electrode thickness [m]"] + + parameter_set["Negative electrode thickness [m]"] + + parameter_set["Separator thickness [m]"] + + parameter_set["Positive current collector thickness [m]"] + + parameter_set["Negative current collector thickness [m]"] + ) + + # Calculate cross-sectional area + cross_sectional_area = ( + parameter_set["Electrode height [m]"] * parameter_set["Electrode width [m]"] + ) + + # Calculate and return total cell volume + return cross_sectional_area * cell_thickness + + def cell_mass(self, parameter_set=None): + """ + Calculate the total cell mass in kilograms. + + This method uses the provided parameter set to calculate the mass of different + components of the cell, such as electrodes, separator, and current collectors, + based on their densities, porosities, and thicknesses. It then calculates the + total mass by summing the mass of each component. + + Parameters + ---------- + parameter_set : dict, optional + A dictionary containing the parameter values necessary for the mass + calculations. + + Returns + ------- + float + The total mass of the cell in kilograms. + """ + parameter_set = parameter_set or self._parameter_set + + def mass_density( + active_material_vol_frac, density, porosity, electrolyte_density + ): + return (active_material_vol_frac * density) + ( + porosity * electrolyte_density + ) + + def area_density(thickness, mass_density): + return thickness * mass_density + + # Approximations due to SPM(e) parameter set limitations + electrolyte_density = parameter_set["Separator density [kg.m-3]"] + + # Calculate mass densities + positive_mass_density = mass_density( + parameter_set["Positive electrode active material volume fraction"], + parameter_set["Positive electrode density [kg.m-3]"], + parameter_set["Positive electrode porosity"], + electrolyte_density, + ) + negative_mass_density = mass_density( + parameter_set["Negative electrode active material volume fraction"], + parameter_set["Negative electrode density [kg.m-3]"], + parameter_set["Negative electrode porosity"], + electrolyte_density, + ) + + # Calculate area densities + positive_area_density = area_density( + parameter_set["Positive electrode thickness [m]"], positive_mass_density + ) + negative_area_density = area_density( + parameter_set["Negative electrode thickness [m]"], negative_mass_density + ) + separator_area_density = area_density( + parameter_set["Separator thickness [m]"], + parameter_set["Separator porosity"] * electrolyte_density, + ) + positive_cc_area_density = area_density( + parameter_set["Positive current collector thickness [m]"], + parameter_set["Positive current collector density [kg.m-3]"], + ) + negative_cc_area_density = area_density( + parameter_set["Negative current collector thickness [m]"], + parameter_set["Negative current collector density [kg.m-3]"], + ) + + # Calculate cross-sectional area + cross_sectional_area = ( + parameter_set["Electrode height [m]"] * parameter_set["Electrode width [m]"] + ) + + # Calculate and return total cell mass + total_area_density = ( + positive_area_density + + negative_area_density + + separator_area_density + + positive_cc_area_density + + negative_cc_area_density + ) + return cross_sectional_area * total_area_density + + def approximate_capacity(self, x): + """ + Calculate and update an estimate for the nominal cell capacity based on the theoretical + energy density and an average voltage. + + The nominal capacity is computed by dividing the theoretical energy (in watt-hours) by + the average open circuit potential (voltage) of the cell. + + Parameters + ---------- + x : array-like + An array of values representing the model inputs. + + Returns + ------- + None + The nominal cell capacity is updated directly in the model's parameter set. + """ + # Extract stoichiometries and compute mean values + ( + min_sto_neg, + max_sto_neg, + min_sto_pos, + max_sto_pos, + ) = self._electrode_soh.get_min_max_stoichiometries(self._parameter_set) + mean_sto_neg = (min_sto_neg + max_sto_neg) / 2 + mean_sto_pos = (min_sto_pos + max_sto_pos) / 2 + + inputs = { + key: x[i] for i, key in enumerate([param.name for param in self.parameters]) + } + self._parameter_set.update(inputs) + + # Calculate theoretical energy density + theoretical_energy = self._electrode_soh.calculate_theoretical_energy( + self._parameter_set + ) + + # Calculate average voltage + positive_electrode_ocp = self._parameter_set["Positive electrode OCP [V]"] + negative_electrode_ocp = self._parameter_set["Negative electrode OCP [V]"] + average_voltage = positive_electrode_ocp(mean_sto_pos) - negative_electrode_ocp( + mean_sto_neg + ) + + # Calculate and update nominal capacity + theoretical_capacity = theoretical_energy / average_voltage + self._parameter_set.update( + {"Nominal cell capacity [A.h]": theoretical_capacity} + ) + + def set_rebuild_parameters(self): + """ + Sets the parameters that can be changed when rebuilding the model. + + Returns + ------- + dict + A dictionary of parameters that can be changed when rebuilding the model. + + """ + rebuild_parameters = dict.fromkeys( + [ + "Negative particle radius [m]", + "Negative electrode porosity", + "Negative electrode thickness [m]", + "Positive particle radius [m]", + "Positive electrode porosity", + "Positive electrode thickness [m]", + "Separator porosity", + "Separator thickness [m]", + ] + ) + + return rebuild_parameters diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py index 946d05baa..8a99b8b2f 100644 --- a/pybop/parameters/parameter_set.py +++ b/pybop/parameters/parameter_set.py @@ -152,4 +152,10 @@ def pybamm(cls, name): pybamm.ParameterValues A PyBaMM parameter set corresponding to the provided name. """ + + msg = f"Parameter set '{name}' is not a valid PyBaMM parameter set. Available parameter sets are: {list(pybamm.parameter_sets)}" + + if name not in list(pybamm.parameter_sets): + raise ValueError(msg) + return pybamm.ParameterValues(name).copy() diff --git a/pybop/plotting/quick_plot.py b/pybop/plotting/quick_plot.py index 56593efec..56487a8c1 100644 --- a/pybop/plotting/quick_plot.py +++ b/pybop/plotting/quick_plot.py @@ -154,8 +154,13 @@ def create_traces(self): ) if self.y2 is not None: + if isinstance(self.cost.problem, pybop.DesignProblem): + name = "Initial" + else: + name = "Target" + target_trace = self.go.Scatter( - x=self.x, y=self.y2, mode="markers", name="Target" + x=self.x, y=self.y2, mode="markers", name=name ) fill_trace = self.go.Scatter( x=self.x + self.x[::-1], @@ -214,6 +219,10 @@ def quick_plot(params, cost, title="Scatter Plot", width=1024, height=576): time_data = cost.problem.time_data() model_output = cost.problem.evaluate(params) target_output = cost.problem.target() + if isinstance(cost.problem, pybop.DesignProblem): + trace_name = "Optimised" + else: + trace_name = "Model" # Ensure outputs have the same length len_diff = len(target_output) - len(model_output) @@ -235,7 +244,7 @@ def quick_plot(params, cost, title="Scatter Plot", width=1024, height=576): xaxis_title="Time [s]", yaxis_title=cost.problem.signal[i], title=title, - trace_name="Model", + trace_name=trace_name, width=width, height=height, )() diff --git a/scripts/ci/build_matrix.sh b/scripts/ci/build_matrix.sh new file mode 100644 index 000000000..49b13d54e --- /dev/null +++ b/scripts/ci/build_matrix.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# This helper script generates a matrix for further use in the +# scheduled/nightly builds for PyBOP, i.e., in scheduled_tests.yaml +# It generates a matrix of all combinations of the following variables: +# - python_version: 3.X +# - os: ubuntu-latest, windows-latest, macos-latest +# - pybamm_version: the last X versions of PyBaMM from PyPI, excluding release candidates + +# To update the matrix, the variables below can be modified as needed. + +python_version=("3.8" "3.9" "3.10" "3.11") +os=("ubuntu-latest" "windows-latest" "macos-latest") +# This command fetches the last three PyBaMM versions excluding release candidates from PyPI +pybamm_version=($(curl -s https://pypi.org/pypi/pybamm/json | jq -r '.releases | keys[]' | grep -v rc | tail -n 3 | awk '{print "\"" $1 "\"" }' | paste -sd " " -)) + +# open dict +json='{ + "include": [ +' + +# loop through each combination of variables to generate matrix components +for py_ver in "${python_version[@]}"; do + for os_type in "${os[@]}"; do + for pybamm_ver in "${pybamm_version[@]}"; do + json+='{ + "os": "'$os_type'", + "python_version": "'$py_ver'", + "pybamm_version": '$pybamm_ver' + },' + done + done +done + +# fix structure, removing trailing comma +json=${json%,} + +# close dict +json+=' + ] +}' + +echo "$json" | jq -c . diff --git a/tests/unit/test_cost.py b/tests/unit/test_cost.py index 94d5e890c..aa127ffd4 100644 --- a/tests/unit/test_cost.py +++ b/tests/unit/test_cost.py @@ -9,24 +9,42 @@ class TestCosts: Class for tests cost functions """ - @pytest.fixture(params=[2.5, 3.777]) - def problem(self, request): - cut_off = request.param - # Construct model - model = pybop.lithium_ion.SPM() + @pytest.fixture + def model(self): + return pybop.lithium_ion.SPM() - parameters = [ + @pytest.fixture + def parameters(self): + return [ pybop.Parameter( "Negative electrode active material volume fraction", - prior=pybop.Gaussian(0.5, 0.02), + prior=pybop.Gaussian(0.5, 0.01), bounds=[0.375, 0.625], - ) + ), ] - # Form dataset - x0 = np.array([0.52]) - solution = self.getdata(model, x0) - dataset = pybop.Dataset( + @pytest.fixture + def experiment(self): + return pybop.Experiment( + [ + ("Discharge at 1C for 10 minutes (20 second period)"), + ] + ) + + @pytest.fixture + def x0(self): + return np.array([0.52]) + + @pytest.fixture + def dataset(self, model, experiment, x0): + model.parameter_set = model.pybamm_model.default_parameter_values + model.parameter_set.update( + { + "Negative electrode active material volume fraction": x0[0], + } + ) + solution = model.predict(experiment=experiment) + return pybop.Dataset( { "Time [s]": solution["Time [s]"].data, "Current function [A]": solution["Current [A]"].data, @@ -34,10 +52,17 @@ def problem(self, request): } ) - # Construct Problem - signal = ["Voltage [V]"] + @pytest.fixture + def signal(self): + return "Voltage [V]" + + @pytest.fixture(params=[2.5, 3.777]) + def problem(self, model, parameters, dataset, signal, x0, request): + cut_off = request.param model.parameter_set.update({"Lower voltage cut-off [V]": cut_off}) - problem = pybop.FittingProblem(model, parameters, dataset, signal=signal, x0=x0) + problem = pybop.FittingProblem( + model, parameters, dataset, signal=signal, x0=x0, init_soc=1.0 + ) return problem @pytest.fixture( @@ -77,12 +102,19 @@ def test_base(self, problem): base_cost = pybop.BaseCost(problem) assert base_cost.problem == problem with pytest.raises(NotImplementedError): - base_cost._evaluate([0.5]) - base_cost._evaluateS1([0.5]) + base_cost([0.5]) + with pytest.raises(NotImplementedError): + base_cost.evaluateS1([0.5]) + + @pytest.mark.unit + def test_design_base(self, problem): + design_cost = pybop.DesignCost(problem) + with pytest.raises(NotImplementedError): + design_cost([0.5]) @pytest.mark.unit def test_costs(self, cost): - higher_cost = cost([0.5]) + higher_cost = cost([0.55]) lower_cost = cost([0.52]) assert higher_cost > lower_cost or ( higher_cost == lower_cost and higher_cost == np.inf @@ -132,13 +164,41 @@ def test_costs(self, cost): # Test treatment of simulations that terminated early # by variation of the cut-off voltage. - def getdata(self, model, x0): - model.parameter_set = model.pybamm_model.default_parameter_values - model.parameter_set.update( - { - "Negative electrode active material volume fraction": x0[0], - } + @pytest.mark.parametrize( + "cost_class", + [pybop.GravimetricEnergyDensity, pybop.VolumetricEnergyDensity], + ) + @pytest.mark.unit + def test_energy_density_costs( + self, + cost_class, + model, + parameters, + experiment, + signal, + ): + # Construct Problem + problem = pybop.DesignProblem( + model, parameters, experiment, signal=signal, init_soc=0.5 ) - sim = model.predict(t_eval=np.linspace(0, 10, 100)) - return sim + # Construct Cost + cost = cost_class(problem) + + # Test type of returned value + assert type(cost([0.5])) == np.float64 + assert cost([0.4]) <= 0 # Should be a viable design + assert cost([0.8]) == np.inf # Should exceed active material + porosity < 1 + assert cost([1.4]) == np.inf # Definitely not viable + + # Test infeasible locations + cost.problem._model.allow_infeasible_solutions = False + assert cost([1.1]) == np.inf + + # Test exception for non-numeric inputs + with pytest.raises(ValueError): + cost(["StringInputShouldNotWork"]) + + # Compute after updating nominal capacity + cost = cost_class(problem, update_capacity=True) + cost([0.4]) diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index b4f7a315f..685721548 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -199,3 +199,17 @@ def test_simulate(self): expected = y0 * np.exp(-k * t_eval).reshape(-1, 1) solved = model.simulate(inputs, t_eval) np.testing.assert_array_almost_equal(solved, expected, decimal=5) + + @pytest.mark.unit + def test_basemodel(self): + base = pybop.BaseModel() + x = np.array([1, 2, 3]) + + with pytest.raises(NotImplementedError): + base.cell_mass() + + with pytest.raises(NotImplementedError): + base.cell_volume() + + with pytest.raises(NotImplementedError): + base.approximate_capacity(x) diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index fc9356d2f..39d29d415 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -10,7 +10,7 @@ class TestParameterSets: @pytest.mark.unit def test_parameter_set(self): - # Tests parameter set creation + # Tests parameter set creation and validation with pytest.raises(ValueError): pybop.ParameterSet.pybamm("sChen2010s") From fde941bdcf0005995115ed66ed3c8b9f53fa9e2a Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Mon, 19 Feb 2024 20:42:04 +0000 Subject: [PATCH 09/15] Change spm_CMAES example to geometric parameters, add true_value to parameter cls, bigfix geometric logic in problem cls --- examples/scripts/spm_CMAES.py | 24 ++++++++++++++++-------- pybop/_problem.py | 4 ++-- pybop/parameters/parameter.py | 14 +++++++++++--- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/examples/scripts/spm_CMAES.py b/examples/scripts/spm_CMAES.py index e24eb7a15..f5728019e 100644 --- a/examples/scripts/spm_CMAES.py +++ b/examples/scripts/spm_CMAES.py @@ -8,14 +8,16 @@ # Fitting parameters parameters = [ pybop.Parameter( - "Negative electrode active material volume fraction", - prior=pybop.Gaussian(0.6, 0.05), - bounds=[0.5, 0.8], + "Negative particle radius [m]", + prior=pybop.Gaussian(6e-06, 0.1e-6), + bounds=[1e-6, 9e-6], + true_value=parameter_set["Negative particle radius [m]"], ), pybop.Parameter( - "Positive electrode active material volume fraction", - prior=pybop.Gaussian(0.48, 0.05), - bounds=[0.4, 0.7], + "Positive particle radius [m]", + prior=pybop.Gaussian(4.5e-06, 0.1e-6), + bounds=[1e-6, 9e-6], + true_value=parameter_set["Positive particle radius [m]"], ), ] @@ -42,6 +44,13 @@ # Run the optimisation x, final_cost = optim.run() +print( + "True parameters:", + [ + parameters[0].true_value, + parameters[1].true_value, + ], +) print("Estimated parameters:", x) # Plot the timeseries output @@ -57,5 +66,4 @@ pybop.plot_cost2d(cost, steps=15) # Plot the cost landscape with optimisation path and updated bounds -bounds = np.array([[0.55, 0.75], [0.48, 0.68]]) -pybop.plot_cost2d(cost, optim=optim, bounds=bounds, steps=15) +pybop.plot_cost2d(cost, optim=optim, steps=15) diff --git a/pybop/_problem.py b/pybop/_problem.py index 3f7216222..1986032ba 100644 --- a/pybop/_problem.py +++ b/pybop/_problem.py @@ -61,7 +61,7 @@ def __init__( # Add the initial values to the parameter definitions for i, param in enumerate(self.parameters): - param.update(value=self.x0[i]) + param.update(initial_value=self.x0[i]) def evaluate(self, x): """ @@ -211,7 +211,7 @@ def evaluate(self, x): y : np.ndarray The model output y(t) simulated with inputs x. """ - if (x != self.x).all() and self._model.matched_parameters: + if (x != self.x).any() and self._model.matched_parameters: for i, param in enumerate(self.parameters): param.update(value=x[i]) diff --git a/pybop/parameters/parameter.py b/pybop/parameters/parameter.py index 15dffecb7..6136b0acb 100644 --- a/pybop/parameters/parameter.py +++ b/pybop/parameters/parameter.py @@ -28,12 +28,15 @@ class Parameter: the margin is set outside the interval (0, 1). """ - def __init__(self, name, initial_value=None, prior=None, bounds=None): + def __init__( + self, name, initial_value=None, true_value=None, prior=None, bounds=None + ): """ Construct the parameter class with a name, initial value, prior, and bounds. """ self.name = name self.prior = prior + self.true_value = true_value self.initial_value = initial_value self.value = initial_value self.bounds = bounds @@ -69,7 +72,7 @@ def rvs(self, n_samples): return samples - def update(self, value): + def update(self, value=None, initial_value=None): """ Update the parameter's current value. @@ -78,7 +81,12 @@ def update(self, value): value : float The new value to be assigned to the parameter. """ - self.value = value + if value is not None: + self.value = value + elif initial_value is not None: + self.value = initial_value + else: + raise ValueError("No value provided to update parameter") def __repr__(self): """ From 8624a446d0aee16c7a30f36671a8fe8d9e4e54a0 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Tue, 20 Feb 2024 08:56:50 +0000 Subject: [PATCH 10/15] Add tests for pybop parameters --- tests/unit/test_parameters.py | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/unit/test_parameters.py diff --git a/tests/unit/test_parameters.py b/tests/unit/test_parameters.py new file mode 100644 index 000000000..f8a39fadd --- /dev/null +++ b/tests/unit/test_parameters.py @@ -0,0 +1,66 @@ +import pybop +import pytest + + +class TestParameters: + """ + A class to test the parameter classes. + """ + + @pytest.mark.unit + def test_parameter_construction(self): + parameter = pybop.Parameter( + "Negative electrode active material volume fraction", + prior=pybop.Gaussian(0.6, 0.02), + bounds=[0.375, 0.7], + initial_value=0.6, + ) + + assert parameter.name == "Negative electrode active material volume fraction" + assert parameter.prior.mean == 0.6 + assert parameter.prior.sigma == 0.02 + assert parameter.bounds == [0.375, 0.7] + assert parameter.initial_value == 0.6 + + @pytest.mark.unit + def test_parameter_repr(self): + parameter = pybop.Parameter( + "Negative electrode active material volume fraction", + prior=pybop.Gaussian(0.6, 0.02), + bounds=[0.375, 0.7], + initial_value=0.6, + ) + + assert ( + repr(parameter) + == "Parameter: Negative electrode active material volume fraction \n Prior: Gaussian, mean: 0.6, sigma: 0.02 \n Bounds: [0.375, 0.7] \n Value: 0.6" + ) + + @pytest.mark.unit + def test_parameter_rvs(self): + parameter = pybop.Parameter( + "Negative electrode active material volume fraction", + prior=pybop.Gaussian(0.6, 0.02), + bounds=[0.375, 0.7], + initial_value=0.6, + ) + + samples = parameter.rvs(n_samples=500) + assert (samples >= 0.375).all() and (samples <= 0.7).all() + + @pytest.mark.unit + def test_parameter_update(self): + parameter = pybop.Parameter( + "Negative electrode active material volume fraction", + prior=pybop.Gaussian(0.6, 0.02), + bounds=[0.375, 0.7], + initial_value=0.6, + ) + + # Test value update + parameter.update(value=0.534) + assert parameter.value == 0.534 + + # Test initial value update + parameter.update(initial_value=0.654) + assert parameter.value == 0.654 From 626eb603c25039b6942ef2b8f3d0a9a6dfaaaa2e Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Wed, 21 Feb 2024 08:33:59 +0000 Subject: [PATCH 11/15] Updt Changelog, rm redundant example --- CHANGELOG.md | 1 + examples/scripts/spm_geometric_parameters.py | 60 -------------------- 2 files changed, 1 insertion(+), 60 deletions(-) delete mode 100644 examples/scripts/spm_geometric_parameters.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e743a4b5..8af4eba2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Features +- [#18](https://github.com/pybop-team/PyBOP/pull/18) - Adds geometric parameter fitting capability, via `model.rebuild()` with `model.rebuild_parameters`. - [#203](https://github.com/pybop-team/PyBOP/pull/203) - Adds support for modern Python packaging via a `pyproject.toml` file and configures the `pytest` test runner and `ruff` linter to use their configurations stored as declarative metadata. - [#123](https://github.com/pybop-team/PyBOP/issues/123) - Configures scheduled tests to run against the last three PyPI releases of PyBaMM via dynamic GitHub Actions matrix generation. - [#187](https://github.com/pybop-team/PyBOP/issues/187) - Adds M1 Github runner to `test_on_push` workflow, updt. self-hosted supported python versions in scheduled tests. diff --git a/examples/scripts/spm_geometric_parameters.py b/examples/scripts/spm_geometric_parameters.py deleted file mode 100644 index 046f024cd..000000000 --- a/examples/scripts/spm_geometric_parameters.py +++ /dev/null @@ -1,60 +0,0 @@ -import pybop -import numpy as np - -# Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") -model = pybop.lithium_ion.SPM(parameter_set=parameter_set) - -# Fitting parameters -parameters = [ - pybop.Parameter( - "Positive particle radius [m]", - prior=pybop.Gaussian(5.22e-06, 0.05e-06), - bounds=[5e-06, 6e-06], - ), - pybop.Parameter( - "Negative particle radius [m]", - prior=pybop.Gaussian(5.9e-06, 0.05e-06), - bounds=[5e-06, 6.5e-06], - ), -] - -# Generate data -sigma = 0.001 -t_eval = np.arange(0, 900, 2) -values = model.predict(t_eval=t_eval) -corrupt_values = values["Voltage [V]"].data + np.random.normal(0, sigma, len(t_eval)) - -# Form dataset -dataset = pybop.Dataset( - { - "Time [s]": t_eval, - "Current function [A]": values["Current [A]"].data, - "Voltage [V]": corrupt_values, - } -) - -# Generate problem, cost function, and optimisation class -problem = pybop.FittingProblem(model, parameters, dataset) -cost = pybop.SumSquaredError(problem) -optim = pybop.Optimisation(cost, optimiser=pybop.CMAES) -optim.set_max_iterations(100) - -# Run the optimisation -x, final_cost = optim.run() -print("Estimated parameters:", x) - -# Plot the timeseries output -pybop.quick_plot(x, cost, title="Optimised Comparison") - -# Plot convergence -pybop.plot_convergence(optim) - -# Plot the parameter traces -pybop.plot_parameters(optim) - -# Plot the cost landscape -pybop.plot_cost2d(cost, steps=15) - -# Plot the cost landscape with optimisation path and updated bounds -pybop.plot_cost2d(cost, optim=optim, steps=15) From 7e11e0b4e311a68bcd848d6e20d2b69e971b9aeb Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Wed, 21 Feb 2024 09:45:14 +0000 Subject: [PATCH 12/15] Add tests for rebuild, and increase pybop.parameter tests --- tests/unit/test_models.py | 15 +++++++++++++ tests/unit/test_parameters.py | 41 ++++++++++++----------------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index 685721548..23137133e 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -172,6 +172,21 @@ def test_rebuild_geometric_parameters(self): atol=1e-5, ) + # Test model rebuild after a predict() call + parameters[0].update(7e-06) + parameters[1].update(35e-06) + predicted_model = rebuilt_model.copy() + predicted_model.rebuild(parameters=parameters) + out_predicted = predicted_model.predict(t_eval=t_eval) + + with pytest.raises(AssertionError): + np.testing.assert_allclose( + out_predicted["Terminal voltage [V]"].data, + out_rebuild["Terminal voltage [V]"].data, + atol=1e-5, + ) + + @pytest.mark.unit def test_reinit(self): k = 0.1 y0 = 1 diff --git a/tests/unit/test_parameters.py b/tests/unit/test_parameters.py index f8a39fadd..52f0c69fd 100644 --- a/tests/unit/test_parameters.py +++ b/tests/unit/test_parameters.py @@ -7,15 +7,17 @@ class TestParameters: A class to test the parameter classes. """ - @pytest.mark.unit - def test_parameter_construction(self): - parameter = pybop.Parameter( + @pytest.fixture + def parameter(self): + return pybop.Parameter( "Negative electrode active material volume fraction", prior=pybop.Gaussian(0.6, 0.02), bounds=[0.375, 0.7], initial_value=0.6, ) + @pytest.mark.unit + def test_parameter_construction(self, parameter): assert parameter.name == "Negative electrode active material volume fraction" assert parameter.prior.mean == 0.6 assert parameter.prior.sigma == 0.02 @@ -23,40 +25,19 @@ def test_parameter_construction(self): assert parameter.initial_value == 0.6 @pytest.mark.unit - def test_parameter_repr(self): - parameter = pybop.Parameter( - "Negative electrode active material volume fraction", - prior=pybop.Gaussian(0.6, 0.02), - bounds=[0.375, 0.7], - initial_value=0.6, - ) - + def test_parameter_repr(self, parameter): assert ( repr(parameter) == "Parameter: Negative electrode active material volume fraction \n Prior: Gaussian, mean: 0.6, sigma: 0.02 \n Bounds: [0.375, 0.7] \n Value: 0.6" ) @pytest.mark.unit - def test_parameter_rvs(self): - parameter = pybop.Parameter( - "Negative electrode active material volume fraction", - prior=pybop.Gaussian(0.6, 0.02), - bounds=[0.375, 0.7], - initial_value=0.6, - ) - + def test_parameter_rvs(self, parameter): samples = parameter.rvs(n_samples=500) assert (samples >= 0.375).all() and (samples <= 0.7).all() @pytest.mark.unit - def test_parameter_update(self): - parameter = pybop.Parameter( - "Negative electrode active material volume fraction", - prior=pybop.Gaussian(0.6, 0.02), - bounds=[0.375, 0.7], - initial_value=0.6, - ) - + def test_parameter_update(self, parameter): # Test value update parameter.update(value=0.534) assert parameter.value == 0.534 @@ -64,3 +45,9 @@ def test_parameter_update(self): # Test initial value update parameter.update(initial_value=0.654) assert parameter.value == 0.654 + + @pytest.mark.unit + def test_parameter_margin(self, parameter): + assert parameter.margin == 1e-4 + parameter.set_margin(margin=1e-3) + assert parameter.margin == 1e-3 From fb9053dbb6571ba8de8cb4e70e142a5f3f2f7715 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Wed, 21 Feb 2024 11:09:22 +0000 Subject: [PATCH 13/15] Updt problem tests, revert model_tests --- tests/unit/test_models.py | 14 ---------- tests/unit/test_problem.py | 52 +++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index 23137133e..dfce88e48 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -172,20 +172,6 @@ def test_rebuild_geometric_parameters(self): atol=1e-5, ) - # Test model rebuild after a predict() call - parameters[0].update(7e-06) - parameters[1].update(35e-06) - predicted_model = rebuilt_model.copy() - predicted_model.rebuild(parameters=parameters) - out_predicted = predicted_model.predict(t_eval=t_eval) - - with pytest.raises(AssertionError): - np.testing.assert_allclose( - out_predicted["Terminal voltage [V]"].data, - out_rebuild["Terminal voltage [V]"].data, - atol=1e-5, - ) - @pytest.mark.unit def test_reinit(self): k = 0.1 diff --git a/tests/unit/test_problem.py b/tests/unit/test_problem.py index b92b89a3a..0cdfd8bce 100644 --- a/tests/unit/test_problem.py +++ b/tests/unit/test_problem.py @@ -16,14 +16,14 @@ def model(self): def parameters(self): return [ pybop.Parameter( - "Negative electrode active material volume fraction", - prior=pybop.Gaussian(0.5, 0.02), - bounds=[0.375, 0.625], + "Negative particle radius [m]", + prior=pybop.Gaussian(2e-05, 0.1e-5), + bounds=[1e-6, 5e-5], ), pybop.Parameter( - "Positive electrode active material volume fraction", - prior=pybop.Gaussian(0.65, 0.02), - bounds=[0.525, 0.75], + "Positive particle radius [m]", + prior=pybop.Gaussian(0.5e-05, 0.1e-5), + bounds=[1e-6, 5e-5], ), ] @@ -44,11 +44,11 @@ def experiment(self): @pytest.fixture def dataset(self, model, experiment): model.parameter_set = model.pybamm_model.default_parameter_values - x0 = np.array([0.52, 0.63]) + x0 = np.array([2e-5, 0.5e-5]) model.parameter_set.update( { - "Negative electrode active material volume fraction": x0[0], - "Positive electrode active material volume fraction": x0[1], + "Negative particle radius [m]": x0[0], + "Positive particle radius [m]": x0[1], } ) solution = model.predict(experiment=experiment) @@ -76,12 +76,12 @@ def test_base_problem(self, parameters, model): assert problem._model == model with pytest.raises(NotImplementedError): - problem.evaluate([0.5, 0.5]) + problem.evaluate([1e-5, 1e-5]) with pytest.raises(NotImplementedError): - problem.evaluateS1([0.5, 0.5]) + problem.evaluateS1([1e-5, 1e-5]) with pytest.raises(ValueError): - pybop._problem.BaseProblem(parameters, model=model, signal=[0.5, 0.5]) + pybop._problem.BaseProblem(parameters, model=model, signal=[1e-5, 1e-5]) @pytest.mark.unit def test_fitting_problem(self, parameters, dataset, model, signal): @@ -98,7 +98,7 @@ def test_fitting_problem(self, parameters, dataset, model, signal): assert problem._model._built_model is not None # Test model.simulate - model.simulate(inputs=[0.5, 0.5], t_eval=np.linspace(0, 10, 100)) + model.simulate(inputs=[1e-5, 1e-5], t_eval=np.linspace(0, 10, 100)) # Test problem construction errors for bad_dataset in [ @@ -147,5 +147,27 @@ def test_design_problem(self, parameters, experiment, model): ) # building postponed with input experiment # Test model.predict - model.predict(inputs=[0.5, 0.5], experiment=experiment) - model.predict(inputs=[1.1, 0.5], experiment=experiment) + model.predict(inputs=[1e-5, 1e-5], experiment=experiment) + model.predict(inputs=[3e-5, 3e-5], experiment=experiment) + + @pytest.mark.unit + def test_problem_construct_with_model_predict( + self, parameters, model, dataset, signal + ): + # Construct model and predict + out = model.predict(inputs=[1e-5, 1e-5], t_eval=np.linspace(0, 10, 100)) + + problem = pybop.FittingProblem( + model, parameters, dataset=dataset, signal=signal + ) + + # Test problem evaluate + problem_output = problem.evaluate([2e-5, 2e-5]) + + assert problem._model._built_model is not None + with pytest.raises(AssertionError): + np.testing.assert_allclose( + out["Terminal voltage [V]"].data, + problem_output, + atol=1e-5, + ) From 07570918f58aa8801d96401eb3b33ae1dcd661cf Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Wed, 21 Feb 2024 11:46:03 +0000 Subject: [PATCH 14/15] remove redundant rebuild condition --- pybop/_problem.py | 7 ------- pybop/models/base_model.py | 2 -- 2 files changed, 9 deletions(-) diff --git a/pybop/_problem.py b/pybop/_problem.py index 1986032ba..38e28ce20 100644 --- a/pybop/_problem.py +++ b/pybop/_problem.py @@ -189,13 +189,6 @@ def __init__( check_model=self.check_model, init_soc=self.init_soc, ) - elif self._model.has_predict is True: - self._model.rebuild( - dataset=self._dataset, - parameters=self.parameters, - check_model=self.check_model, - init_soc=self.init_soc, - ) def evaluate(self, x): """ diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index a247ade53..1f56f9b4e 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -58,7 +58,6 @@ def __init__(self, name="Base Model"): self.parameters = None self.dataset = None self.signal = None - self.has_predict = False self.matched_parameters = {} self.non_matched_parameters = {} self.fit_keys = [] @@ -461,7 +460,6 @@ def predict( if PyBaMM models are not supported by the current simulation method. """ - self.has_predict = True parameter_set = parameter_set or self._parameter_set if inputs is not None: if not isinstance(inputs, dict): From 8a17a99af18b1740b5f0bc8cc1c1d9fecdf13b64 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Wed, 21 Feb 2024 12:30:36 +0000 Subject: [PATCH 15/15] remove missed merge delete --- pybop/models/lithium_ion/echem.py | 51 ------------------------------- 1 file changed, 51 deletions(-) diff --git a/pybop/models/lithium_ion/echem.py b/pybop/models/lithium_ion/echem.py index be411c862..bb03f6585 100644 --- a/pybop/models/lithium_ion/echem.py +++ b/pybop/models/lithium_ion/echem.py @@ -1,5 +1,4 @@ import pybamm -import warnings from .echem_base import EChemBaseModel @@ -143,53 +142,3 @@ def __init__( self._electrode_soh = pybamm.lithium_ion.electrode_soh self.rebuild_parameters = self.set_rebuild_parameters() - - def _check_params( - self, inputs=None, parameter_set=None, allow_infeasible_solutions=True - ): - """ - Check compatibility of the model parameters. - - Parameters - ---------- - inputs : dict - The input parameters for the simulation. - allow_infeasible_solutions : bool, optional - If True, infeasible parameter values will be allowed in the optimisation (default: True). - - Returns - ------- - bool - A boolean which signifies whether the parameters are compatible. - """ - parameter_set = parameter_set or self._parameter_set - - electrode_params = [ - ( - "Negative electrode active material volume fraction", - "Negative electrode porosity", - ), - ( - "Positive electrode active material volume fraction", - "Positive electrode porosity", - ), - ] - - related_parameters = { - key: inputs.get(key) if inputs and key in inputs else parameter_set[key] - for pair in electrode_params - for key in pair - } - - for material_vol_fraction, porosity in electrode_params: - if ( - related_parameters[material_vol_fraction] + related_parameters[porosity] - > 1 - ): - if self.param_check_counter <= len(electrode_params): - infeasibility_warning = "Non-physical point encountered - [{material_vol_fraction} + {porosity}] > 1.0!" - warnings.warn(infeasibility_warning, UserWarning) - self.param_check_counter += 1 - return allow_infeasible_solutions - - return True