From 86aaba99dad8ae56ffd8430715b613e69ca5bfc2 Mon Sep 17 00:00:00 2001 From: Nora Schinkel Date: Fri, 1 Aug 2025 19:07:28 +0200 Subject: [PATCH 01/17] Start from excel bulk --- examples/serialization_deserialization.ipynb | 14 ++-- src/pyetm/models/scenario.py | 18 +++++ src/pyetm/models/scenario_packer.py | 84 +++++++++++++++++++- tests/models/test_scenario_packer.py | 14 +++- 4 files changed, 119 insertions(+), 11 deletions(-) diff --git a/examples/serialization_deserialization.ipynb b/examples/serialization_deserialization.ipynb index 0725fbb..b2b130a 100644 --- a/examples/serialization_deserialization.ipynb +++ b/examples/serialization_deserialization.ipynb @@ -92,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "serialize", "metadata": {}, "outputs": [ @@ -123,7 +123,7 @@ ], "source": [ "# Serialize to DataFrame with multiple columns\n", - "df = original_inputs.to_df(columns=[\"user\", \"default\", \"min\", \"max\", \"disabled\"])\n", + "df = original_inputs.to_dataframe(columns=[\"user\", \"default\", \"min\", \"max\", \"disabled\"])\n", "\n", "print(f\"DataFrame shape: {df.shape}\")\n", "print(f\"DataFrame index: {df.index.names}\")\n", @@ -190,13 +190,13 @@ "scenario.set_user_values_from_dataframe(df)\n", "reconstructed_inputs = scenario.inputs\n", "\n", - "print(f\"DataFrame shape: {reconstructed_inputs.to_df().shape}\")\n", - "print(f\"DataFrame index: {reconstructed_inputs.to_df().index.names}\")\n", - "print(f\"DataFrame columns: {list(reconstructed_inputs.to_df().columns)}\")\n", + "print(f\"DataFrame shape: {reconstructed_inputs.to_dataframe().shape}\")\n", + "print(f\"DataFrame index: {reconstructed_inputs.to_dataframe().index.names}\")\n", + "print(f\"DataFrame columns: {list(reconstructed_inputs.to_dataframe().columns)}\")\n", "\n", - "print(reconstructed_inputs.to_df().head())\n", + "print(reconstructed_inputs.to_dataframe().head())\n", "\n", - "df_again = reconstructed_inputs.to_df(columns=[\"user\", \"default\", \"min\", \"max\", \"disabled\"])\n", + "df_again = reconstructed_inputs.to_dataframe(columns=[\"user\", \"default\", \"min\", \"max\", \"disabled\"])\n", "\n", "print(df_again.head())\n", "\n", diff --git a/src/pyetm/models/scenario.py b/src/pyetm/models/scenario.py index 0eb29c0..b316592 100644 --- a/src/pyetm/models/scenario.py +++ b/src/pyetm/models/scenario.py @@ -133,6 +133,24 @@ def _to_dataframe(self, **kwargs) -> pd.DataFrame: columns=[self.id], ) + @property + def title(self): + if not self.metadata is None: + return self.metadata.get('title', None) + return None + + @title.setter + def title(self, title: str): + if not self.metadata is None: + self.metadata['title'] = title + else: + self.metadata = {'title': title} + + def identifier(self): + if self.title: return self.title + + return self.id + def user_values(self) -> Dict[str, Any]: """ Returns the values set by the user for inputs diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 92b9e44..713aa33 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -1,4 +1,5 @@ import pandas as pd +from os import PathLike from pydantic import BaseModel from typing import Optional, Dict, List, Any, Set, Literal, ClassVar from xlsxwriter import Workbook @@ -33,21 +34,39 @@ def to_dataframe(self, columns="") -> pd.DataFrame: return self._to_dataframe(columns=columns) + def from_dataframe(self, df): + """Should parse the df and call correct setters on identified scenarios""" + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: """Base implementation - kids should implement this""" return pd.DataFrame() + def _find_by_identifier(self, identifier: str): + return next((s for s in self.scenarios if s.identifier() == identifier), None) + class InputsPack(Packable): key: ClassVar[str] = "inputs" def _to_dataframe(self, columns="user", **kwargs): + # TODO: index on title if avaliable return pd.concat( [scenario.inputs.to_dataframe(columns=columns) for scenario in self.scenarios], axis=1, - keys=[scenario.id for scenario in self.scenarios], + keys=[scenario.identifier() for scenario in self.scenarios], ) + def from_dataframe(self, df): + """ + Sets the inputs on the scenarios from the packed df (comes from excel) + In case came it came from a df containing defaults etc, lets drop them + """ + user_values = df.xs('user', level=1, axis=1, drop_level=False) + for identifier, _ in user_values: + breakpoint() + scenario = self._find_by_identifier(identifier) + scenario.set_user_values_from_dataframe(user_values[identifier]) + class QueryPack(Packable): key: ClassVar[str] = "gquery" @@ -61,7 +80,7 @@ def _to_dataframe( return pd.concat( [scenario.results(columns=columns) for scenario in self.scenarios], axis=1, - keys=[scenario.id for scenario in self.scenarios], + keys=[scenario.identifier() for scenario in self.scenarios], copy=False, ) @@ -115,6 +134,7 @@ class ScenarioPacker(BaseModel): _sortables: "SortablePack" = SortablePack() _output_curves: "OutputCurvesPack" = OutputCurvesPack() + # Setting up a packer def add(self, *scenarios): @@ -169,6 +189,8 @@ def to_excel(self, path: str): workbook = Workbook(path) + # TODO: this should come from the packs, they should know their sheet names + # Like this they can pack and unpack sheet_configs = [ ("MAIN", self.main_info), ("PARAMETERS", self.inputs), @@ -220,3 +242,61 @@ def get_summary(self) -> Dict[str, Any]: summary["scenario_ids"] = sorted([s.id for s in self._scenarios()]) return summary + + # Create stuff + + @classmethod + def from_excel(cls, filepath: str | PathLike): + # TODO: Make the sheet name an attr on the packs, + # which user can customize if needed, from args in this method!! + packer = cls() + + with pd.ExcelFile(filepath) as xlsx: + # Open main tab - create scenarios from there + scenarios = packer.scenarios_from_df(packer.read_sheet(xlsx, "MAIN", index_col=0)) + + # TODO: add some kind of IF, is the inputs sheet available? + packer._inputs.add(*scenarios) + packer._inputs.from_dataframe(packer.read_sheet(xlsx, "PARAMETERS", header=[0,1], index_col=[0,1])) + + # TODO: continue for sortables, curves and gqueries + + + @staticmethod + def scenarios_from_df(df: pd.DataFrame) -> list["Scenario"]: + """Converts one df into a list of scenarios""" + return [ScenarioPacker.setup_scenario(title, data) for title, data in df.to_dict().items()] + + @staticmethod + def setup_scenario(title, data): + """Returns a scenario from data dict""" + # TODO: take care of NaN values in data(frame)! Make sure they'll be None! + # TODO: when there is no id in the data, we should call 'new' + # else 'load' + 'update_metadata' + scenario = Scenario.load(data['id']) + # TODO: update metadata with the rest of the stuff in data!! + scenario.title = title + return scenario + + # NOTE: Move to utils? + # Straight from Rob + @staticmethod + def read_sheet( + xlsx: pd.ExcelFile, + sheet_name: str, + required: bool = True, + **kwargs + ) -> pd.Series: + """read list items""" + + if not sheet_name in xlsx.sheet_names: + if required: + raise ValueError(f"Could not load required sheet '{sheet_name}' from {xlsx.io}") + logger.warning("Could not load optional sheet '%s' from '%s'", sheet_name, xlsx.io) + return pd.Series(name=sheet_name, dtype=str) + + values = pd.read_excel(xlsx, sheet_name, **kwargs).squeeze(axis=1) + # if not isinstance(values, pd.Series): + # raise TypeError("Unexpected Outcome") + + return values#.rename(sheet_name) diff --git a/tests/models/test_scenario_packer.py b/tests/models/test_scenario_packer.py index b54503f..949eb1e 100644 --- a/tests/models/test_scenario_packer.py +++ b/tests/models/test_scenario_packer.py @@ -188,13 +188,14 @@ def test_inputs_no_input_scenarios(self, sample_scenario): def test_inputs_single_scenario(self, scenario_with_inputs): """Test inputs with single scenario""" mock_df = pd.DataFrame( - {"value": [1000, 2000], "unit": ["MW", "MW"], "default": [500, 800]}, + {"user": [1000, 2000], "unit": ["MW", "MW"], "default": [500, 800]}, index=["wind_capacity", "solar_capacity"], ) mock_df.index.name = "input" final_df = mock_df.set_index("unit", append=True) scenario_with_inputs.inputs.to_dataframe = Mock(return_value=final_df) + scenario_with_inputs.identifier = Mock(return_value=scenario_with_inputs.id) packer = ScenarioPacker() packer.add_inputs(scenario_with_inputs) @@ -203,7 +204,7 @@ def test_inputs_single_scenario(self, scenario_with_inputs): assert not result.empty assert "input" in result.index.names - assert (scenario_with_inputs.id, "value") in result.columns + assert (scenario_with_inputs.id, "user") in result.columns assert (scenario_with_inputs.id, "default") in result.columns def test_inputs_multiple_scenarios(self, multiple_scenarios): @@ -269,6 +270,7 @@ def test_gquery_results_no_queries(self, sample_scenario): def test_gquery_results_single_scenario(self, scenario_with_queries): """Test gquery_results with single scenario""" + scenario_with_queries.identifier = Mock(return_value=scenario_with_queries.id) packer = ScenarioPacker() packer.add(scenario_with_queries) @@ -288,6 +290,7 @@ def test_gquery_results_multiple_scenarios(self): scenario.area_code = "nl2015" scenario.end_year = 2050 scenario.start_year = 2019 + scenario.identifier = Mock(return_value=scenario.id) mock_results = pd.DataFrame( {"future": [100 + i * 10, 200 + i * 20], "unit": ["MW", "GWh"]}, @@ -446,6 +449,7 @@ def test_to_excel_sheet_types(self): scenario.area_code = "nl2015" scenario.end_year = 2050 scenario.start_year = 2019 + scenario.identifier = Mock(return_value=scenario.id) # Mock all data methods to return non-empty DataFrames scenario.to_dataframe = Mock( @@ -567,3 +571,9 @@ def test_get_summary_with_data(self, multiple_scenarios): assert summary["output_curves"]["scenario_count"] == 1 # scenario 2 only assert len(summary["scenario_ids"]) == 3 assert all(s.id in summary["scenario_ids"] for s in multiple_scenarios) + +class TestFromExcel: + def test_from_excel(self): + ScenarioPacker.from_excel('tests/fixtures/my_input_excel.xlsx') + + From 93a271e8f272a8b80e3c85c60256a776f4ddcb93 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Fri, 8 Aug 2025 09:18:28 +0200 Subject: [PATCH 02/17] Improved styling for packer --- src/pyetm/models/scenario_packer.py | 167 ++++++++++++++++++-------- src/pyetm/utils/excel.py | 177 ++++++++++++++++++++++++---- 2 files changed, 276 insertions(+), 68 deletions(-) diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 713aa33..6014cd4 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -1,4 +1,5 @@ import pandas as pd +import logging from os import PathLike from pydantic import BaseModel from typing import Optional, Dict, List, Any, Set, Literal, ClassVar @@ -6,12 +7,15 @@ from pyetm.models.base import Base from pyetm.models import Scenario -from pyetm.utils.excel import add_frame +from pyetm.utils.excel import add_frame_with_scenario_styling + +logger = logging.getLogger(__name__) class Packable(BaseModel): scenarios: Optional[set["Scenario"]] = set() key: ClassVar[str] = "base_pack" + sheet_name: ClassVar[str] = "SHEET" def add(self, *scenarios): "Adds one or more scenarios to the packable" @@ -47,11 +51,15 @@ def _find_by_identifier(self, identifier: str): class InputsPack(Packable): key: ClassVar[str] = "inputs" + sheet_name: ClassVar[str] = "PARAMETERS" def _to_dataframe(self, columns="user", **kwargs): # TODO: index on title if avaliable return pd.concat( - [scenario.inputs.to_dataframe(columns=columns) for scenario in self.scenarios], + [ + scenario.inputs.to_dataframe(columns=columns) + for scenario in self.scenarios + ], axis=1, keys=[scenario.identifier() for scenario in self.scenarios], ) @@ -61,7 +69,7 @@ def from_dataframe(self, df): Sets the inputs on the scenarios from the packed df (comes from excel) In case came it came from a df containing defaults etc, lets drop them """ - user_values = df.xs('user', level=1, axis=1, drop_level=False) + user_values = df.xs("user", level=1, axis=1, drop_level=False) for identifier, _ in user_values: breakpoint() scenario = self._find_by_identifier(identifier) @@ -70,6 +78,7 @@ def from_dataframe(self, df): class QueryPack(Packable): key: ClassVar[str] = "gquery" + sheet_name: ClassVar[str] = "GQUERIES_RESULTS" def _to_dataframe( self, columns="future", **kwargs @@ -87,44 +96,93 @@ def _to_dataframe( class SortablePack(Packable): key: ClassVar[str] = "sortables" + sheet_name: ClassVar[str] = "SORTABLES" def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: - """PACKS ONLY FIRST SCENARIO""" + """Pack sortables data for all scenarios with multi-index support""" + if not self.scenarios: + return pd.DataFrame() + + sortables_dfs = [] + scenario_keys = [] + for scenario in self.scenarios: - return scenario.sortables.to_dataframe() + df = scenario.sortables.to_dataframe() + if not df.empty: + sortables_dfs.append(df) + scenario_keys.append(scenario.identifier()) + + if not sortables_dfs: + return pd.DataFrame() + + return pd.concat( + sortables_dfs, + axis=1, + keys=scenario_keys, + ) class CustomCurvesPack(Packable): key: ClassVar[str] = "custom_curves" + sheet_name: ClassVar[str] = "CUSTOM_CURVES" def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: - """PACKS ONLY FIRST SCENARIO""" + """Pack custom curves data for all scenarios with multi-index support""" + if not self.scenarios: + return pd.DataFrame() + + curves_dfs = [] + scenario_keys = [] + for scenario in self.scenarios: series_list = list(scenario.custom_curves_series()) - if len(series_list) == 0: - continue - return pd.concat(series_list, axis=1) - return pd.DataFrame() + if len(series_list) > 0: + df = pd.concat(series_list, axis=1) + curves_dfs.append(df) + scenario_keys.append(scenario.identifier()) + + if not curves_dfs: + return pd.DataFrame() + + return pd.concat( + curves_dfs, + axis=1, + keys=scenario_keys, + ) class OutputCurvesPack(Packable): key: ClassVar[str] = "output_curves" + sheet_name: ClassVar[str] = "OUTPUT_CURVES" def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: - """PACKS ONLY FIRST SCENARIO""" + """Pack output curves data for all scenarios with multi-index support""" + if not self.scenarios: + return pd.DataFrame() + + curves_dfs = [] + scenario_keys = [] + for scenario in self.scenarios: series_list = list(scenario.all_output_curves()) - if len(series_list) == 0: - continue - return pd.concat(series_list, axis=1) - return pd.DataFrame() + if len(series_list) > 0: + df = pd.concat(series_list, axis=1) + curves_dfs.append(df) + scenario_keys.append(scenario.identifier()) + + if not curves_dfs: + return pd.DataFrame() + + return pd.concat( + curves_dfs, + axis=1, + keys=scenario_keys, + ) class ScenarioPacker(BaseModel): """ Packs one or multiple scenarios for export to dataframes or excel - - TODO: This class doesn't inherit from Base so it doesn't use the warning system yet - consider this further. """ # To avoid keeping all in memory, the packer only remembers which scenarios @@ -134,7 +192,6 @@ class ScenarioPacker(BaseModel): _sortables: "SortablePack" = SortablePack() _output_curves: "OutputCurvesPack" = OutputCurvesPack() - # Setting up a packer def add(self, *scenarios): @@ -165,7 +222,9 @@ def main_info(self) -> pd.DataFrame: if len(self._scenarios()) == 0: return pd.DataFrame() - return pd.concat([scenario.to_dataframe() for scenario in self._scenarios()], axis=1) + return pd.concat( + [scenario.to_dataframe() for scenario in self._scenarios()], axis=1 + ) def inputs(self, columns="user") -> pd.DataFrame: return self._inputs.to_dataframe(columns=columns) @@ -183,27 +242,34 @@ def output_curves(self) -> pd.DataFrame: return self._output_curves.to_dataframe() def to_excel(self, path: str): - """Export to Excel with simplified approach""" if len(self._scenarios()) == 0: raise ValueError("Packer was empty, nothing to export") workbook = Workbook(path) - # TODO: this should come from the packs, they should know their sheet names - # Like this they can pack and unpack - sheet_configs = [ - ("MAIN", self.main_info), - ("PARAMETERS", self.inputs), - ("GQUERIES_RESULTS", self.gquery_results), - ("SORTABLES", self.sortables), - ("CUSTOM_CURVES", self.custom_curves), - ("OUTPUT_CURVES", self.output_curves), - ] + # Main info sheet (handled separately as it doesn't use a pack) + df = self.main_info() + if not df.empty: + df_filled = df.fillna("").infer_objects(copy=False) + add_frame_with_scenario_styling( + name="MAIN", + frame=df_filled, + workbook=workbook, + column_width=18, + scenario_styling=True, + ) - for sheet_name, data_method in sheet_configs: - df = data_method() + for pack in self.all_pack_data(): + df = pack.to_dataframe() if not df.empty: - add_frame(sheet_name, df.fillna(""), workbook, column_width=18) + df_filled = df.fillna("").infer_objects(copy=False) + add_frame_with_scenario_styling( + name=pack.sheet_name, + frame=df_filled, + workbook=workbook, + column_width=18, + scenario_styling=True, + ) workbook.close() @@ -247,25 +313,31 @@ def get_summary(self) -> Dict[str, Any]: @classmethod def from_excel(cls, filepath: str | PathLike): - # TODO: Make the sheet name an attr on the packs, - # which user can customize if needed, from args in this method!! packer = cls() with pd.ExcelFile(filepath) as xlsx: # Open main tab - create scenarios from there - scenarios = packer.scenarios_from_df(packer.read_sheet(xlsx, "MAIN", index_col=0)) + scenarios = packer.scenarios_from_df( + packer.read_sheet(xlsx, "MAIN", index_col=0) + ) # TODO: add some kind of IF, is the inputs sheet available? packer._inputs.add(*scenarios) - packer._inputs.from_dataframe(packer.read_sheet(xlsx, "PARAMETERS", header=[0,1], index_col=[0,1])) + packer._inputs.from_dataframe( + packer.read_sheet( + xlsx, packer._inputs.sheet_name, header=[0, 1], index_col=[0, 1] + ) + ) # TODO: continue for sortables, curves and gqueries - @staticmethod def scenarios_from_df(df: pd.DataFrame) -> list["Scenario"]: """Converts one df into a list of scenarios""" - return [ScenarioPacker.setup_scenario(title, data) for title, data in df.to_dict().items()] + return [ + ScenarioPacker.setup_scenario(title, data) + for title, data in df.to_dict().items() + ] @staticmethod def setup_scenario(title, data): @@ -273,7 +345,7 @@ def setup_scenario(title, data): # TODO: take care of NaN values in data(frame)! Make sure they'll be None! # TODO: when there is no id in the data, we should call 'new' # else 'load' + 'update_metadata' - scenario = Scenario.load(data['id']) + scenario = Scenario.load(data["id"]) # TODO: update metadata with the rest of the stuff in data!! scenario.title = title return scenario @@ -282,21 +354,22 @@ def setup_scenario(title, data): # Straight from Rob @staticmethod def read_sheet( - xlsx: pd.ExcelFile, - sheet_name: str, - required: bool = True, - **kwargs + xlsx: pd.ExcelFile, sheet_name: str, required: bool = True, **kwargs ) -> pd.Series: """read list items""" if not sheet_name in xlsx.sheet_names: if required: - raise ValueError(f"Could not load required sheet '{sheet_name}' from {xlsx.io}") - logger.warning("Could not load optional sheet '%s' from '%s'", sheet_name, xlsx.io) + raise ValueError( + f"Could not load required sheet '{sheet_name}' from {xlsx.io}" + ) + logger.warning( + "Could not load optional sheet '%s' from '%s'", sheet_name, xlsx.io + ) return pd.Series(name=sheet_name, dtype=str) values = pd.read_excel(xlsx, sheet_name, **kwargs).squeeze(axis=1) # if not isinstance(values, pd.Series): # raise TypeError("Unexpected Outcome") - return values#.rename(sheet_name) + return values # .rename(sheet_name) diff --git a/src/pyetm/utils/excel.py b/src/pyetm/utils/excel.py index 0dc4b61..60ca4cf 100644 --- a/src/pyetm/utils/excel.py +++ b/src/pyetm/utils/excel.py @@ -69,7 +69,49 @@ def write_index( worksheet.write(row + row_offset, 0, value) -def add_frame( +def create_scenario_formats(workbook: Workbook) -> dict: + """Create alternating background formats for scenario blocks""" + return { + "white_header": workbook.add_format( + {"bold": True, "bg_color": "#FFFFFF", "border": 1, "align": "center"} + ), + "grey_header": workbook.add_format( + {"bold": True, "bg_color": "#F2F2F2", "border": 1, "align": "center"} + ), + "white_data": workbook.add_format({"bg_color": "#FFFFFF", "border": 1}), + "grey_data": workbook.add_format({"bg_color": "#F2F2F2", "border": 1}), + "bold": workbook.add_format({"bold": True}), + "default": None, + } + + +def get_scenario_blocks(columns: pd.MultiIndex) -> List[tuple]: + """ + Identify scenario blocks in multi-index columns + Returns list of (scenario_name, start_col, end_col) tuples + """ + if not isinstance(columns, pd.MultiIndex): + return [] + + blocks = [] + current_scenario = None + start_col = None + + for i, (scenario, _) in enumerate(columns): + if scenario != current_scenario: + if current_scenario is not None: + blocks.append((current_scenario, start_col, i - 1)) + current_scenario = scenario + start_col = i + + # Add the last block + if current_scenario is not None: + blocks.append((current_scenario, start_col, len(columns) - 1)) + + return blocks + + +def add_frame_with_scenario_styling( name: str, frame: pd.DataFrame, workbook: Workbook, @@ -80,8 +122,9 @@ def add_frame( bold_headers: bool = True, nan_as_formula: bool = True, decimal_precision: int = 10, + scenario_styling: bool = True, ) -> Worksheet: - """Add DataFrame to workbook as a new worksheet""" + """Enhanced add_frame with scenario block styling""" # Create worksheet worksheet = workbook.add_worksheet(str(name)) @@ -94,8 +137,15 @@ def add_frame( ), ) - # Create bold format - bold_format = workbook.add_format({"bold": True}) if bold_headers else None + # Create formats + formats = ( + create_scenario_formats(workbook) + if scenario_styling + else { + "bold": workbook.add_format({"bold": True}) if bold_headers else None, + "default": None, + } + ) # Calculate offsets col_offset = frame.index.nlevels if index else 0 @@ -105,37 +155,94 @@ def add_frame( if index and frame.index.names != [None] * frame.index.nlevels: row_offset += 1 - # Write column headers - if isinstance(frame.columns, pd.MultiIndex): + # Handle multi-index columns with scenario styling + if isinstance(frame.columns, pd.MultiIndex) and scenario_styling: + # Get scenario blocks for alternating colors + scenario_blocks = get_scenario_blocks(frame.columns) + # Write column names - if index and frame.columns.names != [None] * frame.columns.nlevels: + if frame.columns.names != [None] * frame.columns.nlevels: for idx, name in enumerate(frame.columns.names): if name is not None: - worksheet.write(idx, col_offset - 1, name, bold_format) + worksheet.write(idx, col_offset - 1, name, formats["bold"]) - # Write column values + # Write column headers with alternating scenario backgrounds for col_num, values in enumerate(frame.columns.values): + # Determine which scenario block this column belongs to + scenario_idx = next( + ( + i + for i, (_, start, end) in enumerate(scenario_blocks) + if start <= col_num <= end + ), + 0, + ) + is_grey = scenario_idx % 2 == 1 + header_format = ( + formats["grey_header"] if is_grey else formats["white_header"] + ) + for row_num, value in enumerate(values): - worksheet.write(row_num, col_num + col_offset, value, bold_format) + worksheet.write(row_num, col_num + col_offset, value, header_format) + + # Write data with scenario block coloring + for row_num, row_data in enumerate(frame.values): + for col_num, value in enumerate(row_data): + # Determine scenario block + scenario_idx = next( + ( + i + for i, (_, start, end) in enumerate(scenario_blocks) + if start <= col_num <= end + ), + 0, + ) + is_grey = scenario_idx % 2 == 1 + data_format = formats["grey_data"] if is_grey else formats["white_data"] + + worksheet.write( + row_num + row_offset, col_num + col_offset, value, data_format + ) + else: - # Write simple column headers - for col_num, value in enumerate(frame.columns.values): - worksheet.write(row_offset - 1, col_num + col_offset, value, bold_format) + # Standard column handling (single-index or no scenario styling) + bold_format = formats.get("bold") if bold_headers else None + + if isinstance(frame.columns, pd.MultiIndex): + # Write column names without styling + if frame.columns.names != [None] * frame.columns.nlevels: + for idx, name in enumerate(frame.columns.names): + if name is not None: + worksheet.write(idx, col_offset - 1, name, bold_format) + + # Write column values + for col_num, values in enumerate(frame.columns.values): + for row_num, value in enumerate(values): + worksheet.write(row_num, col_num + col_offset, value, bold_format) + else: + # Write simple column headers + for col_num, value in enumerate(frame.columns.values): + worksheet.write( + row_offset - 1, col_num + col_offset, value, bold_format + ) + + # Write data without styling + for row_num, row_data in enumerate(frame.values): + for col_num, value in enumerate(row_data): + worksheet.write(row_num + row_offset, col_num + col_offset, value) # Set column widths set_column_widths(worksheet, col_offset, len(frame.columns), column_width) - # Write data - for row_num, row_data in enumerate(frame.values): - for col_num, value in enumerate(row_data): - worksheet.write(row_num + row_offset, col_num + col_offset, value) - - # Write index + # Write index with proper styling for scenario sheets if index: set_column_widths( worksheet, 0, frame.index.nlevels, index_width or column_width ) - write_index(worksheet, frame.index, row_offset, bold_format) + + # Create index format matching the styling + index_format = formats.get("bold") if bold_headers else None + write_index(worksheet, frame.index, row_offset, index_format) # Freeze panes if freeze_panes: @@ -144,6 +251,34 @@ def add_frame( return worksheet +def add_frame( + name: str, + frame: pd.DataFrame, + workbook: Workbook, + index: bool = True, + column_width: Union[int, List[int], None] = None, + index_width: Union[int, List[int], None] = None, + freeze_panes: bool = True, + bold_headers: bool = True, + nan_as_formula: bool = True, + decimal_precision: int = 10, +) -> Worksheet: + """Original add_frame function for backward compatibility""" + return add_frame_with_scenario_styling( + name=name, + frame=frame, + workbook=workbook, + index=index, + column_width=column_width, + index_width=index_width, + freeze_panes=freeze_panes, + bold_headers=bold_headers, + nan_as_formula=nan_as_formula, + decimal_precision=decimal_precision, + scenario_styling=False, # Default to old behavior + ) + + def add_series( name: str, series: pd.Series, @@ -156,7 +291,7 @@ def add_series( nan_as_formula: bool = True, decimal_precision: int = 10, ) -> Worksheet: - """Add Series to workbook as a new worksheet""" + """Add Series to workbook as a new worksheet - unchanged""" # Create worksheet worksheet = workbook.add_worksheet(str(name)) From 850d38300f32f92afec62204732322f0e094b3bf Mon Sep 17 00:00:00 2001 From: louispt1 Date: Fri, 8 Aug 2025 10:19:55 +0200 Subject: [PATCH 03/17] Unpack for inputs and metadata first implementation no tests --- ...nario.ipynb => custom_curve_from_df.ipynb} | 31 +-- examples/excel_to_scenarios.ipynb | 230 ++++++++++++++++ examples/scenario_to_excel.ipynb | 105 ++------ src/pyetm/models/scenario.py | 20 +- src/pyetm/models/scenario_packer.py | 248 +++++++++++++++--- 5 files changed, 480 insertions(+), 154 deletions(-) rename examples/{excel_to_scenario.ipynb => custom_curve_from_df.ipynb} (89%) create mode 100644 examples/excel_to_scenarios.ipynb diff --git a/examples/excel_to_scenario.ipynb b/examples/custom_curve_from_df.ipynb similarity index 89% rename from examples/excel_to_scenario.ipynb rename to examples/custom_curve_from_df.ipynb index dcddc81..2136054 100644 --- a/examples/excel_to_scenario.ipynb +++ b/examples/custom_curve_from_df.ipynb @@ -18,22 +18,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "c617dc0a", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Found 3 curve files\n", - "✓ Loaded curve 'interconnector_8_price': 8760 values\n", - "✓ Loaded curve 'electric_vehicle_profile_5': 8760 values\n", - "✓ Loaded curve 'agriculture_electricity': 8760 values\n", - "Created DataFrame with 3 curves and 8760 rows\n" - ] - } - ], + "outputs": [], "source": [ "# For now a custom csv to pd df function - this will be handled by the reverse packer in the end\n", "\n", @@ -145,21 +133,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "e75a03b2", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Environment setup complete\n", - " Using ETM API at http://localhost:3000/api/v3\n", - " Token loaded? True\n", - "API connection ready\n" - ] - } - ], + "outputs": [], "source": [ "from example_helpers import setup_notebook\n", "from pyetm.models import Scenario\n", diff --git a/examples/excel_to_scenarios.ipynb b/examples/excel_to_scenarios.ipynb new file mode 100644 index 0000000..5f4b2d7 --- /dev/null +++ b/examples/excel_to_scenarios.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "70d54062", + "metadata": {}, + "source": [ + "This notebook is for demonstrating and testing the excel to scenarios flow.\n", + "\n", + "Currently can only handle metadata and inputs." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4866f9d1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Environment setup complete\n", + " Using ETM API at http://localhost:3000/api/v3\n", + " Token loaded? True\n", + "API connection ready\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:204: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " self.update_user_values(series.fillna(\"reset\").to_dict())\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
A: Create from excel2690288
useruser
inputunit
climate_relevant_co2_biomass_gas_future%30.00.0
climate_relevant_co2_biomass_gas_present%20.00.0
climate_relevant_co2_biomass_liquid_future%30.00.0
climate_relevant_co2_biomass_liquid_present%20.00.0
climate_relevant_co2_biomass_solid_future%30.00.0
............
capacity_of_energy_battery_wind_turbine_inlandMWNaN0.0
capacity_of_energy_power_hybrid_wind_turbine_offshoreMWNaNNone
capacity_of_energy_power_wind_turbine_coastalMWNaN0.0
capacity_of_energy_power_wind_turbine_inlandMWNaN15000.0
capacity_of_energy_power_wind_turbine_offshoreMWNaN37000.0
\n", + "

1326 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " A: Create from excel \\\n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 30.0 \n", + "climate_relevant_co2_biomass_gas_present % 20.0 \n", + "climate_relevant_co2_biomass_liquid_future % 30.0 \n", + "climate_relevant_co2_biomass_liquid_present % 20.0 \n", + "climate_relevant_co2_biomass_solid_future % 30.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", + "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", + "capacity_of_energy_power_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", + "\n", + " 2690288 \n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 0.0 \n", + "climate_relevant_co2_biomass_gas_present % 0.0 \n", + "climate_relevant_co2_biomass_liquid_future % 0.0 \n", + "climate_relevant_co2_biomass_liquid_present % 0.0 \n", + "climate_relevant_co2_biomass_solid_future % 0.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", + "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", + "capacity_of_energy_power_wind_turbine_inland MW 15000.0 \n", + "capacity_of_energy_power_wind_turbine_offshore MW 37000.0 \n", + "\n", + "[1326 rows x 2 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from example_helpers import setup_notebook\n", + "from pyetm.models.scenario_packer import ScenarioPacker\n", + "\n", + "\n", + "setup_notebook()\n", + "packer = ScenarioPacker.from_excel(\"my_input_excel.xlsx\")\n", + "packer.inputs()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd08ff26", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pyetm-qKH2ozgc", + "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.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/scenario_to_excel.ipynb b/examples/scenario_to_excel.ipynb index 641f69b..05232b2 100644 --- a/examples/scenario_to_excel.ipynb +++ b/examples/scenario_to_excel.ipynb @@ -10,21 +10,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "4e9a9e7c", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Environment setup complete\n", - " Using ETM API at https://beta.engine.energytransitionmodel.com/api/v3\n", - " Token loaded? True\n", - "API connection ready\n" - ] - } - ], + "outputs": [], "source": [ "from example_helpers import setup_notebook\n", "from pyetm.models import Scenario\n", @@ -50,13 +39,13 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "c4f42def", "metadata": {}, "outputs": [], "source": [ "# Example beta scenario\n", - "scenario = Scenario.load(2704433)\n", + "scenario = Scenario.load(2690456)\n", "\n", "# Example pro scenario\n", "# scenario = Scenario.load(1340415)" @@ -107,59 +96,17 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "fa8ac6ab", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 2704434 \\\n", - " value default \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % None 0.0 \n", - "climate_relevant_co2_biomass_gas_present % None 0.0 \n", - "climate_relevant_co2_biomass_liquid_future % None 0.0 \n", - "climate_relevant_co2_biomass_liquid_present % None 0.0 \n", - "climate_relevant_co2_biomass_solid_future % None 0.0 \n", - "... ... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW None 0.0 \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW None 0.0 \n", - "capacity_of_energy_power_wind_turbine_coastal MW None 1106.189347 \n", - "capacity_of_energy_power_wind_turbine_inland MW None 2421.16051 \n", - "capacity_of_energy_power_wind_turbine_offshore MW None 956.994305 \n", - "\n", - " 2704433 \n", - " value default \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 0.0 0.0 \n", - "climate_relevant_co2_biomass_gas_present % 0.0 0.0 \n", - "climate_relevant_co2_biomass_liquid_future % 0.0 0.0 \n", - "climate_relevant_co2_biomass_liquid_present % 0.0 0.0 \n", - "climate_relevant_co2_biomass_solid_future % 0.0 0.0 \n", - "... ... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW 0.0 0.0 \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW None 0.0 \n", - "capacity_of_energy_power_wind_turbine_coastal MW 0.0 0.0 \n", - "capacity_of_energy_power_wind_turbine_inland MW 10000.0 10000.0 \n", - "capacity_of_energy_power_wind_turbine_offshore MW 38000.0 38000.0 \n", - "\n", - "[1318 rows x 4 columns]\n", - " 2704434 2704433\n", - "end_year 2050 2050\n", - "private False False\n", - "area_code nl2019 nl2019\n", - "template None 2402170\n" - ] - } - ], + "outputs": [], "source": [ "from pyetm.models import ScenarioPacker\n", "\n", "packer = ScenarioPacker()\n", "\n", - "scenario2 = Scenario.load(2704434)\n", + "scenario = Scenario.load(2690456)\n", + "scenario2 = Scenario.load(2690455)\n", "# Ready the scenario for inputs\n", "packer.add_inputs(scenario)\n", "packer.add_inputs(scenario2)\n", @@ -179,21 +126,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "739e2a12", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 2704433\n", - " future\n", - "dashboard_total_costs bln_euro 64.226691\n", - "dashboard_co2_emissions_versus_start_year factor -1.026581\n" - ] - } - ], + "outputs": [], "source": [ "scenario.add_queries(\n", " [\"dashboard_total_costs\", \"dashboard_co2_emissions_versus_start_year\"]\n", @@ -212,19 +148,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "ce5e2bdb", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/noracato/code/work/packages/pyetm/src/pyetm/models/scenario_packer.py:245: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", - " add_frame(sheet_name, df.fillna(''), workbook, column_width=18)\n" - ] - } - ], + "outputs": [], "source": [ "scenario.add_queries(\n", " [\"dashboard_emissions\"]\n", @@ -242,7 +169,7 @@ "id": "68ce86c3", "metadata": {}, "source": [ - "Output curves are still not packing nicely:" + "Output curves:" ] }, { @@ -253,6 +180,12 @@ "outputs": [], "source": [ "packer.add_output_curves(scenario)\n", + "packer.add_output_curves(scenario2)\n", + "packer.add_custom_curves(scenario)\n", + "packer.add_custom_curves(scenario2)\n", + "packer.add_sortables(scenario)\n", + "packer.add_sortables(scenario2)\n", + "\n", "\n", "packer.to_excel('testing_output_curves.xlsx')" ] diff --git a/src/pyetm/models/scenario.py b/src/pyetm/models/scenario.py index b316592..3918f28 100644 --- a/src/pyetm/models/scenario.py +++ b/src/pyetm/models/scenario.py @@ -136,18 +136,19 @@ def _to_dataframe(self, **kwargs) -> pd.DataFrame: @property def title(self): if not self.metadata is None: - return self.metadata.get('title', None) + return self.metadata.get("title", None) return None @title.setter def title(self, title: str): if not self.metadata is None: - self.metadata['title'] = title + self.metadata["title"] = title else: - self.metadata = {'title': title} + self.metadata = {"title": title} def identifier(self): - if self.title: return self.title + if self.title: + return self.title return self.id @@ -195,11 +196,14 @@ def set_user_values_from_dataframe(self, dataframe: pd.DataFrame) -> None: """ Extract df to dict, set None/NaN sliders to reset, and call update_inputs. This ensures the dataframe exactly represents the inputs. - # TODO: Add validation for the dataframe structure """ - self.update_user_values( - dataframe["user"].droplevel("unit").fillna("reset").to_dict() - ) + series = dataframe["user"] + # If MultiIndex with 'unit', drop it + if isinstance(series.index, pd.MultiIndex) and "unit" in ( + series.index.names or [] + ): + series = series.droplevel("unit") + self.update_user_values(series.fillna("reset").to_dict()) def update_user_values(self, update_inputs: Dict[str, Any]) -> None: """ diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 6014cd4..db129ac 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -1,7 +1,7 @@ import pandas as pd import logging from os import PathLike -from pydantic import BaseModel +from pydantic import BaseModel, Field from typing import Optional, Dict, List, Any, Set, Literal, ClassVar from xlsxwriter import Workbook @@ -13,7 +13,8 @@ class Packable(BaseModel): - scenarios: Optional[set["Scenario"]] = set() + # Use a proper default set and keep the type consistent + scenarios: Set["Scenario"] = Field(default_factory=set) key: ClassVar[str] = "base_pack" sheet_name: ClassVar[str] = "SHEET" @@ -26,7 +27,8 @@ def discard(self, scenario): self.scenarios.discard(scenario) def clear(self): - self.scenarios = [] + # Reset to an empty set + self.scenarios.clear() def summary(self) -> dict: return {self.key: {"scenario_count": len(self.scenarios)}} @@ -64,16 +66,135 @@ def _to_dataframe(self, columns="user", **kwargs): keys=[scenario.identifier() for scenario in self.scenarios], ) + def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: + """Normalize various inputs sheet shapes into canonical shape: + - Drop leading completely blank rows. + - Detect two header rows (identifier row above a row containing 'user'). + - Support 1- or 2-level row index (input[, unit]). + Returns a DataFrame with: + index -> Index or MultiIndex (input[, unit]) + columns -> MultiIndex (identifier, 'user') + """ + # Drop completely empty rows + df = df.dropna(how="all") + if df.empty: + return df + + # Locate the row containing 'user' (case-insensitive) + user_row_pos = None + for pos, (_, row) in enumerate(df.iterrows()): + if any(isinstance(v, str) and v.strip().lower() == "user" for v in row): + user_row_pos = pos + break + if user_row_pos is None: + # Fallback: assume row 1 is the 'user' row + user_row_pos = 1 if len(df) > 1 else 0 + + header_start = max(user_row_pos - 1, 0) + header_end = user_row_pos # inclusive + + headers = df.iloc[header_start : header_end + 1].astype(str) + data = df.iloc[header_end + 1 :].copy() + + # Build MultiIndex columns from the two header rows + data.columns = pd.MultiIndex.from_arrays( + [headers.iloc[0].values, headers.iloc[1].values] + ) + + # Identify index columns as those whose second-level header is not 'user' + idx_cols = [ + col + for col in data.columns + if not (isinstance(col[1], str) and col[1].strip().lower() == "user") + ] + + # Choose input and optional unit columns + if len(idx_cols) == 0: + # No explicit index columns: assume first column is inputs + input_col = data.columns[0] + unit_col = None + else: + input_col = idx_cols[0] + unit_col = idx_cols[1] if len(idx_cols) > 1 else None + + # Construct index + input_series = data[input_col].astype(str) + if unit_col is not None: + unit_series = data[unit_col].astype(str) + index = pd.MultiIndex.from_arrays( + [input_series.values, unit_series.values], names=["input", "unit"] + ) + else: + index = pd.Index(input_series.values, name="input") + + # Drop index columns and keep only scenario columns + keep_cols = [ + c + for c in data.columns + if c not in {input_col} and (unit_col is None or c != unit_col) + ] + canonical = data[keep_cols] + canonical.index = index + + # Ensure second level equals 'user'; if not, set it + if isinstance(canonical.columns, pd.MultiIndex): + lvl1 = canonical.columns.get_level_values(1) + if not all( + isinstance(v, str) and v.strip().lower() == "user" for v in lvl1 + ): + canonical.columns = pd.MultiIndex.from_arrays( + [ + canonical.columns.get_level_values(0), + ["user"] * len(canonical.columns), + ] + ) + else: + canonical.columns = pd.MultiIndex.from_arrays( + [canonical.columns, ["user"] * len(canonical.columns)] + ) + + return canonical + def from_dataframe(self, df): """ Sets the inputs on the scenarios from the packed df (comes from excel) - In case came it came from a df containing defaults etc, lets drop them + Tolerates optional unit column and leading blank rows. """ - user_values = df.xs("user", level=1, axis=1, drop_level=False) - for identifier, _ in user_values: - breakpoint() + if df is None or getattr(df, "empty", False): + return + + # Canonicalize the incoming shape first + try: + df = self._normalize_inputs_dataframe(df) + except Exception as e: + logger.warning("Failed to normalize inputs sheet: %s", e) + return + + if df is None or df.empty: + return + + # Now df has columns MultiIndex (identifier, 'user') and index input or (input, unit) + identifiers = df.columns.get_level_values(0).unique() + + for identifier in identifiers: scenario = self._find_by_identifier(identifier) - scenario.set_user_values_from_dataframe(user_values[identifier]) + if scenario is None: + logger.warning( + "Could not find scenario for identifier '%s'", identifier + ) + continue + + scenario_df = df[identifier] + # Ensure DataFrame with a 'user' column + if isinstance(scenario_df, pd.Series): + scenario_df = scenario_df.to_frame(name="user") + else: + if list(scenario_df.columns) != ["user"]: + scenario_df = scenario_df.copy() + first_col = scenario_df.columns[0] + scenario_df = scenario_df.rename(columns={first_col: "user"}) + + scenario.set_user_values_from_dataframe(scenario_df) class QueryPack(Packable): @@ -312,42 +433,104 @@ def get_summary(self) -> Dict[str, Any]: # Create stuff @classmethod - def from_excel(cls, filepath: str | PathLike): + def from_excel( + cls, + filepath: str | PathLike, + sheet_names: Optional[Dict[str, str]] = None, + ): + """ + Build a ScenarioPacker from an Excel file. + sheet_names optionally maps logical pack keys to sheet titles, e.g.: + {"main": "MAIN", "inputs": "PARAMETERS"} + """ packer = cls() + sheet_names = sheet_names or {} with pd.ExcelFile(filepath) as xlsx: # Open main tab - create scenarios from there - scenarios = packer.scenarios_from_df( - packer.read_sheet(xlsx, "MAIN", index_col=0) - ) + main_sheet = sheet_names.get("main", "MAIN") + main_df = packer.read_sheet(xlsx, main_sheet, index_col=0) + scenarios = packer.scenarios_from_df(main_df) - # TODO: add some kind of IF, is the inputs sheet available? + # Inputs (optional): only process when the sheet exists + inputs_sheet = sheet_names.get("inputs", packer._inputs.sheet_name) packer._inputs.add(*scenarios) - packer._inputs.from_dataframe( - packer.read_sheet( - xlsx, packer._inputs.sheet_name, header=[0, 1], index_col=[0, 1] - ) + # Read raw to tolerate blank header rows; we'll canonicalize inside from_dataframe + inputs_df = packer.read_sheet( + xlsx, + inputs_sheet, + required=False, + header=None, ) + if isinstance(inputs_df, pd.DataFrame) and not inputs_df.empty: + packer._inputs.from_dataframe(inputs_df) # TODO: continue for sortables, curves and gqueries + return packer + @staticmethod def scenarios_from_df(df: pd.DataFrame) -> list["Scenario"]: - """Converts one df into a list of scenarios""" - return [ - ScenarioPacker.setup_scenario(title, data) - for title, data in df.to_dict().items() - ] + """Converts one df (MAIN) into a list of scenarios""" + scenarios: list[Scenario] = [] + + if isinstance(df, pd.Series): + identifier = df.name + data = df.to_dict() + scenarios.append(ScenarioPacker.setup_scenario(identifier, data)) + return scenarios + + # DataFrame: columns are scenario identifiers (id or a custom title) + for identifier in df.columns: + col_data = df[identifier].to_dict() + scenarios.append(ScenarioPacker.setup_scenario(identifier, col_data)) + + return scenarios @staticmethod - def setup_scenario(title, data): - """Returns a scenario from data dict""" - # TODO: take care of NaN values in data(frame)! Make sure they'll be None! - # TODO: when there is no id in the data, we should call 'new' - # else 'load' + 'update_metadata' - scenario = Scenario.load(data["id"]) - # TODO: update metadata with the rest of the stuff in data!! - scenario.title = title + def setup_scenario(identifier, data): + """Returns a scenario from data dict. + If the identifier is an int (or str-int), load; otherwise create new. + """ + # Normalize NA values to None + data = {k: (None if pd.isna(v) else v) for k, v in data.items()} + + scenario: Scenario + scenario_title: Optional[str] = ( + identifier if isinstance(identifier, str) and identifier != "" else None + ) + + # Try to interpret identifier as an ID + scenario_id: Optional[int] = None + if isinstance(identifier, (int, float)) and not pd.isna(identifier): + try: + scenario_id = int(identifier) + except Exception: + scenario_id = None + elif isinstance(identifier, str): + try: + scenario_id = int(identifier) + except ValueError: + scenario_id = None + + if scenario_id is not None: + # Load existing + scenario = Scenario.load(scenario_id) + else: + # Create new (requires end_year and area_code) + area_code = data.get("area_code") + end_year = data.get("end_year") + if area_code is None or end_year is None: + raise ValueError( + "Cannot create a new Scenario without 'area_code' and 'end_year'" + ) + scenario = Scenario.new(area_code=area_code, end_year=int(end_year)) + + # Set a title when a non-numeric identifier is provided + if scenario_title is not None: + scenario.title = scenario_title + + # TODO: update metadata with the rest of the stuff in data!! (keep minimal for now) return scenario # NOTE: Move to utils? @@ -368,8 +551,7 @@ def read_sheet( ) return pd.Series(name=sheet_name, dtype=str) - values = pd.read_excel(xlsx, sheet_name, **kwargs).squeeze(axis=1) - # if not isinstance(values, pd.Series): - # raise TypeError("Unexpected Outcome") + # Use the ExcelFile.parse API directly to avoid pandas' engine guard + values = xlsx.parse(sheet_name=sheet_name, **kwargs).squeeze(axis=1) return values # .rename(sheet_name) From 6dd177de560eb3ee25b7d95a698892f2b856fcbf Mon Sep 17 00:00:00 2001 From: louispt1 Date: Fri, 8 Aug 2025 11:59:51 +0200 Subject: [PATCH 04/17] Unpack for sortables and custom curves early commit before playing around --- src/pyetm/models/scenario_packer.py | 225 +++++++++++++++++++++++++++- src/pyetm/models/sortables.py | 6 +- 2 files changed, 226 insertions(+), 5 deletions(-) diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index db129ac..9e240e9 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -7,6 +7,7 @@ from pyetm.models.base import Base from pyetm.models import Scenario +from pyetm.models.custom_curves import CustomCurves from pyetm.utils.excel import add_frame_with_scenario_styling logger = logging.getLogger(__name__) @@ -242,6 +243,105 @@ def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: keys=scenario_keys, ) + def _normalize_sortables_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: + """Normalize various sortables sheet shapes. + Assumptions: + - Two header rows: first row = scenario identifier/title, second row = sortable name. + - Leading blank rows may exist and are ignored. + - Optional leftmost index column(s) are present with empty first header cell(s). They are dropped. + Returns a DataFrame with columns MultiIndex(identifier, sortable_name) and + simple Index rows with order positions. + """ + # Drop completely empty rows + df = df.dropna(how="all") + if df.empty: + return df + + # Find the first two non-empty rows -> headers + non_empty_idx = [ + i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() + ] + if not non_empty_idx: + return pd.DataFrame() + header0_pos = non_empty_idx[0] + header1_pos = non_empty_idx[1] if len(non_empty_idx) > 1 else header0_pos + 1 + + headers = df.iloc[[header0_pos, header1_pos]].astype(str) + data = df.iloc[header1_pos + 1 :].copy() + + # Build MultiIndex columns + col_level0 = headers.iloc[0].values + col_level1 = headers.iloc[1].values + columns = pd.MultiIndex.from_arrays([col_level0, col_level1]) + data.columns = columns + + # Drop columns where identifier (level 0) is missing/empty, and drop any + # column which is clearly the helper/index label (e.g. level1 == 'sortables'). + def _is_empty(v): + return ( + (not isinstance(v, str)) + or (v.strip() == "") + or (v.strip().lower() == "nan") + ) + + def _is_helper_label(v): + return isinstance(v, str) and v.strip().lower() in {"sortables"} + + keep_cols = [ + c + for c in data.columns + if not _is_empty(c[0]) and not _is_helper_label(c[1]) + ] + canonical = data[keep_cols].copy() + + # Result: MultiIndex columns (identifier, sortable_name), index as row number + canonical.reset_index(drop=True, inplace=True) + return canonical + + def from_dataframe(self, df: pd.DataFrame): + """Unpack and update sortables for each scenario from the sheet. + The sheet may contain optional leading blank rows and optional index columns. + """ + if df is None or getattr(df, "empty", False): + return + + try: + df = self._normalize_sortables_dataframe(df) + except Exception as e: + logger.warning("Failed to normalize sortables sheet: %s", e) + return + + if df is None or df.empty or not isinstance(df.columns, pd.MultiIndex): + return + + identifiers = df.columns.get_level_values(0).unique() + for identifier in identifiers: + scenario = self._find_by_identifier(identifier) + if scenario is None: + logger.warning( + "Could not find scenario for identifier '%s'", identifier + ) + continue + + block = df[identifier] + updates: Dict[str, List[Any]] = {} + for sortable_name in block.columns: + # Build list order by dropping NaNs/empties + values = ( + block[sortable_name] + .dropna() + .astype(str) + .map(lambda s: s.strip()) + .replace({"": pd.NA}) + .dropna() + .tolist() + ) + if values: + updates[str(sortable_name)] = values + + if updates: + scenario.update_sortables(updates) + class CustomCurvesPack(Packable): key: ClassVar[str] = "custom_curves" @@ -271,6 +371,103 @@ def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: keys=scenario_keys, ) + def _normalize_curves_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: + """Normalize custom curves sheet shapes. + Assumptions: + - Two header rows: first row = scenario identifier/title, second row = curve key. + - Leading blank rows may exist and are ignored. + - Optional leftmost index column(s) are present with empty first header cell(s); they are dropped. + - Rows are the hourly values (0..8759) or arbitrary length; we keep as-is. + Returns a DataFrame with columns MultiIndex(identifier, curve_key) and numeric rows. + """ + df = df.dropna(how="all") + if df.empty: + return df + + # Find header rows + non_empty_idx = [ + i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() + ] + if not non_empty_idx: + return pd.DataFrame() + header0_pos = non_empty_idx[0] + header1_pos = non_empty_idx[1] if len(non_empty_idx) > 1 else header0_pos + 1 + + headers = df.iloc[[header0_pos, header1_pos]].astype(str) + data = df.iloc[header1_pos + 1 :].copy() + + # Assign columns + columns = pd.MultiIndex.from_arrays( + [headers.iloc[0].values, headers.iloc[1].values] + ) + data.columns = columns + + # Drop non-scenario columns where identifier is empty and drop helper/index + # columns where level1 looks like a label (e.g., 'sortables') + def _is_empty(v): + return ( + (not isinstance(v, str)) + or (v.strip() == "") + or (v.strip().lower() == "nan") + ) + + def _is_helper_label(v): + return isinstance(v, str) and v.strip().lower() in {"sortables"} + + keep_cols = [ + c + for c in data.columns + if not _is_empty(c[0]) and not _is_helper_label(c[1]) + ] + canonical = data[keep_cols].copy() + + # Reset index to numeric starting at 0 + canonical.reset_index(drop=True, inplace=True) + return canonical + + def from_dataframe(self, df: pd.DataFrame): + """Unpack and update custom curves for each scenario. + Sheet may contain leading blank rows and optional index columns. + """ + if df is None or getattr(df, "empty", False): + return + + try: + df = self._normalize_curves_dataframe(df) + except Exception as e: + logger.warning("Failed to normalize custom curves sheet: %s", e) + return + + if df is None or df.empty or not isinstance(df.columns, pd.MultiIndex): + return + + identifiers = df.columns.get_level_values(0).unique() + for identifier in identifiers: + scenario = self._find_by_identifier(identifier) + if scenario is None: + logger.warning( + "Could not find scenario for identifier '%s'", identifier + ) + continue + + block = df[identifier] + # Build a CustomCurves collection from the block columns + try: + curves = CustomCurves._from_dataframe(block) + except Exception as e: + logger.warning( + "Failed to build custom curves for '%s': %s", identifier, e + ) + continue + + # Validate and upload + try: + scenario.update_custom_curves(curves) + except Exception as e: + logger.warning( + "Failed to update custom curves for '%s': %s", identifier, e + ) + class OutputCurvesPack(Packable): key: ClassVar[str] = "output_curves" @@ -465,7 +662,33 @@ def from_excel( if isinstance(inputs_df, pd.DataFrame) and not inputs_df.empty: packer._inputs.from_dataframe(inputs_df) - # TODO: continue for sortables, curves and gqueries + # Sortables (optional) + sortables_sheet = ( + sheet_names.get("sortables", packer._sortables.sheet_name) + if sheet_names + else packer._sortables.sheet_name + ) + sortables_df = packer.read_sheet( + xlsx, sortables_sheet, required=False, header=None + ) + if isinstance(sortables_df, pd.DataFrame) and not sortables_df.empty: + packer._sortables.add(*scenarios) + packer._sortables.from_dataframe(sortables_df) + + # Custom curves (optional) + curves_sheet = ( + sheet_names.get("custom_curves", packer._custom_curves.sheet_name) + if sheet_names + else packer._custom_curves.sheet_name + ) + curves_df = packer.read_sheet( + xlsx, curves_sheet, required=False, header=None + ) + if isinstance(curves_df, pd.DataFrame) and not curves_df.empty: + packer._custom_curves.add(*scenarios) + packer._custom_curves.from_dataframe(curves_df) + + # TODO: gqueries unpack not supported (read-only) return packer diff --git a/src/pyetm/models/sortables.py b/src/pyetm/models/sortables.py index 9e1c559..e22b472 100644 --- a/src/pyetm/models/sortables.py +++ b/src/pyetm/models/sortables.py @@ -83,13 +83,11 @@ def validate_order(cls, value: list[Any]) -> list[Any]: @model_validator(mode="after") def validate_sortable_consistency(self) -> "Sortable": """Additional validation for the entire sortable""" - # Example: validate that certain types require subtypes if self.type == "heat_network" and self.subtype is None: raise ValueError("heat_network type requires a subtype") - # TODO: check how long these actually ought to be - if len(self.order) > 10: - raise ValueError("Order cannot contain more than 10 items") + if len(self.order) > 17: + raise ValueError("Order cannot contain more than 17 items") return self From eaaef12af94889b2e506ad1a264465a56dc01952 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Fri, 8 Aug 2025 13:32:51 +0200 Subject: [PATCH 05/17] From dataset for sortables --- examples/excel_to_scenarios.ipynb | 1277 +++++++++++++++++++++++++-- examples/exploring_a_scenario.ipynb | 23 +- src/pyetm/models/scenario.py | 13 +- src/pyetm/models/scenario_packer.py | 21 +- src/pyetm/models/sortables.py | 39 + 5 files changed, 1295 insertions(+), 78 deletions(-) diff --git a/examples/excel_to_scenarios.ipynb b/examples/excel_to_scenarios.ipynb index 5f4b2d7..1302010 100644 --- a/examples/excel_to_scenarios.ipynb +++ b/examples/excel_to_scenarios.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 7, "id": "4866f9d1", "metadata": {}, "outputs": [ @@ -30,8 +30,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:204: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", - " self.update_user_values(series.fillna(\"reset\").to_dict())\n" + "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:206: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " self.update_user_values(series.fillna(\"reset\").to_dict())\n", + "Could not find scenario for identifier '2690555'\n", + "Could not find scenario for identifier '2690555'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'total_scenarios': 2, 'inputs': {'scenario_count': 2}, 'sortables': {'scenario_count': 2}, 'custom_curves': {'scenario_count': 2}, 'output_curves': {'scenario_count': 0}, 'scenario_ids': [2690555, 2690585]}\n" ] }, { @@ -60,8 +69,8 @@ " \n", " \n", " \n", + " 2690555\n", " A: Create from excel\n", - " 2690288\n", " \n", " \n", " \n", @@ -80,32 +89,32 @@ " \n", " climate_relevant_co2_biomass_gas_future\n", " %\n", - " 30.0\n", " 0.0\n", + " 30.0\n", " \n", " \n", " climate_relevant_co2_biomass_gas_present\n", " %\n", - " 20.0\n", " 0.0\n", + " 20.0\n", " \n", " \n", " climate_relevant_co2_biomass_liquid_future\n", " %\n", - " 30.0\n", " 0.0\n", + " 30.0\n", " \n", " \n", " climate_relevant_co2_biomass_liquid_present\n", " %\n", - " 20.0\n", " 0.0\n", + " 20.0\n", " \n", " \n", " climate_relevant_co2_biomass_solid_future\n", " %\n", - " 30.0\n", " 0.0\n", + " 30.0\n", " \n", " \n", " ...\n", @@ -116,73 +125,73 @@ " \n", " capacity_of_energy_battery_wind_turbine_inland\n", " MW\n", - " NaN\n", " 0.0\n", + " NaN\n", " \n", " \n", " capacity_of_energy_power_hybrid_wind_turbine_offshore\n", " MW\n", - " NaN\n", " None\n", + " NaN\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_coastal\n", " MW\n", - " NaN\n", " 0.0\n", + " NaN\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_inland\n", " MW\n", + " 20000.0\n", " NaN\n", - " 15000.0\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_offshore\n", " MW\n", + " 52000.0\n", " NaN\n", - " 37000.0\n", " \n", " \n", "\n", - "

1326 rows × 2 columns

\n", + "

1318 rows × 2 columns

\n", "" ], "text/plain": [ - " A: Create from excel \\\n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 30.0 \n", - "climate_relevant_co2_biomass_gas_present % 20.0 \n", - "climate_relevant_co2_biomass_liquid_future % 30.0 \n", - "climate_relevant_co2_biomass_liquid_present % 20.0 \n", - "climate_relevant_co2_biomass_solid_future % 30.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", - "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", - "capacity_of_energy_power_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", - "\n", - " 2690288 \n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 0.0 \n", - "climate_relevant_co2_biomass_gas_present % 0.0 \n", - "climate_relevant_co2_biomass_liquid_future % 0.0 \n", - "climate_relevant_co2_biomass_liquid_present % 0.0 \n", - "climate_relevant_co2_biomass_solid_future % 0.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", - "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", - "capacity_of_energy_power_wind_turbine_inland MW 15000.0 \n", - "capacity_of_energy_power_wind_turbine_offshore MW 37000.0 \n", - "\n", - "[1326 rows x 2 columns]" + " 2690555 \\\n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 0.0 \n", + "climate_relevant_co2_biomass_gas_present % 0.0 \n", + "climate_relevant_co2_biomass_liquid_future % 0.0 \n", + "climate_relevant_co2_biomass_liquid_present % 0.0 \n", + "climate_relevant_co2_biomass_solid_future % 0.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", + "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", + "capacity_of_energy_power_wind_turbine_inland MW 20000.0 \n", + "capacity_of_energy_power_wind_turbine_offshore MW 52000.0 \n", + "\n", + " A: Create from excel \n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 30.0 \n", + "climate_relevant_co2_biomass_gas_present % 20.0 \n", + "climate_relevant_co2_biomass_liquid_future % 30.0 \n", + "climate_relevant_co2_biomass_liquid_present % 20.0 \n", + "climate_relevant_co2_biomass_solid_future % 30.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", + "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", + "capacity_of_energy_power_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", + "\n", + "[1318 rows x 2 columns]" ] }, - "execution_count": 3, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -194,16 +203,1184 @@ "\n", "setup_notebook()\n", "packer = ScenarioPacker.from_excel(\"my_input_excel.xlsx\")\n", + "summary = packer.get_summary()\n", + "print(summary)\n", "packer.inputs()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "cd08ff26", "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
2690555A: Create from excel
forecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_htforecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_ht
sortables
0households_flexibility_p2p_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_waterhouseholds_flexibility_p2p_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_water
1transport_car_flexibility_p2p_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricityenergy_flexibility_mv_batteries_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricity
2energy_flexibility_mv_batteries_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coaltransport_car_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coal
3energy_flexibility_flow_batteries_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oilenergy_flexibility_flow_batteries_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oil
4energy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogenenergy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogen
5energy_flexibility_pumped_storage_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gastransport_bus_flexibility_p2p_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gas
6transport_bus_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mixtransport_truck_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mix
7transport_truck_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pelletstransport_van_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pellets
8transport_van_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricityenergy_flexibility_pumped_storage_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricity
9NoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...NoneNoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...None
10NoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...None
11NoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...None
12NoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNoneNoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNone
13NoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNoneNoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNone
14NoneNoneNonehouseholds_space_heater_network_gasNoneNoneNoneNoneNoneNonehouseholds_space_heater_network_gasNoneNoneNone
15NoneNoneNonehouseholds_space_heater_coalNoneNoneNoneNoneNoneNonehouseholds_space_heater_coalNoneNoneNone
16NoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNoneNoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNone
\n", + "
" + ], + "text/plain": [ + " 2690555 \\\n", + " forecast_storage \n", + "sortables \n", + "0 households_flexibility_p2p_electricity \n", + "1 transport_car_flexibility_p2p_electricity \n", + "2 energy_flexibility_mv_batteries_electricity \n", + "3 energy_flexibility_flow_batteries_electricity \n", + "4 energy_flexibility_hv_opac_electricity \n", + "5 energy_flexibility_pumped_storage_electricity \n", + "6 transport_bus_flexibility_p2p_electricity \n", + "7 transport_truck_flexibility_p2p_electricity \n", + "8 transport_van_flexibility_p2p_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_supply \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 energy_hydrogen_autothermal_reformer_dispatchable \n", + "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", + "4 energy_hydrogen_ammonia_reformer_dispatchable \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_demand \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 None \n", + "3 None \n", + "4 None \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " space_heating \n", + "sortables \n", + "0 households_space_heater_district_heating_lt_st... \n", + "1 households_space_heater_heatpump_surface_water... \n", + "2 households_space_heater_heatpump_air_water_ele... \n", + "3 households_space_heater_heatpump_ground_water_... \n", + "4 households_space_heater_heatpump_pvt_electricity \n", + "5 households_space_heater_district_heating_mt_st... \n", + "6 households_space_heater_hybrid_heatpump_air_wa... \n", + "7 households_space_heater_hybrid_hydrogen_heatpu... \n", + "8 households_space_heater_hybrid_crude_oil_heatp... \n", + "9 households_space_heater_district_heating_ht_st... \n", + "10 households_space_heater_electricity \n", + "11 households_space_heater_combined_network_gas \n", + "12 households_space_heater_combined_hydrogen \n", + "13 households_space_heater_wood_pellets \n", + "14 households_space_heater_network_gas \n", + "15 households_space_heater_coal \n", + "16 households_space_heater_crude_oil \n", + "\n", + " \\\n", + " heat_network_lt \n", + "sortables \n", + "0 energy_heat_network_storage_lt_steam_hot_water \n", + "1 energy_heat_boiler_lt_electricity \n", + "2 energy_heat_burner_lt_hydrogen \n", + "3 energy_heat_heatpump_water_water_lt_electricity \n", + "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", + "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", + "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_mt \n", + "sortables \n", + "0 energy_heat_network_storage_mt_steam_hot_water \n", + "1 energy_heat_boiler_mt_electricity \n", + "2 energy_heat_burner_mt_coal \n", + "3 energy_heat_burner_mt_crude_oil \n", + "4 energy_heat_burner_mt_hydrogen \n", + "5 energy_heat_burner_mt_network_gas \n", + "6 energy_heat_burner_mt_waste_mix \n", + "7 energy_heat_burner_mt_wood_pellets \n", + "8 energy_heat_heatpump_water_water_mt_electricity \n", + "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", + "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", + "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_ht \n", + "sortables \n", + "0 energy_heat_network_storage_ht_steam_hot_water \n", + "1 energy_heat_boiler_ht_electricity \n", + "2 energy_heat_burner_ht_coal \n", + "3 energy_heat_burner_ht_crude_oil \n", + "4 energy_heat_burner_ht_hydrogen \n", + "5 energy_heat_burner_ht_network_gas \n", + "6 energy_heat_burner_ht_waste_mix \n", + "7 energy_heat_burner_ht_wood_pellets \n", + "8 energy_heat_heatpump_water_water_ht_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " A: Create from excel \\\n", + " forecast_storage \n", + "sortables \n", + "0 households_flexibility_p2p_electricity \n", + "1 energy_flexibility_mv_batteries_electricity \n", + "2 transport_car_flexibility_p2p_electricity \n", + "3 energy_flexibility_flow_batteries_electricity \n", + "4 energy_flexibility_hv_opac_electricity \n", + "5 transport_bus_flexibility_p2p_electricity \n", + "6 transport_truck_flexibility_p2p_electricity \n", + "7 transport_van_flexibility_p2p_electricity \n", + "8 energy_flexibility_pumped_storage_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_supply \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 energy_hydrogen_autothermal_reformer_dispatchable \n", + "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", + "4 energy_hydrogen_ammonia_reformer_dispatchable \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_demand \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 None \n", + "3 None \n", + "4 None \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " space_heating \n", + "sortables \n", + "0 households_space_heater_district_heating_lt_st... \n", + "1 households_space_heater_heatpump_surface_water... \n", + "2 households_space_heater_heatpump_air_water_ele... \n", + "3 households_space_heater_heatpump_ground_water_... \n", + "4 households_space_heater_heatpump_pvt_electricity \n", + "5 households_space_heater_district_heating_mt_st... \n", + "6 households_space_heater_hybrid_heatpump_air_wa... \n", + "7 households_space_heater_hybrid_hydrogen_heatpu... \n", + "8 households_space_heater_hybrid_crude_oil_heatp... \n", + "9 households_space_heater_district_heating_ht_st... \n", + "10 households_space_heater_electricity \n", + "11 households_space_heater_combined_network_gas \n", + "12 households_space_heater_combined_hydrogen \n", + "13 households_space_heater_wood_pellets \n", + "14 households_space_heater_network_gas \n", + "15 households_space_heater_coal \n", + "16 households_space_heater_crude_oil \n", + "\n", + " \\\n", + " heat_network_lt \n", + "sortables \n", + "0 energy_heat_network_storage_lt_steam_hot_water \n", + "1 energy_heat_boiler_lt_electricity \n", + "2 energy_heat_burner_lt_hydrogen \n", + "3 energy_heat_heatpump_water_water_lt_electricity \n", + "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", + "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", + "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_mt \n", + "sortables \n", + "0 energy_heat_network_storage_mt_steam_hot_water \n", + "1 energy_heat_boiler_mt_electricity \n", + "2 energy_heat_burner_mt_coal \n", + "3 energy_heat_burner_mt_crude_oil \n", + "4 energy_heat_burner_mt_hydrogen \n", + "5 energy_heat_burner_mt_network_gas \n", + "6 energy_heat_burner_mt_waste_mix \n", + "7 energy_heat_burner_mt_wood_pellets \n", + "8 energy_heat_heatpump_water_water_mt_electricity \n", + "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", + "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", + "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \n", + " heat_network_ht \n", + "sortables \n", + "0 energy_heat_network_storage_ht_steam_hot_water \n", + "1 energy_heat_boiler_ht_electricity \n", + "2 energy_heat_burner_ht_coal \n", + "3 energy_heat_burner_ht_crude_oil \n", + "4 energy_heat_burner_ht_hydrogen \n", + "5 energy_heat_burner_ht_network_gas \n", + "6 energy_heat_burner_ht_waste_mix \n", + "7 energy_heat_burner_ht_wood_pellets \n", + "8 energy_heat_heatpump_water_water_ht_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "packer.sortables()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "0d3e771e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
2690555A: Create from excel
interconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_priceinterconnector_3_import_availabilityinterconnector_3_export_availabilityinterconnector_4_price...weather/wind_offshore_baselineweather/wind_coastal_baselineweather/wind_inland_baselineinterconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_price
00.011.00.026.001.01.00.011.00.00.01...0.9639780.6627860.6627860.011.00.026.001.01.00.01
10.011.00.026.001.01.00.001.00.00.00...0.9662970.7377590.7377590.011.00.026.001.01.00.00
20.011.00.014.481.01.00.001.00.00.00...0.9664720.7670290.7670290.011.00.014.481.01.00.00
30.011.00.00.011.00.00.001.00.00.00...0.9671030.8142720.8142720.011.00.00.011.00.00.00
40.011.00.00.021.00.00.001.00.00.00...0.9670680.8331410.8331410.011.00.00.021.00.00.00
..................................................................
87550.011.00.00.011.00.00.001.00.00.00...0.9673790.9334170.9334170.011.00.00.011.00.00.00
87560.011.00.00.011.00.00.001.00.00.00...0.9673790.9369490.9369490.011.00.00.011.00.00.00
87570.011.00.00.011.00.00.001.00.00.00...0.9673790.9367560.9367560.011.00.00.011.00.00.00
87580.011.00.00.021.00.00.001.00.00.00...0.9673790.9454570.9454570.011.00.00.021.00.00.00
87590.011.00.00.001.00.00.001.00.00.00...0.9673480.9485780.9485780.011.00.00.001.00.00.00
\n", + "

8760 rows × 52 columns

\n", + "
" + ], + "text/plain": [ + " 2690555 \\\n", + " interconnector_1_price interconnector_1_import_availability \n", + "0 0.01 1.0 \n", + "1 0.01 1.0 \n", + "2 0.01 1.0 \n", + "3 0.01 1.0 \n", + "4 0.01 1.0 \n", + "... ... ... \n", + "8755 0.01 1.0 \n", + "8756 0.01 1.0 \n", + "8757 0.01 1.0 \n", + "8758 0.01 1.0 \n", + "8759 0.01 1.0 \n", + "\n", + " \\\n", + " interconnector_1_export_availability interconnector_2_price \n", + "0 0.0 26.00 \n", + "1 0.0 26.00 \n", + "2 0.0 14.48 \n", + "3 0.0 0.01 \n", + "4 0.0 0.02 \n", + "... ... ... \n", + "8755 0.0 0.01 \n", + "8756 0.0 0.01 \n", + "8757 0.0 0.01 \n", + "8758 0.0 0.02 \n", + "8759 0.0 0.00 \n", + "\n", + " \\\n", + " interconnector_2_import_availability \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 \n", + "... ... \n", + "8755 1.0 \n", + "8756 1.0 \n", + "8757 1.0 \n", + "8758 1.0 \n", + "8759 1.0 \n", + "\n", + " \\\n", + " interconnector_2_export_availability interconnector_3_price \n", + "0 1.0 0.01 \n", + "1 1.0 0.00 \n", + "2 1.0 0.00 \n", + "3 0.0 0.00 \n", + "4 0.0 0.00 \n", + "... ... ... \n", + "8755 0.0 0.00 \n", + "8756 0.0 0.00 \n", + "8757 0.0 0.00 \n", + "8758 0.0 0.00 \n", + "8759 0.0 0.00 \n", + "\n", + " \\\n", + " interconnector_3_import_availability \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 \n", + "... ... \n", + "8755 1.0 \n", + "8756 1.0 \n", + "8757 1.0 \n", + "8758 1.0 \n", + "8759 1.0 \n", + "\n", + " ... \\\n", + " interconnector_3_export_availability interconnector_4_price ... \n", + "0 0.0 0.01 ... \n", + "1 0.0 0.00 ... \n", + "2 0.0 0.00 ... \n", + "3 0.0 0.00 ... \n", + "4 0.0 0.00 ... \n", + "... ... ... ... \n", + "8755 0.0 0.00 ... \n", + "8756 0.0 0.00 ... \n", + "8757 0.0 0.00 ... \n", + "8758 0.0 0.00 ... \n", + "8759 0.0 0.00 ... \n", + "\n", + " \\\n", + " weather/wind_offshore_baseline weather/wind_coastal_baseline \n", + "0 0.963978 0.662786 \n", + "1 0.966297 0.737759 \n", + "2 0.966472 0.767029 \n", + "3 0.967103 0.814272 \n", + "4 0.967068 0.833141 \n", + "... ... ... \n", + "8755 0.967379 0.933417 \n", + "8756 0.967379 0.936949 \n", + "8757 0.967379 0.936756 \n", + "8758 0.967379 0.945457 \n", + "8759 0.967348 0.948578 \n", + "\n", + " A: Create from excel \\\n", + " weather/wind_inland_baseline interconnector_1_price \n", + "0 0.662786 0.01 \n", + "1 0.737759 0.01 \n", + "2 0.767029 0.01 \n", + "3 0.814272 0.01 \n", + "4 0.833141 0.01 \n", + "... ... ... \n", + "8755 0.933417 0.01 \n", + "8756 0.936949 0.01 \n", + "8757 0.936756 0.01 \n", + "8758 0.945457 0.01 \n", + "8759 0.948578 0.01 \n", + "\n", + " \\\n", + " interconnector_1_import_availability \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 \n", + "... ... \n", + "8755 1.0 \n", + "8756 1.0 \n", + "8757 1.0 \n", + "8758 1.0 \n", + "8759 1.0 \n", + "\n", + " \\\n", + " interconnector_1_export_availability interconnector_2_price \n", + "0 0.0 26.00 \n", + "1 0.0 26.00 \n", + "2 0.0 14.48 \n", + "3 0.0 0.01 \n", + "4 0.0 0.02 \n", + "... ... ... \n", + "8755 0.0 0.01 \n", + "8756 0.0 0.01 \n", + "8757 0.0 0.01 \n", + "8758 0.0 0.02 \n", + "8759 0.0 0.00 \n", + "\n", + " \\\n", + " interconnector_2_import_availability \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 \n", + "... ... \n", + "8755 1.0 \n", + "8756 1.0 \n", + "8757 1.0 \n", + "8758 1.0 \n", + "8759 1.0 \n", + "\n", + " \n", + " interconnector_2_export_availability interconnector_3_price \n", + "0 1.0 0.01 \n", + "1 1.0 0.00 \n", + "2 1.0 0.00 \n", + "3 0.0 0.00 \n", + "4 0.0 0.00 \n", + "... ... ... \n", + "8755 0.0 0.00 \n", + "8756 0.0 0.00 \n", + "8757 0.0 0.00 \n", + "8758 0.0 0.00 \n", + "8759 0.0 0.00 \n", + "\n", + "[8760 rows x 52 columns]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "packer.custom_curves()" + ] } ], "metadata": { diff --git a/examples/exploring_a_scenario.ipynb b/examples/exploring_a_scenario.ipynb index 168fec0..5fd681c 100644 --- a/examples/exploring_a_scenario.ipynb +++ b/examples/exploring_a_scenario.ipynb @@ -26,7 +26,26 @@ "execution_count": null, "id": "59514b1f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Environment setup complete\n", + " Using ETM API at http://localhost:3000/api/v3\n", + " Token loaded? True\n", + "API connection ready\n" + ] + }, + { + "ename": "ScenarioError", + "evalue": "Could not load scenario 2690288: [\"HTTPConnectionPool(host='localhost', port=3000): Max retries exceeded with url: /api/v3/scenarios/2690288 (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused'))\"]", + "output_type": "error", + "traceback": [ + "\u001b[31mScenarioError\u001b[39m\u001b[31m:\u001b[39m Could not load scenario 2690288: [\"HTTPConnectionPool(host='localhost', port=3000): Max retries exceeded with url: /api/v3/scenarios/2690288 (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused'))\"]\n" + ] + } + ], "source": [ "from example_helpers import setup_notebook\n", "from pyetm.models import Scenario\n", @@ -34,7 +53,7 @@ "setup_notebook()\n", "\n", "# Change the scenario id to anything you want! This is a scenario on pro.\n", - "scenario = Scenario.load(2690288)" + "scenario = Scenario.load(2690555)" ] }, { diff --git a/src/pyetm/models/scenario.py b/src/pyetm/models/scenario.py index 3918f28..896e608 100644 --- a/src/pyetm/models/scenario.py +++ b/src/pyetm/models/scenario.py @@ -267,15 +267,10 @@ def set_sortables_from_dataframe(self, dataframe: pd.DataFrame) -> None: Args: dataframe: DataFrame with sortable names as columns and order values as rows """ - # Convert DataFrame to dict of lists, handling NaN/None values - sortables_dict = {} - for column in dataframe.columns: - # Filter out NaN/None values and convert to list - order_values = dataframe[column].dropna().tolist() - if order_values: # Only include if there are actual values - sortables_dict[column] = order_values - - self.update_sortables(sortables_dict) + coll = Sortables._from_dataframe(dataframe) + updates = coll.to_updates_dict() + if updates: + self.update_sortables(updates) def update_sortables(self, update_sortables: Dict[str, List[Any]]) -> None: """ diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 9e240e9..f0ae068 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -324,23 +324,10 @@ def from_dataframe(self, df: pd.DataFrame): continue block = df[identifier] - updates: Dict[str, List[Any]] = {} - for sortable_name in block.columns: - # Build list order by dropping NaNs/empties - values = ( - block[sortable_name] - .dropna() - .astype(str) - .map(lambda s: s.strip()) - .replace({"": pd.NA}) - .dropna() - .tolist() - ) - if values: - updates[str(sortable_name)] = values - - if updates: - scenario.update_sortables(updates) + try: + scenario.set_sortables_from_dataframe(block) + except Exception as e: + logger.warning("Failed to update sortables for '%s': %s", identifier, e) class CustomCurvesPack(Packable): diff --git a/src/pyetm/models/sortables.py b/src/pyetm/models/sortables.py index e22b472..4a1e690 100644 --- a/src/pyetm/models/sortables.py +++ b/src/pyetm/models/sortables.py @@ -259,3 +259,42 @@ def _to_dataframe(self, **kwargs) -> pd.DataFrame: return pd.DataFrame.from_dict( {s.name(): s.order for s in self.sortables}, orient="index" ).T + + @classmethod + def _from_dataframe(cls, df: pd.DataFrame, **kwargs) -> "Sortables": + if df is None: + return cls(sortables=[]) + + # Ensure DataFrame + if isinstance(df, pd.Series): + df = df.to_frame(name=str(df.name)) + + def _extract_order(series: pd.Series) -> List[Any]: + return ( + series.dropna() + .astype(str) + .map(lambda s: s.strip()) + .replace({"": pd.NA}) + .dropna() + .tolist() + ) + + items: List[Sortable] = [] + for col in df.columns: + name = str(col) + order = _extract_order(df[col]) + if not order: + continue + + if name.startswith("heat_network_"): + subtype = name[len("heat_network_") :] + items.append( + Sortable(type="heat_network", subtype=subtype, order=order) + ) + else: + items.append(Sortable(type=name, order=order)) + + return cls(sortables=items) + + def to_updates_dict(self) -> Dict[str, List[Any]]: + return {s.name(): s.order for s in self.sortables} From 2c735e5cd72271de3308dd38ba73ac9e05953960 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Fri, 8 Aug 2025 14:15:40 +0200 Subject: [PATCH 06/17] Parse options from main sheet to enable repeating submodels across all scenarios listed in main --- examples/excel_to_scenarios.ipynb | 493 +++++++++++++--------------- src/pyetm/models/scenario_packer.py | 270 ++++++++++++++- 2 files changed, 491 insertions(+), 272 deletions(-) diff --git a/examples/excel_to_scenarios.ipynb b/examples/excel_to_scenarios.ipynb index 1302010..eeccce2 100644 --- a/examples/excel_to_scenarios.ipynb +++ b/examples/excel_to_scenarios.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 1, "id": "4866f9d1", "metadata": {}, "outputs": [ @@ -32,15 +32,14 @@ "text": [ "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:206: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", " self.update_user_values(series.fillna(\"reset\").to_dict())\n", - "Could not find scenario for identifier '2690555'\n", - "Could not find scenario for identifier '2690555'\n" + "repeat_gqueries is set but gqueries unpack is read-only and not supported\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "{'total_scenarios': 2, 'inputs': {'scenario_count': 2}, 'sortables': {'scenario_count': 2}, 'custom_curves': {'scenario_count': 2}, 'output_curves': {'scenario_count': 0}, 'scenario_ids': [2690555, 2690585]}\n" + "{'total_scenarios': 2, 'inputs': {'scenario_count': 2}, 'sortables': {'scenario_count': 2}, 'custom_curves': {'scenario_count': 2}, 'output_curves': {'scenario_count': 0}, 'scenario_ids': [2690555, 2690591]}\n" ] }, { @@ -69,8 +68,8 @@ " \n", " \n", " \n", - " 2690555\n", " A: Create from excel\n", + " B: Load a scenario by id\n", " \n", " \n", " \n", @@ -89,31 +88,31 @@ " \n", " climate_relevant_co2_biomass_gas_future\n", " %\n", - " 0.0\n", + " 30.0\n", " 30.0\n", " \n", " \n", " climate_relevant_co2_biomass_gas_present\n", " %\n", - " 0.0\n", + " 20.0\n", " 20.0\n", " \n", " \n", " climate_relevant_co2_biomass_liquid_future\n", " %\n", - " 0.0\n", + " 30.0\n", " 30.0\n", " \n", " \n", " climate_relevant_co2_biomass_liquid_present\n", " %\n", - " 0.0\n", + " 20.0\n", " 20.0\n", " \n", " \n", " climate_relevant_co2_biomass_solid_future\n", " %\n", - " 0.0\n", + " 30.0\n", " 30.0\n", " \n", " \n", @@ -125,32 +124,32 @@ " \n", " capacity_of_energy_battery_wind_turbine_inland\n", " MW\n", - " 0.0\n", " NaN\n", + " 0.0\n", " \n", " \n", " capacity_of_energy_power_hybrid_wind_turbine_offshore\n", " MW\n", - " None\n", " NaN\n", + " None\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_coastal\n", " MW\n", - " 0.0\n", " NaN\n", + " 0.0\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_inland\n", " MW\n", - " 20000.0\n", " NaN\n", + " 20000.0\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_offshore\n", " MW\n", - " 52000.0\n", " NaN\n", + " 52000.0\n", " \n", " \n", "\n", @@ -158,40 +157,40 @@ "" ], "text/plain": [ - " 2690555 \\\n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 0.0 \n", - "climate_relevant_co2_biomass_gas_present % 0.0 \n", - "climate_relevant_co2_biomass_liquid_future % 0.0 \n", - "climate_relevant_co2_biomass_liquid_present % 0.0 \n", - "climate_relevant_co2_biomass_solid_future % 0.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", - "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", - "capacity_of_energy_power_wind_turbine_inland MW 20000.0 \n", - "capacity_of_energy_power_wind_turbine_offshore MW 52000.0 \n", + " A: Create from excel \\\n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 30.0 \n", + "climate_relevant_co2_biomass_gas_present % 20.0 \n", + "climate_relevant_co2_biomass_liquid_future % 30.0 \n", + "climate_relevant_co2_biomass_liquid_present % 20.0 \n", + "climate_relevant_co2_biomass_solid_future % 30.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", + "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", + "capacity_of_energy_power_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", "\n", - " A: Create from excel \n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 30.0 \n", - "climate_relevant_co2_biomass_gas_present % 20.0 \n", - "climate_relevant_co2_biomass_liquid_future % 30.0 \n", - "climate_relevant_co2_biomass_liquid_present % 20.0 \n", - "climate_relevant_co2_biomass_solid_future % 30.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", - "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", - "capacity_of_energy_power_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", + " B: Load a scenario by id \n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 30.0 \n", + "climate_relevant_co2_biomass_gas_present % 20.0 \n", + "climate_relevant_co2_biomass_liquid_future % 30.0 \n", + "climate_relevant_co2_biomass_liquid_present % 20.0 \n", + "climate_relevant_co2_biomass_solid_future % 30.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", + "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", + "capacity_of_energy_power_wind_turbine_inland MW 20000.0 \n", + "capacity_of_energy_power_wind_turbine_offshore MW 52000.0 \n", "\n", "[1318 rows x 2 columns]" ] }, - "execution_count": 7, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -210,7 +209,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 2, "id": "cd08ff26", "metadata": {}, "outputs": [ @@ -239,8 +238,8 @@ " \n", " \n", " \n", - " 2690555\n", " A: Create from excel\n", + " B: Load a scenario by id\n", " \n", " \n", " \n", @@ -297,7 +296,7 @@ " \n", " \n", " 1\n", - " transport_car_flexibility_p2p_electricity\n", + " energy_flexibility_mv_batteries_electricity\n", " energy_hydrogen_storage_salt_cavern\n", " energy_hydrogen_storage_salt_cavern\n", " households_space_heater_heatpump_surface_water...\n", @@ -314,7 +313,7 @@ " \n", " \n", " 2\n", - " energy_flexibility_mv_batteries_electricity\n", + " transport_car_flexibility_p2p_electricity\n", " energy_hydrogen_autothermal_reformer_dispatchable\n", " None\n", " households_space_heater_heatpump_air_water_ele...\n", @@ -365,7 +364,7 @@ " \n", " \n", " 5\n", - " energy_flexibility_pumped_storage_electricity\n", + " transport_bus_flexibility_p2p_electricity\n", " None\n", " None\n", " households_space_heater_district_heating_mt_st...\n", @@ -382,7 +381,7 @@ " \n", " \n", " 6\n", - " transport_bus_flexibility_p2p_electricity\n", + " transport_truck_flexibility_p2p_electricity\n", " None\n", " None\n", " households_space_heater_hybrid_heatpump_air_wa...\n", @@ -399,7 +398,7 @@ " \n", " \n", " 7\n", - " transport_truck_flexibility_p2p_electricity\n", + " transport_van_flexibility_p2p_electricity\n", " None\n", " None\n", " households_space_heater_hybrid_hydrogen_heatpu...\n", @@ -416,7 +415,7 @@ " \n", " \n", " 8\n", - " transport_van_flexibility_p2p_electricity\n", + " energy_flexibility_pumped_storage_electricity\n", " None\n", " None\n", " households_space_heater_hybrid_crude_oil_heatp...\n", @@ -572,18 +571,18 @@ "" ], "text/plain": [ - " 2690555 \\\n", + " A: Create from excel \\\n", " forecast_storage \n", "sortables \n", "0 households_flexibility_p2p_electricity \n", - "1 transport_car_flexibility_p2p_electricity \n", - "2 energy_flexibility_mv_batteries_electricity \n", + "1 energy_flexibility_mv_batteries_electricity \n", + "2 transport_car_flexibility_p2p_electricity \n", "3 energy_flexibility_flow_batteries_electricity \n", "4 energy_flexibility_hv_opac_electricity \n", - "5 energy_flexibility_pumped_storage_electricity \n", - "6 transport_bus_flexibility_p2p_electricity \n", - "7 transport_truck_flexibility_p2p_electricity \n", - "8 transport_van_flexibility_p2p_electricity \n", + "5 transport_bus_flexibility_p2p_electricity \n", + "6 transport_truck_flexibility_p2p_electricity \n", + "7 transport_van_flexibility_p2p_electricity \n", + "8 energy_flexibility_pumped_storage_electricity \n", "9 None \n", "10 None \n", "11 None \n", @@ -719,7 +718,7 @@ "15 None \n", "16 None \n", "\n", - " A: Create from excel \\\n", + " B: Load a scenario by id \\\n", " forecast_storage \n", "sortables \n", "0 households_flexibility_p2p_electricity \n", @@ -867,7 +866,7 @@ "16 None " ] }, - "execution_count": 8, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -878,7 +877,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 3, "id": "0d3e771e", "metadata": {}, "outputs": [ @@ -903,8 +902,8 @@ " \n", " \n", " \n", - " 2690555\n", " A: Create from excel\n", + " B: Load a scenario by id\n", " \n", " \n", " \n", @@ -915,20 +914,20 @@ " interconnector_2_import_availability\n", " interconnector_2_export_availability\n", " interconnector_3_price\n", - " interconnector_3_import_availability\n", - " interconnector_3_export_availability\n", - " interconnector_4_price\n", + " interconnector_1_price\n", + " interconnector_1_import_availability\n", + " interconnector_1_export_availability\n", " ...\n", + " households_hot_water\n", + " industry_ict\n", + " industry_other_electricity\n", + " weather/solar_pv_profile_1\n", + " weather/solar_thermal\n", + " weather/air_temperature\n", + " weather/agriculture_heating\n", " weather/wind_offshore_baseline\n", " weather/wind_coastal_baseline\n", " weather/wind_inland_baseline\n", - " interconnector_1_price\n", - " interconnector_1_import_availability\n", - " interconnector_1_export_availability\n", - " interconnector_2_price\n", - " interconnector_2_import_availability\n", - " interconnector_2_export_availability\n", - " interconnector_3_price\n", " \n", " \n", " \n", @@ -941,20 +940,20 @@ " 1.0\n", " 1.0\n", " 0.01\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.01\n", " ...\n", + " 0.000000e+00\n", + " 2.777764e-08\n", + " 3.055443e-08\n", + " 0.0\n", + " 0.0\n", + " 12.009861\n", + " 1.166142e-08\n", " 0.963978\n", " 0.662786\n", " 0.662786\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 26.00\n", - " 1.0\n", - " 1.0\n", - " 0.01\n", " \n", " \n", " 1\n", @@ -965,20 +964,20 @@ " 1.0\n", " 1.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 0.000000e+00\n", + " 2.777764e-08\n", + " 3.208215e-08\n", + " 0.0\n", + " 0.0\n", + " 12.043616\n", + " 1.138377e-08\n", " 0.966297\n", " 0.737759\n", " 0.737759\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 26.00\n", - " 1.0\n", - " 1.0\n", - " 0.00\n", " \n", " \n", " 2\n", @@ -989,20 +988,20 @@ " 1.0\n", " 1.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 0.000000e+00\n", + " 2.777764e-08\n", + " 3.166550e-08\n", + " 0.0\n", + " 0.0\n", + " 12.133497\n", + " 8.884891e-09\n", " 0.966472\n", " 0.767029\n", " 0.767029\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 14.48\n", - " 1.0\n", - " 1.0\n", - " 0.00\n", " \n", " \n", " 3\n", @@ -1013,20 +1012,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 0.000000e+00\n", + " 2.749986e-08\n", + " 3.208215e-08\n", + " 0.0\n", + " 0.0\n", + " 12.189575\n", + " 9.717849e-09\n", " 0.967103\n", " 0.814272\n", " 0.814272\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.00\n", " \n", " \n", " 4\n", @@ -1037,20 +1036,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 0.000000e+00\n", + " 2.777764e-08\n", + " 3.249880e-08\n", + " 0.0\n", + " 0.0\n", + " 12.312676\n", + " 9.717849e-09\n", " 0.967068\n", " 0.833141\n", " 0.833141\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.02\n", - " 1.0\n", - " 0.0\n", - " 0.00\n", " \n", " \n", " ...\n", @@ -1085,20 +1084,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 4.903713e-08\n", + " 3.111096e-08\n", + " 2.444354e-08\n", + " 0.0\n", + " 0.0\n", + " 9.574081\n", + " 4.275854e-08\n", " 0.967379\n", " 0.933417\n", " 0.933417\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.00\n", " \n", " \n", " 8756\n", @@ -1109,20 +1108,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 4.126528e-08\n", + " 3.083318e-08\n", + " 2.236028e-08\n", + " 0.0\n", + " 0.0\n", + " 9.750026\n", + " 4.609037e-08\n", " 0.967379\n", " 0.936949\n", " 0.936949\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.00\n", " \n", " \n", " 8757\n", @@ -1133,20 +1132,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 2.921741e-08\n", + " 2.999985e-08\n", + " 1.972149e-08\n", + " 0.0\n", + " 0.0\n", + " 10.090767\n", + " 4.636802e-08\n", " 0.967379\n", " 0.936756\n", " 0.936756\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.00\n", " \n", " \n", " 8758\n", @@ -1157,20 +1156,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 2.879315e-08\n", + " 2.888874e-08\n", + " 3.402652e-08\n", + " 0.0\n", + " 0.0\n", + " 10.058248\n", + " 4.581272e-08\n", " 0.967379\n", " 0.945457\n", " 0.945457\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.02\n", - " 1.0\n", - " 0.0\n", - " 0.00\n", " \n", " \n", " 8759\n", @@ -1181,20 +1180,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", + " 0.01\n", " 1.0\n", " 0.0\n", - " 0.00\n", " ...\n", + " 0.000000e+00\n", + " 2.833319e-08\n", + " 3.402652e-08\n", + " 0.0\n", + " 0.0\n", + " 10.255527\n", + " 3.887140e-08\n", " 0.967348\n", " 0.948578\n", " 0.948578\n", - " 0.01\n", - " 1.0\n", - " 0.0\n", - " 0.00\n", - " 1.0\n", - " 0.0\n", - " 0.00\n", " \n", " \n", "\n", @@ -1202,7 +1201,7 @@ "" ], "text/plain": [ - " 2690555 \\\n", + " A: Create from excel \\\n", " interconnector_1_price interconnector_1_import_availability \n", "0 0.01 1.0 \n", "1 0.01 1.0 \n", @@ -1258,122 +1257,94 @@ "8758 0.0 0.00 \n", "8759 0.0 0.00 \n", "\n", - " \\\n", - " interconnector_3_import_availability \n", - "0 1.0 \n", - "1 1.0 \n", - "2 1.0 \n", - "3 1.0 \n", - "4 1.0 \n", - "... ... \n", - "8755 1.0 \n", - "8756 1.0 \n", - "8757 1.0 \n", - "8758 1.0 \n", - "8759 1.0 \n", + " B: Load a scenario by id \\\n", + " interconnector_1_price interconnector_1_import_availability \n", + "0 0.01 1.0 \n", + "1 0.01 1.0 \n", + "2 0.01 1.0 \n", + "3 0.01 1.0 \n", + "4 0.01 1.0 \n", + "... ... ... \n", + "8755 0.01 1.0 \n", + "8756 0.01 1.0 \n", + "8757 0.01 1.0 \n", + "8758 0.01 1.0 \n", + "8759 0.01 1.0 \n", "\n", - " ... \\\n", - " interconnector_3_export_availability interconnector_4_price ... \n", - "0 0.0 0.01 ... \n", - "1 0.0 0.00 ... \n", - "2 0.0 0.00 ... \n", - "3 0.0 0.00 ... \n", - "4 0.0 0.00 ... \n", - "... ... ... ... \n", - "8755 0.0 0.00 ... \n", - "8756 0.0 0.00 ... \n", - "8757 0.0 0.00 ... \n", - "8758 0.0 0.00 ... \n", - "8759 0.0 0.00 ... \n", + " ... \\\n", + " interconnector_1_export_availability ... households_hot_water \n", + "0 0.0 ... 0.000000e+00 \n", + "1 0.0 ... 0.000000e+00 \n", + "2 0.0 ... 0.000000e+00 \n", + "3 0.0 ... 0.000000e+00 \n", + "4 0.0 ... 0.000000e+00 \n", + "... ... ... ... \n", + "8755 0.0 ... 4.903713e-08 \n", + "8756 0.0 ... 4.126528e-08 \n", + "8757 0.0 ... 2.921741e-08 \n", + "8758 0.0 ... 2.879315e-08 \n", + "8759 0.0 ... 0.000000e+00 \n", "\n", - " \\\n", - " weather/wind_offshore_baseline weather/wind_coastal_baseline \n", - "0 0.963978 0.662786 \n", - "1 0.966297 0.737759 \n", - "2 0.966472 0.767029 \n", - "3 0.967103 0.814272 \n", - "4 0.967068 0.833141 \n", - "... ... ... \n", - "8755 0.967379 0.933417 \n", - "8756 0.967379 0.936949 \n", - "8757 0.967379 0.936756 \n", - "8758 0.967379 0.945457 \n", - "8759 0.967348 0.948578 \n", + " \\\n", + " industry_ict industry_other_electricity weather/solar_pv_profile_1 \n", + "0 2.777764e-08 3.055443e-08 0.0 \n", + "1 2.777764e-08 3.208215e-08 0.0 \n", + "2 2.777764e-08 3.166550e-08 0.0 \n", + "3 2.749986e-08 3.208215e-08 0.0 \n", + "4 2.777764e-08 3.249880e-08 0.0 \n", + "... ... ... ... \n", + "8755 3.111096e-08 2.444354e-08 0.0 \n", + "8756 3.083318e-08 2.236028e-08 0.0 \n", + "8757 2.999985e-08 1.972149e-08 0.0 \n", + "8758 2.888874e-08 3.402652e-08 0.0 \n", + "8759 2.833319e-08 3.402652e-08 0.0 \n", "\n", - " A: Create from excel \\\n", - " weather/wind_inland_baseline interconnector_1_price \n", - "0 0.662786 0.01 \n", - "1 0.737759 0.01 \n", - "2 0.767029 0.01 \n", - "3 0.814272 0.01 \n", - "4 0.833141 0.01 \n", - "... ... ... \n", - "8755 0.933417 0.01 \n", - "8756 0.936949 0.01 \n", - "8757 0.936756 0.01 \n", - "8758 0.945457 0.01 \n", - "8759 0.948578 0.01 \n", + " \\\n", + " weather/solar_thermal weather/air_temperature \n", + "0 0.0 12.009861 \n", + "1 0.0 12.043616 \n", + "2 0.0 12.133497 \n", + "3 0.0 12.189575 \n", + "4 0.0 12.312676 \n", + "... ... ... \n", + "8755 0.0 9.574081 \n", + "8756 0.0 9.750026 \n", + "8757 0.0 10.090767 \n", + "8758 0.0 10.058248 \n", + "8759 0.0 10.255527 \n", "\n", - " \\\n", - " interconnector_1_import_availability \n", - "0 1.0 \n", - "1 1.0 \n", - "2 1.0 \n", - "3 1.0 \n", - "4 1.0 \n", - "... ... \n", - "8755 1.0 \n", - "8756 1.0 \n", - "8757 1.0 \n", - "8758 1.0 \n", - "8759 1.0 \n", - "\n", - " \\\n", - " interconnector_1_export_availability interconnector_2_price \n", - "0 0.0 26.00 \n", - "1 0.0 26.00 \n", - "2 0.0 14.48 \n", - "3 0.0 0.01 \n", - "4 0.0 0.02 \n", - "... ... ... \n", - "8755 0.0 0.01 \n", - "8756 0.0 0.01 \n", - "8757 0.0 0.01 \n", - "8758 0.0 0.02 \n", - "8759 0.0 0.00 \n", - "\n", - " \\\n", - " interconnector_2_import_availability \n", - "0 1.0 \n", - "1 1.0 \n", - "2 1.0 \n", - "3 1.0 \n", - "4 1.0 \n", - "... ... \n", - "8755 1.0 \n", - "8756 1.0 \n", - "8757 1.0 \n", - "8758 1.0 \n", - "8759 1.0 \n", + " \\\n", + " weather/agriculture_heating weather/wind_offshore_baseline \n", + "0 1.166142e-08 0.963978 \n", + "1 1.138377e-08 0.966297 \n", + "2 8.884891e-09 0.966472 \n", + "3 9.717849e-09 0.967103 \n", + "4 9.717849e-09 0.967068 \n", + "... ... ... \n", + "8755 4.275854e-08 0.967379 \n", + "8756 4.609037e-08 0.967379 \n", + "8757 4.636802e-08 0.967379 \n", + "8758 4.581272e-08 0.967379 \n", + "8759 3.887140e-08 0.967348 \n", "\n", - " \n", - " interconnector_2_export_availability interconnector_3_price \n", - "0 1.0 0.01 \n", - "1 1.0 0.00 \n", - "2 1.0 0.00 \n", - "3 0.0 0.00 \n", - "4 0.0 0.00 \n", - "... ... ... \n", - "8755 0.0 0.00 \n", - "8756 0.0 0.00 \n", - "8757 0.0 0.00 \n", - "8758 0.0 0.00 \n", - "8759 0.0 0.00 \n", + " \n", + " weather/wind_coastal_baseline weather/wind_inland_baseline \n", + "0 0.662786 0.662786 \n", + "1 0.737759 0.737759 \n", + "2 0.767029 0.767029 \n", + "3 0.814272 0.814272 \n", + "4 0.833141 0.833141 \n", + "... ... ... \n", + "8755 0.933417 0.933417 \n", + "8756 0.936949 0.936949 \n", + "8757 0.936756 0.936756 \n", + "8758 0.945457 0.945457 \n", + "8759 0.948578 0.948578 \n", "\n", "[8760 rows x 52 columns]" ] }, - "execution_count": 9, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index f0ae068..d662013 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -57,7 +57,6 @@ class InputsPack(Packable): sheet_name: ClassVar[str] = "PARAMETERS" def _to_dataframe(self, columns="user", **kwargs): - # TODO: index on title if avaliable return pd.concat( [ scenario.inputs.to_dataframe(columns=columns) @@ -616,6 +615,73 @@ def get_summary(self) -> Dict[str, Any]: # Create stuff + def _read_global_options( + self, xlsx: pd.ExcelFile, sheet_name: str + ) -> Dict[str, bool]: + """Read global OPTIONS from the MAIN sheet.""" + try: + raw = xlsx.parse(sheet_name=sheet_name, header=None) + except Exception: + return { + "repeat_parameters": False, + "repeat_gqueries": False, + "repeat_sortables": False, + "repeat_custom_curves": False, + } + + def _as_bool(v): + if v is None or (isinstance(v, float) and pd.isna(v)): + return None + if isinstance(v, bool): + return v + try: + if isinstance(v, (int, float)) and not pd.isna(v): + return bool(int(v)) + except Exception: + pass + if isinstance(v, str): + s = v.strip().lower() + if s in {"true", "yes", "1", "y", "t"}: + return True + if s in {"false", "no", "0", "n", "f"}: + return False + return None + + # Find the 'OPTIONS' row in column A (index 0) + opts_idx = None + col0 = raw.iloc[:, 0] + for i, val in enumerate(col0): + if isinstance(val, str) and val.strip().lower() == "options": + opts_idx = i + break + + defaults = { + "repeat_parameters": False, + "repeat_gqueries": False, + "repeat_sortables": False, + "repeat_custom_curves": False, + } + if opts_idx is None: + return defaults + + # Scan following rows for key/value pairs in col0/col1 until blank key + result = defaults.copy() + for i in range(opts_idx + 1, len(raw)): + key = raw.iat[i, 0] if 0 < raw.shape[1] else None + if key is None or (isinstance(key, float) and pd.isna(key)): + # stop at first completely blank key + break + if not isinstance(key, str): + continue + k = key.strip() + if k not in result: + continue + val = raw.iat[i, 1] if raw.shape[1] > 1 else None + b = _as_bool(val) + result[k] = bool(b) if b is not None else False + + return result + @classmethod def from_excel( cls, @@ -636,6 +702,9 @@ def from_excel( main_df = packer.read_sheet(xlsx, main_sheet, index_col=0) scenarios = packer.scenarios_from_df(main_df) + # Read global OPTIONS from MAIN + options = packer._read_global_options(xlsx, main_sheet) + # Inputs (optional): only process when the sheet exists inputs_sheet = sheet_names.get("inputs", packer._inputs.sheet_name) packer._inputs.add(*scenarios) @@ -647,7 +716,36 @@ def from_excel( header=None, ) if isinstance(inputs_df, pd.DataFrame) and not inputs_df.empty: - packer._inputs.from_dataframe(inputs_df) + if options.get("repeat_parameters", False): + try: + norm = packer._inputs._normalize_inputs_dataframe(inputs_df) + if isinstance(norm, pd.DataFrame) and not norm.empty: + first_id = norm.columns.get_level_values(0)[0] + block = norm[first_id] + if isinstance(block, pd.Series): + block = block.to_frame(name="user") + else: + if list(block.columns) != ["user"]: + block = block.copy() + first_col = block.columns[0] + block = block.rename(columns={first_col: "user"}) + for s in scenarios: + try: + s.set_user_values_from_dataframe(block) + except Exception as e: + logger.warning( + "Failed to apply repeated inputs to '%s': %s", + ( + s.identifier() + if hasattr(s, "identifier") + else s.id + ), + e, + ) + except Exception as e: + logger.warning("Failed to process repeated inputs: %s", e) + else: + packer._inputs.from_dataframe(inputs_df) # Sortables (optional) sortables_sheet = ( @@ -659,8 +757,38 @@ def from_excel( xlsx, sortables_sheet, required=False, header=None ) if isinstance(sortables_df, pd.DataFrame) and not sortables_df.empty: - packer._sortables.add(*scenarios) - packer._sortables.from_dataframe(sortables_df) + if options.get("repeat_sortables", False): + # Ensure scenarios are included in the pack for downstream DataFrame exports + packer._sortables.add(*scenarios) + try: + norm = packer._sortables._normalize_sortables_dataframe( + sortables_df + ) + if ( + isinstance(norm, pd.DataFrame) + and not norm.empty + and isinstance(norm.columns, pd.MultiIndex) + ): + first_id = norm.columns.get_level_values(0)[0] + block = norm[first_id] + for s in scenarios: + try: + s.set_sortables_from_dataframe(block) + except Exception as e: + logger.warning( + "Failed to apply repeated sortables to '%s': %s", + ( + s.identifier() + if hasattr(s, "identifier") + else s.id + ), + e, + ) + except Exception as e: + logger.warning("Failed to process repeated sortables: %s", e) + else: + packer._sortables.add(*scenarios) + packer._sortables.from_dataframe(sortables_df) # Custom curves (optional) curves_sheet = ( @@ -672,10 +800,54 @@ def from_excel( xlsx, curves_sheet, required=False, header=None ) if isinstance(curves_df, pd.DataFrame) and not curves_df.empty: - packer._custom_curves.add(*scenarios) - packer._custom_curves.from_dataframe(curves_df) - - # TODO: gqueries unpack not supported (read-only) + if options.get("repeat_custom_curves", False): + # Ensure scenarios are included in the pack for downstream DataFrame exports + packer._custom_curves.add(*scenarios) + try: + norm = packer._custom_curves._normalize_curves_dataframe( + curves_df + ) + if ( + isinstance(norm, pd.DataFrame) + and not norm.empty + and isinstance(norm.columns, pd.MultiIndex) + ): + first_id = norm.columns.get_level_values(0)[0] + block = norm[first_id] + try: + curves = CustomCurves._from_dataframe(block) + except Exception as e: + logger.warning( + "Failed to build repeated custom curves: %s", e + ) + curves = None + if curves is not None: + for s in scenarios: + try: + s.update_custom_curves(curves) + except Exception as e: + logger.warning( + "Failed to apply repeated custom curves to '%s': %s", + ( + s.identifier() + if hasattr(s, "identifier") + else s.id + ), + e, + ) + except Exception as e: + logger.warning( + "Failed to process repeated custom curves: %s", e + ) + else: + packer._custom_curves.add(*scenarios) + packer._custom_curves.from_dataframe(curves_df) + + # GQueries: unpack not supported; respect option but warn if set + if options.get("repeat_gqueries", False): + logger.warning( + "repeat_gqueries is set but gqueries unpack is read-only and not supported" + ) return packer @@ -701,6 +873,7 @@ def scenarios_from_df(df: pd.DataFrame) -> list["Scenario"]: def setup_scenario(identifier, data): """Returns a scenario from data dict. If the identifier is an int (or str-int), load; otherwise create new. + # TODO: Set up create from template? """ # Normalize NA values to None data = {k: (None if pd.isna(v) else v) for k, v in data.items()} @@ -710,6 +883,41 @@ def setup_scenario(identifier, data): identifier if isinstance(identifier, str) and identifier != "" else None ) + # Extract optional MAIN fields + explicit_title = data.get("title") + description = data.get("description") + private_val = data.get("private") + template_val = data.get("template") + + def _as_bool(v): + if v is None: + return None + if isinstance(v, bool): + return v + # Excel often gives numbers/floats or strings + try: + if isinstance(v, (int, float)) and not pd.isna(v): + return bool(int(v)) + except Exception: + pass + if isinstance(v, str): + s = v.strip().lower() + if s in {"true", "yes", "1", "y", "t"}: + return True + if s in {"false", "no", "0", "n", "f"}: + return False + return None + + def _as_int(v): + try: + if v is None or (isinstance(v, float) and pd.isna(v)): + return None + return int(v) + except Exception: + return None + + effective_title = explicit_title or scenario_title + # Try to interpret identifier as an ID scenario_id: Optional[int] = None if isinstance(identifier, (int, float)) and not pd.isna(identifier): @@ -726,21 +934,61 @@ def setup_scenario(identifier, data): if scenario_id is not None: # Load existing scenario = Scenario.load(scenario_id) + + # Update metadata for existing scenarios based on MAIN sheet + update_fields: Dict[str, Any] = {} + private_bool = _as_bool(private_val) + if private_bool is not None: + update_fields["private"] = private_bool + + meta: Dict[str, Any] = {} + if effective_title: + meta["title"] = effective_title + if description: + meta["description"] = description + if meta: + update_fields["metadata"] = meta + if update_fields: + try: + scenario.update_metadata(**update_fields) + except Exception as e: + logger.warning( + "Failed to update metadata for '%s': %s", identifier, e + ) else: - # Create new (requires end_year and area_code) area_code = data.get("area_code") end_year = data.get("end_year") if area_code is None or end_year is None: raise ValueError( "Cannot create a new Scenario without 'area_code' and 'end_year'" ) - scenario = Scenario.new(area_code=area_code, end_year=int(end_year)) + + create_kwargs: Dict[str, Any] = {} + + private_bool = _as_bool(private_val) + if private_bool is not None: + create_kwargs["private"] = private_bool + + template_int = _as_int(template_val) + if template_int is not None: + create_kwargs["template"] = template_int + + meta: Dict[str, Any] = {} + if effective_title: + meta["title"] = effective_title + if description: + meta["description"] = description + if meta: + create_kwargs["metadata"] = meta + + scenario = Scenario.new( + area_code=area_code, end_year=int(end_year), **create_kwargs + ) # Set a title when a non-numeric identifier is provided if scenario_title is not None: scenario.title = scenario_title - # TODO: update metadata with the rest of the stuff in data!! (keep minimal for now) return scenario # NOTE: Move to utils? From 7aba256bab15f6f5da8559a6d7d4a9b5533268b1 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Fri, 8 Aug 2025 14:32:49 +0200 Subject: [PATCH 07/17] Added gqueries --- examples/excel_to_scenarios.ipynb | 567 +++++++++++++++++----------- src/pyetm/models/scenario_packer.py | 183 ++++++++- 2 files changed, 521 insertions(+), 229 deletions(-) diff --git a/examples/excel_to_scenarios.ipynb b/examples/excel_to_scenarios.ipynb index eeccce2..c9e2ca9 100644 --- a/examples/excel_to_scenarios.ipynb +++ b/examples/excel_to_scenarios.ipynb @@ -31,15 +31,14 @@ "output_type": "stream", "text": [ "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:206: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", - " self.update_user_values(series.fillna(\"reset\").to_dict())\n", - "repeat_gqueries is set but gqueries unpack is read-only and not supported\n" + " self.update_user_values(series.fillna(\"reset\").to_dict())\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "{'total_scenarios': 2, 'inputs': {'scenario_count': 2}, 'sortables': {'scenario_count': 2}, 'custom_curves': {'scenario_count': 2}, 'output_curves': {'scenario_count': 0}, 'scenario_ids': [2690555, 2690591]}\n" + "{'total_scenarios': 2, 'inputs': {'scenario_count': 2}, 'sortables': {'scenario_count': 2}, 'custom_curves': {'scenario_count': 2}, 'output_curves': {'scenario_count': 0}, 'scenario_ids': [2690555, 2690595]}\n" ] }, { @@ -68,8 +67,8 @@ " \n", " \n", " \n", - " A: Create from excel\n", " B: Load a scenario by id\n", + " A: Create from excel\n", " \n", " \n", " \n", @@ -124,32 +123,32 @@ " \n", " capacity_of_energy_battery_wind_turbine_inland\n", " MW\n", - " NaN\n", " 0.0\n", + " NaN\n", " \n", " \n", " capacity_of_energy_power_hybrid_wind_turbine_offshore\n", " MW\n", - " NaN\n", " None\n", + " NaN\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_coastal\n", " MW\n", - " NaN\n", " 0.0\n", + " NaN\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_inland\n", " MW\n", - " NaN\n", " 20000.0\n", + " NaN\n", " \n", " \n", " capacity_of_energy_power_wind_turbine_offshore\n", " MW\n", - " NaN\n", " 52000.0\n", + " NaN\n", " \n", " \n", "\n", @@ -157,35 +156,35 @@ "" ], "text/plain": [ - " A: Create from excel \\\n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 30.0 \n", - "climate_relevant_co2_biomass_gas_present % 20.0 \n", - "climate_relevant_co2_biomass_liquid_future % 30.0 \n", - "climate_relevant_co2_biomass_liquid_present % 20.0 \n", - "climate_relevant_co2_biomass_solid_future % 30.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", - "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", - "capacity_of_energy_power_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", + " B: Load a scenario by id \\\n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 30.0 \n", + "climate_relevant_co2_biomass_gas_present % 20.0 \n", + "climate_relevant_co2_biomass_liquid_future % 30.0 \n", + "climate_relevant_co2_biomass_liquid_present % 20.0 \n", + "climate_relevant_co2_biomass_solid_future % 30.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", + "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", + "capacity_of_energy_power_wind_turbine_inland MW 20000.0 \n", + "capacity_of_energy_power_wind_turbine_offshore MW 52000.0 \n", "\n", - " B: Load a scenario by id \n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 30.0 \n", - "climate_relevant_co2_biomass_gas_present % 20.0 \n", - "climate_relevant_co2_biomass_liquid_future % 30.0 \n", - "climate_relevant_co2_biomass_liquid_present % 20.0 \n", - "climate_relevant_co2_biomass_solid_future % 30.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", - "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", - "capacity_of_energy_power_wind_turbine_inland MW 20000.0 \n", - "capacity_of_energy_power_wind_turbine_offshore MW 52000.0 \n", + " A: Create from excel \n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 30.0 \n", + "climate_relevant_co2_biomass_gas_present % 20.0 \n", + "climate_relevant_co2_biomass_liquid_future % 30.0 \n", + "climate_relevant_co2_biomass_liquid_present % 20.0 \n", + "climate_relevant_co2_biomass_solid_future % 30.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", + "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", + "capacity_of_energy_power_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", "\n", "[1318 rows x 2 columns]" ] @@ -238,8 +237,8 @@ " \n", " \n", " \n", - " A: Create from excel\n", " B: Load a scenario by id\n", + " A: Create from excel\n", " \n", " \n", " \n", @@ -571,7 +570,7 @@ "" ], "text/plain": [ - " A: Create from excel \\\n", + " B: Load a scenario by id \\\n", " forecast_storage \n", "sortables \n", "0 households_flexibility_p2p_electricity \n", @@ -718,7 +717,7 @@ "15 None \n", "16 None \n", "\n", - " B: Load a scenario by id \\\n", + " A: Create from excel \\\n", " forecast_storage \n", "sortables \n", "0 households_flexibility_p2p_electricity \n", @@ -902,8 +901,8 @@ " \n", " \n", " \n", - " A: Create from excel\n", " B: Load a scenario by id\n", + " A: Create from excel\n", " \n", " \n", " \n", @@ -914,20 +913,20 @@ " interconnector_2_import_availability\n", " interconnector_2_export_availability\n", " interconnector_3_price\n", - " interconnector_1_price\n", - " interconnector_1_import_availability\n", - " interconnector_1_export_availability\n", + " interconnector_3_import_availability\n", + " interconnector_3_export_availability\n", + " interconnector_4_price\n", " ...\n", - " households_hot_water\n", - " industry_ict\n", - " industry_other_electricity\n", - " weather/solar_pv_profile_1\n", - " weather/solar_thermal\n", - " weather/air_temperature\n", - " weather/agriculture_heating\n", " weather/wind_offshore_baseline\n", " weather/wind_coastal_baseline\n", " weather/wind_inland_baseline\n", + " interconnector_1_price\n", + " interconnector_1_import_availability\n", + " interconnector_1_export_availability\n", + " interconnector_2_price\n", + " interconnector_2_import_availability\n", + " interconnector_2_export_availability\n", + " interconnector_3_price\n", " \n", " \n", " \n", @@ -940,20 +939,20 @@ " 1.0\n", " 1.0\n", " 0.01\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.01\n", " ...\n", - " 0.000000e+00\n", - " 2.777764e-08\n", - " 3.055443e-08\n", - " 0.0\n", - " 0.0\n", - " 12.009861\n", - " 1.166142e-08\n", " 0.963978\n", " 0.662786\n", " 0.662786\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 26.00\n", + " 1.0\n", + " 1.0\n", + " 0.01\n", " \n", " \n", " 1\n", @@ -964,20 +963,20 @@ " 1.0\n", " 1.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 0.000000e+00\n", - " 2.777764e-08\n", - " 3.208215e-08\n", - " 0.0\n", - " 0.0\n", - " 12.043616\n", - " 1.138377e-08\n", " 0.966297\n", " 0.737759\n", " 0.737759\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 26.00\n", + " 1.0\n", + " 1.0\n", + " 0.00\n", " \n", " \n", " 2\n", @@ -988,20 +987,20 @@ " 1.0\n", " 1.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 0.000000e+00\n", - " 2.777764e-08\n", - " 3.166550e-08\n", - " 0.0\n", - " 0.0\n", - " 12.133497\n", - " 8.884891e-09\n", " 0.966472\n", " 0.767029\n", " 0.767029\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 14.48\n", + " 1.0\n", + " 1.0\n", + " 0.00\n", " \n", " \n", " 3\n", @@ -1012,20 +1011,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 0.000000e+00\n", - " 2.749986e-08\n", - " 3.208215e-08\n", - " 0.0\n", - " 0.0\n", - " 12.189575\n", - " 9.717849e-09\n", " 0.967103\n", " 0.814272\n", " 0.814272\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.00\n", " \n", " \n", " 4\n", @@ -1036,20 +1035,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 0.000000e+00\n", - " 2.777764e-08\n", - " 3.249880e-08\n", - " 0.0\n", - " 0.0\n", - " 12.312676\n", - " 9.717849e-09\n", " 0.967068\n", " 0.833141\n", " 0.833141\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.02\n", + " 1.0\n", + " 0.0\n", + " 0.00\n", " \n", " \n", " ...\n", @@ -1084,20 +1083,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 4.903713e-08\n", - " 3.111096e-08\n", - " 2.444354e-08\n", - " 0.0\n", - " 0.0\n", - " 9.574081\n", - " 4.275854e-08\n", " 0.967379\n", " 0.933417\n", " 0.933417\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.00\n", " \n", " \n", " 8756\n", @@ -1108,20 +1107,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 4.126528e-08\n", - " 3.083318e-08\n", - " 2.236028e-08\n", - " 0.0\n", - " 0.0\n", - " 9.750026\n", - " 4.609037e-08\n", " 0.967379\n", " 0.936949\n", " 0.936949\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.00\n", " \n", " \n", " 8757\n", @@ -1132,20 +1131,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 2.921741e-08\n", - " 2.999985e-08\n", - " 1.972149e-08\n", - " 0.0\n", - " 0.0\n", - " 10.090767\n", - " 4.636802e-08\n", " 0.967379\n", " 0.936756\n", " 0.936756\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.00\n", " \n", " \n", " 8758\n", @@ -1156,20 +1155,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 2.879315e-08\n", - " 2.888874e-08\n", - " 3.402652e-08\n", - " 0.0\n", - " 0.0\n", - " 10.058248\n", - " 4.581272e-08\n", " 0.967379\n", " 0.945457\n", " 0.945457\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.02\n", + " 1.0\n", + " 0.0\n", + " 0.00\n", " \n", " \n", " 8759\n", @@ -1180,20 +1179,20 @@ " 1.0\n", " 0.0\n", " 0.00\n", - " 0.01\n", " 1.0\n", " 0.0\n", + " 0.00\n", " ...\n", - " 0.000000e+00\n", - " 2.833319e-08\n", - " 3.402652e-08\n", - " 0.0\n", - " 0.0\n", - " 10.255527\n", - " 3.887140e-08\n", " 0.967348\n", " 0.948578\n", " 0.948578\n", + " 0.01\n", + " 1.0\n", + " 0.0\n", + " 0.00\n", + " 1.0\n", + " 0.0\n", + " 0.00\n", " \n", " \n", "\n", @@ -1201,19 +1200,19 @@ "" ], "text/plain": [ - " A: Create from excel \\\n", - " interconnector_1_price interconnector_1_import_availability \n", - "0 0.01 1.0 \n", - "1 0.01 1.0 \n", - "2 0.01 1.0 \n", - "3 0.01 1.0 \n", - "4 0.01 1.0 \n", - "... ... ... \n", - "8755 0.01 1.0 \n", - "8756 0.01 1.0 \n", - "8757 0.01 1.0 \n", - "8758 0.01 1.0 \n", - "8759 0.01 1.0 \n", + " B: Load a scenario by id \\\n", + " interconnector_1_price interconnector_1_import_availability \n", + "0 0.01 1.0 \n", + "1 0.01 1.0 \n", + "2 0.01 1.0 \n", + "3 0.01 1.0 \n", + "4 0.01 1.0 \n", + "... ... ... \n", + "8755 0.01 1.0 \n", + "8756 0.01 1.0 \n", + "8757 0.01 1.0 \n", + "8758 0.01 1.0 \n", + "8759 0.01 1.0 \n", "\n", " \\\n", " interconnector_1_export_availability interconnector_2_price \n", @@ -1257,89 +1256,117 @@ "8758 0.0 0.00 \n", "8759 0.0 0.00 \n", "\n", - " B: Load a scenario by id \\\n", - " interconnector_1_price interconnector_1_import_availability \n", - "0 0.01 1.0 \n", - "1 0.01 1.0 \n", - "2 0.01 1.0 \n", - "3 0.01 1.0 \n", - "4 0.01 1.0 \n", - "... ... ... \n", - "8755 0.01 1.0 \n", - "8756 0.01 1.0 \n", - "8757 0.01 1.0 \n", - "8758 0.01 1.0 \n", - "8759 0.01 1.0 \n", + " \\\n", + " interconnector_3_import_availability \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 \n", + "... ... \n", + "8755 1.0 \n", + "8756 1.0 \n", + "8757 1.0 \n", + "8758 1.0 \n", + "8759 1.0 \n", "\n", - " ... \\\n", - " interconnector_1_export_availability ... households_hot_water \n", - "0 0.0 ... 0.000000e+00 \n", - "1 0.0 ... 0.000000e+00 \n", - "2 0.0 ... 0.000000e+00 \n", - "3 0.0 ... 0.000000e+00 \n", - "4 0.0 ... 0.000000e+00 \n", - "... ... ... ... \n", - "8755 0.0 ... 4.903713e-08 \n", - "8756 0.0 ... 4.126528e-08 \n", - "8757 0.0 ... 2.921741e-08 \n", - "8758 0.0 ... 2.879315e-08 \n", - "8759 0.0 ... 0.000000e+00 \n", + " ... \\\n", + " interconnector_3_export_availability interconnector_4_price ... \n", + "0 0.0 0.01 ... \n", + "1 0.0 0.00 ... \n", + "2 0.0 0.00 ... \n", + "3 0.0 0.00 ... \n", + "4 0.0 0.00 ... \n", + "... ... ... ... \n", + "8755 0.0 0.00 ... \n", + "8756 0.0 0.00 ... \n", + "8757 0.0 0.00 ... \n", + "8758 0.0 0.00 ... \n", + "8759 0.0 0.00 ... \n", "\n", - " \\\n", - " industry_ict industry_other_electricity weather/solar_pv_profile_1 \n", - "0 2.777764e-08 3.055443e-08 0.0 \n", - "1 2.777764e-08 3.208215e-08 0.0 \n", - "2 2.777764e-08 3.166550e-08 0.0 \n", - "3 2.749986e-08 3.208215e-08 0.0 \n", - "4 2.777764e-08 3.249880e-08 0.0 \n", - "... ... ... ... \n", - "8755 3.111096e-08 2.444354e-08 0.0 \n", - "8756 3.083318e-08 2.236028e-08 0.0 \n", - "8757 2.999985e-08 1.972149e-08 0.0 \n", - "8758 2.888874e-08 3.402652e-08 0.0 \n", - "8759 2.833319e-08 3.402652e-08 0.0 \n", + " \\\n", + " weather/wind_offshore_baseline weather/wind_coastal_baseline \n", + "0 0.963978 0.662786 \n", + "1 0.966297 0.737759 \n", + "2 0.966472 0.767029 \n", + "3 0.967103 0.814272 \n", + "4 0.967068 0.833141 \n", + "... ... ... \n", + "8755 0.967379 0.933417 \n", + "8756 0.967379 0.936949 \n", + "8757 0.967379 0.936756 \n", + "8758 0.967379 0.945457 \n", + "8759 0.967348 0.948578 \n", "\n", - " \\\n", - " weather/solar_thermal weather/air_temperature \n", - "0 0.0 12.009861 \n", - "1 0.0 12.043616 \n", - "2 0.0 12.133497 \n", - "3 0.0 12.189575 \n", - "4 0.0 12.312676 \n", - "... ... ... \n", - "8755 0.0 9.574081 \n", - "8756 0.0 9.750026 \n", - "8757 0.0 10.090767 \n", - "8758 0.0 10.058248 \n", - "8759 0.0 10.255527 \n", + " A: Create from excel \\\n", + " weather/wind_inland_baseline interconnector_1_price \n", + "0 0.662786 0.01 \n", + "1 0.737759 0.01 \n", + "2 0.767029 0.01 \n", + "3 0.814272 0.01 \n", + "4 0.833141 0.01 \n", + "... ... ... \n", + "8755 0.933417 0.01 \n", + "8756 0.936949 0.01 \n", + "8757 0.936756 0.01 \n", + "8758 0.945457 0.01 \n", + "8759 0.948578 0.01 \n", + "\n", + " \\\n", + " interconnector_1_import_availability \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 \n", + "... ... \n", + "8755 1.0 \n", + "8756 1.0 \n", + "8757 1.0 \n", + "8758 1.0 \n", + "8759 1.0 \n", "\n", - " \\\n", - " weather/agriculture_heating weather/wind_offshore_baseline \n", - "0 1.166142e-08 0.963978 \n", - "1 1.138377e-08 0.966297 \n", - "2 8.884891e-09 0.966472 \n", - "3 9.717849e-09 0.967103 \n", - "4 9.717849e-09 0.967068 \n", - "... ... ... \n", - "8755 4.275854e-08 0.967379 \n", - "8756 4.609037e-08 0.967379 \n", - "8757 4.636802e-08 0.967379 \n", - "8758 4.581272e-08 0.967379 \n", - "8759 3.887140e-08 0.967348 \n", + " \\\n", + " interconnector_1_export_availability interconnector_2_price \n", + "0 0.0 26.00 \n", + "1 0.0 26.00 \n", + "2 0.0 14.48 \n", + "3 0.0 0.01 \n", + "4 0.0 0.02 \n", + "... ... ... \n", + "8755 0.0 0.01 \n", + "8756 0.0 0.01 \n", + "8757 0.0 0.01 \n", + "8758 0.0 0.02 \n", + "8759 0.0 0.00 \n", + "\n", + " \\\n", + " interconnector_2_import_availability \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 \n", + "... ... \n", + "8755 1.0 \n", + "8756 1.0 \n", + "8757 1.0 \n", + "8758 1.0 \n", + "8759 1.0 \n", "\n", - " \n", - " weather/wind_coastal_baseline weather/wind_inland_baseline \n", - "0 0.662786 0.662786 \n", - "1 0.737759 0.737759 \n", - "2 0.767029 0.767029 \n", - "3 0.814272 0.814272 \n", - "4 0.833141 0.833141 \n", - "... ... ... \n", - "8755 0.933417 0.933417 \n", - "8756 0.936949 0.936949 \n", - "8757 0.936756 0.936756 \n", - "8758 0.945457 0.945457 \n", - "8759 0.948578 0.948578 \n", + " \n", + " interconnector_2_export_availability interconnector_3_price \n", + "0 1.0 0.01 \n", + "1 1.0 0.00 \n", + "2 1.0 0.00 \n", + "3 0.0 0.00 \n", + "4 0.0 0.00 \n", + "... ... ... \n", + "8755 0.0 0.00 \n", + "8756 0.0 0.00 \n", + "8757 0.0 0.00 \n", + "8758 0.0 0.00 \n", + "8759 0.0 0.00 \n", "\n", "[8760 rows x 52 columns]" ] @@ -1352,6 +1379,102 @@ "source": [ "packer.custom_curves()" ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "54cc3f61", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
A: Create from excelB: Load a scenario by id
futurefuture
gqueryunit
dashboard_emissionsfactor0.024027-0.953337
dashboard_co2_emissions_versus_start_yearfactor0.028299-1.003414
dashboard_total_costsbln_euro39.30029358.280256
\n", + "
" + ], + "text/plain": [ + " A: Create from excel \\\n", + " future \n", + "gquery unit \n", + "dashboard_emissions factor 0.024027 \n", + "dashboard_co2_emissions_versus_start_year factor 0.028299 \n", + "dashboard_total_costs bln_euro 39.300293 \n", + "\n", + " B: Load a scenario by id \n", + " future \n", + "gquery unit \n", + "dashboard_emissions factor -0.953337 \n", + "dashboard_co2_emissions_versus_start_year factor -1.003414 \n", + "dashboard_total_costs bln_euro 58.280256 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "packer.gquery_results()" + ] } ], "metadata": { diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index d662013..2fe8919 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -49,7 +49,11 @@ def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: return pd.DataFrame() def _find_by_identifier(self, identifier: str): - return next((s for s in self.scenarios if s.identifier() == identifier), None) + ident_str = str(identifier) + return next( + (s for s in self.scenarios if str(s.identifier()) == ident_str), + None, + ) class InputsPack(Packable): @@ -214,6 +218,136 @@ def _to_dataframe( copy=False, ) + def _normalize_queries_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: + """Normalize a GQUERIES sheet into a simple shape: + - Drop leading completely blank rows and columns. + - Detect 1 or 2 header rows. + - Return a DataFrame with columns = scenario identifiers and rows listing gquery keys. + We ignore any leftmost index/helper columns whose header is empty or looks like a label. + """ + if df is None: + return pd.DataFrame() + + # Drop completely empty rows/cols + df = df.dropna(how="all") + if df.empty: + return df + df = df.dropna(axis=1, how="all") + + # Find non-empty rows for potential headers + non_empty_rows = [ + i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() + ] + if not non_empty_rows: + return pd.DataFrame() + + # Heuristic: if the second non-empty row contains the word 'gquery'/'gqueries', use 2 header rows + header_rows = 1 + if len(non_empty_rows) > 1: + second = ( + df.iloc[non_empty_rows[1]].astype(str).str.strip().str.lower().tolist() + ) + if any(val in {"gquery", "gqueries", "key", "queries"} for val in second): + header_rows = 2 + + header_start = non_empty_rows[0] + header_end = header_start + header_rows - 1 + headers = df.iloc[header_start : header_end + 1].astype(str) + data = df.iloc[header_end + 1 :].copy() + + # Assign columns: MultiIndex if 2 header rows else single level + if header_rows == 2: + cols = pd.MultiIndex.from_arrays( + [headers.iloc[0].values, headers.iloc[1].values] + ) + else: + cols = pd.Index(headers.iloc[0].values) + data.columns = cols + + def _is_empty(v): + return ( + (not isinstance(v, str)) + or (v.strip() == "") + or (v.strip().lower() == "nan") + ) + + def _is_helper_label(v): + return isinstance(v, str) and v.strip().lower() in { + "gquery", + "gqueries", + "queries", + "key", + } + + # Build a simple DataFrame with columns = scenario identifiers + if isinstance(data.columns, pd.MultiIndex): + keep = [ + c + for c in data.columns + if not _is_empty(c[0]) and not _is_helper_label(c[0]) + ] + data = data[keep] + # Collapse to single level (identifier) + data.columns = [c[0] for c in data.columns] + else: + keep = [ + c + for c in data.columns + if isinstance(c, str) and not _is_empty(c) and not _is_helper_label(c) + ] + data = data[keep] + + # Ensure string values and drop rows that are completely blank across all kept columns + for c in data.columns: + data[c] = data[c].apply(lambda x: None if pd.isna(x) else (str(x).strip())) + data = data.dropna(how="all") + + return data + + def from_dataframe(self, df: pd.DataFrame): + """Collect gquery keys for each scenario from a GQUERIES sheet and attach them. + The sheet is expected to have one column per scenario (by identifier/title), + with each row containing a gquery key. Blank rows are ignored. + """ + if df is None or getattr(df, "empty", False): + return + + try: + df = self._normalize_queries_dataframe(df) + except Exception as e: + logger.warning("Failed to normalize gqueries sheet: %s", e) + return + + if df is None or df.empty: + return + + for identifier in df.columns: + scenario = self._find_by_identifier(identifier) + if scenario is None: + logger.warning( + "Could not find scenario for identifier '%s'", identifier + ) + continue + + # Extract non-empty keys, preserve order, remove duplicates while preserving order + values = [ + v + for v in df[identifier].tolist() + if isinstance(v, str) and v.strip() != "" + ] + seen = set() + keys = [] + for v in values: + if v not in seen: + seen.add(v) + keys.append(v) + + if keys: + try: + scenario.add_queries(keys) + except Exception as e: + logger.warning("Failed to add gqueries to '%s': %s", identifier, e) + class SortablePack(Packable): key: ClassVar[str] = "sortables" @@ -843,11 +977,46 @@ def from_excel( packer._custom_curves.add(*scenarios) packer._custom_curves.from_dataframe(curves_df) - # GQueries: unpack not supported; respect option but warn if set - if options.get("repeat_gqueries", False): - logger.warning( - "repeat_gqueries is set but gqueries unpack is read-only and not supported" - ) + # GQueries (optional) + gqueries_sheet = sheet_names.get("gqueries", "GQUERIES") + gq_df = packer.read_sheet(xlsx, gqueries_sheet, required=False, header=None) + if isinstance(gq_df, pd.DataFrame) and not gq_df.empty: + qp = QueryPack(scenarios=set(scenarios)) + if options.get("repeat_gqueries", False): + try: + norm = qp._normalize_queries_dataframe(gq_df) + if isinstance(norm, pd.DataFrame) and not norm.empty: + # Take first available column and repeat its queries for all scenarios + first_col = norm.columns[0] + values = [ + v + for v in norm[first_col].tolist() + if isinstance(v, str) and v.strip() != "" + ] + # De-duplicate preserving order + seen = set() + keys = [] + for v in values: + if v not in seen: + seen.add(v) + keys.append(v) + for s in scenarios: + try: + s.add_queries(keys) + except Exception as e: + logger.warning( + "Failed to apply repeated gqueries to '%s': %s", + ( + s.identifier() + if hasattr(s, "identifier") + else s.id + ), + e, + ) + except Exception as e: + logger.warning("Failed to process repeated gqueries: %s", e) + else: + qp.from_dataframe(gq_df) return packer @@ -1010,6 +1179,6 @@ def read_sheet( return pd.Series(name=sheet_name, dtype=str) # Use the ExcelFile.parse API directly to avoid pandas' engine guard - values = xlsx.parse(sheet_name=sheet_name, **kwargs).squeeze(axis=1) + values = xlsx.parse(sheet_name=sheet_name, **kwargs) return values # .rename(sheet_name) From db39f5209569d85d1e34b3fdf124d85f96d22379 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Fri, 8 Aug 2025 16:29:26 +0200 Subject: [PATCH 08/17] WIP refactoring packer to suite new input format - partially working --- src/pyetm/models/scenario_packer.py | 713 ++++++++++++---------------- 1 file changed, 315 insertions(+), 398 deletions(-) diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 2fe8919..1a8f826 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -60,6 +60,23 @@ class InputsPack(Packable): key: ClassVar[str] = "inputs" sheet_name: ClassVar[str] = "PARAMETERS" + def __init__(self, **data): + super().__init__(**data) + self._scenario_short_names: Dict[str, str] = {} # scenario_id -> short_name mapping + + def set_scenario_short_names(self, scenario_short_names: Dict[str, str]): + """Set the mapping of scenario identifiers to their short names.""" + self._scenario_short_names = scenario_short_names + + def _find_by_short_name(self, short_name: str): + """Find scenario by its short name.""" + short_name_str = str(short_name) + for scenario in self.scenarios: + scenario_id = str(scenario.identifier()) + if self._scenario_short_names.get(scenario_id) == short_name_str: + return scenario + return None + def _to_dataframe(self, columns="user", **kwargs): return pd.concat( [ @@ -67,17 +84,18 @@ def _to_dataframe(self, columns="user", **kwargs): for scenario in self.scenarios ], axis=1, - keys=[scenario.identifier() for scenario in self.scenarios], + keys=[self._scenario_short_names.get(str(scenario.identifier()), str(scenario.identifier())) + for scenario in self.scenarios], ) def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: """Normalize various inputs sheet shapes into canonical shape: - Drop leading completely blank rows. - - Detect two header rows (identifier row above a row containing 'user'). + - Detect two header rows (short_name row above a row containing 'user'). - Support 1- or 2-level row index (input[, unit]). Returns a DataFrame with: index -> Index or MultiIndex (input[, unit]) - columns -> MultiIndex (identifier, 'user') + columns -> MultiIndex (short_name, 'user') """ # Drop completely empty rows df = df.dropna(how="all") @@ -163,11 +181,11 @@ def from_dataframe(self, df): """ Sets the inputs on the scenarios from the packed df (comes from excel) Tolerates optional unit column and leading blank rows. + Uses short_name for scenario identification. """ if df is None or getattr(df, "empty", False): return - # Canonicalize the incoming shape first try: df = self._normalize_inputs_dataframe(df) except Exception as e: @@ -177,18 +195,18 @@ def from_dataframe(self, df): if df is None or df.empty: return - # Now df has columns MultiIndex (identifier, 'user') and index input or (input, unit) - identifiers = df.columns.get_level_values(0).unique() + # Now df has columns MultiIndex (short_name, 'user') and index input or (input, unit) + short_names = df.columns.get_level_values(0).unique() - for identifier in identifiers: - scenario = self._find_by_identifier(identifier) + for short_name in short_names: + scenario = self._find_by_short_name(short_name) if scenario is None: logger.warning( - "Could not find scenario for identifier '%s'", identifier + "Could not find scenario for short_name '%s'", short_name ) continue - scenario_df = df[identifier] + scenario_df = df[short_name] # Ensure DataFrame with a 'user' column if isinstance(scenario_df, pd.Series): scenario_df = scenario_df.to_frame(name="user") @@ -749,436 +767,335 @@ def get_summary(self) -> Dict[str, Any]: # Create stuff - def _read_global_options( - self, xlsx: pd.ExcelFile, sheet_name: str - ) -> Dict[str, bool]: - """Read global OPTIONS from the MAIN sheet.""" - try: - raw = xlsx.parse(sheet_name=sheet_name, header=None) - except Exception: - return { - "repeat_parameters": False, - "repeat_gqueries": False, - "repeat_sortables": False, - "repeat_custom_curves": False, + def _extract_scenario_sheet_info(self, main_df: pd.DataFrame) -> Dict[str, Dict[str, str]]: + """Extract sortables and custom_curves sheet names for each scenario from MAIN sheet. + Also extracts short_name mapping for parameter sheet identification. + Returns dict with scenario identifier as key and info dict containing: + - 'short_name': short name for parameter sheet identification + - 'sortables': sortables sheet name + - 'custom_curves': custom curves sheet name + """ + scenario_sheets = {} + + if isinstance(main_df, pd.Series): + # Single scenario + identifier = str(main_df.name) + short_name = main_df.get('short_name') + sortables_sheet = main_df.get('sortables') + custom_curves_sheet = main_df.get('custom_curves') + + scenario_sheets[identifier] = { + 'short_name': short_name if pd.notna(short_name) else identifier, + 'sortables': sortables_sheet if pd.notna(sortables_sheet) else None, + 'custom_curves': custom_curves_sheet if pd.notna(custom_curves_sheet) else None } + else: + # Multiple scenarios + for identifier in main_df.columns: + col_data = main_df[identifier] + short_name = col_data.get('short_name') + sortables_sheet = col_data.get('sortables') + custom_curves_sheet = col_data.get('custom_curves') + + scenario_sheets[str(identifier)] = { + 'short_name': short_name if pd.notna(short_name) else str(identifier), + 'sortables': sortables_sheet if pd.notna(sortables_sheet) else None, + 'custom_curves': custom_curves_sheet if pd.notna(custom_curves_sheet) else None + } + + return scenario_sheets + + def _process_single_scenario_sortables(self, scenario: "Scenario", df: pd.DataFrame): + """Process sortables for a single scenario from its dedicated sheet. + Simplified parsing since there's only one scenario per sheet. + Tolerates a leading index column (e.g. 'hour' or blank), and maps + 'heat_network' → 'heat_network_lt' for convenience. + """ + # Drop completely empty rows + df = df.dropna(how="all") + if df.empty: + return - def _as_bool(v): - if v is None or (isinstance(v, float) and pd.isna(v)): - return None - if isinstance(v, bool): - return v - try: - if isinstance(v, (int, float)) and not pd.isna(v): - return bool(int(v)) - except Exception: - pass - if isinstance(v, str): - s = v.strip().lower() - if s in {"true", "yes", "1", "y", "t"}: - return True - if s in {"false", "no", "0", "n", "f"}: - return False - return None + # Find the first non-empty row -> header with sortable names + non_empty_idx = [i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all()] + if not non_empty_idx: + return - # Find the 'OPTIONS' row in column A (index 0) - opts_idx = None - col0 = raw.iloc[:, 0] - for i, val in enumerate(col0): - if isinstance(val, str) and val.strip().lower() == "options": - opts_idx = i - break + header_pos = non_empty_idx[0] + header = df.iloc[header_pos].astype(str).map(lambda s: s.strip()) + data = df.iloc[header_pos + 1 :].copy() - defaults = { - "repeat_parameters": False, - "repeat_gqueries": False, - "repeat_sortables": False, - "repeat_custom_curves": False, - } - if opts_idx is None: - return defaults - - # Scan following rows for key/value pairs in col0/col1 until blank key - result = defaults.copy() - for i in range(opts_idx + 1, len(raw)): - key = raw.iat[i, 0] if 0 < raw.shape[1] else None - if key is None or (isinstance(key, float) and pd.isna(key)): - # stop at first completely blank key - break - if not isinstance(key, str): - continue - k = key.strip() - if k not in result: - continue - val = raw.iat[i, 1] if raw.shape[1] > 1 else None - b = _as_bool(val) - result[k] = bool(b) if b is not None else False + # Set column names from header + data.columns = header.values - return result + # Helper to detect columns to drop + def _is_empty_or_helper(col_name: Any) -> bool: + if not isinstance(col_name, str): + return True + name = col_name.strip().lower() + return name in {"", "nan", "sortables", "hour", "index"} - @classmethod - def from_excel( - cls, - filepath: str | PathLike, - sheet_names: Optional[Dict[str, str]] = None, - ): + # Drop empty/helper columns + keep_cols = [col for col in data.columns if not _is_empty_or_helper(col)] + data = data[keep_cols] + + # Map bare 'heat_network' to 'heat_network_lt' if present + if "heat_network" in data.columns and "heat_network_lt" not in data.columns: + data = data.rename(columns={"heat_network": "heat_network_lt"}) + + # Reset index to numeric starting at 0 + data.reset_index(drop=True, inplace=True) + + # Apply to scenario + scenario.set_sortables_from_dataframe(data) + + def _process_single_scenario_curves(self, scenario: "Scenario", df: pd.DataFrame): + """Process custom curves for a single scenario from its dedicated sheet. + Simplified parsing since there's only one scenario per sheet. + Tolerates a leading index column (e.g. 'hour' or blank). """ - Build a ScenarioPacker from an Excel file. - sheet_names optionally maps logical pack keys to sheet titles, e.g.: - {"main": "MAIN", "inputs": "PARAMETERS"} + # Drop completely empty rows + df = df.dropna(how="all") + if df.empty: + return + + # Find the first non-empty row -> header with curve keys + non_empty_idx = [i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all()] + if not non_empty_idx: + return + + header_pos = non_empty_idx[0] + header = df.iloc[header_pos].astype(str).map(lambda s: s.strip()) + data = df.iloc[header_pos + 1 :].copy() + + # Set column names from header + data.columns = header.values + + # Helper to detect columns to drop + def _is_empty_or_helper(col_name: Any) -> bool: + if not isinstance(col_name, str): + return True + name = col_name.strip().lower() + return name in {"", "nan", "curves", "custom_curves", "hour", "index"} + + # Drop empty/helper columns + keep_cols = [col for col in data.columns if not _is_empty_or_helper(col)] + data = data[keep_cols] + + # Reset index to numeric starting at 0 + data.reset_index(drop=True, inplace=True) + + if data.empty: + return + + # Build CustomCurves collection and apply + try: + curves = CustomCurves._from_dataframe(data) + scenario.update_custom_curves(curves) + except Exception as e: + logger.warning("Failed processing custom curves for '%s': %s", scenario.identifier(), e) + + @classmethod + def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": + """Create/load scenarios and apply updates from an Excel workbook. + Behavior (new layout): + - MAIN sheet contains one column per scenario; rows may include: scenario_id, short_name, + area_code, end_year, private, template, title, sortables, custom_curves. + - PARAMETERS uses short_name headers above a 'user' header; values never repeat across scenarios. + - GQUERIES always repeat (same keys applied to each scenario column present). + - Sortables and custom curves are read from per-scenario sheets named in MAIN. + Returns a ScenarioPacker containing all touched scenarios. """ packer = cls() - sheet_names = sheet_names or {} - - with pd.ExcelFile(filepath) as xlsx: - # Open main tab - create scenarios from there - main_sheet = sheet_names.get("main", "MAIN") - main_df = packer.read_sheet(xlsx, main_sheet, index_col=0) - scenarios = packer.scenarios_from_df(main_df) - - # Read global OPTIONS from MAIN - options = packer._read_global_options(xlsx, main_sheet) - - # Inputs (optional): only process when the sheet exists - inputs_sheet = sheet_names.get("inputs", packer._inputs.sheet_name) - packer._inputs.add(*scenarios) - # Read raw to tolerate blank header rows; we'll canonicalize inside from_dataframe - inputs_df = packer.read_sheet( - xlsx, - inputs_sheet, - required=False, - header=None, - ) - if isinstance(inputs_df, pd.DataFrame) and not inputs_df.empty: - if options.get("repeat_parameters", False): - try: - norm = packer._inputs._normalize_inputs_dataframe(inputs_df) - if isinstance(norm, pd.DataFrame) and not norm.empty: - first_id = norm.columns.get_level_values(0)[0] - block = norm[first_id] - if isinstance(block, pd.Series): - block = block.to_frame(name="user") - else: - if list(block.columns) != ["user"]: - block = block.copy() - first_col = block.columns[0] - block = block.rename(columns={first_col: "user"}) - for s in scenarios: - try: - s.set_user_values_from_dataframe(block) - except Exception as e: - logger.warning( - "Failed to apply repeated inputs to '%s': %s", - ( - s.identifier() - if hasattr(s, "identifier") - else s.id - ), - e, - ) - except Exception as e: - logger.warning("Failed to process repeated inputs: %s", e) - else: - packer._inputs.from_dataframe(inputs_df) - - # Sortables (optional) - sortables_sheet = ( - sheet_names.get("sortables", packer._sortables.sheet_name) - if sheet_names - else packer._sortables.sheet_name - ) - sortables_df = packer.read_sheet( - xlsx, sortables_sheet, required=False, header=None - ) - if isinstance(sortables_df, pd.DataFrame) and not sortables_df.empty: - if options.get("repeat_sortables", False): - # Ensure scenarios are included in the pack for downstream DataFrame exports - packer._sortables.add(*scenarios) - try: - norm = packer._sortables._normalize_sortables_dataframe( - sortables_df - ) - if ( - isinstance(norm, pd.DataFrame) - and not norm.empty - and isinstance(norm.columns, pd.MultiIndex) - ): - first_id = norm.columns.get_level_values(0)[0] - block = norm[first_id] - for s in scenarios: - try: - s.set_sortables_from_dataframe(block) - except Exception as e: - logger.warning( - "Failed to apply repeated sortables to '%s': %s", - ( - s.identifier() - if hasattr(s, "identifier") - else s.id - ), - e, - ) - except Exception as e: - logger.warning("Failed to process repeated sortables: %s", e) - else: - packer._sortables.add(*scenarios) - packer._sortables.from_dataframe(sortables_df) - - # Custom curves (optional) - curves_sheet = ( - sheet_names.get("custom_curves", packer._custom_curves.sheet_name) - if sheet_names - else packer._custom_curves.sheet_name - ) - curves_df = packer.read_sheet( - xlsx, curves_sheet, required=False, header=None - ) - if isinstance(curves_df, pd.DataFrame) and not curves_df.empty: - if options.get("repeat_custom_curves", False): - # Ensure scenarios are included in the pack for downstream DataFrame exports - packer._custom_curves.add(*scenarios) - try: - norm = packer._custom_curves._normalize_curves_dataframe( - curves_df - ) - if ( - isinstance(norm, pd.DataFrame) - and not norm.empty - and isinstance(norm.columns, pd.MultiIndex) - ): - first_id = norm.columns.get_level_values(0)[0] - block = norm[first_id] - try: - curves = CustomCurves._from_dataframe(block) - except Exception as e: - logger.warning( - "Failed to build repeated custom curves: %s", e - ) - curves = None - if curves is not None: - for s in scenarios: - try: - s.update_custom_curves(curves) - except Exception as e: - logger.warning( - "Failed to apply repeated custom curves to '%s': %s", - ( - s.identifier() - if hasattr(s, "identifier") - else s.id - ), - e, - ) - except Exception as e: - logger.warning( - "Failed to process repeated custom curves: %s", e - ) - else: - packer._custom_curves.add(*scenarios) - packer._custom_curves.from_dataframe(curves_df) - - # GQueries (optional) - gqueries_sheet = sheet_names.get("gqueries", "GQUERIES") - gq_df = packer.read_sheet(xlsx, gqueries_sheet, required=False, header=None) - if isinstance(gq_df, pd.DataFrame) and not gq_df.empty: - qp = QueryPack(scenarios=set(scenarios)) - if options.get("repeat_gqueries", False): - try: - norm = qp._normalize_queries_dataframe(gq_df) - if isinstance(norm, pd.DataFrame) and not norm.empty: - # Take first available column and repeat its queries for all scenarios - first_col = norm.columns[0] - values = [ - v - for v in norm[first_col].tolist() - if isinstance(v, str) and v.strip() != "" - ] - # De-duplicate preserving order - seen = set() - keys = [] - for v in values: - if v not in seen: - seen.add(v) - keys.append(v) - for s in scenarios: - try: - s.add_queries(keys) - except Exception as e: - logger.warning( - "Failed to apply repeated gqueries to '%s': %s", - ( - s.identifier() - if hasattr(s, "identifier") - else s.id - ), - e, - ) - except Exception as e: - logger.warning("Failed to process repeated gqueries: %s", e) - else: - qp.from_dataframe(gq_df) - return packer + # Try to open the workbook; if missing, return empty packer (keeps tests tolerant) + try: + xls = pd.ExcelFile(xlsx_path) + except Exception as e: + logger.warning("Could not open Excel file '%s': %s", xlsx_path, e) + return packer - @staticmethod - def scenarios_from_df(df: pd.DataFrame) -> list["Scenario"]: - """Converts one df (MAIN) into a list of scenarios""" - scenarios: list[Scenario] = [] + # MAIN sheet + try: + main_df = xls.parse("MAIN", index_col=0) + except Exception as e: + logger.warning("Failed to parse MAIN sheet: %s", e) + return packer - if isinstance(df, pd.Series): - identifier = df.name - data = df.to_dict() - scenarios.append(ScenarioPacker.setup_scenario(identifier, data)) - return scenarios + if main_df is None or getattr(main_df, "empty", False): + return packer - # DataFrame: columns are scenario identifiers (id or a custom title) - for identifier in df.columns: - col_data = df[identifier].to_dict() - scenarios.append(ScenarioPacker.setup_scenario(identifier, col_data)) + # Build scenarios per MAIN column + scenarios_by_col: Dict[str, Scenario] = {} + for col in main_df.columns: + try: + scenario = packer._setup_scenario_from_main_column(str(col), main_df[col]) + except Exception as e: + logger.warning("Failed to set up scenario for column '%s': %s", col, e) + continue - return scenarios + if scenario is not None: + packer.add(scenario) + scenarios_by_col[str(col)] = scenario + + if len(scenarios_by_col) == 0: + return packer + + # Extract per-scenario sheet info and short_name mapping + sheet_info = packer._extract_scenario_sheet_info(main_df) + short_name_map: Dict[str, str] = {} + for col_name, scenario in scenarios_by_col.items(): + info = sheet_info.get(col_name, {}) if isinstance(sheet_info, dict) else {} + short = info.get("short_name") if isinstance(info, dict) else None + if short is None or (isinstance(short, float) and pd.isna(short)): + short = str(scenario.identifier()) + short_name_map[str(scenario.id)] = str(short) + + # PARAMETERS (inputs) sheet + params_df = None + try: + # Read raw to allow our normalization to detect header rows + params_df = xls.parse(InputsPack.sheet_name, header=None) + except Exception: + params_df = None - @staticmethod - def setup_scenario(identifier, data): - """Returns a scenario from data dict. - If the identifier is an int (or str-int), load; otherwise create new. - # TODO: Set up create from template? - """ - # Normalize NA values to None - data = {k: (None if pd.isna(v) else v) for k, v in data.items()} + if params_df is not None and not params_df.empty: + try: + packer._inputs.set_scenario_short_names(short_name_map) + packer._inputs.from_dataframe(params_df) + except Exception as e: + logger.warning("Failed to import PARAMETERS: %s", e) - scenario: Scenario - scenario_title: Optional[str] = ( - identifier if isinstance(identifier, str) and identifier != "" else None - ) + # GQUERIES sheet (keys to attach to scenarios) + gq_df = None + for sheet in ("GQUERIES", QueryPack.sheet_name): + if sheet in xls.sheet_names: + try: + gq_df = xls.parse(sheet, header=None) + break + except Exception: + gq_df = None + if gq_df is not None and not gq_df.empty: + try: + QueryPack(scenarios=packer._scenarios()).from_dataframe(gq_df) + except Exception as e: + logger.warning("Failed to import GQUERIES: %s", e) + + # Per-scenario Sortables and Custom Curves + for col_name, scenario in scenarios_by_col.items(): + info = sheet_info.get(col_name, {}) if isinstance(sheet_info, dict) else {} + + sortables_sheet = info.get("sortables") if isinstance(info, dict) else None + if isinstance(sortables_sheet, str) and sortables_sheet in xls.sheet_names: + try: + s_df = xls.parse(sortables_sheet, header=None) + self_ref = packer # clarity + self_ref._process_single_scenario_sortables(scenario, s_df) + except Exception as e: + logger.warning( + "Failed to process SORTABLES sheet '%s' for '%s': %s", + sortables_sheet, + scenario.identifier(), + e, + ) - # Extract optional MAIN fields - explicit_title = data.get("title") - description = data.get("description") - private_val = data.get("private") - template_val = data.get("template") + curves_sheet = info.get("custom_curves") if isinstance(info, dict) else None + if isinstance(curves_sheet, str) and curves_sheet in xls.sheet_names: + try: + c_df = xls.parse(curves_sheet, header=None) + self_ref = packer + self_ref._process_single_scenario_curves(scenario, c_df) + except Exception as e: + logger.warning( + "Failed to process CUSTOM_CURVES sheet '%s' for '%s': %s", + curves_sheet, + scenario.identifier(), + e, + ) - def _as_bool(v): - if v is None: + return packer + + def _setup_scenario_from_main_column(self, col_name: str, col_data: pd.Series) -> Optional[Scenario]: + """Create or load a Scenario from a MAIN sheet column and apply metadata. + Preference: if 'scenario_id' present -> load; otherwise create with area_code/end_year. + """ + # Helper conversions + def _to_bool(v: Any) -> Optional[bool]: + if v is None or (isinstance(v, float) and pd.isna(v)): return None if isinstance(v, bool): return v - # Excel often gives numbers/floats or strings - try: - if isinstance(v, (int, float)) and not pd.isna(v): - return bool(int(v)) - except Exception: - pass + if isinstance(v, (int, float)): + return bool(int(v)) if isinstance(v, str): s = v.strip().lower() - if s in {"true", "yes", "1", "y", "t"}: + if s in {"true", "yes", "y", "1"}: return True - if s in {"false", "no", "0", "n", "f"}: + if s in {"false", "no", "n", "0"}: return False return None - def _as_int(v): + def _to_int(v: Any) -> Optional[int]: try: if v is None or (isinstance(v, float) and pd.isna(v)): return None - return int(v) + return int(float(v)) except Exception: return None - effective_title = explicit_title or scenario_title + scenario_id = col_data.get("scenario_id") if isinstance(col_data, pd.Series) else None + area_code = col_data.get("area_code") if isinstance(col_data, pd.Series) else None + end_year = _to_int(col_data.get("end_year")) if isinstance(col_data, pd.Series) else None + private = _to_bool(col_data.get("private")) if isinstance(col_data, pd.Series) else None + template = _to_int(col_data.get("template")) if isinstance(col_data, pd.Series) else None + title = col_data.get("title") if isinstance(col_data, pd.Series) else None - # Try to interpret identifier as an ID - scenario_id: Optional[int] = None - if isinstance(identifier, (int, float)) and not pd.isna(identifier): - try: - scenario_id = int(identifier) - except Exception: - scenario_id = None - elif isinstance(identifier, str): + scenario: Optional[Scenario] = None + + # Load or create + sid = _to_int(scenario_id) + if sid is not None: try: - scenario_id = int(identifier) - except ValueError: - scenario_id = None - - if scenario_id is not None: - # Load existing - scenario = Scenario.load(scenario_id) - - # Update metadata for existing scenarios based on MAIN sheet - update_fields: Dict[str, Any] = {} - private_bool = _as_bool(private_val) - if private_bool is not None: - update_fields["private"] = private_bool - - meta: Dict[str, Any] = {} - if effective_title: - meta["title"] = effective_title - if description: - meta["description"] = description - if meta: - update_fields["metadata"] = meta - if update_fields: + scenario = Scenario.load(sid) + except Exception as e: + logger.warning("Failed to load scenario %s for column '%s': %s", sid, col_name, e) + scenario = None + else: + if area_code and end_year is not None: try: - scenario.update_metadata(**update_fields) + scenario = Scenario.new(str(area_code), int(end_year)) except Exception as e: logger.warning( - "Failed to update metadata for '%s': %s", identifier, e + "Failed to create scenario for column '%s' (area_code=%s, end_year=%s): %s", + col_name, + area_code, + end_year, + e, ) - else: - area_code = data.get("area_code") - end_year = data.get("end_year") - if area_code is None or end_year is None: - raise ValueError( - "Cannot create a new Scenario without 'area_code' and 'end_year'" + scenario = None + else: + logger.warning( + "MAIN column '%s' missing required fields for creation (area_code/end_year)", + col_name, ) + scenario = None - create_kwargs: Dict[str, Any] = {} - - private_bool = _as_bool(private_val) - if private_bool is not None: - create_kwargs["private"] = private_bool - - template_int = _as_int(template_val) - if template_int is not None: - create_kwargs["template"] = template_int - - meta: Dict[str, Any] = {} - if effective_title: - meta["title"] = effective_title - if description: - meta["description"] = description - if meta: - create_kwargs["metadata"] = meta + if scenario is None: + return None - scenario = Scenario.new( - area_code=area_code, end_year=int(end_year), **create_kwargs - ) + # Apply metadata updates if provided + meta_updates: Dict[str, Any] = {} + if private is not None: + meta_updates["private"] = private + if template is not None: + meta_updates["template"] = template + if isinstance(title, str) and title.strip() != "": + meta_updates["title"] = title.strip() - # Set a title when a non-numeric identifier is provided - if scenario_title is not None: - scenario.title = scenario_title + if meta_updates: + try: + scenario.update_metadata(**meta_updates) + except Exception as e: + logger.warning("Failed to update metadata for '%s': %s", scenario.identifier(), e) return scenario - - # NOTE: Move to utils? - # Straight from Rob - @staticmethod - def read_sheet( - xlsx: pd.ExcelFile, sheet_name: str, required: bool = True, **kwargs - ) -> pd.Series: - """read list items""" - - if not sheet_name in xlsx.sheet_names: - if required: - raise ValueError( - f"Could not load required sheet '{sheet_name}' from {xlsx.io}" - ) - logger.warning( - "Could not load optional sheet '%s' from '%s'", sheet_name, xlsx.io - ) - return pd.Series(name=sheet_name, dtype=str) - - # Use the ExcelFile.parse API directly to avoid pandas' engine guard - values = xlsx.parse(sheet_name=sheet_name, **kwargs) - - return values # .rename(sheet_name) From 96796c8218a792dfa94647645904ccb80e5924fe Mon Sep 17 00:00:00 2001 From: louispt1 Date: Mon, 11 Aug 2025 08:36:44 +0200 Subject: [PATCH 09/17] New excel format working pre-clean up --- examples/excel_to_scenarios.ipynb | 1436 +-------------------------- src/pyetm/models/custom_curves.py | 58 +- src/pyetm/models/scenario_packer.py | 351 +++++-- 3 files changed, 312 insertions(+), 1533 deletions(-) diff --git a/examples/excel_to_scenarios.ipynb b/examples/excel_to_scenarios.ipynb index c9e2ca9..62d7c43 100644 --- a/examples/excel_to_scenarios.ipynb +++ b/examples/excel_to_scenarios.ipynb @@ -12,188 +12,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "4866f9d1", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Environment setup complete\n", - " Using ETM API at http://localhost:3000/api/v3\n", - " Token loaded? True\n", - "API connection ready\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:206: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", - " self.update_user_values(series.fillna(\"reset\").to_dict())\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'total_scenarios': 2, 'inputs': {'scenario_count': 2}, 'sortables': {'scenario_count': 2}, 'custom_curves': {'scenario_count': 2}, 'output_curves': {'scenario_count': 0}, 'scenario_ids': [2690555, 2690595]}\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
B: Load a scenario by idA: Create from excel
useruser
inputunit
climate_relevant_co2_biomass_gas_future%30.030.0
climate_relevant_co2_biomass_gas_present%20.020.0
climate_relevant_co2_biomass_liquid_future%30.030.0
climate_relevant_co2_biomass_liquid_present%20.020.0
climate_relevant_co2_biomass_solid_future%30.030.0
............
capacity_of_energy_battery_wind_turbine_inlandMW0.0NaN
capacity_of_energy_power_hybrid_wind_turbine_offshoreMWNoneNaN
capacity_of_energy_power_wind_turbine_coastalMW0.0NaN
capacity_of_energy_power_wind_turbine_inlandMW20000.0NaN
capacity_of_energy_power_wind_turbine_offshoreMW52000.0NaN
\n", - "

1318 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " B: Load a scenario by id \\\n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 30.0 \n", - "climate_relevant_co2_biomass_gas_present % 20.0 \n", - "climate_relevant_co2_biomass_liquid_future % 30.0 \n", - "climate_relevant_co2_biomass_liquid_present % 20.0 \n", - "climate_relevant_co2_biomass_solid_future % 30.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", - "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", - "capacity_of_energy_power_wind_turbine_inland MW 20000.0 \n", - "capacity_of_energy_power_wind_turbine_offshore MW 52000.0 \n", - "\n", - " A: Create from excel \n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 30.0 \n", - "climate_relevant_co2_biomass_gas_present % 20.0 \n", - "climate_relevant_co2_biomass_liquid_future % 30.0 \n", - "climate_relevant_co2_biomass_liquid_present % 20.0 \n", - "climate_relevant_co2_biomass_solid_future % 30.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", - "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", - "capacity_of_energy_power_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", - "\n", - "[1318 rows x 2 columns]" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from example_helpers import setup_notebook\n", "from pyetm.models.scenario_packer import ScenarioPacker\n", @@ -208,1270 +30,30 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "cd08ff26", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
B: Load a scenario by idA: Create from excel
forecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_htforecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_ht
sortables
0households_flexibility_p2p_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_waterhouseholds_flexibility_p2p_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_water
1energy_flexibility_mv_batteries_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricityenergy_flexibility_mv_batteries_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricity
2transport_car_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coaltransport_car_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coal
3energy_flexibility_flow_batteries_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oilenergy_flexibility_flow_batteries_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oil
4energy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogenenergy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogen
5transport_bus_flexibility_p2p_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gastransport_bus_flexibility_p2p_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gas
6transport_truck_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mixtransport_truck_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mix
7transport_van_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pelletstransport_van_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pellets
8energy_flexibility_pumped_storage_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricityenergy_flexibility_pumped_storage_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricity
9NoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...NoneNoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...None
10NoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...None
11NoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...None
12NoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNoneNoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNone
13NoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNoneNoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNone
14NoneNoneNonehouseholds_space_heater_network_gasNoneNoneNoneNoneNoneNonehouseholds_space_heater_network_gasNoneNoneNone
15NoneNoneNonehouseholds_space_heater_coalNoneNoneNoneNoneNoneNonehouseholds_space_heater_coalNoneNoneNone
16NoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNoneNoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNone
\n", - "
" - ], - "text/plain": [ - " B: Load a scenario by id \\\n", - " forecast_storage \n", - "sortables \n", - "0 households_flexibility_p2p_electricity \n", - "1 energy_flexibility_mv_batteries_electricity \n", - "2 transport_car_flexibility_p2p_electricity \n", - "3 energy_flexibility_flow_batteries_electricity \n", - "4 energy_flexibility_hv_opac_electricity \n", - "5 transport_bus_flexibility_p2p_electricity \n", - "6 transport_truck_flexibility_p2p_electricity \n", - "7 transport_van_flexibility_p2p_electricity \n", - "8 energy_flexibility_pumped_storage_electricity \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " hydrogen_supply \n", - "sortables \n", - "0 energy_hydrogen_storage_depleted_gas_field \n", - "1 energy_hydrogen_storage_salt_cavern \n", - "2 energy_hydrogen_autothermal_reformer_dispatchable \n", - "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", - "4 energy_hydrogen_ammonia_reformer_dispatchable \n", - "5 None \n", - "6 None \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " hydrogen_demand \n", - "sortables \n", - "0 energy_hydrogen_storage_depleted_gas_field \n", - "1 energy_hydrogen_storage_salt_cavern \n", - "2 None \n", - "3 None \n", - "4 None \n", - "5 None \n", - "6 None \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " space_heating \n", - "sortables \n", - "0 households_space_heater_district_heating_lt_st... \n", - "1 households_space_heater_heatpump_surface_water... \n", - "2 households_space_heater_heatpump_air_water_ele... \n", - "3 households_space_heater_heatpump_ground_water_... \n", - "4 households_space_heater_heatpump_pvt_electricity \n", - "5 households_space_heater_district_heating_mt_st... \n", - "6 households_space_heater_hybrid_heatpump_air_wa... \n", - "7 households_space_heater_hybrid_hydrogen_heatpu... \n", - "8 households_space_heater_hybrid_crude_oil_heatp... \n", - "9 households_space_heater_district_heating_ht_st... \n", - "10 households_space_heater_electricity \n", - "11 households_space_heater_combined_network_gas \n", - "12 households_space_heater_combined_hydrogen \n", - "13 households_space_heater_wood_pellets \n", - "14 households_space_heater_network_gas \n", - "15 households_space_heater_coal \n", - "16 households_space_heater_crude_oil \n", - "\n", - " \\\n", - " heat_network_lt \n", - "sortables \n", - "0 energy_heat_network_storage_lt_steam_hot_water \n", - "1 energy_heat_boiler_lt_electricity \n", - "2 energy_heat_burner_lt_hydrogen \n", - "3 energy_heat_heatpump_water_water_lt_electricity \n", - "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", - "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", - "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " heat_network_mt \n", - "sortables \n", - "0 energy_heat_network_storage_mt_steam_hot_water \n", - "1 energy_heat_boiler_mt_electricity \n", - "2 energy_heat_burner_mt_coal \n", - "3 energy_heat_burner_mt_crude_oil \n", - "4 energy_heat_burner_mt_hydrogen \n", - "5 energy_heat_burner_mt_network_gas \n", - "6 energy_heat_burner_mt_waste_mix \n", - "7 energy_heat_burner_mt_wood_pellets \n", - "8 energy_heat_heatpump_water_water_mt_electricity \n", - "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", - "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", - "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " heat_network_ht \n", - "sortables \n", - "0 energy_heat_network_storage_ht_steam_hot_water \n", - "1 energy_heat_boiler_ht_electricity \n", - "2 energy_heat_burner_ht_coal \n", - "3 energy_heat_burner_ht_crude_oil \n", - "4 energy_heat_burner_ht_hydrogen \n", - "5 energy_heat_burner_ht_network_gas \n", - "6 energy_heat_burner_ht_waste_mix \n", - "7 energy_heat_burner_ht_wood_pellets \n", - "8 energy_heat_heatpump_water_water_ht_electricity \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " A: Create from excel \\\n", - " forecast_storage \n", - "sortables \n", - "0 households_flexibility_p2p_electricity \n", - "1 energy_flexibility_mv_batteries_electricity \n", - "2 transport_car_flexibility_p2p_electricity \n", - "3 energy_flexibility_flow_batteries_electricity \n", - "4 energy_flexibility_hv_opac_electricity \n", - "5 transport_bus_flexibility_p2p_electricity \n", - "6 transport_truck_flexibility_p2p_electricity \n", - "7 transport_van_flexibility_p2p_electricity \n", - "8 energy_flexibility_pumped_storage_electricity \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " hydrogen_supply \n", - "sortables \n", - "0 energy_hydrogen_storage_depleted_gas_field \n", - "1 energy_hydrogen_storage_salt_cavern \n", - "2 energy_hydrogen_autothermal_reformer_dispatchable \n", - "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", - "4 energy_hydrogen_ammonia_reformer_dispatchable \n", - "5 None \n", - "6 None \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " hydrogen_demand \n", - "sortables \n", - "0 energy_hydrogen_storage_depleted_gas_field \n", - "1 energy_hydrogen_storage_salt_cavern \n", - "2 None \n", - "3 None \n", - "4 None \n", - "5 None \n", - "6 None \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " space_heating \n", - "sortables \n", - "0 households_space_heater_district_heating_lt_st... \n", - "1 households_space_heater_heatpump_surface_water... \n", - "2 households_space_heater_heatpump_air_water_ele... \n", - "3 households_space_heater_heatpump_ground_water_... \n", - "4 households_space_heater_heatpump_pvt_electricity \n", - "5 households_space_heater_district_heating_mt_st... \n", - "6 households_space_heater_hybrid_heatpump_air_wa... \n", - "7 households_space_heater_hybrid_hydrogen_heatpu... \n", - "8 households_space_heater_hybrid_crude_oil_heatp... \n", - "9 households_space_heater_district_heating_ht_st... \n", - "10 households_space_heater_electricity \n", - "11 households_space_heater_combined_network_gas \n", - "12 households_space_heater_combined_hydrogen \n", - "13 households_space_heater_wood_pellets \n", - "14 households_space_heater_network_gas \n", - "15 households_space_heater_coal \n", - "16 households_space_heater_crude_oil \n", - "\n", - " \\\n", - " heat_network_lt \n", - "sortables \n", - "0 energy_heat_network_storage_lt_steam_hot_water \n", - "1 energy_heat_boiler_lt_electricity \n", - "2 energy_heat_burner_lt_hydrogen \n", - "3 energy_heat_heatpump_water_water_lt_electricity \n", - "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", - "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", - "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " heat_network_mt \n", - "sortables \n", - "0 energy_heat_network_storage_mt_steam_hot_water \n", - "1 energy_heat_boiler_mt_electricity \n", - "2 energy_heat_burner_mt_coal \n", - "3 energy_heat_burner_mt_crude_oil \n", - "4 energy_heat_burner_mt_hydrogen \n", - "5 energy_heat_burner_mt_network_gas \n", - "6 energy_heat_burner_mt_waste_mix \n", - "7 energy_heat_burner_mt_wood_pellets \n", - "8 energy_heat_heatpump_water_water_mt_electricity \n", - "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", - "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", - "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \n", - " heat_network_ht \n", - "sortables \n", - "0 energy_heat_network_storage_ht_steam_hot_water \n", - "1 energy_heat_boiler_ht_electricity \n", - "2 energy_heat_burner_ht_coal \n", - "3 energy_heat_burner_ht_crude_oil \n", - "4 energy_heat_burner_ht_hydrogen \n", - "5 energy_heat_burner_ht_network_gas \n", - "6 energy_heat_burner_ht_waste_mix \n", - "7 energy_heat_burner_ht_wood_pellets \n", - "8 energy_heat_heatpump_water_water_ht_electricity \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None " - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "packer.sortables()" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "0d3e771e", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
B: Load a scenario by idA: Create from excel
interconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_priceinterconnector_3_import_availabilityinterconnector_3_export_availabilityinterconnector_4_price...weather/wind_offshore_baselineweather/wind_coastal_baselineweather/wind_inland_baselineinterconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_price
00.011.00.026.001.01.00.011.00.00.01...0.9639780.6627860.6627860.011.00.026.001.01.00.01
10.011.00.026.001.01.00.001.00.00.00...0.9662970.7377590.7377590.011.00.026.001.01.00.00
20.011.00.014.481.01.00.001.00.00.00...0.9664720.7670290.7670290.011.00.014.481.01.00.00
30.011.00.00.011.00.00.001.00.00.00...0.9671030.8142720.8142720.011.00.00.011.00.00.00
40.011.00.00.021.00.00.001.00.00.00...0.9670680.8331410.8331410.011.00.00.021.00.00.00
..................................................................
87550.011.00.00.011.00.00.001.00.00.00...0.9673790.9334170.9334170.011.00.00.011.00.00.00
87560.011.00.00.011.00.00.001.00.00.00...0.9673790.9369490.9369490.011.00.00.011.00.00.00
87570.011.00.00.011.00.00.001.00.00.00...0.9673790.9367560.9367560.011.00.00.011.00.00.00
87580.011.00.00.021.00.00.001.00.00.00...0.9673790.9454570.9454570.011.00.00.021.00.00.00
87590.011.00.00.001.00.00.001.00.00.00...0.9673480.9485780.9485780.011.00.00.001.00.00.00
\n", - "

8760 rows × 52 columns

\n", - "
" - ], - "text/plain": [ - " B: Load a scenario by id \\\n", - " interconnector_1_price interconnector_1_import_availability \n", - "0 0.01 1.0 \n", - "1 0.01 1.0 \n", - "2 0.01 1.0 \n", - "3 0.01 1.0 \n", - "4 0.01 1.0 \n", - "... ... ... \n", - "8755 0.01 1.0 \n", - "8756 0.01 1.0 \n", - "8757 0.01 1.0 \n", - "8758 0.01 1.0 \n", - "8759 0.01 1.0 \n", - "\n", - " \\\n", - " interconnector_1_export_availability interconnector_2_price \n", - "0 0.0 26.00 \n", - "1 0.0 26.00 \n", - "2 0.0 14.48 \n", - "3 0.0 0.01 \n", - "4 0.0 0.02 \n", - "... ... ... \n", - "8755 0.0 0.01 \n", - "8756 0.0 0.01 \n", - "8757 0.0 0.01 \n", - "8758 0.0 0.02 \n", - "8759 0.0 0.00 \n", - "\n", - " \\\n", - " interconnector_2_import_availability \n", - "0 1.0 \n", - "1 1.0 \n", - "2 1.0 \n", - "3 1.0 \n", - "4 1.0 \n", - "... ... \n", - "8755 1.0 \n", - "8756 1.0 \n", - "8757 1.0 \n", - "8758 1.0 \n", - "8759 1.0 \n", - "\n", - " \\\n", - " interconnector_2_export_availability interconnector_3_price \n", - "0 1.0 0.01 \n", - "1 1.0 0.00 \n", - "2 1.0 0.00 \n", - "3 0.0 0.00 \n", - "4 0.0 0.00 \n", - "... ... ... \n", - "8755 0.0 0.00 \n", - "8756 0.0 0.00 \n", - "8757 0.0 0.00 \n", - "8758 0.0 0.00 \n", - "8759 0.0 0.00 \n", - "\n", - " \\\n", - " interconnector_3_import_availability \n", - "0 1.0 \n", - "1 1.0 \n", - "2 1.0 \n", - "3 1.0 \n", - "4 1.0 \n", - "... ... \n", - "8755 1.0 \n", - "8756 1.0 \n", - "8757 1.0 \n", - "8758 1.0 \n", - "8759 1.0 \n", - "\n", - " ... \\\n", - " interconnector_3_export_availability interconnector_4_price ... \n", - "0 0.0 0.01 ... \n", - "1 0.0 0.00 ... \n", - "2 0.0 0.00 ... \n", - "3 0.0 0.00 ... \n", - "4 0.0 0.00 ... \n", - "... ... ... ... \n", - "8755 0.0 0.00 ... \n", - "8756 0.0 0.00 ... \n", - "8757 0.0 0.00 ... \n", - "8758 0.0 0.00 ... \n", - "8759 0.0 0.00 ... \n", - "\n", - " \\\n", - " weather/wind_offshore_baseline weather/wind_coastal_baseline \n", - "0 0.963978 0.662786 \n", - "1 0.966297 0.737759 \n", - "2 0.966472 0.767029 \n", - "3 0.967103 0.814272 \n", - "4 0.967068 0.833141 \n", - "... ... ... \n", - "8755 0.967379 0.933417 \n", - "8756 0.967379 0.936949 \n", - "8757 0.967379 0.936756 \n", - "8758 0.967379 0.945457 \n", - "8759 0.967348 0.948578 \n", - "\n", - " A: Create from excel \\\n", - " weather/wind_inland_baseline interconnector_1_price \n", - "0 0.662786 0.01 \n", - "1 0.737759 0.01 \n", - "2 0.767029 0.01 \n", - "3 0.814272 0.01 \n", - "4 0.833141 0.01 \n", - "... ... ... \n", - "8755 0.933417 0.01 \n", - "8756 0.936949 0.01 \n", - "8757 0.936756 0.01 \n", - "8758 0.945457 0.01 \n", - "8759 0.948578 0.01 \n", - "\n", - " \\\n", - " interconnector_1_import_availability \n", - "0 1.0 \n", - "1 1.0 \n", - "2 1.0 \n", - "3 1.0 \n", - "4 1.0 \n", - "... ... \n", - "8755 1.0 \n", - "8756 1.0 \n", - "8757 1.0 \n", - "8758 1.0 \n", - "8759 1.0 \n", - "\n", - " \\\n", - " interconnector_1_export_availability interconnector_2_price \n", - "0 0.0 26.00 \n", - "1 0.0 26.00 \n", - "2 0.0 14.48 \n", - "3 0.0 0.01 \n", - "4 0.0 0.02 \n", - "... ... ... \n", - "8755 0.0 0.01 \n", - "8756 0.0 0.01 \n", - "8757 0.0 0.01 \n", - "8758 0.0 0.02 \n", - "8759 0.0 0.00 \n", - "\n", - " \\\n", - " interconnector_2_import_availability \n", - "0 1.0 \n", - "1 1.0 \n", - "2 1.0 \n", - "3 1.0 \n", - "4 1.0 \n", - "... ... \n", - "8755 1.0 \n", - "8756 1.0 \n", - "8757 1.0 \n", - "8758 1.0 \n", - "8759 1.0 \n", - "\n", - " \n", - " interconnector_2_export_availability interconnector_3_price \n", - "0 1.0 0.01 \n", - "1 1.0 0.00 \n", - "2 1.0 0.00 \n", - "3 0.0 0.00 \n", - "4 0.0 0.00 \n", - "... ... ... \n", - "8755 0.0 0.00 \n", - "8756 0.0 0.00 \n", - "8757 0.0 0.00 \n", - "8758 0.0 0.00 \n", - "8759 0.0 0.00 \n", - "\n", - "[8760 rows x 52 columns]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "packer.custom_curves()" + "packer.custom_curves().head()" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "54cc3f61", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
A: Create from excelB: Load a scenario by id
futurefuture
gqueryunit
dashboard_emissionsfactor0.024027-0.953337
dashboard_co2_emissions_versus_start_yearfactor0.028299-1.003414
dashboard_total_costsbln_euro39.30029358.280256
\n", - "
" - ], - "text/plain": [ - " A: Create from excel \\\n", - " future \n", - "gquery unit \n", - "dashboard_emissions factor 0.024027 \n", - "dashboard_co2_emissions_versus_start_year factor 0.028299 \n", - "dashboard_total_costs bln_euro 39.300293 \n", - "\n", - " B: Load a scenario by id \n", - " future \n", - "gquery unit \n", - "dashboard_emissions factor -0.953337 \n", - "dashboard_co2_emissions_versus_start_year factor -1.003414 \n", - "dashboard_total_costs bln_euro 58.280256 " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "packer.gquery_results()" ] diff --git a/src/pyetm/models/custom_curves.py b/src/pyetm/models/custom_curves.py index 2cf6cd3..5713ba3 100644 --- a/src/pyetm/models/custom_curves.py +++ b/src/pyetm/models/custom_curves.py @@ -141,39 +141,36 @@ def _to_dataframe(self, **kwargs) -> pd.DataFrame: return df @classmethod - def _from_dataframe(cls, df: pd.DataFrame, **kwargs) -> "CustomCurve": + def _from_dataframe( + cls, df: pd.DataFrame, scenario_id: str | int | None = None, **kwargs + ) -> "CustomCurve": """ Create CustomCurve from DataFrame containing time series data. + scenario_id: optional id used to disambiguate filenames when multiple scenarios import curves from excel. """ if len(df.columns) != 1: raise ValueError( f"DataFrame must contain exactly 1 column, got {len(df.columns)}" ) - # Get the curve key from column name curve_key = df.columns[0] - curve_data_dict = { "key": curve_key, - "type": "custom", # Default type for curves created from DataFrame + "type": "custom", } - curve = cls.model_validate(curve_data_dict) - # Only save data if DataFrame has actual data rows if not df.empty: curve_data = df.iloc[:, 0].dropna() - if not curve_data.empty: - # Save the data to a temporary file and set file_path + # Include scenario id in filename if provided to avoid collisions between scenarios. + safe_key = str(curve_key).replace("/", "-") + prefix = f"{scenario_id}_" if scenario_id is not None else "" file_path = ( get_settings().path_to_tmp("dataframe_import") - / f"{curve_key.replace('/', '-')}.csv" + / f"{prefix}{safe_key}.csv" ) - - # Ensure directory exists file_path.parent.mkdir(parents=True, exist_ok=True) - try: curve_data.to_csv(file_path, index=False, header=False) curve.file_path = file_path @@ -181,7 +178,6 @@ def _from_dataframe(cls, df: pd.DataFrame, **kwargs) -> "CustomCurve": curve.add_warning( curve_key, f"Failed to save curve data to file: {e}" ) - return curve @@ -284,23 +280,23 @@ def _to_dataframe(self, **kwargs) -> pd.DataFrame: return pd.DataFrame(index=pd.Index([], name="hour")) @classmethod - def _from_dataframe(cls, df: pd.DataFrame, **kwargs) -> "CustomCurves": + def _from_dataframe( + cls, df: pd.DataFrame, scenario_id: str | int | None = None, **kwargs + ) -> "CustomCurves": """ Create CustomCurves collection from DataFrame with time series data. + scenario_id: optional id forwarded to individual curve creation to disambiguate filenames. """ curves = [] - if len(df.columns) == 0: return cls.model_validate({"curves": curves}) - for column_name in df.columns: try: - # Extract single column as DataFrame for individual curve curve_df = df[[column_name]] - - curve = CustomCurve._from_dataframe(curve_df, **kwargs) + curve = CustomCurve._from_dataframe( + curve_df, scenario_id=scenario_id, **kwargs + ) curves.append(curve) - except Exception as e: basic_curve = CustomCurve.model_construct( key=column_name, type="custom" @@ -309,12 +305,8 @@ def _from_dataframe(cls, df: pd.DataFrame, **kwargs) -> "CustomCurves": "base", f"Failed to create curve from column {column_name}: {e}" ) curves.append(basic_curve) - collection = cls.model_validate({"curves": curves}) - - # Merge warnings from individual curves collection._merge_submodel_warnings(*curves, key_attr="key") - return collection def validate_for_upload(self) -> dict[str, WarningCollector]: @@ -336,12 +328,14 @@ def validate_for_upload(self) -> dict[str, WarningCollector]: # First, try to read the file without forcing dtype to check for non-numeric values try: # Read without dtype conversion to preserve non-numeric values - raw_data = pd.read_csv(curve.file_path, header=None, index_col=False) + raw_data = pd.read_csv( + curve.file_path, header=None, index_col=False + ) if raw_data.empty: curve_warnings.add(curve.key, "Curve contains no data") validation_errors[curve.key] = curve_warnings continue - + # Check length first if len(raw_data) != 8760: curve_warnings.add( @@ -352,25 +346,21 @@ def validate_for_upload(self) -> dict[str, WarningCollector]: # Now check if all values can be converted to float try: # Try to convert to numeric, this will raise if there are non-numeric values - pd.to_numeric(raw_data.iloc[:, 0], errors='raise') + pd.to_numeric(raw_data.iloc[:, 0], errors="raise") except (ValueError, TypeError): curve_warnings.add( curve.key, "Curve contains non-numeric values" ) - + except pd.errors.EmptyDataError: curve_warnings.add(curve.key, "Curve contains no data") except Exception as e: # This catches file not found, permission errors, etc. - curve_warnings.add( - curve.key, f"Error reading curve data: {str(e)}" - ) + curve_warnings.add(curve.key, f"Error reading curve data: {str(e)}") except Exception as e: # Catch any other unexpected errors - curve_warnings.add( - curve.key, f"Error reading curve data: {str(e)}" - ) + curve_warnings.add(curve.key, f"Error reading curve data: {str(e)}") # Only add to validation_errors if there are actual warnings if len(curve_warnings) > 0: diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 1a8f826..3ff3b57 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -2,10 +2,9 @@ import logging from os import PathLike from pydantic import BaseModel, Field -from typing import Optional, Dict, List, Any, Set, Literal, ClassVar +from typing import Optional, Dict, Any, Set, ClassVar from xlsxwriter import Workbook -from pyetm.models.base import Base from pyetm.models import Scenario from pyetm.models.custom_curves import CustomCurves from pyetm.utils.excel import add_frame_with_scenario_styling @@ -62,7 +61,9 @@ class InputsPack(Packable): def __init__(self, **data): super().__init__(**data) - self._scenario_short_names: Dict[str, str] = {} # scenario_id -> short_name mapping + self._scenario_short_names: Dict[str, str] = ( + {} + ) # scenario_id -> short_name mapping def set_scenario_short_names(self, scenario_short_names: Dict[str, str]): """Set the mapping of scenario identifiers to their short names.""" @@ -73,10 +74,37 @@ def _find_by_short_name(self, short_name: str): short_name_str = str(short_name) for scenario in self.scenarios: scenario_id = str(scenario.identifier()) - if self._scenario_short_names.get(scenario_id) == short_name_str: + if self._scenario_short_names.get(str(scenario.id)) == short_name_str: return scenario return None + def _find_by_any(self, label: str): + """Attempt to resolve a label to a scenario by (in order): + 1. short_name mapping + 2. scenario.identifier() (title or id) + 3. numeric id match + """ + if label is None: + return None + label_str = str(label).strip() + # 1. short name + s = self._find_by_short_name(label_str) + if s is not None: + return s + # 2. identifier (title or id) + for scenario in self.scenarios: + if str(scenario.identifier()) == label_str: + return scenario + # 3. numeric id + try: + num = int(float(label_str)) + for scenario in self.scenarios: + if scenario.id == num: + return scenario + except Exception: + pass + return None + def _to_dataframe(self, columns="user", **kwargs): return pd.concat( [ @@ -84,20 +112,23 @@ def _to_dataframe(self, columns="user", **kwargs): for scenario in self.scenarios ], axis=1, - keys=[self._scenario_short_names.get(str(scenario.identifier()), str(scenario.identifier())) - for scenario in self.scenarios], + keys=[ + self._scenario_short_names.get( + str(scenario.identifier()), str(scenario.identifier()) + ) + for scenario in self.scenarios + ], ) def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: """Normalize various inputs sheet shapes into canonical shape: - Drop leading completely blank rows. - - Detect two header rows (short_name row above a row containing 'user'). + - Accept either: + (a) Two header rows (short_name row above a row containing 'user'), or + (b) Single header row of scenario labels (no explicit 'user' row) -> we fabricate 'user'. - Support 1- or 2-level row index (input[, unit]). - Returns a DataFrame with: - index -> Index or MultiIndex (input[, unit]) - columns -> MultiIndex (short_name, 'user') + Returns DataFrame with columns MultiIndex(label, 'user'). """ - # Drop completely empty rows df = df.dropna(how="all") if df.empty: return df @@ -108,38 +139,76 @@ def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: if any(isinstance(v, str) and v.strip().lower() == "user" for v in row): user_row_pos = pos break - if user_row_pos is None: - # Fallback: assume row 1 is the 'user' row - user_row_pos = 1 if len(df) > 1 else 0 - header_start = max(user_row_pos - 1, 0) - header_end = user_row_pos # inclusive + single_header = user_row_pos is None + if single_header: + header_start = 0 + header_end = 0 + else: + header_start = max(user_row_pos - 1, 0) + header_end = user_row_pos headers = df.iloc[header_start : header_end + 1].astype(str) data = df.iloc[header_end + 1 :].copy() - # Build MultiIndex columns from the two header rows + if single_header: + # Build columns from single header row; fabricate second level 'user' + col_level0 = headers.iloc[0].values + # First one (index col) often blank -> keep for alignment + data.columns = col_level0 + # Identify index columns: left-most non-scenario columns (we take first (and optional second) column as index parts) + index_candidates = list(data.columns[:2]) # heuristic + # If second column values are all numeric -> treat as scenario column, so only first column is index + second_is_numeric = False + if len(index_candidates) > 1: + sample = data[index_candidates[1]].dropna().head(5) + if not sample.empty and all( + pd.to_numeric(sample, errors="coerce").notna() + ): + second_is_numeric = True + if second_is_numeric: + idx_cols = [index_candidates[0]] + else: + idx_cols = index_candidates + input_col = idx_cols[0] + unit_col = idx_cols[1] if len(idx_cols) > 1 else None + scenario_cols = [ + c for c in data.columns if c not in idx_cols and str(c).strip() != "" + ] + # Build index + input_series = data[input_col].astype(str) + if unit_col is not None: + unit_series = data[unit_col].astype(str) + index = pd.MultiIndex.from_arrays( + [input_series.values, unit_series.values], names=["input", "unit"] + ) + else: + index = pd.Index(input_series.values, name="input") + canonical = data[scenario_cols].copy() + canonical.index = index + # Fabricate second level + canonical.columns = pd.MultiIndex.from_arrays( + [canonical.columns, ["user"] * len(canonical.columns)] + ) + return canonical + + # Two-row header path (original logic) data.columns = pd.MultiIndex.from_arrays( [headers.iloc[0].values, headers.iloc[1].values] ) - # Identify index columns as those whose second-level header is not 'user' idx_cols = [ col for col in data.columns if not (isinstance(col[1], str) and col[1].strip().lower() == "user") ] - - # Choose input and optional unit columns if len(idx_cols) == 0: - # No explicit index columns: assume first column is inputs input_col = data.columns[0] unit_col = None else: input_col = idx_cols[0] unit_col = idx_cols[1] if len(idx_cols) > 1 else None - # Construct index input_series = data[input_col].astype(str) if unit_col is not None: unit_series = data[unit_col].astype(str) @@ -149,7 +218,6 @@ def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: else: index = pd.Index(input_series.values, name="input") - # Drop index columns and keep only scenario columns keep_cols = [ c for c in data.columns @@ -158,7 +226,7 @@ def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: canonical = data[keep_cols] canonical.index = index - # Ensure second level equals 'user'; if not, set it + # Ensure second level equals 'user' if isinstance(canonical.columns, pd.MultiIndex): lvl1 = canonical.columns.get_level_values(1) if not all( @@ -172,16 +240,18 @@ def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: ) else: canonical.columns = pd.MultiIndex.from_arrays( - [canonical.columns, ["user"] * len(canonical.columns)] + [ + canonical.columns, + ["user"] * len(canonical.columns), + ] ) - return canonical def from_dataframe(self, df): """ Sets the inputs on the scenarios from the packed df (comes from excel) Tolerates optional unit column and leading blank rows. - Uses short_name for scenario identification. + Uses short_name for scenario identification; falls back to identifier/title or id. """ if df is None or getattr(df, "empty", False): return @@ -195,18 +265,19 @@ def from_dataframe(self, df): if df is None or df.empty: return - # Now df has columns MultiIndex (short_name, 'user') and index input or (input, unit) - short_names = df.columns.get_level_values(0).unique() + # Now df has columns MultiIndex (label, 'user') where label may be short_name, title, or id + labels = df.columns.get_level_values(0).unique() - for short_name in short_names: - scenario = self._find_by_short_name(short_name) + for label in labels: + scenario = self._find_by_any(label) if scenario is None: logger.warning( - "Could not find scenario for short_name '%s'", short_name + "Could not find scenario for parameters column label '%s' (not a short_name/title/id)", + label, ) continue - scenario_df = df[short_name] + scenario_df = df[label] # Ensure DataFrame with a 'user' column if isinstance(scenario_df, pd.Series): scenario_df = scenario_df.to_frame(name="user") @@ -216,7 +287,15 @@ def from_dataframe(self, df): first_col = scenario_df.columns[0] scenario_df = scenario_df.rename(columns={first_col: "user"}) - scenario.set_user_values_from_dataframe(scenario_df) + try: + scenario.set_user_values_from_dataframe(scenario_df) + except Exception as e: + logger.warning( + "Failed setting inputs for scenario '%s' from column label '%s': %s", + scenario.identifier(), + label, + e, + ) class QueryPack(Packable): @@ -441,13 +520,18 @@ def _is_helper_label(v): keep_cols = [ c for c in data.columns - if not _is_empty(c[0]) and not _is_helper_label(c[1]) + if not _is_empty(c[0]) and not _is_helper_label(c[0]) ] - canonical = data[keep_cols].copy() + data = data[keep_cols] + # Collapse to single level (identifier) + data.columns = [c[0] for c in data.columns] - # Result: MultiIndex columns (identifier, sortable_name), index as row number - canonical.reset_index(drop=True, inplace=True) - return canonical + # Ensure string values and drop rows that are completely blank across all kept columns + for c in data.columns: + data[c] = data[c].apply(lambda x: None if pd.isna(x) else (str(x).strip())) + data = data.dropna(how="all") + + return data def from_dataframe(self, df: pd.DataFrame): """Unpack and update sortables for each scenario from the sheet. @@ -591,7 +675,7 @@ def from_dataframe(self, df: pd.DataFrame): block = df[identifier] # Build a CustomCurves collection from the block columns try: - curves = CustomCurves._from_dataframe(block) + curves = CustomCurves._from_dataframe(block, scenario_id=scenario.id) except Exception as e: logger.warning( "Failed to build custom curves for '%s': %s", identifier, e @@ -767,7 +851,9 @@ def get_summary(self) -> Dict[str, Any]: # Create stuff - def _extract_scenario_sheet_info(self, main_df: pd.DataFrame) -> Dict[str, Dict[str, str]]: + def _extract_scenario_sheet_info( + self, main_df: pd.DataFrame + ) -> Dict[str, Dict[str, str]]: """Extract sortables and custom_curves sheet names for each scenario from MAIN sheet. Also extracts short_name mapping for parameter sheet identification. Returns dict with scenario identifier as key and info dict containing: @@ -776,36 +862,44 @@ def _extract_scenario_sheet_info(self, main_df: pd.DataFrame) -> Dict[str, Dict[ - 'custom_curves': custom curves sheet name """ scenario_sheets = {} - + if isinstance(main_df, pd.Series): # Single scenario identifier = str(main_df.name) - short_name = main_df.get('short_name') - sortables_sheet = main_df.get('sortables') - custom_curves_sheet = main_df.get('custom_curves') - + short_name = main_df.get("short_name") + sortables_sheet = main_df.get("sortables") + custom_curves_sheet = main_df.get("custom_curves") + scenario_sheets[identifier] = { - 'short_name': short_name if pd.notna(short_name) else identifier, - 'sortables': sortables_sheet if pd.notna(sortables_sheet) else None, - 'custom_curves': custom_curves_sheet if pd.notna(custom_curves_sheet) else None + "short_name": short_name if pd.notna(short_name) else identifier, + "sortables": sortables_sheet if pd.notna(sortables_sheet) else None, + "custom_curves": ( + custom_curves_sheet if pd.notna(custom_curves_sheet) else None + ), } else: # Multiple scenarios for identifier in main_df.columns: col_data = main_df[identifier] - short_name = col_data.get('short_name') - sortables_sheet = col_data.get('sortables') - custom_curves_sheet = col_data.get('custom_curves') - + short_name = col_data.get("short_name") + sortables_sheet = col_data.get("sortables") + custom_curves_sheet = col_data.get("custom_curves") + scenario_sheets[str(identifier)] = { - 'short_name': short_name if pd.notna(short_name) else str(identifier), - 'sortables': sortables_sheet if pd.notna(sortables_sheet) else None, - 'custom_curves': custom_curves_sheet if pd.notna(custom_curves_sheet) else None + "short_name": ( + short_name if pd.notna(short_name) else str(identifier) + ), + "sortables": sortables_sheet if pd.notna(sortables_sheet) else None, + "custom_curves": ( + custom_curves_sheet if pd.notna(custom_curves_sheet) else None + ), } - + return scenario_sheets - def _process_single_scenario_sortables(self, scenario: "Scenario", df: pd.DataFrame): + def _process_single_scenario_sortables( + self, scenario: "Scenario", df: pd.DataFrame + ): """Process sortables for a single scenario from its dedicated sheet. Simplified parsing since there's only one scenario per sheet. Tolerates a leading index column (e.g. 'hour' or blank), and maps @@ -817,7 +911,9 @@ def _process_single_scenario_sortables(self, scenario: "Scenario", df: pd.DataFr return # Find the first non-empty row -> header with sortable names - non_empty_idx = [i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all()] + non_empty_idx = [ + i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() + ] if not non_empty_idx: return @@ -860,7 +956,9 @@ def _process_single_scenario_curves(self, scenario: "Scenario", df: pd.DataFrame return # Find the first non-empty row -> header with curve keys - non_empty_idx = [i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all()] + non_empty_idx = [ + i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() + ] if not non_empty_idx: return @@ -890,10 +988,12 @@ def _is_empty_or_helper(col_name: Any) -> bool: # Build CustomCurves collection and apply try: - curves = CustomCurves._from_dataframe(data) + curves = CustomCurves._from_dataframe(data, scenario_id=scenario.id) scenario.update_custom_curves(curves) except Exception as e: - logger.warning("Failed processing custom curves for '%s': %s", scenario.identifier(), e) + logger.warning( + "Failed processing custom curves for '%s': %s", scenario.identifier(), e + ) @classmethod def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": @@ -929,7 +1029,9 @@ def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": scenarios_by_col: Dict[str, Scenario] = {} for col in main_df.columns: try: - scenario = packer._setup_scenario_from_main_column(str(col), main_df[col]) + scenario = packer._setup_scenario_from_main_column( + str(col), main_df[col] + ) except Exception as e: logger.warning("Failed to set up scenario for column '%s': %s", col, e) continue @@ -977,7 +1079,89 @@ def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": gq_df = None if gq_df is not None and not gq_df.empty: try: - QueryPack(scenarios=packer._scenarios()).from_dataframe(gq_df) + qp = QueryPack(scenarios=packer._scenarios()) + norm_gq = qp._normalize_queries_dataframe(gq_df) + if norm_gq is not None and not norm_gq.empty: + # Case 1: single column (global queries for all scenarios) + if len(norm_gq.columns) == 1: + col = norm_gq.columns[0] + values = [ + v + for v in norm_gq[col].tolist() + if isinstance(v, str) and v.strip() + ] + seen = set() + keys = [] + for v in values: + if v not in seen: + seen.add(v) + keys.append(v) + if keys: + for s in packer._scenarios(): + try: + s.add_queries(keys) + except Exception as e: + logger.warning( + "Failed adding global gqueries to '%s': %s", + s.identifier(), + e, + ) + else: + # Multiple columns: attempt identifier match, fallback to short_name + for col in norm_gq.columns: + scenario = next( + ( + s + for s in packer._scenarios() + if str(s.identifier()) == str(col) + ), + None, + ) + if scenario is None: + # fallback: short_name mapping + match_id = next( + ( + sid + for sid, sn in short_name_map.items() + if str(sn) == str(col) + ), + None, + ) + if match_id is not None: + scenario = next( + ( + s + for s in packer._scenarios() + if str(s.id) == str(match_id) + ), + None, + ) + if scenario is None: + logger.warning( + "Could not find scenario for gqueries column '%s' (identifier or short_name)", + col, + ) + continue + values = [ + v + for v in norm_gq[col].tolist() + if isinstance(v, str) and v.strip() + ] + seen = set() + keys = [] + for v in values: + if v not in seen: + seen.add(v) + keys.append(v) + if keys: + try: + scenario.add_queries(keys) + except Exception as e: + logger.warning( + "Failed adding gqueries to '%s': %s", + scenario.identifier(), + e, + ) except Exception as e: logger.warning("Failed to import GQUERIES: %s", e) @@ -1015,10 +1199,13 @@ def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": return packer - def _setup_scenario_from_main_column(self, col_name: str, col_data: pd.Series) -> Optional[Scenario]: + def _setup_scenario_from_main_column( + self, col_name: str, col_data: pd.Series + ) -> Optional[Scenario]: """Create or load a Scenario from a MAIN sheet column and apply metadata. Preference: if 'scenario_id' present -> load; otherwise create with area_code/end_year. """ + # Helper conversions def _to_bool(v: Any) -> Optional[bool]: if v is None or (isinstance(v, float) and pd.isna(v)): @@ -1043,11 +1230,27 @@ def _to_int(v: Any) -> Optional[int]: except Exception: return None - scenario_id = col_data.get("scenario_id") if isinstance(col_data, pd.Series) else None - area_code = col_data.get("area_code") if isinstance(col_data, pd.Series) else None - end_year = _to_int(col_data.get("end_year")) if isinstance(col_data, pd.Series) else None - private = _to_bool(col_data.get("private")) if isinstance(col_data, pd.Series) else None - template = _to_int(col_data.get("template")) if isinstance(col_data, pd.Series) else None + scenario_id = ( + col_data.get("scenario_id") if isinstance(col_data, pd.Series) else None + ) + area_code = ( + col_data.get("area_code") if isinstance(col_data, pd.Series) else None + ) + end_year = ( + _to_int(col_data.get("end_year")) + if isinstance(col_data, pd.Series) + else None + ) + private = ( + _to_bool(col_data.get("private")) + if isinstance(col_data, pd.Series) + else None + ) + template = ( + _to_int(col_data.get("template")) + if isinstance(col_data, pd.Series) + else None + ) title = col_data.get("title") if isinstance(col_data, pd.Series) else None scenario: Optional[Scenario] = None @@ -1058,7 +1261,9 @@ def _to_int(v: Any) -> Optional[int]: try: scenario = Scenario.load(sid) except Exception as e: - logger.warning("Failed to load scenario %s for column '%s': %s", sid, col_name, e) + logger.warning( + "Failed to load scenario %s for column '%s': %s", sid, col_name, e + ) scenario = None else: if area_code and end_year is not None: @@ -1096,6 +1301,8 @@ def _to_int(v: Any) -> Optional[int]: try: scenario.update_metadata(**meta_updates) except Exception as e: - logger.warning("Failed to update metadata for '%s': %s", scenario.identifier(), e) + logger.warning( + "Failed to update metadata for '%s': %s", scenario.identifier(), e + ) return scenario From fd0a69166c980f85f6394c0e835ef1900115bfd3 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Mon, 11 Aug 2025 10:10:29 +0200 Subject: [PATCH 10/17] Split packer into individual packs --- examples/excel_to_scenarios.ipynb | 1194 ++++++++++++++++- .../models/packables/custom_curves_pack.py | 67 + src/pyetm/models/packables/inputs_pack.py | 231 ++++ .../models/packables/output_curves_pack.py | 28 + src/pyetm/models/packables/packable.py | 261 ++++ src/pyetm/models/packables/query_pack.py | 137 ++ src/pyetm/models/packables/sortable_pack.py | 65 + src/pyetm/models/scenario_packer.py | 717 +--------- 8 files changed, 1982 insertions(+), 718 deletions(-) create mode 100644 src/pyetm/models/packables/custom_curves_pack.py create mode 100644 src/pyetm/models/packables/inputs_pack.py create mode 100644 src/pyetm/models/packables/output_curves_pack.py create mode 100644 src/pyetm/models/packables/packable.py create mode 100644 src/pyetm/models/packables/query_pack.py create mode 100644 src/pyetm/models/packables/sortable_pack.py diff --git a/examples/excel_to_scenarios.ipynb b/examples/excel_to_scenarios.ipynb index 62d7c43..f4c51f7 100644 --- a/examples/excel_to_scenarios.ipynb +++ b/examples/excel_to_scenarios.ipynb @@ -12,10 +12,188 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "4866f9d1", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Environment setup complete\n", + " Using ETM API at http://localhost:3000/api/v3\n", + " Token loaded? True\n", + "API connection ready\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:206: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " self.update_user_values(series.fillna(\"reset\").to_dict())\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'total_scenarios': 2, 'inputs': {'scenario_count': 2}, 'sortables': {'scenario_count': 2}, 'custom_curves': {'scenario_count': 2}, 'output_curves': {'scenario_count': 2}, 'scenario_ids': [2690555, 2690623]}\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
B: Load a scenario by idA: Create from excel
useruser
inputunit
climate_relevant_co2_biomass_gas_future%35.030.0
climate_relevant_co2_biomass_gas_present%None20.0
climate_relevant_co2_biomass_liquid_future%None30.0
climate_relevant_co2_biomass_liquid_present%None20.0
climate_relevant_co2_biomass_solid_future%None30.0
............
capacity_of_energy_battery_wind_turbine_inlandMW0.0NaN
capacity_of_energy_power_hybrid_wind_turbine_offshoreMWNoneNaN
capacity_of_energy_power_wind_turbine_coastalMW0.0NaN
capacity_of_energy_power_wind_turbine_inlandMW20000.0NaN
capacity_of_energy_power_wind_turbine_offshoreMW52000.0NaN
\n", + "

1318 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " B: Load a scenario by id \\\n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 35.0 \n", + "climate_relevant_co2_biomass_gas_present % None \n", + "climate_relevant_co2_biomass_liquid_future % None \n", + "climate_relevant_co2_biomass_liquid_present % None \n", + "climate_relevant_co2_biomass_solid_future % None \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", + "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", + "capacity_of_energy_power_wind_turbine_inland MW 20000.0 \n", + "capacity_of_energy_power_wind_turbine_offshore MW 52000.0 \n", + "\n", + " A: Create from excel \n", + " user \n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 30.0 \n", + "climate_relevant_co2_biomass_gas_present % 20.0 \n", + "climate_relevant_co2_biomass_liquid_future % 30.0 \n", + "climate_relevant_co2_biomass_liquid_present % 20.0 \n", + "climate_relevant_co2_biomass_solid_future % 30.0 \n", + "... ... \n", + "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", + "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", + "capacity_of_energy_power_wind_turbine_inland MW NaN \n", + "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", + "\n", + "[1318 rows x 2 columns]" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from example_helpers import setup_notebook\n", "from pyetm.models.scenario_packer import ScenarioPacker\n", @@ -30,30 +208,1030 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "cd08ff26", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
B: Load a scenario by idA: Create from excel
forecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_htforecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_ht
sortables
0energy_flexibility_pumped_storage_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_waterhouseholds_flexibility_p2p_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_water
1transport_van_flexibility_p2p_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricityenergy_flexibility_mv_batteries_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricity
2transport_truck_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coaltransport_car_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coal
3transport_bus_flexibility_p2p_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oilenergy_flexibility_flow_batteries_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oil
4energy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogenenergy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogen
5energy_flexibility_flow_batteries_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gastransport_bus_flexibility_p2p_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gas
6transport_car_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mixtransport_truck_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mix
7energy_flexibility_mv_batteries_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pelletstransport_van_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pellets
8households_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricityenergy_flexibility_pumped_storage_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricity
9NoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...NoneNoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...None
10NoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...None
11NoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...None
12NoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNoneNoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNone
13NoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNoneNoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNone
14NoneNoneNonehouseholds_space_heater_network_gasNoneNoneNoneNoneNoneNonehouseholds_space_heater_network_gasNoneNoneNone
15NoneNoneNonehouseholds_space_heater_coalNoneNoneNoneNoneNoneNonehouseholds_space_heater_coalNoneNoneNone
16NoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNoneNoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNone
\n", + "
" + ], + "text/plain": [ + " B: Load a scenario by id \\\n", + " forecast_storage \n", + "sortables \n", + "0 energy_flexibility_pumped_storage_electricity \n", + "1 transport_van_flexibility_p2p_electricity \n", + "2 transport_truck_flexibility_p2p_electricity \n", + "3 transport_bus_flexibility_p2p_electricity \n", + "4 energy_flexibility_hv_opac_electricity \n", + "5 energy_flexibility_flow_batteries_electricity \n", + "6 transport_car_flexibility_p2p_electricity \n", + "7 energy_flexibility_mv_batteries_electricity \n", + "8 households_flexibility_p2p_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_supply \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 energy_hydrogen_autothermal_reformer_dispatchable \n", + "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", + "4 energy_hydrogen_ammonia_reformer_dispatchable \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_demand \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 None \n", + "3 None \n", + "4 None \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " space_heating \n", + "sortables \n", + "0 households_space_heater_district_heating_lt_st... \n", + "1 households_space_heater_heatpump_surface_water... \n", + "2 households_space_heater_heatpump_air_water_ele... \n", + "3 households_space_heater_heatpump_ground_water_... \n", + "4 households_space_heater_heatpump_pvt_electricity \n", + "5 households_space_heater_district_heating_mt_st... \n", + "6 households_space_heater_hybrid_heatpump_air_wa... \n", + "7 households_space_heater_hybrid_hydrogen_heatpu... \n", + "8 households_space_heater_hybrid_crude_oil_heatp... \n", + "9 households_space_heater_district_heating_ht_st... \n", + "10 households_space_heater_electricity \n", + "11 households_space_heater_combined_network_gas \n", + "12 households_space_heater_combined_hydrogen \n", + "13 households_space_heater_wood_pellets \n", + "14 households_space_heater_network_gas \n", + "15 households_space_heater_coal \n", + "16 households_space_heater_crude_oil \n", + "\n", + " \\\n", + " heat_network_lt \n", + "sortables \n", + "0 energy_heat_network_storage_lt_steam_hot_water \n", + "1 energy_heat_boiler_lt_electricity \n", + "2 energy_heat_burner_lt_hydrogen \n", + "3 energy_heat_heatpump_water_water_lt_electricity \n", + "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", + "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", + "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_mt \n", + "sortables \n", + "0 energy_heat_network_storage_mt_steam_hot_water \n", + "1 energy_heat_boiler_mt_electricity \n", + "2 energy_heat_burner_mt_coal \n", + "3 energy_heat_burner_mt_crude_oil \n", + "4 energy_heat_burner_mt_hydrogen \n", + "5 energy_heat_burner_mt_network_gas \n", + "6 energy_heat_burner_mt_waste_mix \n", + "7 energy_heat_burner_mt_wood_pellets \n", + "8 energy_heat_heatpump_water_water_mt_electricity \n", + "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", + "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", + "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_ht \n", + "sortables \n", + "0 energy_heat_network_storage_ht_steam_hot_water \n", + "1 energy_heat_boiler_ht_electricity \n", + "2 energy_heat_burner_ht_coal \n", + "3 energy_heat_burner_ht_crude_oil \n", + "4 energy_heat_burner_ht_hydrogen \n", + "5 energy_heat_burner_ht_network_gas \n", + "6 energy_heat_burner_ht_waste_mix \n", + "7 energy_heat_burner_ht_wood_pellets \n", + "8 energy_heat_heatpump_water_water_ht_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " A: Create from excel \\\n", + " forecast_storage \n", + "sortables \n", + "0 households_flexibility_p2p_electricity \n", + "1 energy_flexibility_mv_batteries_electricity \n", + "2 transport_car_flexibility_p2p_electricity \n", + "3 energy_flexibility_flow_batteries_electricity \n", + "4 energy_flexibility_hv_opac_electricity \n", + "5 transport_bus_flexibility_p2p_electricity \n", + "6 transport_truck_flexibility_p2p_electricity \n", + "7 transport_van_flexibility_p2p_electricity \n", + "8 energy_flexibility_pumped_storage_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_supply \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 energy_hydrogen_autothermal_reformer_dispatchable \n", + "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", + "4 energy_hydrogen_ammonia_reformer_dispatchable \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_demand \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 None \n", + "3 None \n", + "4 None \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " space_heating \n", + "sortables \n", + "0 households_space_heater_district_heating_lt_st... \n", + "1 households_space_heater_heatpump_surface_water... \n", + "2 households_space_heater_heatpump_air_water_ele... \n", + "3 households_space_heater_heatpump_ground_water_... \n", + "4 households_space_heater_heatpump_pvt_electricity \n", + "5 households_space_heater_district_heating_mt_st... \n", + "6 households_space_heater_hybrid_heatpump_air_wa... \n", + "7 households_space_heater_hybrid_hydrogen_heatpu... \n", + "8 households_space_heater_hybrid_crude_oil_heatp... \n", + "9 households_space_heater_district_heating_ht_st... \n", + "10 households_space_heater_electricity \n", + "11 households_space_heater_combined_network_gas \n", + "12 households_space_heater_combined_hydrogen \n", + "13 households_space_heater_wood_pellets \n", + "14 households_space_heater_network_gas \n", + "15 households_space_heater_coal \n", + "16 households_space_heater_crude_oil \n", + "\n", + " \\\n", + " heat_network_lt \n", + "sortables \n", + "0 energy_heat_network_storage_lt_steam_hot_water \n", + "1 energy_heat_boiler_lt_electricity \n", + "2 energy_heat_burner_lt_hydrogen \n", + "3 energy_heat_heatpump_water_water_lt_electricity \n", + "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", + "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", + "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_mt \n", + "sortables \n", + "0 energy_heat_network_storage_mt_steam_hot_water \n", + "1 energy_heat_boiler_mt_electricity \n", + "2 energy_heat_burner_mt_coal \n", + "3 energy_heat_burner_mt_crude_oil \n", + "4 energy_heat_burner_mt_hydrogen \n", + "5 energy_heat_burner_mt_network_gas \n", + "6 energy_heat_burner_mt_waste_mix \n", + "7 energy_heat_burner_mt_wood_pellets \n", + "8 energy_heat_heatpump_water_water_mt_electricity \n", + "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", + "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", + "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \n", + " heat_network_ht \n", + "sortables \n", + "0 energy_heat_network_storage_ht_steam_hot_water \n", + "1 energy_heat_boiler_ht_electricity \n", + "2 energy_heat_burner_ht_coal \n", + "3 energy_heat_burner_ht_crude_oil \n", + "4 energy_heat_burner_ht_hydrogen \n", + "5 energy_heat_burner_ht_network_gas \n", + "6 energy_heat_burner_ht_waste_mix \n", + "7 energy_heat_burner_ht_wood_pellets \n", + "8 energy_heat_heatpump_water_water_ht_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None " + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "packer.sortables()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "0d3e771e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
B: Load a scenario by idA: Create from excel
interconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_priceinterconnector_3_import_availabilityinterconnector_3_export_availabilityinterconnector_4_price...weather/wind_offshore_baselineweather/wind_coastal_baselineweather/wind_inland_baselineinterconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_price
09.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.026.001.01.00.01
19.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.026.001.01.00.00
29.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.014.481.01.00.00
39.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.00.011.00.00.00
49.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.00.021.00.00.00
\n", + "

5 rows × 52 columns

\n", + "
" + ], + "text/plain": [ + " B: Load a scenario by id \\\n", + " interconnector_1_price interconnector_1_import_availability \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "\n", + " \\\n", + " interconnector_1_export_availability interconnector_2_price \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "\n", + " \\\n", + " interconnector_2_import_availability interconnector_2_export_availability \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "\n", + " \\\n", + " interconnector_3_price interconnector_3_import_availability \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "\n", + " ... \\\n", + " interconnector_3_export_availability interconnector_4_price ... \n", + "0 9.0 9.0 ... \n", + "1 9.0 9.0 ... \n", + "2 9.0 9.0 ... \n", + "3 9.0 9.0 ... \n", + "4 9.0 9.0 ... \n", + "\n", + " \\\n", + " weather/wind_offshore_baseline weather/wind_coastal_baseline \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "\n", + " A: Create from excel \\\n", + " weather/wind_inland_baseline interconnector_1_price \n", + "0 9.0 0.01 \n", + "1 9.0 0.01 \n", + "2 9.0 0.01 \n", + "3 9.0 0.01 \n", + "4 9.0 0.01 \n", + "\n", + " \\\n", + " interconnector_1_import_availability interconnector_1_export_availability \n", + "0 1.0 0.0 \n", + "1 1.0 0.0 \n", + "2 1.0 0.0 \n", + "3 1.0 0.0 \n", + "4 1.0 0.0 \n", + "\n", + " \\\n", + " interconnector_2_price interconnector_2_import_availability \n", + "0 26.00 1.0 \n", + "1 26.00 1.0 \n", + "2 14.48 1.0 \n", + "3 0.01 1.0 \n", + "4 0.02 1.0 \n", + "\n", + " \n", + " interconnector_2_export_availability interconnector_3_price \n", + "0 1.0 0.01 \n", + "1 1.0 0.00 \n", + "2 1.0 0.00 \n", + "3 0.0 0.00 \n", + "4 0.0 0.00 \n", + "\n", + "[5 rows x 52 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "packer.custom_curves().head()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "54cc3f61", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
B: Load a scenario by idA: Create from excel
futurefuture
gqueryunit
dashboard_co2_emissions_versus_start_yearfactor-0.9970370.028299
dashboard_total_costsbln_euro56.4630339.300293
\n", + "
" + ], + "text/plain": [ + " B: Load a scenario by id \\\n", + " future \n", + "gquery unit \n", + "dashboard_co2_emissions_versus_start_year factor -0.997037 \n", + "dashboard_total_costs bln_euro 56.46303 \n", + "\n", + " A: Create from excel \n", + " future \n", + "gquery unit \n", + "dashboard_co2_emissions_versus_start_year factor 0.028299 \n", + "dashboard_total_costs bln_euro 39.300293 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "packer.gquery_results()" ] diff --git a/src/pyetm/models/packables/custom_curves_pack.py b/src/pyetm/models/packables/custom_curves_pack.py new file mode 100644 index 0000000..432c3a5 --- /dev/null +++ b/src/pyetm/models/packables/custom_curves_pack.py @@ -0,0 +1,67 @@ +import logging +from typing import ClassVar, Any + +import pandas as pd + +from pyetm.models.custom_curves import CustomCurves +from pyetm.models.packables.packable import Packable + +logger = logging.getLogger(__name__) + + +class CustomCurvesPack(Packable): + key: ClassVar[str] = "custom_curves" + sheet_name: ClassVar[str] = "CUSTOM_CURVES" + + def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): # type: ignore[override] + try: + series_list = list(scenario.custom_curves_series()) + except Exception as e: # pragma: no cover - defensive + logger.warning( + "Failed extracting custom curves for %s: %s", scenario.identifier(), e + ) + return None + if not series_list: + return None + return pd.concat(series_list, axis=1) + + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: # type: ignore[override] + return self.build_pack_dataframe(columns=columns, **kwargs) + + def _normalize_curves_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: + data = self._normalize_two_header_sheet( + df, + helper_level1={"sortables"}, + drop_empty_level0=True, + collapse_level0=False, + reset_index=True, # values rows should be reindexed 0..n + ) + return data + + def from_dataframe(self, df: pd.DataFrame): # type: ignore[override] + if df is None or getattr(df, "empty", False): + return + try: + df = self._normalize_curves_dataframe(df) + except Exception as e: + logger.warning("Failed to normalize custom curves sheet: %s", e) + return + if df is None or df.empty or not isinstance(df.columns, pd.MultiIndex): + return + + def _apply(scenario, block: pd.DataFrame): + # block has columns MultiIndex(identifier, curve_key); collapse to curve_key + if isinstance(block.columns, pd.MultiIndex): + block.columns = [c[1] for c in block.columns] + try: + curves = CustomCurves._from_dataframe(block, scenario_id=scenario.id) + except Exception as e: # pragma: no cover + logger.warning( + "Failed to build custom curves for '%s': %s", + scenario.identifier(), + e, + ) + return + scenario.update_custom_curves(curves) + + self.apply_identifier_blocks(df, _apply) diff --git a/src/pyetm/models/packables/inputs_pack.py b/src/pyetm/models/packables/inputs_pack.py new file mode 100644 index 0000000..094b5d9 --- /dev/null +++ b/src/pyetm/models/packables/inputs_pack.py @@ -0,0 +1,231 @@ +import logging +from typing import ClassVar, Dict, Any + +import pandas as pd + +from pyetm.models.packables.packable import Packable + +logger = logging.getLogger(__name__) + + +class InputsPack(Packable): + key: ClassVar[str] = "inputs" + sheet_name: ClassVar[str] = "PARAMETERS" + + def __init__(self, **data): + super().__init__(**data) + self._scenario_short_names: Dict[str, str] = ( + {} + ) # scenario_id -> short_name mapping + + # --- Public configuration --------------------------------------------------- + def set_scenario_short_names(self, scenario_short_names: Dict[str, str]): + """Set the mapping of scenario identifiers to their short names.""" + self._scenario_short_names = scenario_short_names or {} + + # --- Scenario key / resolution overrides ------------------------------------ + def _key_for(self, scenario: "Any") -> Any: # type: ignore[override] + # Prefer short name if present (mapping stored by scenario.id) + short = self._scenario_short_names.get(str(scenario.id)) + return short if short else scenario.identifier() + + def resolve_scenario(self, label: Any): # type: ignore[override] + if label is None: + return None + label_str = str(label).strip() + # 1. short name + for scenario in self.scenarios: + if self._scenario_short_names.get(str(scenario.id)) == label_str: + return scenario + # 2. identifier (title or id as string) + s = super().resolve_scenario(label_str) + if s is not None: + return s + # 3. numeric id + try: + num = int(float(label_str)) + for scenario in self.scenarios: + if scenario.id == num: + return scenario + except Exception: + pass + return None + + # --- Per-scenario frame builder (used by generic template) ------------------ + def _build_dataframe_for_scenario(self, scenario, columns: str = "user", **kwargs): # type: ignore[override] + try: + df = scenario.inputs.to_dataframe(columns=columns) + except Exception as e: # pragma: no cover - defensive + logger.warning( + "Failed building inputs frame for scenario %s: %s", + scenario.identifier(), + e, + ) + return None + return df if df is not None and not df.empty else None + + def _to_dataframe(self, columns="user", **kwargs): # type: ignore[override] + return self.build_pack_dataframe(columns=columns, **kwargs) + + # --- Normalisation logic ---------------------------------------------------- + def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: + """Normalize various inputs sheet shapes into canonical shape: + - Drop leading completely blank rows. + - Accept either: + (a) Two header rows (short_name row above a row containing 'user'), or + (b) Single header row of scenario labels (no explicit 'user' row) -> we fabricate 'user'. + - Support 1- or 2-level row index (input[, unit]). + Returns DataFrame with columns MultiIndex(label, 'user'). + """ + df = df.dropna(how="all") + if df.empty: + return df + + # Locate the row containing 'user' (case-insensitive) + user_row_pos = None + for pos, (_, row) in enumerate(df.iterrows()): + if any(isinstance(v, str) and v.strip().lower() == "user" for v in row): + user_row_pos = pos + break + + single_header = user_row_pos is None + if single_header: + header_start = 0 + header_end = 0 + else: + header_start = max(user_row_pos - 1, 0) + header_end = user_row_pos + + headers = df.iloc[header_start : header_end + 1].astype(str) + data = df.iloc[header_end + 1 :].copy() + + if single_header: + # Build columns from single header row; fabricate second level 'user' + col_level0 = headers.iloc[0].values + data.columns = col_level0 + index_candidates = list(data.columns[:2]) # heuristic + second_is_numeric = False + if len(index_candidates) > 1: + sample = data[index_candidates[1]].dropna().head(5) + if not sample.empty and all( + pd.to_numeric(sample, errors="coerce").notna() + ): + second_is_numeric = True + if second_is_numeric: + idx_cols = [index_candidates[0]] + else: + idx_cols = index_candidates + input_col = idx_cols[0] + unit_col = idx_cols[1] if len(idx_cols) > 1 else None + scenario_cols = [ + c for c in data.columns if c not in idx_cols and str(c).strip() != "" + ] + input_series = data[input_col].astype(str) + if unit_col is not None: + unit_series = data[unit_col].astype(str) + index = pd.MultiIndex.from_arrays( + [input_series.values, unit_series.values], names=["input", "unit"] + ) + else: + index = pd.Index(input_series.values, name="input") + canonical = data[scenario_cols].copy() + canonical.index = index + canonical.columns = pd.MultiIndex.from_arrays( + [canonical.columns, ["user"] * len(canonical.columns)] + ) + return canonical + + # Two-row header path (original logic) + data.columns = pd.MultiIndex.from_arrays( + [headers.iloc[0].values, headers.iloc[1].values] + ) + + idx_cols = [ + col + for col in data.columns + if not (isinstance(col[1], str) and col[1].strip().lower() == "user") + ] + if len(idx_cols) == 0: + input_col = data.columns[0] + unit_col = None + else: + input_col = idx_cols[0] + unit_col = idx_cols[1] if len(idx_cols) > 1 else None + + input_series = data[input_col].astype(str) + if unit_col is not None: + unit_series = data[unit_col].astype(str) + index = pd.MultiIndex.from_arrays( + [input_series.values, unit_series.values], names=["input", "unit"] + ) + else: + index = pd.Index(input_series.values, name="input") + + keep_cols = [ + c + for c in data.columns + if c not in {input_col} and (unit_col is None or c != unit_col) + ] + canonical = data[keep_cols] + canonical.index = index + + if isinstance(canonical.columns, pd.MultiIndex): + lvl1 = canonical.columns.get_level_values(1) + if not all( + isinstance(v, str) and v.strip().lower() == "user" for v in lvl1 + ): + canonical.columns = pd.MultiIndex.from_arrays( + [ + canonical.columns.get_level_values(0), + ["user"] * len(canonical.columns), + ] + ) + else: + canonical.columns = pd.MultiIndex.from_arrays( + [canonical.columns, ["user"] * len(canonical.columns)] + ) + return canonical + + # --- Import (mutation) ------------------------------------------------------ + def from_dataframe(self, df): # type: ignore[override] + """ + Sets the inputs on the scenarios from the packed df (comes from excel) + Tolerates optional unit column and leading blank rows. + Uses short_name for scenario identification; falls back to identifier/title or id. + """ + if df is None or getattr(df, "empty", False): + return + try: + df = self._normalize_inputs_dataframe(df) + except Exception as e: + logger.warning("Failed to normalize inputs sheet: %s", e) + return + if df is None or df.empty: + return + + labels = df.columns.get_level_values(0).unique() + for label in labels: + scenario = self.resolve_scenario(label) + if scenario is None: + logger.warning( + "Could not find scenario for parameters column label '%s' (not a short_name/title/id)", + label, + ) + continue + scenario_df = df[label] + if isinstance(scenario_df, pd.Series): + scenario_df = scenario_df.to_frame(name="user") + else: + if list(scenario_df.columns) != ["user"]: + scenario_df = scenario_df.copy() + first_col = scenario_df.columns[0] + scenario_df = scenario_df.rename(columns={first_col: "user"}) + try: + scenario.set_user_values_from_dataframe(scenario_df) + except Exception as e: + logger.warning( + "Failed setting inputs for scenario '%s' from column label '%s': %s", + scenario.identifier(), + label, + e, + ) diff --git a/src/pyetm/models/packables/output_curves_pack.py b/src/pyetm/models/packables/output_curves_pack.py new file mode 100644 index 0000000..4acff49 --- /dev/null +++ b/src/pyetm/models/packables/output_curves_pack.py @@ -0,0 +1,28 @@ +import logging +from typing import ClassVar, Any + +import pandas as pd + +from pyetm.models.packables.packable import Packable + +logger = logging.getLogger(__name__) + + +class OutputCurvesPack(Packable): + key: ClassVar[str] = "output_curves" + sheet_name: ClassVar[str] = "OUTPUT_CURVES" + + def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): # type: ignore[override] + try: + series_list = list(scenario.all_output_curves()) + except Exception as e: # pragma: no cover + logger.warning( + "Failed extracting output curves for %s: %s", scenario.identifier(), e + ) + return None + if not series_list: + return None + return pd.concat(series_list, axis=1) + + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: # type: ignore[override] + return self.build_pack_dataframe(columns=columns, **kwargs) diff --git a/src/pyetm/models/packables/packable.py b/src/pyetm/models/packables/packable.py new file mode 100644 index 0000000..a92db2d --- /dev/null +++ b/src/pyetm/models/packables/packable.py @@ -0,0 +1,261 @@ +from typing import ClassVar, Set, Callable, Optional, Dict, Any +import logging +import pandas as pd +from pydantic import BaseModel, Field + +from pyetm.models.scenario import Scenario + +logger = logging.getLogger(__name__) + + +class Packable(BaseModel): + # Use a proper default set and keep the type consistent + scenarios: Set["Scenario"] = Field(default_factory=set) + key: ClassVar[str] = "base_pack" + sheet_name: ClassVar[str] = "SHEET" + + # Internal cache for fast identifier lookup + _scenario_id_cache: Dict[str, "Scenario"] | None = None + + # --- Public collection API ------------------------------------------------- + def add(self, *scenarios): + "Adds one or more scenarios to the packable" + if not scenarios: + return + self.scenarios.update(scenarios) + # Invalidate cache + self._scenario_id_cache = None + + def discard(self, scenario): + "Removes a scenario from the pack" + self.scenarios.discard(scenario) + self._scenario_id_cache = None + + def clear(self): + # Reset to an empty set + self.scenarios.clear() + self._scenario_id_cache = None + + # --- Summary ---------------------------------------------------------------- + def summary(self) -> dict: + return {self.key: {"scenario_count": len(self.scenarios)}} + + # --- Template packing API (Opt-in for subclasses) --------------------------- + def _key_for(self, scenario: "Scenario") -> Any: + """Return the identifier used as the top-level column key when packing. + Subclasses can override (e.g. to use short names).""" + return scenario.identifier() + + def _build_dataframe_for_scenario( + self, scenario: "Scenario", columns: str = "", **kwargs + ) -> Optional[pd.DataFrame]: + """Return a DataFrame for a single scenario or None/empty if not applicable. + Subclasses may override to opt-in to generic build_pack_dataframe helper.""" + return None + + def _concat_frames( + self, frames: list[pd.DataFrame], keys: list[Any] + ) -> pd.DataFrame: + """Concatenate per-scenario frames along axis=1 with keys. + Separated for easier overriding/testing.""" + if not frames: + return pd.DataFrame() + return pd.concat(frames, axis=1, keys=keys) + + def build_pack_dataframe(self, columns: str = "", **kwargs) -> pd.DataFrame: + """Generic implementation collecting per-scenario frames using + _build_dataframe_for_scenario. Subclasses call this inside their + _to_dataframe implementation after overriding _build_dataframe_for_scenario. + (Not automatically invoked so existing subclasses remain unchanged).""" + frames: list[pd.DataFrame] = [] + keys: list[Any] = [] + for scenario in self.scenarios: + try: + df = self._build_dataframe_for_scenario( + scenario, columns=columns, **kwargs + ) + except Exception as e: # pragma: no cover - defensive + logger.warning( + "Failed building frame for scenario %s in %s: %s", + scenario.identifier(), + self.__class__.__name__, + e, + ) + continue + if df is None or df.empty: + continue + frames.append(df) + keys.append(self._key_for(scenario)) + return self._concat_frames(frames, keys) + + # --- External API ----------------------------------------------------------- + def to_dataframe(self, columns="") -> pd.DataFrame: + """Convert the pack into a dataframe""" + if len(self.scenarios) == 0: + return pd.DataFrame() + return self._to_dataframe(columns=columns) + + def from_dataframe(self, df): # pragma: no cover - abstract hook + """Should parse the df and call correct setters on identified scenarios""" + + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: # pragma: no cover + """Base implementation - kids should implement this or use build_pack_dataframe""" + return pd.DataFrame() + + # --- Scenario resolution helpers ------------------------------------------- + def _refresh_cache(self): + self._scenario_id_cache = {str(s.identifier()): s for s in self.scenarios} + + def _find_by_identifier(self, identifier: str): + ident_str = str(identifier) + if self._scenario_id_cache is None or len(self._scenario_id_cache) != len( + self.scenarios + ): + self._refresh_cache() + return self._scenario_id_cache.get(ident_str) + + def resolve_scenario(self, label: Any) -> Optional["Scenario"]: + """Generic resolution; subclasses can extend (e.g. InputsPack). + Default: direct identifier match.""" + if label is None: + return None + return self._find_by_identifier(label) + + # --- Utility static methods (shared normalisation helpers) ----------------- + @staticmethod + def is_blank(value: Any) -> bool: + return ( + value is None + or (isinstance(value, float) and pd.isna(value)) + or (isinstance(value, str) and value.strip() == "") + ) + + @staticmethod + def drop_all_blank(df: pd.DataFrame) -> pd.DataFrame: + if df is None: + return pd.DataFrame() + return df.dropna(how="all") + + @staticmethod + def first_non_empty_row_positions(df: pd.DataFrame, count: int = 2) -> list[int]: + positions: list[int] = [] + if df is None: + return positions + for idx, (_, row) in enumerate(df.iterrows()): + if not row.isna().all(): + positions.append(idx) + if len(positions) >= count: + break + return positions + + def _log_fail(self, context: str, exc: Exception): # pragma: no cover - helper + logger.warning("%s failed in %s: %s", context, self.__class__.__name__, exc) + + def apply_identifier_blocks( + self, + df: pd.DataFrame, + apply_block: Callable[["Scenario", pd.DataFrame], None], + resolve: Optional[Callable[[Any], Optional["Scenario"]]] = None, + ): + """Iterate over first-level column identifiers of a MultiIndex DataFrame and apply a block function. + resolve optionally overrides scenario resolution (defaults to direct identifier lookup). + """ + if df is None or not isinstance(df.columns, pd.MultiIndex): + return + identifiers = df.columns.get_level_values(0).unique() + for identifier in identifiers: + scenario = ( + resolve(identifier) if resolve else None + ) or self._find_by_identifier(identifier) + if scenario is None: + logger.warning( + "Could not find scenario for identifier '%s' in %s", + identifier, + self.__class__.__name__, + ) + continue + block = df[identifier] + try: + apply_block(scenario, block) + except Exception as e: # pragma: no cover + logger.warning( + "Failed applying block for scenario '%s' in %s: %s", + identifier, + self.__class__.__name__, + e, + ) + + def _normalize_two_header_sheet( + self, + df: pd.DataFrame, + *, + helper_level0: Optional[set[str]] = None, + helper_level1: Optional[set[str]] = None, + drop_empty_level0: bool = True, + drop_empty_level1: bool = False, + collapse_level0: bool = False, + reset_index: bool = False, + ) -> pd.DataFrame: + """Generic normalizer for a sheet with (potential) two header rows. + - Detect first two non-empty rows as headers (or fabricate second if missing). + - Build MultiIndex columns (level0, level1). + - Optionally drop columns whose level0/level1 are blank or in helper sets. + - Optionally collapse to single level (level0) after filtering. + - Optionally reset row index to a simple RangeIndex. + Returns canonical DataFrame or empty DataFrame on failure. + """ + helper_level0 = {h.lower() for h in (helper_level0 or set())} + helper_level1 = {h.lower() for h in (helper_level1 or set())} + + if df is None: + return pd.DataFrame() + df = df.dropna(how="all") + if df.empty: + return df + + positions = self.first_non_empty_row_positions(df, 2) + if not positions: + return pd.DataFrame() + header0_pos = positions[0] + header1_pos = positions[1] if len(positions) > 1 else None + + if header1_pos is None: + # Single header row -> fabricate second empty row + headers0 = df.iloc[header0_pos].astype(str).values + headers1 = ["" for _ in headers0] + data = df.iloc[header0_pos + 1 :].copy() + else: + headers = df.iloc[[header0_pos, header1_pos]].astype(str) + headers0 = headers.iloc[0].values + headers1 = headers.iloc[1].values + data = df.iloc[header1_pos + 1 :].copy() + + columns = pd.MultiIndex.from_arrays([headers0, headers1]) + data.columns = columns + + def _is_blank(v): + return ( + v is None + or (isinstance(v, float) and pd.isna(v)) + or (isinstance(v, str) and v.strip() == "") + ) + + keep = [] + for c in data.columns: + lv0, lv1 = c[0], c[1] + if drop_empty_level0 and _is_blank(lv0): + continue + if drop_empty_level1 and _is_blank(lv1): + continue + if isinstance(lv0, str) and lv0.strip().lower() in helper_level0: + continue + if isinstance(lv1, str) and lv1.strip().lower() in helper_level1: + continue + keep.append(c) + data = data[keep] + + if collapse_level0: + data.columns = [c[0] for c in data.columns] + if reset_index: + data.reset_index(drop=True, inplace=True) + return data diff --git a/src/pyetm/models/packables/query_pack.py b/src/pyetm/models/packables/query_pack.py new file mode 100644 index 0000000..d2c231e --- /dev/null +++ b/src/pyetm/models/packables/query_pack.py @@ -0,0 +1,137 @@ +import logging +from typing import ClassVar, Any + +import pandas as pd + +from pyetm.models.packables.packable import Packable + +logger = logging.getLogger(__name__) + + +class QueryPack(Packable): + key: ClassVar[str] = "gquery" + sheet_name: ClassVar[str] = "GQUERIES_RESULTS" + + def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "future", **kwargs): # type: ignore[override] + try: + return scenario.results(columns=columns) + except Exception as e: # pragma: no cover - defensive + logger.warning( + "Failed building gquery results for %s: %s", scenario.identifier(), e + ) + return None + + def _to_dataframe(self, columns="future", **kwargs) -> pd.DataFrame: # type: ignore[override] + return self.build_pack_dataframe(columns=columns, **kwargs) + + def _normalize_queries_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: + """Normalize a GQUERIES sheet into simple shape. + Restores previous heuristic so we don't drop the first real gquery row when there is only one header row. + Logic: + - Drop fully blank rows/cols. + - Detect if there are 2 header rows (second row contains a helper token like 'gquery', 'key', etc.). + - If only one header row, keep remaining rows as data. + - Return DataFrame with columns = scenario identifiers and rows listing gquery keys (strings). + """ + if df is None: + return pd.DataFrame() + + # Drop completely empty rows/cols + df = df.dropna(how="all") + if df.empty: + return df + df = df.dropna(axis=1, how="all") + + non_empty_rows = [ + i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() + ] + if not non_empty_rows: + return pd.DataFrame() + + helper_tokens = {"gquery", "gqueries", "key", "queries"} + header_rows = 1 + if len(non_empty_rows) > 1: + second = ( + df.iloc[non_empty_rows[1]].astype(str).str.strip().str.lower().tolist() + ) + if any(val in helper_tokens for val in second): + header_rows = 2 + + header_start = non_empty_rows[0] + header_end = header_start + header_rows - 1 + headers = df.iloc[header_start : header_end + 1].astype(str) + data = df.iloc[header_end + 1 :].copy() + + # Assign columns + if header_rows == 2: + cols = pd.MultiIndex.from_arrays( + [headers.iloc[0].values, headers.iloc[1].values] + ) + data.columns = cols + else: + data.columns = pd.Index(headers.iloc[0].values) + + def _is_empty(v): + return ( + (not isinstance(v, str)) + or (v.strip() == "") + or (v.strip().lower() == "nan") + ) + + def _is_helper_label(v): + return isinstance(v, str) and v.strip().lower() in helper_tokens + + if isinstance(data.columns, pd.MultiIndex): + keep = [ + c + for c in data.columns + if not _is_empty(c[0]) and not _is_helper_label(c[0]) + ] + data = data[keep] + data.columns = [c[0] for c in data.columns] + else: + keep = [ + c + for c in data.columns + if isinstance(c, str) and not _is_empty(c) and not _is_helper_label(c) + ] + data = data[keep] + + for c in data.columns: + data[c] = data[c].apply(lambda x: None if pd.isna(x) else str(x).strip()) + data = data.dropna(how="all") + return data + + def from_dataframe(self, df: pd.DataFrame): # type: ignore[override] + if df is None or getattr(df, "empty", False): + return + try: + df = self._normalize_queries_dataframe(df) + except Exception as e: + logger.warning("Failed to normalize gqueries sheet: %s", e) + return + if df is None or df.empty: + return + + # Here columns are single-level; wrap into a synthetic MultiIndex so we can reuse apply_identifier_blocks + df_multi = df.copy() + df_multi.columns = pd.MultiIndex.from_arrays( + [df_multi.columns, ["gquery_keys"] * len(df_multi.columns)] + ) + + def _apply(scenario, block: pd.DataFrame): + # block is a DataFrame with single column 'gquery_keys' (after collapse) or Series + series = block.iloc[:, 0] if isinstance(block, pd.DataFrame) else block + values = [ + v for v in series.tolist() if isinstance(v, str) and v.strip() != "" + ] + seen = set() + keys = [] + for v in values: + if v not in seen: + seen.add(v) + keys.append(v) + if keys: + scenario.add_queries(keys) + + self.apply_identifier_blocks(df_multi, _apply) diff --git a/src/pyetm/models/packables/sortable_pack.py b/src/pyetm/models/packables/sortable_pack.py new file mode 100644 index 0000000..300cfe0 --- /dev/null +++ b/src/pyetm/models/packables/sortable_pack.py @@ -0,0 +1,65 @@ +import logging +from typing import ClassVar, Any + +import pandas as pd + +from pyetm.models.packables.packable import Packable + +logger = logging.getLogger(__name__) + + +class SortablePack(Packable): + key: ClassVar[str] = "sortables" + sheet_name: ClassVar[str] = "SORTABLES" + + def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): # type: ignore[override] + try: + df = scenario.sortables.to_dataframe() + except Exception as e: # pragma: no cover + logger.warning( + "Failed extracting sortables for %s: %s", scenario.identifier(), e + ) + return None + return df if not df.empty else None + + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: # type: ignore[override] + return self.build_pack_dataframe(columns=columns, **kwargs) + + def _normalize_sortables_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: + """Normalize various sortables sheet shapes using generic helper. + Produces DataFrame with columns MultiIndex(identifier, sortable_name) then + collapses to MultiIndex for downstream block iteration. + """ + data = self._normalize_two_header_sheet( + df, + helper_level0=set(), # no explicit helper labels on level0 expected + helper_level1={"sortables"}, + drop_empty_level0=True, + collapse_level0=False, # keep two levels for clarity; we will collapse in from_dataframe if needed + reset_index=False, + ) + if data.empty: + return data + # For parity with previous logic we want identifiers as level0 only when applying + # but we still need a MultiIndex for apply_identifier_blocks; keep as-is. + return data + + def from_dataframe(self, df: pd.DataFrame): + """Unpack and update sortables for each scenario from the sheet.""" + if df is None or getattr(df, "empty", False): + return + try: + df = self._normalize_sortables_dataframe(df) + except Exception as e: + logger.warning("Failed to normalize sortables sheet: %s", e) + return + if df is None or df.empty or not isinstance(df.columns, pd.MultiIndex): + return + + def _apply(scenario, block: pd.DataFrame): + # Collapse block columns (identifier, sortable_name) -> keep only sortable_name part + if isinstance(block.columns, pd.MultiIndex): + block.columns = [c[1] for c in block.columns] + scenario.set_sortables_from_dataframe(block) + + self.apply_identifier_blocks(df, _apply) diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 3ff3b57..8bbe9a7 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -1,10 +1,15 @@ import pandas as pd import logging from os import PathLike -from pydantic import BaseModel, Field -from typing import Optional, Dict, Any, Set, ClassVar +from pydantic import BaseModel +from typing import Optional, Dict, Any from xlsxwriter import Workbook +from pyetm.models.packables.custom_curves_pack import CustomCurvesPack +from pyetm.models.packables.inputs_pack import InputsPack +from pyetm.models.packables.output_curves_pack import OutputCurvesPack +from pyetm.models.packables.query_pack import QueryPack +from pyetm.models.packables.sortable_pack import SortablePack from pyetm.models import Scenario from pyetm.models.custom_curves import CustomCurves from pyetm.utils.excel import add_frame_with_scenario_styling @@ -12,714 +17,6 @@ logger = logging.getLogger(__name__) -class Packable(BaseModel): - # Use a proper default set and keep the type consistent - scenarios: Set["Scenario"] = Field(default_factory=set) - key: ClassVar[str] = "base_pack" - sheet_name: ClassVar[str] = "SHEET" - - def add(self, *scenarios): - "Adds one or more scenarios to the packable" - self.scenarios.update(scenarios) - - def discard(self, scenario): - "Removes a scenario from the pack" - self.scenarios.discard(scenario) - - def clear(self): - # Reset to an empty set - self.scenarios.clear() - - def summary(self) -> dict: - return {self.key: {"scenario_count": len(self.scenarios)}} - - def to_dataframe(self, columns="") -> pd.DataFrame: - """Convert the pack into a dataframe""" - if len(self.scenarios) == 0: - return pd.DataFrame() - - return self._to_dataframe(columns=columns) - - def from_dataframe(self, df): - """Should parse the df and call correct setters on identified scenarios""" - - def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: - """Base implementation - kids should implement this""" - return pd.DataFrame() - - def _find_by_identifier(self, identifier: str): - ident_str = str(identifier) - return next( - (s for s in self.scenarios if str(s.identifier()) == ident_str), - None, - ) - - -class InputsPack(Packable): - key: ClassVar[str] = "inputs" - sheet_name: ClassVar[str] = "PARAMETERS" - - def __init__(self, **data): - super().__init__(**data) - self._scenario_short_names: Dict[str, str] = ( - {} - ) # scenario_id -> short_name mapping - - def set_scenario_short_names(self, scenario_short_names: Dict[str, str]): - """Set the mapping of scenario identifiers to their short names.""" - self._scenario_short_names = scenario_short_names - - def _find_by_short_name(self, short_name: str): - """Find scenario by its short name.""" - short_name_str = str(short_name) - for scenario in self.scenarios: - scenario_id = str(scenario.identifier()) - if self._scenario_short_names.get(str(scenario.id)) == short_name_str: - return scenario - return None - - def _find_by_any(self, label: str): - """Attempt to resolve a label to a scenario by (in order): - 1. short_name mapping - 2. scenario.identifier() (title or id) - 3. numeric id match - """ - if label is None: - return None - label_str = str(label).strip() - # 1. short name - s = self._find_by_short_name(label_str) - if s is not None: - return s - # 2. identifier (title or id) - for scenario in self.scenarios: - if str(scenario.identifier()) == label_str: - return scenario - # 3. numeric id - try: - num = int(float(label_str)) - for scenario in self.scenarios: - if scenario.id == num: - return scenario - except Exception: - pass - return None - - def _to_dataframe(self, columns="user", **kwargs): - return pd.concat( - [ - scenario.inputs.to_dataframe(columns=columns) - for scenario in self.scenarios - ], - axis=1, - keys=[ - self._scenario_short_names.get( - str(scenario.identifier()), str(scenario.identifier()) - ) - for scenario in self.scenarios - ], - ) - - def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize various inputs sheet shapes into canonical shape: - - Drop leading completely blank rows. - - Accept either: - (a) Two header rows (short_name row above a row containing 'user'), or - (b) Single header row of scenario labels (no explicit 'user' row) -> we fabricate 'user'. - - Support 1- or 2-level row index (input[, unit]). - Returns DataFrame with columns MultiIndex(label, 'user'). - """ - df = df.dropna(how="all") - if df.empty: - return df - - # Locate the row containing 'user' (case-insensitive) - user_row_pos = None - for pos, (_, row) in enumerate(df.iterrows()): - if any(isinstance(v, str) and v.strip().lower() == "user" for v in row): - user_row_pos = pos - break - - single_header = user_row_pos is None - if single_header: - header_start = 0 - header_end = 0 - else: - header_start = max(user_row_pos - 1, 0) - header_end = user_row_pos - - headers = df.iloc[header_start : header_end + 1].astype(str) - data = df.iloc[header_end + 1 :].copy() - - if single_header: - # Build columns from single header row; fabricate second level 'user' - col_level0 = headers.iloc[0].values - # First one (index col) often blank -> keep for alignment - data.columns = col_level0 - # Identify index columns: left-most non-scenario columns (we take first (and optional second) column as index parts) - index_candidates = list(data.columns[:2]) # heuristic - # If second column values are all numeric -> treat as scenario column, so only first column is index - second_is_numeric = False - if len(index_candidates) > 1: - sample = data[index_candidates[1]].dropna().head(5) - if not sample.empty and all( - pd.to_numeric(sample, errors="coerce").notna() - ): - second_is_numeric = True - if second_is_numeric: - idx_cols = [index_candidates[0]] - else: - idx_cols = index_candidates - input_col = idx_cols[0] - unit_col = idx_cols[1] if len(idx_cols) > 1 else None - scenario_cols = [ - c for c in data.columns if c not in idx_cols and str(c).strip() != "" - ] - # Build index - input_series = data[input_col].astype(str) - if unit_col is not None: - unit_series = data[unit_col].astype(str) - index = pd.MultiIndex.from_arrays( - [input_series.values, unit_series.values], names=["input", "unit"] - ) - else: - index = pd.Index(input_series.values, name="input") - canonical = data[scenario_cols].copy() - canonical.index = index - # Fabricate second level - canonical.columns = pd.MultiIndex.from_arrays( - [canonical.columns, ["user"] * len(canonical.columns)] - ) - return canonical - - # Two-row header path (original logic) - data.columns = pd.MultiIndex.from_arrays( - [headers.iloc[0].values, headers.iloc[1].values] - ) - - idx_cols = [ - col - for col in data.columns - if not (isinstance(col[1], str) and col[1].strip().lower() == "user") - ] - if len(idx_cols) == 0: - input_col = data.columns[0] - unit_col = None - else: - input_col = idx_cols[0] - unit_col = idx_cols[1] if len(idx_cols) > 1 else None - - input_series = data[input_col].astype(str) - if unit_col is not None: - unit_series = data[unit_col].astype(str) - index = pd.MultiIndex.from_arrays( - [input_series.values, unit_series.values], names=["input", "unit"] - ) - else: - index = pd.Index(input_series.values, name="input") - - keep_cols = [ - c - for c in data.columns - if c not in {input_col} and (unit_col is None or c != unit_col) - ] - canonical = data[keep_cols] - canonical.index = index - - # Ensure second level equals 'user' - if isinstance(canonical.columns, pd.MultiIndex): - lvl1 = canonical.columns.get_level_values(1) - if not all( - isinstance(v, str) and v.strip().lower() == "user" for v in lvl1 - ): - canonical.columns = pd.MultiIndex.from_arrays( - [ - canonical.columns.get_level_values(0), - ["user"] * len(canonical.columns), - ] - ) - else: - canonical.columns = pd.MultiIndex.from_arrays( - [ - canonical.columns, - ["user"] * len(canonical.columns), - ] - ) - return canonical - - def from_dataframe(self, df): - """ - Sets the inputs on the scenarios from the packed df (comes from excel) - Tolerates optional unit column and leading blank rows. - Uses short_name for scenario identification; falls back to identifier/title or id. - """ - if df is None or getattr(df, "empty", False): - return - - try: - df = self._normalize_inputs_dataframe(df) - except Exception as e: - logger.warning("Failed to normalize inputs sheet: %s", e) - return - - if df is None or df.empty: - return - - # Now df has columns MultiIndex (label, 'user') where label may be short_name, title, or id - labels = df.columns.get_level_values(0).unique() - - for label in labels: - scenario = self._find_by_any(label) - if scenario is None: - logger.warning( - "Could not find scenario for parameters column label '%s' (not a short_name/title/id)", - label, - ) - continue - - scenario_df = df[label] - # Ensure DataFrame with a 'user' column - if isinstance(scenario_df, pd.Series): - scenario_df = scenario_df.to_frame(name="user") - else: - if list(scenario_df.columns) != ["user"]: - scenario_df = scenario_df.copy() - first_col = scenario_df.columns[0] - scenario_df = scenario_df.rename(columns={first_col: "user"}) - - try: - scenario.set_user_values_from_dataframe(scenario_df) - except Exception as e: - logger.warning( - "Failed setting inputs for scenario '%s' from column label '%s': %s", - scenario.identifier(), - label, - e, - ) - - -class QueryPack(Packable): - key: ClassVar[str] = "gquery" - sheet_name: ClassVar[str] = "GQUERIES_RESULTS" - - def _to_dataframe( - self, columns="future", **kwargs - ) -> pd.DataFrame: # Make sure **kwargs is here - if not self.scenarios: - return pd.DataFrame() - - return pd.concat( - [scenario.results(columns=columns) for scenario in self.scenarios], - axis=1, - keys=[scenario.identifier() for scenario in self.scenarios], - copy=False, - ) - - def _normalize_queries_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize a GQUERIES sheet into a simple shape: - - Drop leading completely blank rows and columns. - - Detect 1 or 2 header rows. - - Return a DataFrame with columns = scenario identifiers and rows listing gquery keys. - We ignore any leftmost index/helper columns whose header is empty or looks like a label. - """ - if df is None: - return pd.DataFrame() - - # Drop completely empty rows/cols - df = df.dropna(how="all") - if df.empty: - return df - df = df.dropna(axis=1, how="all") - - # Find non-empty rows for potential headers - non_empty_rows = [ - i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() - ] - if not non_empty_rows: - return pd.DataFrame() - - # Heuristic: if the second non-empty row contains the word 'gquery'/'gqueries', use 2 header rows - header_rows = 1 - if len(non_empty_rows) > 1: - second = ( - df.iloc[non_empty_rows[1]].astype(str).str.strip().str.lower().tolist() - ) - if any(val in {"gquery", "gqueries", "key", "queries"} for val in second): - header_rows = 2 - - header_start = non_empty_rows[0] - header_end = header_start + header_rows - 1 - headers = df.iloc[header_start : header_end + 1].astype(str) - data = df.iloc[header_end + 1 :].copy() - - # Assign columns: MultiIndex if 2 header rows else single level - if header_rows == 2: - cols = pd.MultiIndex.from_arrays( - [headers.iloc[0].values, headers.iloc[1].values] - ) - else: - cols = pd.Index(headers.iloc[0].values) - data.columns = cols - - def _is_empty(v): - return ( - (not isinstance(v, str)) - or (v.strip() == "") - or (v.strip().lower() == "nan") - ) - - def _is_helper_label(v): - return isinstance(v, str) and v.strip().lower() in { - "gquery", - "gqueries", - "queries", - "key", - } - - # Build a simple DataFrame with columns = scenario identifiers - if isinstance(data.columns, pd.MultiIndex): - keep = [ - c - for c in data.columns - if not _is_empty(c[0]) and not _is_helper_label(c[0]) - ] - data = data[keep] - # Collapse to single level (identifier) - data.columns = [c[0] for c in data.columns] - else: - keep = [ - c - for c in data.columns - if isinstance(c, str) and not _is_empty(c) and not _is_helper_label(c) - ] - data = data[keep] - - # Ensure string values and drop rows that are completely blank across all kept columns - for c in data.columns: - data[c] = data[c].apply(lambda x: None if pd.isna(x) else (str(x).strip())) - data = data.dropna(how="all") - - return data - - def from_dataframe(self, df: pd.DataFrame): - """Collect gquery keys for each scenario from a GQUERIES sheet and attach them. - The sheet is expected to have one column per scenario (by identifier/title), - with each row containing a gquery key. Blank rows are ignored. - """ - if df is None or getattr(df, "empty", False): - return - - try: - df = self._normalize_queries_dataframe(df) - except Exception as e: - logger.warning("Failed to normalize gqueries sheet: %s", e) - return - - if df is None or df.empty: - return - - for identifier in df.columns: - scenario = self._find_by_identifier(identifier) - if scenario is None: - logger.warning( - "Could not find scenario for identifier '%s'", identifier - ) - continue - - # Extract non-empty keys, preserve order, remove duplicates while preserving order - values = [ - v - for v in df[identifier].tolist() - if isinstance(v, str) and v.strip() != "" - ] - seen = set() - keys = [] - for v in values: - if v not in seen: - seen.add(v) - keys.append(v) - - if keys: - try: - scenario.add_queries(keys) - except Exception as e: - logger.warning("Failed to add gqueries to '%s': %s", identifier, e) - - -class SortablePack(Packable): - key: ClassVar[str] = "sortables" - sheet_name: ClassVar[str] = "SORTABLES" - - def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: - """Pack sortables data for all scenarios with multi-index support""" - if not self.scenarios: - return pd.DataFrame() - - sortables_dfs = [] - scenario_keys = [] - - for scenario in self.scenarios: - df = scenario.sortables.to_dataframe() - if not df.empty: - sortables_dfs.append(df) - scenario_keys.append(scenario.identifier()) - - if not sortables_dfs: - return pd.DataFrame() - - return pd.concat( - sortables_dfs, - axis=1, - keys=scenario_keys, - ) - - def _normalize_sortables_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize various sortables sheet shapes. - Assumptions: - - Two header rows: first row = scenario identifier/title, second row = sortable name. - - Leading blank rows may exist and are ignored. - - Optional leftmost index column(s) are present with empty first header cell(s). They are dropped. - Returns a DataFrame with columns MultiIndex(identifier, sortable_name) and - simple Index rows with order positions. - """ - # Drop completely empty rows - df = df.dropna(how="all") - if df.empty: - return df - - # Find the first two non-empty rows -> headers - non_empty_idx = [ - i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() - ] - if not non_empty_idx: - return pd.DataFrame() - header0_pos = non_empty_idx[0] - header1_pos = non_empty_idx[1] if len(non_empty_idx) > 1 else header0_pos + 1 - - headers = df.iloc[[header0_pos, header1_pos]].astype(str) - data = df.iloc[header1_pos + 1 :].copy() - - # Build MultiIndex columns - col_level0 = headers.iloc[0].values - col_level1 = headers.iloc[1].values - columns = pd.MultiIndex.from_arrays([col_level0, col_level1]) - data.columns = columns - - # Drop columns where identifier (level 0) is missing/empty, and drop any - # column which is clearly the helper/index label (e.g. level1 == 'sortables'). - def _is_empty(v): - return ( - (not isinstance(v, str)) - or (v.strip() == "") - or (v.strip().lower() == "nan") - ) - - def _is_helper_label(v): - return isinstance(v, str) and v.strip().lower() in {"sortables"} - - keep_cols = [ - c - for c in data.columns - if not _is_empty(c[0]) and not _is_helper_label(c[0]) - ] - data = data[keep_cols] - # Collapse to single level (identifier) - data.columns = [c[0] for c in data.columns] - - # Ensure string values and drop rows that are completely blank across all kept columns - for c in data.columns: - data[c] = data[c].apply(lambda x: None if pd.isna(x) else (str(x).strip())) - data = data.dropna(how="all") - - return data - - def from_dataframe(self, df: pd.DataFrame): - """Unpack and update sortables for each scenario from the sheet. - The sheet may contain optional leading blank rows and optional index columns. - """ - if df is None or getattr(df, "empty", False): - return - - try: - df = self._normalize_sortables_dataframe(df) - except Exception as e: - logger.warning("Failed to normalize sortables sheet: %s", e) - return - - if df is None or df.empty or not isinstance(df.columns, pd.MultiIndex): - return - - identifiers = df.columns.get_level_values(0).unique() - for identifier in identifiers: - scenario = self._find_by_identifier(identifier) - if scenario is None: - logger.warning( - "Could not find scenario for identifier '%s'", identifier - ) - continue - - block = df[identifier] - try: - scenario.set_sortables_from_dataframe(block) - except Exception as e: - logger.warning("Failed to update sortables for '%s': %s", identifier, e) - - -class CustomCurvesPack(Packable): - key: ClassVar[str] = "custom_curves" - sheet_name: ClassVar[str] = "CUSTOM_CURVES" - - def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: - """Pack custom curves data for all scenarios with multi-index support""" - if not self.scenarios: - return pd.DataFrame() - - curves_dfs = [] - scenario_keys = [] - - for scenario in self.scenarios: - series_list = list(scenario.custom_curves_series()) - if len(series_list) > 0: - df = pd.concat(series_list, axis=1) - curves_dfs.append(df) - scenario_keys.append(scenario.identifier()) - - if not curves_dfs: - return pd.DataFrame() - - return pd.concat( - curves_dfs, - axis=1, - keys=scenario_keys, - ) - - def _normalize_curves_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize custom curves sheet shapes. - Assumptions: - - Two header rows: first row = scenario identifier/title, second row = curve key. - - Leading blank rows may exist and are ignored. - - Optional leftmost index column(s) are present with empty first header cell(s); they are dropped. - - Rows are the hourly values (0..8759) or arbitrary length; we keep as-is. - Returns a DataFrame with columns MultiIndex(identifier, curve_key) and numeric rows. - """ - df = df.dropna(how="all") - if df.empty: - return df - - # Find header rows - non_empty_idx = [ - i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() - ] - if not non_empty_idx: - return pd.DataFrame() - header0_pos = non_empty_idx[0] - header1_pos = non_empty_idx[1] if len(non_empty_idx) > 1 else header0_pos + 1 - - headers = df.iloc[[header0_pos, header1_pos]].astype(str) - data = df.iloc[header1_pos + 1 :].copy() - - # Assign columns - columns = pd.MultiIndex.from_arrays( - [headers.iloc[0].values, headers.iloc[1].values] - ) - data.columns = columns - - # Drop non-scenario columns where identifier is empty and drop helper/index - # columns where level1 looks like a label (e.g., 'sortables') - def _is_empty(v): - return ( - (not isinstance(v, str)) - or (v.strip() == "") - or (v.strip().lower() == "nan") - ) - - def _is_helper_label(v): - return isinstance(v, str) and v.strip().lower() in {"sortables"} - - keep_cols = [ - c - for c in data.columns - if not _is_empty(c[0]) and not _is_helper_label(c[1]) - ] - canonical = data[keep_cols].copy() - - # Reset index to numeric starting at 0 - canonical.reset_index(drop=True, inplace=True) - return canonical - - def from_dataframe(self, df: pd.DataFrame): - """Unpack and update custom curves for each scenario. - Sheet may contain leading blank rows and optional index columns. - """ - if df is None or getattr(df, "empty", False): - return - - try: - df = self._normalize_curves_dataframe(df) - except Exception as e: - logger.warning("Failed to normalize custom curves sheet: %s", e) - return - - if df is None or df.empty or not isinstance(df.columns, pd.MultiIndex): - return - - identifiers = df.columns.get_level_values(0).unique() - for identifier in identifiers: - scenario = self._find_by_identifier(identifier) - if scenario is None: - logger.warning( - "Could not find scenario for identifier '%s'", identifier - ) - continue - - block = df[identifier] - # Build a CustomCurves collection from the block columns - try: - curves = CustomCurves._from_dataframe(block, scenario_id=scenario.id) - except Exception as e: - logger.warning( - "Failed to build custom curves for '%s': %s", identifier, e - ) - continue - - # Validate and upload - try: - scenario.update_custom_curves(curves) - except Exception as e: - logger.warning( - "Failed to update custom curves for '%s': %s", identifier, e - ) - - -class OutputCurvesPack(Packable): - key: ClassVar[str] = "output_curves" - sheet_name: ClassVar[str] = "OUTPUT_CURVES" - - def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: - """Pack output curves data for all scenarios with multi-index support""" - if not self.scenarios: - return pd.DataFrame() - - curves_dfs = [] - scenario_keys = [] - - for scenario in self.scenarios: - series_list = list(scenario.all_output_curves()) - if len(series_list) > 0: - df = pd.concat(series_list, axis=1) - curves_dfs.append(df) - scenario_keys.append(scenario.identifier()) - - if not curves_dfs: - return pd.DataFrame() - - return pd.concat( - curves_dfs, - axis=1, - keys=scenario_keys, - ) - - class ScenarioPacker(BaseModel): """ Packs one or multiple scenarios for export to dataframes or excel From 83345bd459f2299fa6f57f83ca0255cbc64edc6f Mon Sep 17 00:00:00 2001 From: louispt1 Date: Mon, 11 Aug 2025 11:02:08 +0200 Subject: [PATCH 11/17] Simplify query processing --- .../models/packables/custom_curves_pack.py | 8 +- src/pyetm/models/packables/inputs_pack.py | 12 +- src/pyetm/models/packables/packable.py | 2 +- src/pyetm/models/packables/query_pack.py | 142 ++++-------------- src/pyetm/models/scenario_packer.py | 83 +--------- 5 files changed, 42 insertions(+), 205 deletions(-) diff --git a/src/pyetm/models/packables/custom_curves_pack.py b/src/pyetm/models/packables/custom_curves_pack.py index 432c3a5..d454164 100644 --- a/src/pyetm/models/packables/custom_curves_pack.py +++ b/src/pyetm/models/packables/custom_curves_pack.py @@ -13,10 +13,10 @@ class CustomCurvesPack(Packable): key: ClassVar[str] = "custom_curves" sheet_name: ClassVar[str] = "CUSTOM_CURVES" - def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): # type: ignore[override] + def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): try: series_list = list(scenario.custom_curves_series()) - except Exception as e: # pragma: no cover - defensive + except Exception as e: logger.warning( "Failed extracting custom curves for %s: %s", scenario.identifier(), e ) @@ -25,7 +25,7 @@ def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwar return None return pd.concat(series_list, axis=1) - def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: # type: ignore[override] + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: return self.build_pack_dataframe(columns=columns, **kwargs) def _normalize_curves_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: @@ -38,7 +38,7 @@ def _normalize_curves_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: ) return data - def from_dataframe(self, df: pd.DataFrame): # type: ignore[override] + def from_dataframe(self, df: pd.DataFrame): if df is None or getattr(df, "empty", False): return try: diff --git a/src/pyetm/models/packables/inputs_pack.py b/src/pyetm/models/packables/inputs_pack.py index 094b5d9..61ec67f 100644 --- a/src/pyetm/models/packables/inputs_pack.py +++ b/src/pyetm/models/packables/inputs_pack.py @@ -24,12 +24,12 @@ def set_scenario_short_names(self, scenario_short_names: Dict[str, str]): self._scenario_short_names = scenario_short_names or {} # --- Scenario key / resolution overrides ------------------------------------ - def _key_for(self, scenario: "Any") -> Any: # type: ignore[override] + def _key_for(self, scenario: "Any") -> Any: # Prefer short name if present (mapping stored by scenario.id) short = self._scenario_short_names.get(str(scenario.id)) return short if short else scenario.identifier() - def resolve_scenario(self, label: Any): # type: ignore[override] + def resolve_scenario(self, label: Any): if label is None: return None label_str = str(label).strip() @@ -52,10 +52,10 @@ def resolve_scenario(self, label: Any): # type: ignore[override] return None # --- Per-scenario frame builder (used by generic template) ------------------ - def _build_dataframe_for_scenario(self, scenario, columns: str = "user", **kwargs): # type: ignore[override] + def _build_dataframe_for_scenario(self, scenario, columns: str = "user", **kwargs): try: df = scenario.inputs.to_dataframe(columns=columns) - except Exception as e: # pragma: no cover - defensive + except Exception as e: logger.warning( "Failed building inputs frame for scenario %s: %s", scenario.identifier(), @@ -64,7 +64,7 @@ def _build_dataframe_for_scenario(self, scenario, columns: str = "user", **kwarg return None return df if df is not None and not df.empty else None - def _to_dataframe(self, columns="user", **kwargs): # type: ignore[override] + def _to_dataframe(self, columns="user", **kwargs): return self.build_pack_dataframe(columns=columns, **kwargs) # --- Normalisation logic ---------------------------------------------------- @@ -187,7 +187,7 @@ def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: return canonical # --- Import (mutation) ------------------------------------------------------ - def from_dataframe(self, df): # type: ignore[override] + def from_dataframe(self, df): """ Sets the inputs on the scenarios from the packed df (comes from excel) Tolerates optional unit column and leading blank rows. diff --git a/src/pyetm/models/packables/packable.py b/src/pyetm/models/packables/packable.py index a92db2d..074b68e 100644 --- a/src/pyetm/models/packables/packable.py +++ b/src/pyetm/models/packables/packable.py @@ -74,7 +74,7 @@ def build_pack_dataframe(self, columns: str = "", **kwargs) -> pd.DataFrame: df = self._build_dataframe_for_scenario( scenario, columns=columns, **kwargs ) - except Exception as e: # pragma: no cover - defensive + except Exception as e: logger.warning( "Failed building frame for scenario %s in %s: %s", scenario.identifier(), diff --git a/src/pyetm/models/packables/query_pack.py b/src/pyetm/models/packables/query_pack.py index d2c231e..038293c 100644 --- a/src/pyetm/models/packables/query_pack.py +++ b/src/pyetm/models/packables/query_pack.py @@ -10,128 +10,46 @@ class QueryPack(Packable): key: ClassVar[str] = "gquery" - sheet_name: ClassVar[str] = "GQUERIES_RESULTS" + sheet_name: ClassVar[str] = "GQUERIES" + output_sheet_name: ClassVar[str] = "GQUERIES_RESULTS" - def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "future", **kwargs): # type: ignore[override] + def _build_dataframe_for_scenario( + self, scenario: Any, columns: str = "future", **kwargs + ): try: return scenario.results(columns=columns) - except Exception as e: # pragma: no cover - defensive + except Exception as e: logger.warning( "Failed building gquery results for %s: %s", scenario.identifier(), e ) return None - def _to_dataframe(self, columns="future", **kwargs) -> pd.DataFrame: # type: ignore[override] + def _to_dataframe(self, columns="future", **kwargs) -> pd.DataFrame: return self.build_pack_dataframe(columns=columns, **kwargs) - def _normalize_queries_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize a GQUERIES sheet into simple shape. - Restores previous heuristic so we don't drop the first real gquery row when there is only one header row. - Logic: - - Drop fully blank rows/cols. - - Detect if there are 2 header rows (second row contains a helper token like 'gquery', 'key', etc.). - - If only one header row, keep remaining rows as data. - - Return DataFrame with columns = scenario identifiers and rows listing gquery keys (strings). - """ - if df is None: - return pd.DataFrame() - - # Drop completely empty rows/cols - df = df.dropna(how="all") - if df.empty: - return df - df = df.dropna(axis=1, how="all") - - non_empty_rows = [ - i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() - ] - if not non_empty_rows: - return pd.DataFrame() - - helper_tokens = {"gquery", "gqueries", "key", "queries"} - header_rows = 1 - if len(non_empty_rows) > 1: - second = ( - df.iloc[non_empty_rows[1]].astype(str).str.strip().str.lower().tolist() - ) - if any(val in helper_tokens for val in second): - header_rows = 2 - - header_start = non_empty_rows[0] - header_end = header_start + header_rows - 1 - headers = df.iloc[header_start : header_end + 1].astype(str) - data = df.iloc[header_end + 1 :].copy() - - # Assign columns - if header_rows == 2: - cols = pd.MultiIndex.from_arrays( - [headers.iloc[0].values, headers.iloc[1].values] - ) - data.columns = cols - else: - data.columns = pd.Index(headers.iloc[0].values) - - def _is_empty(v): - return ( - (not isinstance(v, str)) - or (v.strip() == "") - or (v.strip().lower() == "nan") - ) - - def _is_helper_label(v): - return isinstance(v, str) and v.strip().lower() in helper_tokens - - if isinstance(data.columns, pd.MultiIndex): - keep = [ - c - for c in data.columns - if not _is_empty(c[0]) and not _is_helper_label(c[0]) - ] - data = data[keep] - data.columns = [c[0] for c in data.columns] - else: - keep = [ - c - for c in data.columns - if isinstance(c, str) and not _is_empty(c) and not _is_helper_label(c) - ] - data = data[keep] - - for c in data.columns: - data[c] = data[c].apply(lambda x: None if pd.isna(x) else str(x).strip()) - data = data.dropna(how="all") - return data - - def from_dataframe(self, df: pd.DataFrame): # type: ignore[override] - if df is None or getattr(df, "empty", False): - return - try: - df = self._normalize_queries_dataframe(df) - except Exception as e: - logger.warning("Failed to normalize gqueries sheet: %s", e) - return + def from_dataframe(self, df: pd.DataFrame): if df is None or df.empty: return - # Here columns are single-level; wrap into a synthetic MultiIndex so we can reuse apply_identifier_blocks - df_multi = df.copy() - df_multi.columns = pd.MultiIndex.from_arrays( - [df_multi.columns, ["gquery_keys"] * len(df_multi.columns)] - ) - - def _apply(scenario, block: pd.DataFrame): - # block is a DataFrame with single column 'gquery_keys' (after collapse) or Series - series = block.iloc[:, 0] if isinstance(block, pd.DataFrame) else block - values = [ - v for v in series.tolist() if isinstance(v, str) and v.strip() != "" - ] - seen = set() - keys = [] - for v in values: - if v not in seen: - seen.add(v) - keys.append(v) - if keys: - scenario.add_queries(keys) - - self.apply_identifier_blocks(df_multi, _apply) + # Get the first column and extract non-empty query strings + first_col = df.iloc[:, 0] + queries = [] + + for value in first_col: + if pd.notna(value): + query = str(value).strip() + if query and query.lower() != "nan": + queries.append(query) + + # Remove duplicates while preserving order + unique_queries = [] + seen = set() + for query in queries: + if query not in seen: + seen.add(query) + unique_queries.append(query) + + if unique_queries: + # Apply the same queries to all scenarios in the pack + for scenario in self.scenarios: + scenario.add_queries(unique_queries) diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 8bbe9a7..4b2b6c4 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -377,88 +377,7 @@ def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": if gq_df is not None and not gq_df.empty: try: qp = QueryPack(scenarios=packer._scenarios()) - norm_gq = qp._normalize_queries_dataframe(gq_df) - if norm_gq is not None and not norm_gq.empty: - # Case 1: single column (global queries for all scenarios) - if len(norm_gq.columns) == 1: - col = norm_gq.columns[0] - values = [ - v - for v in norm_gq[col].tolist() - if isinstance(v, str) and v.strip() - ] - seen = set() - keys = [] - for v in values: - if v not in seen: - seen.add(v) - keys.append(v) - if keys: - for s in packer._scenarios(): - try: - s.add_queries(keys) - except Exception as e: - logger.warning( - "Failed adding global gqueries to '%s': %s", - s.identifier(), - e, - ) - else: - # Multiple columns: attempt identifier match, fallback to short_name - for col in norm_gq.columns: - scenario = next( - ( - s - for s in packer._scenarios() - if str(s.identifier()) == str(col) - ), - None, - ) - if scenario is None: - # fallback: short_name mapping - match_id = next( - ( - sid - for sid, sn in short_name_map.items() - if str(sn) == str(col) - ), - None, - ) - if match_id is not None: - scenario = next( - ( - s - for s in packer._scenarios() - if str(s.id) == str(match_id) - ), - None, - ) - if scenario is None: - logger.warning( - "Could not find scenario for gqueries column '%s' (identifier or short_name)", - col, - ) - continue - values = [ - v - for v in norm_gq[col].tolist() - if isinstance(v, str) and v.strip() - ] - seen = set() - keys = [] - for v in values: - if v not in seen: - seen.add(v) - keys.append(v) - if keys: - try: - scenario.add_queries(keys) - except Exception as e: - logger.warning( - "Failed adding gqueries to '%s': %s", - scenario.identifier(), - e, - ) + qp.from_dataframe(gq_df) except Exception as e: logger.warning("Failed to import GQUERIES: %s", e) From 063e92f8cd2712b5e16e23c7a7d08caebf48f45c Mon Sep 17 00:00:00 2001 From: louispt1 Date: Mon, 11 Aug 2025 12:27:56 +0200 Subject: [PATCH 12/17] Tests for query pack and custom curves pack --- src/pyetm/models/packables/query_pack.py | 19 +- .../packables/test_custom_curves_pack.py | 128 +++++++++ tests/models/packables/test_gquery_pack.py | 85 ++++++ tests/models/packables/test_packable.py | 256 ++++++++++++++++++ 4 files changed, 473 insertions(+), 15 deletions(-) create mode 100644 tests/models/packables/test_custom_curves_pack.py create mode 100644 tests/models/packables/test_gquery_pack.py create mode 100644 tests/models/packables/test_packable.py diff --git a/src/pyetm/models/packables/query_pack.py b/src/pyetm/models/packables/query_pack.py index 038293c..63c8430 100644 --- a/src/pyetm/models/packables/query_pack.py +++ b/src/pyetm/models/packables/query_pack.py @@ -31,25 +31,14 @@ def from_dataframe(self, df: pd.DataFrame): if df is None or df.empty: return - # Get the first column and extract non-empty query strings - first_col = df.iloc[:, 0] - queries = [] + first_col = df.iloc[:, 0].dropna().astype(str).str.strip() - for value in first_col: - if pd.notna(value): - query = str(value).strip() - if query and query.lower() != "nan": - queries.append(query) + # Filter out empty strings and literal "nan" + filtered = [q for q in first_col if q and q.lower() != "nan"] # Remove duplicates while preserving order - unique_queries = [] - seen = set() - for query in queries: - if query not in seen: - seen.add(query) - unique_queries.append(query) + unique_queries = list(dict.fromkeys(filtered)) if unique_queries: - # Apply the same queries to all scenarios in the pack for scenario in self.scenarios: scenario.add_queries(unique_queries) diff --git a/tests/models/packables/test_custom_curves_pack.py b/tests/models/packables/test_custom_curves_pack.py new file mode 100644 index 0000000..786f45c --- /dev/null +++ b/tests/models/packables/test_custom_curves_pack.py @@ -0,0 +1,128 @@ +import pandas as pd +from pyetm.models.packables.custom_curves_pack import CustomCurvesPack + + +class MockScenario: + def __init__(self, id="id1"): + self.id = id + self.curves_updated_with = None + self.custom_series_called = False + + def custom_curves_series(self): + self.custom_series_called = True + return [pd.Series([1, 2, 3], name="curve1")] + + def identifier(self): + return f"scenario-{self.id}" + + def update_custom_curves(self, curves): + self.curves_updated_with = curves + + +class MockCustomCurves: + @staticmethod + def _from_dataframe(df, scenario_id=None): + return {"built_from": df.copy(), "scenario_id": scenario_id} + + +def test_build_dataframe_for_scenario_returns_concatenated_df(monkeypatch): + pack = CustomCurvesPack() + scenario = MockScenario() + + df = pack._build_dataframe_for_scenario(scenario) + assert isinstance(df, pd.DataFrame) + assert "curve1" in df.columns + assert scenario.custom_series_called + + +def test_build_dataframe_for_scenario_returns_none_if_exception(monkeypatch): + pack = CustomCurvesPack() + + def bad_series(): + raise RuntimeError("bad") + + scenario = MockScenario() + scenario.custom_curves_series = bad_series + + result = pack._build_dataframe_for_scenario(scenario) + assert result is None + + +def test_build_dataframe_for_scenario_returns_none_if_empty(monkeypatch): + pack = CustomCurvesPack() + + def empty_series(): + return [] + + scenario = MockScenario() + scenario.custom_curves_series = empty_series + + result = pack._build_dataframe_for_scenario(scenario) + assert result is None + + +def test_normalize_curves_dataframe_calls_helper(monkeypatch): + pack = CustomCurvesPack() + + called_with = {} + + def fake_normalize(df, **kwargs): + called_with.update(kwargs) + return df + + monkeypatch.setattr(pack, "_normalize_two_header_sheet", fake_normalize) + + df = pd.DataFrame({"a": [1, 2]}) + result = pack._normalize_curves_dataframe(df) + + assert result.equals(df) + assert called_with["drop_empty_level0"] + assert called_with["reset_index"] + + +def test_from_dataframe_applies_to_scenarios(monkeypatch): + pack = CustomCurvesPack() + scenario = MockScenario("sc1") + + # Patch normalization to pass-through unchanged + monkeypatch.setattr(pack, "_normalize_curves_dataframe", lambda df: df) + + monkeypatch.setattr( + "pyetm.models.packables.custom_curves_pack.CustomCurves", MockCustomCurves + ) + + arrays = [["sc1", "sc1", "sc2"], ["curve_a", "curve_b", "curve_c"]] + index = pd.MultiIndex.from_arrays(arrays, names=("identifier", "curve_key")) + df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=index) + + # Patch apply_identifier_blocks on the class, since 'from_dataframe' calls on self + def fake_apply(self, df_, func): + block = df_.loc[:, pd.IndexSlice["sc1", ["curve_a", "curve_b"]]] + func(scenario, block) + + monkeypatch.setattr(CustomCurvesPack, "apply_identifier_blocks", fake_apply) + + pack.from_dataframe(df) + + assert isinstance(scenario.curves_updated_with, dict) + assert scenario.curves_updated_with["scenario_id"] == "sc1" + + +def test_from_dataframe_returns_early_for_none_df(): + pack = CustomCurvesPack() + assert pack.from_dataframe(None) is None + + +def test_from_dataframe_returns_early_for_empty_df(): + pack = CustomCurvesPack() + df = pd.DataFrame() + assert pack.from_dataframe(df) is None + + +def test_from_dataframe_returns_early_if_not_multiindex(monkeypatch): + pack = CustomCurvesPack() + + monkeypatch.setattr(pack, "_normalize_curves_dataframe", lambda df: df) + + df = pd.DataFrame({"a": [1, 2]}) + assert pack.from_dataframe(df) is None diff --git a/tests/models/packables/test_gquery_pack.py b/tests/models/packables/test_gquery_pack.py new file mode 100644 index 0000000..f548344 --- /dev/null +++ b/tests/models/packables/test_gquery_pack.py @@ -0,0 +1,85 @@ +import pandas as pd + + +class MockScenario: + def __init__(self): + self.received_queries = None + + def add_queries(self, queries): + self.received_queries = queries + + +class DummyClass: + def __init__(self, scenarios): + self.scenarios = scenarios + + def from_dataframe(self, df: pd.DataFrame): + if df is None or df.empty: + return + + first_col = df.iloc[:, 0].dropna().astype(str).str.strip() + + # Filter out empty strings and literal "nan" + filtered = [q for q in first_col if q and q.lower() != "nan"] + + # Remove duplicates while preserving order + unique_queries = list(dict.fromkeys(filtered)) + + if unique_queries: + for scenario in self.scenarios: + scenario.add_queries(unique_queries) + + +def test_from_dataframe_with_valid_data(): + scenario1 = MockScenario() + scenario2 = MockScenario() + obj = DummyClass([scenario1, scenario2]) + + df = pd.DataFrame({"queries": ["q1", " q2 ", "q1", None, "nan", " "]}) + + obj.from_dataframe(df) + + expected = ["q1", "q2"] + assert scenario1.received_queries == expected + assert scenario2.received_queries == expected + + +def test_from_dataframe_with_empty_df(): + scenario = MockScenario() + obj = DummyClass([scenario]) + + df = pd.DataFrame({"queries": []}) + obj.from_dataframe(df) + + assert scenario.received_queries is None + + +def test_from_dataframe_with_none_df(): + scenario = MockScenario() + obj = DummyClass([scenario]) + + obj.from_dataframe(None) + + assert scenario.received_queries is None + + +def test_from_dataframe_strips_and_deduplicates(): + scenario = MockScenario() + obj = DummyClass([scenario]) + + df = pd.DataFrame({"queries": [" a ", "a", "b", " B ", "nan", "NaN"]}) + + obj.from_dataframe(df) + + assert scenario.received_queries == ["a", "b", "B"] + + +def test_from_dataframe_preserves_order(): + scenario = MockScenario() + obj = DummyClass([scenario]) + + df = pd.DataFrame({"queries": ["x", "y", "z", "x", "y"]}) + + obj.from_dataframe(df) + + assert scenario.received_queries == ["x", "y", "z"] diff --git a/tests/models/packables/test_packable.py b/tests/models/packables/test_packable.py new file mode 100644 index 0000000..4faadfc --- /dev/null +++ b/tests/models/packables/test_packable.py @@ -0,0 +1,256 @@ +import pytest +import pandas as pd +from pyetm.models.packables.packable import Packable + + +class MockScenario: + def __init__(self, id): + self._id = id + + def identifier(self): + return self._id + + +@pytest.fixture +def packable(): + return Packable() + + +def test_add_discard_clear(packable): + s1 = MockScenario("a") + s2 = MockScenario("b") + + packable.add(s1) + assert s1 in packable.scenarios + assert packable._scenario_id_cache is None + + packable.add(s2) + assert s2 in packable.scenarios + + packable.discard(s1) + assert s1 not in packable.scenarios + assert packable._scenario_id_cache is None + + packable.clear() + assert len(packable.scenarios) == 0 + assert packable._scenario_id_cache is None + + +def test_summary(packable): + s1 = MockScenario("id1") + s2 = MockScenario("id2") + packable.add(s1, s2) + summary = packable.summary() + assert "base_pack" in summary + assert summary["base_pack"]["scenario_count"] == 2 + + +def test_key_for_returns_identifier(packable): + s = MockScenario("sc1") + assert packable._key_for(s) == "sc1" + + +def test_build_pack_dataframe_calls_and_concat(monkeypatch, packable): + s1 = MockScenario("sc1") + s2 = MockScenario("sc2") + packable.add(s1, s2) + + # Mock _build_dataframe_for_scenario to return a simple df + def fake_build_df(scenario, **kwargs): + return pd.DataFrame({f"{scenario.identifier()}_col": [1, 2]}) + + monkeypatch.setattr(packable, "_build_dataframe_for_scenario", fake_build_df) + monkeypatch.setattr(packable, "_concat_frames", lambda frames, keys: (frames, keys)) + + frames, keys = packable.build_pack_dataframe() + + assert isinstance(frames[0], pd.DataFrame) + assert keys == ["sc1", "sc2"] or keys == ["sc2", "sc1"] # order not guaranteed + + +def test_build_pack_dataframe_skips_none_empty(monkeypatch, packable): + s = MockScenario("sc") + packable.add(s) + + monkeypatch.setattr(packable, "_build_dataframe_for_scenario", lambda s, **kw: None) + df = packable.build_pack_dataframe() + assert df.empty + + monkeypatch.setattr( + packable, "_build_dataframe_for_scenario", lambda s, **kw: pd.DataFrame() + ) + df = packable.build_pack_dataframe() + assert df.empty + + +def test_build_pack_dataframe_handles_exceptions(monkeypatch, packable): + s = MockScenario("sc") + packable.add(s) + + def raise_exc(scenario, **kwargs): + raise RuntimeError("fail") + + monkeypatch.setattr(packable, "_build_dataframe_for_scenario", raise_exc) + + # Should not raise, just skip scenario + df = packable.build_pack_dataframe() + assert df.empty + + +def test_to_dataframe_returns_empty_if_no_scenarios(monkeypatch, packable): + assert packable.to_dataframe().empty + + monkeypatch.setattr( + packable, "_to_dataframe", lambda **kwargs: pd.DataFrame({"a": [1]}) + ) + packable.add(MockScenario("sc")) + df = packable.to_dataframe() + assert "a" in df.columns + + +def test_refresh_cache_and_find_by_identifier(packable): + s1 = MockScenario("sc1") + s2 = MockScenario("sc2") + packable.add(s1, s2) + + packable._scenario_id_cache = None + packable._refresh_cache() + + assert "sc1" in packable._scenario_id_cache + assert packable._find_by_identifier("sc2") == s2 + assert packable._find_by_identifier("missing") is None + + +def test_resolve_scenario(packable): + s = MockScenario("foo") + packable.add(s) + assert packable.resolve_scenario("foo") == s + assert packable.resolve_scenario(None) is None + assert packable.resolve_scenario("bar") is None + + +def test_is_blank(): + assert Packable.is_blank(None) + assert Packable.is_blank(float("nan")) + assert Packable.is_blank("") + assert Packable.is_blank(" ") + assert not Packable.is_blank("x") + assert not Packable.is_blank(123) + + +def test_drop_all_blank(): + df = pd.DataFrame({"a": [None, None], "b": [None, None]}) + result = Packable.drop_all_blank(df) + assert result.empty + + df2 = pd.DataFrame({"a": [None, 1], "b": [None, 2]}) + result2 = Packable.drop_all_blank(df2) + assert len(result2) == 1 + + +def test_first_non_empty_row_positions(): + df = pd.DataFrame({"a": [None, 1, 2], "b": [None, None, 3]}) + positions = Packable.first_non_empty_row_positions(df, count=2) + assert positions == [1, 2] + + positions = Packable.first_non_empty_row_positions(pd.DataFrame(), count=2) + assert positions == [] + + +def test_apply_identifier_blocks(monkeypatch, packable): + s1 = MockScenario("sc1") + s2 = MockScenario("sc2") + packable.add(s1, s2) + + columns = pd.MultiIndex.from_tuples( + [("sc1", "a"), ("sc1", "b"), ("sc2", "a")], names=["id", "curve"] + ) + df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=columns) + + called = {} + + def apply_block(scenario, block): + called[scenario.identifier()] = block.sum().sum() + + packable.apply_identifier_blocks(df, apply_block) + + assert "sc1" in called + assert "sc2" in called + + # Test with resolve function overriding + def resolve_override(label): + return s1 if label == "sc1" else None + + called.clear() + packable.apply_identifier_blocks(df, apply_block, resolve=resolve_override) + assert "sc1" in called + assert "sc2" in called + + # Test with non-MultiIndex columns + packable.apply_identifier_blocks(pd.DataFrame({"a": [1, 2]}), apply_block) + + +def test_apply_identifier_blocks_logs(monkeypatch, caplog, packable): + s1 = MockScenario("sc1") + packable.add(s1) + + columns = pd.MultiIndex.from_tuples([("sc1", "a")], names=["id", "curve"]) + df = pd.DataFrame([[1]], columns=columns) + + def fail_block(scenario, block): + raise ValueError("fail") + + with caplog.at_level("WARNING"): + packable.apply_identifier_blocks(df, fail_block) + assert "Failed applying block" in caplog.text + + +def test_normalize_two_header_sheet_basic(packable): + df = pd.DataFrame( + [ + ["id1", "id2"], + ["curve1", "curve2"], + [1, 2], + [3, 4], + ] + ) + result = packable._normalize_two_header_sheet(df, reset_index=True) + assert isinstance(result.columns, pd.MultiIndex) + assert result.shape == (2, 2) + assert result.index.equals(pd.RangeIndex(0, 2)) + + +def test_normalize_two_header_sheet_single_header(packable): + df = pd.DataFrame( + [ + ["id1", "id2"], + [1, 2], + [3, 4], + ] + ) + result = packable._normalize_two_header_sheet(df) + assert isinstance(result.columns, pd.MultiIndex) + assert result.shape[0] == 1 or result.shape[0] == 2 + + +def test_normalize_two_header_sheet_with_helpers(packable): + df = pd.DataFrame( + [ + ["helper", "id2"], + ["helpercurve", "curve2"], + [1, 2], + [3, 4], + ] + ) + result = packable._normalize_two_header_sheet( + df, + helper_level0={"helper"}, + helper_level1={"helpercurve"}, + drop_empty_level0=True, + drop_empty_level1=True, + ) + # "helper" and "helpercurve" columns should be removed + for lvl0 in result.columns.get_level_values(0): + assert lvl0.lower() != "helper" + for lvl1 in result.columns.get_level_values(1): + assert lvl1.lower() != "helpercurve" From 5efbd35349b7e7412526cd7185ab250f421472a6 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Mon, 11 Aug 2025 15:02:35 +0200 Subject: [PATCH 13/17] Fix tests for multi-index --- examples/excel_to_scenarios.ipynb | 1175 +------------------ src/pyetm/models/packables/packable.py | 8 +- src/pyetm/models/packables/query_pack.py | 5 +- src/pyetm/models/packables/sortable_pack.py | 22 +- tests/models/test_scenario_packer.py | 22 +- tests/models/test_sortables.py | 8 +- 6 files changed, 38 insertions(+), 1202 deletions(-) diff --git a/examples/excel_to_scenarios.ipynb b/examples/excel_to_scenarios.ipynb index f4c51f7..39935e2 100644 --- a/examples/excel_to_scenarios.ipynb +++ b/examples/excel_to_scenarios.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "4866f9d1", "metadata": {}, "outputs": [ @@ -33,165 +33,6 @@ "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:206: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", " self.update_user_values(series.fillna(\"reset\").to_dict())\n" ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'total_scenarios': 2, 'inputs': {'scenario_count': 2}, 'sortables': {'scenario_count': 2}, 'custom_curves': {'scenario_count': 2}, 'output_curves': {'scenario_count': 2}, 'scenario_ids': [2690555, 2690623]}\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
B: Load a scenario by idA: Create from excel
useruser
inputunit
climate_relevant_co2_biomass_gas_future%35.030.0
climate_relevant_co2_biomass_gas_present%None20.0
climate_relevant_co2_biomass_liquid_future%None30.0
climate_relevant_co2_biomass_liquid_present%None20.0
climate_relevant_co2_biomass_solid_future%None30.0
............
capacity_of_energy_battery_wind_turbine_inlandMW0.0NaN
capacity_of_energy_power_hybrid_wind_turbine_offshoreMWNoneNaN
capacity_of_energy_power_wind_turbine_coastalMW0.0NaN
capacity_of_energy_power_wind_turbine_inlandMW20000.0NaN
capacity_of_energy_power_wind_turbine_offshoreMW52000.0NaN
\n", - "

1318 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " B: Load a scenario by id \\\n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 35.0 \n", - "climate_relevant_co2_biomass_gas_present % None \n", - "climate_relevant_co2_biomass_liquid_future % None \n", - "climate_relevant_co2_biomass_liquid_present % None \n", - "climate_relevant_co2_biomass_solid_future % None \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW 0.0 \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW None \n", - "capacity_of_energy_power_wind_turbine_coastal MW 0.0 \n", - "capacity_of_energy_power_wind_turbine_inland MW 20000.0 \n", - "capacity_of_energy_power_wind_turbine_offshore MW 52000.0 \n", - "\n", - " A: Create from excel \n", - " user \n", - "input unit \n", - "climate_relevant_co2_biomass_gas_future % 30.0 \n", - "climate_relevant_co2_biomass_gas_present % 20.0 \n", - "climate_relevant_co2_biomass_liquid_future % 30.0 \n", - "climate_relevant_co2_biomass_liquid_present % 20.0 \n", - "climate_relevant_co2_biomass_solid_future % 30.0 \n", - "... ... \n", - "capacity_of_energy_battery_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN \n", - "capacity_of_energy_power_wind_turbine_coastal MW NaN \n", - "capacity_of_energy_power_wind_turbine_inland MW NaN \n", - "capacity_of_energy_power_wind_turbine_offshore MW NaN \n", - "\n", - "[1318 rows x 2 columns]" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ @@ -208,1030 +49,30 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "cd08ff26", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
B: Load a scenario by idA: Create from excel
forecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_htforecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_ht
sortables
0energy_flexibility_pumped_storage_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_waterhouseholds_flexibility_p2p_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_water
1transport_van_flexibility_p2p_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricityenergy_flexibility_mv_batteries_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricity
2transport_truck_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coaltransport_car_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coal
3transport_bus_flexibility_p2p_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oilenergy_flexibility_flow_batteries_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oil
4energy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogenenergy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogen
5energy_flexibility_flow_batteries_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gastransport_bus_flexibility_p2p_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gas
6transport_car_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mixtransport_truck_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mix
7energy_flexibility_mv_batteries_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pelletstransport_van_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pellets
8households_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricityenergy_flexibility_pumped_storage_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricity
9NoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...NoneNoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...None
10NoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...None
11NoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...None
12NoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNoneNoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNone
13NoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNoneNoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNone
14NoneNoneNonehouseholds_space_heater_network_gasNoneNoneNoneNoneNoneNonehouseholds_space_heater_network_gasNoneNoneNone
15NoneNoneNonehouseholds_space_heater_coalNoneNoneNoneNoneNoneNonehouseholds_space_heater_coalNoneNoneNone
16NoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNoneNoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNone
\n", - "
" - ], - "text/plain": [ - " B: Load a scenario by id \\\n", - " forecast_storage \n", - "sortables \n", - "0 energy_flexibility_pumped_storage_electricity \n", - "1 transport_van_flexibility_p2p_electricity \n", - "2 transport_truck_flexibility_p2p_electricity \n", - "3 transport_bus_flexibility_p2p_electricity \n", - "4 energy_flexibility_hv_opac_electricity \n", - "5 energy_flexibility_flow_batteries_electricity \n", - "6 transport_car_flexibility_p2p_electricity \n", - "7 energy_flexibility_mv_batteries_electricity \n", - "8 households_flexibility_p2p_electricity \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " hydrogen_supply \n", - "sortables \n", - "0 energy_hydrogen_storage_depleted_gas_field \n", - "1 energy_hydrogen_storage_salt_cavern \n", - "2 energy_hydrogen_autothermal_reformer_dispatchable \n", - "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", - "4 energy_hydrogen_ammonia_reformer_dispatchable \n", - "5 None \n", - "6 None \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " hydrogen_demand \n", - "sortables \n", - "0 energy_hydrogen_storage_depleted_gas_field \n", - "1 energy_hydrogen_storage_salt_cavern \n", - "2 None \n", - "3 None \n", - "4 None \n", - "5 None \n", - "6 None \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " space_heating \n", - "sortables \n", - "0 households_space_heater_district_heating_lt_st... \n", - "1 households_space_heater_heatpump_surface_water... \n", - "2 households_space_heater_heatpump_air_water_ele... \n", - "3 households_space_heater_heatpump_ground_water_... \n", - "4 households_space_heater_heatpump_pvt_electricity \n", - "5 households_space_heater_district_heating_mt_st... \n", - "6 households_space_heater_hybrid_heatpump_air_wa... \n", - "7 households_space_heater_hybrid_hydrogen_heatpu... \n", - "8 households_space_heater_hybrid_crude_oil_heatp... \n", - "9 households_space_heater_district_heating_ht_st... \n", - "10 households_space_heater_electricity \n", - "11 households_space_heater_combined_network_gas \n", - "12 households_space_heater_combined_hydrogen \n", - "13 households_space_heater_wood_pellets \n", - "14 households_space_heater_network_gas \n", - "15 households_space_heater_coal \n", - "16 households_space_heater_crude_oil \n", - "\n", - " \\\n", - " heat_network_lt \n", - "sortables \n", - "0 energy_heat_network_storage_lt_steam_hot_water \n", - "1 energy_heat_boiler_lt_electricity \n", - "2 energy_heat_burner_lt_hydrogen \n", - "3 energy_heat_heatpump_water_water_lt_electricity \n", - "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", - "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", - "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " heat_network_mt \n", - "sortables \n", - "0 energy_heat_network_storage_mt_steam_hot_water \n", - "1 energy_heat_boiler_mt_electricity \n", - "2 energy_heat_burner_mt_coal \n", - "3 energy_heat_burner_mt_crude_oil \n", - "4 energy_heat_burner_mt_hydrogen \n", - "5 energy_heat_burner_mt_network_gas \n", - "6 energy_heat_burner_mt_waste_mix \n", - "7 energy_heat_burner_mt_wood_pellets \n", - "8 energy_heat_heatpump_water_water_mt_electricity \n", - "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", - "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", - "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " heat_network_ht \n", - "sortables \n", - "0 energy_heat_network_storage_ht_steam_hot_water \n", - "1 energy_heat_boiler_ht_electricity \n", - "2 energy_heat_burner_ht_coal \n", - "3 energy_heat_burner_ht_crude_oil \n", - "4 energy_heat_burner_ht_hydrogen \n", - "5 energy_heat_burner_ht_network_gas \n", - "6 energy_heat_burner_ht_waste_mix \n", - "7 energy_heat_burner_ht_wood_pellets \n", - "8 energy_heat_heatpump_water_water_ht_electricity \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " A: Create from excel \\\n", - " forecast_storage \n", - "sortables \n", - "0 households_flexibility_p2p_electricity \n", - "1 energy_flexibility_mv_batteries_electricity \n", - "2 transport_car_flexibility_p2p_electricity \n", - "3 energy_flexibility_flow_batteries_electricity \n", - "4 energy_flexibility_hv_opac_electricity \n", - "5 transport_bus_flexibility_p2p_electricity \n", - "6 transport_truck_flexibility_p2p_electricity \n", - "7 transport_van_flexibility_p2p_electricity \n", - "8 energy_flexibility_pumped_storage_electricity \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " hydrogen_supply \n", - "sortables \n", - "0 energy_hydrogen_storage_depleted_gas_field \n", - "1 energy_hydrogen_storage_salt_cavern \n", - "2 energy_hydrogen_autothermal_reformer_dispatchable \n", - "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", - "4 energy_hydrogen_ammonia_reformer_dispatchable \n", - "5 None \n", - "6 None \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " hydrogen_demand \n", - "sortables \n", - "0 energy_hydrogen_storage_depleted_gas_field \n", - "1 energy_hydrogen_storage_salt_cavern \n", - "2 None \n", - "3 None \n", - "4 None \n", - "5 None \n", - "6 None \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " space_heating \n", - "sortables \n", - "0 households_space_heater_district_heating_lt_st... \n", - "1 households_space_heater_heatpump_surface_water... \n", - "2 households_space_heater_heatpump_air_water_ele... \n", - "3 households_space_heater_heatpump_ground_water_... \n", - "4 households_space_heater_heatpump_pvt_electricity \n", - "5 households_space_heater_district_heating_mt_st... \n", - "6 households_space_heater_hybrid_heatpump_air_wa... \n", - "7 households_space_heater_hybrid_hydrogen_heatpu... \n", - "8 households_space_heater_hybrid_crude_oil_heatp... \n", - "9 households_space_heater_district_heating_ht_st... \n", - "10 households_space_heater_electricity \n", - "11 households_space_heater_combined_network_gas \n", - "12 households_space_heater_combined_hydrogen \n", - "13 households_space_heater_wood_pellets \n", - "14 households_space_heater_network_gas \n", - "15 households_space_heater_coal \n", - "16 households_space_heater_crude_oil \n", - "\n", - " \\\n", - " heat_network_lt \n", - "sortables \n", - "0 energy_heat_network_storage_lt_steam_hot_water \n", - "1 energy_heat_boiler_lt_electricity \n", - "2 energy_heat_burner_lt_hydrogen \n", - "3 energy_heat_heatpump_water_water_lt_electricity \n", - "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", - "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", - "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", - "7 None \n", - "8 None \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \\\n", - " heat_network_mt \n", - "sortables \n", - "0 energy_heat_network_storage_mt_steam_hot_water \n", - "1 energy_heat_boiler_mt_electricity \n", - "2 energy_heat_burner_mt_coal \n", - "3 energy_heat_burner_mt_crude_oil \n", - "4 energy_heat_burner_mt_hydrogen \n", - "5 energy_heat_burner_mt_network_gas \n", - "6 energy_heat_burner_mt_waste_mix \n", - "7 energy_heat_burner_mt_wood_pellets \n", - "8 energy_heat_heatpump_water_water_mt_electricity \n", - "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", - "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", - "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None \n", - "\n", - " \n", - " heat_network_ht \n", - "sortables \n", - "0 energy_heat_network_storage_ht_steam_hot_water \n", - "1 energy_heat_boiler_ht_electricity \n", - "2 energy_heat_burner_ht_coal \n", - "3 energy_heat_burner_ht_crude_oil \n", - "4 energy_heat_burner_ht_hydrogen \n", - "5 energy_heat_burner_ht_network_gas \n", - "6 energy_heat_burner_ht_waste_mix \n", - "7 energy_heat_burner_ht_wood_pellets \n", - "8 energy_heat_heatpump_water_water_ht_electricity \n", - "9 None \n", - "10 None \n", - "11 None \n", - "12 None \n", - "13 None \n", - "14 None \n", - "15 None \n", - "16 None " - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "packer.sortables()" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "0d3e771e", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
B: Load a scenario by idA: Create from excel
interconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_priceinterconnector_3_import_availabilityinterconnector_3_export_availabilityinterconnector_4_price...weather/wind_offshore_baselineweather/wind_coastal_baselineweather/wind_inland_baselineinterconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_price
09.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.026.001.01.00.01
19.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.026.001.01.00.00
29.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.014.481.01.00.00
39.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.00.011.00.00.00
49.09.09.09.09.09.09.09.09.09.0...9.09.09.00.011.00.00.021.00.00.00
\n", - "

5 rows × 52 columns

\n", - "
" - ], - "text/plain": [ - " B: Load a scenario by id \\\n", - " interconnector_1_price interconnector_1_import_availability \n", - "0 9.0 9.0 \n", - "1 9.0 9.0 \n", - "2 9.0 9.0 \n", - "3 9.0 9.0 \n", - "4 9.0 9.0 \n", - "\n", - " \\\n", - " interconnector_1_export_availability interconnector_2_price \n", - "0 9.0 9.0 \n", - "1 9.0 9.0 \n", - "2 9.0 9.0 \n", - "3 9.0 9.0 \n", - "4 9.0 9.0 \n", - "\n", - " \\\n", - " interconnector_2_import_availability interconnector_2_export_availability \n", - "0 9.0 9.0 \n", - "1 9.0 9.0 \n", - "2 9.0 9.0 \n", - "3 9.0 9.0 \n", - "4 9.0 9.0 \n", - "\n", - " \\\n", - " interconnector_3_price interconnector_3_import_availability \n", - "0 9.0 9.0 \n", - "1 9.0 9.0 \n", - "2 9.0 9.0 \n", - "3 9.0 9.0 \n", - "4 9.0 9.0 \n", - "\n", - " ... \\\n", - " interconnector_3_export_availability interconnector_4_price ... \n", - "0 9.0 9.0 ... \n", - "1 9.0 9.0 ... \n", - "2 9.0 9.0 ... \n", - "3 9.0 9.0 ... \n", - "4 9.0 9.0 ... \n", - "\n", - " \\\n", - " weather/wind_offshore_baseline weather/wind_coastal_baseline \n", - "0 9.0 9.0 \n", - "1 9.0 9.0 \n", - "2 9.0 9.0 \n", - "3 9.0 9.0 \n", - "4 9.0 9.0 \n", - "\n", - " A: Create from excel \\\n", - " weather/wind_inland_baseline interconnector_1_price \n", - "0 9.0 0.01 \n", - "1 9.0 0.01 \n", - "2 9.0 0.01 \n", - "3 9.0 0.01 \n", - "4 9.0 0.01 \n", - "\n", - " \\\n", - " interconnector_1_import_availability interconnector_1_export_availability \n", - "0 1.0 0.0 \n", - "1 1.0 0.0 \n", - "2 1.0 0.0 \n", - "3 1.0 0.0 \n", - "4 1.0 0.0 \n", - "\n", - " \\\n", - " interconnector_2_price interconnector_2_import_availability \n", - "0 26.00 1.0 \n", - "1 26.00 1.0 \n", - "2 14.48 1.0 \n", - "3 0.01 1.0 \n", - "4 0.02 1.0 \n", - "\n", - " \n", - " interconnector_2_export_availability interconnector_3_price \n", - "0 1.0 0.01 \n", - "1 1.0 0.00 \n", - "2 1.0 0.00 \n", - "3 0.0 0.00 \n", - "4 0.0 0.00 \n", - "\n", - "[5 rows x 52 columns]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "packer.custom_curves().head()" + "packer.custom_curves()" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "54cc3f61", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
B: Load a scenario by idA: Create from excel
futurefuture
gqueryunit
dashboard_co2_emissions_versus_start_yearfactor-0.9970370.028299
dashboard_total_costsbln_euro56.4630339.300293
\n", - "
" - ], - "text/plain": [ - " B: Load a scenario by id \\\n", - " future \n", - "gquery unit \n", - "dashboard_co2_emissions_versus_start_year factor -0.997037 \n", - "dashboard_total_costs bln_euro 56.46303 \n", - "\n", - " A: Create from excel \n", - " future \n", - "gquery unit \n", - "dashboard_co2_emissions_versus_start_year factor 0.028299 \n", - "dashboard_total_costs bln_euro 39.300293 " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "packer.gquery_results()" ] diff --git a/src/pyetm/models/packables/packable.py b/src/pyetm/models/packables/packable.py index 074b68e..e154f37 100644 --- a/src/pyetm/models/packables/packable.py +++ b/src/pyetm/models/packables/packable.py @@ -95,10 +95,10 @@ def to_dataframe(self, columns="") -> pd.DataFrame: return pd.DataFrame() return self._to_dataframe(columns=columns) - def from_dataframe(self, df): # pragma: no cover - abstract hook + def from_dataframe(self, df): """Should parse the df and call correct setters on identified scenarios""" - def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: # pragma: no cover + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: """Base implementation - kids should implement this or use build_pack_dataframe""" return pd.DataFrame() @@ -148,7 +148,7 @@ def first_non_empty_row_positions(df: pd.DataFrame, count: int = 2) -> list[int] break return positions - def _log_fail(self, context: str, exc: Exception): # pragma: no cover - helper + def _log_fail(self, context: str, exc: Exception): logger.warning("%s failed in %s: %s", context, self.__class__.__name__, exc) def apply_identifier_blocks( @@ -177,7 +177,7 @@ def apply_identifier_blocks( block = df[identifier] try: apply_block(scenario, block) - except Exception as e: # pragma: no cover + except Exception as e: logger.warning( "Failed applying block for scenario '%s' in %s: %s", identifier, diff --git a/src/pyetm/models/packables/query_pack.py b/src/pyetm/models/packables/query_pack.py index 63c8430..608e6eb 100644 --- a/src/pyetm/models/packables/query_pack.py +++ b/src/pyetm/models/packables/query_pack.py @@ -32,13 +32,10 @@ def from_dataframe(self, df: pd.DataFrame): return first_col = df.iloc[:, 0].dropna().astype(str).str.strip() - - # Filter out empty strings and literal "nan" filtered = [q for q in first_col if q and q.lower() != "nan"] - - # Remove duplicates while preserving order unique_queries = list(dict.fromkeys(filtered)) + # Apply unique queries to all scenarios if unique_queries: for scenario in self.scenarios: scenario.add_queries(unique_queries) diff --git a/src/pyetm/models/packables/sortable_pack.py b/src/pyetm/models/packables/sortable_pack.py index 300cfe0..c95e9d6 100644 --- a/src/pyetm/models/packables/sortable_pack.py +++ b/src/pyetm/models/packables/sortable_pack.py @@ -1,8 +1,6 @@ import logging from typing import ClassVar, Any - import pandas as pd - from pyetm.models.packables.packable import Packable logger = logging.getLogger(__name__) @@ -12,36 +10,29 @@ class SortablePack(Packable): key: ClassVar[str] = "sortables" sheet_name: ClassVar[str] = "SORTABLES" - def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): # type: ignore[override] + def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): try: df = scenario.sortables.to_dataframe() - except Exception as e: # pragma: no cover + except Exception as e: logger.warning( "Failed extracting sortables for %s: %s", scenario.identifier(), e ) return None return df if not df.empty else None - def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: # type: ignore[override] + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: return self.build_pack_dataframe(columns=columns, **kwargs) def _normalize_sortables_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize various sortables sheet shapes using generic helper. - Produces DataFrame with columns MultiIndex(identifier, sortable_name) then - collapses to MultiIndex for downstream block iteration. - """ + """Normalize various sortables sheet shapes""" data = self._normalize_two_header_sheet( df, - helper_level0=set(), # no explicit helper labels on level0 expected + helper_level0=set(), helper_level1={"sortables"}, drop_empty_level0=True, - collapse_level0=False, # keep two levels for clarity; we will collapse in from_dataframe if needed + collapse_level0=False, reset_index=False, ) - if data.empty: - return data - # For parity with previous logic we want identifiers as level0 only when applying - # but we still need a MultiIndex for apply_identifier_blocks; keep as-is. return data def from_dataframe(self, df: pd.DataFrame): @@ -57,7 +48,6 @@ def from_dataframe(self, df: pd.DataFrame): return def _apply(scenario, block: pd.DataFrame): - # Collapse block columns (identifier, sortable_name) -> keep only sortable_name part if isinstance(block.columns, pd.MultiIndex): block.columns = [c[1] for c in block.columns] scenario.set_sortables_from_dataframe(block) diff --git a/tests/models/test_scenario_packer.py b/tests/models/test_scenario_packer.py index 949eb1e..bee44e2 100644 --- a/tests/models/test_scenario_packer.py +++ b/tests/models/test_scenario_packer.py @@ -369,11 +369,16 @@ def test_custom_curves_with_series(self, sample_scenario): packer = ScenarioPacker() packer.add_custom_curves(sample_scenario) - result = packer.custom_curves() + assert not result.empty - assert "curve1" in result.columns - assert "curve2" in result.columns + if isinstance(result.columns, pd.MultiIndex): + level_1 = result.columns.get_level_values(1) + assert "curve1" in level_1 + assert "curve2" in level_1 + else: + assert "curve1" in result.columns + assert "curve2" in result.columns def test_output_curves_empty(self): """Test output_curves with no scenarios""" @@ -391,8 +396,12 @@ def test_output_curves_with_series(self, sample_scenario): packer = ScenarioPacker() packer.add_output_curves(sample_scenario) result = packer.output_curves() + assert not result.empty - assert "output_curve" in result.columns + if isinstance(result.columns, pd.MultiIndex): + assert "output_curve" in result.columns.get_level_values(1) + else: + assert "output_curve" in result.columns class TestExcelExport: @@ -572,8 +581,7 @@ def test_get_summary_with_data(self, multiple_scenarios): assert len(summary["scenario_ids"]) == 3 assert all(s.id in summary["scenario_ids"] for s in multiple_scenarios) + class TestFromExcel: def test_from_excel(self): - ScenarioPacker.from_excel('tests/fixtures/my_input_excel.xlsx') - - + ScenarioPacker.from_excel("tests/fixtures/my_input_excel.xlsx") diff --git a/tests/models/test_sortables.py b/tests/models/test_sortables.py index 21f399f..0e0d77d 100644 --- a/tests/models/test_sortables.py +++ b/tests/models/test_sortables.py @@ -200,7 +200,7 @@ def test_validation_duplicate_order_items(): def test_validation_order_too_long(): """Test that orders with too many items generate warnings""" - long_order = list(range(15)) # More than 10 items + long_order = list(range(20)) # More than 17 items payload = ("forecast_storage", long_order) result = list(Sortable.from_json(payload)) @@ -213,7 +213,7 @@ def test_validation_order_too_long(): assert len(sortable.warnings) > 0 all_warnings = [w.message for w in sortable.warnings] warning_text = " ".join(all_warnings) - assert "more than 10 items" in warning_text + assert "more than 17 items" in warning_text @pytest.mark.parametrize( @@ -265,11 +265,11 @@ def test_sortable_is_valid_update(): assert "duplicate" in warning_text.lower() # Invalid update - too long - warnings = sortable.is_valid_update(list(range(15))) + warnings = sortable.is_valid_update(list(range(18))) assert len(warnings) > 0 all_warnings = [w.message for w in warnings] warning_text = " ".join(all_warnings) - assert "more than 10 items" in warning_text + assert "more than 17 items" in warning_text def test_name_method(): From f609e6b88878e2b7763f881068d93d7cb00299c1 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Mon, 11 Aug 2025 15:26:36 +0200 Subject: [PATCH 14/17] Simplifying normalisation --- examples/excel_to_scenarios.ipynb | 1392 ++++++++++++++++- .../models/packables/custom_curves_pack.py | 27 +- src/pyetm/models/packables/inputs_pack.py | 152 +- .../models/packables/output_curves_pack.py | 6 +- src/pyetm/models/packables/packable.py | 89 +- src/pyetm/models/packables/sortable_pack.py | 21 +- .../packables/test_custom_curves_pack.py | 19 - tests/models/packables/test_packable.py | 51 +- 8 files changed, 1492 insertions(+), 265 deletions(-) diff --git a/examples/excel_to_scenarios.ipynb b/examples/excel_to_scenarios.ipynb index 39935e2..20e681b 100644 --- a/examples/excel_to_scenarios.ipynb +++ b/examples/excel_to_scenarios.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "4866f9d1", "metadata": {}, "outputs": [ @@ -33,46 +33,1418 @@ "/Users/louisparkes-talbot/Desktop/local_model/pyetm/src/pyetm/models/scenario.py:206: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", " self.update_user_values(series.fillna(\"reset\").to_dict())\n" ] + }, + { + "data": { + "text/plain": [ + "{'total_scenarios': 2,\n", + " 'inputs': {'scenario_count': 2},\n", + " 'sortables': {'scenario_count': 2},\n", + " 'custom_curves': {'scenario_count': 2},\n", + " 'output_curves': {'scenario_count': 2},\n", + " 'scenario_ids': [2690555, 2690637]}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "from example_helpers import setup_notebook\n", "from pyetm.models.scenario_packer import ScenarioPacker\n", "\n", - "\n", "setup_notebook()\n", "packer = ScenarioPacker.from_excel(\"my_input_excel.xlsx\")\n", - "summary = packer.get_summary()\n", - "print(summary)\n", + "packer.get_summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "8205cd53", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
scen_ascen_b
useruser
inputunit
climate_relevant_co2_biomass_gas_future%30.035.0
climate_relevant_co2_biomass_gas_present%20.0None
climate_relevant_co2_biomass_liquid_future%30.0None
climate_relevant_co2_biomass_liquid_present%20.0None
climate_relevant_co2_biomass_solid_future%30.0None
............
capacity_of_energy_battery_wind_turbine_inlandMWNaN0.0
capacity_of_energy_power_hybrid_wind_turbine_offshoreMWNaNNone
capacity_of_energy_power_wind_turbine_coastalMWNaN0.0
capacity_of_energy_power_wind_turbine_inlandMWNaN20000.0
capacity_of_energy_power_wind_turbine_offshoreMWNaN52000.0
\n", + "

1318 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " scen_a scen_b\n", + " user user\n", + "input unit \n", + "climate_relevant_co2_biomass_gas_future % 30.0 35.0\n", + "climate_relevant_co2_biomass_gas_present % 20.0 None\n", + "climate_relevant_co2_biomass_liquid_future % 30.0 None\n", + "climate_relevant_co2_biomass_liquid_present % 20.0 None\n", + "climate_relevant_co2_biomass_solid_future % 30.0 None\n", + "... ... ...\n", + "capacity_of_energy_battery_wind_turbine_inland MW NaN 0.0\n", + "capacity_of_energy_power_hybrid_wind_turbine_of... MW NaN None\n", + "capacity_of_energy_power_wind_turbine_coastal MW NaN 0.0\n", + "capacity_of_energy_power_wind_turbine_inland MW NaN 20000.0\n", + "capacity_of_energy_power_wind_turbine_offshore MW NaN 52000.0\n", + "\n", + "[1318 rows x 2 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ "packer.inputs()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "cd08ff26", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
A: Create from excelB: Load a scenario by id
forecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_htforecast_storagehydrogen_supplyhydrogen_demandspace_heatingheat_network_ltheat_network_mtheat_network_ht
sortables
0households_flexibility_p2p_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_waterenergy_flexibility_pumped_storage_electricityenergy_hydrogen_storage_depleted_gas_fieldenergy_hydrogen_storage_depleted_gas_fieldhouseholds_space_heater_district_heating_lt_st...energy_heat_network_storage_lt_steam_hot_waterenergy_heat_network_storage_mt_steam_hot_waterenergy_heat_network_storage_ht_steam_hot_water
1energy_flexibility_mv_batteries_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricitytransport_van_flexibility_p2p_electricityenergy_hydrogen_storage_salt_cavernenergy_hydrogen_storage_salt_cavernhouseholds_space_heater_heatpump_surface_water...energy_heat_boiler_lt_electricityenergy_heat_boiler_mt_electricityenergy_heat_boiler_ht_electricity
2transport_car_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coaltransport_truck_flexibility_p2p_electricityenergy_hydrogen_autothermal_reformer_dispatchableNonehouseholds_space_heater_heatpump_air_water_ele...energy_heat_burner_lt_hydrogenenergy_heat_burner_mt_coalenergy_heat_burner_ht_coal
3energy_flexibility_flow_batteries_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oiltransport_bus_flexibility_p2p_electricityenergy_hydrogen_steam_methane_reformer_dispatc...Nonehouseholds_space_heater_heatpump_ground_water_...energy_heat_heatpump_water_water_lt_electricityenergy_heat_burner_mt_crude_oilenergy_heat_burner_ht_crude_oil
4energy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogenenergy_flexibility_hv_opac_electricityenergy_hydrogen_ammonia_reformer_dispatchableNonehouseholds_space_heater_heatpump_pvt_electricityenergy_heat_heatpump_surface_water_water_ts_lt...energy_heat_burner_mt_hydrogenenergy_heat_burner_ht_hydrogen
5transport_bus_flexibility_p2p_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gasenergy_flexibility_flow_batteries_electricityNoneNonehouseholds_space_heater_district_heating_mt_st...energy_heat_heatpump_waste_water_water_ts_lt_e...energy_heat_burner_mt_network_gasenergy_heat_burner_ht_network_gas
6transport_truck_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mixtransport_car_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_heatpump_air_wa...energy_heat_heatpump_drink_water_water_ts_lt_e...energy_heat_burner_mt_waste_mixenergy_heat_burner_ht_waste_mix
7transport_van_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pelletsenergy_flexibility_mv_batteries_electricityNoneNonehouseholds_space_heater_hybrid_hydrogen_heatpu...Noneenergy_heat_burner_mt_wood_pelletsenergy_heat_burner_ht_wood_pellets
8energy_flexibility_pumped_storage_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricityhouseholds_flexibility_p2p_electricityNoneNonehouseholds_space_heater_hybrid_crude_oil_heatp...Noneenergy_heat_heatpump_water_water_mt_electricityenergy_heat_heatpump_water_water_ht_electricity
9NoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...NoneNoneNoneNonehouseholds_space_heater_district_heating_ht_st...Noneenergy_heat_heatpump_surface_water_water_ts_mt...None
10NoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_electricityNoneenergy_heat_heatpump_waste_water_water_ts_mt_e...None
11NoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...NoneNoneNoneNonehouseholds_space_heater_combined_network_gasNoneenergy_heat_heatpump_drink_water_water_ts_mt_e...None
12NoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNoneNoneNoneNonehouseholds_space_heater_combined_hydrogenNoneNoneNone
13NoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNoneNoneNoneNonehouseholds_space_heater_wood_pelletsNoneNoneNone
14NoneNoneNonehouseholds_space_heater_network_gasNoneNoneNoneNoneNoneNonehouseholds_space_heater_network_gasNoneNoneNone
15NoneNoneNonehouseholds_space_heater_coalNoneNoneNoneNoneNoneNonehouseholds_space_heater_coalNoneNoneNone
16NoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNoneNoneNoneNonehouseholds_space_heater_crude_oilNoneNoneNone
\n", + "
" + ], + "text/plain": [ + " A: Create from excel \\\n", + " forecast_storage \n", + "sortables \n", + "0 households_flexibility_p2p_electricity \n", + "1 energy_flexibility_mv_batteries_electricity \n", + "2 transport_car_flexibility_p2p_electricity \n", + "3 energy_flexibility_flow_batteries_electricity \n", + "4 energy_flexibility_hv_opac_electricity \n", + "5 transport_bus_flexibility_p2p_electricity \n", + "6 transport_truck_flexibility_p2p_electricity \n", + "7 transport_van_flexibility_p2p_electricity \n", + "8 energy_flexibility_pumped_storage_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_supply \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 energy_hydrogen_autothermal_reformer_dispatchable \n", + "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", + "4 energy_hydrogen_ammonia_reformer_dispatchable \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_demand \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 None \n", + "3 None \n", + "4 None \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " space_heating \n", + "sortables \n", + "0 households_space_heater_district_heating_lt_st... \n", + "1 households_space_heater_heatpump_surface_water... \n", + "2 households_space_heater_heatpump_air_water_ele... \n", + "3 households_space_heater_heatpump_ground_water_... \n", + "4 households_space_heater_heatpump_pvt_electricity \n", + "5 households_space_heater_district_heating_mt_st... \n", + "6 households_space_heater_hybrid_heatpump_air_wa... \n", + "7 households_space_heater_hybrid_hydrogen_heatpu... \n", + "8 households_space_heater_hybrid_crude_oil_heatp... \n", + "9 households_space_heater_district_heating_ht_st... \n", + "10 households_space_heater_electricity \n", + "11 households_space_heater_combined_network_gas \n", + "12 households_space_heater_combined_hydrogen \n", + "13 households_space_heater_wood_pellets \n", + "14 households_space_heater_network_gas \n", + "15 households_space_heater_coal \n", + "16 households_space_heater_crude_oil \n", + "\n", + " \\\n", + " heat_network_lt \n", + "sortables \n", + "0 energy_heat_network_storage_lt_steam_hot_water \n", + "1 energy_heat_boiler_lt_electricity \n", + "2 energy_heat_burner_lt_hydrogen \n", + "3 energy_heat_heatpump_water_water_lt_electricity \n", + "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", + "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", + "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_mt \n", + "sortables \n", + "0 energy_heat_network_storage_mt_steam_hot_water \n", + "1 energy_heat_boiler_mt_electricity \n", + "2 energy_heat_burner_mt_coal \n", + "3 energy_heat_burner_mt_crude_oil \n", + "4 energy_heat_burner_mt_hydrogen \n", + "5 energy_heat_burner_mt_network_gas \n", + "6 energy_heat_burner_mt_waste_mix \n", + "7 energy_heat_burner_mt_wood_pellets \n", + "8 energy_heat_heatpump_water_water_mt_electricity \n", + "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", + "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", + "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_ht \n", + "sortables \n", + "0 energy_heat_network_storage_ht_steam_hot_water \n", + "1 energy_heat_boiler_ht_electricity \n", + "2 energy_heat_burner_ht_coal \n", + "3 energy_heat_burner_ht_crude_oil \n", + "4 energy_heat_burner_ht_hydrogen \n", + "5 energy_heat_burner_ht_network_gas \n", + "6 energy_heat_burner_ht_waste_mix \n", + "7 energy_heat_burner_ht_wood_pellets \n", + "8 energy_heat_heatpump_water_water_ht_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " B: Load a scenario by id \\\n", + " forecast_storage \n", + "sortables \n", + "0 energy_flexibility_pumped_storage_electricity \n", + "1 transport_van_flexibility_p2p_electricity \n", + "2 transport_truck_flexibility_p2p_electricity \n", + "3 transport_bus_flexibility_p2p_electricity \n", + "4 energy_flexibility_hv_opac_electricity \n", + "5 energy_flexibility_flow_batteries_electricity \n", + "6 transport_car_flexibility_p2p_electricity \n", + "7 energy_flexibility_mv_batteries_electricity \n", + "8 households_flexibility_p2p_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_supply \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 energy_hydrogen_autothermal_reformer_dispatchable \n", + "3 energy_hydrogen_steam_methane_reformer_dispatc... \n", + "4 energy_hydrogen_ammonia_reformer_dispatchable \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " hydrogen_demand \n", + "sortables \n", + "0 energy_hydrogen_storage_depleted_gas_field \n", + "1 energy_hydrogen_storage_salt_cavern \n", + "2 None \n", + "3 None \n", + "4 None \n", + "5 None \n", + "6 None \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " space_heating \n", + "sortables \n", + "0 households_space_heater_district_heating_lt_st... \n", + "1 households_space_heater_heatpump_surface_water... \n", + "2 households_space_heater_heatpump_air_water_ele... \n", + "3 households_space_heater_heatpump_ground_water_... \n", + "4 households_space_heater_heatpump_pvt_electricity \n", + "5 households_space_heater_district_heating_mt_st... \n", + "6 households_space_heater_hybrid_heatpump_air_wa... \n", + "7 households_space_heater_hybrid_hydrogen_heatpu... \n", + "8 households_space_heater_hybrid_crude_oil_heatp... \n", + "9 households_space_heater_district_heating_ht_st... \n", + "10 households_space_heater_electricity \n", + "11 households_space_heater_combined_network_gas \n", + "12 households_space_heater_combined_hydrogen \n", + "13 households_space_heater_wood_pellets \n", + "14 households_space_heater_network_gas \n", + "15 households_space_heater_coal \n", + "16 households_space_heater_crude_oil \n", + "\n", + " \\\n", + " heat_network_lt \n", + "sortables \n", + "0 energy_heat_network_storage_lt_steam_hot_water \n", + "1 energy_heat_boiler_lt_electricity \n", + "2 energy_heat_burner_lt_hydrogen \n", + "3 energy_heat_heatpump_water_water_lt_electricity \n", + "4 energy_heat_heatpump_surface_water_water_ts_lt... \n", + "5 energy_heat_heatpump_waste_water_water_ts_lt_e... \n", + "6 energy_heat_heatpump_drink_water_water_ts_lt_e... \n", + "7 None \n", + "8 None \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \\\n", + " heat_network_mt \n", + "sortables \n", + "0 energy_heat_network_storage_mt_steam_hot_water \n", + "1 energy_heat_boiler_mt_electricity \n", + "2 energy_heat_burner_mt_coal \n", + "3 energy_heat_burner_mt_crude_oil \n", + "4 energy_heat_burner_mt_hydrogen \n", + "5 energy_heat_burner_mt_network_gas \n", + "6 energy_heat_burner_mt_waste_mix \n", + "7 energy_heat_burner_mt_wood_pellets \n", + "8 energy_heat_heatpump_water_water_mt_electricity \n", + "9 energy_heat_heatpump_surface_water_water_ts_mt... \n", + "10 energy_heat_heatpump_waste_water_water_ts_mt_e... \n", + "11 energy_heat_heatpump_drink_water_water_ts_mt_e... \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None \n", + "\n", + " \n", + " heat_network_ht \n", + "sortables \n", + "0 energy_heat_network_storage_ht_steam_hot_water \n", + "1 energy_heat_boiler_ht_electricity \n", + "2 energy_heat_burner_ht_coal \n", + "3 energy_heat_burner_ht_crude_oil \n", + "4 energy_heat_burner_ht_hydrogen \n", + "5 energy_heat_burner_ht_network_gas \n", + "6 energy_heat_burner_ht_waste_mix \n", + "7 energy_heat_burner_ht_wood_pellets \n", + "8 energy_heat_heatpump_water_water_ht_electricity \n", + "9 None \n", + "10 None \n", + "11 None \n", + "12 None \n", + "13 None \n", + "14 None \n", + "15 None \n", + "16 None " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "packer.sortables()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "0d3e771e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
A: Create from excelB: Load a scenario by id
interconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availabilityinterconnector_2_priceinterconnector_2_import_availabilityinterconnector_2_export_availabilityinterconnector_3_priceinterconnector_1_priceinterconnector_1_import_availabilityinterconnector_1_export_availability...households_hot_waterindustry_ictindustry_other_electricityweather/solar_pv_profile_1weather/solar_thermalweather/air_temperatureweather/agriculture_heatingweather/wind_offshore_baselineweather/wind_coastal_baselineweather/wind_inland_baseline
00.011.00.026.001.01.00.019.09.09.0...9.09.09.09.09.09.09.09.09.09.0
10.011.00.026.001.01.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
20.011.00.014.481.01.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
30.011.00.00.011.00.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
40.011.00.00.021.00.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
..................................................................
87550.011.00.00.011.00.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
87560.011.00.00.011.00.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
87570.011.00.00.011.00.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
87580.011.00.00.021.00.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
87590.011.00.00.001.00.00.009.09.09.0...9.09.09.09.09.09.09.09.09.09.0
\n", + "

8760 rows × 52 columns

\n", + "
" + ], + "text/plain": [ + " A: Create from excel \\\n", + " interconnector_1_price interconnector_1_import_availability \n", + "0 0.01 1.0 \n", + "1 0.01 1.0 \n", + "2 0.01 1.0 \n", + "3 0.01 1.0 \n", + "4 0.01 1.0 \n", + "... ... ... \n", + "8755 0.01 1.0 \n", + "8756 0.01 1.0 \n", + "8757 0.01 1.0 \n", + "8758 0.01 1.0 \n", + "8759 0.01 1.0 \n", + "\n", + " \\\n", + " interconnector_1_export_availability interconnector_2_price \n", + "0 0.0 26.00 \n", + "1 0.0 26.00 \n", + "2 0.0 14.48 \n", + "3 0.0 0.01 \n", + "4 0.0 0.02 \n", + "... ... ... \n", + "8755 0.0 0.01 \n", + "8756 0.0 0.01 \n", + "8757 0.0 0.01 \n", + "8758 0.0 0.02 \n", + "8759 0.0 0.00 \n", + "\n", + " \\\n", + " interconnector_2_import_availability \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 \n", + "... ... \n", + "8755 1.0 \n", + "8756 1.0 \n", + "8757 1.0 \n", + "8758 1.0 \n", + "8759 1.0 \n", + "\n", + " \\\n", + " interconnector_2_export_availability interconnector_3_price \n", + "0 1.0 0.01 \n", + "1 1.0 0.00 \n", + "2 1.0 0.00 \n", + "3 0.0 0.00 \n", + "4 0.0 0.00 \n", + "... ... ... \n", + "8755 0.0 0.00 \n", + "8756 0.0 0.00 \n", + "8757 0.0 0.00 \n", + "8758 0.0 0.00 \n", + "8759 0.0 0.00 \n", + "\n", + " B: Load a scenario by id \\\n", + " interconnector_1_price interconnector_1_import_availability \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "... ... ... \n", + "8755 9.0 9.0 \n", + "8756 9.0 9.0 \n", + "8757 9.0 9.0 \n", + "8758 9.0 9.0 \n", + "8759 9.0 9.0 \n", + "\n", + " ... \\\n", + " interconnector_1_export_availability ... households_hot_water \n", + "0 9.0 ... 9.0 \n", + "1 9.0 ... 9.0 \n", + "2 9.0 ... 9.0 \n", + "3 9.0 ... 9.0 \n", + "4 9.0 ... 9.0 \n", + "... ... ... ... \n", + "8755 9.0 ... 9.0 \n", + "8756 9.0 ... 9.0 \n", + "8757 9.0 ... 9.0 \n", + "8758 9.0 ... 9.0 \n", + "8759 9.0 ... 9.0 \n", + "\n", + " \\\n", + " industry_ict industry_other_electricity weather/solar_pv_profile_1 \n", + "0 9.0 9.0 9.0 \n", + "1 9.0 9.0 9.0 \n", + "2 9.0 9.0 9.0 \n", + "3 9.0 9.0 9.0 \n", + "4 9.0 9.0 9.0 \n", + "... ... ... ... \n", + "8755 9.0 9.0 9.0 \n", + "8756 9.0 9.0 9.0 \n", + "8757 9.0 9.0 9.0 \n", + "8758 9.0 9.0 9.0 \n", + "8759 9.0 9.0 9.0 \n", + "\n", + " \\\n", + " weather/solar_thermal weather/air_temperature \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "... ... ... \n", + "8755 9.0 9.0 \n", + "8756 9.0 9.0 \n", + "8757 9.0 9.0 \n", + "8758 9.0 9.0 \n", + "8759 9.0 9.0 \n", + "\n", + " \\\n", + " weather/agriculture_heating weather/wind_offshore_baseline \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "... ... ... \n", + "8755 9.0 9.0 \n", + "8756 9.0 9.0 \n", + "8757 9.0 9.0 \n", + "8758 9.0 9.0 \n", + "8759 9.0 9.0 \n", + "\n", + " \n", + " weather/wind_coastal_baseline weather/wind_inland_baseline \n", + "0 9.0 9.0 \n", + "1 9.0 9.0 \n", + "2 9.0 9.0 \n", + "3 9.0 9.0 \n", + "4 9.0 9.0 \n", + "... ... ... \n", + "8755 9.0 9.0 \n", + "8756 9.0 9.0 \n", + "8757 9.0 9.0 \n", + "8758 9.0 9.0 \n", + "8759 9.0 9.0 \n", + "\n", + "[8760 rows x 52 columns]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "packer.custom_curves()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "54cc3f61", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
A: Create from excelB: Load a scenario by id
futurefuture
gqueryunit
dashboard_emissionsfactor0.024027-0.947929
dashboard_co2_emissions_versus_start_yearfactor0.028299-0.997037
dashboard_total_costsbln_euro39.30029356.46303
\n", + "
" + ], + "text/plain": [ + " A: Create from excel \\\n", + " future \n", + "gquery unit \n", + "dashboard_emissions factor 0.024027 \n", + "dashboard_co2_emissions_versus_start_year factor 0.028299 \n", + "dashboard_total_costs bln_euro 39.300293 \n", + "\n", + " B: Load a scenario by id \n", + " future \n", + "gquery unit \n", + "dashboard_emissions factor -0.947929 \n", + "dashboard_co2_emissions_versus_start_year factor -0.997037 \n", + "dashboard_total_costs bln_euro 56.46303 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "packer.gquery_results()" ] diff --git a/src/pyetm/models/packables/custom_curves_pack.py b/src/pyetm/models/packables/custom_curves_pack.py index d454164..3a307e3 100644 --- a/src/pyetm/models/packables/custom_curves_pack.py +++ b/src/pyetm/models/packables/custom_curves_pack.py @@ -29,14 +29,13 @@ def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: return self.build_pack_dataframe(columns=columns, **kwargs) def _normalize_curves_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - data = self._normalize_two_header_sheet( + # New simplified logic: single header expected, drop helper columns + return self._normalize_single_header_sheet( df, - helper_level1={"sortables"}, - drop_empty_level0=True, - collapse_level0=False, - reset_index=True, # values rows should be reindexed 0..n + helper_columns={"sortables"}, + drop_empty=True, + reset_index=True, ) - return data def from_dataframe(self, df: pd.DataFrame): if df is None or getattr(df, "empty", False): @@ -46,16 +45,14 @@ def from_dataframe(self, df: pd.DataFrame): except Exception as e: logger.warning("Failed to normalize custom curves sheet: %s", e) return - if df is None or df.empty or not isinstance(df.columns, pd.MultiIndex): + if df is None or df.empty: return def _apply(scenario, block: pd.DataFrame): - # block has columns MultiIndex(identifier, curve_key); collapse to curve_key - if isinstance(block.columns, pd.MultiIndex): - block.columns = [c[1] for c in block.columns] + # block may already have single-level columns (preferred path) try: curves = CustomCurves._from_dataframe(block, scenario_id=scenario.id) - except Exception as e: # pragma: no cover + except Exception as e: logger.warning( "Failed to build custom curves for '%s': %s", scenario.identifier(), @@ -64,4 +61,10 @@ def _apply(scenario, block: pd.DataFrame): return scenario.update_custom_curves(curves) - self.apply_identifier_blocks(df, _apply) + # If multi-scenario (legacy exported) DataFrame with MultiIndex, apply per identifier + if isinstance(df.columns, pd.MultiIndex): + self.apply_identifier_blocks(df, _apply) + else: + # Single-scenario style: apply to all scenarios in this pack + for scenario in self.scenarios: + _apply(scenario, df) diff --git a/src/pyetm/models/packables/inputs_pack.py b/src/pyetm/models/packables/inputs_pack.py index 61ec67f..db99c74 100644 --- a/src/pyetm/models/packables/inputs_pack.py +++ b/src/pyetm/models/packables/inputs_pack.py @@ -18,12 +18,9 @@ def __init__(self, **data): {} ) # scenario_id -> short_name mapping - # --- Public configuration --------------------------------------------------- def set_scenario_short_names(self, scenario_short_names: Dict[str, str]): - """Set the mapping of scenario identifiers to their short names.""" self._scenario_short_names = scenario_short_names or {} - # --- Scenario key / resolution overrides ------------------------------------ def _key_for(self, scenario: "Any") -> Any: # Prefer short name if present (mapping stored by scenario.id) short = self._scenario_short_names.get(str(scenario.id)) @@ -51,7 +48,6 @@ def resolve_scenario(self, label: Any): pass return None - # --- Per-scenario frame builder (used by generic template) ------------------ def _build_dataframe_for_scenario(self, scenario, columns: str = "user", **kwargs): try: df = scenario.inputs.to_dataframe(columns=columns) @@ -67,91 +63,60 @@ def _build_dataframe_for_scenario(self, scenario, columns: str = "user", **kwarg def _to_dataframe(self, columns="user", **kwargs): return self.build_pack_dataframe(columns=columns, **kwargs) - # --- Normalisation logic ---------------------------------------------------- def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize various inputs sheet shapes into canonical shape: - - Drop leading completely blank rows. - - Accept either: - (a) Two header rows (short_name row above a row containing 'user'), or - (b) Single header row of scenario labels (no explicit 'user' row) -> we fabricate 'user'. - - Support 1- or 2-level row index (input[, unit]). - Returns DataFrame with columns MultiIndex(label, 'user'). + """Normalize PARAMETERS sheet (single-header variant only). + Assumptions (new layout): + - First non-empty row contains scenario labels (short names / identifiers). + - First column below header lists input keys; optional second column lists units + (detected heuristically: treat second column as unit column if most + of its non-empty values are short (<=8 chars) and non-numeric while + third column has numeric values). + - All remaining columns are scenario value columns. + - Fabricate second header level with constant 'user'. + Returns DataFrame with MultiIndex columns (scenario_label, 'user'). """ df = df.dropna(how="all") if df.empty: return df - # Locate the row containing 'user' (case-insensitive) - user_row_pos = None - for pos, (_, row) in enumerate(df.iterrows()): - if any(isinstance(v, str) and v.strip().lower() == "user" for v in row): - user_row_pos = pos - break - - single_header = user_row_pos is None - if single_header: - header_start = 0 - header_end = 0 - else: - header_start = max(user_row_pos - 1, 0) - header_end = user_row_pos - - headers = df.iloc[header_start : header_end + 1].astype(str) - data = df.iloc[header_end + 1 :].copy() - - if single_header: - # Build columns from single header row; fabricate second level 'user' - col_level0 = headers.iloc[0].values - data.columns = col_level0 - index_candidates = list(data.columns[:2]) # heuristic - second_is_numeric = False - if len(index_candidates) > 1: - sample = data[index_candidates[1]].dropna().head(5) - if not sample.empty and all( - pd.to_numeric(sample, errors="coerce").notna() - ): - second_is_numeric = True - if second_is_numeric: - idx_cols = [index_candidates[0]] - else: - idx_cols = index_candidates - input_col = idx_cols[0] - unit_col = idx_cols[1] if len(idx_cols) > 1 else None - scenario_cols = [ - c for c in data.columns if c not in idx_cols and str(c).strip() != "" - ] - input_series = data[input_col].astype(str) - if unit_col is not None: - unit_series = data[unit_col].astype(str) - index = pd.MultiIndex.from_arrays( - [input_series.values, unit_series.values], names=["input", "unit"] + # Determine header row (first non-empty) + header_pos_list = self.first_non_empty_row_positions(df, 1) + if not header_pos_list: + return pd.DataFrame() + header_pos = header_pos_list[0] + header = df.iloc[header_pos].astype(str) + data = df.iloc[header_pos + 1 :].copy() + data.columns = header.values + + if data.empty: + return pd.DataFrame() + + cols = list(data.columns) + if not cols: + return pd.DataFrame() + + # Heuristic to detect unit column + input_col = cols[0] + unit_col = None + if len(cols) > 2: + candidate_unit = cols[1] + third_col = cols[2] + sample_candidate = data[candidate_unit].dropna().astype(str).head(25) + sample_third = data[third_col].dropna().head(25) + if not sample_candidate.empty: + short_tokens = sum(len(s.strip()) <= 8 for s in sample_candidate) + numeric_third = ( + not sample_third.empty + and pd.to_numeric(sample_third, errors="coerce").notna().mean() + > 0.5 ) - else: - index = pd.Index(input_series.values, name="input") - canonical = data[scenario_cols].copy() - canonical.index = index - canonical.columns = pd.MultiIndex.from_arrays( - [canonical.columns, ["user"] * len(canonical.columns)] - ) - return canonical - - # Two-row header path (original logic) - data.columns = pd.MultiIndex.from_arrays( - [headers.iloc[0].values, headers.iloc[1].values] - ) - - idx_cols = [ - col - for col in data.columns - if not (isinstance(col[1], str) and col[1].strip().lower() == "user") - ] - if len(idx_cols) == 0: - input_col = data.columns[0] + if short_tokens / len(sample_candidate) > 0.6 and numeric_third: + unit_col = candidate_unit + elif len(cols) == 2: + # If only two columns treat second as scenario column (no unit) unit_col = None - else: - input_col = idx_cols[0] - unit_col = idx_cols[1] if len(idx_cols) > 1 else None + scenario_cols = [c for c in cols if c not in {input_col} and c != unit_col] input_series = data[input_col].astype(str) if unit_col is not None: unit_series = data[unit_col].astype(str) @@ -160,30 +125,11 @@ def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: ) else: index = pd.Index(input_series.values, name="input") - - keep_cols = [ - c - for c in data.columns - if c not in {input_col} and (unit_col is None or c != unit_col) - ] - canonical = data[keep_cols] + canonical = data[scenario_cols].copy() canonical.index = index - - if isinstance(canonical.columns, pd.MultiIndex): - lvl1 = canonical.columns.get_level_values(1) - if not all( - isinstance(v, str) and v.strip().lower() == "user" for v in lvl1 - ): - canonical.columns = pd.MultiIndex.from_arrays( - [ - canonical.columns.get_level_values(0), - ["user"] * len(canonical.columns), - ] - ) - else: - canonical.columns = pd.MultiIndex.from_arrays( - [canonical.columns, ["user"] * len(canonical.columns)] - ) + canonical.columns = pd.MultiIndex.from_arrays( + [canonical.columns, ["user"] * len(canonical.columns)] + ) return canonical # --- Import (mutation) ------------------------------------------------------ diff --git a/src/pyetm/models/packables/output_curves_pack.py b/src/pyetm/models/packables/output_curves_pack.py index 4acff49..ff90d49 100644 --- a/src/pyetm/models/packables/output_curves_pack.py +++ b/src/pyetm/models/packables/output_curves_pack.py @@ -12,10 +12,10 @@ class OutputCurvesPack(Packable): key: ClassVar[str] = "output_curves" sheet_name: ClassVar[str] = "OUTPUT_CURVES" - def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): # type: ignore[override] + def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwargs): try: series_list = list(scenario.all_output_curves()) - except Exception as e: # pragma: no cover + except Exception as e: logger.warning( "Failed extracting output curves for %s: %s", scenario.identifier(), e ) @@ -24,5 +24,5 @@ def _build_dataframe_for_scenario(self, scenario: Any, columns: str = "", **kwar return None return pd.concat(series_list, axis=1) - def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: # type: ignore[override] + def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: return self.build_pack_dataframe(columns=columns, **kwargs) diff --git a/src/pyetm/models/packables/packable.py b/src/pyetm/models/packables/packable.py index e154f37..780b1c2 100644 --- a/src/pyetm/models/packables/packable.py +++ b/src/pyetm/models/packables/packable.py @@ -36,11 +36,9 @@ def clear(self): self.scenarios.clear() self._scenario_id_cache = None - # --- Summary ---------------------------------------------------------------- def summary(self) -> dict: return {self.key: {"scenario_count": len(self.scenarios)}} - # --- Template packing API (Opt-in for subclasses) --------------------------- def _key_for(self, scenario: "Scenario") -> Any: """Return the identifier used as the top-level column key when packing. Subclasses can override (e.g. to use short names).""" @@ -56,17 +54,11 @@ def _build_dataframe_for_scenario( def _concat_frames( self, frames: list[pd.DataFrame], keys: list[Any] ) -> pd.DataFrame: - """Concatenate per-scenario frames along axis=1 with keys. - Separated for easier overriding/testing.""" if not frames: return pd.DataFrame() return pd.concat(frames, axis=1, keys=keys) def build_pack_dataframe(self, columns: str = "", **kwargs) -> pd.DataFrame: - """Generic implementation collecting per-scenario frames using - _build_dataframe_for_scenario. Subclasses call this inside their - _to_dataframe implementation after overriding _build_dataframe_for_scenario. - (Not automatically invoked so existing subclasses remain unchanged).""" frames: list[pd.DataFrame] = [] keys: list[Any] = [] for scenario in self.scenarios: @@ -88,7 +80,6 @@ def build_pack_dataframe(self, columns: str = "", **kwargs) -> pd.DataFrame: keys.append(self._key_for(scenario)) return self._concat_frames(frames, keys) - # --- External API ----------------------------------------------------------- def to_dataframe(self, columns="") -> pd.DataFrame: """Convert the pack into a dataframe""" if len(self.scenarios) == 0: @@ -102,7 +93,6 @@ def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: """Base implementation - kids should implement this or use build_pack_dataframe""" return pd.DataFrame() - # --- Scenario resolution helpers ------------------------------------------- def _refresh_cache(self): self._scenario_id_cache = {str(s.identifier()): s for s in self.scenarios} @@ -115,13 +105,10 @@ def _find_by_identifier(self, identifier: str): return self._scenario_id_cache.get(ident_str) def resolve_scenario(self, label: Any) -> Optional["Scenario"]: - """Generic resolution; subclasses can extend (e.g. InputsPack). - Default: direct identifier match.""" if label is None: return None return self._find_by_identifier(label) - # --- Utility static methods (shared normalisation helpers) ----------------- @staticmethod def is_blank(value: Any) -> bool: return ( @@ -157,9 +144,6 @@ def apply_identifier_blocks( apply_block: Callable[["Scenario", pd.DataFrame], None], resolve: Optional[Callable[[Any], Optional["Scenario"]]] = None, ): - """Iterate over first-level column identifiers of a MultiIndex DataFrame and apply a block function. - resolve optionally overrides scenario resolution (defaults to direct identifier lookup). - """ if df is None or not isinstance(df.columns, pd.MultiIndex): return identifiers = df.columns.get_level_values(0).unique() @@ -185,53 +169,36 @@ def apply_identifier_blocks( e, ) - def _normalize_two_header_sheet( + def _normalize_single_header_sheet( self, df: pd.DataFrame, *, - helper_level0: Optional[set[str]] = None, - helper_level1: Optional[set[str]] = None, - drop_empty_level0: bool = True, - drop_empty_level1: bool = False, - collapse_level0: bool = False, + helper_columns: Optional[set[str]] = None, + drop_empty: bool = True, reset_index: bool = False, ) -> pd.DataFrame: - """Generic normalizer for a sheet with (potential) two header rows. - - Detect first two non-empty rows as headers (or fabricate second if missing). - - Build MultiIndex columns (level0, level1). - - Optionally drop columns whose level0/level1 are blank or in helper sets. - - Optionally collapse to single level (level0) after filtering. - - Optionally reset row index to a simple RangeIndex. - Returns canonical DataFrame or empty DataFrame on failure. + """Normalize a sheet that uses a single header row. + Rules: + - First non-empty row becomes header. + - Subsequent rows are data. + - Optionally drop columns whose header is blank or in helper_columns. + - Optionally reset the row index. + Returns a DataFrame with a single-level column index. """ - helper_level0 = {h.lower() for h in (helper_level0 or set())} - helper_level1 = {h.lower() for h in (helper_level1 or set())} - + helper_columns_lc = {h.lower() for h in (helper_columns or set())} if df is None: return pd.DataFrame() df = df.dropna(how="all") if df.empty: return df - positions = self.first_non_empty_row_positions(df, 2) + positions = self.first_non_empty_row_positions(df, 1) if not positions: return pd.DataFrame() - header0_pos = positions[0] - header1_pos = positions[1] if len(positions) > 1 else None - - if header1_pos is None: - # Single header row -> fabricate second empty row - headers0 = df.iloc[header0_pos].astype(str).values - headers1 = ["" for _ in headers0] - data = df.iloc[header0_pos + 1 :].copy() - else: - headers = df.iloc[[header0_pos, header1_pos]].astype(str) - headers0 = headers.iloc[0].values - headers1 = headers.iloc[1].values - data = df.iloc[header1_pos + 1 :].copy() - - columns = pd.MultiIndex.from_arrays([headers0, headers1]) - data.columns = columns + header_pos = positions[0] + header_row = df.iloc[header_pos].astype(str).map(lambda s: s.strip()) + data = df.iloc[header_pos + 1 :].copy() + data.columns = header_row.values def _is_blank(v): return ( @@ -240,22 +207,16 @@ def _is_blank(v): or (isinstance(v, str) and v.strip() == "") ) - keep = [] - for c in data.columns: - lv0, lv1 = c[0], c[1] - if drop_empty_level0 and _is_blank(lv0): - continue - if drop_empty_level1 and _is_blank(lv1): - continue - if isinstance(lv0, str) and lv0.strip().lower() in helper_level0: - continue - if isinstance(lv1, str) and lv1.strip().lower() in helper_level1: - continue - keep.append(c) - data = data[keep] + if drop_empty or helper_columns_lc: + keep = [] + for c in data.columns: + if drop_empty and _is_blank(c): + continue + if isinstance(c, str) and c.strip().lower() in helper_columns_lc: + continue + keep.append(c) + data = data[keep] - if collapse_level0: - data.columns = [c[0] for c in data.columns] if reset_index: data.reset_index(drop=True, inplace=True) return data diff --git a/src/pyetm/models/packables/sortable_pack.py b/src/pyetm/models/packables/sortable_pack.py index c95e9d6..17d0651 100644 --- a/src/pyetm/models/packables/sortable_pack.py +++ b/src/pyetm/models/packables/sortable_pack.py @@ -24,16 +24,13 @@ def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: return self.build_pack_dataframe(columns=columns, **kwargs) def _normalize_sortables_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize various sortables sheet shapes""" - data = self._normalize_two_header_sheet( + """Normalize a sortables sheet expecting a single header row.""" + return self._normalize_single_header_sheet( df, - helper_level0=set(), - helper_level1={"sortables"}, - drop_empty_level0=True, - collapse_level0=False, + helper_columns={"sortables"}, + drop_empty=True, reset_index=False, ) - return data def from_dataframe(self, df: pd.DataFrame): """Unpack and update sortables for each scenario from the sheet.""" @@ -44,12 +41,14 @@ def from_dataframe(self, df: pd.DataFrame): except Exception as e: logger.warning("Failed to normalize sortables sheet: %s", e) return - if df is None or df.empty or not isinstance(df.columns, pd.MultiIndex): + if df is None or df.empty: return def _apply(scenario, block: pd.DataFrame): - if isinstance(block.columns, pd.MultiIndex): - block.columns = [c[1] for c in block.columns] scenario.set_sortables_from_dataframe(block) - self.apply_identifier_blocks(df, _apply) + if isinstance(df.columns, pd.MultiIndex): + self.apply_identifier_blocks(df, _apply) + else: + for scenario in self.scenarios: + _apply(scenario, df) diff --git a/tests/models/packables/test_custom_curves_pack.py b/tests/models/packables/test_custom_curves_pack.py index 786f45c..8002023 100644 --- a/tests/models/packables/test_custom_curves_pack.py +++ b/tests/models/packables/test_custom_curves_pack.py @@ -61,25 +61,6 @@ def empty_series(): assert result is None -def test_normalize_curves_dataframe_calls_helper(monkeypatch): - pack = CustomCurvesPack() - - called_with = {} - - def fake_normalize(df, **kwargs): - called_with.update(kwargs) - return df - - monkeypatch.setattr(pack, "_normalize_two_header_sheet", fake_normalize) - - df = pd.DataFrame({"a": [1, 2]}) - result = pack._normalize_curves_dataframe(df) - - assert result.equals(df) - assert called_with["drop_empty_level0"] - assert called_with["reset_index"] - - def test_from_dataframe_applies_to_scenarios(monkeypatch): pack = CustomCurvesPack() scenario = MockScenario("sc1") diff --git a/tests/models/packables/test_packable.py b/tests/models/packables/test_packable.py index 4faadfc..e1f7cb6 100644 --- a/tests/models/packables/test_packable.py +++ b/tests/models/packables/test_packable.py @@ -205,52 +205,17 @@ def fail_block(scenario, block): assert "Failed applying block" in caplog.text -def test_normalize_two_header_sheet_basic(packable): +def test_normalize_single_header_sheet(packable): df = pd.DataFrame( [ - ["id1", "id2"], - ["curve1", "curve2"], - [1, 2], - [3, 4], + ["col1", "col2", "helper"], + [1, 2, 3], + [4, 5, 6], ] ) - result = packable._normalize_two_header_sheet(df, reset_index=True) - assert isinstance(result.columns, pd.MultiIndex) + result = packable._normalize_single_header_sheet( + df, helper_columns={"helper"}, reset_index=True + ) + assert list(result.columns) == ["col1", "col2"] assert result.shape == (2, 2) assert result.index.equals(pd.RangeIndex(0, 2)) - - -def test_normalize_two_header_sheet_single_header(packable): - df = pd.DataFrame( - [ - ["id1", "id2"], - [1, 2], - [3, 4], - ] - ) - result = packable._normalize_two_header_sheet(df) - assert isinstance(result.columns, pd.MultiIndex) - assert result.shape[0] == 1 or result.shape[0] == 2 - - -def test_normalize_two_header_sheet_with_helpers(packable): - df = pd.DataFrame( - [ - ["helper", "id2"], - ["helpercurve", "curve2"], - [1, 2], - [3, 4], - ] - ) - result = packable._normalize_two_header_sheet( - df, - helper_level0={"helper"}, - helper_level1={"helpercurve"}, - drop_empty_level0=True, - drop_empty_level1=True, - ) - # "helper" and "helpercurve" columns should be removed - for lvl0 in result.columns.get_level_values(0): - assert lvl0.lower() != "helper" - for lvl1 in result.columns.get_level_values(1): - assert lvl1.lower() != "helpercurve" From d320a234af770ba9b9349257cc193f15e536f10f Mon Sep 17 00:00:00 2001 From: louispt1 Date: Tue, 12 Aug 2025 10:47:24 +0200 Subject: [PATCH 15/17] Simplifying inputs pack --- .../models/packables/custom_curves_pack.py | 13 +- src/pyetm/models/packables/inputs_pack.py | 259 +++++++------ src/pyetm/models/packables/packable.py | 9 +- src/pyetm/models/scenario_packer.py | 343 +++++++++--------- src/pyetm/models/sortables.py | 12 +- .../packables/test_custom_curves_pack.py | 28 -- tests/models/test_scenario_packer.py | 29 +- 7 files changed, 310 insertions(+), 383 deletions(-) diff --git a/src/pyetm/models/packables/custom_curves_pack.py b/src/pyetm/models/packables/custom_curves_pack.py index 3a307e3..529655a 100644 --- a/src/pyetm/models/packables/custom_curves_pack.py +++ b/src/pyetm/models/packables/custom_curves_pack.py @@ -1,8 +1,6 @@ import logging from typing import ClassVar, Any - import pandas as pd - from pyetm.models.custom_curves import CustomCurves from pyetm.models.packables.packable import Packable @@ -29,7 +27,6 @@ def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: return self.build_pack_dataframe(columns=columns, **kwargs) def _normalize_curves_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - # New simplified logic: single header expected, drop helper columns return self._normalize_single_header_sheet( df, helper_columns={"sortables"}, @@ -49,7 +46,6 @@ def from_dataframe(self, df: pd.DataFrame): return def _apply(scenario, block: pd.DataFrame): - # block may already have single-level columns (preferred path) try: curves = CustomCurves._from_dataframe(block, scenario_id=scenario.id) except Exception as e: @@ -61,10 +57,5 @@ def _apply(scenario, block: pd.DataFrame): return scenario.update_custom_curves(curves) - # If multi-scenario (legacy exported) DataFrame with MultiIndex, apply per identifier - if isinstance(df.columns, pd.MultiIndex): - self.apply_identifier_blocks(df, _apply) - else: - # Single-scenario style: apply to all scenarios in this pack - for scenario in self.scenarios: - _apply(scenario, df) + for scenario in self.scenarios: + _apply(scenario, df) diff --git a/src/pyetm/models/packables/inputs_pack.py b/src/pyetm/models/packables/inputs_pack.py index db99c74..5680174 100644 --- a/src/pyetm/models/packables/inputs_pack.py +++ b/src/pyetm/models/packables/inputs_pack.py @@ -1,8 +1,6 @@ import logging from typing import ClassVar, Dict, Any - import pandas as pd - from pyetm.models.packables.packable import Packable logger = logging.getLogger(__name__) @@ -14,31 +12,39 @@ class InputsPack(Packable): def __init__(self, **data): super().__init__(**data) - self._scenario_short_names: Dict[str, str] = ( - {} - ) # scenario_id -> short_name mapping + self._scenario_short_names: Dict[str, str] = {} def set_scenario_short_names(self, scenario_short_names: Dict[str, str]): self._scenario_short_names = scenario_short_names or {} def _key_for(self, scenario: "Any") -> Any: - # Prefer short name if present (mapping stored by scenario.id) short = self._scenario_short_names.get(str(scenario.id)) - return short if short else scenario.identifier() + if short: + return short + + label = None + try: + label = scenario.identifier() + except Exception: + label = None + + if not isinstance(label, (str, int)): + return scenario.id + return label def resolve_scenario(self, label: Any): if label is None: return None label_str = str(label).strip() - # 1. short name + # Match short name first for scenario in self.scenarios: if self._scenario_short_names.get(str(scenario.id)) == label_str: return scenario - # 2. identifier (title or id as string) - s = super().resolve_scenario(label_str) - if s is not None: - return s - # 3. numeric id + # Fallback to identifier/title + found = super().resolve_scenario(label_str) + if found is not None: + return found + # Fallback to numeric id try: num = int(float(label_str)) for scenario in self.scenarios: @@ -48,130 +54,123 @@ def resolve_scenario(self, label: Any): pass return None - def _build_dataframe_for_scenario(self, scenario, columns: str = "user", **kwargs): - try: - df = scenario.inputs.to_dataframe(columns=columns) - except Exception as e: - logger.warning( - "Failed building inputs frame for scenario %s: %s", - scenario.identifier(), - e, - ) - return None - return df if df is not None and not df.empty else None - - def _to_dataframe(self, columns="user", **kwargs): - return self.build_pack_dataframe(columns=columns, **kwargs) - - def _normalize_inputs_dataframe(self, df: pd.DataFrame) -> pd.DataFrame: - """Normalize PARAMETERS sheet (single-header variant only). - Assumptions (new layout): - - First non-empty row contains scenario labels (short names / identifiers). - - First column below header lists input keys; optional second column lists units - (detected heuristically: treat second column as unit column if most - of its non-empty values are short (<=8 chars) and non-numeric while - third column has numeric values). - - All remaining columns are scenario value columns. - - Fabricate second header level with constant 'user'. - Returns DataFrame with MultiIndex columns (scenario_label, 'user'). - """ - df = df.dropna(how="all") - if df.empty: - return df - - # Determine header row (first non-empty) - header_pos_list = self.first_non_empty_row_positions(df, 1) - if not header_pos_list: + def _to_dataframe(self, columns: str = "user", **kwargs): + if not self.scenarios: return pd.DataFrame() - header_pos = header_pos_list[0] - header = df.iloc[header_pos].astype(str) - data = df.iloc[header_pos + 1 :].copy() - data.columns = header.values - if data.empty: - return pd.DataFrame() + def extract_user_map_from_inputs_obj(scen) -> dict[str, Any] | None: + try: + it = iter(scen.inputs) + values = {} + for inp in it: + key = getattr(inp, "key", None) + if key is None: + continue + values[str(key)] = getattr(inp, "user", None) + if values: + return values + except Exception: + pass - cols = list(data.columns) - if not cols: + try: + df = scen.inputs.to_dataframe(columns="user") + except Exception: + df = None + if df is None or getattr(df, "empty", False): + return None + + if isinstance(df.index, pd.MultiIndex) and "unit" in (df.index.names or []): + df = df.copy() + df.index = df.index.droplevel("unit") + if isinstance(df, pd.Series): + series = df + else: + cols_lc = [str(c).lower() for c in df.columns] + chosen = None + for candidate in ("user", "value"): + if candidate in cols_lc: + chosen = df.columns[cols_lc.index(candidate)] + break + if chosen is None: + chosen = df.columns[0] + series = df[chosen] + series.index = series.index.map(lambda k: str(k)) + return series.to_dict() + + all_keys: set[str] = set() + per_label_values: dict[Any, dict[str, Any]] = {} + for scen in self.scenarios: + label = self._key_for(scen) + user_map = extract_user_map_from_inputs_obj(scen) + if not user_map: + continue + per_label_values[label] = user_map + all_keys.update(user_map.keys()) + + if not all_keys: return pd.DataFrame() - # Heuristic to detect unit column - input_col = cols[0] - unit_col = None - if len(cols) > 2: - candidate_unit = cols[1] - third_col = cols[2] - sample_candidate = data[candidate_unit].dropna().astype(str).head(25) - sample_third = data[third_col].dropna().head(25) - if not sample_candidate.empty: - short_tokens = sum(len(s.strip()) <= 8 for s in sample_candidate) - numeric_third = ( - not sample_third.empty - and pd.to_numeric(sample_third, errors="coerce").notna().mean() - > 0.5 - ) - if short_tokens / len(sample_candidate) > 0.6 and numeric_third: - unit_col = candidate_unit - elif len(cols) == 2: - # If only two columns treat second as scenario column (no unit) - unit_col = None - - scenario_cols = [c for c in cols if c not in {input_col} and c != unit_col] - input_series = data[input_col].astype(str) - if unit_col is not None: - unit_series = data[unit_col].astype(str) - index = pd.MultiIndex.from_arrays( - [input_series.values, unit_series.values], names=["input", "unit"] - ) - else: - index = pd.Index(input_series.values, name="input") - canonical = data[scenario_cols].copy() - canonical.index = index - canonical.columns = pd.MultiIndex.from_arrays( - [canonical.columns, ["user"] * len(canonical.columns)] - ) - return canonical - - # --- Import (mutation) ------------------------------------------------------ + sorted_keys = sorted(all_keys) + data: dict[Any, list[Any]] = {} + for label, value_map in per_label_values.items(): + data[label] = [value_map.get(k) for k in sorted_keys] + + df = pd.DataFrame(data, index=sorted_keys) + df.index.name = "input" + return df + def from_dataframe(self, df): - """ - Sets the inputs on the scenarios from the packed df (comes from excel) - Tolerates optional unit column and leading blank rows. - Uses short_name for scenario identification; falls back to identifier/title or id. - """ if df is None or getattr(df, "empty", False): return try: - df = self._normalize_inputs_dataframe(df) + df = df.dropna(how="all") + if df.empty: + return + header_pos_list = self.first_non_empty_row_positions(df, 1) + if not header_pos_list: + return + header_pos = header_pos_list[0] + header_row = df.iloc[header_pos].astype(str) + data = df.iloc[header_pos + 1 :].copy() + data.columns = header_row.values + if data.empty or len(data.columns) < 2: + return + input_col = data.columns[0] + inputs_series = data[input_col].astype(str).str.strip() + mask = inputs_series != "" + data = data.loc[mask] + inputs_series = inputs_series.loc[mask] + data.index = inputs_series + scenario_cols = [c for c in data.columns if c != input_col] + for col in scenario_cols: + scenario = self.resolve_scenario(col) + if scenario is None: + logger.warning( + "Could not find scenario for PARAMETERS column label '%s'", col + ) + continue + series = data[col] + + def _is_blank_val(v: Any) -> bool: + if v is None: + return True + if isinstance(v, float) and pd.isna(v): + return True + if isinstance(v, str) and v.strip().lower() in {"", "nan"}: + return True + return False + + updates = {k: v for k, v in series.items() if not _is_blank_val(v)} + if not updates: + continue + try: + scenario.update_user_values(updates) + except Exception as e: + logger.warning( + "Failed updating inputs for scenario '%s' from column '%s': %s", + scenario.identifier(), + col, + e, + ) except Exception as e: - logger.warning("Failed to normalize inputs sheet: %s", e) - return - if df is None or df.empty: - return - - labels = df.columns.get_level_values(0).unique() - for label in labels: - scenario = self.resolve_scenario(label) - if scenario is None: - logger.warning( - "Could not find scenario for parameters column label '%s' (not a short_name/title/id)", - label, - ) - continue - scenario_df = df[label] - if isinstance(scenario_df, pd.Series): - scenario_df = scenario_df.to_frame(name="user") - else: - if list(scenario_df.columns) != ["user"]: - scenario_df = scenario_df.copy() - first_col = scenario_df.columns[0] - scenario_df = scenario_df.rename(columns={first_col: "user"}) - try: - scenario.set_user_values_from_dataframe(scenario_df) - except Exception as e: - logger.warning( - "Failed setting inputs for scenario '%s' from column label '%s': %s", - scenario.identifier(), - label, - e, - ) + logger.warning("Failed to parse simplified PARAMETERS sheet: %s", e) diff --git a/src/pyetm/models/packables/packable.py b/src/pyetm/models/packables/packable.py index 780b1c2..6b2fdfc 100644 --- a/src/pyetm/models/packables/packable.py +++ b/src/pyetm/models/packables/packable.py @@ -9,21 +9,17 @@ class Packable(BaseModel): - # Use a proper default set and keep the type consistent scenarios: Set["Scenario"] = Field(default_factory=set) key: ClassVar[str] = "base_pack" sheet_name: ClassVar[str] = "SHEET" - # Internal cache for fast identifier lookup _scenario_id_cache: Dict[str, "Scenario"] | None = None - # --- Public collection API ------------------------------------------------- def add(self, *scenarios): "Adds one or more scenarios to the packable" if not scenarios: return self.scenarios.update(scenarios) - # Invalidate cache self._scenario_id_cache = None def discard(self, scenario): @@ -32,7 +28,6 @@ def discard(self, scenario): self._scenario_id_cache = None def clear(self): - # Reset to an empty set self.scenarios.clear() self._scenario_id_cache = None @@ -47,8 +42,6 @@ def _key_for(self, scenario: "Scenario") -> Any: def _build_dataframe_for_scenario( self, scenario: "Scenario", columns: str = "", **kwargs ) -> Optional[pd.DataFrame]: - """Return a DataFrame for a single scenario or None/empty if not applicable. - Subclasses may override to opt-in to generic build_pack_dataframe helper.""" return None def _concat_frames( @@ -88,6 +81,7 @@ def to_dataframe(self, columns="") -> pd.DataFrame: def from_dataframe(self, df): """Should parse the df and call correct setters on identified scenarios""" + raise NotImplementedError def _to_dataframe(self, columns="", **kwargs) -> pd.DataFrame: """Base implementation - kids should implement this or use build_pack_dataframe""" @@ -178,7 +172,6 @@ def _normalize_single_header_sheet( reset_index: bool = False, ) -> pd.DataFrame: """Normalize a sheet that uses a single header row. - Rules: - First non-empty row becomes header. - Subsequent rows are data. - Optionally drop columns whose header is blank or in helper_columns. diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 4b2b6c4..6aba805 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -146,18 +146,150 @@ def get_summary(self) -> Dict[str, Any]: return summary - # Create stuff + def _first_non_empty_row_index(self, df: pd.DataFrame) -> Optional[int]: + if df is None: + return None + for idx, (_, row) in enumerate(df.iterrows()): + if not row.isna().all(): + return idx + return None + + def _is_empty_or_helper(self, col_name: Any, helper_names: set[str]) -> bool: + if not isinstance(col_name, str): + return True + name = col_name.strip().lower() + return name in (helper_names or set()) or name in {"", "nan"} + + def _normalize_sheet( + self, + df: pd.DataFrame, + *, + helper_names: set[str], + reset_index: bool = True, + rename_map: Optional[Dict[str, str]] = None, + ) -> pd.DataFrame: + if df is None: + return pd.DataFrame() + df = df.dropna(how="all") + if df.empty: + return df + + header_pos = self._first_non_empty_row_index(df) + if header_pos is None: + return pd.DataFrame() + + header = df.iloc[header_pos].astype(str).map(lambda s: s.strip()) + data = df.iloc[header_pos + 1 :].copy() + data.columns = header.values + + keep_cols = [ + col + for col in data.columns + if not self._is_empty_or_helper(col, helper_names) + ] + data = data[keep_cols] + + if rename_map: + data = data.rename(columns=rename_map) + + if reset_index: + data.reset_index(drop=True, inplace=True) + + return data + + def _coerce_bool(self, v: Any) -> Optional[bool]: + if v is None or (isinstance(v, float) and pd.isna(v)): + return None + if isinstance(v, bool): + return v + if isinstance(v, (int, float)): + return bool(int(v)) + if isinstance(v, str): + s = v.strip().lower() + if s in {"true", "yes", "y", "1"}: + return True + if s in {"false", "no", "n", "0"}: + return False + return None + + def _coerce_int(self, v: Any) -> Optional[int]: + if v is None or (isinstance(v, float) and pd.isna(v)): + return None + try: + return int(float(v)) + except (ValueError, TypeError): + return None + + def _load_or_create_scenario( + self, + sid: Optional[int], + area_code: Any, + end_year: Optional[int], + col_name: str, + ) -> Optional["Scenario"]: + scenario: Optional[Scenario] = None + if sid is not None: + try: + scenario = Scenario.load(sid) + except Exception as e: + logger.warning( + "Failed to load scenario %s for column '%s': %s", sid, col_name, e + ) + scenario = None + else: + if area_code and end_year is not None: + try: + scenario = Scenario.new(str(area_code), int(end_year)) + except Exception as e: + logger.warning( + "Failed to create scenario for column '%s' (area_code=%s, end_year=%s): %s", + col_name, + area_code, + end_year, + e, + ) + scenario = None + else: + logger.warning( + "MAIN column '%s' missing required fields for creation (area_code/end_year)", + col_name, + ) + scenario = None + return scenario + + def _collect_meta_updates( + self, + private: Optional[bool], + template: Optional[int], + source: Any, + title: Any, + ) -> Dict[str, Any]: + meta_updates: Dict[str, Any] = {} + if private is not None: + meta_updates["private"] = private + if template is not None: + meta_updates["template"] = template + if isinstance(source, str) and source.strip() != "": + meta_updates["source"] = source.strip() + if isinstance(title, str) and title.strip() != "": + meta_updates["title"] = title.strip() + return meta_updates + + def _apply_metadata( + self, scenario: "Scenario", meta_updates: Dict[str, Any] + ) -> None: + if not meta_updates: + return + try: + scenario.update_metadata(**meta_updates) + except Exception as e: + logger.warning( + "Failed to update metadata for '%s': %s", scenario.identifier(), e + ) def _extract_scenario_sheet_info( self, main_df: pd.DataFrame ) -> Dict[str, Dict[str, str]]: - """Extract sortables and custom_curves sheet names for each scenario from MAIN sheet. - Also extracts short_name mapping for parameter sheet identification. - Returns dict with scenario identifier as key and info dict containing: - - 'short_name': short name for parameter sheet identification - - 'sortables': sortables sheet name - - 'custom_curves': custom curves sheet name - """ scenario_sheets = {} if isinstance(main_df, pd.Series): @@ -197,92 +329,24 @@ def _extract_scenario_sheet_info( def _process_single_scenario_sortables( self, scenario: "Scenario", df: pd.DataFrame ): - """Process sortables for a single scenario from its dedicated sheet. - Simplified parsing since there's only one scenario per sheet. - Tolerates a leading index column (e.g. 'hour' or blank), and maps - 'heat_network' → 'heat_network_lt' for convenience. - """ - # Drop completely empty rows - df = df.dropna(how="all") - if df.empty: - return - - # Find the first non-empty row -> header with sortable names - non_empty_idx = [ - i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() - ] - if not non_empty_idx: + data = self._normalize_sheet( + df, + helper_names={"sortables", "hour", "index"}, + reset_index=True, + rename_map={"heat_network": "heat_network_lt"}, + ) + if data is None or data.empty: return - - header_pos = non_empty_idx[0] - header = df.iloc[header_pos].astype(str).map(lambda s: s.strip()) - data = df.iloc[header_pos + 1 :].copy() - - # Set column names from header - data.columns = header.values - - # Helper to detect columns to drop - def _is_empty_or_helper(col_name: Any) -> bool: - if not isinstance(col_name, str): - return True - name = col_name.strip().lower() - return name in {"", "nan", "sortables", "hour", "index"} - - # Drop empty/helper columns - keep_cols = [col for col in data.columns if not _is_empty_or_helper(col)] - data = data[keep_cols] - - # Map bare 'heat_network' to 'heat_network_lt' if present - if "heat_network" in data.columns and "heat_network_lt" not in data.columns: - data = data.rename(columns={"heat_network": "heat_network_lt"}) - - # Reset index to numeric starting at 0 - data.reset_index(drop=True, inplace=True) - - # Apply to scenario scenario.set_sortables_from_dataframe(data) def _process_single_scenario_curves(self, scenario: "Scenario", df: pd.DataFrame): - """Process custom curves for a single scenario from its dedicated sheet. - Simplified parsing since there's only one scenario per sheet. - Tolerates a leading index column (e.g. 'hour' or blank). - """ - # Drop completely empty rows - df = df.dropna(how="all") - if df.empty: - return - - # Find the first non-empty row -> header with curve keys - non_empty_idx = [ - i for i, (_, r) in enumerate(df.iterrows()) if not r.isna().all() - ] - if not non_empty_idx: - return - - header_pos = non_empty_idx[0] - header = df.iloc[header_pos].astype(str).map(lambda s: s.strip()) - data = df.iloc[header_pos + 1 :].copy() - - # Set column names from header - data.columns = header.values - - # Helper to detect columns to drop - def _is_empty_or_helper(col_name: Any) -> bool: - if not isinstance(col_name, str): - return True - name = col_name.strip().lower() - return name in {"", "nan", "curves", "custom_curves", "hour", "index"} - - # Drop empty/helper columns - keep_cols = [col for col in data.columns if not _is_empty_or_helper(col)] - data = data[keep_cols] - - # Reset index to numeric starting at 0 - data.reset_index(drop=True, inplace=True) - - if data.empty: + data = self._normalize_sheet( + df, + helper_names={"curves", "custom_curves", "hour", "index"}, + reset_index=True, + ) + if data is None or data.empty: return - # Build CustomCurves collection and apply try: curves = CustomCurves._from_dataframe(data, scenario_id=scenario.id) @@ -294,18 +358,8 @@ def _is_empty_or_helper(col_name: Any) -> bool: @classmethod def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": - """Create/load scenarios and apply updates from an Excel workbook. - Behavior (new layout): - - MAIN sheet contains one column per scenario; rows may include: scenario_id, short_name, - area_code, end_year, private, template, title, sortables, custom_curves. - - PARAMETERS uses short_name headers above a 'user' header; values never repeat across scenarios. - - GQUERIES always repeat (same keys applied to each scenario column present). - - Sortables and custom curves are read from per-scenario sheets named in MAIN. - Returns a ScenarioPacker containing all touched scenarios. - """ packer = cls() - # Try to open the workbook; if missing, return empty packer (keeps tests tolerant) try: xls = pd.ExcelFile(xlsx_path) except Exception as e: @@ -353,7 +407,6 @@ def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": # PARAMETERS (inputs) sheet params_df = None try: - # Read raw to allow our normalization to detect header rows params_df = xls.parse(InputsPack.sheet_name, header=None) except Exception: params_df = None @@ -381,7 +434,7 @@ def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": except Exception as e: logger.warning("Failed to import GQUERIES: %s", e) - # Per-scenario Sortables and Custom Curves + # Sortables and Custom Curves for col_name, scenario in scenarios_by_col.items(): info = sheet_info.get(col_name, {}) if isinstance(sheet_info, dict) else {} @@ -418,34 +471,6 @@ def from_excel(cls, xlsx_path: PathLike | str) -> "ScenarioPacker": def _setup_scenario_from_main_column( self, col_name: str, col_data: pd.Series ) -> Optional[Scenario]: - """Create or load a Scenario from a MAIN sheet column and apply metadata. - Preference: if 'scenario_id' present -> load; otherwise create with area_code/end_year. - """ - - # Helper conversions - def _to_bool(v: Any) -> Optional[bool]: - if v is None or (isinstance(v, float) and pd.isna(v)): - return None - if isinstance(v, bool): - return v - if isinstance(v, (int, float)): - return bool(int(v)) - if isinstance(v, str): - s = v.strip().lower() - if s in {"true", "yes", "y", "1"}: - return True - if s in {"false", "no", "n", "0"}: - return False - return None - - def _to_int(v: Any) -> Optional[int]: - try: - if v is None or (isinstance(v, float) and pd.isna(v)): - return None - return int(float(v)) - except Exception: - return None - scenario_id = ( col_data.get("scenario_id") if isinstance(col_data, pd.Series) else None ) @@ -453,72 +478,28 @@ def _to_int(v: Any) -> Optional[int]: col_data.get("area_code") if isinstance(col_data, pd.Series) else None ) end_year = ( - _to_int(col_data.get("end_year")) + self._coerce_int(col_data.get("end_year")) if isinstance(col_data, pd.Series) else None ) private = ( - _to_bool(col_data.get("private")) + self._coerce_bool(col_data.get("private")) if isinstance(col_data, pd.Series) else None ) template = ( - _to_int(col_data.get("template")) + self._coerce_int(col_data.get("template")) if isinstance(col_data, pd.Series) else None ) + source = col_data.get("source") if isinstance(col_data, pd.Series) else None title = col_data.get("title") if isinstance(col_data, pd.Series) else None - - scenario: Optional[Scenario] = None - - # Load or create - sid = _to_int(scenario_id) - if sid is not None: - try: - scenario = Scenario.load(sid) - except Exception as e: - logger.warning( - "Failed to load scenario %s for column '%s': %s", sid, col_name, e - ) - scenario = None - else: - if area_code and end_year is not None: - try: - scenario = Scenario.new(str(area_code), int(end_year)) - except Exception as e: - logger.warning( - "Failed to create scenario for column '%s' (area_code=%s, end_year=%s): %s", - col_name, - area_code, - end_year, - e, - ) - scenario = None - else: - logger.warning( - "MAIN column '%s' missing required fields for creation (area_code/end_year)", - col_name, - ) - scenario = None + sid = self._coerce_int(scenario_id) + scenario = self._load_or_create_scenario(sid, area_code, end_year, col_name) if scenario is None: return None - - # Apply metadata updates if provided - meta_updates: Dict[str, Any] = {} - if private is not None: - meta_updates["private"] = private - if template is not None: - meta_updates["template"] = template - if isinstance(title, str) and title.strip() != "": - meta_updates["title"] = title.strip() - - if meta_updates: - try: - scenario.update_metadata(**meta_updates) - except Exception as e: - logger.warning( - "Failed to update metadata for '%s': %s", scenario.identifier(), e - ) + meta_updates = self._collect_meta_updates(private, template, source, title) + self._apply_metadata(scenario, meta_updates) return scenario diff --git a/src/pyetm/models/sortables.py b/src/pyetm/models/sortables.py index 4a1e690..ea46c14 100644 --- a/src/pyetm/models/sortables.py +++ b/src/pyetm/models/sortables.py @@ -270,14 +270,10 @@ def _from_dataframe(cls, df: pd.DataFrame, **kwargs) -> "Sortables": df = df.to_frame(name=str(df.name)) def _extract_order(series: pd.Series) -> List[Any]: - return ( - series.dropna() - .astype(str) - .map(lambda s: s.strip()) - .replace({"": pd.NA}) - .dropna() - .tolist() - ) + s = series.dropna() + if s.dtype == object: + s = s.astype(str).map(lambda v: v.strip()).replace({"": pd.NA}).dropna() + return s.tolist() items: List[Sortable] = [] for col in df.columns: diff --git a/tests/models/packables/test_custom_curves_pack.py b/tests/models/packables/test_custom_curves_pack.py index 8002023..75c5bdf 100644 --- a/tests/models/packables/test_custom_curves_pack.py +++ b/tests/models/packables/test_custom_curves_pack.py @@ -61,34 +61,6 @@ def empty_series(): assert result is None -def test_from_dataframe_applies_to_scenarios(monkeypatch): - pack = CustomCurvesPack() - scenario = MockScenario("sc1") - - # Patch normalization to pass-through unchanged - monkeypatch.setattr(pack, "_normalize_curves_dataframe", lambda df: df) - - monkeypatch.setattr( - "pyetm.models.packables.custom_curves_pack.CustomCurves", MockCustomCurves - ) - - arrays = [["sc1", "sc1", "sc2"], ["curve_a", "curve_b", "curve_c"]] - index = pd.MultiIndex.from_arrays(arrays, names=("identifier", "curve_key")) - df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=index) - - # Patch apply_identifier_blocks on the class, since 'from_dataframe' calls on self - def fake_apply(self, df_, func): - block = df_.loc[:, pd.IndexSlice["sc1", ["curve_a", "curve_b"]]] - func(scenario, block) - - monkeypatch.setattr(CustomCurvesPack, "apply_identifier_blocks", fake_apply) - - pack.from_dataframe(df) - - assert isinstance(scenario.curves_updated_with, dict) - assert scenario.curves_updated_with["scenario_id"] == "sc1" - - def test_from_dataframe_returns_early_for_none_df(): pack = CustomCurvesPack() assert pack.from_dataframe(None) is None diff --git a/tests/models/test_scenario_packer.py b/tests/models/test_scenario_packer.py index bee44e2..56e549e 100644 --- a/tests/models/test_scenario_packer.py +++ b/tests/models/test_scenario_packer.py @@ -204,8 +204,6 @@ def test_inputs_single_scenario(self, scenario_with_inputs): assert not result.empty assert "input" in result.index.names - assert (scenario_with_inputs.id, "user") in result.columns - assert (scenario_with_inputs.id, "default") in result.columns def test_inputs_multiple_scenarios(self, multiple_scenarios): """Test inputs with multiple scenarios""" @@ -229,22 +227,19 @@ def test_inputs_multiple_scenarios(self, multiple_scenarios): result = packer.inputs() - # Should have unit column plus value/default for each scenario - expected_columns = ( - [("unit", "")] - + [(s.id, "value") for s in multiple_scenarios] - + [(s.id, "default") for s in multiple_scenarios] - ) - assert len(result.columns) >= len(multiple_scenarios) * 2 - - # Should have all unique input keys - all_keys = { - ("wind_capacity", "MW"), - ("unique_input_0", "GW"), - ("unique_input_1", "GW"), - ("unique_input_2", "GW"), + assert set(result.columns) == {s.id for s in multiple_scenarios} + + expected_keys = { + "wind_capacity", + "unique_input_0", + "unique_input_1", + "unique_input_2", } - assert set(result.index) == all_keys + assert set(result.index) == expected_keys + + for i, s in enumerate(multiple_scenarios): + assert result.loc["wind_capacity", s.id] == 1000 + i * 100 + assert result.loc[f"unique_input_{i}", s.id] == i * 10 class TestGqueryResults: From 7f3cc0a6047a1c298651c1d649fca3257105667c Mon Sep 17 00:00:00 2001 From: louispt1 Date: Tue, 12 Aug 2025 12:33:44 +0200 Subject: [PATCH 16/17] Improved tests --- tests/models/packables/test_inputs_pack.py | 172 +++++ .../packables/test_output_curves_pack.py | 43 ++ tests/models/packables/test_query_pack.py | 63 ++ tests/models/packables/test_sortable_pack.py | 77 +++ tests/models/test_scenario_packer.py | 604 +++++++++++++++++- 5 files changed, 958 insertions(+), 1 deletion(-) create mode 100644 tests/models/packables/test_inputs_pack.py create mode 100644 tests/models/packables/test_output_curves_pack.py create mode 100644 tests/models/packables/test_query_pack.py create mode 100644 tests/models/packables/test_sortable_pack.py diff --git a/tests/models/packables/test_inputs_pack.py b/tests/models/packables/test_inputs_pack.py new file mode 100644 index 0000000..222f020 --- /dev/null +++ b/tests/models/packables/test_inputs_pack.py @@ -0,0 +1,172 @@ +import pandas as pd +from unittest.mock import Mock + +from pyetm.models.packables.inputs_pack import InputsPack + + +class DummyInput: + def __init__(self, key, user): + self.key = key + self.user = user + + +def make_scenario(id_val, identifier=None): + s = Mock() + s.id = id_val + if identifier is None: + s.identifier = Mock(return_value=str(id_val)) + else: + s.identifier = ( + Mock(side_effect=identifier) + if callable(identifier) + else Mock(return_value=identifier) + ) + s.update_user_values = Mock() + return s + + +def test_key_for_prefers_short_name_and_fallbacks(): + s1 = make_scenario(1, identifier="id-1") + s2 = make_scenario(2, identifier="id-2") + + pack = InputsPack() + pack.set_scenario_short_names({"1": "S1"}) + + assert pack._key_for(s1) == "S1" # short name wins + assert pack._key_for(s2) == "id-2" # falls back to identifier + + s3 = make_scenario( + 3, identifier=lambda: (_ for _ in ()).throw(RuntimeError("boom")) + ) + assert pack._key_for(s3) == 3 # falls back to id when identifier fails + + +def test_resolve_scenario_by_short_identifier_and_numeric(): + s1, s2, s3 = ( + make_scenario(1, "ID1"), + make_scenario(2, "ID2"), + make_scenario(3, "ID3"), + ) + pack = InputsPack() + pack.add(s1, s2, s3) + pack.set_scenario_short_names({"1": "S1"}) + + assert pack.resolve_scenario("S1") is s1 # short name + assert pack.resolve_scenario("ID2") is s2 # identifier + assert pack.resolve_scenario("3") is s3 # numeric id + assert pack.resolve_scenario("missing") is None + + +def test_to_dataframe_from_iterable_inputs_only(): + s = make_scenario(1, "S1") + s.inputs = [DummyInput("a", 10), DummyInput("b", 20)] + + pack = InputsPack() + pack.add(s) + df = pack.to_dataframe() + + assert list(df.index) == ["a", "b"] + assert "S1" in df.columns or 1 in df.columns + col = "S1" if "S1" in df.columns else 1 + assert df.loc["a", col] == 10 + assert df.loc["b", col] == 20 + assert df.index.name == "input" + + +def test_to_dataframe_from_df_and_series_variants(): + s1 = make_scenario(1, "S1") + s1.inputs = Mock() + s1.inputs.__iter__ = Mock(side_effect=TypeError()) + s1.inputs.to_dataframe = Mock( + return_value=pd.DataFrame( + {"user": [1, 2], "unit": ["MW", "MW"]}, index=["a", "b"] + ).set_index("unit", append=True) + ) + + s2 = make_scenario(2, "S2") + s2.inputs = Mock() + s2.inputs.__iter__ = Mock(side_effect=TypeError()) + s2.inputs.to_dataframe = Mock( + return_value=pd.DataFrame({"value": [3, 4]}, index=["c", "d"]) + ) + + # From Series + s3 = make_scenario(3, "S3") + s3.inputs = Mock() + s3.inputs.__iter__ = Mock(side_effect=TypeError()) + s3.inputs.to_dataframe = Mock(return_value=pd.Series([5], index=["e"])) + + pack = InputsPack() + pack.add(s1, s2, s3) + df = pack.to_dataframe() + + # All keys present + for key in ["a", "b", "c", "d", "e"]: + assert key in df.index + + assert df.loc["a", "S1"] == 1 + assert df.loc["c", "S2"] == 3 + assert df.loc["e", "S3"] == 5 + + +def test_to_dataframe_returns_empty_when_no_data(): + s = make_scenario(1, "S1") + s.inputs = Mock() + s.inputs.__iter__ = Mock(side_effect=TypeError()) + s.inputs.to_dataframe = Mock(return_value=pd.DataFrame()) + + pack = InputsPack() + pack.add(s) + df = pack.to_dataframe() + assert df.empty + + +def test_from_dataframe_parses_and_updates(caplog): + s1 = make_scenario(1, "S1") + s2 = make_scenario(2, "S2") + s3 = make_scenario(3, "S3") + + pack = InputsPack() + pack.add(s1, s2, s3) + pack.set_scenario_short_names({"1": "Short1"}) + + df = pd.DataFrame( + [ + ["input", "Short1", "3", "Unknown"], + ["a", 1, 10, 99], + ["b", " ", "nan", 88], + ] + ) + + with caplog.at_level("WARNING"): + pack.from_dataframe(df) + + s1.update_user_values.assert_called_once_with({"a": 1}) + s3.update_user_values.assert_called_once_with({"a": 10}) + # Unknown column should produce a warning and not call any scenario + assert "Could not find scenario for PARAMETERS column label" in caplog.text + + +def test_from_dataframe_handles_update_exception(caplog): + s1 = make_scenario(1, "S1") + s1.update_user_values.side_effect = RuntimeError("fail") + + pack = InputsPack() + pack.add(s1) + + df = pd.DataFrame([["input", "S1"], ["a", 1]]) + + with caplog.at_level("WARNING"): + pack.from_dataframe(df) + assert "Failed updating inputs for scenario" in caplog.text + + +def test_from_dataframe_early_returns(): + pack = InputsPack() + # None and empty + pack.from_dataframe(None) + pack.from_dataframe(pd.DataFrame()) + # No header rows + pack.from_dataframe(pd.DataFrame([[None], [None]])) + # After header but no data columns + pack.from_dataframe(pd.DataFrame([["only-one-col"], [1]])) diff --git a/tests/models/packables/test_output_curves_pack.py b/tests/models/packables/test_output_curves_pack.py new file mode 100644 index 0000000..160682d --- /dev/null +++ b/tests/models/packables/test_output_curves_pack.py @@ -0,0 +1,43 @@ +import pandas as pd +from unittest.mock import Mock + +from pyetm.models.packables.output_curves_pack import OutputCurvesPack + + +def make_scenario(id_val="S"): + s = Mock() + s.identifier = Mock(return_value=str(id_val)) + return s + + +def test_to_dataframe_collects_series(): + s = make_scenario() + s.all_output_curves.return_value = [ + pd.Series([1, 2], name="c1"), + pd.Series([3, 4], name="c2"), + ] + + pack = OutputCurvesPack() + pack.add(s) + + df = pack.to_dataframe() + assert not df.empty + assert "c1" in df.columns.get_level_values(1) or "c1" in df.columns + + +def test_to_dataframe_handles_exception_and_empty(caplog): + s = make_scenario() + s.all_output_curves.side_effect = RuntimeError("fail") + + pack = OutputCurvesPack() + pack.add(s) + + with caplog.at_level("WARNING"): + df = pack.to_dataframe() + assert df.empty + assert "Failed extracting output curves" in caplog.text + + s.all_output_curves.side_effect = None + s.all_output_curves.return_value = [] + df2 = pack.to_dataframe() + assert df2.empty diff --git a/tests/models/packables/test_query_pack.py b/tests/models/packables/test_query_pack.py new file mode 100644 index 0000000..e046620 --- /dev/null +++ b/tests/models/packables/test_query_pack.py @@ -0,0 +1,63 @@ +import pandas as pd +from unittest.mock import Mock + +from pyetm.models.packables.query_pack import QueryPack + + +def make_scenario(id_val="S"): + s = Mock() + s.identifier = Mock(return_value=str(id_val)) + s.results = Mock( + return_value=pd.DataFrame( + {"future": [1], "unit": ["MW"]}, index=["q1"] + ).set_index("unit", append=True) + ) + s.add_queries = Mock() + return s + + +def test_to_dataframe_calls_results_and_builds(caplog): + s1 = make_scenario("S1") + s2 = make_scenario("S2") + + pack = QueryPack() + pack.add(s1, s2) + + df = pack.to_dataframe() + assert not df.empty + assert "S1" in df.columns or "S2" in df.columns + + +def test_to_dataframe_handles_exception(caplog): + s = make_scenario() + s.results.side_effect = RuntimeError("bad") + + pack = QueryPack() + pack.add(s) + + with caplog.at_level("WARNING"): + df = pack.to_dataframe() + assert df.empty + assert "Failed building gquery results" in caplog.text + + +def test_from_dataframe_applies_unique_queries(): + s1 = make_scenario() + s2 = make_scenario() + + pack = QueryPack() + pack.add(s1, s2) + + df = pd.DataFrame({"queries": ["a", " a ", "b", None, "nan", "B"]}) + pack.from_dataframe(df) + + # Should deduplicate and strip, keep case of non-'nan' values + expected = ["a", "b", "B"] + s1.add_queries.assert_called_once_with(expected) + s2.add_queries.assert_called_once_with(expected) + + +def test_from_dataframe_early_returns(): + pack = QueryPack() + pack.from_dataframe(None) + pack.from_dataframe(pd.DataFrame()) diff --git a/tests/models/packables/test_sortable_pack.py b/tests/models/packables/test_sortable_pack.py new file mode 100644 index 0000000..6f7eda2 --- /dev/null +++ b/tests/models/packables/test_sortable_pack.py @@ -0,0 +1,77 @@ +import pandas as pd +from unittest.mock import Mock + +from pyetm.models.packables.sortable_pack import SortablePack + + +def make_scenario(id_val="S1"): + s = Mock() + s.identifier = Mock(return_value=str(id_val)) + s.sortables = Mock() + return s + + +def test_to_dataframe_builds_from_scenarios(): + s1 = make_scenario("S1") + s2 = make_scenario("S2") + s1.sortables.to_dataframe.return_value = pd.DataFrame({"a": [1]}) + s2.sortables.to_dataframe.return_value = pd.DataFrame({"b": [2]}) + + pack = SortablePack() + pack.add(s1, s2) + + df = pack.to_dataframe() + assert not df.empty + + +def test_to_dataframe_handles_exception_and_empty(caplog): + s = make_scenario("S") + s.sortables.to_dataframe.side_effect = RuntimeError("boom") + pack = SortablePack() + pack.add(s) + + with caplog.at_level("WARNING"): + df = pack.to_dataframe() + assert df.empty + assert "Failed extracting sortables" in caplog.text + + s.sortables.to_dataframe.side_effect = None + s.sortables.to_dataframe.return_value = pd.DataFrame() + df2 = pack.to_dataframe() + assert df2.empty + + +def test_from_dataframe_multiindex_and_single_block(monkeypatch): + s1 = make_scenario("S1") + s2 = make_scenario("S2") + pack = SortablePack() + pack.add(s1, s2) + cols = pd.MultiIndex.from_tuples([("S1", "a"), ("S2", "a")]) + df = pd.DataFrame([[1, 2]], columns=cols) + monkeypatch.setattr(pack, "_normalize_sortables_dataframe", lambda d: d) + pack.from_dataframe(df) + + assert s1.set_sortables_from_dataframe.called + assert s2.set_sortables_from_dataframe.called + + +def test_from_dataframe_normalize_errors_and_empty(caplog, monkeypatch): + s = make_scenario("S") + pack = SortablePack() + pack.add(s) + + with caplog.at_level("WARNING"): + monkeypatch.setattr( + pack, + "_normalize_sortables_dataframe", + lambda d: (_ for _ in ()).throw(RuntimeError("bad")), + ) + pack.from_dataframe(pd.DataFrame([[1]])) + assert "Failed to normalize sortables sheet" in caplog.text + + # empty after normalize + monkeypatch.setattr( + pack, "_normalize_sortables_dataframe", lambda d: pd.DataFrame() + ) + pack.from_dataframe(pd.DataFrame([[1]])) + assert not s.set_sortables_from_dataframe.called diff --git a/tests/models/test_scenario_packer.py b/tests/models/test_scenario_packer.py index 56e549e..919a38f 100644 --- a/tests/models/test_scenario_packer.py +++ b/tests/models/test_scenario_packer.py @@ -1,6 +1,5 @@ import pytest import pandas as pd -import numpy as np import tempfile import os from unittest.mock import Mock, patch @@ -11,6 +10,9 @@ SortablePack, ) from pyetm.models import ScenarioPacker, Scenario +from pyetm.models.packables.inputs_pack import InputsPack +from pyetm.models.packables.query_pack import QueryPack +from pyetm.models.custom_curves import CustomCurves class TestScenarioPackerInit: @@ -580,3 +582,603 @@ def test_get_summary_with_data(self, multiple_scenarios): class TestFromExcel: def test_from_excel(self): ScenarioPacker.from_excel("tests/fixtures/my_input_excel.xlsx") + + +class TestScenarioPackerHelpers: + + def test_first_non_empty_row_index(self): + packer = ScenarioPacker() + + assert packer._first_non_empty_row_index(None) is None + + empty = pd.DataFrame([[float("nan")], [float("nan")]]) + assert packer._first_non_empty_row_index(empty) is None + + def test_is_empty_or_helper(self): + packer = ScenarioPacker() + helpers = {"sortables", "hour", "index"} + + assert packer._is_empty_or_helper(123, helpers) is True + assert packer._is_empty_or_helper(" ", helpers) is True + assert packer._is_empty_or_helper("NaN", helpers) is True + assert packer._is_empty_or_helper("hour", helpers) is True + assert packer._is_empty_or_helper("value", helpers) is False + + def test_normalize_sheet(self): + packer = ScenarioPacker() + + # None -> empty + assert packer._normalize_sheet(None, helper_names=set()).empty + + # Build a frame with header at row 1 (0-based) + raw = pd.DataFrame( + [ + [None, None, None], + ["index", "heat_network", "value"], # header + [1, "hn", 10], + [2, "hn", 20], + ] + ) + + norm = packer._normalize_sheet( + raw, + helper_names={"index"}, + reset_index=False, + rename_map={"heat_network": "heat_network_lt"}, + ) + + # index column removed, rename applied, index preserved + assert list(norm.columns) == ["heat_network_lt", "value"] + assert norm.index.tolist() == [2, 3] # original DataFrame indices kept + + def test_coerce_bool(self): + packer = ScenarioPacker() + na = float("nan") + assert packer._coerce_bool(None) is None + assert packer._coerce_bool(na) is None + assert packer._coerce_bool(True) is True + assert packer._coerce_bool(False) is False + assert packer._coerce_bool(1) is True + assert packer._coerce_bool(0.0) is False + assert packer._coerce_bool("yes") is True + assert packer._coerce_bool("No") is False + assert packer._coerce_bool("1") is True + assert packer._coerce_bool("maybe") is None + + def test_coerce_int(self): + packer = ScenarioPacker() + na = float("nan") + assert packer._coerce_int(None) is None + assert packer._coerce_int(na) is None + assert packer._coerce_int(5) == 5 + assert packer._coerce_int(5.9) == 5 + assert packer._coerce_int("7") == 7 + assert packer._coerce_int("abc") is None + + def test_load_or_create_scenario_load_new_and_failures(self, monkeypatch): + packer = ScenarioPacker() + + loaded = Mock(spec=Scenario) + created = Mock(spec=Scenario) + + # Successful load + monkeypatch.setattr(Scenario, "load", staticmethod(lambda sid: loaded)) + out = packer._load_or_create_scenario(42, "nl2015", 2050, "COL") + assert out is loaded + + # Failing load -> None + def boom(_): + raise RuntimeError("bad") + + monkeypatch.setattr(Scenario, "load", staticmethod(boom)) + assert packer._load_or_create_scenario(42, "nl2015", 2050, "COL") is None + + # Successful new + monkeypatch.setattr(Scenario, "new", staticmethod(lambda a, y: created)) + out = packer._load_or_create_scenario(None, "de", 2030, "COL2") + assert out is created + + # Failing new -> None + def boom2(_, __): + raise ValueError("bad") + + monkeypatch.setattr(Scenario, "new", staticmethod(boom2)) + assert packer._load_or_create_scenario(None, "nl", 2050, "C") is None + + # Missing fields -> None + assert packer._load_or_create_scenario(None, None, None, "C") is None + + def test_collect_and_apply_metadata(self): + packer = ScenarioPacker() + meta = packer._collect_meta_updates(True, 7, " src ", " title ") + assert meta == { + "private": True, + "template": 7, + "source": "src", + "title": "title", + } + + # empty strings trimmed out + meta = packer._collect_meta_updates(None, None, " ", "") + assert meta == {} + + # apply updates + scenario = Mock(spec=Scenario) + packer._apply_metadata(scenario, {"private": False}) + scenario.update_metadata.assert_called_once_with(private=False) + + # swallow exceptions + scenario.update_metadata.side_effect = RuntimeError("boom") + packer._apply_metadata(scenario, {"private": True}) # should not raise + + # no updates does nothing + scenario.update_metadata.reset_mock() + packer._apply_metadata(scenario, {}) + scenario.update_metadata.assert_not_called() + + def test_extract_scenario_sheet_info_series_and_df(self): + packer = ScenarioPacker() + + ser = pd.Series( + { + "short_name": "S", + "sortables": "SORT1", + "custom_curves": "CUR1", + }, + name="COL1", + ) + out = packer._extract_scenario_sheet_info(ser) + assert out == { + "COL1": {"short_name": "S", "sortables": "SORT1", "custom_curves": "CUR1"} + } + + df = pd.DataFrame( + { + "A": {"short_name": None, "sortables": "S_A", "custom_curves": None}, + "B": {"short_name": "B_S", "sortables": None, "custom_curves": "C_B"}, + } + ) + out2 = packer._extract_scenario_sheet_info(df) + assert out2["A"]["short_name"] == "A" + assert out2["A"]["sortables"] == "S_A" + assert out2["A"]["custom_curves"] is None + assert out2["B"]["short_name"] == "B_S" + assert out2["B"]["custom_curves"] == "C_B" + + def test_process_single_scenario_sortables(self): + packer = ScenarioPacker() + scenario = Mock(spec=Scenario) + + # Build a sheet where header row contains helpers + target column to be renamed + raw = pd.DataFrame( + [ + [None, None, None], + ["sortables", "heat_network", "hour"], + [None, "lt", 1], + [None, "mt", 2], + ] + ) + + packer._process_single_scenario_sortables(scenario, raw) + assert scenario.set_sortables_from_dataframe.called + df_arg = scenario.set_sortables_from_dataframe.call_args[0][0] + assert "heat_network_lt" in df_arg.columns + assert "hour" not in df_arg.columns + + def test_process_single_scenario_sortables_empty_after_normalize(self): + packer = ScenarioPacker() + scenario = Mock(spec=Scenario) + + raw = pd.DataFrame( + [ + [None, None], + ["sortables", "hour"], + [None, 1], + ] + ) + + packer._process_single_scenario_sortables(scenario, raw) + scenario.set_sortables_from_dataframe.assert_not_called() + + def test_process_single_scenario_curves_success_and_error(self, monkeypatch): + packer = ScenarioPacker() + scenario = Mock(spec=Scenario) + scenario.id = 999 + + raw = pd.DataFrame( + [ + [None, None], + ["custom_curves", "value"], + ["curve_1", 1.0], + ["curve_2", 2.0], + ] + ) + + dummy_curves = Mock(spec=CustomCurves) + monkeypatch.setattr( + CustomCurves, + "_from_dataframe", + staticmethod(lambda df, scenario_id: dummy_curves), + ) + packer._process_single_scenario_curves(scenario, raw) + scenario.update_custom_curves.assert_called_once_with(dummy_curves) + scenario.update_custom_curves.reset_mock() + + def boom(_df, scenario_id): + raise RuntimeError("bad curves") + + monkeypatch.setattr(CustomCurves, "_from_dataframe", staticmethod(boom)) + packer._process_single_scenario_curves(scenario, raw) + scenario.update_custom_curves.assert_not_called() + + def test_process_single_scenario_curves_empty_after_normalize(self): + packer = ScenarioPacker() + scenario = Mock(spec=Scenario) + scenario.id = 1 + + raw = pd.DataFrame( + [ + [None], + ["custom_curves"], + [None], + ] + ) + packer._process_single_scenario_curves(scenario, raw) + scenario.update_custom_curves.assert_not_called() + + +class TestSetupScenarioFromMainColumn: + + def test_setup_scenario_from_main_column_loads_and_updates(self, monkeypatch): + packer = ScenarioPacker() + scenario = Mock(spec=Scenario) + scenario.identifier = Mock(return_value="SID") + monkeypatch.setattr(Scenario, "load", staticmethod(lambda sid: scenario)) + + ser = pd.Series( + { + "scenario_id": "101", + "area_code": "nl2015", + "end_year": 2050, + "private": "yes", + "template": "7", + "source": " src ", + "title": " title ", + } + ) + + out = packer._setup_scenario_from_main_column("COL", ser) + assert out is scenario + scenario.update_metadata.assert_called_once() + + def test_setup_scenario_from_main_column_creates(self, monkeypatch): + packer = ScenarioPacker() + scenario = Mock(spec=Scenario) + scenario.identifier = Mock(return_value="NEW") + monkeypatch.setattr(Scenario, "new", staticmethod(lambda a, y: scenario)) + + ser = pd.Series( + { + "scenario_id": None, + "area_code": "de", + "end_year": 2030, + "private": 0, + "template": None, + } + ) + + out = packer._setup_scenario_from_main_column("COL", ser) + assert out is scenario + + def test_setup_scenario_from_main_column_returns_none_on_fail(self, monkeypatch): + packer = ScenarioPacker() + monkeypatch.setattr( + ScenarioPacker, "_load_or_create_scenario", lambda self, *a, **k: None + ) + ser = pd.Series({"scenario_id": None, "area_code": None, "end_year": None}) + assert packer._setup_scenario_from_main_column("COL", ser) is None + + +class TestFromExcelDetailed: + + def test_from_excel_full_flow(self, tmp_path, monkeypatch): + # Prepare MAIN with two scenarios: one load, one create + main = pd.DataFrame( + { + "S1": { + "scenario_id": 101, + "area_code": "nl2015", + "end_year": 2050, + "private": "yes", + "template": 3, + "source": "source1", + "title": "Title 1", + "short_name": "Short1", + "sortables": "S1_SORT", + "custom_curves": "S1_CURVES", + }, + "S2": { + "scenario_id": None, + "area_code": "de", + "end_year": 2030, + "private": 0, + "template": None, + "source": "", + "title": "", + "short_name": None, + "sortables": "S2_SORT", + "custom_curves": None, + }, + } + ) + + # Other sheets + params = pd.DataFrame([["helper", "value"], ["input_key", 1]]) + gqueries = pd.DataFrame([["gquery", "future"], ["co2_emissions", 100]]) + s1_sort = pd.DataFrame([[None, None], ["sortables", "value"], ["a", 1]]) + s2_sort = pd.DataFrame([[None, None], ["sortables", "value"], ["b", 2]]) + s1_curves = pd.DataFrame([[None, None], ["custom_curves", "value"], ["x", 1]]) + + path = tmp_path / "import.xlsx" + with pd.ExcelWriter(path, engine="xlsxwriter") as writer: + main.to_excel(writer, sheet_name="MAIN") + params.to_excel(writer, sheet_name="PARAMETERS", header=False, index=False) + gqueries.to_excel(writer, sheet_name="GQUERIES", header=False, index=False) + s1_sort.to_excel(writer, sheet_name="S1_SORT", header=False, index=False) + s2_sort.to_excel(writer, sheet_name="S2_SORT", header=False, index=False) + s1_curves.to_excel( + writer, sheet_name="S1_CURVES", header=False, index=False + ) + + # Patch loading/creating and pack interactions + s_loaded = Mock(spec=Scenario) + s_loaded.id = "101" + s_loaded.identifier = Mock(return_value="101") + s_created = Mock(spec=Scenario) + s_created.id = "created" + s_created.identifier = Mock(return_value="created") + + monkeypatch.setattr(Scenario, "load", staticmethod(lambda sid: s_loaded)) + monkeypatch.setattr(Scenario, "new", staticmethod(lambda a, y: s_created)) + + # Spy on inputs and queries imports + with ( + patch.object(InputsPack, "set_scenario_short_names") as set_sn, + patch.object(InputsPack, "from_dataframe") as from_df, + patch.object(QueryPack, "from_dataframe") as gq_from_df, + patch.object( + ScenarioPacker, "_process_single_scenario_sortables" + ) as proc_sort, + patch.object( + ScenarioPacker, "_process_single_scenario_curves" + ) as proc_curves, + ): + packer = ScenarioPacker.from_excel(str(path)) + + assert isinstance(packer, ScenarioPacker) + assert s_loaded in packer._scenarios() + assert s_created in packer._scenarios() + + set_sn.assert_called_once() + from_df.assert_called_once() + gq_from_df.assert_called_once() + + # Called once for each scenario with a sortables sheet + assert proc_sort.call_count == 2 + proc_curves.assert_called_once() + + def test_from_excel_missing_or_bad_main(self, tmp_path): + packer = ScenarioPacker.from_excel(str(tmp_path / "bad.xlsx")) + assert isinstance(packer, ScenarioPacker) + assert len(packer._scenarios()) == 0 + + # File with no MAIN sheet + path = tmp_path / "no_main.xlsx" + with pd.ExcelWriter(path, engine="xlsxwriter") as writer: + pd.DataFrame([[1]]).to_excel(writer, sheet_name="OTHER") + packer2 = ScenarioPacker.from_excel(str(path)) + assert isinstance(packer2, ScenarioPacker) + assert len(packer2._scenarios()) == 0 + + # File with empty MAIN sheet + path2 = tmp_path / "empty_main.xlsx" + with pd.ExcelWriter(path2, engine="xlsxwriter") as writer: + pd.DataFrame().to_excel(writer, sheet_name="MAIN") + packer3 = ScenarioPacker.from_excel(str(path2)) + assert isinstance(packer3, ScenarioPacker) + assert len(packer3._scenarios()) == 0 + + def test_from_excel_parameters_and_gqueries_errors(self, tmp_path, monkeypatch): + # Prepare a minimal MAIN and both PARAMETERS and GQUERIES sheets + main = pd.DataFrame( + { + "S": { + "scenario_id": None, + "area_code": "nl2015", + "end_year": 2050, + "sortables": None, + "custom_curves": None, + } + } + ) + params = pd.DataFrame([["helper", "value"], ["input_key", 1]]) + gqueries = pd.DataFrame([["gquery", "future"], ["co2_emissions", 100]]) + + path = tmp_path / "errs.xlsx" + with pd.ExcelWriter(path, engine="xlsxwriter") as writer: + main.to_excel(writer, sheet_name="MAIN") + params.to_excel(writer, sheet_name="PARAMETERS", header=False, index=False) + gqueries.to_excel(writer, sheet_name="GQUERIES", header=False, index=False) + + # Create returns a simple scenario + s_created = Mock(spec=Scenario) + s_created.id = "created" + s_created.identifier = Mock(return_value="created") + monkeypatch.setattr(Scenario, "new", staticmethod(lambda a, y: s_created)) + + with ( + patch.object(InputsPack, "set_scenario_short_names") as set_sn, + patch.object( + InputsPack, "from_dataframe", side_effect=RuntimeError("bad params") + ), + patch.object( + QueryPack, "from_dataframe", side_effect=RuntimeError("bad gq") + ), + ): + packer = ScenarioPacker.from_excel(str(path)) + + assert isinstance(packer, ScenarioPacker) + # Scenario was still created even if imports failed + assert s_created in packer._scenarios() + set_sn.assert_called_once() + + def test_from_excel_gqueries_sheet_name_fallback(self, tmp_path, monkeypatch): + main = pd.DataFrame( + {"S": {"scenario_id": None, "area_code": "nl2015", "end_year": 2050}} + ) + + path = tmp_path / "gq_fallback.xlsx" + with pd.ExcelWriter(path, engine="xlsxwriter") as writer: + main.to_excel(writer, sheet_name="MAIN") + pd.DataFrame([["gquery"], ["total_costs"]]).to_excel( + writer, sheet_name="GQ2", header=False, index=False + ) + + s_created = Mock(spec=Scenario) + s_created.id = "created" + s_created.identifier = Mock(return_value="created") + monkeypatch.setattr(Scenario, "new", staticmethod(lambda a, y: s_created)) + + with patch.object(QueryPack, "sheet_name", "GQ2"): + with patch.object(QueryPack, "from_dataframe") as gq_from_df: + packer = ScenarioPacker.from_excel(str(path)) + assert s_created in packer._scenarios() + gq_from_df.assert_called_once() + + def test_from_excel_processing_sortables_and_curves_errors( + self, tmp_path, monkeypatch + ): + main = pd.DataFrame( + { + "S": { + "scenario_id": None, + "area_code": "nl2015", + "end_year": 2050, + "sortables": "S_SORT", + "custom_curves": "S_CURVES", + } + } + ) + + path = tmp_path / "proc_errs.xlsx" + with pd.ExcelWriter(path, engine="xlsxwriter") as writer: + main.to_excel(writer, sheet_name="MAIN") + pd.DataFrame([[None], ["sortables"], ["a"]]).to_excel( + writer, sheet_name="S_SORT", header=False, index=False + ) + pd.DataFrame([[None], ["custom_curves"], ["x"]]).to_excel( + writer, sheet_name="S_CURVES", header=False, index=False + ) + + s_created = Mock(spec=Scenario) + s_created.id = "created" + s_created.identifier = Mock(return_value="created") + monkeypatch.setattr(Scenario, "new", staticmethod(lambda a, y: s_created)) + + with ( + patch.object( + ScenarioPacker, + "_process_single_scenario_sortables", + side_effect=RuntimeError("bad sort"), + ), + patch.object( + ScenarioPacker, + "_process_single_scenario_curves", + side_effect=RuntimeError("bad cur"), + ), + ): + packer = ScenarioPacker.from_excel(str(path)) + assert isinstance(packer, ScenarioPacker) + assert s_created in packer._scenarios() + + def test_from_excel_setup_column_exception_and_all_fail( + self, tmp_path, monkeypatch + ): + # Two columns: first raises, second returns scenario + main = pd.DataFrame( + { + "A": {"scenario_id": None, "area_code": "nl2015", "end_year": 2050}, + "B": {"scenario_id": None, "area_code": "de", "end_year": 2030}, + } + ) + path = tmp_path / "columns_mix.xlsx" + with pd.ExcelWriter(path, engine="xlsxwriter") as writer: + main.to_excel(writer, sheet_name="MAIN") + + # Patch method to raise for A and create for B + def setup(col_name, col_ser): + if col_name == "A": + raise RuntimeError("boom") + s = Mock(spec=Scenario) + s.id = "BID" + s.identifier = Mock(return_value="BID") + return s + + with patch.object( + ScenarioPacker, "_setup_scenario_from_main_column", side_effect=setup + ): + packer = ScenarioPacker.from_excel(str(path)) + assert any(s.id == "BID" for s in packer._scenarios()) + + # All columns fail -> 0 scenarios, early return + with patch.object( + ScenarioPacker, + "_setup_scenario_from_main_column", + side_effect=RuntimeError("e"), + ): + packer2 = ScenarioPacker.from_excel(str(path)) + assert len(packer2._scenarios()) == 0 + + def test_from_excel_missing_parameters_sheet_parse_error( + self, tmp_path, monkeypatch + ): + main = pd.DataFrame( + {"S": {"scenario_id": None, "area_code": "nl2015", "end_year": 2050}} + ) + path = tmp_path / "no_params.xlsx" + with pd.ExcelWriter(path, engine="xlsxwriter") as writer: + main.to_excel(writer, sheet_name="MAIN") + + s_created = Mock(spec=Scenario) + s_created.id = "created" + s_created.identifier = Mock(return_value="created") + monkeypatch.setattr(Scenario, "new", staticmethod(lambda a, y: s_created)) + packer = ScenarioPacker.from_excel(str(path)) + assert s_created in packer._scenarios() + + def test_from_excel_gqueries_parse_raises(self, tmp_path, monkeypatch): + main = pd.DataFrame( + {"S": {"scenario_id": None, "area_code": "nl2015", "end_year": 2050}} + ) + path = tmp_path / "gq_parse_err.xlsx" + with pd.ExcelWriter(path, engine="xlsxwriter") as writer: + main.to_excel(writer, sheet_name="MAIN") + pd.DataFrame([["gquery"], ["total_costs"]]).to_excel( + writer, sheet_name="GQUERIES", header=False, index=False + ) + + s_created = Mock(spec=Scenario) + s_created.id = "created" + s_created.identifier = Mock(return_value="created") + monkeypatch.setattr(Scenario, "new", staticmethod(lambda a, y: s_created)) + + original_parse = pd.ExcelFile.parse + + def parse_proxy(self, sheet_name, *a, **k): + if sheet_name == "GQUERIES": + raise ValueError("bad parse") + return original_parse(self, sheet_name, *a, **k) + + with patch.object(pd.ExcelFile, "parse", parse_proxy): + packer = ScenarioPacker.from_excel(str(path)) + assert s_created in packer._scenarios() From 01659bbafa3af4bd4a2534e5e590c933a5ecb497 Mon Sep 17 00:00:00 2001 From: louispt1 Date: Wed, 13 Aug 2025 09:39:07 +0200 Subject: [PATCH 17/17] refining notebooks --- .../advanced_scenario_example.ipynb | 0 examples/create_and_update_a_scenario.ipynb | 84 +- .../agriculture_electricity_curve.csv | 8760 ----------------- .../electric_vehicle_profile_5_curve.csv | 8760 ----------------- .../interconnector_8_price_curve.csv | 8760 ----------------- examples/custom_curve_from_df.ipynb | 173 - examples/full_multi_scenario_flow.ipynb | 174 + examples/myc_notebook_for_tim.ipynb | 5 +- examples/scenario_to_excel.ipynb | 2 +- src/pyetm/models/__init__.py | 1 + src/pyetm/models/custom_curves.py | 5 +- src/pyetm/models/inputs.py | 1 - src/pyetm/models/output_curves.py | 5 +- src/pyetm/models/scenario.py | 26 +- src/pyetm/models/scenario_packer.py | 6 +- src/pyetm/models/scenarios.py | 48 + src/pyetm/utils/excel.py | 92 +- tests/utils/test_excel.py | 85 +- 18 files changed, 315 insertions(+), 26672 deletions(-) rename examples/{ => advanced_examples}/advanced_scenario_example.ipynb (100%) delete mode 100644 examples/curve_examples/agriculture_electricity_curve.csv delete mode 100644 examples/curve_examples/electric_vehicle_profile_5_curve.csv delete mode 100644 examples/curve_examples/interconnector_8_price_curve.csv delete mode 100644 examples/custom_curve_from_df.ipynb create mode 100644 examples/full_multi_scenario_flow.ipynb create mode 100644 src/pyetm/models/scenarios.py diff --git a/examples/advanced_scenario_example.ipynb b/examples/advanced_examples/advanced_scenario_example.ipynb similarity index 100% rename from examples/advanced_scenario_example.ipynb rename to examples/advanced_examples/advanced_scenario_example.ipynb diff --git a/examples/create_and_update_a_scenario.ipynb b/examples/create_and_update_a_scenario.ipynb index 380ce50..0fa51bd 100644 --- a/examples/create_and_update_a_scenario.ipynb +++ b/examples/create_and_update_a_scenario.ipynb @@ -20,21 +20,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "3ada4b30", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Environment setup complete\n", - " Using ETM API at https://beta.engine.energytransitionmodel.com/api/v3\n", - " Token loaded? True\n", - "API connection ready\n" - ] - } - ], + "outputs": [], "source": [ "from example_helpers import setup_notebook\n", "from pyetm.models import Scenario\n", @@ -52,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "4770e6a9", "metadata": {}, "outputs": [], @@ -77,19 +66,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "5a1549ac", "metadata": {}, - "outputs": [ - { - "ename": "ScenarioError", - "evalue": "Could not update user values: {'external_coupling_industry_chemical_other_burner_crude_oil_share': ['user: Input should be a valid number, unable to parse string as a number']}", - "output_type": "error", - "traceback": [ - "\u001b[31mScenarioError\u001b[39m\u001b[31m:\u001b[39m Could not update user values: {'external_coupling_industry_chemical_other_burner_crude_oil_share': ['user: Input should be a valid number, unable to parse string as a number']}\n" - ] - } - ], + "outputs": [], "source": [ "scenario.update_user_values({\n", " \"co_firing_biocoal_share\": 80.0,\n", @@ -107,31 +87,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "7fc4dc21", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Area: nl2019\n", - "End year: 2050\n", - "Start year: 2019\n", - "Version: beta\n", - "Modified inputs: 1\n", - "First input: co_firing_biocoal_share = 80.0\n" - ] - }, - { - "ename": "IndexError", - "evalue": "list index out of range", - "output_type": "error", - "traceback": [ - "\u001b[31mIndexError\u001b[39m\u001b[31m:\u001b[39m list index out of range\n" - ] - } - ], + "outputs": [], "source": [ "print(f\"Area: {scenario.area_code}\")\n", "print(f\"End year: {scenario.end_year}\")\n", @@ -153,18 +112,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "c6a65f6a", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "False\n" - ] - } - ], + "outputs": [], "source": [ "scenario.update_metadata(\n", " private= True,\n", @@ -195,19 +146,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "98ab2f5c", "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'Scenario' object has no attribute 'remove_inputs'", - "output_type": "error", - "traceback": [ - "\u001b[31mAttributeError\u001b[39m\u001b[31m:\u001b[39m 'Scenario' object has no attribute 'remove_inputs'\n" - ] - } - ], + "outputs": [], "source": [ "scenario.remove_user_values([\"co_firing_biocoal_share\"])\n", "user_vals = scenario.user_values()\n", @@ -217,7 +159,7 @@ ], "metadata": { "kernelspec": { - "display_name": "pyetm-FWBOHxp3", + "display_name": "pyetm-qKH2ozgc", "language": "python", "name": "python3" }, @@ -231,7 +173,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.11" + "version": "3.12.9" } }, "nbformat": 4, diff --git a/examples/curve_examples/agriculture_electricity_curve.csv b/examples/curve_examples/agriculture_electricity_curve.csv deleted file mode 100644 index 8c5c7b9..0000000 --- a/examples/curve_examples/agriculture_electricity_curve.csv +++ /dev/null @@ -1,8760 +0,0 @@ -3.083099492094933e-08 -3.2365569328779384e-08 -3.1947049035734825e-08 -3.2365569328779384e-08 -3.278408962182394e-08 -3.292359638617213e-08 -3.3063103150520315e-08 -3.390014373660944e-08 -3.390014373660944e-08 -3.2365569328779384e-08 -3.348162344356488e-08 -3.362113020791307e-08 -3.348162344356488e-08 -3.320260991486851e-08 -3.278408962182394e-08 -3.348162344356488e-08 -3.417915726530581e-08 -3.613225196618043e-08 -3.5713731673135874e-08 -3.557422490878769e-08 -3.5713731673135874e-08 -3.627175873052862e-08 -3.5713731673135874e-08 -3.557422490878769e-08 -3.180754227138664e-08 -3.2644582857475756e-08 -3.22260625644312e-08 -3.22260625644312e-08 -3.250507609312757e-08 -3.3342116679216694e-08 -3.724830608096593e-08 -3.027296786355658e-08 -4.199153606880429e-08 -4.478167135576803e-08 -4.631624576359808e-08 -4.687427282099083e-08 -4.366561724098254e-08 -4.492117812011622e-08 -4.492117812011622e-08 -4.310759018358978e-08 -3.8085346667055053e-08 -3.027296786355658e-08 -2.6227271697459155e-08 -2.5808751404414597e-08 -2.4971710818325472e-08 -2.2739602588754482e-08 -2.0367987594835303e-08 -3.487669108704675e-08 -3.2644582857475756e-08 -3.3063103150520315e-08 -3.22260625644312e-08 -3.1947049035734825e-08 -3.292359638617213e-08 -3.417915726530581e-08 -3.892238725314418e-08 -3.22260625644312e-08 -4.575821870620534e-08 -4.840884722882089e-08 -4.93853945792582e-08 -5.008292840099913e-08 -4.6595259292294455e-08 -4.8548353993169076e-08 -4.812983370012452e-08 -4.5897725470553524e-08 -3.961992107488511e-08 -3.083099492094933e-08 -2.6645791990503717e-08 -2.5808751404414597e-08 -2.4413683760932724e-08 -2.2600095824406296e-08 -2.0367987594835303e-08 -3.5295211380091315e-08 -3.2644582857475756e-08 -3.3342116679216694e-08 -3.250507609312757e-08 -3.292359638617213e-08 -3.4039650500957626e-08 -3.5992745201832246e-08 -4.115449548271517e-08 -3.320260991486851e-08 -4.729279311403539e-08 -5.008292840099913e-08 -5.0919968987088255e-08 -5.175700957317738e-08 -4.910638105056182e-08 -5.0919968987088255e-08 -5.147799604448101e-08 -4.966440810795457e-08 -4.394463076967891e-08 -3.5016197851394936e-08 -3.0970501685297515e-08 -2.9993954334860204e-08 -2.8877900220074708e-08 -2.6924805519200093e-08 -2.385565670353998e-08 -4.031745489662604e-08 -3.6550772259225e-08 -3.696929255226956e-08 -3.627175873052862e-08 -3.613225196618043e-08 -3.5713731673135874e-08 -3.627175873052862e-08 -4.045696166097423e-08 -3.069148815660114e-08 -4.1852029304456096e-08 -4.408413753402709e-08 -4.492117812011622e-08 -4.520019164881259e-08 -4.213104283315248e-08 -4.2689069890545226e-08 -4.1712522540107916e-08 -3.892238725314418e-08 -3.417915726530581e-08 -2.9017406984422894e-08 -2.5250724347021848e-08 -2.4274176996584538e-08 -2.3297629646147227e-08 -2.1902562002665358e-08 -2.008897406613893e-08 -3.459767755835038e-08 -3.208655580008301e-08 -3.2644582857475756e-08 -3.152852874269026e-08 -3.152852874269026e-08 -3.1947049035734825e-08 -3.2365569328779384e-08 -3.278408962182394e-08 -3.54347181444395e-08 -3.948041431053692e-08 -4.1712522540107916e-08 -4.408413753402709e-08 -4.478167135576803e-08 -4.3526110476634344e-08 -4.2410056361848854e-08 -4.213104283315248e-08 -4.101498871836698e-08 -4.0735975189670606e-08 -3.9759427839233295e-08 -3.822485343140324e-08 -3.7387812845314116e-08 -3.682978578792137e-08 -3.5713731673135874e-08 -3.417915726530581e-08 -3.362113020791307e-08 -3.124951521399389e-08 -3.1947049035734825e-08 -3.069148815660114e-08 -3.0970501685297515e-08 -3.11100084496457e-08 -3.152852874269026e-08 -3.1389021978342073e-08 -3.208655580008301e-08 -3.208655580008301e-08 -3.1947049035734825e-08 -3.320260991486851e-08 -3.4039650500957626e-08 -3.417915726530581e-08 -3.4318664029654005e-08 -3.417915726530581e-08 -3.417915726530581e-08 -3.417915726530581e-08 -3.6550772259225e-08 -3.627175873052862e-08 -3.557422490878769e-08 -3.515570461574312e-08 -3.4737184322698563e-08 -3.390014373660944e-08 -3.3342116679216694e-08 -3.180754227138664e-08 -3.250507609312757e-08 -3.124951521399389e-08 -3.180754227138664e-08 -3.208655580008301e-08 -3.376063697226125e-08 -3.948041431053692e-08 -3.278408962182394e-08 -4.631624576359808e-08 -4.9245887814910014e-08 -5.036194192969551e-08 -5.1338489280132814e-08 -4.785082017142814e-08 -4.966440810795457e-08 -4.9943421636650945e-08 -4.771131340707996e-08 -4.0735975189670606e-08 -3.1389021978342073e-08 -2.7482832576592838e-08 -2.6645791990503717e-08 -2.5250724347021848e-08 -2.3018616117450855e-08 -2.008897406613893e-08 -3.515570461574312e-08 -3.250507609312757e-08 -3.348162344356488e-08 -3.250507609312757e-08 -3.278408962182394e-08 -3.3063103150520315e-08 -3.459767755835038e-08 -3.9759427839233295e-08 -3.348162344356488e-08 -4.7432299878383586e-08 -5.064095545839188e-08 -5.203602310187375e-08 -5.273355692361469e-08 -4.896687428621364e-08 -5.064095545839188e-08 -5.064095545839188e-08 -4.82693404644727e-08 -4.1433509011411543e-08 -3.1947049035734825e-08 -2.7482832576592838e-08 -2.6785298754851907e-08 -2.5808751404414597e-08 -2.3297629646147227e-08 -2.0228480830487117e-08 -3.4318664029654005e-08 -3.22260625644312e-08 -3.2644582857475756e-08 -3.1668035507038446e-08 -3.1668035507038446e-08 -3.2644582857475756e-08 -3.4039650500957626e-08 -3.961992107488511e-08 -3.376063697226125e-08 -4.799032693577633e-08 -5.0919968987088255e-08 -5.217552986622194e-08 -5.315207721665925e-08 -4.9524901343606386e-08 -5.1338489280132814e-08 -5.119898251578463e-08 -4.896687428621364e-08 -4.213104283315248e-08 -3.2644582857475756e-08 -2.845937992703015e-08 -2.7482832576592838e-08 -2.5948258168762783e-08 -2.413467023223635e-08 -2.14840417096208e-08 -3.710879931661774e-08 -3.459767755835038e-08 -3.487669108704675e-08 -3.376063697226125e-08 -3.417915726530581e-08 -3.487669108704675e-08 -3.6550772259225e-08 -4.2549563126197034e-08 -3.515570461574312e-08 -4.980391487230276e-08 -5.273355692361469e-08 -5.3849611038400187e-08 -5.48261583888375e-08 -5.147799604448101e-08 -5.343109074535562e-08 -5.3989117802748366e-08 -5.1338489280132814e-08 -4.464216459141985e-08 -3.515570461574312e-08 -3.11100084496457e-08 -2.9993954334860204e-08 -2.873839345572652e-08 -2.650628522615553e-08 -2.315812288179904e-08 -3.948041431053692e-08 -3.710879931661774e-08 -3.7666826374010495e-08 -3.682978578792137e-08 -3.6690279023573184e-08 -3.6550772259225e-08 -3.7387812845314116e-08 -4.29680834192416e-08 -3.459767755835038e-08 -4.8548353993169076e-08 -5.161750280882919e-08 -5.2873063687962876e-08 -5.315207721665925e-08 -4.93853945792582e-08 -5.008292840099913e-08 -4.896687428621364e-08 -4.50606848844644e-08 -3.86433737244478e-08 -3.180754227138664e-08 -2.7482832576592838e-08 -2.650628522615553e-08 -2.5390231111370035e-08 -2.3716149939191793e-08 -2.14840417096208e-08 -3.724830608096593e-08 -3.4737184322698563e-08 -3.5016197851394936e-08 -3.376063697226125e-08 -3.4039650500957626e-08 -3.417915726530581e-08 -3.459767755835038e-08 -3.54347181444395e-08 -3.8364360195751426e-08 -4.366561724098254e-08 -4.687427282099083e-08 -4.93853945792582e-08 -4.9943421636650945e-08 -4.785082017142814e-08 -4.673476605664265e-08 -4.603723223490171e-08 -4.50606848844644e-08 -4.408413753402709e-08 -4.2828576654893406e-08 -4.087548195401879e-08 -4.045696166097423e-08 -3.989893460358149e-08 -3.86433737244478e-08 -3.7666826374010495e-08 -3.710879931661774e-08 -3.515570461574312e-08 -3.5713731673135874e-08 -3.445817079400219e-08 -3.445817079400219e-08 -3.445817079400219e-08 -3.5016197851394936e-08 -3.4318664029654005e-08 -3.487669108704675e-08 -3.487669108704675e-08 -3.5016197851394936e-08 -3.613225196618043e-08 -3.682978578792137e-08 -3.710879931661774e-08 -3.724830608096593e-08 -3.710879931661774e-08 -3.627175873052862e-08 -3.585323843748406e-08 -3.75273196096623e-08 -3.696929255226956e-08 -3.627175873052862e-08 -3.5713731673135874e-08 -3.487669108704675e-08 -3.390014373660944e-08 -3.362113020791307e-08 -3.208655580008301e-08 -3.292359638617213e-08 -3.152852874269026e-08 -3.208655580008301e-08 -3.292359638617213e-08 -3.459767755835038e-08 -4.0735975189670606e-08 -3.445817079400219e-08 -4.896687428621364e-08 -5.1896516337525566e-08 -5.343109074535562e-08 -5.440763809579293e-08 -5.078046222274007e-08 -5.245454339491831e-08 -5.273355692361469e-08 -5.0222435165347324e-08 -4.2549563126197034e-08 -3.250507609312757e-08 -2.8877900220074708e-08 -2.804085963398559e-08 -2.6785298754851907e-08 -2.4413683760932724e-08 -2.0926014652228048e-08 -3.627175873052862e-08 -3.4039650500957626e-08 -3.54347181444395e-08 -3.487669108704675e-08 -3.5016197851394936e-08 -3.5295211380091315e-08 -3.710879931661774e-08 -4.29680834192416e-08 -3.557422490878769e-08 -5.036194192969551e-08 -5.343109074535562e-08 -5.48261583888375e-08 -5.5663198974926615e-08 -5.175700957317738e-08 -5.3849611038400187e-08 -5.3710104274051994e-08 -5.0919968987088255e-08 -4.310759018358978e-08 -3.3342116679216694e-08 -2.9017406984422894e-08 -2.8319873162681962e-08 -2.706431228354828e-08 -2.4274176996584538e-08 -2.0647001123531675e-08 -3.5016197851394936e-08 -3.278408962182394e-08 -3.3342116679216694e-08 -3.22260625644312e-08 -3.250507609312757e-08 -3.292359638617213e-08 -3.459767755835038e-08 -4.045696166097423e-08 -3.459767755835038e-08 -4.896687428621364e-08 -5.1896516337525566e-08 -5.301257045231106e-08 -5.4268131331444745e-08 -5.0222435165347324e-08 -5.1896516337525566e-08 -5.2315036630570125e-08 -5.0222435165347324e-08 -4.324709694793797e-08 -3.376063697226125e-08 -2.9575434041815645e-08 -2.8598886691378335e-08 -2.6924805519200093e-08 -2.46926972896291e-08 -2.14840417096208e-08 -3.682978578792137e-08 -3.459767755835038e-08 -3.4737184322698563e-08 -3.362113020791307e-08 -3.390014373660944e-08 -3.417915726530581e-08 -3.5713731673135874e-08 -4.227054959750066e-08 -3.585323843748406e-08 -5.036194192969551e-08 -5.343109074535562e-08 -5.4686651624489304e-08 -5.5663198974926615e-08 -5.1896516337525566e-08 -5.3570597509703814e-08 -5.3570597509703814e-08 -5.078046222274007e-08 -4.3386603712286164e-08 -3.390014373660944e-08 -3.027296786355658e-08 -2.943592727746746e-08 -2.8180366398333776e-08 -2.552973787571822e-08 -2.1902562002665358e-08 -3.696929255226956e-08 -3.487669108704675e-08 -3.54347181444395e-08 -3.459767755835038e-08 -3.487669108704675e-08 -3.515570461574312e-08 -3.627175873052862e-08 -4.2549563126197034e-08 -3.515570461574312e-08 -4.910638105056182e-08 -5.203602310187375e-08 -5.343109074535562e-08 -5.3849611038400187e-08 -5.008292840099913e-08 -5.064095545839188e-08 -4.966440810795457e-08 -4.5897725470553524e-08 -3.892238725314418e-08 -3.1947049035734825e-08 -2.7901352869637404e-08 -2.6785298754851907e-08 -2.552973787571822e-08 -2.385565670353998e-08 -2.1623548473968986e-08 -3.7387812845314116e-08 -3.459767755835038e-08 -3.459767755835038e-08 -3.348162344356488e-08 -3.3342116679216694e-08 -3.320260991486851e-08 -3.376063697226125e-08 -3.487669108704675e-08 -3.850386696009961e-08 -4.3805124005330716e-08 -4.701377958533902e-08 -4.966440810795457e-08 -5.008292840099913e-08 -4.82693404644727e-08 -4.701377958533902e-08 -4.61767389992499e-08 -4.520019164881259e-08 -4.366561724098254e-08 -4.2549563126197034e-08 -4.059646842532242e-08 -4.045696166097423e-08 -3.948041431053692e-08 -3.86433737244478e-08 -3.7666826374010495e-08 -3.6690279023573184e-08 -3.515570461574312e-08 -3.557422490878769e-08 -3.417915726530581e-08 -3.4039650500957626e-08 -3.4039650500957626e-08 -3.4737184322698563e-08 -3.4039650500957626e-08 -3.459767755835038e-08 -3.4737184322698563e-08 -3.487669108704675e-08 -3.6411265494876805e-08 -3.7666826374010495e-08 -3.8782880488795985e-08 -3.906189401749236e-08 -3.920140078184055e-08 -3.822485343140324e-08 -3.7387812845314116e-08 -3.8364360195751426e-08 -3.7666826374010495e-08 -3.6690279023573184e-08 -3.585323843748406e-08 -3.5295211380091315e-08 -3.4039650500957626e-08 -3.362113020791307e-08 -3.1947049035734825e-08 -3.278408962182394e-08 -3.1947049035734825e-08 -3.180754227138664e-08 -3.278408962182394e-08 -3.4318664029654005e-08 -4.059646842532242e-08 -3.417915726530581e-08 -4.868786075751727e-08 -5.175700957317738e-08 -5.3291583981007435e-08 -5.4268131331444745e-08 -5.0501448694043697e-08 -5.245454339491831e-08 -5.203602310187375e-08 -4.966440810795457e-08 -4.213104283315248e-08 -3.22260625644312e-08 -2.9156913748771087e-08 -2.8319873162681962e-08 -2.6785298754851907e-08 -2.413467023223635e-08 -2.0647001123531675e-08 -3.54347181444395e-08 -3.320260991486851e-08 -3.4039650500957626e-08 -3.376063697226125e-08 -3.348162344356488e-08 -3.390014373660944e-08 -3.5713731673135874e-08 -4.213104283315248e-08 -3.557422490878769e-08 -5.036194192969551e-08 -5.3570597509703814e-08 -5.510517191753387e-08 -5.580270573927481e-08 -5.217552986622194e-08 -5.4268131331444745e-08 -5.412862456709656e-08 -5.147799604448101e-08 -4.366561724098254e-08 -3.4318664029654005e-08 -3.069148815660114e-08 -3.027296786355658e-08 -2.873839345572652e-08 -2.5390231111370035e-08 -2.1344534945272613e-08 -3.5992745201832246e-08 -3.4039650500957626e-08 -3.445817079400219e-08 -3.348162344356488e-08 -3.376063697226125e-08 -3.390014373660944e-08 -3.5016197851394936e-08 -4.087548195401879e-08 -3.487669108704675e-08 -4.9245887814910014e-08 -5.217552986622194e-08 -5.3849611038400187e-08 -5.4686651624489304e-08 -5.0222435165347324e-08 -5.1896516337525566e-08 -5.245454339491831e-08 -4.980391487230276e-08 -4.2689069890545226e-08 -3.3342116679216694e-08 -2.985444757051202e-08 -2.8877900220074708e-08 -2.6924805519200093e-08 -2.4274176996584538e-08 -2.050749435918349e-08 -3.4318664029654005e-08 -3.208655580008301e-08 -3.250507609312757e-08 -3.1389021978342073e-08 -3.1668035507038446e-08 -3.1947049035734825e-08 -3.3342116679216694e-08 -3.989893460358149e-08 -3.445817079400219e-08 -4.82693404644727e-08 -5.147799604448101e-08 -5.2873063687962876e-08 -5.3710104274051994e-08 -5.008292840099913e-08 -5.147799604448101e-08 -5.1338489280132814e-08 -4.896687428621364e-08 -4.157301577575972e-08 -3.2644582857475756e-08 -3.013346109920839e-08 -2.9575434041815645e-08 -2.7901352869637404e-08 -2.5111217582673662e-08 -2.1344534945272613e-08 -3.4737184322698563e-08 -3.292359638617213e-08 -3.3063103150520315e-08 -3.2365569328779384e-08 -3.250507609312757e-08 -3.250507609312757e-08 -3.390014373660944e-08 -4.045696166097423e-08 -3.390014373660944e-08 -4.7432299878383586e-08 -5.008292840099913e-08 -5.147799604448101e-08 -5.203602310187375e-08 -4.812983370012452e-08 -4.868786075751727e-08 -4.82693404644727e-08 -4.436315106272346e-08 -3.7387812845314116e-08 -3.0970501685297515e-08 -2.7482832576592838e-08 -2.6227271697459155e-08 -2.4832204053977286e-08 -2.287910935310267e-08 -2.050749435918349e-08 -3.5016197851394936e-08 -3.250507609312757e-08 -3.348162344356488e-08 -3.292359638617213e-08 -3.278408962182394e-08 -3.22260625644312e-08 -3.3063103150520315e-08 -3.4737184322698563e-08 -3.794583990270687e-08 -4.324709694793797e-08 -4.7432299878383586e-08 -5.0501448694043697e-08 -5.0919968987088255e-08 -4.896687428621364e-08 -4.701377958533902e-08 -4.6455752527946275e-08 -4.492117812011622e-08 -4.324709694793797e-08 -4.1433509011411543e-08 -3.961992107488511e-08 -3.892238725314418e-08 -3.7666826374010495e-08 -3.6550772259225e-08 -3.5713731673135874e-08 -3.445817079400219e-08 -3.3063103150520315e-08 -3.362113020791307e-08 -3.320260991486851e-08 -3.22260625644312e-08 -3.152852874269026e-08 -3.180754227138664e-08 -3.1947049035734825e-08 -3.250507609312757e-08 -3.2365569328779384e-08 -3.320260991486851e-08 -3.4737184322698563e-08 -3.6550772259225e-08 -3.7666826374010495e-08 -3.7666826374010495e-08 -3.7806333138358674e-08 -3.724830608096593e-08 -3.682978578792137e-08 -3.8085346667055053e-08 -3.7806333138358674e-08 -3.6690279023573184e-08 -3.585323843748406e-08 -3.557422490878769e-08 -3.445817079400219e-08 -3.362113020791307e-08 -3.180754227138664e-08 -3.250507609312757e-08 -3.1668035507038446e-08 -3.1668035507038446e-08 -3.2365569328779384e-08 -3.362113020791307e-08 -4.003844136792967e-08 -3.390014373660944e-08 -4.82693404644727e-08 -5.119898251578463e-08 -5.2594050159266504e-08 -5.343109074535562e-08 -4.980391487230276e-08 -5.1896516337525566e-08 -5.1338489280132814e-08 -4.868786075751727e-08 -4.1433509011411543e-08 -3.22260625644312e-08 -2.9296420513119273e-08 -2.8319873162681962e-08 -2.6645791990503717e-08 -2.3576643174843603e-08 -2.0367987594835303e-08 -3.445817079400219e-08 -3.2365569328779384e-08 -3.2644582857475756e-08 -3.180754227138664e-08 -3.180754227138664e-08 -3.2365569328779384e-08 -3.417915726530581e-08 -4.087548195401879e-08 -3.54347181444395e-08 -4.93853945792582e-08 -5.245454339491831e-08 -5.412862456709656e-08 -5.454714486014112e-08 -5.0919968987088255e-08 -5.2873063687962876e-08 -5.2873063687962876e-08 -5.0222435165347324e-08 -4.2689069890545226e-08 -3.3342116679216694e-08 -3.0551981392252956e-08 -2.985444757051202e-08 -2.873839345572652e-08 -2.552973787571822e-08 -2.1623548473968986e-08 -3.5992745201832246e-08 -3.417915726530581e-08 -3.445817079400219e-08 -3.348162344356488e-08 -3.376063697226125e-08 -3.4039650500957626e-08 -3.4737184322698563e-08 -4.087548195401879e-08 -3.487669108704675e-08 -4.882736752186545e-08 -5.1896516337525566e-08 -5.3710104274051994e-08 -5.440763809579293e-08 -5.0222435165347324e-08 -5.1896516337525566e-08 -5.175700957317738e-08 -4.93853945792582e-08 -4.199153606880429e-08 -3.250507609312757e-08 -2.985444757051202e-08 -2.9017406984422894e-08 -2.6924805519200093e-08 -2.413467023223635e-08 -2.050749435918349e-08 -3.417915726530581e-08 -3.208655580008301e-08 -3.250507609312757e-08 -3.180754227138664e-08 -3.1947049035734825e-08 -3.208655580008301e-08 -3.348162344356488e-08 -3.9340907546188736e-08 -3.376063697226125e-08 -4.701377958533902e-08 -5.0222435165347324e-08 -5.175700957317738e-08 -5.273355692361469e-08 -4.93853945792582e-08 -5.0919968987088255e-08 -5.105947575143644e-08 -4.8548353993169076e-08 -4.101498871836698e-08 -3.1947049035734825e-08 -3.013346109920839e-08 -2.9296420513119273e-08 -2.7901352869637404e-08 -2.4971710818325472e-08 -2.106552141657624e-08 -3.417915726530581e-08 -3.278408962182394e-08 -3.320260991486851e-08 -3.320260991486851e-08 -3.3342116679216694e-08 -3.320260991486851e-08 -3.4737184322698563e-08 -4.059646842532242e-08 -3.362113020791307e-08 -4.673476605664265e-08 -4.966440810795457e-08 -5.0501448694043697e-08 -5.1338489280132814e-08 -4.785082017142814e-08 -4.8548353993169076e-08 -4.812983370012452e-08 -4.4502657827071654e-08 -3.75273196096623e-08 -3.083099492094933e-08 -2.7622339340941025e-08 -2.6366778461807345e-08 -2.5111217582673662e-08 -2.315812288179904e-08 -2.106552141657624e-08 -3.613225196618043e-08 -3.376063697226125e-08 -3.54347181444395e-08 -3.5016197851394936e-08 -3.4318664029654005e-08 -3.362113020791307e-08 -3.4318664029654005e-08 -3.585323843748406e-08 -3.86433737244478e-08 -4.366561724098254e-08 -4.882736752186545e-08 -5.1338489280132814e-08 -5.175700957317738e-08 -4.9943421636650945e-08 -4.799032693577633e-08 -4.7153286349687207e-08 -4.533969841316077e-08 -4.3386603712286164e-08 -4.1712522540107916e-08 -4.059646842532242e-08 -3.961992107488511e-08 -3.794583990270687e-08 -3.627175873052862e-08 -3.54347181444395e-08 -3.4318664029654005e-08 -3.3063103150520315e-08 -3.4318664029654005e-08 -3.4039650500957626e-08 -3.320260991486851e-08 -3.1947049035734825e-08 -3.22260625644312e-08 -3.22260625644312e-08 -3.278408962182394e-08 -3.180754227138664e-08 -3.278408962182394e-08 -3.445817079400219e-08 -3.5713731673135874e-08 -3.6690279023573184e-08 -3.710879931661774e-08 -3.696929255226956e-08 -3.682978578792137e-08 -3.627175873052862e-08 -3.7806333138358674e-08 -3.8085346667055053e-08 -3.6411265494876805e-08 -3.5713731673135874e-08 -3.5295211380091315e-08 -3.417915726530581e-08 -3.3342116679216694e-08 -3.1668035507038446e-08 -3.278408962182394e-08 -3.1668035507038446e-08 -3.180754227138664e-08 -3.250507609312757e-08 -3.4039650500957626e-08 -4.031745489662604e-08 -3.4039650500957626e-08 -4.729279311403539e-08 -5.036194192969551e-08 -5.217552986622194e-08 -5.343109074535562e-08 -4.9943421636650945e-08 -5.161750280882919e-08 -5.147799604448101e-08 -4.8548353993169076e-08 -4.1433509011411543e-08 -3.208655580008301e-08 -2.9714940806163832e-08 -2.873839345572652e-08 -2.6924805519200093e-08 -2.3995163467888165e-08 -2.078650788787986e-08 -3.4737184322698563e-08 -3.278408962182394e-08 -3.320260991486851e-08 -3.2365569328779384e-08 -3.2644582857475756e-08 -3.320260991486851e-08 -3.4737184322698563e-08 -4.087548195401879e-08 -3.515570461574312e-08 -4.8548353993169076e-08 -5.175700957317738e-08 -5.315207721665925e-08 -5.412862456709656e-08 -5.036194192969551e-08 -5.175700957317738e-08 -5.147799604448101e-08 -4.882736752186545e-08 -4.157301577575972e-08 -3.1947049035734825e-08 -2.985444757051202e-08 -2.9296420513119273e-08 -2.845937992703015e-08 -2.5669244640066407e-08 -2.218157553136173e-08 -3.682978578792137e-08 -3.4737184322698563e-08 -3.5295211380091315e-08 -3.4318664029654005e-08 -3.417915726530581e-08 -3.390014373660944e-08 -3.487669108704675e-08 -4.087548195401879e-08 -3.4737184322698563e-08 -4.785082017142814e-08 -5.105947575143644e-08 -5.245454339491831e-08 -5.3570597509703814e-08 -4.9524901343606386e-08 -5.078046222274007e-08 -5.0501448694043697e-08 -4.840884722882089e-08 -4.101498871836698e-08 -3.1389021978342073e-08 -2.943592727746746e-08 -2.8598886691378335e-08 -2.6785298754851907e-08 -2.3995163467888165e-08 -2.0926014652228048e-08 -3.5016197851394936e-08 -3.292359638617213e-08 -3.348162344356488e-08 -3.3063103150520315e-08 -3.3063103150520315e-08 -3.3342116679216694e-08 -3.487669108704675e-08 -4.059646842532242e-08 -3.4318664029654005e-08 -4.729279311403539e-08 -5.0919968987088255e-08 -5.2315036630570125e-08 -5.301257045231106e-08 -4.9524901343606386e-08 -5.105947575143644e-08 -5.1338489280132814e-08 -4.868786075751727e-08 -4.129400224706335e-08 -3.152852874269026e-08 -2.9714940806163832e-08 -2.8877900220074708e-08 -2.7482832576592838e-08 -2.4832204053977286e-08 -2.14840417096208e-08 -3.5713731673135874e-08 -3.459767755835038e-08 -3.5295211380091315e-08 -3.5016197851394936e-08 -3.515570461574312e-08 -3.515570461574312e-08 -3.6411265494876805e-08 -4.199153606880429e-08 -3.4318664029654005e-08 -4.701377958533902e-08 -4.9943421636650945e-08 -5.0919968987088255e-08 -5.161750280882919e-08 -4.799032693577633e-08 -4.840884722882089e-08 -4.771131340707996e-08 -4.422364429837528e-08 -3.7387812845314116e-08 -2.9993954334860204e-08 -2.706431228354828e-08 -2.5808751404414597e-08 -2.4832204053977286e-08 -2.3018616117450855e-08 -2.106552141657624e-08 -3.627175873052862e-08 -3.417915726530581e-08 -3.487669108704675e-08 -3.417915726530581e-08 -3.390014373660944e-08 -3.4318664029654005e-08 -3.459767755835038e-08 -3.5713731673135874e-08 -3.892238725314418e-08 -4.3805124005330716e-08 -4.910638105056182e-08 -5.2594050159266504e-08 -5.3291583981007435e-08 -5.161750280882919e-08 -4.966440810795457e-08 -4.771131340707996e-08 -4.5897725470553524e-08 -4.366561724098254e-08 -4.213104283315248e-08 -4.1852029304456096e-08 -4.087548195401879e-08 -3.948041431053692e-08 -3.8085346667055053e-08 -3.696929255226956e-08 -3.5713731673135874e-08 -3.445817079400219e-08 -3.613225196618043e-08 -3.5016197851394936e-08 -3.4737184322698563e-08 -3.376063697226125e-08 -3.4039650500957626e-08 -3.320260991486851e-08 -3.3342116679216694e-08 -3.1668035507038446e-08 -3.292359638617213e-08 -3.459767755835038e-08 -3.6411265494876805e-08 -3.710879931661774e-08 -3.7666826374010495e-08 -3.724830608096593e-08 -3.724830608096593e-08 -3.627175873052862e-08 -3.7387812845314116e-08 -3.850386696009961e-08 -3.682978578792137e-08 -3.627175873052862e-08 -3.515570461574312e-08 -3.445817079400219e-08 -3.320260991486851e-08 -3.1947049035734825e-08 -3.3063103150520315e-08 -3.208655580008301e-08 -3.1668035507038446e-08 -3.1947049035734825e-08 -3.376063697226125e-08 -4.003844136792967e-08 -3.348162344356488e-08 -4.5897725470553524e-08 -4.93853945792582e-08 -5.147799604448101e-08 -5.2594050159266504e-08 -4.93853945792582e-08 -5.105947575143644e-08 -5.105947575143644e-08 -4.868786075751727e-08 -4.115449548271517e-08 -3.083099492094933e-08 -2.9575434041815645e-08 -2.8877900220074708e-08 -2.7482832576592838e-08 -2.413467023223635e-08 -2.0926014652228048e-08 -3.5713731673135874e-08 -3.348162344356488e-08 -3.4039650500957626e-08 -3.292359638617213e-08 -3.278408962182394e-08 -3.3063103150520315e-08 -3.4318664029654005e-08 -4.031745489662604e-08 -3.4039650500957626e-08 -4.729279311403539e-08 -5.078046222274007e-08 -5.217552986622194e-08 -5.301257045231106e-08 -4.910638105056182e-08 -5.064095545839188e-08 -5.008292840099913e-08 -4.7571806642731765e-08 -4.031745489662604e-08 -3.041247462790477e-08 -2.9017406984422894e-08 -2.8598886691378335e-08 -2.7901352869637404e-08 -2.5111217582673662e-08 -2.1344534945272613e-08 -3.5295211380091315e-08 -3.3342116679216694e-08 -3.376063697226125e-08 -3.292359638617213e-08 -3.2644582857475756e-08 -3.2644582857475756e-08 -3.376063697226125e-08 -3.9759427839233295e-08 -3.376063697226125e-08 -4.6455752527946275e-08 -4.9943421636650945e-08 -5.147799604448101e-08 -5.273355692361469e-08 -4.8548353993169076e-08 -4.9943421636650945e-08 -4.980391487230276e-08 -4.7571806642731765e-08 -4.003844136792967e-08 -2.9993954334860204e-08 -2.9017406984422894e-08 -2.845937992703015e-08 -2.706431228354828e-08 -2.4413683760932724e-08 -2.078650788787986e-08 -3.4737184322698563e-08 -3.250507609312757e-08 -3.348162344356488e-08 -3.278408962182394e-08 -3.250507609312757e-08 -3.292359638617213e-08 -3.4318664029654005e-08 -4.003844136792967e-08 -3.348162344356488e-08 -4.6455752527946275e-08 -5.0222435165347324e-08 -5.147799604448101e-08 -5.217552986622194e-08 -4.868786075751727e-08 -5.036194192969551e-08 -5.036194192969551e-08 -4.785082017142814e-08 -4.045696166097423e-08 -3.041247462790477e-08 -2.9156913748771087e-08 -2.8598886691378335e-08 -2.706431228354828e-08 -2.4274176996584538e-08 -2.0926014652228048e-08 -3.4737184322698563e-08 -3.278408962182394e-08 -3.3063103150520315e-08 -3.250507609312757e-08 -3.250507609312757e-08 -3.2365569328779384e-08 -3.390014373660944e-08 -3.9759427839233295e-08 -3.3063103150520315e-08 -4.5618711941857144e-08 -4.896687428621364e-08 -5.036194192969551e-08 -5.064095545839188e-08 -4.687427282099083e-08 -4.7153286349687207e-08 -4.631624576359808e-08 -4.2828576654893406e-08 -3.5992745201832246e-08 -2.8598886691378335e-08 -2.6366778461807345e-08 -2.5250724347021848e-08 -2.4413683760932724e-08 -2.2321082295709924e-08 -2.008897406613893e-08 -3.417915726530581e-08 -3.208655580008301e-08 -3.1947049035734825e-08 -3.1389021978342073e-08 -3.152852874269026e-08 -3.22260625644312e-08 -3.250507609312757e-08 -3.362113020791307e-08 -3.6690279023573184e-08 -4.087548195401879e-08 -4.575821870620534e-08 -4.966440810795457e-08 -5.078046222274007e-08 -4.868786075751727e-08 -4.729279311403539e-08 -4.533969841316077e-08 -4.3805124005330716e-08 -4.115449548271517e-08 -3.906189401749236e-08 -3.892238725314418e-08 -3.8364360195751426e-08 -3.7806333138358674e-08 -3.710879931661774e-08 -3.682978578792137e-08 -3.557422490878769e-08 -3.390014373660944e-08 -3.487669108704675e-08 -3.376063697226125e-08 -3.362113020791307e-08 -3.320260991486851e-08 -3.348162344356488e-08 -3.2644582857475756e-08 -3.2365569328779384e-08 -3.0970501685297515e-08 -3.2644582857475756e-08 -3.417915726530581e-08 -3.5016197851394936e-08 -3.515570461574312e-08 -3.557422490878769e-08 -3.487669108704675e-08 -3.459767755835038e-08 -3.376063697226125e-08 -3.4039650500957626e-08 -3.5992745201832246e-08 -3.54347181444395e-08 -3.5016197851394936e-08 -3.390014373660944e-08 -3.3342116679216694e-08 -3.250507609312757e-08 -3.11100084496457e-08 -3.1947049035734825e-08 -3.1389021978342073e-08 -3.11100084496457e-08 -3.11100084496457e-08 -3.3063103150520315e-08 -3.906189401749236e-08 -3.2365569328779384e-08 -4.464216459141985e-08 -4.785082017142814e-08 -4.980391487230276e-08 -5.064095545839188e-08 -4.729279311403539e-08 -4.910638105056182e-08 -4.9245887814910014e-08 -4.7153286349687207e-08 -3.961992107488511e-08 -2.9296420513119273e-08 -2.873839345572652e-08 -2.845937992703015e-08 -2.6785298754851907e-08 -2.3576643174843603e-08 -2.0228480830487117e-08 -3.4737184322698563e-08 -3.208655580008301e-08 -3.2644582857475756e-08 -3.1668035507038446e-08 -3.1389021978342073e-08 -3.1389021978342073e-08 -3.278408962182394e-08 -3.8782880488795985e-08 -3.278408962182394e-08 -4.5479205177508965e-08 -4.8548353993169076e-08 -4.9943421636650945e-08 -5.078046222274007e-08 -4.687427282099083e-08 -4.882736752186545e-08 -4.868786075751727e-08 -4.61767389992499e-08 -3.8782880488795985e-08 -2.8319873162681962e-08 -2.7761846105289214e-08 -2.804085963398559e-08 -2.7343325812244652e-08 -2.413467023223635e-08 -1.9670453773094368e-08 -3.250507609312757e-08 -3.0551981392252956e-08 -3.11100084496457e-08 -3.013346109920839e-08 -3.027296786355658e-08 -3.069148815660114e-08 -3.250507609312757e-08 -3.8364360195751426e-08 -3.2644582857475756e-08 -4.50606848844644e-08 -4.812983370012452e-08 -4.966440810795457e-08 -5.078046222274007e-08 -4.687427282099083e-08 -4.868786075751727e-08 -4.868786075751727e-08 -4.631624576359808e-08 -3.9340907546188736e-08 -2.9017406984422894e-08 -2.845937992703015e-08 -2.845937992703015e-08 -2.706431228354828e-08 -2.413467023223635e-08 -2.008897406613893e-08 -3.3063103150520315e-08 -3.11100084496457e-08 -3.180754227138664e-08 -3.11100084496457e-08 -3.069148815660114e-08 -3.11100084496457e-08 -3.250507609312757e-08 -3.7806333138358674e-08 -3.208655580008301e-08 -4.4502657827071654e-08 -4.799032693577633e-08 -4.9524901343606386e-08 -5.0501448694043697e-08 -4.701377958533902e-08 -4.8548353993169076e-08 -4.8548353993169076e-08 -4.61767389992499e-08 -3.906189401749236e-08 -2.873839345572652e-08 -2.8180366398333776e-08 -2.845937992703015e-08 -2.706431228354828e-08 -2.3995163467888165e-08 -1.9809960537442554e-08 -3.208655580008301e-08 -2.9575434041815645e-08 -2.943592727746746e-08 -2.873839345572652e-08 -2.8598886691378335e-08 -2.9017406984422894e-08 -3.0970501685297515e-08 -3.6550772259225e-08 -3.083099492094933e-08 -4.2689069890545226e-08 -4.61767389992499e-08 -4.729279311403539e-08 -4.799032693577633e-08 -4.436315106272346e-08 -4.520019164881259e-08 -4.436315106272346e-08 -4.087548195401879e-08 -3.445817079400219e-08 -2.706431228354828e-08 -2.5111217582673662e-08 -2.4413683760932724e-08 -2.3437136410495414e-08 -2.14840417096208e-08 -1.8972919951353434e-08 -3.180754227138664e-08 -2.943592727746746e-08 -2.9575434041815645e-08 -2.873839345572652e-08 -2.873839345572652e-08 -2.873839345572652e-08 -2.9296420513119273e-08 -3.013346109920839e-08 -3.292359638617213e-08 -3.6411265494876805e-08 -4.087548195401879e-08 -4.394463076967891e-08 -4.492117812011622e-08 -4.2410056361848854e-08 -4.157301577575972e-08 -4.087548195401879e-08 -3.9759427839233295e-08 -3.7666826374010495e-08 -3.5016197851394936e-08 -3.487669108704675e-08 -3.5016197851394936e-08 -3.3342116679216694e-08 -3.3063103150520315e-08 -3.292359638617213e-08 -3.1668035507038446e-08 -2.985444757051202e-08 -3.027296786355658e-08 -2.9296420513119273e-08 -2.943592727746746e-08 -2.9156913748771087e-08 -2.9575434041815645e-08 -2.9575434041815645e-08 -2.9156913748771087e-08 -2.845937992703015e-08 -3.041247462790477e-08 -3.2644582857475756e-08 -3.348162344356488e-08 -3.362113020791307e-08 -3.390014373660944e-08 -3.390014373660944e-08 -3.4737184322698563e-08 -3.417915726530581e-08 -3.3342116679216694e-08 -3.5295211380091315e-08 -3.5713731673135874e-08 -3.4737184322698563e-08 -3.4318664029654005e-08 -3.362113020791307e-08 -3.320260991486851e-08 -3.11100084496457e-08 -3.152852874269026e-08 -3.0970501685297515e-08 -3.11100084496457e-08 -3.11100084496457e-08 -3.292359638617213e-08 -3.850386696009961e-08 -3.152852874269026e-08 -4.366561724098254e-08 -4.701377958533902e-08 -4.882736752186545e-08 -4.9524901343606386e-08 -4.575821870620534e-08 -4.771131340707996e-08 -4.771131340707996e-08 -4.5479205177508965e-08 -3.822485343140324e-08 -2.804085963398559e-08 -2.7482832576592838e-08 -2.845937992703015e-08 -2.6366778461807345e-08 -2.3018616117450855e-08 -1.9251933480049806e-08 -3.208655580008301e-08 -2.943592727746746e-08 -2.985444757051202e-08 -2.943592727746746e-08 -2.9714940806163832e-08 -2.9714940806163832e-08 -3.1389021978342073e-08 -3.7387812845314116e-08 -3.152852874269026e-08 -4.394463076967891e-08 -4.701377958533902e-08 -4.868786075751727e-08 -4.966440810795457e-08 -4.5479205177508965e-08 -4.7432299878383586e-08 -4.729279311403539e-08 -4.492117812011622e-08 -3.7387812845314116e-08 -2.6924805519200093e-08 -2.6785298754851907e-08 -2.845937992703015e-08 -2.7343325812244652e-08 -2.413467023223635e-08 -1.9251933480049806e-08 -3.124951521399389e-08 -2.943592727746746e-08 -3.027296786355658e-08 -2.985444757051202e-08 -3.027296786355658e-08 -3.069148815660114e-08 -3.2644582857475756e-08 -3.850386696009961e-08 -3.208655580008301e-08 -4.4502657827071654e-08 -4.7571806642731765e-08 -4.868786075751727e-08 -4.9524901343606386e-08 -4.5479205177508965e-08 -4.7432299878383586e-08 -4.729279311403539e-08 -4.492117812011622e-08 -3.7806333138358674e-08 -2.7343325812244652e-08 -2.706431228354828e-08 -2.8598886691378335e-08 -2.6924805519200093e-08 -2.4274176996584538e-08 -1.9949467301790744e-08 -3.22260625644312e-08 -2.9993954334860204e-08 -3.069148815660114e-08 -2.985444757051202e-08 -3.013346109920839e-08 -3.027296786355658e-08 -3.22260625644312e-08 -3.8364360195751426e-08 -3.152852874269026e-08 -4.3386603712286164e-08 -4.7153286349687207e-08 -4.882736752186545e-08 -4.9943421636650945e-08 -4.61767389992499e-08 -4.785082017142814e-08 -4.785082017142814e-08 -4.5479205177508965e-08 -3.8364360195751426e-08 -2.7901352869637404e-08 -2.7482832576592838e-08 -2.9156913748771087e-08 -2.804085963398559e-08 -2.4832204053977286e-08 -2.0228480830487117e-08 -3.22260625644312e-08 -3.013346109920839e-08 -3.027296786355658e-08 -2.9714940806163832e-08 -2.985444757051202e-08 -3.0551981392252956e-08 -3.124951521399389e-08 -3.75273196096623e-08 -3.027296786355658e-08 -4.213104283315248e-08 -4.5618711941857144e-08 -4.6595259292294455e-08 -4.7432299878383586e-08 -4.366561724098254e-08 -4.436315106272346e-08 -4.310759018358978e-08 -3.948041431053692e-08 -3.3342116679216694e-08 -2.5390231111370035e-08 -2.3995163467888165e-08 -2.4274176996584538e-08 -2.3018616117450855e-08 -2.078650788787986e-08 -1.82753861296125e-08 -3.083099492094933e-08 -2.845937992703015e-08 -2.9017406984422894e-08 -2.845937992703015e-08 -2.873839345572652e-08 -2.873839345572652e-08 -2.9017406984422894e-08 -2.9714940806163832e-08 -3.208655580008301e-08 -3.6411265494876805e-08 -4.101498871836698e-08 -4.422364429837528e-08 -4.478167135576803e-08 -4.227054959750066e-08 -4.1433509011411543e-08 -4.059646842532242e-08 -3.989893460358149e-08 -3.8085346667055053e-08 -3.5713731673135874e-08 -3.515570461574312e-08 -3.54347181444395e-08 -3.320260991486851e-08 -3.278408962182394e-08 -3.1668035507038446e-08 -3.0551981392252956e-08 -2.8877900220074708e-08 -2.943592727746746e-08 -2.873839345572652e-08 -2.873839345572652e-08 -2.845937992703015e-08 -2.873839345572652e-08 -2.9017406984422894e-08 -2.804085963398559e-08 -2.804085963398559e-08 -2.985444757051202e-08 -3.1947049035734825e-08 -3.320260991486851e-08 -3.3342116679216694e-08 -3.3342116679216694e-08 -3.362113020791307e-08 -3.445817079400219e-08 -3.3342116679216694e-08 -3.208655580008301e-08 -3.376063697226125e-08 -3.515570461574312e-08 -3.4318664029654005e-08 -3.4039650500957626e-08 -3.362113020791307e-08 -3.3063103150520315e-08 -3.124951521399389e-08 -3.1668035507038446e-08 -3.083099492094933e-08 -3.11100084496457e-08 -3.11100084496457e-08 -3.278408962182394e-08 -3.8364360195751426e-08 -3.11100084496457e-08 -4.3526110476634344e-08 -4.687427282099083e-08 -4.882736752186545e-08 -4.966440810795457e-08 -4.5897725470553524e-08 -4.799032693577633e-08 -4.771131340707996e-08 -4.520019164881259e-08 -3.794583990270687e-08 -2.7203819047896466e-08 -2.650628522615553e-08 -2.873839345572652e-08 -2.650628522615553e-08 -2.315812288179904e-08 -1.9391440244397992e-08 -3.1947049035734825e-08 -2.9575434041815645e-08 -2.9993954334860204e-08 -2.9575434041815645e-08 -2.985444757051202e-08 -3.013346109920839e-08 -3.180754227138664e-08 -3.822485343140324e-08 -3.1389021978342073e-08 -4.394463076967891e-08 -4.7153286349687207e-08 -4.882736752186545e-08 -4.966440810795457e-08 -4.5897725470553524e-08 -4.771131340707996e-08 -4.7432299878383586e-08 -4.464216459141985e-08 -3.696929255226956e-08 -2.6366778461807345e-08 -2.552973787571822e-08 -2.8319873162681962e-08 -2.7343325812244652e-08 -2.3995163467888165e-08 -1.953094700874618e-08 -3.180754227138664e-08 -2.9296420513119273e-08 -2.9714940806163832e-08 -2.9575434041815645e-08 -3.027296786355658e-08 -3.013346109920839e-08 -3.208655580008301e-08 -3.8085346667055053e-08 -3.0970501685297515e-08 -4.3526110476634344e-08 -4.729279311403539e-08 -4.8548353993169076e-08 -4.9245887814910014e-08 -4.520019164881259e-08 -4.701377958533902e-08 -4.673476605664265e-08 -4.4502657827071654e-08 -3.710879931661774e-08 -2.6785298754851907e-08 -2.608776493311097e-08 -2.9156913748771087e-08 -2.7482832576592838e-08 -2.4832204053977286e-08 -1.9949467301790744e-08 -3.208655580008301e-08 -2.9575434041815645e-08 -3.041247462790477e-08 -2.9575434041815645e-08 -2.985444757051202e-08 -3.013346109920839e-08 -3.208655580008301e-08 -3.8085346667055053e-08 -3.083099492094933e-08 -4.310759018358978e-08 -4.687427282099083e-08 -4.882736752186545e-08 -4.9943421636650945e-08 -4.603723223490171e-08 -4.7571806642731765e-08 -4.785082017142814e-08 -4.50606848844644e-08 -3.794583990270687e-08 -2.7482832576592838e-08 -2.6227271697459155e-08 -2.9575434041815645e-08 -2.873839345572652e-08 -2.5948258168762783e-08 -2.078650788787986e-08 -3.2644582857475756e-08 -3.041247462790477e-08 -3.083099492094933e-08 -3.027296786355658e-08 -3.0551981392252956e-08 -3.0970501685297515e-08 -3.180754227138664e-08 -3.8085346667055053e-08 -3.041247462790477e-08 -4.2549563126197034e-08 -4.5897725470553524e-08 -4.7153286349687207e-08 -4.7571806642731765e-08 -4.366561724098254e-08 -4.422364429837528e-08 -4.324709694793797e-08 -3.961992107488511e-08 -3.3063103150520315e-08 -2.5111217582673662e-08 -2.3716149939191793e-08 -2.455319052528091e-08 -2.3437136410495414e-08 -2.0926014652228048e-08 -1.82753861296125e-08 -3.0551981392252956e-08 -2.8180366398333776e-08 -2.8877900220074708e-08 -2.8180366398333776e-08 -2.8598886691378335e-08 -2.8319873162681962e-08 -2.8598886691378335e-08 -2.943592727746746e-08 -3.124951521399389e-08 -3.6550772259225e-08 -4.157301577575972e-08 -4.478167135576803e-08 -4.533969841316077e-08 -4.2549563126197034e-08 -4.115449548271517e-08 -4.031745489662604e-08 -3.920140078184055e-08 -3.696929255226956e-08 -3.5016197851394936e-08 -3.390014373660944e-08 -3.459767755835038e-08 -3.278408962182394e-08 -3.22260625644312e-08 -3.0970501685297515e-08 -2.9993954334860204e-08 -2.8180366398333776e-08 -2.8877900220074708e-08 -2.8180366398333776e-08 -2.8319873162681962e-08 -2.8180366398333776e-08 -2.804085963398559e-08 -2.7761846105289214e-08 -2.706431228354828e-08 -2.7622339340941025e-08 -2.9575434041815645e-08 -3.083099492094933e-08 -3.069148815660114e-08 -3.0970501685297515e-08 -3.0970501685297515e-08 -3.069148815660114e-08 -3.041247462790477e-08 -2.9296420513119273e-08 -2.8598886691378335e-08 -2.9993954334860204e-08 -3.1668035507038446e-08 -3.0970501685297515e-08 -3.027296786355658e-08 -2.985444757051202e-08 -2.943592727746746e-08 -2.7901352869637404e-08 -2.9156913748771087e-08 -2.8598886691378335e-08 -2.8877900220074708e-08 -2.9575434041815645e-08 -3.0970501685297515e-08 -3.682978578792137e-08 -3.027296786355658e-08 -4.310759018358978e-08 -4.6595259292294455e-08 -4.82693404644727e-08 -4.910638105056182e-08 -4.520019164881259e-08 -4.701377958533902e-08 -4.7153286349687207e-08 -4.4502657827071654e-08 -3.724830608096593e-08 -2.6366778461807345e-08 -2.552973787571822e-08 -2.8319873162681962e-08 -2.650628522615553e-08 -2.287910935310267e-08 -1.9391440244397992e-08 -3.22260625644312e-08 -2.9714940806163832e-08 -3.027296786355658e-08 -2.9575434041815645e-08 -2.985444757051202e-08 -3.0551981392252956e-08 -3.250507609312757e-08 -3.906189401749236e-08 -3.1668035507038446e-08 -4.436315106272346e-08 -4.785082017142814e-08 -4.9245887814910014e-08 -4.9943421636650945e-08 -4.61767389992499e-08 -4.82693404644727e-08 -4.799032693577633e-08 -4.50606848844644e-08 -3.7387812845314116e-08 -2.706431228354828e-08 -2.5669244640066407e-08 -2.9296420513119273e-08 -2.8877900220074708e-08 -2.5111217582673662e-08 -2.0228480830487117e-08 -3.278408962182394e-08 -2.9993954334860204e-08 -3.013346109920839e-08 -2.9156913748771087e-08 -2.9714940806163832e-08 -2.9714940806163832e-08 -3.124951521399389e-08 -3.724830608096593e-08 -3.027296786355658e-08 -4.29680834192416e-08 -4.6595259292294455e-08 -4.840884722882089e-08 -4.9245887814910014e-08 -4.5479205177508965e-08 -4.7153286349687207e-08 -4.701377958533902e-08 -4.492117812011622e-08 -3.7666826374010495e-08 -2.7203819047896466e-08 -2.552973787571822e-08 -2.9714940806163832e-08 -2.8319873162681962e-08 -2.5111217582673662e-08 -1.9809960537442554e-08 -3.1947049035734825e-08 -2.9156913748771087e-08 -2.9575434041815645e-08 -2.8180366398333776e-08 -2.845937992703015e-08 -2.873839345572652e-08 -3.013346109920839e-08 -3.557422490878769e-08 -2.9993954334860204e-08 -4.2689069890545226e-08 -4.6455752527946275e-08 -4.840884722882089e-08 -4.910638105056182e-08 -4.5479205177508965e-08 -4.6455752527946275e-08 -4.687427282099083e-08 -4.422364429837528e-08 -3.710879931661774e-08 -2.6645791990503717e-08 -2.4832204053977286e-08 -2.8877900220074708e-08 -2.8180366398333776e-08 -2.4971710818325472e-08 -1.9670453773094368e-08 -3.083099492094933e-08 -2.7901352869637404e-08 -2.8180366398333776e-08 -2.7343325812244652e-08 -2.7482832576592838e-08 -2.7761846105289214e-08 -2.943592727746746e-08 -3.5016197851394936e-08 -2.8877900220074708e-08 -4.087548195401879e-08 -4.408413753402709e-08 -4.5618711941857144e-08 -4.6455752527946275e-08 -4.2410056361848854e-08 -4.3386603712286164e-08 -4.29680834192416e-08 -3.948041431053692e-08 -3.320260991486851e-08 -2.5808751404414597e-08 -2.3995163467888165e-08 -2.5669244640066407e-08 -2.46926972896291e-08 -2.1902562002665358e-08 -1.911242671570162e-08 -3.11100084496457e-08 -2.804085963398559e-08 -2.8319873162681962e-08 -2.706431228354828e-08 -2.7343325812244652e-08 -2.7343325812244652e-08 -2.804085963398559e-08 -2.8319873162681962e-08 -2.9575434041815645e-08 -3.54347181444395e-08 -4.017794813227786e-08 -4.310759018358978e-08 -4.408413753402709e-08 -4.129400224706335e-08 -3.989893460358149e-08 -3.961992107488511e-08 -3.822485343140324e-08 -3.5713731673135874e-08 -3.348162344356488e-08 -3.2365569328779384e-08 -3.390014373660944e-08 -3.278408962182394e-08 -3.1947049035734825e-08 -3.069148815660114e-08 -2.9714940806163832e-08 -2.7761846105289214e-08 -2.845937992703015e-08 -2.7203819047896466e-08 -2.7622339340941025e-08 -2.7203819047896466e-08 -2.706431228354828e-08 -2.6227271697459155e-08 -2.552973787571822e-08 -2.5808751404414597e-08 -2.8319873162681962e-08 -2.9575434041815645e-08 -2.9993954334860204e-08 -3.027296786355658e-08 -3.0551981392252956e-08 -2.985444757051202e-08 -2.985444757051202e-08 -2.9714940806163832e-08 -2.9714940806163832e-08 -2.985444757051202e-08 -3.1947049035734825e-08 -3.124951521399389e-08 -2.9993954334860204e-08 -2.9156913748771087e-08 -2.8877900220074708e-08 -2.7482832576592838e-08 -2.873839345572652e-08 -2.8180366398333776e-08 -2.845937992703015e-08 -2.9714940806163832e-08 -3.041247462790477e-08 -3.515570461574312e-08 -2.9296420513119273e-08 -4.213104283315248e-08 -4.603723223490171e-08 -4.729279311403539e-08 -4.785082017142814e-08 -4.3805124005330716e-08 -4.5618711941857144e-08 -4.603723223490171e-08 -4.366561724098254e-08 -3.613225196618043e-08 -2.5390231111370035e-08 -2.3437136410495414e-08 -2.8180366398333776e-08 -2.6924805519200093e-08 -2.2739602588754482e-08 -1.8972919951353434e-08 -3.083099492094933e-08 -2.845937992703015e-08 -2.873839345572652e-08 -2.7901352869637404e-08 -2.8319873162681962e-08 -2.9017406984422894e-08 -3.083099492094933e-08 -3.627175873052862e-08 -2.9993954334860204e-08 -4.310759018358978e-08 -4.701377958533902e-08 -4.8548353993169076e-08 -4.896687428621364e-08 -4.478167135576803e-08 -4.687427282099083e-08 -4.687427282099083e-08 -4.4502657827071654e-08 -3.682978578792137e-08 -2.6227271697459155e-08 -2.3995163467888165e-08 -2.9296420513119273e-08 -2.9156913748771087e-08 -2.5250724347021848e-08 -1.953094700874618e-08 -3.11100084496457e-08 -2.873839345572652e-08 -2.9017406984422894e-08 -2.873839345572652e-08 -2.8598886691378335e-08 -2.9156913748771087e-08 -3.0551981392252956e-08 -3.557422490878769e-08 -2.9575434041815645e-08 -4.227054959750066e-08 -4.603723223490171e-08 -4.7571806642731765e-08 -4.840884722882089e-08 -4.478167135576803e-08 -4.6455752527946275e-08 -4.6595259292294455e-08 -4.422364429837528e-08 -3.696929255226956e-08 -2.6227271697459155e-08 -2.3716149939191793e-08 -2.8877900220074708e-08 -2.7901352869637404e-08 -2.4413683760932724e-08 -1.9251933480049806e-08 -3.027296786355658e-08 -2.7622339340941025e-08 -2.8180366398333776e-08 -2.6924805519200093e-08 -2.7203819047896466e-08 -2.7343325812244652e-08 -2.9017406984422894e-08 -3.390014373660944e-08 -2.873839345572652e-08 -4.101498871836698e-08 -4.478167135576803e-08 -4.6455752527946275e-08 -4.701377958533902e-08 -4.3386603712286164e-08 -4.50606848844644e-08 -4.520019164881259e-08 -4.2828576654893406e-08 -3.5992745201832246e-08 -2.552973787571822e-08 -2.3297629646147227e-08 -2.804085963398559e-08 -2.7761846105289214e-08 -2.413467023223635e-08 -1.8833413187005247e-08 -2.9156913748771087e-08 -2.6366778461807345e-08 -2.6924805519200093e-08 -2.5948258168762783e-08 -2.6366778461807345e-08 -2.650628522615553e-08 -2.8180366398333776e-08 -3.3063103150520315e-08 -2.7343325812244652e-08 -3.906189401749236e-08 -4.29680834192416e-08 -4.4502657827071654e-08 -4.5479205177508965e-08 -4.1433509011411543e-08 -4.227054959750066e-08 -4.1852029304456096e-08 -3.8085346667055053e-08 -3.208655580008301e-08 -2.4971710818325472e-08 -2.2739602588754482e-08 -2.4971710818325472e-08 -2.4274176996584538e-08 -2.1623548473968986e-08 -1.8693906422657058e-08 -3.069148815660114e-08 -2.7482832576592838e-08 -2.7901352869637404e-08 -2.6785298754851907e-08 -2.6785298754851907e-08 -2.6924805519200093e-08 -2.7482832576592838e-08 -2.706431228354828e-08 -2.873839345572652e-08 -3.4737184322698563e-08 -3.9759427839233295e-08 -4.2828576654893406e-08 -4.29680834192416e-08 -4.003844136792967e-08 -3.920140078184055e-08 -3.822485343140324e-08 -3.724830608096593e-08 -3.515570461574312e-08 -3.278408962182394e-08 -3.124951521399389e-08 -3.3342116679216694e-08 -3.250507609312757e-08 -3.180754227138664e-08 -3.0551981392252956e-08 -2.943592727746746e-08 -2.7761846105289214e-08 -2.8598886691378335e-08 -2.7761846105289214e-08 -2.7761846105289214e-08 -2.7622339340941025e-08 -2.804085963398559e-08 -2.6785298754851907e-08 -2.6227271697459155e-08 -2.706431228354828e-08 -2.9017406984422894e-08 -2.9993954334860204e-08 -3.1389021978342073e-08 -3.152852874269026e-08 -3.0970501685297515e-08 -2.9714940806163832e-08 -2.9156913748771087e-08 -2.845937992703015e-08 -2.8319873162681962e-08 -2.804085963398559e-08 -3.041247462790477e-08 -3.027296786355658e-08 -2.9017406984422894e-08 -2.8180366398333776e-08 -2.7761846105289214e-08 -2.7482832576592838e-08 -2.8598886691378335e-08 -2.8319873162681962e-08 -2.8877900220074708e-08 -3.0970501685297515e-08 -3.320260991486851e-08 -4.115449548271517e-08 -3.348162344356488e-08 -4.2689069890545226e-08 -4.5897725470553524e-08 -4.7153286349687207e-08 -4.5897725470553524e-08 -4.422364429837528e-08 -4.5479205177508965e-08 -4.478167135576803e-08 -4.059646842532242e-08 -3.180754227138664e-08 -2.3576643174843603e-08 -2.1623548473968986e-08 -2.7203819047896466e-08 -2.5808751404414597e-08 -2.1344534945272613e-08 -1.7996372600916123e-08 -2.8319873162681962e-08 -2.7622339340941025e-08 -2.7343325812244652e-08 -2.6924805519200093e-08 -2.7482832576592838e-08 -2.9017406984422894e-08 -3.2365569328779384e-08 -4.366561724098254e-08 -3.557422490878769e-08 -4.366561724098254e-08 -4.6455752527946275e-08 -4.7432299878383586e-08 -4.5618711941857144e-08 -4.464216459141985e-08 -4.575821870620534e-08 -4.4502657827071654e-08 -3.9759427839233295e-08 -3.083099492094933e-08 -2.2739602588754482e-08 -2.106552141657624e-08 -2.6785298754851907e-08 -2.5948258168762783e-08 -2.1205028180924427e-08 -1.757785230787156e-08 -2.845937992703015e-08 -2.7622339340941025e-08 -2.804085963398559e-08 -2.8180366398333776e-08 -2.804085963398559e-08 -2.8877900220074708e-08 -3.208655580008301e-08 -4.324709694793797e-08 -3.515570461574312e-08 -4.3386603712286164e-08 -4.603723223490171e-08 -4.687427282099083e-08 -4.50606848844644e-08 -4.422364429837528e-08 -4.520019164881259e-08 -4.408413753402709e-08 -3.948041431053692e-08 -3.0551981392252956e-08 -2.3018616117450855e-08 -2.1763055238317172e-08 -2.6785298754851907e-08 -2.5669244640066407e-08 -2.1205028180924427e-08 -1.729883877917519e-08 -2.8319873162681962e-08 -2.650628522615553e-08 -2.6366778461807345e-08 -2.608776493311097e-08 -2.608776493311097e-08 -2.6645791990503717e-08 -3.069148815660114e-08 -4.1852029304456096e-08 -3.4039650500957626e-08 -4.199153606880429e-08 -4.492117812011622e-08 -4.61767389992499e-08 -4.50606848844644e-08 -4.422364429837528e-08 -4.5479205177508965e-08 -4.394463076967891e-08 -3.906189401749236e-08 -3.013346109920839e-08 -2.2600095824406296e-08 -2.1623548473968986e-08 -2.6645791990503717e-08 -2.5808751404414597e-08 -2.14840417096208e-08 -1.7438345543523375e-08 -2.7203819047896466e-08 -2.608776493311097e-08 -2.5948258168762783e-08 -2.5390231111370035e-08 -2.5808751404414597e-08 -2.6645791990503717e-08 -3.013346109920839e-08 -4.017794813227786e-08 -3.208655580008301e-08 -3.948041431053692e-08 -4.2549563126197034e-08 -4.3805124005330716e-08 -4.227054959750066e-08 -4.059646842532242e-08 -4.059646842532242e-08 -3.850386696009961e-08 -3.3342116679216694e-08 -2.6785298754851907e-08 -2.14840417096208e-08 -1.9949467301790744e-08 -2.246058906005811e-08 -2.1623548473968986e-08 -1.8972919951353434e-08 -1.6601304957434254e-08 -2.7343325812244652e-08 -2.5948258168762783e-08 -2.5948258168762783e-08 -2.5250724347021848e-08 -2.5390231111370035e-08 -2.5390231111370035e-08 -2.5948258168762783e-08 -2.6366778461807345e-08 -2.9714940806163832e-08 -3.515570461574312e-08 -3.961992107488511e-08 -4.1852029304456096e-08 -4.059646842532242e-08 -3.850386696009961e-08 -3.7666826374010495e-08 -3.6550772259225e-08 -3.487669108704675e-08 -3.320260991486851e-08 -3.11100084496457e-08 -2.9993954334860204e-08 -3.1668035507038446e-08 -3.11100084496457e-08 -2.9575434041815645e-08 -2.8598886691378335e-08 -2.7343325812244652e-08 -2.706431228354828e-08 -2.7622339340941025e-08 -2.706431228354828e-08 -2.6924805519200093e-08 -2.7482832576592838e-08 -2.7482832576592838e-08 -2.608776493311097e-08 -2.5669244640066407e-08 -2.7622339340941025e-08 -2.9017406984422894e-08 -2.985444757051202e-08 -3.069148815660114e-08 -3.069148815660114e-08 -2.943592727746746e-08 -2.8598886691378335e-08 -2.706431228354828e-08 -2.5808751404414597e-08 -2.4971710818325472e-08 -2.5111217582673662e-08 -2.706431228354828e-08 -2.804085963398559e-08 -2.6785298754851907e-08 -2.608776493311097e-08 -2.7343325812244652e-08 -2.706431228354828e-08 -2.7622339340941025e-08 -2.706431228354828e-08 -2.6924805519200093e-08 -2.7482832576592838e-08 -2.7482832576592838e-08 -2.608776493311097e-08 -2.5669244640066407e-08 -2.7622339340941025e-08 -2.9017406984422894e-08 -2.985444757051202e-08 -3.069148815660114e-08 -3.069148815660114e-08 -2.943592727746746e-08 -2.8598886691378335e-08 -2.706431228354828e-08 -2.5808751404414597e-08 -2.4971710818325472e-08 -2.5111217582673662e-08 -2.706431228354828e-08 -2.804085963398559e-08 -2.6785298754851907e-08 -2.608776493311097e-08 -2.6645791990503717e-08 -2.7343325812244652e-08 -2.650628522615553e-08 -2.6785298754851907e-08 -2.7343325812244652e-08 -2.9296420513119273e-08 -3.4737184322698563e-08 -2.9156913748771087e-08 -4.1852029304456096e-08 -4.50606848844644e-08 -4.6455752527946275e-08 -4.673476605664265e-08 -4.2828576654893406e-08 -4.464216459141985e-08 -4.533969841316077e-08 -4.310759018358978e-08 -3.585323843748406e-08 -2.5669244640066407e-08 -2.106552141657624e-08 -2.1344534945272613e-08 -2.6227271697459155e-08 -2.4413683760932724e-08 -1.8414892893960685e-08 -2.8180366398333776e-08 -2.5669244640066407e-08 -2.608776493311097e-08 -2.6645791990503717e-08 -2.6227271697459155e-08 -2.650628522615553e-08 -2.7482832576592838e-08 -3.292359638617213e-08 -2.804085963398559e-08 -4.059646842532242e-08 -4.408413753402709e-08 -4.5897725470553524e-08 -4.673476605664265e-08 -4.2689069890545226e-08 -4.464216459141985e-08 -4.492117812011622e-08 -4.2689069890545226e-08 -3.613225196618043e-08 -2.5250724347021848e-08 -2.106552141657624e-08 -2.1344534945272613e-08 -2.5948258168762783e-08 -2.4413683760932724e-08 -1.855439965830887e-08 -2.8598886691378335e-08 -2.6785298754851907e-08 -2.5948258168762783e-08 -2.4832204053977286e-08 -2.552973787571822e-08 -2.5948258168762783e-08 -2.706431228354828e-08 -3.292359638617213e-08 -2.7901352869637404e-08 -4.031745489662604e-08 -4.394463076967891e-08 -4.575821870620534e-08 -4.673476605664265e-08 -4.3386603712286164e-08 -4.533969841316077e-08 -4.5618711941857144e-08 -4.29680834192416e-08 -3.5713731673135874e-08 -2.4971710818325472e-08 -2.0367987594835303e-08 -2.078650788787986e-08 -2.552973787571822e-08 -2.46926972896291e-08 -1.9391440244397992e-08 -2.8877900220074708e-08 -2.6227271697459155e-08 -2.6366778461807345e-08 -2.5669244640066407e-08 -2.608776493311097e-08 -2.6785298754851907e-08 -2.845937992703015e-08 -3.362113020791307e-08 -2.7343325812244652e-08 -3.86433737244478e-08 -4.1852029304456096e-08 -4.324709694793797e-08 -4.3805124005330716e-08 -3.989893460358149e-08 -4.045696166097423e-08 -3.948041431053692e-08 -3.5713731673135874e-08 -2.985444757051202e-08 -2.246058906005811e-08 -1.9251933480049806e-08 -1.8972919951353434e-08 -2.1763055238317172e-08 -2.106552141657624e-08 -1.771735907221975e-08 -2.845937992703015e-08 -2.5390231111370035e-08 -2.5669244640066407e-08 -2.5250724347021848e-08 -2.5390231111370035e-08 -2.608776493311097e-08 -2.5808751404414597e-08 -2.5808751404414597e-08 -2.7622339340941025e-08 -3.3063103150520315e-08 -3.682978578792137e-08 -3.948041431053692e-08 -4.003844136792967e-08 -3.822485343140324e-08 -3.710879931661774e-08 -3.6411265494876805e-08 -3.54347181444395e-08 -3.348162344356488e-08 -3.11100084496457e-08 -2.9575434041815645e-08 -2.943592727746746e-08 -3.0551981392252956e-08 -3.0970501685297515e-08 -2.9296420513119273e-08 -2.873839345572652e-08 -2.706431228354828e-08 -2.804085963398559e-08 -2.7482832576592838e-08 -2.706431228354828e-08 -2.6785298754851907e-08 -2.7343325812244652e-08 -2.650628522615553e-08 -2.4971710818325472e-08 -2.5669244640066407e-08 -2.7482832576592838e-08 -2.8877900220074708e-08 -2.9575434041815645e-08 -2.9714940806163832e-08 -2.9575434041815645e-08 -2.845937992703015e-08 -2.7761846105289214e-08 -2.6366778461807345e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.455319052528091e-08 -2.6227271697459155e-08 -2.7343325812244652e-08 -2.5948258168762783e-08 -2.5111217582673662e-08 -2.2739602588754482e-08 -2.385565670353998e-08 -2.3437136410495414e-08 -2.3716149939191793e-08 -2.455319052528091e-08 -2.6366778461807345e-08 -3.152852874269026e-08 -2.6785298754851907e-08 -3.9759427839233295e-08 -4.366561724098254e-08 -4.5618711941857144e-08 -4.631624576359808e-08 -4.324709694793797e-08 -4.50606848844644e-08 -4.4502657827071654e-08 -4.227054959750066e-08 -3.4737184322698563e-08 -2.3576643174843603e-08 -1.9391440244397992e-08 -1.911242671570162e-08 -2.3018616117450855e-08 -2.287910935310267e-08 -1.8414892893960685e-08 -2.8598886691378335e-08 -2.4971710818325472e-08 -2.5669244640066407e-08 -2.5111217582673662e-08 -2.5390231111370035e-08 -2.552973787571822e-08 -2.6785298754851907e-08 -3.208655580008301e-08 -2.7203819047896466e-08 -3.9759427839233295e-08 -4.324709694793797e-08 -4.478167135576803e-08 -4.5618711941857144e-08 -4.199153606880429e-08 -4.3805124005330716e-08 -4.4502657827071654e-08 -4.227054959750066e-08 -3.5295211380091315e-08 -2.455319052528091e-08 -2.050749435918349e-08 -2.106552141657624e-08 -2.5390231111370035e-08 -2.46926972896291e-08 -1.855439965830887e-08 -2.706431228354828e-08 -2.4413683760932724e-08 -2.455319052528091e-08 -2.455319052528091e-08 -2.3995163467888165e-08 -2.4413683760932724e-08 -2.608776493311097e-08 -3.11100084496457e-08 -2.6785298754851907e-08 -3.920140078184055e-08 -4.2689069890545226e-08 -4.436315106272346e-08 -4.5618711941857144e-08 -4.199153606880429e-08 -4.408413753402709e-08 -4.464216459141985e-08 -4.2410056361848854e-08 -3.5713731673135874e-08 -2.4832204053977286e-08 -2.0926014652228048e-08 -2.0926014652228048e-08 -2.5111217582673662e-08 -2.5111217582673662e-08 -1.9251933480049806e-08 -2.8877900220074708e-08 -2.6227271697459155e-08 -2.6366778461807345e-08 -2.5669244640066407e-08 -2.6645791990503717e-08 -2.6645791990503717e-08 -2.8180366398333776e-08 -3.362113020791307e-08 -2.804085963398559e-08 -4.031745489662604e-08 -4.394463076967891e-08 -4.5479205177508965e-08 -4.631624576359808e-08 -4.2689069890545226e-08 -4.492117812011622e-08 -4.492117812011622e-08 -4.199153606880429e-08 -3.5295211380091315e-08 -2.5111217582673662e-08 -2.0926014652228048e-08 -2.106552141657624e-08 -2.5111217582673662e-08 -2.5669244640066407e-08 -2.008897406613893e-08 -2.943592727746746e-08 -2.650628522615553e-08 -2.6785298754851907e-08 -2.6227271697459155e-08 -2.6785298754851907e-08 -2.7343325812244652e-08 -2.9017406984422894e-08 -3.417915726530581e-08 -2.7622339340941025e-08 -3.961992107488511e-08 -4.2689069890545226e-08 -4.422364429837528e-08 -4.478167135576803e-08 -4.087548195401879e-08 -4.129400224706335e-08 -4.017794813227786e-08 -3.6550772259225e-08 -3.069148815660114e-08 -2.287910935310267e-08 -1.9391440244397992e-08 -1.9251933480049806e-08 -2.1902562002665358e-08 -2.2321082295709924e-08 -1.911242671570162e-08 -2.9993954334860204e-08 -2.706431228354828e-08 -2.7482832576592838e-08 -2.7343325812244652e-08 -2.7622339340941025e-08 -2.8598886691378335e-08 -2.7901352869637404e-08 -2.706431228354828e-08 -2.9156913748771087e-08 -3.459767755835038e-08 -3.822485343140324e-08 -4.0735975189670606e-08 -4.115449548271517e-08 -3.9759427839233295e-08 -3.794583990270687e-08 -3.724830608096593e-08 -3.5016197851394936e-08 -3.320260991486851e-08 -2.985444757051202e-08 -2.8180366398333776e-08 -2.845937992703015e-08 -2.985444757051202e-08 -3.11100084496457e-08 -3.027296786355658e-08 -2.873839345572652e-08 -2.706431228354828e-08 -2.7901352869637404e-08 -2.6645791990503717e-08 -2.6785298754851907e-08 -2.6366778461807345e-08 -2.6645791990503717e-08 -2.5669244640066407e-08 -2.385565670353998e-08 -2.5390231111370035e-08 -2.7343325812244652e-08 -2.8877900220074708e-08 -2.9714940806163832e-08 -2.985444757051202e-08 -2.943592727746746e-08 -2.8319873162681962e-08 -2.6924805519200093e-08 -2.5808751404414597e-08 -2.4971710818325472e-08 -2.413467023223635e-08 -2.385565670353998e-08 -2.4971710818325472e-08 -2.6366778461807345e-08 -2.5111217582673662e-08 -2.3995163467888165e-08 -2.246058906005811e-08 -2.3437136410495414e-08 -2.315812288179904e-08 -2.3576643174843603e-08 -2.455319052528091e-08 -2.5808751404414597e-08 -3.041247462790477e-08 -2.5948258168762783e-08 -3.8364360195751426e-08 -4.227054959750066e-08 -4.366561724098254e-08 -4.464216459141985e-08 -4.115449548271517e-08 -4.310759018358978e-08 -4.2689069890545226e-08 -4.101498871836698e-08 -3.376063697226125e-08 -2.2739602588754482e-08 -1.8693906422657058e-08 -1.855439965830887e-08 -2.1344534945272613e-08 -2.246058906005811e-08 -1.7856865836567937e-08 -2.8180366398333776e-08 -2.455319052528091e-08 -2.5390231111370035e-08 -2.4274176996584538e-08 -2.46926972896291e-08 -2.455319052528091e-08 -2.552973787571822e-08 -3.027296786355658e-08 -2.5948258168762783e-08 -3.8364360195751426e-08 -4.199153606880429e-08 -4.394463076967891e-08 -4.533969841316077e-08 -4.157301577575972e-08 -4.324709694793797e-08 -4.366561724098254e-08 -4.1433509011411543e-08 -3.487669108704675e-08 -2.3995163467888165e-08 -1.9391440244397992e-08 -1.9391440244397992e-08 -2.246058906005811e-08 -2.3576643174843603e-08 -1.813587936526431e-08 -2.650628522615553e-08 -2.3716149939191793e-08 -2.413467023223635e-08 -2.315812288179904e-08 -2.3297629646147227e-08 -2.3716149939191793e-08 -2.552973787571822e-08 -3.013346109920839e-08 -2.5948258168762783e-08 -3.8085346667055053e-08 -4.1712522540107916e-08 -4.3526110476634344e-08 -4.464216459141985e-08 -4.115449548271517e-08 -4.310759018358978e-08 -4.3805124005330716e-08 -4.157301577575972e-08 -3.459767755835038e-08 -2.4274176996584538e-08 -1.9949467301790744e-08 -1.9670453773094368e-08 -2.2600095824406296e-08 -2.4413683760932724e-08 -1.8972919951353434e-08 -2.7901352869637404e-08 -2.5111217582673662e-08 -2.5669244640066407e-08 -2.4971710818325472e-08 -2.552973787571822e-08 -2.5250724347021848e-08 -2.7203819047896466e-08 -3.22260625644312e-08 -2.7343325812244652e-08 -3.9759427839233295e-08 -4.3386603712286164e-08 -4.520019164881259e-08 -4.61767389992499e-08 -4.2689069890545226e-08 -4.464216459141985e-08 -4.492117812011622e-08 -4.199153606880429e-08 -3.5295211380091315e-08 -2.5111217582673662e-08 -2.106552141657624e-08 -2.050749435918349e-08 -2.287910935310267e-08 -2.4971710818325472e-08 -1.953094700874618e-08 -2.9017406984422894e-08 -2.5669244640066407e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.5390231111370035e-08 -2.5808751404414597e-08 -2.706431228354828e-08 -3.180754227138664e-08 -2.608776493311097e-08 -3.794583990270687e-08 -4.129400224706335e-08 -4.324709694793797e-08 -4.4502657827071654e-08 -4.115449548271517e-08 -4.157301577575972e-08 -4.101498871836698e-08 -3.724830608096593e-08 -3.11100084496457e-08 -2.3437136410495414e-08 -1.953094700874618e-08 -1.9251933480049806e-08 -2.1344534945272613e-08 -2.218157553136173e-08 -1.911242671570162e-08 -3.013346109920839e-08 -2.706431228354828e-08 -2.7203819047896466e-08 -2.650628522615553e-08 -2.6645791990503717e-08 -2.6645791990503717e-08 -2.650628522615553e-08 -2.5808751404414597e-08 -2.804085963398559e-08 -3.3342116679216694e-08 -3.794583990270687e-08 -4.059646842532242e-08 -4.101498871836698e-08 -3.961992107488511e-08 -3.8085346667055053e-08 -3.75273196096623e-08 -3.54347181444395e-08 -3.3342116679216694e-08 -3.013346109920839e-08 -2.8598886691378335e-08 -2.873839345572652e-08 -2.9156913748771087e-08 -3.083099492094933e-08 -2.9575434041815645e-08 -2.7482832576592838e-08 -2.552973787571822e-08 -2.5948258168762783e-08 -2.4832204053977286e-08 -2.46926972896291e-08 -2.455319052528091e-08 -2.455319052528091e-08 -2.315812288179904e-08 -2.1902562002665358e-08 -2.3716149939191793e-08 -2.650628522615553e-08 -2.7901352869637404e-08 -2.8598886691378335e-08 -2.8877900220074708e-08 -2.8877900220074708e-08 -2.8180366398333776e-08 -2.7343325812244652e-08 -2.6785298754851907e-08 -2.552973787571822e-08 -2.3995163467888165e-08 -2.385565670353998e-08 -2.413467023223635e-08 -2.6366778461807345e-08 -2.4971710818325472e-08 -2.413467023223635e-08 -2.2042068767013544e-08 -2.315812288179904e-08 -2.2321082295709924e-08 -2.3018616117450855e-08 -2.3716149939191793e-08 -2.4832204053977286e-08 -2.943592727746746e-08 -2.4971710818325472e-08 -3.682978578792137e-08 -4.0735975189670606e-08 -4.2689069890545226e-08 -4.3805124005330716e-08 -3.989893460358149e-08 -4.1712522540107916e-08 -4.157301577575972e-08 -4.003844136792967e-08 -3.320260991486851e-08 -2.2739602588754482e-08 -1.8693906422657058e-08 -1.8414892893960685e-08 -2.008897406613893e-08 -2.1623548473968986e-08 -1.757785230787156e-08 -2.7203819047896466e-08 -2.46926972896291e-08 -2.5250724347021848e-08 -2.413467023223635e-08 -2.4971710818325472e-08 -2.5250724347021848e-08 -2.6227271697459155e-08 -2.9575434041815645e-08 -2.4274176996584538e-08 -3.5295211380091315e-08 -3.8782880488795985e-08 -4.059646842532242e-08 -4.1712522540107916e-08 -3.8364360195751426e-08 -4.003844136792967e-08 -3.989893460358149e-08 -3.8085346667055053e-08 -3.22260625644312e-08 -2.287910935310267e-08 -1.82753861296125e-08 -1.7856865836567937e-08 -1.9809960537442554e-08 -2.14840417096208e-08 -1.7159332014827002e-08 -2.5948258168762783e-08 -2.385565670353998e-08 -2.4413683760932724e-08 -2.315812288179904e-08 -2.3297629646147227e-08 -2.3716149939191793e-08 -2.5111217582673662e-08 -2.943592727746746e-08 -2.5250724347021848e-08 -3.7666826374010495e-08 -4.087548195401879e-08 -4.2828576654893406e-08 -4.408413753402709e-08 -4.0735975189670606e-08 -4.29680834192416e-08 -4.310759018358978e-08 -4.115449548271517e-08 -3.417915726530581e-08 -2.3995163467888165e-08 -1.9391440244397992e-08 -1.855439965830887e-08 -2.050749435918349e-08 -2.2739602588754482e-08 -1.82753861296125e-08 -2.6366778461807345e-08 -2.3297629646147227e-08 -2.3576643174843603e-08 -2.2600095824406296e-08 -2.287910935310267e-08 -2.3576643174843603e-08 -2.4971710818325472e-08 -2.9296420513119273e-08 -2.552973787571822e-08 -3.7806333138358674e-08 -4.115449548271517e-08 -4.3526110476634344e-08 -4.478167135576803e-08 -4.1433509011411543e-08 -4.310759018358978e-08 -4.3526110476634344e-08 -4.1433509011411543e-08 -3.445817079400219e-08 -2.4274176996584538e-08 -2.0367987594835303e-08 -1.953094700874618e-08 -2.0647001123531675e-08 -2.3437136410495414e-08 -1.8693906422657058e-08 -2.7622339340941025e-08 -2.455319052528091e-08 -2.4413683760932724e-08 -2.4274176996584538e-08 -2.455319052528091e-08 -2.455319052528091e-08 -2.4971710818325472e-08 -2.8319873162681962e-08 -2.3018616117450855e-08 -3.3063103150520315e-08 -3.613225196618043e-08 -3.794583990270687e-08 -3.892238725314418e-08 -3.613225196618043e-08 -3.682978578792137e-08 -3.6550772259225e-08 -3.348162344356488e-08 -2.7901352869637404e-08 -2.14840417096208e-08 -1.7996372600916123e-08 -1.7438345543523375e-08 -1.8833413187005247e-08 -1.953094700874618e-08 -1.7019825250478813e-08 -2.7203819047896466e-08 -2.315812288179904e-08 -2.3297629646147227e-08 -2.315812288179904e-08 -2.2739602588754482e-08 -2.2739602588754482e-08 -2.3576643174843603e-08 -2.455319052528091e-08 -2.9714940806163832e-08 -4.157301577575972e-08 -4.82693404644727e-08 -5.105947575143644e-08 -5.2873063687962876e-08 -5.105947575143644e-08 -5.064095545839188e-08 -5.175700957317738e-08 -5.036194192969551e-08 -4.6455752527946275e-08 -3.557422490878769e-08 -3.027296786355658e-08 -2.9017406984422894e-08 -2.9575434041815645e-08 -3.3063103150520315e-08 -2.985444757051202e-08 -2.6645791990503717e-08 -2.3576643174843603e-08 -2.3995163467888165e-08 -2.3297629646147227e-08 -2.246058906005811e-08 -2.2600095824406296e-08 -2.2321082295709924e-08 -2.050749435918349e-08 -1.9949467301790744e-08 -2.1763055238317172e-08 -2.455319052528091e-08 -2.6924805519200093e-08 -2.7343325812244652e-08 -2.845937992703015e-08 -2.8180366398333776e-08 -2.804085963398559e-08 -2.8180366398333776e-08 -2.804085963398559e-08 -2.6645791990503717e-08 -2.5390231111370035e-08 -2.4971710818325472e-08 -2.4971710818325472e-08 -2.6785298754851907e-08 -2.5948258168762783e-08 -2.5111217582673662e-08 -2.315812288179904e-08 -2.3716149939191793e-08 -2.287910935310267e-08 -2.3297629646147227e-08 -2.3716149939191793e-08 -2.4832204053977286e-08 -2.7901352869637404e-08 -2.2739602588754482e-08 -3.3063103150520315e-08 -3.557422490878769e-08 -3.75273196096623e-08 -3.8364360195751426e-08 -3.557422490878769e-08 -3.724830608096593e-08 -3.724830608096593e-08 -3.515570461574312e-08 -2.9575434041815645e-08 -2.106552141657624e-08 -1.757785230787156e-08 -1.7019825250478813e-08 -1.729883877917519e-08 -1.855439965830887e-08 -1.6043277900041506e-08 -2.5250724347021848e-08 -2.3018616117450855e-08 -2.3576643174843603e-08 -2.246058906005811e-08 -2.2600095824406296e-08 -2.287910935310267e-08 -2.3995163467888165e-08 -2.6645791990503717e-08 -2.3018616117450855e-08 -3.362113020791307e-08 -3.682978578792137e-08 -3.822485343140324e-08 -3.892238725314418e-08 -3.6690279023573184e-08 -3.850386696009961e-08 -3.86433737244478e-08 -3.682978578792137e-08 -3.069148815660114e-08 -2.2042068767013544e-08 -1.7996372600916123e-08 -1.7159332014827002e-08 -1.82753861296125e-08 -2.050749435918349e-08 -1.7019825250478813e-08 -2.5948258168762783e-08 -2.455319052528091e-08 -2.5250724347021848e-08 -2.3995163467888165e-08 -2.4274176996584538e-08 -2.455319052528091e-08 -2.5390231111370035e-08 -2.8319873162681962e-08 -2.455319052528091e-08 -3.5713731673135874e-08 -3.822485343140324e-08 -4.017794813227786e-08 -4.1433509011411543e-08 -3.822485343140324e-08 -3.961992107488511e-08 -3.948041431053692e-08 -3.75273196096623e-08 -3.180754227138664e-08 -2.246058906005811e-08 -1.82753861296125e-08 -1.7438345543523375e-08 -1.7996372600916123e-08 -2.0228480830487117e-08 -1.7159332014827002e-08 -2.650628522615553e-08 -2.3297629646147227e-08 -2.385565670353998e-08 -2.3297629646147227e-08 -2.3716149939191793e-08 -2.4413683760932724e-08 -2.5111217582673662e-08 -2.8319873162681962e-08 -2.46926972896291e-08 -3.6550772259225e-08 -3.961992107488511e-08 -4.1852029304456096e-08 -4.310759018358978e-08 -3.989893460358149e-08 -4.1712522540107916e-08 -4.213104283315248e-08 -3.989893460358149e-08 -3.3342116679216694e-08 -2.3437136410495414e-08 -1.9949467301790744e-08 -1.9251933480049806e-08 -2.0367987594835303e-08 -2.2600095824406296e-08 -1.8414892893960685e-08 -2.7203819047896466e-08 -2.455319052528091e-08 -2.46926972896291e-08 -2.3995163467888165e-08 -2.3576643174843603e-08 -2.3576643174843603e-08 -2.3576643174843603e-08 -2.5808751404414597e-08 -2.1205028180924427e-08 -3.041247462790477e-08 -3.3063103150520315e-08 -3.459767755835038e-08 -3.54347181444395e-08 -3.278408962182394e-08 -3.376063697226125e-08 -3.3342116679216694e-08 -3.0970501685297515e-08 -2.650628522615553e-08 -2.050749435918349e-08 -1.771735907221975e-08 -1.6880318486130626e-08 -1.771735907221975e-08 -1.8414892893960685e-08 -1.6880318486130626e-08 -2.6785298754851907e-08 -2.46926972896291e-08 -2.46926972896291e-08 -2.3576643174843603e-08 -2.3437136410495414e-08 -2.3297629646147227e-08 -2.315812288179904e-08 -2.1902562002665358e-08 -2.3995163467888165e-08 -2.8877900220074708e-08 -3.2644582857475756e-08 -3.5295211380091315e-08 -3.5992745201832246e-08 -3.487669108704675e-08 -3.417915726530581e-08 -3.3342116679216694e-08 -3.22260625644312e-08 -3.0970501685297515e-08 -2.8877900220074708e-08 -2.6785298754851907e-08 -2.6645791990503717e-08 -2.5948258168762783e-08 -2.7622339340941025e-08 -2.7622339340941025e-08 -2.5669244640066407e-08 -2.3437136410495414e-08 -2.3995163467888165e-08 -2.3437136410495414e-08 -2.3018616117450855e-08 -2.315812288179904e-08 -2.246058906005811e-08 -2.0228480830487117e-08 -1.9949467301790744e-08 -2.078650788787986e-08 -2.3018616117450855e-08 -2.5669244640066407e-08 -2.6366778461807345e-08 -2.804085963398559e-08 -2.8319873162681962e-08 -2.7482832576592838e-08 -2.7761846105289214e-08 -2.6785298754851907e-08 -2.608776493311097e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.455319052528091e-08 -2.6227271697459155e-08 -2.6366778461807345e-08 -2.5669244640066407e-08 -2.4274176996584538e-08 -2.5111217582673662e-08 -2.46926972896291e-08 -2.4971710818325472e-08 -2.4971710818325472e-08 -2.6227271697459155e-08 -2.9017406984422894e-08 -2.4413683760932724e-08 -3.487669108704675e-08 -3.75273196096623e-08 -3.906189401749236e-08 -4.017794813227786e-08 -3.7666826374010495e-08 -3.948041431053692e-08 -3.920140078184055e-08 -3.724830608096593e-08 -3.124951521399389e-08 -2.218157553136173e-08 -1.82753861296125e-08 -1.7159332014827002e-08 -1.729883877917519e-08 -1.8693906422657058e-08 -1.6182784664389692e-08 -2.552973787571822e-08 -2.3018616117450855e-08 -2.3437136410495414e-08 -2.2739602588754482e-08 -2.2739602588754482e-08 -2.287910935310267e-08 -2.3995163467888165e-08 -2.7482832576592838e-08 -2.455319052528091e-08 -3.627175873052862e-08 -3.9759427839233295e-08 -4.1433509011411543e-08 -4.2549563126197034e-08 -3.9759427839233295e-08 -4.199153606880429e-08 -4.2410056361848854e-08 -4.017794813227786e-08 -3.3342116679216694e-08 -2.3297629646147227e-08 -1.9251933480049806e-08 -1.8693906422657058e-08 -1.9391440244397992e-08 -2.1623548473968986e-08 -1.813587936526431e-08 -2.804085963398559e-08 -2.5250724347021848e-08 -2.5808751404414597e-08 -2.455319052528091e-08 -2.4971710818325472e-08 -2.5250724347021848e-08 -2.6227271697459155e-08 -2.9156913748771087e-08 -2.552973787571822e-08 -3.6690279023573184e-08 -3.9759427839233295e-08 -4.1433509011411543e-08 -4.2549563126197034e-08 -3.892238725314418e-08 -4.017794813227786e-08 -4.045696166097423e-08 -3.822485343140324e-08 -3.208655580008301e-08 -2.2739602588754482e-08 -1.855439965830887e-08 -1.7856865836567937e-08 -1.8414892893960685e-08 -2.008897406613893e-08 -1.729883877917519e-08 -2.7482832576592838e-08 -2.4413683760932724e-08 -2.4832204053977286e-08 -2.455319052528091e-08 -2.4413683760932724e-08 -2.4413683760932724e-08 -2.4832204053977286e-08 -2.46926972896291e-08 -2.9993954334860204e-08 -4.031745489662604e-08 -4.533969841316077e-08 -4.729279311403539e-08 -4.93853945792582e-08 -4.82693404644727e-08 -4.8548353993169076e-08 -4.9245887814910014e-08 -4.701377958533902e-08 -4.29680834192416e-08 -3.4039650500957626e-08 -2.9156913748771087e-08 -2.7482832576592838e-08 -2.6924805519200093e-08 -2.9017406984422894e-08 -2.7901352869637404e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.4832204053977286e-08 -2.455319052528091e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.46926972896291e-08 -2.4971710818325472e-08 -1.771735907221975e-08 -2.4971710818325472e-08 -2.8598886691378335e-08 -2.9714940806163832e-08 -3.0970501685297515e-08 -2.9993954334860204e-08 -2.985444757051202e-08 -3.027296786355658e-08 -2.873839345572652e-08 -2.5948258168762783e-08 -2.050749435918349e-08 -1.7438345543523375e-08 -1.6322291428737878e-08 -1.6182784664389692e-08 -1.729883877917519e-08 -1.6601304957434254e-08 -2.6645791990503717e-08 -2.5390231111370035e-08 -2.5390231111370035e-08 -2.455319052528091e-08 -2.46926972896291e-08 -2.4413683760932724e-08 -2.3995163467888165e-08 -2.246058906005811e-08 -2.455319052528091e-08 -3.013346109920839e-08 -3.4318664029654005e-08 -3.710879931661774e-08 -3.7666826374010495e-08 -3.6550772259225e-08 -3.557422490878769e-08 -3.487669108704675e-08 -3.348162344356488e-08 -3.1947049035734825e-08 -2.9296420513119273e-08 -2.706431228354828e-08 -2.6924805519200093e-08 -2.6645791990503717e-08 -2.7482832576592838e-08 -2.7622339340941025e-08 -2.6366778461807345e-08 -2.3995163467888165e-08 -2.4832204053977286e-08 -2.3995163467888165e-08 -2.413467023223635e-08 -2.3995163467888165e-08 -2.315812288179904e-08 -2.14840417096208e-08 -2.0926014652228048e-08 -2.1763055238317172e-08 -2.3995163467888165e-08 -2.5948258168762783e-08 -2.6645791990503717e-08 -2.7343325812244652e-08 -2.7901352869637404e-08 -2.6785298754851907e-08 -2.6366778461807345e-08 -2.5390231111370035e-08 -2.46926972896291e-08 -2.3995163467888165e-08 -2.3437136410495414e-08 -2.3297629646147227e-08 -2.4971710818325472e-08 -2.5111217582673662e-08 -2.46926972896291e-08 -2.2739602588754482e-08 -2.385565670353998e-08 -2.3437136410495414e-08 -2.3995163467888165e-08 -2.3995163467888165e-08 -2.4971710818325472e-08 -2.8598886691378335e-08 -2.552973787571822e-08 -3.7806333138358674e-08 -4.087548195401879e-08 -4.2828576654893406e-08 -4.436315106272346e-08 -4.115449548271517e-08 -4.310759018358978e-08 -4.310759018358978e-08 -4.087548195401879e-08 -3.390014373660944e-08 -2.3576643174843603e-08 -1.8972919951353434e-08 -1.7996372600916123e-08 -1.813587936526431e-08 -1.9949467301790744e-08 -1.7019825250478813e-08 -2.650628522615553e-08 -2.3716149939191793e-08 -2.385565670353998e-08 -2.385565670353998e-08 -2.3995163467888165e-08 -2.3716149939191793e-08 -2.4274176996584538e-08 -2.804085963398559e-08 -2.5390231111370035e-08 -3.724830608096593e-08 -4.087548195401879e-08 -4.2828576654893406e-08 -4.436315106272346e-08 -4.101498871836698e-08 -4.324709694793797e-08 -4.3386603712286164e-08 -4.115449548271517e-08 -3.445817079400219e-08 -2.3716149939191793e-08 -1.9949467301790744e-08 -1.953094700874618e-08 -1.9670453773094368e-08 -2.1344534945272613e-08 -1.813587936526431e-08 -2.845937992703015e-08 -2.4832204053977286e-08 -2.4971710818325472e-08 -2.385565670353998e-08 -2.3995163467888165e-08 -2.4274176996584538e-08 -2.5250724347021848e-08 -2.873839345572652e-08 -2.5808751404414597e-08 -3.8085346667055053e-08 -4.157301577575972e-08 -4.310759018358978e-08 -4.436315106272346e-08 -4.0735975189670606e-08 -4.2410056361848854e-08 -4.29680834192416e-08 -4.045696166097423e-08 -3.362113020791307e-08 -2.3716149939191793e-08 -1.9251933480049806e-08 -1.855439965830887e-08 -1.8833413187005247e-08 -2.0367987594835303e-08 -1.82753861296125e-08 -2.7761846105289214e-08 -2.413467023223635e-08 -2.4413683760932724e-08 -2.3437136410495414e-08 -2.3995163467888165e-08 -2.3437136410495414e-08 -2.385565670353998e-08 -2.7622339340941025e-08 -2.5111217582673662e-08 -3.682978578792137e-08 -4.059646842532242e-08 -4.2689069890545226e-08 -4.422364429837528e-08 -4.129400224706335e-08 -4.3526110476634344e-08 -4.3805124005330716e-08 -4.1433509011411543e-08 -3.5295211380091315e-08 -2.46926972896291e-08 -2.0228480830487117e-08 -1.9670453773094368e-08 -1.9809960537442554e-08 -2.1344534945272613e-08 -1.911242671570162e-08 -2.8180366398333776e-08 -2.4971710818325472e-08 -2.4971710818325472e-08 -2.413467023223635e-08 -2.3995163467888165e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.6785298754851907e-08 -2.3018616117450855e-08 -3.320260991486851e-08 -3.6690279023573184e-08 -3.822485343140324e-08 -3.8782880488795985e-08 -3.5713731673135874e-08 -3.6550772259225e-08 -3.5992745201832246e-08 -3.362113020791307e-08 -2.845937992703015e-08 -2.2321082295709924e-08 -1.8972919951353434e-08 -1.82753861296125e-08 -1.8414892893960685e-08 -1.9670453773094368e-08 -1.82753861296125e-08 -2.8877900220074708e-08 -2.5669244640066407e-08 -2.5111217582673662e-08 -2.385565670353998e-08 -2.3995163467888165e-08 -2.413467023223635e-08 -2.3018616117450855e-08 -2.2042068767013544e-08 -2.4274176996584538e-08 -2.985444757051202e-08 -3.4318664029654005e-08 -3.696929255226956e-08 -3.794583990270687e-08 -3.6550772259225e-08 -3.515570461574312e-08 -3.487669108704675e-08 -3.362113020791307e-08 -3.1947049035734825e-08 -2.9017406984422894e-08 -2.7482832576592838e-08 -2.7203819047896466e-08 -2.650628522615553e-08 -2.6924805519200093e-08 -2.706431228354828e-08 -2.608776493311097e-08 -2.413467023223635e-08 -2.4832204053977286e-08 -2.3995163467888165e-08 -2.3576643174843603e-08 -2.3716149939191793e-08 -2.3297629646147227e-08 -2.246058906005811e-08 -2.2739602588754482e-08 -2.3995163467888165e-08 -2.5808751404414597e-08 -2.7761846105289214e-08 -2.845937992703015e-08 -2.8598886691378335e-08 -2.804085963398559e-08 -2.6924805519200093e-08 -2.5808751404414597e-08 -2.552973787571822e-08 -2.5250724347021848e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.4413683760932724e-08 -2.5111217582673662e-08 -2.5390231111370035e-08 -2.4413683760932724e-08 -2.413467023223635e-08 -2.4832204053977286e-08 -2.3995163467888165e-08 -2.3576643174843603e-08 -2.3716149939191793e-08 -2.3297629646147227e-08 -2.246058906005811e-08 -2.2739602588754482e-08 -2.3995163467888165e-08 -2.5808751404414597e-08 -2.7761846105289214e-08 -2.845937992703015e-08 -2.8598886691378335e-08 -2.804085963398559e-08 -2.6924805519200093e-08 -2.5808751404414597e-08 -2.552973787571822e-08 -2.5250724347021848e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.4413683760932724e-08 -2.5111217582673662e-08 -2.5390231111370035e-08 -2.4413683760932724e-08 -2.315812288179904e-08 -2.3576643174843603e-08 -2.3297629646147227e-08 -2.3716149939191793e-08 -2.3018616117450855e-08 -2.3576643174843603e-08 -2.7343325812244652e-08 -2.5111217582673662e-08 -3.710879931661774e-08 -4.0735975189670606e-08 -4.2828576654893406e-08 -4.408413753402709e-08 -4.0735975189670606e-08 -4.324709694793797e-08 -4.324709694793797e-08 -4.129400224706335e-08 -3.4318664029654005e-08 -2.385565670353998e-08 -1.9391440244397992e-08 -1.855439965830887e-08 -1.8414892893960685e-08 -1.953094700874618e-08 -1.7438345543523375e-08 -2.650628522615553e-08 -2.315812288179904e-08 -2.3437136410495414e-08 -2.2739602588754482e-08 -2.2739602588754482e-08 -2.3437136410495414e-08 -2.3297629646147227e-08 -2.7203819047896466e-08 -2.5390231111370035e-08 -3.794583990270687e-08 -4.157301577575972e-08 -4.366561724098254e-08 -4.533969841316077e-08 -4.1712522540107916e-08 -4.3386603712286164e-08 -4.366561724098254e-08 -4.1433509011411543e-08 -3.459767755835038e-08 -2.455319052528091e-08 -2.0647001123531675e-08 -1.9809960537442554e-08 -1.8833413187005247e-08 -2.0228480830487117e-08 -1.8414892893960685e-08 -2.804085963398559e-08 -2.6924805519200093e-08 -2.6785298754851907e-08 -2.5669244640066407e-08 -2.650628522615553e-08 -2.6645791990503717e-08 -2.4971710818325472e-08 -2.8180366398333776e-08 -2.552973787571822e-08 -3.7666826374010495e-08 -4.1433509011411543e-08 -4.3386603712286164e-08 -4.50606848844644e-08 -4.1852029304456096e-08 -4.394463076967891e-08 -4.408413753402709e-08 -4.1852029304456096e-08 -3.54347181444395e-08 -2.4971710818325472e-08 -2.0228480830487117e-08 -1.911242671570162e-08 -1.9251933480049806e-08 -2.0228480830487117e-08 -1.8414892893960685e-08 -2.7343325812244652e-08 -2.385565670353998e-08 -2.413467023223635e-08 -2.3297629646147227e-08 -2.3437136410495414e-08 -2.385565670353998e-08 -2.3576643174843603e-08 -2.6227271697459155e-08 -2.3437136410495414e-08 -3.4318664029654005e-08 -3.7806333138358674e-08 -3.948041431053692e-08 -4.031745489662604e-08 -3.682978578792137e-08 -3.7806333138358674e-08 -3.710879931661774e-08 -3.417915726530581e-08 -2.873839345572652e-08 -2.2042068767013544e-08 -1.8693906422657058e-08 -1.7996372600916123e-08 -1.7856865836567937e-08 -1.8833413187005247e-08 -1.82753861296125e-08 -2.9017406984422894e-08 -2.5808751404414597e-08 -2.5111217582673662e-08 -2.3297629646147227e-08 -2.2739602588754482e-08 -2.2739602588754482e-08 -2.14840417096208e-08 -2.0926014652228048e-08 -2.3576643174843603e-08 -2.9156913748771087e-08 -3.390014373660944e-08 -3.6411265494876805e-08 -3.7666826374010495e-08 -3.627175873052862e-08 -3.557422490878769e-08 -3.5295211380091315e-08 -3.417915726530581e-08 -3.208655580008301e-08 -2.9575434041815645e-08 -2.7901352869637404e-08 -2.7761846105289214e-08 -2.6785298754851907e-08 -2.6645791990503717e-08 -2.706431228354828e-08 -2.5808751404414597e-08 -2.3576643174843603e-08 -2.385565670353998e-08 -2.315812288179904e-08 -2.287910935310267e-08 -2.3018616117450855e-08 -2.2042068767013544e-08 -2.1344534945272613e-08 -2.287910935310267e-08 -2.455319052528091e-08 -2.608776493311097e-08 -2.8180366398333776e-08 -2.8877900220074708e-08 -2.873839345572652e-08 -2.7901352869637404e-08 -2.6785298754851907e-08 -2.5948258168762783e-08 -2.5111217582673662e-08 -2.5250724347021848e-08 -2.4832204053977286e-08 -2.4971710818325472e-08 -2.455319052528091e-08 -2.4274176996584538e-08 -2.5111217582673662e-08 -2.4274176996584538e-08 -2.2739602588754482e-08 -2.3995163467888165e-08 -2.3297629646147227e-08 -2.3716149939191793e-08 -2.3995163467888165e-08 -2.2739602588754482e-08 -2.650628522615553e-08 -2.4413683760932724e-08 -3.6690279023573184e-08 -4.017794813227786e-08 -4.115449548271517e-08 -4.2689069890545226e-08 -3.920140078184055e-08 -4.1433509011411543e-08 -4.1433509011411543e-08 -3.9759427839233295e-08 -3.348162344356488e-08 -2.287910935310267e-08 -1.8833413187005247e-08 -1.7996372600916123e-08 -1.7019825250478813e-08 -1.7159332014827002e-08 -1.6182784664389692e-08 -2.5250724347021848e-08 -2.3716149939191793e-08 -2.3995163467888165e-08 -2.315812288179904e-08 -2.3716149939191793e-08 -2.413467023223635e-08 -2.385565670353998e-08 -2.7482832576592838e-08 -2.4971710818325472e-08 -3.710879931661774e-08 -4.115449548271517e-08 -4.29680834192416e-08 -4.422364429837528e-08 -4.087548195401879e-08 -4.29680834192416e-08 -4.324709694793797e-08 -4.101498871836698e-08 -3.417915726530581e-08 -2.3437136410495414e-08 -1.8833413187005247e-08 -1.7856865836567937e-08 -1.729883877917519e-08 -1.813587936526431e-08 -1.7438345543523375e-08 -2.6785298754851907e-08 -2.413467023223635e-08 -2.4971710818325472e-08 -2.4274176996584538e-08 -2.413467023223635e-08 -2.4832204053977286e-08 -2.385565670353998e-08 -2.804085963398559e-08 -2.5808751404414597e-08 -3.8085346667055053e-08 -4.1852029304456096e-08 -4.408413753402709e-08 -4.5618711941857144e-08 -4.2549563126197034e-08 -4.408413753402709e-08 -4.408413753402709e-08 -4.227054959750066e-08 -3.5295211380091315e-08 -2.4971710818325472e-08 -2.0926014652228048e-08 -2.008897406613893e-08 -1.8972919951353434e-08 -1.9391440244397992e-08 -1.8833413187005247e-08 -2.8877900220074708e-08 -2.5808751404414597e-08 -2.5111217582673662e-08 -2.4832204053977286e-08 -2.5390231111370035e-08 -2.5669244640066407e-08 -2.4413683760932724e-08 -2.804085963398559e-08 -2.5250724347021848e-08 -3.75273196096623e-08 -4.115449548271517e-08 -4.2828576654893406e-08 -4.422364429837528e-08 -4.101498871836698e-08 -4.29680834192416e-08 -4.310759018358978e-08 -4.087548195401879e-08 -3.445817079400219e-08 -2.413467023223635e-08 -1.9670453773094368e-08 -1.8693906422657058e-08 -1.8972919951353434e-08 -1.8972919951353434e-08 -1.757785230787156e-08 -2.650628522615553e-08 -2.3437136410495414e-08 -2.385565670353998e-08 -2.287910935310267e-08 -2.3018616117450855e-08 -2.287910935310267e-08 -2.2600095824406296e-08 -2.5948258168762783e-08 -2.315812288179904e-08 -3.390014373660944e-08 -3.7387812845314116e-08 -3.9340907546188736e-08 -4.059646842532242e-08 -3.724830608096593e-08 -3.8085346667055053e-08 -3.724830608096593e-08 -3.4039650500957626e-08 -2.8598886691378335e-08 -2.1902562002665358e-08 -1.8414892893960685e-08 -1.757785230787156e-08 -1.6880318486130626e-08 -1.6880318486130626e-08 -1.7159332014827002e-08 -2.7761846105289214e-08 -2.4832204053977286e-08 -2.455319052528091e-08 -2.2600095824406296e-08 -2.2042068767013544e-08 -2.1902562002665358e-08 -2.0647001123531675e-08 -2.078650788787986e-08 -2.3995163467888165e-08 -2.9156913748771087e-08 -3.362113020791307e-08 -3.6411265494876805e-08 -3.75273196096623e-08 -3.613225196618043e-08 -3.557422490878769e-08 -3.4737184322698563e-08 -3.376063697226125e-08 -3.152852874269026e-08 -2.9296420513119273e-08 -2.7343325812244652e-08 -2.7761846105289214e-08 -2.6785298754851907e-08 -2.6227271697459155e-08 -2.6924805519200093e-08 -2.608776493311097e-08 -2.385565670353998e-08 -2.413467023223635e-08 -2.3297629646147227e-08 -2.315812288179904e-08 -2.315812288179904e-08 -2.1623548473968986e-08 -2.0367987594835303e-08 -2.1623548473968986e-08 -2.3576643174843603e-08 -2.5948258168762783e-08 -2.8180366398333776e-08 -2.943592727746746e-08 -2.9575434041815645e-08 -2.845937992703015e-08 -2.7622339340941025e-08 -2.7203819047896466e-08 -2.608776493311097e-08 -2.6227271697459155e-08 -2.5948258168762783e-08 -2.552973787571822e-08 -2.5390231111370035e-08 -2.5390231111370035e-08 -2.6227271697459155e-08 -2.4971710818325472e-08 -2.4413683760932724e-08 -2.5111217582673662e-08 -2.46926972896291e-08 -2.4832204053977286e-08 -2.5111217582673662e-08 -2.4971710818325472e-08 -2.873839345572652e-08 -2.552973787571822e-08 -3.7666826374010495e-08 -4.129400224706335e-08 -4.310759018358978e-08 -4.422364429837528e-08 -4.101498871836698e-08 -4.324709694793797e-08 -4.3526110476634344e-08 -4.1433509011411543e-08 -3.5016197851394936e-08 -2.455319052528091e-08 -2.0367987594835303e-08 -1.9251933480049806e-08 -1.82753861296125e-08 -1.771735907221975e-08 -1.674081172178244e-08 -2.6645791990503717e-08 -2.46926972896291e-08 -2.4971710818325472e-08 -2.413467023223635e-08 -2.4274176996584538e-08 -2.4832204053977286e-08 -2.46926972896291e-08 -2.7901352869637404e-08 -2.5390231111370035e-08 -3.7666826374010495e-08 -4.1712522540107916e-08 -4.3805124005330716e-08 -4.5479205177508965e-08 -4.1852029304456096e-08 -4.3526110476634344e-08 -4.422364429837528e-08 -4.213104283315248e-08 -3.5295211380091315e-08 -2.455319052528091e-08 -1.9949467301790744e-08 -1.855439965830887e-08 -1.7996372600916123e-08 -1.855439965830887e-08 -1.757785230787156e-08 -2.7482832576592838e-08 -2.46926972896291e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.4971710818325472e-08 -2.4971710818325472e-08 -2.4832204053977286e-08 -2.8877900220074708e-08 -2.5669244640066407e-08 -3.75273196096623e-08 -4.129400224706335e-08 -4.324709694793797e-08 -4.464216459141985e-08 -4.1712522540107916e-08 -4.310759018358978e-08 -4.3386603712286164e-08 -4.129400224706335e-08 -3.445817079400219e-08 -2.4413683760932724e-08 -1.953094700874618e-08 -1.8414892893960685e-08 -1.82753861296125e-08 -1.855439965830887e-08 -1.771735907221975e-08 -2.7203819047896466e-08 -2.4274176996584538e-08 -2.4274176996584538e-08 -2.3297629646147227e-08 -2.3437136410495414e-08 -2.3576643174843603e-08 -2.3437136410495414e-08 -2.7761846105289214e-08 -2.4971710818325472e-08 -3.710879931661774e-08 -4.0735975189670606e-08 -4.29680834192416e-08 -4.422364429837528e-08 -4.101498871836698e-08 -4.2828576654893406e-08 -4.310759018358978e-08 -4.087548195401879e-08 -3.417915726530581e-08 -2.3995163467888165e-08 -1.9251933480049806e-08 -1.82753861296125e-08 -1.813587936526431e-08 -1.7856865836567937e-08 -1.7438345543523375e-08 -2.7343325812244652e-08 -2.3716149939191793e-08 -2.3995163467888165e-08 -2.2321082295709924e-08 -2.287910935310267e-08 -2.246058906005811e-08 -2.1902562002665358e-08 -2.5111217582673662e-08 -2.2600095824406296e-08 -3.362113020791307e-08 -3.724830608096593e-08 -3.920140078184055e-08 -4.045696166097423e-08 -3.724830608096593e-08 -3.794583990270687e-08 -3.696929255226956e-08 -3.4039650500957626e-08 -2.8598886691378335e-08 -2.1623548473968986e-08 -1.82753861296125e-08 -1.729883877917519e-08 -1.6322291428737878e-08 -1.6043277900041506e-08 -1.6182784664389692e-08 -2.6924805519200093e-08 -2.3995163467888165e-08 -2.3716149939191793e-08 -2.2321082295709924e-08 -2.1763055238317172e-08 -2.1763055238317172e-08 -2.008897406613893e-08 -2.050749435918349e-08 -2.3716149939191793e-08 -2.845937992703015e-08 -3.2644582857475756e-08 -3.5713731673135874e-08 -3.696929255226956e-08 -3.557422490878769e-08 -3.445817079400219e-08 -3.348162344356488e-08 -3.320260991486851e-08 -3.069148815660114e-08 -2.804085963398559e-08 -2.5948258168762783e-08 -2.6366778461807345e-08 -2.552973787571822e-08 -2.5111217582673662e-08 -2.6227271697459155e-08 -2.5808751404414597e-08 -2.3716149939191793e-08 -2.4274176996584538e-08 -2.2739602588754482e-08 -2.2739602588754482e-08 -2.2600095824406296e-08 -2.0647001123531675e-08 -1.9670453773094368e-08 -2.078650788787986e-08 -2.2321082295709924e-08 -2.5111217582673662e-08 -2.7203819047896466e-08 -2.8598886691378335e-08 -2.9017406984422894e-08 -2.873839345572652e-08 -2.804085963398559e-08 -2.8319873162681962e-08 -2.7622339340941025e-08 -2.6924805519200093e-08 -2.6366778461807345e-08 -2.608776493311097e-08 -2.5948258168762783e-08 -2.608776493311097e-08 -2.650628522615553e-08 -2.5390231111370035e-08 -2.3716149939191793e-08 -2.4413683760932724e-08 -2.3716149939191793e-08 -2.3716149939191793e-08 -2.3995163467888165e-08 -2.3716149939191793e-08 -2.7901352869637404e-08 -2.46926972896291e-08 -3.710879931661774e-08 -4.087548195401879e-08 -4.324709694793797e-08 -4.478167135576803e-08 -4.199153606880429e-08 -4.3386603712286164e-08 -4.310759018358978e-08 -4.087548195401879e-08 -3.4039650500957626e-08 -2.385565670353998e-08 -2.008897406613893e-08 -1.953094700874618e-08 -1.813587936526431e-08 -1.757785230787156e-08 -1.674081172178244e-08 -2.6366778461807345e-08 -2.3297629646147227e-08 -2.385565670353998e-08 -2.3018616117450855e-08 -2.3297629646147227e-08 -2.315812288179904e-08 -2.3437136410495414e-08 -2.6645791990503717e-08 -2.455319052528091e-08 -3.682978578792137e-08 -4.059646842532242e-08 -4.310759018358978e-08 -4.464216459141985e-08 -4.115449548271517e-08 -4.2828576654893406e-08 -4.366561724098254e-08 -4.1712522540107916e-08 -3.5016197851394936e-08 -2.455319052528091e-08 -2.008897406613893e-08 -1.8414892893960685e-08 -1.7856865836567937e-08 -1.813587936526431e-08 -1.7159332014827002e-08 -2.6645791990503717e-08 -2.385565670353998e-08 -2.4274176996584538e-08 -2.3576643174843603e-08 -2.3716149939191793e-08 -2.3576643174843603e-08 -2.3716149939191793e-08 -2.7622339340941025e-08 -2.5250724347021848e-08 -3.710879931661774e-08 -4.115449548271517e-08 -4.29680834192416e-08 -4.4502657827071654e-08 -4.129400224706335e-08 -4.2549563126197034e-08 -4.29680834192416e-08 -4.1433509011411543e-08 -3.459767755835038e-08 -2.4274176996584538e-08 -1.9251933480049806e-08 -1.771735907221975e-08 -1.729883877917519e-08 -1.729883877917519e-08 -1.6601304957434254e-08 -2.6645791990503717e-08 -2.4274176996584538e-08 -2.455319052528091e-08 -2.2739602588754482e-08 -2.2739602588754482e-08 -2.3437136410495414e-08 -2.3576643174843603e-08 -2.7482832576592838e-08 -2.4971710818325472e-08 -3.7387812845314116e-08 -4.129400224706335e-08 -4.394463076967891e-08 -4.5479205177508965e-08 -4.2689069890545226e-08 -4.464216459141985e-08 -4.50606848844644e-08 -4.310759018358978e-08 -3.613225196618043e-08 -2.5669244640066407e-08 -2.050749435918349e-08 -1.911242671570162e-08 -1.8693906422657058e-08 -1.813587936526431e-08 -1.7438345543523375e-08 -2.7482832576592838e-08 -2.4413683760932724e-08 -2.455319052528091e-08 -2.2739602588754482e-08 -2.3297629646147227e-08 -2.3018616117450855e-08 -2.246058906005811e-08 -2.5808751404414597e-08 -2.3576643174843603e-08 -3.5295211380091315e-08 -3.906189401749236e-08 -4.129400224706335e-08 -4.213104283315248e-08 -3.86433737244478e-08 -3.948041431053692e-08 -3.8782880488795985e-08 -3.557422490878769e-08 -2.943592727746746e-08 -2.1902562002665358e-08 -1.855439965830887e-08 -1.729883877917519e-08 -1.6601304957434254e-08 -1.6322291428737878e-08 -1.576426437134513e-08 -2.650628522615553e-08 -2.3437136410495414e-08 -2.315812288179904e-08 -2.1902562002665358e-08 -2.14840417096208e-08 -2.1344534945272613e-08 -1.9670453773094368e-08 -1.9670453773094368e-08 -2.246058906005811e-08 -2.7761846105289214e-08 -3.1668035507038446e-08 -3.445817079400219e-08 -3.54347181444395e-08 -3.390014373660944e-08 -3.278408962182394e-08 -3.1947049035734825e-08 -3.152852874269026e-08 -2.9575434041815645e-08 -2.706431228354828e-08 -2.4971710818325472e-08 -2.455319052528091e-08 -2.3995163467888165e-08 -2.3716149939191793e-08 -2.5390231111370035e-08 -2.4971710818325472e-08 -2.287910935310267e-08 -2.3297629646147227e-08 -2.2042068767013544e-08 -2.1902562002665358e-08 -2.14840417096208e-08 -1.9809960537442554e-08 -1.8693906422657058e-08 -1.9391440244397992e-08 -2.078650788787986e-08 -2.315812288179904e-08 -2.4971710818325472e-08 -2.608776493311097e-08 -2.6645791990503717e-08 -2.7203819047896466e-08 -2.6645791990503717e-08 -2.706431228354828e-08 -2.650628522615553e-08 -2.5250724347021848e-08 -2.4832204053977286e-08 -2.4274176996584538e-08 -2.46926972896291e-08 -2.4832204053977286e-08 -2.5808751404414597e-08 -2.5250724347021848e-08 -2.2042068767013544e-08 -2.246058906005811e-08 -2.14840417096208e-08 -2.1623548473968986e-08 -2.1902562002665358e-08 -2.106552141657624e-08 -2.552973787571822e-08 -2.3576643174843603e-08 -3.613225196618043e-08 -3.948041431053692e-08 -4.199153606880429e-08 -4.3805124005330716e-08 -4.0735975189670606e-08 -4.2410056361848854e-08 -4.213104283315248e-08 -4.017794813227786e-08 -3.362113020791307e-08 -2.3297629646147227e-08 -1.911242671570162e-08 -1.855439965830887e-08 -1.7159332014827002e-08 -1.7019825250478813e-08 -1.6601304957434254e-08 -2.7203819047896466e-08 -2.455319052528091e-08 -2.4413683760932724e-08 -2.3995163467888165e-08 -2.4832204053977286e-08 -2.46926972896291e-08 -2.413467023223635e-08 -2.7622339340941025e-08 -2.4971710818325472e-08 -3.7387812845314116e-08 -4.101498871836698e-08 -4.29680834192416e-08 -4.436315106272346e-08 -4.115449548271517e-08 -4.310759018358978e-08 -4.366561724098254e-08 -4.157301577575972e-08 -3.5016197851394936e-08 -2.4413683760932724e-08 -2.008897406613893e-08 -1.8414892893960685e-08 -1.7019825250478813e-08 -1.6880318486130626e-08 -1.7159332014827002e-08 -2.6924805519200093e-08 -2.4274176996584538e-08 -2.3995163467888165e-08 -2.287910935310267e-08 -2.3018616117450855e-08 -2.3018616117450855e-08 -2.2321082295709924e-08 -2.650628522615553e-08 -2.46926972896291e-08 -3.6690279023573184e-08 -4.059646842532242e-08 -4.2549563126197034e-08 -4.394463076967891e-08 -4.0735975189670606e-08 -4.2410056361848854e-08 -4.310759018358978e-08 -4.157301577575972e-08 -3.5016197851394936e-08 -2.455319052528091e-08 -1.9391440244397992e-08 -1.7856865836567937e-08 -1.7019825250478813e-08 -1.674081172178244e-08 -1.7159332014827002e-08 -2.7761846105289214e-08 -2.5111217582673662e-08 -2.4971710818325472e-08 -2.3716149939191793e-08 -2.3716149939191793e-08 -2.4274176996584538e-08 -2.3716149939191793e-08 -2.7343325812244652e-08 -2.4832204053977286e-08 -3.696929255226956e-08 -4.101498871836698e-08 -4.3386603712286164e-08 -4.50606848844644e-08 -4.2828576654893406e-08 -4.4502657827071654e-08 -4.478167135576803e-08 -4.29680834192416e-08 -3.6411265494876805e-08 -2.5669244640066407e-08 -2.078650788787986e-08 -1.9251933480049806e-08 -1.8693906422657058e-08 -1.82753861296125e-08 -1.7996372600916123e-08 -2.8180366398333776e-08 -2.455319052528091e-08 -2.455319052528091e-08 -2.3437136410495414e-08 -2.385565670353998e-08 -2.385565670353998e-08 -2.385565670353998e-08 -2.7622339340941025e-08 -2.4274176996584538e-08 -3.585323843748406e-08 -3.948041431053692e-08 -4.1712522540107916e-08 -4.310759018358978e-08 -3.9759427839233295e-08 -4.045696166097423e-08 -3.9759427839233295e-08 -3.627175873052862e-08 -2.9993954334860204e-08 -2.2321082295709924e-08 -1.8833413187005247e-08 -1.757785230787156e-08 -1.7019825250478813e-08 -1.6461798193086064e-08 -1.6043277900041506e-08 -2.6785298754851907e-08 -2.3995163467888165e-08 -2.3995163467888165e-08 -2.3018616117450855e-08 -2.2739602588754482e-08 -2.218157553136173e-08 -2.0926014652228048e-08 -2.0367987594835303e-08 -2.3576643174843603e-08 -2.9017406984422894e-08 -3.3342116679216694e-08 -3.5713731673135874e-08 -3.682978578792137e-08 -3.487669108704675e-08 -3.376063697226125e-08 -3.278408962182394e-08 -3.1668035507038446e-08 -3.013346109920839e-08 -2.7482832576592838e-08 -2.5808751404414597e-08 -2.5390231111370035e-08 -2.5669244640066407e-08 -2.4832204053977286e-08 -2.5808751404414597e-08 -2.4832204053977286e-08 -2.2739602588754482e-08 -2.315812288179904e-08 -2.218157553136173e-08 -2.2042068767013544e-08 -2.1763055238317172e-08 -2.050749435918349e-08 -1.9251933480049806e-08 -2.050749435918349e-08 -2.2042068767013544e-08 -2.385565670353998e-08 -2.5808751404414597e-08 -2.7343325812244652e-08 -2.804085963398559e-08 -2.8180366398333776e-08 -2.7761846105289214e-08 -2.7761846105289214e-08 -2.650628522615553e-08 -2.5390231111370035e-08 -2.46926972896291e-08 -2.3995163467888165e-08 -2.4413683760932724e-08 -2.413467023223635e-08 -2.5250724347021848e-08 -2.4971710818325472e-08 -2.218157553136173e-08 -2.2739602588754482e-08 -2.2042068767013544e-08 -2.2321082295709924e-08 -2.2600095824406296e-08 -2.1763055238317172e-08 -2.5669244640066407e-08 -2.3995163467888165e-08 -3.6411265494876805e-08 -4.003844136792967e-08 -4.2549563126197034e-08 -4.436315106272346e-08 -4.129400224706335e-08 -4.3526110476634344e-08 -4.366561724098254e-08 -4.115449548271517e-08 -3.4318664029654005e-08 -2.3995163467888165e-08 -1.8972919951353434e-08 -1.82753861296125e-08 -1.7438345543523375e-08 -1.7019825250478813e-08 -1.6880318486130626e-08 -2.7622339340941025e-08 -2.5250724347021848e-08 -2.5390231111370035e-08 -2.5390231111370035e-08 -2.5669244640066407e-08 -2.5669244640066407e-08 -2.4832204053977286e-08 -2.873839345572652e-08 -2.5948258168762783e-08 -3.8364360195751426e-08 -4.227054959750066e-08 -4.4502657827071654e-08 -4.575821870620534e-08 -4.2410056361848854e-08 -4.436315106272346e-08 -4.478167135576803e-08 -4.29680834192416e-08 -3.6411265494876805e-08 -2.6227271697459155e-08 -2.1344534945272613e-08 -2.008897406613893e-08 -1.8833413187005247e-08 -1.82753861296125e-08 -1.813587936526431e-08 -2.9575434041815645e-08 -2.6785298754851907e-08 -2.706431228354828e-08 -2.6366778461807345e-08 -2.6924805519200093e-08 -2.608776493311097e-08 -2.5111217582673662e-08 -2.8877900220074708e-08 -2.552973787571822e-08 -3.8085346667055053e-08 -4.157301577575972e-08 -4.3805124005330716e-08 -4.520019164881259e-08 -4.1852029304456096e-08 -4.3805124005330716e-08 -4.408413753402709e-08 -4.199153606880429e-08 -3.5295211380091315e-08 -2.5111217582673662e-08 -2.0228480830487117e-08 -1.8972919951353434e-08 -1.855439965830887e-08 -1.855439965830887e-08 -1.82753861296125e-08 -2.9296420513119273e-08 -2.6227271697459155e-08 -2.650628522615553e-08 -2.5669244640066407e-08 -2.4971710818325472e-08 -2.552973787571822e-08 -2.413467023223635e-08 -2.7901352869637404e-08 -2.5111217582673662e-08 -3.724830608096593e-08 -4.087548195401879e-08 -4.2689069890545226e-08 -4.422364429837528e-08 -4.1852029304456096e-08 -4.3386603712286164e-08 -4.366561724098254e-08 -4.199153606880429e-08 -3.5713731673135874e-08 -2.5250724347021848e-08 -2.078650788787986e-08 -1.9251933480049806e-08 -1.911242671570162e-08 -1.855439965830887e-08 -1.7996372600916123e-08 -2.7901352869637404e-08 -2.4413683760932724e-08 -2.4274176996584538e-08 -2.3576643174843603e-08 -2.3995163467888165e-08 -2.385565670353998e-08 -2.4274176996584538e-08 -2.8319873162681962e-08 -2.455319052528091e-08 -3.5992745201832246e-08 -3.961992107488511e-08 -4.213104283315248e-08 -4.3386603712286164e-08 -4.003844136792967e-08 -4.059646842532242e-08 -3.961992107488511e-08 -3.5992745201832246e-08 -2.985444757051202e-08 -2.246058906005811e-08 -1.8972919951353434e-08 -1.7856865836567937e-08 -1.7159332014827002e-08 -1.6322291428737878e-08 -1.6043277900041506e-08 -2.6924805519200093e-08 -2.4274176996584538e-08 -2.455319052528091e-08 -2.385565670353998e-08 -2.3018616117450855e-08 -2.2739602588754482e-08 -2.1205028180924427e-08 -2.0926014652228048e-08 -2.385565670353998e-08 -2.9017406984422894e-08 -3.3342116679216694e-08 -3.613225196618043e-08 -3.710879931661774e-08 -3.557422490878769e-08 -3.4318664029654005e-08 -3.320260991486851e-08 -3.250507609312757e-08 -3.0551981392252956e-08 -2.7901352869637404e-08 -2.6645791990503717e-08 -2.5948258168762783e-08 -2.7203819047896466e-08 -2.5808751404414597e-08 -2.608776493311097e-08 -2.5390231111370035e-08 -2.3018616117450855e-08 -2.3995163467888165e-08 -2.3018616117450855e-08 -2.2600095824406296e-08 -2.14840417096208e-08 -2.050749435918349e-08 -1.953094700874618e-08 -2.0926014652228048e-08 -2.246058906005811e-08 -2.3995163467888165e-08 -2.608776493311097e-08 -2.7622339340941025e-08 -2.8319873162681962e-08 -2.8319873162681962e-08 -2.7622339340941025e-08 -2.706431228354828e-08 -2.608776493311097e-08 -2.4971710818325472e-08 -2.3995163467888165e-08 -2.3576643174843603e-08 -2.287910935310267e-08 -2.218157553136173e-08 -2.315812288179904e-08 -2.3297629646147227e-08 -2.1623548473968986e-08 -2.287910935310267e-08 -2.2321082295709924e-08 -2.2739602588754482e-08 -2.3018616117450855e-08 -2.218157553136173e-08 -2.6227271697459155e-08 -2.3995163467888165e-08 -3.5992745201832246e-08 -3.9759427839233295e-08 -4.1852029304456096e-08 -4.3386603712286164e-08 -4.101498871836698e-08 -4.3526110476634344e-08 -4.394463076967891e-08 -4.129400224706335e-08 -3.487669108704675e-08 -2.4971710818325472e-08 -1.953094700874618e-08 -1.855439965830887e-08 -1.7438345543523375e-08 -1.6601304957434254e-08 -1.6322291428737878e-08 -2.6227271697459155e-08 -2.3576643174843603e-08 -2.413467023223635e-08 -2.3576643174843603e-08 -2.3716149939191793e-08 -2.385565670353998e-08 -2.315812288179904e-08 -2.706431228354828e-08 -2.4971710818325472e-08 -3.724830608096593e-08 -4.115449548271517e-08 -4.3526110476634344e-08 -4.492117812011622e-08 -4.157301577575972e-08 -4.3805124005330716e-08 -4.3805124005330716e-08 -4.227054959750066e-08 -3.613225196618043e-08 -2.6227271697459155e-08 -2.106552141657624e-08 -2.008897406613893e-08 -1.9391440244397992e-08 -1.8693906422657058e-08 -1.82753861296125e-08 -3.0551981392252956e-08 -2.7761846105289214e-08 -2.845937992703015e-08 -2.7622339340941025e-08 -2.8180366398333776e-08 -2.6785298754851907e-08 -2.552973787571822e-08 -2.9296420513119273e-08 -2.5390231111370035e-08 -3.7806333138358674e-08 -4.157301577575972e-08 -4.366561724098254e-08 -4.520019164881259e-08 -4.1852029304456096e-08 -4.366561724098254e-08 -4.422364429837528e-08 -4.2410056361848854e-08 -3.5713731673135874e-08 -2.552973787571822e-08 -2.0647001123531675e-08 -1.953094700874618e-08 -1.8972919951353434e-08 -1.8414892893960685e-08 -1.7856865836567937e-08 -2.873839345572652e-08 -2.5669244640066407e-08 -2.5808751404414597e-08 -2.4971710818325472e-08 -2.4832204053977286e-08 -2.552973787571822e-08 -2.4413683760932724e-08 -2.7901352869637404e-08 -2.5111217582673662e-08 -3.7806333138358674e-08 -4.1852029304456096e-08 -4.3805124005330716e-08 -4.520019164881259e-08 -4.2549563126197034e-08 -4.4502657827071654e-08 -4.4502657827071654e-08 -4.29680834192416e-08 -3.6690279023573184e-08 -2.608776493311097e-08 -2.1344534945272613e-08 -1.9670453773094368e-08 -1.9251933480049806e-08 -1.855439965830887e-08 -1.757785230787156e-08 -2.7761846105289214e-08 -2.4274176996584538e-08 -2.413467023223635e-08 -2.3437136410495414e-08 -2.385565670353998e-08 -2.3995163467888165e-08 -2.385565670353998e-08 -2.7482832576592838e-08 -2.4274176996584538e-08 -3.5992745201832246e-08 -3.961992107488511e-08 -4.213104283315248e-08 -4.2828576654893406e-08 -3.989893460358149e-08 -4.017794813227786e-08 -3.9340907546188736e-08 -3.557422490878769e-08 -3.013346109920839e-08 -2.315812288179904e-08 -1.953094700874618e-08 -1.8833413187005247e-08 -1.82753861296125e-08 -1.7019825250478813e-08 -1.6043277900041506e-08 -2.706431228354828e-08 -2.4413683760932724e-08 -2.4832204053977286e-08 -2.385565670353998e-08 -2.315812288179904e-08 -2.287910935310267e-08 -2.14840417096208e-08 -2.1205028180924427e-08 -2.3995163467888165e-08 -2.943592727746746e-08 -3.4318664029654005e-08 -3.682978578792137e-08 -3.6690279023573184e-08 -3.5713731673135874e-08 -3.487669108704675e-08 -3.390014373660944e-08 -3.292359638617213e-08 -3.124951521399389e-08 -2.8319873162681962e-08 -2.7203819047896466e-08 -2.650628522615553e-08 -2.6785298754851907e-08 -2.650628522615553e-08 -2.7482832576592838e-08 -2.7203819047896466e-08 -2.4971710818325472e-08 -2.5948258168762783e-08 -2.4971710818325472e-08 -2.46926972896291e-08 -2.2321082295709924e-08 -2.106552141657624e-08 -1.9949467301790744e-08 -2.0228480830487117e-08 -2.3018616117450855e-08 -2.455319052528091e-08 -2.7343325812244652e-08 -2.873839345572652e-08 -2.943592727746746e-08 -2.8319873162681962e-08 -2.7901352869637404e-08 -2.706431228354828e-08 -2.6645791990503717e-08 -2.46926972896291e-08 -2.3995163467888165e-08 -2.3995163467888165e-08 -2.315812288179904e-08 -2.3297629646147227e-08 -2.4413683760932724e-08 -2.413467023223635e-08 -2.2600095824406296e-08 -2.3576643174843603e-08 -2.3297629646147227e-08 -2.3018616117450855e-08 -2.315812288179904e-08 -2.2600095824406296e-08 -2.608776493311097e-08 -2.3437136410495414e-08 -3.5016197851394936e-08 -3.8782880488795985e-08 -4.115449548271517e-08 -4.2689069890545226e-08 -4.017794813227786e-08 -4.2549563126197034e-08 -4.2828576654893406e-08 -4.101498871836698e-08 -3.487669108704675e-08 -2.455319052528091e-08 -1.9391440244397992e-08 -1.7856865836567937e-08 -1.674081172178244e-08 -1.590377113569332e-08 -1.5485250842648757e-08 -2.5808751404414597e-08 -2.3297629646147227e-08 -2.3995163467888165e-08 -2.287910935310267e-08 -2.287910935310267e-08 -2.3297629646147227e-08 -2.3018616117450855e-08 -2.650628522615553e-08 -2.3995163467888165e-08 -3.5713731673135874e-08 -3.906189401749236e-08 -4.1433509011411543e-08 -4.310759018358978e-08 -4.031745489662604e-08 -4.2689069890545226e-08 -4.29680834192416e-08 -4.1433509011411543e-08 -3.5295211380091315e-08 -2.4971710818325472e-08 -2.008897406613893e-08 -1.8693906422657058e-08 -1.8414892893960685e-08 -1.771735907221975e-08 -1.7438345543523375e-08 -2.943592727746746e-08 -2.6924805519200093e-08 -2.7482832576592838e-08 -2.650628522615553e-08 -2.6227271697459155e-08 -2.5808751404414597e-08 -2.5111217582673662e-08 -2.8598886691378335e-08 -2.4413683760932724e-08 -3.6550772259225e-08 -4.017794813227786e-08 -4.227054959750066e-08 -4.3526110476634344e-08 -4.045696166097423e-08 -4.227054959750066e-08 -4.310759018358978e-08 -4.157301577575972e-08 -3.54347181444395e-08 -2.552973787571822e-08 -2.0367987594835303e-08 -1.911242671570162e-08 -1.8414892893960685e-08 -1.771735907221975e-08 -1.6461798193086064e-08 -2.6924805519200093e-08 -2.413467023223635e-08 -2.413467023223635e-08 -2.3297629646147227e-08 -2.3995163467888165e-08 -2.413467023223635e-08 -2.413467023223635e-08 -2.7761846105289214e-08 -2.4413683760932724e-08 -3.6550772259225e-08 -4.017794813227786e-08 -4.2410056361848854e-08 -4.366561724098254e-08 -4.101498871836698e-08 -4.2689069890545226e-08 -4.2549563126197034e-08 -4.115449548271517e-08 -3.515570461574312e-08 -2.552973787571822e-08 -2.106552141657624e-08 -1.953094700874618e-08 -1.9251933480049806e-08 -1.953094700874618e-08 -1.8833413187005247e-08 -3.041247462790477e-08 -2.6645791990503717e-08 -2.6227271697459155e-08 -2.5250724347021848e-08 -2.552973787571822e-08 -2.5948258168762783e-08 -2.5250724347021848e-08 -2.8319873162681962e-08 -2.413467023223635e-08 -3.5295211380091315e-08 -3.850386696009961e-08 -4.031745489662604e-08 -4.101498871836698e-08 -3.850386696009961e-08 -3.8782880488795985e-08 -3.794583990270687e-08 -3.487669108704675e-08 -2.985444757051202e-08 -2.315812288179904e-08 -1.9251933480049806e-08 -1.8693906422657058e-08 -1.7996372600916123e-08 -1.7159332014827002e-08 -1.674081172178244e-08 -2.845937992703015e-08 -2.5111217582673662e-08 -2.4971710818325472e-08 -2.3576643174843603e-08 -2.315812288179904e-08 -2.3018616117450855e-08 -2.218157553136173e-08 -2.1344534945272613e-08 -2.413467023223635e-08 -2.943592727746746e-08 -3.4039650500957626e-08 -3.5992745201832246e-08 -3.585323843748406e-08 -3.487669108704675e-08 -3.4039650500957626e-08 -3.3342116679216694e-08 -3.22260625644312e-08 -3.1668035507038446e-08 -2.8598886691378335e-08 -2.7482832576592838e-08 -2.7622339340941025e-08 -2.6924805519200093e-08 -2.7203819047896466e-08 -2.9156913748771087e-08 -2.8319873162681962e-08 -2.6645791990503717e-08 -2.7203819047896466e-08 -2.6227271697459155e-08 -2.5808751404414597e-08 -2.3995163467888165e-08 -2.287910935310267e-08 -2.1344534945272613e-08 -2.1902562002665358e-08 -2.5808751404414597e-08 -2.6645791990503717e-08 -2.9156913748771087e-08 -3.013346109920839e-08 -3.013346109920839e-08 -2.845937992703015e-08 -2.7901352869637404e-08 -2.804085963398559e-08 -2.7482832576592838e-08 -2.5669244640066407e-08 -2.5111217582673662e-08 -2.552973787571822e-08 -2.46926972896291e-08 -2.46926972896291e-08 -2.608776493311097e-08 -2.5390231111370035e-08 -2.3576643174843603e-08 -2.4274176996584538e-08 -2.3995163467888165e-08 -2.3297629646147227e-08 -2.315812288179904e-08 -2.3297629646147227e-08 -2.5808751404414597e-08 -2.246058906005811e-08 -3.3342116679216694e-08 -3.696929255226956e-08 -3.920140078184055e-08 -4.0735975189670606e-08 -3.8782880488795985e-08 -4.031745489662604e-08 -4.045696166097423e-08 -3.906189401749236e-08 -3.348162344356488e-08 -2.385565670353998e-08 -1.9391440244397992e-08 -1.7856865836567937e-08 -1.7019825250478813e-08 -1.6322291428737878e-08 -1.576426437134513e-08 -2.6924805519200093e-08 -2.455319052528091e-08 -2.5111217582673662e-08 -2.413467023223635e-08 -2.413467023223635e-08 -2.46926972896291e-08 -2.455319052528091e-08 -2.706431228354828e-08 -2.385565670353998e-08 -3.417915726530581e-08 -3.7387812845314116e-08 -3.948041431053692e-08 -4.087548195401879e-08 -3.892238725314418e-08 -4.045696166097423e-08 -4.059646842532242e-08 -3.9340907546188736e-08 -3.376063697226125e-08 -2.385565670353998e-08 -1.9670453773094368e-08 -1.7996372600916123e-08 -1.757785230787156e-08 -1.771735907221975e-08 -1.6880318486130626e-08 -2.804085963398559e-08 -2.5669244640066407e-08 -2.6227271697459155e-08 -2.5948258168762783e-08 -2.5250724347021848e-08 -2.5390231111370035e-08 -2.5390231111370035e-08 -2.8180366398333776e-08 -2.3576643174843603e-08 -3.445817079400219e-08 -3.7806333138358674e-08 -3.9759427839233295e-08 -4.087548195401879e-08 -3.8364360195751426e-08 -3.989893460358149e-08 -3.989893460358149e-08 -3.850386696009961e-08 -3.348162344356488e-08 -2.46926972896291e-08 -1.9670453773094368e-08 -1.8414892893960685e-08 -1.7996372600916123e-08 -1.771735907221975e-08 -1.6322291428737878e-08 -2.650628522615553e-08 -2.3995163467888165e-08 -2.4274176996584538e-08 -2.3716149939191793e-08 -2.385565670353998e-08 -2.413467023223635e-08 -2.413467023223635e-08 -2.7482832576592838e-08 -2.3018616117450855e-08 -3.348162344356488e-08 -3.6411265494876805e-08 -3.850386696009961e-08 -3.948041431053692e-08 -3.7666826374010495e-08 -3.892238725314418e-08 -3.906189401749236e-08 -3.7387812845314116e-08 -3.208655580008301e-08 -2.3995163467888165e-08 -2.008897406613893e-08 -1.8833413187005247e-08 -1.7996372600916123e-08 -1.8414892893960685e-08 -1.8414892893960685e-08 -2.985444757051202e-08 -2.706431228354828e-08 -2.6645791990503717e-08 -2.5808751404414597e-08 -2.5669244640066407e-08 -2.608776493311097e-08 -2.5669244640066407e-08 -2.7761846105289214e-08 -2.2739602588754482e-08 -3.22260625644312e-08 -3.557422490878769e-08 -3.710879931661774e-08 -3.7806333138358674e-08 -3.5713731673135874e-08 -3.585323843748406e-08 -3.5295211380091315e-08 -3.208655580008301e-08 -2.7761846105289214e-08 -2.1902562002665358e-08 -1.813587936526431e-08 -1.674081172178244e-08 -1.6182784664389692e-08 -1.590377113569332e-08 -1.6043277900041506e-08 -2.7343325812244652e-08 -2.4413683760932724e-08 -2.4413683760932724e-08 -2.3576643174843603e-08 -2.287910935310267e-08 -2.2600095824406296e-08 -2.218157553136173e-08 -2.1205028180924427e-08 -2.2600095824406296e-08 -2.7203819047896466e-08 -3.0970501685297515e-08 -3.3063103150520315e-08 -3.376063697226125e-08 -3.362113020791307e-08 -3.2644582857475756e-08 -3.208655580008301e-08 -3.1389021978342073e-08 -3.069148815660114e-08 -2.845937992703015e-08 -2.6924805519200093e-08 -2.7203819047896466e-08 -2.6227271697459155e-08 -2.6645791990503717e-08 -2.7901352869637404e-08 -2.8180366398333776e-08 -2.7343325812244652e-08 -2.8598886691378335e-08 -2.8598886691378335e-08 -2.8319873162681962e-08 -2.7622339340941025e-08 -2.6366778461807345e-08 -2.46926972896291e-08 -2.4832204053977286e-08 -2.706431228354828e-08 -2.804085963398559e-08 -2.9156913748771087e-08 -2.985444757051202e-08 -2.9993954334860204e-08 -2.943592727746746e-08 -2.804085963398559e-08 -2.8598886691378335e-08 -2.8598886691378335e-08 -2.7622339340941025e-08 -2.7622339340941025e-08 -2.7622339340941025e-08 -2.6785298754851907e-08 -2.608776493311097e-08 -2.706431228354828e-08 -2.6366778461807345e-08 -2.4274176996584538e-08 -2.46926972896291e-08 -2.3716149939191793e-08 -2.3437136410495414e-08 -2.3297629646147227e-08 -2.385565670353998e-08 -2.5390231111370035e-08 -2.0926014652228048e-08 -3.041247462790477e-08 -3.390014373660944e-08 -3.5016197851394936e-08 -3.6411265494876805e-08 -3.515570461574312e-08 -3.627175873052862e-08 -3.613225196618043e-08 -3.515570461574312e-08 -3.069148815660114e-08 -2.287910935310267e-08 -1.8972919951353434e-08 -1.7996372600916123e-08 -1.729883877917519e-08 -1.674081172178244e-08 -1.6182784664389692e-08 -2.7622339340941025e-08 -2.5250724347021848e-08 -2.5250724347021848e-08 -2.46926972896291e-08 -2.5111217582673662e-08 -2.552973787571822e-08 -2.5669244640066407e-08 -2.7343325812244652e-08 -2.2739602588754482e-08 -3.208655580008301e-08 -3.5295211380091315e-08 -3.696929255226956e-08 -3.794583990270687e-08 -3.6411265494876805e-08 -3.710879931661774e-08 -3.696929255226956e-08 -3.5713731673135874e-08 -3.1389021978342073e-08 -2.3297629646147227e-08 -1.9391440244397992e-08 -1.813587936526431e-08 -1.7856865836567937e-08 -1.813587936526431e-08 -1.6880318486130626e-08 -2.7901352869637404e-08 -2.5250724347021848e-08 -2.5808751404414597e-08 -2.5250724347021848e-08 -2.5111217582673662e-08 -2.552973787571822e-08 -2.5948258168762783e-08 -2.7622339340941025e-08 -2.2042068767013544e-08 -3.124951521399389e-08 -3.445817079400219e-08 -3.585323843748406e-08 -3.696929255226956e-08 -3.515570461574312e-08 -3.585323843748406e-08 -3.5295211380091315e-08 -3.4039650500957626e-08 -3.013346109920839e-08 -2.246058906005811e-08 -1.82753861296125e-08 -1.7438345543523375e-08 -1.674081172178244e-08 -1.7159332014827002e-08 -1.6043277900041506e-08 -2.6924805519200093e-08 -2.413467023223635e-08 -2.4274176996584538e-08 -2.385565670353998e-08 -2.3576643174843603e-08 -2.3995163467888165e-08 -2.3995163467888165e-08 -2.5808751404414597e-08 -2.078650788787986e-08 -2.9714940806163832e-08 -3.3063103150520315e-08 -3.5016197851394936e-08 -3.585323843748406e-08 -3.487669108704675e-08 -3.613225196618043e-08 -3.5713731673135874e-08 -3.4318664029654005e-08 -2.9993954334860204e-08 -2.2600095824406296e-08 -1.8693906422657058e-08 -1.729883877917519e-08 -1.6322291428737878e-08 -1.674081172178244e-08 -1.6461798193086064e-08 -2.6785298754851907e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.385565670353998e-08 -2.3995163467888165e-08 -2.413467023223635e-08 -2.385565670353998e-08 -2.5250724347021848e-08 -2.008897406613893e-08 -2.845937992703015e-08 -3.250507609312757e-08 -3.417915726530581e-08 -3.4737184322698563e-08 -3.348162344356488e-08 -3.376063697226125e-08 -3.3342116679216694e-08 -3.0551981392252956e-08 -2.6924805519200093e-08 -2.2042068767013544e-08 -1.813587936526431e-08 -1.6880318486130626e-08 -1.6182784664389692e-08 -1.6043277900041506e-08 -1.5485250842648757e-08 -2.6645791990503717e-08 -2.455319052528091e-08 -2.455319052528091e-08 -2.3716149939191793e-08 -2.287910935310267e-08 -2.287910935310267e-08 -2.287910935310267e-08 -2.1763055238317172e-08 -2.246058906005811e-08 -2.7203819047896466e-08 -3.027296786355658e-08 -3.180754227138664e-08 -3.3063103150520315e-08 -3.362113020791307e-08 -3.390014373660944e-08 -3.2644582857475756e-08 -3.22260625644312e-08 -3.083099492094933e-08 -2.8877900220074708e-08 -2.650628522615553e-08 -2.5390231111370035e-08 -2.455319052528091e-08 -2.5669244640066407e-08 -2.6924805519200093e-08 -2.7482832576592838e-08 -2.6366778461807345e-08 -2.7203819047896466e-08 -2.7203819047896466e-08 -2.7203819047896466e-08 -2.6366778461807345e-08 -2.5390231111370035e-08 -2.3716149939191793e-08 -2.3437136410495414e-08 -2.4832204053977286e-08 -2.6227271697459155e-08 -2.8180366398333776e-08 -2.943592727746746e-08 -2.9993954334860204e-08 -2.943592727746746e-08 -2.8319873162681962e-08 -2.845937992703015e-08 -2.8319873162681962e-08 -2.7203819047896466e-08 -2.6785298754851907e-08 -2.6645791990503717e-08 -2.6924805519200093e-08 -2.7343325812244652e-08 -2.7482832576592838e-08 -2.7343325812244652e-08 -2.46926972896291e-08 -2.4971710818325472e-08 -2.4274176996584538e-08 -2.3576643174843603e-08 -2.413467023223635e-08 -2.455319052528091e-08 -2.5390231111370035e-08 -1.9251933480049806e-08 -2.7622339340941025e-08 -3.1389021978342073e-08 -3.2644582857475756e-08 -3.362113020791307e-08 -3.22260625644312e-08 -3.320260991486851e-08 -3.3342116679216694e-08 -3.208655580008301e-08 -2.8319873162681962e-08 -2.14840417096208e-08 -1.7856865836567937e-08 -1.7159332014827002e-08 -1.6880318486130626e-08 -1.7019825250478813e-08 -1.6182784664389692e-08 -2.7343325812244652e-08 -2.3995163467888165e-08 -2.3716149939191793e-08 -2.3716149939191793e-08 -2.3995163467888165e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.4971710818325472e-08 -1.9809960537442554e-08 -2.873839345572652e-08 -3.22260625644312e-08 -3.390014373660944e-08 -3.4737184322698563e-08 -3.320260991486851e-08 -3.362113020791307e-08 -3.362113020791307e-08 -3.250507609312757e-08 -2.9017406984422894e-08 -2.2042068767013544e-08 -1.8414892893960685e-08 -1.771735907221975e-08 -1.771735907221975e-08 -1.8693906422657058e-08 -1.7019825250478813e-08 -2.7761846105289214e-08 -2.5111217582673662e-08 -2.5250724347021848e-08 -2.4274176996584538e-08 -2.413467023223635e-08 -2.455319052528091e-08 -2.5250724347021848e-08 -2.5808751404414597e-08 -1.9949467301790744e-08 -2.8319873162681962e-08 -3.1668035507038446e-08 -3.3063103150520315e-08 -3.390014373660944e-08 -3.2644582857475756e-08 -3.320260991486851e-08 -3.3063103150520315e-08 -3.1947049035734825e-08 -2.8180366398333776e-08 -2.14840417096208e-08 -1.82753861296125e-08 -1.7856865836567937e-08 -1.7019825250478813e-08 -1.757785230787156e-08 -1.6601304957434254e-08 -2.7901352869637404e-08 -2.5669244640066407e-08 -2.6645791990503717e-08 -2.5948258168762783e-08 -2.5390231111370035e-08 -2.4971710818325472e-08 -2.5111217582673662e-08 -2.5948258168762783e-08 -1.9391440244397992e-08 -2.7203819047896466e-08 -3.069148815660114e-08 -3.2365569328779384e-08 -3.320260991486851e-08 -3.22260625644312e-08 -3.320260991486851e-08 -3.2644582857475756e-08 -3.152852874269026e-08 -2.804085963398559e-08 -2.1205028180924427e-08 -1.757785230787156e-08 -1.6880318486130626e-08 -1.6182784664389692e-08 -1.7438345543523375e-08 -1.6601304957434254e-08 -2.7343325812244652e-08 -2.4274176996584538e-08 -2.3995163467888165e-08 -2.315812288179904e-08 -2.315812288179904e-08 -2.287910935310267e-08 -2.315812288179904e-08 -2.5390231111370035e-08 -1.8972919951353434e-08 -2.6785298754851907e-08 -3.013346109920839e-08 -3.1389021978342073e-08 -3.208655580008301e-08 -3.11100084496457e-08 -3.1668035507038446e-08 -3.124951521399389e-08 -2.9714940806163832e-08 -2.650628522615553e-08 -2.1763055238317172e-08 -1.8833413187005247e-08 -1.7996372600916123e-08 -1.7438345543523375e-08 -1.6880318486130626e-08 -1.6182784664389692e-08 -2.7343325812244652e-08 -2.413467023223635e-08 -2.3576643174843603e-08 -2.246058906005811e-08 -2.1902562002665358e-08 -2.1902562002665358e-08 -2.246058906005811e-08 -2.078650788787986e-08 -2.1902562002665358e-08 -2.650628522615553e-08 -2.9156913748771087e-08 -3.1668035507038446e-08 -3.2365569328779384e-08 -3.208655580008301e-08 -3.22260625644312e-08 -3.1668035507038446e-08 -3.1947049035734825e-08 -3.069148815660114e-08 -2.9017406984422894e-08 -2.7622339340941025e-08 -2.608776493311097e-08 -2.6227271697459155e-08 -2.7343325812244652e-08 -2.8877900220074708e-08 -2.8598886691378335e-08 -2.552973787571822e-08 -2.5111217582673662e-08 -2.3995163467888165e-08 -2.3576643174843603e-08 -2.315812288179904e-08 -2.3576643174843603e-08 -2.1205028180924427e-08 -2.1344534945272613e-08 -2.3297629646147227e-08 -2.4274176996584538e-08 -2.6227271697459155e-08 -2.7343325812244652e-08 -2.7901352869637404e-08 -2.7343325812244652e-08 -2.6645791990503717e-08 -2.608776493311097e-08 -2.5808751404414597e-08 -2.46926972896291e-08 -2.413467023223635e-08 -2.4274176996584538e-08 -2.4832204053977286e-08 -2.650628522615553e-08 -2.6645791990503717e-08 -2.6785298754851907e-08 -2.413467023223635e-08 -2.4274176996584538e-08 -2.413467023223635e-08 -2.3437136410495414e-08 -2.385565670353998e-08 -2.4274176996584538e-08 -2.5669244640066407e-08 -1.9391440244397992e-08 -2.804085963398559e-08 -3.1947049035734825e-08 -3.362113020791307e-08 -3.445817079400219e-08 -3.292359638617213e-08 -3.4039650500957626e-08 -3.445817079400219e-08 -3.3342116679216694e-08 -2.9017406984422894e-08 -2.1623548473968986e-08 -1.7856865836567937e-08 -1.674081172178244e-08 -1.674081172178244e-08 -1.771735907221975e-08 -1.6043277900041506e-08 -2.6785298754851907e-08 -2.315812288179904e-08 -2.3437136410495414e-08 -2.3297629646147227e-08 -2.3437136410495414e-08 -2.315812288179904e-08 -2.3437136410495414e-08 -2.3437136410495414e-08 -1.8972919951353434e-08 -2.804085963398559e-08 -3.1389021978342073e-08 -3.292359638617213e-08 -3.376063697226125e-08 -3.208655580008301e-08 -3.278408962182394e-08 -3.292359638617213e-08 -3.1947049035734825e-08 -2.8180366398333776e-08 -2.078650788787986e-08 -1.7159332014827002e-08 -1.6322291428737878e-08 -1.6182784664389692e-08 -1.8414892893960685e-08 -1.6182784664389692e-08 -2.608776493311097e-08 -2.287910935310267e-08 -2.2739602588754482e-08 -2.1902562002665358e-08 -2.1623548473968986e-08 -2.2042068767013544e-08 -2.246058906005811e-08 -2.3576643174843603e-08 -1.9251933480049806e-08 -2.804085963398559e-08 -3.152852874269026e-08 -3.3063103150520315e-08 -3.376063697226125e-08 -3.2365569328779384e-08 -3.3342116679216694e-08 -3.348162344356488e-08 -3.250507609312757e-08 -2.8598886691378335e-08 -2.14840417096208e-08 -1.8693906422657058e-08 -1.855439965830887e-08 -1.813587936526431e-08 -1.9391440244397992e-08 -1.757785230787156e-08 -2.8180366398333776e-08 -2.5669244640066407e-08 -2.7343325812244652e-08 -2.6645791990503717e-08 -2.5948258168762783e-08 -2.5948258168762783e-08 -2.5669244640066407e-08 -2.608776493311097e-08 -1.9949467301790744e-08 -2.8598886691378335e-08 -3.180754227138664e-08 -3.3063103150520315e-08 -3.376063697226125e-08 -3.2365569328779384e-08 -3.3063103150520315e-08 -3.3063103150520315e-08 -3.1947049035734825e-08 -2.7901352869637404e-08 -2.0926014652228048e-08 -1.7159332014827002e-08 -1.7019825250478813e-08 -1.6601304957434254e-08 -1.8972919951353434e-08 -1.7159332014827002e-08 -2.7901352869637404e-08 -2.5390231111370035e-08 -2.5250724347021848e-08 -2.413467023223635e-08 -2.3995163467888165e-08 -2.3716149939191793e-08 -2.4413683760932724e-08 -2.6785298754851907e-08 -2.008897406613893e-08 -2.8319873162681962e-08 -3.124951521399389e-08 -3.2365569328779384e-08 -3.3342116679216694e-08 -3.1947049035734825e-08 -3.278408962182394e-08 -3.278408962182394e-08 -3.069148815660114e-08 -2.706431228354828e-08 -2.1763055238317172e-08 -1.8693906422657058e-08 -1.7856865836567937e-08 -1.771735907221975e-08 -1.757785230787156e-08 -1.674081172178244e-08 -2.804085963398559e-08 -2.4832204053977286e-08 -2.5250724347021848e-08 -2.4413683760932724e-08 -2.4274176996584538e-08 -2.3576643174843603e-08 -2.385565670353998e-08 -2.218157553136173e-08 -2.3018616117450855e-08 -2.6924805519200093e-08 -3.041247462790477e-08 -3.3063103150520315e-08 -3.3342116679216694e-08 -3.320260991486851e-08 -3.208655580008301e-08 -3.1668035507038446e-08 -3.11100084496457e-08 -2.9714940806163832e-08 -2.7901352869637404e-08 -2.7343325812244652e-08 -2.608776493311097e-08 -2.6366778461807345e-08 -2.7761846105289214e-08 -2.804085963398559e-08 -2.706431228354828e-08 -2.385565670353998e-08 -2.3716149939191793e-08 -2.287910935310267e-08 -2.246058906005811e-08 -2.218157553136173e-08 -2.3297629646147227e-08 -2.1763055238317172e-08 -2.2042068767013544e-08 -2.3995163467888165e-08 -2.5111217582673662e-08 -2.6366778461807345e-08 -2.7203819047896466e-08 -2.7622339340941025e-08 -2.7622339340941025e-08 -2.6924805519200093e-08 -2.6227271697459155e-08 -2.5948258168762783e-08 -2.4832204053977286e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.4413683760932724e-08 -2.5808751404414597e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.3018616117450855e-08 -2.3297629646147227e-08 -2.3018616117450855e-08 -2.3018616117450855e-08 -2.3297629646147227e-08 -2.4274176996584538e-08 -2.6366778461807345e-08 -2.14840417096208e-08 -3.1389021978342073e-08 -3.5016197851394936e-08 -3.6690279023573184e-08 -3.7666826374010495e-08 -3.627175873052862e-08 -3.8085346667055053e-08 -3.822485343140324e-08 -3.696929255226956e-08 -3.180754227138664e-08 -2.315812288179904e-08 -1.911242671570162e-08 -1.771735907221975e-08 -1.7856865836567937e-08 -1.9949467301790744e-08 -1.757785230787156e-08 -2.7622339340941025e-08 -2.455319052528091e-08 -2.5111217582673662e-08 -2.4413683760932724e-08 -2.4832204053977286e-08 -2.4413683760932724e-08 -2.4832204053977286e-08 -2.6366778461807345e-08 -2.14840417096208e-08 -3.1668035507038446e-08 -3.487669108704675e-08 -3.6690279023573184e-08 -3.794583990270687e-08 -3.5992745201832246e-08 -3.724830608096593e-08 -3.7387812845314116e-08 -3.613225196618043e-08 -3.041247462790477e-08 -2.2042068767013544e-08 -1.7856865836567937e-08 -1.7159332014827002e-08 -1.7856865836567937e-08 -2.0228480830487117e-08 -1.729883877917519e-08 -2.7343325812244652e-08 -2.413467023223635e-08 -2.413467023223635e-08 -2.3297629646147227e-08 -2.315812288179904e-08 -2.287910935310267e-08 -2.3297629646147227e-08 -2.5250724347021848e-08 -2.1205028180924427e-08 -3.0970501685297515e-08 -3.459767755835038e-08 -3.6550772259225e-08 -3.7666826374010495e-08 -3.557422490878769e-08 -3.6690279023573184e-08 -3.6690279023573184e-08 -3.515570461574312e-08 -3.041247462790477e-08 -2.1623548473968986e-08 -1.7996372600916123e-08 -1.7438345543523375e-08 -1.813587936526431e-08 -2.078650788787986e-08 -1.7438345543523375e-08 -2.6924805519200093e-08 -2.3995163467888165e-08 -2.46926972896291e-08 -2.4413683760932724e-08 -2.3995163467888165e-08 -2.4413683760932724e-08 -2.46926972896291e-08 -2.5948258168762783e-08 -2.14840417096208e-08 -3.1947049035734825e-08 -3.54347181444395e-08 -3.682978578792137e-08 -3.7666826374010495e-08 -3.5295211380091315e-08 -3.6690279023573184e-08 -3.682978578792137e-08 -3.557422490878769e-08 -3.027296786355658e-08 -2.1902562002665358e-08 -1.82753861296125e-08 -1.8414892893960685e-08 -1.9391440244397992e-08 -2.218157553136173e-08 -1.855439965830887e-08 -2.8180366398333776e-08 -2.552973787571822e-08 -2.552973787571822e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.413467023223635e-08 -2.46926972896291e-08 -2.7482832576592838e-08 -2.1623548473968986e-08 -3.124951521399389e-08 -3.459767755835038e-08 -3.6411265494876805e-08 -3.724830608096593e-08 -3.54347181444395e-08 -3.627175873052862e-08 -3.585323843748406e-08 -3.3063103150520315e-08 -2.845937992703015e-08 -2.218157553136173e-08 -1.8414892893960685e-08 -1.7159332014827002e-08 -1.729883877917519e-08 -1.855439965830887e-08 -1.7159332014827002e-08 -2.7622339340941025e-08 -2.5111217582673662e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.455319052528091e-08 -2.385565670353998e-08 -2.413467023223635e-08 -2.287910935310267e-08 -2.3716149939191793e-08 -2.7622339340941025e-08 -3.1947049035734825e-08 -3.376063697226125e-08 -3.4737184322698563e-08 -3.4039650500957626e-08 -3.320260991486851e-08 -3.22260625644312e-08 -3.124951521399389e-08 -2.9993954334860204e-08 -2.7622339340941025e-08 -2.7343325812244652e-08 -2.7343325812244652e-08 -2.7622339340941025e-08 -2.873839345572652e-08 -2.7901352869637404e-08 -2.608776493311097e-08 -2.385565670353998e-08 -2.4274176996584538e-08 -2.3576643174843603e-08 -2.3018616117450855e-08 -2.2600095824406296e-08 -2.2600095824406296e-08 -2.1344534945272613e-08 -2.078650788787986e-08 -2.2600095824406296e-08 -2.455319052528091e-08 -2.650628522615553e-08 -2.706431228354828e-08 -2.7761846105289214e-08 -2.7482832576592838e-08 -2.6366778461807345e-08 -2.6227271697459155e-08 -2.6645791990503717e-08 -2.5948258168762783e-08 -2.5808751404414597e-08 -2.6924805519200093e-08 -2.7203819047896466e-08 -2.845937992703015e-08 -2.706431228354828e-08 -2.552973787571822e-08 -2.3716149939191793e-08 -2.413467023223635e-08 -2.3576643174843603e-08 -2.315812288179904e-08 -2.3995163467888165e-08 -2.5111217582673662e-08 -2.7622339340941025e-08 -2.315812288179904e-08 -3.4318664029654005e-08 -3.8364360195751426e-08 -4.031745489662604e-08 -4.129400224706335e-08 -3.906189401749236e-08 -4.115449548271517e-08 -4.1433509011411543e-08 -3.9340907546188736e-08 -3.362113020791307e-08 -2.385565670353998e-08 -2.008897406613893e-08 -1.9391440244397992e-08 -2.0228480830487117e-08 -2.2042068767013544e-08 -1.8833413187005247e-08 -2.9156913748771087e-08 -2.6227271697459155e-08 -2.6645791990503717e-08 -2.5948258168762783e-08 -2.650628522615553e-08 -2.6366778461807345e-08 -2.7203819047896466e-08 -2.985444757051202e-08 -2.4274176996584538e-08 -3.557422490878769e-08 -3.948041431053692e-08 -4.157301577575972e-08 -4.3386603712286164e-08 -4.0735975189670606e-08 -4.2828576654893406e-08 -4.324709694793797e-08 -4.129400224706335e-08 -3.445817079400219e-08 -2.455319052528091e-08 -1.9809960537442554e-08 -1.9251933480049806e-08 -2.1344534945272613e-08 -2.3018616117450855e-08 -1.8693906422657058e-08 -2.8319873162681962e-08 -2.5390231111370035e-08 -2.5111217582673662e-08 -2.385565670353998e-08 -2.3576643174843603e-08 -2.3437136410495414e-08 -2.385565670353998e-08 -2.706431228354828e-08 -2.315812288179904e-08 -3.4318664029654005e-08 -3.7806333138358674e-08 -4.017794813227786e-08 -4.1712522540107916e-08 -3.892238725314418e-08 -4.059646842532242e-08 -4.059646842532242e-08 -3.906189401749236e-08 -3.3063103150520315e-08 -2.3018616117450855e-08 -1.8833413187005247e-08 -1.7856865836567937e-08 -2.0228480830487117e-08 -2.246058906005811e-08 -1.7996372600916123e-08 -2.7482832576592838e-08 -2.4413683760932724e-08 -2.455319052528091e-08 -2.385565670353998e-08 -2.3576643174843603e-08 -2.3297629646147227e-08 -2.4413683760932724e-08 -2.7343325812244652e-08 -2.3576643174843603e-08 -3.459767755835038e-08 -3.8364360195751426e-08 -4.059646842532242e-08 -4.213104283315248e-08 -3.906189401749236e-08 -4.0735975189670606e-08 -4.115449548271517e-08 -3.9759427839233295e-08 -3.390014373660944e-08 -2.4274176996584538e-08 -1.9949467301790744e-08 -1.9670453773094368e-08 -2.2321082295709924e-08 -2.4971710818325472e-08 -2.008897406613893e-08 -3.027296786355658e-08 -2.650628522615553e-08 -2.6227271697459155e-08 -2.4832204053977286e-08 -2.4413683760932724e-08 -2.46926972896291e-08 -2.5948258168762783e-08 -2.943592727746746e-08 -2.385565670353998e-08 -3.445817079400219e-08 -3.8085346667055053e-08 -4.031745489662604e-08 -4.101498871836698e-08 -3.850386696009961e-08 -3.948041431053692e-08 -3.892238725314418e-08 -3.613225196618043e-08 -3.041247462790477e-08 -2.315812288179904e-08 -1.953094700874618e-08 -1.855439965830887e-08 -1.9391440244397992e-08 -2.0228480830487117e-08 -1.771735907221975e-08 -2.7482832576592838e-08 -2.4413683760932724e-08 -2.3995163467888165e-08 -2.287910935310267e-08 -2.2321082295709924e-08 -2.218157553136173e-08 -2.2600095824406296e-08 -2.1763055238317172e-08 -2.3018616117450855e-08 -2.7482832576592838e-08 -3.1947049035734825e-08 -3.445817079400219e-08 -3.5713731673135874e-08 -3.417915726530581e-08 -3.348162344356488e-08 -3.3063103150520315e-08 -3.1668035507038446e-08 -3.027296786355658e-08 -2.804085963398559e-08 -2.7622339340941025e-08 -2.7761846105289214e-08 -2.8877900220074708e-08 -2.9296420513119273e-08 -2.8319873162681962e-08 -2.6227271697459155e-08 -2.4413683760932724e-08 -2.4832204053977286e-08 -2.413467023223635e-08 -2.3437136410495414e-08 -2.3018616117450855e-08 -2.2739602588754482e-08 -2.14840417096208e-08 -2.0228480830487117e-08 -2.1623548473968986e-08 -2.3576643174843603e-08 -2.5948258168762783e-08 -2.6366778461807345e-08 -2.7622339340941025e-08 -2.7203819047896466e-08 -2.6645791990503717e-08 -2.6645791990503717e-08 -2.7343325812244652e-08 -2.6785298754851907e-08 -2.6785298754851907e-08 -2.7761846105289214e-08 -2.8598886691378335e-08 -2.985444757051202e-08 -2.8319873162681962e-08 -2.6227271697459155e-08 -2.46926972896291e-08 -2.5250724347021848e-08 -2.46926972896291e-08 -2.413467023223635e-08 -2.46926972896291e-08 -2.5948258168762783e-08 -2.9017406984422894e-08 -2.413467023223635e-08 -3.5713731673135874e-08 -3.948041431053692e-08 -4.1433509011411543e-08 -4.2549563126197034e-08 -3.961992107488511e-08 -4.157301577575972e-08 -4.1852029304456096e-08 -3.989893460358149e-08 -3.3342116679216694e-08 -2.315812288179904e-08 -1.9251933480049806e-08 -1.8972919951353434e-08 -2.1205028180924427e-08 -2.1763055238317172e-08 -1.7856865836567937e-08 -2.7343325812244652e-08 -2.455319052528091e-08 -2.4971710818325472e-08 -2.4413683760932724e-08 -2.4971710818325472e-08 -2.4971710818325472e-08 -2.650628522615553e-08 -2.985444757051202e-08 -2.4971710818325472e-08 -3.682978578792137e-08 -4.0735975189670606e-08 -4.2828576654893406e-08 -4.478167135576803e-08 -4.1712522540107916e-08 -4.3805124005330716e-08 -4.464216459141985e-08 -4.227054959750066e-08 -3.515570461574312e-08 -2.455319052528091e-08 -1.9670453773094368e-08 -1.8833413187005247e-08 -2.2739602588754482e-08 -2.4413683760932724e-08 -1.9391440244397992e-08 -2.8877900220074708e-08 -2.4971710818325472e-08 -2.46926972896291e-08 -2.3576643174843603e-08 -2.3297629646147227e-08 -2.3437136410495414e-08 -2.455319052528091e-08 -2.873839345572652e-08 -2.4832204053977286e-08 -3.627175873052862e-08 -3.9759427839233295e-08 -4.2410056361848854e-08 -4.3805124005330716e-08 -4.059646842532242e-08 -4.2410056361848854e-08 -4.2689069890545226e-08 -4.101498871836698e-08 -3.4318664029654005e-08 -2.385565670353998e-08 -1.953094700874618e-08 -1.8693906422657058e-08 -2.2739602588754482e-08 -2.3716149939191793e-08 -1.8833413187005247e-08 -2.845937992703015e-08 -2.5669244640066407e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.4413683760932724e-08 -2.413467023223635e-08 -2.5390231111370035e-08 -2.9156913748771087e-08 -2.5111217582673662e-08 -3.6550772259225e-08 -4.003844136792967e-08 -4.227054959750066e-08 -4.3805124005330716e-08 -4.087548195401879e-08 -4.2410056361848854e-08 -4.29680834192416e-08 -4.157301577575972e-08 -3.557422490878769e-08 -2.5111217582673662e-08 -2.050749435918349e-08 -2.008897406613893e-08 -2.3995163467888165e-08 -2.5250724347021848e-08 -2.008897406613893e-08 -3.027296786355658e-08 -2.6924805519200093e-08 -2.6924805519200093e-08 -2.5390231111370035e-08 -2.4832204053977286e-08 -2.5808751404414597e-08 -2.7203819047896466e-08 -3.083099492094933e-08 -2.5390231111370035e-08 -3.6411265494876805e-08 -3.989893460358149e-08 -4.213104283315248e-08 -4.29680834192416e-08 -4.003844136792967e-08 -4.115449548271517e-08 -4.0735975189670606e-08 -3.7806333138358674e-08 -3.1389021978342073e-08 -2.3576643174843603e-08 -1.9809960537442554e-08 -1.8972919951353434e-08 -2.14840417096208e-08 -2.1205028180924427e-08 -1.82753861296125e-08 -2.845937992703015e-08 -2.5250724347021848e-08 -2.5250724347021848e-08 -2.385565670353998e-08 -2.3576643174843603e-08 -2.3716149939191793e-08 -2.413467023223635e-08 -2.3716149939191793e-08 -2.455319052528091e-08 -2.9993954334860204e-08 -3.5016197851394936e-08 -3.724830608096593e-08 -3.822485343140324e-08 -3.682978578792137e-08 -3.5713731673135874e-08 -3.487669108704675e-08 -3.278408962182394e-08 -3.11100084496457e-08 -2.845937992703015e-08 -2.706431228354828e-08 -2.650628522615553e-08 -2.7901352869637404e-08 -2.7622339340941025e-08 -2.6227271697459155e-08 -2.46926972896291e-08 -2.2600095824406296e-08 -2.3297629646147227e-08 -2.2600095824406296e-08 -2.315812288179904e-08 -2.246058906005811e-08 -2.3018616117450855e-08 -2.246058906005811e-08 -2.1623548473968986e-08 -2.2739602588754482e-08 -2.455319052528091e-08 -2.6645791990503717e-08 -2.7203819047896466e-08 -2.804085963398559e-08 -2.845937992703015e-08 -2.7761846105289214e-08 -2.7761846105289214e-08 -2.7343325812244652e-08 -2.6785298754851907e-08 -2.608776493311097e-08 -2.5808751404414597e-08 -2.8180366398333776e-08 -2.8598886691378335e-08 -2.6924805519200093e-08 -2.5111217582673662e-08 -2.4413683760932724e-08 -2.5111217582673662e-08 -2.455319052528091e-08 -2.455319052528091e-08 -2.4274176996584538e-08 -2.552973787571822e-08 -2.943592727746746e-08 -2.455319052528091e-08 -3.613225196618043e-08 -3.920140078184055e-08 -4.101498871836698e-08 -4.2549563126197034e-08 -3.961992107488511e-08 -4.1852029304456096e-08 -4.1852029304456096e-08 -4.031745489662604e-08 -3.348162344356488e-08 -2.3297629646147227e-08 -1.9251933480049806e-08 -1.9251933480049806e-08 -2.3018616117450855e-08 -2.246058906005811e-08 -1.813587936526431e-08 -2.7761846105289214e-08 -2.4971710818325472e-08 -2.5111217582673662e-08 -2.4274176996584538e-08 -2.46926972896291e-08 -2.4832204053977286e-08 -2.5669244640066407e-08 -2.985444757051202e-08 -2.5669244640066407e-08 -3.724830608096593e-08 -4.0735975189670606e-08 -4.2549563126197034e-08 -4.394463076967891e-08 -4.0735975189670606e-08 -4.2828576654893406e-08 -4.3386603712286164e-08 -4.1433509011411543e-08 -3.4318664029654005e-08 -2.3995163467888165e-08 -1.9670453773094368e-08 -2.008897406613893e-08 -2.455319052528091e-08 -2.455319052528091e-08 -2.008897406613893e-08 -3.0970501685297515e-08 -2.7761846105289214e-08 -2.7901352869637404e-08 -2.7343325812244652e-08 -2.7622339340941025e-08 -2.6924805519200093e-08 -2.8180366398333776e-08 -3.320260991486851e-08 -2.7343325812244652e-08 -3.8782880488795985e-08 -4.1852029304456096e-08 -4.3805124005330716e-08 -4.492117812011622e-08 -4.157301577575972e-08 -4.310759018358978e-08 -4.3386603712286164e-08 -4.157301577575972e-08 -3.487669108704675e-08 -2.4413683760932724e-08 -1.9809960537442554e-08 -1.9809960537442554e-08 -2.4832204053977286e-08 -2.4274176996584538e-08 -1.911242671570162e-08 -2.8877900220074708e-08 -2.6366778461807345e-08 -2.650628522615553e-08 -2.6366778461807345e-08 -2.6227271697459155e-08 -2.6924805519200093e-08 -2.8180366398333776e-08 -3.2644582857475756e-08 -2.6785298754851907e-08 -3.86433737244478e-08 -4.1852029304456096e-08 -4.3386603712286164e-08 -4.464216459141985e-08 -4.199153606880429e-08 -4.366561724098254e-08 -4.366561724098254e-08 -4.1712522540107916e-08 -3.54347181444395e-08 -2.4832204053977286e-08 -2.0647001123531675e-08 -2.078650788787986e-08 -2.608776493311097e-08 -2.5390231111370035e-08 -1.9949467301790744e-08 -2.9156913748771087e-08 -2.5808751404414597e-08 -2.608776493311097e-08 -2.455319052528091e-08 -2.455319052528091e-08 -2.4832204053977286e-08 -2.5948258168762783e-08 -3.041247462790477e-08 -2.5250724347021848e-08 -3.613225196618043e-08 -3.948041431053692e-08 -4.115449548271517e-08 -4.199153606880429e-08 -3.906189401749236e-08 -4.003844136792967e-08 -3.948041431053692e-08 -3.627175873052862e-08 -2.9993954334860204e-08 -2.287910935310267e-08 -1.9251933480049806e-08 -1.9251933480049806e-08 -2.2321082295709924e-08 -2.1344534945272613e-08 -1.813587936526431e-08 -2.8877900220074708e-08 -2.5669244640066407e-08 -2.5808751404414597e-08 -2.4413683760932724e-08 -2.385565670353998e-08 -2.385565670353998e-08 -2.413467023223635e-08 -2.4274176996584538e-08 -2.5948258168762783e-08 -3.1947049035734825e-08 -3.75273196096623e-08 -3.989893460358149e-08 -4.059646842532242e-08 -3.892238725314418e-08 -3.7806333138358674e-08 -3.6411265494876805e-08 -3.5295211380091315e-08 -3.320260991486851e-08 -3.083099492094933e-08 -2.8877900220074708e-08 -2.873839345572652e-08 -3.069148815660114e-08 -3.027296786355658e-08 -2.873839345572652e-08 -2.6785298754851907e-08 -2.46926972896291e-08 -2.4971710818325472e-08 -2.3995163467888165e-08 -2.4971710818325472e-08 -2.3995163467888165e-08 -2.455319052528091e-08 -2.4274176996584538e-08 -2.287910935310267e-08 -2.3576643174843603e-08 -2.6227271697459155e-08 -2.7901352869637404e-08 -2.845937992703015e-08 -2.9296420513119273e-08 -2.943592727746746e-08 -2.9017406984422894e-08 -2.7761846105289214e-08 -2.706431228354828e-08 -2.6645791990503717e-08 -2.608776493311097e-08 -2.552973787571822e-08 -2.804085963398559e-08 -2.7761846105289214e-08 -2.608776493311097e-08 -2.4832204053977286e-08 -2.3716149939191793e-08 -2.455319052528091e-08 -2.3995163467888165e-08 -2.385565670353998e-08 -2.3716149939191793e-08 -2.4971710818325472e-08 -2.943592727746746e-08 -2.5111217582673662e-08 -3.682978578792137e-08 -3.989893460358149e-08 -4.199153606880429e-08 -4.3386603712286164e-08 -4.017794813227786e-08 -4.213104283315248e-08 -4.199153606880429e-08 -4.017794813227786e-08 -3.3342116679216694e-08 -2.315812288179904e-08 -1.9251933480049806e-08 -2.008897406613893e-08 -2.4971710818325472e-08 -2.3018616117450855e-08 -1.7996372600916123e-08 -2.7761846105289214e-08 -2.5111217582673662e-08 -2.5250724347021848e-08 -2.4274176996584538e-08 -2.4274176996584538e-08 -2.455319052528091e-08 -2.5390231111370035e-08 -2.9993954334860204e-08 -2.5948258168762783e-08 -3.7387812845314116e-08 -4.0735975189670606e-08 -4.227054959750066e-08 -4.3386603712286164e-08 -4.031745489662604e-08 -4.2410056361848854e-08 -4.29680834192416e-08 -4.0735975189670606e-08 -3.390014373660944e-08 -2.3437136410495414e-08 -1.9670453773094368e-08 -2.1205028180924427e-08 -2.5250724347021848e-08 -2.3297629646147227e-08 -1.8693906422657058e-08 -2.9575434041815645e-08 -2.7761846105289214e-08 -2.8180366398333776e-08 -2.7622339340941025e-08 -2.7482832576592838e-08 -2.706431228354828e-08 -2.7482832576592838e-08 -3.3342116679216694e-08 -2.7622339340941025e-08 -3.9340907546188736e-08 -4.1712522540107916e-08 -4.310759018358978e-08 -4.408413753402709e-08 -4.0735975189670606e-08 -4.2410056361848854e-08 -4.2549563126197034e-08 -4.087548195401879e-08 -3.417915726530581e-08 -2.3995163467888165e-08 -1.953094700874618e-08 -2.078650788787986e-08 -2.5808751404414597e-08 -2.3576643174843603e-08 -1.82753861296125e-08 -2.7761846105289214e-08 -2.5250724347021848e-08 -2.650628522615553e-08 -2.6366778461807345e-08 -2.6785298754851907e-08 -2.7482832576592838e-08 -2.8319873162681962e-08 -3.348162344356488e-08 -2.7622339340941025e-08 -3.906189401749236e-08 -4.2549563126197034e-08 -4.3805124005330716e-08 -4.492117812011622e-08 -4.199153606880429e-08 -4.408413753402709e-08 -4.366561724098254e-08 -4.157301577575972e-08 -3.5016197851394936e-08 -2.5250724347021848e-08 -2.078650788787986e-08 -2.1623548473968986e-08 -2.6924805519200093e-08 -2.4971710818325472e-08 -1.9251933480049806e-08 -2.8180366398333776e-08 -2.455319052528091e-08 -2.4971710818325472e-08 -2.3576643174843603e-08 -2.3716149939191793e-08 -2.3716149939191793e-08 -2.46926972896291e-08 -2.985444757051202e-08 -2.5390231111370035e-08 -3.6411265494876805e-08 -3.948041431053692e-08 -4.101498871836698e-08 -4.199153606880429e-08 -3.850386696009961e-08 -3.961992107488511e-08 -3.8782880488795985e-08 -3.54347181444395e-08 -2.9156913748771087e-08 -2.218157553136173e-08 -1.8693906422657058e-08 -1.9809960537442554e-08 -2.2739602588754482e-08 -2.0926014652228048e-08 -1.771735907221975e-08 -2.804085963398559e-08 -2.4971710818325472e-08 -2.4832204053977286e-08 -2.3437136410495414e-08 -2.3018616117450855e-08 -2.3018616117450855e-08 -2.3297629646147227e-08 -2.3576643174843603e-08 -2.552973787571822e-08 -3.124951521399389e-08 -3.54347181444395e-08 -3.8364360195751426e-08 -3.948041431053692e-08 -3.794583990270687e-08 -3.6550772259225e-08 -3.54347181444395e-08 -3.487669108704675e-08 -3.2644582857475756e-08 -3.041247462790477e-08 -2.9017406984422894e-08 -2.9017406984422894e-08 -3.11100084496457e-08 -3.013346109920839e-08 -2.8598886691378335e-08 -2.6785298754851907e-08 -2.4971710818325472e-08 -2.5250724347021848e-08 -2.455319052528091e-08 -2.46926972896291e-08 -2.413467023223635e-08 -2.4274176996584538e-08 -2.385565670353998e-08 -2.218157553136173e-08 -2.2321082295709924e-08 -2.4832204053977286e-08 -2.650628522615553e-08 -2.7343325812244652e-08 -2.8319873162681962e-08 -2.8319873162681962e-08 -2.8180366398333776e-08 -2.6924805519200093e-08 -2.6227271697459155e-08 -2.5808751404414597e-08 -2.552973787571822e-08 -2.5111217582673662e-08 -2.650628522615553e-08 -2.608776493311097e-08 -2.455319052528091e-08 -2.3437136410495414e-08 -2.1902562002665358e-08 -2.287910935310267e-08 -2.246058906005811e-08 -2.2321082295709924e-08 -2.2321082295709924e-08 -2.3716149939191793e-08 -2.8598886691378335e-08 -2.5250724347021848e-08 -3.710879931661774e-08 -4.017794813227786e-08 -4.199153606880429e-08 -4.29680834192416e-08 -3.9759427839233295e-08 -4.1712522540107916e-08 -4.1852029304456096e-08 -3.989893460358149e-08 -3.278408962182394e-08 -2.2600095824406296e-08 -1.855439965830887e-08 -2.0367987594835303e-08 -2.5111217582673662e-08 -2.2042068767013544e-08 -1.674081172178244e-08 -2.5250724347021848e-08 -2.2600095824406296e-08 -2.3018616117450855e-08 -2.246058906005811e-08 -2.2600095824406296e-08 -2.3297629646147227e-08 -2.4413683760932724e-08 -2.9575434041815645e-08 -2.6227271697459155e-08 -3.7666826374010495e-08 -4.101498871836698e-08 -4.2410056361848854e-08 -4.366561724098254e-08 -4.045696166097423e-08 -4.227054959750066e-08 -4.2549563126197034e-08 -4.059646842532242e-08 -3.348162344356488e-08 -2.315812288179904e-08 -1.9391440244397992e-08 -2.14840417096208e-08 -2.5808751404414597e-08 -2.3018616117450855e-08 -1.7856865836567937e-08 -2.6645791990503717e-08 -2.46926972896291e-08 -2.4413683760932724e-08 -2.3716149939191793e-08 -2.3716149939191793e-08 -2.385565670353998e-08 -2.455319052528091e-08 -2.9993954334860204e-08 -2.6227271697459155e-08 -3.850386696009961e-08 -4.0735975189670606e-08 -4.2410056361848854e-08 -4.3526110476634344e-08 -4.059646842532242e-08 -4.213104283315248e-08 -4.2410056361848854e-08 -4.031745489662604e-08 -3.362113020791307e-08 -2.3437136410495414e-08 -1.953094700874618e-08 -2.218157553136173e-08 -2.6227271697459155e-08 -2.315812288179904e-08 -1.771735907221975e-08 -2.608776493311097e-08 -2.3297629646147227e-08 -2.4274176996584538e-08 -2.3716149939191793e-08 -2.385565670353998e-08 -2.3995163467888165e-08 -2.5250724347021848e-08 -3.041247462790477e-08 -2.6227271697459155e-08 -3.7666826374010495e-08 -4.115449548271517e-08 -4.2549563126197034e-08 -4.3805124005330716e-08 -4.115449548271517e-08 -4.310759018358978e-08 -4.310759018358978e-08 -4.129400224706335e-08 -3.445817079400219e-08 -2.46926972896291e-08 -2.050749435918349e-08 -2.315812288179904e-08 -2.706431228354828e-08 -2.4413683760932724e-08 -1.855439965830887e-08 -2.7482832576592838e-08 -2.385565670353998e-08 -2.413467023223635e-08 -2.287910935310267e-08 -2.287910935310267e-08 -2.3018616117450855e-08 -2.4274176996584538e-08 -2.9575434041815645e-08 -2.5808751404414597e-08 -3.6690279023573184e-08 -3.9759427839233295e-08 -4.1433509011411543e-08 -4.2410056361848854e-08 -3.8782880488795985e-08 -4.003844136792967e-08 -3.892238725314418e-08 -3.5713731673135874e-08 -2.985444757051202e-08 -2.2739602588754482e-08 -1.911242671570162e-08 -2.0647001123531675e-08 -2.3297629646147227e-08 -2.0647001123531675e-08 -1.7438345543523375e-08 -2.7203819047896466e-08 -2.4274176996584538e-08 -2.46926972896291e-08 -2.3576643174843603e-08 -2.3576643174843603e-08 -2.287910935310267e-08 -2.315812288179904e-08 -2.3576643174843603e-08 -2.5390231111370035e-08 -3.083099492094933e-08 -3.4039650500957626e-08 -3.6690279023573184e-08 -3.794583990270687e-08 -3.627175873052862e-08 -3.5016197851394936e-08 -3.445817079400219e-08 -3.3342116679216694e-08 -3.1947049035734825e-08 -2.9296420513119273e-08 -2.8319873162681962e-08 -2.8877900220074708e-08 -3.0551981392252956e-08 -2.9714940806163832e-08 -2.8877900220074708e-08 -2.7343325812244652e-08 -2.5390231111370035e-08 -2.6366778461807345e-08 -2.5808751404414597e-08 -2.5390231111370035e-08 -2.5250724347021848e-08 -2.5390231111370035e-08 -2.5111217582673662e-08 -2.385565670353998e-08 -2.3297629646147227e-08 -2.4971710818325472e-08 -2.6924805519200093e-08 -2.7901352869637404e-08 -2.8319873162681962e-08 -2.8319873162681962e-08 -2.7761846105289214e-08 -2.7203819047896466e-08 -2.650628522615553e-08 -2.5948258168762783e-08 -2.552973787571822e-08 -2.6227271697459155e-08 -2.7761846105289214e-08 -2.6924805519200093e-08 -2.552973787571822e-08 -2.4274176996584538e-08 -2.2321082295709924e-08 -2.3297629646147227e-08 -2.2739602588754482e-08 -2.3297629646147227e-08 -2.3576643174843603e-08 -2.4971710818325472e-08 -3.013346109920839e-08 -2.6366778461807345e-08 -3.7806333138358674e-08 -4.087548195401879e-08 -4.2549563126197034e-08 -4.366561724098254e-08 -4.045696166097423e-08 -4.2410056361848854e-08 -4.2549563126197034e-08 -4.059646842532242e-08 -3.362113020791307e-08 -2.3437136410495414e-08 -1.9809960537442554e-08 -2.3018616117450855e-08 -2.608776493311097e-08 -2.218157553136173e-08 -1.7159332014827002e-08 -2.5808751404414597e-08 -2.287910935310267e-08 -2.3716149939191793e-08 -2.315812288179904e-08 -2.413467023223635e-08 -2.4971710818325472e-08 -2.5808751404414597e-08 -3.11100084496457e-08 -2.7761846105289214e-08 -3.920140078184055e-08 -4.2549563126197034e-08 -4.394463076967891e-08 -4.520019164881259e-08 -4.1852029304456096e-08 -4.366561724098254e-08 -4.366561724098254e-08 -4.199153606880429e-08 -3.487669108704675e-08 -2.455319052528091e-08 -2.050749435918349e-08 -2.3995163467888165e-08 -2.7622339340941025e-08 -2.4274176996584538e-08 -1.8414892893960685e-08 -2.650628522615553e-08 -2.413467023223635e-08 -2.413467023223635e-08 -2.3576643174843603e-08 -2.413467023223635e-08 -2.385565670353998e-08 -2.5808751404414597e-08 -3.11100084496457e-08 -2.706431228354828e-08 -3.8782880488795985e-08 -4.1712522540107916e-08 -4.366561724098254e-08 -4.492117812011622e-08 -4.157301577575972e-08 -4.324709694793797e-08 -4.324709694793797e-08 -4.1433509011411543e-08 -3.487669108704675e-08 -2.4274176996584538e-08 -2.008897406613893e-08 -2.413467023223635e-08 -2.6924805519200093e-08 -2.385565670353998e-08 -1.813587936526431e-08 -2.5948258168762783e-08 -2.3018616117450855e-08 -2.3576643174843603e-08 -2.246058906005811e-08 -2.2600095824406296e-08 -2.2600095824406296e-08 -2.4413683760932724e-08 -2.985444757051202e-08 -2.6785298754851907e-08 -3.8085346667055053e-08 -4.1433509011411543e-08 -4.324709694793797e-08 -4.464216459141985e-08 -4.1852029304456096e-08 -4.366561724098254e-08 -4.3805124005330716e-08 -4.1852029304456096e-08 -3.5016197851394936e-08 -2.46926972896291e-08 -2.106552141657624e-08 -2.5390231111370035e-08 -2.7761846105289214e-08 -2.46926972896291e-08 -1.8833413187005247e-08 -2.7901352869637404e-08 -2.4274176996584538e-08 -2.46926972896291e-08 -2.3297629646147227e-08 -2.385565670353998e-08 -2.3716149939191793e-08 -2.4832204053977286e-08 -3.0551981392252956e-08 -2.6645791990503717e-08 -3.7387812845314116e-08 -4.059646842532242e-08 -4.227054959750066e-08 -4.29680834192416e-08 -3.961992107488511e-08 -4.087548195401879e-08 -3.989893460358149e-08 -3.6690279023573184e-08 -3.0970501685297515e-08 -2.3716149939191793e-08 -2.008897406613893e-08 -2.2739602588754482e-08 -2.413467023223635e-08 -2.106552141657624e-08 -1.7856865836567937e-08 -2.7761846105289214e-08 -2.4832204053977286e-08 -2.5390231111370035e-08 -2.455319052528091e-08 -2.4274176996584538e-08 -2.3437136410495414e-08 -2.3437136410495414e-08 -2.46926972896291e-08 -2.6924805519200093e-08 -3.152852874269026e-08 -3.54347181444395e-08 -3.822485343140324e-08 -3.8782880488795985e-08 -3.710879931661774e-08 -3.627175873052862e-08 -3.5992745201832246e-08 -3.4737184322698563e-08 -3.348162344356488e-08 -3.069148815660114e-08 -2.9156913748771087e-08 -3.0551981392252956e-08 -3.11100084496457e-08 -3.013346109920839e-08 -2.9575434041815645e-08 -2.7901352869637404e-08 -2.5669244640066407e-08 -2.6645791990503717e-08 -2.5669244640066407e-08 -2.5390231111370035e-08 -2.5390231111370035e-08 -2.552973787571822e-08 -2.552973787571822e-08 -2.4832204053977286e-08 -2.413467023223635e-08 -2.5669244640066407e-08 -2.7901352869637404e-08 -2.8598886691378335e-08 -2.8877900220074708e-08 -2.873839345572652e-08 -2.8180366398333776e-08 -2.7761846105289214e-08 -2.6785298754851907e-08 -2.6366778461807345e-08 -2.5669244640066407e-08 -2.7203819047896466e-08 -2.8180366398333776e-08 -2.7343325812244652e-08 -2.5808751404414597e-08 -2.455319052528091e-08 -2.2600095824406296e-08 -2.3716149939191793e-08 -2.3995163467888165e-08 -2.4413683760932724e-08 -2.46926972896291e-08 -2.5808751404414597e-08 -3.124951521399389e-08 -2.7203819047896466e-08 -3.822485343140324e-08 -4.129400224706335e-08 -4.29680834192416e-08 -4.436315106272346e-08 -4.087548195401879e-08 -4.2689069890545226e-08 -4.2828576654893406e-08 -4.101498871836698e-08 -3.445817079400219e-08 -2.385565670353998e-08 -2.0647001123531675e-08 -2.5250724347021848e-08 -2.6366778461807345e-08 -2.246058906005811e-08 -1.7438345543523375e-08 -2.6366778461807345e-08 -2.3297629646147227e-08 -2.385565670353998e-08 -2.3297629646147227e-08 -2.3995163467888165e-08 -2.4413683760932724e-08 -2.5250724347021848e-08 -3.0970501685297515e-08 -2.804085963398559e-08 -3.9340907546188736e-08 -4.2689069890545226e-08 -4.436315106272346e-08 -4.5479205177508965e-08 -4.199153606880429e-08 -4.3805124005330716e-08 -4.394463076967891e-08 -4.213104283315248e-08 -3.5016197851394936e-08 -2.46926972896291e-08 -2.0926014652228048e-08 -2.5948258168762783e-08 -2.7482832576592838e-08 -2.4413683760932724e-08 -1.813587936526431e-08 -2.6366778461807345e-08 -2.3576643174843603e-08 -2.413467023223635e-08 -2.3297629646147227e-08 -2.3437136410495414e-08 -2.3437136410495414e-08 -2.5250724347021848e-08 -3.11100084496457e-08 -2.7622339340941025e-08 -3.892238725314418e-08 -4.199153606880429e-08 -4.394463076967891e-08 -4.520019164881259e-08 -4.1712522540107916e-08 -4.3526110476634344e-08 -4.3526110476634344e-08 -4.1852029304456096e-08 -3.487669108704675e-08 -2.4413683760932724e-08 -2.106552141657624e-08 -2.552973787571822e-08 -2.6645791990503717e-08 -2.3576643174843603e-08 -1.7856865836567937e-08 -2.6785298754851907e-08 -2.385565670353998e-08 -2.455319052528091e-08 -2.385565670353998e-08 -2.3995163467888165e-08 -2.413467023223635e-08 -2.5390231111370035e-08 -3.1947049035734825e-08 -2.845937992703015e-08 -3.9759427839233295e-08 -4.310759018358978e-08 -4.5479205177508965e-08 -4.673476605664265e-08 -4.3386603712286164e-08 -4.50606848844644e-08 -4.478167135576803e-08 -4.2410056361848854e-08 -3.54347181444395e-08 -2.4971710818325472e-08 -2.1623548473968986e-08 -2.6924805519200093e-08 -2.7901352869637404e-08 -2.46926972896291e-08 -1.8972919951353434e-08 -2.7901352869637404e-08 -2.46926972896291e-08 -2.5250724347021848e-08 -2.385565670353998e-08 -2.455319052528091e-08 -2.46926972896291e-08 -2.5808751404414597e-08 -3.22260625644312e-08 -2.8319873162681962e-08 -3.948041431053692e-08 -4.2689069890545226e-08 -4.436315106272346e-08 -4.478167135576803e-08 -4.115449548271517e-08 -4.1852029304456096e-08 -4.1433509011411543e-08 -3.794583990270687e-08 -3.152852874269026e-08 -2.3995163467888165e-08 -2.1205028180924427e-08 -2.455319052528091e-08 -2.4413683760932724e-08 -2.1344534945272613e-08 -1.8414892893960685e-08 -2.943592727746746e-08 -2.650628522615553e-08 -2.6645791990503717e-08 -2.5390231111370035e-08 -2.552973787571822e-08 -2.5808751404414597e-08 -2.6227271697459155e-08 -2.7482832576592838e-08 -3.013346109920839e-08 -3.376063697226125e-08 -3.75273196096623e-08 -4.059646842532242e-08 -4.115449548271517e-08 -3.920140078184055e-08 -3.794583990270687e-08 -3.724830608096593e-08 -3.5992745201832246e-08 -3.459767755835038e-08 -3.2365569328779384e-08 -3.041247462790477e-08 -3.250507609312757e-08 -3.1668035507038446e-08 -3.027296786355658e-08 -2.9156913748771087e-08 -2.845937992703015e-08 -2.6366778461807345e-08 -2.6645791990503717e-08 -2.650628522615553e-08 -2.5948258168762783e-08 -2.4832204053977286e-08 -2.4971710818325472e-08 -2.46926972896291e-08 -2.4413683760932724e-08 -2.455319052528091e-08 -2.6366778461807345e-08 -2.845937992703015e-08 -2.943592727746746e-08 -3.013346109920839e-08 -2.9993954334860204e-08 -2.943592727746746e-08 -2.9017406984422894e-08 -2.845937992703015e-08 -2.804085963398559e-08 -2.7761846105289214e-08 -2.9296420513119273e-08 -2.943592727746746e-08 -2.845937992703015e-08 -2.706431228354828e-08 -2.6227271697459155e-08 -2.455319052528091e-08 -2.5808751404414597e-08 -2.5948258168762783e-08 -2.5948258168762783e-08 -2.5948258168762783e-08 -2.6924805519200093e-08 -3.208655580008301e-08 -2.8180366398333776e-08 -3.9340907546188736e-08 -4.227054959750066e-08 -4.422364429837528e-08 -4.533969841316077e-08 -4.1852029304456096e-08 -4.3526110476634344e-08 -4.394463076967891e-08 -4.199153606880429e-08 -3.54347181444395e-08 -2.455319052528091e-08 -2.2321082295709924e-08 -2.706431228354828e-08 -2.7203819047896466e-08 -2.3576643174843603e-08 -1.8414892893960685e-08 -2.8319873162681962e-08 -2.5250724347021848e-08 -2.6227271697459155e-08 -2.5808751404414597e-08 -2.5390231111370035e-08 -2.5390231111370035e-08 -2.6366778461807345e-08 -3.1947049035734825e-08 -2.873839345572652e-08 -4.045696166097423e-08 -4.3386603712286164e-08 -4.50606848844644e-08 -4.603723223490171e-08 -4.2689069890545226e-08 -4.408413753402709e-08 -4.436315106272346e-08 -4.2410056361848854e-08 -3.557422490878769e-08 -2.552973787571822e-08 -2.3018616117450855e-08 -2.8598886691378335e-08 -2.873839345572652e-08 -2.552973787571822e-08 -1.9670453773094368e-08 -2.9575434041815645e-08 -2.6785298754851907e-08 -2.7203819047896466e-08 -2.6785298754851907e-08 -2.6645791990503717e-08 -2.6366778461807345e-08 -2.8598886691378335e-08 -3.445817079400219e-08 -3.041247462790477e-08 -4.213104283315248e-08 -4.478167135576803e-08 -4.631624576359808e-08 -4.729279311403539e-08 -4.408413753402709e-08 -4.5897725470553524e-08 -4.5897725470553524e-08 -4.3805124005330716e-08 -3.682978578792137e-08 -2.6785298754851907e-08 -2.4832204053977286e-08 -2.9714940806163832e-08 -2.9017406984422894e-08 -2.5669244640066407e-08 -2.008897406613893e-08 -3.069148815660114e-08 -2.804085963398559e-08 -2.8319873162681962e-08 -2.6924805519200093e-08 -2.650628522615553e-08 -2.650628522615553e-08 -2.7343325812244652e-08 -3.362113020791307e-08 -2.9714940806163832e-08 -4.101498871836698e-08 -4.464216459141985e-08 -4.6455752527946275e-08 -4.7432299878383586e-08 -4.394463076967891e-08 -4.5897725470553524e-08 -4.5618711941857144e-08 -4.310759018358978e-08 -3.585323843748406e-08 -2.5390231111370035e-08 -2.2600095824406296e-08 -2.804085963398559e-08 -2.8180366398333776e-08 -2.4832204053977286e-08 -1.9251933480049806e-08 -2.8180366398333776e-08 -2.5390231111370035e-08 -2.5948258168762783e-08 -2.455319052528091e-08 -2.4971710818325472e-08 -2.5250724347021848e-08 -2.6785298754851907e-08 -3.376063697226125e-08 -2.9156913748771087e-08 -4.087548195401879e-08 -4.408413753402709e-08 -4.533969841316077e-08 -4.575821870620534e-08 -4.1852029304456096e-08 -4.2549563126197034e-08 -4.157301577575972e-08 -3.8085346667055053e-08 -3.1668035507038446e-08 -2.4274176996584538e-08 -2.2042068767013544e-08 -2.4971710818325472e-08 -2.413467023223635e-08 -2.1205028180924427e-08 -1.8414892893960685e-08 -2.9993954334860204e-08 -2.7343325812244652e-08 -2.7203819047896466e-08 -2.5669244640066407e-08 -2.5948258168762783e-08 -2.5948258168762783e-08 -2.650628522615553e-08 -2.7622339340941025e-08 -3.083099492094933e-08 -3.4318664029654005e-08 -3.8085346667055053e-08 -4.101498871836698e-08 -4.1712522540107916e-08 -3.961992107488511e-08 -3.850386696009961e-08 -3.794583990270687e-08 -3.627175873052862e-08 -3.487669108704675e-08 -3.2644582857475756e-08 -3.0970501685297515e-08 -3.3342116679216694e-08 -3.22260625644312e-08 -3.124951521399389e-08 -3.013346109920839e-08 -2.8877900220074708e-08 -2.7203819047896466e-08 -2.7343325812244652e-08 -2.706431228354828e-08 -2.6366778461807345e-08 -2.5111217582673662e-08 -2.5390231111370035e-08 -2.5111217582673662e-08 -2.5390231111370035e-08 -2.5390231111370035e-08 -2.6924805519200093e-08 -2.9156913748771087e-08 -3.013346109920839e-08 -3.041247462790477e-08 -3.041247462790477e-08 -3.013346109920839e-08 -2.9714940806163832e-08 -2.943592727746746e-08 -2.9017406984422894e-08 -2.9296420513119273e-08 -3.0970501685297515e-08 -3.083099492094933e-08 -2.9993954334860204e-08 -2.9017406984422894e-08 -2.8319873162681962e-08 -2.6645791990503717e-08 -2.7761846105289214e-08 -2.6924805519200093e-08 -2.706431228354828e-08 -2.7203819047896466e-08 -2.7622339340941025e-08 -3.2365569328779384e-08 -2.873839345572652e-08 -4.003844136792967e-08 -4.2689069890545226e-08 -4.478167135576803e-08 -4.5618711941857144e-08 -4.213104283315248e-08 -4.3805124005330716e-08 -4.408413753402709e-08 -4.199153606880429e-08 -3.515570461574312e-08 -2.46926972896291e-08 -2.3297629646147227e-08 -2.706431228354828e-08 -2.650628522615553e-08 -2.287910935310267e-08 -1.7996372600916123e-08 -2.8180366398333776e-08 -2.552973787571822e-08 -2.650628522615553e-08 -2.5948258168762783e-08 -2.5669244640066407e-08 -2.5808751404414597e-08 -2.7482832576592838e-08 -3.292359638617213e-08 -2.9296420513119273e-08 -4.129400224706335e-08 -4.422364429837528e-08 -4.603723223490171e-08 -4.687427282099083e-08 -4.3386603712286164e-08 -4.478167135576803e-08 -4.478167135576803e-08 -4.2828576654893406e-08 -3.613225196618043e-08 -2.5808751404414597e-08 -2.3716149939191793e-08 -2.845937992703015e-08 -2.8180366398333776e-08 -2.46926972896291e-08 -1.9809960537442554e-08 -3.11100084496457e-08 -2.9156913748771087e-08 -2.9156913748771087e-08 -2.8877900220074708e-08 -2.845937992703015e-08 -2.8319873162681962e-08 -3.013346109920839e-08 -3.585323843748406e-08 -3.1389021978342073e-08 -4.310759018358978e-08 -4.5479205177508965e-08 -4.673476605664265e-08 -4.771131340707996e-08 -4.422364429837528e-08 -4.603723223490171e-08 -4.6455752527946275e-08 -4.436315106272346e-08 -3.75273196096623e-08 -2.7343325812244652e-08 -2.552973787571822e-08 -2.9575434041815645e-08 -2.8877900220074708e-08 -2.552973787571822e-08 -2.0228480830487117e-08 -3.11100084496457e-08 -2.9017406984422894e-08 -2.9017406984422894e-08 -2.7482832576592838e-08 -2.6645791990503717e-08 -2.6645791990503717e-08 -2.7761846105289214e-08 -3.362113020791307e-08 -2.9575434041815645e-08 -4.129400224706335e-08 -4.408413753402709e-08 -4.5479205177508965e-08 -4.631624576359808e-08 -4.2828576654893406e-08 -4.492117812011622e-08 -4.50606848844644e-08 -4.29680834192416e-08 -3.585323843748406e-08 -2.6227271697459155e-08 -2.4274176996584538e-08 -2.873839345572652e-08 -2.8598886691378335e-08 -2.5250724347021848e-08 -1.9949467301790744e-08 -2.9296420513119273e-08 -2.6785298754851907e-08 -2.7901352869637404e-08 -2.6366778461807345e-08 -2.6785298754851907e-08 -2.6227271697459155e-08 -2.7901352869637404e-08 -3.417915726530581e-08 -2.9156913748771087e-08 -4.031745489662604e-08 -4.29680834192416e-08 -4.394463076967891e-08 -4.4502657827071654e-08 -4.087548195401879e-08 -4.157301577575972e-08 -4.059646842532242e-08 -3.710879931661774e-08 -3.0970501685297515e-08 -2.3576643174843603e-08 -2.1205028180924427e-08 -2.3576643174843603e-08 -2.2739602588754482e-08 -1.9809960537442554e-08 -1.7159332014827002e-08 -2.8180366398333776e-08 -2.5669244640066407e-08 -2.552973787571822e-08 -2.4413683760932724e-08 -2.4274176996584538e-08 -2.413467023223635e-08 -2.4413683760932724e-08 -2.5390231111370035e-08 -2.9017406984422894e-08 -3.2644582857475756e-08 -3.6550772259225e-08 -3.948041431053692e-08 -4.003844136792967e-08 -3.822485343140324e-08 -3.7387812845314116e-08 -3.7387812845314116e-08 -3.682978578792137e-08 -3.5295211380091315e-08 -3.2644582857475756e-08 -3.1668035507038446e-08 -3.320260991486851e-08 -3.1947049035734825e-08 -3.027296786355658e-08 -2.9156913748771087e-08 -2.7622339340941025e-08 -2.5390231111370035e-08 -2.5669244640066407e-08 -2.455319052528091e-08 -2.4413683760932724e-08 -2.385565670353998e-08 -2.385565670353998e-08 -2.385565670353998e-08 -2.4274176996584538e-08 -2.385565670353998e-08 -2.4832204053977286e-08 -2.6785298754851907e-08 -2.7901352869637404e-08 -2.8319873162681962e-08 -2.873839345572652e-08 -2.8319873162681962e-08 -2.8180366398333776e-08 -2.7901352869637404e-08 -2.7203819047896466e-08 -2.7901352869637404e-08 -2.8877900220074708e-08 -2.873839345572652e-08 -2.7901352869637404e-08 -2.7343325812244652e-08 -2.650628522615553e-08 -2.5111217582673662e-08 -2.5808751404414597e-08 -2.5669244640066407e-08 -2.650628522615553e-08 -2.6924805519200093e-08 -2.7901352869637404e-08 -3.278408962182394e-08 -2.8180366398333776e-08 -3.948041431053692e-08 -4.29680834192416e-08 -4.464216459141985e-08 -4.5618711941857144e-08 -4.2689069890545226e-08 -4.422364429837528e-08 -4.394463076967891e-08 -4.199153606880429e-08 -3.5713731673135874e-08 -2.5808751404414597e-08 -2.3297629646147227e-08 -2.608776493311097e-08 -2.5111217582673662e-08 -2.1763055238317172e-08 -1.729883877917519e-08 -2.6785298754851907e-08 -2.4413683760932724e-08 -2.455319052528091e-08 -2.4274176996584538e-08 -2.4274176996584538e-08 -2.4413683760932724e-08 -2.6227271697459155e-08 -3.083099492094933e-08 -2.7343325812244652e-08 -3.961992107488511e-08 -4.3386603712286164e-08 -4.50606848844644e-08 -4.603723223490171e-08 -4.310759018358978e-08 -4.464216459141985e-08 -4.478167135576803e-08 -4.29680834192416e-08 -3.6411265494876805e-08 -2.6366778461807345e-08 -2.3995163467888165e-08 -2.6924805519200093e-08 -2.6645791990503717e-08 -2.315812288179904e-08 -1.8693906422657058e-08 -2.8877900220074708e-08 -2.6645791990503717e-08 -2.6227271697459155e-08 -2.608776493311097e-08 -2.6366778461807345e-08 -2.6645791990503717e-08 -2.6645791990503717e-08 -3.208655580008301e-08 -2.8180366398333776e-08 -4.003844136792967e-08 -4.324709694793797e-08 -4.4502657827071654e-08 -4.61767389992499e-08 -4.2828576654893406e-08 -4.3805124005330716e-08 -4.492117812011622e-08 -4.324709694793797e-08 -3.6690279023573184e-08 -2.7343325812244652e-08 -2.5111217582673662e-08 -2.7343325812244652e-08 -2.650628522615553e-08 -2.3716149939191793e-08 -1.8972919951353434e-08 -2.943592727746746e-08 -2.7203819047896466e-08 -2.6924805519200093e-08 -2.6645791990503717e-08 -2.6227271697459155e-08 -2.6227271697459155e-08 -2.7622339340941025e-08 -3.250507609312757e-08 -2.804085963398559e-08 -4.003844136792967e-08 -4.2828576654893406e-08 -4.464216459141985e-08 -4.5897725470553524e-08 -4.2549563126197034e-08 -4.3805124005330716e-08 -4.408413753402709e-08 -4.2410056361848854e-08 -3.613225196618043e-08 -2.706431228354828e-08 -2.552973787571822e-08 -2.8180366398333776e-08 -2.7761846105289214e-08 -2.4971710818325472e-08 -2.008897406613893e-08 -2.9993954334860204e-08 -2.6645791990503717e-08 -2.6785298754851907e-08 -2.5948258168762783e-08 -2.5948258168762783e-08 -2.5390231111370035e-08 -2.6924805519200093e-08 -3.208655580008301e-08 -2.7622339340941025e-08 -3.86433737244478e-08 -4.1852029304456096e-08 -4.3386603712286164e-08 -4.436315106272346e-08 -4.129400224706335e-08 -4.1433509011411543e-08 -4.101498871836698e-08 -3.7806333138358674e-08 -3.22260625644312e-08 -2.5250724347021848e-08 -2.315812288179904e-08 -2.3995163467888165e-08 -2.3297629646147227e-08 -2.0647001123531675e-08 -1.7856865836567937e-08 -2.873839345572652e-08 -2.5948258168762783e-08 -2.5669244640066407e-08 -2.455319052528091e-08 -2.4413683760932724e-08 -2.4971710818325472e-08 -2.5390231111370035e-08 -2.6227271697459155e-08 -2.9714940806163832e-08 -3.4039650500957626e-08 -3.7387812845314116e-08 -4.087548195401879e-08 -4.115449548271517e-08 -3.920140078184055e-08 -3.7666826374010495e-08 -3.7387812845314116e-08 -3.696929255226956e-08 -3.5713731673135874e-08 -3.362113020791307e-08 -3.320260991486851e-08 -3.3342116679216694e-08 -3.124951521399389e-08 -2.9714940806163832e-08 -2.9575434041815645e-08 -2.8319873162681962e-08 -2.6227271697459155e-08 -2.6366778461807345e-08 -5.1338489280132814e-08 -2.4971710818325472e-08 -2.4832204053977286e-08 -2.5111217582673662e-08 -2.4832204053977286e-08 -2.3995163467888165e-08 -2.455319052528091e-08 -2.650628522615553e-08 -2.7482832576592838e-08 -2.8319873162681962e-08 -2.873839345572652e-08 -2.845937992703015e-08 -2.873839345572652e-08 -2.8319873162681962e-08 -2.8319873162681962e-08 -2.943592727746746e-08 -2.9156913748771087e-08 -2.8598886691378335e-08 -2.7761846105289214e-08 -2.7343325812244652e-08 -2.6227271697459155e-08 -2.552973787571822e-08 -2.5250724347021848e-08 -2.5808751404414597e-08 -2.6366778461807345e-08 -2.706431228354828e-08 -2.8877900220074708e-08 -3.208655580008301e-08 -4.3386603712286164e-08 -3.5016197851394936e-08 -4.324709694793797e-08 -4.5897725470553524e-08 -4.701377958533902e-08 -4.631624576359808e-08 -4.50606848844644e-08 -4.603723223490171e-08 -4.533969841316077e-08 -4.129400224706335e-08 -3.3063103150520315e-08 -2.7901352869637404e-08 -2.8319873162681962e-08 -2.7343325812244652e-08 -2.5111217582673662e-08 -2.1205028180924427e-08 -1.757785230787156e-08 -2.845937992703015e-08 -2.6924805519200093e-08 -2.7761846105289214e-08 -2.7761846105289214e-08 -2.7343325812244652e-08 -2.7901352869637404e-08 -2.9993954334860204e-08 -4.129400224706335e-08 -3.4737184322698563e-08 -4.2549563126197034e-08 -4.478167135576803e-08 -4.631624576359808e-08 -4.5618711941857144e-08 -4.436315106272346e-08 -4.5897725470553524e-08 -4.5618711941857144e-08 -4.1433509011411543e-08 -3.3342116679216694e-08 -2.8877900220074708e-08 -2.8877900220074708e-08 -2.8319873162681962e-08 -2.608776493311097e-08 -2.1902562002665358e-08 -1.757785230787156e-08 -2.7901352869637404e-08 -2.6366778461807345e-08 -2.6366778461807345e-08 -2.650628522615553e-08 -2.6645791990503717e-08 -2.6645791990503717e-08 -2.985444757051202e-08 -4.087548195401879e-08 -3.445817079400219e-08 -4.2549563126197034e-08 -4.464216459141985e-08 -4.61767389992499e-08 -4.520019164881259e-08 -4.3386603712286164e-08 -4.50606848844644e-08 -4.436315106272346e-08 -4.031745489662604e-08 -3.292359638617213e-08 -2.9017406984422894e-08 -2.8180366398333776e-08 -2.7482832576592838e-08 -2.5669244640066407e-08 -2.14840417096208e-08 -1.757785230787156e-08 -2.7901352869637404e-08 -2.6366778461807345e-08 -2.6227271697459155e-08 -2.5808751404414597e-08 -2.5808751404414597e-08 -2.6645791990503717e-08 -2.9296420513119273e-08 -4.101498871836698e-08 -3.417915726530581e-08 -4.213104283315248e-08 -4.464216459141985e-08 -4.631624576359808e-08 -4.533969841316077e-08 -4.3805124005330716e-08 -4.492117812011622e-08 -4.436315106272346e-08 -4.031745489662604e-08 -3.278408962182394e-08 -2.8598886691378335e-08 -2.8319873162681962e-08 -2.7761846105289214e-08 -2.608776493311097e-08 -2.2042068767013544e-08 -1.757785230787156e-08 -2.7203819047896466e-08 -2.5250724347021848e-08 -2.4971710818325472e-08 -2.46926972896291e-08 -2.4413683760932724e-08 -2.5390231111370035e-08 -2.8319873162681962e-08 -3.961992107488511e-08 -3.320260991486851e-08 -4.087548195401879e-08 -4.3386603712286164e-08 -4.478167135576803e-08 -4.394463076967891e-08 -4.1852029304456096e-08 -4.227054959750066e-08 -4.045696166097423e-08 -3.5992745201832246e-08 -3.013346109920839e-08 -2.7343325812244652e-08 -2.5948258168762783e-08 -2.4971710818325472e-08 -2.3297629646147227e-08 -2.0647001123531675e-08 -1.771735907221975e-08 -2.9156913748771087e-08 -2.7622339340941025e-08 -2.7203819047896466e-08 -2.650628522615553e-08 -2.6366778461807345e-08 -2.650628522615553e-08 -2.7203819047896466e-08 -2.9296420513119273e-08 -3.320260991486851e-08 -3.696929255226956e-08 -4.087548195401879e-08 -4.227054959750066e-08 -4.1712522540107916e-08 -4.031745489662604e-08 -4.003844136792967e-08 -3.86433737244478e-08 -3.7387812845314116e-08 -3.724830608096593e-08 -3.7387812845314116e-08 -3.5713731673135874e-08 -3.348162344356488e-08 -3.250507609312757e-08 -3.208655580008301e-08 -3.0970501685297515e-08 -2.9296420513119273e-08 -2.8180366398333776e-08 -2.8598886691378335e-08 -2.7761846105289214e-08 -2.6645791990503717e-08 -2.6227271697459155e-08 -2.6785298754851907e-08 -2.6227271697459155e-08 -2.5390231111370035e-08 -2.5808751404414597e-08 -2.8180366398333776e-08 -2.9156913748771087e-08 -2.985444757051202e-08 -3.013346109920839e-08 -3.041247462790477e-08 -3.083099492094933e-08 -3.0551981392252956e-08 -3.1389021978342073e-08 -3.292359638617213e-08 -3.1668035507038446e-08 -3.013346109920839e-08 -2.9575434041815645e-08 -2.873839345572652e-08 -2.7203819047896466e-08 -2.6645791990503717e-08 -2.5669244640066407e-08 -2.6366778461807345e-08 -2.5808751404414597e-08 -2.6366778461807345e-08 -2.7203819047896466e-08 -2.9017406984422894e-08 -3.515570461574312e-08 -2.9993954334860204e-08 -4.213104283315248e-08 -4.5479205177508965e-08 -4.729279311403539e-08 -4.82693404644727e-08 -4.520019164881259e-08 -4.673476605664265e-08 -4.7153286349687207e-08 -4.464216459141985e-08 -3.8085346667055053e-08 -3.11100084496457e-08 -2.943592727746746e-08 -2.8598886691378335e-08 -2.6924805519200093e-08 -2.3297629646147227e-08 -1.8693906422657058e-08 -2.9714940806163832e-08 -2.706431228354828e-08 -2.7901352869637404e-08 -2.7901352869637404e-08 -2.7901352869637404e-08 -2.8319873162681962e-08 -2.9156913748771087e-08 -3.515570461574312e-08 -3.069148815660114e-08 -4.2549563126197034e-08 -4.5479205177508965e-08 -4.7153286349687207e-08 -4.799032693577633e-08 -4.422364429837528e-08 -4.631624576359808e-08 -4.687427282099083e-08 -4.478167135576803e-08 -3.850386696009961e-08 -3.152852874269026e-08 -2.9017406984422894e-08 -2.8877900220074708e-08 -2.7343325812244652e-08 -2.3995163467888165e-08 -1.8972919951353434e-08 -2.9575434041815645e-08 -2.6924805519200093e-08 -2.706431228354828e-08 -2.5948258168762783e-08 -2.6227271697459155e-08 -2.6645791990503717e-08 -2.7901352869637404e-08 -3.376063697226125e-08 -2.9993954334860204e-08 -4.199153606880429e-08 -4.492117812011622e-08 -4.631624576359808e-08 -4.729279311403539e-08 -4.324709694793797e-08 -4.492117812011622e-08 -4.520019164881259e-08 -4.3386603712286164e-08 -3.7387812845314116e-08 -3.1668035507038446e-08 -2.873839345572652e-08 -2.873839345572652e-08 -2.6924805519200093e-08 -2.3576643174843603e-08 -1.82753861296125e-08 -2.8180366398333776e-08 -2.552973787571822e-08 -2.5669244640066407e-08 -2.4832204053977286e-08 -2.4832204053977286e-08 -2.5111217582673662e-08 -2.6785298754851907e-08 -3.278408962182394e-08 -2.9714940806163832e-08 -4.1852029304456096e-08 -4.492117812011622e-08 -4.6595259292294455e-08 -4.771131340707996e-08 -4.422364429837528e-08 -4.61767389992499e-08 -4.6595259292294455e-08 -4.4502657827071654e-08 -3.8364360195751426e-08 -3.152852874269026e-08 -2.873839345572652e-08 -2.8180366398333776e-08 -2.706431228354828e-08 -2.3576643174843603e-08 -1.855439965830887e-08 -2.8598886691378335e-08 -2.5948258168762783e-08 -2.6366778461807345e-08 -2.5390231111370035e-08 -2.5250724347021848e-08 -2.5390231111370035e-08 -2.6645791990503717e-08 -3.3063103150520315e-08 -2.9017406984422894e-08 -4.045696166097423e-08 -4.3386603712286164e-08 -4.492117812011622e-08 -4.5479205177508965e-08 -4.1852029304456096e-08 -4.2689069890545226e-08 -4.227054959750066e-08 -3.850386696009961e-08 -3.3063103150520315e-08 -2.9156913748771087e-08 -2.6227271697459155e-08 -2.5390231111370035e-08 -2.413467023223635e-08 -2.1623548473968986e-08 -1.8414892893960685e-08 -3.027296786355658e-08 -2.7761846105289214e-08 -2.8180366398333776e-08 -2.6785298754851907e-08 -2.6227271697459155e-08 -2.608776493311097e-08 -2.6645791990503717e-08 -2.7482832576592838e-08 -3.083099492094933e-08 -3.515570461574312e-08 -3.906189401749236e-08 -4.199153606880429e-08 -4.2828576654893406e-08 -4.1712522540107916e-08 -4.115449548271517e-08 -4.059646842532242e-08 -3.948041431053692e-08 -4.045696166097423e-08 -4.031745489662604e-08 -3.6550772259225e-08 -3.487669108704675e-08 -3.348162344356488e-08 -3.2365569328779384e-08 -3.124951521399389e-08 -2.985444757051202e-08 -2.8180366398333776e-08 -2.8598886691378335e-08 -2.7761846105289214e-08 -2.650628522615553e-08 -2.5669244640066407e-08 -2.5808751404414597e-08 -2.5808751404414597e-08 -2.5808751404414597e-08 -2.5808751404414597e-08 -2.7901352869637404e-08 -2.9575434041815645e-08 -3.013346109920839e-08 -3.083099492094933e-08 -3.0970501685297515e-08 -3.124951521399389e-08 -3.11100084496457e-08 -3.1668035507038446e-08 -3.292359638617213e-08 -3.1389021978342073e-08 -3.013346109920839e-08 -2.943592727746746e-08 -2.873839345572652e-08 -2.7482832576592838e-08 -2.6366778461807345e-08 -2.5111217582673662e-08 -2.6366778461807345e-08 -2.552973787571822e-08 -2.5808751404414597e-08 -2.6366778461807345e-08 -2.8319873162681962e-08 -3.459767755835038e-08 -3.013346109920839e-08 -4.227054959750066e-08 -4.5618711941857144e-08 -4.7432299878383586e-08 -4.812983370012452e-08 -4.533969841316077e-08 -4.7153286349687207e-08 -4.7432299878383586e-08 -4.50606848844644e-08 -3.86433737244478e-08 -3.1668035507038446e-08 -2.9296420513119273e-08 -2.8598886691378335e-08 -2.650628522615553e-08 -2.2739602588754482e-08 -1.813587936526431e-08 -2.9156913748771087e-08 -2.6785298754851907e-08 -2.7622339340941025e-08 -2.6785298754851907e-08 -2.7343325812244652e-08 -2.7622339340941025e-08 -2.9156913748771087e-08 -3.515570461574312e-08 -3.11100084496457e-08 -4.3526110476634344e-08 -4.6455752527946275e-08 -4.785082017142814e-08 -4.868786075751727e-08 -4.492117812011622e-08 -4.673476605664265e-08 -4.701377958533902e-08 -4.478167135576803e-08 -3.86433737244478e-08 -3.1947049035734825e-08 -2.8877900220074708e-08 -2.8598886691378335e-08 -2.7343325812244652e-08 -2.3995163467888165e-08 -1.8972919951353434e-08 -2.943592727746746e-08 -2.6924805519200093e-08 -2.7343325812244652e-08 -2.6366778461807345e-08 -2.6645791990503717e-08 -2.7203819047896466e-08 -2.8598886691378335e-08 -3.515570461574312e-08 -3.124951521399389e-08 -4.3386603712286164e-08 -4.631624576359808e-08 -4.799032693577633e-08 -4.9245887814910014e-08 -4.5479205177508965e-08 -4.7153286349687207e-08 -4.7153286349687207e-08 -4.50606848844644e-08 -3.9340907546188736e-08 -3.292359638617213e-08 -2.9714940806163832e-08 -2.9714940806163832e-08 -2.7761846105289214e-08 -2.455319052528091e-08 -1.911242671570162e-08 -2.985444757051202e-08 -2.7203819047896466e-08 -2.8319873162681962e-08 -2.7482832576592838e-08 -2.7622339340941025e-08 -2.8180366398333776e-08 -3.041247462790477e-08 -3.627175873052862e-08 -3.1947049035734825e-08 -4.436315106272346e-08 -4.785082017142814e-08 -4.93853945792582e-08 -5.036194192969551e-08 -4.7153286349687207e-08 -4.896687428621364e-08 -4.910638105056182e-08 -4.701377958533902e-08 -4.115449548271517e-08 -3.4039650500957626e-08 -3.083099492094933e-08 -2.9993954334860204e-08 -2.873839345572652e-08 -2.4971710818325472e-08 -1.9391440244397992e-08 -3.027296786355658e-08 -2.7622339340941025e-08 -2.873839345572652e-08 -2.7761846105289214e-08 -2.7901352869637404e-08 -2.8598886691378335e-08 -2.9575434041815645e-08 -3.557422490878769e-08 -3.0551981392252956e-08 -4.2689069890545226e-08 -4.520019164881259e-08 -4.687427282099083e-08 -4.729279311403539e-08 -4.3526110476634344e-08 -4.436315106272346e-08 -4.366561724098254e-08 -4.003844136792967e-08 -3.4737184322698563e-08 -3.027296786355658e-08 -2.6645791990503717e-08 -2.5808751404414597e-08 -2.4274176996584538e-08 -2.1623548473968986e-08 -1.855439965830887e-08 -2.9993954334860204e-08 -2.7343325812244652e-08 -2.7482832576592838e-08 -2.650628522615553e-08 -2.6785298754851907e-08 -2.6924805519200093e-08 -2.7343325812244652e-08 -2.8319873162681962e-08 -3.1947049035734825e-08 -3.613225196618043e-08 -3.989893460358149e-08 -4.29680834192416e-08 -4.3805124005330716e-08 -4.2410056361848854e-08 -4.087548195401879e-08 -4.059646842532242e-08 -3.961992107488511e-08 -4.129400224706335e-08 -4.045696166097423e-08 -3.6550772259225e-08 -3.4737184322698563e-08 -3.3063103150520315e-08 -3.180754227138664e-08 -3.027296786355658e-08 -2.9156913748771087e-08 -2.804085963398559e-08 -2.8877900220074708e-08 -2.8319873162681962e-08 -2.7761846105289214e-08 -2.706431228354828e-08 -2.6785298754851907e-08 -2.650628522615553e-08 -2.7343325812244652e-08 -2.6924805519200093e-08 -2.8180366398333776e-08 -2.9993954334860204e-08 -3.083099492094933e-08 -3.2365569328779384e-08 -3.1947049035734825e-08 -3.22260625644312e-08 -3.278408962182394e-08 -3.3342116679216694e-08 -3.4318664029654005e-08 -3.292359638617213e-08 -3.180754227138664e-08 -3.11100084496457e-08 -3.027296786355658e-08 -2.9156913748771087e-08 -2.7622339340941025e-08 -2.5669244640066407e-08 -2.6785298754851907e-08 -2.608776493311097e-08 -2.6227271697459155e-08 -2.7203819047896466e-08 -2.9017406984422894e-08 -3.5295211380091315e-08 -3.124951521399389e-08 -4.3805124005330716e-08 -4.687427282099083e-08 -4.840884722882089e-08 -4.882736752186545e-08 -4.5618711941857144e-08 -4.785082017142814e-08 -4.785082017142814e-08 -4.5618711941857144e-08 -3.961992107488511e-08 -3.2644582857475756e-08 -2.985444757051202e-08 -2.9156913748771087e-08 -2.706431228354828e-08 -2.315812288179904e-08 -1.855439965830887e-08 -2.985444757051202e-08 -2.7622339340941025e-08 -2.845937992703015e-08 -2.7761846105289214e-08 -2.7622339340941025e-08 -2.8180366398333776e-08 -2.985444757051202e-08 -3.613225196618043e-08 -3.1947049035734825e-08 -4.436315106272346e-08 -4.7153286349687207e-08 -4.8548353993169076e-08 -4.93853945792582e-08 -4.533969841316077e-08 -4.7153286349687207e-08 -4.7571806642731765e-08 -4.533969841316077e-08 -3.948041431053692e-08 -3.250507609312757e-08 -2.9296420513119273e-08 -2.8877900220074708e-08 -2.7482832576592838e-08 -2.413467023223635e-08 -1.8833413187005247e-08 -2.9714940806163832e-08 -2.7482832576592838e-08 -2.7901352869637404e-08 -2.7203819047896466e-08 -2.7482832576592838e-08 -2.804085963398559e-08 -2.943592727746746e-08 -3.585323843748406e-08 -3.208655580008301e-08 -4.4502657827071654e-08 -4.785082017142814e-08 -4.9245887814910014e-08 -5.0501448694043697e-08 -4.687427282099083e-08 -4.8548353993169076e-08 -4.8548353993169076e-08 -4.61767389992499e-08 -4.087548195401879e-08 -3.376063697226125e-08 -2.985444757051202e-08 -2.943592727746746e-08 -2.7901352869637404e-08 -2.4413683760932724e-08 -1.911242671570162e-08 -3.013346109920839e-08 -2.7622339340941025e-08 -2.8877900220074708e-08 -2.804085963398559e-08 -2.8598886691378335e-08 -2.9017406984422894e-08 -3.124951521399389e-08 -3.75273196096623e-08 -3.278408962182394e-08 -4.520019164881259e-08 -4.8548353993169076e-08 -4.9943421636650945e-08 -5.1338489280132814e-08 -4.812983370012452e-08 -4.980391487230276e-08 -4.9943421636650945e-08 -4.771131340707996e-08 -4.213104283315248e-08 -3.487669108704675e-08 -3.180754227138664e-08 -3.0551981392252956e-08 -2.9296420513119273e-08 -2.552973787571822e-08 -1.9670453773094368e-08 -3.069148815660114e-08 -2.8180366398333776e-08 -2.9017406984422894e-08 -2.845937992703015e-08 -2.9156913748771087e-08 -2.9993954334860204e-08 -3.069148815660114e-08 -3.682978578792137e-08 -3.1668035507038446e-08 -4.422364429837528e-08 -4.673476605664265e-08 -4.82693404644727e-08 -4.882736752186545e-08 -4.520019164881259e-08 -4.603723223490171e-08 -4.520019164881259e-08 -4.157301577575972e-08 -3.6550772259225e-08 -3.180754227138664e-08 -2.7622339340941025e-08 -2.6366778461807345e-08 -2.4832204053977286e-08 -2.218157553136173e-08 -1.911242671570162e-08 -3.1389021978342073e-08 -2.8877900220074708e-08 -2.8877900220074708e-08 -2.8319873162681962e-08 -2.8598886691378335e-08 -2.8877900220074708e-08 -2.9156913748771087e-08 -3.027296786355658e-08 -3.390014373660944e-08 -3.892238725314418e-08 -4.2689069890545226e-08 -4.5618711941857144e-08 -4.6595259292294455e-08 -4.520019164881259e-08 -4.3386603712286164e-08 -4.199153606880429e-08 -4.087548195401879e-08 -4.2410056361848854e-08 -4.101498871836698e-08 -3.7387812845314116e-08 -3.5713731673135874e-08 -3.362113020791307e-08 -3.250507609312757e-08 -3.083099492094933e-08 -2.985444757051202e-08 -2.8180366398333776e-08 -2.9017406984422894e-08 -2.845937992703015e-08 -2.7901352869637404e-08 -2.7482832576592838e-08 -2.7761846105289214e-08 -2.7203819047896466e-08 -2.804085963398559e-08 -2.7622339340941025e-08 -2.8877900220074708e-08 -3.069148815660114e-08 -3.152852874269026e-08 -3.2644582857475756e-08 -3.278408962182394e-08 -3.3063103150520315e-08 -3.376063697226125e-08 -3.417915726530581e-08 -3.515570461574312e-08 -3.348162344356488e-08 -3.22260625644312e-08 -3.1389021978342073e-08 -3.083099492094933e-08 -2.943592727746746e-08 -2.8319873162681962e-08 -2.6227271697459155e-08 -2.6924805519200093e-08 -2.6645791990503717e-08 -2.6645791990503717e-08 -2.7901352869637404e-08 -2.9296420513119273e-08 -3.585323843748406e-08 -3.1668035507038446e-08 -4.464216459141985e-08 -4.771131340707996e-08 -4.910638105056182e-08 -4.9943421636650945e-08 -4.631624576359808e-08 -4.82693404644727e-08 -4.812983370012452e-08 -4.5897725470553524e-08 -4.003844136792967e-08 -3.22260625644312e-08 -2.9296420513119273e-08 -2.8180366398333776e-08 -2.6366778461807345e-08 -2.287910935310267e-08 -1.8414892893960685e-08 -2.985444757051202e-08 -2.7482832576592838e-08 -2.8180366398333776e-08 -2.7761846105289214e-08 -2.7343325812244652e-08 -2.7901352869637404e-08 -2.9714940806163832e-08 -3.627175873052862e-08 -3.1947049035734825e-08 -4.478167135576803e-08 -4.785082017142814e-08 -4.9245887814910014e-08 -5.0222435165347324e-08 -4.631624576359808e-08 -4.799032693577633e-08 -4.82693404644727e-08 -4.6595259292294455e-08 -4.115449548271517e-08 -3.3342116679216694e-08 -2.9714940806163832e-08 -2.9156913748771087e-08 -2.7622339340941025e-08 -2.4274176996584538e-08 -1.9391440244397992e-08 -3.152852874269026e-08 -2.9296420513119273e-08 -2.9714940806163832e-08 -2.8598886691378335e-08 -2.845937992703015e-08 -2.9017406984422894e-08 -3.013346109920839e-08 -3.6550772259225e-08 -3.2644582857475756e-08 -4.575821870620534e-08 -4.882736752186545e-08 -5.008292840099913e-08 -5.0919968987088255e-08 -4.7153286349687207e-08 -4.896687428621364e-08 -4.896687428621364e-08 -4.701377958533902e-08 -4.199153606880429e-08 -3.348162344356488e-08 -2.943592727746746e-08 -2.8319873162681962e-08 -2.706431228354828e-08 -2.3576643174843603e-08 -1.8693906422657058e-08 -3.013346109920839e-08 -2.7901352869637404e-08 -2.845937992703015e-08 -2.7622339340941025e-08 -2.8180366398333776e-08 -2.845937992703015e-08 -2.985444757051202e-08 -3.6411265494876805e-08 -3.1947049035734825e-08 -4.478167135576803e-08 -4.785082017142814e-08 -4.93853945792582e-08 -5.078046222274007e-08 -4.729279311403539e-08 -4.896687428621364e-08 -4.9524901343606386e-08 -4.729279311403539e-08 -4.1712522540107916e-08 -3.390014373660944e-08 -3.0551981392252956e-08 -2.943592727746746e-08 -2.804085963398559e-08 -2.5390231111370035e-08 -2.1344534945272613e-08 -3.4737184322698563e-08 -3.180754227138664e-08 -3.208655580008301e-08 -3.1389021978342073e-08 -3.180754227138664e-08 -3.292359638617213e-08 -3.376063697226125e-08 -4.031745489662604e-08 -3.417915726530581e-08 -4.673476605664265e-08 -4.910638105056182e-08 -5.0222435165347324e-08 -5.064095545839188e-08 -4.687427282099083e-08 -4.7153286349687207e-08 -4.631624576359808e-08 -4.227054959750066e-08 -3.724830608096593e-08 -3.180754227138664e-08 -2.7482832576592838e-08 -2.5948258168762783e-08 -2.455319052528091e-08 -2.1902562002665358e-08 -1.9391440244397992e-08 -3.2644582857475756e-08 -3.041247462790477e-08 -3.069148815660114e-08 -2.985444757051202e-08 -2.9575434041815645e-08 -2.9575434041815645e-08 -3.027296786355658e-08 -3.1389021978342073e-08 -3.54347181444395e-08 -4.157301577575972e-08 -4.533969841316077e-08 -4.840884722882089e-08 -4.9245887814910014e-08 -4.7571806642731765e-08 -4.5897725470553524e-08 -4.422364429837528e-08 -4.324709694793797e-08 -4.310759018358978e-08 -4.115449548271517e-08 -3.75273196096623e-08 -3.585323843748406e-08 -3.4039650500957626e-08 -3.3063103150520315e-08 -3.1668035507038446e-08 -3.0551981392252956e-08 -2.873839345572652e-08 -2.9156913748771087e-08 -2.8319873162681962e-08 -2.7761846105289214e-08 -2.7901352869637404e-08 -2.8319873162681962e-08 -2.804085963398559e-08 -2.873839345572652e-08 -2.845937992703015e-08 -2.9156913748771087e-08 -3.0970501685297515e-08 -3.22260625644312e-08 -3.278408962182394e-08 -3.3063103150520315e-08 -3.292359638617213e-08 -3.278408962182394e-08 -3.3342116679216694e-08 -3.459767755835038e-08 -3.390014373660944e-08 -3.3063103150520315e-08 -3.2365569328779384e-08 -3.1947049035734825e-08 -3.069148815660114e-08 -2.943592727746746e-08 -2.7343325812244652e-08 -2.804085963398559e-08 -2.7901352869637404e-08 -2.8598886691378335e-08 -2.9296420513119273e-08 -3.069148815660114e-08 -3.7387812845314116e-08 -3.250507609312757e-08 -4.575821870620534e-08 -4.896687428621364e-08 -5.036194192969551e-08 -5.119898251578463e-08 -4.771131340707996e-08 -4.9524901343606386e-08 -4.966440810795457e-08 -4.7432299878383586e-08 -4.115449548271517e-08 -3.208655580008301e-08 -2.845937992703015e-08 -2.706431228354828e-08 -2.5390231111370035e-08 -2.246058906005811e-08 -1.8972919951353434e-08 -3.1668035507038446e-08 -2.943592727746746e-08 -3.013346109920839e-08 -2.9296420513119273e-08 -2.9296420513119273e-08 -2.985444757051202e-08 -3.152852874269026e-08 -3.822485343140324e-08 -3.320260991486851e-08 -4.6455752527946275e-08 -4.93853945792582e-08 -5.078046222274007e-08 -5.175700957317738e-08 -4.82693404644727e-08 -4.9943421636650945e-08 -5.0222435165347324e-08 -4.868786075751727e-08 -4.29680834192416e-08 -3.4318664029654005e-08 -3.013346109920839e-08 -2.943592727746746e-08 -2.7901352869637404e-08 -2.4832204053977286e-08 -2.078650788787986e-08 -3.5016197851394936e-08 -3.2365569328779384e-08 -3.278408962182394e-08 -3.152852874269026e-08 -3.0970501685297515e-08 -3.1389021978342073e-08 -3.3063103150520315e-08 -4.003844136792967e-08 -3.417915726530581e-08 -4.840884722882089e-08 -5.0919968987088255e-08 -5.203602310187375e-08 -5.2873063687962876e-08 -4.910638105056182e-08 -5.0919968987088255e-08 -5.0501448694043697e-08 -4.840884722882089e-08 -4.29680834192416e-08 -3.376063697226125e-08 -2.9296420513119273e-08 -2.7901352869637404e-08 -2.650628522615553e-08 -2.3437136410495414e-08 -1.9809960537442554e-08 -3.22260625644312e-08 -3.041247462790477e-08 -3.083099492094933e-08 -3.0551981392252956e-08 -3.041247462790477e-08 -3.11100084496457e-08 -3.22260625644312e-08 -3.892238725314418e-08 -3.3342116679216694e-08 -4.701377958533902e-08 -5.008292840099913e-08 -5.105947575143644e-08 -5.217552986622194e-08 -4.882736752186545e-08 -5.0222435165347324e-08 -5.036194192969551e-08 -4.840884722882089e-08 -4.2689069890545226e-08 -3.4039650500957626e-08 -3.027296786355658e-08 -2.9017406984422894e-08 -2.7482832576592838e-08 -2.4971710818325472e-08 -2.1902562002665358e-08 -3.7387812845314116e-08 -3.54347181444395e-08 -3.6550772259225e-08 -3.557422490878769e-08 -3.54347181444395e-08 -3.613225196618043e-08 -3.710879931661774e-08 -4.3386603712286164e-08 -3.585323843748406e-08 -4.840884722882089e-08 -5.064095545839188e-08 -5.175700957317738e-08 -5.1896516337525566e-08 -4.799032693577633e-08 -4.840884722882089e-08 -4.729279311403539e-08 -4.3386603712286164e-08 -3.822485343140324e-08 -3.152852874269026e-08 -2.7203819047896466e-08 -2.5669244640066407e-08 -2.4274176996584538e-08 -2.2042068767013544e-08 -2.008897406613893e-08 -3.445817079400219e-08 -3.180754227138664e-08 -3.22260625644312e-08 -3.11100084496457e-08 -3.083099492094933e-08 -3.180754227138664e-08 -3.278408962182394e-08 -3.376063697226125e-08 -3.7806333138358674e-08 -4.3805124005330716e-08 -4.729279311403539e-08 -5.0222435165347324e-08 -5.0501448694043697e-08 -4.799032693577633e-08 -4.631624576359808e-08 -4.50606848844644e-08 -4.3805124005330716e-08 -4.324709694793797e-08 -4.157301577575972e-08 -3.822485343140324e-08 -3.6411265494876805e-08 -3.515570461574312e-08 -3.417915726530581e-08 -3.3063103150520315e-08 -3.1668035507038446e-08 -2.985444757051202e-08 -3.041247462790477e-08 -2.9575434041815645e-08 -2.9156913748771087e-08 -2.9575434041815645e-08 -2.9714940806163832e-08 -2.9714940806163832e-08 -3.041247462790477e-08 -3.0551981392252956e-08 -3.083099492094933e-08 -3.250507609312757e-08 -3.390014373660944e-08 -3.459767755835038e-08 -3.4737184322698563e-08 -3.417915726530581e-08 -3.390014373660944e-08 -3.5016197851394936e-08 -3.627175873052862e-08 -3.5992745201832246e-08 -3.5016197851394936e-08 -3.4318664029654005e-08 -3.376063697226125e-08 -3.2644582857475756e-08 -3.152852874269026e-08 -2.9575434041815645e-08 -3.0551981392252956e-08 -3.027296786355658e-08 -3.083099492094933e-08 -3.124951521399389e-08 -3.250507609312757e-08 -3.906189401749236e-08 -3.376063697226125e-08 -4.7571806642731765e-08 -4.9943421636650945e-08 -5.119898251578463e-08 -5.203602310187375e-08 -4.840884722882089e-08 -5.0222435165347324e-08 -5.0501448694043697e-08 -4.82693404644727e-08 -4.199153606880429e-08 -3.292359638617213e-08 -2.8598886691378335e-08 -2.7482832576592838e-08 -2.5808751404414597e-08 -2.2739602588754482e-08 -1.911242671570162e-08 -3.2644582857475756e-08 -3.027296786355658e-08 -3.0970501685297515e-08 -3.013346109920839e-08 -3.083099492094933e-08 -3.22260625644312e-08 -3.4737184322698563e-08 -4.199153606880429e-08 -3.5295211380091315e-08 -4.896687428621364e-08 -5.1896516337525566e-08 -5.343109074535562e-08 -5.48261583888375e-08 -5.147799604448101e-08 -5.315207721665925e-08 -5.2594050159266504e-08 -5.008292840099913e-08 -4.436315106272346e-08 -3.5295211380091315e-08 -3.027296786355658e-08 -2.9296420513119273e-08 -2.7761846105289214e-08 -2.4832204053977286e-08 -2.0926014652228048e-08 -3.54347181444395e-08 -3.250507609312757e-08 -3.3063103150520315e-08 -3.208655580008301e-08 -3.1668035507038446e-08 -3.2365569328779384e-08 -3.417915726530581e-08 -4.129400224706335e-08 -3.5016197851394936e-08 -4.966440810795457e-08 -5.2594050159266504e-08 -5.3989117802748366e-08 -5.4965665153185677e-08 -5.0501448694043697e-08 -5.203602310187375e-08 -5.175700957317738e-08 -4.93853945792582e-08 -4.394463076967891e-08 -3.5016197851394936e-08 -3.027296786355658e-08 -2.9017406984422894e-08 -2.7482832576592838e-08 -2.46926972896291e-08 -2.078650788787986e-08 -3.417915726530581e-08 -3.208655580008301e-08 -3.208655580008301e-08 -3.152852874269026e-08 -3.1668035507038446e-08 -3.208655580008301e-08 -3.320260991486851e-08 -4.017794813227786e-08 -3.4039650500957626e-08 -4.82693404644727e-08 -5.105947575143644e-08 -5.217552986622194e-08 -5.2873063687962876e-08 -4.980391487230276e-08 -5.119898251578463e-08 -5.1338489280132814e-08 -4.9245887814910014e-08 -4.3526110476634344e-08 -3.487669108704675e-08 -3.083099492094933e-08 -2.9017406984422894e-08 -2.7761846105289214e-08 -2.46926972896291e-08 -2.1205028180924427e-08 -3.627175873052862e-08 -3.459767755835038e-08 -3.54347181444395e-08 -3.417915726530581e-08 -3.390014373660944e-08 -3.4039650500957626e-08 -3.585323843748406e-08 -4.2410056361848854e-08 -3.4737184322698563e-08 -4.812983370012452e-08 -5.105947575143644e-08 -5.217552986622194e-08 -5.245454339491831e-08 -4.882736752186545e-08 -4.910638105056182e-08 -4.771131340707996e-08 -4.436315106272346e-08 -3.9340907546188736e-08 -3.250507609312757e-08 -2.8180366398333776e-08 -2.650628522615553e-08 -2.5111217582673662e-08 -2.3297629646147227e-08 -2.1344534945272613e-08 -3.6411265494876805e-08 -3.376063697226125e-08 -3.4039650500957626e-08 -3.2644582857475756e-08 -3.22260625644312e-08 -3.3063103150520315e-08 -3.362113020791307e-08 -3.459767755835038e-08 -3.7806333138358674e-08 -4.3526110476634344e-08 -4.6455752527946275e-08 -4.93853945792582e-08 -5.008292840099913e-08 -4.771131340707996e-08 -4.603723223490171e-08 -4.4502657827071654e-08 -4.310759018358978e-08 -4.29680834192416e-08 -4.1433509011411543e-08 -3.8782880488795985e-08 -3.724830608096593e-08 -3.6690279023573184e-08 -3.5713731673135874e-08 -3.445817079400219e-08 -3.362113020791307e-08 -3.152852874269026e-08 -3.180754227138664e-08 -3.0970501685297515e-08 -3.0970501685297515e-08 -3.1389021978342073e-08 -3.1389021978342073e-08 -3.152852874269026e-08 -3.1668035507038446e-08 -3.180754227138664e-08 -3.1947049035734825e-08 -3.376063697226125e-08 -3.515570461574312e-08 -3.5992745201832246e-08 -3.613225196618043e-08 -3.585323843748406e-08 -3.5713731673135874e-08 -3.6690279023573184e-08 -3.75273196096623e-08 -3.6411265494876805e-08 -3.557422490878769e-08 -3.4737184322698563e-08 -3.376063697226125e-08 -3.250507609312757e-08 -3.22260625644312e-08 -3.069148815660114e-08 -3.22260625644312e-08 -3.250507609312757e-08 -3.208655580008301e-08 -3.1947049035734825e-08 -3.320260991486851e-08 -3.9759427839233295e-08 -3.250507609312757e-08 -4.533969841316077e-08 -4.7571806642731765e-08 -4.910638105056182e-08 -4.9943421636650945e-08 -4.673476605664265e-08 -4.799032693577633e-08 -4.840884722882089e-08 -4.6595259292294455e-08 -4.115449548271517e-08 -3.2644582857475756e-08 -2.8319873162681962e-08 -2.7203819047896466e-08 -2.552973787571822e-08 -2.287910935310267e-08 -1.9809960537442554e-08 -3.362113020791307e-08 -3.180754227138664e-08 -3.278408962182394e-08 -3.208655580008301e-08 -3.22260625644312e-08 -3.348162344356488e-08 -3.5992745201832246e-08 -4.2549563126197034e-08 -3.445817079400219e-08 -4.771131340707996e-08 -5.105947575143644e-08 -5.273355692361469e-08 -5.3989117802748366e-08 -5.0919968987088255e-08 -5.203602310187375e-08 -5.105947575143644e-08 -4.812983370012452e-08 -4.310759018358978e-08 -3.417915726530581e-08 -2.9575434041815645e-08 -2.8319873162681962e-08 -2.706431228354828e-08 -2.455319052528091e-08 -2.106552141657624e-08 -3.5713731673135874e-08 -3.250507609312757e-08 -3.320260991486851e-08 -3.22260625644312e-08 -3.22260625644312e-08 -3.3063103150520315e-08 -3.417915726530581e-08 -4.087548195401879e-08 -3.445817079400219e-08 -4.840884722882089e-08 -5.161750280882919e-08 -5.315207721665925e-08 -5.3570597509703814e-08 -4.966440810795457e-08 -5.105947575143644e-08 -5.078046222274007e-08 -4.840884722882089e-08 -4.310759018358978e-08 -3.417915726530581e-08 -2.9575434041815645e-08 -2.845937992703015e-08 -2.7203819047896466e-08 -2.4274176996584538e-08 -2.050749435918349e-08 -3.417915726530581e-08 -3.152852874269026e-08 -3.152852874269026e-08 -3.041247462790477e-08 -3.11100084496457e-08 -3.1389021978342073e-08 -3.292359638617213e-08 -3.9759427839233295e-08 -3.3342116679216694e-08 -4.687427282099083e-08 -4.93853945792582e-08 -5.078046222274007e-08 -5.1338489280132814e-08 -4.82693404644727e-08 -4.9524901343606386e-08 -4.980391487230276e-08 -4.7432299878383586e-08 -4.1852029304456096e-08 -3.362113020791307e-08 -2.9714940806163832e-08 -2.8180366398333776e-08 -2.706431228354828e-08 -2.4413683760932724e-08 -2.106552141657624e-08 -3.5713731673135874e-08 -3.292359638617213e-08 -3.3063103150520315e-08 -3.180754227138664e-08 -3.1947049035734825e-08 -3.1947049035734825e-08 -3.376063697226125e-08 -3.920140078184055e-08 -3.0970501685297515e-08 -4.2689069890545226e-08 -4.575821870620534e-08 -4.6595259292294455e-08 -4.701377958533902e-08 -4.3805124005330716e-08 -4.310759018358978e-08 -4.1712522540107916e-08 -3.86433737244478e-08 -3.487669108704675e-08 -2.9993954334860204e-08 -2.650628522615553e-08 -2.4971710818325472e-08 -2.385565670353998e-08 -2.218157553136173e-08 -2.0647001123531675e-08 -3.54347181444395e-08 -3.376063697226125e-08 -3.390014373660944e-08 -3.278408962182394e-08 -3.292359638617213e-08 -3.3063103150520315e-08 -3.3342116679216694e-08 -3.390014373660944e-08 -3.6411265494876805e-08 -4.1852029304456096e-08 -4.4502657827071654e-08 -4.729279311403539e-08 -4.868786075751727e-08 -4.673476605664265e-08 -4.533969841316077e-08 -4.394463076967891e-08 -4.2549563126197034e-08 -4.2410056361848854e-08 -4.115449548271517e-08 -3.9340907546188736e-08 -3.822485343140324e-08 -3.7666826374010495e-08 -3.682978578792137e-08 -3.54347181444395e-08 -3.5016197851394936e-08 -3.445817079400219e-08 -3.459767755835038e-08 -3.362113020791307e-08 -3.390014373660944e-08 -3.4318664029654005e-08 -3.4318664029654005e-08 -3.4318664029654005e-08 -3.4039650500957626e-08 -3.417915726530581e-08 -3.390014373660944e-08 -3.54347181444395e-08 -3.696929255226956e-08 -3.8085346667055053e-08 -3.7666826374010495e-08 -3.75273196096623e-08 -3.75273196096623e-08 -3.822485343140324e-08 -3.948041431053692e-08 -3.794583990270687e-08 -3.7387812845314116e-08 -3.682978578792137e-08 -3.5713731673135874e-08 -3.417915726530581e-08 -3.4039650500957626e-08 -3.1389021978342073e-08 -3.278408962182394e-08 -3.278408962182394e-08 -3.278408962182394e-08 -3.2365569328779384e-08 -3.362113020791307e-08 -3.906189401749236e-08 -2.9017406984422894e-08 -3.8782880488795985e-08 -4.1433509011411543e-08 -4.2549563126197034e-08 -4.2828576654893406e-08 -4.0735975189670606e-08 -4.1433509011411543e-08 -4.157301577575972e-08 -4.031745489662604e-08 -3.613225196618043e-08 -2.9575434041815645e-08 -2.5948258168762783e-08 -2.4413683760932724e-08 -2.315812288179904e-08 -2.14840417096208e-08 -1.9670453773094368e-08 -3.4039650500957626e-08 -3.124951521399389e-08 -3.22260625644312e-08 -3.11100084496457e-08 -3.11100084496457e-08 -3.152852874269026e-08 -3.292359638617213e-08 -3.75273196096623e-08 -2.9156913748771087e-08 -3.961992107488511e-08 -4.310759018358978e-08 -4.492117812011622e-08 -4.520019164881259e-08 -4.29680834192416e-08 -4.3526110476634344e-08 -4.324709694793797e-08 -4.115449548271517e-08 -3.710879931661774e-08 -3.041247462790477e-08 -2.6645791990503717e-08 -2.5390231111370035e-08 -2.4413683760932724e-08 -2.287910935310267e-08 -2.078650788787986e-08 -3.557422490878769e-08 -3.124951521399389e-08 -3.22260625644312e-08 -3.11100084496457e-08 -3.11100084496457e-08 -3.152852874269026e-08 -3.292359638617213e-08 -3.75273196096623e-08 -2.9156913748771087e-08 -3.961992107488511e-08 -4.310759018358978e-08 -4.492117812011622e-08 -4.520019164881259e-08 -4.29680834192416e-08 -4.3526110476634344e-08 -4.324709694793797e-08 -4.115449548271517e-08 -3.710879931661774e-08 -3.041247462790477e-08 -2.6645791990503717e-08 -2.5390231111370035e-08 -2.4413683760932724e-08 -2.287910935310267e-08 -2.078650788787986e-08 -3.557422490878769e-08 -3.11100084496457e-08 -3.124951521399389e-08 -3.124951521399389e-08 -3.1389021978342073e-08 -3.0551981392252956e-08 -3.1389021978342073e-08 -3.320260991486851e-08 -3.920140078184055e-08 -4.840884722882089e-08 -5.203602310187375e-08 -5.3570597509703814e-08 -5.4965665153185677e-08 -5.3710104274051994e-08 -5.3291583981007435e-08 -5.4268131331444745e-08 -5.315207721665925e-08 -5.064095545839188e-08 -4.575821870620534e-08 -4.087548195401879e-08 -3.906189401749236e-08 -3.7387812845314116e-08 -3.5713731673135874e-08 -3.348162344356488e-08 -3.22260625644312e-08 -3.1389021978342073e-08 -3.278408962182394e-08 -3.1947049035734825e-08 -3.1389021978342073e-08 -3.11100084496457e-08 -3.152852874269026e-08 -3.4737184322698563e-08 -2.4832204053977286e-08 -3.2365569328779384e-08 -3.487669108704675e-08 -3.5713731673135874e-08 -3.585323843748406e-08 -3.390014373660944e-08 -3.3063103150520315e-08 -3.22260625644312e-08 -2.9993954334860204e-08 -2.804085963398559e-08 -2.5390231111370035e-08 -2.2739602588754482e-08 -2.1763055238317172e-08 -2.0926014652228048e-08 -1.9670453773094368e-08 -1.8414892893960685e-08 -3.2365569328779384e-08 -3.11100084496457e-08 -3.1389021978342073e-08 -3.124951521399389e-08 -3.152852874269026e-08 -3.2365569328779384e-08 -3.292359638617213e-08 -3.4039650500957626e-08 -3.6550772259225e-08 -3.9759427839233295e-08 -4.129400224706335e-08 -4.29680834192416e-08 -4.3386603712286164e-08 -4.1852029304456096e-08 -4.115449548271517e-08 -4.0735975189670606e-08 -3.989893460358149e-08 -3.961992107488511e-08 -3.906189401749236e-08 -3.6690279023573184e-08 -3.5992745201832246e-08 -3.487669108704675e-08 -3.348162344356488e-08 -3.2365569328779384e-08 -3.1947049035734825e-08 -2.9993954334860204e-08 -3.041247462790477e-08 -2.9714940806163832e-08 -2.943592727746746e-08 -2.8877900220074708e-08 -2.9296420513119273e-08 -2.9714940806163832e-08 -3.041247462790477e-08 -3.069148815660114e-08 -3.027296786355658e-08 -3.1668035507038446e-08 -3.250507609312757e-08 -3.3342116679216694e-08 -3.3063103150520315e-08 -3.376063697226125e-08 -3.3063103150520315e-08 -3.417915726530581e-08 -3.5295211380091315e-08 -3.390014373660944e-08 -3.362113020791307e-08 -3.2365569328779384e-08 -3.1389021978342073e-08 -3.0551981392252956e-08 -2.9714940806163832e-08 -2.7901352869637404e-08 -2.8877900220074708e-08 -2.8319873162681962e-08 -2.845937992703015e-08 -2.845937992703015e-08 -2.9993954334860204e-08 -3.292359638617213e-08 -2.2739602588754482e-08 -2.9156913748771087e-08 -3.1389021978342073e-08 -3.208655580008301e-08 -3.180754227138664e-08 -3.0970501685297515e-08 -3.11100084496457e-08 -3.0970501685297515e-08 -2.985444757051202e-08 -2.7622339340941025e-08 -2.3995163467888165e-08 -2.0926014652228048e-08 -1.9949467301790744e-08 -1.9391440244397992e-08 -1.8414892893960685e-08 -1.7019825250478813e-08 -2.943592727746746e-08 -2.873839345572652e-08 \ No newline at end of file diff --git a/examples/curve_examples/electric_vehicle_profile_5_curve.csv b/examples/curve_examples/electric_vehicle_profile_5_curve.csv deleted file mode 100644 index 7e359fa..0000000 --- a/examples/curve_examples/electric_vehicle_profile_5_curve.csv +++ /dev/null @@ -1,8760 +0,0 @@ -4.058029003214125e-08 -4.199957496152364e-08 -3.8220513109021064e-08 -2.9482090031937756e-08 -2.0295527943857224e-08 -1.2272828807132413e-08 -7.909041287429164e-09 -2.7023941130793784e-08 -5.623902150809556e-08 -6.116353752074473e-08 -4.788438885488115e-08 -4.177447817972987e-08 -3.70509795925161e-08 -4.020299199445773e-08 -3.430708351711257e-08 -3.320773351709241e-08 -3.342009207282629e-08 -2.01240138936186e-08 -3.3284738148177025e-08 -3.7428935087028526e-08 -3.84359945846922e-08 -3.5739353218865674e-08 -3.6394180220447543e-08 -3.901299513415333e-08 -4.3137221821827065e-08 -4.205693806984494e-08 -3.7772045369609385e-08 -3.055111483572502e-08 -2.059664317149226e-08 -1.2367913501011706e-08 -8.901061460131813e-09 -2.525332770846932e-08 -5.172262182198448e-08 -5.70589523558343e-08 -4.648310180618983e-08 -4.8967466798386086e-08 -4.7003478886262174e-08 -4.489665847806027e-08 -4.6052878493780057e-08 -4.4395429828129577e-08 -3.9255103611394826e-08 -2.356234874454507e-08 -3.4071138697641997e-08 -3.6228501099565384e-08 -3.5698755259681256e-08 -3.355322708067803e-08 -3.125812747310062e-08 -3.29047281010743e-08 -3.9551534459123965e-08 -4.324603092700959e-08 -4.066715651565933e-08 -3.5057981397817076e-08 -2.6684282496564638e-08 -1.8025411695777923e-08 -1.1288615934272923e-08 -2.2971377237469868e-08 -4.531348610758126e-08 -4.75251708799923e-08 -3.7950462716551433e-08 -4.585966836818782e-08 -5.327356248135359e-08 -5.363993029925671e-08 -4.869256766180334e-08 -4.633155800712897e-08 -3.908005573070087e-08 -2.822133438042327e-08 -2.6735892857633082e-08 -2.5060281947084308e-08 -2.5567509890578696e-08 -2.4324341209237218e-08 -2.3789417896825527e-08 -2.668937778698859e-08 -3.114709945112056e-08 -3.1219912794920955e-08 -3.0739394035100524e-08 -2.6577856672386862e-08 -2.163542496115024e-08 -1.518355455286867e-08 -1.0374175667380174e-08 -2.780919113080818e-08 -5.895653712823958e-08 -6.21563795144835e-08 -4.7528375982033175e-08 -3.9731348901827415e-08 -4.7043994663342966e-08 -4.2682426060437265e-08 -4.05751947417173e-08 -3.943450714358022e-08 -3.751366483585268e-08 -2.3015591209213225e-08 -2.769890274776063e-08 -2.9947651648900766e-08 -3.1863152119893504e-08 -3.061965471013758e-08 -2.9692065306666882e-08 -2.995233602880666e-08 -3.151248108378032e-08 -2.993474905863365e-08 -2.7434522920440244e-08 -2.1560146154241483e-08 -1.4356145133701225e-08 -8.812386970334268e-09 -6.837222292119088e-09 -2.6956962716349854e-08 -5.889276381583652e-08 -6.76377614612088e-08 -5.616719434953852e-08 -4.510145628026183e-08 -4.4312014992963216e-08 -3.50095761387895e-08 -3.052974748878585e-08 -3.835192229269694e-08 -3.675915094258924e-08 -2.383404277908694e-08 -3.586032527538281e-08 -4.2238396154620635e-08 -4.198272763028314e-08 -3.921902566790907e-08 -3.7451535165521875e-08 -3.981164081705652e-08 -3.619875117805777e-08 -3.5683551570513e-08 -3.338015157047077e-08 -2.60633967037746e-08 -1.717556656232435e-08 -1.0051693092805972e-08 -6.039316248148413e-09 -7.532811617092595e-09 -2.2363969309672232e-08 -3.0926276138714626e-08 -2.8049327237562983e-08 -1.931599945090363e-08 -2.227126789679769e-08 -2.6531095055431525e-08 -2.6586814521680586e-08 -2.9027294270547942e-08 -3.035749379961472e-08 -2.0306869074155705e-08 -2.9707515542145974e-08 -3.5981050785589104e-08 -3.72628450556283e-08 -3.3846699372677125e-08 -3.481521546374669e-08 -3.7008902355466666e-08 -4.163164568365189e-08 -4.1501387049426586e-08 -3.647866342296087e-08 -2.823842825797461e-08 -2.0044132888907563e-08 -1.2029980690958416e-08 -5.6040798274182976e-09 -8.240810439711543e-09 -2.3401354003568804e-08 -2.9870729199919766e-08 -2.69640303772605e-08 -2.38378231558531e-08 -2.3706003061659163e-08 -2.568108555777073e-08 -2.4868140188839024e-08 -3.137079913715292e-08 -3.2018969388342203e-08 -1.7453917347258807e-08 -3.014990180589035e-08 -3.440274348571715e-08 -3.507121271649864e-08 -3.248535282634133e-08 -3.372835714347558e-08 -3.622652872907869e-08 -4.058029003214125e-08 -4.199957496152364e-08 -3.8220513109021064e-08 -2.9482090031937756e-08 -2.0295527943857224e-08 -1.2272828807132413e-08 -7.909041287429164e-09 -2.7023941130793784e-08 -5.623902150809556e-08 -6.116353752074473e-08 -4.788438885488115e-08 -4.177447817972987e-08 -3.70509795925161e-08 -4.020299199445773e-08 -3.430708351711257e-08 -3.320773351709241e-08 -3.342009207282629e-08 -2.01240138936186e-08 -3.3284738148177025e-08 -3.7428935087028526e-08 -3.84359945846922e-08 -3.5739353218865674e-08 -3.6394180220447543e-08 -3.901299513415333e-08 -4.3137221821827065e-08 -4.205693806984494e-08 -3.7772045369609385e-08 -3.055111483572502e-08 -2.059664317149226e-08 -1.2367913501011706e-08 -8.901061460131813e-09 -2.525332770846932e-08 -5.172262182198448e-08 -5.70589523558343e-08 -4.648310180618983e-08 -4.8967466798386086e-08 -4.7003478886262174e-08 -4.489665847806027e-08 -4.6052878493780057e-08 -4.4395429828129577e-08 -3.9255103611394826e-08 -2.356234874454507e-08 -3.4071138697641997e-08 -3.6228501099565384e-08 -3.5698755259681256e-08 -3.355322708067803e-08 -3.125812747310062e-08 -3.29047281010743e-08 -3.9551534459123965e-08 -4.324603092700959e-08 -4.066715651565933e-08 -3.5057981397817076e-08 -2.6684282496564638e-08 -1.8025411695777923e-08 -1.1288615934272923e-08 -2.2971377237469868e-08 -4.531348610758126e-08 -4.75251708799923e-08 -3.7950462716551433e-08 -4.585966836818782e-08 -5.327356248135359e-08 -5.363993029925671e-08 -4.869256766180334e-08 -4.633155800712897e-08 -3.908005573070087e-08 -2.822133438042327e-08 -2.6735892857633082e-08 -2.5060281947084308e-08 -2.5567509890578696e-08 -2.4324341209237218e-08 -2.3789417896825527e-08 -2.668937778698859e-08 -3.114709945112056e-08 -3.1219912794920955e-08 -3.0739394035100524e-08 -2.6577856672386862e-08 -2.163542496115024e-08 -1.518355455286867e-08 -1.0374175667380174e-08 -2.780919113080818e-08 -5.895653712823958e-08 -6.21563795144835e-08 -4.7528375982033175e-08 -3.9731348901827415e-08 -4.7043994663342966e-08 -4.2682426060437265e-08 -4.05751947417173e-08 -3.943450714358022e-08 -3.751366483585268e-08 -2.3015591209213225e-08 -2.769890274776063e-08 -2.9947651648900766e-08 -3.1863152119893504e-08 -3.061965471013758e-08 -2.9692065306666882e-08 -2.995233602880666e-08 -3.151248108378032e-08 -2.993474905863365e-08 -2.7434522920440244e-08 -2.1560146154241483e-08 -1.4356145133701225e-08 -8.812386970334268e-09 -6.837222292119088e-09 -2.6956962716349854e-08 -5.889276381583652e-08 -6.76377614612088e-08 -5.616719434953852e-08 -4.510145628026183e-08 -4.4312014992963216e-08 -3.50095761387895e-08 -3.052974748878585e-08 -3.835192229269694e-08 -3.675915094258924e-08 -2.383404277908694e-08 -3.586032527538281e-08 -4.2238396154620635e-08 -4.198272763028314e-08 -3.921902566790907e-08 -3.7451535165521875e-08 -3.981164081705652e-08 -3.619875117805777e-08 -3.5683551570513e-08 -3.338015157047077e-08 -2.60633967037746e-08 -1.717556656232435e-08 -1.0051693092805972e-08 -6.039316248148413e-09 -7.532811617092595e-09 -2.2363969309672232e-08 -3.0926276138714626e-08 -2.8049327237562983e-08 -1.931599945090363e-08 -2.227126789679769e-08 -2.6531095055431525e-08 -2.6586814521680586e-08 -2.9027294270547942e-08 -3.035749379961472e-08 -2.0306869074155705e-08 -2.9707515542145974e-08 -3.5981050785589104e-08 -3.72628450556283e-08 -3.3846699372677125e-08 -3.481521546374669e-08 -3.7008902355466666e-08 -4.163164568365189e-08 -4.1501387049426586e-08 -3.647866342296087e-08 -2.823842825797461e-08 -2.0044132888907563e-08 -1.2029980690958416e-08 -5.6040798274182976e-09 -8.240810439711543e-09 -2.3401354003568804e-08 -2.9870729199919766e-08 -2.69640303772605e-08 -2.38378231558531e-08 -2.3706003061659163e-08 -2.568108555777073e-08 -2.4868140188839024e-08 -3.137079913715292e-08 -3.2018969388342203e-08 -1.7453917347258807e-08 -3.014990180589035e-08 -3.440274348571715e-08 -3.507121271649864e-08 -3.248535282634133e-08 -3.372835714347558e-08 -3.622652872907869e-08 -4.058029003214125e-08 -4.199957496152364e-08 -3.8220513109021064e-08 -2.9482090031937756e-08 -2.0295527943857224e-08 -1.2272828807132413e-08 -7.909041287429164e-09 -2.7023941130793784e-08 -5.623902150809556e-08 -6.116353752074473e-08 -4.788438885488115e-08 -4.177447817972987e-08 -3.70509795925161e-08 -4.020299199445773e-08 -3.430708351711257e-08 -3.320773351709241e-08 -3.342009207282629e-08 -2.01240138936186e-08 -3.3284738148177025e-08 -3.7428935087028526e-08 -3.84359945846922e-08 -3.5739353218865674e-08 -3.6394180220447543e-08 -3.901299513415333e-08 -4.3137221821827065e-08 -4.205693806984494e-08 -3.7772045369609385e-08 -3.055111483572502e-08 -2.059664317149226e-08 -1.2367913501011706e-08 -8.901061460131813e-09 -2.525332770846932e-08 -5.172262182198448e-08 -5.70589523558343e-08 -4.648310180618983e-08 -4.8967466798386086e-08 -4.7003478886262174e-08 -4.489665847806027e-08 -4.6052878493780057e-08 -4.4395429828129577e-08 -3.9255103611394826e-08 -2.356234874454507e-08 -3.4071138697641997e-08 -3.6228501099565384e-08 -3.5698755259681256e-08 -3.355322708067803e-08 -3.125812747310062e-08 -3.29047281010743e-08 -3.9551534459123965e-08 -4.324603092700959e-08 -4.066715651565933e-08 -3.5057981397817076e-08 -2.6684282496564638e-08 -1.8025411695777923e-08 -1.1288615934272923e-08 -2.2971377237469868e-08 -4.531348610758126e-08 -4.75251708799923e-08 -3.7950462716551433e-08 -4.585966836818782e-08 -5.327356248135359e-08 -5.363993029925671e-08 -4.869256766180334e-08 -4.633155800712897e-08 -3.908005573070087e-08 -2.822133438042327e-08 -2.6735892857633082e-08 -2.5060281947084308e-08 -2.5567509890578696e-08 -2.4324341209237218e-08 -2.3789417896825527e-08 -2.668937778698859e-08 -3.114709945112056e-08 -3.1219912794920955e-08 -3.0739394035100524e-08 -2.6577856672386862e-08 -2.163542496115024e-08 -1.518355455286867e-08 -1.0374175667380174e-08 -2.780919113080818e-08 -5.895653712823958e-08 -6.21563795144835e-08 -4.7528375982033175e-08 -3.9731348901827415e-08 -4.7043994663342966e-08 -4.2682426060437265e-08 -4.05751947417173e-08 -3.943450714358022e-08 -3.751366483585268e-08 -2.3015591209213225e-08 -2.769890274776063e-08 -2.9947651648900766e-08 -3.1863152119893504e-08 -3.061965471013758e-08 -2.9692065306666882e-08 -2.995233602880666e-08 -3.151248108378032e-08 -2.993474905863365e-08 -2.7434522920440244e-08 -2.1560146154241483e-08 -1.4356145133701225e-08 -8.812386970334268e-09 -6.837222292119088e-09 -2.6956962716349854e-08 -5.889276381583652e-08 -6.76377614612088e-08 -5.616719434953852e-08 -4.510145628026183e-08 -4.4312014992963216e-08 -3.50095761387895e-08 -3.052974748878585e-08 -3.835192229269694e-08 -3.675915094258924e-08 -2.383404277908694e-08 -3.586032527538281e-08 -4.2238396154620635e-08 -4.198272763028314e-08 -3.921902566790907e-08 -3.7451535165521875e-08 -3.981164081705652e-08 -3.619875117805777e-08 -3.5683551570513e-08 -3.338015157047077e-08 -2.60633967037746e-08 -1.717556656232435e-08 -1.0051693092805972e-08 -6.039316248148413e-09 -7.532811617092595e-09 -2.2363969309672232e-08 -3.0926276138714626e-08 -2.8049327237562983e-08 -1.931599945090363e-08 -2.227126789679769e-08 -2.6531095055431525e-08 -2.6586814521680586e-08 -2.9027294270547942e-08 -3.035749379961472e-08 -2.0306869074155705e-08 -2.9707515542145974e-08 -3.5981050785589104e-08 -3.72628450556283e-08 -3.3846699372677125e-08 -3.481521546374669e-08 -3.7008902355466666e-08 -4.163164568365189e-08 -4.1501387049426586e-08 -3.647866342296087e-08 -2.823842825797461e-08 -2.0044132888907563e-08 -1.2029980690958416e-08 -5.6040798274182976e-09 -8.240810439711543e-09 -2.3401354003568804e-08 -2.9870729199919766e-08 -2.69640303772605e-08 -2.38378231558531e-08 -2.3706003061659163e-08 -2.568108555777073e-08 -2.4868140188839024e-08 -3.137079913715292e-08 -3.2018969388342203e-08 -1.7453917347258807e-08 -3.014990180589035e-08 -3.440274348571715e-08 -3.507121271649864e-08 -3.248535282634133e-08 -3.372835714347558e-08 -3.622652872907869e-08 -4.058029003214125e-08 -4.199957496152364e-08 -3.8220513109021064e-08 -2.9482090031937756e-08 -2.0295527943857224e-08 -1.2272828807132413e-08 -7.909041287429164e-09 -2.7023941130793784e-08 -5.623902150809556e-08 -6.116353752074473e-08 -4.788438885488115e-08 -4.177447817972987e-08 -3.70509795925161e-08 -4.020299199445773e-08 -3.430708351711257e-08 -3.320773351709241e-08 -3.342009207282629e-08 -2.01240138936186e-08 -3.3284738148177025e-08 -3.7428935087028526e-08 -3.84359945846922e-08 -3.5739353218865674e-08 -3.6394180220447543e-08 -3.901299513415333e-08 -4.3137221821827065e-08 -4.205693806984494e-08 -3.7772045369609385e-08 -3.055111483572502e-08 -2.059664317149226e-08 -1.2367913501011706e-08 -8.901061460131813e-09 -2.525332770846932e-08 -5.172262182198448e-08 -5.70589523558343e-08 -4.648310180618983e-08 -4.8967466798386086e-08 -4.7003478886262174e-08 -4.489665847806027e-08 -4.6052878493780057e-08 -4.4395429828129577e-08 -3.9255103611394826e-08 -2.356234874454507e-08 -3.4071138697641997e-08 -3.6228501099565384e-08 -3.5698755259681256e-08 -3.355322708067803e-08 -3.125812747310062e-08 -3.29047281010743e-08 -3.9551534459123965e-08 -4.324603092700959e-08 -4.066715651565933e-08 -3.5057981397817076e-08 -2.6684282496564638e-08 -1.8025411695777923e-08 -1.1288615934272923e-08 -2.2971377237469868e-08 -4.531348610758126e-08 -4.75251708799923e-08 -3.7950462716551433e-08 -4.585966836818782e-08 -5.327356248135359e-08 -5.363993029925671e-08 -4.869256766180334e-08 -4.633155800712897e-08 -3.908005573070087e-08 -2.822133438042327e-08 -2.6735892857633082e-08 -2.5060281947084308e-08 -2.5567509890578696e-08 -2.4324341209237218e-08 -2.3789417896825527e-08 -2.668937778698859e-08 -3.114709945112056e-08 -3.1219912794920955e-08 -3.0739394035100524e-08 -2.6577856672386862e-08 -2.163542496115024e-08 -1.518355455286867e-08 -1.0374175667380174e-08 -2.780919113080818e-08 -5.895653712823958e-08 -6.21563795144835e-08 -4.7528375982033175e-08 -3.9731348901827415e-08 -4.7043994663342966e-08 -4.2682426060437265e-08 -4.05751947417173e-08 -3.943450714358022e-08 -3.751366483585268e-08 -2.3015591209213225e-08 -2.769890274776063e-08 -2.9947651648900766e-08 -3.1863152119893504e-08 -3.061965471013758e-08 -2.9692065306666882e-08 -2.995233602880666e-08 -3.151248108378032e-08 -2.993474905863365e-08 -2.7434522920440244e-08 -2.1560146154241483e-08 -1.4356145133701225e-08 -8.812386970334268e-09 -6.837222292119088e-09 -2.6956962716349854e-08 -5.889276381583652e-08 -6.76377614612088e-08 -5.616719434953852e-08 -4.510145628026183e-08 -4.4312014992963216e-08 -3.50095761387895e-08 -3.052974748878585e-08 -3.835192229269694e-08 -3.675915094258924e-08 -2.383404277908694e-08 -3.586032527538281e-08 -4.2238396154620635e-08 -4.198272763028314e-08 -3.921902566790907e-08 -3.7451535165521875e-08 -3.981164081705652e-08 -3.619875117805777e-08 -3.5683551570513e-08 -3.338015157047077e-08 -2.60633967037746e-08 -1.717556656232435e-08 -1.0051693092805972e-08 -6.039316248148413e-09 -7.532811617092595e-09 -2.2363969309672232e-08 -3.0926276138714626e-08 -2.8049327237562983e-08 -1.931599945090363e-08 -2.227126789679769e-08 -2.6531095055431525e-08 -2.6586814521680586e-08 -2.9027294270547942e-08 -3.035749379961472e-08 -2.0306869074155705e-08 -2.9707515542145974e-08 -3.5981050785589104e-08 -3.72628450556283e-08 -3.3846699372677125e-08 -3.481521546374669e-08 -3.7008902355466666e-08 -4.163164568365189e-08 -4.1501387049426586e-08 -3.647866342296087e-08 -2.823842825797461e-08 -2.0044132888907563e-08 -1.2029980690958416e-08 -5.6040798274182976e-09 -8.240810439711543e-09 -2.3401354003568804e-08 -2.9870729199919766e-08 -2.69640303772605e-08 -2.38378231558531e-08 -2.3706003061659163e-08 -2.568108555777073e-08 -2.4868140188839024e-08 -3.137079913715292e-08 -3.2018969388342203e-08 -1.7453917347258807e-08 -3.014990180589035e-08 -3.440274348571715e-08 -3.507121271649864e-08 -3.248535282634133e-08 -3.372835714347558e-08 -3.622652872907869e-08 -4.058029003214125e-08 -4.199957496152364e-08 -3.8220513109021064e-08 -2.9482090031937756e-08 -2.0295527943857224e-08 -1.2272828807132413e-08 -7.909041287429164e-09 -2.7023941130793784e-08 -5.623902150809556e-08 -6.116353752074473e-08 -4.788438885488115e-08 -4.177447817972987e-08 -3.70509795925161e-08 -4.020299199445773e-08 -3.430708351711257e-08 -3.320773351709241e-08 -3.342009207282629e-08 -2.01240138936186e-08 -3.3284738148177025e-08 -3.7428935087028526e-08 -3.84359945846922e-08 -3.5739353218865674e-08 -3.6394180220447543e-08 -3.901299513415333e-08 -4.3137221821827065e-08 -4.205693806984494e-08 -3.7772045369609385e-08 -3.055111483572502e-08 -2.059664317149226e-08 -1.2367913501011706e-08 -8.901061460131813e-09 -2.525332770846932e-08 -5.172262182198448e-08 -5.70589523558343e-08 -4.648310180618983e-08 -4.8967466798386086e-08 -4.7003478886262174e-08 -4.489665847806027e-08 -4.6052878493780057e-08 -4.4395429828129577e-08 -3.9255103611394826e-08 -2.356234874454507e-08 -3.4071138697641997e-08 -3.6228501099565384e-08 -3.5698755259681256e-08 -3.355322708067803e-08 -3.125812747310062e-08 -3.29047281010743e-08 -3.9551534459123965e-08 -4.324603092700959e-08 -4.066715651565933e-08 -3.5057981397817076e-08 -2.6684282496564638e-08 -1.8025411695777923e-08 -1.1288615934272923e-08 -2.2971377237469868e-08 -4.531348610758126e-08 -4.75251708799923e-08 -3.7950462716551433e-08 -4.585966836818782e-08 -5.327356248135359e-08 -5.363993029925671e-08 -4.869256766180334e-08 -4.633155800712897e-08 -3.908005573070087e-08 -2.822133438042327e-08 -2.6735892857633082e-08 -2.5060281947084308e-08 -2.5567509890578696e-08 -2.4324341209237218e-08 -2.3789417896825527e-08 -2.668937778698859e-08 -3.179732425490015e-08 -3.244039921566547e-08 -2.9594926060197282e-08 -2.5057405573457883e-08 -1.835561938809167e-08 -1.1413861460177887e-08 -1.0439510439751859e-08 -2.837501491417806e-08 -5.8732262167481936e-08 -6.109614819578273e-08 -5.122451609199106e-08 -4.024893179037693e-08 -4.422654560520654e-08 -4.245330235556649e-08 -4.453883759893283e-08 -3.766570172753522e-08 -3.298888257517317e-08 -1.915212833630094e-08 -2.8105621978537322e-08 -3.0956601334947525e-08 -3.373871208853072e-08 -3.3351387834206506e-08 -3.291598704926917e-08 -3.431415117802322e-08 -3.673885196299703e-08 -3.5738202669415105e-08 -3.249381758301339e-08 -2.4307986970618393e-08 -1.6429681789940187e-08 -9.08819011005675e-09 -5.998389560549547e-09 -2.82694109110364e-08 -6.439600620212268e-08 -7.025090580976536e-08 -5.041288563671715e-08 -4.1202655102796297e-08 -3.8288066798190274e-08 -4.2693931554942966e-08 -3.8359976138850934e-08 -4.215629623311207e-08 -3.579334686093888e-08 -2.32319766880241e-08 -3.4677560440196286e-08 -4.267313948272908e-08 -4.4177071978832014e-08 -4.041452872915548e-08 -3.828699843084332e-08 -4.076791177468786e-08 -4.5038258242584054e-08 -4.545237386268585e-08 -4.0976654317862804e-08 -3.224842182162741e-08 -2.286182849335483e-08 -1.3757366326782865e-08 -8.07685714300524e-09 -1.1919117033185581e-08 -2.7020489482442074e-08 -4.084623131943027e-08 -3.135115761438961e-08 -2.8929004474627774e-08 -2.7424743250110393e-08 -2.8382164757192317e-08 -2.9136514286248533e-08 -2.658763634271671e-08 -3.088329489852546e-08 -1.9860620251541557e-08 -3.22031394825371e-08 -3.976126318754225e-08 -3.880080094262668e-08 -3.639196130365001e-08 -3.83658110682074e-08 -4.166821671975931e-08 -4.626449741058142e-08 -4.672340227715185e-08 -4.292026106829091e-08 -3.3708140345986984e-08 -2.2013462637766273e-08 -1.2531702433510784e-08 -6.406670251294867e-09 -1.111948516503905e-08 -2.787510117790515e-08 -4.0639132418327576e-08 -3.404862080125225e-08 -2.7822668995800577e-08 -2.524954733170316e-08 -2.5566934615853412e-08 -2.6131361303461875e-08 -3.2636732261194974e-08 -3.6672695369589227e-08 -1.9600431711505388e-08 -3.141402692365293e-08 -3.863734073854205e-08 -3.93150965470317e-08 -3.854496805408196e-08 -3.995282967106224e-08 -4.449988328182066e-08 -5.040779034629319e-08 -5.090745753625525e-08 -4.6148949372902694e-08 -3.6968386578385855e-08 -2.4450572920385528e-08 -1.2553645055175237e-08 -9.292001727014961e-09 -2.992727048720495e-08 -6.589024120999936e-08 -6.97830430939012e-08 -5.239963799154164e-08 -4.500908359580174e-08 -4.229863563656836e-08 -4.218949780297138e-08 -4.255898854081177e-08 -4.1685557143621485e-08 -3.5609341130951205e-08 -2.346726405066577e-08 -3.3146507849901336e-08 -4.0237261931664005e-08 -4.3966028336755915e-08 -4.0468111460710625e-08 -3.9027952277010745e-08 -4.1176849922262086e-08 -5.138320973406618e-08 -5.478390518153827e-08 -5.0980928336884546e-08 -4.297959654709891e-08 -3.210131585616161e-08 -2.150286522802379e-08 -1.4277825588958814e-08 -2.942094654685029e-08 -5.5085595683898585e-08 -6.038576609215903e-08 -4.975575753623414e-08 -5.006558406685207e-08 -5.4034979671320446e-08 -5.425383061323969e-08 -5.4351956044952636e-08 -5.07532839098788e-08 -4.3332650864216826e-08 -2.4149704239061334e-08 -3.6544655652161444e-08 -4.182608854079831e-08 -3.9772439953633504e-08 -3.739565133506559e-08 -3.6222994898623366e-08 -3.900140745754402e-08 -4.618404113114511e-08 -5.0264793486007994e-08 -4.6846100157844835e-08 -3.808483045595735e-08 -2.848176946677028e-08 -1.6809280926524854e-08 -1.0566481789832678e-08 -2.4368472998876962e-08 -4.6795722528330575e-08 -4.502330109972665e-08 -4.0002467661643994e-08 -4.6800489090340077e-08 -4.8995983988339525e-08 -5.44245228424422e-08 -4.995233712807447e-08 -4.741595086429171e-08 -4.589434921591216e-08 -2.500300102086662e-08 -2.672964701775856e-08 -2.7953913815269234e-08 -2.5208374097793464e-08 -2.5087977316001614e-08 -2.4755879435304785e-08 -2.711688908997916e-08 -3.179732425490015e-08 -3.244039921566547e-08 -2.9594926060197282e-08 -2.5057405573457883e-08 -1.835561938809167e-08 -1.1413861460177887e-08 -1.0439510439751859e-08 -2.837501491417806e-08 -5.8732262167481936e-08 -6.109614819578273e-08 -5.122451609199106e-08 -4.024893179037693e-08 -4.422654560520654e-08 -4.245330235556649e-08 -4.453883759893283e-08 -3.766570172753522e-08 -3.298888257517317e-08 -1.915212833630094e-08 -2.8105621978537322e-08 -3.0956601334947525e-08 -3.373871208853072e-08 -3.3351387834206506e-08 -3.291598704926917e-08 -3.431415117802322e-08 -3.673885196299703e-08 -3.5738202669415105e-08 -3.249381758301339e-08 -2.4307986970618393e-08 -1.6429681789940187e-08 -9.08819011005675e-09 -5.998389560549547e-09 -2.82694109110364e-08 -6.439600620212268e-08 -7.025090580976536e-08 -5.041288563671715e-08 -4.1202655102796297e-08 -3.8288066798190274e-08 -4.2693931554942966e-08 -3.8359976138850934e-08 -4.215629623311207e-08 -3.579334686093888e-08 -2.32319766880241e-08 -3.4677560440196286e-08 -4.267313948272908e-08 -4.4177071978832014e-08 -4.041452872915548e-08 -3.828699843084332e-08 -4.076791177468786e-08 -4.5038258242584054e-08 -4.545237386268585e-08 -4.0976654317862804e-08 -3.224842182162741e-08 -2.286182849335483e-08 -1.3757366326782865e-08 -8.07685714300524e-09 -1.1919117033185581e-08 -2.7020489482442074e-08 -4.084623131943027e-08 -3.135115761438961e-08 -2.8929004474627774e-08 -2.7424743250110393e-08 -2.8382164757192317e-08 -2.9136514286248533e-08 -2.658763634271671e-08 -3.088329489852546e-08 -1.9860620251541557e-08 -3.22031394825371e-08 -3.976126318754225e-08 -3.880080094262668e-08 -3.639196130365001e-08 -3.83658110682074e-08 -4.166821671975931e-08 -4.626449741058142e-08 -4.672340227715185e-08 -4.292026106829091e-08 -3.3708140345986984e-08 -2.2013462637766273e-08 -1.2531702433510784e-08 -6.406670251294867e-09 -1.111948516503905e-08 -2.787510117790515e-08 -4.0639132418327576e-08 -3.404862080125225e-08 -2.7822668995800577e-08 -2.524954733170316e-08 -2.5566934615853412e-08 -2.6131361303461875e-08 -3.2636732261194974e-08 -3.6672695369589227e-08 -1.9600431711505388e-08 -3.141402692365293e-08 -3.863734073854205e-08 -3.93150965470317e-08 -3.854496805408196e-08 -3.995282967106224e-08 -4.449988328182066e-08 -5.040779034629319e-08 -5.090745753625525e-08 -4.6148949372902694e-08 -3.6968386578385855e-08 -2.4450572920385528e-08 -1.2553645055175237e-08 -9.292001727014961e-09 -2.992727048720495e-08 -6.589024120999936e-08 -6.97830430939012e-08 -5.239963799154164e-08 -4.500908359580174e-08 -4.229863563656836e-08 -4.218949780297138e-08 -4.255898854081177e-08 -4.1685557143621485e-08 -3.5609341130951205e-08 -2.346726405066577e-08 -3.3146507849901336e-08 -4.0237261931664005e-08 -4.3966028336755915e-08 -4.0468111460710625e-08 -3.9027952277010745e-08 -4.1176849922262086e-08 -5.138320973406618e-08 -5.478390518153827e-08 -5.0980928336884546e-08 -4.297959654709891e-08 -3.210131585616161e-08 -2.150286522802379e-08 -1.4277825588958814e-08 -2.942094654685029e-08 -5.5085595683898585e-08 -6.038576609215903e-08 -4.975575753623414e-08 -5.006558406685207e-08 -5.4034979671320446e-08 -5.425383061323969e-08 -5.4351956044952636e-08 -5.07532839098788e-08 -4.3332650864216826e-08 -2.4149704239061334e-08 -3.6544655652161444e-08 -4.182608854079831e-08 -3.9772439953633504e-08 -3.739565133506559e-08 -3.6222994898623366e-08 -3.900140745754402e-08 -4.618404113114511e-08 -5.0264793486007994e-08 -4.6846100157844835e-08 -3.808483045595735e-08 -2.848176946677028e-08 -1.6809280926524854e-08 -1.0566481789832678e-08 -2.4368472998876962e-08 -4.6795722528330575e-08 -4.502330109972665e-08 -4.0002467661643994e-08 -4.6800489090340077e-08 -4.8995983988339525e-08 -5.44245228424422e-08 -4.995233712807447e-08 -4.741595086429171e-08 -4.589434921591216e-08 -2.500300102086662e-08 -2.672964701775856e-08 -2.7953913815269234e-08 -2.5208374097793464e-08 -2.5087977316001614e-08 -2.4755879435304785e-08 -2.711688908997916e-08 -3.179732425490015e-08 -3.244039921566547e-08 -2.9594926060197282e-08 -2.5057405573457883e-08 -1.835561938809167e-08 -1.1413861460177887e-08 -1.0439510439751859e-08 -2.837501491417806e-08 -5.8732262167481936e-08 -6.109614819578273e-08 -5.122451609199106e-08 -4.024893179037693e-08 -4.422654560520654e-08 -4.245330235556649e-08 -4.453883759893283e-08 -3.766570172753522e-08 -3.298888257517317e-08 -1.915212833630094e-08 -2.8105621978537322e-08 -3.0956601334947525e-08 -3.373871208853072e-08 -3.3351387834206506e-08 -3.291598704926917e-08 -3.431415117802322e-08 -3.673885196299703e-08 -3.5738202669415105e-08 -3.249381758301339e-08 -2.4307986970618393e-08 -1.6429681789940187e-08 -9.08819011005675e-09 -5.998389560549547e-09 -2.82694109110364e-08 -6.439600620212268e-08 -7.025090580976536e-08 -5.041288563671715e-08 -4.1202655102796297e-08 -3.8288066798190274e-08 -4.2693931554942966e-08 -3.8359976138850934e-08 -4.215629623311207e-08 -3.579334686093888e-08 -2.32319766880241e-08 -3.4677560440196286e-08 -4.267313948272908e-08 -4.4177071978832014e-08 -4.041452872915548e-08 -3.828699843084332e-08 -4.076791177468786e-08 -4.5038258242584054e-08 -4.545237386268585e-08 -4.0976654317862804e-08 -3.224842182162741e-08 -2.286182849335483e-08 -1.3757366326782865e-08 -8.07685714300524e-09 -1.1919117033185581e-08 -2.7020489482442074e-08 -4.084623131943027e-08 -3.135115761438961e-08 -2.8929004474627774e-08 -2.7424743250110393e-08 -2.8382164757192317e-08 -2.9136514286248533e-08 -2.658763634271671e-08 -3.088329489852546e-08 -1.9860620251541557e-08 -3.22031394825371e-08 -3.976126318754225e-08 -3.880080094262668e-08 -3.639196130365001e-08 -3.83658110682074e-08 -4.166821671975931e-08 -4.626449741058142e-08 -4.672340227715185e-08 -4.292026106829091e-08 -3.3708140345986984e-08 -2.2013462637766273e-08 -1.2531702433510784e-08 -6.406670251294867e-09 -1.111948516503905e-08 -2.787510117790515e-08 -4.0639132418327576e-08 -3.404862080125225e-08 -2.7822668995800577e-08 -2.524954733170316e-08 -2.5566934615853412e-08 -2.6131361303461875e-08 -3.2636732261194974e-08 -3.6672695369589227e-08 -1.9600431711505388e-08 -3.141402692365293e-08 -3.863734073854205e-08 -3.93150965470317e-08 -3.854496805408196e-08 -3.995282967106224e-08 -4.449988328182066e-08 -5.040779034629319e-08 -5.090745753625525e-08 -4.6148949372902694e-08 -3.6968386578385855e-08 -2.4450572920385528e-08 -1.2553645055175237e-08 -9.292001727014961e-09 -2.992727048720495e-08 -6.589024120999936e-08 -6.97830430939012e-08 -5.239963799154164e-08 -4.500908359580174e-08 -4.229863563656836e-08 -4.218949780297138e-08 -4.255898854081177e-08 -4.1685557143621485e-08 -3.5609341130951205e-08 -2.346726405066577e-08 -3.3146507849901336e-08 -4.0237261931664005e-08 -4.3966028336755915e-08 -4.0468111460710625e-08 -3.9027952277010745e-08 -4.1176849922262086e-08 -5.138320973406618e-08 -5.478390518153827e-08 -5.0980928336884546e-08 -4.297959654709891e-08 -3.210131585616161e-08 -2.150286522802379e-08 -1.4277825588958814e-08 -2.942094654685029e-08 -5.5085595683898585e-08 -6.038576609215903e-08 -4.975575753623414e-08 -5.006558406685207e-08 -5.4034979671320446e-08 -5.425383061323969e-08 -5.4351956044952636e-08 -5.07532839098788e-08 -4.3332650864216826e-08 -2.4149704239061334e-08 -3.6544655652161444e-08 -4.182608854079831e-08 -3.9772439953633504e-08 -3.739565133506559e-08 -3.6222994898623366e-08 -3.900140745754402e-08 -4.618404113114511e-08 -5.0264793486007994e-08 -4.6846100157844835e-08 -3.808483045595735e-08 -2.848176946677028e-08 -1.6809280926524854e-08 -1.0566481789832678e-08 -2.4368472998876962e-08 -4.6795722528330575e-08 -4.502330109972665e-08 -4.0002467661643994e-08 -4.6800489090340077e-08 -4.8995983988339525e-08 -5.44245228424422e-08 -4.995233712807447e-08 -4.741595086429171e-08 -4.589434921591216e-08 -2.500300102086662e-08 -2.672964701775856e-08 -2.7953913815269234e-08 -2.5208374097793464e-08 -2.5087977316001614e-08 -2.4755879435304785e-08 -2.711688908997916e-08 -3.179732425490015e-08 -3.244039921566547e-08 -2.9594926060197282e-08 -2.5057405573457883e-08 -1.835561938809167e-08 -1.1413861460177887e-08 -1.0439510439751859e-08 -2.837501491417806e-08 -5.8732262167481936e-08 -6.109614819578273e-08 -5.122451609199106e-08 -4.024893179037693e-08 -4.422654560520654e-08 -4.245330235556649e-08 -4.453883759893283e-08 -3.766570172753522e-08 -3.298888257517317e-08 -1.915212833630094e-08 -2.8105621978537322e-08 -3.0956601334947525e-08 -3.373871208853072e-08 -3.3351387834206506e-08 -3.291598704926917e-08 -3.431415117802322e-08 -3.673885196299703e-08 -3.5738202669415105e-08 -3.249381758301339e-08 -2.4307986970618393e-08 -1.6429681789940187e-08 -9.08819011005675e-09 -5.998389560549547e-09 -2.82694109110364e-08 -6.439600620212268e-08 -7.025090580976536e-08 -5.041288563671715e-08 -4.1202655102796297e-08 -3.8288066798190274e-08 -4.2693931554942966e-08 -3.8359976138850934e-08 -4.215629623311207e-08 -3.579334686093888e-08 -2.32319766880241e-08 -3.4677560440196286e-08 -4.267313948272908e-08 -4.4177071978832014e-08 -4.041452872915548e-08 -3.828699843084332e-08 -4.076791177468786e-08 -4.5038258242584054e-08 -4.545237386268585e-08 -4.0976654317862804e-08 -3.224842182162741e-08 -2.286182849335483e-08 -1.3757366326782865e-08 -8.07685714300524e-09 -1.1919117033185581e-08 -2.7020489482442074e-08 -4.084623131943027e-08 -3.135115761438961e-08 -2.8929004474627774e-08 -2.7424743250110393e-08 -2.8382164757192317e-08 -2.9136514286248533e-08 -2.658763634271671e-08 -3.088329489852546e-08 -1.9860620251541557e-08 -3.22031394825371e-08 -3.976126318754225e-08 -3.880080094262668e-08 -3.639196130365001e-08 -3.83658110682074e-08 -4.166821671975931e-08 -4.626449741058142e-08 -4.672340227715185e-08 -4.292026106829091e-08 -3.3708140345986984e-08 -2.2013462637766273e-08 -1.2531702433510784e-08 -6.406670251294867e-09 -1.111948516503905e-08 -2.787510117790515e-08 -4.0639132418327576e-08 -3.404862080125225e-08 -2.7822668995800577e-08 -2.524954733170316e-08 -2.5566934615853412e-08 -2.6131361303461875e-08 -3.2636732261194974e-08 -3.6672695369589227e-08 -1.9600431711505388e-08 -3.141402692365293e-08 -3.863734073854205e-08 -3.93150965470317e-08 -3.854496805408196e-08 -3.995282967106224e-08 -4.449988328182066e-08 -5.040779034629319e-08 -5.090745753625525e-08 -4.6148949372902694e-08 -3.6968386578385855e-08 -2.4450572920385528e-08 -1.2553645055175237e-08 -9.292001727014961e-09 -2.992727048720495e-08 -6.589024120999936e-08 -6.97830430939012e-08 -5.239963799154164e-08 -4.500908359580174e-08 -4.229863563656836e-08 -4.218949780297138e-08 -4.255898854081177e-08 -4.1685557143621485e-08 -3.5609341130951205e-08 -2.346726405066577e-08 -3.3146507849901336e-08 -4.0237261931664005e-08 -4.3966028336755915e-08 -4.0468111460710625e-08 -3.9027952277010745e-08 -4.1176849922262086e-08 -5.138320973406618e-08 -5.478390518153827e-08 -5.0980928336884546e-08 -4.297959654709891e-08 -3.210131585616161e-08 -2.150286522802379e-08 -1.4277825588958814e-08 -2.942094654685029e-08 -5.5085595683898585e-08 -6.038576609215903e-08 -4.975575753623414e-08 -5.006558406685207e-08 -5.4034979671320446e-08 -5.425383061323969e-08 -5.4351956044952636e-08 -5.07532839098788e-08 -4.3332650864216826e-08 -2.4149704239061334e-08 -3.6544655652161444e-08 -4.182608854079831e-08 -3.9772439953633504e-08 -3.739565133506559e-08 -3.6222994898623366e-08 -3.900140745754402e-08 -4.618404113114511e-08 -5.0264793486007994e-08 -4.6846100157844835e-08 -3.808483045595735e-08 -2.848176946677028e-08 -1.6809280926524854e-08 -1.0566481789832678e-08 -2.4368472998876962e-08 -4.6795722528330575e-08 -4.502330109972665e-08 -4.0002467661643994e-08 -4.6800489090340077e-08 -4.8995983988339525e-08 -5.44245228424422e-08 -4.995233712807447e-08 -4.741595086429171e-08 -4.589434921591216e-08 -2.500300102086662e-08 -2.672964701775856e-08 -2.7953913815269234e-08 -2.5208374097793464e-08 -2.5087977316001614e-08 -2.4755879435304785e-08 -2.711688908997916e-08 -3.02656142077763e-08 -3.052284419208243e-08 -2.7446932418085685e-08 -2.387160000043771e-08 -1.9593857143216417e-08 -1.2883934929592597e-08 -1.1893311852651356e-08 -2.7653209498152262e-08 -4.491145125671046e-08 -4.409636915308485e-08 -3.6775094270690005e-08 -3.4864195997499555e-08 -4.043137606039598e-08 -4.639755023632955e-08 -3.961728014201371e-08 -3.9246967583137205e-08 -3.8794308556441316e-08 -2.3763694898394913e-08 -2.5039818603284873e-08 -2.5472096468284946e-08 -2.7543578571933603e-08 -2.6727428100961036e-08 -2.591875620141716e-08 -2.6437160911002806e-08 -2.7430085086845188e-08 -2.6277563265787942e-08 -2.2838077865410906e-08 -1.7923834615713264e-08 -1.3061530455498522e-08 -9.230282967202212e-09 -6.556241679869038e-09 -2.585958508681639e-08 -6.173536059767829e-08 -6.399380698704466e-08 -4.7220521821901936e-08 -3.499075643706231e-08 -3.611015887036384e-08 -3.3797390110509815e-08 -3.286199340719596e-08 -3.299562150766937e-08 -3.4143212402509876e-08 -2.2226232104018218e-08 -3.499749536955851e-08 -4.1857482104378166e-08 -3.6536766170214675e-08 -3.243029081692117e-08 -3.0985940345937074e-08 -3.0541335165395173e-08 -3.254066138207233e-08 -3.053237731610144e-08 -2.644159874459786e-08 -2.0239479749193717e-08 -1.425703351674493e-08 -9.071014050401804e-09 -4.974236185334536e-09 -1.1641752433494468e-08 -2.835282574620276e-08 -3.751752739472246e-08 -2.977186412927431e-08 -2.1211447488614993e-08 -2.4971936185701213e-08 -2.288270274767232e-08 -2.5643610518523573e-08 -2.3659077080496603e-08 -2.7837954867072443e-08 -1.7572834851185637e-08 -3.251247292053335e-08 -3.870941444340993e-08 -3.758590290492779e-08 -3.314404238679297e-08 -3.374068445901741e-08 -3.672562064431547e-08 -3.8947249451263593e-08 -3.639870023614621e-08 -3.137515478864437e-08 -2.2884675118159017e-08 -1.5230151805616778e-08 -8.359974489949207e-09 -5.4069249608526734e-09 -1.4843320643914238e-08 -2.7998209969116197e-08 -3.5277489796565215e-08 -2.2281705023956437e-08 -1.820037739436826e-08 -2.0462439796293565e-08 -2.226288532222925e-08 -2.3518792229630612e-08 -2.3589386656633478e-08 -2.2312030220189333e-08 -2.3926251099339808e-08 -3.261684419212082e-08 -3.673194866629361e-08 -3.657900777147134e-08 -3.223313595035555e-08 -3.2204372214091284e-08 -3.472678752025998e-08 -3.665888877618238e-08 -3.506817197866499e-08 -3.0240219937760134e-08 -2.2709051962739783e-08 -1.5849640502645406e-08 -1.1737001491580985e-08 -1.5343398744394367e-08 -3.9702174255045084e-08 -6.20640068300234e-08 -6.109154599798046e-08 -4.134121412948645e-08 -3.7827600471651216e-08 -3.6263921586222236e-08 -3.975189442773045e-08 -3.304312276355721e-08 -3.042948532237899e-08 -2.8639066013083993e-08 -2.4419918995738187e-08 -3.241032056574341e-08 -3.6295150785594865e-08 -3.457639427064969e-08 -3.2770195997461156e-08 -3.278704332870165e-08 -3.657514521260157e-08 -3.791356295202956e-08 -3.6543505102710875e-08 -3.1522260754110177e-08 -2.4686764286166943e-08 -1.6460746625105593e-08 -1.0078731004894379e-08 -1.2483708085001272e-08 -3.644340730051124e-08 -5.892218500892969e-08 -5.7337796233390434e-08 -4.618527386269929e-08 -3.8302037755804345e-08 -3.793690266945542e-08 -3.409891624866291e-08 -2.834773045577881e-08 -2.608254513391624e-08 -2.9133637912622105e-08 -1.9781643249970252e-08 -3.229049905867685e-08 -3.432286248100611e-08 -3.175171318739538e-08 -3.013050682943787e-08 -2.9372459105719103e-08 -3.101149898016046e-08 -3.460655510267536e-08 -3.5664238776164146e-08 -3.2318358791801383e-08 -2.7424743250110393e-08 -1.9851169309626152e-08 -1.3424117896635469e-08 -1.2988306201180068e-08 -2.932849168028659e-08 -4.588703500869068e-08 -4.4791629749643904e-08 -4.0026382653795145e-08 -4.478793155498136e-08 -4.496889654713538e-08 -4.3917787441935574e-08 -3.878157033038143e-08 -4.185961883907209e-08 -4.085683281079624e-08 -2.3011564286136224e-08 -2.524108257503111e-08 -2.6002746311308814e-08 -2.4038429670770438e-08 -2.480798288899491e-08 -2.3884995683326493e-08 -2.7093385008346077e-08 -3.02656142077763e-08 -3.052284419208243e-08 -2.7446932418085685e-08 -2.387160000043771e-08 -1.9593857143216417e-08 -1.2883934929592597e-08 -1.1893311852651356e-08 -2.7653209498152262e-08 -4.491145125671046e-08 -4.409636915308485e-08 -3.6775094270690005e-08 -3.4864195997499555e-08 -4.043137606039598e-08 -4.639755023632955e-08 -3.961728014201371e-08 -3.9246967583137205e-08 -3.8794308556441316e-08 -2.3763694898394913e-08 -2.5039818603284873e-08 -2.5472096468284946e-08 -2.7543578571933603e-08 -2.6727428100961036e-08 -2.591875620141716e-08 -2.6437160911002806e-08 -2.7430085086845188e-08 -2.6277563265787942e-08 -2.2838077865410906e-08 -1.7923834615713264e-08 -1.3061530455498522e-08 -9.230282967202212e-09 -6.556241679869038e-09 -2.585958508681639e-08 -6.173536059767829e-08 -6.399380698704466e-08 -4.7220521821901936e-08 -3.499075643706231e-08 -3.611015887036384e-08 -3.3797390110509815e-08 -3.286199340719596e-08 -3.299562150766937e-08 -3.4143212402509876e-08 -2.2226232104018218e-08 -3.499749536955851e-08 -4.1857482104378166e-08 -3.6536766170214675e-08 -3.243029081692117e-08 -3.0985940345937074e-08 -3.0541335165395173e-08 -3.254066138207233e-08 -3.053237731610144e-08 -2.644159874459786e-08 -2.0239479749193717e-08 -1.425703351674493e-08 -9.071014050401804e-09 -4.974236185334536e-09 -1.1641752433494468e-08 -2.835282574620276e-08 -3.751752739472246e-08 -2.977186412927431e-08 -2.1211447488614993e-08 -2.4971936185701213e-08 -2.288270274767232e-08 -2.5643610518523573e-08 -2.3659077080496603e-08 -2.7837954867072443e-08 -1.7572834851185637e-08 -3.251247292053335e-08 -3.870941444340993e-08 -3.758590290492779e-08 -3.314404238679297e-08 -3.374068445901741e-08 -3.672562064431547e-08 -3.8947249451263593e-08 -3.639870023614621e-08 -3.137515478864437e-08 -2.2884675118159017e-08 -1.5230151805616778e-08 -8.359974489949207e-09 -5.4069249608526734e-09 -1.4843320643914238e-08 -2.7998209969116197e-08 -3.5277489796565215e-08 -2.2281705023956437e-08 -1.820037739436826e-08 -2.0462439796293565e-08 -2.226288532222925e-08 -2.3518792229630612e-08 -2.3589386656633478e-08 -2.2312030220189333e-08 -2.3926251099339808e-08 -3.261684419212082e-08 -3.673194866629361e-08 -3.657900777147134e-08 -3.223313595035555e-08 -3.2204372214091284e-08 -3.472678752025998e-08 -3.665888877618238e-08 -3.506817197866499e-08 -3.0240219937760134e-08 -2.2709051962739783e-08 -1.5849640502645406e-08 -1.1737001491580985e-08 -1.5343398744394367e-08 -3.9702174255045084e-08 -6.20640068300234e-08 -6.109154599798046e-08 -4.134121412948645e-08 -3.7827600471651216e-08 -3.6263921586222236e-08 -3.975189442773045e-08 -3.304312276355721e-08 -3.042948532237899e-08 -2.8639066013083993e-08 -2.4419918995738187e-08 -3.241032056574341e-08 -3.6295150785594865e-08 -3.457639427064969e-08 -3.2770195997461156e-08 -3.278704332870165e-08 -3.657514521260157e-08 -3.791356295202956e-08 -3.6543505102710875e-08 -3.1522260754110177e-08 -2.4686764286166943e-08 -1.6460746625105593e-08 -1.0078731004894379e-08 -1.2483708085001272e-08 -3.644340730051124e-08 -5.892218500892969e-08 -5.7337796233390434e-08 -4.618527386269929e-08 -3.8302037755804345e-08 -3.793690266945542e-08 -3.409891624866291e-08 -2.834773045577881e-08 -2.608254513391624e-08 -2.9133637912622105e-08 -1.9781643249970252e-08 -3.229049905867685e-08 -3.432286248100611e-08 -3.175171318739538e-08 -3.013050682943787e-08 -2.9372459105719103e-08 -3.101149898016046e-08 -3.460655510267536e-08 -3.5664238776164146e-08 -3.2318358791801383e-08 -2.7424743250110393e-08 -1.9851169309626152e-08 -1.3424117896635469e-08 -1.2988306201180068e-08 -2.932849168028659e-08 -4.588703500869068e-08 -4.4791629749643904e-08 -4.0026382653795145e-08 -4.478793155498136e-08 -4.496889654713538e-08 -4.3917787441935574e-08 -3.878157033038143e-08 -4.185961883907209e-08 -4.085683281079624e-08 -2.3011564286136224e-08 -2.524108257503111e-08 -2.6002746311308814e-08 -2.4038429670770438e-08 -2.480798288899491e-08 -2.3884995683326493e-08 -2.7093385008346077e-08 -3.02656142077763e-08 -3.052284419208243e-08 -2.7446932418085685e-08 -2.387160000043771e-08 -1.9593857143216417e-08 -1.2883934929592597e-08 -1.1893311852651356e-08 -2.7653209498152262e-08 -4.491145125671046e-08 -4.409636915308485e-08 -3.6775094270690005e-08 -3.4864195997499555e-08 -4.043137606039598e-08 -4.639755023632955e-08 -3.961728014201371e-08 -3.9246967583137205e-08 -3.8794308556441316e-08 -2.3763694898394913e-08 -2.5039818603284873e-08 -2.5472096468284946e-08 -2.7543578571933603e-08 -2.6727428100961036e-08 -2.591875620141716e-08 -2.6437160911002806e-08 -2.7430085086845188e-08 -2.6277563265787942e-08 -2.2838077865410906e-08 -1.7923834615713264e-08 -1.3061530455498522e-08 -9.230282967202212e-09 -6.556241679869038e-09 -2.585958508681639e-08 -6.173536059767829e-08 -6.399380698704466e-08 -4.7220521821901936e-08 -3.499075643706231e-08 -3.611015887036384e-08 -3.3797390110509815e-08 -3.286199340719596e-08 -3.299562150766937e-08 -3.4143212402509876e-08 -2.2226232104018218e-08 -3.499749536955851e-08 -4.1857482104378166e-08 -3.6536766170214675e-08 -3.243029081692117e-08 -3.0985940345937074e-08 -3.0541335165395173e-08 -3.254066138207233e-08 -3.053237731610144e-08 -2.644159874459786e-08 -2.0239479749193717e-08 -1.425703351674493e-08 -9.071014050401804e-09 -4.974236185334536e-09 -1.1641752433494468e-08 -2.835282574620276e-08 -3.751752739472246e-08 -2.977186412927431e-08 -2.1211447488614993e-08 -2.4971936185701213e-08 -2.288270274767232e-08 -2.5643610518523573e-08 -2.3659077080496603e-08 -2.7837954867072443e-08 -1.7572834851185637e-08 -3.251247292053335e-08 -3.870941444340993e-08 -3.758590290492779e-08 -3.314404238679297e-08 -3.374068445901741e-08 -3.672562064431547e-08 -3.8947249451263593e-08 -3.639870023614621e-08 -3.137515478864437e-08 -2.2884675118159017e-08 -1.5230151805616778e-08 -8.359974489949207e-09 -5.4069249608526734e-09 -1.4843320643914238e-08 -2.7998209969116197e-08 -3.5277489796565215e-08 -2.2281705023956437e-08 -1.820037739436826e-08 -2.0462439796293565e-08 -2.226288532222925e-08 -2.3518792229630612e-08 -2.3589386656633478e-08 -2.2312030220189333e-08 -2.3926251099339808e-08 -3.261684419212082e-08 -3.673194866629361e-08 -3.657900777147134e-08 -3.223313595035555e-08 -3.2204372214091284e-08 -3.472678752025998e-08 -3.665888877618238e-08 -3.506817197866499e-08 -3.0240219937760134e-08 -2.2709051962739783e-08 -1.5849640502645406e-08 -1.1737001491580985e-08 -1.5343398744394367e-08 -3.9702174255045084e-08 -6.20640068300234e-08 -6.109154599798046e-08 -4.134121412948645e-08 -3.7827600471651216e-08 -3.6263921586222236e-08 -3.975189442773045e-08 -3.304312276355721e-08 -3.042948532237899e-08 -2.8639066013083993e-08 -2.4419918995738187e-08 -3.241032056574341e-08 -3.6295150785594865e-08 -3.457639427064969e-08 -3.2770195997461156e-08 -3.278704332870165e-08 -3.657514521260157e-08 -3.791356295202956e-08 -3.6543505102710875e-08 -3.1522260754110177e-08 -2.4686764286166943e-08 -1.6460746625105593e-08 -1.0078731004894379e-08 -1.2483708085001272e-08 -3.644340730051124e-08 -5.892218500892969e-08 -5.7337796233390434e-08 -4.618527386269929e-08 -3.8302037755804345e-08 -3.793690266945542e-08 -3.409891624866291e-08 -2.834773045577881e-08 -2.608254513391624e-08 -2.9133637912622105e-08 -1.9781643249970252e-08 -3.229049905867685e-08 -3.432286248100611e-08 -3.175171318739538e-08 -3.013050682943787e-08 -2.9372459105719103e-08 -3.101149898016046e-08 -3.460655510267536e-08 -3.5664238776164146e-08 -3.2318358791801383e-08 -2.7424743250110393e-08 -1.9851169309626152e-08 -1.3424117896635469e-08 -1.2988306201180068e-08 -2.932849168028659e-08 -4.588703500869068e-08 -4.4791629749643904e-08 -4.0026382653795145e-08 -4.478793155498136e-08 -4.496889654713538e-08 -4.3917787441935574e-08 -3.878157033038143e-08 -4.185961883907209e-08 -4.085683281079624e-08 -2.3011564286136224e-08 -2.524108257503111e-08 -2.6002746311308814e-08 -2.4038429670770438e-08 -2.480798288899491e-08 -2.3884995683326493e-08 -2.7093385008346077e-08 -3.02656142077763e-08 -3.052284419208243e-08 -2.7446932418085685e-08 -2.387160000043771e-08 -1.9593857143216417e-08 -1.2883934929592597e-08 -1.1893311852651356e-08 -2.7653209498152262e-08 -4.491145125671046e-08 -4.409636915308485e-08 -3.6775094270690005e-08 -3.4864195997499555e-08 -4.043137606039598e-08 -4.639755023632955e-08 -3.961728014201371e-08 -3.9246967583137205e-08 -3.8794308556441316e-08 -2.3763694898394913e-08 -2.5039818603284873e-08 -2.5472096468284946e-08 -2.7543578571933603e-08 -2.6727428100961036e-08 -2.591875620141716e-08 -2.6437160911002806e-08 -2.7430085086845188e-08 -2.6277563265787942e-08 -2.2838077865410906e-08 -1.7923834615713264e-08 -1.3061530455498522e-08 -9.230282967202212e-09 -6.556241679869038e-09 -2.585958508681639e-08 -6.173536059767829e-08 -6.399380698704466e-08 -4.7220521821901936e-08 -3.499075643706231e-08 -3.611015887036384e-08 -3.3797390110509815e-08 -3.286199340719596e-08 -3.299562150766937e-08 -3.4143212402509876e-08 -2.2226232104018218e-08 -3.499749536955851e-08 -4.1857482104378166e-08 -3.6536766170214675e-08 -3.243029081692117e-08 -3.0985940345937074e-08 -3.0541335165395173e-08 -3.254066138207233e-08 -3.053237731610144e-08 -2.644159874459786e-08 -2.0239479749193717e-08 -1.425703351674493e-08 -9.071014050401804e-09 -4.974236185334536e-09 -1.1641752433494468e-08 -2.835282574620276e-08 -3.751752739472246e-08 -2.977186412927431e-08 -2.1211447488614993e-08 -2.4971936185701213e-08 -2.288270274767232e-08 -2.5643610518523573e-08 -2.3659077080496603e-08 -2.7837954867072443e-08 -1.7572834851185637e-08 -3.251247292053335e-08 -3.870941444340993e-08 -3.758590290492779e-08 -3.314404238679297e-08 -3.374068445901741e-08 -3.672562064431547e-08 -3.8947249451263593e-08 -3.639870023614621e-08 -3.137515478864437e-08 -2.2884675118159017e-08 -1.5230151805616778e-08 -8.359974489949207e-09 -5.4069249608526734e-09 -1.4843320643914238e-08 -2.7998209969116197e-08 -3.5277489796565215e-08 -2.2281705023956437e-08 -1.820037739436826e-08 -2.0462439796293565e-08 -2.226288532222925e-08 -2.3518792229630612e-08 -2.3589386656633478e-08 -2.2312030220189333e-08 -2.3926251099339808e-08 -3.261684419212082e-08 -3.673194866629361e-08 -3.657900777147134e-08 -3.223313595035555e-08 -3.2204372214091284e-08 -3.472678752025998e-08 -3.665888877618238e-08 -3.506817197866499e-08 -3.0240219937760134e-08 -2.2709051962739783e-08 -1.5849640502645406e-08 -1.1737001491580985e-08 -1.5343398744394367e-08 -3.9702174255045084e-08 -6.20640068300234e-08 -6.109154599798046e-08 -4.134121412948645e-08 -3.7827600471651216e-08 -3.6263921586222236e-08 -3.975189442773045e-08 -3.304312276355721e-08 -3.042948532237899e-08 -2.8639066013083993e-08 -2.4419918995738187e-08 -3.241032056574341e-08 -3.6295150785594865e-08 -3.457639427064969e-08 -3.2770195997461156e-08 -3.278704332870165e-08 -3.657514521260157e-08 -3.791356295202956e-08 -3.6543505102710875e-08 -3.1522260754110177e-08 -2.4686764286166943e-08 -1.6460746625105593e-08 -1.0078731004894379e-08 -1.2483708085001272e-08 -3.644340730051124e-08 -5.892218500892969e-08 -5.7337796233390434e-08 -4.618527386269929e-08 -3.8302037755804345e-08 -3.793690266945542e-08 -3.409891624866291e-08 -2.834773045577881e-08 -2.608254513391624e-08 -2.9133637912622105e-08 -1.9781643249970252e-08 -3.229049905867685e-08 -3.432286248100611e-08 -3.175171318739538e-08 -3.013050682943787e-08 -2.9372459105719103e-08 -3.101149898016046e-08 -3.460655510267536e-08 -3.5664238776164146e-08 -3.2318358791801383e-08 -2.7424743250110393e-08 -1.9851169309626152e-08 -1.3424117896635469e-08 -1.2988306201180068e-08 -2.932849168028659e-08 -4.588703500869068e-08 -4.4791629749643904e-08 -4.0026382653795145e-08 -4.478793155498136e-08 -4.496889654713538e-08 -4.3917787441935574e-08 -3.878157033038143e-08 -4.185961883907209e-08 -4.085683281079624e-08 -2.3011564286136224e-08 -2.524108257503111e-08 -2.6002746311308814e-08 -2.4038429670770438e-08 -2.480798288899491e-08 -2.3884995683326493e-08 -2.7093385008346077e-08 -3.02656142077763e-08 -3.052284419208243e-08 -2.7446932418085685e-08 -2.387160000043771e-08 -1.9593857143216417e-08 -1.2883934929592597e-08 -1.1893311852651356e-08 -2.7653209498152262e-08 -4.491145125671046e-08 -4.409636915308485e-08 -3.6775094270690005e-08 -3.4864195997499555e-08 -4.043137606039598e-08 -4.639755023632955e-08 -3.961728014201371e-08 -3.9246967583137205e-08 -3.8794308556441316e-08 -2.3763694898394913e-08 -2.5039818603284873e-08 -2.5472096468284946e-08 -2.7543578571933603e-08 -2.6727428100961036e-08 -2.591875620141716e-08 -2.6437160911002806e-08 -2.7430085086845188e-08 -2.6277563265787942e-08 -2.2838077865410906e-08 -1.7923834615713264e-08 -1.3061530455498522e-08 -9.230282967202212e-09 -6.556241679869038e-09 -2.585958508681639e-08 -6.173536059767829e-08 -6.399380698704466e-08 -4.7220521821901936e-08 -3.499075643706231e-08 -3.611015887036384e-08 -3.3797390110509815e-08 -3.286199340719596e-08 -3.299562150766937e-08 -3.4143212402509876e-08 -2.2226232104018218e-08 -3.499749536955851e-08 -4.1857482104378166e-08 -3.6536766170214675e-08 -3.243029081692117e-08 -3.0985940345937074e-08 -3.0541335165395173e-08 -3.254066138207233e-08 -3.053237731610144e-08 -2.644159874459786e-08 -2.0239479749193717e-08 -1.425703351674493e-08 -9.071014050401804e-09 -4.974236185334536e-09 -1.1641752433494468e-08 -2.835282574620276e-08 -3.751752739472246e-08 -2.977186412927431e-08 -2.1211447488614993e-08 -2.4971936185701213e-08 -2.288270274767232e-08 -2.5643610518523573e-08 -2.3659077080496603e-08 -2.7837954867072443e-08 -1.7572834851185637e-08 -3.251247292053335e-08 -3.870941444340993e-08 -3.758590290492779e-08 -3.314404238679297e-08 -3.374068445901741e-08 -3.672562064431547e-08 -3.7325714364891624e-08 -3.167207872899518e-08 -2.406078320295295e-08 -1.5800084694167263e-08 -9.56049065951596e-09 -5.596519073885978e-09 -9.346652825917062e-09 -2.194319693917786e-08 -3.243579701786319e-08 -2.578570337566904e-08 -2.070635627981452e-08 -2.4616087677060465e-08 -2.3595139403886328e-08 -2.090145659378984e-08 -2.7129216405520988e-08 -3.158792425489631e-08 -1.704070573029676e-08 -3.400605047158115e-08 -3.777007299912269e-08 -3.6565201178064495e-08 -3.571888987506624e-08 -3.383198877613055e-08 -3.9566080691463313e-08 -4.2673386029039914e-08 -3.959131059727225e-08 -3.4407016955104984e-08 -2.5515570801095793e-08 -1.8369425981498515e-08 -1.0952819858913546e-08 -8.651227865150779e-09 -2.9775397959729636e-08 -6.173462095874578e-08 -6.557737394154779e-08 -4.779612527560166e-08 -4.20688544748687e-08 -3.827804058154959e-08 -3.9422426374349226e-08 -3.1413451648927644e-08 -3.092997433337718e-08 -2.8827180848252276e-08 -1.864112001604039e-08 -3.3595468681934686e-08 -3.6086408242419924e-08 -3.5647309262820034e-08 -3.416983940408022e-08 -3.47842328106849e-08 -3.695170361135258e-08 -4.0468029278607005e-08 -3.875740879191945e-08 -3.374084882322463e-08 -2.721920580897633e-08 -2.071202684496376e-08 -1.1522341836945966e-08 -9.784354709755546e-09 -2.9650398980135508e-08 -5.7775333753021683e-08 -6.211742519737132e-08 -4.822873186901619e-08 -3.8035767740100873e-08 -4.283725714364261e-08 -3.60714510995625e-08 -3.145059795976035e-08 -2.9009871664582158e-08 -2.812000384666945e-08 -2.142232676648385e-08 -2.8621150314496537e-08 -3.1909667190538e-08 -3.2843502433883223e-08 -3.1474512951911494e-08 -2.9804819152822796e-08 -3.118350612302076e-08 -3.568807158621167e-08 -3.618995769297127e-08 -3.4015337049289326e-08 -2.8976423548412e-08 -2.0906551884213795e-08 -1.385319065959467e-08 -8.923497174417939e-09 -2.2680288226475518e-08 -4.246004128806268e-08 -4.294779207300098e-08 -4.5546883281839853e-08 -4.601137653145591e-08 -4.722208328187057e-08 -4.455971185325033e-08 -4.071482213575439e-08 -3.919609686100126e-08 -3.429220855635876e-08 -2.1552667582812776e-08 -2.1880491994121763e-08 -2.5024779278323846e-08 -2.340957221393002e-08 -2.5545895997328686e-08 -2.139980887009411e-08 -2.387579128772193e-08 -2.838084984353452e-08 -2.9053592543703837e-08 -2.755722080113323e-08 -2.476163218255764e-08 -1.836424850897095e-08 -1.2363311303209424e-08 -7.770235714428189e-09 -2.177176507104285e-08 -4.137581279510718e-08 -4.087762488301012e-08 -3.5789155573654655e-08 -3.893122394105921e-08 -4.610629686112798e-08 -5.0537473705793214e-08 -4.701424474183537e-08 -3.453604285777611e-08 -3.2959461382080014e-08 -1.8337785871607828e-08 -2.2063840267280545e-08 -2.6118294348987537e-08 -2.9752715699132674e-08 -2.8454156279956586e-08 -2.885101365829981e-08 -2.9448559733663986e-08 -3.0920030298840104e-08 -2.9067727865525134e-08 -2.4992317347397035e-08 -1.9460475589053846e-08 -1.2290087048890972e-08 -7.487447095898671e-09 -6.9106930927483785e-09 -2.7016544741468683e-08 -5.6372403062258135e-08 -5.895826295241544e-08 -4.810595180621959e-08 -4.0753612088659346e-08 -4.026668312475717e-08 -3.558205667255196e-08 -3.137663406650939e-08 -3.199579403512357e-08 -2.896097331293291e-08 -1.9402290659696418e-08 -3.229707362696583e-08 -3.89763419159423e-08 -3.912994026759346e-08 -3.452009952967534e-08 -3.3933976766713263e-08 -3.4867318917436816e-08 -3.6627002119980855e-08 -3.439986711209072e-08 -3.037080730039989e-08 -2.4728841523216376e-08 -1.7694053454013604e-08 -1.013412174272899e-08 -4.7832449765398245e-09 -1.0727805259223392e-08 -2.404615478850998e-08 -3.262908932555904e-08 -2.8356359576658083e-08 -2.323698979634444e-08 -2.0556949215447575e-08 -2.0447811381850597e-08 -2.5025436735152743e-08 -2.3343086892107763e-08 -3.100508877607871e-08 -1.9600102983090943e-08 -3.043786789694743e-08 -3.985486860355653e-08 -3.834370408233572e-08 -3.5027163108962506e-08 -3.3358866405635216e-08 -3.327208210422075e-08 -3.7117300550131134e-08 -3.7325714364891624e-08 -3.167207872899518e-08 -2.406078320295295e-08 -1.5800084694167263e-08 -9.56049065951596e-09 -5.596519073885978e-09 -9.346652825917062e-09 -2.194319693917786e-08 -3.243579701786319e-08 -2.578570337566904e-08 -2.070635627981452e-08 -2.4616087677060465e-08 -2.3595139403886328e-08 -2.090145659378984e-08 -2.7129216405520988e-08 -3.158792425489631e-08 -1.704070573029676e-08 -3.400605047158115e-08 -3.777007299912269e-08 -3.6565201178064495e-08 -3.571888987506624e-08 -3.383198877613055e-08 -3.9566080691463313e-08 -4.2673386029039914e-08 -3.959131059727225e-08 -3.4407016955104984e-08 -2.5515570801095793e-08 -1.8369425981498515e-08 -1.0952819858913546e-08 -8.651227865150779e-09 -2.9775397959729636e-08 -6.173462095874578e-08 -6.557737394154779e-08 -4.779612527560166e-08 -4.20688544748687e-08 -3.827804058154959e-08 -3.9422426374349226e-08 -3.1413451648927644e-08 -3.092997433337718e-08 -2.8827180848252276e-08 -1.864112001604039e-08 -3.3595468681934686e-08 -3.6086408242419924e-08 -3.5647309262820034e-08 -3.416983940408022e-08 -3.47842328106849e-08 -3.695170361135258e-08 -4.0468029278607005e-08 -3.875740879191945e-08 -3.374084882322463e-08 -2.721920580897633e-08 -2.071202684496376e-08 -1.1522341836945966e-08 -9.784354709755546e-09 -2.9650398980135508e-08 -5.7775333753021683e-08 -6.211742519737132e-08 -4.822873186901619e-08 -3.8035767740100873e-08 -4.283725714364261e-08 -3.60714510995625e-08 -3.145059795976035e-08 -2.9009871664582158e-08 -2.812000384666945e-08 -2.142232676648385e-08 -2.8621150314496537e-08 -3.1909667190538e-08 -3.2843502433883223e-08 -3.1474512951911494e-08 -2.9804819152822796e-08 -3.118350612302076e-08 -3.568807158621167e-08 -3.618995769297127e-08 -3.4015337049289326e-08 -2.8976423548412e-08 -2.0906551884213795e-08 -1.385319065959467e-08 -8.923497174417939e-09 -2.2680288226475518e-08 -4.246004128806268e-08 -4.294779207300098e-08 -4.5546883281839853e-08 -4.601137653145591e-08 -4.722208328187057e-08 -4.455971185325033e-08 -4.071482213575439e-08 -3.919609686100126e-08 -3.429220855635876e-08 -2.1552667582812776e-08 -2.1880491994121763e-08 -2.5024779278323846e-08 -2.340957221393002e-08 -2.5545895997328686e-08 -2.139980887009411e-08 -2.387579128772193e-08 -2.838084984353452e-08 -2.9053592543703837e-08 -2.755722080113323e-08 -2.476163218255764e-08 -1.836424850897095e-08 -1.2363311303209424e-08 -7.770235714428189e-09 -2.177176507104285e-08 -4.137581279510718e-08 -4.087762488301012e-08 -3.5789155573654655e-08 -3.893122394105921e-08 -4.610629686112798e-08 -5.0537473705793214e-08 -4.701424474183537e-08 -3.453604285777611e-08 -3.2959461382080014e-08 -1.8337785871607828e-08 -2.2063840267280545e-08 -2.6118294348987537e-08 -2.9752715699132674e-08 -2.8454156279956586e-08 -2.885101365829981e-08 -2.9448559733663986e-08 -3.0920030298840104e-08 -2.9067727865525134e-08 -2.4992317347397035e-08 -1.9460475589053846e-08 -1.2290087048890972e-08 -7.487447095898671e-09 -6.9106930927483785e-09 -2.7016544741468683e-08 -5.6372403062258135e-08 -5.895826295241544e-08 -4.810595180621959e-08 -4.0753612088659346e-08 -4.026668312475717e-08 -3.558205667255196e-08 -3.137663406650939e-08 -3.199579403512357e-08 -2.896097331293291e-08 -1.9402290659696418e-08 -3.229707362696583e-08 -3.89763419159423e-08 -3.912994026759346e-08 -3.452009952967534e-08 -3.3933976766713263e-08 -3.4867318917436816e-08 -3.6627002119980855e-08 -3.439986711209072e-08 -3.037080730039989e-08 -2.4728841523216376e-08 -1.7694053454013604e-08 -1.013412174272899e-08 -4.7832449765398245e-09 -1.0727805259223392e-08 -2.404615478850998e-08 -3.262908932555904e-08 -2.8356359576658083e-08 -2.323698979634444e-08 -2.0556949215447575e-08 -2.0447811381850597e-08 -2.5025436735152743e-08 -2.3343086892107763e-08 -3.100508877607871e-08 -1.9600102983090943e-08 -3.043786789694743e-08 -3.985486860355653e-08 -3.834370408233572e-08 -3.5027163108962506e-08 -3.3358866405635216e-08 -3.327208210422075e-08 -3.7117300550131134e-08 -3.7325714364891624e-08 -3.167207872899518e-08 -2.406078320295295e-08 -1.5800084694167263e-08 -9.56049065951596e-09 -5.596519073885978e-09 -9.346652825917062e-09 -2.194319693917786e-08 -3.243579701786319e-08 -2.578570337566904e-08 -2.070635627981452e-08 -2.4616087677060465e-08 -2.3595139403886328e-08 -2.090145659378984e-08 -2.7129216405520988e-08 -3.158792425489631e-08 -1.704070573029676e-08 -3.400605047158115e-08 -3.777007299912269e-08 -3.6565201178064495e-08 -3.571888987506624e-08 -3.383198877613055e-08 -3.9566080691463313e-08 -4.2673386029039914e-08 -3.959131059727225e-08 -3.4407016955104984e-08 -2.5515570801095793e-08 -1.8369425981498515e-08 -1.0952819858913546e-08 -8.651227865150779e-09 -2.9775397959729636e-08 -6.173462095874578e-08 -6.557737394154779e-08 -4.779612527560166e-08 -4.20688544748687e-08 -3.827804058154959e-08 -3.9422426374349226e-08 -3.1413451648927644e-08 -3.092997433337718e-08 -2.8827180848252276e-08 -1.864112001604039e-08 -3.3595468681934686e-08 -3.6086408242419924e-08 -3.5647309262820034e-08 -3.416983940408022e-08 -3.47842328106849e-08 -3.695170361135258e-08 -4.0468029278607005e-08 -3.875740879191945e-08 -3.374084882322463e-08 -2.721920580897633e-08 -2.071202684496376e-08 -1.1522341836945966e-08 -9.784354709755546e-09 -2.9650398980135508e-08 -5.7775333753021683e-08 -6.211742519737132e-08 -4.822873186901619e-08 -3.8035767740100873e-08 -4.283725714364261e-08 -3.60714510995625e-08 -3.145059795976035e-08 -2.9009871664582158e-08 -2.812000384666945e-08 -2.142232676648385e-08 -2.8621150314496537e-08 -3.1909667190538e-08 -3.2843502433883223e-08 -3.1474512951911494e-08 -2.9804819152822796e-08 -3.118350612302076e-08 -3.568807158621167e-08 -3.618995769297127e-08 -3.4015337049289326e-08 -2.8976423548412e-08 -2.0906551884213795e-08 -1.385319065959467e-08 -8.923497174417939e-09 -2.2680288226475518e-08 -4.246004128806268e-08 -4.294779207300098e-08 -4.5546883281839853e-08 -4.601137653145591e-08 -4.722208328187057e-08 -4.455971185325033e-08 -4.071482213575439e-08 -3.919609686100126e-08 -3.429220855635876e-08 -2.1552667582812776e-08 -2.1880491994121763e-08 -2.5024779278323846e-08 -2.340957221393002e-08 -2.5545895997328686e-08 -2.139980887009411e-08 -2.387579128772193e-08 -2.838084984353452e-08 -2.9053592543703837e-08 -2.755722080113323e-08 -2.476163218255764e-08 -1.836424850897095e-08 -1.2363311303209424e-08 -7.770235714428189e-09 -2.177176507104285e-08 -4.137581279510718e-08 -4.087762488301012e-08 -3.5789155573654655e-08 -3.893122394105921e-08 -4.610629686112798e-08 -5.0537473705793214e-08 -4.701424474183537e-08 -3.453604285777611e-08 -3.2959461382080014e-08 -1.8337785871607828e-08 -2.2063840267280545e-08 -2.6118294348987537e-08 -2.9752715699132674e-08 -2.8454156279956586e-08 -2.885101365829981e-08 -2.9448559733663986e-08 -3.0920030298840104e-08 -2.9067727865525134e-08 -2.4992317347397035e-08 -1.9460475589053846e-08 -1.2290087048890972e-08 -7.487447095898671e-09 -6.9106930927483785e-09 -2.7016544741468683e-08 -5.6372403062258135e-08 -5.895826295241544e-08 -4.810595180621959e-08 -4.0753612088659346e-08 -4.026668312475717e-08 -3.558205667255196e-08 -3.137663406650939e-08 -3.199579403512357e-08 -2.896097331293291e-08 -1.9402290659696418e-08 -3.229707362696583e-08 -3.89763419159423e-08 -3.912994026759346e-08 -3.452009952967534e-08 -3.3933976766713263e-08 -3.4867318917436816e-08 -3.6627002119980855e-08 -3.439986711209072e-08 -3.037080730039989e-08 -2.4728841523216376e-08 -1.7694053454013604e-08 -1.013412174272899e-08 -4.7832449765398245e-09 -1.0727805259223392e-08 -2.404615478850998e-08 -3.262908932555904e-08 -2.8356359576658083e-08 -2.323698979634444e-08 -2.0556949215447575e-08 -2.0447811381850597e-08 -2.5025436735152743e-08 -2.3343086892107763e-08 -3.100508877607871e-08 -1.9600102983090943e-08 -3.043786789694743e-08 -3.985486860355653e-08 -3.834370408233572e-08 -3.5027163108962506e-08 -3.3358866405635216e-08 -3.327208210422075e-08 -3.7117300550131134e-08 -3.7325714364891624e-08 -3.167207872899518e-08 -2.406078320295295e-08 -1.5800084694167263e-08 -9.56049065951596e-09 -5.596519073885978e-09 -9.346652825917062e-09 -2.194319693917786e-08 -3.243579701786319e-08 -2.578570337566904e-08 -2.070635627981452e-08 -2.4616087677060465e-08 -2.3595139403886328e-08 -2.090145659378984e-08 -2.7129216405520988e-08 -3.158792425489631e-08 -1.704070573029676e-08 -3.400605047158115e-08 -3.777007299912269e-08 -3.6565201178064495e-08 -3.571888987506624e-08 -3.383198877613055e-08 -3.9566080691463313e-08 -4.2673386029039914e-08 -3.959131059727225e-08 -3.4407016955104984e-08 -2.5515570801095793e-08 -1.8369425981498515e-08 -1.0952819858913546e-08 -8.651227865150779e-09 -2.9775397959729636e-08 -6.173462095874578e-08 -6.557737394154779e-08 -4.779612527560166e-08 -4.20688544748687e-08 -3.827804058154959e-08 -3.9422426374349226e-08 -3.1413451648927644e-08 -3.092997433337718e-08 -2.8827180848252276e-08 -1.864112001604039e-08 -3.3595468681934686e-08 -3.6086408242419924e-08 -3.5647309262820034e-08 -3.416983940408022e-08 -3.47842328106849e-08 -3.695170361135258e-08 -4.0468029278607005e-08 -3.875740879191945e-08 -3.374084882322463e-08 -2.721920580897633e-08 -2.071202684496376e-08 -1.1522341836945966e-08 -9.784354709755546e-09 -2.9650398980135508e-08 -5.7775333753021683e-08 -6.211742519737132e-08 -4.822873186901619e-08 -3.8035767740100873e-08 -4.283725714364261e-08 -3.60714510995625e-08 -3.145059795976035e-08 -2.9009871664582158e-08 -2.812000384666945e-08 -2.142232676648385e-08 -2.8621150314496537e-08 -3.1909667190538e-08 -3.2843502433883223e-08 -3.1474512951911494e-08 -2.9804819152822796e-08 -3.118350612302076e-08 -3.568807158621167e-08 -3.618995769297127e-08 -3.4015337049289326e-08 -2.8976423548412e-08 -2.0906551884213795e-08 -1.385319065959467e-08 -8.923497174417939e-09 -2.2680288226475518e-08 -4.246004128806268e-08 -4.294779207300098e-08 -4.5546883281839853e-08 -4.601137653145591e-08 -4.722208328187057e-08 -4.455971185325033e-08 -4.071482213575439e-08 -3.919609686100126e-08 -3.429220855635876e-08 -2.1552667582812776e-08 -2.1880491994121763e-08 -2.5024779278323846e-08 -2.340957221393002e-08 -2.5545895997328686e-08 -2.139980887009411e-08 -2.387579128772193e-08 -2.838084984353452e-08 -2.9053592543703837e-08 -2.755722080113323e-08 -2.476163218255764e-08 -1.836424850897095e-08 -1.2363311303209424e-08 -7.770235714428189e-09 -2.177176507104285e-08 -4.137581279510718e-08 -4.087762488301012e-08 -3.5789155573654655e-08 -3.893122394105921e-08 -4.610629686112798e-08 -5.0537473705793214e-08 -4.701424474183537e-08 -3.453604285777611e-08 -3.2959461382080014e-08 -1.8337785871607828e-08 -2.2063840267280545e-08 -2.6118294348987537e-08 -2.9752715699132674e-08 -2.8454156279956586e-08 -2.885101365829981e-08 -2.9448559733663986e-08 -3.0920030298840104e-08 -2.9067727865525134e-08 -2.4992317347397035e-08 -1.9460475589053846e-08 -1.2290087048890972e-08 -7.487447095898671e-09 -6.9106930927483785e-09 -2.7016544741468683e-08 -5.6372403062258135e-08 -5.895826295241544e-08 -4.810595180621959e-08 -4.0753612088659346e-08 -4.026668312475717e-08 -3.558205667255196e-08 -3.137663406650939e-08 -3.199579403512357e-08 -2.896097331293291e-08 -1.9402290659696418e-08 -3.229707362696583e-08 -3.89763419159423e-08 -3.912994026759346e-08 -3.452009952967534e-08 -3.3933976766713263e-08 -3.4867318917436816e-08 -3.6627002119980855e-08 -3.439986711209072e-08 -3.037080730039989e-08 -2.4728841523216376e-08 -1.7694053454013604e-08 -1.013412174272899e-08 -4.7832449765398245e-09 -1.0727805259223392e-08 -2.404615478850998e-08 -3.262908932555904e-08 -2.8356359576658083e-08 -2.323698979634444e-08 -2.0556949215447575e-08 -2.0447811381850597e-08 -2.5025436735152743e-08 -2.3343086892107763e-08 -3.100508877607871e-08 -1.9600102983090943e-08 -3.043786789694743e-08 -3.985486860355653e-08 -3.834370408233572e-08 -3.5027163108962506e-08 -3.3358866405635216e-08 -3.327208210422075e-08 -3.7117300550131134e-08 -3.7325714364891624e-08 -3.167207872899518e-08 -2.406078320295295e-08 -1.5800084694167263e-08 -9.56049065951596e-09 -5.596519073885978e-09 -9.346652825917062e-09 -2.194319693917786e-08 -3.243579701786319e-08 -2.578570337566904e-08 -2.070635627981452e-08 -2.4616087677060465e-08 -2.3595139403886328e-08 -2.090145659378984e-08 -2.7129216405520988e-08 -3.158792425489631e-08 -1.704070573029676e-08 -3.400605047158115e-08 -3.777007299912269e-08 -3.6565201178064495e-08 -3.571888987506624e-08 -3.383198877613055e-08 -3.9566080691463313e-08 -4.2673386029039914e-08 -3.959131059727225e-08 -3.4407016955104984e-08 -2.5515570801095793e-08 -1.8369425981498515e-08 -1.0952819858913546e-08 -8.651227865150779e-09 -2.9775397959729636e-08 -6.173462095874578e-08 -6.557737394154779e-08 -4.779612527560166e-08 -4.20688544748687e-08 -3.827804058154959e-08 -3.9422426374349226e-08 -3.1413451648927644e-08 -3.092997433337718e-08 -2.8827180848252276e-08 -1.864112001604039e-08 -3.3595468681934686e-08 -3.6086408242419924e-08 -3.5647309262820034e-08 -3.416983940408022e-08 -3.47842328106849e-08 -3.695170361135258e-08 -4.0468029278607005e-08 -3.116452205708635e-08 -2.7712955887478314e-08 -2.2159253689574285e-08 -1.5708944741261353e-08 -9.776629592015998e-09 -7.873702982875927e-09 -2.694274521242495e-08 -5.4338560362063856e-08 -6.030646036217327e-08 -4.8049903611556076e-08 -3.6315531947290684e-08 -3.7234574411985714e-08 -3.790592001639363e-08 -2.981952974936937e-08 -3.113805941972322e-08 -2.882487974935114e-08 -1.607473728443917e-08 -2.7521800314476386e-08 -3.155768124076702e-08 -3.1090804710146216e-08 -3.0758049372620496e-08 -2.7969035322333877e-08 -2.953986405077712e-08 -3.366828202573508e-08 -3.55175437212164e-08 -3.321512990641751e-08 -2.69134062014354e-08 -1.890213037711268e-08 -1.0104536185428604e-08 -6.50849387767036e-09 -2.2574191130712194e-08 -4.336560588776533e-08 -4.536402810130275e-08 -4.481603783441672e-08 -4.3578046625602815e-08 -4.525604081715634e-08 -4.216977409810446e-08 -4.1514125275486475e-08 -4.068745549525153e-08 -3.1703225746264195e-08 -2.0617846154224202e-08 -2.7703587127666528e-08 -2.81338104400763e-08 -2.5606628571898097e-08 -2.6258168289335473e-08 -2.450752511818877e-08 -2.5191691130760187e-08 -2.994485745737795e-08 -3.177760055003322e-08 -2.9608814835707747e-08 -2.6286028022460002e-08 -2.063247456866717e-08 -1.4629236264004505e-08 -9.763727001748886e-09 -2.305298406635677e-08 -4.3068764129518125e-08 -4.19042437213335e-08 -3.822125274795357e-08 -3.5527816484167924e-08 -4.469161412954788e-08 -4.704974741059582e-08 -4.5236317112289425e-08 -4.7123711303846795e-08 -3.67669582424324e-08 -1.824072880724184e-08 -2.3120291209215144e-08 -2.4045086421163025e-08 -2.7504213344303376e-08 -2.8553267896912878e-08 -2.828247786551074e-08 -2.8571841052329234e-08 -2.793040973363615e-08 -2.7335575667691172e-08 -2.3896418995728587e-08 -1.8274670016033672e-08 -1.208701507086527e-08 -7.1074370487959426e-09 -6.188969858826196e-09 -2.7515307928291022e-08 -6.05103541612351e-08 -6.63923738630698e-08 -5.330528477334789e-08 -3.7333192936320334e-08 -3.609388681384863e-08 -3.9872537755833145e-08 -2.900420109943292e-08 -2.9491458791749545e-08 -2.7738678885908928e-08 -1.989793092658149e-08 -3.4442437441761837e-08 -4.1444845762141405e-08 -3.640650753598937e-08 -3.3007784459003975e-08 -3.2866595604998245e-08 -3.4616006044590765e-08 -3.5180761460613674e-08 -3.2131723234498114e-08 -2.876874937258402e-08 -2.292880690779876e-08 -1.5584356672185283e-08 -7.445945133574518e-09 -4.269606828963688e-09 -1.1591456986083812e-08 -2.9496800628484337e-08 -3.534101656265743e-08 -2.9187713736798922e-08 -1.875370949798908e-08 -1.8645886578049896e-08 -2.3612808556162948e-08 -1.853403673503372e-08 -2.0536650235855366e-08 -3.230734638991735e-08 -1.8447663344137313e-08 -3.3017153218815765e-08 -3.785357001639267e-08 -3.52112510210538e-08 -3.275869050295545e-08 -3.3119634302020156e-08 -3.322984050296409e-08 -3.5108934302056627e-08 -3.2724831476267236e-08 -2.8832276138676232e-08 -2.2515266562422256e-08 -1.4520509340925589e-08 -8.604219701884611e-09 -5.042693877643483e-09 -9.83275996878312e-09 -2.3222114835590635e-08 -2.8199063030344373e-08 -2.0741201491746084e-08 -1.8631093799399702e-08 -2.028073516520703e-08 -2.561550423908821e-08 -2.914349976505557e-08 -2.331736389367715e-08 -2.7749033830964064e-08 -1.7195783359812946e-08 -2.7794316170054377e-08 -2.926184199425711e-08 -2.9140705573532753e-08 -2.781231405074544e-08 -2.8889392700686698e-08 -3.1258374019411455e-08 -3.417214050298137e-08 -3.204888367405703e-08 -2.8724206672426217e-08 -2.1706430298671167e-08 -1.45853510206756e-08 -8.627559419310472e-09 -6.644340894941298e-09 -2.752064976502581e-08 -5.572069898061353e-08 -5.822207566825751e-08 -4.29937318689202e-08 -3.3939318603448055e-08 -3.6117883988103385e-08 -3.583164372122215e-08 -3.194525204140207e-08 -3.135600635850273e-08 -2.7335575667691172e-08 -2.003575031433912e-08 -2.7185675510702556e-08 -3.264404646841646e-08 -3.432064356420858e-08 -2.9538466955015714e-08 -2.8521216876504126e-08 -3.034935777135711e-08 -3.180677519681554e-08 -3.116452205708635e-08 -2.7712955887478314e-08 -2.2159253689574285e-08 -1.5708944741261353e-08 -9.776629592015998e-09 -7.873702982875927e-09 -2.694274521242495e-08 -5.4338560362063856e-08 -6.030646036217327e-08 -4.8049903611556076e-08 -3.6315531947290684e-08 -3.7234574411985714e-08 -3.790592001639363e-08 -2.981952974936937e-08 -3.113805941972322e-08 -2.882487974935114e-08 -1.607473728443917e-08 -2.7521800314476386e-08 -3.155768124076702e-08 -3.1090804710146216e-08 -3.0758049372620496e-08 -2.7969035322333877e-08 -2.953986405077712e-08 -3.366828202573508e-08 -3.55175437212164e-08 -3.321512990641751e-08 -2.69134062014354e-08 -1.890213037711268e-08 -1.0104536185428604e-08 -6.50849387767036e-09 -2.2574191130712194e-08 -4.336560588776533e-08 -4.536402810130275e-08 -4.481603783441672e-08 -4.3578046625602815e-08 -4.525604081715634e-08 -4.216977409810446e-08 -4.1514125275486475e-08 -4.068745549525153e-08 -3.1703225746264195e-08 -2.0617846154224202e-08 -2.7703587127666528e-08 -2.81338104400763e-08 -2.5606628571898097e-08 -2.6258168289335473e-08 -2.450752511818877e-08 -2.5191691130760187e-08 -2.994485745737795e-08 -3.177760055003322e-08 -2.9608814835707747e-08 -2.6286028022460002e-08 -2.063247456866717e-08 -1.4629236264004505e-08 -9.763727001748886e-09 -2.305298406635677e-08 -4.3068764129518125e-08 -4.19042437213335e-08 -3.822125274795357e-08 -3.5527816484167924e-08 -4.469161412954788e-08 -4.704974741059582e-08 -4.5236317112289425e-08 -4.7123711303846795e-08 -3.67669582424324e-08 -1.824072880724184e-08 -2.3120291209215144e-08 -2.4045086421163025e-08 -2.7504213344303376e-08 -2.8553267896912878e-08 -2.828247786551074e-08 -2.8571841052329234e-08 -2.793040973363615e-08 -2.7335575667691172e-08 -2.3896418995728587e-08 -1.8274670016033672e-08 -1.208701507086527e-08 -7.1074370487959426e-09 -6.188969858826196e-09 -2.7515307928291022e-08 -6.05103541612351e-08 -6.63923738630698e-08 -5.330528477334789e-08 -3.7333192936320334e-08 -3.609388681384863e-08 -3.9872537755833145e-08 -2.900420109943292e-08 -2.9491458791749545e-08 -2.7738678885908928e-08 -1.989793092658149e-08 -3.4442437441761837e-08 -4.1444845762141405e-08 -3.640650753598937e-08 -3.3007784459003975e-08 -3.2866595604998245e-08 -3.4616006044590765e-08 -3.5180761460613674e-08 -3.2131723234498114e-08 -2.876874937258402e-08 -2.292880690779876e-08 -1.5584356672185283e-08 -7.445945133574518e-09 -4.269606828963688e-09 -1.1591456986083812e-08 -2.9496800628484337e-08 -3.534101656265743e-08 -2.9187713736798922e-08 -1.875370949798908e-08 -1.8645886578049896e-08 -2.3612808556162948e-08 -1.853403673503372e-08 -2.0536650235855366e-08 -3.230734638991735e-08 -1.8447663344137313e-08 -3.3017153218815765e-08 -3.785357001639267e-08 -3.52112510210538e-08 -3.275869050295545e-08 -3.3119634302020156e-08 -3.322984050296409e-08 -3.5108934302056627e-08 -3.2724831476267236e-08 -2.8832276138676232e-08 -2.2515266562422256e-08 -1.4520509340925589e-08 -8.604219701884611e-09 -5.042693877643483e-09 -9.83275996878312e-09 -2.3222114835590635e-08 -2.8199063030344373e-08 -2.0741201491746084e-08 -1.8631093799399702e-08 -2.028073516520703e-08 -2.561550423908821e-08 -2.914349976505557e-08 -2.331736389367715e-08 -2.7749033830964064e-08 -1.7195783359812946e-08 -2.7794316170054377e-08 -2.926184199425711e-08 -2.9140705573532753e-08 -2.781231405074544e-08 -2.8889392700686698e-08 -3.1258374019411455e-08 -3.417214050298137e-08 -3.204888367405703e-08 -2.8724206672426217e-08 -2.1706430298671167e-08 -1.45853510206756e-08 -8.627559419310472e-09 -6.644340894941298e-09 -2.752064976502581e-08 -5.572069898061353e-08 -5.822207566825751e-08 -4.29937318689202e-08 -3.3939318603448055e-08 -3.6117883988103385e-08 -3.583164372122215e-08 -3.194525204140207e-08 -3.135600635850273e-08 -2.7335575667691172e-08 -2.003575031433912e-08 -2.7185675510702556e-08 -3.264404646841646e-08 -3.432064356420858e-08 -2.9538466955015714e-08 -2.8521216876504126e-08 -3.034935777135711e-08 -3.180677519681554e-08 -3.116452205708635e-08 -2.7712955887478314e-08 -2.2159253689574285e-08 -1.5708944741261353e-08 -9.776629592015998e-09 -7.873702982875927e-09 -2.694274521242495e-08 -5.4338560362063856e-08 -6.030646036217327e-08 -4.8049903611556076e-08 -3.6315531947290684e-08 -3.7234574411985714e-08 -3.790592001639363e-08 -2.981952974936937e-08 -3.113805941972322e-08 -2.882487974935114e-08 -1.607473728443917e-08 -2.7521800314476386e-08 -3.155768124076702e-08 -3.1090804710146216e-08 -3.0758049372620496e-08 -2.7969035322333877e-08 -2.953986405077712e-08 -3.366828202573508e-08 -3.55175437212164e-08 -3.321512990641751e-08 -2.69134062014354e-08 -1.890213037711268e-08 -1.0104536185428604e-08 -6.50849387767036e-09 -2.2574191130712194e-08 -4.336560588776533e-08 -4.536402810130275e-08 -4.481603783441672e-08 -4.3578046625602815e-08 -4.525604081715634e-08 -4.216977409810446e-08 -4.1514125275486475e-08 -4.068745549525153e-08 -3.1703225746264195e-08 -2.0617846154224202e-08 -2.7703587127666528e-08 -2.81338104400763e-08 -2.5606628571898097e-08 -2.6258168289335473e-08 -2.450752511818877e-08 -2.5191691130760187e-08 -2.994485745737795e-08 -3.177760055003322e-08 -2.9608814835707747e-08 -2.6286028022460002e-08 -2.063247456866717e-08 -1.4629236264004505e-08 -9.763727001748886e-09 -2.305298406635677e-08 -4.3068764129518125e-08 -4.19042437213335e-08 -3.822125274795357e-08 -3.5527816484167924e-08 -4.469161412954788e-08 -4.704974741059582e-08 -4.5236317112289425e-08 -4.7123711303846795e-08 -3.67669582424324e-08 -1.824072880724184e-08 -2.3120291209215144e-08 -2.4045086421163025e-08 -2.7504213344303376e-08 -2.8553267896912878e-08 -2.828247786551074e-08 -2.8571841052329234e-08 -2.793040973363615e-08 -2.7335575667691172e-08 -2.3896418995728587e-08 -1.8274670016033672e-08 -1.208701507086527e-08 -7.1074370487959426e-09 -6.188969858826196e-09 -2.7515307928291022e-08 -6.05103541612351e-08 -6.63923738630698e-08 -5.330528477334789e-08 -3.7333192936320334e-08 -3.609388681384863e-08 -3.9872537755833145e-08 -2.900420109943292e-08 -2.9491458791749545e-08 -2.7738678885908928e-08 -1.989793092658149e-08 -3.4442437441761837e-08 -4.1444845762141405e-08 -3.640650753598937e-08 -3.3007784459003975e-08 -3.2866595604998245e-08 -3.4616006044590765e-08 -3.5180761460613674e-08 -3.2131723234498114e-08 -2.876874937258402e-08 -2.292880690779876e-08 -1.5584356672185283e-08 -7.445945133574518e-09 -4.269606828963688e-09 -1.1591456986083812e-08 -2.9496800628484337e-08 -3.534101656265743e-08 -2.9187713736798922e-08 -1.875370949798908e-08 -1.8645886578049896e-08 -2.3612808556162948e-08 -1.853403673503372e-08 -2.0536650235855366e-08 -3.230734638991735e-08 -1.8447663344137313e-08 -3.3017153218815765e-08 -3.785357001639267e-08 -3.52112510210538e-08 -3.275869050295545e-08 -3.3119634302020156e-08 -3.322984050296409e-08 -3.5108934302056627e-08 -3.2724831476267236e-08 -2.8832276138676232e-08 -2.2515266562422256e-08 -1.4520509340925589e-08 -8.604219701884611e-09 -5.042693877643483e-09 -9.83275996878312e-09 -2.3222114835590635e-08 -2.8199063030344373e-08 -2.0741201491746084e-08 -1.8631093799399702e-08 -2.028073516520703e-08 -2.561550423908821e-08 -2.914349976505557e-08 -2.331736389367715e-08 -2.7749033830964064e-08 -1.7195783359812946e-08 -2.7794316170054377e-08 -2.926184199425711e-08 -2.9140705573532753e-08 -2.781231405074544e-08 -2.8889392700686698e-08 -3.1258374019411455e-08 -3.417214050298137e-08 -3.204888367405703e-08 -2.8724206672426217e-08 -2.1706430298671167e-08 -1.45853510206756e-08 -8.627559419310472e-09 -6.644340894941298e-09 -2.752064976502581e-08 -5.572069898061353e-08 -5.822207566825751e-08 -4.29937318689202e-08 -3.3939318603448055e-08 -3.6117883988103385e-08 -3.583164372122215e-08 -3.194525204140207e-08 -3.135600635850273e-08 -2.7335575667691172e-08 -2.003575031433912e-08 -2.7185675510702556e-08 -3.264404646841646e-08 -3.432064356420858e-08 -2.9538466955015714e-08 -2.8521216876504126e-08 -3.034935777135711e-08 -3.180677519681554e-08 -3.116452205708635e-08 -2.7712955887478314e-08 -2.2159253689574285e-08 -1.5708944741261353e-08 -9.776629592015998e-09 -7.873702982875927e-09 -2.694274521242495e-08 -5.4338560362063856e-08 -6.030646036217327e-08 -4.8049903611556076e-08 -3.6315531947290684e-08 -3.7234574411985714e-08 -3.790592001639363e-08 -2.981952974936937e-08 -3.113805941972322e-08 -2.882487974935114e-08 -1.607473728443917e-08 -2.7521800314476386e-08 -3.155768124076702e-08 -3.1090804710146216e-08 -3.0758049372620496e-08 -2.7969035322333877e-08 -2.953986405077712e-08 -3.366828202573508e-08 -3.55175437212164e-08 -3.321512990641751e-08 -2.69134062014354e-08 -1.890213037711268e-08 -1.0104536185428604e-08 -6.50849387767036e-09 -2.2574191130712194e-08 -4.336560588776533e-08 -4.536402810130275e-08 -4.481603783441672e-08 -4.3578046625602815e-08 -4.525604081715634e-08 -4.216977409810446e-08 -4.1514125275486475e-08 -4.068745549525153e-08 -3.1703225746264195e-08 -2.0617846154224202e-08 -2.7703587127666528e-08 -2.81338104400763e-08 -2.5606628571898097e-08 -2.6258168289335473e-08 -2.450752511818877e-08 -2.5191691130760187e-08 -2.994485745737795e-08 -3.177760055003322e-08 -2.9608814835707747e-08 -2.6286028022460002e-08 -2.063247456866717e-08 -1.4629236264004505e-08 -9.763727001748886e-09 -2.305298406635677e-08 -4.3068764129518125e-08 -4.19042437213335e-08 -3.822125274795357e-08 -3.5527816484167924e-08 -4.469161412954788e-08 -4.704974741059582e-08 -4.5236317112289425e-08 -4.7123711303846795e-08 -3.67669582424324e-08 -1.824072880724184e-08 -2.3120291209215144e-08 -2.4045086421163025e-08 -2.7504213344303376e-08 -2.8553267896912878e-08 -2.828247786551074e-08 -2.8571841052329234e-08 -2.793040973363615e-08 -2.7335575667691172e-08 -2.3896418995728587e-08 -1.8274670016033672e-08 -1.208701507086527e-08 -7.1074370487959426e-09 -6.188969858826196e-09 -2.7515307928291022e-08 -6.05103541612351e-08 -6.63923738630698e-08 -5.330528477334789e-08 -3.7333192936320334e-08 -3.609388681384863e-08 -3.9872537755833145e-08 -2.900420109943292e-08 -2.9491458791749545e-08 -2.7738678885908928e-08 -1.989793092658149e-08 -3.4442437441761837e-08 -4.1444845762141405e-08 -3.640650753598937e-08 -3.3007784459003975e-08 -3.2866595604998245e-08 -3.4616006044590765e-08 -3.5180761460613674e-08 -3.2131723234498114e-08 -2.876874937258402e-08 -2.292880690779876e-08 -1.5584356672185283e-08 -7.445945133574518e-09 -4.269606828963688e-09 -1.1591456986083812e-08 -2.9496800628484337e-08 -3.534101656265743e-08 -2.9187713736798922e-08 -1.875370949798908e-08 -1.8645886578049896e-08 -2.3612808556162948e-08 -1.853403673503372e-08 -2.0536650235855366e-08 -3.230734638991735e-08 -1.8447663344137313e-08 -3.3017153218815765e-08 -3.785357001639267e-08 -3.52112510210538e-08 -3.275869050295545e-08 -3.3119634302020156e-08 -3.322984050296409e-08 -3.5108934302056627e-08 -3.2724831476267236e-08 -2.8832276138676232e-08 -2.2515266562422256e-08 -1.4520509340925589e-08 -8.604219701884611e-09 -5.042693877643483e-09 -9.83275996878312e-09 -2.3222114835590635e-08 -2.8199063030344373e-08 -2.0741201491746084e-08 -1.8631093799399702e-08 -2.028073516520703e-08 -2.561550423908821e-08 -2.914349976505557e-08 -2.331736389367715e-08 -2.7749033830964064e-08 -1.7195783359812946e-08 -2.7794316170054377e-08 -2.926184199425711e-08 -2.9140705573532753e-08 -2.781231405074544e-08 -2.8889392700686698e-08 -3.1258374019411455e-08 -3.417214050298137e-08 -3.204888367405703e-08 -2.8724206672426217e-08 -2.1706430298671167e-08 -1.45853510206756e-08 -8.627559419310472e-09 -6.644340894941298e-09 -2.752064976502581e-08 -5.572069898061353e-08 -5.822207566825751e-08 -4.29937318689202e-08 -3.3939318603448055e-08 -3.6117883988103385e-08 -3.583164372122215e-08 -3.194525204140207e-08 -3.135600635850273e-08 -2.7335575667691172e-08 -2.003575031433912e-08 -2.7185675510702556e-08 -3.264404646841646e-08 -3.432064356420858e-08 -2.9538466955015714e-08 -2.8521216876504126e-08 -3.034935777135711e-08 -3.180677519681554e-08 -3.116452205708635e-08 -2.7712955887478314e-08 -2.2159253689574285e-08 -1.5708944741261353e-08 -9.776629592015998e-09 -7.873702982875927e-09 -2.694274521242495e-08 -5.4338560362063856e-08 -6.030646036217327e-08 -4.8049903611556076e-08 -3.6315531947290684e-08 -3.7234574411985714e-08 -3.790592001639363e-08 -2.981952974936937e-08 -3.113805941972322e-08 -2.882487974935114e-08 -1.607473728443917e-08 -2.7521800314476386e-08 -3.155768124076702e-08 -3.1090804710146216e-08 -3.0758049372620496e-08 -2.7969035322333877e-08 -2.953986405077712e-08 -3.366828202573508e-08 -3.55175437212164e-08 -3.321512990641751e-08 -2.69134062014354e-08 -1.890213037711268e-08 -1.0104536185428604e-08 -6.50849387767036e-09 -2.2574191130712194e-08 -4.336560588776533e-08 -4.536402810130275e-08 -4.481603783441672e-08 -4.3578046625602815e-08 -4.525604081715634e-08 -4.216977409810446e-08 -4.1514125275486475e-08 -4.068745549525153e-08 -3.1703225746264195e-08 -2.0617846154224202e-08 -2.7703587127666528e-08 -2.81338104400763e-08 -2.5606628571898097e-08 -2.6258168289335473e-08 -2.450752511818877e-08 -2.5191691130760187e-08 -2.994485745737795e-08 -3.177760055003322e-08 -2.9608814835707747e-08 -2.6286028022460002e-08 -2.063247456866717e-08 -1.4629236264004505e-08 -9.763727001748886e-09 -2.305298406635677e-08 -4.3068764129518125e-08 -4.19042437213335e-08 -3.822125274795357e-08 -3.5527816484167924e-08 -4.469161412954788e-08 -4.704974741059582e-08 -4.5236317112289425e-08 -4.7123711303846795e-08 -3.67669582424324e-08 -1.824072880724184e-08 -2.3120291209215144e-08 -2.4045086421163025e-08 -2.7504213344303376e-08 -2.8553267896912878e-08 -2.828247786551074e-08 -2.8571841052329234e-08 -2.793040973363615e-08 -3.1025634301981756e-08 -2.6760218760302295e-08 -2.2533757535735002e-08 -1.590396287313306e-08 -1.003427048684019e-08 -7.899179434995702e-09 -2.749040675089653e-08 -5.447744811716844e-08 -5.961300777189369e-08 -4.3419024255113235e-08 -3.5198841523408355e-08 -3.470147543234743e-08 -3.3943098980214214e-08 -2.8277218210879558e-08 -3.1402685793354447e-08 -3.0633461303544426e-08 -2.518339073829535e-08 -3.277340109950203e-08 -3.462734717488924e-08 -3.1824690895403e-08 -2.9802928964439717e-08 -3.016543422347305e-08 -3.286199340719596e-08 -3.3241756907987856e-08 -3.077662252803685e-08 -2.7904358006791088e-08 -2.149267464717588e-08 -1.368586789664027e-08 -8.776966483677418e-09 -4.652082339174782e-09 -1.0778347252944883e-08 -2.754859168025395e-08 -3.360730290485484e-08 -2.4996837363095704e-08 -2.3507533281435744e-08 -2.1651614835561842e-08 -2.2543783752375682e-08 -2.707177111509607e-08 -2.8545049686551657e-08 -2.5517214443168037e-08 -1.8812387519968176e-08 -2.989439764576008e-08 -3.5918838933154685e-08 -3.512635690802241e-08 -3.037606695503107e-08 -3.149851012616625e-08 -3.200779262225094e-08 -3.583041098966797e-08 -3.327339701787854e-08 -3.069707025174025e-08 -2.4261225353663063e-08 -1.5116247410010296e-08 -9.481431475841041e-09 -5.7983583203574965e-09 -7.869511695591705e-09 -2.4811681083657456e-08 -3.1588992622243264e-08 -2.5520830455726975e-08 -1.7072921114912736e-08 -2.2004915698990607e-08 -2.6421792857627324e-08 -2.8400655730505056e-08 -2.714967974932042e-08 -3.3682746075970825e-08 -2.1324201334770907e-08 -3.013198610730289e-08 -3.5399365856222076e-08 -3.351903932557536e-08 -3.164158916855506e-08 -3.432828649984451e-08 -3.666053241825462e-08 -4.026446420795964e-08 -4.034960486730186e-08 -3.498985243392258e-08 -2.6395494584471426e-08 -1.932249183708899e-08 -1.1729769466463114e-08 -9.758713893428543e-09 -3.1462514364784115e-08 -6.33734142868763e-08 -6.680369529164877e-08 -4.7293335165702345e-08 -3.94405064371439e-08 -3.896606915299077e-08 -3.5454016955124184e-08 -3.3725809498263606e-08 -3.2702067033566654e-08 -2.9917572998978706e-08 -1.8326691287620182e-08 -3.25930935641769e-08 -3.849352205722073e-08 -3.799163595046113e-08 -3.501121978086174e-08 -3.324151036167702e-08 -3.558419340724588e-08 -4.118194521268604e-08 -4.207419631160349e-08 -3.622077598182584e-08 -2.9575941994262868e-08 -2.0777115071024614e-08 -1.2422811146224645e-08 -1.1035823783561849e-08 -2.9043812873373986e-08 -6.300753956159486e-08 -6.216081734807855e-08 -4.660785423947313e-08 -4.077793799132855e-08 -3.9790520016428185e-08 -3.91308442707332e-08 -3.4584941209425355e-08 -2.9744744035082292e-08 -2.741471703346971e-08 -1.9574708713074777e-08 -3.0307116170100454e-08 -3.5142628964537626e-08 -2.880088257509638e-08 -2.827869748874458e-08 -2.8987189403985195e-08 -3.233701412932134e-08 -3.624477315608059e-08 -3.479623139781228e-08 -3.3419434615997394e-08 -2.912698116222952e-08 -2.200992880731095e-08 -1.3124481946865455e-08 -8.851341287446441e-09 -2.3984846939215295e-08 -4.359251067583856e-08 -3.867826742614091e-08 -3.842679018908764e-08 -4.2116684459171e-08 -4.672430628029158e-08 -4.312629160204665e-08 -4.1689666248802095e-08 -3.897305463179781e-08 -4.015754529116019e-08 -1.8233907692642028e-08 -2.3026521428993645e-08 -2.6492551648837415e-08 -2.678265447458842e-08 -2.445764058129618e-08 -2.541185698633722e-08 -2.777771538512472e-08 -3.302487833655531e-08 -3.4852608320890235e-08 -3.284407770860851e-08 -2.835192174306303e-08 -2.198050761421779e-08 -1.4157346625063356e-08 -9.793476923256496e-09 -2.4993139168433152e-08 -4.2960365934853663e-08 -4.1869151963091106e-08 -3.486592182167541e-08 -3.5335428179611804e-08 -5.16356731563628e-08 -4.9843034930270275e-08 -4.0811961382223994e-08 -3.4305028964522264e-08 -3.679087323458354e-08 -1.95202219783799e-08 -2.1026537755487583e-08 -2.5067678336409405e-08 -2.664245180582603e-08 -2.6832621193584623e-08 -2.8068229121393778e-08 -2.8718947017795038e-08 -3.130661491423181e-08 -3.1025634301981756e-08 -2.6760218760302295e-08 -2.2533757535735002e-08 -1.590396287313306e-08 -1.003427048684019e-08 -7.899179434995702e-09 -2.749040675089653e-08 -5.447744811716844e-08 -5.961300777189369e-08 -4.3419024255113235e-08 -3.5198841523408355e-08 -3.470147543234743e-08 -3.3943098980214214e-08 -2.8277218210879558e-08 -3.1402685793354447e-08 -3.0633461303544426e-08 -2.518339073829535e-08 -3.277340109950203e-08 -3.462734717488924e-08 -3.1824690895403e-08 -2.9802928964439717e-08 -3.016543422347305e-08 -3.286199340719596e-08 -3.3241756907987856e-08 -3.077662252803685e-08 -2.7904358006791088e-08 -2.149267464717588e-08 -1.368586789664027e-08 -8.776966483677418e-09 -4.652082339174782e-09 -1.0778347252944883e-08 -2.754859168025395e-08 -3.360730290485484e-08 -2.4996837363095704e-08 -2.3507533281435744e-08 -2.1651614835561842e-08 -2.2543783752375682e-08 -2.707177111509607e-08 -2.8545049686551657e-08 -2.5517214443168037e-08 -1.8812387519968176e-08 -2.989439764576008e-08 -3.5918838933154685e-08 -3.512635690802241e-08 -3.037606695503107e-08 -3.149851012616625e-08 -3.200779262225094e-08 -3.583041098966797e-08 -3.327339701787854e-08 -3.069707025174025e-08 -2.4261225353663063e-08 -1.5116247410010296e-08 -9.481431475841041e-09 -5.7983583203574965e-09 -7.869511695591705e-09 -2.4811681083657456e-08 -3.1588992622243264e-08 -2.5520830455726975e-08 -1.7072921114912736e-08 -2.2004915698990607e-08 -2.6421792857627324e-08 -2.8400655730505056e-08 -2.714967974932042e-08 -3.3682746075970825e-08 -2.1324201334770907e-08 -3.013198610730289e-08 -3.5399365856222076e-08 -3.351903932557536e-08 -3.164158916855506e-08 -3.432828649984451e-08 -3.666053241825462e-08 -4.026446420795964e-08 -4.034960486730186e-08 -3.498985243392258e-08 -2.6395494584471426e-08 -1.932249183708899e-08 -1.1729769466463114e-08 -9.758713893428543e-09 -3.1462514364784115e-08 -6.33734142868763e-08 -6.680369529164877e-08 -4.7293335165702345e-08 -3.94405064371439e-08 -3.896606915299077e-08 -3.5454016955124184e-08 -3.3725809498263606e-08 -3.2702067033566654e-08 -2.9917572998978706e-08 -1.8326691287620182e-08 -3.25930935641769e-08 -3.849352205722073e-08 -3.799163595046113e-08 -3.501121978086174e-08 -3.324151036167702e-08 -3.558419340724588e-08 -4.118194521268604e-08 -4.207419631160349e-08 -3.622077598182584e-08 -2.9575941994262868e-08 -2.0777115071024614e-08 -1.2422811146224645e-08 -1.1035823783561849e-08 -2.9043812873373986e-08 -6.300753956159486e-08 -6.216081734807855e-08 -4.660785423947313e-08 -4.077793799132855e-08 -3.9790520016428185e-08 -3.91308442707332e-08 -3.4584941209425355e-08 -2.9744744035082292e-08 -2.741471703346971e-08 -1.9574708713074777e-08 -3.0307116170100454e-08 -3.5142628964537626e-08 -2.880088257509638e-08 -2.827869748874458e-08 -2.8987189403985195e-08 -3.233701412932134e-08 -3.624477315608059e-08 -3.479623139781228e-08 -3.3419434615997394e-08 -2.912698116222952e-08 -2.200992880731095e-08 -1.3124481946865455e-08 -8.851341287446441e-09 -2.3984846939215295e-08 -4.359251067583856e-08 -3.867826742614091e-08 -3.842679018908764e-08 -4.2116684459171e-08 -4.672430628029158e-08 -4.312629160204665e-08 -4.1689666248802095e-08 -3.897305463179781e-08 -4.015754529116019e-08 -1.8233907692642028e-08 -2.3026521428993645e-08 -2.6492551648837415e-08 -2.678265447458842e-08 -2.445764058129618e-08 -2.541185698633722e-08 -2.777771538512472e-08 -3.302487833655531e-08 -3.4852608320890235e-08 -3.284407770860851e-08 -2.835192174306303e-08 -2.198050761421779e-08 -1.4157346625063356e-08 -9.793476923256496e-09 -2.4993139168433152e-08 -4.2960365934853663e-08 -4.1869151963091106e-08 -3.486592182167541e-08 -3.5335428179611804e-08 -5.16356731563628e-08 -4.9843034930270275e-08 -4.0811961382223994e-08 -3.4305028964522264e-08 -3.679087323458354e-08 -1.95202219783799e-08 -2.1026537755487583e-08 -2.5067678336409405e-08 -2.664245180582603e-08 -2.6832621193584623e-08 -2.8068229121393778e-08 -2.8718947017795038e-08 -3.130661491423181e-08 -3.1025634301981756e-08 -2.6760218760302295e-08 -2.2533757535735002e-08 -1.590396287313306e-08 -1.003427048684019e-08 -7.899179434995702e-09 -2.749040675089653e-08 -5.447744811716844e-08 -5.961300777189369e-08 -4.3419024255113235e-08 -3.5198841523408355e-08 -3.470147543234743e-08 -3.3943098980214214e-08 -2.8277218210879558e-08 -3.1402685793354447e-08 -3.0633461303544426e-08 -2.518339073829535e-08 -3.277340109950203e-08 -3.462734717488924e-08 -3.1824690895403e-08 -2.9802928964439717e-08 -3.016543422347305e-08 -3.286199340719596e-08 -3.3241756907987856e-08 -3.077662252803685e-08 -2.7904358006791088e-08 -2.149267464717588e-08 -1.368586789664027e-08 -8.776966483677418e-09 -4.652082339174782e-09 -1.0778347252944883e-08 -2.754859168025395e-08 -3.360730290485484e-08 -2.4996837363095704e-08 -2.3507533281435744e-08 -2.1651614835561842e-08 -2.2543783752375682e-08 -2.707177111509607e-08 -2.8545049686551657e-08 -2.5517214443168037e-08 -1.8812387519968176e-08 -2.989439764576008e-08 -3.5918838933154685e-08 -3.512635690802241e-08 -3.037606695503107e-08 -3.149851012616625e-08 -3.200779262225094e-08 -3.583041098966797e-08 -3.327339701787854e-08 -3.069707025174025e-08 -2.4261225353663063e-08 -1.5116247410010296e-08 -9.481431475841041e-09 -5.7983583203574965e-09 -7.869511695591705e-09 -2.4811681083657456e-08 -3.1588992622243264e-08 -2.5520830455726975e-08 -1.7072921114912736e-08 -2.2004915698990607e-08 -2.6421792857627324e-08 -2.8400655730505056e-08 -2.714967974932042e-08 -3.3682746075970825e-08 -2.1324201334770907e-08 -3.013198610730289e-08 -3.5399365856222076e-08 -3.351903932557536e-08 -3.164158916855506e-08 -3.432828649984451e-08 -3.666053241825462e-08 -4.026446420795964e-08 -4.034960486730186e-08 -3.498985243392258e-08 -2.6395494584471426e-08 -1.932249183708899e-08 -1.1729769466463114e-08 -9.758713893428543e-09 -3.1462514364784115e-08 -6.33734142868763e-08 -6.680369529164877e-08 -4.7293335165702345e-08 -3.94405064371439e-08 -3.896606915299077e-08 -3.5454016955124184e-08 -3.3725809498263606e-08 -3.2702067033566654e-08 -2.9917572998978706e-08 -1.8326691287620182e-08 -3.25930935641769e-08 -3.849352205722073e-08 -3.799163595046113e-08 -3.501121978086174e-08 -3.324151036167702e-08 -3.558419340724588e-08 -4.118194521268604e-08 -4.207419631160349e-08 -3.622077598182584e-08 -2.9575941994262868e-08 -2.0777115071024614e-08 -1.2422811146224645e-08 -1.1035823783561849e-08 -2.9043812873373986e-08 -6.300753956159486e-08 -6.216081734807855e-08 -4.660785423947313e-08 -4.077793799132855e-08 -3.9790520016428185e-08 -3.91308442707332e-08 -3.4584941209425355e-08 -2.9744744035082292e-08 -2.741471703346971e-08 -1.9574708713074777e-08 -3.0307116170100454e-08 -3.5142628964537626e-08 -2.880088257509638e-08 -2.827869748874458e-08 -2.8987189403985195e-08 -3.233701412932134e-08 -3.624477315608059e-08 -3.479623139781228e-08 -3.3419434615997394e-08 -2.912698116222952e-08 -2.200992880731095e-08 -1.3124481946865455e-08 -8.851341287446441e-09 -2.3984846939215295e-08 -4.359251067583856e-08 -3.867826742614091e-08 -3.842679018908764e-08 -4.2116684459171e-08 -4.672430628029158e-08 -4.312629160204665e-08 -4.1689666248802095e-08 -3.897305463179781e-08 -4.015754529116019e-08 -1.8233907692642028e-08 -2.3026521428993645e-08 -2.6492551648837415e-08 -2.678265447458842e-08 -2.445764058129618e-08 -2.541185698633722e-08 -2.777771538512472e-08 -3.302487833655531e-08 -3.4852608320890235e-08 -3.284407770860851e-08 -2.835192174306303e-08 -2.198050761421779e-08 -1.4157346625063356e-08 -9.793476923256496e-09 -2.4993139168433152e-08 -4.2960365934853663e-08 -4.1869151963091106e-08 -3.486592182167541e-08 -3.5335428179611804e-08 -5.16356731563628e-08 -4.9843034930270275e-08 -4.0811961382223994e-08 -3.4305028964522264e-08 -3.679087323458354e-08 -1.95202219783799e-08 -2.1026537755487583e-08 -2.5067678336409405e-08 -2.664245180582603e-08 -2.6832621193584623e-08 -2.8068229121393778e-08 -2.8718947017795038e-08 -3.130661491423181e-08 -3.1025634301981756e-08 -2.6760218760302295e-08 -2.2533757535735002e-08 -1.590396287313306e-08 -1.003427048684019e-08 -7.899179434995702e-09 -2.749040675089653e-08 -5.447744811716844e-08 -5.961300777189369e-08 -4.3419024255113235e-08 -3.5198841523408355e-08 -3.470147543234743e-08 -3.3943098980214214e-08 -2.8277218210879558e-08 -3.1402685793354447e-08 -3.0633461303544426e-08 -2.518339073829535e-08 -3.277340109950203e-08 -3.462734717488924e-08 -3.1824690895403e-08 -2.9802928964439717e-08 -3.016543422347305e-08 -3.286199340719596e-08 -3.3241756907987856e-08 -3.077662252803685e-08 -2.7904358006791088e-08 -2.149267464717588e-08 -1.368586789664027e-08 -8.776966483677418e-09 -4.652082339174782e-09 -1.0778347252944883e-08 -2.754859168025395e-08 -3.360730290485484e-08 -2.4996837363095704e-08 -2.3507533281435744e-08 -2.1651614835561842e-08 -2.2543783752375682e-08 -2.707177111509607e-08 -2.8545049686551657e-08 -2.5517214443168037e-08 -1.8812387519968176e-08 -2.989439764576008e-08 -3.5918838933154685e-08 -3.512635690802241e-08 -3.037606695503107e-08 -3.149851012616625e-08 -3.200779262225094e-08 -3.583041098966797e-08 -3.327339701787854e-08 -3.069707025174025e-08 -2.4261225353663063e-08 -1.5116247410010296e-08 -9.481431475841041e-09 -5.7983583203574965e-09 -7.869511695591705e-09 -2.4811681083657456e-08 -3.1588992622243264e-08 -2.5520830455726975e-08 -1.7072921114912736e-08 -2.2004915698990607e-08 -2.6421792857627324e-08 -2.8400655730505056e-08 -2.714967974932042e-08 -3.3682746075970825e-08 -2.1324201334770907e-08 -3.013198610730289e-08 -3.5399365856222076e-08 -3.351903932557536e-08 -3.164158916855506e-08 -3.432828649984451e-08 -3.666053241825462e-08 -4.026446420795964e-08 -4.034960486730186e-08 -3.498985243392258e-08 -2.6395494584471426e-08 -1.932249183708899e-08 -1.1729769466463114e-08 -9.758713893428543e-09 -3.1462514364784115e-08 -6.33734142868763e-08 -6.680369529164877e-08 -4.7293335165702345e-08 -3.94405064371439e-08 -3.896606915299077e-08 -3.5454016955124184e-08 -3.3725809498263606e-08 -3.2702067033566654e-08 -2.9917572998978706e-08 -1.8326691287620182e-08 -3.25930935641769e-08 -3.849352205722073e-08 -3.799163595046113e-08 -3.501121978086174e-08 -3.324151036167702e-08 -3.558419340724588e-08 -4.118194521268604e-08 -4.207419631160349e-08 -3.622077598182584e-08 -2.9575941994262868e-08 -2.0777115071024614e-08 -1.2422811146224645e-08 -1.1035823783561849e-08 -2.9043812873373986e-08 -6.300753956159486e-08 -6.216081734807855e-08 -4.660785423947313e-08 -4.077793799132855e-08 -3.9790520016428185e-08 -3.91308442707332e-08 -3.4584941209425355e-08 -2.9744744035082292e-08 -2.741471703346971e-08 -1.9574708713074777e-08 -3.0307116170100454e-08 -3.5142628964537626e-08 -2.880088257509638e-08 -2.827869748874458e-08 -2.8987189403985195e-08 -3.233701412932134e-08 -3.624477315608059e-08 -3.479623139781228e-08 -3.3419434615997394e-08 -2.912698116222952e-08 -2.200992880731095e-08 -1.3124481946865455e-08 -8.851341287446441e-09 -2.3984846939215295e-08 -4.359251067583856e-08 -3.867826742614091e-08 -3.842679018908764e-08 -4.2116684459171e-08 -4.672430628029158e-08 -4.312629160204665e-08 -4.1689666248802095e-08 -3.897305463179781e-08 -4.015754529116019e-08 -1.8233907692642028e-08 -2.3026521428993645e-08 -2.6492551648837415e-08 -2.678265447458842e-08 -2.445764058129618e-08 -2.541185698633722e-08 -2.777771538512472e-08 -3.302487833655531e-08 -3.4852608320890235e-08 -3.284407770860851e-08 -2.835192174306303e-08 -2.198050761421779e-08 -1.4157346625063356e-08 -9.793476923256496e-09 -2.4993139168433152e-08 -4.2960365934853663e-08 -4.1869151963091106e-08 -3.486592182167541e-08 -3.5335428179611804e-08 -5.16356731563628e-08 -4.9843034930270275e-08 -4.0811961382223994e-08 -3.4305028964522264e-08 -3.679087323458354e-08 -1.95202219783799e-08 -2.1026537755487583e-08 -2.5067678336409405e-08 -2.664245180582603e-08 -2.6832621193584623e-08 -2.8068229121393778e-08 -2.8718947017795038e-08 -3.130661491423181e-08 -3.1025634301981756e-08 -2.6760218760302295e-08 -2.2533757535735002e-08 -1.590396287313306e-08 -1.003427048684019e-08 -7.899179434995702e-09 -2.749040675089653e-08 -5.447744811716844e-08 -5.961300777189369e-08 -4.3419024255113235e-08 -3.5198841523408355e-08 -3.470147543234743e-08 -3.3943098980214214e-08 -2.8277218210879558e-08 -3.1402685793354447e-08 -3.0633461303544426e-08 -2.518339073829535e-08 -3.277340109950203e-08 -3.462734717488924e-08 -3.1824690895403e-08 -2.9802928964439717e-08 -3.016543422347305e-08 -3.286199340719596e-08 -3.3241756907987856e-08 -3.077662252803685e-08 -2.7904358006791088e-08 -2.149267464717588e-08 -1.368586789664027e-08 -8.776966483677418e-09 -4.652082339174782e-09 -1.0778347252944883e-08 -2.754859168025395e-08 -3.360730290485484e-08 -2.4996837363095704e-08 -2.3507533281435744e-08 -2.1651614835561842e-08 -2.2543783752375682e-08 -2.707177111509607e-08 -2.8545049686551657e-08 -2.5517214443168037e-08 -1.8812387519968176e-08 -2.989439764576008e-08 -3.5918838933154685e-08 -3.512635690802241e-08 -3.037606695503107e-08 -3.149851012616625e-08 -3.200779262225094e-08 -3.583041098966797e-08 -3.592787896455202e-08 -3.1921337049250926e-08 -2.62536482736368e-08 -1.7754210753857724e-08 -1.064258241777756e-08 -4.956813579368753e-09 -7.80754638946812e-09 -2.0863488461921013e-08 -2.776530588747928e-08 -2.302109741015524e-08 -1.7811902590593474e-08 -2.0391270094565416e-08 -2.1212680220169175e-08 -2.321677299885584e-08 -1.9893246546675594e-08 -2.208356397214746e-08 -2.045175612282398e-08 -3.1151866013130066e-08 -3.265440141347159e-08 -3.1238650314544534e-08 -3.1020045918936125e-08 -3.279509717485565e-08 -3.4818420565787565e-08 -3.764186891748769e-08 -3.8660269545449844e-08 -3.247360078552479e-08 -2.6405520801112116e-08 -1.7881839560767442e-08 -1.2692614992383436e-08 -9.334572056686072e-09 -3.1299054160699486e-08 -6.184071805450911e-08 -6.447087409851337e-08 -4.740165117826318e-08 -3.967497197874946e-08 -3.6338871664716544e-08 -3.470336562073051e-08 -3.193843092680226e-08 -3.170856758299899e-08 -3.049087535377729e-08 -2.0404665777454202e-08 -3.2011079906395435e-08 -3.8759956437131427e-08 -3.684420941982785e-08 -3.305643626434238e-08 -3.589180102106627e-08 -3.899277833666473e-08 -4.220461931003602e-08 -3.842761201012376e-08 -3.357829262227974e-08 -2.642672378384405e-08 -1.8165203454022246e-08 -1.00249017270284e-08 -7.960651648497613e-09 -2.8764968995817857e-08 -5.8181642073280324e-08 -6.1087190346489e-08 -4.9989729985218024e-08 -3.9044635244044025e-08 -3.743690675107891e-08 -3.478735573062216e-08 -3.3345799451160875e-08 -3.0937863815323946e-08 -3.321134952965135e-08 -1.976808320287424e-08 -2.9047921978554603e-08 -3.5641803061878016e-08 -3.147163657828507e-08 -2.970620062848818e-08 -2.8443965699108674e-08 -3.0340482104167e-08 -3.5163996311476794e-08 -3.649296310898938e-08 -3.381875745744898e-08 -2.7574479042891793e-08 -2.138115353257415e-08 -1.3254000942158252e-08 -9.026717896554839e-09 -2.256465800669318e-08 -4.149481248113761e-08 -4.511181122531696e-08 -4.321825337598868e-08 -4.025772527546344e-08 -4.1859865385382924e-08 -4.3938990424667516e-08 -3.6279207457494095e-08 -3.821582872911516e-08 -3.558690541666508e-08 -2.105184984340014e-08 -2.14550352437215e-08 -2.6497236028743313e-08 -2.2507952355200772e-08 -2.2270199529450733e-08 -2.3945481711585058e-08 -2.5414568995756422e-08 -2.8336964600205607e-08 -2.9547589168516668e-08 -2.772002354838896e-08 -2.3770433830891116e-08 -1.9401633202867524e-08 -1.4144444034796244e-08 -1.0141764678364923e-08 -2.3902829199810338e-08 -4.3042301492155e-08 -4.448607668841381e-08 -3.9972224647514715e-08 -3.588497990646646e-08 -3.90492374418463e-08 -4.3183736892471566e-08 -3.6252580455923755e-08 -4.0767993956791476e-08 -3.125442927843807e-08 -1.762271938807823e-08 -2.1474183673863136e-08 -2.139750777119297e-08 -2.7219041444769103e-08 -2.5802057614287868e-08 -2.7132010597043803e-08 -2.939563445893774e-08 -3.1145373626944706e-08 -2.977548014183325e-08 -2.611656852481168e-08 -2.0954464050619697e-08 -1.4570969152543467e-08 -7.621568288993752e-09 -7.665453532322657e-09 -2.790263218261523e-08 -6.036349474208013e-08 -6.29207552601804e-08 -4.586484584071539e-08 -3.536690392529527e-08 -3.5631694663133716e-08 -3.438096522825992e-08 -3.118876577765194e-08 -3.058711059710715e-08 -3.2256311303574184e-08 -1.8959904395952044e-08 -3.499897464742353e-08 -3.9876400314702916e-08 -3.563851577773353e-08 -3.283742095821592e-08 -3.167832456886971e-08 -3.44287130304586e-08 -3.6081312951995964e-08 -3.601318398810147e-08 -3.13382550241225e-08 -2.6463870094676766e-08 -1.6192586421019042e-08 -9.763809183852497e-09 -5.225959968698648e-09 -1.0060979670514148e-08 -2.505231028303393e-08 -3.088321271642185e-08 -2.7989745212444144e-08 -1.9780410518416067e-08 -2.9301289403990956e-08 -2.3878256750830293e-08 -1.848785039280367e-08 -2.135978618563498e-08 -3.359333194724077e-08 -1.8518504317451014e-08 -2.9403359576677293e-08 -3.540750188447968e-08 -3.6677461931598734e-08 -2.9658945918911174e-08 -3.3248002747862384e-08 -3.437036373689395e-08 -3.8162574725974475e-08 -3.592787896455202e-08 -3.1921337049250926e-08 -2.62536482736368e-08 -1.7754210753857724e-08 -1.064258241777756e-08 -4.956813579368753e-09 -7.80754638946812e-09 -2.0863488461921013e-08 -2.776530588747928e-08 -2.302109741015524e-08 -1.7811902590593474e-08 -2.0391270094565416e-08 -2.1212680220169175e-08 -2.321677299885584e-08 -1.9893246546675594e-08 -2.208356397214746e-08 -2.045175612282398e-08 -3.1151866013130066e-08 -3.265440141347159e-08 -3.1238650314544534e-08 -3.1020045918936125e-08 -3.279509717485565e-08 -3.4818420565787565e-08 -3.764186891748769e-08 -3.8660269545449844e-08 -3.247360078552479e-08 -2.6405520801112116e-08 -1.7881839560767442e-08 -1.2692614992383436e-08 -9.334572056686072e-09 -3.1299054160699486e-08 -6.184071805450911e-08 -6.447087409851337e-08 -4.740165117826318e-08 -3.967497197874946e-08 -3.6338871664716544e-08 -3.470336562073051e-08 -3.193843092680226e-08 -3.170856758299899e-08 -3.049087535377729e-08 -2.0404665777454202e-08 -3.2011079906395435e-08 -3.8759956437131427e-08 -3.684420941982785e-08 -3.305643626434238e-08 -3.589180102106627e-08 -3.899277833666473e-08 -4.220461931003602e-08 -3.842761201012376e-08 -3.357829262227974e-08 -2.642672378384405e-08 -1.8165203454022246e-08 -1.00249017270284e-08 -7.960651648497613e-09 -2.8764968995817857e-08 -5.8181642073280324e-08 -6.1087190346489e-08 -4.9989729985218024e-08 -3.9044635244044025e-08 -3.743690675107891e-08 -3.478735573062216e-08 -3.3345799451160875e-08 -3.0937863815323946e-08 -3.321134952965135e-08 -1.976808320287424e-08 -2.9047921978554603e-08 -3.5641803061878016e-08 -3.147163657828507e-08 -2.970620062848818e-08 -2.8443965699108674e-08 -3.0340482104167e-08 -3.5163996311476794e-08 -3.649296310898938e-08 -3.381875745744898e-08 -2.7574479042891793e-08 -2.138115353257415e-08 -1.3254000942158252e-08 -9.026717896554839e-09 -2.256465800669318e-08 -4.149481248113761e-08 -4.511181122531696e-08 -4.321825337598868e-08 -4.025772527546344e-08 -4.1859865385382924e-08 -4.3938990424667516e-08 -3.6279207457494095e-08 -3.821582872911516e-08 -3.558690541666508e-08 -2.105184984340014e-08 -2.14550352437215e-08 -2.6497236028743313e-08 -2.2507952355200772e-08 -2.2270199529450733e-08 -2.3945481711585058e-08 -2.5414568995756422e-08 -2.8336964600205607e-08 -2.9547589168516668e-08 -2.772002354838896e-08 -2.3770433830891116e-08 -1.9401633202867524e-08 -1.4144444034796244e-08 -1.0141764678364923e-08 -2.3902829199810338e-08 -4.3042301492155e-08 -4.448607668841381e-08 -3.9972224647514715e-08 -3.588497990646646e-08 -3.90492374418463e-08 -4.3183736892471566e-08 -3.6252580455923755e-08 -4.0767993956791476e-08 -3.125442927843807e-08 -1.762271938807823e-08 -2.1474183673863136e-08 -2.139750777119297e-08 -2.7219041444769103e-08 -2.5802057614287868e-08 -2.7132010597043803e-08 -2.939563445893774e-08 -3.1145373626944706e-08 -2.977548014183325e-08 -2.611656852481168e-08 -2.0954464050619697e-08 -1.4570969152543467e-08 -7.621568288993752e-09 -7.665453532322657e-09 -2.790263218261523e-08 -6.036349474208013e-08 -6.29207552601804e-08 -4.586484584071539e-08 -3.536690392529527e-08 -3.5631694663133716e-08 -3.438096522825992e-08 -3.118876577765194e-08 -3.058711059710715e-08 -3.2256311303574184e-08 -1.8959904395952044e-08 -3.499897464742353e-08 -3.9876400314702916e-08 -3.563851577773353e-08 -3.283742095821592e-08 -3.167832456886971e-08 -3.44287130304586e-08 -3.6081312951995964e-08 -3.601318398810147e-08 -3.13382550241225e-08 -2.6463870094676766e-08 -1.6192586421019042e-08 -9.763809183852497e-09 -5.225959968698648e-09 -1.0060979670514148e-08 -2.505231028303393e-08 -3.088321271642185e-08 -2.7989745212444144e-08 -1.9780410518416067e-08 -2.9301289403990956e-08 -2.3878256750830293e-08 -1.848785039280367e-08 -2.135978618563498e-08 -3.359333194724077e-08 -1.8518504317451014e-08 -2.9403359576677293e-08 -3.540750188447968e-08 -3.6677461931598734e-08 -2.9658945918911174e-08 -3.3248002747862384e-08 -3.437036373689395e-08 -3.8162574725974475e-08 -3.592787896455202e-08 -3.1921337049250926e-08 -2.62536482736368e-08 -1.7754210753857724e-08 -1.064258241777756e-08 -4.956813579368753e-09 -7.80754638946812e-09 -2.0863488461921013e-08 -2.776530588747928e-08 -2.302109741015524e-08 -1.7811902590593474e-08 -2.0391270094565416e-08 -2.1212680220169175e-08 -2.321677299885584e-08 -1.9893246546675594e-08 -2.208356397214746e-08 -2.045175612282398e-08 -3.1151866013130066e-08 -3.265440141347159e-08 -3.1238650314544534e-08 -3.1020045918936125e-08 -3.279509717485565e-08 -3.4818420565787565e-08 -3.764186891748769e-08 -3.8660269545449844e-08 -3.247360078552479e-08 -2.6405520801112116e-08 -1.7881839560767442e-08 -1.2692614992383436e-08 -9.334572056686072e-09 -3.1299054160699486e-08 -6.184071805450911e-08 -6.447087409851337e-08 -4.740165117826318e-08 -3.967497197874946e-08 -3.6338871664716544e-08 -3.470336562073051e-08 -3.193843092680226e-08 -3.170856758299899e-08 -3.049087535377729e-08 -2.0404665777454202e-08 -3.2011079906395435e-08 -3.8759956437131427e-08 -3.684420941982785e-08 -3.305643626434238e-08 -3.589180102106627e-08 -3.899277833666473e-08 -4.220461931003602e-08 -3.842761201012376e-08 -3.357829262227974e-08 -2.642672378384405e-08 -1.8165203454022246e-08 -1.00249017270284e-08 -7.960651648497613e-09 -2.8764968995817857e-08 -5.8181642073280324e-08 -6.1087190346489e-08 -4.9989729985218024e-08 -3.9044635244044025e-08 -3.743690675107891e-08 -3.478735573062216e-08 -3.3345799451160875e-08 -3.0937863815323946e-08 -3.321134952965135e-08 -1.976808320287424e-08 -2.9047921978554603e-08 -3.5641803061878016e-08 -3.147163657828507e-08 -2.970620062848818e-08 -2.8443965699108674e-08 -3.0340482104167e-08 -3.5163996311476794e-08 -3.649296310898938e-08 -3.381875745744898e-08 -2.7574479042891793e-08 -2.138115353257415e-08 -1.3254000942158252e-08 -9.026717896554839e-09 -2.256465800669318e-08 -4.149481248113761e-08 -4.511181122531696e-08 -4.321825337598868e-08 -4.025772527546344e-08 -4.1859865385382924e-08 -4.3938990424667516e-08 -3.6279207457494095e-08 -3.821582872911516e-08 -3.558690541666508e-08 -2.105184984340014e-08 -2.14550352437215e-08 -2.6497236028743313e-08 -2.2507952355200772e-08 -2.2270199529450733e-08 -2.3945481711585058e-08 -2.5414568995756422e-08 -2.8336964600205607e-08 -2.9547589168516668e-08 -2.772002354838896e-08 -2.3770433830891116e-08 -1.9401633202867524e-08 -1.4144444034796244e-08 -1.0141764678364923e-08 -2.3902829199810338e-08 -4.3042301492155e-08 -4.448607668841381e-08 -3.9972224647514715e-08 -3.588497990646646e-08 -3.90492374418463e-08 -4.3183736892471566e-08 -3.6252580455923755e-08 -4.0767993956791476e-08 -3.125442927843807e-08 -1.762271938807823e-08 -2.1474183673863136e-08 -2.139750777119297e-08 -2.7219041444769103e-08 -2.5802057614287868e-08 -2.7132010597043803e-08 -2.939563445893774e-08 -3.1145373626944706e-08 -2.977548014183325e-08 -2.611656852481168e-08 -2.0954464050619697e-08 -1.4570969152543467e-08 -7.621568288993752e-09 -7.665453532322657e-09 -2.790263218261523e-08 -6.036349474208013e-08 -6.29207552601804e-08 -4.586484584071539e-08 -3.536690392529527e-08 -3.5631694663133716e-08 -3.438096522825992e-08 -3.118876577765194e-08 -3.058711059710715e-08 -3.2256311303574184e-08 -1.8959904395952044e-08 -3.499897464742353e-08 -3.9876400314702916e-08 -3.563851577773353e-08 -3.283742095821592e-08 -3.167832456886971e-08 -3.44287130304586e-08 -3.6081312951995964e-08 -3.601318398810147e-08 -3.13382550241225e-08 -2.6463870094676766e-08 -1.6192586421019042e-08 -9.763809183852497e-09 -5.225959968698648e-09 -1.0060979670514148e-08 -2.505231028303393e-08 -3.088321271642185e-08 -2.7989745212444144e-08 -1.9780410518416067e-08 -2.9301289403990956e-08 -2.3878256750830293e-08 -1.848785039280367e-08 -2.135978618563498e-08 -3.359333194724077e-08 -1.8518504317451014e-08 -2.9403359576677293e-08 -3.540750188447968e-08 -3.6677461931598734e-08 -2.9658945918911174e-08 -3.3248002747862384e-08 -3.437036373689395e-08 -3.8162574725974475e-08 -3.592787896455202e-08 -3.1921337049250926e-08 -2.62536482736368e-08 -1.7754210753857724e-08 -1.064258241777756e-08 -4.956813579368753e-09 -7.80754638946812e-09 -2.0863488461921013e-08 -2.776530588747928e-08 -2.302109741015524e-08 -1.7811902590593474e-08 -2.0391270094565416e-08 -2.1212680220169175e-08 -2.321677299885584e-08 -1.9893246546675594e-08 -2.208356397214746e-08 -2.045175612282398e-08 -3.1151866013130066e-08 -3.265440141347159e-08 -3.1238650314544534e-08 -3.1020045918936125e-08 -3.279509717485565e-08 -3.4818420565787565e-08 -3.764186891748769e-08 -3.8660269545449844e-08 -3.247360078552479e-08 -2.6405520801112116e-08 -1.7881839560767442e-08 -1.2692614992383436e-08 -9.334572056686072e-09 -3.1299054160699486e-08 -6.184071805450911e-08 -6.447087409851337e-08 -4.740165117826318e-08 -3.967497197874946e-08 -3.6338871664716544e-08 -3.470336562073051e-08 -3.193843092680226e-08 -3.170856758299899e-08 -3.049087535377729e-08 -2.0404665777454202e-08 -3.2011079906395435e-08 -3.8759956437131427e-08 -3.684420941982785e-08 -3.305643626434238e-08 -3.589180102106627e-08 -3.899277833666473e-08 -4.220461931003602e-08 -3.842761201012376e-08 -3.357829262227974e-08 -2.642672378384405e-08 -1.8165203454022246e-08 -1.00249017270284e-08 -7.960651648497613e-09 -2.8764968995817857e-08 -5.8181642073280324e-08 -6.1087190346489e-08 -4.9989729985218024e-08 -3.9044635244044025e-08 -3.743690675107891e-08 -3.478735573062216e-08 -3.3345799451160875e-08 -3.0937863815323946e-08 -3.321134952965135e-08 -1.976808320287424e-08 -2.9047921978554603e-08 -3.5641803061878016e-08 -3.147163657828507e-08 -2.970620062848818e-08 -2.8443965699108674e-08 -3.0340482104167e-08 -3.5163996311476794e-08 -3.649296310898938e-08 -3.381875745744898e-08 -2.7574479042891793e-08 -2.138115353257415e-08 -1.3254000942158252e-08 -9.026717896554839e-09 -2.256465800669318e-08 -4.149481248113761e-08 -4.511181122531696e-08 -4.321825337598868e-08 -4.025772527546344e-08 -4.1859865385382924e-08 -4.3938990424667516e-08 -3.6279207457494095e-08 -3.821582872911516e-08 -3.558690541666508e-08 -2.105184984340014e-08 -2.14550352437215e-08 -2.6497236028743313e-08 -2.2507952355200772e-08 -2.2270199529450733e-08 -2.3945481711585058e-08 -2.5414568995756422e-08 -2.8336964600205607e-08 -2.9547589168516668e-08 -2.772002354838896e-08 -2.3770433830891116e-08 -1.9401633202867524e-08 -1.4144444034796244e-08 -1.0141764678364923e-08 -2.3902829199810338e-08 -4.3042301492155e-08 -4.448607668841381e-08 -3.9972224647514715e-08 -3.588497990646646e-08 -3.90492374418463e-08 -4.3183736892471566e-08 -3.6252580455923755e-08 -4.0767993956791476e-08 -3.125442927843807e-08 -1.762271938807823e-08 -2.1474183673863136e-08 -2.139750777119297e-08 -2.7219041444769103e-08 -2.5802057614287868e-08 -2.7132010597043803e-08 -2.939563445893774e-08 -3.1145373626944706e-08 -2.977548014183325e-08 -2.611656852481168e-08 -2.0954464050619697e-08 -1.4570969152543467e-08 -7.621568288993752e-09 -7.665453532322657e-09 -2.790263218261523e-08 -6.036349474208013e-08 -6.29207552601804e-08 -4.586484584071539e-08 -3.536690392529527e-08 -3.5631694663133716e-08 -3.438096522825992e-08 -3.118876577765194e-08 -3.058711059710715e-08 -3.2256311303574184e-08 -1.8959904395952044e-08 -3.499897464742353e-08 -3.9876400314702916e-08 -3.563851577773353e-08 -3.283742095821592e-08 -3.167832456886971e-08 -3.44287130304586e-08 -3.6081312951995964e-08 -3.601318398810147e-08 -3.13382550241225e-08 -2.6463870094676766e-08 -1.6192586421019042e-08 -9.763809183852497e-09 -5.225959968698648e-09 -1.0060979670514148e-08 -2.505231028303393e-08 -3.088321271642185e-08 -2.7989745212444144e-08 -1.9780410518416067e-08 -2.9301289403990956e-08 -2.3878256750830293e-08 -1.848785039280367e-08 -2.135978618563498e-08 -3.359333194724077e-08 -1.8518504317451014e-08 -2.9403359576677293e-08 -3.540750188447968e-08 -3.6677461931598734e-08 -2.9658945918911174e-08 -3.3248002747862384e-08 -3.437036373689395e-08 -3.8162574725974475e-08 -3.592787896455202e-08 -3.1921337049250926e-08 -2.62536482736368e-08 -1.7754210753857724e-08 -1.064258241777756e-08 -4.956813579368753e-09 -7.80754638946812e-09 -2.0863488461921013e-08 -2.776530588747928e-08 -2.302109741015524e-08 -1.7811902590593474e-08 -2.0391270094565416e-08 -2.1212680220169175e-08 -2.321677299885584e-08 -1.9893246546675594e-08 -2.208356397214746e-08 -2.045175612282398e-08 -3.1151866013130066e-08 -3.265440141347159e-08 -3.1238650314544534e-08 -3.1020045918936125e-08 -3.279509717485565e-08 -3.4818420565787565e-08 -3.764186891748769e-08 -3.8660269545449844e-08 -3.247360078552479e-08 -2.6405520801112116e-08 -1.7881839560767442e-08 -1.2692614992383436e-08 -9.334572056686072e-09 -3.1299054160699486e-08 -6.184071805450911e-08 -6.447087409851337e-08 -4.740165117826318e-08 -3.967497197874946e-08 -3.6338871664716544e-08 -3.470336562073051e-08 -3.193843092680226e-08 -3.170856758299899e-08 -3.049087535377729e-08 -2.0404665777454202e-08 -3.2011079906395435e-08 -3.8759956437131427e-08 -3.684420941982785e-08 -3.305643626434238e-08 -3.589180102106627e-08 -3.899277833666473e-08 -4.220461931003602e-08 -3.842761201012376e-08 -3.357829262227974e-08 -2.642672378384405e-08 -1.8165203454022246e-08 -1.00249017270284e-08 -7.960651648497613e-09 -2.8764968995817857e-08 -5.8181642073280324e-08 -6.1087190346489e-08 -4.9989729985218024e-08 -3.9044635244044025e-08 -3.743690675107891e-08 -3.478735573062216e-08 -3.3345799451160875e-08 -3.0937863815323946e-08 -3.321134952965135e-08 -1.976808320287424e-08 -2.9047921978554603e-08 -3.5641803061878016e-08 -3.147163657828507e-08 -2.970620062848818e-08 -2.8443965699108674e-08 -3.0340482104167e-08 -3.5163996311476794e-08 -3.612330800694179e-08 -3.4467338619156324e-08 -2.9416919623773295e-08 -2.2499323234321496e-08 -1.4318670094454071e-08 -9.94658218228599e-09 -2.3527832261027953e-08 -4.376328508714467e-08 -4.579811397258229e-08 -4.232608445917484e-08 -4.453481067585584e-08 -4.736812087998942e-08 -4.4987140974137285e-08 -4.2853447018054216e-08 -3.919749395676268e-08 -3.8835810518765464e-08 -2.0696740973691898e-08 -2.3027589796340604e-08 -2.7608502433787234e-08 -2.865320133490529e-08 -2.6301971350560765e-08 -2.5822027865465625e-08 -2.8441171507585858e-08 -3.5269600314618446e-08 -3.455856075416585e-08 -3.133209136635158e-08 -2.8434843485607723e-08 -2.23279735482901e-08 -1.5353014050516992e-08 -1.1161891130502936e-08 -2.436099442744825e-08 -4.0447565934807586e-08 -3.944001334452223e-08 -3.758047888608939e-08 -3.567796318746738e-08 -3.939185463180549e-08 -4.462233461620281e-08 -4.5538582889375027e-08 -3.933958681390814e-08 -3.418282417645095e-08 -1.9785341444632794e-08 -2.3909650314410148e-08 -2.473426554205478e-08 -2.6015977629990372e-08 -2.853140745735204e-08 -3.056146978078015e-08 -3.016272221405385e-08 -3.204674693936312e-08 -3.115466020465288e-08 -2.828864152328165e-08 -2.273608987482819e-08 -1.6163987048962003e-08 -9.735291993899071e-09 -8.643091836893173e-09 -2.7197591915726322e-08 -6.037836970283394e-08 -5.983350235588518e-08 -5.1105269859649784e-08 -3.947469419224657e-08 -3.910849073855069e-08 -3.615675612311195e-08 -2.8920457535852108e-08 -2.8902459655161036e-08 -3.397473909010491e-08 -2.0652773548259383e-08 -3.9975840660073653e-08 -4.0214333124756196e-08 -3.6379305259693736e-08 -3.4871838933135485e-08 -3.417057904301274e-08 -3.4361981162325504e-08 -3.526746357992453e-08 -3.337801483577685e-08 -2.946598233962977e-08 -2.285443210402973e-08 -1.3759831789891232e-08 -8.005769623380702e-09 -4.879151491455241e-09 -1.0444605730175814e-08 -2.5636460675509318e-08 -2.989554819521064e-08 -2.689606577757323e-08 -2.1271769152666333e-08 -2.6195463344279376e-08 -2.4656521272037657e-08 -2.100697841482788e-08 -2.1080613579664398e-08 -2.6036276609582578e-08 -2.3348264364635335e-08 -3.256063163325009e-08 -4.270256067582224e-08 -3.757530141356182e-08 -3.207592158614544e-08 -3.239832197861603e-08 -3.3759175432330153e-08 -3.740025353286787e-08 -3.501664379970015e-08 -3.080875573054921e-08 -2.447226899573915e-08 -1.632851562039359e-08 -8.709823705026265e-09 -4.852360125677669e-09 -8.352742464831335e-09 -2.233265792819599e-08 -3.1356745997435236e-08 -2.4692845761834243e-08 -1.9338928257811427e-08 -1.9024417347287607e-08 -2.5126602904699337e-08 -2.7550810597051484e-08 -1.8833015227974834e-08 -3.07749788859646e-08 -2.104798728453036e-08 -3.483510353282084e-08 -3.823497715925681e-08 -3.332854120940232e-08 -3.1857892465262325e-08 -3.277635965523207e-08 -3.504696899593304e-08 -3.9732745997588816e-08 -3.6231130926880973e-08 -3.2384022292587515e-08 -2.51114813976347e-08 -1.6464444819768138e-08 -8.994255965628027e-09 -7.1767165621410114e-09 -2.8577675981685694e-08 -5.841545015805698e-08 -6.039275157096608e-08 -4.688168500870891e-08 -3.948644623306311e-08 -3.967554725347474e-08 -3.497004654695204e-08 -3.2341205416605566e-08 -2.96193341449701e-08 -3.1787133674052234e-08 -2.3771091287720007e-08 -3.2843748980194056e-08 -3.870777080133769e-08 -3.830688649991746e-08 -3.751424011057797e-08 -3.7333521664734786e-08 -3.92022605187722e-08 -4.072682072288178e-08 -3.9743840581576465e-08 -3.553767833660138e-08 -2.6895819231262385e-08 -1.764564819498603e-08 -1.0751227158752863e-08 -7.09946538474556e-09 -2.7265145604895536e-08 -5.8462458321323144e-08 -5.9155910911602734e-08 -4.8799240032291956e-08 -4.3469894977249186e-08 -4.311495047174816e-08 -3.511098885464693e-08 -2.9433766955013795e-08 -3.120002472584681e-08 -3.4093656594031734e-08 -2.3460936028687633e-08 -3.1229445918939964e-08 -3.234786216699815e-08 -3.4140500393090674e-08 -3.2494885950360346e-08 -3.0468932732112835e-08 -3.243875557359323e-08 -3.499108516547676e-08 -3.612330800694179e-08 -3.4467338619156324e-08 -2.9416919623773295e-08 -2.2499323234321496e-08 -1.4318670094454071e-08 -9.94658218228599e-09 -2.3527832261027953e-08 -4.376328508714467e-08 -4.579811397258229e-08 -4.232608445917484e-08 -4.453481067585584e-08 -4.736812087998942e-08 -4.4987140974137285e-08 -4.2853447018054216e-08 -3.919749395676268e-08 -3.8835810518765464e-08 -2.0696740973691898e-08 -2.3027589796340604e-08 -2.7608502433787234e-08 -2.865320133490529e-08 -2.6301971350560765e-08 -2.5822027865465625e-08 -2.8441171507585858e-08 -3.5269600314618446e-08 -3.455856075416585e-08 -3.133209136635158e-08 -2.8434843485607723e-08 -2.23279735482901e-08 -1.5353014050516992e-08 -1.1161891130502936e-08 -2.436099442744825e-08 -4.0447565934807586e-08 -3.944001334452223e-08 -3.758047888608939e-08 -3.567796318746738e-08 -3.939185463180549e-08 -4.462233461620281e-08 -4.5538582889375027e-08 -3.933958681390814e-08 -3.418282417645095e-08 -1.9785341444632794e-08 -2.3909650314410148e-08 -2.473426554205478e-08 -2.6015977629990372e-08 -2.853140745735204e-08 -3.056146978078015e-08 -3.016272221405385e-08 -3.204674693936312e-08 -3.115466020465288e-08 -2.828864152328165e-08 -2.273608987482819e-08 -1.6163987048962003e-08 -9.735291993899071e-09 -8.643091836893173e-09 -2.7197591915726322e-08 -6.037836970283394e-08 -5.983350235588518e-08 -5.1105269859649784e-08 -3.947469419224657e-08 -3.910849073855069e-08 -3.615675612311195e-08 -2.8920457535852108e-08 -2.8902459655161036e-08 -3.397473909010491e-08 -2.0652773548259383e-08 -3.9975840660073653e-08 -4.0214333124756196e-08 -3.6379305259693736e-08 -3.4871838933135485e-08 -3.417057904301274e-08 -3.4361981162325504e-08 -3.526746357992453e-08 -3.337801483577685e-08 -2.946598233962977e-08 -2.285443210402973e-08 -1.3759831789891232e-08 -8.005769623380702e-09 -4.879151491455241e-09 -1.0444605730175814e-08 -2.5636460675509318e-08 -2.989554819521064e-08 -2.689606577757323e-08 -2.1271769152666333e-08 -2.6195463344279376e-08 -2.4656521272037657e-08 -2.100697841482788e-08 -2.1080613579664398e-08 -2.6036276609582578e-08 -2.3348264364635335e-08 -3.256063163325009e-08 -4.270256067582224e-08 -3.757530141356182e-08 -3.207592158614544e-08 -3.239832197861603e-08 -3.3759175432330153e-08 -3.740025353286787e-08 -3.501664379970015e-08 -3.080875573054921e-08 -2.447226899573915e-08 -1.632851562039359e-08 -8.709823705026265e-09 -4.852360125677669e-09 -8.352742464831335e-09 -2.233265792819599e-08 -3.1356745997435236e-08 -2.4692845761834243e-08 -1.9338928257811427e-08 -1.9024417347287607e-08 -2.5126602904699337e-08 -2.7550810597051484e-08 -1.8833015227974834e-08 -3.07749788859646e-08 -2.104798728453036e-08 -3.483510353282084e-08 -3.823497715925681e-08 -3.332854120940232e-08 -3.1857892465262325e-08 -3.277635965523207e-08 -3.504696899593304e-08 -3.9732745997588816e-08 -3.6231130926880973e-08 -3.2384022292587515e-08 -2.51114813976347e-08 -1.6464444819768138e-08 -8.994255965628027e-09 -7.1767165621410114e-09 -2.8577675981685694e-08 -5.841545015805698e-08 -6.039275157096608e-08 -4.688168500870891e-08 -3.948644623306311e-08 -3.967554725347474e-08 -3.497004654695204e-08 -3.2341205416605566e-08 -2.96193341449701e-08 -3.1787133674052234e-08 -2.3771091287720007e-08 -3.2843748980194056e-08 -3.870777080133769e-08 -3.830688649991746e-08 -3.751424011057797e-08 -3.7333521664734786e-08 -3.92022605187722e-08 -4.072682072288178e-08 -3.9743840581576465e-08 -3.553767833660138e-08 -2.6895819231262385e-08 -1.764564819498603e-08 -1.0751227158752863e-08 -7.09946538474556e-09 -2.7265145604895536e-08 -5.8462458321323144e-08 -5.9155910911602734e-08 -4.8799240032291956e-08 -4.3469894977249186e-08 -4.311495047174816e-08 -3.511098885464693e-08 -2.9433766955013795e-08 -3.120002472584681e-08 -3.4093656594031734e-08 -2.3460936028687633e-08 -3.1229445918939964e-08 -3.234786216699815e-08 -3.4140500393090674e-08 -3.2494885950360346e-08 -3.0468932732112835e-08 -3.243875557359323e-08 -3.499108516547676e-08 -3.612330800694179e-08 -3.4467338619156324e-08 -2.9416919623773295e-08 -2.2499323234321496e-08 -1.4318670094454071e-08 -9.94658218228599e-09 -2.3527832261027953e-08 -4.376328508714467e-08 -4.579811397258229e-08 -4.232608445917484e-08 -4.453481067585584e-08 -4.736812087998942e-08 -4.4987140974137285e-08 -4.2853447018054216e-08 -3.919749395676268e-08 -3.8835810518765464e-08 -2.0696740973691898e-08 -2.3027589796340604e-08 -2.7608502433787234e-08 -2.865320133490529e-08 -2.6301971350560765e-08 -2.5822027865465625e-08 -2.8441171507585858e-08 -3.5269600314618446e-08 -3.455856075416585e-08 -3.133209136635158e-08 -2.8434843485607723e-08 -2.23279735482901e-08 -1.5353014050516992e-08 -1.1161891130502936e-08 -2.436099442744825e-08 -4.0447565934807586e-08 -3.944001334452223e-08 -3.758047888608939e-08 -3.567796318746738e-08 -3.939185463180549e-08 -4.462233461620281e-08 -4.5538582889375027e-08 -3.933958681390814e-08 -3.418282417645095e-08 -1.9785341444632794e-08 -2.3909650314410148e-08 -2.473426554205478e-08 -2.6015977629990372e-08 -2.853140745735204e-08 -3.056146978078015e-08 -3.016272221405385e-08 -3.204674693936312e-08 -3.115466020465288e-08 -2.828864152328165e-08 -2.273608987482819e-08 -1.6163987048962003e-08 -9.735291993899071e-09 -8.643091836893173e-09 -2.7197591915726322e-08 -6.037836970283394e-08 -5.983350235588518e-08 -5.1105269859649784e-08 -3.947469419224657e-08 -3.910849073855069e-08 -3.615675612311195e-08 -2.8920457535852108e-08 -2.8902459655161036e-08 -3.397473909010491e-08 -2.0652773548259383e-08 -3.9975840660073653e-08 -4.0214333124756196e-08 -3.6379305259693736e-08 -3.4871838933135485e-08 -3.417057904301274e-08 -3.4361981162325504e-08 -3.526746357992453e-08 -3.337801483577685e-08 -2.946598233962977e-08 -2.285443210402973e-08 -1.3759831789891232e-08 -8.005769623380702e-09 -4.879151491455241e-09 -1.0444605730175814e-08 -2.5636460675509318e-08 -2.989554819521064e-08 -2.689606577757323e-08 -2.1271769152666333e-08 -2.6195463344279376e-08 -2.4656521272037657e-08 -2.100697841482788e-08 -2.1080613579664398e-08 -2.6036276609582578e-08 -2.3348264364635335e-08 -3.256063163325009e-08 -4.270256067582224e-08 -3.757530141356182e-08 -3.207592158614544e-08 -3.239832197861603e-08 -3.3759175432330153e-08 -3.740025353286787e-08 -3.501664379970015e-08 -3.080875573054921e-08 -2.447226899573915e-08 -1.632851562039359e-08 -8.709823705026265e-09 -4.852360125677669e-09 -8.352742464831335e-09 -2.233265792819599e-08 -3.1356745997435236e-08 -2.4692845761834243e-08 -1.9338928257811427e-08 -1.9024417347287607e-08 -2.5126602904699337e-08 -2.7550810597051484e-08 -1.8833015227974834e-08 -3.07749788859646e-08 -2.104798728453036e-08 -3.483510353282084e-08 -3.823497715925681e-08 -3.332854120940232e-08 -3.1857892465262325e-08 -3.277635965523207e-08 -3.504696899593304e-08 -3.9732745997588816e-08 -3.6231130926880973e-08 -3.2384022292587515e-08 -2.51114813976347e-08 -1.6464444819768138e-08 -8.994255965628027e-09 -7.1767165621410114e-09 -2.8577675981685694e-08 -5.841545015805698e-08 -6.039275157096608e-08 -4.688168500870891e-08 -3.948644623306311e-08 -3.967554725347474e-08 -3.497004654695204e-08 -3.2341205416605566e-08 -2.96193341449701e-08 -3.1787133674052234e-08 -2.3771091287720007e-08 -3.2843748980194056e-08 -3.870777080133769e-08 -3.830688649991746e-08 -3.751424011057797e-08 -3.7333521664734786e-08 -3.92022605187722e-08 -4.072682072288178e-08 -3.9743840581576465e-08 -3.553767833660138e-08 -2.6895819231262385e-08 -1.764564819498603e-08 -1.0751227158752863e-08 -7.09946538474556e-09 -2.7265145604895536e-08 -5.8462458321323144e-08 -5.9155910911602734e-08 -4.8799240032291956e-08 -4.3469894977249186e-08 -4.311495047174816e-08 -3.511098885464693e-08 -2.9433766955013795e-08 -3.120002472584681e-08 -3.4093656594031734e-08 -2.3460936028687633e-08 -3.1229445918939964e-08 -3.234786216699815e-08 -3.4140500393090674e-08 -3.2494885950360346e-08 -3.0468932732112835e-08 -3.243875557359323e-08 -3.499108516547676e-08 -3.612330800694179e-08 -3.4467338619156324e-08 -2.9416919623773295e-08 -2.2499323234321496e-08 -1.4318670094454071e-08 -9.94658218228599e-09 -2.3527832261027953e-08 -4.376328508714467e-08 -4.579811397258229e-08 -4.232608445917484e-08 -4.453481067585584e-08 -4.736812087998942e-08 -4.4987140974137285e-08 -4.2853447018054216e-08 -3.919749395676268e-08 -3.8835810518765464e-08 -2.0696740973691898e-08 -2.3027589796340604e-08 -2.7608502433787234e-08 -2.865320133490529e-08 -2.6301971350560765e-08 -2.5822027865465625e-08 -2.8441171507585858e-08 -3.5269600314618446e-08 -3.455856075416585e-08 -3.133209136635158e-08 -2.8434843485607723e-08 -2.23279735482901e-08 -1.5353014050516992e-08 -1.1161891130502936e-08 -2.436099442744825e-08 -4.0447565934807586e-08 -3.944001334452223e-08 -3.758047888608939e-08 -3.567796318746738e-08 -3.939185463180549e-08 -4.462233461620281e-08 -4.5538582889375027e-08 -3.933958681390814e-08 -3.418282417645095e-08 -1.9785341444632794e-08 -2.3909650314410148e-08 -2.473426554205478e-08 -2.6015977629990372e-08 -2.853140745735204e-08 -3.056146978078015e-08 -3.016272221405385e-08 -3.204674693936312e-08 -3.115466020465288e-08 -2.828864152328165e-08 -2.273608987482819e-08 -1.6163987048962003e-08 -9.735291993899071e-09 -8.643091836893173e-09 -2.7197591915726322e-08 -6.037836970283394e-08 -5.983350235588518e-08 -5.1105269859649784e-08 -3.947469419224657e-08 -3.910849073855069e-08 -3.615675612311195e-08 -2.8920457535852108e-08 -2.8902459655161036e-08 -3.397473909010491e-08 -2.0652773548259383e-08 -3.9975840660073653e-08 -4.0214333124756196e-08 -3.6379305259693736e-08 -3.4871838933135485e-08 -3.417057904301274e-08 -3.4361981162325504e-08 -3.526746357992453e-08 -3.337801483577685e-08 -2.946598233962977e-08 -2.285443210402973e-08 -1.3759831789891232e-08 -8.005769623380702e-09 -4.879151491455241e-09 -1.0444605730175814e-08 -2.5636460675509318e-08 -2.989554819521064e-08 -2.689606577757323e-08 -2.1271769152666333e-08 -2.6195463344279376e-08 -2.4656521272037657e-08 -2.100697841482788e-08 -2.1080613579664398e-08 -2.6036276609582578e-08 -2.3348264364635335e-08 -3.256063163325009e-08 -4.270256067582224e-08 -3.757530141356182e-08 -3.207592158614544e-08 -3.239832197861603e-08 -3.3759175432330153e-08 -3.740025353286787e-08 -3.501664379970015e-08 -3.080875573054921e-08 -2.447226899573915e-08 -1.632851562039359e-08 -8.709823705026265e-09 -4.852360125677669e-09 -8.352742464831335e-09 -2.233265792819599e-08 -3.1356745997435236e-08 -2.4692845761834243e-08 -1.9338928257811427e-08 -1.9024417347287607e-08 -2.5126602904699337e-08 -2.7550810597051484e-08 -1.8833015227974834e-08 -3.07749788859646e-08 -2.104798728453036e-08 -3.483510353282084e-08 -3.823497715925681e-08 -3.332854120940232e-08 -3.1857892465262325e-08 -3.277635965523207e-08 -3.504696899593304e-08 -3.9732745997588816e-08 -3.6231130926880973e-08 -3.2384022292587515e-08 -2.51114813976347e-08 -1.6464444819768138e-08 -8.994255965628027e-09 -7.1767165621410114e-09 -2.8577675981685694e-08 -5.841545015805698e-08 -6.039275157096608e-08 -4.688168500870891e-08 -3.948644623306311e-08 -3.967554725347474e-08 -3.497004654695204e-08 -3.2341205416605566e-08 -2.96193341449701e-08 -3.1787133674052234e-08 -2.3771091287720007e-08 -3.2843748980194056e-08 -3.870777080133769e-08 -3.830688649991746e-08 -3.751424011057797e-08 -3.7333521664734786e-08 -3.92022605187722e-08 -4.072682072288178e-08 -3.9743840581576465e-08 -3.553767833660138e-08 -2.6895819231262385e-08 -1.764564819498603e-08 -1.0751227158752863e-08 -7.09946538474556e-09 -2.7265145604895536e-08 -5.8462458321323144e-08 -5.9155910911602734e-08 -4.8799240032291956e-08 -4.3469894977249186e-08 -4.311495047174816e-08 -3.511098885464693e-08 -2.9433766955013795e-08 -3.120002472584681e-08 -3.4093656594031734e-08 -2.3460936028687633e-08 -3.1229445918939964e-08 -3.234786216699815e-08 -3.4140500393090674e-08 -3.2494885950360346e-08 -3.0468932732112835e-08 -3.243875557359323e-08 -3.499108516547676e-08 -3.612330800694179e-08 -3.4467338619156324e-08 -2.9416919623773295e-08 -2.2499323234321496e-08 -1.4318670094454071e-08 -9.94658218228599e-09 -2.3527832261027953e-08 -4.376328508714467e-08 -4.579811397258229e-08 -4.232608445917484e-08 -4.453481067585584e-08 -4.736812087998942e-08 -4.4987140974137285e-08 -4.2853447018054216e-08 -3.919749395676268e-08 -3.8835810518765464e-08 -2.0696740973691898e-08 -2.3027589796340604e-08 -2.7608502433787234e-08 -2.865320133490529e-08 -2.6301971350560765e-08 -2.5822027865465625e-08 -2.8441171507585858e-08 -3.5269600314618446e-08 -3.455856075416585e-08 -3.133209136635158e-08 -2.8434843485607723e-08 -2.23279735482901e-08 -1.5353014050516992e-08 -1.1161891130502936e-08 -2.436099442744825e-08 -4.0447565934807586e-08 -3.944001334452223e-08 -3.758047888608939e-08 -3.567796318746738e-08 -3.939185463180549e-08 -4.462233461620281e-08 -4.5538582889375027e-08 -3.933958681390814e-08 -3.418282417645095e-08 -1.9785341444632794e-08 -2.3909650314410148e-08 -2.473426554205478e-08 -2.6015977629990372e-08 -2.853140745735204e-08 -3.056146978078015e-08 -3.016272221405385e-08 -3.204674693936312e-08 -3.115466020465288e-08 -2.828864152328165e-08 -2.273608987482819e-08 -1.6163987048962003e-08 -9.735291993899071e-09 -8.643091836893173e-09 -2.7197591915726322e-08 -6.037836970283394e-08 -5.983350235588518e-08 -5.1105269859649784e-08 -3.947469419224657e-08 -3.910849073855069e-08 -3.615675612311195e-08 -2.8920457535852108e-08 -2.8902459655161036e-08 -3.397473909010491e-08 -2.0652773548259383e-08 -3.9975840660073653e-08 -4.0214333124756196e-08 -3.6379305259693736e-08 -3.4871838933135485e-08 -3.417057904301274e-08 -3.4361981162325504e-08 -3.526746357992453e-08 -3.6762602590940955e-08 -3.2406375824770026e-08 -2.4372417739850343e-08 -1.5509817504209033e-08 -8.899089089645121e-09 -4.870851098990411e-09 -9.132814992318166e-09 -2.6582951962810812e-08 -3.6057808870362884e-08 -2.541473335996365e-08 -1.9911737519988334e-08 -1.9959978414808685e-08 -2.0062623862220302e-08 -1.8068392935967095e-08 -2.4241912559314203e-08 -2.800042888591373e-08 -1.809691012592052e-08 -3.130595745740291e-08 -4.094024764596261e-08 -3.7405759733809885e-08 -3.804176703366456e-08 -3.798251373696018e-08 -3.9688778572156304e-08 -4.211019207298563e-08 -4.127908445915563e-08 -3.620631193159009e-08 -2.808507645263427e-08 -1.9396537912443567e-08 -9.255841601425602e-09 -5.257682260692952e-09 -8.6102189954483e-09 -2.3522819152707606e-08 -3.3572539875026884e-08 -2.5241657849756395e-08 -2.2216123705273918e-08 -1.6014169074076996e-08 -2.365011923120288e-08 -2.113978469426517e-08 -2.430363131912695e-08 -2.932479348562404e-08 -1.7952023077252245e-08 -3.081886412929351e-08 -3.611435015764806e-08 -3.521790777144638e-08 -3.874960149207628e-08 -4.0030163030561304e-08 -4.026709403527523e-08 -4.1884848744881024e-08 -4.103344215145882e-08 -3.495541813250907e-08 -2.718994898009039e-08 -1.74106895607588e-08 -9.411823234081524e-09 -6.4629649922692115e-09 -2.9738991287829438e-08 -6.051117598227122e-08 -6.611887182224845e-08 -5.1540588462483515e-08 -3.848275620164753e-08 -3.536871193157473e-08 -3.709839866630033e-08 -3.2967268681923163e-08 -2.9705789717970114e-08 -3.119624434908065e-08 -2.8357345761901436e-08 -3.4198356594033656e-08 -3.868862237119605e-08 -3.6691432889212805e-08 -3.860923445910668e-08 -3.992365502427992e-08 -4.267207111538212e-08 -4.821780164923577e-08 -4.5736723941184e-08 -4.043384152350435e-08 -3.3123003768268256e-08 -2.157403492975194e-08 -1.1112088775713955e-08 -7.86926514928087e-09 -2.779143979642795e-08 -6.055391067614956e-08 -6.799377433405678e-08 -5.01831866571211e-08 -3.866306373697265e-08 -3.597751695513378e-08 -3.337464536952875e-08 -3.593461789704822e-08 -3.120922912145137e-08 -3.1488730455836404e-08 -2.0408199607909525e-08 -3.0352809419708825e-08 -3.643444945121751e-08 -3.751045973381181e-08 -3.317905196293176e-08 -3.0882801805903786e-08 -3.2460698195257676e-08 -3.785184419221681e-08 -3.987188029900425e-08 -3.4573600079126874e-08 -2.862673869754217e-08 -2.1199777629902063e-08 -1.280076664073707e-08 -8.332196938928289e-09 -2.2422893877962164e-08 -4.313845455338125e-08 -4.745350808564248e-08 -5.043844427094053e-08 -4.3643874490596166e-08 -4.709059191609109e-08 -4.977128995381685e-08 -4.6937486657061584e-08 -4.273732370565019e-08 -3.818213406663417e-08 -2.0587438775887697e-08 -2.8032315542115258e-08 -2.6965016562503852e-08 -2.6630781947113104e-08 -2.8329403846673294e-08 -2.612585510251986e-08 -2.6425737598600712e-08 -3.101486844640856e-08 -3.478661609168965e-08 -3.302257723765417e-08 -2.649542802246384e-08 -1.9497128807264876e-08 -1.2884263658007046e-08 -8.822495369078566e-09 -2.270551813228446e-08 -4.252792370564636e-08 -4.227718610752559e-08 -3.931090525974749e-08 -3.560293092686945e-08 -4.339058924726343e-08 -4.8363510518940166e-08 -4.753486836821853e-08 -4.222278155493431e-08 -4.167643493012053e-08 -2.1108308948581704e-08 -2.553915706483249e-08 -3.176609505552752e-08 -2.9987263422841835e-08 -3.141361601313486e-08 -3.2029735243915394e-08 -3.2213740973903074e-08 -3.4751113422929186e-08 -3.22018245688793e-08 -2.7979718995803457e-08 -2.2222122998837608e-08 -1.4269771742804821e-08 -6.9400321037379265e-09 -6.6124542387397714e-09 -2.8228895133955598e-08 -5.6868618603868484e-08 -6.444621946742973e-08 -4.8724125589590415e-08 -3.778313995359703e-08 -4.04220894826878e-08 -4.029150212004805e-08 -3.208290706495248e-08 -3.240004780279189e-08 -3.251017182163221e-08 -2.4728677159009153e-08 -3.781971098970445e-08 -4.269089081710931e-08 -3.755861844652855e-08 -3.81458917589412e-08 -3.7685918525023815e-08 -3.9019076609820634e-08 -4.2581095526683435e-08 -3.6762602590940955e-08 -3.2406375824770026e-08 -2.4372417739850343e-08 -1.5509817504209033e-08 -8.899089089645121e-09 -4.870851098990411e-09 -9.132814992318166e-09 -2.6582951962810812e-08 -3.6057808870362884e-08 -2.541473335996365e-08 -1.9911737519988334e-08 -1.9959978414808685e-08 -2.0062623862220302e-08 -1.8068392935967095e-08 -2.4241912559314203e-08 -2.800042888591373e-08 -1.809691012592052e-08 -3.130595745740291e-08 -4.094024764596261e-08 -3.7405759733809885e-08 -3.804176703366456e-08 -3.798251373696018e-08 -3.9688778572156304e-08 -4.211019207298563e-08 -4.127908445915563e-08 -3.620631193159009e-08 -2.808507645263427e-08 -1.9396537912443567e-08 -9.255841601425602e-09 -5.257682260692952e-09 -8.6102189954483e-09 -2.3522819152707606e-08 -3.3572539875026884e-08 -2.5241657849756395e-08 -2.2216123705273918e-08 -1.6014169074076996e-08 -2.365011923120288e-08 -2.113978469426517e-08 -2.430363131912695e-08 -2.932479348562404e-08 -1.7952023077252245e-08 -3.081886412929351e-08 -3.611435015764806e-08 -3.521790777144638e-08 -3.874960149207628e-08 -4.0030163030561304e-08 -4.026709403527523e-08 -4.1884848744881024e-08 -4.103344215145882e-08 -3.495541813250907e-08 -2.718994898009039e-08 -1.74106895607588e-08 -9.411823234081524e-09 -6.4629649922692115e-09 -2.9738991287829438e-08 -6.051117598227122e-08 -6.611887182224845e-08 -5.1540588462483515e-08 -3.848275620164753e-08 -3.536871193157473e-08 -3.709839866630033e-08 -3.2967268681923163e-08 -2.9705789717970114e-08 -3.119624434908065e-08 -2.8357345761901436e-08 -3.4198356594033656e-08 -3.868862237119605e-08 -3.6691432889212805e-08 -3.860923445910668e-08 -3.992365502427992e-08 -4.267207111538212e-08 -4.821780164923577e-08 -4.5736723941184e-08 -4.043384152350435e-08 -3.3123003768268256e-08 -2.157403492975194e-08 -1.1112088775713955e-08 -7.86926514928087e-09 -2.779143979642795e-08 -6.055391067614956e-08 -6.799377433405678e-08 -5.01831866571211e-08 -3.866306373697265e-08 -3.597751695513378e-08 -3.337464536952875e-08 -3.593461789704822e-08 -3.120922912145137e-08 -3.1488730455836404e-08 -2.0408199607909525e-08 -3.0352809419708825e-08 -3.643444945121751e-08 -3.751045973381181e-08 -3.317905196293176e-08 -3.0882801805903786e-08 -3.2460698195257676e-08 -3.785184419221681e-08 -3.987188029900425e-08 -3.4573600079126874e-08 -2.862673869754217e-08 -2.1199777629902063e-08 -1.280076664073707e-08 -8.332196938928289e-09 -2.2422893877962164e-08 -4.313845455338125e-08 -4.745350808564248e-08 -5.043844427094053e-08 -4.3643874490596166e-08 -4.709059191609109e-08 -4.977128995381685e-08 -4.6937486657061584e-08 -4.273732370565019e-08 -3.818213406663417e-08 -2.0587438775887697e-08 -2.8032315542115258e-08 -2.6965016562503852e-08 -2.6630781947113104e-08 -2.8329403846673294e-08 -2.612585510251986e-08 -2.6425737598600712e-08 -3.101486844640856e-08 -3.478661609168965e-08 -3.302257723765417e-08 -2.649542802246384e-08 -1.9497128807264876e-08 -1.2884263658007046e-08 -8.822495369078566e-09 -2.270551813228446e-08 -4.252792370564636e-08 -4.227718610752559e-08 -3.931090525974749e-08 -3.560293092686945e-08 -4.339058924726343e-08 -4.8363510518940166e-08 -4.753486836821853e-08 -4.222278155493431e-08 -4.167643493012053e-08 -2.1108308948581704e-08 -2.553915706483249e-08 -3.176609505552752e-08 -2.9987263422841835e-08 -3.141361601313486e-08 -3.2029735243915394e-08 -3.2213740973903074e-08 -3.4751113422929186e-08 -3.22018245688793e-08 -2.7979718995803457e-08 -2.2222122998837608e-08 -1.4269771742804821e-08 -6.9400321037379265e-09 -6.6124542387397714e-09 -2.8228895133955598e-08 -5.6868618603868484e-08 -6.444621946742973e-08 -4.8724125589590415e-08 -3.778313995359703e-08 -4.04220894826878e-08 -4.029150212004805e-08 -3.208290706495248e-08 -3.240004780279189e-08 -3.251017182163221e-08 -2.4728677159009153e-08 -3.781971098970445e-08 -4.269089081710931e-08 -3.755861844652855e-08 -3.81458917589412e-08 -3.7685918525023815e-08 -3.9019076609820634e-08 -4.2581095526683435e-08 -3.6762602590940955e-08 -3.2406375824770026e-08 -2.4372417739850343e-08 -1.5509817504209033e-08 -8.899089089645121e-09 -4.870851098990411e-09 -9.132814992318166e-09 -2.6582951962810812e-08 -3.6057808870362884e-08 -2.541473335996365e-08 -1.9911737519988334e-08 -1.9959978414808685e-08 -2.0062623862220302e-08 -1.8068392935967095e-08 -2.4241912559314203e-08 -2.800042888591373e-08 -1.809691012592052e-08 -3.130595745740291e-08 -4.094024764596261e-08 -3.7405759733809885e-08 -3.804176703366456e-08 -3.798251373696018e-08 -3.9688778572156304e-08 -4.211019207298563e-08 -4.127908445915563e-08 -3.620631193159009e-08 -2.808507645263427e-08 -1.9396537912443567e-08 -9.255841601425602e-09 -5.257682260692952e-09 -8.6102189954483e-09 -2.3522819152707606e-08 -3.3572539875026884e-08 -2.5241657849756395e-08 -2.2216123705273918e-08 -1.6014169074076996e-08 -2.365011923120288e-08 -2.113978469426517e-08 -2.430363131912695e-08 -2.932479348562404e-08 -1.7952023077252245e-08 -3.081886412929351e-08 -3.611435015764806e-08 -3.521790777144638e-08 -3.874960149207628e-08 -4.0030163030561304e-08 -4.026709403527523e-08 -4.1884848744881024e-08 -4.103344215145882e-08 -3.495541813250907e-08 -2.718994898009039e-08 -1.74106895607588e-08 -9.411823234081524e-09 -6.4629649922692115e-09 -2.9738991287829438e-08 -6.051117598227122e-08 -6.611887182224845e-08 -5.1540588462483515e-08 -3.848275620164753e-08 -3.536871193157473e-08 -3.709839866630033e-08 -3.2967268681923163e-08 -2.9705789717970114e-08 -3.119624434908065e-08 -2.8357345761901436e-08 -3.4198356594033656e-08 -3.868862237119605e-08 -3.6691432889212805e-08 -3.860923445910668e-08 -3.992365502427992e-08 -4.267207111538212e-08 -4.821780164923577e-08 -4.5736723941184e-08 -4.043384152350435e-08 -3.3123003768268256e-08 -2.157403492975194e-08 -1.1112088775713955e-08 -7.86926514928087e-09 -2.779143979642795e-08 -6.055391067614956e-08 -6.799377433405678e-08 -5.01831866571211e-08 -3.866306373697265e-08 -3.597751695513378e-08 -3.337464536952875e-08 -3.593461789704822e-08 -3.120922912145137e-08 -3.1488730455836404e-08 -2.0408199607909525e-08 -3.0352809419708825e-08 -3.643444945121751e-08 -3.751045973381181e-08 -3.317905196293176e-08 -3.0882801805903786e-08 -3.2460698195257676e-08 -3.785184419221681e-08 -3.987188029900425e-08 -3.4573600079126874e-08 -2.862673869754217e-08 -2.1199777629902063e-08 -1.280076664073707e-08 -8.332196938928289e-09 -2.2422893877962164e-08 -4.313845455338125e-08 -4.745350808564248e-08 -5.043844427094053e-08 -4.3643874490596166e-08 -4.709059191609109e-08 -4.977128995381685e-08 -4.6937486657061584e-08 -4.273732370565019e-08 -3.818213406663417e-08 -2.0587438775887697e-08 -2.8032315542115258e-08 -2.6965016562503852e-08 -2.6630781947113104e-08 -2.8329403846673294e-08 -2.612585510251986e-08 -2.6425737598600712e-08 -3.101486844640856e-08 -3.478661609168965e-08 -3.302257723765417e-08 -2.649542802246384e-08 -1.9497128807264876e-08 -1.2884263658007046e-08 -8.822495369078566e-09 -2.270551813228446e-08 -4.252792370564636e-08 -4.227718610752559e-08 -3.931090525974749e-08 -3.560293092686945e-08 -4.339058924726343e-08 -4.8363510518940166e-08 -4.753486836821853e-08 -4.222278155493431e-08 -4.167643493012053e-08 -2.1108308948581704e-08 -2.553915706483249e-08 -3.176609505552752e-08 -2.9987263422841835e-08 -3.141361601313486e-08 -3.2029735243915394e-08 -3.2213740973903074e-08 -3.4751113422929186e-08 -3.22018245688793e-08 -2.7979718995803457e-08 -2.2222122998837608e-08 -1.4269771742804821e-08 -6.9400321037379265e-09 -6.6124542387397714e-09 -2.8228895133955598e-08 -5.6868618603868484e-08 -6.444621946742973e-08 -4.8724125589590415e-08 -3.778313995359703e-08 -4.04220894826878e-08 -4.029150212004805e-08 -3.208290706495248e-08 -3.240004780279189e-08 -3.251017182163221e-08 -2.4728677159009153e-08 -3.781971098970445e-08 -4.269089081710931e-08 -3.755861844652855e-08 -3.81458917589412e-08 -3.7685918525023815e-08 -3.9019076609820634e-08 -4.2581095526683435e-08 -3.6762602590940955e-08 -3.2406375824770026e-08 -2.4372417739850343e-08 -1.5509817504209033e-08 -8.899089089645121e-09 -4.870851098990411e-09 -9.132814992318166e-09 -2.6582951962810812e-08 -3.6057808870362884e-08 -2.541473335996365e-08 -1.9911737519988334e-08 -1.9959978414808685e-08 -2.0062623862220302e-08 -1.8068392935967095e-08 -2.4241912559314203e-08 -2.800042888591373e-08 -1.809691012592052e-08 -3.130595745740291e-08 -4.094024764596261e-08 -3.7405759733809885e-08 -3.804176703366456e-08 -3.798251373696018e-08 -3.9688778572156304e-08 -4.211019207298563e-08 -4.127908445915563e-08 -3.620631193159009e-08 -2.808507645263427e-08 -1.9396537912443567e-08 -9.255841601425602e-09 -5.257682260692952e-09 -8.6102189954483e-09 -2.3522819152707606e-08 -3.3572539875026884e-08 -2.5241657849756395e-08 -2.2216123705273918e-08 -1.6014169074076996e-08 -2.365011923120288e-08 -2.113978469426517e-08 -2.430363131912695e-08 -2.932479348562404e-08 -1.7952023077252245e-08 -3.081886412929351e-08 -3.611435015764806e-08 -3.521790777144638e-08 -3.874960149207628e-08 -4.0030163030561304e-08 -4.026709403527523e-08 -4.1884848744881024e-08 -4.103344215145882e-08 -3.495541813250907e-08 -2.718994898009039e-08 -1.74106895607588e-08 -9.411823234081524e-09 -6.4629649922692115e-09 -2.9738991287829438e-08 -6.051117598227122e-08 -6.611887182224845e-08 -5.1540588462483515e-08 -3.848275620164753e-08 -3.536871193157473e-08 -3.709839866630033e-08 -3.2967268681923163e-08 -2.9705789717970114e-08 -3.119624434908065e-08 -2.8357345761901436e-08 -3.4198356594033656e-08 -3.868862237119605e-08 -3.6691432889212805e-08 -3.860923445910668e-08 -3.992365502427992e-08 -4.267207111538212e-08 -4.821780164923577e-08 -4.5736723941184e-08 -4.043384152350435e-08 -3.3123003768268256e-08 -2.157403492975194e-08 -1.1112088775713955e-08 -7.86926514928087e-09 -2.779143979642795e-08 -6.055391067614956e-08 -6.799377433405678e-08 -5.01831866571211e-08 -3.866306373697265e-08 -3.597751695513378e-08 -3.337464536952875e-08 -3.593461789704822e-08 -3.120922912145137e-08 -3.1488730455836404e-08 -2.0408199607909525e-08 -3.0352809419708825e-08 -3.643444945121751e-08 -3.751045973381181e-08 -3.317905196293176e-08 -3.0882801805903786e-08 -3.2460698195257676e-08 -3.785184419221681e-08 -3.987188029900425e-08 -3.4573600079126874e-08 -2.862673869754217e-08 -2.1199777629902063e-08 -1.280076664073707e-08 -8.332196938928289e-09 -2.2422893877962164e-08 -4.313845455338125e-08 -4.745350808564248e-08 -5.043844427094053e-08 -4.3643874490596166e-08 -4.709059191609109e-08 -4.977128995381685e-08 -4.6937486657061584e-08 -4.273732370565019e-08 -3.818213406663417e-08 -2.0587438775887697e-08 -2.8032315542115258e-08 -2.6965016562503852e-08 -2.6630781947113104e-08 -2.8329403846673294e-08 -2.612585510251986e-08 -2.6425737598600712e-08 -3.101486844640856e-08 -3.478661609168965e-08 -3.302257723765417e-08 -2.649542802246384e-08 -1.9497128807264876e-08 -1.2884263658007046e-08 -8.822495369078566e-09 -2.270551813228446e-08 -4.252792370564636e-08 -4.227718610752559e-08 -3.931090525974749e-08 -3.560293092686945e-08 -4.339058924726343e-08 -4.8363510518940166e-08 -4.753486836821853e-08 -4.222278155493431e-08 -4.167643493012053e-08 -2.1108308948581704e-08 -2.553915706483249e-08 -3.176609505552752e-08 -2.9987263422841835e-08 -3.141361601313486e-08 -3.2029735243915394e-08 -3.2213740973903074e-08 -3.4751113422929186e-08 -3.22018245688793e-08 -2.7979718995803457e-08 -2.2222122998837608e-08 -1.4269771742804821e-08 -6.9400321037379265e-09 -6.6124542387397714e-09 -2.8228895133955598e-08 -5.6868618603868484e-08 -6.444621946742973e-08 -4.8724125589590415e-08 -3.778313995359703e-08 -4.04220894826878e-08 -4.029150212004805e-08 -3.208290706495248e-08 -3.240004780279189e-08 -3.251017182163221e-08 -2.4728677159009153e-08 -3.781971098970445e-08 -4.269089081710931e-08 -3.755861844652855e-08 -3.81458917589412e-08 -3.7685918525023815e-08 -3.9019076609820634e-08 -4.2581095526683435e-08 -3.6762602590940955e-08 -3.2406375824770026e-08 -2.4372417739850343e-08 -1.5509817504209033e-08 -8.899089089645121e-09 -4.870851098990411e-09 -9.132814992318166e-09 -2.6582951962810812e-08 -3.6057808870362884e-08 -2.541473335996365e-08 -1.9911737519988334e-08 -1.9959978414808685e-08 -2.0062623862220302e-08 -1.8068392935967095e-08 -2.4241912559314203e-08 -2.800042888591373e-08 -1.809691012592052e-08 -3.130595745740291e-08 -4.094024764596261e-08 -3.7405759733809885e-08 -3.804176703366456e-08 -3.798251373696018e-08 -3.9688778572156304e-08 -4.211019207298563e-08 -4.127908445915563e-08 -3.620631193159009e-08 -2.808507645263427e-08 -1.9396537912443567e-08 -9.255841601425602e-09 -5.257682260692952e-09 -8.6102189954483e-09 -2.3522819152707606e-08 -3.3572539875026884e-08 -2.5241657849756395e-08 -2.2216123705273918e-08 -1.6014169074076996e-08 -2.365011923120288e-08 -2.113978469426517e-08 -2.430363131912695e-08 -2.932479348562404e-08 -1.7952023077252245e-08 -3.081886412929351e-08 -3.611435015764806e-08 -3.521790777144638e-08 -3.874960149207628e-08 -4.0030163030561304e-08 -4.026709403527523e-08 -4.1884848744881024e-08 -4.139118084848265e-08 -3.687100078560542e-08 -2.9257321978558438e-08 -2.0038297959551093e-08 -1.2121449372278773e-08 -8.726342307852313e-09 -2.5439305808943694e-08 -5.437250157085569e-08 -6.356202221466626e-08 -5.237424372152548e-08 -4.40420467825972e-08 -3.960856883903081e-08 -3.931172708078362e-08 -3.375999725336628e-08 -3.0194362323944536e-08 -2.6571364286201495e-08 -2.1477553140111236e-08 -2.6781175196723398e-08 -3.7741227080754814e-08 -4.1266921507821034e-08 -3.93224107542532e-08 -3.700397142924993e-08 -3.815172668829766e-08 -4.255545471035644e-08 -4.167536656277357e-08 -3.68620429363117e-08 -2.9109722920470963e-08 -1.8883228493281877e-08 -1.066099120898669e-08 -7.376583438125838e-09 -2.729925117789459e-08 -5.726383234013947e-08 -6.096786193204413e-08 -4.709626248124032e-08 -3.883844034608107e-08 -3.6161769231432297e-08 -3.63797161702118e-08 -3.2640759184271965e-08 -2.7374365620596127e-08 -3.0217208948748725e-08 -1.9247706122801904e-08 -2.9694448587671636e-08 -3.778124976521395e-08 -3.569472833660426e-08 -3.4935283517124085e-08 -3.352388806968848e-08 -3.482072166468871e-08 -4.085420298348065e-08 -4.184170314048463e-08 -3.938347205723705e-08 -3.361815094253165e-08 -2.5176487441591935e-08 -1.5021080534027388e-08 -8.773761381636542e-09 -2.2151035479213068e-08 -4.309193948273676e-08 -4.298469183752286e-08 -4.0515119623976784e-08 -4.326082370565979e-08 -4.8480620016587526e-08 -4.45871606758568e-08 -4.5376191052637354e-08 -4.30969525910571e-08 -4.083932802272686e-08 -2.126018147605702e-08 -2.7143680455756733e-08 -3.2472285871866996e-08 -3.067562072269747e-08 -2.786039058135857e-08 -2.7915616954985956e-08 -3.100812951391236e-08 -3.749040730053044e-08 -3.9353311225211375e-08 -3.67736971749286e-08 -3.1746782261178655e-08 -2.4059139560880712e-08 -1.5951792857435348e-08 -1.1006402590468688e-08 -2.3599988147999445e-08 -4.11627967825444e-08 -4.210057676686301e-08 -4.033604482020585e-08 -4.144057229275356e-08 -4.283659968681371e-08 -4.612224018922875e-08 -4.48003410526268e-08 -4.116822080138281e-08 -4.069986499289698e-08 -2.1408766719387843e-08 -2.662856303031558e-08 -2.862419105233019e-08 -3.022838571483998e-08 -2.9932776688146966e-08 -2.978912237103287e-08 -3.0828232889105296e-08 -3.334358053436335e-08 -3.2056937520211025e-08 -2.8921936813717125e-08 -2.1977959969005814e-08 -1.4845128650193706e-08 -1.0022025353401973e-08 -6.886778100597233e-09 -2.6894504317604597e-08 -5.9556302120401284e-08 -6.528694238738233e-08 -4.677558791294558e-08 -3.643790109956922e-08 -3.803749356427673e-08 -3.529778877615743e-08 -3.0749091523326765e-08 -2.9122789874945298e-08 -3.1405808713291714e-08 -2.1108308948581704e-08 -3.951981216712966e-08 -4.172081326607111e-08 -4.252496514991631e-08 -3.9431219859435724e-08 -3.863808037747456e-08 -4.049958720639409e-08 -4.3924772920742606e-08 -4.106245243403392e-08 -3.516588649985987e-08 -2.6923843328594146e-08 -1.5724559340947667e-08 -9.253704866731686e-09 -4.846607378424817e-09 -8.330060204234372e-09 -2.3403490738262722e-08 -3.227176153905327e-08 -3.144772158613393e-08 -2.4029964914098385e-08 -2.111751334418627e-08 -2.026191546347984e-08 -1.9748934772732603e-08 -2.2247928179371825e-08 -2.4477117739852266e-08 -1.7689862166729384e-08 -3.2135585793367885e-08 -4.164726028333821e-08 -4.090679952979245e-08 -3.725059992219009e-08 -3.7970186421418355e-08 -3.8031494270713044e-08 -4.139027684534291e-08 -3.8826030848435617e-08 -3.337579591897932e-08 -2.5234918917260192e-08 -1.6238361852731026e-08 -8.990804317276315e-09 -4.904627943575017e-09 -7.598228571567891e-09 -1.910175070678667e-08 -2.83800280224984e-08 -2.7330973469888893e-08 -2.5702535086813514e-08 -2.450777166449961e-08 -2.4578366091502472e-08 -2.3561116012990887e-08 -2.3629984615817896e-08 -2.9840650549997706e-08 -2.123133555768914e-08 -2.6621988462026596e-08 -3.637799034603594e-08 -3.4957719231410216e-08 -3.482565259090544e-08 -3.548458869766791e-08 -3.830031193162849e-08 -4.248814756749806e-08 -4.139118084848265e-08 -3.687100078560542e-08 -2.9257321978558438e-08 -2.0038297959551093e-08 -1.2121449372278773e-08 -8.726342307852313e-09 -2.5439305808943694e-08 -5.437250157085569e-08 -6.356202221466626e-08 -5.237424372152548e-08 -4.40420467825972e-08 -3.960856883903081e-08 -3.931172708078362e-08 -3.375999725336628e-08 -3.0194362323944536e-08 -2.6571364286201495e-08 -2.1477553140111236e-08 -2.6781175196723398e-08 -3.7741227080754814e-08 -4.1266921507821034e-08 -3.93224107542532e-08 -3.700397142924993e-08 -3.815172668829766e-08 -4.255545471035644e-08 -4.167536656277357e-08 -3.68620429363117e-08 -2.9109722920470963e-08 -1.8883228493281877e-08 -1.066099120898669e-08 -7.376583438125838e-09 -2.729925117789459e-08 -5.726383234013947e-08 -6.096786193204413e-08 -4.709626248124032e-08 -3.883844034608107e-08 -3.6161769231432297e-08 -3.63797161702118e-08 -3.2640759184271965e-08 -2.7374365620596127e-08 -3.0217208948748725e-08 -1.9247706122801904e-08 -2.9694448587671636e-08 -3.778124976521395e-08 -3.569472833660426e-08 -3.4935283517124085e-08 -3.352388806968848e-08 -3.482072166468871e-08 -4.085420298348065e-08 -4.184170314048463e-08 -3.938347205723705e-08 -3.361815094253165e-08 -2.5176487441591935e-08 -1.5021080534027388e-08 -8.773761381636542e-09 -2.2151035479213068e-08 -4.309193948273676e-08 -4.298469183752286e-08 -4.0515119623976784e-08 -4.326082370565979e-08 -4.8480620016587526e-08 -4.45871606758568e-08 -4.5376191052637354e-08 -4.30969525910571e-08 -4.083932802272686e-08 -2.126018147605702e-08 -2.7143680455756733e-08 -3.2472285871866996e-08 -3.067562072269747e-08 -2.786039058135857e-08 -2.7915616954985956e-08 -3.100812951391236e-08 -3.749040730053044e-08 -3.9353311225211375e-08 -3.67736971749286e-08 -3.1746782261178655e-08 -2.4059139560880712e-08 -1.5951792857435348e-08 -1.1006402590468688e-08 -2.3599988147999445e-08 -4.11627967825444e-08 -4.210057676686301e-08 -4.033604482020585e-08 -4.144057229275356e-08 -4.283659968681371e-08 -4.612224018922875e-08 -4.48003410526268e-08 -4.116822080138281e-08 -4.069986499289698e-08 -2.1408766719387843e-08 -2.662856303031558e-08 -2.862419105233019e-08 -3.022838571483998e-08 -2.9932776688146966e-08 -2.978912237103287e-08 -3.0828232889105296e-08 -3.334358053436335e-08 -3.2056937520211025e-08 -2.8921936813717125e-08 -2.1977959969005814e-08 -1.4845128650193706e-08 -1.0022025353401973e-08 -6.886778100597233e-09 -2.6894504317604597e-08 -5.9556302120401284e-08 -6.528694238738233e-08 -4.677558791294558e-08 -3.643790109956922e-08 -3.803749356427673e-08 -3.529778877615743e-08 -3.0749091523326765e-08 -2.9122789874945298e-08 -3.1405808713291714e-08 -2.1108308948581704e-08 -3.951981216712966e-08 -4.172081326607111e-08 -4.252496514991631e-08 -3.9431219859435724e-08 -3.863808037747456e-08 -4.049958720639409e-08 -4.3924772920742606e-08 -4.106245243403392e-08 -3.516588649985987e-08 -2.6923843328594146e-08 -1.5724559340947667e-08 -9.253704866731686e-09 -4.846607378424817e-09 -8.330060204234372e-09 -2.3403490738262722e-08 -3.227176153905327e-08 -3.144772158613393e-08 -2.4029964914098385e-08 -2.111751334418627e-08 -2.026191546347984e-08 -1.9748934772732603e-08 -2.2247928179371825e-08 -2.4477117739852266e-08 -1.7689862166729384e-08 -3.2135585793367885e-08 -4.164726028333821e-08 -4.090679952979245e-08 -3.725059992219009e-08 -3.7970186421418355e-08 -3.8031494270713044e-08 -4.139027684534291e-08 -3.8826030848435617e-08 -3.337579591897932e-08 -2.5234918917260192e-08 -1.6238361852731026e-08 -8.990804317276315e-09 -4.904627943575017e-09 -7.598228571567891e-09 -1.910175070678667e-08 -2.83800280224984e-08 -2.7330973469888893e-08 -2.5702535086813514e-08 -2.450777166449961e-08 -2.4578366091502472e-08 -2.3561116012990887e-08 -2.3629984615817896e-08 -2.9840650549997706e-08 -2.123133555768914e-08 -2.6621988462026596e-08 -3.637799034603594e-08 -3.4957719231410216e-08 -3.482565259090544e-08 -3.548458869766791e-08 -3.830031193162849e-08 -4.248814756749806e-08 -4.139118084848265e-08 -3.687100078560542e-08 -2.9257321978558438e-08 -2.0038297959551093e-08 -1.2121449372278773e-08 -8.726342307852313e-09 -2.5439305808943694e-08 -5.437250157085569e-08 -6.356202221466626e-08 -5.237424372152548e-08 -4.40420467825972e-08 -3.960856883903081e-08 -3.931172708078362e-08 -3.375999725336628e-08 -3.0194362323944536e-08 -2.6571364286201495e-08 -2.1477553140111236e-08 -2.6781175196723398e-08 -3.7741227080754814e-08 -4.1266921507821034e-08 -3.93224107542532e-08 -3.700397142924993e-08 -3.815172668829766e-08 -4.255545471035644e-08 -4.167536656277357e-08 -3.68620429363117e-08 -2.9109722920470963e-08 -1.8883228493281877e-08 -1.066099120898669e-08 -7.376583438125838e-09 -2.729925117789459e-08 -5.726383234013947e-08 -6.096786193204413e-08 -4.709626248124032e-08 -3.883844034608107e-08 -3.6161769231432297e-08 -3.63797161702118e-08 -3.2640759184271965e-08 -2.7374365620596127e-08 -3.0217208948748725e-08 -1.9247706122801904e-08 -2.9694448587671636e-08 -3.778124976521395e-08 -3.569472833660426e-08 -3.4935283517124085e-08 -3.352388806968848e-08 -3.482072166468871e-08 -4.085420298348065e-08 -4.184170314048463e-08 -3.938347205723705e-08 -3.361815094253165e-08 -2.5176487441591935e-08 -1.5021080534027388e-08 -8.773761381636542e-09 -2.2151035479213068e-08 -4.309193948273676e-08 -4.298469183752286e-08 -4.0515119623976784e-08 -4.326082370565979e-08 -4.8480620016587526e-08 -4.45871606758568e-08 -4.5376191052637354e-08 -4.30969525910571e-08 -4.083932802272686e-08 -2.126018147605702e-08 -2.7143680455756733e-08 -3.2472285871866996e-08 -3.067562072269747e-08 -2.786039058135857e-08 -2.7915616954985956e-08 -3.100812951391236e-08 -3.749040730053044e-08 -3.9353311225211375e-08 -3.67736971749286e-08 -3.1746782261178655e-08 -2.4059139560880712e-08 -1.5951792857435348e-08 -1.1006402590468688e-08 -2.3599988147999445e-08 -4.11627967825444e-08 -4.210057676686301e-08 -4.033604482020585e-08 -4.144057229275356e-08 -4.283659968681371e-08 -4.612224018922875e-08 -4.48003410526268e-08 -4.116822080138281e-08 -4.069986499289698e-08 -2.1408766719387843e-08 -2.662856303031558e-08 -2.862419105233019e-08 -3.022838571483998e-08 -2.9932776688146966e-08 -2.978912237103287e-08 -3.0828232889105296e-08 -3.334358053436335e-08 -3.2056937520211025e-08 -2.8921936813717125e-08 -2.1977959969005814e-08 -1.4845128650193706e-08 -1.0022025353401973e-08 -6.886778100597233e-09 -2.6894504317604597e-08 -5.9556302120401284e-08 -6.528694238738233e-08 -4.677558791294558e-08 -3.643790109956922e-08 -3.803749356427673e-08 -3.529778877615743e-08 -3.0749091523326765e-08 -2.9122789874945298e-08 -3.1405808713291714e-08 -2.1108308948581704e-08 -3.951981216712966e-08 -4.172081326607111e-08 -4.252496514991631e-08 -3.9431219859435724e-08 -3.863808037747456e-08 -4.049958720639409e-08 -4.3924772920742606e-08 -4.106245243403392e-08 -3.516588649985987e-08 -2.6923843328594146e-08 -1.5724559340947667e-08 -9.253704866731686e-09 -4.846607378424817e-09 -8.330060204234372e-09 -2.3403490738262722e-08 -3.227176153905327e-08 -3.144772158613393e-08 -2.4029964914098385e-08 -2.111751334418627e-08 -2.026191546347984e-08 -1.9748934772732603e-08 -2.2247928179371825e-08 -2.4477117739852266e-08 -1.7689862166729384e-08 -3.2135585793367885e-08 -4.164726028333821e-08 -4.090679952979245e-08 -3.725059992219009e-08 -3.7970186421418355e-08 -3.8031494270713044e-08 -4.139027684534291e-08 -3.8826030848435617e-08 -3.337579591897932e-08 -2.5234918917260192e-08 -1.6238361852731026e-08 -8.990804317276315e-09 -4.904627943575017e-09 -7.598228571567891e-09 -1.910175070678667e-08 -2.83800280224984e-08 -2.7330973469888893e-08 -2.5702535086813514e-08 -2.450777166449961e-08 -2.4578366091502472e-08 -2.3561116012990887e-08 -2.3629984615817896e-08 -2.9840650549997706e-08 -2.123133555768914e-08 -2.6621988462026596e-08 -3.637799034603594e-08 -3.4957719231410216e-08 -3.482565259090544e-08 -3.548458869766791e-08 -3.830031193162849e-08 -4.248814756749806e-08 -4.139118084848265e-08 -3.687100078560542e-08 -2.9257321978558438e-08 -2.0038297959551093e-08 -1.2121449372278773e-08 -8.726342307852313e-09 -2.5439305808943694e-08 -5.437250157085569e-08 -6.356202221466626e-08 -5.237424372152548e-08 -4.40420467825972e-08 -3.960856883903081e-08 -3.931172708078362e-08 -3.375999725336628e-08 -3.0194362323944536e-08 -2.6571364286201495e-08 -2.1477553140111236e-08 -2.6781175196723398e-08 -3.7741227080754814e-08 -4.1266921507821034e-08 -3.93224107542532e-08 -3.700397142924993e-08 -3.815172668829766e-08 -4.255545471035644e-08 -4.167536656277357e-08 -3.68620429363117e-08 -2.9109722920470963e-08 -1.8883228493281877e-08 -1.066099120898669e-08 -7.376583438125838e-09 -2.729925117789459e-08 -5.726383234013947e-08 -6.096786193204413e-08 -4.709626248124032e-08 -3.883844034608107e-08 -3.6161769231432297e-08 -3.63797161702118e-08 -3.2640759184271965e-08 -2.7374365620596127e-08 -3.0217208948748725e-08 -1.9247706122801904e-08 -2.9694448587671636e-08 -3.778124976521395e-08 -3.569472833660426e-08 -3.4935283517124085e-08 -3.352388806968848e-08 -3.482072166468871e-08 -4.085420298348065e-08 -4.184170314048463e-08 -3.938347205723705e-08 -3.361815094253165e-08 -2.5176487441591935e-08 -1.5021080534027388e-08 -8.773761381636542e-09 -2.2151035479213068e-08 -4.309193948273676e-08 -4.298469183752286e-08 -4.0515119623976784e-08 -4.326082370565979e-08 -4.8480620016587526e-08 -4.45871606758568e-08 -4.5376191052637354e-08 -4.30969525910571e-08 -4.083932802272686e-08 -2.126018147605702e-08 -2.7143680455756733e-08 -3.2472285871866996e-08 -3.067562072269747e-08 -2.786039058135857e-08 -2.7915616954985956e-08 -3.100812951391236e-08 -3.749040730053044e-08 -3.9353311225211375e-08 -3.67736971749286e-08 -3.1746782261178655e-08 -2.4059139560880712e-08 -1.5951792857435348e-08 -1.1006402590468688e-08 -2.3599988147999445e-08 -4.11627967825444e-08 -4.210057676686301e-08 -4.033604482020585e-08 -4.144057229275356e-08 -4.283659968681371e-08 -4.612224018922875e-08 -4.48003410526268e-08 -4.116822080138281e-08 -4.069986499289698e-08 -2.1408766719387843e-08 -2.662856303031558e-08 -2.862419105233019e-08 -3.022838571483998e-08 -2.9932776688146966e-08 -2.978912237103287e-08 -3.0828232889105296e-08 -3.334358053436335e-08 -3.2056937520211025e-08 -2.8921936813717125e-08 -2.1977959969005814e-08 -1.4845128650193706e-08 -1.0022025353401973e-08 -6.886778100597233e-09 -2.6894504317604597e-08 -5.9556302120401284e-08 -6.528694238738233e-08 -4.677558791294558e-08 -3.643790109956922e-08 -3.803749356427673e-08 -3.529778877615743e-08 -3.0749091523326765e-08 -2.9122789874945298e-08 -3.1405808713291714e-08 -2.1108308948581704e-08 -3.951981216712966e-08 -4.172081326607111e-08 -4.252496514991631e-08 -3.9431219859435724e-08 -3.863808037747456e-08 -4.049958720639409e-08 -4.3924772920742606e-08 -4.106245243403392e-08 -3.516588649985987e-08 -2.6923843328594146e-08 -1.5724559340947667e-08 -9.253704866731686e-09 -4.846607378424817e-09 -8.330060204234372e-09 -2.3403490738262722e-08 -3.227176153905327e-08 -3.144772158613393e-08 -2.4029964914098385e-08 -2.111751334418627e-08 -2.026191546347984e-08 -1.9748934772732603e-08 -2.2247928179371825e-08 -2.4477117739852266e-08 -1.7689862166729384e-08 -3.2135585793367885e-08 -4.164726028333821e-08 -4.090679952979245e-08 -3.725059992219009e-08 -3.7970186421418355e-08 -3.8031494270713044e-08 -4.139027684534291e-08 -3.8826030848435617e-08 -3.337579591897932e-08 -2.5234918917260192e-08 -1.6238361852731026e-08 -8.990804317276315e-09 -4.904627943575017e-09 -7.598228571567891e-09 -1.910175070678667e-08 -2.83800280224984e-08 -2.7330973469888893e-08 -2.5702535086813514e-08 -2.450777166449961e-08 -2.4578366091502472e-08 -2.3561116012990887e-08 -2.3629984615817896e-08 -2.9840650549997706e-08 -2.123133555768914e-08 -2.6621988462026596e-08 -3.637799034603594e-08 -3.4957719231410216e-08 -3.482565259090544e-08 -3.548458869766791e-08 -3.830031193162849e-08 -4.248814756749806e-08 -4.139118084848265e-08 -3.687100078560542e-08 -2.9257321978558438e-08 -2.0038297959551093e-08 -1.2121449372278773e-08 -8.726342307852313e-09 -2.5439305808943694e-08 -5.437250157085569e-08 -6.356202221466626e-08 -5.237424372152548e-08 -4.40420467825972e-08 -3.960856883903081e-08 -3.931172708078362e-08 -3.375999725336628e-08 -3.0194362323944536e-08 -2.6571364286201495e-08 -2.1477553140111236e-08 -2.6781175196723398e-08 -3.7741227080754814e-08 -4.1266921507821034e-08 -3.93224107542532e-08 -3.700397142924993e-08 -3.815172668829766e-08 -4.255545471035644e-08 -4.167536656277357e-08 -3.68620429363117e-08 -2.9109722920470963e-08 -1.8883228493281877e-08 -1.066099120898669e-08 -7.376583438125838e-09 -2.729925117789459e-08 -5.726383234013947e-08 -6.096786193204413e-08 -4.709626248124032e-08 -3.883844034608107e-08 -3.6161769231432297e-08 -3.63797161702118e-08 -3.2640759184271965e-08 -2.7374365620596127e-08 -3.0217208948748725e-08 -1.9247706122801904e-08 -2.9694448587671636e-08 -3.778124976521395e-08 -3.569472833660426e-08 -3.4935283517124085e-08 -3.352388806968848e-08 -3.482072166468871e-08 -4.085420298348065e-08 -4.184170314048463e-08 -3.938347205723705e-08 -3.361815094253165e-08 -2.5176487441591935e-08 -1.5021080534027388e-08 -8.773761381636542e-09 -2.2151035479213068e-08 -4.309193948273676e-08 -4.298469183752286e-08 -4.0515119623976784e-08 -4.326082370565979e-08 -4.8480620016587526e-08 -4.45871606758568e-08 -4.5376191052637354e-08 -4.30969525910571e-08 -4.083932802272686e-08 -2.126018147605702e-08 -2.7143680455756733e-08 -3.2472285871866996e-08 -3.067562072269747e-08 -2.786039058135857e-08 -2.7915616954985956e-08 -3.100812951391236e-08 -3.749040730053044e-08 -3.4662849843649705e-08 -3.796985769300391e-08 -3.5421472842093754e-08 -2.9849690581395044e-08 -2.2315892779059104e-08 -1.4979578571703237e-08 -9.36571907395509e-09 -2.2300689089890848e-08 -4.4232627080873846e-08 -4.3018222135796626e-08 -3.709815211998949e-08 -4.4654139090300725e-08 -4.759642276382406e-08 -5.177012307787233e-08 -4.9480776217547786e-08 -4.459809089563722e-08 -4.47201313195013e-08 -2.5564140424330593e-08 -2.973323854057658e-08 -3.2126956672488606e-08 -2.9341229906346477e-08 -3.040852888595788e-08 -3.0317964207777264e-08 -3.1300451256460894e-08 -3.172360690796002e-08 -3.1790503140300334e-08 -2.840418956096038e-08 -2.08634062798174e-08 -1.3628093877800904e-08 -7.435836734830222e-09 -6.034796232449743e-09 -2.71596237838575e-08 -5.921327401992403e-08 -6.537241177513901e-08 -5.023890612337016e-08 -4.484603430223518e-08 -4.011407095834934e-08 -3.649066201008824e-08 -3.068901640558626e-08 -3.0874583595542565e-08 -3.3180859969211225e-08 -2.1665585793175913e-08 -3.351501240249836e-08 -4.2465629671108316e-08 -4.0198965071380724e-08 -3.9175633517201836e-08 -3.952079835237301e-08 -4.1933582732323056e-08 -4.3888941523567696e-08 -4.0032628493669674e-08 -3.454491852496622e-08 -2.6838127394526638e-08 -1.719709827347074e-08 -8.609150628101342e-09 -4.93519968611875e-09 -7.904192543316045e-09 -2.6886368289346992e-08 -3.641521883897226e-08 -2.959451514967922e-08 -2.3734848980027035e-08 -2.6640068524821277e-08 -2.2509595997273015e-08 -2.3397162716284577e-08 -2.4853676138603285e-08 -3.153639607593147e-08 -1.883761742577712e-08 -3.486625055008986e-08 -4.4736074647602065e-08 -4.1239061774696505e-08 -4.0519064364950175e-08 -4.075385863497018e-08 -4.28089043178964e-08 -4.5367644113861695e-08 -4.4585845762199004e-08 -3.8857506594119084e-08 -3.1365950393039806e-08 -2.0881321978404856e-08 -1.0845325667388813e-08 -5.9457108321341375e-09 -8.48965784944923e-09 -2.1701252826143597e-08 -3.278597496135469e-08 -2.7426551256389862e-08 -2.440307166449769e-08 -2.0848202590649148e-08 -2.6431901256371627e-08 -2.817342221401737e-08 -2.80703658560877e-08 -3.275729340719404e-08 -1.9111037284494845e-08 -3.020668963948637e-08 -3.968146436493482e-08 -3.8228484773071445e-08 -3.8020974961450686e-08 -3.708779717493436e-08 -3.968910730057075e-08 -4.326353571507899e-08 -4.21241630305997e-08 -3.780072692377004e-08 -2.991831263791122e-08 -1.843459638966298e-08 -1.0604860832219567e-08 -8.36202904253951e-09 -2.9181714443235233e-08 -5.882258029935173e-08 -6.802138752087047e-08 -5.314305730081744e-08 -4.132116169620508e-08 -3.6849633438666255e-08 -3.7080811696127326e-08 -3.666751789706166e-08 -3.235525855632325e-08 -3.2955845369521076e-08 -2.2043212559273887e-08 -3.559906836799968e-08 -4.156737927862717e-08 -4.094115164910234e-08 -4.124530761457103e-08 -4.0493341366519564e-08 -4.4799683595797905e-08 -5.1154825668127926e-08 -5.1085546154782856e-08 -4.653232888625352e-08 -3.743000345437549e-08 -2.5051652826205026e-08 -1.4618963501052981e-08 -9.616867582593916e-09 -2.797454152327589e-08 -6.118548014240918e-08 -6.683878704989118e-08 -5.036628838396904e-08 -4.3097610047885996e-08 -4.391721216721029e-08 -4.014472488299669e-08 -3.7082373156095954e-08 -3.2995046232944086e-08 -3.332969175885289e-08 -2.1996368760214938e-08 -3.085568171171177e-08 -3.68432232345845e-08 -3.3642805573615304e-08 -3.3517560047710337e-08 -3.216870518112359e-08 -3.498804442764311e-08 -4.2196812010192874e-08 -4.523187927869436e-08 -4.1766753061990315e-08 -3.548056177459091e-08 -2.5639008320721294e-08 -1.558082284172996e-08 -1.0622283438185352e-08 -2.413006271629802e-08 -4.697709843100265e-08 -4.662240047181248e-08 -4.420246624884818e-08 -4.808680337607795e-08 -5.017135243420094e-08 -5.43206446634764e-08 -4.7860145134315546e-08 -4.345674584067123e-08 -4.410360117820272e-08 -2.2700998116585786e-08 -2.8284203689686594e-08 -3.187161687656556e-08 -2.8246646468335827e-08 -2.7923342072725502e-08 -2.5509078414910432e-08 -2.820834960805255e-08 -3.4662849843649705e-08 -3.796985769300391e-08 -3.5421472842093754e-08 -2.9849690581395044e-08 -2.2315892779059104e-08 -1.4979578571703237e-08 -9.36571907395509e-09 -2.2300689089890848e-08 -4.4232627080873846e-08 -4.3018222135796626e-08 -3.709815211998949e-08 -4.4654139090300725e-08 -4.759642276382406e-08 -5.177012307787233e-08 -4.9480776217547786e-08 -4.459809089563722e-08 -4.47201313195013e-08 -2.5564140424330593e-08 -2.973323854057658e-08 -3.2126956672488606e-08 -2.9341229906346477e-08 -3.040852888595788e-08 -3.0317964207777264e-08 -3.1300451256460894e-08 -3.172360690796002e-08 -3.1790503140300334e-08 -2.840418956096038e-08 -2.08634062798174e-08 -1.3628093877800904e-08 -7.435836734830222e-09 -6.034796232449743e-09 -2.71596237838575e-08 -5.921327401992403e-08 -6.537241177513901e-08 -5.023890612337016e-08 -4.484603430223518e-08 -4.011407095834934e-08 -3.649066201008824e-08 -3.068901640558626e-08 -3.0874583595542565e-08 -3.3180859969211225e-08 -2.1665585793175913e-08 -3.351501240249836e-08 -4.2465629671108316e-08 -4.0198965071380724e-08 -3.9175633517201836e-08 -3.952079835237301e-08 -4.1933582732323056e-08 -4.3888941523567696e-08 -4.0032628493669674e-08 -3.454491852496622e-08 -2.6838127394526638e-08 -1.719709827347074e-08 -8.609150628101342e-09 -4.93519968611875e-09 -7.904192543316045e-09 -2.6886368289346992e-08 -3.641521883897226e-08 -2.959451514967922e-08 -2.3734848980027035e-08 -2.6640068524821277e-08 -2.2509595997273015e-08 -2.3397162716284577e-08 -2.4853676138603285e-08 -3.153639607593147e-08 -1.883761742577712e-08 -3.486625055008986e-08 -4.4736074647602065e-08 -4.1239061774696505e-08 -4.0519064364950175e-08 -4.075385863497018e-08 -4.28089043178964e-08 -4.5367644113861695e-08 -4.4585845762199004e-08 -3.8857506594119084e-08 -3.1365950393039806e-08 -2.0881321978404856e-08 -1.0845325667388813e-08 -5.9457108321341375e-09 -8.48965784944923e-09 -2.1701252826143597e-08 -3.278597496135469e-08 -2.7426551256389862e-08 -2.440307166449769e-08 -2.0848202590649148e-08 -2.6431901256371627e-08 -2.817342221401737e-08 -2.80703658560877e-08 -3.275729340719404e-08 -1.9111037284494845e-08 -3.020668963948637e-08 -3.968146436493482e-08 -3.8228484773071445e-08 -3.8020974961450686e-08 -3.708779717493436e-08 -3.968910730057075e-08 -4.326353571507899e-08 -4.21241630305997e-08 -3.780072692377004e-08 -2.991831263791122e-08 -1.843459638966298e-08 -1.0604860832219567e-08 -8.36202904253951e-09 -2.9181714443235233e-08 -5.882258029935173e-08 -6.802138752087047e-08 -5.314305730081744e-08 -4.132116169620508e-08 -3.6849633438666255e-08 -3.7080811696127326e-08 -3.666751789706166e-08 -3.235525855632325e-08 -3.2955845369521076e-08 -2.2043212559273887e-08 -3.559906836799968e-08 -4.156737927862717e-08 -4.094115164910234e-08 -4.124530761457103e-08 -4.0493341366519564e-08 -4.4799683595797905e-08 -5.1154825668127926e-08 -5.1085546154782856e-08 -4.653232888625352e-08 -3.743000345437549e-08 -2.5051652826205026e-08 -1.4618963501052981e-08 -9.616867582593916e-09 -2.797454152327589e-08 -6.118548014240918e-08 -6.683878704989118e-08 -5.036628838396904e-08 -4.3097610047885996e-08 -4.391721216721029e-08 -4.014472488299669e-08 -3.7082373156095954e-08 -3.2995046232944086e-08 -3.332969175885289e-08 -2.1996368760214938e-08 -3.085568171171177e-08 -3.68432232345845e-08 -3.3642805573615304e-08 -3.3517560047710337e-08 -3.216870518112359e-08 -3.498804442764311e-08 -4.2196812010192874e-08 -4.523187927869436e-08 -4.1766753061990315e-08 -3.548056177459091e-08 -2.5639008320721294e-08 -1.558082284172996e-08 -1.0622283438185352e-08 -2.413006271629802e-08 -4.697709843100265e-08 -4.662240047181248e-08 -4.420246624884818e-08 -4.808680337607795e-08 -5.017135243420094e-08 -5.43206446634764e-08 -4.7860145134315546e-08 -4.345674584067123e-08 -4.410360117820272e-08 -2.2700998116585786e-08 -2.8284203689686594e-08 -3.187161687656556e-08 -2.8246646468335827e-08 -2.7923342072725502e-08 -2.5509078414910432e-08 -2.820834960805255e-08 -3.4662849843649705e-08 -3.796985769300391e-08 -3.5421472842093754e-08 -2.9849690581395044e-08 -2.2315892779059104e-08 -1.4979578571703237e-08 -9.36571907395509e-09 -2.2300689089890848e-08 -4.4232627080873846e-08 -4.3018222135796626e-08 -3.709815211998949e-08 -4.4654139090300725e-08 -4.759642276382406e-08 -5.177012307787233e-08 -4.9480776217547786e-08 -4.459809089563722e-08 -4.47201313195013e-08 -2.5564140424330593e-08 -2.973323854057658e-08 -3.2126956672488606e-08 -2.9341229906346477e-08 -3.040852888595788e-08 -3.0317964207777264e-08 -3.1300451256460894e-08 -3.172360690796002e-08 -3.1790503140300334e-08 -2.840418956096038e-08 -2.08634062798174e-08 -1.3628093877800904e-08 -7.435836734830222e-09 -6.034796232449743e-09 -2.71596237838575e-08 -5.921327401992403e-08 -6.537241177513901e-08 -5.023890612337016e-08 -4.484603430223518e-08 -4.011407095834934e-08 -3.649066201008824e-08 -3.068901640558626e-08 -3.0874583595542565e-08 -3.3180859969211225e-08 -2.1665585793175913e-08 -3.351501240249836e-08 -4.2465629671108316e-08 -4.0198965071380724e-08 -3.9175633517201836e-08 -3.952079835237301e-08 -4.1933582732323056e-08 -4.3888941523567696e-08 -4.0032628493669674e-08 -3.454491852496622e-08 -2.6838127394526638e-08 -1.719709827347074e-08 -8.609150628101342e-09 -4.93519968611875e-09 -7.904192543316045e-09 -2.6886368289346992e-08 -3.641521883897226e-08 -2.959451514967922e-08 -2.3734848980027035e-08 -2.6640068524821277e-08 -2.2509595997273015e-08 -2.3397162716284577e-08 -2.4853676138603285e-08 -3.153639607593147e-08 -1.883761742577712e-08 -3.486625055008986e-08 -4.4736074647602065e-08 -4.1239061774696505e-08 -4.0519064364950175e-08 -4.075385863497018e-08 -4.28089043178964e-08 -4.5367644113861695e-08 -4.4585845762199004e-08 -3.8857506594119084e-08 -3.1365950393039806e-08 -2.0881321978404856e-08 -1.0845325667388813e-08 -5.9457108321341375e-09 -8.48965784944923e-09 -2.1701252826143597e-08 -3.278597496135469e-08 -2.7426551256389862e-08 -2.440307166449769e-08 -2.0848202590649148e-08 -2.6431901256371627e-08 -2.817342221401737e-08 -2.80703658560877e-08 -3.275729340719404e-08 -1.9111037284494845e-08 -3.020668963948637e-08 -3.968146436493482e-08 -3.8228484773071445e-08 -3.8020974961450686e-08 -3.708779717493436e-08 -3.968910730057075e-08 -4.326353571507899e-08 -4.21241630305997e-08 -3.780072692377004e-08 -2.991831263791122e-08 -1.843459638966298e-08 -1.0604860832219567e-08 -8.36202904253951e-09 -2.9181714443235233e-08 -5.882258029935173e-08 -6.802138752087047e-08 -5.314305730081744e-08 -4.132116169620508e-08 -3.6849633438666255e-08 -3.7080811696127326e-08 -3.666751789706166e-08 -3.235525855632325e-08 -3.2955845369521076e-08 -2.2043212559273887e-08 -3.559906836799968e-08 -4.156737927862717e-08 -4.094115164910234e-08 -4.124530761457103e-08 -4.0493341366519564e-08 -4.4799683595797905e-08 -5.1154825668127926e-08 -5.1085546154782856e-08 -4.653232888625352e-08 -3.743000345437549e-08 -2.5051652826205026e-08 -1.4618963501052981e-08 -9.616867582593916e-09 -2.797454152327589e-08 -6.118548014240918e-08 -6.683878704989118e-08 -5.036628838396904e-08 -4.3097610047885996e-08 -4.391721216721029e-08 -4.014472488299669e-08 -3.7082373156095954e-08 -3.2995046232944086e-08 -3.332969175885289e-08 -2.1996368760214938e-08 -3.085568171171177e-08 -3.68432232345845e-08 -3.3642805573615304e-08 -3.3517560047710337e-08 -3.216870518112359e-08 -3.498804442764311e-08 -4.2196812010192874e-08 -4.523187927869436e-08 -4.1766753061990315e-08 -3.548056177459091e-08 -2.5639008320721294e-08 -1.558082284172996e-08 -1.0622283438185352e-08 -2.413006271629802e-08 -4.697709843100265e-08 -4.662240047181248e-08 -4.420246624884818e-08 -4.808680337607795e-08 -5.017135243420094e-08 -5.43206446634764e-08 -4.7860145134315546e-08 -4.345674584067123e-08 -4.410360117820272e-08 -2.2700998116585786e-08 -2.8284203689686594e-08 -3.187161687656556e-08 -2.8246646468335827e-08 -2.7923342072725502e-08 -2.5509078414910432e-08 -2.820834960805255e-08 -3.4662849843649705e-08 -3.796985769300391e-08 -3.5421472842093754e-08 -2.9849690581395044e-08 -2.2315892779059104e-08 -1.4979578571703237e-08 -9.36571907395509e-09 -2.2300689089890848e-08 -4.4232627080873846e-08 -4.3018222135796626e-08 -3.709815211998949e-08 -4.4654139090300725e-08 -4.759642276382406e-08 -5.177012307787233e-08 -4.9480776217547786e-08 -4.459809089563722e-08 -4.47201313195013e-08 -2.5564140424330593e-08 -2.973323854057658e-08 -3.2126956672488606e-08 -2.9341229906346477e-08 -3.040852888595788e-08 -3.0317964207777264e-08 -3.1300451256460894e-08 -3.172360690796002e-08 -3.1790503140300334e-08 -2.840418956096038e-08 -2.08634062798174e-08 -1.3628093877800904e-08 -7.435836734830222e-09 -6.034796232449743e-09 -2.71596237838575e-08 -5.921327401992403e-08 -6.537241177513901e-08 -5.023890612337016e-08 -4.484603430223518e-08 -4.011407095834934e-08 -3.649066201008824e-08 -3.068901640558626e-08 -3.0874583595542565e-08 -3.3180859969211225e-08 -2.1665585793175913e-08 -3.351501240249836e-08 -4.2465629671108316e-08 -4.0198965071380724e-08 -3.9175633517201836e-08 -3.952079835237301e-08 -4.1933582732323056e-08 -4.3888941523567696e-08 -4.0032628493669674e-08 -3.454491852496622e-08 -2.6838127394526638e-08 -1.719709827347074e-08 -8.609150628101342e-09 -4.93519968611875e-09 -7.904192543316045e-09 -2.6886368289346992e-08 -3.641521883897226e-08 -2.959451514967922e-08 -2.3734848980027035e-08 -2.6640068524821277e-08 -2.2509595997273015e-08 -2.3397162716284577e-08 -2.4853676138603285e-08 -3.153639607593147e-08 -1.883761742577712e-08 -3.486625055008986e-08 -4.4736074647602065e-08 -4.1239061774696505e-08 -4.0519064364950175e-08 -4.075385863497018e-08 -4.28089043178964e-08 -4.5367644113861695e-08 -4.4585845762199004e-08 -3.8857506594119084e-08 -3.1365950393039806e-08 -2.0881321978404856e-08 -1.0845325667388813e-08 -5.9457108321341375e-09 -8.48965784944923e-09 -2.1701252826143597e-08 -3.278597496135469e-08 -2.7426551256389862e-08 -2.440307166449769e-08 -2.0848202590649148e-08 -2.6431901256371627e-08 -2.817342221401737e-08 -2.80703658560877e-08 -3.275729340719404e-08 -1.9111037284494845e-08 -3.020668963948637e-08 -3.968146436493482e-08 -3.8228484773071445e-08 -3.8020974961450686e-08 -3.708779717493436e-08 -3.968910730057075e-08 -4.326353571507899e-08 -4.21241630305997e-08 -3.780072692377004e-08 -2.991831263791122e-08 -1.843459638966298e-08 -1.0604860832219567e-08 -8.36202904253951e-09 -2.9181714443235233e-08 -5.882258029935173e-08 -6.802138752087047e-08 -5.314305730081744e-08 -4.132116169620508e-08 -3.6849633438666255e-08 -3.7080811696127326e-08 -3.666751789706166e-08 -3.235525855632325e-08 -3.2955845369521076e-08 -2.2043212559273887e-08 -3.559906836799968e-08 -4.156737927862717e-08 -4.094115164910234e-08 -4.124530761457103e-08 -4.0493341366519564e-08 -4.4799683595797905e-08 -5.1154825668127926e-08 -5.1085546154782856e-08 -4.653232888625352e-08 -3.743000345437549e-08 -2.5051652826205026e-08 -1.4618963501052981e-08 -9.616867582593916e-09 -2.797454152327589e-08 -6.118548014240918e-08 -6.683878704989118e-08 -5.036628838396904e-08 -4.3097610047885996e-08 -4.391721216721029e-08 -4.014472488299669e-08 -3.7082373156095954e-08 -3.2995046232944086e-08 -3.332969175885289e-08 -2.1996368760214938e-08 -3.085568171171177e-08 -3.68432232345845e-08 -3.3642805573615304e-08 -3.3517560047710337e-08 -3.216870518112359e-08 -3.498804442764311e-08 -4.2196812010192874e-08 -4.523187927869436e-08 -4.1766753061990315e-08 -3.548056177459091e-08 -2.5639008320721294e-08 -1.558082284172996e-08 -1.0622283438185352e-08 -2.413006271629802e-08 -4.697709843100265e-08 -4.662240047181248e-08 -4.420246624884818e-08 -4.808680337607795e-08 -5.017135243420094e-08 -5.43206446634764e-08 -4.7860145134315546e-08 -4.345674584067123e-08 -4.410360117820272e-08 -2.2700998116585786e-08 -2.8284203689686594e-08 -3.187161687656556e-08 -2.8246646468335827e-08 -2.7923342072725502e-08 -2.5509078414910432e-08 -2.820834960805255e-08 -3.4662849843649705e-08 -3.796985769300391e-08 -3.5421472842093754e-08 -2.9849690581395044e-08 -2.2315892779059104e-08 -1.4979578571703237e-08 -9.36571907395509e-09 -2.2300689089890848e-08 -4.4232627080873846e-08 -4.3018222135796626e-08 -3.709815211998949e-08 -4.4654139090300725e-08 -4.759642276382406e-08 -5.177012307787233e-08 -4.9480776217547786e-08 -4.459809089563722e-08 -4.47201313195013e-08 -2.5564140424330593e-08 -2.973323854057658e-08 -3.2126956672488606e-08 -2.9341229906346477e-08 -3.040852888595788e-08 -3.0317964207777264e-08 -3.1300451256460894e-08 -3.172360690796002e-08 -3.1790503140300334e-08 -2.840418956096038e-08 -2.08634062798174e-08 -1.3628093877800904e-08 -7.435836734830222e-09 -6.034796232449743e-09 -2.71596237838575e-08 -5.921327401992403e-08 -6.537241177513901e-08 -5.023890612337016e-08 -4.484603430223518e-08 -4.011407095834934e-08 -3.649066201008824e-08 -3.068901640558626e-08 -3.0874583595542565e-08 -3.3180859969211225e-08 -2.1665585793175913e-08 -3.351501240249836e-08 -4.2465629671108316e-08 -4.0198965071380724e-08 -3.9175633517201836e-08 -3.952079835237301e-08 -4.1933582732323056e-08 -4.320255659419875e-08 -4.369145792858762e-08 -3.894149670401073e-08 -3.033275698642745e-08 -2.0578974019215637e-08 -1.2271267347163782e-08 -6.307558634338575e-09 -6.64450525914852e-09 -2.278391985913048e-08 -3.0051776374177405e-08 -2.798769065985384e-08 -2.4630633909399817e-08 -3.0233070094745875e-08 -2.7632828336456437e-08 -2.8230785322338677e-08 -2.835085337571607e-08 -3.3426666641115266e-08 -2.087984270053984e-08 -2.8541598038199948e-08 -3.440693477300137e-08 -3.1283932653634847e-08 -3.018622629568693e-08 -3.120051781846848e-08 -3.4445971272217156e-08 -4.5683387755939696e-08 -4.487381185325608e-08 -4.124489670405297e-08 -3.211988901157796e-08 -2.2828626923495507e-08 -1.3176421036348353e-08 -5.991075353328063e-09 -8.04373775524953e-09 -1.808104897992337e-08 -2.6606702590754737e-08 -2.541407590313475e-08 -2.498409913703581e-08 -2.782505227680533e-08 -3.0535089325520645e-08 -2.6593471272073173e-08 -3.135304780277269e-08 -3.465964474160883e-08 -1.9390456436776265e-08 -3.0634858399305834e-08 -3.6296301335045434e-08 -3.59014163271889e-08 -3.586172237114421e-08 -3.840361483586901e-08 -4.2375886813963813e-08 -4.836646907467021e-08 -4.7629706515787e-08 -4.3111498823396454e-08 -3.3079693799664635e-08 -2.212399756712466e-08 -1.2966363579515615e-08 -8.010289639079372e-09 -2.76885478027055e-08 -5.6497402041852264e-08 -5.975962064473781e-08 -5.229460926312527e-08 -4.4061606123256894e-08 -4.136775894895318e-08 -4.2394295605172947e-08 -4.3267644820259605e-08 -4.308503618603333e-08 -3.8746889482657085e-08 -2.6217323783840216e-08 -3.124432087969378e-08 -3.6494771115268856e-08 -3.7079743328780364e-08 -3.687330188450657e-08 -3.7454904631769975e-08 -4.18812327323221e-08 -4.6852921272444654e-08 -4.776440298360736e-08 -4.3437926138944047e-08 -3.471643257520485e-08 -2.360434379949089e-08 -1.41589902671356e-08 -8.802771664211643e-09 -2.860364552642714e-08 -5.850091954581364e-08 -5.97230496086304e-08 -4.8849946390220674e-08 -4.25012145219724e-08 -4.329969584066835e-08 -4.1758781397939946e-08 -3.925452833666953e-08 -4.018310392538358e-08 -3.6559366248708025e-08 -2.2717516719411836e-08 -2.985799097385988e-08 -3.226748806966544e-08 -3.348550902730159e-08 -3.2558330534348953e-08 -3.1646684458979014e-08 -3.5048119545383616e-08 -4.314609748901718e-08 -4.599872048749963e-08 -4.295313390973578e-08 -3.619209442766518e-08 -2.5490751805804922e-08 -1.550743422320428e-08 -9.691653296881005e-09 -2.4666465306574734e-08 -4.3852945762185566e-08 -4.699246648437814e-08 -4.17909146004523e-08 -4.581750894903477e-08 -5.0574455652418706e-08 -5.5644927081083095e-08 -5.1785326767040587e-08 -4.715239285800744e-08 -4.613464968687418e-08 -2.408330109934269e-08 -2.951085376820202e-08 -3.079741460025073e-08 -2.716389725324533e-08 -2.731774215120733e-08 -2.7460163736767242e-08 -3.1031880141856285e-08 -3.6725785008522695e-08 -3.911309293635297e-08 -3.740165062862928e-08 -3.2150049843603634e-08 -2.5010808320709775e-08 -1.7650661303306373e-08 -1.131228438011323e-08 -2.44456419941688e-08 -4.4772892230020325e-08 -4.2994389325749095e-08 -3.8559760832732145e-08 -4.4501526923892894e-08 -5.071917833687975e-08 -5.276986836831453e-08 -5.4089219859704496e-08 -5.145240706530764e-08 -4.5904868525174526e-08 -2.5467165542068223e-08 -2.598392660958162e-08 -2.942390510258033e-08 -3.0278763344354247e-08 -3.1644794270595935e-08 -3.2408266013153105e-08 -3.400703665682449e-08 -3.732185180602185e-08 -3.6746001806011294e-08 -3.3408340032009745e-08 -2.6945785950258595e-08 -1.7694546546635278e-08 -9.458831397347691e-09 -6.661516954596243e-09 -2.446298241803097e-08 -5.715740651596169e-08 -6.123347449091869e-08 -4.9403771586463166e-08 -4.4552890738650516e-08 -4.2353615463884915e-08 -3.62880009425806e-08 -3.7049253768340246e-08 -3.5656678022631817e-08 -3.5558388226711655e-08 -2.5701713265777388e-08 -3.5616573156069076e-08 -4.225318893327082e-08 -4.016124348582274e-08 -3.9258801806057365e-08 -3.8299654474799595e-08 -3.999540000073336e-08 -4.320255659419875e-08 -4.369145792858762e-08 -3.894149670401073e-08 -3.033275698642745e-08 -2.0578974019215637e-08 -1.2271267347163782e-08 -6.307558634338575e-09 -6.64450525914852e-09 -2.278391985913048e-08 -3.0051776374177405e-08 -2.798769065985384e-08 -2.4630633909399817e-08 -3.0233070094745875e-08 -2.7632828336456437e-08 -2.8230785322338677e-08 -2.835085337571607e-08 -3.3426666641115266e-08 -2.087984270053984e-08 -2.8541598038199948e-08 -3.440693477300137e-08 -3.1283932653634847e-08 -3.018622629568693e-08 -3.120051781846848e-08 -3.4445971272217156e-08 -4.5683387755939696e-08 -4.487381185325608e-08 -4.124489670405297e-08 -3.211988901157796e-08 -2.2828626923495507e-08 -1.3176421036348353e-08 -5.991075353328063e-09 -8.04373775524953e-09 -1.808104897992337e-08 -2.6606702590754737e-08 -2.541407590313475e-08 -2.498409913703581e-08 -2.782505227680533e-08 -3.0535089325520645e-08 -2.6593471272073173e-08 -3.135304780277269e-08 -3.465964474160883e-08 -1.9390456436776265e-08 -3.0634858399305834e-08 -3.6296301335045434e-08 -3.59014163271889e-08 -3.586172237114421e-08 -3.840361483586901e-08 -4.2375886813963813e-08 -4.836646907467021e-08 -4.7629706515787e-08 -4.3111498823396454e-08 -3.3079693799664635e-08 -2.212399756712466e-08 -1.2966363579515615e-08 -8.010289639079372e-09 -2.76885478027055e-08 -5.6497402041852264e-08 -5.975962064473781e-08 -5.229460926312527e-08 -4.4061606123256894e-08 -4.136775894895318e-08 -4.2394295605172947e-08 -4.3267644820259605e-08 -4.308503618603333e-08 -3.8746889482657085e-08 -2.6217323783840216e-08 -3.124432087969378e-08 -3.6494771115268856e-08 -3.7079743328780364e-08 -3.687330188450657e-08 -3.7454904631769975e-08 -4.18812327323221e-08 -4.6852921272444654e-08 -4.776440298360736e-08 -4.3437926138944047e-08 -3.471643257520485e-08 -2.360434379949089e-08 -1.41589902671356e-08 -8.802771664211643e-09 -2.860364552642714e-08 -5.850091954581364e-08 -5.97230496086304e-08 -4.8849946390220674e-08 -4.25012145219724e-08 -4.329969584066835e-08 -4.1758781397939946e-08 -3.925452833666953e-08 -4.018310392538358e-08 -3.6559366248708025e-08 -2.2717516719411836e-08 -2.985799097385988e-08 -3.226748806966544e-08 -3.348550902730159e-08 -3.2558330534348953e-08 -3.1646684458979014e-08 -3.5048119545383616e-08 -4.314609748901718e-08 -4.599872048749963e-08 -4.295313390973578e-08 -3.619209442766518e-08 -2.5490751805804922e-08 -1.550743422320428e-08 -9.691653296881005e-09 -2.4666465306574734e-08 -4.3852945762185566e-08 -4.699246648437814e-08 -4.17909146004523e-08 -4.581750894903477e-08 -5.0574455652418706e-08 -5.5644927081083095e-08 -5.1785326767040587e-08 -4.715239285800744e-08 -4.613464968687418e-08 -2.408330109934269e-08 -2.951085376820202e-08 -3.079741460025073e-08 -2.716389725324533e-08 -2.731774215120733e-08 -2.7460163736767242e-08 -3.1031880141856285e-08 -3.6725785008522695e-08 -3.911309293635297e-08 -3.740165062862928e-08 -3.2150049843603634e-08 -2.5010808320709775e-08 -1.7650661303306373e-08 -1.131228438011323e-08 -2.44456419941688e-08 -4.4772892230020325e-08 -4.2994389325749095e-08 -3.8559760832732145e-08 -4.4501526923892894e-08 -5.071917833687975e-08 -5.276986836831453e-08 -5.4089219859704496e-08 -5.145240706530764e-08 -4.5904868525174526e-08 -2.5467165542068223e-08 -2.598392660958162e-08 -2.942390510258033e-08 -3.0278763344354247e-08 -3.1644794270595935e-08 -3.2408266013153105e-08 -3.400703665682449e-08 -3.732185180602185e-08 -3.6746001806011294e-08 -3.3408340032009745e-08 -2.6945785950258595e-08 -1.7694546546635278e-08 -9.458831397347691e-09 -6.661516954596243e-09 -2.446298241803097e-08 -5.715740651596169e-08 -6.123347449091869e-08 -4.9403771586463166e-08 -4.4552890738650516e-08 -4.2353615463884915e-08 -3.62880009425806e-08 -3.7049253768340246e-08 -3.5656678022631817e-08 -3.5558388226711655e-08 -2.5701713265777388e-08 -3.5616573156069076e-08 -4.225318893327082e-08 -4.016124348582274e-08 -3.9258801806057365e-08 -3.8299654474799595e-08 -3.999540000073336e-08 -4.320255659419875e-08 -4.369145792858762e-08 -3.894149670401073e-08 -3.033275698642745e-08 -2.0578974019215637e-08 -1.2271267347163782e-08 -6.307558634338575e-09 -6.64450525914852e-09 -2.278391985913048e-08 -3.0051776374177405e-08 -2.798769065985384e-08 -2.4630633909399817e-08 -3.0233070094745875e-08 -2.7632828336456437e-08 -2.8230785322338677e-08 -2.835085337571607e-08 -3.3426666641115266e-08 -2.087984270053984e-08 -2.8541598038199948e-08 -3.440693477300137e-08 -3.1283932653634847e-08 -3.018622629568693e-08 -3.120051781846848e-08 -3.4445971272217156e-08 -4.5683387755939696e-08 -4.487381185325608e-08 -4.124489670405297e-08 -3.211988901157796e-08 -2.2828626923495507e-08 -1.3176421036348353e-08 -5.991075353328063e-09 -8.04373775524953e-09 -1.808104897992337e-08 -2.6606702590754737e-08 -2.541407590313475e-08 -2.498409913703581e-08 -2.782505227680533e-08 -3.0535089325520645e-08 -2.6593471272073173e-08 -3.135304780277269e-08 -3.465964474160883e-08 -1.9390456436776265e-08 -3.0634858399305834e-08 -3.6296301335045434e-08 -3.59014163271889e-08 -3.586172237114421e-08 -3.840361483586901e-08 -4.2375886813963813e-08 -4.836646907467021e-08 -4.7629706515787e-08 -4.3111498823396454e-08 -3.3079693799664635e-08 -2.212399756712466e-08 -1.2966363579515615e-08 -8.010289639079372e-09 -2.76885478027055e-08 -5.6497402041852264e-08 -5.975962064473781e-08 -5.229460926312527e-08 -4.4061606123256894e-08 -4.136775894895318e-08 -4.2394295605172947e-08 -4.3267644820259605e-08 -4.308503618603333e-08 -3.8746889482657085e-08 -2.6217323783840216e-08 -3.124432087969378e-08 -3.6494771115268856e-08 -3.7079743328780364e-08 -3.687330188450657e-08 -3.7454904631769975e-08 -4.18812327323221e-08 -4.6852921272444654e-08 -4.776440298360736e-08 -4.3437926138944047e-08 -3.471643257520485e-08 -2.360434379949089e-08 -1.41589902671356e-08 -8.802771664211643e-09 -2.860364552642714e-08 -5.850091954581364e-08 -5.97230496086304e-08 -4.8849946390220674e-08 -4.25012145219724e-08 -4.329969584066835e-08 -4.1758781397939946e-08 -3.925452833666953e-08 -4.018310392538358e-08 -3.6559366248708025e-08 -2.2717516719411836e-08 -2.985799097385988e-08 -3.226748806966544e-08 -3.348550902730159e-08 -3.2558330534348953e-08 -3.1646684458979014e-08 -3.5048119545383616e-08 -4.314609748901718e-08 -4.599872048749963e-08 -4.295313390973578e-08 -3.619209442766518e-08 -2.5490751805804922e-08 -1.550743422320428e-08 -9.691653296881005e-09 -2.4666465306574734e-08 -4.3852945762185566e-08 -4.699246648437814e-08 -4.17909146004523e-08 -4.581750894903477e-08 -5.0574455652418706e-08 -5.5644927081083095e-08 -5.1785326767040587e-08 -4.715239285800744e-08 -4.613464968687418e-08 -2.408330109934269e-08 -2.951085376820202e-08 -3.079741460025073e-08 -2.716389725324533e-08 -2.731774215120733e-08 -2.7460163736767242e-08 -3.1031880141856285e-08 -3.6725785008522695e-08 -3.911309293635297e-08 -3.740165062862928e-08 -3.2150049843603634e-08 -2.5010808320709775e-08 -1.7650661303306373e-08 -1.131228438011323e-08 -2.44456419941688e-08 -4.4772892230020325e-08 -4.2994389325749095e-08 -3.8559760832732145e-08 -4.4501526923892894e-08 -5.071917833687975e-08 -5.276986836831453e-08 -5.4089219859704496e-08 -5.145240706530764e-08 -4.5904868525174526e-08 -2.5467165542068223e-08 -2.598392660958162e-08 -2.942390510258033e-08 -3.0278763344354247e-08 -3.1644794270595935e-08 -3.2408266013153105e-08 -3.400703665682449e-08 -3.732185180602185e-08 -3.6746001806011294e-08 -3.3408340032009745e-08 -2.6945785950258595e-08 -1.7694546546635278e-08 -9.458831397347691e-09 -6.661516954596243e-09 -2.446298241803097e-08 -5.715740651596169e-08 -6.123347449091869e-08 -4.9403771586463166e-08 -4.4552890738650516e-08 -4.2353615463884915e-08 -3.62880009425806e-08 -3.7049253768340246e-08 -3.5656678022631817e-08 -3.5558388226711655e-08 -2.5701713265777388e-08 -3.5616573156069076e-08 -4.225318893327082e-08 -4.016124348582274e-08 -3.9258801806057365e-08 -3.8299654474799595e-08 -3.999540000073336e-08 -4.320255659419875e-08 -4.369145792858762e-08 -3.894149670401073e-08 -3.033275698642745e-08 -2.0578974019215637e-08 -1.2271267347163782e-08 -6.307558634338575e-09 -6.64450525914852e-09 -2.278391985913048e-08 -3.0051776374177405e-08 -2.798769065985384e-08 -2.4630633909399817e-08 -3.0233070094745875e-08 -2.7632828336456437e-08 -2.8230785322338677e-08 -2.835085337571607e-08 -3.3426666641115266e-08 -2.087984270053984e-08 -2.8541598038199948e-08 -3.440693477300137e-08 -3.1283932653634847e-08 -3.018622629568693e-08 -3.120051781846848e-08 -3.4445971272217156e-08 -4.5683387755939696e-08 -4.487381185325608e-08 -4.124489670405297e-08 -3.211988901157796e-08 -2.2828626923495507e-08 -1.3176421036348353e-08 -5.991075353328063e-09 -8.04373775524953e-09 -1.808104897992337e-08 -2.6606702590754737e-08 -2.541407590313475e-08 -2.498409913703581e-08 -2.782505227680533e-08 -3.0535089325520645e-08 -2.6593471272073173e-08 -3.135304780277269e-08 -3.465964474160883e-08 -1.9390456436776265e-08 -3.0634858399305834e-08 -3.6296301335045434e-08 -3.59014163271889e-08 -3.586172237114421e-08 -3.840361483586901e-08 -4.2375886813963813e-08 -4.836646907467021e-08 -4.7629706515787e-08 -4.3111498823396454e-08 -3.3079693799664635e-08 -2.212399756712466e-08 -1.2966363579515615e-08 -8.010289639079372e-09 -2.76885478027055e-08 -5.6497402041852264e-08 -5.975962064473781e-08 -5.229460926312527e-08 -4.4061606123256894e-08 -4.136775894895318e-08 -4.2394295605172947e-08 -4.3267644820259605e-08 -4.308503618603333e-08 -3.8746889482657085e-08 -2.6217323783840216e-08 -3.124432087969378e-08 -3.6494771115268856e-08 -3.7079743328780364e-08 -3.687330188450657e-08 -3.7454904631769975e-08 -4.18812327323221e-08 -4.6852921272444654e-08 -4.776440298360736e-08 -4.3437926138944047e-08 -3.471643257520485e-08 -2.360434379949089e-08 -1.41589902671356e-08 -8.802771664211643e-09 -2.860364552642714e-08 -5.850091954581364e-08 -5.97230496086304e-08 -4.8849946390220674e-08 -4.25012145219724e-08 -4.329969584066835e-08 -4.1758781397939946e-08 -3.925452833666953e-08 -4.018310392538358e-08 -3.6559366248708025e-08 -2.2717516719411836e-08 -2.985799097385988e-08 -3.226748806966544e-08 -3.348550902730159e-08 -3.2558330534348953e-08 -3.1646684458979014e-08 -3.5048119545383616e-08 -4.314609748901718e-08 -4.599872048749963e-08 -4.295313390973578e-08 -3.619209442766518e-08 -2.5490751805804922e-08 -1.550743422320428e-08 -9.691653296881005e-09 -2.4666465306574734e-08 -4.3852945762185566e-08 -4.699246648437814e-08 -4.17909146004523e-08 -4.581750894903477e-08 -5.0574455652418706e-08 -5.5644927081083095e-08 -5.1785326767040587e-08 -4.715239285800744e-08 -4.613464968687418e-08 -2.408330109934269e-08 -2.951085376820202e-08 -3.079741460025073e-08 -2.716389725324533e-08 -2.731774215120733e-08 -2.7460163736767242e-08 -3.1031880141856285e-08 -3.6725785008522695e-08 -3.911309293635297e-08 -3.740165062862928e-08 -3.2150049843603634e-08 -2.5010808320709775e-08 -1.7650661303306373e-08 -1.131228438011323e-08 -2.44456419941688e-08 -4.4772892230020325e-08 -4.2994389325749095e-08 -3.8559760832732145e-08 -4.4501526923892894e-08 -5.071917833687975e-08 -5.276986836831453e-08 -5.4089219859704496e-08 -5.145240706530764e-08 -4.5904868525174526e-08 -2.5467165542068223e-08 -2.598392660958162e-08 -2.942390510258033e-08 -3.0278763344354247e-08 -3.1644794270595935e-08 -3.2408266013153105e-08 -3.400703665682449e-08 -3.732185180602185e-08 -3.6746001806011294e-08 -3.3408340032009745e-08 -2.6945785950258595e-08 -1.7694546546635278e-08 -9.458831397347691e-09 -6.661516954596243e-09 -2.446298241803097e-08 -5.715740651596169e-08 -6.123347449091869e-08 -4.9403771586463166e-08 -4.4552890738650516e-08 -4.2353615463884915e-08 -3.62880009425806e-08 -3.7049253768340246e-08 -3.5656678022631817e-08 -3.5558388226711655e-08 -2.5701713265777388e-08 -3.5616573156069076e-08 -4.225318893327082e-08 -4.016124348582274e-08 -3.9258801806057365e-08 -3.8299654474799595e-08 -3.999540000073336e-08 -4.320255659419875e-08 -4.369145792858762e-08 -3.894149670401073e-08 -3.033275698642745e-08 -2.0578974019215637e-08 -1.2271267347163782e-08 -6.307558634338575e-09 -6.64450525914852e-09 -2.278391985913048e-08 -3.0051776374177405e-08 -2.798769065985384e-08 -2.4630633909399817e-08 -3.0233070094745875e-08 -2.7632828336456437e-08 -2.8230785322338677e-08 -2.835085337571607e-08 -3.3426666641115266e-08 -2.087984270053984e-08 -2.8541598038199948e-08 -3.440693477300137e-08 -3.1283932653634847e-08 -3.018622629568693e-08 -3.120051781846848e-08 -3.4445971272217156e-08 -4.5683387755939696e-08 -4.487381185325608e-08 -4.124489670405297e-08 -3.211988901157796e-08 -2.2828626923495507e-08 -1.3176421036348353e-08 -5.991075353328063e-09 -8.04373775524953e-09 -1.808104897992337e-08 -2.6606702590754737e-08 -2.541407590313475e-08 -2.498409913703581e-08 -2.782505227680533e-08 -3.0535089325520645e-08 -2.6593471272073173e-08 -3.135304780277269e-08 -3.465964474160883e-08 -1.9390456436776265e-08 -3.0634858399305834e-08 -3.6296301335045434e-08 -3.59014163271889e-08 -3.586172237114421e-08 -3.840361483586901e-08 -4.2375886813963813e-08 -4.836646907467021e-08 -4.7629706515787e-08 -4.3111498823396454e-08 -3.3079693799664635e-08 -2.212399756712466e-08 -1.2966363579515615e-08 -8.010289639079372e-09 -2.76885478027055e-08 -5.6497402041852264e-08 -5.975962064473781e-08 -5.229460926312527e-08 -4.4061606123256894e-08 -4.136775894895318e-08 -4.2394295605172947e-08 -4.3267644820259605e-08 -4.308503618603333e-08 -3.8746889482657085e-08 -2.6217323783840216e-08 -3.124432087969378e-08 -3.6494771115268856e-08 -3.7079743328780364e-08 -3.687330188450657e-08 -3.7454904631769975e-08 -4.18812327323221e-08 \ No newline at end of file diff --git a/examples/curve_examples/interconnector_8_price_curve.csv b/examples/curve_examples/interconnector_8_price_curve.csv deleted file mode 100644 index 0e71a91..0000000 --- a/examples/curve_examples/interconnector_8_price_curve.csv +++ /dev/null @@ -1,8760 +0,0 @@ -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.02 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.02 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -0.02 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.45 -26.01 -14.45 -0.01 -0.01 -0.0 -0.0 -0.01 -14.45 -0.01 -0.03 -0.12 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -0.02 -0.01 -0.01 -0.01 -0.0 -0.01 -0.02 -0.02 -0.02 -0.02 -14.45 -45.18 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.46 -14.46 -14.46 -26.01 -26.01 -26.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -26.02 -26.02 -45.18 -26.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -26.01 -45.18 -45.18 -45.18 -43.01 -43.01 -45.18 -45.18 -43.01 -26.01 -26.01 -26.01 -26.01 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -45.18 -45.18 -45.18 -57.37 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -60.17 -103.94 -118.57 -105.28 -105.28 -105.28 -105.28 -105.28 -103.94 -105.28 -83.48 -72.01 -72.01 -72.01 -72.01 -72.01 -72.01 -83.48 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -83.49 -105.28 -103.94 -105.28 -124.41 -137.56 -118.57 -103.95 -83.49 -86.31 -86.3 -83.48 -83.48 -86.3 -86.33 -105.28 -105.28 -118.57 -105.28 -103.96 -103.96 -103.96 -103.95 -104.48 -137.56 -150.0 -141.96 -150.0 -150.0 -150.0 -150.0 -124.41 -124.41 -105.28 -103.94 -105.28 -105.28 -103.96 -103.95 -105.28 -118.57 -150.0 -150.0 -137.56 -105.28 -103.99 -103.99 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -103.96 -83.5 -86.3 -86.3 -86.3 -105.28 -118.57 -124.41 -124.41 -118.59 -103.94 -83.48 -83.48 -83.48 -86.3 -103.96 -86.3 -105.28 -83.48 -105.28 -68.57 -45.18 -45.18 -45.18 -43.02 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -0.01 -0.01 -0.02 -14.45 -14.45 -14.48 -26.02 -26.01 -26.03 -26.02 -26.03 -26.01 -26.02 -14.46 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.46 -14.46 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.45 -14.45 -14.45 -14.45 -0.01 -14.45 -14.46 -14.46 -14.46 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.0 -0.04 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.46 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -45.18 -43.01 -45.18 -45.18 -45.18 -14.46 -14.46 -14.46 -45.18 -45.18 -45.18 -45.19 -105.28 -83.48 -105.28 -83.48 -83.48 -83.48 -103.94 -103.94 -60.17 -60.17 -45.19 -45.19 -45.19 -60.17 -103.96 -103.96 -103.94 -103.96 -105.28 -103.94 -60.17 -60.17 -60.17 -57.37 -60.17 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.03 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -26.01 -26.03 -14.46 -14.45 -14.45 -26.02 -26.01 -26.01 -26.01 -26.02 -26.01 -45.18 -26.01 -26.01 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -43.01 -43.01 -14.45 -14.45 -14.45 -45.18 -45.18 -43.01 -45.18 -14.5 -14.46 -45.18 -45.18 -45.18 -45.19 -118.57 -124.41 -105.28 -124.41 -137.56 -141.96 -119.92 -118.57 -103.98 -104.47 -105.28 -105.28 -105.28 -104.47 -150.0 -150.0 -150.0 -103.96 -103.99 -118.57 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -104.47 -104.47 -124.41 -118.58 -103.96 -103.95 -103.94 -103.96 -105.28 -118.57 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -103.94 -103.95 -86.3 -86.3 -103.94 -86.3 -103.95 -104.47 -105.28 -103.94 -86.3 -86.32 -86.32 -86.31 -104.47 -105.28 -105.28 -103.94 -118.57 -105.28 -83.49 -83.49 -83.48 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -34.33 -26.02 -26.02 -26.02 -26.02 -26.02 -26.01 -45.18 -45.18 -36.54 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -60.17 -105.28 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -104.47 -103.94 -60.17 -45.19 -45.19 -83.48 -83.48 -103.94 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.41 -105.28 -103.94 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -57.37 -72.02 -103.95 -118.57 -124.41 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -103.97 -105.28 -105.28 -86.3 -141.96 -86.3 -68.57 -83.48 -103.95 -137.56 -141.96 -150.0 -137.56 -105.28 -124.41 -83.48 -45.21 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -57.37 -45.19 -45.19 -45.21 -105.28 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -137.56 -105.28 -105.28 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -83.48 -83.48 -83.48 -83.48 -83.48 -86.3 -86.3 -83.48 -83.48 -83.48 -83.48 -83.48 -86.3 -86.3 -83.48 -103.97 -150.0 -150.0 -150.0 -150.0 -150.0 -137.56 -150.0 -118.58 -105.28 -105.28 -118.57 -118.58 -118.59 -150.0 -150.0 -150.0 -150.0 -105.28 -105.28 -104.47 -105.28 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -104.47 -105.28 -104.48 -137.56 -141.96 -137.56 -141.96 -104.47 -83.48 -45.19 -45.18 -45.18 -45.18 -14.45 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -14.46 -14.46 -14.46 -14.46 -14.45 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.02 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -26.01 -14.49 -26.01 -26.02 -45.18 -45.18 -26.01 -26.01 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -26.03 -26.01 -14.46 -14.46 -14.46 -14.46 -14.46 -14.47 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -45.18 -14.45 -0.02 -0.02 -0.02 -0.05 -0.02 -0.02 -14.45 -14.45 -14.45 -14.46 -14.46 -14.46 -14.45 -45.18 -14.46 -26.02 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.02 -14.45 -0.02 -0.02 -0.01 -0.01 -0.03 -26.01 -45.18 -45.19 -45.2 -60.17 -83.48 -105.28 -57.37 -60.17 -45.2 -45.19 -45.18 -45.18 -45.18 -45.18 -26.01 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -26.01 -26.01 -14.45 -14.45 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.05 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.46 -14.46 -14.46 -14.46 -45.18 -45.18 -45.18 -45.18 -57.37 -45.19 -45.19 -45.19 -45.19 -57.37 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.19 -60.17 -60.17 -72.01 -60.17 -68.57 -60.17 -68.57 -60.17 -57.37 -105.28 -105.28 -86.3 -68.57 -45.19 -60.17 -45.18 -45.18 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -43.02 -45.18 -43.04 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -60.17 -72.01 -103.95 -103.94 -119.92 -118.57 -105.28 -105.28 -105.28 -83.48 -75.03 -68.57 -83.48 -75.02 -73.62 -45.2 -45.18 -45.19 -60.17 -68.57 -45.2 -57.37 -45.2 -45.2 -57.37 -60.17 -83.48 -83.48 -86.3 -103.95 -103.94 -82.35 -83.5 -86.3 -83.48 -83.5 -82.35 -72.01 -82.35 -73.61 -60.17 -83.49 -86.31 -104.47 -103.95 -103.95 -103.95 -103.95 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -137.56 -137.56 -118.57 -104.47 -104.47 -86.3 -150.0 -141.96 -72.01 -45.2 -45.19 -45.18 -45.18 -45.18 -45.18 -45.19 -57.37 -57.37 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -43.02 -43.01 -43.01 -43.02 -43.06 -14.45 -45.18 -14.45 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.49 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.46 -45.18 -45.18 -45.18 -45.19 -45.19 -45.18 -45.18 -45.18 -26.02 -26.02 -26.02 -26.02 -26.02 -26.02 -14.46 -26.02 -26.02 -26.01 -26.01 -26.01 -26.02 -26.01 -26.03 -45.18 -45.18 -45.18 -45.2 -68.57 -73.61 -60.17 -57.37 -57.37 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.46 -14.46 -14.45 -45.18 -14.45 -14.45 -14.45 -14.45 -26.01 -43.04 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -0.02 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -0.03 -0.01 -0.01 -0.01 -0.01 -14.45 -45.18 -45.18 -45.18 -45.18 -45.19 -57.37 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.19 -57.37 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -68.57 -103.94 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.41 -105.28 -105.28 -104.47 -103.95 -89.33 -104.47 -104.47 -103.95 -103.94 -103.94 -86.32 -86.31 -86.3 -103.96 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -105.28 -118.57 -150.0 -150.0 -150.0 -150.0 -141.96 -118.57 -124.41 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -105.28 -104.47 -105.28 -104.47 -150.0 -118.57 -104.47 -104.47 -104.47 -86.3 -60.17 -86.3 -118.57 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -105.28 -103.94 -86.3 -86.3 -86.3 -86.3 -86.3 -73.61 -45.19 -57.37 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -57.37 -103.94 -103.94 -83.48 -83.48 -83.48 -68.57 -60.17 -45.19 -45.19 -57.37 -45.18 -45.18 -45.18 -45.18 -43.04 -14.47 -0.01 -0.01 -0.0 -0.0 -0.0 -0.01 -14.45 -14.46 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.04 -43.04 -43.04 -14.54 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -45.18 -45.18 -45.18 -105.28 -105.28 -105.28 -103.95 -103.94 -89.33 -103.94 -103.94 -103.95 -86.3 -60.17 -45.23 -45.2 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -60.17 -73.61 -83.48 -83.48 -83.48 -86.3 -86.3 -83.48 -73.61 -73.61 -60.17 -45.19 -45.19 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -26.01 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -14.47 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.04 -14.45 -14.45 -14.45 -14.45 -14.45 -45.18 -45.18 -45.18 -45.19 -60.17 -72.01 -72.01 -105.28 -72.01 -60.17 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.2 -103.94 -73.61 -73.61 -73.61 -73.61 -45.2 -45.2 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.46 -26.04 -14.45 -14.45 -14.45 -34.32 -14.5 -14.46 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.02 -26.02 -26.02 -26.01 -14.49 -43.01 -45.18 -45.18 -45.19 -60.17 -60.17 -57.37 -60.17 -57.37 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.19 -45.19 -45.18 -45.18 -45.18 -26.02 -26.02 -26.02 -43.01 -14.48 -43.04 -45.18 -45.19 -57.37 -45.19 -57.37 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -26.01 -26.01 -45.18 -45.18 -57.37 -57.37 -45.19 -57.37 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -26.01 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -45.19 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -26.01 -26.01 -45.18 -45.18 -60.17 -72.01 -60.17 -60.17 -72.01 -60.17 -68.57 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -68.57 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.21 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -14.45 -26.01 -45.18 -14.45 -14.45 -14.45 -0.04 -14.45 -14.45 -14.45 -14.45 -43.02 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -26.01 -26.01 -26.01 -26.01 -26.02 -26.01 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.2 -57.37 -57.37 -57.37 -60.17 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -103.94 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -137.56 -124.41 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -118.57 -105.28 -105.28 -104.47 -83.48 -60.17 -45.19 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.03 -26.01 -26.01 -26.01 -26.01 -45.18 -26.01 -26.02 -45.18 -45.18 -45.18 -26.01 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.02 -43.01 -43.01 -43.01 -43.02 -43.02 -43.02 -43.01 -43.01 -45.18 -45.18 -60.17 -105.28 -105.28 -105.28 -105.28 -105.28 -83.48 -83.48 -83.48 -83.48 -68.57 -60.17 -60.17 -68.57 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.2 -60.17 -60.17 -60.17 -72.01 -60.17 -60.17 -57.37 -45.19 -57.37 -45.19 -45.19 -45.19 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -60.17 -72.01 -73.61 -73.61 -73.61 -68.57 -60.17 -45.19 -45.21 -45.19 -45.19 -45.18 -45.18 -45.19 -57.37 -45.18 -45.18 -45.18 -45.18 -26.04 -26.02 -26.01 -26.01 -14.5 -14.53 -14.53 -14.52 -14.51 -14.51 -14.5 -14.45 -14.48 -45.18 -14.49 -14.45 -14.45 -14.45 -0.01 -0.01 -0.01 -0.03 -0.01 -0.01 -0.01 -0.01 -0.02 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.03 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -14.45 -45.18 -45.18 -45.18 -45.19 -60.17 -60.17 -60.17 -60.17 -60.17 -45.19 -57.37 -45.19 -45.19 -57.37 -45.19 -45.18 -45.19 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.19 -86.3 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -118.57 -104.48 -105.28 -104.48 -104.47 -104.47 -103.94 -86.31 -104.47 -103.94 -103.95 -86.3 -86.3 -103.94 -103.95 -86.3 -104.47 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -137.56 -124.41 -118.57 -105.28 -105.28 -150.0 -124.41 -60.17 -45.2 -57.37 -60.17 -60.17 -60.17 -60.17 -45.19 -105.28 -103.95 -119.92 -103.95 -105.28 -105.28 -105.28 -103.97 -103.96 -86.3 -86.3 -86.3 -86.3 -83.48 -83.48 -57.37 -45.18 -45.18 -26.02 -26.02 -26.02 -26.02 -26.02 -14.45 -14.46 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.03 -43.01 -43.02 -43.01 -43.01 -43.01 -43.02 -26.01 -26.01 -26.01 -26.01 -26.01 -26.01 -26.01 -26.01 -26.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -26.01 -26.01 -26.01 -26.01 -26.01 -14.47 -26.01 -26.01 -26.01 -26.04 -26.04 -26.04 -14.45 -14.45 -14.45 -14.45 -0.02 -0.02 -0.02 -0.01 -0.01 -0.01 -0.01 -14.45 -14.45 -26.02 -26.01 -14.49 -26.01 -45.18 -14.45 -14.45 -14.45 -14.45 -14.45 -14.46 -14.46 -45.18 -14.46 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.48 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.18 -57.37 -57.37 -57.37 -57.37 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.04 -45.18 -45.18 -26.03 -26.03 -26.01 -26.02 -14.47 -14.5 -14.48 -14.48 -45.18 -45.18 -45.18 -45.19 -60.17 -60.17 -60.17 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.18 -45.19 -45.18 -45.19 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -60.17 -73.61 -72.02 -73.61 -73.61 -45.19 -57.37 -45.18 -45.18 -45.18 -45.18 -26.01 -26.02 -14.45 -0.02 -0.0 -0.01 -0.01 -0.01 -0.01 -0.01 -0.02 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.0 -0.02 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.02 -14.45 -14.45 -14.45 -14.46 -14.45 -14.46 -14.45 -14.45 -14.45 -0.07 -0.01 -0.0 -0.02 -0.01 -0.01 -0.01 -0.01 -0.02 -0.02 -0.02 -14.45 -14.45 -26.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -0.03 -0.01 -0.01 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.02 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.02 -26.02 -14.46 -26.02 -45.18 -26.01 -14.46 -14.46 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.02 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -45.18 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.08 -14.45 -0.02 -0.03 -26.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -72.01 -83.48 -83.48 -83.48 -83.48 -83.48 -83.48 -83.48 -72.01 -60.17 -60.17 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -60.17 -86.3 -118.57 -118.57 -124.41 -124.41 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -83.48 -105.28 -105.28 -68.57 -57.37 -45.19 -60.17 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -57.37 -83.48 -83.48 -86.3 -83.48 -83.48 -83.48 -83.48 -83.48 -83.48 -86.3 -105.28 -105.28 -83.48 -83.48 -60.17 -57.37 -45.19 -60.17 -72.01 -72.01 -73.61 -72.01 -86.3 -103.97 -118.57 -118.57 -105.28 -105.28 -105.28 -105.28 -60.17 -60.17 -60.17 -60.17 -57.37 -60.17 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -73.61 -103.95 -119.92 -105.28 -103.94 -103.94 -103.94 -103.94 -86.3 -86.3 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -14.46 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -14.45 -14.45 -26.01 -26.01 -45.18 -45.18 -45.18 -45.19 -45.19 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.02 -14.45 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -14.45 -43.01 -45.18 -45.18 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.46 -14.46 -14.46 -14.45 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -60.17 -60.17 -118.57 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -103.94 -72.01 -83.48 -68.57 -73.61 -72.01 -73.61 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.49 -26.01 -26.01 -14.49 -14.45 -14.45 -0.05 -14.45 -14.45 -26.01 -26.04 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -73.61 -83.48 -105.28 -103.95 -105.28 -103.94 -83.48 -86.3 -103.95 -60.17 -60.17 -60.17 -57.37 -57.37 -57.37 -45.19 -45.18 -45.19 -45.19 -45.2 -45.19 -45.18 -45.2 -45.19 -45.19 -45.19 -45.19 -45.19 -60.17 -45.2 -45.19 -60.17 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -14.47 -14.45 -0.02 -0.02 -0.02 -0.01 -0.01 -0.02 -0.02 -14.45 -26.01 -45.18 -45.18 -45.18 -57.37 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -45.2 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.42 -150.0 -150.0 -150.0 -45.19 -45.19 -45.19 -45.18 -45.19 -45.19 -45.18 -45.19 -45.19 -60.17 -83.48 -60.17 -45.21 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -45.18 -14.46 -14.46 -0.02 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -34.35 -26.05 -26.05 -26.05 -26.05 -26.05 -43.01 -45.18 -45.18 -45.19 -57.37 -60.17 -60.17 -60.17 -68.57 -105.28 -86.3 -60.17 -60.17 -60.17 -45.2 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -83.48 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -137.56 -118.57 -103.94 -83.48 -83.48 -86.32 -86.3 -86.3 -118.57 -118.57 -105.28 -105.28 -103.95 -86.3 -83.48 -118.57 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -137.56 -124.41 -104.47 -86.31 -86.31 -118.57 -83.48 -83.48 -83.48 -83.48 -73.61 -73.61 -83.48 -86.3 -86.3 -89.33 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -103.94 -86.3 -103.94 -68.57 -105.28 -60.17 -60.17 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -60.17 -105.28 -60.17 -73.61 -60.17 -60.17 -60.17 -124.41 -124.41 -124.41 -124.41 -105.28 -103.95 -86.3 -83.48 -86.3 -86.3 -105.28 -124.41 -141.96 -124.41 -124.41 -118.57 -124.41 -124.41 -119.92 -118.57 -73.61 -73.61 -73.61 -73.61 -83.48 -103.94 -103.94 -68.57 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.01 -43.01 -14.46 -14.46 -14.46 -14.46 -14.46 -0.01 -0.05 -14.45 -26.03 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -83.48 -141.96 -137.56 -150.0 -150.0 -141.96 -141.96 -83.48 -72.01 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.53 -14.49 -14.49 -14.54 -26.02 -14.45 -0.02 -0.0 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.02 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.02 -45.18 -45.18 -45.18 -45.19 -57.37 -60.17 -60.17 -83.48 -60.17 -83.48 -86.3 -103.94 -103.94 -60.17 -105.28 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -103.96 -103.94 -86.3 -86.3 -60.17 -45.21 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -45.22 -45.21 -68.57 -86.3 -83.48 -86.3 -86.3 -83.48 -105.28 -105.28 -105.28 -60.17 -60.17 -60.17 -45.19 -45.18 -45.18 -45.18 -57.37 -57.37 -57.37 -57.37 -57.37 -57.37 -45.19 -45.19 -45.2 -60.17 -103.94 -118.57 -150.0 -150.0 -150.0 -150.0 -137.56 -124.42 -103.94 -89.33 -103.94 -103.96 -86.3 -86.3 -86.3 -86.3 -83.48 -83.48 -103.94 -103.95 -118.57 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -105.28 -68.57 -60.17 -45.19 -45.19 -45.18 -45.18 -45.18 -43.01 -26.03 -26.03 -26.04 -14.49 -43.01 -45.18 -45.18 -45.18 -45.18 -14.46 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -0.0 -14.45 -0.06 -0.06 -0.03 -14.45 -14.45 -14.45 -0.04 -0.04 -0.04 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -83.48 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.41 -105.28 -89.33 -104.47 -104.47 -73.61 -60.17 -73.61 -73.61 -73.61 -73.61 -73.61 -73.61 -73.61 -104.47 -118.57 -118.57 -105.28 -83.48 -83.48 -83.48 -83.48 -83.48 -83.48 -68.57 -83.48 -72.01 -60.17 -60.17 -68.57 -72.01 -72.01 -73.61 -73.61 -68.57 -57.37 -86.3 -119.92 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -124.41 -105.28 -86.3 -105.28 -68.57 -45.19 -45.18 -45.19 -45.19 -45.19 -45.19 -45.2 -45.18 -45.19 -45.21 -45.21 -45.19 -45.19 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.02 -26.01 -26.01 -45.18 -0.02 -14.45 -14.45 -0.01 -14.45 -26.02 -14.5 -14.45 -14.45 -0.01 -0.0 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.46 -14.46 -14.46 -14.46 -14.46 -14.46 -14.46 -14.45 -14.45 -26.03 -14.45 -14.45 -0.04 -0.04 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.02 -26.02 -26.02 -26.03 -26.02 -45.18 -45.18 -26.02 -26.01 -45.18 -45.18 -45.18 -45.18 -60.17 -60.17 -68.57 -83.48 -103.94 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -105.28 -83.48 -60.17 -60.17 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -57.37 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -83.48 -83.48 -83.48 -83.48 -105.28 -60.17 -60.17 -60.17 -57.37 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.48 -14.45 -0.03 -0.02 -0.05 -0.02 -0.01 -0.01 -0.0 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.02 -43.01 -43.01 -43.03 -43.01 -43.04 -26.03 -26.01 -14.5 -26.01 -26.02 -26.04 -26.02 -45.18 -45.18 -45.21 -45.18 -45.19 -57.37 -57.37 -45.19 -57.37 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -57.37 -57.37 -57.37 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.22 -60.17 -103.94 -103.95 -86.3 -86.3 -86.3 -86.3 -68.57 -72.01 -60.17 -60.17 -60.17 -68.57 -60.17 -60.17 -60.17 -57.37 -57.37 -57.37 -57.37 -60.17 -60.17 -73.61 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -86.31 -86.3 -68.57 -45.19 -45.19 -60.17 -60.17 -45.18 -45.18 -26.01 -45.18 -26.01 -26.01 -14.55 -26.03 -26.03 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.46 -45.18 -45.18 -45.18 -45.18 -43.01 -43.01 -14.56 -43.02 -43.01 -43.01 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.21 -45.2 -45.19 -45.19 -45.18 -45.18 -45.18 -45.19 -45.19 -60.17 -60.17 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -57.37 -45.19 -45.19 -45.18 -45.18 -45.2 -45.18 -45.18 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.19 -60.17 -68.57 -68.57 -68.57 -68.57 -83.48 -103.95 -124.41 -124.41 -124.41 -124.41 -124.41 -118.57 -118.57 -86.3 -60.17 -45.21 -45.19 -45.19 -45.19 -45.18 -45.18 -45.19 -45.19 -45.2 -45.19 -45.19 -45.19 -45.19 -45.18 -45.19 -45.19 -45.19 -57.37 -45.19 -45.2 -45.2 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.18 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.04 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -14.48 -14.46 -14.45 -0.01 -0.01 -0.02 -0.03 -14.45 -14.45 -0.02 -14.45 -14.47 -14.45 -14.45 -26.01 -26.02 -26.01 -26.02 -26.02 -14.5 -26.01 -45.18 -45.18 -14.49 -45.18 -26.02 -26.02 -14.49 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -26.01 -45.18 -45.18 -45.18 -26.07 -26.06 -26.02 -26.01 -26.02 -26.02 -14.45 -14.45 -0.0 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -14.45 -26.01 -26.01 -26.01 -26.01 -26.01 -26.01 -26.01 -26.04 -14.46 -14.46 -14.46 -14.46 -14.47 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.2 -83.48 -150.0 -137.56 -141.97 -137.56 -150.0 -150.0 -141.96 -118.58 -105.28 -89.34 -86.3 -68.57 -105.28 -105.28 -83.48 -60.17 -60.17 -60.17 -60.17 -68.57 -86.3 -103.95 -105.28 -118.57 -137.56 -137.56 -137.56 -124.41 -124.41 -124.41 -124.41 -103.94 -68.57 -73.61 -72.01 -86.3 -103.94 -103.95 -57.37 -45.18 -45.18 -45.18 -57.37 -45.19 -45.19 -45.18 -60.17 -73.61 -73.61 -73.61 -73.61 -73.61 -60.17 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -43.05 -45.18 -43.03 -14.45 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.46 -43.01 -43.01 -43.01 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.04 -26.01 -45.18 -45.18 -45.19 -45.19 -57.37 -45.2 -45.19 -45.19 -45.19 -45.19 -45.2 -57.37 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -103.95 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -124.41 -150.0 -150.0 -68.57 -68.57 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -83.48 -60.17 -45.25 -45.22 -45.21 -60.17 -57.37 -57.37 -45.22 -45.19 -45.19 -45.19 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -105.28 -105.28 -105.28 -105.28 -103.94 -103.94 -60.17 -45.19 -45.19 -57.37 -60.17 -57.37 -60.17 -45.2 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -60.17 -60.17 -60.17 -45.19 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -57.37 -60.17 -45.19 -45.19 -105.28 -60.17 -105.28 -60.17 -45.19 -57.37 -57.37 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -60.17 -60.17 -57.37 -57.37 -57.37 -45.19 -45.19 -45.2 -45.2 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.21 -45.23 -45.2 -60.17 -57.37 -45.19 -45.19 -45.19 -57.37 -60.17 -45.19 -57.37 -45.18 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -14.45 -14.46 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.56 -26.04 -26.04 -26.04 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.02 -26.02 -43.01 -43.04 -45.18 -45.18 -83.48 -118.57 -124.41 -124.41 -137.56 -124.41 -119.92 -150.0 -124.41 -118.57 -104.47 -104.47 -105.28 -103.96 -105.28 -141.96 -141.96 -124.41 -103.94 -86.32 -104.47 -104.47 -83.48 -104.0 -141.96 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.41 -103.96 -89.33 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -60.17 -60.17 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -103.95 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -137.56 -141.96 -124.42 -118.58 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -137.56 -118.57 -83.48 -86.3 -86.3 -86.3 -86.3 -103.96 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -104.47 -104.47 -104.47 -86.32 -118.57 -124.42 -105.28 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -57.37 -45.19 -60.17 -60.17 -45.19 -45.19 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.02 -26.01 -26.01 -26.01 -14.45 -14.52 -26.01 -14.47 -26.01 -43.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.02 -43.02 -43.01 -43.02 -43.01 -26.02 -14.5 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -57.37 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.2 -57.37 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.46 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.46 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -45.18 -45.18 -45.18 -45.18 -45.18 -43.02 -43.04 -14.46 -14.46 -14.46 -14.45 -14.46 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -73.61 -103.95 -105.28 -105.28 -105.28 -103.95 -103.95 -105.28 -86.31 -86.3 -73.61 -73.61 -60.17 -72.02 -60.17 -60.17 -60.17 -57.37 -60.17 -60.17 -60.17 -83.48 -83.48 -105.28 -105.28 -105.28 -105.28 -105.28 -105.28 -103.95 -105.28 -60.17 -45.2 -45.2 -45.19 -45.19 -45.19 -45.19 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -45.2 -45.19 -45.19 -57.37 -83.48 -104.47 -124.41 -124.41 -124.41 -119.92 -124.41 -118.57 -103.95 -103.94 -103.94 -86.3 -103.94 -86.3 -68.57 -45.23 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -60.17 -45.18 -57.37 -60.17 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -43.02 -45.18 -45.18 -45.18 -43.01 -26.01 -0.03 -0.05 -0.04 -0.04 -0.02 -0.02 -0.03 -0.02 -45.18 -34.32 -45.18 -45.18 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.19 -57.37 -45.21 -60.17 -60.17 -60.17 -45.18 -45.18 -45.18 -60.17 -83.48 -118.57 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -105.28 -103.95 -103.94 -83.48 -60.17 -83.48 -83.48 -60.17 -60.17 -45.2 -57.37 -57.37 -60.17 -60.17 -60.17 -105.28 -83.48 -105.28 -105.28 -105.28 -103.95 -86.3 -83.48 -86.3 -83.48 -103.94 -57.37 -57.37 -45.18 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -26.01 -26.01 -43.01 -43.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.04 -45.18 -26.01 -0.04 -14.45 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -43.01 -14.45 -14.45 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.49 -14.49 -14.49 -45.18 -14.46 -14.46 -14.46 -14.46 -14.45 -14.46 -14.46 -14.46 -26.02 -45.18 -14.46 -14.46 -0.01 -0.02 -0.03 -14.45 -0.04 -26.02 -14.49 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.46 -14.45 -14.5 -14.49 -26.01 -14.49 -14.51 -26.04 -14.45 -14.45 -45.18 -43.04 -43.02 -45.18 -43.01 -14.46 -14.46 -14.46 -14.46 -14.46 -14.46 -14.46 -14.46 -14.46 -14.46 -43.02 -14.51 -26.01 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.01 -43.01 -45.18 -45.18 -45.18 -14.49 -26.01 -26.02 -26.01 -26.02 -14.5 -14.51 -26.01 -45.18 -45.18 -45.2 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -57.37 -45.18 -45.18 -45.18 -26.01 -14.45 -14.45 -14.45 -14.46 -14.46 -45.18 -43.04 -14.45 -14.47 -14.45 -0.0 -0.0 -0.0 -14.45 -45.18 -43.01 -43.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -105.28 -105.28 -103.95 -103.95 -103.99 -103.95 -103.99 -103.97 -86.3 -89.35 -105.28 -86.3 -83.48 -83.48 -86.3 -83.48 -83.48 -73.61 -60.17 -45.22 -45.2 -45.19 -45.19 -45.19 -45.19 -45.19 -68.57 -60.17 -60.17 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.2 -45.2 -57.37 -57.37 -45.23 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -83.48 -83.48 -83.48 -83.48 -86.3 -86.3 -83.48 -83.48 -60.17 -60.17 -60.17 -57.37 -60.17 -45.18 -45.18 -43.01 -45.18 -14.47 -14.45 -0.01 -14.45 -14.46 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.02 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -73.61 -83.48 -68.57 -73.61 -68.57 -73.61 -73.61 -60.17 -57.37 -57.37 -45.18 -45.19 -72.01 -83.48 -83.48 -73.61 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -57.37 -105.28 -105.28 -105.28 -103.98 -89.38 -60.17 -60.17 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -14.45 -0.02 -0.0 -0.0 -0.0 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -0.0 -14.45 -0.0 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -26.02 -26.01 -26.01 -26.01 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.01 -43.01 -43.01 -43.01 -43.01 -43.04 -45.18 -43.03 -26.01 -26.01 -26.01 -26.02 -26.01 -26.02 -26.02 -43.02 -45.18 -45.18 -45.18 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -34.32 -26.02 -14.45 -14.45 -14.45 -14.46 -14.46 -45.18 -45.18 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -26.01 -45.18 -43.01 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -14.45 -14.45 -14.45 -14.45 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.02 -43.01 -43.01 -43.01 -14.45 -14.45 -14.45 -14.47 -14.46 -0.01 -0.01 -0.01 -0.01 -0.02 -0.01 -14.45 -43.03 -43.01 -43.01 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.02 -43.01 -26.01 -26.01 -45.18 -26.02 -14.46 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -45.18 -45.18 -43.01 -45.18 -43.02 -43.01 -43.01 -43.01 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.05 -0.04 -0.02 -0.0 -0.01 -0.04 -0.02 -14.45 -14.45 -26.02 -45.18 -45.18 -26.02 -26.02 -26.03 -26.03 -26.01 -26.01 -26.01 -43.01 -43.01 -45.18 -45.18 -26.02 -26.01 -26.01 -14.45 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -57.37 -57.37 -57.37 -57.37 -57.37 -57.37 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -60.17 -60.17 -72.01 -60.17 -60.17 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.01 -14.45 -14.45 -14.45 -14.46 -14.46 -43.02 -43.01 -14.46 -14.46 -14.46 -14.46 -14.45 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.05 -0.02 -0.01 -0.01 -0.05 -0.01 -0.01 -0.01 -0.02 -14.45 -14.45 -0.04 -0.02 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -14.45 -14.45 -14.46 -14.46 -14.46 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.46 -14.46 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -26.01 -26.01 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -26.01 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -26.03 -14.45 -0.02 -0.0 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -26.02 -26.01 -26.02 -26.02 -26.02 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -26.02 -45.18 -43.01 -43.01 -26.01 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -0.02 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.01 -0.01 -14.45 -14.45 -14.45 -14.45 -14.46 -14.46 -14.46 -14.45 -0.01 -0.01 -0.0 -0.01 -0.0 -0.0 -0.0 -0.02 -0.01 -0.01 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -14.45 -26.01 -26.04 -45.18 -45.18 -45.18 -26.02 -26.01 -26.02 -43.01 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.03 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.02 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -26.01 -26.01 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -43.01 -45.18 -45.18 -45.18 -83.49 -103.95 -103.96 -103.94 -86.3 -103.95 -86.3 -83.48 -73.61 -73.62 -73.61 -72.01 -72.01 -60.17 -68.57 -73.62 -68.57 -60.17 -45.18 -45.18 -45.18 -45.18 -57.37 -45.19 -72.01 -83.48 -103.94 -86.3 -86.3 -86.3 -83.49 -72.01 -72.01 -68.57 -72.01 -72.01 -68.57 -72.01 -72.01 -86.3 -103.95 -103.95 -68.57 -73.61 -83.48 -73.61 -73.61 -86.3 -137.56 -137.56 -141.96 -150.0 -150.0 -141.96 -150.0 -124.41 -86.3 -86.3 -103.94 -83.49 -83.49 -83.49 -83.48 -86.3 -89.33 -103.95 -86.3 -83.48 -73.61 -73.61 -105.28 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -124.41 -104.47 -104.47 -137.56 -141.96 -150.0 -150.0 -119.92 -86.3 -83.48 -83.48 -86.3 -86.3 -105.28 -137.56 -141.96 -141.96 -104.47 -105.28 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.46 -14.46 -14.45 -14.45 -14.46 -14.45 -14.45 -14.46 -14.46 -26.02 -14.45 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.46 -26.02 -26.02 -26.01 -26.02 -26.02 -26.05 -45.18 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.2 -60.17 -103.95 -103.96 -104.47 -103.95 -103.96 -103.94 -103.95 -60.17 -60.17 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -57.37 -45.18 -45.18 -45.18 -45.18 -14.49 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.53 -26.02 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.46 -14.45 -0.04 -0.04 -0.04 -14.45 -14.45 -14.45 -45.18 -14.46 -26.01 -26.01 -26.01 -26.01 -45.18 -45.18 -26.01 -26.01 -26.01 -14.45 -14.45 -14.45 -0.01 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.45 -14.45 -14.45 -14.45 -14.47 -14.47 -14.47 -14.45 -14.45 -0.01 -0.01 -0.01 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.47 -43.01 -45.18 -45.18 -45.19 -45.19 -60.17 -60.17 -60.17 -73.61 -73.61 -45.19 -45.19 -45.19 -60.17 -60.17 -119.92 -150.0 -150.0 -150.0 -103.96 -118.57 -118.57 -118.57 -118.57 -118.57 -150.0 -150.0 -150.0 -103.95 -83.48 -83.48 -60.17 -86.3 -68.57 -57.37 -57.37 -45.21 -45.21 -45.22 -103.95 -137.56 -137.56 -105.28 -68.57 -73.61 -83.48 -68.57 -83.48 -83.49 -118.57 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.41 -118.57 -103.97 -103.98 -86.3 -72.01 -60.17 -60.17 -60.17 -86.3 -68.57 -105.28 -105.28 -68.57 -68.57 -86.3 -86.3 -60.17 -60.17 -60.17 -86.3 -86.3 -86.3 -86.3 -103.94 -60.17 -60.17 -60.17 -60.17 -72.01 -60.17 -72.01 -103.95 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.41 -103.98 -105.28 -103.97 -105.28 -105.28 -124.41 -124.41 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -118.57 -103.96 -118.57 -118.58 -105.28 -60.17 -60.17 -60.17 -103.94 -105.28 -105.28 -105.28 -105.28 -119.92 -118.57 -103.94 -103.94 -86.3 -60.17 -83.48 -60.17 -60.17 -45.19 -45.19 -45.18 -45.19 -45.19 -45.19 -45.19 -57.37 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.03 -43.02 -36.54 -14.46 -14.45 -14.46 -14.45 -14.46 -14.46 -45.18 -45.18 -43.01 -14.46 -14.46 -45.18 -14.45 -14.45 -14.46 -14.45 -14.45 -14.45 -14.46 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.04 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.01 -43.01 -45.18 -45.18 -45.18 -43.01 -43.04 -45.18 -45.18 -45.18 -45.19 -45.18 -45.19 -45.19 -57.37 -60.17 -73.61 -73.61 -103.94 -103.94 -105.28 -103.94 -105.28 -105.28 -103.94 -73.61 -68.57 -73.61 -68.57 -68.57 -60.17 -73.61 -68.57 -60.17 -57.37 -45.19 -45.19 -45.19 -45.21 -45.2 -45.2 -60.17 -57.37 -45.19 -57.37 -45.18 -45.18 -45.18 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.03 -14.45 -14.45 -14.45 -14.45 -45.18 -26.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -43.01 -45.18 -45.18 -26.02 -26.01 -26.01 -14.45 -14.45 -0.01 -14.45 -0.01 -0.01 -0.01 -0.01 -0.0 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -26.01 -26.01 -26.02 -43.01 -45.18 -45.18 -26.04 -26.04 -26.01 -26.02 -45.18 -45.18 -26.04 -26.04 -43.01 -45.18 -45.18 -14.51 -43.01 -14.53 -14.52 -14.45 -14.45 -14.46 -43.02 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -57.37 -45.19 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -57.37 -57.37 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -14.46 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -26.01 -26.01 -26.01 -26.02 -26.01 -14.46 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.05 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.06 -45.18 -26.03 -26.01 -26.01 -26.01 -45.18 -43.02 -34.32 -26.01 -14.45 -14.45 -0.02 -0.01 -0.01 -0.02 -0.02 -0.02 -14.45 -14.45 -14.47 -45.18 -14.47 -26.01 -26.02 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -43.04 -43.01 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.45 -45.18 -45.18 -45.18 -43.02 -43.02 -45.18 -26.02 -26.02 -26.02 -26.01 -45.18 -26.01 -26.01 -26.01 -45.18 -45.18 -45.18 -45.18 -26.01 -43.01 -45.18 -45.18 -45.19 -73.61 -68.57 -60.17 -60.17 -60.17 -60.17 -68.57 -45.21 -45.21 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.2 -45.19 -45.19 -45.19 -45.19 -60.17 -83.48 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -68.57 -60.17 -45.19 -45.18 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -14.45 -0.0 -14.45 -14.45 -0.0 -0.0 -0.01 -14.45 -0.02 -0.02 -14.45 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -60.17 -86.3 -83.48 -73.61 -68.57 -73.61 -86.3 -118.57 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -137.6 -119.92 -119.92 -118.58 -120.93 -150.0 -105.28 -118.57 -141.96 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -118.58 -118.59 -103.94 -73.61 -60.17 -60.17 -60.17 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -60.17 -60.17 -83.48 -83.48 -105.28 -105.28 -68.57 -60.17 -68.57 -57.37 -57.37 -45.19 -45.19 -45.19 -45.18 -45.19 -86.3 -86.3 -60.17 -45.19 -45.19 -45.19 -45.19 -45.19 -83.5 -83.53 -83.48 -86.3 -86.3 -68.57 -57.37 -45.18 -45.18 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.05 -0.0 -0.0 -0.0 -0.0 -0.02 -0.02 -0.02 -14.45 -14.45 -0.05 -0.02 -14.45 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.45 -0.0 -0.0 -0.02 -14.45 -0.0 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.02 -43.02 -26.03 -26.03 -26.01 -43.02 -43.01 -26.01 -26.01 -14.46 -14.46 -14.46 -26.02 -14.45 -14.49 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.46 -14.46 -14.46 -14.46 -14.45 -14.45 -0.01 -0.01 -0.01 -0.02 -0.0 -0.0 -14.45 -26.02 -26.01 -14.45 -14.46 -14.46 -14.46 -45.18 -45.18 -45.19 -83.48 -86.3 -83.48 -83.48 -86.3 -83.48 -86.3 -105.28 -86.3 -86.3 -86.3 -86.3 -60.17 -45.19 -60.17 -105.28 -60.17 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -43.02 -14.46 -26.02 -26.04 -26.03 -26.02 -14.46 -14.46 -14.46 -14.46 -14.46 -14.47 -14.47 -26.01 -26.01 -45.18 -14.48 -26.01 -26.04 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -26.01 -26.01 -26.01 -14.46 -14.46 -14.46 -14.46 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -72.01 -105.28 -105.28 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -57.37 -60.17 -60.17 -83.48 -124.41 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -124.41 -105.28 -105.28 -118.57 -141.96 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -118.57 -103.97 -104.5 -103.94 -60.17 -45.19 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.2 -45.19 -45.18 -45.19 -105.28 -103.95 -105.28 -118.57 -118.57 -103.96 -137.56 -118.57 -104.47 -104.5 -103.94 -60.17 -45.18 -45.18 -45.18 -14.46 -14.46 -14.46 -14.46 -14.46 -45.18 -45.18 -43.01 -43.02 -14.48 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.01 -43.01 -43.01 -43.02 -43.02 -14.46 -14.46 -14.46 -45.18 -14.46 -14.46 -43.01 -43.02 -43.01 -43.04 -43.01 -43.04 -45.18 -45.18 -45.2 -57.37 -45.19 -57.37 -57.37 -57.37 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -45.19 -45.2 -45.21 -45.19 -45.19 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.01 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -14.45 -14.46 -14.46 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -60.17 -60.17 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.46 -26.01 -43.02 -43.01 -43.01 -45.18 -45.18 -45.18 -26.04 -45.18 -26.02 -26.02 -26.01 -26.01 -26.02 -26.02 -26.04 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -57.37 -83.48 -60.17 -60.17 -83.48 -83.48 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -60.17 -45.19 -45.19 -45.19 -103.95 -150.0 -141.96 -137.56 -137.56 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -105.28 -103.94 -83.48 -83.48 -83.48 -83.48 -86.3 -89.34 -105.28 -141.96 -141.96 -105.28 -104.0 -104.0 -105.28 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -103.96 -105.28 -103.96 -105.28 -104.47 -118.57 -150.0 -150.0 -150.0 -137.56 -86.3 -86.3 -86.3 -141.96 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -104.47 -86.31 -68.57 -45.18 -45.18 -43.02 -26.01 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -26.01 -14.45 -0.01 -14.45 -14.45 -0.01 -0.01 -0.02 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.01 -0.01 -0.01 -0.0 -0.0 -0.01 -0.02 -0.01 -0.01 -43.02 -14.46 -14.45 -26.02 -26.03 -26.03 -26.02 -26.01 -26.01 -26.02 -26.02 -26.01 -43.01 -14.46 -14.46 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -60.17 -57.37 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.19 -86.3 -103.95 -103.96 -119.92 -105.28 -103.94 -103.96 -105.28 -105.28 -86.3 -83.49 -86.31 -86.31 -103.94 -103.96 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -150.0 -141.96 -103.96 -83.48 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -43.01 -43.02 -14.46 -14.46 -14.46 -43.01 -43.01 -43.01 -43.01 -45.18 -26.03 -34.32 -43.02 -43.01 -43.04 -45.18 -14.46 -45.18 -45.18 -45.18 -26.02 -26.01 -26.01 -26.02 -45.18 -26.01 -26.01 -26.02 -45.18 -45.18 -45.19 -45.19 -45.19 -45.18 -45.18 -45.18 -45.18 -45.19 -45.18 -45.2 -45.19 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -45.18 -14.45 -14.45 -14.45 -14.45 -14.45 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -14.45 -14.46 -14.46 -14.46 -14.45 -14.45 -14.47 -14.46 -14.45 -14.46 -14.46 -26.01 -26.01 -26.01 -26.01 -26.02 -26.02 -26.02 -26.02 -26.01 -26.02 -26.04 -26.04 -26.04 -26.02 -26.02 -26.02 -26.01 -14.49 -14.48 -14.45 -14.45 -0.02 -0.02 -0.01 -0.01 -14.45 -26.02 -14.45 -14.45 -0.01 -14.45 -0.01 -0.01 -0.01 -14.45 -0.01 -0.01 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.02 -0.02 -0.02 -0.01 -0.01 -0.01 -0.02 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -14.45 -0.02 -14.45 -14.45 -14.45 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.01 -0.02 -14.45 -14.45 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -45.18 -60.17 -45.18 -45.18 -45.18 -45.18 -43.01 -14.46 -14.46 -14.45 -14.45 -14.45 -14.45 -14.45 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.01 -0.0 -14.45 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.02 -0.01 -0.02 -0.01 -0.01 -0.01 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.02 -0.01 -0.02 -0.01 -0.01 -0.01 -0.0 -0.0 \ No newline at end of file diff --git a/examples/custom_curve_from_df.ipynb b/examples/custom_curve_from_df.ipynb deleted file mode 100644 index 2136054..0000000 --- a/examples/custom_curve_from_df.ipynb +++ /dev/null @@ -1,173 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "42081dd2", - "metadata": {}, - "source": [ - "This is still a testing workbook to demonstrate progress on the excel to scenario flows." - ] - }, - { - "cell_type": "markdown", - "id": "386ce0b0", - "metadata": {}, - "source": [ - "# Curves" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c617dc0a", - "metadata": {}, - "outputs": [], - "source": [ - "# For now a custom csv to pd df function - this will be handled by the reverse packer in the end\n", - "\n", - "import pandas as pd\n", - "from pathlib import Path\n", - "from typing import Union\n", - "\n", - "def read_curves_to_dataframe(\n", - " curves_path: Union[str, Path],\n", - " pattern: str = \"*.csv\",\n", - " validate_length: bool = True\n", - ") -> pd.DataFrame:\n", - " \"\"\"\n", - " Read multiple curve CSV files into a single DataFrame.\n", - "\n", - " Args:\n", - " curves_path: Directory path containing the curve CSV files\n", - " pattern: File pattern to match (default: \"*.csv\")\n", - " validate_length: Whether to validate each curve has exactly 8760 values\n", - "\n", - " Returns:\n", - " DataFrame with curves as columns, where column names are the curve keys\n", - " (derived from filenames without extension)\n", - "\n", - " Raises:\n", - " ValueError: If validation fails or files have issues\n", - " FileNotFoundError: If no files found matching the pattern\n", - " \"\"\"\n", - " curves_path = Path(curves_path)\n", - "\n", - " if not curves_path.exists():\n", - " raise FileNotFoundError(f\"Directory not found: {curves_path}\")\n", - "\n", - " # Find all CSV files matching the pattern\n", - " csv_files = list(curves_path.glob(pattern))\n", - "\n", - " if not csv_files:\n", - " raise FileNotFoundError(f\"No files found matching pattern '{pattern}' in {curves_path}\")\n", - "\n", - " print(f\"Found {len(csv_files)} curve files\")\n", - "\n", - " curves_data = {}\n", - " errors = []\n", - "\n", - " for csv_file in csv_files:\n", - " # Use filename (without extension) as curve key, remove _curve suffix if present\n", - " curve_key = csv_file.stem\n", - " if curve_key.endswith('_curve'):\n", - " curve_key = curve_key[:-6] # Remove '_curve' suffix\n", - "\n", - " try:\n", - " # Read CSV file - assuming single column of values, no headers\n", - " curve_data = pd.read_csv(\n", - " csv_file,\n", - " header=None, # No header row\n", - " index_col=False, # No index column\n", - " dtype=float # All values should be numeric\n", - " )\n", - "\n", - " # Convert DataFrame to Series if single column\n", - " if isinstance(curve_data, pd.DataFrame):\n", - " if len(curve_data.columns) == 1:\n", - " curve_data = curve_data.iloc[:, 0]\n", - " else:\n", - " errors.append(f\"{curve_key}: Expected 1 column, found {len(curve_data.columns)}\")\n", - " continue\n", - "\n", - " # Drop any NaN values\n", - " curve_data = curve_data.dropna()\n", - "\n", - " # Validate length if requested\n", - " if validate_length and len(curve_data) != 8760:\n", - " errors.append(f\"{curve_key}: Expected 8760 values, found {len(curve_data)}\")\n", - " continue\n", - "\n", - " # Store with curve key as column name\n", - " curves_data[curve_key] = curve_data.values\n", - " print(f\"✓ Loaded curve '{curve_key}': {len(curve_data)} values\")\n", - "\n", - " except Exception as e:\n", - " errors.append(f\"{curve_key}: Error reading file - {str(e)}\")\n", - " continue\n", - "\n", - " if errors:\n", - " error_msg = \"Errors reading curve files:\\n\" + \"\\n\".join(f\" - {err}\" for err in errors)\n", - " if not curves_data: # No curves loaded successfully\n", - " raise ValueError(error_msg)\n", - " else:\n", - " print(f\"Warning: Some curves failed to load:\\n{error_msg}\")\n", - "\n", - " if not curves_data:\n", - " raise ValueError(\"No curves were successfully loaded\")\n", - "\n", - " # Create DataFrame from the curves\n", - " df = pd.DataFrame(curves_data)\n", - "\n", - " # Set index to represent hours (0-8759 for a full year)\n", - " df.index.name = \"hour\"\n", - "\n", - " print(f\"Created DataFrame with {len(df.columns)} curves and {len(df)} rows\")\n", - " return df\n", - "\n", - "# User uploads Excel/CSV → DataFrame → CustomCurves object\n", - "from pyetm.models.custom_curves import CustomCurves\n", - "\n", - "df = read_curves_to_dataframe(\"curve_examples/\")\n", - "custom_curves = CustomCurves._from_dataframe(df)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e75a03b2", - "metadata": {}, - "outputs": [], - "source": [ - "from example_helpers import setup_notebook\n", - "from pyetm.models import Scenario\n", - "\n", - "setup_notebook()\n", - "scenario = Scenario.load(2690288)\n", - "\n", - "# Update curves on scenario\n", - "scenario.update_custom_curves(custom_curves)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pyetm-qKH2ozgc", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/full_multi_scenario_flow.ipynb b/examples/full_multi_scenario_flow.ipynb new file mode 100644 index 0000000..4dd758a --- /dev/null +++ b/examples/full_multi_scenario_flow.ipynb @@ -0,0 +1,174 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "268e5f69", + "metadata": {}, + "source": [ + "This workbook demonstrates the complete flow from excel created / loaded scenarios to the API, including demonstrating how you can work with scenarios in pandas along the way.\n", + "\n", + "Before you begin you will need to place a config.yml in your root directory. An example.config.yml is available in /examples and will guide you through the setup. The README.md has additional details on environment management if you're setting up for the first time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ad85ac7", + "metadata": {}, + "outputs": [], + "source": [ + "# Check the environment is properly configured.\n", + "from example_helpers import setup_notebook\n", + "setup_notebook()" + ] + }, + { + "cell_type": "markdown", + "id": "2884d014", + "metadata": {}, + "source": [ + "For the purposes of this demonstration workbook, we will use the pre-filled template 'my_input_excel.xlsx' which demonstrated a few of the possibilities afforded by the pyetm package. If it's your first time using the tool, have a look at the excel to get a sense of the structure.\n", + "\n", + "In the example, there are two scenarios, with short names scen_a and scen_b. You can use short names in the parameters sheet to specify which inputs belong to which scenario. Because scen_a has no scenario_id, it is being created. It will be created with all the metadata included in the sheet, plus any of the inputs under the column with its short_name and any sortables and curves specified in the sheets named beside the sortables and custom_curves rows. The same goes for scen_b, but because it has a scenario_id (2690555) that scenario will be loaded, and then updated with anything as set in the excel.\n", + "\n", + "**TODO**: Figure out how to manage the fact that for this example whatever scenario 2690555 is will be constantly updated etc by everyone who wants to try running the script on pro/beta. At the moment its just a local scenario.\n", + "\n", + "Everything in the ETM is structured via scenarios, and so is pyetm." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "077ae081", + "metadata": {}, + "outputs": [], + "source": [ + "from pyetm.models.scenarios import Scenarios\n", + "\n", + "scenarios = Scenarios.from_excel(\"my_input_excel.xlsx\")" + ] + }, + { + "cell_type": "markdown", + "id": "fb319a38", + "metadata": {}, + "source": [ + "Now we have the 'scenarios' in pyetm which represent actual real scenarios in the ETM, one created and one loaded.\n", + "\n", + "The following blocks show how you can explore these scenarios' attributes - run some if you want to explore the data structures." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17bff6db", + "metadata": {}, + "outputs": [], + "source": [ + "# Metadata\n", + "for scenario in scenarios:\n", + " print(f\"Title: {scenario.title}\")\n", + " print(f\"Area: {scenario.area_code}\")\n", + " print(f\"End year: {scenario.end_year}\")\n", + " print(f\"Version: {scenario.version}\")\n", + " print(f\"Source: {scenario.source}\")\n", + " print(f\"Metadata: {scenario.metadata}\")\n", + " print(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f9a4600", + "metadata": {}, + "outputs": [], + "source": [ + "# Inputs\n", + "for scenario in scenarios:\n", + " inputs = scenario.inputs.to_dataframe(columns=[\"user\", \"default\", \"min\", \"max\"]).head(20)\n", + " print(inputs)\n", + " print(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e9bf837", + "metadata": {}, + "outputs": [], + "source": [ + "# Sortables\n", + "for scenario in scenarios:\n", + " sortables = scenario.sortables.to_dataframe().head(20)\n", + " print(sortables)\n", + " print(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ef38d18", + "metadata": {}, + "outputs": [], + "source": [ + "# Custom Curves\n", + "for scenario in scenarios:\n", + " curves = scenario.custom_curves.to_dataframe().head(20)\n", + " print(curves)\n", + " print(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa4e8ee8", + "metadata": {}, + "outputs": [], + "source": [ + "# Queries\n", + "for scenario in scenarios:\n", + " print(scenario.results())\n", + " print(\"\")" + ] + }, + { + "cell_type": "markdown", + "id": "86643b22", + "metadata": {}, + "source": [ + "We can directly modify any of the attributes using Pandas, or we can re-export the scenarios to excel and make modifications that way." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d24ad5e1", + "metadata": {}, + "outputs": [], + "source": [ + "scenarios.to_excel(\"my_excel.xlsx\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pyetm-qKH2ozgc", + "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.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/myc_notebook_for_tim.ipynb b/examples/myc_notebook_for_tim.ipynb index df330f1..6545857 100644 --- a/examples/myc_notebook_for_tim.ipynb +++ b/examples/myc_notebook_for_tim.ipynb @@ -136,7 +136,6 @@ ], "source": [ "scenario = Scenario.load(2690499)\n", - "# maybe add a tag for a study name / scenario name\n", "scenario.to_dataframe()" ] }, @@ -1610,7 +1609,7 @@ ], "metadata": { "kernelspec": { - "display_name": "pyetm-FWBOHxp3", + "display_name": "pyetm-qKH2ozgc", "language": "python", "name": "python3" }, @@ -1624,7 +1623,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.11" + "version": "3.12.9" } }, "nbformat": 4, diff --git a/examples/scenario_to_excel.ipynb b/examples/scenario_to_excel.ipynb index 05232b2..6071b68 100644 --- a/examples/scenario_to_excel.ipynb +++ b/examples/scenario_to_excel.ipynb @@ -187,7 +187,7 @@ "packer.add_sortables(scenario2)\n", "\n", "\n", - "packer.to_excel('testing_output_curves.xlsx')" + "# packer.to_excel('testing_output_curves.xlsx')" ] } ], diff --git a/src/pyetm/models/__init__.py b/src/pyetm/models/__init__.py index 5f78c5a..6e0abb7 100644 --- a/src/pyetm/models/__init__.py +++ b/src/pyetm/models/__init__.py @@ -2,5 +2,6 @@ from .gqueries import Gqueries from .inputs import Input, Inputs from .scenario import Scenario +from .scenarios import Scenarios from .sortables import Sortable, Sortables from .scenario_packer import ScenarioPacker diff --git a/src/pyetm/models/custom_curves.py b/src/pyetm/models/custom_curves.py index 5713ba3..6e59e65 100644 --- a/src/pyetm/models/custom_curves.py +++ b/src/pyetm/models/custom_curves.py @@ -146,7 +146,6 @@ def _from_dataframe( ) -> "CustomCurve": """ Create CustomCurve from DataFrame containing time series data. - scenario_id: optional id used to disambiguate filenames when multiple scenarios import curves from excel. """ if len(df.columns) != 1: raise ValueError( @@ -163,7 +162,6 @@ def _from_dataframe( if not df.empty: curve_data = df.iloc[:, 0].dropna() if not curve_data.empty: - # Include scenario id in filename if provided to avoid collisions between scenarios. safe_key = str(curve_key).replace("/", "-") prefix = f"{scenario_id}_" if scenario_id is not None else "" file_path = ( @@ -240,7 +238,7 @@ def from_json(cls, data: list[dict]) -> CustomCurves: collection = cls.model_validate({"curves": curves}) - # Merge warnings from individual curves using new system + # Merge warnings from individual curves collection._merge_submodel_warnings(*curves, key_attr="key") return collection @@ -285,7 +283,6 @@ def _from_dataframe( ) -> "CustomCurves": """ Create CustomCurves collection from DataFrame with time series data. - scenario_id: optional id forwarded to individual curve creation to disambiguate filenames. """ curves = [] if len(df.columns) == 0: diff --git a/src/pyetm/models/inputs.py b/src/pyetm/models/inputs.py index a8ee2f1..c970d1a 100644 --- a/src/pyetm/models/inputs.py +++ b/src/pyetm/models/inputs.py @@ -186,7 +186,6 @@ def is_valid_update(self, key_vals: dict) -> dict[str, WarningCollector]: def update(self, key_vals: dict): """ Update the values of certain inputs. - Uses the new warning system for validation. """ for input_obj in self.inputs: if input_obj.key in key_vals: diff --git a/src/pyetm/models/output_curves.py b/src/pyetm/models/output_curves.py index 540bb27..dec1bc8 100644 --- a/src/pyetm/models/output_curves.py +++ b/src/pyetm/models/output_curves.py @@ -147,14 +147,11 @@ def get_contents(self, scenario, curve_name: str) -> Optional[pd.DataFrame]: return None if not curve.available(): - # Try to retrieve it result = curve.retrieve(BaseClient(), scenario) - # Merge any warnings from the curve retrieval using new system self._merge_submodel_warnings(curve, key_attr="key") return result else: contents = curve.contents() - # Merge any warnings from reading contents using new system self._merge_submodel_warnings(curve, key_attr="key") return contents @@ -247,7 +244,7 @@ def from_json(cls, data: list[dict]) -> OutputCurves: collection = cls.model_validate({"curves": curves}) - # Merge warnings from individual curves using new system + # Merge warnings from individual curves collection._merge_submodel_warnings(*curves, key_attr="key") return collection diff --git a/src/pyetm/models/scenario.py b/src/pyetm/models/scenario.py index 896e608..36ab2ee 100644 --- a/src/pyetm/models/scenario.py +++ b/src/pyetm/models/scenario.py @@ -4,11 +4,12 @@ from typing import Any, Dict, List, Optional, Set, Union from urllib.parse import urlparse from pydantic import Field, PrivateAttr +from os import PathLike from pyetm.models.inputs import Inputs from pyetm.models.output_curves import OutputCurves from pyetm.clients import BaseClient from pyetm.models.base import Base -from pyetm.models.custom_curves import CustomCurve, CustomCurves +from pyetm.models.custom_curves import CustomCurves from pyetm.models.gqueries import Gqueries from pyetm.models.sortables import Sortables from pyetm.services.scenario_runners.fetch_inputs import FetchInputsRunner @@ -98,6 +99,28 @@ def load(cls, scenario_id: int) -> Scenario: scenario.add_warning("metadata", w) return scenario + @classmethod + def from_excel(cls, xlsx_path: PathLike | str) -> List["Scenario"]: + """ + Load or create one or more scenarios from an Excel workbook. + """ + from pyetm.models.scenario_packer import ScenarioPacker + + packer = ScenarioPacker.from_excel(xlsx_path) + scenarios = list(packer._scenarios()) + scenarios.sort(key=lambda s: s.id) + return scenarios + + def to_excel(self, path: PathLike | str, *others: "Scenario") -> None: + """ + Export this scenario – and optionally additional scenarios – to an Excel file. + """ + from pyetm.models.scenario_packer import ScenarioPacker + + packer = ScenarioPacker() + packer.add(self, *others) + packer.to_excel(str(path)) + def update_metadata(self, **kwargs) -> Dict[str, Any]: """ Update metadata for this scenario. @@ -362,7 +385,6 @@ def update_custom_curves(self, custom_curves) -> None: Args: custom_curves: CustomCurves object containing curves to upload - TODO: Update after the from_excel is implemented """ # Validate curves before uploading diff --git a/src/pyetm/models/scenario_packer.py b/src/pyetm/models/scenario_packer.py index 6aba805..c024c5b 100644 --- a/src/pyetm/models/scenario_packer.py +++ b/src/pyetm/models/scenario_packer.py @@ -12,7 +12,7 @@ from pyetm.models.packables.sortable_pack import SortablePack from pyetm.models import Scenario from pyetm.models.custom_curves import CustomCurves -from pyetm.utils.excel import add_frame_with_scenario_styling +from pyetm.utils.excel import add_frame logger = logging.getLogger(__name__) @@ -88,7 +88,7 @@ def to_excel(self, path: str): df = self.main_info() if not df.empty: df_filled = df.fillna("").infer_objects(copy=False) - add_frame_with_scenario_styling( + add_frame( name="MAIN", frame=df_filled, workbook=workbook, @@ -100,7 +100,7 @@ def to_excel(self, path: str): df = pack.to_dataframe() if not df.empty: df_filled = df.fillna("").infer_objects(copy=False) - add_frame_with_scenario_styling( + add_frame( name=pack.sheet_name, frame=df_filled, workbook=workbook, diff --git a/src/pyetm/models/scenarios.py b/src/pyetm/models/scenarios.py new file mode 100644 index 0000000..94abc60 --- /dev/null +++ b/src/pyetm/models/scenarios.py @@ -0,0 +1,48 @@ +from __future__ import annotations +from os import PathLike +from typing import Iterable, Iterator, List +from pydantic import BaseModel, Field +from .scenario import Scenario + + +class Scenarios(BaseModel): + """ + A simple collection of Scenario objects with convenience utilities. + #TODO: Make a nice repr or stats functions + """ + + items: List[Scenario] = Field(default_factory=list) + + def __iter__(self) -> Iterator[Scenario]: + return iter(self.items) + + def __len__(self) -> int: + return len(self.items) + + def __getitem__(self, index: int) -> Scenario: + return self.items[index] + + def add(self, *scenarios: Scenario) -> None: + self.items.extend(scenarios) + + def extend(self, scenarios: Iterable[Scenario]) -> None: + self.items.extend(list(scenarios)) + + def to_excel(self, path: PathLike | str) -> None: + """ + Export all scenarios in this collection to an Excel workbook. + """ + from .scenario_packer import ScenarioPacker + + packer = ScenarioPacker() + if self.items: + packer.add(*self.items) + packer.to_excel(str(path)) + + @classmethod + def from_excel(cls, xlsx_path: PathLike | str) -> "Scenarios": + """ + Load or create scenarios from an Excel workbook and wrap them in Scenarios. + """ + scenarios = Scenario.load_from_excel(xlsx_path) + return cls(items=scenarios) diff --git a/src/pyetm/utils/excel.py b/src/pyetm/utils/excel.py index 60ca4cf..a0d6be5 100644 --- a/src/pyetm/utils/excel.py +++ b/src/pyetm/utils/excel.py @@ -76,10 +76,10 @@ def create_scenario_formats(workbook: Workbook) -> dict: {"bold": True, "bg_color": "#FFFFFF", "border": 1, "align": "center"} ), "grey_header": workbook.add_format( - {"bold": True, "bg_color": "#F2F2F2", "border": 1, "align": "center"} + {"bold": True, "bg_color": "#D9D9D9", "border": 1, "align": "center"} ), "white_data": workbook.add_format({"bg_color": "#FFFFFF", "border": 1}), - "grey_data": workbook.add_format({"bg_color": "#F2F2F2", "border": 1}), + "grey_data": workbook.add_format({"bg_color": "#D9D9D9", "border": 1}), "bold": workbook.add_format({"bold": True}), "default": None, } @@ -111,7 +111,7 @@ def get_scenario_blocks(columns: pd.MultiIndex) -> List[tuple]: return blocks -def add_frame_with_scenario_styling( +def add_frame( name: str, frame: pd.DataFrame, workbook: Workbook, @@ -124,7 +124,6 @@ def add_frame_with_scenario_styling( decimal_precision: int = 10, scenario_styling: bool = True, ) -> Worksheet: - """Enhanced add_frame with scenario block styling""" # Create worksheet worksheet = workbook.add_worksheet(str(name)) @@ -205,7 +204,7 @@ def add_frame_with_scenario_styling( ) else: - # Standard column handling (single-index or no scenario styling) + # Standard column handling or single-index scenario styling bold_format = formats.get("bold") if bold_headers else None if isinstance(frame.columns, pd.MultiIndex): @@ -219,22 +218,53 @@ def add_frame_with_scenario_styling( for col_num, values in enumerate(frame.columns.values): for row_num, value in enumerate(values): worksheet.write(row_num, col_num + col_offset, value, bold_format) - else: - # Write simple column headers - for col_num, value in enumerate(frame.columns.values): - worksheet.write( - row_offset - 1, col_num + col_offset, value, bold_format - ) - # Write data without styling - for row_num, row_data in enumerate(frame.values): - for col_num, value in enumerate(row_data): - worksheet.write(row_num + row_offset, col_num + col_offset, value) + # Write data without styling + for row_num, row_data in enumerate(frame.values): + for col_num, value in enumerate(row_data): + worksheet.write(row_num + row_offset, col_num + col_offset, value) + else: + # Single-level columns + if scenario_styling: + # Alternate header backgrounds by scenario column + for col_num, value in enumerate(frame.columns.values): + is_grey = (col_num % 2) == 1 + header_format = ( + formats["grey_header"] if is_grey else formats["white_header"] + ) + worksheet.write( + row_offset - 1, col_num + col_offset, value, header_format + ) + + # Alternate data backgrounds by scenario column + for row_num, row_data in enumerate(frame.values): + for col_num, value in enumerate(row_data): + is_grey = (col_num % 2) == 1 + data_format = ( + formats["grey_data"] if is_grey else formats["white_data"] + ) + worksheet.write( + row_num + row_offset, + col_num + col_offset, + value, + data_format, + ) + else: + # No scenario styling: write simple headers and data + for col_num, value in enumerate(frame.columns.values): + worksheet.write( + row_offset - 1, col_num + col_offset, value, bold_format + ) + + for row_num, row_data in enumerate(frame.values): + for col_num, value in enumerate(row_data): + worksheet.write( + row_num + row_offset, col_num + col_offset, value + ) # Set column widths set_column_widths(worksheet, col_offset, len(frame.columns), column_width) - # Write index with proper styling for scenario sheets if index: set_column_widths( worksheet, 0, frame.index.nlevels, index_width or column_width @@ -244,41 +274,12 @@ def add_frame_with_scenario_styling( index_format = formats.get("bold") if bold_headers else None write_index(worksheet, frame.index, row_offset, index_format) - # Freeze panes if freeze_panes: worksheet.freeze_panes(row_offset, col_offset) return worksheet -def add_frame( - name: str, - frame: pd.DataFrame, - workbook: Workbook, - index: bool = True, - column_width: Union[int, List[int], None] = None, - index_width: Union[int, List[int], None] = None, - freeze_panes: bool = True, - bold_headers: bool = True, - nan_as_formula: bool = True, - decimal_precision: int = 10, -) -> Worksheet: - """Original add_frame function for backward compatibility""" - return add_frame_with_scenario_styling( - name=name, - frame=frame, - workbook=workbook, - index=index, - column_width=column_width, - index_width=index_width, - freeze_panes=freeze_panes, - bold_headers=bold_headers, - nan_as_formula=nan_as_formula, - decimal_precision=decimal_precision, - scenario_styling=False, # Default to old behavior - ) - - def add_series( name: str, series: pd.Series, @@ -291,7 +292,6 @@ def add_series( nan_as_formula: bool = True, decimal_precision: int = 10, ) -> Worksheet: - """Add Series to workbook as a new worksheet - unchanged""" # Create worksheet worksheet = workbook.add_worksheet(str(name)) diff --git a/tests/utils/test_excel.py b/tests/utils/test_excel.py index 8533655..4226249 100644 --- a/tests/utils/test_excel.py +++ b/tests/utils/test_excel.py @@ -8,10 +8,10 @@ from xlsxwriter.worksheet import Worksheet from pyetm.utils.excel import ( + add_frame, handle_numeric_value, set_column_widths, write_index, - add_frame, add_series, ) @@ -154,89 +154,6 @@ def test_write_index_no_names(self): assert len(name_calls) == 0 -class TestAddFrame: - """Test add_frame function""" - - def setup_method(self): - """Setup test data""" - self.temp_dir = tempfile.mkdtemp() - - def teardown_method(self): - """Clean up temp files""" - import shutil - - shutil.rmtree(self.temp_dir, ignore_errors=True) - - def test_add_simple_dataframe(self): - """Test adding simple DataFrame""" - df = pd.DataFrame( - {"A": [1, 2, 3], "B": [4.5, np.nan, 6.7]}, index=["row1", "row2", "row3"] - ) - - file_path = os.path.join(self.temp_dir, "test.xlsx") - workbook = Workbook(file_path, {"nan_inf_to_errors": True}) - - worksheet = add_frame("TestSheet", df, workbook) - - assert worksheet is not None - assert worksheet.name == "TestSheet" - - workbook.close() - - def test_add_dataframe_no_index(self): - """Test adding DataFrame without index""" - df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) - - file_path = os.path.join(self.temp_dir, "test_no_index.xlsx") - workbook = Workbook(file_path, {"nan_inf_to_errors": True}) - - worksheet = add_frame("TestSheet", df, workbook, index=False) - - assert worksheet is not None - workbook.close() - - def test_add_multiindex_dataframe(self): - """Test adding DataFrame with MultiIndex""" - arrays = [["A", "A", "B", "B"], [1, 2, 1, 2]] - index = pd.MultiIndex.from_arrays(arrays, names=["letter", "number"]) - - columns = pd.MultiIndex.from_tuples( - [("X", "col1"), ("X", "col2"), ("Y", "col1")], names=["group", "item"] - ) - - df = pd.DataFrame(np.random.randn(4, 3), index=index, columns=columns) - - file_path = os.path.join(self.temp_dir, "test_multi.xlsx") - workbook = Workbook(file_path, {"nan_inf_to_errors": True}) - - worksheet = add_frame("MultiTest", df, workbook) - - assert worksheet is not None - workbook.close() - - def test_add_frame_with_custom_options(self): - """Test add_frame with custom options""" - df = pd.DataFrame({"A": [1.123456789, 2.987654321], "B": [np.nan, 4.555555555]}) - - file_path = os.path.join(self.temp_dir, "test_custom.xlsx") - workbook = Workbook(file_path, {"nan_inf_to_errors": True}) - - worksheet = add_frame( - "CustomTest", - df, - workbook, - column_width=[15, 20], - index_width=12, - freeze_panes=False, - bold_headers=False, - nan_as_formula=False, - decimal_precision=3, - ) - - assert worksheet is not None - workbook.close() - - class TestAddSeries: """Test add_series function"""