From c3d170b2690e70cb50061e0cfff36aa520f0d379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Fri, 15 May 2020 16:37:35 +0200 Subject: [PATCH 01/34] Add Architecture files. Write overview --- docs/source/architecture/analyzer.rst | 4 + docs/source/architecture/optimizer.rst | 4 + docs/source/architecture/overview.rst | 98 ++++++++++++++++++++++++ docs/source/architecture/viewer.rst | 5 ++ docs/source/architecture/workflow.rst | 4 + docs/source/dev-guide/best-practices.rst | 4 + docs/source/dev-guide/devops.rst | 4 + docs/source/dev-guide/repository.rst | 4 + docs/source/index.rst | 30 +++++++- docs/source/mathematics/linear-model.rst | 4 + 10 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 docs/source/architecture/analyzer.rst create mode 100644 docs/source/architecture/optimizer.rst create mode 100644 docs/source/architecture/overview.rst create mode 100644 docs/source/architecture/viewer.rst create mode 100644 docs/source/architecture/workflow.rst create mode 100644 docs/source/dev-guide/best-practices.rst create mode 100644 docs/source/dev-guide/devops.rst create mode 100644 docs/source/dev-guide/repository.rst create mode 100644 docs/source/mathematics/linear-model.rst diff --git a/docs/source/architecture/analyzer.rst b/docs/source/architecture/analyzer.rst new file mode 100644 index 0000000..ec1e0c5 --- /dev/null +++ b/docs/source/architecture/analyzer.rst @@ -0,0 +1,4 @@ +Analyzer +======== + +Hello world \ No newline at end of file diff --git a/docs/source/architecture/optimizer.rst b/docs/source/architecture/optimizer.rst new file mode 100644 index 0000000..fd75ce9 --- /dev/null +++ b/docs/source/architecture/optimizer.rst @@ -0,0 +1,4 @@ +Optimizer +========= + +Hello world \ No newline at end of file diff --git a/docs/source/architecture/overview.rst b/docs/source/architecture/overview.rst new file mode 100644 index 0000000..8ff817c --- /dev/null +++ b/docs/source/architecture/overview.rst @@ -0,0 +1,98 @@ +Overview +======== + +Welcome to the Hadar Architecture Documentation. +If you are here that mean you want to go deeper into Hadar gears. +If you want just to know how to use Hadar, then `tutorials `_ will be a better place to you. + +If you want just to see mathematics model then mathematics section will be better for you. + +Ok If you are still here than mean you want to speak about code, class, method and you are at the right place. + +Hadar purpose is to be *an adequacy library for everyone*. +Term *everyone* is important, Hadar must be such easy that everyone can use it. +And Hadar must be such flexible that everyone business can use it or customize it. + +**Why these goals ?** + +We design Hadar in the same spirit of python libraries like numy or scipy, and moreover like scikit-learn. +Before scikit-learn, people how want to develop machine learning have to had strong skill in mathematics background to develop their own code. +Some *ready to go* code existed but was not easy to use and flexible. + +Scikit-learn release the power of machine learning by abstract complex algorithms into very streight forward API. +It was designed like a toolbox to handle full machine learning vision, where user can juste assemble scikit-learn component or build their own. + +Hadar want to be the next scikit-learn for adequacy. +Hadar has to be easy to use and flexible, which if we translate into architecture terms become **high abstraction level** and **independent modules**. + + +Independent modules +------------------- + +User has the choice : Use only Hadar components, assemble them and create a full solution to generate adequacy study, solve it and analyze result. Or use their parts. + + +To reach this constraint, we split Hadar into 4 main modules which can be use together or separated : + +- **workflow:** module used to generate data study. Hadar handle deterministic computation like stochastic. For stochastic computation user needs to generate many scenarios. Workflow will help user by providing a highly customizable pipeline framework to transform and generate data. + + +- **optimizer:** more complex and mathematical module. User will use it to describe study adequacy to resolve. No need to understand mathematics, Hadar will handle data input given and translate it to a linear optimization problem before to call a solver. + +- **analyzer:** input data given to optimizer and output date with study result can be heavy to analyze. To avoid that every user build their own toolbox, we develop the most used features once for everyone. + +- **viewer** analyzer output will be numpy matrix or pandas Dataframe, it great but not enough to analyze result. Viewer uses the analyzer feature and API to generate graphics from study data. + +As said, these modules can be used together to handle complet adequacy study lifecycle or used seperately. + +TODO graph architecture module + + +High Abstraction API +-------------------- + +Each above modules are like a tiny independent libraries. Therefore each module has a high level API. +High abstraction, is a bit confuse to handle and benchmark. For us a high abstraction is when user doesn't need to know mathematics or technicals stuffs when he uses library. + +Scikit-learn is the best example of high abstraction level API. For example, if we just want to start a complet SVM research +:: + + from sklean.svm import SVR + svm = SVR() + svm.fit(X_train, y_train) + y_pred = svm.predict(X_test) + + +How many people using this features know that scikit-learn tries to project data into higher space to find a linear regression inside. And to accelerate computation, it uses mathematics feature called *a kernel trick* because problem respect strict requirements ? Perhaps just few people and it's all the beauty of an high level API, it hidden background gear. + + +Hadar tries to keep this high abstraction features. Look at the *Get Started* example +:: + + import hadar as hd + + study = hd.Study(['a', 'b'], horizon=3) \ + .add_on_node('a', data=hd.Consumption(cost=10 ** 6, quantity=[20, 20, 20], name='load')) \ + .add_on_node('a', data=hd.Production(cost=10, quantity=[30, 20, 10], name='prod')) \ + .add_on_node('b', data=hd.Consumption(cost=10 ** 6, quantity=[20, 20, 20], name='load')) \ + .add_on_node('b', data=hd.Production(cost=20, quantity=[10, 20, 30], name='prod')) \ + .add_link(src='a', dest='b', quantity=[10, 10, 10], cost=2) \ + .add_link(src='b', dest='a', quantity=[10, 10, 10], cost=2) \ + + + optim = hd.LPOptimizer() + res = optim.solve(study) + + +Create a study like you will draw it on a paper. Put your nodes, attach some production, consumption, link and run optimizer. + + +Go Next +------- + +Now goals are fixed, we can go deeper into specific module documentation. +All architecture focuses on : High Abstraction and Independent module. You can also read the best practices guide to understand more development choice made in Hadar. + + +Let't start code explanation. + diff --git a/docs/source/architecture/viewer.rst b/docs/source/architecture/viewer.rst new file mode 100644 index 0000000..1ec93c9 --- /dev/null +++ b/docs/source/architecture/viewer.rst @@ -0,0 +1,5 @@ +Viewer +====== + + +Hello world \ No newline at end of file diff --git a/docs/source/architecture/workflow.rst b/docs/source/architecture/workflow.rst new file mode 100644 index 0000000..edd46c7 --- /dev/null +++ b/docs/source/architecture/workflow.rst @@ -0,0 +1,4 @@ +Workflow +======== + +Hello world \ No newline at end of file diff --git a/docs/source/dev-guide/best-practices.rst b/docs/source/dev-guide/best-practices.rst new file mode 100644 index 0000000..5ef41c6 --- /dev/null +++ b/docs/source/dev-guide/best-practices.rst @@ -0,0 +1,4 @@ +Best Practices +============== + +Hello world \ No newline at end of file diff --git a/docs/source/dev-guide/devops.rst b/docs/source/dev-guide/devops.rst new file mode 100644 index 0000000..d68a911 --- /dev/null +++ b/docs/source/dev-guide/devops.rst @@ -0,0 +1,4 @@ +Devops lifecycle +================ + +Hello world \ No newline at end of file diff --git a/docs/source/dev-guide/repository.rst b/docs/source/dev-guide/repository.rst new file mode 100644 index 0000000..3eef551 --- /dev/null +++ b/docs/source/dev-guide/repository.rst @@ -0,0 +1,4 @@ +Repository Organization +======================= + +Hello world \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index dc7d9dc..d7ccc84 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -64,16 +64,40 @@ Or :: .. image:: /_static/get-started-3.png .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + :caption: Architecture: + + architecture/overview.rst + architecture/workflow.rst + architecture/optimizer.rst + architecture/analyzer.rst + architecture/viewer.rst + +.. toctree:: + :maxdepth: 1 + :caption: Mathematics: + + mathematics/linear-model.rst + +.. toctree:: + :maxdepth: 1 + :caption: Dev Guide: + + dev-guide/repository.rst + dev-guide/best-practices.rst + dev-guide/devops.rst + +.. toctree:: + :maxdepth: 1 :caption: Reference: - reference/hadar.analyzer.rst + reference/hadar.workflow.rst reference/hadar.optimizer.rst reference/hadar.analyzer.rst reference/hadar.viewer.rst .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: Legal Terms terms/terms.rst \ No newline at end of file diff --git a/docs/source/mathematics/linear-model.rst b/docs/source/mathematics/linear-model.rst new file mode 100644 index 0000000..c5833f3 --- /dev/null +++ b/docs/source/mathematics/linear-model.rst @@ -0,0 +1,4 @@ +Linear Model +============ + +Hello world \ No newline at end of file From a7201631e4719a5297b7454b8b5a754a8c84cc42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Mon, 18 May 2020 17:35:14 +0200 Subject: [PATCH 02/34] close #55. WIP #56 add workflow description --- docs/source/architecture/overview.rst | 18 ++-- docs/source/architecture/workflow.rst | 140 +++++++++++++++++++++++++- docs/source/index.rst | 48 ++------- 3 files changed, 152 insertions(+), 54 deletions(-) diff --git a/docs/source/architecture/overview.rst b/docs/source/architecture/overview.rst index 8ff817c..2df238f 100644 --- a/docs/source/architecture/overview.rst +++ b/docs/source/architecture/overview.rst @@ -2,12 +2,6 @@ Overview ======== Welcome to the Hadar Architecture Documentation. -If you are here that mean you want to go deeper into Hadar gears. -If you want just to know how to use Hadar, then `tutorials `_ will be a better place to you. - -If you want just to see mathematics model then mathematics section will be better for you. - -Ok If you are still here than mean you want to speak about code, class, method and you are at the right place. Hadar purpose is to be *an adequacy library for everyone*. Term *everyone* is important, Hadar must be such easy that everyone can use it. @@ -16,11 +10,11 @@ And Hadar must be such flexible that everyone business can use it or customize i **Why these goals ?** We design Hadar in the same spirit of python libraries like numy or scipy, and moreover like scikit-learn. -Before scikit-learn, people how want to develop machine learning have to had strong skill in mathematics background to develop their own code. -Some *ready to go* code existed but was not easy to use and flexible. +Before scikit-learn, people who want to develop machine learning have to had strong skill in mathematics background to develop their own code. +Some *ready to go* codes existed but were not easy to use and flexible. -Scikit-learn release the power of machine learning by abstract complex algorithms into very streight forward API. -It was designed like a toolbox to handle full machine learning vision, where user can juste assemble scikit-learn component or build their own. +Scikit-learn release the power of machine learning by abstract complex algorithms into very straight forward API. +It was designed like a toolbox to handle full machine learning framework, where user can juste assemble scikit-learn component or build their own. Hadar want to be the next scikit-learn for adequacy. Hadar has to be easy to use and flexible, which if we translate into architecture terms become **high abstraction level** and **independent modules**. @@ -29,10 +23,10 @@ Hadar has to be easy to use and flexible, which if we translate into architectur Independent modules ------------------- -User has the choice : Use only Hadar components, assemble them and create a full solution to generate adequacy study, solve it and analyze result. Or use their parts. +User has the choice : Use only Hadar components, assemble them and create a full solution to generate, solve and analyze adequacy study. Or build their parts. -To reach this constraint, we split Hadar into 4 main modules which can be use together or separated : +To reach this constraint, we split Hadar into 4 main modules which can be use together or apart : - **workflow:** module used to generate data study. Hadar handle deterministic computation like stochastic. For stochastic computation user needs to generate many scenarios. Workflow will help user by providing a highly customizable pipeline framework to transform and generate data. diff --git a/docs/source/architecture/workflow.rst b/docs/source/architecture/workflow.rst index edd46c7..583e05a 100644 --- a/docs/source/architecture/workflow.rst +++ b/docs/source/architecture/workflow.rst @@ -1,4 +1,142 @@ Workflow ======== -Hello world \ No newline at end of file +What is a stochastic study ? +---------------------------- + + +Workflow is the preprocessing module for Hadar. It's a toolbox for create pipelines to transform data for solver. + +When you want to simulate a network adequacy, you can perform a *deterministic* computation. That means you believe you won't have too much fluky behavior in the futur. If you perform adequacy for the next hour or day, it's a good hypothesis. But if you simulate network for the next week, month or year, it's sound curious. + +Are you sur wind will blow next week or sun will shines ? If not, you eolian or solar production could change. Can you warrant that no failure will occur on your network next month or next year ? + +Of course, we can not predict futur with such precision. The best solution could to be to compute a *God function* which tell you for each input variation (solar production, line, consumptions) what is the adequacy result. Like that, Hadar has just to analyze function, its derivates etc to predict futur. But this *Got function* doesn't exist, we just have an algorithm which tell us adequacy according to one fixed set of input data. + + +It's why we use *stochastic* computation. With stochastic computation, you run many *scenarios* to analyze many different behavior. Scenario with more consumption in cities, less solar production, less coat production or one line deleted due to crash. By this method we recreate *Got function* by sampling it with the Monte-Carlo method. + + +TODO Monte Carlo sampling graphics + + +Workflow will help user to generate these scenarios and sample them to create a stochastic study. + +The main issue when we want to *help people generating their scenarios* is they are as many generating process than user. +Therefore workflow is build upon a Stage and Pipeline Architecture. + + +Stages, Pipelines & Plug +------------------------ + +Stage is an atomic process applied to data. In workflow, data is a pandas Dataframe with this form + +TODO stage data + +A stage will perform compute to this Dataframe. As you assume it, stages can be linked together to create pipeline. +Hadar has its own stages very generic, each user can build these stages and create these pipelines. + +For examples, you have many coal production. Each production plan has 10 generators of 100 MW. That means a coal plan production are 1,000 MW of power. You know that sometime, some generator crash or need shutdown for maintenance. With Hadar you can create a pipeline to generate these fault scenarios. :: + + # In this example, one timestep = one hour + import hadar as hd + + # Copy scenarios ten times + copy = hd.RepeatScenario(n=10) + + # Apply on each scenario random fault, such as power drop is 100 MW, there is 0.01% chance of failure each hour + # if failture, it's a least for the whole day and until next week. + fault = hd.Fault(loss=100, occur_freq=0.0001, downtime_min=24, downtime_max=168) + + pipe = copy + fault + out = pipe.compute(in) + +In this example, if input is a constant time series of 1,000 MW, you will have as output 10 timeseries with random drop of 100 MW during 24 to 168 timestep. + +**Create its own Stage** + +:code:`RepeatScenario`, :code:`Fault` and all other are build upon :code:`Stage` abstract class. A Stage is specified by its :code:`Plug` (we will see sooner) and a :code:`_process_timeline(self, timeline: pd.DataFrame) -> pd.DataFrame` to implement. :code:`timeline` variable inside method is the data passed thought pipeline to transform. + +For example, you need to multiply by 2 during your pipeline. You can create your stage by :: + + class Twice(Stage): + def __init__(self): + Stage.__init__(self, FreePlug()) + + def _process_timeline(self, timelines: pd.DataFrame) -> pd.DataFrame: + return timelines * 2 + + +Implement Stage will work every time. Often, you want to apply function independently for each scenario. +You can of course handle yourself this mechanism to split current :code:`timeline` apply method and rebuild at the end. Or use :code:`FocusStage`, same thing but already coded. In this case, you need to inherent from :code:`FocusStage` and implement :code:`_process_scenarios(self, n_scn: int, scenario: pd.DataFrame) -> pd.DataFrame` method. + +For example, you have thousand of scenarios, your stage has to generate gaussian series according to mean and sigma given. :: + + class Gaussian(FocusStage): + def __init__(self): + FocusStage.__init__(self, plug=RestrictedPlug(input=['mean', 'sigma'], output=['gaussian'])) + + def _process_scenarios(self, n_scn: int, scenario: pd.DataFrame) -> pd.DataFrame: + scenario['gaussian'] = np.random.randn(scenario.shape[0]) + scenario['gaussian'] *= scenario['sigma'] + scenario['gaussian'] += scenario['mean'] + + return scenario.drop(['mean', 'sigma'], axis=1) + + +**What's Plug ?** + +You are already see :code:`FreePlug` and :code:`RestrictedPlug`, what's it ? + +Stage are linked together to build pipeline. Some Stage accept every thing as input, like :code:`Twice`, but other need specific data like :code:`Gaussian`. How we know that stage can be link together and data given at the beginning of pipeline is correct for all pipeline. + +First solution is saying : *We don't care about. During execution, if data is missing, error will be raised and it's enough.* +Indeed... That's work, but if pipeline job is heavy, takes hour, and failed just due to a misspelling column name, it's ugly. + +:code:`Plug` object describe linkable constraint for Stage and Pipeline. Like Stage, Plug can be added together. In this case, constraint are merged. You can use :code:`FreePlug` telling this Stage is not constraint and doesn't expected any column name to run. Or use :code:`RestrictedPlug(inputs=[], outputs=[])` to specify inputs mandatories columns and new columns generated. + +Plug arithmetic rules are described below (:math:`\emptyset` = :code:`FreePlug`) + +.. math:: + \begin{array}{rcl} + \emptyset & + & \emptyset & = & \emptyset \\ + [a \rightarrow \alpha ] & + & \emptyset & = & [a \rightarrow \alpha ] \\ + [a \rightarrow \alpha ] & + & [\alpha \rightarrow A]& = & [a \rightarrow A] \\ + [a \rightarrow \alpha, \beta ] & + & [\alpha \rightarrow A]& = & [a \rightarrow A, \beta] \\ + \end{array} + + + +Shuffler +-------- + +User can create as many pipeline as he want. At the end, he could have some pipelines and input data or directly input data pre-generated. He needs to sampling this dataset to create study. For example, he could have 10 coal generation, 25 solar, 10 consumptions. He needs to create study with 100 scenarios. + +Of cours he can develop sampling algorithm, but he can also use :code:`Shuffler`. Indeed Shuffler does a bit more than just sampling: + +#. It is like a sink where user put pipeline or raw data. Shuffler will homogenous them to create scenarios. Behind code, we use :code:`Timeline` and :code:`PipelineTimeline` class to homogenize data according to raw data or data from output pipeline. + +#. It will schedule pipelines compute. If shuffler is used with pipeline, it will distribute pipeline running over computer cores. A good tips ! + +#. Yes it samples data to create study scenarios. + +TODO shuffler graphics + +Below an example how to use Shuffler :: + + shuffler = Shuffler() + # Add raw data as a bumpy array + shuffler.add_data(name='solar', data=np.array([[1, 2, 3], [5, 6, 7]])) + + # Add pipeline and its input data + i = pd.DataFrame({(0, 'a'): [3, 4, 5], (1, 'a'): [7, 8, 9]}) + pipe = RepeatScenario(2) + ToShuffler('a') + shuffler.add_pipeline(name='load', data=i, pipeline=pipe) + + # Shuffle to sample 3 scenarios + res = shuffler.shuffle(3) + + # Get result according name given + solar = res['solar'] + load = res['load'] + diff --git a/docs/source/index.rst b/docs/source/index.rst index d7ccc84..0cfc979 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -14,54 +14,20 @@ Welcome to Hadar! Hadar is a adequacy python library for deterministic and stochastic computation -Adequacy problem -^^^^^^^^^^^^^^^^ +You are in the technical documentation. -Each kind of network has a needs of adequacy. On one side, some network nodes need to consume -items such as watt, litter, package. And other side, some network nodes produce items. -Applying adequacy on network, is tring to find the best available exchanges to avoid any lack at the best cost. +* If you want to discover Hadar and the project, please go to https://www.hadar-simulator.org for an overview -For example, a electric grid can have some nodes wich produce too more power and some nodes wich produce not enough power. +* If you want to start using Hadar, you can begin with `tutorials `_ -.. image:: https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggTFJcblx0QVtBPGJyLz5sb2FkPTIwPGJyLz5wcm9kPTMwXSAtLT5CW0I8YnIvPmxvYWQ9MjA8YnIvPnByb2Q9MTBdXG5cdFx0XHRcdFx0IiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifSwidXBkYXRlRWRpdG9yIjpmYWxzZX0 +* If you want to understand Hadar engine, see **Architecture** -In this case, A produce 10 more and B need 10 more. Perform adequecy is quiet easy : A will share 10 to B +* If you want to look at a method or object behavior search inside **References** -.. image:: https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggTFJcblx0QVtBPGJyLz5sb2FkPTIwPGJyLz5wcm9kPTMwXSAtLT4gfHNoYXJlIDEwfCBCW0I8YnIvPmxvYWQ9MjA8YnIvPnByb2Q9MTBdXG5cdFx0XHRcdFx0IiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0) +* If you want to help us coding Hadar, please read **Dev Guide** before. -Hadar compute adequacy from simple to complex network. For example, to compute above network, just few line need:: +* If you want to see Mathematics model used in Hadar, go to **Mathematics**. - from hadar.solver.input import * - from hadar.solver.study import solve - - study = Study(['a', 'b']) \ - .add_on_node('a', data=Consumption(cost=10 ** 6, quantity=[20, 20], type='load')) \ - .add_on_node('a', data=Production(cost=10, quantity=[30, 30], type='prod')) \ - .add_on_node('b', data=Consumption(cost=10 ** 6, quantity=[20, 20], type='load')) \ - .add_on_node('b', data=Production(cost=20, quantity=[10, 10], type='prod')) \ - .add_border(src='a', dest='b', quantity=[10, 10], cost=2) \ - - res = solve(study) - -Then you can analyze by yourself result or use hadar aggragator and plotting:: - - from hadar.aggregator.result import ResultAggregator - from hadar.viewer.jupyter import JupyterPlotting - plot = JupyterPlotting(agg=ResultAggregator(study, res), - node_coord={'a': [2.33, 48.86], 'b': [4.38, 50.83]}) - plot.stack(node='a') - -.. image:: /_static/get-started-1.png - -Or :: - - plot.stack(node='b') -.. image:: /_static/get-started-2.png - -Or :: - - plot.exchanges_map(t=0) -.. image:: /_static/get-started-3.png .. toctree:: :maxdepth: 1 From 10e3906b1c118cc078a667c6afa860845ac8d57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Tue, 19 May 2020 11:36:51 +0200 Subject: [PATCH 03/34] finish workflow docs close #56 --- docs/source/architecture/workflow.rst | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/source/architecture/workflow.rst b/docs/source/architecture/workflow.rst index 583e05a..fcdf053 100644 --- a/docs/source/architecture/workflow.rst +++ b/docs/source/architecture/workflow.rst @@ -11,10 +11,12 @@ When you want to simulate a network adequacy, you can perform a *deterministic* Are you sur wind will blow next week or sun will shines ? If not, you eolian or solar production could change. Can you warrant that no failure will occur on your network next month or next year ? -Of course, we can not predict futur with such precision. The best solution could to be to compute a *God function* which tell you for each input variation (solar production, line, consumptions) what is the adequacy result. Like that, Hadar has just to analyze function, its derivates etc to predict futur. But this *Got function* doesn't exist, we just have an algorithm which tell us adequacy according to one fixed set of input data. +Of course, we can not predict futur with such precision. It's why we use *stochastic* computation. *Stochastic* means there are fluky behavior in the pyshics we want simulate. Simulation is quiet useless, if result is a unique result. + The best solution could to be to compute a *God function* which tell you for each input variation (solar production, line, consumptions) what is the adequacy result. Like that, Hadar has just to analyze function, its derivates etc to predict futur. But this *Got function* doesn't exist, we just have an algorithm which tell us adequacy according to one fixed set of input data. -It's why we use *stochastic* computation. With stochastic computation, you run many *scenarios* to analyze many different behavior. Scenario with more consumption in cities, less solar production, less coat production or one line deleted due to crash. By this method we recreate *Got function* by sampling it with the Monte-Carlo method. + +It's why we use *Monte Carlo* algorithm. Monte Carlo run many *scenarios* to analyze many different behavior. Scenario with more consumption in cities, less solar production, less coat production or one line deleted due to crash. By this method we recreate *Got function* by sampling it with the Monte-Carlo method. TODO Monte Carlo sampling graphics @@ -25,11 +27,11 @@ Workflow will help user to generate these scenarios and sample them to create a The main issue when we want to *help people generating their scenarios* is they are as many generating process than user. Therefore workflow is build upon a Stage and Pipeline Architecture. - + Stages, Pipelines & Plug ------------------------ -Stage is an atomic process applied to data. In workflow, data is a pandas Dataframe with this form +Stage is an atomic process applied on data. In workflow, data is a pandas Dataframe with this form TODO stage data @@ -40,14 +42,14 @@ For examples, you have many coal production. Each production plan has 10 generat # In this example, one timestep = one hour import hadar as hd - + # Copy scenarios ten times copy = hd.RepeatScenario(n=10) - + # Apply on each scenario random fault, such as power drop is 100 MW, there is 0.01% chance of failure each hour # if failture, it's a least for the whole day and until next week. fault = hd.Fault(loss=100, occur_freq=0.0001, downtime_min=24, downtime_max=168) - + pipe = copy + fault out = pipe.compute(in) @@ -118,14 +120,14 @@ Of cours he can develop sampling algorithm, but he can also use :code:`Shuffler #. It will schedule pipelines compute. If shuffler is used with pipeline, it will distribute pipeline running over computer cores. A good tips ! -#. Yes it samples data to create study scenarios. +#. It samples data to create study scenarios. TODO shuffler graphics Below an example how to use Shuffler :: shuffler = Shuffler() - # Add raw data as a bumpy array + # Add raw data as a numpy array shuffler.add_data(name='solar', data=np.array([[1, 2, 3], [5, 6, 7]])) # Add pipeline and its input data @@ -139,4 +141,3 @@ Below an example how to use Shuffler :: # Get result according name given solar = res['solar'] load = res['load'] - From 72f6b44d697ae182d9895d9496dc59e7c67b816c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Tue, 19 May 2020 17:49:51 +0200 Subject: [PATCH 04/34] WIP #57 start optimizer page --- docs/source/architecture/optimizer.rst | 179 ++++++++++++++++++++++- docs/source/architecture/workflow.rst | 10 +- docs/source/mathematics/linear-model.rst | 4 +- 3 files changed, 187 insertions(+), 6 deletions(-) diff --git a/docs/source/architecture/optimizer.rst b/docs/source/architecture/optimizer.rst index fd75ce9..e570725 100644 --- a/docs/source/architecture/optimizer.rst +++ b/docs/source/architecture/optimizer.rst @@ -1,4 +1,181 @@ Optimizer ========= -Hello world \ No newline at end of file +Optimizer is the heart of Hadar. Behind it, there is adequacy solver. There are more than one optimizer : + +#. Input object called :code:`Study`. Output object called :code:`Result`. These two objects encapsulate all data needed to compute adequacy. + +#. Many optimizers. User can choose in which will solve study. + +Therefore :code:`Optimizer` is an abstract class builded on *Strategy* pattern. User can select optimizer or create their own by implemented :code:`Optimizer.solve(study: Study) -> Result` + +Today, two optimizers are present :code:`LPOptimizer` and :code:`RemoteOptimizer` + +TODO ULM Optimizer + +RemoteOptimizer +--------------- + +Let's start by the simplest. :code:`RemoteOptimizer` is a client to hadar server. As you may know Hadar exist like a python library, but has also a tiny project to package hadar inside web server. You can find more details on this server in this `repository. `_ + +Client implements :code:`Optimizer` interface. Like that, to deploy compute on a datacenter, only one line of code changes. :: + + import hadar as hd + # Normal : optim = hd.LPOptimizer() + optim = hd.RemoteOptimizer(host='example.com') + res = optim.solve(study=study) + + +LPOptimizer +----------- + +Before read this chapter, we kindly advertise you to read :ref:`Linear Model ` + +:code:`LPOptimizer` translate data into optimization problem. Hadar algorithms focus only on modeling problem and uses `or-tools `_ to solve problem it. + +To achive modeling goal, :code:`LPOptimizer` is designed to receive :code:`Study` object, convert data into or-tools *Variables*. Then *Variables* are placed inside objective and constraint equations. Equations are solved by or-tools. Finally *Variables* are converted to Result object. + +Analyze that in details. + +InputMapper +************ + +If you look in code, you will see two domain. One at :code:`hadar.optimizer.[input/output]` and another at :code:`hadar.optimizer.lp.domain` . If you look carefully it seems the same :code:`Consumption` , :code:`OutputConsumption` in one hand, :code:`LPConsumption` in other hand. The only change is a new attribute in :code:`LP*` called :code:`variable` . Variables are the parameters of the problem. It's what or-tools has to find, i.e. power used for production, capacity used for border and lost of load for consumption. + +Therefore, :code:`InputMapper` roles are just to create new object with ortools Variables initialized, like we can see in this code snippet. :: + + # hadar.optimizer.lp.mapper.InputMapper.get_var + LPLink(dest=l.dest, + cost=float(l.cost), + src=name, + quantity=l.quantity[scn][t], + variable=self.solver.NumVar(0, float(l.quantity[scn][t]), + 'link on {} to {} at t={} for scn={}'.format(name, l.dest, t, scn) + ) + ) + +OutputMapper +************ + +At the end, :code:`OutputMapper` does the reverse thing. :code:`LP*` objects have computed variables. We need to extract result find by or-tool to :code:`Result` object. + +Mapping of :code:`LPProduction` and :code:`LPLink` are straight forward. I propose you to look at :code:`LPConsumption` code :: + + self.nodes[name].consumptions[i].quantity[scn, t] = + vars.consumptions[i].quantity - vars.consumptions[i].variable.solution_value() + +Line seems strange due to complex index. First we select good node *name*, then good consumption *i*, then good scenario *scn* and at this end good timestep *t*. Rewritting without index, this line means : + +.. math:: + Cons_{final} = Cons_{given} - Cons_{var} + +Keep in mind that :math:`Cons_{var}` is the lost of load. So we need to substract it from initial consumption to get really consumption available. + +Modeler +******* + +Hadar has to build problem optimization. These algorithms are encapsulated inside two builders. + +:code:`ObjectiveBuilder` get node by its method :code:`add_node`. Then for all productions, consumptions, links, it adds :math:`variable * cost` into objective equation. + +:code:`AdequacyBuilder` is a bit more tricky. For each node, it will create a new adequacy contraint equation (c.f. :ref:`Linear Model `). Coefficients, here are 1 or -1 depending of *inner* power or *outer* power. You also have see these lines :: + + self.constraints[(t, link.src)].SetCoefficient(link.variable, -1) # Export from src + self.importations[(t, link.src, link.dest)] = link.variable # Import to dest + +Hadar has to set power importation to *dest* node equation. But maybe this node is not yet setup and this constraint equation doesn't exist yet. Therefore he has to store all constraint equations and all link capacities. And at the end :code:`build()` is called :: + + def build(self): + """ + Call when all node are added. Apply all import flow for each node. + + :return: + """ + # Apply import link in adequacy + for (t, src, dest), var in self.importations.items(): + self.constraints[(t, dest)].SetCoefficient(var, 1) + +Which will add importation terms into all adequacy constraints to finalize equations. + +:code:`solve_batch` method resolve study scenario by scenario. It iterates over node and time, calls :code:`InputMapper`, then constructs problem with :code:`*Buidler`, and asks or-tools to solve problem. + +:code:`solve_lp` applies the last iteration over scenarios and it's the entry point for linear programming optimizer. After all scenarios are solved, results are mapped to :code:`Result` object. + +Or-tools, multiprocessing & pickle nightmare +............................................ + +Scenarios are distributed over cores by mutliprocessing library. :code:`solve_batch` is the compute method called by multiprocessing. Therefore all input data received by this method and output data returned must be serializable by pickle (used by multiprocessing). However, output has ortools :code:`Variable` object which is not serializable. + +Hadar doesn't need complet :code:`Variable` object. Indeed, it just want value solution found by or-tools. So we will help pickle by creating more simpler object :: + + class SerializableVariable(DTO): + def __init__(self, var: Variable): + self.val = var.solution_value() + + def solution_value(self): + return self.val + +Then specify cleary how to serialize object by implementing :code:`__reduce__` method :: + + # hadar.optimizer.lp.domain.LPConsumption + def __reduce__(self): + """ + Help pickle to serialize object, specially variable object + :return: (constructor, values...) + """ + return self.__class__, (self.quantity, SerializableVariable(self.variable), self.cost, self.name) + +It should work, but in fact not... I don't know why, when multiprocessing want to serialize returned data, or-tools :code:`Variable` are empty, and mutliprocessing failed. Nevermind, we just need to handle serialization oneself :: + + # hadar.optimizer.lp.solver._solve_batch + return pickle.dumps(variables) + +TODO ULM LPOptimizer + +Study +----- + +:code:`Study` is a *API object* I means it encapsulates all data needed to compute adequacy. It's the glue between workflow (or any other preprocessing) and optimizer. Study has an hierarchical structure of 3 levels : + +#. node level with node name as key. + +#. type elements level with *consumption*, *production* and *link* entries. Represented inside :code:`InputNode` object. + +#. element with index as key. Represented with :code:`Consumption`, :code:`Production`, :code:`Link` objects + +Most important attribute could be :code:`quantity` which represent quantity of power used in network. For link, is a transfert capacity. For production is a generation capacity. For consumption is a forced load to sustain. + +User can construct Study step by step thanks to a *fluent API* :: + + import hadar as hd + + study = hd.Study(['a', 'b'], horizon=3) \ + .add_on_node('a', data=hd.Consumption(cost=10 ** 6, quantity=[20, 20, 20], name='load')) \ + .add_on_node('a', data=hd.Production(cost=10, quantity=[30, 20, 10], name='prod')) \ + .add_on_node('b', data=hd.Consumption(cost=10 ** 6, quantity=[20, 20, 20], name='load')) \ + .add_on_node('b', data=hd.Production(cost=20, quantity=[10, 20, 30], name='prod')) \ + .add_link(src='a', dest='b', quantity=[10, 10, 10], cost=2) \ + .add_link(src='b', dest='a', quantity=[10, 10, 10], cost=2) \ + + + optim = hd.LPOptimizer() + res = optim.solve(study) + +To help user, quantity field is flexible: + +* lists are converted to numpy array + +* if user give a scalar, hadar extends to create (scenario, horizon) matrix size + +* if user give (horizon, ) matrix or list, hadar copies N time scenario to make (secnario, horizon) matrix size + +* if user give (scenario, 1) matrix or list, hadar copies N time timestep to make (scenario, horizon) matrix size + +Study includes also check mechanism to be sure: node existe, consumption is unique, etc. + +Result +------ + +:code:`Result` look like :code:`Study`, it has the same hierarchical structure, same element, just different naming to respect *Domain Driven Development* . Indeed, :code:`Result`is used as output computation, therefore we can reuse the same object. + +:code:`Result` souldn't be created by user. User will only read it. So, :code:`Result` has not fluent API to help construction. diff --git a/docs/source/architecture/workflow.rst b/docs/source/architecture/workflow.rst index fcdf053..ab18ae7 100644 --- a/docs/source/architecture/workflow.rst +++ b/docs/source/architecture/workflow.rst @@ -13,10 +13,10 @@ Are you sur wind will blow next week or sun will shines ? If not, you eolian or Of course, we can not predict futur with such precision. It's why we use *stochastic* computation. *Stochastic* means there are fluky behavior in the pyshics we want simulate. Simulation is quiet useless, if result is a unique result. - The best solution could to be to compute a *God function* which tell you for each input variation (solar production, line, consumptions) what is the adequacy result. Like that, Hadar has just to analyze function, its derivates etc to predict futur. But this *Got function* doesn't exist, we just have an algorithm which tell us adequacy according to one fixed set of input data. +The best solution could be to compute a *God function* which tell you for each input variation (solar production, line, consumptions) what is the adequacy result. Like that, Hadar has just to analyze function, its derivates, min, max, etc to predict futur. But this *God function* doesn't exist, we just have an algorithm which tell us adequacy according to one fixed set of input data. -It's why we use *Monte Carlo* algorithm. Monte Carlo run many *scenarios* to analyze many different behavior. Scenario with more consumption in cities, less solar production, less coat production or one line deleted due to crash. By this method we recreate *Got function* by sampling it with the Monte-Carlo method. +It's why we use *Monte Carlo* algorithm. Monte Carlo run many *scenarios* to analyze many different behavior. Scenario with more consumption in cities, less solar production, less coal production or one line deleted due to crash. By this method we recreate *God function* by sampling it with the Monte-Carlo method. TODO Monte Carlo sampling graphics @@ -55,7 +55,8 @@ For examples, you have many coal production. Each production plan has 10 generat In this example, if input is a constant time series of 1,000 MW, you will have as output 10 timeseries with random drop of 100 MW during 24 to 168 timestep. -**Create its own Stage** +Create its own Stage +******************** :code:`RepeatScenario`, :code:`Fault` and all other are build upon :code:`Stage` abstract class. A Stage is specified by its :code:`Plug` (we will see sooner) and a :code:`_process_timeline(self, timeline: pd.DataFrame) -> pd.DataFrame` to implement. :code:`timeline` variable inside method is the data passed thought pipeline to transform. @@ -86,7 +87,8 @@ For example, you have thousand of scenarios, your stage has to generate gaussian return scenario.drop(['mean', 'sigma'], axis=1) -**What's Plug ?** +What's Plug ? +************* You are already see :code:`FreePlug` and :code:`RestrictedPlug`, what's it ? diff --git a/docs/source/mathematics/linear-model.rst b/docs/source/mathematics/linear-model.rst index c5833f3..6fb21c6 100644 --- a/docs/source/mathematics/linear-model.rst +++ b/docs/source/mathematics/linear-model.rst @@ -1,4 +1,6 @@ +.. _linear-model: + Linear Model ============ -Hello world \ No newline at end of file +Hello world From 0871e6c2ecd2bc7a4192b6e5b1272f7227e964d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 20 May 2020 11:04:40 +0200 Subject: [PATCH 05/34] finish optimizer page. close #57 --- docs/source/architecture/optimizer.rst | 19 ++++++++++--------- hadar/optimizer/lp/mapper.py | 12 ++++++------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/source/architecture/optimizer.rst b/docs/source/architecture/optimizer.rst index e570725..abffe03 100644 --- a/docs/source/architecture/optimizer.rst +++ b/docs/source/architecture/optimizer.rst @@ -1,7 +1,7 @@ Optimizer ========= -Optimizer is the heart of Hadar. Behind it, there is adequacy solver. There are more than one optimizer : +Optimizer is the heart of Hadar. Behind it, there are : #. Input object called :code:`Study`. Output object called :code:`Result`. These two objects encapsulate all data needed to compute adequacy. @@ -31,9 +31,9 @@ LPOptimizer Before read this chapter, we kindly advertise you to read :ref:`Linear Model ` -:code:`LPOptimizer` translate data into optimization problem. Hadar algorithms focus only on modeling problem and uses `or-tools `_ to solve problem it. +:code:`LPOptimizer` translate data into optimization problem. Hadar algorithms focus only on modeling problem and uses `or-tools `_ to solve problem. -To achive modeling goal, :code:`LPOptimizer` is designed to receive :code:`Study` object, convert data into or-tools *Variables*. Then *Variables* are placed inside objective and constraint equations. Equations are solved by or-tools. Finally *Variables* are converted to Result object. +To achive modeling goal, :code:`LPOptimizer` is designed to receive :code:`Study` object, convert data into or-tools *Variables*. Then *Variables* are placed inside objective and constraint equations. Equations are solved by or-tools. Finally *Variables* are converted to :code:`Result` object. Analyze that in details. @@ -48,8 +48,8 @@ Therefore, :code:`InputMapper` roles are just to create new object with ortools LPLink(dest=l.dest, cost=float(l.cost), src=name, - quantity=l.quantity[scn][t], - variable=self.solver.NumVar(0, float(l.quantity[scn][t]), + quantity=l.quantity[scn, t], + variable=self.solver.NumVar(0, float(l.quantity[scn, t]), 'link on {} to {} at t={} for scn={}'.format(name, l.dest, t, scn) ) ) @@ -69,7 +69,7 @@ Line seems strange due to complex index. First we select good node *name*, then .. math:: Cons_{final} = Cons_{given} - Cons_{var} -Keep in mind that :math:`Cons_{var}` is the lost of load. So we need to substract it from initial consumption to get really consumption available. +Keep in mind that :math:`Cons_{var}` is the lost of load. So we need to substract it from initial consumption to get really consumption sustained. Modeler ******* @@ -139,9 +139,9 @@ Study #. node level with node name as key. -#. type elements level with *consumption*, *production* and *link* entries. Represented inside :code:`InputNode` object. +#. type elements level with *consumption*, *production* and *link* entries. Represented by :code:`InputNode` object. -#. element with index as key. Represented with :code:`Consumption`, :code:`Production`, :code:`Link` objects +#. element with index as key. Represented by :code:`Consumption`, :code:`Production`, :code:`Link` objects Most important attribute could be :code:`quantity` which represent quantity of power used in network. For link, is a transfert capacity. For production is a generation capacity. For consumption is a forced load to sustain. @@ -176,6 +176,7 @@ Study includes also check mechanism to be sure: node existe, consumption is uniq Result ------ -:code:`Result` look like :code:`Study`, it has the same hierarchical structure, same element, just different naming to respect *Domain Driven Development* . Indeed, :code:`Result`is used as output computation, therefore we can reuse the same object. +:code:`Result` look like :code:`Study`, it has the same hierarchical structure, same element, just different naming to respect *Domain Driven Development* . Indeed, :code:`Result` is used as output computation, therefore we can reuse the same object. +:code:`Result` is the glue between optimizer and analyzer (or any else postprocessing). :code:`Result` souldn't be created by user. User will only read it. So, :code:`Result` has not fluent API to help construction. diff --git a/hadar/optimizer/lp/mapper.py b/hadar/optimizer/lp/mapper.py index c68b601..746ada2 100644 --- a/hadar/optimizer/lp/mapper.py +++ b/hadar/optimizer/lp/mapper.py @@ -36,16 +36,16 @@ def get_var(self, name: str, t: int, scn: int) -> LPNode: :param scn: scenario index :return: LPNode according to node name at t in study """ - consumptions = [LPConsumption(name=c.name, cost=float(c.cost), quantity=c.quantity[scn][t], - variable=self.solver.NumVar(0, float(c.quantity[scn][t]), name='lol {} on {} at t={} for scn={}'.format(c.name, name, t, scn))) + consumptions = [LPConsumption(name=c.name, cost=float(c.cost), quantity=c.quantity[scn, t], + variable=self.solver.NumVar(0, float(c.quantity[scn, t]), name='lol {} on {} at t={} for scn={}'.format(c.name, name, t, scn))) for c in self.study.nodes[name].consumptions] - productions = [LPProduction(name=p.name, cost=float(p.cost), quantity=p.quantity[scn][t], - variable=self.solver.NumVar(0, float(p.quantity[scn][t]), 'prod {} on {} at t={} for scn={}'.format(p.name, name, t, scn))) + productions = [LPProduction(name=p.name, cost=float(p.cost), quantity=p.quantity[scn, t], + variable=self.solver.NumVar(0, float(p.quantity[scn, t]), 'prod {} on {} at t={} for scn={}'.format(p.name, name, t, scn))) for p in self.study.nodes[name].productions] - links = [LPLink(dest=l.dest, cost=float(l.cost), src=name, quantity=l.quantity[scn][t], - variable=self.solver.NumVar(0, float(l.quantity[scn][t]), 'link on {} to {} at t={} for scn={}'.format(name, l.dest, t, scn))) + links = [LPLink(dest=l.dest, cost=float(l.cost), src=name, quantity=l.quantity[scn, t], + variable=self.solver.NumVar(0, float(l.quantity[scn, t]), 'link on {} to {} at t={} for scn={}'.format(name, l.dest, t, scn))) for l in self.study.nodes[name].links] return LPNode(consumptions=consumptions, productions=productions, links=links) From 10370f92913b84c21859e95eea05fdc6c1b8255f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 20 May 2020 17:39:46 +0200 Subject: [PATCH 06/34] start analyzer page #58. finish viewer page close #59 --- docs/source/architecture/analyzer.rst | 194 ++++++++++++++++++++++++- docs/source/architecture/optimizer.rst | 7 +- docs/source/architecture/viewer.rst | 5 +- 3 files changed, 200 insertions(+), 6 deletions(-) diff --git a/docs/source/architecture/analyzer.rst b/docs/source/architecture/analyzer.rst index ec1e0c5..bf172fa 100644 --- a/docs/source/architecture/analyzer.rst +++ b/docs/source/architecture/analyzer.rst @@ -1,4 +1,196 @@ Analyzer ======== -Hello world \ No newline at end of file +Analyzer containts tools to help analyze study result. Today, there is only :code:`ResultAnalyzer`. For a high abstraction and to be agnostic about technology, Hadar uses objects as glue for optimizer. Objects are cool, but are too complicated to manipulated for data analysis. + +Therefore :code:`ResultAnalyzer` was two features level: + +* **high level ** user asks directly to compute global cost and global remain capacity, etc. + +* **low level ** user asks *raw* data represented inside pandas Dataframe. + +Before speaking about this features, let's see how data are transformed. + +Flatten Data +--------- + +As said above, object is nice to encapsulate data and represent it into agnostic form. Objects can be serialized into JSON or something else to be used by another software maybe in another language. But keep object to analyze data is awful. + +Python has a very efficent tool for data analysis : pandas. Therefore challange is to transform object into pandas Dataframe. Solution used is to flatten data to fill into table. + +Consumption +*********** + +For example with consumption. Data into :code:`Study` is cost and asked quantity. And in :code:`Result` it's cost (same) and given quantity. This tuple *(cost, asked, given)* is present for each node, each consumption attached on this node, each sceanario and each timestep. If we want to flatten data, we need to fill this table + ++------+------+------+------+------+------+------+ +| cost | asked| given| node | name | scn | t | ++------+------+------+------+------+------+------+ +| 10 | 5 | 5 | fr | load | 0 | 0 | ++------+------+------+------+------+------+------+ +| 10 | 7 | 7 | fr | load | 0 | 1 | ++------+------+------+------+------+------+------+ +| 10 | 7 | 5 | fr | load | 1 | 0 | ++------+------+------+------+------+------+------+ +| 10 | 6 | 6 | fr | load | 1 | 1 | ++------+------+------+------+------+------+------+ +| ... | ... | ... | ... | ... | .. | ... | ++------+------+------+------+------+------+------+ + +It is a purpose of :code:`_build_consumption(study: Study, result: Result) -> pd.Dataframe` to build this array + +Production +********** + +Production follow the same pattern. However, they don't have *asked* and *given* but *availaible* and *used* quantity. Therefore table looks like + ++------+------+------+------+------+------+------+ +| cost | avail| used | node | name | scn | t | ++------+------+------+------+------+------+------+ +| 10 | 100 | 21 | fr | coal | 0 | 0 | ++------+------+------+------+------+------+------+ +| 10 | 100 | 36 | fr | coal | 0 | 1 | ++------+------+------+------+------+------+------+ +| 10 | 100 | 12 | fr | coal | 1 | 0 | ++------+------+------+------+------+------+------+ +| 10 | 100 | 81 | fr | coal | 1 | 1 | ++------+------+------+------+------+------+------+ +| ... | ... | ... | ... | ... | .. | ... | ++------+------+------+------+------+------+------+ + +It's done by :code:`_build_production(study: Study, result: Result) -> pd.Dataframe` method. + + +Link +**** + +Link follow the same pattern. Hierarchical structur naming change. There are not *node* and *name* but *source* and *destination*. Therefore table looks like. + ++------+------+------+------+------+------+------+ +| cost | avail| used | src | dest | scn | t | ++------+------+------+------+------+------+------+ +| 10 | 100 | 21 | fr | uk | 0 | 0 | ++------+------+------+------+------+------+------+ +| 10 | 100 | 36 | fr | uk | 0 | 1 | ++------+------+------+------+------+------+------+ +| 10 | 100 | 12 | fr | uk | 1 | 0 | ++------+------+------+------+------+------+------+ +| 10 | 100 | 81 | fr | uk | 1 | 1 | ++------+------+------+------+------+------+------+ +| ... | ... | ... | ... | ... | .. | ... | ++------+------+------+------+------+------+------+ + +It's done by :code:`_build_link(study: Study, result: Result) -> pd.Dataframe` method. + + +Low level analysis +------------------ + +When you observe flat data, there are two kind of data. *Content* like cost, given, asked and *index* describes by node, name, scn, t. + +Low level API analysis provided by :code:`ResultAnalyzer` lets user to + +#. Organize index level, for exemple set time, then scenario, then name, then node. +#. Filter index, for example just time from 10 to 150, just 'fr' node, etc + +User can said, *I want 'fr' node productions for first scenario and 50 to 60 time.* In this cas :code:`ResultAnalyzer` will return + ++------+------+------+------+------+ +| | | used | cost | avail| ++------+------+------+------+------+ +| t | name | 21 | fr | uk | ++------+------+------+------+------+ +| 50 | oil | 36 | fr | uk | ++ +------+------+------+------+ +| | coal | 12 | fr | uk | ++------+------+------+------+------+ +| 60 | oil | 81 | fr | uk | ++ +------+------+------+------+ +| ... | ... | ... | ... | ... | ++------+------+------+------+------+ + +If first index like node and scenario has only one element, there are removed. + +This result can be done by this line of code. :: + + agg = hd.ResultAnalyzer(study, result) + df = agg.agg_prod(agg.inode['fr'], agg.scn[0], agg.itime[50:60], agg.iname) + +As you can see, user select index hierarchy by sorting :code:`agg.ixxx` . Then user specify filter by :code:`agg.ixxx[yy]`. + +Behind this mechanism, there are :code:`Index` objects. As you can see directly in the code :: + + @property + def inode(self) -> NodeIndex: + """ + Get a node index to specify node slice to aggregate consumption or production. + + :return: new instance of NodeIndex() + """ + return NodeIndex() + + +Each kind of index has to inherents from this class. :code:`Index` object encapsulate column metadata to use and range of filtered elements to keep (accessible by overriding :code:`__getitem__` method). Then, Hadar create child class with good parameters : :code:`NameIndex` , :code:`NodeIndex` , :code:`ScnIndex` , :code:`TimeIndex` , :code:`SrcIndex` , :code:`DestIndex` . For example you can find below :code:`NodeIndex` impementation :: + + class NodeIndex(Index[str]): + """Index implementation to filter nodes""" + def __init__(self): + Index.__init__(self, column='node') + + +TODO index ULM + +Index instanciation are completly hidden for user. It created inplicitely when user types :code:`agg.ixxx[yy]`. Then, hadar will + +#. check that mandatories indexes are given with :code:`_assert_index` method. + +#. pivot table to recreate indexing according to filter and sort asked with :code:`_pivot` method. + +#. remove one-size top-level index with :code:`_remove_useless_index_level` method. + +As you can see, low level analyze provides efficient method to extract data from adequacy study result. However data returned remains a kind of *roots* and is not ready to use. + +High Level Analysis +------------------- + +Unlike low level, high level focus on provides ready to use data. Unlike low level, features should be designed one by one for business purpose. Today we have 2 features: + +* :code:`get_cost(self, node: str) -> np.ndarray:` method which according to node selected returns a matrix (scenario, horizon) shape with summerize cost. + +* :code:`get_balance(self, node: str) -> np.ndarray` method which according to node selected returns a matrix (scenario, horizon) shape with exchange balance (i.e. sum of exportation minus sum of importation) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +j diff --git a/docs/source/architecture/optimizer.rst b/docs/source/architecture/optimizer.rst index abffe03..3b49b4f 100644 --- a/docs/source/architecture/optimizer.rst +++ b/docs/source/architecture/optimizer.rst @@ -78,12 +78,12 @@ Hadar has to build problem optimization. These algorithms are encapsulated insid :code:`ObjectiveBuilder` get node by its method :code:`add_node`. Then for all productions, consumptions, links, it adds :math:`variable * cost` into objective equation. -:code:`AdequacyBuilder` is a bit more tricky. For each node, it will create a new adequacy contraint equation (c.f. :ref:`Linear Model `). Coefficients, here are 1 or -1 depending of *inner* power or *outer* power. You also have see these lines :: +:code:`AdequacyBuilder` is a bit more tricky. For each node, it will create a new adequacy contraint equation (c.f. :ref:`Linear Model `). Coefficients, here are 1 or -1 depending of *inner* power or *outer* power. Have you seen these line ? :: self.constraints[(t, link.src)].SetCoefficient(link.variable, -1) # Export from src self.importations[(t, link.src, link.dest)] = link.variable # Import to dest -Hadar has to set power importation to *dest* node equation. But maybe this node is not yet setup and this constraint equation doesn't exist yet. Therefore he has to store all constraint equations and all link capacities. And at the end :code:`build()` is called :: +Hadar has to set power importation to *dest* node equation. But maybe this node is not yet setup and this constraint equation doesn't exist yet. Therefore he has to store all constraint equations and all link capacities. And at the end :code:`build()` is called, which will add importation terms into all adequacy constraints to finalize equations. :: def build(self): """ @@ -95,9 +95,8 @@ Hadar has to set power importation to *dest* node equation. But maybe this node for (t, src, dest), var in self.importations.items(): self.constraints[(t, dest)].SetCoefficient(var, 1) -Which will add importation terms into all adequacy constraints to finalize equations. -:code:`solve_batch` method resolve study scenario by scenario. It iterates over node and time, calls :code:`InputMapper`, then constructs problem with :code:`*Buidler`, and asks or-tools to solve problem. +:code:`solve_batch` method resolve study for one scenario. It iterates over node and time, calls :code:`InputMapper`, then constructs problem with :code:`*Buidler`, and asks or-tools to solve problem. :code:`solve_lp` applies the last iteration over scenarios and it's the entry point for linear programming optimizer. After all scenarios are solved, results are mapped to :code:`Result` object. diff --git a/docs/source/architecture/viewer.rst b/docs/source/architecture/viewer.rst index 1ec93c9..ecf59a8 100644 --- a/docs/source/architecture/viewer.rst +++ b/docs/source/architecture/viewer.rst @@ -1,5 +1,8 @@ Viewer ====== +Even with the highest level analyzer features. Data remains simple matrix or tables. Viewer is the end of Hadar framework, it will create amazing plot to bring most valuable data for humain analysis. -Hello world \ No newline at end of file +Viewer use Analyzer API to build plots. It like an extract layer to convert numeric result to visual result. + +There are many viewers, all inherent from :code:`ABCPlotting` abstract class. Available plots are identical between viewers, only technologies used to build these plots change. Today, we have one type of plotting :code:`HTMLPlotting` which is coded upon plotly library to build html interactive plots. From 6fbb782e339e92d606e0e5f66cc52f0bf50cb791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Mon, 25 May 2020 12:26:14 +0200 Subject: [PATCH 07/34] close #56. Review all code. Fix error in Fault Stage --- .../_static/architecture/workflow/fault.png | Bin 0 -> 86332 bytes docs/source/architecture/analyzer.rst | 30 +++++----- docs/source/architecture/optimizer.rst | 36 ++++++------ docs/source/architecture/overview.rst | 21 ++++--- docs/source/architecture/viewer.rst | 2 +- docs/source/architecture/workflow.rst | 53 ++++++++++++------ hadar/workflow/pipeline.py | 3 +- 7 files changed, 82 insertions(+), 63 deletions(-) create mode 100644 docs/source/_static/architecture/workflow/fault.png diff --git a/docs/source/_static/architecture/workflow/fault.png b/docs/source/_static/architecture/workflow/fault.png new file mode 100644 index 0000000000000000000000000000000000000000..77d05798d533007541ad7d66b6920f321bd248f5 GIT binary patch literal 86332 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

u$ZJteP*(!mkwnI))VR&ywZ9r$ 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

e)!7?DLdVoj=-gL;8g;2aVN4VD<5!w0 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 pd.Dataframe` to build this array +It is the purpose of :code:`_build_consumption(study: Study, result: Result) -> pd.Dataframe` to build this array Production ********** -Production follow the same pattern. However, they don't have *asked* and *given* but *availaible* and *used* quantity. Therefore table looks like +Production follow the same pattern. However, they don't have *asked* and *given* but *available* and *used* quantity. Therefore table looks like +------+------+------+------+------+------+------+ | cost | avail| used | node | name | scn | t | @@ -64,7 +64,7 @@ It's done by :code:`_build_production(study: Study, result: Result) -> pd.Datafr Link **** -Link follow the same pattern. Hierarchical structur naming change. There are not *node* and *name* but *source* and *destination*. Therefore table looks like. +Link follow the same pattern. Hierarchical structure naming change. There are not *node* and *name* but *source* and *destination*. Therefore table looks like. +------+------+------+------+------+------+------+ | cost | avail| used | src | dest | scn | t | @@ -90,10 +90,10 @@ When you observe flat data, there are two kind of data. *Content* like cost, giv Low level API analysis provided by :code:`ResultAnalyzer` lets user to -#. Organize index level, for exemple set time, then scenario, then name, then node. +#. Organize index level, for example set time, then scenario, then name, then node. #. Filter index, for example just time from 10 to 150, just 'fr' node, etc -User can said, *I want 'fr' node productions for first scenario and 50 to 60 time.* In this cas :code:`ResultAnalyzer` will return +User can said, *I want 'fr' node productions for first scenario to 50 until 60 timestep.* In this cas :code:`ResultAnalyzer` will return +------+------+------+------+------+ | | | used | cost | avail| @@ -130,7 +130,7 @@ Behind this mechanism, there are :code:`Index` objects. As you can see directly return NodeIndex() -Each kind of index has to inherents from this class. :code:`Index` object encapsulate column metadata to use and range of filtered elements to keep (accessible by overriding :code:`__getitem__` method). Then, Hadar create child class with good parameters : :code:`NameIndex` , :code:`NodeIndex` , :code:`ScnIndex` , :code:`TimeIndex` , :code:`SrcIndex` , :code:`DestIndex` . For example you can find below :code:`NodeIndex` impementation :: +Each kind of index has to inherent from this class. :code:`Index` object encapsulate column metadata to use and range of filtered elements to keep (accessible by overriding :code:`__getitem__` method). Then, Hadar has child classes with good parameters : :code:`NameIndex` , :code:`NodeIndex` , :code:`ScnIndex` , :code:`TimeIndex` , :code:`SrcIndex` , :code:`DestIndex` . For example you can find below :code:`NodeIndex` implementation :: class NodeIndex(Index[str]): """Index implementation to filter nodes""" @@ -140,24 +140,24 @@ Each kind of index has to inherents from this class. :code:`Index` object encaps TODO index ULM -Index instanciation are completly hidden for user. It created inplicitely when user types :code:`agg.ixxx[yy]`. Then, hadar will +Index instantiation are completely hidden for user. It created implicitly when user types :code:`agg.ixxx[yy]`. Then, hadar will -#. check that mandatories indexes are given with :code:`_assert_index` method. +#. check that mandatory indexes are given with :code:`_assert_index` method. #. pivot table to recreate indexing according to filter and sort asked with :code:`_pivot` method. #. remove one-size top-level index with :code:`_remove_useless_index_level` method. -As you can see, low level analyze provides efficient method to extract data from adequacy study result. However data returned remains a kind of *roots* and is not ready to use. +As you can see, low level analyze provides efficient method to extract data from adequacy study result. However data returned remains a kind of *roots* and is not ready for business purposes. High Level Analysis ------------------- Unlike low level, high level focus on provides ready to use data. Unlike low level, features should be designed one by one for business purpose. Today we have 2 features: -* :code:`get_cost(self, node: str) -> np.ndarray:` method which according to node selected returns a matrix (scenario, horizon) shape with summerize cost. +* :code:`get_cost(self, node: str) -> np.ndarray:` method which according to node given returns a matrix (scenario, horizon) shape with summarize cost. -* :code:`get_balance(self, node: str) -> np.ndarray` method which according to node selected returns a matrix (scenario, horizon) shape with exchange balance (i.e. sum of exportation minus sum of importation) +* :code:`get_balance(self, node: str) -> np.ndarray` method which according to node given returns a matrix (scenario, horizon) shape with exchange balance (i.e. sum of exportation minus sum of importation) diff --git a/docs/source/architecture/optimizer.rst b/docs/source/architecture/optimizer.rst index 3b49b4f..daa48a3 100644 --- a/docs/source/architecture/optimizer.rst +++ b/docs/source/architecture/optimizer.rst @@ -5,9 +5,9 @@ Optimizer is the heart of Hadar. Behind it, there are : #. Input object called :code:`Study`. Output object called :code:`Result`. These two objects encapsulate all data needed to compute adequacy. -#. Many optimizers. User can choose in which will solve study. +#. Many optimizers. User can chose which will solve study. -Therefore :code:`Optimizer` is an abstract class builded on *Strategy* pattern. User can select optimizer or create their own by implemented :code:`Optimizer.solve(study: Study) -> Result` +Therefore :code:`Optimizer` is an abstract class build on *Strategy* pattern. User can select optimizer or create their own by implemented :code:`Optimizer.solve(study: Study) -> Result` Today, two optimizers are present :code:`LPOptimizer` and :code:`RemoteOptimizer` @@ -18,7 +18,7 @@ RemoteOptimizer Let's start by the simplest. :code:`RemoteOptimizer` is a client to hadar server. As you may know Hadar exist like a python library, but has also a tiny project to package hadar inside web server. You can find more details on this server in this `repository. `_ -Client implements :code:`Optimizer` interface. Like that, to deploy compute on a datacenter, only one line of code changes. :: +Client implements :code:`Optimizer` interface. Like that, to deploy compute on a data-center, only one line of code changes. :: import hadar as hd # Normal : optim = hd.LPOptimizer() @@ -33,14 +33,14 @@ Before read this chapter, we kindly advertise you to read :ref:`Linear Model

  • `_ to solve problem. -To achive modeling goal, :code:`LPOptimizer` is designed to receive :code:`Study` object, convert data into or-tools *Variables*. Then *Variables* are placed inside objective and constraint equations. Equations are solved by or-tools. Finally *Variables* are converted to :code:`Result` object. +To achieve modeling goal, :code:`LPOptimizer` is designed to receive :code:`Study` object, convert data into or-tools :code:`Variables`. Then :code:`Variables` are placed inside objective and constraint equations. Equations are solved by or-tools. Finally :code:`Variables` are converted to :code:`Result` object. Analyze that in details. InputMapper ************ -If you look in code, you will see two domain. One at :code:`hadar.optimizer.[input/output]` and another at :code:`hadar.optimizer.lp.domain` . If you look carefully it seems the same :code:`Consumption` , :code:`OutputConsumption` in one hand, :code:`LPConsumption` in other hand. The only change is a new attribute in :code:`LP*` called :code:`variable` . Variables are the parameters of the problem. It's what or-tools has to find, i.e. power used for production, capacity used for border and lost of load for consumption. +If you look in code, you will see two domains. One at :code:`hadar.optimizer.[input/output]` and another at :code:`hadar.optimizer.lp.domain` . If you look carefully it seems the same :code:`Consumption` , :code:`OutputConsumption` in one hand, :code:`LPConsumption` in other hand. The only change is a new attribute in :code:`LP*` called :code:`variable` . Variables are the parameters of the problem. It's what or-tools has to find, i.e. power used for production, capacity used for border and lost of load for consumption. Therefore, :code:`InputMapper` roles are just to create new object with ortools Variables initialized, like we can see in this code snippet. :: @@ -57,33 +57,33 @@ Therefore, :code:`InputMapper` roles are just to create new object with ortools OutputMapper ************ -At the end, :code:`OutputMapper` does the reverse thing. :code:`LP*` objects have computed variables. We need to extract result find by or-tool to :code:`Result` object. +At the end, :code:`OutputMapper` does the reverse thing. :code:`LP*` objects have computed :code:`Variables`. We need to extract result find by or-tool to :code:`Result` object. Mapping of :code:`LPProduction` and :code:`LPLink` are straight forward. I propose you to look at :code:`LPConsumption` code :: self.nodes[name].consumptions[i].quantity[scn, t] = vars.consumptions[i].quantity - vars.consumptions[i].variable.solution_value() -Line seems strange due to complex index. First we select good node *name*, then good consumption *i*, then good scenario *scn* and at this end good timestep *t*. Rewritting without index, this line means : +Line seems strange due to complex indexing. First we select good node *name*, then good consumption *i*, then good scenario *scn* and at the end good timestep *t*. Rewriting without index, this line means : .. math:: Cons_{final} = Cons_{given} - Cons_{var} -Keep in mind that :math:`Cons_{var}` is the lost of load. So we need to substract it from initial consumption to get really consumption sustained. +Keep in mind that :math:`Cons_{var}` is the lost of load. So we need to subtract it from initial consumption to get really consumption sustained. Modeler ******* Hadar has to build problem optimization. These algorithms are encapsulated inside two builders. -:code:`ObjectiveBuilder` get node by its method :code:`add_node`. Then for all productions, consumptions, links, it adds :math:`variable * cost` into objective equation. +:code:`ObjectiveBuilder` takes node by its method :code:`add_node`. Then for all productions, consumptions, links, it adds :math:`variable * cost` into objective equation. -:code:`AdequacyBuilder` is a bit more tricky. For each node, it will create a new adequacy contraint equation (c.f. :ref:`Linear Model `). Coefficients, here are 1 or -1 depending of *inner* power or *outer* power. Have you seen these line ? :: +:code:`AdequacyBuilder` is a bit more tricky. For each node, it will create a new adequacy constraint equation (c.f. :ref:`Linear Model `). Coefficients, here are 1 or -1 depending of *inner* power or *outer* power. Have you seen these line ? :: self.constraints[(t, link.src)].SetCoefficient(link.variable, -1) # Export from src self.importations[(t, link.src, link.dest)] = link.variable # Import to dest -Hadar has to set power importation to *dest* node equation. But maybe this node is not yet setup and this constraint equation doesn't exist yet. Therefore he has to store all constraint equations and all link capacities. And at the end :code:`build()` is called, which will add importation terms into all adequacy constraints to finalize equations. :: +Hadar has to set power importation to *dest* node equation. But maybe this node is not yet setup and its constraint equation doesn't exist yet. Therefore it has to store all constraint equations and all link capacities. And at the end :code:`build()` is called, which will add importation terms into all adequacy constraints to finalize equations. :: def build(self): """ @@ -105,7 +105,7 @@ Or-tools, multiprocessing & pickle nightmare Scenarios are distributed over cores by mutliprocessing library. :code:`solve_batch` is the compute method called by multiprocessing. Therefore all input data received by this method and output data returned must be serializable by pickle (used by multiprocessing). However, output has ortools :code:`Variable` object which is not serializable. -Hadar doesn't need complet :code:`Variable` object. Indeed, it just want value solution found by or-tools. So we will help pickle by creating more simpler object :: +Hadar doesn't need complete :code:`Variable` object. Indeed, it just want value solution found by or-tools. So we will help pickle by creating more simpler object, we carefully recreate same API :code:`solution_value()` to be compliant with downstream code :: class SerializableVariable(DTO): def __init__(self, var: Variable): @@ -114,7 +114,7 @@ Hadar doesn't need complet :code:`Variable` object. Indeed, it just want value s def solution_value(self): return self.val -Then specify cleary how to serialize object by implementing :code:`__reduce__` method :: +Then specify clearly how to serialize object by implementing :code:`__reduce__` method :: # hadar.optimizer.lp.domain.LPConsumption def __reduce__(self): @@ -124,7 +124,7 @@ Then specify cleary how to serialize object by implementing :code:`__reduce__` m """ return self.__class__, (self.quantity, SerializableVariable(self.variable), self.cost, self.name) -It should work, but in fact not... I don't know why, when multiprocessing want to serialize returned data, or-tools :code:`Variable` are empty, and mutliprocessing failed. Nevermind, we just need to handle serialization oneself :: +It should work, but in fact not... I don't know why, when multiprocessing want to serialize returned data, or-tools :code:`Variable` are empty, and mutliprocessing failed. Whatever, we just need to handle serialization oneself :: # hadar.optimizer.lp.solver._solve_batch return pickle.dumps(variables) @@ -166,16 +166,16 @@ To help user, quantity field is flexible: * if user give a scalar, hadar extends to create (scenario, horizon) matrix size -* if user give (horizon, ) matrix or list, hadar copies N time scenario to make (secnario, horizon) matrix size +* if user give (horizon, ) matrix or list, hadar copies N time scenario to make (scenario, horizon) matrix size * if user give (scenario, 1) matrix or list, hadar copies N time timestep to make (scenario, horizon) matrix size -Study includes also check mechanism to be sure: node existe, consumption is unique, etc. +Study includes also check mechanism to be sure: node exist, consumption is unique, etc. Result ------ -:code:`Result` look like :code:`Study`, it has the same hierarchical structure, same element, just different naming to respect *Domain Driven Development* . Indeed, :code:`Result` is used as output computation, therefore we can reuse the same object. +:code:`Result` look like :code:`Study`, it has the same hierarchical structure, same element, just different naming to respect *Domain Driven Development* . Indeed, :code:`Result` is used as output computation, therefore we can't reuse the same object. :code:`Result` is the glue between optimizer and analyzer (or any else postprocessing). -:code:`Result` souldn't be created by user. User will only read it. So, :code:`Result` has not fluent API to help construction. +:code:`Result` shouldn't be created by user. User will only read it. So, :code:`Result` has not fluent API to help construction. diff --git a/docs/source/architecture/overview.rst b/docs/source/architecture/overview.rst index 2df238f..9618217 100644 --- a/docs/source/architecture/overview.rst +++ b/docs/source/architecture/overview.rst @@ -4,8 +4,10 @@ Overview Welcome to the Hadar Architecture Documentation. Hadar purpose is to be *an adequacy library for everyone*. -Term *everyone* is important, Hadar must be such easy that everyone can use it. -And Hadar must be such flexible that everyone business can use it or customize it. + +#. Term *everyone* is important, Hadar must be such easy that everyone can use it. + +#. And Hadar must be such flexible that everyone business can use it or customize it. **Why these goals ?** @@ -14,7 +16,7 @@ Before scikit-learn, people who want to develop machine learning have to had str Some *ready to go* codes existed but were not easy to use and flexible. Scikit-learn release the power of machine learning by abstract complex algorithms into very straight forward API. -It was designed like a toolbox to handle full machine learning framework, where user can juste assemble scikit-learn component or build their own. +It was designed like a toolbox to handle full machine learning framework, where user can just assemble scikit-learn component or build their own. Hadar want to be the next scikit-learn for adequacy. Hadar has to be easy to use and flexible, which if we translate into architecture terms become **high abstraction level** and **independent modules**. @@ -37,7 +39,7 @@ To reach this constraint, we split Hadar into 4 main modules which can be use to - **viewer** analyzer output will be numpy matrix or pandas Dataframe, it great but not enough to analyze result. Viewer uses the analyzer feature and API to generate graphics from study data. -As said, these modules can be used together to handle complet adequacy study lifecycle or used seperately. +As said, these modules can be used together to handle complete adequacy study lifecycle or used apart. TODO graph architecture module @@ -48,8 +50,7 @@ High Abstraction API Each above modules are like a tiny independent libraries. Therefore each module has a high level API. High abstraction, is a bit confuse to handle and benchmark. For us a high abstraction is when user doesn't need to know mathematics or technicals stuffs when he uses library. -Scikit-learn is the best example of high abstraction level API. For example, if we just want to start a complet SVM research -:: +Scikit-learn is the best example of high abstraction level API. For example, if we just want to start a complete SVM research :: from sklean.svm import SVR svm = SVR() @@ -57,11 +58,10 @@ Scikit-learn is the best example of high abstraction level API. For example, if y_pred = svm.predict(X_test) -How many people using this features know that scikit-learn tries to project data into higher space to find a linear regression inside. And to accelerate computation, it uses mathematics feature called *a kernel trick* because problem respect strict requirements ? Perhaps just few people and it's all the beauty of an high level API, it hidden background gear. +How many people using this feature know that scikit-learn tries to project data into higher space to find a linear regression inside. And to accelerate computation, it uses mathematics a feature called *a kernel trick* because problem respect strict requirements ? Perhaps just few people and it's all the beauty of an high level API, it hidden background gear. -Hadar tries to keep this high abstraction features. Look at the *Get Started* example -:: +Hadar tries to keep this high abstraction features. Look at the *Get Started* example :: import hadar as hd @@ -88,5 +88,4 @@ Now goals are fixed, we can go deeper into specific module documentation. All architecture focuses on : High Abstraction and Independent module. You can also read the best practices guide to understand more development choice made in Hadar. -Let't start code explanation. - +Let't start code explanation. \ No newline at end of file diff --git a/docs/source/architecture/viewer.rst b/docs/source/architecture/viewer.rst index ecf59a8..cd22ab2 100644 --- a/docs/source/architecture/viewer.rst +++ b/docs/source/architecture/viewer.rst @@ -1,7 +1,7 @@ Viewer ====== -Even with the highest level analyzer features. Data remains simple matrix or tables. Viewer is the end of Hadar framework, it will create amazing plot to bring most valuable data for humain analysis. +Even with the highest level analyzer features. Data remains simple matrix or tables. Viewer is the end of Hadar framework, it will create amazing plot to bring most valuable data for human analysis. Viewer use Analyzer API to build plots. It like an extract layer to convert numeric result to visual result. diff --git a/docs/source/architecture/workflow.rst b/docs/source/architecture/workflow.rst index ab18ae7..3d05749 100644 --- a/docs/source/architecture/workflow.rst +++ b/docs/source/architecture/workflow.rst @@ -5,15 +5,15 @@ What is a stochastic study ? ---------------------------- -Workflow is the preprocessing module for Hadar. It's a toolbox for create pipelines to transform data for solver. +Workflow is the preprocessing module for Hadar. It's a toolbox to create pipelines to transform data for optimizer. -When you want to simulate a network adequacy, you can perform a *deterministic* computation. That means you believe you won't have too much fluky behavior in the futur. If you perform adequacy for the next hour or day, it's a good hypothesis. But if you simulate network for the next week, month or year, it's sound curious. +When you want to simulate a network adequacy, you can perform a *deterministic* computation. That means you believe you won't have too much fluky behavior in the future. If you perform adequacy for the next hour or day, it's a good hypothesis. But if you simulate network for the next week, month or year, it's sound curious. Are you sur wind will blow next week or sun will shines ? If not, you eolian or solar production could change. Can you warrant that no failure will occur on your network next month or next year ? -Of course, we can not predict futur with such precision. It's why we use *stochastic* computation. *Stochastic* means there are fluky behavior in the pyshics we want simulate. Simulation is quiet useless, if result is a unique result. +Of course, we can not predict future with such precision. It's why we use *stochastic* computation. *Stochastic* means there are fluky behavior in the physics we want simulate. Simulation is quiet useless, if result is a unique result. -The best solution could be to compute a *God function* which tell you for each input variation (solar production, line, consumptions) what is the adequacy result. Like that, Hadar has just to analyze function, its derivates, min, max, etc to predict futur. But this *God function* doesn't exist, we just have an algorithm which tell us adequacy according to one fixed set of input data. +The best solution could be to compute a *God function* which tell you for each input variation (solar production, line, consumptions) what is the adequacy result. Like that, Hadar has just to analyze function, its derivatives, min, max, etc to predict future. But this *God function* doesn't exist, we just have an algorithm which tell us adequacy according to one fixed set of input data. It's why we use *Monte Carlo* algorithm. Monte Carlo run many *scenarios* to analyze many different behavior. Scenario with more consumption in cities, less solar production, less coal production or one line deleted due to crash. By this method we recreate *God function* by sampling it with the Monte-Carlo method. @@ -24,36 +24,57 @@ TODO Monte Carlo sampling graphics Workflow will help user to generate these scenarios and sample them to create a stochastic study. -The main issue when we want to *help people generating their scenarios* is they are as many generating process than user. +The main issue when we want to *help people generating their scenarios* is they are as many generating process as user. Therefore workflow is build upon a Stage and Pipeline Architecture. Stages, Pipelines & Plug ------------------------ -Stage is an atomic process applied on data. In workflow, data is a pandas Dataframe with this form +Stage is an atomic process applied on data. In workflow, data is a pandas Dataframe. Index is time. First column level is for scenario, second is for data (it could be anything like mean, max, sigma, ...). Dataframe is represented below: -TODO stage data ++----+-------------------------+-------------------------+ +| | scn 1 | scn n ... | ++----+------+-----+-----+------+------+-----+-----+------+ +| t | mean | max | min | ... | mean | max | min | ... | ++----+------+-----+-----+------+------+-----+-----+------+ +| 0 | 10 | 20 | 2 | ... | 15 | 22 | 8 | ... | ++----+------+-----+-----+------+------+-----+-----+------+ +| 1 | 12 | 20 | 2 | ... | 14 | 22 | 8 | ... | ++----+------+-----+-----+------+------+-----+-----+------+ +|... | ... | ... | ... | ... | ... | ... | ... | ... | ++----+------+-----+-----+------+------+-----+-----+------+ A stage will perform compute to this Dataframe. As you assume it, stages can be linked together to create pipeline. Hadar has its own stages very generic, each user can build these stages and create these pipelines. -For examples, you have many coal production. Each production plan has 10 generators of 100 MW. That means a coal plan production are 1,000 MW of power. You know that sometime, some generator crash or need shutdown for maintenance. With Hadar you can create a pipeline to generate these fault scenarios. :: +For examples, you have many coal production. Each production plan has 10 generators of 100 MW. That means a coal plan production has 1,000 MW of power. You know that sometime, some generators crash or need shutdown for maintenance. With Hadar you can create a pipeline to generate these fault scenarios. :: # In this example, one timestep = one hour import hadar as hd + import numpy as np + import hadar as hd + import matplotlib.pyplot as plt + + # coal production over 8 weeks with hourly step + coal = pd.DataFrame({'quantity': np.ones(8 * 168) * 1000}) # Copy scenarios ten times copy = hd.RepeatScenario(n=10) - # Apply on each scenario random fault, such as power drop is 100 MW, there is 0.01% chance of failure each hour - # if failture, it's a least for the whole day and until next week. - fault = hd.Fault(loss=100, occur_freq=0.0001, downtime_min=24, downtime_max=168) + # Apply on each scenario random fault, such as power drop is 100 MW, there is 0.1% chance of failure each hour + # if failure, it's a least for the whole day and until next week. + fault = hd.Fault(loss=100, occur_freq=0.001, downtime_min=24, downtime_max=168) pipe = copy + fault - out = pipe.compute(in) + out = pipe.compute(coal) + + out.plot() + plt.show() + +Output: -In this example, if input is a constant time series of 1,000 MW, you will have as output 10 timeseries with random drop of 100 MW during 24 to 168 timestep. +.. image:: /_static/architecture/workflow/fault.png Create its own Stage ******************** @@ -97,7 +118,7 @@ Stage are linked together to build pipeline. Some Stage accept every thing as in First solution is saying : *We don't care about. During execution, if data is missing, error will be raised and it's enough.* Indeed... That's work, but if pipeline job is heavy, takes hour, and failed just due to a misspelling column name, it's ugly. -:code:`Plug` object describe linkable constraint for Stage and Pipeline. Like Stage, Plug can be added together. In this case, constraint are merged. You can use :code:`FreePlug` telling this Stage is not constraint and doesn't expected any column name to run. Or use :code:`RestrictedPlug(inputs=[], outputs=[])` to specify inputs mandatories columns and new columns generated. +:code:`Plug` object describe linkable constraint for Stage and Pipeline. Like Stage, Plug can be added together. In this case, constraint are merged. You can use :code:`FreePlug` telling this Stage is not constraint and doesn't expected any column name to run. Or use :code:`RestrictedPlug(inputs=[], outputs=[])` to specify inputs mandatory columns and new columns generated. Plug arithmetic rules are described below (:math:`\emptyset` = :code:`FreePlug`) @@ -116,9 +137,9 @@ Shuffler User can create as many pipeline as he want. At the end, he could have some pipelines and input data or directly input data pre-generated. He needs to sampling this dataset to create study. For example, he could have 10 coal generation, 25 solar, 10 consumptions. He needs to create study with 100 scenarios. -Of cours he can develop sampling algorithm, but he can also use :code:`Shuffler`. Indeed Shuffler does a bit more than just sampling: +Of course he can develop sampling algorithm, but he can also use :code:`Shuffler`. Indeed Shuffler does a bit more than just sampling: -#. It is like a sink where user put pipeline or raw data. Shuffler will homogenous them to create scenarios. Behind code, we use :code:`Timeline` and :code:`PipelineTimeline` class to homogenize data according to raw data or data from output pipeline. +#. It is like a sink where user put pipeline or raw data. Shuffler will homogeneous them to create scenarios. Behind code, we use :code:`Timeline` and :code:`PipelineTimeline` class to homogenize data according to raw data or data from output pipeline. #. It will schedule pipelines compute. If shuffler is used with pipeline, it will distribute pipeline running over computer cores. A good tips ! diff --git a/hadar/workflow/pipeline.py b/hadar/workflow/pipeline.py index a5c4dc5..3296af8 100644 --- a/hadar/workflow/pipeline.py +++ b/hadar/workflow/pipeline.py @@ -464,10 +464,9 @@ def __init__(self, loss: float, occur_freq: float, downtime_min: int, downtime_m self.downtime_min = downtime_min self.downtime_max = downtime_max self.seed = np.random.randint(0, 100000000) if seed is None else seed - - def _process_scenarios(self, n_scn: int, scenario: pd.DataFrame) -> pd.DataFrame: np.random.seed(self.seed) + def _process_scenarios(self, n_scn: int, scenario: pd.DataFrame) -> pd.DataFrame: horizon = scenario.shape[0] nb_faults = np.random.choice([0, 1], size=horizon, p=[1 - self.occur_freq, self.occur_freq]).sum() From 1935c4dd5b8b903e106625d2dcf359af82cc6a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Mon, 25 May 2020 19:02:10 +0200 Subject: [PATCH 08/34] Add graphics in documentation --- .../_static/architecture/analyzer/ulm-index.png | Bin 0 -> 33675 bytes .../architecture/optimizer/lpoptimizer.png | Bin 0 -> 91023 bytes .../architecture/optimizer/ulm-optimizer.png | Bin 0 -> 26599 bytes .../architecture/workflow/monte-carlo.png | Bin 0 -> 24697 bytes .../_static/architecture/workflow/shuffler.png | Bin 0 -> 22640 bytes docs/source/_static/get-started-1.png | Bin 25431 -> 0 bytes docs/source/_static/get-started-2.png | Bin 24497 -> 0 bytes docs/source/_static/get-started-3.png | Bin 29546 -> 0 bytes docs/source/architecture/analyzer.rst | 3 +-- docs/source/architecture/optimizer.rst | 6 ++++-- docs/source/architecture/workflow.rst | 4 ++-- docs/source/graphics.drawio | 1 + hadar/analyzer/result.py | 2 +- 13 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 docs/source/_static/architecture/analyzer/ulm-index.png create mode 100644 docs/source/_static/architecture/optimizer/lpoptimizer.png create mode 100644 docs/source/_static/architecture/optimizer/ulm-optimizer.png create mode 100644 docs/source/_static/architecture/workflow/monte-carlo.png create mode 100644 docs/source/_static/architecture/workflow/shuffler.png delete mode 100644 docs/source/_static/get-started-1.png delete mode 100644 docs/source/_static/get-started-2.png delete mode 100644 docs/source/_static/get-started-3.png create mode 100644 docs/source/graphics.drawio diff --git a/docs/source/_static/architecture/analyzer/ulm-index.png b/docs/source/_static/architecture/analyzer/ulm-index.png new file mode 100644 index 0000000000000000000000000000000000000000..4d8ba4bee7dd0fd73b986f5682c5400329bdca52 GIT binary patch literal 33675 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 literal 0 HcmV?d00001 diff --git a/docs/source/_static/architecture/optimizer/lpoptimizer.png b/docs/source/_static/architecture/optimizer/lpoptimizer.png new file mode 100644 index 0000000000000000000000000000000000000000..9d94f9b911cfdcd628bef41e77de27366f7b63cc GIT binary patch literal 91023 zcmeFZ2T+q;*ESkDM1%kVL69b3=pZ5>AT1yrLJ^TJ0xHs_C@p{>L6F{iP-)Uck=_La z1VyEn&_y~(Z)eBn@$sGid%yS0ob&%@=FEIE8O`M0d*5rXwf5TAYG8D=ubqaTg+d^Z z(`u?nJqUydd?$KDP6~bzI$Mu}K-eK_NCg8g^QCl(O092fA#zH=xATw}KX{saeS6$q#~-~C(o%W8%M3NJP4~oKKKthYuI>H~ z(rkoUz#>HBT5)^P4nstB#YvgB1nFr;5fm2Yo^2GQ%sxb+3XhQ`EAqH2) zqtlhJ?5NNs)>p$%jqz}N2uf+Y-1x}T^IH3_fDRQ|U*IrV=~K-V1p0N9 zt9(k>U({9845Rop*!(m@Kom_B;xT0rlp){~__k}u55&8>$~|7KgvAwk6^L`dB2uUMb6GHFMRbqNyAZrOND~a5l!=4fus?~D>P7P`N zJAQH0qEt`eu0fI^ZwO1t8;()=nmcdZasIO(2o9?%#sm(X^!2S2z@|sNMM<%Q{VjZ&eFzSdF@;b50tQL z=5^K_q@E~>sWC;ecb5545A?ncMm5fpO6uG3JH(6pIZAyGyPi<5)>Tg@PMf|1_7IOwxkY%N>m-sSv&=K*S?oAsxPFfaXT2%W1vzvO%E3Y& zKt750lvlQf5jG>G812HM-A5il45ua)QDL22s5LeZOdwDT;r0G=v?NaN^^0hJna9Tx zQ0{IUc^^KqhVt%!D~ar8Yc%L<5CLLc=0*cI`38u*4W#_z0fNCt!-B1m91=_L6|z=Q zMK)y&fz!QwF!zekCW{;`2w^;UF?V17s=ltzUFVkp?lW2GVzmCrHf~W)7%Dr#jnv*r zbEr_x6lK#}$m^67o0_YaHuYS`3Dy|Us5#1ZTF3=01ze0k54%X2;ONX4Q)B8}$oFuU zO5FnNMK$>06Ek4(*CsS--Jc+vOx6wTk&UOpv7L-m)N<1yOk^|0Fej%%l5QOn*pb&m z8ehm95UfSWk&UqUY?{BEhiF2aOCA=`BwloZO}x)FU7^4ojcPOoNZ2$F>#W7?$@D+* zXO$=-)rCP4DbhuSZ!*UkvxN~PDxSV%cj?t(nwl4pJOgC3@?*fsm${HREyzC6orTR( zKgi9bslKr^7u;(uA*)-QM2-o^-Dyngv$V(Gt7b6Suwa)j-y_D=L`6l*uCT~gi|#-V z-I{*P5!`k@5)@T!Y9sq}9LCf$IW?qF?1XBhzdf3)x9fDcr<~|Atl>cBEX6bD3T=EG zCGvJcCr!q}ZuId_0=I7woZx;{Ydo2Fj>2#YM9lHn2%Rdh6FPN;97pB0M`K4WnU%{Z z;=w^2CBp2vA-|U z;^v4OW!TqO%)Y1R<@oBnGoukmoA2N5(3C36V=Ye^=}K(g(G_~Je$LB;M4Pzrg`&@? zUWK2mZo0h^>zcU`O|rGXJ#Rg{-dc%?`TNm=4b;=qJ}O3W~Q5##4hIoFyoRVIinUS$fhGv zz0=BnDdSVZiE+1nbQjtu)}0eJ@!ajphSp1g8_eMk^=J}zozX`D$6w_YdXmfXI?Fa#bBCxJQ7;v$7yDhygIj$LzCq`RX4oFo6jhmkyXRu z?u&4No6XKU?m#0JQ7NZVkp1hf=I}vPew3m8=1C)&NVpC^?}rR0vVF;Nm5pb*Vcf^9 zm!Re?I^|l1tG-C&mDvnZKcj#H>dH4yCS)vMKRY`c!#-h5YJURRfjR4D>fUO|dcGFq zbRC=LEGnGYTjAV>Zf<#@b$u$tx_*6r36dzde(8b+`gN*VKD(WT#zK9RAzv@_uyRA06$IC1vqx_q;-~ zL$`KjqSRzyuStxRtkY+mdxaYJId{~*QNd@l^@dvmfgRZ{!CU$I?d~So%q|<0fLMLC z>w*Etros8J$aqQbW@Gro>Sbq-p!R&%Ucy9fmo^T^TMzpe)cd2$`eoN$D4dARHh|>I z1ERpCnzoEu5eApnF=KwnZ!pC1#=Wu!oO7p(KSdHRzke4nlz&q<#H*Iqju}BX>X|(w zLJ+1{bs^(N9JdC;hPH^qP$jGTJ;Q4W-N!l#GwXR*wmK%|mE~QoY^mn5D$7e4(gUX; z27^X&BsV@;FOxZr1L|IpIU$Ur$;sA~p~0{{n0Dn5a@pvgJj~{@D_QCcB0Zh*H4k;Z zr;#hE`scw}dOiaHo2&|%NIoJ457wU^)`;i8_CyU%A=z2*=07W~wiow~zVcFNd+tWp zhiq+`p-^weir{?(lzBa}sfh{?>m>)%Ik5NpPSxY)saGNmJx$fzcJ z4rS2%hj&+t>pC*dOZPq3dT=VNC~SGOf=q(>o=EA&4Gio*Io?mDzR&wVS~o~8QnQ)u((Y?sT=U6)#eh|DKyGGz{R^(@aQ%IDeL z3k$qQ~M{Mo9niBkR^ip~?pf7w^@LvbK;t zP^mjpz$1moh6nGEoo)+RmKMnuZs1S$I=i=g>CM6zvr=_i#d5I6vgmUSyV@Iq3l5t* znwUU2#cCl!z(rj)SU?AN)O~E}Vy?sP;j|;dVvjfcc*D)K{sD!s#C;5(j;!6M(ZlJR zKbMCnYCP^MH8t;Kx!3GC8`1dPB)ZXHOA_LDOrxD~NMu+rpg8c(TK6HM=^-Kfi-h%zFOhdA# zZHeKNmDt7?az~H0uhkSgeBS>yP&V5x=v8TI{FCi7+Zkc=)-!btjh!zFqqrA8dKHgv zwu#r%`z^m8(9OO_B9K%E^UpY>6BhTO@jpB!k92bU#_p*|X_nLt(b@Mqy#Mh&=WtSU z?NJ_bvW6`oXX}Zq%i#>gCBJRs+KJc7Sa$)v>ATi*lSTVw4)$ACIAO@e)Hxhy z0cYTE_4*VZxF0}{leQ_NFH`GSFSoV4up9<9i*$OHPF~fg@kzSo%@$*T1 ztC+ia6ZWB)sC6f?z|C^zL?N^0b&I{|jgyyMqKTig-HFcox6C<|-CsBT`F)i1;pRl} zqllZ>>tmz@$`aWxt`&L~H4h56Pkv#|yoIYIKy2P&QX-`~b|u#uzY{p!?x)n-Qzx>t zn2kVH6NlYyXom$#j6Wn=G%9KD{vZ~8Qhb;<@#dsW~E`_Aby^~mfV{x<%PZ;r1Fn9C&w6J1?Pn#GAa8gYLvW|K38&jj$~!koNbA%0WJ4lS!Y2GO zBJY+bFghKQZ7-w4nfh`JYsPnI2a?e$M&6dsl8r z)(hr4{Pz9wQ2F%t)%ACR{wt#$H(tXTD47HMl&wcD;|eieb#}sO7MVXQ_JTN3Yu8i< zz`eo+{XxVDt0ImugEPDu#-vqkGP>&4$}?zY)SP`f|FLy&lBo1nmsOC!#OsO7Rh2i3 zU+E-ncZ7NlUuvpOZ#Zw$8Mo^)#`m>AZx|MwE?to|@4Z~=v&r#XE0roy*g~c3P-1dy z#n)wOXS(g}ZeLrSKh`j37;zm7Kl|=}3C8=FXP|Eg94iMR%$=o6ffa z$8Oi|R4KOQ)OYP+nF-cIShi0uw9dR5t!lQca~V_ln!gb^jct5)xWn)vQs=4{(a`Jh z$H5x?S=~W9*?JKS2m>4y<^G!>)apWcqUA|I4&spxff9WC{yxJ)$A;4vv@@C`s#sfw zxpT_ye7IS=)sws4cE9Tfrm_Ypc>ks-fiiTyPS5u3{CMO038SeLdp$B1`w3L6sQ%@9pqC~bm zeOOigUD~VGWw}r8Bun?%r4WRVgxhP;j>y#UrNMI%CauC0{dEyPuGgpoYmgDHeS=QnWWKvY4F|%NAF2(8$UaxPTZc1B64G7sj|e)T=3Fc?c3J8WRf0eA z_(75}`g0vO&aYBp=P1G*Fe9&X_yvLMKuKR%Y1#9JnCUm;AC&9w&gf?t)&{~Jm`|yMMjEii` z(mN8*&*$@+Vxw*x^_W$nyQve}Mw^0kxBbf;QZG4O9bXt=8_C7n&7^;^n|_)9@!Ps1_w`QwSWI` z>b|nLF6u_P&*>ksW^7*)e4d&()qL}6i&nZ8eli}tL!|_7`^fUt`{|gsGMvHjh9%{c zuX2DlgWuj>;>lN0lkHb|W)0i%Ouri?G11bvr&LoH-h|Cq-;<<|FB z4#f4>j2_E_5jW}Yfm8P3z_-+Q)5AyHE-*S$Bb_harx}H+^jdeiKUP2B)zUCOACz>( zx=hr0qS8lZ_`%ZCsrS$v?_ArqO{3zWa3Zouj)Nj&N>pjWDVIn>Wvii4E6ay&XWF(S zD)a51w0W(q?|T)Y1Zy{LE%7R@?wk$LGV!#U>Ui#Si#ieE(_kw&R}$XfuzLA!_!Eob zNS@wr&0XKDNBXV5i`*Z2d&=6I2MELu0zzoy3)SSI5D?z}N{wW{NKvT=e|F+Q`O(6c z!6G~Yrx2qVw%Ke799HE7PM zF2vV+CwosrP`BhmSKdgeV*g_oRz{7wdPuAaljXJvU;$&K4E7WrW&{B;4AfE?ie>ky!r_6^Yu9 z?)$!DxN^;!;GNgqLG~}yUgfa+Xup^P3OQc@qJy?mB&BkC($ z9kpxOq1$b|O~l|Q1wVDYxcQCp`n%=W3WraVU;J)V-V>jrJ{PVf?K$;=YBkF`hxCpf zKLCjBNGvWgs`x1yfc&pyNOo5WVgV?VV^73`f!xiJK5&_}och+aU)MX_eVEAB zv19B?MO%`vT!UT@nQsU#d3Y;gC|KJe)oLm!yX|d^4Xe1e>egHNLmfUd{+JX+*Lj90X8P8{F6I;8ae{7P%+Q`jKBn61EP#EQziQn%Gb__a3^p z<=x!7&^4VyP#48#$OleI@7X8bD-G?tmL|bd^kvR1inr^w7)(H*W8rg0{(0S{fLps+ z*3{t#uA}snWBU(UzPz<(%w?*(vCM5POspToa9ZTy;q4jzq~0W(@59@&K4Lr`3w=a3 ztRmWuXJ!08#n;ha4`}jnb{Nca`keJpVl?V%h5t9dikLFt$(hVtRJo&xz@cBn`n-6- z)i9TqYU{Dck!gAoe~ri+ZEP2`vwhy$-e_=ng0d~j?P9ihsUF{FaYk+J5ds{a{Vl{m zR&-ffXjd4m#)V^<;7+YntCnYj6|(yEGAi5OpBeDRj$iiI{c|Gjs3;tP+(0Y{SAVMW z_B1FqWm5k5#emlS-T=o_RPM0SvroH6yCrRE%2g|sUk1~bQlFiZdi?Z^Fe7vJG>>EW zRo6Ah>-mmgN+vNWy+nB^rsgNYkyV{4m_w3x-I!ah8VSrnLPBxa#?B-6?N?=I&YPt))|Y8*U{?jtBOW=O|;RmDS)p&plZRpl|}3H8{vx z!x^;%pjOipoH<09U@bOfG@Z%2vO0$RaYAF7LJ+C@UEr=`Yq(Q@-?WKG6+zO$lq&_o2s5SW6eLvR{A7-e;&NQKjR6FuEow!h zVvrmcr=H&olXs;9RLByFUNxpB8a!nwfj&|b){|0Zw?veOQe{< zcEW=_$l0(2k7_~O9y_{Ic!fE*gB!#F1<#yCT`h&_NHx!|c zh0$2)asQR5TzY~#2N{D1kgnw&Ep>7bJ_Gqj$w1Kx7(Vpgv;wCA0{X-Iz#~{VA&6OK zL(UHO7PD~T$bq2FGjc=ocfu8qIscs?wv|9yDV3!NJoy_}W6L7aj%n-u~69?Z=boay!hy#H) zUK*+MKMVXP9%OEK5&W(N_+J@%Ik~O1m0cNn6mLhD>bQddT62x4&=!MkA^utN(l-mR zzdNqwArJ$zrcu$&;H|}h9M{>-j&$jF5oy)pyu|gpQ%|4Yewri$?|G?}s-o#TU6_aD zz_#ReK9wKDi#I0$F=+Rar3ai9;*JMfKfVptcnU+$2!+3YdM4-Q+j}v=kRk4^%VCOj zkG5h`#I# zslo%Z&t%l5pvbB1WR;0ILD;RykC^)()$vPeizi<6_z<|6F6xM(4gMrXwM{`AY)Qe_ zK#n8>`#zG?fG>&ZQ_TYyMQfE3#ih!Swi>z~j{qyqTV`;g$U`zV!sLH~b2u3J7TI)F zY}Ppg#P$eY9&;(Y#`)NN4Ojf0eC3E36Zi#bm_hCpi>JW!4+ZNYrwwSiPW5=IPSAqb zcek^m@lI9sfpz=v{ zb$FUJQ$Y+DG@G-~Rk_gw9MA1(UQ}tXrc~Mm*f%VUPc2G7@(YR^+T%=V!%G{i+h;h$ zi93hiN!f4NhTcSxzXjw4uD+rT#xaFd6Jr$fC<=XO)<}N|NBwW%AYULJYXCMjx!=Gj zIv+Min_yv7osUAukyr8K82=fUj(BVW#;L8op$&dse#%H2qgbiBD8&gI`bFP`-}D(` zqfEg*RByJ&Be)_=B;C~D&1xpSv>?O>j0>AICeYWmb5bTCk0y8~f%rq^O#?O$-&6f-+VC$4Kx7?VOc^1^l4rFSq(SzgMwKvJfPz|em$|j*CXhC8aM*R z!MrXcAc%YTs#f9uLG2z87n{-9`i&KL`0%$=##z(%G0+`3N_ z%JPeWF@LMV+ABn*8QAc#bUCs~E@!4*2^%#^^J!C={UZJlwX6NM%&}M)FMh+dN*eIA zlK{_Zh>Xf|Wwa{qdeK?e`JUw)Rna%2Mv#+zFEki0-X_1-{|X~u{F*qzeWoM& z&hVSNpJuu22xx<6o|o7?m7n=_!s37HtsRmhEv8ZAmB~A*l7{0e2?EAbcMP~rolHGQ zMVMAP6U=rcw&R+DP^FelS<^x&^0V1c7y(Tv49}c^f0*+a@mP=6wkHk4BxcL56hev6 ze@U4jXc8hZ?nSg(e<0+sG#Eg}<^yB%StHPUp+0-#0oSQAL^>=OV8L6vYm*_LY`PLo zgCv6d`!M>5jfR62X-yE{zM!2Z{~4Qw5re(SkrGOf^VNgq$a5I$c!7R zW|y1RLlb%jAMkH#3?Pb-IBKdNi=gHui)c9B=dboyzGs?o)%VKP{qN_kacUUy_kHIl z9(AWmQ0MFCs>Jgdrako{j)yOW6WWnVX03kBr|XR8w|nE${Fp+;Vv_x+V#Kj!#HqpI zP|9X=Hqqkpaay@*n$(Z+I_Zs>4?zwi6_bF`DlavY-~2>qpL}KwCf^UxGgM}0!mDOW z;@@Wi(8o?yzn*^CAw`rONGLbwafbi#!|4dOh_mA1t`ZKzkLNz7K2e5Ok_9?77G5t3 zdvo{8mEmGlUV$5^UGQGrcaCP(6=)*A34?q+ZtJ$j7!eJ={q5za(kqoMQ7zy)WY&o0 zGb+BXN^BSL=Gx?s@$;zAxJ;gJ`ouAb;22-^|7|`(&jjmsHlGr%wWR#YOR1Trh8tPX z?M0~4-jaS)inTm_EO)$X4Hq^aMZ|hjI#$gxSX)roG5r`Q0a^T&v6}Tx{u0aWrJ*(f zS{?DJd&R~4q)B2HWV%EF!4-{1~I@BBKNH+~;YI$(T_agbQ2crr>xO96tZ z{RcgKy6|0#V#E21@yw2uO=TUbw8zR!uMnkNJ(RkP<35{OEYcp`lFuIe{Qh}&d&H^C zXV0~EXWY9ZRidO!!fK-4*RmU=$`7bh#O*=kyNVQC#iGvx+p$-VccCGZe-=ken+YK={4CD3yb{ zyXENA(f(G8@6Om6gAQ(}!lXVv1xAjCi);eFEwBzo5pg?!`DK+6yYK!_T#9GCO~td1 zwLW{VIViQefoP6Ls?uR337wM0T^OIpGMoF6tg>MZC&wd$gG=7aqg8H_557m05%XHN zg&P^JfKyj_yuTQcqaUOOfW>#-67o=ayf-u$nef|~%_BMBuPv=6UfXmTVsQqNTomiE z55WBy7W-uuxG+2g8=#bJR2_dIU;KR`XTXDXKM+ocY$0UEvzot!R z_>dE)g|~Muzi|P$3?8d9q)`TNak!+=l3egMxzibgcpOrwPESzsi=@2YB;_hMeSFQX zwl4LxS!-Z=;C@H2FVFk!R;o(%1O$T&kH(HY3aQTj{(MINs2I?jz!)!u(pL5`%t zU%WTeeqYeRh)OjEE{XupTNp*$tC&S_@w!G2xGA&0{&f%iW9sgKnmF*{(t!Ygk-WIu z$H0rTitWPWXMPcw{5OH}24FsTag*OXes>HjEVRMSbOW3CKo|ZR()wH1vs~+a_NsUJ zFZ1y5476hC${7T2ew`@#?S<^r&(vC-93LfJb~wvtkcUo_ato>Di+TKh2AoM(W}ZsXbul{?f{Ic zq~b@BKeLc@)qpoE825slA;=e(vMK#iKd^EwA2d6TL``um-4F|tY0*t&N0EzL#S0UT zgJQr^wrl^46M$w%k*EcVodYUE*{+)apeVOlyddE?2Y#H!KjVa;+IT)yX#?Q)%qCAA z2t4dnCq04FFMj6!rtdR5R2$Iup8+1&$7fDx6Mo!Y55VIY`CkAM{iUFd_$tTkX}(_o zDh4Be38ScYTOkIP@{AWne%k1QMm$1NP2UEC_WUKE>%Zi~MHg^~jzk*Bo7^ln4)OR| zkv=zoADsEF$i|Uh>)}zArWAg?FhzF!IEN=-TtW%m3otG#?;^7C06)%J;P<#UVT!l# z<9zMFxD1z49pGVT=KPr_@m!zjg`KtUlz2&3pk?iO|4pDRgg|}P zbTBb%B4{Cq3gH@ka6RNE!JX4tApk#Wj!l{a!gktJ#OVlffgt~g{&@P4G&=L+$Too_ zbygNHNt!b5e)A55b=@Lv1xBy~ypBqV%LU2gl3IYUOQ`q@gyWz#np~hb&Cp9K+Jx=f zeML)l_e5{7=qNMuH%;O+9#Bk_lGjN`-~=WUGZ;-62Ukj6N`)~hjm^3ODiX<5ztItp zfe9>+^RdWA{AL2kB(jZ3KJpOv=z3Nsfvfg?6Y3kX(FzQI5>OyXvj%)wMO;9H({+V% zih#{8=|X@z&JWQBvNX<7V7NjOsJ)QU1S}P-Hk{tkNVexw7z+vAncXAke(f!BQ zM5S#AHG|L6U|CL$$1>k!)60i1)%G@KO_r0}@;E>ZpC85d)!PlB4}!>%vLN-AAY_&z z_Ct+aUX|kevZ3mFfiv)=|Nc0qfxWvt=M%X~_;7P>tlq9S!-(J&kuxd|Xv9CCQM~9@ zcD-JDc#c1ue^%$c(@$1vj>RRH7U19a*M}8|ZOz$v>?^1QO2uYZhoV79=dX`H*#1fQ zgC|6ICdwPo{4<9WrUC**BF)d{uBpMXQv3I6e$SET0?b6-`pQ|_LmNy^nNlF|_iH#| z-@q!UbH{7q=2+O({zoytr=ZCt!4-ugR*s*WEO zgHQpmosKZ0*8b~QSXs9Idyr24i;LJeu!=en+lnnP|5~QKbiXA43&4RB7&x6fimz-T zCRcy=4{4!j4e-d6mb}CW6qj$27yACgICJ1UuH8hM4YOhbHHdQV{h1?A2-x%EtQ9!T zJ^TZ{ye~Ym>jP`@c(T*0(t+tfy?g=1t5UW8`{_Sq-N;v zOZNA6knEC#AQy)R-W#)Bl?N*|LH34GRTB3H(He~S1N(QF*+<28mGZb6;2>0< zZZ>-+!?_`D=w}+cw|c){-zZHCf+E0+YO(M?3eNP~=e_?}*t8PeD|f;|Eq5rg>+=%M ztH*faFkUMKT$hu~YMH&6*d!@8p0G2*&%PBJJt-=VK4ixza$VDL2ie}gR6A6K5G4!+ z?pR}l#CT}E?*SHAa3f6fX^BxZK-NS6IM(+`>>i{#R)5&7LvpOKG2zk4gWNyL1giAy zl_xX(kDKRCJ}3gy=J9CabXyO)4hIqr-7clw@FK;a0>Zp5f-m*DQ!fQ6{j zxJ(?s(Te&wDo14!@8J~B_oN>bFp;RY0|b4n-z)#)(edHKrQx@y9&XGu0kSYJG!oDD zBEa2HT(>=3xZjx}>)q%PO=J_Sk(D&~61;|K89VB;Gv?_vmuv@;Jq5Q{?P-H=QwQ+< z%ekl^ue=WTJ6M*m&N9tWISsCxS@j&(nT`N@{_E(IBEv$4`jcbt=Q^3J-a9LGuDyvC zei*6bJCWj z5L7&>U*&4UBIh^Cn3gH!HW!9?bLTT*rtkKU;TrSh`=L!iWX%3^CB-be6W*(JUQ1=| zrOuPh{Ij~mw!Ik+-M4g!uRQpU2D>z`>M@QqF1O7F)Jpp9U%Gg^16}RDc&j@}v`rSU zO$j*4_ua#EM*%V=F^uQ^bE31);~t?bzes(btw&$=-OsWgC}tF~M6YjW2Caf z*4_jNUoiH9*V0O!YD^9vtMNQ;}-~bMam}D)8pL!i_4Sas7#f--t;`aTQY|RHf92;%ZlanG} zZ+=puHXCxIsdk)cxD8rIRI2~w9FHO!x3IXH?4+*f;;Ok6{?u?m6fPzcaEZwjRGv5r z43yc@)6$U$Nvq!h`R8nqWob)&RA1&lg}Fd^7Y9kBRg@}2PIg3}Z=>bzq}-7%%~-A5 zVFj!u&6sJ8jXwMq&z#Q-T^@cb_WZqi+7XUdv;EmQvCAfGGG3o{m8mpA5JL3F_VT-l zsn6Hg#E}8Zb|a&4Tu{fbkRP0Xgm6qzX%6@L0kdgR2SOAlooNXayf1VMz}^U!sblQGYU z2qSoX8CK2i)N04|>>eF+@S*6(s zPFrXXqBf^d_@GeuEb{uJm8y9Wmno$6m&Nj|R)XTM6Xv-peuiR8 z?|tK&=Hj-G6`dHL@ECD0!Vtcnd@5WINn~F))*RJnVv1-@VBPDFx6y-327Su8Mx8^s zB86L0Z3-lbsDsrWZ}!SrxZmdAv34d6&}*dwh2F=~bpX=+z8yd!P^Xa&tNTKo-a4N~ zV#`%blr9oBt9LHL?-B?oS+jqPEO62Ncto6lSTkT}&FuUVe{~l}WUcGyVEYo$+STtXZ!SSt%37ocvI(YxaX$zbh~FRHA^3Em|*D*R0C)!*I9Eqn~%CB?mwZ zt+m5?`CaL@sxyX0LUMJmtYwg_$wm!MZZB4D3qSPq8RPgPN6siof`PC=_hwk+nOV`C z>r<@31%`!z2V}3#U)z%C2r7I|O zm$`=z46d??tbhLk;-F?jqnb20O_JG0b(wK@0NrqX=b=QKyM8h~f^v|Xk7g27^H~46 z-8o^51V$J|OT*(Gp)f+ZjJCHYqe_kMP7ViejJB>)uSFby%QZZlNv!RFk!t(ltNg9? zi#6_(M?R#P?_(2^y!dE!_^~Xzg@xSEFS$DH(~)w|z-b8Tdg*0qKiXQoapeVi2Sg+< z@_svQ&x%pJ;j(D;FYmrY&>O1wiA&KGU4m%cL0F)0`P$|hv?L|U2Fw3w;@TB}r;|7Z zP?c`&<8|J9RZCkCp%981*7N_$eIy}`Ak_3nO9|bkq~5y={_e9ExrHuFz2;tA>~wUB zP2az(0&<>X{D0lLp}7kh=QLA83P?25@MUhOBo$5sTY{6$bo6G%Fqs z-H;y}X2ArSoX>gmXO8?K9u6`6e*lL-nqrsN6AfNR5ZLGN4{4k@yhoQv+`RY=^#92= z-^=_5Vhn)o)H0wFE3RR2eT{iH|ICSk0LPMPfFRe{FRvTeoEXoL};10QgDzb)I7f z!bE31Nd1R2^2)~m;&KP9Jrd`Fnn#unU-&H|oH*D{iSpMM%h8C+OCkjcf97z3vWl!? z8U`@HPSo@4n>98&jqtQS$9ik!&W7IfdKM{hkK&i{7tK^3PIga#1oEk;)_NIN+<5s$ zjt?-g^NZoBQR7t^&tveAnOy`x=|;(gVs=1&ATi?wY2|Fkt=IW!g5np|QyaFdWlSs8 zZyWSa-h4SO2Hku5)wS|#2g1>zR}`UF?)dA0_R82nII_tqk53z{$Bs`)i!8jf#IMKg z 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 literal 0 HcmV?d00001 diff --git a/docs/source/_static/architecture/optimizer/ulm-optimizer.png b/docs/source/_static/architecture/optimizer/ulm-optimizer.png new file mode 100644 index 0000000000000000000000000000000000000000..226893b644cb6dcbf5566a8f60a7546c4a1be193 GIT binary patch literal 26599 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 literal 0 HcmV?d00001 diff --git a/docs/source/_static/architecture/workflow/monte-carlo.png b/docs/source/_static/architecture/workflow/monte-carlo.png new file mode 100644 index 0000000000000000000000000000000000000000..f2853485523526351503b22387f441397b9188b3 GIT binary patch literal 24697 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 Qvi*PaboFyt=akR{04YDwZ2$lO diff --git a/docs/source/_static/get-started-2.png b/docs/source/_static/get-started-2.png deleted file mode 100644 index 5eb61348c5698637d227844692d7ffd0703632c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24497 zcmeIaXIN8N+XiYu0U1C=ML>!T5CldLBQ;n6MFHtjGgbtINKGI>6ckhhR0O1}NG}m7 zp(I2^L_m6pw1i#~A)!VHNzTfQ^Ul2Q%$zgVb-q)+@0&kdT!E~;_u6Z%=Xvh?e(nbs zObi9Lh;Lc9Zk^!SGpEhht=oWGw{HD=zRlcE0>t6#*2%0pd-{YW(rISUKRMEuQ$NS} zy!&Id${~HDq+>hXjUr0+&X%;vKDqzU{_evIcAu;Vj1Fa-F3B#rZ*KR@{@_b}=04lv z*5~BW%1Y4&>-< zsY!YrGw!nYU!Q&3z@wtV!?RUy-FohiJFj=iAY%e>+8Y1*XnjaL@z)V#ZtIx~Y{i|` zaZ26ueNZrbO_SR%-{uY>le3AB^jb>AROsgcxj$|XjjR9bf-;Z0Ht@jBqvPem|23)} zeO~uQp^M#md|dyK6(+~!}OVLi`NyW2y? zl)3q_-#+4Va@zRYRGd}PqsuNK{k?wsh(`tUuN(en8vb%M+|lEu#TE3Icy){KRJ1-H z+ZbC1;h#g=$i{S?IY^m5FlI#U8Q)O45Icy6hJedX)EGF|(FYDOP|s%4bc zhB{T2x{1)-=6hLrHxtbHD@x+Y$rwR2+`Qk~S#B&andke9c$ldt6Urz)NOm1d?_6wu zkC{K8VP5A|N&gztRWx`n*YailTfeVupA0i|TG-6&ZvRLDpAf^N6$WzB=(|$>FKir` zfoo(;7dsBMkROEV3(a-Pxa=?~(Dw>u04>N$MOzfhlC$j8^A3*9E6-?OPz+u(mL_N_ z@0}by@O@!iIJ#+rC=SgowH9^gHI#t3w+}A~wYfw_^(^NfR${Fh;t4|nXrmbEYDYt9 zC!2n(Gv#?EF{h!Se(GfvT)B#<$y}aKa`0`FZ2Rg}*fy6I<3>*xyH!QvBXOud*&@YX4`G!ulU^cZdt{gvK(@$S( zQLw0dMoQJx?h(5;f((J|xH7VD+s}JQ{^^E00wlHm#WrblVGm9$eQfako2+n#&~!6G zdyGJ}ue1z{f>O3}F3@zz!y7AIn=1w9_uZU^Kq-vaJQm^+wYwlALglz)eA)3+bq_Pf zHI~*kMJz2o!Y;1ZkPqQ69+5P|lqIHlKW))q@o>u5NW+fHGp1~%out%_C`T$ezKXhE zQSsd1YGj9&ba33HW~)}-lSGJ4FEp_4GvX+#8!Ma@yqLtYKOc zlUy%pWtxP&+5L1J`ql4Tt(NrR4iO6&aU?@=&0EU*+lf_%U_9kEYd%$tAotk&Tk#x1B zG8Cp$NH}0aDRPE&zVWp13iV-;lNQN!FeZULKJZ{=GlsFg{%d2D{)}R`KS6vWsUJ?s1S8h069lrn!89MPHDv7-p{RM~nwwXpMl<_ACh( z#GsUEfogJsgGvtG%40Qi7E4oOHeQ$}0k$s{vWkB31#{gBuj!KA(ZS~DU?+ldlRTtn zI5h9p8}hV`q27}!^Bn(=cTcdTcj3ZC%at%QG!9IqMR~Z-6{e>zz35{q96WdsaRF78aj7ZJeRZ5+m1|#heRhr{$8IIO zjV|*TjANe2PX2Lu!>y6fpc2!iM)n+OMkHNU8-rT)12;X1K%!ZrD*i_%^wUI%a(ldQ zd=QPsl2CGs4Q4^!(X0t3tZP0oIQT;V?Q+}-S?hzwONxGl=p<>s92+<3eXjl(JF&nX zn`hVkP@y^;q3PY??Ke8w1y1c_$Pn5tLd;yJue45iDh z#+zc7qnAj&vyeqI$L`F800ce|
    I(xV)|Lhc&Er&qZyX*znb^f-1f^hEFs*0lTn z@}6GxSnhn$0d27i-LBn%3n&mCQ6_eYrk~qT2A&Gp)AxPk;`&2IC5jJ@Hb#Z8B498u-Ii*jABB~c$ zlT?fd#vVkHE$3LKgh`V5wpJUTnL|ie5Oe=hrCYvqy67>T1_A-w`gl&<$BnmC7fK^m zjooR6xkCM#sUAsb&lBBu*sRH~gQ5fDW!u>JcQYzFDipC> zGQVyY<2&y*(+WrFv-g%psJ)`(WoVl(E4G;-j!Tz2Pb@#HvcgCWAoo)@y+yQ64W_4d zD8hrX!JB;FD)8wIw=kGBvjb>vzGG!XaNS!p2_+u0c_UJlUnVxvv}hum-W( zP4>R!gTmB0Zz%?R^vqRywJzdLzz;}y2of*cJh<|1w2|gG%dFQ`q=kEEYb^`K9R?P0c)DQh!pw_c2-QMmvg~Byi7FPFzcAvrAblT6{)mg!bTm>tI{dA z7CB_zuPnXD80D`c;UkJM?25DsnNTA0kPC4M2OBJOFKDqT{j?D1QGMkRDUc!3929() zV=*l5cq>#~{rLH4L0ZaWxnn31 zCBnaCN8zRDgmIZkNhcchedVHm8|SBGZ|`_Ckx-iOm=Uretz<@cK}Y_o~nQ1AmPZ-ZQbrOuoN7i%mT~U#2aczfgVY zN_#x{8;nqfH4JX;W!`qA3SpVc4T~|9efZ#SzTZoU`!MjtN#4}kqP8RiRm##C#>uP1 z-JaK#p9u1D6lqUHaJ{{~l(q$3PSy*5@~c~N@0LmW~g_=Le>6cb^ z_slGFzD|M0I4#qXf^Ypq9H8xA_BbTAI26N19DsG;9^l~BNcWcd3h5sQH16Ut8Vl94 zpObnC%EukA8C|>4K!i?p_e!ryFE8lki-M&NO-9nDP_)}9;#km&cBVq*MUrDQ2g|GY zOY){CBgO*~PLiqZLdYi+!ad`b5)h*_Sp{vgk8dWbdNAr@vwyr?acKehI`EA7;VT9#8`T(+nR;S zWbh}I$*USP8QLBSDSQnlJv%fQ_NKUI2I~+z*{_HjHPBXV=J-VGuVZ#|FWei?Hw62xnI8$VLxr|hmwGvNeFQ)f0 zYi}b|jtGBW-g+{2-~@)3nBE@!t?bNoLk zOPJ;;=lkyd_d2E(V$IIGK|F|=N(n_u6I0K5j9zEuo^SABl?J<=ryf7*2wqsMokTOZKGjIn_68 z!$sX*?_@&n6AT|JEtW;jGX7Co@FBkrGjM_?(8tQS45aPBU-!<_&RSj?b?dG{-g!{^c5IwzkF#CVH9SXAfv#$xvu}ac{SrF`I3XO$P>+-%f?BT zg?{dmw@Ci{r(}^L24bH@3heMEHe{dZYR)u*vw_-Em=iUlY`Ksr$K>Du(5gJ6jCnRx1Xq*nwy*Hvkn!EiK9e%YbZ?^%W<2nHJJPjyYa~)E_C+ad zsbSXFOS}0om;K9K)!lPH?l(9PazTq1-V-I6_~Xh>9p=a$7TzH$5X>A>C^{yVYu`eAIIE zg9t(^cycIZb>3kRx@@~tIjq{9ZGDzoBa2%px-CAQoo5@Y-Ls`le_7?tL(cgaBPVti ze4B$9OF}OsB-pz4R;O{W!;+Zt3w50lIb?u#70#^iz`I0LHR+RNwq%B5qf+V$2| zoziKatVDH}Y-*p=5UhskEt*|_JG=zhGHP`8?2({wL^n>uPHj@~TA_X3qPV&h-rp@& zXOVAz!YiyG*hJp{+C&1RfZ7g~rKU$NeMJ;R&Ut?;t*V6Fqq^xs5H?u|?D0n^3|7mh zjV2wuo3V-%P1U$`^23mO|Fy?LIycaR?W3;fq+XhmC4-&5$Ub+)@}+~Ad+%H0G^G`5 z#o$$ASm08M^gCEfiaae8PSU9Y$VfBmu{eYNQ7dPI6J)g1pMs|GG@~w+C|Jqog-s%Q zhDee=Ez@$}v{Y=_q0%+q>t**{I5*MYSNae{%fi=)Smkts*6J6F^DAV8!#m5f=m4dO!NAO<5o9r1=e_^-X0R1*TO~G``SdCxOY)-AK7ZG znP`H~a)yrjmG?3knHjk(B}T48g1M{D*GqkG-K(6|VDxGL9|}s%z19u(btr_^xXqhC za*x5-tmXST@=_`1TC9j}%I1E4Wt6mbCt+c{epVW?1pSs9 zGn%d``ZO$UEFCKKRIpO5g`K0@;ZMFAsIQ70o>vZCTQ5B8odP{g8^+gay>9h&4d{cS z?LPa5Ginorxu|nrS&-o~t#Zk-TXe@&k3LIm%p38ale9YrM32))j=8pRgkqd+wOMJ_ zZvrj`ovS@10&82q;PQBR{j4H$clr`TO&ghyImK6KZC~V^x{?-jyV0{VIqv;fCMVhZ z+$n48I1^WrRlK85TwkfKeVWROH7iWFF}x?=N#@D2Eqkz)TePUV2PUr$243^{8bHPM zi?+CTT#($dB1KBe(oKgO2=~wA?D6WER|FS+ z722>Pz_I2@l~B%S14_@!QqGB^G_%U9VG34CE*@6bC#8`f?gxFpcPnh}n}KG)m))FQhawDB zH^GCQND$SVq)OxNJj;QZcrGAlbr@!FP|c4}P%ChqHYqxWZMm$xGGjIt$|%J`I|wxK zswCqGZ<8LKAgvX2kaSd>sD|o zbhw1~c=(|j#PjFh6A2KDi%2Ec3py06dwOccbI0!R_TF42I6l=u8Xplr7VneBwXX)C z8+*%i)EK-bWBJ8Gq%9epvFvffzVfe%?vogFx+Kh@ejCoSsIK(>P-KKsp*|1X;ijk3 zKIG`-2sg8eS|MUzXcUAHbayDy&EekL`$N80<^IPeF8FKIV;s5W%q&rFsO`E|J-VjQ zy}!t^W_xS~j-NJ^bh5$vReWY$jdGq+yNc5+(Sh+2dt2wua|p>pzON7b=~RKR`uQNI zbYq`OR+mC|tX;u`2MY6T8WDTg%t1ZZO5qu`&%bkjqC@(F{i{=VuLv1`Dcy>TdiJOJ znC7FJs+knqzM^>>t=F6x%e6)C1wj&1D%hI0n`Bea3eV>8RwZZf1c5jrV1E4aE{EVHnZ^V?j@UJL_h@kaK1SEI`#|rH1aPkEiPgg zdvK<{vtoivm<7|$tTYv(H`w!o)B9teK7FMeB-JI_WSwo#v{rx>K9Wj2e#%fP;6>PC zg$X&36Jh7n*&5yVF*0hgb!qNZM!;wS(@Hh{E)L<1ueTCSOApGmvBqz7%Q@A`?5d)U zYvP>Tp=FHzEZ0TTTf&ChaZz{wbmkL>B1xKkLrbKbps_nn><5!77xMwS))wzAx5~kJ zunbZLUgbFjQJf^-z?`8@ss-St z_>cf909uAcn|!ZftGq)I)Up}ZTPB9h&wo6#MCs{MLdK&R#dePUFz?LBHabT;>)DR! z)an#3mHE%dbO0Z^sdDXA@!C*Ozx(>I6fb3W|b)1V~y*9%*s1n%+$;8ZDam;18FJWFK^8c}UYX4CU#rIwy8ld+Xy zgT4CF$_}rDbY?p@A_j)Y!fRtCkfX~FM3-6?pRmKp^B~OkNiisQ(}lZB3GbeRIxGX0V38f7qRwWgvPT?45&g^OCHogEwXsJ7 z=T}rYgZ3apP(#5uEx~O8(Vj6*9aH?BERG}KNW+$?uhmRfCMBfi1xO%e?7DqPgvAVk zmse(RBDWR_hY-yk|Hb*@*RwM7Y~f|8UqP$&_3LpQ-|JPnxU{h{z|YKB6g=(d=-B6U z3)ByGRkLub+zUM%Sw13f4ORXx_L!3v6%X)R?9m;w-D3nTQ2y=wi|VV-b`l%ID7{9S z5gGb}DA=4gi*1~R=0bWR zuXAm%C#y^tX^S@E=jCrdsG#rq$V#{S{K^oWqn-i99W3}ES>l2G85)IV7Ao7 znaH!Gy<@E{-0Z{YGj!JSol;mYjh@LDnjbtj)mF(|5W=i{5GmPPlO*$LU1}J>CAR$T zo_OGkJ*X|D|C6JZTlXke4J%t=?9Ph9ZY8R!8cmgmM4LCct>$#@Z0;^^e-aR|YQKtX zH^ig7A-0)-Iq`CiC$SC}DJXW`OTAlbFL_K}SN3HPGfmN9Tynfj-XBlaOh-tX={ z%SXz7zTInUP14qn*(N9H26fLKhw_o8#L@*x<78I8HF5dp5~DsXk2U0|J?WY8dd-^y zPun{>&T0iLapU0H_oLNyfG)4@)_+bd4QJ@POb#E44A!pEc{(IGd(#2)XvlZxqhOsH z34AQ|2@fXkr$s712#XHU2axHakB%W>!QR!!+dGiUN zDKV>E&~p2ByHK;rbEBlMHLs3le!Pk1EFU<+=Xe-rLLlYEo_N&|qScS9OJI7f3qf2f z3~9&6A=9y5I;xLqxMwYWcDTU20>>U)F%M$aVk%Kx7JXzfLO?a#nZ2$x#VMveKhYW?p zoOaw+lO*5pX>u=ezr;Zbm=3e2Pg+mW4UQRgZR5dIy#_oIavj)1tH4?qq+0rNIM&idj9!jB>)j6fN z-~{Rd56yl-*NTjiY6rCG0?rzwQ;Fc#_(%uXlBWS^9sg^R`8&}1X-^@?-X81GIqtYQ z4{+dBn`rNbO>dAM4U)%~!dkR&mx87Zt35&>Z_Qps$sk1zimhn#z^|sCmOMe1HBz1T z=OcYG&}Z?5AhK-qip%g_1wmABm}T}G=8acmDWoGSqoAu>)!n>8Kz_3pOTdsWuZk+kM9Ust9>S#r~hLukiZ4pq{M^jV20>a_)9zKQk*CKDGFjpTt*Fg`D1k zpPQ9afMq@lUI~iL#2qz^hxx>?vU};t2?sxBGdI0M!=t*s;U(~ zONh;gn_=cG#47o4scp=j1rKQ?2*tTJ2xvF-byQD2(;h1%o;6YzFB@aMJeuYD9*DlsGXUmwyFoDNgQw;4 zz%Rm<%$y)K5(h0e2<=CT+}=HYh>s-ya{H~_HA(9}$eW&^8}M7*72c0b-_7PKLMa$u z1&hqrKqC|5yop9PSiigD6rWR7&A-L||GWIef6-?C?@Q49GXZ~xqTA_8H%V4K=evw~ zX(1t%Q&LiLL3}&zmR+&GZkZXgrmfw7m9(MV>r{jSd z2~m582tHEzml3|TrP5TJgh?G4swJMC zyR33Anm`=7PrBQuNS?V80(pGp>?i$gIQ~nICfl~c{om&H;21z9_C7L80eIxYLwk9-7d%gi+2Kl`2)xmZf?yq~nU&w(cb38<6{_xF zKo&aQxOt)WCJ%g`&6WXt;JM%U!0%iwcvtm0D^HgPvmPd<`r%ZKb_i$et&wOf()Vru zs|QKf#*sj+L)LT-j#l69Oqok3bId zz)!!rD+xL-9;uEz;3M5X&94ReGj?D5AhHd&?ZLyf^%FJJ!Nxa>Nz&azp91Vwh~n;F z%Kf8H9bbIGij7MYpW3?(cSkC^vu@j;?zi~P8Xk-Y?8(KOQaD=Rn=_6c5-)AiDs6-x zrM$wDVdaKX!cM{RZ=kpKO}^qMjj@7G()*g@{*WOh@X{!y5+#dN=`{qBh6i-P^&c} z1om8fqEnv*U?TDPN`XM%{BI6HpPPl6h<`7e>ZJ0EBowhO__>1~cA5ZQiosZxr zJugodlKqcWWpiMcs1ZE?s_))hNhqa9jOSi_nNR8JlM_YtFVC#r7`D;Gk=7?_2LCh^ zu1DV-eA*KxQzHR!{44;*YZ!6Tqkl9OT{sy6x&F3XbSuuYb7#W6d)sk{0nYQD0&@1f z2!eHmYKG5+nIP|)bI;D$)Ls$lbdi%PaJ5q43Es*BA2Qs**t8vduMYQkC^F&j>?R)g zfX@+?1IR0~5vcXtOFgl@C|{G5PGx;4rC2FaUXMocDIKqo=xf)<-3o#1GkY%tl2!w; zxzm4GZu;!oCk07+SX{xce^bw3m|3Nz!4U81zxy2GI3Tm@{+8v`L!}*l%n)`wdklzTMUxgw-97yy&pDI1q0 z=|$I1kMMzg{QK8lSMq!)@wL>ed$lA@a|T@$Yd% zfAs~JX(vQvcOD#FQoo-5vUJepTU+8F&F0?^(C<I1D8qf@jCPm` zmnhNbn*+2>M1hEA?)S6tZ>OmKWzUzJ;i`NhxP~9=*3tkb@h6A$j{8F_)aXPYntm4n zgBuwcy>RFMyR*)^(k%|^HKU05!cU_8t5T%={KFZqUn{8lGCq;scowUwsaX{T_G%N2 zxcRoopXS>+Ai@+5n@%S?X3Okd*qYsyVaSz6(W1;#usI9I|8((lJteK!;&}kdG9ScxE^alzB<( z{}A*Qz>4V}_H#ropRJr9@%FjdNnM;5K>)RgDl>h_aFsUgT1F(Pvb&!vU?JLRh(j zj;QVLl(Jk>*x7s&zmC>Z?VCEZbTaT3O-OTcQDlvJ@$DL~|F&dr^pP63V^Rx|;1~xO z@PCx@U>j=%y!TOJEgS0iFq&6yHelyB9G`3lWQe%#i@Y3aVNFs>O2Mjg39# zZHDyQ#mhN;ZzG`&I~D~F=qOno$~n|mCP@t`Q%+6I{3_Yo*Mf#_NwgEI>nzdn4quVj zzlr@}LwU_h-klZ&EVbr>Je$McTE#X!)_NAdBYQ~cX3bg%u_|bIKvuAOuO5RQ%ref6 z3yL4-gg-N^;lFk6R88+}!1aHti*?tAF6UN|{T7A_Y%5+5#$1(?<31yVWcxyzF`s@9 z4~M_`*8V;rfmD_8v&2Xf)_Za?rS}t=$h^>(9s_IdO7LD9%dQ5J!IO|h|2J)fj5|ZV z0nLVZaBwCzuIPmj6Mm$KfNb7ELmE&jA_hSq-Eqy`hx+N|W|})9n)sE$UJ33`k(Pk4 zyp!}=+&6C0NlD!(-IK2&J=uGG;`Pg1i@Y!#ZFuH8yUz(=ouc0O{5Z+7)N2zbOkDH(qAxtjakT&tDIl&%-L;2S0%S(SWFh}s)~+cr=f4+hDD z$L<+1KGKbhf$06nLBSZ-58#XNYL31VW;!cpl$Sye;N=O}{5RvjD?PaU)`MVJg{JW0 zDgojGI)zFA6N=XuU!ReYxj6uY>A#gnxYGTo5F?KoI$7l>{JIgP1V} zx~j%$fz{_V$W?7%|VnWE14EG~I6eS~FIcK(nrMg9Ci zwTFP3MTuF5uUh7dpY_JacN*Yx6h@B|4f5Kj79C)xWT@qOYt$+h`;2q^CRJLb&`UahKf3IX}4n+V-1EmjfS2smnmkhr~@A@_CwT+=!fRty0 z4oG+YPW9CsN~|(ud_9Mvd~dY=0Jwscd#b&=I)9UlxiR;!$|HSnL z_*;oJx6yd+5N2h#idxIeeOo<Z0_jur+uX?J;{8m*y zvA>XAlk`I$4_x*95zeIEpH^1?lLgcN;BkKkkNal@{15IK_;0cWBrbUslkKx-S%x!y zUGE`MW)DWD_aSRnJE8*z|G;xS&tET*80<5|-@n?98dT>@diVT*MXZ^&W4(0H{X~H6 zxwyEnjY1&)XaPW~6d(LU+6eBlLCLA|Bpk73-A+Tx8z+0sz zpXKQ~^HSv5GV8TBr?lQ0W0k#xMy*RuWnv*s~3tG ze7G!?x)k;G=CuVfWdnNe9;9Bbkd|fRv5zhC?A9chc8ChVe~zb%VVW&CD7mSHUXe9~ zzYYA$u2Hc8A(a%f^XKBvlJh^A%kG^B6T9SVXY}yl&U4*8GiB)PLv3<9+hRn|8OJhs zAI;cWUOW*kucOp0{O0^a?28<$eLBVo30lvt?YZUmQr_KRT@Rw z+|aFuRbbB>X)!laxA=ulVjIm43sTQP=Y2)M0@&`$^A}141&ZNT+%~86we_amcN;Kc zQobN*R0j$N(0y+e0%<@qKzq){-}Mju+JXb$5!25VE3isUt~EZhyytaoK7UA(B){%d z03U!d0BHOlmFWMUyN3RooB;pNwN3pq0smwH|I0fE|JefnJGKD)Sxo=$&~HVc30Z#% zxf{f+qkj^!44x1C9>f0hAKjOKS8@b-ulN&?s4NbAu1GwZn`RVu_@zXEF!2uW*Yv6Y z$8&Vq6`B+P;NSgO4)$Zkv6NZMVp&0MN5a~E*l*ynjgiq78a-?&R=N&^c{7=VQ(HqI zCmx$6hy6jEqrV3J^j_e_@Jfn$If6IEdzGL489H)v46YSm*$<^VkuP1wx zjDN9%;7feBzSP{uht>7MaTifU2IM*q5y)`R8v(pNbX&D>z#Qiy=ndJ@CSS4RS093P zch-3LNPHLp+VVZ`q@$MMIs>&$O(v?Q_VrF1#R*Np zXS;JPEnO8jK@WB*TT=-=`8EJ1Yn0!{y7>wp_bTAK=+1v|SGTC%j#jR0szK{2=pLSb zFF(m^a=PO1rEq`g7ZQxIbK(o%e&8g>D#R_+_A^iH)*cbL-@V9fB?Qve<@9%`Y!^ba|pvw)^ZlGoyv@f(mF|U zKHd0C+4kTHM~w@HnwxbD?@%Yx4h6(R1Nfxf$Dng@Hn zl)5Sy)Wx|L0;#mI&2p->%=8JHo$WLuuqy20ouGPHvR5o{U(+Cq;1+83`Bu2!)hw&J zpwy~kwX-SS%wTTh2wrW^VC+G%S-_-cw?@ znF2h!_!^4&dahL_R^qr?Fo9=)h_(3c;1%rrd+bI&6v~NHsivE1<9Jd{t9<0&f9eM&q`sq(7Hvv@DHE8 zw@~h#UR|$T<-`E6-Z1BO{I-p7%hKGP-M}&oi1})pS5oN}tb> zIG1g8Zdx6CoBNi{vC9Sgq%#-vzY+OKkAEOD^NLRi=VnL|VNX$YPN#pE@{eqRQa?P_ zj`+zjGs2~%sw!HDI!+F+ztXy)h`lbJYw5-qb@Xni__7=cqBOsz!2|tgGc?4HukkCTE*uAeVcQ2+)~^y#yr^N`YzDDaBD{}t%+_0ghw0=+$EW*Fl zWHW;~^{FUYHfOmWR{1roYCiB>C}Va7bb#j(1>;xbmf2nKmB8Pp@9nib&dl!d#%Ci*POsjO zI`;yhe&gpx^QL81*Gl6qP11jLyiBG@}ochuR{ z=*i&iS_e$`Ux*iLSOlFDs|@G_j;T6TBew*!b+qL@n;Ek&tS8lly1WJY>VDpob|Sbr z(>CTiSeCtX8`mW=?e)@1q_1!@Gul1Z=hU z%b-c*TI)dYICwNvyQxRJ6$@V7K@c58A+b~>_W5DXtQ;pT2`J4f5jP5e45b$q`1I=+ zAgN_1LA9XQO~fgLkNz@miovUTORNR5*s-9u0cozW-$ZVPTn~2%kx4&pe2KFzUS9c# zi_i*C7;xkY^qE*;lDj!cIO|hIJj6xjhtxCqJ-`{FhjTWPr1eC5tKK_<+n~+;y6A5a z{^WKUqyT@a`*+tUU?y{uhtEmE+3&-l6Jf8Jn^b+-xi)}+k#Yvx`nw(v@$fF?fmrSXbY zuh|b*gIBd7U`k({;oFMSzx-MIEYH?2G4H@j^KmFP;p#LTeP(ki!re)4t@_KZaRs15 zKW9dF9e^#v%DRd`o~^e;rT_~CI>2AET&=CTjdrfZ=&b6gfH1zX8CZFS2~SZtRa^*; zH!UznBwEWM#u=AEwkhnf%{tcRKG-)sJq@3}MR7%K$2@wn z4buQsy^9hJwE>nTwOv(i_LAnZaD9?p6@*T&yK{BN^J5E=T>HJsp|2ub z42qTYW#YXocONAlq3Ymue9Jksu;{d0{utO??Y9vD6Cxm^1CS#EY)p57qlIWn|3x>V zd)r-Sr*6<1=L4)PpOsz-@ADITT}tIxS6MsfUB34=fU*K99jPZDMNvY5t?yOUr}N3c z(CN-Q{;jw>68xff*KLT~fU3;6w0L(Kv==-gPE0pDOJ6W}fF|K*22ka}tShmp=rQGt zEYStdU`7fr<$ge^uVFNBosGgH9?JoJNR%$FkV9=EFl`G8XVN6<;#yD53q%(V%rK1U8~qx~wY)iw*x>XM9W@JJ4fqoDay}Jp2`6gF zL@xuE*K9_lyKi^hmN@(s#BeYm9vs1HF~1xOX+7|p^?^eE)j zL@ED(Ob!7N)CHVcN?ol5lz*@Z1NMXmo&fvl)3swczzzHB2B6*4q~r^+mH2>P?tTW( z%3#MEV08E-gi%K%+i+VnB1FQcfMMxGMfumSH-UoaLvT(0&rZGfZNXAac(e&D)tehg z_;NISAip18VdO?+6^up~W`)bmvR{^73`LA)D!B&x!eT$m7ur`j74|W^+Za$zA(uSf zHJSWM7M$=mpJ_{jCzE*$a(kKj_xgKp-_Cf)n--kIwK@jQ9^GU=AXQj{+drS{4N*ETF6lG2UR-5?+x(nz@uU@@Ek`NbGc=ZYr^y(Ev2P_Que_ZgaUcDlE zB_S-RGF{;34-)aHaIe+Zf-a1Z!LUDwh$f8R0l z?jsrz#6LgqjJ^LX4E*Ayg`Rmj?{HIT^Y1PMAThMV|NR8;(IyIkwVH!t!;ODe_X2i6 z0QKJ=`Y!F&VK%cg*c0_%50G=>g!%6e9VWl>n<;Hd2qXQk2V|bwBK~{aS8%gz5b$MM zj*R$X|79D2wJn_gItN<08L-W!V{P{E|2i{ZDCYk))c-w0-OS<4)}BCjbdZkcJ6nXq z{}V>QFWe-$4joN44_`x58!!C=?Y3aMypbk{mtU7OhWD)09j_0K+!>87OtXBRdvkyt zE)+y^r^rUk!0?`pe?K6yH|yu)cR0FauCeLlzWeCEL*^q2L=pP(l?Jlj<>eNY!YLal znL9vG724>ka~C2bsX2rSG#a&kFW^@2b=Z+<>%j7t(+Q6?9#rp;V#|$8gPt186K&Pa z8&r4*xg*o z%d!6QIsNU?fQ}Q+BXoDjrr46HRgSYy;pzFMmyFZQ$OE2T{8L~~fv4j7{>;xn?*tIvq3+8>m85sbF(Mai%o&0o8=zk5>$EommEN)%(~~>+cv#+<?@a@PS_NrtQ}3>LAgCFQIM}>H80RG z8+$hS%eu-6tT50s>#zAMbv)df;84JnbW9!8S)T|7l5}NT60#Tit4N!*O-+gPlX6jD zJ&BG8&MEjs-NX@~Y(2R>)4*?!`pEJZ2O#6CPTt$KpG*7=PlthC!|*3QVzOhmlkLGu zCCR)5R&jK>_JbWKb=1)m>={T0F?1&UI`zSC-6^PFT01mE*7nxIbv#@1yGoNdAoD^n zm3&nL^BLmkz6hX-oQ=E*TkcHses{%RG!Np?)6+Xs3Fjk0xxqOgn(G%y#W7(Ey5XXgn z@3Z2-D3{0LtEZ+~h3A(U#dzJxaMIw=1bTTK$76m4gQ-NeF|M^I%XtC1FE#H9Jez;y z@WT)@g%I9{!glmmC6v2&ll{Iu9aQR|eU=|zjVX&|@zrcvg!0sKEB;Hv zNf=|<_wBwf7E;mtcyFjQ@!t_W7VR|!U*<)!$!Ov7G^IIP zZe4wDL9CtjAS(}j&`Yj=c5~$VZPJ}?0E02maOJIcQwnVtOp(#M09v8O!-e*ra``{e z@G;-{oTwZLJSAhw*S8h9a2_pZ;c~ezqNJxE!#bn+-&?@YbX+fZli$xx(t0inM{#IR zg;?n6q1}h4hCPXmuJ`6`#6Bv(TZuZuS6Dvop@`@vjNpW(&Q(#Jy(~Kix>&&EqiHj{ zHh&+4_>4FGI?PPtD z1ja02f5VlbELA{pXS;0G#m6!WGHfcWz>?KsAqE<>vo@*8-((O$Ti*rI>Ez zZQkcOC@3bo&$3T-_N+NV$)%6Z2y3WOvyJAEwmXPQ%MI3d{v_=t#wL^757}&>C(+^d z^iTX7t363BsF)RcdtG6k$E(LrVon%n!K4KYR2|%o>j^(qsMS|PhwZw1niF|kYbrTE zo1;zUt@dU)l{s5ApTbu#C||IOz}C@cz#3ChJ~inz^gPCCRG4q;8cwUimfgPT>=DU{ zVzes#9QHf5<3VO_{oAxnVx@4_h^y5`?^3U|xl|-cj)|YDY9PvrndeH6Pk=1SIT^-^ z)p9{OSA)gd$0xT-R*+spUv<=y;#A3j>SWv&*~5%4suYi%D_zxlBN*m5*rMb#x&6y^xz_E6$8bd-QOPO%Uh$QDYeM*De`kxp23H)D zL5Gl`bh)_RFOi05zqpeGrz!#e4ByxeS~bf#JAzM?3<~S^2hQDG>(w2!_j=30B?Djf zE+@`Ps-n7AZt^;~EuOjP)SD2BcEaV1_LKf47XtJUDcIT&0_JZuD!xW^tOt;9#BRYf zR)1X}4o$B8tPVMrE3<`t?hGg7t)+HB>ev4 zb&+jqGIK`?`{>u07DXeOZvO^_?&Yx==91HAhl{t#)r5tx<_AWj9Q%3ZN(~BrakyH{ zP|eQ0sOF0{AE)LGD(;So-k0cbSx&&0&Aw7?QuY)%bu39P-poipg`r#i#v#EGDT1CBo70` z7l<+*mj~XtFcpSa!KGuNx^qlP3fuk;IqmXY?IE90?CEzx9;g6Wt+t>NJCxNEeS7>n zl7A^FD9}q9p=|c|RQ3g|lT*EZZ*Y)Wqh+0~q)%c$CTk-JTswLJO(5=EvsnR6tHKPq z4b7);bBKX$27NzO&3YmRZSe+sp+_1|y)jcmidl>`%-*6PLtMS>>!x2&YdZ&F1zD(x zt$GMu_sg*bAF7Wy-|sLy2XUge{IFaAf*p**5z(o%mP$TlLImX4kd6z0_jrC5U*zwt2xse0+j)Ta25gmu;i5 z7dj$e%5CwD=$CT?Ef$dX+g3*LDLor}m)?x#a>dg%7x_&x@Q?Lp_7#~dZIYu2k#y(N zMSVuqMx8NS{qV$WKw@Qcn8=Wap`C^ioDsy#DlUT&nphCPSH?&oPv*OXL5zoIqq=GJ%adI%T)cMWdXlLLch2Y{bO|UfITIQ+c zh*f;+|FJ}nAd1{bcgBj>7dM1`cT4IK^nL0a=h={ZvoC(jj}^4h`t-iYb2cJlT2@uY z1I5{$*YH>6wn~EUDkgob?A&6!?e>*ORgcL9#$8uWw|@V8+DC`$N|Ixt+iq%@BNu6L zhn7;On~54vCYxy*!+Z`yQ>6z_oW&fZRIOBE_Ku)Qas>(-@9sX2cd?4^wd3vG%bo6t z9?LY(>~%1E!=B1)9JdrgMHJuAoCNBRx*)xwvb>Z`X*5*pC&7f!Xj$k<)5 z@!`taCs8*0ML{?H#!RTF%zFs7&tI8H6ykbmbQvk7SByUkGiya+l zkVD-%q9*ayo`nLsnajyCvdTO$d%zw8XlzQP@2)u@0<#|*n>&!S-GI`@KDquK0}BnF zv#p`5;1 zuoTDGNu(~WEhzkasTfnc+V)uxa2Lqc4e-Qrq>24TC`wXB}DC zOj0bIpgmL2hskgNL#gD;RB~ZYBRGe=hEWo^9B3Y&o~S|WllqLMRDP-=l=+z21EuhZ zSco;)zlLGw+PtC89!^^IZ;qF6n+G!fgJZd$0BwxF^G8QfHlrduqoL|+ak#8-k{aBs zBGt0@1F_UTRxNiFIjVPdf6(9i0|24dtYlOmntKIGki-7(H5M35f?-sbqj|QWbYA=f zMjcThp&!!p{7hmGIvvMGGotY)P+#PWetS{sNkR8PL^@n5H`YVi|MK$i;=Vb>P^3c;+s* zu~aFp5m3#~@e3tL5JMZ&n*ZriaVr+aQce+K+;@!7;}+szx5&&^R!W}>0TSa01+Zw|(wd$cV7+0CduL^KrOj8_Q# zE|$7aUdJX5%kdGKQaprZBCbHVCP9Cuv4U-yc&}z`>4F>gUm;S{vUrL z!uDY-AHQ4f?W2}L{m{Z;+M+Qc;B>Nx+|#9AWPQJA7)z~L4YFI}fgu8~L_V67Ny4>Uu;cN+G6~Um;T5lY+n9k(`^Y8KNy6kj zf_KP$jsPe^TfG7R^SLYogpBeTV@+?>Pb#``OU(E4MQaGV*saoQ!Q4@ z5)Mhyrr?C`ihg~D99&=j(Xe004<0l2>gVTt)ZO_STFb?HZ}*4mq!{Ql~|xF70p+ibAoP2CedH$R{h zv7e|yE7I8j(oQi;(Y-_KwdAgBuZPIVT9viifw^0&Nd^lP{)bu)_|~(+^P6&@UYNg( zSKjr|26R59Z)2E>Eyw=;Y%B5|-R391bQm`Ry7e*Fc%Ls$)IK<5o>#S6t$f<}?qj2O zKwucJE}9KMgyfns1Y_D5r`@(dpQW1{PXb*cHa%675zN3L;8KDgUgm3<`2Ag>`}aoy zOyvi?i73^QbJexZJMxD80&~%RiZ-R{d8s5NJ*8{B-?vEy;^}-fIU(hI?SfW4ZMe_K>I|B_ETr9>|e~~&{au7=Is7c6L^Qh!M0->H?=WH`rLGFWY z*s(lXrJdj6&AdUCAMcBwTFJajfICSwj;n63s&D2>zR3YcveqN zBDzDcQ!v%Ptc3-IDMHT-Pbqu8J-G{+IlKBzUVk?FF3-FIq`N-G@KZT2wQ^h8T%ZZ8 zgB-3s%yqJmgY;CKZ#TOKf{;nJJn1=p^j!7em+iDi*EBH!l979oPFl!kfjTNFr~GctnU!f`}MGt)3mr^EoZ?YXzocQ>KGr9pcIc!nHI}v-(mj{ded!Ope^3mxhnr z`1aq;HF@6iBYhe%S4T8Tu&^+Yb5g#<@w@3h4JY9IF`gsVIW>j(^l%e!i-{WJfU=sb zeX#pxy5kXA#XP+8ZV*n?ShFgc7H?+#bJ=*?;bAxS@IF`cX>iJH*If%q*!$C@mc8|d z3sv*(!@T~Kv~FhobrN`+Xx|bF__E;ioYQ<{tHpYokJhWN&bNn)%;WVc`5v2r_Ml6zPUT{km0d=kW3-zH62hzyMC}Vbcp8TgZ<#7!R?N3f68g)HOO^)(K zD)hfgG*n+}`43PC?8QkZ-f2X)W!F^H+wyMYA(|XqYKvfhC>qQ|ia(?^qmqIxtG7A7 zJ=CSfzWLnj<{R1Ld)oTuNbbq<@2Ehy zs4o4Z)S%Hd0$vx49MQ0KG#Jbci4Zx-GOXX~`G}BDJt8Tw7R!qxyDM``xoR+T4Bh|` z>Q3ZJQ0cVr7>%UvMY4h#MMFZ!0mA}$9w^0F34QxjEu+?jeZ8-uA?BVY!Eja&xEpra z;H_AAY!;^g%2V$v*sV6f5<5{u?jCRP7BWg+0*8;jC%4!Ql*Uv`I7-b5mmc;;3*>|f z*g~wqc1xS8nZ?MduBqi0Ttm;9XRd}Npe+JY7Y6+$-o5)-6konxXDQB9D-_=JeFnvq zss_NbUkd^c1no~1(bkOz@_$S;k9n0h!~PIfBSV4m4hk_%Zyu4+Z>B;_UUY)?lar$h zwsIzSy9DPu!2|<-j!=+k^=UBfaxP?V*a`T zZ9j2va1f%^^nK3BOwC=4l*!ZxQK&OxQ019LK%SP75x{YWUedoCiSFSxw zjzWu-7G7m^L)epJFTLRH;1Zqq$NAMg%p5<};FuzvVSNue6N}#afj?s} zBCRd7cA8@XP~d?QQT*gOi_HQkTzRa66h#;-azA z7o^jrO6_hG3P&_ruZTotb<+1;_1`!M0k(oT2kR@K+h<5T7fLr7bajW|zyI@O+#CV8s_hFS&kBtwkej|K%}lQ-}RT=qH4nZVcUjnKSBGvSfts&V!Jhv zM|Z`d$|YC+Au=`>HaAhiFD6DL-R$|QsUcZ6=FZw*Riuuy^3=8}IoMm@CrdA=GsE-w z*J3KAYf$I$Qd8UobGHt=kV}|EP*Bipt0({S(~ZvNP!jt3fLw4H^QQSjTA-CGv1w4b{Soqbit#3DHMBxIn91#c^O*wowGnw8K@p!&+0C)mJ(}VRb#Df&+O0GhKQ=U}*9y@MAHxADykR(K)^W6CXUs-D z^94Q+Kvy_1Ol_O(QcDV%*L?o-5ZpHgI9&EWD>X@o zyjZ<@Y^(Bb(2jY8zpYqBo~}G8O`ZSL!1d5^tjRB|WcV&D;D4I#*7Sp-;Dgfh7B=^O z(h!GVM~bu2JuLi*F6JeUsVubbZE!127r!qFDe09o`oT9vz5bZ14j+D-8$Z zQL6d`1qFLRBaX#^0*_$}PV)|Q(b)t|o}olP>D* zJ1$@1PyW{NGic?*YNCtX2f)KZ1;e#1@H-0*#Ej^I)T6wJA#gifx0f8dei<}Q_R(Em zrJ)zRYYYLCn2ZjoHDzWuoI(hQk#o~mS|U+4{5oBeEh{*is}~|tPBmuPB*y;HUN+DM zuqUI+v?i6gS?lA9J#6zbE8zQ04W7|YwfpqzPZ((XDv;~-p?7O*D-4@%R1aDp?>T}{ zzzB=eQk{;gQ|(Vfb9T1~XeHE0Vvuo>>a>CX%~2<%QbqZdE^xs2xu-xBArktV3VT(7 z@VrNbE0~+YNz5Nfd|+EqwbtazY$%zbFPLDy-?vpUsL(B3_vpgn_MW6;>#iDwVG>k;xtK`PyzT?N`})t>`k# z0k~vK_}gF15T#pF^-u~JFV!=`U1?2va#_U(1s&wFG6%n?%+{^JE1gIe(srb*w`qm& zB+PsCt=%&k`uq>4GlQMJ2r(M$`Pi>Zwg`$TWRcN+-`8jZlM3Zlk`rC**NFzWD`B}T zC^y$QW!iq(%zGzV1DVU5KiFRpxRUt)veIvOSnGJzCK>VI5HaydZE^Szab>t20&mzw zCM0Wz@lsp5BYR)v2Wlik*foWPVQjR>1lHzr|8y#9i>hS4EeQ z;2oVelnu0)1ydv|l+eTjfCy;5|N8E!!eG>GhGevx{n&ArFCPd-kG~Bahq6jnX2?yl zcJgvszl7o=v@`$;^5X2I)4+`vg~UYxHsa}~#Nq6(>Un%zg{##+Dl&88u>1UfF0#c% za(rmWbHv)8DR4t$xW@mhY>TENTD(mhlEwGt%fUU?TyFe#Ma`(1rZDpw_ZCrr)0X`w zWjp0)N#trwl|yk^Vc1N6muG*OQ&rY`n=UvTI0qAU{!{0*M`zQls{R~a6EV>zr%P zX5@6{C!hO5`+*OaExchVnXV|<8fD?q5K9eB5(9B&Sk4~$d+e;y70tz9aW?d?s5KP< z1l#SC(DE|`)T)C-!5$CNruG~e@(b)f0to>~Ab}nncW&6`s#SE)u;6^nDWw2tXvzKy z8or=H5QFk0<2q6~?TUY@)M~_y2~MKAu7d=j9t)6tUAq-(7nr6O*Ix`U6T@tx%d z%@C~elAiL~x3U0MFYnI_IpX+;w6^ehR(-mm1n9txq7#r${>Yz7BE4kXNJ&WK>MXT_ zttcLLZ4Ly*>)l6*Xb${MtewflDC{;4$TE4s5Yf~dkW3&IZ*@#@<0CbRn*bI$2!;<&_b(g9iV1X#s;0lFjtwiFGL`cD=hFYCUbjkhL;kGwwZ{T`1z& zdv#&z%20oka2jE?D=BddD7*&%Wi{t7Uvqu*#^@2R$O+Vy}OGuDLTrM`fLg1H)CKAO#A+U@mS~y z^3%JWjE(skGqvh(QB#sui*tic^TyGFPu)@a>$}VpXyw?D3cil3l*y~kh66Ox12yqN zfOlPf{1v>Ckc?zwMXHQoEk=d9nfc8qk$IQ7Ph-d+Syvt!U^H2<(VoiqrZOfn`6E;v zFOrYlwBbe@TGdTtwPN;a<(yc<4xRtqk+x(TULMDNFBEJ><51@Eda|yK787tJdPyky7y}>(mHdbw7a`1nA410a;{`#DA(JKEC%&-;V}P zwdNRwOJ{@o{QP_IoE^>Io)H4;k%IHeTJ24U_Qxy@yi_~T8o$a>#i;ggaNWP0|Chz1 z1^l6(Z#R(bcgG+ofkN+8D~VAUxk_H z?`+=nytHUdNQW6l{-w^}nHudS4{iGUr#Db7Wh>KKj2t84x1s>|Iqq-e;u*|??@8iq z>0r1K%i)5O7)XWzvXsxIg4a>m-y-MKC~&u%QSPtAl4zrX)Nwm|jfRdMhh!cvljW07 zdfnyhqt`8gxGoF>IL#4&9uB9=ozXHZ4;Z-y8)?|`uARf2ma3a$7n277eg5G%l8~aP zv*ll*wuh2@J_WqRy=rODcA0QMTxZng=#xpUpdFbvB!LhkA`)@x^~i#2G$$o^*!~3A z=&RUY;7JaV1E*A|1Q&wMC<=7h!ouY*);FeoBCQ|N1+mtzKiGr-A^8y=us1$SOA*B_ zWWexDuBI7vEYQ%Rr25-ux*xoahLf{^Rviwrp6@twehbdxPwwb+e|%r#g{oIFeA@X& zgCEh#CBUG1)^*%ZXK&`@U_i!i{ElUY;-O754uCSEzX2V*r_YH@5CyUsJ@ND!q2c|9 zAz%VuIyFc1S-dn-ivrDB7#!HPvLTi#lR*yC?REqe2v-*WjfYflIMM>wX9j1du0!OmhMB7&sxI_Vg=`(|~8LKsk zfHfF4H2ldf7&hR!2H@v@$=G29an(2K50LS_K}_80(~?+Io_qjfUh-L|8d@JB1a5Ck zcUp63fjb4R(kB8=itzXPfFme@Tk(_e<}M7apV8+0YfAhL$E@xI~K`)Yanh= z>FJIIZk7a`YgIZd@ck*jC$>*sw(KZyb>OeAO8`=WtK;kO!{=3fkj_6Q^kR!Gf5uv`-dpbufrW)_Yj(Xs!NT$f z1_zy-ov9(y7VTI`xgln!xIGxjRl&W? zyuahto-d2+F3? zr>?F}5Le#pJF(sfp3jLZ7!EQj_MV>}K02S1dAvM10%~8UfbY}eW4XtZi<65BUJCgN zDMS$|kO0QW6PvLxt=ftT2q%YA^$t4_Fb-BFFD(TD__kZH)r}rZVtznwQ7QbLr$m#` z-%pmqUL#-$^yMcWrSUjd+CrsRiq?HjV!`3}0C~&_%|nu4TL^ESm%wb@Uz$Rdsa&yY zWn4lEFTExBnAvyS8Gt(2!9 zA~E-BjbLl6|6>iNB;W$>K8K9bX3r_2C3Cxn7q(iqlFL6?l{q!n9NugM(ODlaHh@(u zcnqpcy6#o;GK`@ir9b|+3hcsb{b;sgiH_v!IJ%~D+Irp%Oi^O9t zwKc=P_$3wGPYR;0x-T`R17GG7^2(VnP^xZn+i5-YT|06_MW(Kt)L~>Z_(Wz(wQL@) zEk>>-$%lswQ6fn|2m#bmc&VwWv6FcADT4<54<5|KnAsK&GOOFIH*0Ih{voO_J!RH>y?P!Vl0ap@|O!qBhI~zAKHTwurk+~~YTmQ~h%EFMm zhY{fYW?(+Szn-fB&_t7vb{@!x;=op7R>5Dhu&R$Gp(BBh$nYgGt}Q;jtdE2ieR4m^Q1RL0dtC3+v4Z~hE2a+&MAyMZp1a5284vqE^J^x_I%U& zlI3i-VP&M?oty=X_AnAhTHg@AuRF9l^|!qWY=!mDbNI4V|(818(1BiJs@BdGh)Y7KA6KcG_409NbQG;$9DeJNnp0+0 z!;yqUgYEi*{`Q{Ee2i^1;vNR-=jWt>WJ&G}!IACO?Ti`1doH!AR>n*nL+Z4mdDvdckSlG%E9W7gb z)s9zRd=P-!qkha6g@0Fmi1gYb~Leq@zcv*Q}aIszQ|z-T4F0&WkhM(a(a`Ap*@!Ph;9 z%Os-VR;i_kPhN|Q`xr+|NnP0tKtk^)m;Dkdi}b9SVxh@U0yV2qqXz5nHV@~r+1(!8 zX|jax)JIY{kO7Dgt}+^C`WC5Q#vCh~LT(Tb#NpH0!e+B+Jj;^tmQ(F+%-r_E6ma`u zE}4w}@c`2w5BSRJc<&BBAlY7<&Oie~ajabSBc0zNgH8*^?Mcq8RXD z(t9W*Dkkc7Xa`i>k1z32^MVsb5`>qo~}b)lgO%3Y{K>;Eq(A=qbq4Mn5E=o z0q0q!UAQ5YSr&5a&E>NNji#U6C?R+G+hqdl@VH`t*Ma!YI`*p{y3#?qkyTc$*Qe(4 zQbIxJRk??FEXz%fjMpcgd_IKu_y~?S*g98u*x0@Li<`*G;;73OcJy*~og_Rd_Wx3^ zLun`KCK?#1Pe76BU7*!Va=e}a!}$=l3m@SUM;`kviEanrgvv!K#AegQ0}B2TeD{4U zuQg1lfv{^IN#kAvdagXq=TtSJ5fK4JMP`j`SOwdQAZK);Xc5F19x%&!aC64=kQhl1 zLn?belS_h!37!gAPWJ_Sjp&cp{szIws+Zgr>oNrup`iHD^MkV19&e~OC@3gi%gwHz z2xPav{c<>%uD9C>ul!mjpCc;Drc>^6drCZA%*<2L`4jOrdK~P6Qa_-G+@2d_m$hMT ztYUGB>L~h=+YAd%03zK#32^RVMFzvq+{a1ujcRcKD^4!ERvpl}F^GwY6Zzb^XjF=S zS{TwP-M6?uFn#TS1_X4)q$7`Ub4!=0UkZ7_Bz-^dV>H1rX*%OLT8dG7$c&_o#Fv0D zIA90%Igu;MA78co@p-)wC0Tb5?q;fCzgj((vzAcMbkvrrj=SGRZv?mRB_IF;ojvUJ z7h?+gFV*5nbC|3fpU>d{ckxP9qb|FoZ9-M8qXF>C)jJIi^y~`&ag8VOEPTi#Z8;z^(`yGyZg z#t#)88-Jhu)WZRc4DitUa9Aii)mbd$4`n+!Ih`U)V?K?_p)p~5=N7ENTE;%V-ETXx zTTSgA)f7>8=M!>~P5tQowbMV#SM@OI5X|3b6VVW&KA}U<2OzZ3GaqtU0PtLan zcV{a|If@LEQ}-Z%ICwe7=#AzrN_kdeaURun;7WYk@sn)#ynz%avk-Bj zZlvK#0fsP|rr^WeGE-gw%S%ZZ-Ilcbrw5z6*mJmM#?0LV_eS@2$x)l|Vs(cEY zs$@Ku{BB9qWvC*B;g>!VI(;Ns&vY4J3RV!(^+yzmeyG@!Gcro>4?q zq<|$Bnoa;Ly726o)^o3rTQL}Dadbnnl`oS31*AWaf1eh6j1Hvm@IHL=dc3=!wUAG# zSC^(2oLtX?Jz1;ij~h>u%r8pbG(IsUOo3^a$p#0~#Jq1pc2PDf5J*@gD2~@G>DNgH za>-^{Zhe*JseYzk)4E~jjwbRDB;#oOGKm&4wn~+Lp#iPN0H84Y1vxToT6p>kKAr?5 zHZAxJ>2HuRO)j54>RR%TVqJ~3mbY8DD-5XPui?7h^GA%8AlqB@jGmN9Tm^>*(eJP&ZbH% zA|DSGw?6&5XxyoSy|O(X0C-T4e+%i+yoIV>EA`rVzx!N*3ApU3!ryWGvltG{cC+}$ z8Voac4i1~nhbvQexURqHwsY_>`&HI*!ajqQ-;)Q{dcE@e9Ip@OW}98>Y{MChf#nH4 zNwocd&i1^8Tbqo>AF%YHImMsu{=rsJn(e#$p3e;jsE-B=;fGTeR&;u{QM7^b^ZVie z!0BT&KB!NuYBVI(GO;nF0mU(t0fLpLCIJ?sb||S>_$tukv;O|QhqesVk%s`thgoF0 z5|Hv{j>LM`cs?Y&8o&Lm_Tly6(OM+U#RoHG`giABAMLgg z*EcreLMT2jRrd^=PBhVWLISw?%R*dI5_riDJvtJa@}v6ZT$#co;)2;Ipg1UBmLje# z)magCMf(AKj)a*R6%G!rFOC*_AddEp%>#;+sN(onFrh^Y)NFYj71H&k`FH<8jOgj! z_H0w$LajxS_^K})I^8Vkd9WmP15g4eTUHj!=fD8dkXfIV5|iuIhm~x%Lt=noS0 zrg&xq?W&S1nu$+%0sk5mfZ$unj9Y_|{%xfx`Z*rW*PyUA0JvIrPK$Jwp%z0s?HWg~ zp&}9nPz16}Ht#_7B9t1B2thVCml|)?qWdqZqoxBdYXOAi2K{KhzP_1GXY1c)O5Xuf z!YxcKxPQ+Auz`S4tU@CZL$*^OzXrA&!KKU~rozZ(vZAfS6?V#$O34>LK$7VN_wvSYdkKU^p2Q=phON zt)7x|WJgRepL{DtF!uQPm`X15RiSc`KgY7uCy`%Z2bYUNe$~e&G8(n< zDZC5Yhl!YvE3Oz&(V#qAV60e_g8g~RdI<~z4SX(-94jwp5*8IDVQ0V2`$5;G^qCHz zDZ=WC4?x>9A-Fgp0sHas5hDvzfu0=}Aq&gX5}QUzJjzn4AeqgK#?v^IfOBF(qzYsV zRxT&2Tr-xc^B1b~QwLH&&eC&T6g!+!ca3kCfQAORmD)0q2Wg*yGr%@(`WrGn%vHzdX<7_IRcE7tuTFiS=P}TO zz`Q^def#NZm}6zrh!yiQ0PMA*M1PS)xg#(2Ppc}Wi6v|SS2Zk<>$z{37w9(=`p>~+ z=?-c%f_PF#;OsDwC1_NAaJrI5fR+ZJOxdhl4*R+0Jm|)fwpB^+k%0N}$xr|8s6Ehy zh_=_@Brwc_hXfmLh{(u|0H$2CS1o`p=AguqHTJbVH!i z?Qz3y2RRT6)2|*Rtot*1u~NFYG^imMEXGRp4PdSM{794OOkmvxD-u+J>(DJ6xV2W9 zW1-Cx+hVReQ9L(l1rZ=QhP~_<($g$DwajXiv9Z;wO(tQ0VTgvQ>GAip6e3QZ+}Dr( zY)jH+ShvX~_R6k@BsmMhYixLNYazh4PJykkORm}!d5hnkvs zwxBW_4tQ9@ts12-)R?0n6q!Q+T_pqonF3fqE!xMm;;V#3EQr2H`~o)qP7omC z5x@-N6v*q^O` zv>`-w3?@4+7A!QN{$&D{&qQk(FDQ1a#=;D9=5kV$RsfY6G(=QcbpNi-1{`FG=9ANj z)}6AabNMmaS1Gq)tzr;6N=dE~P!om&HI7%W99lUGq)qEf&}@z|s_UgH*<#Dh#Jn?m z$=emdcO}KIi^F-*e<~J)+hU#rD0kG5q%y+}VD=S(eE^Hv`2lS=!9%hgSUwM~ zeN02IucJN;<{9+!et#Q8EE`rDWt?-f%AH#^esUp#CMQKiMFk67i@m`3_1gXby5R5g z5A51NC+2CR13Y_Rp`sYi9!QRamT`gMJ~(T%umzN1m`mUS2C!Qugm-Qr6~J#2=o$(< z#1xdOC2C-AzcVckU~^E%3zF&5c!P%^0VGqa(DVDH&cqP&r+MW0nBO1m53-8yH#j&t z0Cb_?XF$pNb9@x+?2~s)UeLeM zVBz2dV<@D@D)hwyTRjsu!R^f#?WUiwR_8`+TG20$rcny#-s(1Rz=qR+c|!1piK4vf zuT_h?F0gTZ? z@w{dc6yvCvarp2hDtZsn3F922Wm)_5(tebO2tOEHpVIvmhIVM;pM@5!X40*=nl9Sv z7t_*K?|X^@TRj$5-A92JS07?TVec}n&XbZx72?VD*S>5zY@F|CkP&$c6seTN<{?QX zFih>dCnU_+t7+CmNVVAkq#O-TZD*Bol!+bBS~4A8;uB7tHN9VWZU?OoyX;Od&(5_H zH$I{#YX>byYy11r%sBXNJ^+AC{*_%oV;tzcFaBCVaXp;bls1;_3>_HnUqZ69O7MDc z-C9fSM$Ymv#_MvfF@erFE!QmiAG=Fk%O|x8SiNuLH1Hju+6qxyMbzD#hr{fcuC}{kKBPLl$d1H+LT9 zuctfp4@}S{EjWIt?))M#TyaO0O#p~Df``rD1B4M8a@|yixQN zpRiul1L0VCu>Hx?aCLJpygq|*-DJfIalM(FJ>XV0m+~k;kS=13{A83LsI~J&u;b?fps60E`od93b7HIL9EEc zZx~EFnsckf&~>KH^>Os@AGr@Ux+IXYbcUJwdJ8mYo!lqH?^^2J)@>Gue=Wl;@}Q4! zLWR*}Fh+URpl4nhEq(&f$x6g2YCXTknAYWrqom*2BS-G5yN}hQ-5Y6c#O^F<)+ka9 ztgQ!Hj^pm>=H800YrCQCv#a>v*aqebz_ERb26;APNm16zYs)@`XeK(QiO`Zyr;HN) zknK<_l-}w826x~%;b`>=7>~Fi-7XXReY0>iYMBR5s=FK*TG*Bm<0XwcCUF7~T0qmV zQgo;jHUy?IbvP_}_^nhOk4s;-V9}|`MI1hMAKd2dd`w+rfAj3YH*mvY&h6_=Tf5%o zzZWlHcE$okT_jKxv;pc^E?Hz^V7;9xW`7vxJuTYF8~onhIb6%U5US_{`DP*isxoF* zSt9cxHy@Du8^<5U8>XYJ8L_$MD(F>%jhhRtygVs0ET!6RA<*W5UiGzV1kT$V8&Jd| zakQ$UAz1WOZLa`wa)s|%@G<_g=Tujf{=gAa{Y2UhyBTH<_shh5HrR}DR670=Tpdelxz^vJ*<2l4a{UQD(lf#7Y| z38MBD{v6VK2b#QlkHtIw)9RhuofW(9qP6erLKy}V?@!;Ml~X{DkB`sR+mM25CICxm z@mK93H8TYu5OJejoFmw#w2ZViVNdw)*_uYLuJ1TO{TeevFPinb5WIz#(|^87;f9cJ z8&5k4YCz>8|8(ATv|{-SDheev)eqX~jb~dpi3%H00`^NcaEq<1nY9j)rYyCrX~RYMW;^xCrk{7F0a&@1TK3!ZuD6RtE2XN-Yy>a}c>$YftC~Hz4fLs>J4!k2Q zXPAC1N_4hN+C{(n&f6IysV~iLZy$uy;iW#g^)-g}1*>8B zwII>+fX={Y%b}>M0h2d96f^%{d*A&}_5c1~Qkglj6N!)!MJRh0WtQy_WoMM^ovqNa zH`(JTvmBfpBU_T~aF9KYdF=CfJk{%U``%uE!S{#vubjua*5kUa$NjpVVjFzSU5)ok z2K{qH!_}X<19GP?&pXZu`UTD%P+cSC}GwC8GrVek-S+QNs9@2G=)d31_h&q0`^{p)jf zV>09p)#1lH>!6zpZ*A>A5z0?G`Q^T_EJWc|P?t% zkr#%7Pqf1@?E|aU&-o3)=Ji3wZ$=$A-uC4jYf;`EQgpxn4JdoFAde)U1AE zk6cOF-Y0blo#F#wxnl8{#nl?-oNvElE(&(?dd_MEY3P6SYq?!0LsZqF>SCj0xzOOI zf_h7`G*U$cu#6~B#IiQ`gQNC@UcUBeDbLMP66&R$>nZv} z95~D)X;e3r;4Fol?ct^d_a7 z$Zp4n%ML%FQ>>g6t$eyq>8Rsn@K!_ICvr#T=tuqJp@Fcwo2^-np%60&?^vKrD7Gg< zLG*I%^C0|NuB84p`qq`6z&F4H0Wb2$aZ87+Y;qi5SEpJ601r}EKX%A@uCcRvlC|o> z8(!s(l?Ve9C{o;@DW#i_xs0qgAy)?g=EsFKPxLX)x5*seJsV(6@I#JxN70%jt;&m{ zLP&$Q(;^0c)@R3#B@e->J(P2d=yu1r6a_{yqiJS0BQ`vtwl>q$uwDoeySX}k380bc zkS`xj^DDS_A5mv!D(8g8`U&@JK9UHVra(lf|8+n$w$Mssw5;sQZ5T0ehD}N-&2OL#%Nw}ph94yIMmt+xhDWvcr)U>>O3^f~l|j1+{vFbnA!DsqJsB zO%_b~GX>u7iVgsec?sN)ilIUd4O5@>ry&FLL%}qq-!}*m7OmbbgIdG@$ohioPn00b zMJnkaMoj9rxRS1M&XrH^;>ofzRzkV72yQNRePhmx^cjSl@lpYtwPw?%B$En|sPiZ7 zK9~RzT2Rg7n#Jkz#;*OA;BrZhB!;q8wEs*?B6;M_cK)a~jklrJoM%VlQhc~Eg=wVJ z7PI_WNg2BV;DZK8%%ED^AL!IkaDlSpNdF2I1UUDz+xHE6*-Gfuk2t;7>Cm6k_!!)l zEDS+8ob-Fuztj7_C6+hz4sSf0?hI)EYOKJ1%)SmhYtqqo)$oUL$ zQ%lfC;*EcS!u?VIf4Q+npxDT;%09(xQa2i|Y&N1md7 zRTqW{3j{cVg4evuY#;HUfC;KnY>r}i#c#l0Kd%~sWBu|0X~pJo8NG33f4BC$wCz{) z%wq`rLjG6POyt?BEps0VBPMmC#bYMKJ|_)T2cJt08GO&Mx$9A9daCY}jIhyBM;JJP zQ~=1RLJ=V0XkQQmP$xQ*H5Tpk$laMFWj$U=$%_(hD~iyohWna%)|8Ov8m{U4Ym>L@ z8@8Oa+0%A>2_QGI`46`}iO-*3%QHM1nC9MxAgag0JDTq&x3Q^P$(mN3lO?c80GtLu9gjiM*mI3V%;6#tk%{jD>WlMisoj7;vWy?A+sbG_Xz1C@Ol?B{ z)vT8r0K|3oGtAUEJJ1swBbA#ZPPjm8l8UxlV9UWJszyD#^5`xbkNBBy6*6Kw0l<;O zv5dABea{qIy|c4Pw(!IyBg_cVhYU)D6ZL0UpJ97eDSd1wvrY zZ)*4ND}wx03@0@N{q$O`jhiQH)$ethz+VM0r$U`!zMsogxhJ|n#HaQr;tQZ9ekacX z8|`uW^3tj-5y$fA)>I)q=6%UynBUr0X=X%aB=+YPN5zm(DyZR>hl&KU&q0Z=xU0ls zpoFP_Sj>J4INBQZN{iiCHIt^rCvRtmX-&FtiF>;r|C|k%ENhOV2||vKoCqH{>oW1P zDrHD3oTIBz%Zleg|0;I_r=Lk#ToVQ84fr$(xp=6TH?=O{OwskVoNgEC$I_Lh4*uM$AKGbjoGNHuu* z*S;!&@y}oMdX!8fwlM3Z%UzlVUVsGtz!ktTF5rmIJB&3=iJF2agFABKXK~C;>1ZQL z*#?pa3-EzW3AhPTTHSp*csx_Xoyl4egwiIliOJ*ofx0Y4}lAa1!H$_aDBQb{hGRh#H`EJO^! z^FjOB%W7WPUke8Dg;BVt+Hl)X9l(b`xkB)yWvllH;ek%%!rXUX2V+d9t3(5Z$Sehd zEbI@(oQNlVzXau)s*74z=_3}mR5<1(C%a4K4F66vuksmqF5)dMg@$o+&M=^qAc%3LL5Fu{8Axn^7El zpGU{}s0gG!{Mw@Apmw`d4dhbY+6C7VQSN~1YIZqMl4OYdX~x;R#O73lmpx`>6c$yE z5@BVo*WOLiz(&)V-(_ZQHSI<&o{nCiNQp@d4HVU2jlzg&8Ahv+09omf?l-UgxChZQ!5A};2 z=7U_55prtK4+E-%BdFMp?~-Aulb^h0`8n<;dH)F$>FxdIdK{^}ri<$CcPp=cbGvKx zsy`qYh{GT&BwX_^$gmX?O*EH|q8r+oOlV{RX-#Op-RM{$RV28dz&?m$D*x%|&HyZx z`HyYxU?sL{6%96NIa3EzRUlTku3BmFTLZ8YPop7aa_6O1QBiSv{#^A_x!jR+yD9`N z3r~|fKC9&bac2LjTw{?=$Y+Vq%#sTaKf8})Rk6zNh~3-#EpD}SXQDrSS~wscOm}yJ z6XN0?P52%_Ip?k#PTCc=b)6dnrsMkSZ1r2ZVVnQdqb>)o}02%Tq~8+fMec z-q72!@bVcwAuVNOr_DeQC6bMx*~Bj+>5bdcCC2enZam0jtjOBN9jplTMfB1;+3DU( z)L-1ottXb>UXvq{m!2d4?HFgp)BX-rn5=*0+A@RCKb1-Vf?aYuHjgx@ zUk5^@(uA@G4=6fOlt~cDzX-eD=I1tTP>|mdda6=E``0yK>Tk_blwa^IA^}snK)FFaDsG$4Hp`%Q zjH99O)|4_p$*H$nTcXI%#S=3ed^(+RG_?#`nqG#%$E6S zNEV>t61eZ&E(L;94B?XZjR`W*J40ExM3N{oQ4KcpEt0Ro-Dx@eEdpF!Z~S>6Qjd-eTkGNXXied zf{Ty}AZ9=9?UlVe9&`>EGBN8=Q9W|J!_!2Z=<;=1v7;~V$*iK!b@tRM2s^V?>a(h= zs32`RAAF(;2}RU&#RF2{Z4%Aj+XRoV%oM{>jG8%FYU zIr|V=THT_k@v{a8KAmlbu9m?32mLYsykH`@f4o!+Ai)@I^>n92jEiM9WO8Kb0n;R$ zld5g5&F^;7d<}fg>38@!zf2{*k-{-F`a-%Ax`3<6=pGD&e;UW(U*0cj5@so?8~f@P z+E(^#oLb+b7Z%#dpsUvZDRg!0#VY%rz%6j#KjNtloR}_~E z@8vW~b$>9Ix8bpC-B&;o6q)=gK24pekH=~1#jV*c2OSp+3ut>NZHPnVmuM>DCz||c z@`K$*>S(I*Y**kPI3uR-{3hd!N$Z4fbAV2TbUcLlL4(l)ytF9)#mE8EisJD-5N>$e z{#nEpED|3XA7}+=`A7Q`JwLM_bH)bRb=!>MJuw9y$49UF8fs=j)13BK&@UFXOCFl_ zl^9|ste!nv%NwwS4f|@IWsz}6SCP1X?L&hd@9h)Ex3w)Dv3zK!{1Vob!UEr70BVPu zco)8_9*d|hbOf=a^EYj}(y5F)v>ggdvb1V@jXaMSMu$0Ps@{AU+C8v$Ze{4qvUHK%HTaVkQdg16Swi06@e`Vf114@Q4xVAe zuF8ybeR2By$(c?h@H=GeLEjn*EK9wpiCL~pHkL_cs2eTqDw5yb=t2pwte1s&&mgAB z4*b0EtQLAY<0rkx6M`hU-!l+JXr@aSlvfwYf1-uaU8UEzH6vYC$JCuTK|=|BBY=cc zmIL8WeCjQZOhuO{NKyMPQ4r3TmrU)A7%3;)OLm=CI`;|(3$ER}^8Re=6Zx+z_d~8* zvI)C&*WoSGx(|dG1y)v*H}(&DV z8K&+2m@&f#>}K@ctmbNYl1oei%hL;>4RBjvu^0LB5&JTWj~uxro`hkILyZ`HszRDh zM4}!Tx&*|o#fA1;`5{5mq`5@R3qpAdEssN?(QaTg{@uuk?fOJGdGx&L>ZnSz#zf=< zojV8agRah_T|EKH#X5pxQs~&767p=hQw5&omqQDQs$9{n2iMaKqP2$ZD|sQ@N{@gJ&+BBqAn3M#@H@ zynb{Ri>#%38-F4o-9p67he(ms?y80CrQV~Pr7NK_W0Fe(28^nQuY9ERbk02DCMJ3M zi-?D4HCU`7_LAZDOkBUHw85?2MIHhhP8@B7ZPA)2hN&Cq5Mu|uU2v4T z7Tr|G94(BLGTBb5*MgXksF*%dI?@AE7KAg(D=5748NLc=@SN^0wL7;7elMp+=mjPv zgREYVh41(r+&ahSI3M7Ec6j`l@o?}ZY|lPLqgjQ>A`5JAE(4-nm&k9F(V;LhF3or; zl>9b&1g$haHgbF*AKo7O!R2wm*Ssy*_DV*uOpzAW!;{1W7Yfe2%#xM3W5K zt4G@#`OcN-B*5}!L7egg&$4j9Z>#%Mi>a%gi=Uo&J|S=uar4%gLXmY4m;jv(3hw;c4l*zVVIUmGpvpCjxvbFM)yn zvec)wi7{(n&w=+YSf)vrhjDn9Sy}zFZX~_+Z7)mfLrnD7r@1$sWEnlilQl1BF9~uh zP7R*`)RHFw3+v4k&6O^DPb%iVm>e*b$;$5${&(k*=dEvB>00~j1(%q);ZWDtQ-?D8 z9xnM+M!eLy4}`Xg1RUPVcu4ydl6fZic2Q5+ze9`l(=8?k6c#_v)`W~*4r~akL6A^( zHXU&nMrhHU2TW#$1Y&e4R!q=lZq#Cy^Bj+8ROcCs>HV@qb!fLxg`p86DYyHpIlln214IovWpjFAE!nIlEmc zYt$4P!i=nfLbRHWlDvXHwgCylML`tL7d9l#an z75Qu?l$cd{STjDGD(@);S#sDS-A6GRuyF=xFi+fJ23Oq84jH#6g5uq)#YB#c_fJED zFGa8ato5LD8=G5$tT%Iiz*y&`YVEG~iEv`^My42aa3aV=v7FR~QHNFQSA_RM*E-60UozcF$GN zF0*v|1STR!i?o1kUTFXG^rv;zO=10`1VK1@<@-#JB%z^aXT`osf0Ys%4dZ^pj!V6{ z9J5V>%+}7A+Hp;tQ#2thHg8NeV*RhNZoyT=eB@+uZkFe@~4rjRSRnWZZ0 zjz5qa9T-qDjpTJzHP&lL98tgk`~vSm4+)a4fyZmMRAQsKbOzG`SZ04GXojzz{({?Z zDl2549;yIy!6LltSNLKR?&geEYLYgXq;PEfOaqoAGX~G&?Fu7;Cg+%Si^zawRG2DR zC5@DLanR}YyC?~r=qNQTvQ%gH#5&bS-FkF)?6mGraWHLxAUF`K-;dRT@w+70=GG=@ zGeAmy2|x^lfA*q@H&0QW%@0cr6}|_XgzsnN6@E_id|e6!#Bt4%-{?SuG{Z3uWN%!9 zSX&9P_8G&G>reYuQA`oGle?JH+o%15dD=~CcMj=$;QlcArrI8NwW#`_nbif(JD$%K z)KiU~>$y2q)ZUKRn8In4U5+V&-cA;afOi`kn9-@ZDea<(-W-`3C2U>`_ESY1{ScF#lbUG1(5 z67j`O;P8z-z!V~1ey9_5@YKg2Xn2j;qvx<@eLl{f@LXsh@t!(h@!@1poY-m1dIF|r z?L@@3a2=`XxJcPx+;_0~H1a=-*ULWwyzJTDFxBZ>uGAPa z)=FVNrW|CI@Z?r?ePU+^+KWe>e>>C`eP3J#XO{%(4bEPIT<^#2jZxvhj@WNwIBs@J z)(p6i9rJt@GDqFf`_Xk0D3ho2Mug4WT6Z^JM_>~zdBH_M_p#jDwaPoTs!9f(lgxVN zVyTs5J2LH75Cjfs%FTGdCd6lftv8KL-g=(kI z#B7i=cWdVma~C4I4YVv;HqU9xv zmHTq0lD8;W++LitD2J^79xXJOW#7C7&M3axteHLj3UR3E!>%`<2js*WVsv`;?>m$T z_`0$6{*d6vB{Ac=Zio6YSBg{HyVll&4iDvY%GLgvNye*JW7x5NWX&48eu`V%p(SZ= z%dKR*R{Cw>i-&+|<&fw00iqU3-xo+ozLUz7v~p5Xjp7(wN>a9QU{O=Bs0I)86Ih-z z#L9^&LIoFG#(j!aWXQ30=^>zK(0}LYc_!HRaWT~4=&stfk)Q-%7uRLz-sU`31{VQH z8FsQ~#o)a?yT2>8?L6)!)pf*9Y;jZ_TBO+JN=XKYHRwT>TlH867K|ZYZr+fYJBS_5 zS&^u#h~3=Es`4x9s`$y8iekp{{bzFDg}hnY_3Vn4RsQXt5~nd?R7wBcBI@nvO;aO9`fP#^c5#x_h+KT88O+=1CCI6Xc zzm+33zm*A-Jw94vzAR#AhqvC|mc2#+X7#QW*#yU(6lu833Ldme}KI$Xww z)-VWCR&^xMo}s(|Q@`z|JLodY(!fcho@Z^!^9t|`{vV#Xjdx!g*?Cf-HV$7r=rU{@ z*TB?hC=DYjiYV*`Dnqi=Q!X?|OJ&}hkTPFV!lobMDY#hM*^<4dayzr^$ULiDav{4MxAnCCVLFXe1sI1(|us_^$ z+KE@ePCuq1_wz!Tn4v@uM-Xx*PWy*g=2vkcNwdieXQ(d1)Dv!vz%QKdKye*Y2h!H_ zWXVz<4(?8^W$^9NomeKbIK0E9Haz%{l!dSU-X{4n!3R&Za=s+d)pF3a4;OUj;ZP2| zS2H1r7gFP6&cWo{BXlxc;6`w1r%Y#AB1HBdRRjNiQ{j(F+Hw~;_DrDPv*8R+{T+9b z$bg&#X%MaF{O=!#5F*D~4gKMNL;sNXe`NZfNc>N8{(rL)D8i}HQ@5W!Q#wck-_Sgv NqNJ`^BLC>+{{c6Xr+fea diff --git a/docs/source/architecture/analyzer.rst b/docs/source/architecture/analyzer.rst index 20b4a0d..aa28f7a 100644 --- a/docs/source/architecture/analyzer.rst +++ b/docs/source/architecture/analyzer.rst @@ -138,8 +138,7 @@ Each kind of index has to inherent from this class. :code:`Index` object encapsu Index.__init__(self, column='node') -TODO index ULM - +.. image:: /_static/architecture/analyzer/ulm-index.png Index instantiation are completely hidden for user. It created implicitly when user types :code:`agg.ixxx[yy]`. Then, hadar will #. check that mandatory indexes are given with :code:`_assert_index` method. diff --git a/docs/source/architecture/optimizer.rst b/docs/source/architecture/optimizer.rst index daa48a3..209c4e8 100644 --- a/docs/source/architecture/optimizer.rst +++ b/docs/source/architecture/optimizer.rst @@ -11,7 +11,8 @@ Therefore :code:`Optimizer` is an abstract class build on *Strategy* pattern. Us Today, two optimizers are present :code:`LPOptimizer` and :code:`RemoteOptimizer` -TODO ULM Optimizer +.. image:: /_static/architecture/optimizer/ulm-optimizer.png + :scale: 50% RemoteOptimizer --------------- @@ -100,6 +101,8 @@ Hadar has to set power importation to *dest* node equation. But maybe this node :code:`solve_lp` applies the last iteration over scenarios and it's the entry point for linear programming optimizer. After all scenarios are solved, results are mapped to :code:`Result` object. +.. image:: /_static/architecture/optimizer/lpoptimizer.png + Or-tools, multiprocessing & pickle nightmare ............................................ @@ -129,7 +132,6 @@ It should work, but in fact not... I don't know why, when multiprocessing want t # hadar.optimizer.lp.solver._solve_batch return pickle.dumps(variables) -TODO ULM LPOptimizer Study ----- diff --git a/docs/source/architecture/workflow.rst b/docs/source/architecture/workflow.rst index 3d05749..3d4dace 100644 --- a/docs/source/architecture/workflow.rst +++ b/docs/source/architecture/workflow.rst @@ -19,7 +19,7 @@ The best solution could be to compute a *God function* which tell you for each i It's why we use *Monte Carlo* algorithm. Monte Carlo run many *scenarios* to analyze many different behavior. Scenario with more consumption in cities, less solar production, less coal production or one line deleted due to crash. By this method we recreate *God function* by sampling it with the Monte-Carlo method. -TODO Monte Carlo sampling graphics +.. image:: /_static/architecture/workflow/monte-carlo.png Workflow will help user to generate these scenarios and sample them to create a stochastic study. @@ -145,7 +145,7 @@ Of course he can develop sampling algorithm, but he can also use :code:`Shuffle #. It samples data to create study scenarios. -TODO shuffler graphics +.. image:: /_static/architecture/workflow/shuffler.png Below an example how to use Shuffler :: diff --git a/docs/source/graphics.drawio b/docs/source/graphics.drawio new file mode 100644 index 0000000..c3c20d7 --- /dev/null +++ b/docs/source/graphics.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/hadar/analyzer/result.py b/hadar/analyzer/result.py index 278bb91..294d446 100644 --- a/hadar/analyzer/result.py +++ b/hadar/analyzer/result.py @@ -57,7 +57,7 @@ def filter(self, df: pd.DataFrame) -> pd.Series: return df[self.column].notnull() return df[self.column].isin(self.index) - def is_alone(self): + def is_alone(self) -> bool: """ Ask if index filter element is alone. From 1949be4d0e5300604cc36f15d0a64101d3691972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Tue, 26 May 2020 18:10:15 +0200 Subject: [PATCH 09/34] close #57. explain mathematical model --- docs/source/mathematics/linear-model.rst | 127 ++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/docs/source/mathematics/linear-model.rst b/docs/source/mathematics/linear-model.rst index 6fb21c6..6b58c49 100644 --- a/docs/source/mathematics/linear-model.rst +++ b/docs/source/mathematics/linear-model.rst @@ -3,4 +3,129 @@ Linear Model ============ -Hello world +Main Optimizer is a :code:`LPOptimizer`. It creates linear programming problem represented grid adequacy. We will see mathematics problem, step by step + +#. Basic adequacy equations +#. Add lack of adequacy terms (lost of load and spillage) + +As you will see, :math:`\Gamma_x` represents a quantity in network, :math:`\overline{\Gamma_x}` is the maximum, :math:`\underline{\Gamma_x}` is the minimum, :math:`\overline{\underline{\Gamma_x}}` is the maximum and minimum a.k.a it's a forced quantity. Upper case grec letter is for quantity, and lower case grec letter is for cost :math:`\gamma_x` associated to this quantity. + +Basic adequacy +-------------- + +Let's begin by the first adequacy behavior. We have a graph :math:`G(N, L)` with :math:`N` nodes on the graph and :math:`L` edges on this graph. + +Variables +********* + +* :math:`n \in N` a node belongs graph + +* :math:`T \in \mathbb{Z}_+` time horizon + +Edge variabl + +* :math:`l \in L` an edge belongs to graphs + +* :math:`\overline{\Gamma_l} \in \mathbb{R}^T_+` maximum power transfert capacity for :math:`l` + +* :math:`\Gamma_l \in \mathbb{R}^T_+` power transfered inside :math:`l` + +* :math:`\gamma_l \in \mathbb{R}^T_+` proportional cost when :math:`\Gamma_l` is used + +* :math:`L^n_\uparrow \subset L` set of edges with a upstream to node :math:`n` + +* :math:`L^n_\downarrow \subset L` set of edges with a downstream from node :math:`n` + + +Productions variables + +* :math:`P^n` set of productions attached to node :math:`n` + +* :math:`p \in P^n` a production inside set of productions attached to node :math:`n` + +* :math:`\overline{\Gamma_p} \in \mathbb{R}^T_+` maximum power capacity available for :math:`p` production. + +* :math:`\Gamma_p \in \mathbb{R}^T_+` power capacity of :math:`p` used during adequacy + +* :math:`\gamma_p \in \mathbb{R}^T_+` proportional cost when :math:`\Gamma_p` is used + +Consumptions variables + +* :math:`C^n` set of consumptions attached to node :math:`n` + +* :math:`c \in C^n` a consumption inside set of consumptions attached to node :math:`n` + +* :math:`\underline{\overline{\Gamma_c}} \in \mathbb{R}^T_+` forced consumptions of :math:`c` to sustain. + +Objective +********* + +.. math:: + \begin{array}{rcl} + objective & = & \min{\Omega_{transmission} + \Omega_{production}} \\ + \Omega_{transmission} &=& \sum^{L}_{l}{\Gamma_l*{\gamma_l}} \\ + \Omega_{production} & = & \sum^N_n \sum^{P^n}_{p}{\Gamma_p * {\gamma_p}} + \end{array} + +Constraint +********** + +First constraint is from Kirschhoff law and describes balance between productions and consumptions + +.. math:: + \Pi_{kirschhoff} : \forall n, \sum^{C^n}_{c}{\underline{\overline{\Gamma_c}}} + \sum^{L^n_{\downarrow}}_{l}{ \Gamma_l } = \sum^{P^n}_{p}{ \Gamma_p } + \sum^{L^n_{\uparrow}}_{l}{ \Gamma_l } + +Then productions and edges need to be bounded + +.. math:: + \Pi_{Edge\ bound}: \forall l \in L, 0 \le \Gamma_{l} \le \overline{\Gamma_l} \\ + \Pi_{Prod\ bound}: + \left\{ \begin{array}{cl} + \forall n \in N \\ + \forall p \in P^n + \end{array} \right. + , 0 \le \Gamma_p \le \overline{\Gamma_p} + + +Lack of adequacy +-------------- + +Variables +********* + +Sometime, there are a lack of adequacy because there are not enough production, called *lost of load*. + +Like :math:`\Gamma_x` mean present quantity, :math:`\Lambda_x` represent a lack in network (consumption or production) to reach adequacy. Like for :math:`\Gamma_x`, lower case grec letter :math:`\lambda_x` is for cost associated to this lack. + +* :math:`\Lambda_c \in \mathbb{R}^T_+` lost of load for :math:`c` consumption + +* :math:`\lambda_c \in \mathbb{R}^T_+` proportional cost when :math:`\Lambda_c` is used + +Objective +********* + +Objective has a new term + +.. math:: + \begin{array}{rcl} + objective & = & \min{\Omega_{transmission} + \Omega_{production}} + \underbrace{\Omega_{lol}}\\ + \Omega_{lol} & = & \sum^N_n \sum^{C^n}_{c}{\Lambda_c * {\lambda_c}} + \end{array} + +Constraints +********** + +Kirschhoff law needs an update too. Lost of Load is represented like a *fantom* import of energy to reach adequacy. + +.. math:: + \Pi_{kirschhoff} : \forall n, \sum^{C^n}_{c}{\underline{\overline{\Gamma_c}}} + \sum^{L^n_{\downarrow}}_{l}{ \Gamma_l } = \sum^{P^n}_{p}{ \Gamma_p } + \sum^{L^n_{\uparrow}}_{l}{ \Gamma_l } + \underbrace{\sum^{C^n}_{c}{ \Lambda_c }} + +Lost of load must be bounded + +.. math:: + \Pi_{Lol\ bound}: + \left\{ \begin{array}{cl} + \forall n \in N \\ + \forall c \in C^n + \end{array} \right. + , 0 \le \Lambda_c \le \overline{\underline{\Gamma_c}} From 3118f333268e889de6bb5095874647b4782cedd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 27 May 2020 11:27:25 +0200 Subject: [PATCH 10/34] Fix mistake in linear model --- docs/source/architecture/analyzer.rst | 4 ++-- docs/source/mathematics/linear-model.rst | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/architecture/analyzer.rst b/docs/source/architecture/analyzer.rst index aa28f7a..578942d 100644 --- a/docs/source/architecture/analyzer.rst +++ b/docs/source/architecture/analyzer.rst @@ -5,9 +5,9 @@ For a high abstraction and to be agnostic about technology, Hadar uses objects a Today, there is only :code:`ResultAnalyzer`, with two features level: -* **high level ** user asks directly to compute global cost and global remain capacity, etc. +* **high level** user asks directly to compute global cost and global remain capacity, etc. -* **low level ** user asks *raw* data represented inside pandas Dataframe. +* **low level** user asks *raw* data represented inside pandas Dataframe. Before speaking about this features, let's see how data are transformed. diff --git a/docs/source/mathematics/linear-model.rst b/docs/source/mathematics/linear-model.rst index 6b58c49..edeac0d 100644 --- a/docs/source/mathematics/linear-model.rst +++ b/docs/source/mathematics/linear-model.rst @@ -3,7 +3,7 @@ Linear Model ============ -Main Optimizer is a :code:`LPOptimizer`. It creates linear programming problem represented grid adequacy. We will see mathematics problem, step by step +The main optimizer is :code:`LPOptimizer`. It creates linear programming problem representing network adequacy. We will see mathematics problem, step by step #. Basic adequacy equations #. Add lack of adequacy terms (lost of load and spillage) @@ -13,18 +13,18 @@ As you will see, :math:`\Gamma_x` represents a quantity in network, :math:`\over Basic adequacy -------------- -Let's begin by the first adequacy behavior. We have a graph :math:`G(N, L)` with :math:`N` nodes on the graph and :math:`L` edges on this graph. +Let's begin by the first adequacy behavior. We have a graph :math:`G(N, L)` with :math:`N` nodes on the graph and :math:`L` unidirectional edges on this graph. Variables ********* -* :math:`n \in N` a node belongs graph +* :math:`n \in N` a node belongs to graph * :math:`T \in \mathbb{Z}_+` time horizon -Edge variabl +Edge variables -* :math:`l \in L` an edge belongs to graphs +* :math:`l \in L` an unidirectional edge belongs to graphs * :math:`\overline{\Gamma_l} \in \mathbb{R}^T_+` maximum power transfert capacity for :math:`l` @@ -32,9 +32,9 @@ Edge variabl * :math:`\gamma_l \in \mathbb{R}^T_+` proportional cost when :math:`\Gamma_l` is used -* :math:`L^n_\uparrow \subset L` set of edges with a upstream to node :math:`n` +* :math:`L^n_\uparrow \subset L` set of edges with direction to node :math:`n` (i.e. importation for :math:`n`) -* :math:`L^n_\downarrow \subset L` set of edges with a downstream from node :math:`n` +* :math:`L^n_\downarrow \subset L` set of edges with direction from node :math:`n` (i.e. exportation for :math:`n`) Productions variables From f39ddae7e61046b4cb46a5eda4a2e46665edcf9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 27 May 2020 12:11:13 +0200 Subject: [PATCH 11/34] Add code of conduct close #61 --- CODE_OF_CONDUCT.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6e9618f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,11 @@ +# Contributor Code of Conduct + +As contributors and maintainers of the Hadar project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities. + +Communication through any of Hadar's channels (TODO) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. + +We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Hadar project to do the same. + +If any member of the community violates this code of conduct, the maintainers of the Hadar project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate. + +If you are subject to or witness unacceptable behavior, or have any other concerns, please email us at [contact@hadar-simulator.org](mailto:contact@hadar-simulator.org). From 8eb5728114013fbd517aeee569f994e5d8862902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 27 May 2020 17:22:55 +0200 Subject: [PATCH 12/34] Add contributing close #60 --- CONTRIBUTING.md | 4 ++ docs/source/dev-guide/best-practices.rst | 4 -- docs/source/dev-guide/contributing.rst | 70 ++++++++++++++++++++++++ docs/source/dev-guide/devops.rst | 4 -- docs/source/dev-guide/repository.rst | 50 ++++++++++++++++- docs/source/index.rst | 5 +- 6 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 docs/source/dev-guide/best-practices.rst create mode 100644 docs/source/dev-guide/contributing.rst delete mode 100644 docs/source/dev-guide/devops.rst diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e1db4d5 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +# Contributing +We appreciate your helps + +Before fillings issue, please read [Contribution Guide](https://doc.hadar-simulator.org/en/develop/dev-guide/devops.html) diff --git a/docs/source/dev-guide/best-practices.rst b/docs/source/dev-guide/best-practices.rst deleted file mode 100644 index 5ef41c6..0000000 --- a/docs/source/dev-guide/best-practices.rst +++ /dev/null @@ -1,4 +0,0 @@ -Best Practices -============== - -Hello world \ No newline at end of file diff --git a/docs/source/dev-guide/contributing.rst b/docs/source/dev-guide/contributing.rst new file mode 100644 index 0000000..8b885de --- /dev/null +++ b/docs/source/dev-guide/contributing.rst @@ -0,0 +1,70 @@ +How to Contribute +================ + + +First off, thank you to considering contributing to Hadar. We believe technology can change the world. But only great community and open source can improve the world. + +Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests. + +We try to describe most of Hadar behavior and organization to avoid any *shadow part*. Additionaly, you can read *Dev Guide* section or *Architecture* to learn hadar purposes and processes. + +What kind of contribution ? +--------------------------- + +You can participate on Hadar from many ways: + +* just use it and spread it ! + +* write plugin and extension for hadar + +* Improve docs, code, examples + +* Add new features + +**Issue tracker are only for features, bug or improvment; not for support. If you have some question please go to TODO . Any support issue will be clossed.** + +Feature / Improvment +-------------------- + +Little change can be directly send into a pull request. Like : + +* Spelling / grammar fixes + +* Typo correction, white space and formatting changes + +* Comment clean up + +* Adding logging messages or debugging output + +For all other, you need first to create an issue. If issue receives good feedback. Then you can fork project, work on your side and send a Pull Request + +Bug +--- + +**If you find a security bug, please DON'T create an issue. Contact use at admin@hadar-simulator.org** + +First be sure it's a bug and not a misuse ! Issues are not for technical support. To speed up bug fixing (and avoid misuse), you need to clearly explain bug, with most simple step by step guide to reproduce bug. Specify us all details like OS, Hadar version and so on. + +Please provide us responce to these questions :: + + - What version of Hadar and python are you using ? + - What operating system and processor architecture are you using? + - What did you do? + - What did you expect to see? + - What did you see instead? + + +Best Practices +-------------- + +We try to have the most clear and maintenable code. Your Pull Request has to follow some good practices: + + +- respect `PEP 8 `_ style guide +- name meaningful variables, method, class +- respect `SOLID `_ , `KISS `_ , `DRY `_ , `YAGNI `_ principes +- make code easy testable (use dependencies injection) +- test code (at least 80% UT code coverage) +- Add docstring for each class and method. + +TL;TR: code as Uncle Bob ! diff --git a/docs/source/dev-guide/devops.rst b/docs/source/dev-guide/devops.rst deleted file mode 100644 index d68a911..0000000 --- a/docs/source/dev-guide/devops.rst +++ /dev/null @@ -1,4 +0,0 @@ -Devops lifecycle -================ - -Hello world \ No newline at end of file diff --git a/docs/source/dev-guide/repository.rst b/docs/source/dev-guide/repository.rst index 3eef551..9d88ef8 100644 --- a/docs/source/dev-guide/repository.rst +++ b/docs/source/dev-guide/repository.rst @@ -1,4 +1,52 @@ Repository Organization ======================= -Hello world \ No newline at end of file +Hadar `repository `_ is split in many parts. + +* :code:`hadar` source code + +* :code:`tests` unit and integration test perform by unittest + +* :code:`examples` set of notebooks used like End to End test when executed during devops or like `tutorials `_ when exported to html. + +* :code:`docs` sphinx documentation hosted by readthedocs at https://docs.hadar-simulator.org . Main website is hosted by Github Pages and source code can be find in `this repository `_ + +* :code:`.github` github configuration to use Github Action devops. + +Ticketing +------ + +We use all github features to organize development. We implement a Agile methodology and try to recreate Jira behavior in github. Therefore we swap Jira features to Github such as : + ++----------------------+---------------------+ +| Jira | github swap | ++----------------------+---------------------+ +| User Story / Bug | Issue | ++----------------------+---------------------+ +| Version = Sprint | Project | ++----------------------+---------------------+ +| task | check list in issue | ++----------------------+---------------------+ +| Epic | Milestone | ++----------------------+---------------------+ + +Devops +------ + +We respect *git flow* pattern. Main developments are on :code:`develop` branch. We accepte :code:`feature/**` branch but is not mandatory. + +Devops pipelines are backed on *git flow*, actions are sum up in table below : + + ++----------+----------------+--------------------+----------------------+ +| | develop | release/** | master | ++----------+----------------+--------------------+----------------------+ +| TU + IT |3.6, 3.7, 3.8 / | linux-3.7 | linux-3.7 | +| |linux, mac, win | | | ++----------+----------------+--------------------+----------------------+ +| E2E | | from source code | from test.pypip.org | ++----------+----------------+--------------------+----------------------+ +| Sonar | yes | yes | yes | ++----------+----------------+--------------------+----------------------+ +| package | | to test.pypip.org | to pypip.org | ++----------+----------------+--------------------+----------------------+ diff --git a/docs/source/index.rst b/docs/source/index.rst index 0cfc979..35e61a8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -50,8 +50,7 @@ You are in the technical documentation. :caption: Dev Guide: dev-guide/repository.rst - dev-guide/best-practices.rst - dev-guide/devops.rst + dev-guide/contributing.rst .. toctree:: :maxdepth: 1 @@ -66,4 +65,4 @@ You are in the technical documentation. :maxdepth: 1 :caption: Legal Terms - terms/terms.rst \ No newline at end of file + terms/terms.rst From 95221bfc1a30cd3994ffedc02a715a75aa579bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Thu, 28 May 2020 15:36:40 +0200 Subject: [PATCH 13/34] Improve docs --- docs/source/dev-guide/contributing.rst | 14 ++++++------ docs/source/dev-guide/repository.rst | 20 ++++++++--------- docs/source/mathematics/linear-model.rst | 28 ++++++++++++++---------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/docs/source/dev-guide/contributing.rst b/docs/source/dev-guide/contributing.rst index 8b885de..412d565 100644 --- a/docs/source/dev-guide/contributing.rst +++ b/docs/source/dev-guide/contributing.rst @@ -6,7 +6,7 @@ First off, thank you to considering contributing to Hadar. We believe technology Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests. -We try to describe most of Hadar behavior and organization to avoid any *shadow part*. Additionaly, you can read *Dev Guide* section or *Architecture* to learn hadar purposes and processes. +We try to describe most of Hadar behavior and organization to avoid any *shadow part*. Additionally, you can read *Dev Guide* section or *Architecture* to learn hadar purposes and processes. What kind of contribution ? --------------------------- @@ -21,12 +21,12 @@ You can participate on Hadar from many ways: * Add new features -**Issue tracker are only for features, bug or improvment; not for support. If you have some question please go to TODO . Any support issue will be clossed.** +**Issue tracker are only for features, bug or improvment; not for support. If you have some question please go to TODO . Any support issue will be closed.** -Feature / Improvment +Feature / Improvement -------------------- -Little change can be directly send into a pull request. Like : +Little changes can be directly send into a pull request. Like : * Spelling / grammar fixes @@ -45,7 +45,7 @@ Bug First be sure it's a bug and not a misuse ! Issues are not for technical support. To speed up bug fixing (and avoid misuse), you need to clearly explain bug, with most simple step by step guide to reproduce bug. Specify us all details like OS, Hadar version and so on. -Please provide us responce to these questions :: +Please provide us response to these questions :: - What version of Hadar and python are you using ? - What operating system and processor architecture are you using? @@ -57,12 +57,12 @@ Please provide us responce to these questions :: Best Practices -------------- -We try to have the most clear and maintenable code. Your Pull Request has to follow some good practices: +We try to code the most clear and maintainable software. Your Pull Request has to follow some good practices: - respect `PEP 8 `_ style guide - name meaningful variables, method, class -- respect `SOLID `_ , `KISS `_ , `DRY `_ , `YAGNI `_ principes +- respect `SOLID `_ , `KISS `_ , `DRY `_ , `YAGNI `_ principe - make code easy testable (use dependencies injection) - test code (at least 80% UT code coverage) - Add docstring for each class and method. diff --git a/docs/source/dev-guide/repository.rst b/docs/source/dev-guide/repository.rst index 9d88ef8..cf5081e 100644 --- a/docs/source/dev-guide/repository.rst +++ b/docs/source/dev-guide/repository.rst @@ -3,15 +3,15 @@ Repository Organization Hadar `repository `_ is split in many parts. -* :code:`hadar` source code +* :code:`hadar/` source code -* :code:`tests` unit and integration test perform by unittest +* :code:`tests/` unit and integration tests perform by unittest -* :code:`examples` set of notebooks used like End to End test when executed during devops or like `tutorials `_ when exported to html. +* :code:`examples/` set of notebooks used like End to End test when executed during CI or like `tutorials `_ when exported to html. -* :code:`docs` sphinx documentation hosted by readthedocs at https://docs.hadar-simulator.org . Main website is hosted by Github Pages and source code can be find in `this repository `_ +* :code:`docs/` sphinx documentation hosted by readthedocs at https://docs.hadar-simulator.org . Main website is hosted by Github Pages and source code can be find in `this repository `_ -* :code:`.github` github configuration to use Github Action devops. +* :code:`.github/` github configuration to use Github Action for CI. Ticketing ------ @@ -20,7 +20,7 @@ We use all github features to organize development. We implement a Agile methodo +----------------------+---------------------+ | Jira | github swap | -+----------------------+---------------------+ ++======================+=====================+ | User Story / Bug | Issue | +----------------------+---------------------+ | Version = Sprint | Project | @@ -33,14 +33,14 @@ We use all github features to organize development. We implement a Agile methodo Devops ------ -We respect *git flow* pattern. Main developments are on :code:`develop` branch. We accepte :code:`feature/**` branch but is not mandatory. +We respect *git flow* pattern. Main developments are on :code:`develop` branch. We accept :code:`feature/**` branch but is not mandatory. -Devops pipelines are backed on *git flow*, actions are sum up in table below : +CI pipelines are backed on *git flow*, actions are sum up in table below : +----------+----------------+--------------------+----------------------+ -| | develop | release/** | master | -+----------+----------------+--------------------+----------------------+ +| action | develop | release/** | master | ++==========+================+====================+======================+ | TU + IT |3.6, 3.7, 3.8 / | linux-3.7 | linux-3.7 | | |linux, mac, win | | | +----------+----------------+--------------------+----------------------+ diff --git a/docs/source/mathematics/linear-model.rst b/docs/source/mathematics/linear-model.rst index edeac0d..1a1a961 100644 --- a/docs/source/mathematics/linear-model.rst +++ b/docs/source/mathematics/linear-model.rst @@ -8,7 +8,7 @@ The main optimizer is :code:`LPOptimizer`. It creates linear programming problem #. Basic adequacy equations #. Add lack of adequacy terms (lost of load and spillage) -As you will see, :math:`\Gamma_x` represents a quantity in network, :math:`\overline{\Gamma_x}` is the maximum, :math:`\underline{\Gamma_x}` is the minimum, :math:`\overline{\underline{\Gamma_x}}` is the maximum and minimum a.k.a it's a forced quantity. Upper case grec letter is for quantity, and lower case grec letter is for cost :math:`\gamma_x` associated to this quantity. + As you will see, :math:`\Gamma_x` represents a quantity in network, :math:`\overline{\Gamma_x}` is the maximum, :math:`\underline{\Gamma_x}` is the minimum, :math:`\overline{\underline{\Gamma_x}}` is the maximum and minimum a.k.a it's a forced quantity. Upper case grec letter is for quantity, and lower case grec letter is for cost :math:`\gamma_x` associated to this quantity. Basic adequacy -------------- @@ -73,18 +73,21 @@ Constraint First constraint is from Kirschhoff law and describes balance between productions and consumptions .. math:: - \Pi_{kirschhoff} : \forall n, \sum^{C^n}_{c}{\underline{\overline{\Gamma_c}}} + \sum^{L^n_{\downarrow}}_{l}{ \Gamma_l } = \sum^{P^n}_{p}{ \Gamma_p } + \sum^{L^n_{\uparrow}}_{l}{ \Gamma_l } + \begin{array}{rcl} + \Pi_{kirschhoff} &:& \forall n &,& \sum^{C^n}_{c}{\underline{\overline{\Gamma_c}}} + \sum^{L^n_{\downarrow}}_{l}{ \Gamma_l } = \sum^{P^n}_{p}{ \Gamma_p } + \sum^{L^n_{\uparrow}}_{l}{ \Gamma_l } + \end{array} Then productions and edges need to be bounded .. math:: - \Pi_{Edge\ bound}: \forall l \in L, 0 \le \Gamma_{l} \le \overline{\Gamma_l} \\ - \Pi_{Prod\ bound}: + \begin{array}{rcl} + \Pi_{Edge\ bound} &:& \forall l \in L &,& 0 \le \Gamma_{l} \le \overline{\Gamma_l} \\ + \Pi_{Prod\ bound} &:& \left\{ \begin{array}{cl} \forall n \in N \\ \forall p \in P^n - \end{array} \right. - , 0 \le \Gamma_p \le \overline{\Gamma_p} + \end{array} \right. &,& 0 \le \Gamma_p \le \overline{\Gamma_p} + \end{array} Lack of adequacy @@ -95,7 +98,7 @@ Variables Sometime, there are a lack of adequacy because there are not enough production, called *lost of load*. -Like :math:`\Gamma_x` mean present quantity, :math:`\Lambda_x` represent a lack in network (consumption or production) to reach adequacy. Like for :math:`\Gamma_x`, lower case grec letter :math:`\lambda_x` is for cost associated to this lack. + Like :math:`\Gamma_x` means quantity present in network, :math:`\Lambda_x` represents a lack in network (consumption or production) to reach adequacy. Like for :math:`\Gamma_x`, lower case grec letter :math:`\lambda_x` is for cost associated to this lack. * :math:`\Lambda_c \in \mathbb{R}^T_+` lost of load for :math:`c` consumption @@ -118,14 +121,17 @@ Constraints Kirschhoff law needs an update too. Lost of Load is represented like a *fantom* import of energy to reach adequacy. .. math:: - \Pi_{kirschhoff} : \forall n, \sum^{C^n}_{c}{\underline{\overline{\Gamma_c}}} + \sum^{L^n_{\downarrow}}_{l}{ \Gamma_l } = \sum^{P^n}_{p}{ \Gamma_p } + \sum^{L^n_{\uparrow}}_{l}{ \Gamma_l } + \underbrace{\sum^{C^n}_{c}{ \Lambda_c }} + \begin{array}{rcl} + \Pi_{kirschhoff} &:& \forall n &,& \sum^{C^n}_{c}{\underline{\overline{\Gamma_c}}} + \sum^{L^n_{\downarrow}}_{l}{ \Gamma_l } = \sum^{P^n}_{p}{ \Gamma_p } + \sum^{L^n_{\uparrow}}_{l}{ \Gamma_l } + \underbrace{\sum^{C^n}_{c}{ \Lambda_c }} + \end{array} Lost of load must be bounded .. math:: - \Pi_{Lol\ bound}: + \begin{array}{rcl} + \Pi_{Lol\ bound} &:& \left\{ \begin{array}{cl} \forall n \in N \\ \forall c \in C^n - \end{array} \right. - , 0 \le \Lambda_c \le \overline{\underline{\Gamma_c}} + \end{array} \right. &,& 0 \le \Lambda_c \le \overline{\underline{\Gamma_c}} + \end{array} From b360e6e5377b30f4019fa36c4e5e0d8ae8f16a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Fri, 12 Jun 2020 12:30:52 +0200 Subject: [PATCH 14/34] Add timeline plot with all scenario timeseries close #63 --- hadar/viewer/abc.py | 14 +++++++- hadar/viewer/html.py | 74 ++++++++++++++++++++++++++++++++++++++- tests/viewer/test_html.py | 26 +++++++++----- 3 files changed, 104 insertions(+), 10 deletions(-) diff --git a/hadar/viewer/abc.py b/hadar/viewer/abc.py index f7ac153..221b46b 100644 --- a/hadar/viewer/abc.py +++ b/hadar/viewer/abc.py @@ -19,4 +19,16 @@ def stack(self, node: str): @abstractmethod def exchanges_map(self, t: int, limit: int): - pass \ No newline at end of file + pass + + @abstractmethod + def consumptions(self, node: str, name: str, kind: str = 'given'): + pass + + @abstractmethod + def productions(self, node: str, name: str, kind: str = 'used'): + pass + + @abstractmethod + def links(self, src: str, dest: str, kind: str = 'used'): + pass diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index 17243e8..e228c4f 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -83,7 +83,7 @@ def stack(self, node: str, scn: int = 0, prod_kind: str = 'used', cons_kind: str :param node: select node to plot. :param scn: scenario index to plot. :param prod_kind: select which prod to stack : available ('avail') or 'used' - :param cons_kind: select which cons to stacl : 'asked' or 'given' + :param cons_kind: select which cons to stack : 'asked' or 'given' :return: plotly figure or jupyter widget to plot """ fig = go.Figure() @@ -211,4 +211,76 @@ def exchanges_map(self, t: int, scn: int = 0, limit: int = None): resolution=50, landcolor='rgb(200, 200, 200)', countrycolor='rgb(0, 0, 0)', fitbounds='locations')) + return fig + + def consumptions(self, node: str, name: str, kind: str = 'given'): + """ + Plot all timelines consumption scenario. + + :param node: selected node name + :param name: select consumption name + :param kind: kind of data 'asked' or 'given' + :return: + """ + cons = self.agg.agg_cons(self.agg.inode[node], self.agg.iname[name], self.agg.iscn, self.agg.itime)[kind] + scenarios = cons.index.get_level_values('scn').unique() + alpha = max(10, 255 / scenarios.size) + color = 'rgba(100, 100, 100, %d)' % alpha + + fig = go.Figure() + for scn in scenarios: + fig.add_trace(go.Scatter(x=self.time_index, y=cons.loc[scn], mode='lines', hoverinfo='name', + name='scn %0d' % scn, line=dict(color=color))) + + fig.update_layout(title_text='Consumptions %s for %s on node %s' % (kind, name, node), + yaxis_title="Quantity %s" % self.unit, xaxis_title="time", showlegend=False) + + return fig + + def productions(self, node: str, name: str, kind: str = 'used'): + """ + Plot all timelines production scenario. + + :param node: selected node name + :param name: select production name + :param kind: kind of data available ('avail') or 'used' + :return: + """ + prod = self.agg.agg_prod(self.agg.inode[node], self.agg.iname[name], self.agg.iscn, self.agg.itime)[kind] + scenarios = prod.index.get_level_values('scn').unique() + alpha = max(10, 255 / scenarios.size) + color = 'rgba(100, 100, 100, %d)' % alpha + + fig = go.Figure() + for scn in scenarios: + fig.add_trace(go.Scatter(x=self.time_index, y=prod.loc[scn], mode='lines', hoverinfo='name', + name='scn %0d' % scn, line=dict(color=color))) + + fig.update_layout(title_text='Productions %s for %s on node %s' % (kind, name, node), + yaxis_title="Quantity %s" % self.unit, xaxis_title="time", showlegend=False) + + return fig + + def links(self, src: str, dest: str, kind: str = 'used'): + """ + Plot all timelines links scenario. + + :param src: selected source node name + :param dest: select destination node name + :param kind: kind of data available ('avail') or 'used' + :return: + """ + links = self.agg.agg_link(self.agg.isrc[src], self.agg.idest[dest], self.agg.iscn, self.agg.itime)[kind] + scenarios = links.index.get_level_values('scn').unique() + alpha = max(10, 255 / scenarios.size) + color = 'rgba(100, 100, 100, %d)' % alpha + + fig = go.Figure() + for scn in scenarios: + fig.add_trace(go.Scatter(x=self.time_index, y=links.loc[scn], mode='lines', hoverinfo='name', + name='scn %0d' % scn, line=dict(color=color))) + + fig.update_layout(title_text='Link %s from %s to %s' % (kind, src, dest), + yaxis_title="Quantity %s" % self.unit, xaxis_title="time", showlegend=False) + return fig \ No newline at end of file diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 7029b4c..4646f60 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -19,15 +19,15 @@ class TestHTMLPlotting(unittest.TestCase): def setUp(self) -> None: - self.study = Study(['a', 'b'], horizon=3) \ - .add_on_node('a', data=Consumption(cost=10 ** 6, quantity=[20, 10, 2], name='load')) \ - .add_on_node('a', data=Consumption(cost=10 ** 6, quantity=[30, 15, 3], name='car')) \ - .add_on_node('a', data=Production(cost=10, quantity=[60, 30, 5], name='prod')) \ + self.study = Study(['a', 'b'], horizon=3, nb_scn=2) \ + .add_on_node('a', data=Consumption(cost=10 ** 6, quantity=[[20, 10, 2], [10, 5, 3]], name='load')) \ + .add_on_node('a', data=Consumption(cost=10 ** 6, quantity=[[30, 15, 3], [15, 7, 2]], name='car')) \ + .add_on_node('a', data=Production(cost=10, quantity=[[60, 30, 5], [30, 15, 3]], name='prod')) \ \ - .add_on_node('b', data=Consumption(cost=10 ** 6, quantity=[40, 20, 2], name='load')) \ - .add_on_node('b', data=Production(cost=20, quantity=[10, 5, 1], name='prod')) \ - .add_on_node('b', data=Production(cost=20, quantity=[20, 10, 2], name='nuclear')) \ - .add_link(src='a', dest='b', quantity=[10, 10, 10], cost=2) + .add_on_node('b', data=Consumption(cost=10 ** 6, quantity=[[40, 20, 2], [20, 10, 1]], name='load')) \ + .add_on_node('b', data=Production(cost=20, quantity=[[10, 5, 1], [5, 3, 1]], name='prod')) \ + .add_on_node('b', data=Production(cost=30, quantity=[[20, 10, 2], [10, 5, 1]], name='nuclear')) \ + .add_link(src='a', dest='b', quantity=[[10, 10, 10], [5, 5, 5]], cost=2) optimizer = LPOptimizer() self.result = optimizer.solve(study=self.study) @@ -46,6 +46,16 @@ def test_map_exchanges(self): fig = self.plot.exchanges_map(t=0, scn=0) self.assert_fig_hash('9aa34f28665ea9e6766b271ffbc677d3cda6810b', fig) + def test_plot_timeline(self): + fig = self.plot.consumptions(node='a', name='load') + self.assert_fig_hash('7787e0487f8f4012dc8b8f0cf979ffbb09fffb63', fig) + + fig = self.plot.productions(node='b', name='nuclear') + self.assert_fig_hash('44e414ef08a43add5ef68b5c533b47145fab0ba2', fig) + + fig = self.plot.links(src='a', dest='b') + self.assert_fig_hash('6375e591679d12907f440a8c23eb850a037d9cd8', fig) + def assert_fig_hash(self, expected: str, fig: go.Figure): h = hashlib.sha1() h.update(TestHTMLPlotting.get_html(fig)) From 12326e46185c4596c3b0ea41c20ae8a83307f264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Fri, 12 Jun 2020 16:22:51 +0200 Subject: [PATCH 15/34] Add monotone plot over time and scenario close #66 --- hadar/viewer/abc.py | 12 ++++ hadar/viewer/html.py | 138 ++++++++++++++++++++++++++++---------- tests/viewer/test_html.py | 10 +++ 3 files changed, 126 insertions(+), 34 deletions(-) diff --git a/hadar/viewer/abc.py b/hadar/viewer/abc.py index 221b46b..03049f5 100644 --- a/hadar/viewer/abc.py +++ b/hadar/viewer/abc.py @@ -32,3 +32,15 @@ def productions(self, node: str, name: str, kind: str = 'used'): @abstractmethod def links(self, src: str, dest: str, kind: str = 'used'): pass + + @abstractmethod + def monotone_consumption(self, node: str, name: str, t: int, scn: int, kind: str = 'given'): + pass + + @abstractmethod + def monotone_production(self, node: str, name: str, t: int = None, scn: int = None, kind: str = 'used'): + pass + + @abstractmethod + def monotone_link(self, src: str, dest: str, t: int = None, scn: int = None, kind: str = 'used'): + pass diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index e228c4f..136a216 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -213,30 +213,34 @@ def exchanges_map(self, t: int, scn: int = 0, limit: int = None): return fig - def consumptions(self, node: str, name: str, kind: str = 'given'): - """ - Plot all timelines consumption scenario. - - :param node: selected node name - :param name: select consumption name - :param kind: kind of data 'asked' or 'given' - :return: - """ - cons = self.agg.agg_cons(self.agg.inode[node], self.agg.iname[name], self.agg.iscn, self.agg.itime)[kind] - scenarios = cons.index.get_level_values('scn').unique() + def _timeline(self, df: pd.DataFrame, title: str): + scenarios = df.index.get_level_values('scn').unique() alpha = max(10, 255 / scenarios.size) color = 'rgba(100, 100, 100, %d)' % alpha fig = go.Figure() for scn in scenarios: - fig.add_trace(go.Scatter(x=self.time_index, y=cons.loc[scn], mode='lines', hoverinfo='name', + fig.add_trace(go.Scatter(x=self.time_index, y=df.loc[scn], mode='lines', hoverinfo='name', name='scn %0d' % scn, line=dict(color=color))) - fig.update_layout(title_text='Consumptions %s for %s on node %s' % (kind, name, node), + fig.update_layout(title_text=title, yaxis_title="Quantity %s" % self.unit, xaxis_title="time", showlegend=False) return fig + def consumptions(self, node: str, name: str, kind: str = 'given'): + """ + Plot all timelines consumption scenario. + + :param node: selected node name + :param name: select consumption name + :param kind: kind of data 'asked' or 'given' + :return: + """ + cons = self.agg.agg_cons(self.agg.inode[node], self.agg.iname[name], self.agg.iscn, self.agg.itime)[kind] + title = 'Consumptions %s for %s on node %s' % (kind, name, node) + return self._timeline(cons, title) + def productions(self, node: str, name: str, kind: str = 'used'): """ Plot all timelines production scenario. @@ -247,19 +251,9 @@ def productions(self, node: str, name: str, kind: str = 'used'): :return: """ prod = self.agg.agg_prod(self.agg.inode[node], self.agg.iname[name], self.agg.iscn, self.agg.itime)[kind] - scenarios = prod.index.get_level_values('scn').unique() - alpha = max(10, 255 / scenarios.size) - color = 'rgba(100, 100, 100, %d)' % alpha + title = 'Productions %s for %s on node %s' % (kind, name, node) + return self._timeline(prod, title) - fig = go.Figure() - for scn in scenarios: - fig.add_trace(go.Scatter(x=self.time_index, y=prod.loc[scn], mode='lines', hoverinfo='name', - name='scn %0d' % scn, line=dict(color=color))) - - fig.update_layout(title_text='Productions %s for %s on node %s' % (kind, name, node), - yaxis_title="Quantity %s" % self.unit, xaxis_title="time", showlegend=False) - - return fig def links(self, src: str, dest: str, kind: str = 'used'): """ @@ -271,16 +265,92 @@ def links(self, src: str, dest: str, kind: str = 'used'): :return: """ links = self.agg.agg_link(self.agg.isrc[src], self.agg.idest[dest], self.agg.iscn, self.agg.itime)[kind] - scenarios = links.index.get_level_values('scn').unique() - alpha = max(10, 255 / scenarios.size) - color = 'rgba(100, 100, 100, %d)' % alpha + title = 'Link %s from %s to %s' % (kind, src, dest) + return self._timeline(links, title) + + + def _monotone(self, y: np.ndarray, title: str): + y.sort() + x = np.linspace(0, 100, y.size) fig = go.Figure() - for scn in scenarios: - fig.add_trace(go.Scatter(x=self.time_index, y=links.loc[scn], mode='lines', hoverinfo='name', - name='scn %0d' % scn, line=dict(color=color))) + fig.add_trace(go.Scatter(x=x, y=y, mode='markers')) + fig.update_layout(title_text=title, + yaxis_title="Quantity %s" % self.unit, xaxis_title="%", showlegend=False) - fig.update_layout(title_text='Link %s from %s to %s' % (kind, src, dest), - yaxis_title="Quantity %s" % self.unit, xaxis_title="time", showlegend=False) + return fig + + def monotone_consumption(self, node: str, name: str, t: int = None, scn: int = None, kind: str = 'given'): + """ + Plot ascending monotone of consumption. + + :param node: selected node + :param name: selected consumption name + :param t: select t index (only if scn is not used) + :param scn: select scn index (only if t is not used) + :param kind: kind of consumption 'asked' or 'given' + :return: + """ + if t is not None and scn is not None: + raise ValueError('you have to specify time or scenario index but not both') - return fig \ No newline at end of file + if t is not None: + y = self.agg.agg_cons(self.agg.inode[node], self.agg.iname[name], + self.agg.itime[t], self.agg.iscn)[kind].values + title = 'Monotone consumption of %s on node %s at t=%0d' % (name, node, t) + elif scn is not None: + y = self.agg.agg_cons(self.agg.inode[node], self.agg.iname[name], + self.agg.iscn[scn], self.agg.itime)[kind].values + title = 'Monotone consumption of %s on node %s at t=%0d' % (name, node, scn) + + return self._monotone(y, title) + + def monotone_production(self, node: str, name: str, t: int = None, scn: int = None, kind: str = 'used'): + """ + Plot ascending monotone of production + + :param node: selected node name + :param name: selected production name + :param t: select t index (only if scn is not used) + :param scn: select scn index (only if t is not used) + :param kind: kind of production available ('avail') of 'used + :return: + """ + if t is not None and scn is not None: + raise ValueError('you have to specify time or scenario index but not both') + + if t is not None: + y = self.agg.agg_prod(self.agg.inode[node], self.agg.iname[name], + self.agg.itime[t], self.agg.iscn)[kind].values + title = 'Monotone production of %s on node %s at t=%0d' % (name, node, t) + elif scn is not None: + y = self.agg.agg_prod(self.agg.inode[node], self.agg.iname[name], + self.agg.iscn[scn], self.agg.itime)[kind].values + title = 'Monotone production of %s on node %s at t=%0d' % (name, node, scn) + + return self._monotone(y, title) + + def monotone_link(self, src: str, dest: str, t: int = None, scn: int = None, kind: str = 'used'): + """ + Plot ascending monotone of production + + :param src: selected source node name + :param dest: selected destination node name + :param t: select t index (only if scn is not used) + :param scn: select scn index (only if t is not used) + :param kind: kind of link available ('avail') of 'used + :return: + """ + if t is not None and scn is not None: + raise ValueError('you have to specify time or scenario index but not both') + + if t is not None: + y = self.agg.agg_link(self.agg.isrc[src], self.agg.idest[dest], + self.agg.itime[t], self.agg.iscn)[kind].values + title = 'Monotone link from %s to %s at t=%0d' % (src, dest, t) + elif scn is not None: + y = self.agg.agg_link(self.agg.isrc[src], self.agg.idest[dest], + self.agg.iscn[scn], self.agg.itime)[kind].values + title = 'Monotone link from %s to %s at t=%0d' % (src, dest, scn) + + return self._monotone(y, title) \ No newline at end of file diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 4646f60..8da5ca8 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -56,6 +56,16 @@ def test_plot_timeline(self): fig = self.plot.links(src='a', dest='b') self.assert_fig_hash('6375e591679d12907f440a8c23eb850a037d9cd8', fig) + def test_plot_monotone(self): + fig = self.plot.monotone_consumption(node='a', name='load', scn=0) + self.assert_fig_hash('753619bf85b387f3b0f304688bb578efe39db3e9', fig) + + fig = self.plot.monotone_production(node='b', name='nuclear', t=0) + self.assert_fig_hash('0a99228bf1a0743b604e9082b0ba7db86f3993f3', fig) + + fig = self.plot.monotone_link(src='a', dest='b', scn=0) + self.assert_fig_hash('2e2410dad5800c9658846c40421dbe83c9e5f3f9', fig) + def assert_fig_hash(self, expected: str, fig: go.Figure): h = hashlib.sha1() h.update(TestHTMLPlotting.get_html(fig)) From c69a8318d79421e7366cc13112fdaae6d9fb6a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Mon, 15 Jun 2020 12:02:46 +0200 Subject: [PATCH 16/34] Add grid green / red scenario according to rac close #64 --- hadar/analyzer/result.py | 25 +++++++++++++++++++++++++ hadar/viewer/abc.py | 4 ++++ hadar/viewer/html.py | 17 ++++++++++++++++- tests/analyzer/test_result.py | 4 ++++ tests/viewer/test_html.py | 4 ++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/hadar/analyzer/result.py b/hadar/analyzer/result.py index 294d446..a474d34 100644 --- a/hadar/analyzer/result.py +++ b/hadar/analyzer/result.py @@ -374,6 +374,31 @@ def get_cost(self, node: str) -> np.ndarray: return cost + def get_rac(self) -> np.ndarray: + prod_used = self.production\ + .drop(['avail', 'cost'], axis=1)\ + .pivot_table(index='scn', columns='t', aggfunc=np.sum)\ + .values + + prod_avail = self.production\ + .drop(['used', 'cost'], axis=1)\ + .pivot_table(index='scn', columns='t', aggfunc=np.sum)\ + .values + + cons_asked = self.consumption\ + .drop(['given', 'cost'], axis=1)\ + .pivot_table(index='scn', columns='t', aggfunc=np.sum)\ + .values + + cons_given = self.consumption\ + .drop(['asked', 'cost'], axis=1)\ + .pivot_table(index='scn', columns='t', aggfunc=np.sum)\ + .values + + rac = (prod_avail - prod_used) - (cons_asked - cons_given) + + return rac + @property def horizon(self) -> int: """ diff --git a/hadar/viewer/abc.py b/hadar/viewer/abc.py index 03049f5..d6bd3c6 100644 --- a/hadar/viewer/abc.py +++ b/hadar/viewer/abc.py @@ -44,3 +44,7 @@ def monotone_production(self, node: str, name: str, t: int = None, scn: int = No @abstractmethod def monotone_link(self, src: str, dest: str, t: int = None, scn: int = None, kind: str = 'used'): pass + + @abstractmethod + def rac_heatmap(self): + pass diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index 136a216..fa4450e 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -353,4 +353,19 @@ def monotone_link(self, src: str, dest: str, t: int = None, scn: int = None, kin self.agg.iscn[scn], self.agg.itime)[kind].values title = 'Monotone link from %s to %s at t=%0d' % (src, dest, scn) - return self._monotone(y, title) \ No newline at end of file + return self._monotone(y, title) + + def rac_heatmap(self): + rac = self.agg.get_rac() + pct = (rac >= 0).sum() / rac.size * 100 + + fig = go.Figure(data=go.Heatmap( + z=rac, + x=self.time_index, + y=np.arange(self.agg.nb_scn), + colorscale='RdBu', zmid=0)) + + fig.update_layout(title_text="RAC Matrix %0d %% passed" % pct, + yaxis_title="scenarios", xaxis_title="time", showlegend=False) + + return fig \ No newline at end of file diff --git a/tests/analyzer/test_result.py b/tests/analyzer/test_result.py index 3433d25..eb31ea6 100644 --- a/tests/analyzer/test_result.py +++ b/tests/analyzer/test_result.py @@ -183,3 +183,7 @@ def test_cost(self): agg = ResultAnalyzer(study=self.study, result=self.result) np.testing.assert_array_equal([[200360, 20036, 20036], [20036, 200360, 200360]], agg.get_cost(node='a')) np.testing.assert_array_equal([[100600, 10060, 10060], [10060, 100600, 100600]], agg.get_cost(node='b')) + + def test_rac(self): + agg = ResultAnalyzer(study=self.study, result=self.result) + np.testing.assert_array_equal([[0, 0, 0], [0, 0, 0]], agg.get_rac()) diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 8da5ca8..46bbfbe 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -66,6 +66,10 @@ def test_plot_monotone(self): fig = self.plot.monotone_link(src='a', dest='b', scn=0) self.assert_fig_hash('2e2410dad5800c9658846c40421dbe83c9e5f3f9', fig) + def test_rac_heatmap(self): + fig = self.plot.rac_heatmap() + self.assert_fig_hash('1fa715af27e4ab85b033cff41f5edff72f4bca88', fig) + def assert_fig_hash(self, expected: str, fig: go.Figure): h = hashlib.sha1() h.update(TestHTMLPlotting.get_html(fig)) From bffb57dadcb13f4019a7926f9ba9cf4719bec095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Mon, 15 Jun 2020 19:10:43 +0200 Subject: [PATCH 17/34] WIP #65 Refactor Plotting architecture to improve extern API. Add gaussian plot for over time and scenario --- hadar/viewer/abc.py | 168 ++++++++++++++++++++++++++++++--- hadar/viewer/html.py | 190 ++++++++++++++------------------------ tests/viewer/test_html.py | 21 +++-- 3 files changed, 240 insertions(+), 139 deletions(-) diff --git a/hadar/viewer/abc.py b/hadar/viewer/abc.py index d6bd3c6..be1111b 100644 --- a/hadar/viewer/abc.py +++ b/hadar/viewer/abc.py @@ -5,44 +5,188 @@ # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. +import numpy as np +import pandas as pd from abc import ABC, abstractmethod +from hadar.analyzer.result import ResultAnalyzer -class ABCPlotting(ABC): - """ - Abstract method to plot optimizer result. - """ +class ElementPlotting(ABC): @abstractmethod - def stack(self, node: str): + def timeline(self, df: pd.DataFrame, title: str): pass @abstractmethod - def exchanges_map(self, t: int, limit: int): + def monotone(self, y: np.ndarray, title: str): pass @abstractmethod - def consumptions(self, node: str, name: str, kind: str = 'given'): + def gaussian(self, rac: np.ndarray, qt: np.ndarray, title: str): pass + +class Element(ABC): + def __init__(self, plotting: ElementPlotting, agg: ResultAnalyzer): + self.plotting = plotting + self.agg = agg + @abstractmethod - def productions(self, node: str, name: str, kind: str = 'used'): + def timeline(self): pass @abstractmethod - def links(self, src: str, dest: str, kind: str = 'used'): + def monotone(self, t: int = None, scn: int = None): + if t is not None and scn is not None: + raise ValueError('you have to specify time or scenario index but not both') + + @abstractmethod + def gaussian(self, t: int = None, scn: int = None): + if t is not None and scn is not None: + raise ValueError('you have to specify time or scenario index but not both') + + +class ConsumptionElement(Element): + def __init__(self, plotting: ElementPlotting, agg: ResultAnalyzer, name: str, node: str, kind: str): + Element.__init__(self, plotting, agg) + self.name = name + self.node = node + self.kind = kind + + def timeline(self): + cons = self.agg.agg_cons(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.iscn, self.agg.itime)[self.kind] + title = 'Consumptions %s for %s on node %s' % (self.kind, self.name, self.node) + return self.plotting.timeline(cons, title) + + def monotone(self, t: int = None, scn: int = None): + if t is not None and scn is not None: + raise ValueError('you have to specify time or scenario index but not both') + + if t is not None: + y = self.agg.agg_cons(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.itime[t], self.agg.iscn)[self.kind].values + title = 'Monotone consumption of %s on node %s at t=%0d' % (self.name, self.node, t) + elif scn is not None: + y = self.agg.agg_cons(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.iscn[scn], self.agg.itime)[self.kind].values + title = 'Monotone consumption of %s on node %s at t=%0d' % (self.name, self.node, scn) + + return self.plotting.monotone(y, title) + + def gaussian(self, t: int = None, scn: int = None): + + if t is None: + cons = self.agg.agg_cons(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.iscn[scn], self.agg.itime)[self.kind].values + rac = self.agg.get_rac()[scn, :] + title = 'Gaussian consumption of %s on node %s at scn=%0d' % (self.name, self.node, scn) + elif scn is None: + cons = self.agg.agg_cons(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.itime[t], self.agg.iscn)[self.kind].values + rac = self.agg.get_rac()[:, t] + title = 'Gaussian consumption of %s on node %s at t=%0d' % (self.name, self.node, t) + + return self.plotting.gaussian(rac=rac, qt=cons, title=title) + + +class ProductionElement(Element): + def __init__(self, plotting: ElementPlotting, agg: ResultAnalyzer, name: str, node: str, kind: str): + Element.__init__(self, plotting, agg) + self.name = name + self.node = node + self.kind = kind + + def timeline(self): + prod = self.agg.agg_prod(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.iscn, self.agg.itime)[self.kind] + title = 'Production %s for %s on node %s' % (self.kind, self.name, self.node) + return self.plotting.timeline(prod, title) + + def monotone(self, t: int = None, scn: int = None): + Element.monotone(self, t, scn) + + if t is not None: + y = self.agg.agg_prod(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.itime[t], self.agg.iscn)[self.kind].values + title = 'Monotone production of %s on node %s at t=%0d' % (self.name, self.node, t) + elif scn is not None: + y = self.agg.agg_prod(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.iscn[scn], self.agg.itime)[self.kind].values + title = 'Monotone production of %s on node %s at t=%0d' % (self.name, self.node, scn) + + return self.plotting.monotone(y, title) + + def gaussian(self, t: int = None, scn: int = None): + + if t is None: + prod = self.agg.agg_prod(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.iscn[scn], self.agg.itime)[self.kind].values + rac = self.agg.get_rac()[scn, :] + title = 'Gaussian production of %s on node %s at scn=%0d' % (self.name, self.node, scn) + elif scn is None: + prod = self.agg.agg_prod(self.agg.inode[self.node], self.agg.iname[self.name], + self.agg.itime[t], self.agg.iscn)[self.kind].values + rac = self.agg.get_rac()[:, t] + title = 'Gaussian production of %s on node %s at t=%0d' % (self.name, self.node, t) + + return self.plotting.gaussian(rac=rac, qt=prod, title=title) + + +class LinkElement(Element): + def __init__(self, plotting: ElementPlotting, agg: ResultAnalyzer, src: str, dest: str, kind: str): + Element.__init__(self, plotting, agg) + self.src = src + self.dest = dest + self.kind = kind + + def timeline(self): + links = self.agg.agg_link(self.agg.isrc[self.src], self.agg.idest[self.dest], self.agg.iscn, + self.agg.itime)[self.kind] + title = 'Link %s from %s to %s' % (self.kind, self.src, self.dest) + return self.plotting.timeline(links, title) + + def monotone(self, t: int = None, scn: int = None): + Element.monotone(self, t, scn) + + if t is not None: + y = self.agg.agg_link(self.agg.isrc[self.src], self.agg.idest[self.dest], + self.agg.itime[t], self.agg.iscn)[self.kind].values + title = 'Monotone link from %s to %s at t=%0d' % (self.src, self.dest, t) + elif scn is not None: + y = self.agg.agg_link(self.agg.isrc[self.src], self.agg.idest[self.dest], + self.agg.iscn[scn], self.agg.itime)[self.kind].values + title = 'Monotone link from %s to %s at t=%0d' % (self.src, self.dest, scn) + + return self.plotting.monotone(y, title) + + def gaussian(self, t: int = None, scn: int = None): + pass + + +class ABCPlotting(ABC): + """ + Abstract method to plot optimizer result. + """ + + @abstractmethod + def stack(self, node: str): + pass + + @abstractmethod + def exchanges_map(self, t: int, limit: int): pass @abstractmethod - def monotone_consumption(self, node: str, name: str, t: int, scn: int, kind: str = 'given'): + def consumption(self, node: str, name: str, kind: str = 'given') -> ConsumptionElement: pass @abstractmethod - def monotone_production(self, node: str, name: str, t: int = None, scn: int = None, kind: str = 'used'): + def production(self, node: str, name: str, kind: str = 'used') -> ProductionElement: pass @abstractmethod - def monotone_link(self, src: str, dest: str, t: int = None, scn: int = None, kind: str = 'used'): + def links(self, src: str, dest: str, kind: str = 'used') -> LinkElement: pass @abstractmethod diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index fa4450e..1cd4cf4 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -13,15 +13,71 @@ from matplotlib.cm import coolwarm from hadar.analyzer.result import ResultAnalyzer, NodeIndex, SrcIndex, TimeIndex, DestIndex, NameIndex -from hadar.viewer.abc import ABCPlotting - +from hadar.viewer.abc import ABCPlotting, ConsumptionElement, ElementPlotting, ProductionElement, LinkElement __all__ = ['HTMLPlotting'] + +class HTMLElementPlotting(ElementPlotting): + def __init__(self, unit: str, time_index): + self.unit = unit + self.time_index = time_index + + def timeline(self, df: pd.DataFrame, title: str): + scenarios = df.index.get_level_values('scn').unique() + alpha = max(10, 255 / scenarios.size) + color = 'rgba(100, 100, 100, %d)' % alpha + + fig = go.Figure() + for scn in scenarios: + fig.add_trace(go.Scatter(x=self.time_index, y=df.loc[scn], mode='lines', hoverinfo='name', + name='scn %0d' % scn, line=dict(color=color))) + + fig.update_layout(title_text=title, + yaxis_title="Quantity %s" % self.unit, xaxis_title="time", showlegend=False) + + return fig + + def monotone(self, y: np.ndarray, title: str): + y.sort() + x = np.linspace(0, 100, y.size) + + fig = go.Figure() + fig.add_trace(go.Scatter(x=x, y=y, mode='markers')) + fig.update_layout(title_text=title, + yaxis_title="Quantity %s" % self.unit, xaxis_title="%", showlegend=False) + + return fig + + def gaussian(self, rac: np.ndarray, qt: np.ndarray, title: str): + # 1 / x - m \ 2 + # --------- * exp -0.5 * | -------- | + # o * √2*Pi \ o / + def _gaussian(x, m, o): + return np.exp(-0.5 * np.power((x - m) / o, 2)) / o / 1.772454 + + x = np.linspace(np.min(qt) * 0, np.max(qt) * 1.2, 100) + m = np.mean(qt) + o = np.std(qt) + + green = qt[rac >= 0] + red = qt[rac < 0] + + fig = go.Figure() + fig.add_trace(go.Scatter(x=x, y=_gaussian(x, m, o), mode='lines', hoverinfo='none', line=dict(color='grey'))) + fig.add_trace(go.Scatter(x=green, y=_gaussian(green, m, o), hovertemplate='%{x:.2f} ' + self.unit, + name='passed', mode='markers', marker=dict(color='green', size=10))) + fig.add_trace(go.Scatter(x=green, y=_gaussian(red, m, o), hovertemplate='%{x:.2f} ' + self.unit, + name='failed', mode='markers', marker=dict(color='red', size=10))) + + return fig + + class HTMLPlotting(ABCPlotting): """ Plotting implementation interactive html graphics. (Use plotly) """ + def __init__(self, agg: ResultAnalyzer, unit_symbol: str = '', time_start=None, time_end=None, cmap=coolwarm, @@ -92,7 +148,7 @@ def stack(self, node: str, scn: int = 0, prod_kind: str = 'used', cons_kind: str # stack production with area if p > 0: - prod = self.agg.agg_prod(self.agg.iscn[scn], self.agg.inode[node], self.agg.iname, self.agg.itime)\ + prod = self.agg.agg_prod(self.agg.iscn[scn], self.agg.inode[node], self.agg.iname, self.agg.itime) \ .sort_values('cost', ascending=True) for i, name in enumerate(prod.index.get_level_values('name').unique()): stack += prod.loc[name][prod_kind].sort_index().values @@ -111,7 +167,7 @@ def stack(self, node: str, scn: int = 0, prod_kind: str = 'used', cons_kind: str cons_lines = [] # Stack consumptions with line if c > 0: - cons = self.agg.agg_cons(self.agg.iscn[scn], self.agg.inode[node], self.agg.iname, self.agg.itime)\ + cons = self.agg.agg_cons(self.agg.iscn[scn], self.agg.inode[node], self.agg.iname, self.agg.itime) \ .sort_values('cost', ascending=False) for i, name in enumerate(cons.index.get_level_values('name').unique()): stack += cons.loc[name][cons_kind].sort_index().values @@ -126,7 +182,7 @@ def stack(self, node: str, scn: int = 0, prod_kind: str = 'used', cons_kind: str # Plot line in the reverse sens to avoid misunderstood during graphics analyze for i, (name, stack) in enumerate(cons_lines[::-1]): fig.add_trace(go.Scatter(x=self.time_index, y=stack.copy(), line_color=self.cmap_cons[i % 10], - name= name, line=dict(width=2))) + name=name, line=dict(width=2))) fig.update_layout(title_text='Stack for node %s' % node, yaxis_title="Quantity %s" % self.unit, xaxis_title="time") @@ -213,22 +269,7 @@ def exchanges_map(self, t: int, scn: int = 0, limit: int = None): return fig - def _timeline(self, df: pd.DataFrame, title: str): - scenarios = df.index.get_level_values('scn').unique() - alpha = max(10, 255 / scenarios.size) - color = 'rgba(100, 100, 100, %d)' % alpha - - fig = go.Figure() - for scn in scenarios: - fig.add_trace(go.Scatter(x=self.time_index, y=df.loc[scn], mode='lines', hoverinfo='name', - name='scn %0d' % scn, line=dict(color=color))) - - fig.update_layout(title_text=title, - yaxis_title="Quantity %s" % self.unit, xaxis_title="time", showlegend=False) - - return fig - - def consumptions(self, node: str, name: str, kind: str = 'given'): + def consumption(self, node: str, name: str, kind: str = 'given') -> ConsumptionElement: """ Plot all timelines consumption scenario. @@ -237,11 +278,10 @@ def consumptions(self, node: str, name: str, kind: str = 'given'): :param kind: kind of data 'asked' or 'given' :return: """ - cons = self.agg.agg_cons(self.agg.inode[node], self.agg.iname[name], self.agg.iscn, self.agg.itime)[kind] - title = 'Consumptions %s for %s on node %s' % (kind, name, node) - return self._timeline(cons, title) + return ConsumptionElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg, + node=node, name=name, kind=kind) - def productions(self, node: str, name: str, kind: str = 'used'): + def production(self, node: str, name: str, kind: str = 'used') -> ProductionElement: """ Plot all timelines production scenario. @@ -250,10 +290,8 @@ def productions(self, node: str, name: str, kind: str = 'used'): :param kind: kind of data available ('avail') or 'used' :return: """ - prod = self.agg.agg_prod(self.agg.inode[node], self.agg.iname[name], self.agg.iscn, self.agg.itime)[kind] - title = 'Productions %s for %s on node %s' % (kind, name, node) - return self._timeline(prod, title) - + return ProductionElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg, + node=node, name=name, kind=kind) def links(self, src: str, dest: str, kind: str = 'used'): """ @@ -264,96 +302,8 @@ def links(self, src: str, dest: str, kind: str = 'used'): :param kind: kind of data available ('avail') or 'used' :return: """ - links = self.agg.agg_link(self.agg.isrc[src], self.agg.idest[dest], self.agg.iscn, self.agg.itime)[kind] - title = 'Link %s from %s to %s' % (kind, src, dest) - return self._timeline(links, title) - - - def _monotone(self, y: np.ndarray, title: str): - y.sort() - x = np.linspace(0, 100, y.size) - - fig = go.Figure() - fig.add_trace(go.Scatter(x=x, y=y, mode='markers')) - fig.update_layout(title_text=title, - yaxis_title="Quantity %s" % self.unit, xaxis_title="%", showlegend=False) - - return fig - - def monotone_consumption(self, node: str, name: str, t: int = None, scn: int = None, kind: str = 'given'): - """ - Plot ascending monotone of consumption. - - :param node: selected node - :param name: selected consumption name - :param t: select t index (only if scn is not used) - :param scn: select scn index (only if t is not used) - :param kind: kind of consumption 'asked' or 'given' - :return: - """ - if t is not None and scn is not None: - raise ValueError('you have to specify time or scenario index but not both') - - if t is not None: - y = self.agg.agg_cons(self.agg.inode[node], self.agg.iname[name], - self.agg.itime[t], self.agg.iscn)[kind].values - title = 'Monotone consumption of %s on node %s at t=%0d' % (name, node, t) - elif scn is not None: - y = self.agg.agg_cons(self.agg.inode[node], self.agg.iname[name], - self.agg.iscn[scn], self.agg.itime)[kind].values - title = 'Monotone consumption of %s on node %s at t=%0d' % (name, node, scn) - - return self._monotone(y, title) - - def monotone_production(self, node: str, name: str, t: int = None, scn: int = None, kind: str = 'used'): - """ - Plot ascending monotone of production - - :param node: selected node name - :param name: selected production name - :param t: select t index (only if scn is not used) - :param scn: select scn index (only if t is not used) - :param kind: kind of production available ('avail') of 'used - :return: - """ - if t is not None and scn is not None: - raise ValueError('you have to specify time or scenario index but not both') - - if t is not None: - y = self.agg.agg_prod(self.agg.inode[node], self.agg.iname[name], - self.agg.itime[t], self.agg.iscn)[kind].values - title = 'Monotone production of %s on node %s at t=%0d' % (name, node, t) - elif scn is not None: - y = self.agg.agg_prod(self.agg.inode[node], self.agg.iname[name], - self.agg.iscn[scn], self.agg.itime)[kind].values - title = 'Monotone production of %s on node %s at t=%0d' % (name, node, scn) - - return self._monotone(y, title) - - def monotone_link(self, src: str, dest: str, t: int = None, scn: int = None, kind: str = 'used'): - """ - Plot ascending monotone of production - - :param src: selected source node name - :param dest: selected destination node name - :param t: select t index (only if scn is not used) - :param scn: select scn index (only if t is not used) - :param kind: kind of link available ('avail') of 'used - :return: - """ - if t is not None and scn is not None: - raise ValueError('you have to specify time or scenario index but not both') - - if t is not None: - y = self.agg.agg_link(self.agg.isrc[src], self.agg.idest[dest], - self.agg.itime[t], self.agg.iscn)[kind].values - title = 'Monotone link from %s to %s at t=%0d' % (src, dest, t) - elif scn is not None: - y = self.agg.agg_link(self.agg.isrc[src], self.agg.idest[dest], - self.agg.iscn[scn], self.agg.itime)[kind].values - title = 'Monotone link from %s to %s at t=%0d' % (src, dest, scn) - - return self._monotone(y, title) + return LinkElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg, + src=src, dest=dest, kind=kind) def rac_heatmap(self): rac = self.agg.get_rac() @@ -368,4 +318,4 @@ def rac_heatmap(self): fig.update_layout(title_text="RAC Matrix %0d %% passed" % pct, yaxis_title="scenarios", xaxis_title="time", showlegend=False) - return fig \ No newline at end of file + return fig diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 46bbfbe..21ec3a2 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -47,29 +47,36 @@ def test_map_exchanges(self): self.assert_fig_hash('9aa34f28665ea9e6766b271ffbc677d3cda6810b', fig) def test_plot_timeline(self): - fig = self.plot.consumptions(node='a', name='load') + fig = self.plot.consumption(node='a', name='load').timeline() self.assert_fig_hash('7787e0487f8f4012dc8b8f0cf979ffbb09fffb63', fig) - fig = self.plot.productions(node='b', name='nuclear') - self.assert_fig_hash('44e414ef08a43add5ef68b5c533b47145fab0ba2', fig) + fig = self.plot.production(node='b', name='nuclear').timeline() + self.assert_fig_hash('e9d05c4f002acaebbc39eb813d53994a6a34a1fa', fig) - fig = self.plot.links(src='a', dest='b') + fig = self.plot.links(src='a', dest='b').timeline() self.assert_fig_hash('6375e591679d12907f440a8c23eb850a037d9cd8', fig) def test_plot_monotone(self): - fig = self.plot.monotone_consumption(node='a', name='load', scn=0) + fig = self.plot.consumption(node='a', name='load').monotone(scn=0) self.assert_fig_hash('753619bf85b387f3b0f304688bb578efe39db3e9', fig) - fig = self.plot.monotone_production(node='b', name='nuclear', t=0) + fig = self.plot.production(node='b', name='nuclear').monotone(t=0) self.assert_fig_hash('0a99228bf1a0743b604e9082b0ba7db86f3993f3', fig) - fig = self.plot.monotone_link(src='a', dest='b', scn=0) + fig = self.plot.links(src='a', dest='b').monotone(scn=0) self.assert_fig_hash('2e2410dad5800c9658846c40421dbe83c9e5f3f9', fig) def test_rac_heatmap(self): fig = self.plot.rac_heatmap() self.assert_fig_hash('1fa715af27e4ab85b033cff41f5edff72f4bca88', fig) + def test_gaussian(self): + fig = self.plot.consumption(node='a', name='load').gaussian(scn=0) + self.assert_fig_hash('389ae83ae6bac5d6215712a9666bda4b80a4f8cf', fig) + + fig = self.plot.production(node='b', name='nuclear').gaussian(t=0) + fig.show() + def assert_fig_hash(self, expected: str, fig: go.Figure): h = hashlib.sha1() h.update(TestHTMLPlotting.get_html(fig)) From 167b8066a71688af6cbeb826b6c70b1d3b892399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Tue, 16 Jun 2020 14:20:40 +0200 Subject: [PATCH 18/34] close #65 Add gaussian. refactor stack with new APi --- hadar/viewer/abc.py | 107 +++++++++++++++++++++++++++++--------- hadar/viewer/html.py | 94 +++++++++++++-------------------- tests/viewer/test_html.py | 10 ++-- 3 files changed, 126 insertions(+), 85 deletions(-) diff --git a/hadar/viewer/abc.py b/hadar/viewer/abc.py index be1111b..031853b 100644 --- a/hadar/viewer/abc.py +++ b/hadar/viewer/abc.py @@ -4,6 +4,7 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. +from typing import List, Tuple import numpy as np import pandas as pd @@ -12,7 +13,7 @@ from hadar.analyzer.result import ResultAnalyzer -class ElementPlotting(ABC): +class ABCElementPlotting(ABC): @abstractmethod def timeline(self, df: pd.DataFrame, title: str): pass @@ -25,29 +26,24 @@ def monotone(self, y: np.ndarray, title: str): def gaussian(self, rac: np.ndarray, qt: np.ndarray, title: str): pass + @abstractmethod + def stack(self, areas: List[Tuple[str, np.ndarray]], lines: List[Tuple[str, np.ndarray]], title: str): + pass + class Element(ABC): - def __init__(self, plotting: ElementPlotting, agg: ResultAnalyzer): + def __init__(self, plotting: ABCElementPlotting, agg: ResultAnalyzer): self.plotting = plotting self.agg = agg - @abstractmethod - def timeline(self): - pass - - @abstractmethod - def monotone(self, t: int = None, scn: int = None): - if t is not None and scn is not None: - raise ValueError('you have to specify time or scenario index but not both') - - @abstractmethod - def gaussian(self, t: int = None, scn: int = None): + @staticmethod + def not_both(t: int, scn: int): if t is not None and scn is not None: raise ValueError('you have to specify time or scenario index but not both') class ConsumptionElement(Element): - def __init__(self, plotting: ElementPlotting, agg: ResultAnalyzer, name: str, node: str, kind: str): + def __init__(self, plotting: ABCElementPlotting, agg: ResultAnalyzer, name: str, node: str, kind: str): Element.__init__(self, plotting, agg) self.name = name self.node = node @@ -60,8 +56,7 @@ def timeline(self): return self.plotting.timeline(cons, title) def monotone(self, t: int = None, scn: int = None): - if t is not None and scn is not None: - raise ValueError('you have to specify time or scenario index but not both') + Element.not_both(t, scn) if t is not None: y = self.agg.agg_cons(self.agg.inode[self.node], self.agg.iname[self.name], @@ -75,6 +70,7 @@ def monotone(self, t: int = None, scn: int = None): return self.plotting.monotone(y, title) def gaussian(self, t: int = None, scn: int = None): + Element.not_both(t, scn) if t is None: cons = self.agg.agg_cons(self.agg.inode[self.node], self.agg.iname[self.name], @@ -91,7 +87,7 @@ def gaussian(self, t: int = None, scn: int = None): class ProductionElement(Element): - def __init__(self, plotting: ElementPlotting, agg: ResultAnalyzer, name: str, node: str, kind: str): + def __init__(self, plotting: ABCElementPlotting, agg: ResultAnalyzer, name: str, node: str, kind: str): Element.__init__(self, plotting, agg) self.name = name self.node = node @@ -104,7 +100,7 @@ def timeline(self): return self.plotting.timeline(prod, title) def monotone(self, t: int = None, scn: int = None): - Element.monotone(self, t, scn) + Element.not_both(t, scn) if t is not None: y = self.agg.agg_prod(self.agg.inode[self.node], self.agg.iname[self.name], @@ -118,6 +114,7 @@ def monotone(self, t: int = None, scn: int = None): return self.plotting.monotone(y, title) def gaussian(self, t: int = None, scn: int = None): + Element.not_both(t, scn) if t is None: prod = self.agg.agg_prod(self.agg.inode[self.node], self.agg.iname[self.name], @@ -134,7 +131,7 @@ def gaussian(self, t: int = None, scn: int = None): class LinkElement(Element): - def __init__(self, plotting: ElementPlotting, agg: ResultAnalyzer, src: str, dest: str, kind: str): + def __init__(self, plotting: ABCElementPlotting, agg: ResultAnalyzer, src: str, dest: str, kind: str): Element.__init__(self, plotting, agg) self.src = src self.dest = dest @@ -147,7 +144,7 @@ def timeline(self): return self.plotting.timeline(links, title) def monotone(self, t: int = None, scn: int = None): - Element.monotone(self, t, scn) + Element.not_both(t, scn) if t is not None: y = self.agg.agg_link(self.agg.isrc[self.src], self.agg.idest[self.dest], @@ -161,7 +158,69 @@ def monotone(self, t: int = None, scn: int = None): return self.plotting.monotone(y, title) def gaussian(self, t: int = None, scn: int = None): - pass + Element.not_both(t, scn) + + if t is None: + prod = self.agg.agg_link(self.agg.isrc[self.src], self.agg.idest[self.dest], + self.agg.iscn[scn], self.agg.itime)[self.kind].values + rac = self.agg.get_rac()[scn, :] + title = 'Gaussian link from %s to %s at t=%0d' % (self.src, self.dest, scn) + elif scn is None: + prod = self.agg.agg_prod(self.agg.isrc[self.src], self.agg.idest[self.dest], + self.agg.itime[t], self.agg.iscn)[self.kind].values + rac = self.agg.get_rac()[:, t] + title = 'Gaussian link from %s to %s at t=%0d' % (self.src, self.dest, t) + + return self.plotting.gaussian(rac=rac, qt=prod, title=title) + + +class NodeElement(Element): + def __init__(self, plotting: ABCElementPlotting, agg: ResultAnalyzer, node: str): + Element.__init__(self, plotting, agg) + self.node = node + + def stack(self, scn: int = 0, prod_kind: str = 'used', cons_kind: str = 'asked'): + """ + Plot with production stacked with area and consumptions stacked by dashed lines. + + :param node: select node to plot. + :param scn: scenario index to plot. + :param prod_kind: select which prod to stack : available ('avail') or 'used' + :param cons_kind: select which cons to stack : 'asked' or 'given' + :return: plotly figure or jupyter widget to plot + """ + c, p, b = self.agg.get_elements_inside(node=self.node) + + areas = [] + # stack production with area + if p > 0: + prod = self.agg.agg_prod(self.agg.iscn[scn], self.agg.inode[self.node], self.agg.iname, self.agg.itime) \ + .sort_values('cost', ascending=True) + for i, name in enumerate(prod.index.get_level_values('name').unique()): + areas.append((name, prod.loc[name][prod_kind].sort_index().values)) + + # add import in production stack + balance = self.agg.get_balance(node=self.node)[scn] + im = -np.clip(balance, None, 0) + if not (im == 0).all(): + areas.append(('import', im)) + + lines = [] + # Stack consumptions with line + if c > 0: + cons = self.agg.agg_cons(self.agg.iscn[scn], self.agg.inode[self.node], self.agg.iname, self.agg.itime) \ + .sort_values('cost', ascending=False) + for i, name in enumerate(cons.index.get_level_values('name').unique()): + lines.append((name, cons.loc[name][cons_kind].sort_index().values)) + + # Add export in consumption stack + exp = np.clip(balance, 0, None) + if not (exp == 0).all(): + lines.append(('export', exp)) + + title = 'Stack for node %s' % self.node + + return self.plotting.stack(areas, lines, title) class ABCPlotting(ABC): @@ -170,7 +229,7 @@ class ABCPlotting(ABC): """ @abstractmethod - def stack(self, node: str): + def node(self, node: str) -> NodeElement: pass @abstractmethod @@ -189,6 +248,6 @@ def production(self, node: str, name: str, kind: str = 'used') -> ProductionElem def links(self, src: str, dest: str, kind: str = 'used') -> LinkElement: pass - @abstractmethod - def rac_heatmap(self): + # abstractmethod + def adequacy(self): pass diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index 1cd4cf4..f018ab8 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. -from typing import Dict, List +from typing import Dict, List, Tuple import numpy as np import pandas as pd @@ -13,16 +13,20 @@ from matplotlib.cm import coolwarm from hadar.analyzer.result import ResultAnalyzer, NodeIndex, SrcIndex, TimeIndex, DestIndex, NameIndex -from hadar.viewer.abc import ABCPlotting, ConsumptionElement, ElementPlotting, ProductionElement, LinkElement +from hadar.viewer.abc import ABCPlotting, ConsumptionElement, ABCElementPlotting, ProductionElement, LinkElement, \ + NodeElement __all__ = ['HTMLPlotting'] -class HTMLElementPlotting(ElementPlotting): +class HTMLElementPlotting(ABCElementPlotting): def __init__(self, unit: str, time_index): self.unit = unit self.time_index = time_index + self.cmap_cons = ['brown', 'blue', 'darkgoldenrod', 'darkmagenta', 'darkorange', 'cadetblue', 'forestgreen', + 'indigo', 'olive', 'darkred'] + def timeline(self, df: pd.DataFrame, title: str): scenarios = df.index.get_level_values('scn').unique() alpha = max(10, 255 / scenarios.size) @@ -69,7 +73,34 @@ def _gaussian(x, m, o): name='passed', mode='markers', marker=dict(color='green', size=10))) fig.add_trace(go.Scatter(x=green, y=_gaussian(red, m, o), hovertemplate='%{x:.2f} ' + self.unit, name='failed', mode='markers', marker=dict(color='red', size=10))) + fig.update_layout(title_text=title, yaxis=dict(visible=False), + yaxis_title='', xaxis_title="Quantity %s" % self.unit, showlegend=False) + + return fig + + def stack(self, areas: List[Tuple[str, np.ndarray]], lines: List[Tuple[str, np.ndarray]], title: str): + fig = go.Figure() + + # Stack areas + stack = np.zeros_like(self.time_index, dtype=float) + for i, (name, data) in enumerate(areas): + stack += data + fig.add_trace(go.Scatter(x=self.time_index, y=stack.copy(), name=name, mode='none', + fill='tozeroy' if i == 0 else 'tonexty')) + + # Stack lines. + # Bottom line have to be top frontward. So we firstly stack lines then plot in reverse set. + stack = np.zeros_like(self.time_index, dtype=float) + stacked_lines = [] + for i, (name, data) in enumerate(lines): + stack += data + stacked_lines.append((name, stack.copy())) + + for i, (name, data) in enumerate(stacked_lines[::-1]): + fig.add_trace(go.Scatter(x=self.time_index, y=data, line_color=self.cmap_cons[i % 10], + name=name, line=dict(width=2))) + fig.update_layout(title_text=title, yaxis_title="Quantity %s" % self.unit, xaxis_title="time") return fig @@ -132,61 +163,8 @@ def matplotlib_to_plotly(cls, cmap, res: int): pl_colorscale.append([k * h, 'rgb' + str((C[0], C[1], C[2]))]) return pl_colorscale - def stack(self, node: str, scn: int = 0, prod_kind: str = 'used', cons_kind: str = 'asked'): - """ - Plot with production stacked with area and consumptions stacked by dashed lines. - - :param node: select node to plot. - :param scn: scenario index to plot. - :param prod_kind: select which prod to stack : available ('avail') or 'used' - :param cons_kind: select which cons to stack : 'asked' or 'given' - :return: plotly figure or jupyter widget to plot - """ - fig = go.Figure() - c, p, b = self.agg.get_elements_inside(node=node) - stack = np.zeros(self.agg.horizon) - - # stack production with area - if p > 0: - prod = self.agg.agg_prod(self.agg.iscn[scn], self.agg.inode[node], self.agg.iname, self.agg.itime) \ - .sort_values('cost', ascending=True) - for i, name in enumerate(prod.index.get_level_values('name').unique()): - stack += prod.loc[name][prod_kind].sort_index().values - fig.add_trace(go.Scatter(x=self.time_index, y=stack.copy(), name=name, mode='none', - fill='tozeroy' if i == 0 else 'tonexty')) - - # add import in production stack - balance = self.agg.get_balance(node=node)[scn] - im = -np.clip(balance, None, 0) - if not (im == 0).all(): - stack += im - fig.add_trace(go.Scatter(x=self.time_index, y=stack.copy(), name='import', mode='none', fill='tonexty')) - - # Reset stack - stack = np.zeros_like(stack) - cons_lines = [] - # Stack consumptions with line - if c > 0: - cons = self.agg.agg_cons(self.agg.iscn[scn], self.agg.inode[node], self.agg.iname, self.agg.itime) \ - .sort_values('cost', ascending=False) - for i, name in enumerate(cons.index.get_level_values('name').unique()): - stack += cons.loc[name][cons_kind].sort_index().values - cons_lines.append([name, stack.copy()]) - - # Add export in consumption stack - exp = np.clip(balance, 0, None) - if not (exp == 0).all(): - stack += exp - cons_lines.append(['export', stack.copy()]) - - # Plot line in the reverse sens to avoid misunderstood during graphics analyze - for i, (name, stack) in enumerate(cons_lines[::-1]): - fig.add_trace(go.Scatter(x=self.time_index, y=stack.copy(), line_color=self.cmap_cons[i % 10], - name=name, line=dict(width=2))) - - fig.update_layout(title_text='Stack for node %s' % node, - yaxis_title="Quantity %s" % self.unit, xaxis_title="time") - return fig + def node(self, node: str): + return NodeElement(plotting=HTMLElementPlotting(unit=self.unit, time_index=self.time_index), agg=self.agg, node=node) def _plot_links(self, fig: go.Figure, start: str, end: str, color: str, qt: float): """ diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 21ec3a2..0ddc96e 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -39,7 +39,8 @@ def setUp(self) -> None: self.hash = hashlib.sha3_256() def test_stack(self): - fig = self.plot.stack(node='a', scn=0) + fig = self.plot.node('a').stack(scn=0) + fig.show() self.assert_fig_hash('d9f9f004b98ca62be934d69d4fd0c1a302512242', fig) def test_map_exchanges(self): @@ -72,10 +73,13 @@ def test_rac_heatmap(self): def test_gaussian(self): fig = self.plot.consumption(node='a', name='load').gaussian(scn=0) - self.assert_fig_hash('389ae83ae6bac5d6215712a9666bda4b80a4f8cf', fig) + self.assert_fig_hash('ac67d36ff0aaff356144ccb78f665947e8b13adb', fig) fig = self.plot.production(node='b', name='nuclear').gaussian(t=0) - fig.show() + self.assert_fig_hash('2094b8141fbbdfd6841a782ceef2196bf76b2a8c', fig) + + fig = self.plot.links(src='a', dest='b').gaussian(scn=0) + self.assert_fig_hash('3420c78029bafebbadedeb39d906269810acfd88', fig) def assert_fig_hash(self, expected: str, fig: go.Figure): h = hashlib.sha1() From e87755280f0360e9aee1b1d346d2ed3b97b3e2dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Tue, 16 Jun 2020 15:21:36 +0200 Subject: [PATCH 19/34] refactor rac heatmap with new api --- hadar/viewer/abc.py | 18 +++++++++++++++--- hadar/viewer/html.py | 31 +++++++++++++++---------------- tests/viewer/test_html.py | 8 ++++---- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/hadar/viewer/abc.py b/hadar/viewer/abc.py index 031853b..f91968e 100644 --- a/hadar/viewer/abc.py +++ b/hadar/viewer/abc.py @@ -30,6 +30,10 @@ def gaussian(self, rac: np.ndarray, qt: np.ndarray, title: str): def stack(self, areas: List[Tuple[str, np.ndarray]], lines: List[Tuple[str, np.ndarray]], title: str): pass + @abstractmethod + def matrix(self, data: np.ndarray, title): + pass + class Element(ABC): def __init__(self, plotting: ABCElementPlotting, agg: ResultAnalyzer): @@ -223,6 +227,14 @@ def stack(self, scn: int = 0, prod_kind: str = 'used', cons_kind: str = 'asked') return self.plotting.stack(areas, lines, title) +class NetworkElement(Element): + def rac_matrix(self): + rac = self.agg.get_rac() + pct = (rac >= 0).sum() / rac.size * 100 + title = "RAC Matrix %0d %% passed" % pct + + return self.plotting.matrix(data=rac, title=title) + class ABCPlotting(ABC): """ Abstract method to plot optimizer result. @@ -245,9 +257,9 @@ def production(self, node: str, name: str, kind: str = 'used') -> ProductionElem pass @abstractmethod - def links(self, src: str, dest: str, kind: str = 'used') -> LinkElement: + def link(self, src: str, dest: str, kind: str = 'used') -> LinkElement: pass - # abstractmethod - def adequacy(self): + @abstractmethod + def network(self): pass diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index f018ab8..25077ef 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -14,7 +14,7 @@ from hadar.analyzer.result import ResultAnalyzer, NodeIndex, SrcIndex, TimeIndex, DestIndex, NameIndex from hadar.viewer.abc import ABCPlotting, ConsumptionElement, ABCElementPlotting, ProductionElement, LinkElement, \ - NodeElement + NodeElement, NetworkElement __all__ = ['HTMLPlotting'] @@ -103,6 +103,17 @@ def stack(self, areas: List[Tuple[str, np.ndarray]], lines: List[Tuple[str, np.n fig.update_layout(title_text=title, yaxis_title="Quantity %s" % self.unit, xaxis_title="time") return fig + def matrix(self, data: np.ndarray, title): + fig = go.Figure(data=go.Heatmap( + z=data, + x=self.time_index, + y=np.arange(data.shape[0]), + colorscale='RdBu', zmid=0)) + + fig.update_layout(title_text=title, yaxis_title="scenarios", xaxis_title="time", showlegend=False) + + return fig + class HTMLPlotting(ABCPlotting): """ @@ -271,7 +282,7 @@ def production(self, node: str, name: str, kind: str = 'used') -> ProductionElem return ProductionElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg, node=node, name=name, kind=kind) - def links(self, src: str, dest: str, kind: str = 'used'): + def link(self, src: str, dest: str, kind: str = 'used'): """ Plot all timelines links scenario. @@ -283,17 +294,5 @@ def links(self, src: str, dest: str, kind: str = 'used'): return LinkElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg, src=src, dest=dest, kind=kind) - def rac_heatmap(self): - rac = self.agg.get_rac() - pct = (rac >= 0).sum() / rac.size * 100 - - fig = go.Figure(data=go.Heatmap( - z=rac, - x=self.time_index, - y=np.arange(self.agg.nb_scn), - colorscale='RdBu', zmid=0)) - - fig.update_layout(title_text="RAC Matrix %0d %% passed" % pct, - yaxis_title="scenarios", xaxis_title="time", showlegend=False) - - return fig + def network(self): + return NetworkElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg) diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 0ddc96e..3d8aa31 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -54,7 +54,7 @@ def test_plot_timeline(self): fig = self.plot.production(node='b', name='nuclear').timeline() self.assert_fig_hash('e9d05c4f002acaebbc39eb813d53994a6a34a1fa', fig) - fig = self.plot.links(src='a', dest='b').timeline() + fig = self.plot.link(src='a', dest='b').timeline() self.assert_fig_hash('6375e591679d12907f440a8c23eb850a037d9cd8', fig) def test_plot_monotone(self): @@ -64,11 +64,11 @@ def test_plot_monotone(self): fig = self.plot.production(node='b', name='nuclear').monotone(t=0) self.assert_fig_hash('0a99228bf1a0743b604e9082b0ba7db86f3993f3', fig) - fig = self.plot.links(src='a', dest='b').monotone(scn=0) + fig = self.plot.link(src='a', dest='b').monotone(scn=0) self.assert_fig_hash('2e2410dad5800c9658846c40421dbe83c9e5f3f9', fig) def test_rac_heatmap(self): - fig = self.plot.rac_heatmap() + fig = self.plot.network().rac_matrix() self.assert_fig_hash('1fa715af27e4ab85b033cff41f5edff72f4bca88', fig) def test_gaussian(self): @@ -78,7 +78,7 @@ def test_gaussian(self): fig = self.plot.production(node='b', name='nuclear').gaussian(t=0) self.assert_fig_hash('2094b8141fbbdfd6841a782ceef2196bf76b2a8c', fig) - fig = self.plot.links(src='a', dest='b').gaussian(scn=0) + fig = self.plot.link(src='a', dest='b').gaussian(scn=0) self.assert_fig_hash('3420c78029bafebbadedeb39d906269810acfd88', fig) def assert_fig_hash(self, expected: str, fig: go.Figure): From f33663b40953b7a5b06f3202776282d748997459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 17 Jun 2020 17:26:43 +0200 Subject: [PATCH 20/34] close #62 Improve map exchange graphics --- hadar/viewer/abc.py | 103 ++++++++++++++--- hadar/viewer/html.py | 237 ++++++++++++++------------------------ tests/viewer/test_html.py | 5 +- 3 files changed, 173 insertions(+), 172 deletions(-) diff --git a/hadar/viewer/abc.py b/hadar/viewer/abc.py index f91968e..124e0fa 100644 --- a/hadar/viewer/abc.py +++ b/hadar/viewer/abc.py @@ -4,7 +4,7 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. -from typing import List, Tuple +from typing import List, Tuple, Dict import numpy as np import pandas as pd @@ -34,6 +34,9 @@ def stack(self, areas: List[Tuple[str, np.ndarray]], lines: List[Tuple[str, np.n def matrix(self, data: np.ndarray, title): pass + def map_exchange(self, nodes, lines, limit, title): + pass + class Element(ABC): def __init__(self, plotting: ABCElementPlotting, agg: ResultAnalyzer): @@ -235,31 +238,97 @@ def rac_matrix(self): return self.plotting.matrix(data=rac, title=title) -class ABCPlotting(ABC): + def map(self, scn: int, t: int, limit: int = None): + nodes = {node: self.agg.get_balance(node=node)[scn, t] for node in self.agg.nodes} + + if limit is None: + limit = max(max(nodes.values()), -min(nodes.values())) + + lines = {} + # Compute lines + links = self.agg.agg_link(self.agg.iscn[scn], self.agg.itime[t], self.agg.isrc, self.agg.idest) + for src in links.index.get_level_values('src').unique(): + for dest in links.loc[src].index.get_level_values('dest').unique(): + exchange = links.loc[src, dest]['used'] # forward + exchange -= links.loc[dest, src]['used'] if (dest, src) in links.index else 0 # backward + + if exchange >= 0: + lines[(src, dest)] = exchange + else: + lines[(dest, src)] = -exchange + + title = 'Exchange map at t=%0d scn=%0d' % (t, scn) + return self.plotting.map_exchange(nodes, lines, limit, title) + + +class Plotting(ABC): """ Abstract method to plot optimizer result. """ - @abstractmethod - def node(self, node: str) -> NodeElement: - pass + def __init__(self, agg: ResultAnalyzer, + unit_symbol: str = '', + time_start=None, time_end=None, + node_coord: Dict[str, List[float]] = None): + """ + Create instance. + + :param agg: ResultAggragator instence to use + :param unit_symbol: symbol on quantity unit used. ex. MW, litter, Go, ... + :param time_start: time to use as the start of study horizon + :param time_end: time to use as the end of study horizon + :param node_coord: nodes coordinates to use for map plotting + :param map_element_size: size on element draw on map. default as 1. + """ + self.plotting = None + self.agg = agg + self.unit = '(%s)' % unit_symbol if unit_symbol != '' else '' + self.coord = node_coord - @abstractmethod - def exchanges_map(self, t: int, limit: int): - pass + # Create time_index + time = [time_start is None, time_end is None] + if time == [True, False] or time == [False, True]: + raise ValueError('You have to give both time_start and time_end') + elif time == [False, False]: + self.time_index = pd.date_range(start=time_start, end=time_end, periods=self.agg.horizon) + else: + self.time_index = np.arange(self.agg.horizon) + + def node(self, node: str): + return NodeElement(plotting=self.plotting, agg=self.agg, node=node) - @abstractmethod def consumption(self, node: str, name: str, kind: str = 'given') -> ConsumptionElement: - pass + """ + Plot all timelines consumption scenario. + + :param node: selected node name + :param name: select consumption name + :param kind: kind of data 'asked' or 'given' + :return: + """ + return ConsumptionElement(plotting=self.plotting, agg=self.agg, node=node, name=name, kind=kind) - @abstractmethod def production(self, node: str, name: str, kind: str = 'used') -> ProductionElement: - pass + """ + Plot all timelines production scenario. - @abstractmethod - def link(self, src: str, dest: str, kind: str = 'used') -> LinkElement: - pass + :param node: selected node name + :param name: select production name + :param kind: kind of data available ('avail') or 'used' + :return: + """ + return ProductionElement(plotting=self.plotting, agg=self.agg, node=node, name=name, kind=kind) + + def link(self, src: str, dest: str, kind: str = 'used'): + """ + Plot all timelines links scenario. + + :param src: selected source node name + :param dest: select destination node name + :param kind: kind of data available ('avail') or 'used' + :return: + """ + return LinkElement(plotting=self.plotting, agg=self.agg, src=src, dest=dest, kind=kind) - @abstractmethod def network(self): - pass + return NetworkElement(plotting=self.plotting, agg=self.agg) diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index 25077ef..3219dd9 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -7,26 +7,47 @@ from typing import Dict, List, Tuple +import folium import numpy as np import pandas as pd import plotly.graph_objects as go from matplotlib.cm import coolwarm from hadar.analyzer.result import ResultAnalyzer, NodeIndex, SrcIndex, TimeIndex, DestIndex, NameIndex -from hadar.viewer.abc import ABCPlotting, ConsumptionElement, ABCElementPlotting, ProductionElement, LinkElement, \ +from hadar.viewer.abc import Plotting, ConsumptionElement, ABCElementPlotting, ProductionElement, LinkElement, \ NodeElement, NetworkElement __all__ = ['HTMLPlotting'] class HTMLElementPlotting(ABCElementPlotting): - def __init__(self, unit: str, time_index): + def __init__(self, unit: str, time_index, node_coord: Dict[str, List[float]] = None): self.unit = unit self.time_index = time_index + self.coord = node_coord + + self.cmap = coolwarm + self.cmap_plotly = HTMLElementPlotting.matplotlib_to_plotly(self.cmap, 255) self.cmap_cons = ['brown', 'blue', 'darkgoldenrod', 'darkmagenta', 'darkorange', 'cadetblue', 'forestgreen', 'indigo', 'olive', 'darkred'] + @classmethod + def matplotlib_to_plotly(cls, cmap, res: int): + """ + Convert matplotlib color scale to plotly color scale. + + :param cmap: matplotlib color scale function + :param res: resolution to use + :return: list of string use by plotly + """ + h = 1.0 / (res - 1) + pl_colorscale = [] + for k in range(res): + C = (np.array(cmap(k * h)[:3]) * 255).astype(np.uint8) + pl_colorscale.append([k * h, 'rgb' + str((C[0], C[1], C[2]))]) + return pl_colorscale + def timeline(self, df: pd.DataFrame, title: str): scenarios = df.index.get_level_values('scn').unique() alpha = max(10, 255 / scenarios.size) @@ -114,70 +135,44 @@ def matrix(self, data: np.ndarray, title): return fig + def map_exchange(self, nodes, lines, limit, title): + if self.coord is None: + raise ValueError('Please provide node coordinate by setting param node_coord in Plotting constructor') -class HTMLPlotting(ABCPlotting): - """ - Plotting implementation interactive html graphics. (Use plotly) - """ - - def __init__(self, agg: ResultAnalyzer, unit_symbol: str = '', - time_start=None, time_end=None, - cmap=coolwarm, - node_coord: Dict[str, List[float]] = None, - map_element_size: int = 1): - """ - Create instance. - - :param agg: ResultAggragator instence to use - :param unit_symbol: symbol on quantity unit used. ex. MW, litter, Go, ... - :param time_start: time to use as the start of study horizon - :param time_end: time to use as the end of study horizon - :param cmap: matplotlib color map to use (coolwarm as default) - :param node_coord: nodes coordinates to use for map plotting - :param map_element_size: size on element draw on map. default as 1. - """ - - self.agg = agg - self.unit = '(%s)' % unit_symbol if unit_symbol != '' else '' - self.coord = node_coord - self.size = map_element_size - - # Create time_index - time = [time_start is None, time_end is None] - if time == [True, False] or time == [False, True]: - raise ValueError('You have to give both time_start and time_end') - elif time == [False, False]: - self.time_index = pd.date_range(start=time_start, end=time_end, periods=self.agg.horizon) - else: - self.time_index = np.arange(self.agg.horizon) - - # Create colors scale - self.cmap = cmap - self.cmap_plotly = HTMLPlotting.matplotlib_to_plotly(cmap, 255) - - self.cmap_cons = ['brown', 'blue', 'darkgoldenrod', 'darkmagenta', 'darkorange', 'cadetblue', 'forestgreen', - 'indigo', 'olive', 'darkred'] - - @classmethod - def matplotlib_to_plotly(cls, cmap, res: int): - """ - Convert matplotlib color scale to plotly color scale. - - :param cmap: matplotlib color scale function - :param res: resolution to use - :return: list of string use by plotly - """ - h = 1.0 / (res - 1) - pl_colorscale = [] - for k in range(res): - C = (np.array(cmap(k * h)[:3]) * 255).astype(np.uint8) - pl_colorscale.append([k * h, 'rgb' + str((C[0], C[1], C[2]))]) - return pl_colorscale - - def node(self, node: str): - return NodeElement(plotting=HTMLElementPlotting(unit=self.unit, time_index=self.time_index), agg=self.agg, node=node) + fig = go.Figure() + # Add node circle + keys = nodes.keys() + node_qt = [nodes[k] for k in keys] + node_coords = np.array([self.coord[n] for n in keys]) + center = np.mean(node_coords, axis=0) + + # To scale objects and select zoom with use a size parameter which are the max + # distance between center to node. + size = np.max(np.sum(np.power(node_coords - center, 2), axis=1)) + + # Plot arrows + for (src, dest), qt in lines.items(): + color = 'rgb' + str(self.cmap(abs(qt) / 2 / limit + 0.5)[:-1]) + self._plot_links(fig, src, dest, color, qt, size) + + # Plot nodes + fig.add_trace(go.Scattermapbox( + mode="markers", + lon=node_coords[:, 0], + lat=node_coords[:, 1], + hoverinfo='text', text=node_qt, + marker=dict(size=20, colorscale=self.cmap_plotly, cmin=-limit, color=node_qt, + cmax=limit, colorbar_title="Net Position %s" % self.unit))) + + fig.update_layout(showlegend=False, + title_text=title, + mapbox=dict( + style="open-street-map", + center={'lon': center[0], 'lat': center[1]}, + zoom=1 / size / 0.07)) + return fig - def _plot_links(self, fig: go.Figure, start: str, end: str, color: str, qt: float): + def _plot_links(self, fig: go.Figure, start: str, end: str, color: str, qt: float, size: float): """ Plot line with arrow to a figure. @@ -192,107 +187,45 @@ def _plot_links(self, fig: go.Figure, start: str, end: str, color: str, qt: floa E = np.array([self.coord[end][0], self.coord[end][1]]) # plot line - fig.add_trace(go.Scattergeo(lat=[S[1], E[1]], hoverinfo='skip', - lon=[S[0], E[0]], mode='lines', - line=dict(width=4 * self.size, color=color))) + fig.add_trace(go.Scattermapbox(lat=[S[1], E[1]], hoverinfo='skip', + lon=[S[0], E[0]], mode='lines', + line=dict(width=2 * size, color=color))) # vector flow direction v = E - S n = np.linalg.norm(v) # Get orthogonal vector w = np.array([v[1], -v[0]]) # Compute triangle points - A = E - v * 0.5 - B = A - v / n * self.size * 0.5 - w / n * self.size * 0.25 - C = A - v / n * self.size * 0.5 + w / n * self.size * 0.25 + A = E - v * 0.1 + B = A - v / n * size / 4 - w / n * size / 8 + C = A - v / n * size / 4 + w / n * size / 8 # plot arrow - fig.add_trace(go.Scattergeo(lat=[B[1], A[1], C[1]], hoverinfo='text', - lon=[B[0], A[0], C[0]], text=str(qt), mode='lines', - line=dict(width=4 * self.size, color=color))) + fig.add_trace(go.Scattermapbox(lat=[B[1], A[1], C[1]], hoverinfo='text', + lon=[B[0], A[0], C[0]], text=str(qt), mode='lines', + line=dict(width=2 * size, color=color))) - def exchanges_map(self, t: int, scn: int = 0, limit: int = None): - """ - Plot a map with node (color are balance) and arrow between nodes (color for quantity). - - :param t: timestep to plot - :param scn: scenario index to plot - :param limit: limite to use as min/max for color scale. If not provided we use min/max from dataset. - :return: plotly figure or jupyter widget to plot - """ - if self.coord is None: - raise ValueError('Please provide node coordinate by setting param node_coord in Plotting constructor') - balances = [self.agg.get_balance(node=node)[scn, t] for node in self.agg.nodes] - if limit is None: - limit = max(max(balances), -min(balances)) - - fig = go.Figure() - - # plot links - links = self.agg.agg_link(self.agg.iscn[scn], self.agg.isrc, self.agg.idest, self.agg.itime) - for src in links.index.get_level_values('src').unique(): - for dest in links.loc[src].index.get_level_values('dest').unique(): - exchange = links.loc[src, dest, t]['used'] # forward - exchange -= links.loc[dest, src, t]['used'] if (dest, src, t) in links.index else 0 # backward - - color = 'rgb' + str(self.cmap(abs(exchange) / 2 / limit + 0.5)[:-1]) - if exchange > 0: - self._plot_links(fig=fig, start=src, end=dest, color=color, qt=exchange) - else: - self._plot_links(fig=fig, start=dest, end=src, color=color, qt=-exchange) - - # plot nodes - text = ['%s: %i' % (n, b) for n, b in zip(self.agg.nodes, balances)] - lon = [self.coord[node][0] for node in self.agg.nodes] - lat = [self.coord[node][1] for node in self.agg.nodes] - - fig.add_trace(go.Scattergeo(lon=lon, lat=lat, hoverinfo='text', text=text, mode='markers', - marker=dict(size=15 * self.size, - colorscale=self.cmap_plotly, cmin=-limit, color=balances, - cmax=limit, colorbar_title="Net Position %s" % self.unit))) - # Config plot - fig.update_layout(title_text='Exchanges Map', showlegend=False, height=600, - geo=dict(projection_type='equirectangular', showland=True, showcountries=True, - resolution=50, landcolor='rgb(200, 200, 200)', countrycolor='rgb(0, 0, 0)', - fitbounds='locations')) - - return fig - - def consumption(self, node: str, name: str, kind: str = 'given') -> ConsumptionElement: - """ - Plot all timelines consumption scenario. +class HTMLPlotting(Plotting): + """ + Plotting implementation interactive html graphics. (Use plotly) + """ - :param node: selected node name - :param name: select consumption name - :param kind: kind of data 'asked' or 'given' - :return: + def __init__(self, agg: ResultAnalyzer, unit_symbol: str = '', + time_start=None, time_end=None, + node_coord: Dict[str, List[float]] = None): """ - return ConsumptionElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg, - node=node, name=name, kind=kind) + Create instance. - def production(self, node: str, name: str, kind: str = 'used') -> ProductionElement: + :param agg: ResultAggragator instence to use + :param unit_symbol: symbol on quantity unit used. ex. MW, litter, Go, ... + :param time_start: time to use as the start of study horizon + :param time_end: time to use as the end of study horizon + :param cmap: matplotlib color map to use (coolwarm as default) + :param node_coord: nodes coordinates to use for map plotting + :param map_element_size: size on element draw on map. default as 1. """ - Plot all timelines production scenario. + Plotting.__init__(self, agg, unit_symbol, time_start, time_end, node_coord) + self.plotting = HTMLElementPlotting(self.unit, self.time_index, self.coord) - :param node: selected node name - :param name: select production name - :param kind: kind of data available ('avail') or 'used' - :return: - """ - return ProductionElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg, - node=node, name=name, kind=kind) - def link(self, src: str, dest: str, kind: str = 'used'): - """ - Plot all timelines links scenario. - - :param src: selected source node name - :param dest: select destination node name - :param kind: kind of data available ('avail') or 'used' - :return: - """ - return LinkElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg, - src=src, dest=dest, kind=kind) - - def network(self): - return NetworkElement(plotting=HTMLElementPlotting(self.unit, self.time_index), agg=self.agg) diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 3d8aa31..926dafa 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -40,12 +40,11 @@ def setUp(self) -> None: def test_stack(self): fig = self.plot.node('a').stack(scn=0) - fig.show() self.assert_fig_hash('d9f9f004b98ca62be934d69d4fd0c1a302512242', fig) def test_map_exchanges(self): - fig = self.plot.exchanges_map(t=0, scn=0) - self.assert_fig_hash('9aa34f28665ea9e6766b271ffbc677d3cda6810b', fig) + fig = self.plot.network().map(t=0, scn=0) + self.assert_fig_hash('df17e8ce15f81e4e48758241d08508f872dd4f0b', fig) def test_plot_timeline(self): fig = self.plot.consumption(node='a', name='load').timeline() From 6927cfcf1b517ab7408b047729a81cb9ff63c21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Fri, 19 Jun 2020 14:32:14 +0200 Subject: [PATCH 21/34] Fix random error in stage --- hadar/workflow/pipeline.py | 13 +++++++++---- hadar/workflow/shuffler.py | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/hadar/workflow/pipeline.py b/hadar/workflow/pipeline.py index 3296af8..7586fcd 100644 --- a/hadar/workflow/pipeline.py +++ b/hadar/workflow/pipeline.py @@ -4,7 +4,7 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - +import os from abc import ABC, abstractmethod from copy import deepcopy from typing import List, Tuple, Union, Dict @@ -260,6 +260,10 @@ def compute(self, timeline: pd.DataFrame) -> pd.DataFrame: """ timeline = Stage.standardize_column(timeline) + # If compute run inside multiprocessing like in Shuffler. randomness are not independence. + # We need to reseed with urandom + np.random.seed(int.from_bytes(os.urandom(4), byteorder='little')) + names = Stage.get_names(timeline) if not self.plug.computable(names): raise ValueError("Stage accept %s in input, but receive %s" % (self.plug.inputs, names)) @@ -463,13 +467,14 @@ def __init__(self, loss: float, occur_freq: float, downtime_min: int, downtime_m self.occur_freq = occur_freq self.downtime_min = downtime_min self.downtime_max = downtime_max - self.seed = np.random.randint(0, 100000000) if seed is None else seed - np.random.seed(self.seed) + self.seed = seed def _process_scenarios(self, n_scn: int, scenario: pd.DataFrame) -> pd.DataFrame: + if self.seed: + np.random.seed(self.seed) + horizon = scenario.shape[0] nb_faults = np.random.choice([0, 1], size=horizon, p=[1 - self.occur_freq, self.occur_freq]).sum() - loss_qt = np.zeros(horizon) faults_begin = np.random.randint(low=0, high=horizon, size=nb_faults) faults_duration = np.random.randint(low=self.downtime_min, high=self.downtime_max, size=nb_faults) diff --git a/hadar/workflow/shuffler.py b/hadar/workflow/shuffler.py index 9f61fcb..20c1d3f 100644 --- a/hadar/workflow/shuffler.py +++ b/hadar/workflow/shuffler.py @@ -11,7 +11,7 @@ import pandas as pd from numpy.random.mtrand import randint -from hadar.workflow.pipeline import Pipeline, TO_SHUFFLER +from hadar.workflow.pipeline import Pipeline, TO_SHUFFLER, Stage __all__ = ['Shuffler', 'Timeline'] @@ -127,6 +127,7 @@ def add_pipeline(self, name: str, data: pd.DataFrame, pipeline: Pipeline): :param pipeline: pipeline to generate data :return: self """ + data = Stage.standardize_column(data) pipeline.assert_computable(data) pipeline.assert_to_shuffler() From 242b730076893c74b62bfcdcc04535481d42ca7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Fri, 19 Jun 2020 18:17:48 +0200 Subject: [PATCH 22/34] WIP #67 #68. begin new examples. Improve matrix plot --- .../Begin Stochastic/Begin Stochastic.ipynb | 3 + examples/Begin Stochastic/eolien.csv | 168 ++++++++++++++++++ examples/Begin Stochastic/figure.png | Bin 0 -> 36425 bytes examples/Begin Stochastic/gas.csv | 168 ++++++++++++++++++ examples/Begin Stochastic/load_A.csv | 168 ++++++++++++++++++ examples/Begin Stochastic/load_B.csv | 168 ++++++++++++++++++ examples/Begin Stochastic/load_D.csv | 168 ++++++++++++++++++ examples/Begin Stochastic/monte-carlo.png | Bin 0 -> 24697 bytes examples/Begin Stochastic/nuclear.csv | 168 ++++++++++++++++++ .../Cost and Prioritization.ipynb | 4 +- examples/FR-DE Adequacy/FR-DE Adequacy.ipynb | 4 +- examples/Get Started/Get Started.ipynb | 4 +- examples/Workflow/Workflow.ipynb | 3 + hadar/viewer/abc.py | 12 +- hadar/viewer/html.py | 21 ++- tests/viewer/test_html.py | 17 +- 16 files changed, 1048 insertions(+), 28 deletions(-) create mode 100644 examples/Begin Stochastic/Begin Stochastic.ipynb create mode 100644 examples/Begin Stochastic/eolien.csv create mode 100644 examples/Begin Stochastic/figure.png create mode 100644 examples/Begin Stochastic/gas.csv create mode 100644 examples/Begin Stochastic/load_A.csv create mode 100644 examples/Begin Stochastic/load_B.csv create mode 100644 examples/Begin Stochastic/load_D.csv create mode 100644 examples/Begin Stochastic/monte-carlo.png create mode 100644 examples/Begin Stochastic/nuclear.csv create mode 100644 examples/Workflow/Workflow.ipynb diff --git a/examples/Begin Stochastic/Begin Stochastic.ipynb b/examples/Begin Stochastic/Begin Stochastic.ipynb new file mode 100644 index 0000000..fae9494 --- /dev/null +++ b/examples/Begin Stochastic/Begin Stochastic.ipynb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53a75f6876bf676081b22c7d21f5b883ed805d95b59ad51552c228e43a049687 +size 4293297 diff --git a/examples/Begin Stochastic/eolien.csv b/examples/Begin Stochastic/eolien.csv new file mode 100644 index 0000000..7cd8d9d --- /dev/null +++ b/examples/Begin Stochastic/eolien.csv @@ -0,0 +1,168 @@ +320.37 70.08 320.37 70.08 70.08 320.37 70.08 939.56 70.08 939.56 +564.96 345.90 564.96 345.90 345.90 564.96 345.90 579.29 345.90 579.29 +615.63 588.94 615.63 588.94 588.94 615.63 588.94 542.87 588.94 542.87 +77.44 339.74 77.44 339.74 339.74 77.44 339.74 762.46 339.74 762.46 +227.71 697.99 227.71 697.99 697.99 227.71 697.99 113.53 697.99 113.53 +792.63 257.60 792.63 257.60 257.60 792.63 257.60 977.96 257.60 977.96 +396.37 120.42 396.37 120.42 120.42 396.37 120.42 757.07 120.42 757.07 +609.55 886.41 609.55 886.41 886.41 609.55 886.41 106.71 886.41 106.71 +249.52 89.65 249.52 89.65 89.65 249.52 89.65 710.85 89.65 710.85 +340.89 332.23 340.89 332.23 332.23 340.89 332.23 671.71 332.23 671.71 +197.53 4.25 197.53 4.25 4.25 197.53 4.25 96.72 4.25 96.72 +754.51 202.94 754.51 202.94 202.94 754.51 202.94 855.20 202.94 855.20 +210.03 452.35 210.03 452.35 452.35 210.03 452.35 831.69 452.35 831.69 +237.32 861.60 237.32 861.60 861.60 237.32 861.60 414.60 861.60 414.60 +13.50 781.64 13.50 781.64 781.64 13.50 781.64 792.38 781.64 792.38 +56.57 712.65 56.57 712.65 712.65 56.57 712.65 304.08 712.65 304.08 +977.81 714.70 977.81 714.70 714.70 977.81 714.70 79.12 714.70 79.12 +594.69 888.04 594.69 888.04 888.04 594.69 888.04 827.34 888.04 827.34 +172.98 617.84 172.98 617.84 617.84 172.98 617.84 361.85 617.84 361.85 +853.76 944.54 853.76 944.54 944.54 853.76 944.54 303.33 944.54 303.33 +401.03 856.55 401.03 856.55 856.55 401.03 856.55 922.79 856.55 922.79 +911.40 607.21 911.40 607.21 607.21 911.40 607.21 172.53 607.21 172.53 +363.83 984.07 363.83 984.07 984.07 363.83 984.07 534.33 984.07 534.33 +615.71 777.71 615.71 777.71 777.71 615.71 777.71 647.50 777.71 647.50 +776.07 220.64 776.07 220.64 220.64 776.07 220.64 883.75 220.64 883.75 +586.71 98.27 586.71 98.27 98.27 586.71 98.27 68.39 98.27 68.39 +378.21 916.98 378.21 916.98 916.98 378.21 916.98 913.05 916.98 913.05 +163.96 336.72 163.96 336.72 336.72 163.96 336.72 525.89 336.72 525.89 +758.78 225.85 758.78 225.85 225.85 758.78 225.85 636.00 225.85 636.00 +427.60 211.38 427.60 211.38 211.38 427.60 211.38 700.48 211.38 700.48 +593.64 257.53 593.64 257.53 257.53 593.64 257.53 556.72 257.53 556.72 +904.04 678.75 904.04 678.75 678.75 904.04 678.75 791.72 678.75 791.72 +667.02 858.48 667.02 858.48 858.48 667.02 858.48 407.58 858.48 407.58 +967.98 412.06 967.98 412.06 412.06 967.98 412.06 818.56 412.06 818.56 +967.34 724.26 967.34 724.26 724.26 967.34 724.26 481.39 724.26 481.39 +183.91 411.25 183.91 411.25 411.25 183.91 411.25 30.18 411.25 30.18 +390.57 129.15 390.57 129.15 129.15 390.57 129.15 549.79 129.15 549.79 +243.72 931.69 243.72 931.69 931.69 243.72 931.69 295.29 931.69 295.29 +493.19 139.88 493.19 139.88 139.88 493.19 139.88 533.46 139.88 533.46 +761.54 282.42 761.54 282.42 282.42 761.54 282.42 223.19 282.42 223.19 +472.71 312.36 472.71 312.36 312.36 472.71 312.36 447.56 312.36 447.56 +637.08 314.91 637.08 314.91 314.91 637.08 314.91 980.01 314.91 980.01 +648.57 794.59 648.57 794.59 794.59 648.57 794.59 631.49 794.59 631.49 +800.76 968.32 800.76 968.32 968.32 800.76 968.32 802.19 968.32 802.19 +36.86 370.66 36.86 370.66 370.66 36.86 370.66 786.68 370.66 786.68 +451.95 959.66 451.95 959.66 959.66 451.95 959.66 183.72 959.66 183.72 +872.30 268.66 872.30 268.66 268.66 872.30 268.66 515.42 268.66 515.42 +7.61 168.47 7.61 168.47 168.47 7.61 168.47 432.56 168.47 432.56 +878.67 28.04 878.67 28.04 28.04 878.67 28.04 326.80 28.04 326.80 +114.50 41.29 114.50 41.29 41.29 114.50 41.29 714.15 41.29 714.15 +994.62 408.08 994.62 408.08 408.08 994.62 408.08 958.01 408.08 958.01 +811.01 570.22 811.01 570.22 570.22 811.01 570.22 310.85 570.22 310.85 +481.82 672.23 481.82 672.23 672.23 481.82 672.23 490.19 672.23 490.19 +346.71 781.37 346.71 781.37 781.37 346.71 781.37 232.64 781.37 232.64 +478.58 716.88 478.58 716.88 716.88 478.58 716.88 588.54 716.88 588.54 +105.51 15.17 105.51 15.17 15.17 105.51 15.17 108.24 15.17 108.24 +263.32 88.23 263.32 88.23 88.23 263.32 88.23 7.08 88.23 7.08 +192.80 365.13 192.80 365.13 365.13 192.80 365.13 118.01 365.13 118.01 +822.35 480.52 822.35 480.52 480.52 822.35 480.52 669.51 480.52 669.51 +551.01 822.22 551.01 822.22 822.22 551.01 822.22 780.09 822.22 780.09 +447.24 369.76 447.24 369.76 369.76 447.24 369.76 559.30 369.76 559.30 +945.37 803.61 945.37 803.61 803.61 945.37 803.61 835.16 803.61 835.16 +266.81 298.94 266.81 298.94 298.94 266.81 298.94 523.49 298.94 523.49 +554.80 69.36 554.80 69.36 69.36 554.80 69.36 791.70 69.36 791.70 +708.97 541.66 708.97 541.66 541.66 708.97 541.66 338.13 541.66 338.13 +599.51 19.30 599.51 19.30 19.30 599.51 19.30 921.42 19.30 921.42 +11.47 711.35 11.47 711.35 711.35 11.47 711.35 545.32 711.35 545.32 +856.14 829.64 856.14 829.64 829.64 856.14 829.64 228.50 829.64 228.50 +265.59 532.05 265.59 532.05 532.05 265.59 532.05 665.58 532.05 665.58 +358.57 434.75 358.57 434.75 434.75 358.57 434.75 457.48 434.75 457.48 +687.17 86.48 687.17 86.48 86.48 687.17 86.48 223.46 86.48 223.46 +912.99 162.37 912.99 162.37 162.37 912.99 162.37 112.33 162.37 112.33 +519.17 507.15 519.17 507.15 507.15 519.17 507.15 774.53 507.15 774.53 +505.74 773.89 505.74 773.89 773.89 505.74 773.89 95.68 773.89 95.68 +319.51 49.65 319.51 49.65 49.65 319.51 49.65 222.59 49.65 222.59 +781.43 223.79 781.43 223.79 223.79 781.43 223.79 519.31 223.79 519.31 +248.38 239.74 248.38 239.74 239.74 248.38 239.74 379.97 239.74 379.97 +150.27 911.66 150.27 911.66 911.66 150.27 911.66 731.61 911.66 731.61 +953.04 340.62 953.04 340.62 340.62 953.04 340.62 986.95 340.62 986.95 +614.99 824.88 614.99 824.88 824.88 614.99 824.88 398.81 824.88 398.81 +185.90 35.72 185.90 35.72 35.72 185.90 35.72 7.14 35.72 7.14 +995.18 578.46 995.18 578.46 578.46 995.18 578.46 884.42 578.46 884.42 +760.20 222.18 760.20 222.18 222.18 760.20 222.18 797.79 222.18 797.79 +595.12 281.86 595.12 281.86 281.86 595.12 281.86 13.22 281.86 13.22 +17.18 367.48 17.18 367.48 367.48 17.18 367.48 69.74 367.48 69.74 +316.06 188.05 316.06 188.05 188.05 316.06 188.05 974.54 188.05 974.54 +663.46 825.80 663.46 825.80 825.80 663.46 825.80 939.78 825.80 939.78 +682.82 87.20 682.82 87.20 87.20 682.82 87.20 266.59 87.20 266.59 +97.28 783.04 97.28 783.04 783.04 97.28 783.04 789.51 783.04 789.51 +774.36 33.35 774.36 33.35 33.35 774.36 33.35 807.97 33.35 807.97 +483.75 157.33 483.75 157.33 157.33 483.75 157.33 189.56 157.33 189.56 +604.71 296.86 604.71 296.86 296.86 604.71 296.86 490.27 296.86 490.27 +450.17 799.66 450.17 799.66 799.66 450.17 799.66 222.58 799.66 222.58 +949.78 546.54 949.78 546.54 546.54 949.78 546.54 636.16 546.54 636.16 +151.64 662.48 151.64 662.48 662.48 151.64 662.48 954.95 662.48 954.95 +69.35 256.69 69.35 256.69 256.69 69.35 256.69 332.90 256.69 332.90 +267.91 664.52 267.91 664.52 664.52 267.91 664.52 23.02 664.52 23.02 +255.01 338.42 255.01 338.42 338.42 255.01 338.42 642.05 338.42 642.05 +908.73 617.05 908.73 617.05 617.05 908.73 617.05 678.18 617.05 678.18 +932.98 330.89 932.98 330.89 330.89 932.98 330.89 118.55 330.89 118.55 +668.14 258.01 668.14 258.01 258.01 668.14 258.01 385.61 258.01 385.61 +398.63 41.98 398.63 41.98 41.98 398.63 41.98 291.36 41.98 291.36 +571.68 9.92 571.68 9.92 9.92 571.68 9.92 928.42 9.92 928.42 +662.46 588.03 662.46 588.03 588.03 662.46 588.03 85.84 588.03 85.84 +829.78 535.01 829.78 535.01 535.01 829.78 535.01 18.09 535.01 18.09 +199.95 49.78 199.95 49.78 49.78 199.95 49.78 490.81 49.78 490.81 +358.10 711.81 358.10 711.81 711.81 358.10 711.81 191.87 711.81 191.87 +112.68 319.00 112.68 319.00 319.00 112.68 319.00 745.70 319.00 745.70 +552.25 465.99 552.25 465.99 465.99 552.25 465.99 742.19 465.99 742.19 +740.26 501.90 740.26 501.90 501.90 740.26 501.90 879.92 501.90 879.92 +387.67 755.44 387.67 755.44 755.44 387.67 755.44 401.74 755.44 401.74 +764.80 542.52 764.80 542.52 542.52 764.80 542.52 278.65 542.52 278.65 +385.00 171.21 385.00 171.21 171.21 385.00 171.21 51.21 171.21 51.21 +896.96 704.14 896.96 704.14 704.14 896.96 704.14 992.27 704.14 992.27 +555.67 949.26 555.67 949.26 949.26 555.67 949.26 247.62 949.26 247.62 +727.39 890.58 727.39 890.58 890.58 727.39 890.58 733.31 890.58 733.31 +182.35 233.70 182.35 233.70 233.70 182.35 233.70 287.30 233.70 287.30 +423.68 74.42 423.68 74.42 74.42 423.68 74.42 51.57 74.42 51.57 +600.06 459.95 600.06 459.95 459.95 600.06 459.95 225.58 459.95 225.58 +823.18 349.87 823.18 349.87 349.87 823.18 349.87 970.85 349.87 970.85 +327.08 123.99 327.08 123.99 123.99 327.08 123.99 581.88 123.99 581.88 +715.94 461.64 715.94 461.64 461.64 715.94 461.64 927.61 461.64 927.61 +560.13 519.29 560.13 519.29 519.29 560.13 519.29 16.09 519.29 16.09 +448.66 212.88 448.66 212.88 212.88 448.66 212.88 690.35 212.88 690.35 +68.94 376.88 68.94 376.88 376.88 68.94 376.88 305.30 376.88 305.30 +350.40 965.89 350.40 965.89 965.89 350.40 965.89 537.67 965.89 537.67 +552.87 955.06 552.87 955.06 955.06 552.87 955.06 546.62 955.06 546.62 +114.01 560.83 114.01 560.83 560.83 114.01 560.83 927.50 560.83 927.50 +22.37 115.04 22.37 115.04 115.04 22.37 115.04 386.14 115.04 386.14 +530.42 856.67 530.42 856.67 856.67 530.42 856.67 386.34 856.67 386.34 +674.57 957.88 674.57 957.88 957.88 674.57 957.88 282.60 957.88 282.60 +866.75 770.57 866.75 770.57 770.57 866.75 770.57 139.02 770.57 139.02 +491.34 304.01 491.34 304.01 304.01 491.34 304.01 854.79 304.01 854.79 +861.36 799.67 861.36 799.67 799.67 861.36 799.67 849.68 799.67 849.68 +372.43 326.50 372.43 326.50 326.50 372.43 326.50 259.71 326.50 259.71 +800.77 827.92 800.77 827.92 827.92 800.77 827.92 408.95 827.92 408.95 +830.02 437.19 830.02 437.19 437.19 830.02 437.19 184.81 437.19 184.81 +308.33 724.50 308.33 724.50 724.50 308.33 724.50 936.79 724.50 936.79 +842.61 876.57 842.61 876.57 876.57 842.61 876.57 111.19 876.57 111.19 +587.31 376.35 587.31 376.35 376.35 587.31 376.35 556.39 376.35 556.39 +401.02 81.79 401.02 81.79 81.79 401.02 81.79 88.40 81.79 88.40 +653.30 873.45 653.30 873.45 873.45 653.30 873.45 506.43 873.45 506.43 +811.28 5.28 811.28 5.28 5.28 811.28 5.28 874.67 5.28 874.67 +186.20 373.20 186.20 373.20 373.20 186.20 373.20 283.72 373.20 283.72 +345.66 219.17 345.66 219.17 219.17 345.66 219.17 330.01 219.17 330.01 +975.48 539.78 975.48 539.78 539.78 975.48 539.78 786.70 539.78 786.70 +143.15 994.85 143.15 994.85 994.85 143.15 994.85 78.22 994.85 78.22 +590.74 526.15 590.74 526.15 526.15 590.74 526.15 235.96 526.15 235.96 +435.40 266.13 435.40 266.13 266.13 435.40 266.13 858.19 266.13 858.19 +971.37 85.62 971.37 85.62 85.62 971.37 85.62 849.00 85.62 849.00 +363.75 916.82 363.75 916.82 916.82 363.75 916.82 93.61 916.82 93.61 +479.86 235.68 479.86 235.68 235.68 479.86 235.68 220.23 235.68 220.23 +141.19 397.57 141.19 397.57 397.57 141.19 397.57 168.11 397.57 168.11 +202.96 798.25 202.96 798.25 798.25 202.96 798.25 990.12 798.25 990.12 +314.97 909.12 314.97 909.12 909.12 314.97 909.12 545.36 909.12 545.36 +240.94 225.69 240.94 225.69 225.69 240.94 225.69 857.13 225.69 857.13 +454.51 534.98 454.51 534.98 534.98 454.51 534.98 393.37 534.98 393.37 +921.08 672.24 921.08 672.24 672.24 921.08 672.24 609.20 672.24 609.20 +433.15 413.92 433.15 413.92 413.92 433.15 413.92 281.62 413.92 281.62 +460.59 466.82 460.59 466.82 466.82 460.59 466.82 835.38 466.82 835.38 +798.54 401.50 798.54 401.50 401.50 798.54 401.50 785.10 401.50 785.10 +560.44 808.80 560.44 808.80 808.80 560.44 808.80 920.08 808.80 920.08 +190.47 221.99 190.47 221.99 221.99 190.47 221.99 493.18 221.99 493.18 +28.20 438.81 28.20 438.81 438.81 28.20 438.81 240.98 438.81 240.98 +360.09 452.32 360.09 452.32 452.32 360.09 452.32 165.06 452.32 165.06 +927.92 747.19 927.92 747.19 747.19 927.92 747.19 832.71 747.19 832.71 +380.85 376.52 380.85 376.52 376.52 380.85 376.52 758.82 376.52 758.82 +756.57 769.08 756.57 769.08 769.08 756.57 769.08 854.99 769.08 854.99 diff --git a/examples/Begin Stochastic/figure.png b/examples/Begin Stochastic/figure.png new file mode 100644 index 0000000000000000000000000000000000000000..999ac057535c83bb0af5d92a7029d6948ab6e624 GIT binary patch literal 36425 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 is>V|QKk0UWJa+v;PA 0] /= np.max(x[x > 0]) + x[x < 0] /= -np.min(x[x < 0]) + return x + fig = go.Figure(data=go.Heatmap( - z=data, + z=sdt(data.copy()), x=self.time_index, y=np.arange(data.shape[0]), - colorscale='RdBu', zmid=0)) + hoverinfo='text', + text=data, + colorscale='RdBu', zmid=0, + showscale=False)) fig.update_layout(title_text=title, yaxis_title="scenarios", xaxis_title="time", showlegend=False) return fig - def map_exchange(self, nodes, lines, limit, title): + def map_exchange(self, nodes, lines, limit, title, size): if self.coord is None: raise ValueError('Please provide node coordinate by setting param node_coord in Plotting constructor') @@ -146,10 +155,6 @@ def map_exchange(self, nodes, lines, limit, title): node_coords = np.array([self.coord[n] for n in keys]) center = np.mean(node_coords, axis=0) - # To scale objects and select zoom with use a size parameter which are the max - # distance between center to node. - size = np.max(np.sum(np.power(node_coords - center, 2), axis=1)) - # Plot arrows for (src, dest), qt in lines.items(): color = 'rgb' + str(self.cmap(abs(qt) / 2 / limit + 0.5)[:-1]) diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 926dafa..0664010 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -4,7 +4,7 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - +import base64 import hashlib import unittest @@ -58,17 +58,17 @@ def test_plot_timeline(self): def test_plot_monotone(self): fig = self.plot.consumption(node='a', name='load').monotone(scn=0) - self.assert_fig_hash('753619bf85b387f3b0f304688bb578efe39db3e9', fig) + self.assert_fig_hash('1ffa51a52b066aab8cabb817c11fd1272549eb9d', fig) fig = self.plot.production(node='b', name='nuclear').monotone(t=0) - self.assert_fig_hash('0a99228bf1a0743b604e9082b0ba7db86f3993f3', fig) + self.assert_fig_hash('e059878aac45330810578482df8c3d19261f7f75', fig) fig = self.plot.link(src='a', dest='b').monotone(scn=0) - self.assert_fig_hash('2e2410dad5800c9658846c40421dbe83c9e5f3f9', fig) + self.assert_fig_hash('1d5dba9e2189c741e5daa36d69ff1a879f169964', fig) def test_rac_heatmap(self): fig = self.plot.network().rac_matrix() - self.assert_fig_hash('1fa715af27e4ab85b033cff41f5edff72f4bca88', fig) + self.assert_fig_hash('2b87a4e781e9eeb532f5d2b091c474bb0de625fd', fig) def test_gaussian(self): fig = self.plot.consumption(node='a', name='load').gaussian(scn=0) @@ -81,9 +81,10 @@ def test_gaussian(self): self.assert_fig_hash('3420c78029bafebbadedeb39d906269810acfd88', fig) def assert_fig_hash(self, expected: str, fig: go.Figure): - h = hashlib.sha1() - h.update(TestHTMLPlotting.get_html(fig)) - self.assertEqual(expected, h.hexdigest()) + actual = hashlib.sha1(TestHTMLPlotting.get_html(fig)).hexdigest() + if expected != actual: + fig.show() + self.assertEqual(expected, actual) @staticmethod def get_html(fig: go.Figure) -> bytes: From af780cd5384da47ac076faf0af934e59d8795909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Mon, 22 Jun 2020 12:13:42 +0200 Subject: [PATCH 23/34] WIP #67 #68. Fix alpha error in timeline --- hadar/viewer/html.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index 5b38696..53aa9a2 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -50,8 +50,8 @@ def matplotlib_to_plotly(cls, cmap, res: int): def timeline(self, df: pd.DataFrame, title: str): scenarios = df.index.get_level_values('scn').unique() - alpha = max(10, 255 / scenarios.size) - color = 'rgba(100, 100, 100, %d)' % alpha + alpha = max(0.01, 1 / scenarios.size) + color = 'rgba(0, 0, 0, %.2f)' % alpha fig = go.Figure() for scn in scenarios: @@ -145,6 +145,8 @@ def sdt(x): return fig def map_exchange(self, nodes, lines, limit, title, size): + # TODO Fix arrow auto sizing. Change carte color or arrow color for visibility + # TODO Use fill='self' to fill triangle if self.coord is None: raise ValueError('Please provide node coordinate by setting param node_coord in Plotting constructor') From 92c6b318062d5d60c4ba8caf1ce399876241caba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Mon, 22 Jun 2020 15:03:59 +0200 Subject: [PATCH 24/34] WIP #67 close #68. finish workflow and stochastic examples --- .../Begin Stochastic/Begin Stochastic.ipynb | 4 +- examples/Begin Stochastic/eolien.csv | 336 +++++++++--------- examples/Begin Stochastic/gas.csv | 78 ++-- examples/Begin Stochastic/load_A.csv | 336 +++++++++--------- examples/Begin Stochastic/load_B.csv | 336 +++++++++--------- examples/Begin Stochastic/load_D.csv | 336 +++++++++--------- examples/Begin Stochastic/nuclear.csv | 72 ++-- examples/Workflow/Workflow.ipynb | 4 +- examples/Workflow/shuffler.png | Bin 0 -> 22640 bytes hadar/viewer/html.py | 12 +- tests/viewer/test_html.py | 17 +- 11 files changed, 765 insertions(+), 766 deletions(-) create mode 100644 examples/Workflow/shuffler.png diff --git a/examples/Begin Stochastic/Begin Stochastic.ipynb b/examples/Begin Stochastic/Begin Stochastic.ipynb index fae9494..810f723 100644 --- a/examples/Begin Stochastic/Begin Stochastic.ipynb +++ b/examples/Begin Stochastic/Begin Stochastic.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53a75f6876bf676081b22c7d21f5b883ed805d95b59ad51552c228e43a049687 -size 4293297 +oid sha256:63dac9e2a0f7595429880c88b4c100e5b2895a7d7a2894f99e7fdc52037da054 +size 785660 diff --git a/examples/Begin Stochastic/eolien.csv b/examples/Begin Stochastic/eolien.csv index 7cd8d9d..2bf8061 100644 --- a/examples/Begin Stochastic/eolien.csv +++ b/examples/Begin Stochastic/eolien.csv @@ -1,168 +1,168 @@ -320.37 70.08 320.37 70.08 70.08 320.37 70.08 939.56 70.08 939.56 -564.96 345.90 564.96 345.90 345.90 564.96 345.90 579.29 345.90 579.29 -615.63 588.94 615.63 588.94 588.94 615.63 588.94 542.87 588.94 542.87 -77.44 339.74 77.44 339.74 339.74 77.44 339.74 762.46 339.74 762.46 -227.71 697.99 227.71 697.99 697.99 227.71 697.99 113.53 697.99 113.53 -792.63 257.60 792.63 257.60 257.60 792.63 257.60 977.96 257.60 977.96 -396.37 120.42 396.37 120.42 120.42 396.37 120.42 757.07 120.42 757.07 -609.55 886.41 609.55 886.41 886.41 609.55 886.41 106.71 886.41 106.71 -249.52 89.65 249.52 89.65 89.65 249.52 89.65 710.85 89.65 710.85 -340.89 332.23 340.89 332.23 332.23 340.89 332.23 671.71 332.23 671.71 -197.53 4.25 197.53 4.25 4.25 197.53 4.25 96.72 4.25 96.72 -754.51 202.94 754.51 202.94 202.94 754.51 202.94 855.20 202.94 855.20 -210.03 452.35 210.03 452.35 452.35 210.03 452.35 831.69 452.35 831.69 -237.32 861.60 237.32 861.60 861.60 237.32 861.60 414.60 861.60 414.60 -13.50 781.64 13.50 781.64 781.64 13.50 781.64 792.38 781.64 792.38 -56.57 712.65 56.57 712.65 712.65 56.57 712.65 304.08 712.65 304.08 -977.81 714.70 977.81 714.70 714.70 977.81 714.70 79.12 714.70 79.12 -594.69 888.04 594.69 888.04 888.04 594.69 888.04 827.34 888.04 827.34 -172.98 617.84 172.98 617.84 617.84 172.98 617.84 361.85 617.84 361.85 -853.76 944.54 853.76 944.54 944.54 853.76 944.54 303.33 944.54 303.33 -401.03 856.55 401.03 856.55 856.55 401.03 856.55 922.79 856.55 922.79 -911.40 607.21 911.40 607.21 607.21 911.40 607.21 172.53 607.21 172.53 -363.83 984.07 363.83 984.07 984.07 363.83 984.07 534.33 984.07 534.33 -615.71 777.71 615.71 777.71 777.71 615.71 777.71 647.50 777.71 647.50 -776.07 220.64 776.07 220.64 220.64 776.07 220.64 883.75 220.64 883.75 -586.71 98.27 586.71 98.27 98.27 586.71 98.27 68.39 98.27 68.39 -378.21 916.98 378.21 916.98 916.98 378.21 916.98 913.05 916.98 913.05 -163.96 336.72 163.96 336.72 336.72 163.96 336.72 525.89 336.72 525.89 -758.78 225.85 758.78 225.85 225.85 758.78 225.85 636.00 225.85 636.00 -427.60 211.38 427.60 211.38 211.38 427.60 211.38 700.48 211.38 700.48 -593.64 257.53 593.64 257.53 257.53 593.64 257.53 556.72 257.53 556.72 -904.04 678.75 904.04 678.75 678.75 904.04 678.75 791.72 678.75 791.72 -667.02 858.48 667.02 858.48 858.48 667.02 858.48 407.58 858.48 407.58 -967.98 412.06 967.98 412.06 412.06 967.98 412.06 818.56 412.06 818.56 -967.34 724.26 967.34 724.26 724.26 967.34 724.26 481.39 724.26 481.39 -183.91 411.25 183.91 411.25 411.25 183.91 411.25 30.18 411.25 30.18 -390.57 129.15 390.57 129.15 129.15 390.57 129.15 549.79 129.15 549.79 -243.72 931.69 243.72 931.69 931.69 243.72 931.69 295.29 931.69 295.29 -493.19 139.88 493.19 139.88 139.88 493.19 139.88 533.46 139.88 533.46 -761.54 282.42 761.54 282.42 282.42 761.54 282.42 223.19 282.42 223.19 -472.71 312.36 472.71 312.36 312.36 472.71 312.36 447.56 312.36 447.56 -637.08 314.91 637.08 314.91 314.91 637.08 314.91 980.01 314.91 980.01 -648.57 794.59 648.57 794.59 794.59 648.57 794.59 631.49 794.59 631.49 -800.76 968.32 800.76 968.32 968.32 800.76 968.32 802.19 968.32 802.19 -36.86 370.66 36.86 370.66 370.66 36.86 370.66 786.68 370.66 786.68 -451.95 959.66 451.95 959.66 959.66 451.95 959.66 183.72 959.66 183.72 -872.30 268.66 872.30 268.66 268.66 872.30 268.66 515.42 268.66 515.42 -7.61 168.47 7.61 168.47 168.47 7.61 168.47 432.56 168.47 432.56 -878.67 28.04 878.67 28.04 28.04 878.67 28.04 326.80 28.04 326.80 -114.50 41.29 114.50 41.29 41.29 114.50 41.29 714.15 41.29 714.15 -994.62 408.08 994.62 408.08 408.08 994.62 408.08 958.01 408.08 958.01 -811.01 570.22 811.01 570.22 570.22 811.01 570.22 310.85 570.22 310.85 -481.82 672.23 481.82 672.23 672.23 481.82 672.23 490.19 672.23 490.19 -346.71 781.37 346.71 781.37 781.37 346.71 781.37 232.64 781.37 232.64 -478.58 716.88 478.58 716.88 716.88 478.58 716.88 588.54 716.88 588.54 -105.51 15.17 105.51 15.17 15.17 105.51 15.17 108.24 15.17 108.24 -263.32 88.23 263.32 88.23 88.23 263.32 88.23 7.08 88.23 7.08 -192.80 365.13 192.80 365.13 365.13 192.80 365.13 118.01 365.13 118.01 -822.35 480.52 822.35 480.52 480.52 822.35 480.52 669.51 480.52 669.51 -551.01 822.22 551.01 822.22 822.22 551.01 822.22 780.09 822.22 780.09 -447.24 369.76 447.24 369.76 369.76 447.24 369.76 559.30 369.76 559.30 -945.37 803.61 945.37 803.61 803.61 945.37 803.61 835.16 803.61 835.16 -266.81 298.94 266.81 298.94 298.94 266.81 298.94 523.49 298.94 523.49 -554.80 69.36 554.80 69.36 69.36 554.80 69.36 791.70 69.36 791.70 -708.97 541.66 708.97 541.66 541.66 708.97 541.66 338.13 541.66 338.13 -599.51 19.30 599.51 19.30 19.30 599.51 19.30 921.42 19.30 921.42 -11.47 711.35 11.47 711.35 711.35 11.47 711.35 545.32 711.35 545.32 -856.14 829.64 856.14 829.64 829.64 856.14 829.64 228.50 829.64 228.50 -265.59 532.05 265.59 532.05 532.05 265.59 532.05 665.58 532.05 665.58 -358.57 434.75 358.57 434.75 434.75 358.57 434.75 457.48 434.75 457.48 -687.17 86.48 687.17 86.48 86.48 687.17 86.48 223.46 86.48 223.46 -912.99 162.37 912.99 162.37 162.37 912.99 162.37 112.33 162.37 112.33 -519.17 507.15 519.17 507.15 507.15 519.17 507.15 774.53 507.15 774.53 -505.74 773.89 505.74 773.89 773.89 505.74 773.89 95.68 773.89 95.68 -319.51 49.65 319.51 49.65 49.65 319.51 49.65 222.59 49.65 222.59 -781.43 223.79 781.43 223.79 223.79 781.43 223.79 519.31 223.79 519.31 -248.38 239.74 248.38 239.74 239.74 248.38 239.74 379.97 239.74 379.97 -150.27 911.66 150.27 911.66 911.66 150.27 911.66 731.61 911.66 731.61 -953.04 340.62 953.04 340.62 340.62 953.04 340.62 986.95 340.62 986.95 -614.99 824.88 614.99 824.88 824.88 614.99 824.88 398.81 824.88 398.81 -185.90 35.72 185.90 35.72 35.72 185.90 35.72 7.14 35.72 7.14 -995.18 578.46 995.18 578.46 578.46 995.18 578.46 884.42 578.46 884.42 -760.20 222.18 760.20 222.18 222.18 760.20 222.18 797.79 222.18 797.79 -595.12 281.86 595.12 281.86 281.86 595.12 281.86 13.22 281.86 13.22 -17.18 367.48 17.18 367.48 367.48 17.18 367.48 69.74 367.48 69.74 -316.06 188.05 316.06 188.05 188.05 316.06 188.05 974.54 188.05 974.54 -663.46 825.80 663.46 825.80 825.80 663.46 825.80 939.78 825.80 939.78 -682.82 87.20 682.82 87.20 87.20 682.82 87.20 266.59 87.20 266.59 -97.28 783.04 97.28 783.04 783.04 97.28 783.04 789.51 783.04 789.51 -774.36 33.35 774.36 33.35 33.35 774.36 33.35 807.97 33.35 807.97 -483.75 157.33 483.75 157.33 157.33 483.75 157.33 189.56 157.33 189.56 -604.71 296.86 604.71 296.86 296.86 604.71 296.86 490.27 296.86 490.27 -450.17 799.66 450.17 799.66 799.66 450.17 799.66 222.58 799.66 222.58 -949.78 546.54 949.78 546.54 546.54 949.78 546.54 636.16 546.54 636.16 -151.64 662.48 151.64 662.48 662.48 151.64 662.48 954.95 662.48 954.95 -69.35 256.69 69.35 256.69 256.69 69.35 256.69 332.90 256.69 332.90 -267.91 664.52 267.91 664.52 664.52 267.91 664.52 23.02 664.52 23.02 -255.01 338.42 255.01 338.42 338.42 255.01 338.42 642.05 338.42 642.05 -908.73 617.05 908.73 617.05 617.05 908.73 617.05 678.18 617.05 678.18 -932.98 330.89 932.98 330.89 330.89 932.98 330.89 118.55 330.89 118.55 -668.14 258.01 668.14 258.01 258.01 668.14 258.01 385.61 258.01 385.61 -398.63 41.98 398.63 41.98 41.98 398.63 41.98 291.36 41.98 291.36 -571.68 9.92 571.68 9.92 9.92 571.68 9.92 928.42 9.92 928.42 -662.46 588.03 662.46 588.03 588.03 662.46 588.03 85.84 588.03 85.84 -829.78 535.01 829.78 535.01 535.01 829.78 535.01 18.09 535.01 18.09 -199.95 49.78 199.95 49.78 49.78 199.95 49.78 490.81 49.78 490.81 -358.10 711.81 358.10 711.81 711.81 358.10 711.81 191.87 711.81 191.87 -112.68 319.00 112.68 319.00 319.00 112.68 319.00 745.70 319.00 745.70 -552.25 465.99 552.25 465.99 465.99 552.25 465.99 742.19 465.99 742.19 -740.26 501.90 740.26 501.90 501.90 740.26 501.90 879.92 501.90 879.92 -387.67 755.44 387.67 755.44 755.44 387.67 755.44 401.74 755.44 401.74 -764.80 542.52 764.80 542.52 542.52 764.80 542.52 278.65 542.52 278.65 -385.00 171.21 385.00 171.21 171.21 385.00 171.21 51.21 171.21 51.21 -896.96 704.14 896.96 704.14 704.14 896.96 704.14 992.27 704.14 992.27 -555.67 949.26 555.67 949.26 949.26 555.67 949.26 247.62 949.26 247.62 -727.39 890.58 727.39 890.58 890.58 727.39 890.58 733.31 890.58 733.31 -182.35 233.70 182.35 233.70 233.70 182.35 233.70 287.30 233.70 287.30 -423.68 74.42 423.68 74.42 74.42 423.68 74.42 51.57 74.42 51.57 -600.06 459.95 600.06 459.95 459.95 600.06 459.95 225.58 459.95 225.58 -823.18 349.87 823.18 349.87 349.87 823.18 349.87 970.85 349.87 970.85 -327.08 123.99 327.08 123.99 123.99 327.08 123.99 581.88 123.99 581.88 -715.94 461.64 715.94 461.64 461.64 715.94 461.64 927.61 461.64 927.61 -560.13 519.29 560.13 519.29 519.29 560.13 519.29 16.09 519.29 16.09 -448.66 212.88 448.66 212.88 212.88 448.66 212.88 690.35 212.88 690.35 -68.94 376.88 68.94 376.88 376.88 68.94 376.88 305.30 376.88 305.30 -350.40 965.89 350.40 965.89 965.89 350.40 965.89 537.67 965.89 537.67 -552.87 955.06 552.87 955.06 955.06 552.87 955.06 546.62 955.06 546.62 -114.01 560.83 114.01 560.83 560.83 114.01 560.83 927.50 560.83 927.50 -22.37 115.04 22.37 115.04 115.04 22.37 115.04 386.14 115.04 386.14 -530.42 856.67 530.42 856.67 856.67 530.42 856.67 386.34 856.67 386.34 -674.57 957.88 674.57 957.88 957.88 674.57 957.88 282.60 957.88 282.60 -866.75 770.57 866.75 770.57 770.57 866.75 770.57 139.02 770.57 139.02 -491.34 304.01 491.34 304.01 304.01 491.34 304.01 854.79 304.01 854.79 -861.36 799.67 861.36 799.67 799.67 861.36 799.67 849.68 799.67 849.68 -372.43 326.50 372.43 326.50 326.50 372.43 326.50 259.71 326.50 259.71 -800.77 827.92 800.77 827.92 827.92 800.77 827.92 408.95 827.92 408.95 -830.02 437.19 830.02 437.19 437.19 830.02 437.19 184.81 437.19 184.81 -308.33 724.50 308.33 724.50 724.50 308.33 724.50 936.79 724.50 936.79 -842.61 876.57 842.61 876.57 876.57 842.61 876.57 111.19 876.57 111.19 -587.31 376.35 587.31 376.35 376.35 587.31 376.35 556.39 376.35 556.39 -401.02 81.79 401.02 81.79 81.79 401.02 81.79 88.40 81.79 88.40 -653.30 873.45 653.30 873.45 873.45 653.30 873.45 506.43 873.45 506.43 -811.28 5.28 811.28 5.28 5.28 811.28 5.28 874.67 5.28 874.67 -186.20 373.20 186.20 373.20 373.20 186.20 373.20 283.72 373.20 283.72 -345.66 219.17 345.66 219.17 219.17 345.66 219.17 330.01 219.17 330.01 -975.48 539.78 975.48 539.78 539.78 975.48 539.78 786.70 539.78 786.70 -143.15 994.85 143.15 994.85 994.85 143.15 994.85 78.22 994.85 78.22 -590.74 526.15 590.74 526.15 526.15 590.74 526.15 235.96 526.15 235.96 -435.40 266.13 435.40 266.13 266.13 435.40 266.13 858.19 266.13 858.19 -971.37 85.62 971.37 85.62 85.62 971.37 85.62 849.00 85.62 849.00 -363.75 916.82 363.75 916.82 916.82 363.75 916.82 93.61 916.82 93.61 -479.86 235.68 479.86 235.68 235.68 479.86 235.68 220.23 235.68 220.23 -141.19 397.57 141.19 397.57 397.57 141.19 397.57 168.11 397.57 168.11 -202.96 798.25 202.96 798.25 798.25 202.96 798.25 990.12 798.25 990.12 -314.97 909.12 314.97 909.12 909.12 314.97 909.12 545.36 909.12 545.36 -240.94 225.69 240.94 225.69 225.69 240.94 225.69 857.13 225.69 857.13 -454.51 534.98 454.51 534.98 534.98 454.51 534.98 393.37 534.98 393.37 -921.08 672.24 921.08 672.24 672.24 921.08 672.24 609.20 672.24 609.20 -433.15 413.92 433.15 413.92 413.92 433.15 413.92 281.62 413.92 281.62 -460.59 466.82 460.59 466.82 466.82 460.59 466.82 835.38 466.82 835.38 -798.54 401.50 798.54 401.50 401.50 798.54 401.50 785.10 401.50 785.10 -560.44 808.80 560.44 808.80 808.80 560.44 808.80 920.08 808.80 920.08 -190.47 221.99 190.47 221.99 221.99 190.47 221.99 493.18 221.99 493.18 -28.20 438.81 28.20 438.81 438.81 28.20 438.81 240.98 438.81 240.98 -360.09 452.32 360.09 452.32 452.32 360.09 452.32 165.06 452.32 165.06 -927.92 747.19 927.92 747.19 747.19 927.92 747.19 832.71 747.19 832.71 -380.85 376.52 380.85 376.52 376.52 380.85 376.52 758.82 376.52 758.82 -756.57 769.08 756.57 769.08 769.08 756.57 769.08 854.99 769.08 854.99 +264.71 264.71 264.71 566.64 878.89 878.89 566.64 566.64 878.89 878.89 +971.26 971.26 971.26 352.33 598.43 598.43 352.33 352.33 598.43 598.43 +504.60 504.60 504.60 939.58 614.61 614.61 939.58 939.58 614.61 614.61 +737.68 737.68 737.68 697.15 492.77 492.77 697.15 697.15 492.77 492.77 +50.23 50.23 50.23 611.89 57.34 57.34 611.89 611.89 57.34 57.34 +601.41 601.41 601.41 722.90 552.38 552.38 722.90 722.90 552.38 552.38 +688.73 688.73 688.73 203.78 388.51 388.51 203.78 203.78 388.51 388.51 +379.93 379.93 379.93 369.24 78.25 78.25 369.24 369.24 78.25 78.25 +68.91 68.91 68.91 275.18 603.95 603.95 275.18 275.18 603.95 603.95 +870.19 870.19 870.19 235.93 631.62 631.62 235.93 235.93 631.62 631.62 +69.67 69.67 69.67 126.75 645.57 645.57 126.75 126.75 645.57 645.57 +896.09 896.09 896.09 572.73 620.71 620.71 572.73 572.73 620.71 620.71 +679.82 679.82 679.82 819.46 586.93 586.93 819.46 819.46 586.93 586.93 +182.57 182.57 182.57 983.99 46.59 46.59 983.99 983.99 46.59 46.59 +368.87 368.87 368.87 824.20 252.54 252.54 824.20 824.20 252.54 252.54 +786.31 786.31 786.31 74.14 996.90 996.90 74.14 74.14 996.90 996.90 +660.25 660.25 660.25 185.20 880.61 880.61 185.20 185.20 880.61 880.61 +759.76 759.76 759.76 715.18 234.91 234.91 715.18 715.18 234.91 234.91 +711.72 711.72 711.72 567.51 348.54 348.54 567.51 567.51 348.54 348.54 +125.85 125.85 125.85 399.16 820.54 820.54 399.16 399.16 820.54 820.54 +492.97 492.97 492.97 111.50 350.69 350.69 111.50 111.50 350.69 350.69 +106.60 106.60 106.60 308.35 281.62 281.62 308.35 308.35 281.62 281.62 +883.76 883.76 883.76 391.17 174.96 174.96 391.17 391.17 174.96 174.96 +493.97 493.97 493.97 159.35 964.44 964.44 159.35 159.35 964.44 964.44 +80.62 80.62 80.62 19.13 906.95 906.95 19.13 19.13 906.95 906.95 +402.81 402.81 402.81 973.02 82.18 82.18 973.02 973.02 82.18 82.18 +273.53 273.53 273.53 452.96 736.84 736.84 452.96 452.96 736.84 736.84 +711.05 711.05 711.05 931.52 607.82 607.82 931.52 931.52 607.82 607.82 +768.64 768.64 768.64 898.76 236.46 236.46 898.76 898.76 236.46 236.46 +518.88 518.88 518.88 15.66 282.06 282.06 15.66 15.66 282.06 282.06 +106.83 106.83 106.83 381.46 331.69 331.69 381.46 381.46 331.69 331.69 +316.95 316.95 316.95 701.88 600.10 600.10 701.88 701.88 600.10 600.10 +361.23 361.23 361.23 57.27 160.27 160.27 57.27 57.27 160.27 160.27 +465.02 465.02 465.02 462.95 527.01 527.01 462.95 462.95 527.01 527.01 +388.99 388.99 388.99 574.06 286.74 286.74 574.06 574.06 286.74 286.74 +752.84 752.84 752.84 170.92 854.34 854.34 170.92 170.92 854.34 854.34 +539.28 539.28 539.28 857.39 125.62 125.62 857.39 857.39 125.62 125.62 +823.67 823.67 823.67 59.28 682.14 682.14 59.28 59.28 682.14 682.14 +469.29 469.29 469.29 72.35 803.10 803.10 72.35 72.35 803.10 803.10 +694.13 694.13 694.13 524.98 646.37 646.37 524.98 524.98 646.37 646.37 +931.65 931.65 931.65 897.16 296.06 296.06 897.16 897.16 296.06 296.06 +532.88 532.88 532.88 375.26 297.38 297.38 375.26 375.26 297.38 297.38 +163.70 163.70 163.70 870.02 663.03 663.03 870.02 870.02 663.03 663.03 +827.21 827.21 827.21 701.10 464.22 464.22 701.10 701.10 464.22 464.22 +841.35 841.35 841.35 888.47 590.47 590.47 888.47 888.47 590.47 590.47 +687.23 687.23 687.23 174.11 102.13 102.13 174.11 174.11 102.13 102.13 +607.50 607.50 607.50 38.72 824.93 824.93 38.72 38.72 824.93 824.93 +992.25 992.25 992.25 60.09 986.76 986.76 60.09 60.09 986.76 986.76 +908.36 908.36 908.36 355.30 541.77 541.77 355.30 355.30 541.77 541.77 +519.25 519.25 519.25 843.53 254.46 254.46 843.53 843.53 254.46 254.46 +105.86 105.86 105.86 182.72 868.60 868.60 182.72 182.72 868.60 868.60 +368.98 368.98 368.98 877.84 506.68 506.68 877.84 877.84 506.68 506.68 +673.38 673.38 673.38 714.30 199.00 199.00 714.30 714.30 199.00 199.00 +412.97 412.97 412.97 637.80 537.33 537.33 637.80 637.80 537.33 537.33 +607.16 607.16 607.16 728.29 475.63 475.63 728.29 728.29 475.63 475.63 +219.12 219.12 219.12 586.52 896.52 896.52 586.52 586.52 896.52 896.52 +206.13 206.13 206.13 388.52 291.19 291.19 388.52 388.52 291.19 291.19 +956.88 956.88 956.88 837.87 472.84 472.84 837.87 837.87 472.84 472.84 +501.00 501.00 501.00 154.89 701.31 701.31 154.89 154.89 701.31 701.31 +621.34 621.34 621.34 768.86 46.37 46.37 768.86 768.86 46.37 46.37 +776.35 776.35 776.35 733.08 137.23 137.23 733.08 733.08 137.23 137.23 +835.96 835.96 835.96 387.43 120.99 120.99 387.43 387.43 120.99 120.99 +652.95 652.95 652.95 860.53 453.16 453.16 860.53 860.53 453.16 453.16 +876.58 876.58 876.58 737.98 892.18 892.18 737.98 737.98 892.18 892.18 +329.44 329.44 329.44 503.65 530.28 530.28 503.65 503.65 530.28 530.28 +638.42 638.42 638.42 183.84 583.72 583.72 183.84 183.84 583.72 583.72 +449.83 449.83 449.83 792.36 593.44 593.44 792.36 792.36 593.44 593.44 +72.32 72.32 72.32 381.23 66.19 66.19 381.23 381.23 66.19 66.19 +77.54 77.54 77.54 879.93 191.53 191.53 879.93 879.93 191.53 191.53 +397.13 397.13 397.13 260.53 539.48 539.48 260.53 260.53 539.48 539.48 +736.18 736.18 736.18 884.81 677.45 677.45 884.81 884.81 677.45 677.45 +899.73 899.73 899.73 741.07 818.38 818.38 741.07 741.07 818.38 818.38 +583.79 583.79 583.79 251.54 238.86 238.86 251.54 251.54 238.86 238.86 +177.14 177.14 177.14 156.66 3.31 3.31 156.66 156.66 3.31 3.31 +341.89 341.89 341.89 275.04 642.86 642.86 275.04 275.04 642.86 642.86 +84.82 84.82 84.82 443.91 376.13 376.13 443.91 443.91 376.13 376.13 +459.31 459.31 459.31 746.24 361.17 361.17 746.24 746.24 361.17 361.17 +467.72 467.72 467.72 379.34 799.38 799.38 379.34 379.34 799.38 799.38 +291.40 291.40 291.40 700.85 260.03 260.03 700.85 700.85 260.03 260.03 +593.67 593.67 593.67 135.04 459.93 459.93 135.04 135.04 459.93 459.93 +31.92 31.92 31.92 275.61 524.96 524.96 275.61 275.61 524.96 524.96 +607.94 607.94 607.94 704.60 601.17 601.17 704.60 704.60 601.17 601.17 +10.44 10.44 10.44 3.55 956.57 956.57 3.55 3.55 956.57 956.57 +539.89 539.89 539.89 611.15 487.26 487.26 611.15 611.15 487.26 487.26 +284.33 284.33 284.33 18.53 803.06 803.06 18.53 18.53 803.06 803.06 +241.25 241.25 241.25 381.83 168.26 168.26 381.83 381.83 168.26 168.26 +243.90 243.90 243.90 794.91 210.80 210.80 794.91 794.91 210.80 210.80 +839.33 839.33 839.33 572.80 447.99 447.99 572.80 572.80 447.99 447.99 +92.40 92.40 92.40 259.43 561.34 561.34 259.43 259.43 561.34 561.34 +850.73 850.73 850.73 441.06 152.72 152.72 441.06 441.06 152.72 152.72 +952.64 952.64 952.64 873.21 190.73 190.73 873.21 873.21 190.73 190.73 +27.20 27.20 27.20 183.75 37.92 37.92 183.75 183.75 37.92 37.92 +354.09 354.09 354.09 630.51 99.11 99.11 630.51 630.51 99.11 99.11 +582.75 582.75 582.75 663.76 485.43 485.43 663.76 663.76 485.43 485.43 +954.38 954.38 954.38 706.85 989.44 989.44 706.85 706.85 989.44 989.44 +926.25 926.25 926.25 621.43 96.83 96.83 621.43 621.43 96.83 96.83 +298.74 298.74 298.74 762.59 921.54 921.54 762.59 762.59 921.54 921.54 +137.02 137.02 137.02 21.89 841.89 841.89 21.89 21.89 841.89 841.89 +634.01 634.01 634.01 315.06 936.70 936.70 315.06 315.06 936.70 936.70 +675.62 675.62 675.62 475.66 98.70 98.70 475.66 475.66 98.70 98.70 +613.95 613.95 613.95 405.72 113.07 113.07 405.72 405.72 113.07 113.07 +84.21 84.21 84.21 914.49 356.39 356.39 914.49 914.49 356.39 356.39 +225.27 225.27 225.27 216.13 137.15 137.15 216.13 216.13 137.15 137.15 +693.53 693.53 693.53 514.87 266.36 266.36 514.87 514.87 266.36 266.36 +985.51 985.51 985.51 883.18 823.14 823.14 883.18 883.18 823.14 823.14 +132.96 132.96 132.96 220.58 65.46 65.46 220.58 220.58 65.46 65.46 +664.28 664.28 664.28 323.64 636.67 636.67 323.64 323.64 636.67 636.67 +92.79 92.79 92.79 980.85 777.64 777.64 980.85 980.85 777.64 777.64 +875.92 875.92 875.92 213.63 534.22 534.22 213.63 213.63 534.22 534.22 +250.34 250.34 250.34 822.62 501.89 501.89 822.62 822.62 501.89 501.89 +444.33 444.33 444.33 170.25 609.89 609.89 170.25 170.25 609.89 609.89 +864.45 864.45 864.45 949.71 3.70 3.70 949.71 949.71 3.70 3.70 +804.47 804.47 804.47 697.79 901.56 901.56 697.79 697.79 901.56 901.56 +229.44 229.44 229.44 9.62 931.54 931.54 9.62 9.62 931.54 931.54 +725.94 725.94 725.94 989.96 338.07 338.07 989.96 989.96 338.07 338.07 +137.09 137.09 137.09 375.54 442.46 442.46 375.54 375.54 442.46 442.46 +469.32 469.32 469.32 72.32 909.20 909.20 72.32 72.32 909.20 909.20 +604.65 604.65 604.65 572.65 421.37 421.37 572.65 572.65 421.37 421.37 +522.67 522.67 522.67 234.62 814.20 814.20 234.62 234.62 814.20 814.20 +997.87 997.87 997.87 290.65 223.30 223.30 290.65 290.65 223.30 223.30 +155.41 155.41 155.41 502.64 973.09 973.09 502.64 502.64 973.09 973.09 +492.74 492.74 492.74 269.19 379.74 379.74 269.19 269.19 379.74 379.74 +1.24 1.24 1.24 388.32 876.67 876.67 388.32 388.32 876.67 876.67 +777.61 777.61 777.61 707.87 694.20 694.20 707.87 707.87 694.20 694.20 +755.52 755.52 755.52 715.97 447.65 447.65 715.97 715.97 447.65 447.65 +71.29 71.29 71.29 895.08 46.14 46.14 895.08 895.08 46.14 46.14 +521.86 521.86 521.86 750.76 405.05 405.05 750.76 750.76 405.05 405.05 +649.79 649.79 649.79 110.07 925.57 925.57 110.07 110.07 925.57 925.57 +755.08 755.08 755.08 883.66 602.46 602.46 883.66 883.66 602.46 602.46 +922.27 922.27 922.27 775.86 678.65 678.65 775.86 775.86 678.65 678.65 +338.96 338.96 338.96 654.60 716.29 716.29 654.60 654.60 716.29 716.29 +74.31 74.31 74.31 444.02 949.31 949.31 444.02 444.02 949.31 949.31 +655.65 655.65 655.65 39.72 498.44 498.44 39.72 39.72 498.44 498.44 +542.56 542.56 542.56 58.94 208.86 208.86 58.94 58.94 208.86 208.86 +62.06 62.06 62.06 141.98 999.21 999.21 141.98 141.98 999.21 999.21 +700.95 700.95 700.95 302.52 368.15 368.15 302.52 302.52 368.15 368.15 +415.43 415.43 415.43 27.65 718.62 718.62 27.65 27.65 718.62 718.62 +728.81 728.81 728.81 729.98 25.21 25.21 729.98 729.98 25.21 25.21 +776.95 776.95 776.95 500.71 711.01 711.01 500.71 500.71 711.01 711.01 +533.61 533.61 533.61 751.34 593.97 593.97 751.34 751.34 593.97 593.97 +196.53 196.53 196.53 42.53 714.44 714.44 42.53 42.53 714.44 714.44 +30.32 30.32 30.32 652.23 828.39 828.39 652.23 652.23 828.39 828.39 +818.60 818.60 818.60 412.52 596.17 596.17 412.52 412.52 596.17 596.17 +499.12 499.12 499.12 402.12 764.05 764.05 402.12 402.12 764.05 764.05 +173.14 173.14 173.14 431.13 382.21 382.21 431.13 431.13 382.21 382.21 +111.40 111.40 111.40 275.46 286.42 286.42 275.46 275.46 286.42 286.42 +988.69 988.69 988.69 590.53 178.77 178.77 590.53 590.53 178.77 178.77 +867.89 867.89 867.89 389.35 984.91 984.91 389.35 389.35 984.91 984.91 +28.29 28.29 28.29 926.46 477.54 477.54 926.46 926.46 477.54 477.54 +884.65 884.65 884.65 467.30 176.01 176.01 467.30 467.30 176.01 176.01 +522.79 522.79 522.79 669.83 354.69 354.69 669.83 669.83 354.69 354.69 +625.01 625.01 625.01 696.87 568.69 568.69 696.87 696.87 568.69 568.69 +728.65 728.65 728.65 806.26 780.83 780.83 806.26 806.26 780.83 780.83 +944.84 944.84 944.84 332.17 810.43 810.43 332.17 332.17 810.43 810.43 +134.29 134.29 134.29 341.59 871.49 871.49 341.59 341.59 871.49 871.49 +606.31 606.31 606.31 327.20 703.86 703.86 327.20 327.20 703.86 703.86 +969.75 969.75 969.75 985.28 989.78 989.78 985.28 985.28 989.78 989.78 +188.24 188.24 188.24 734.37 149.33 149.33 734.37 734.37 149.33 149.33 +397.67 397.67 397.67 954.67 623.73 623.73 954.67 954.67 623.73 623.73 +254.66 254.66 254.66 564.56 363.43 363.43 564.56 564.56 363.43 363.43 +565.94 565.94 565.94 823.34 878.93 878.93 823.34 823.34 878.93 878.93 +289.32 289.32 289.32 142.06 771.63 771.63 142.06 142.06 771.63 771.63 +196.78 196.78 196.78 952.03 926.53 926.53 952.03 952.03 926.53 926.53 +616.10 616.10 616.10 576.41 715.36 715.36 576.41 576.41 715.36 715.36 +113.07 113.07 113.07 942.40 989.13 989.13 942.40 942.40 989.13 989.13 +950.04 950.04 950.04 983.63 860.33 860.33 983.63 983.63 860.33 860.33 +668.23 668.23 668.23 738.31 30.80 30.80 738.31 738.31 30.80 30.80 +452.46 452.46 452.46 725.22 934.62 934.62 725.22 725.22 934.62 934.62 diff --git a/examples/Begin Stochastic/gas.csv b/examples/Begin Stochastic/gas.csv index 52358d3..2255530 100644 --- a/examples/Begin Stochastic/gas.csv +++ b/examples/Begin Stochastic/gas.csv @@ -15,6 +15,12 @@ 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 @@ -36,17 +42,6 @@ 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 @@ -54,23 +49,11 @@ 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 -1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 @@ -99,8 +82,6 @@ 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 -1000.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 @@ -111,27 +92,31 @@ 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 +1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 +1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 +1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 +1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 +1000.00 1000.00 1000.00 700.00 700.00 1000.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 700.00 700.00 1000.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 -1000.00 700.00 1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 @@ -141,6 +126,23 @@ 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 700.00 +1000.00 1000.00 1000.00 700.00 700.00 1000.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 700.00 700.00 1000.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 700.00 700.00 1000.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 700.00 700.00 1000.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 700.00 700.00 700.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 700.00 700.00 1000.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 700.00 700.00 1000.00 700.00 1000.00 700.00 700.00 +1000.00 1000.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 700.00 1000.00 +1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 +1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 @@ -157,8 +159,6 @@ 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 -1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 -1000.00 1000.00 700.00 1000.00 700.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 1000.00 diff --git a/examples/Begin Stochastic/load_A.csv b/examples/Begin Stochastic/load_A.csv index feeebc6..4f20fe7 100644 --- a/examples/Begin Stochastic/load_A.csv +++ b/examples/Begin Stochastic/load_A.csv @@ -1,168 +1,168 @@ -1268.05 1269.16 1268.05 1269.16 1269.16 1268.05 1269.16 1261.69 1269.16 1261.69 -1324.11 1336.47 1324.11 1336.47 1336.47 1324.11 1336.47 1322.28 1336.47 1322.28 -1399.22 1438.12 1399.22 1438.12 1438.12 1399.22 1438.12 1409.81 1438.12 1409.81 -1494.83 1543.23 1494.83 1543.23 1543.23 1494.83 1543.23 1515.53 1543.23 1515.53 -1609.86 1648.44 1609.86 1648.44 1648.44 1609.86 1648.44 1619.84 1648.44 1619.84 -1727.17 1744.24 1727.17 1744.24 1744.24 1727.17 1744.24 1720.06 1744.24 1720.06 -1825.77 1825.73 1825.77 1825.73 1825.73 1825.77 1825.73 1808.50 1825.73 1808.50 -1906.07 1906.12 1906.07 1906.12 1906.12 1906.07 1906.12 1878.37 1906.12 1878.37 -1962.30 1962.76 1962.30 1962.76 1962.76 1962.30 1962.76 1927.31 1962.76 1927.31 -1983.33 2017.63 1983.33 2017.63 2017.63 1983.33 2017.63 1967.70 2017.63 1967.70 -1982.88 2025.39 1982.88 2025.39 2025.39 1982.88 2025.39 1958.42 2025.39 1958.42 -1965.59 2013.90 1965.59 2013.90 2013.90 1965.59 2013.90 1943.33 2013.90 1943.33 -1924.49 1960.11 1924.49 1960.11 1960.11 1924.49 1960.11 1884.10 1960.11 1884.10 -1842.83 1892.85 1842.83 1892.85 1892.85 1842.83 1892.85 1818.35 1892.85 1818.35 -1738.11 1800.54 1738.11 1800.54 1800.54 1738.11 1800.54 1736.68 1800.54 1736.68 -1635.52 1701.90 1635.52 1701.90 1701.90 1635.52 1701.90 1639.94 1701.90 1639.94 -1546.09 1594.92 1546.09 1594.92 1594.92 1546.09 1594.92 1546.59 1594.92 1546.59 -1429.80 1502.60 1429.80 1502.60 1502.60 1429.80 1502.60 1439.03 1502.60 1439.03 -1327.16 1411.94 1327.16 1411.94 1411.94 1327.16 1411.94 1339.77 1411.94 1339.77 -1249.37 1332.57 1249.37 1332.57 1332.57 1249.37 1332.57 1276.20 1332.57 1276.20 -1193.68 1268.10 1193.68 1268.10 1268.10 1193.68 1268.10 1215.57 1268.10 1215.57 -1166.55 1223.15 1166.55 1223.15 1223.15 1166.55 1223.15 1181.81 1223.15 1181.81 -1165.31 1224.43 1165.31 1224.43 1224.43 1165.31 1224.43 1192.91 1224.43 1192.91 -1176.79 1234.12 1176.79 1234.12 1234.12 1176.79 1234.12 1218.82 1234.12 1218.82 -1220.41 1276.90 1220.41 1276.90 1276.90 1220.41 1276.90 1270.25 1276.90 1270.25 -1298.40 1335.37 1298.40 1335.37 1335.37 1298.40 1335.37 1323.97 1335.37 1323.97 -1384.69 1420.29 1384.69 1420.29 1420.29 1384.69 1420.29 1416.89 1420.29 1416.89 -1476.33 1528.27 1476.33 1528.27 1528.27 1476.33 1528.27 1501.44 1528.27 1501.44 -1591.85 1644.40 1591.85 1644.40 1644.40 1591.85 1644.40 1610.82 1644.40 1610.82 -1680.01 1744.58 1680.01 1744.58 1744.58 1680.01 1744.58 1726.58 1744.58 1726.58 -1774.12 1839.05 1774.12 1839.05 1839.05 1774.12 1839.05 1808.87 1839.05 1808.87 -1842.25 1935.17 1842.25 1935.17 1935.17 1842.25 1935.17 1884.89 1935.17 1884.89 -1886.22 1986.08 1886.22 1986.08 1986.08 1886.22 1986.08 1935.37 1986.08 1935.37 -1905.86 2022.28 1905.86 2022.28 2022.28 1905.86 2022.28 1971.56 2022.28 1971.56 -1913.25 2016.55 1913.25 2016.55 2016.55 1913.25 2016.55 1983.86 2016.55 1983.86 -1876.56 1993.99 1876.56 1993.99 1993.99 1876.56 1993.99 1968.43 1993.99 1968.43 -1835.83 1930.67 1835.83 1930.67 1930.67 1835.83 1930.67 1921.91 1930.67 1921.91 -1750.90 1851.13 1750.90 1851.13 1851.13 1750.90 1851.13 1844.44 1851.13 1844.44 -1661.72 1746.26 1661.72 1746.26 1746.26 1661.72 1746.26 1756.48 1746.26 1756.48 -1560.90 1627.11 1560.90 1627.11 1627.11 1560.90 1627.11 1662.53 1627.11 1662.53 -1446.92 1518.35 1446.92 1518.35 1518.35 1446.92 1518.35 1560.20 1518.35 1560.20 -1346.74 1406.37 1346.74 1406.37 1406.37 1346.74 1406.37 1466.97 1406.37 1466.97 -1240.85 1335.19 1240.85 1335.19 1335.19 1240.85 1335.19 1381.34 1335.19 1381.34 -1177.96 1269.85 1177.96 1269.85 1269.85 1177.96 1269.85 1289.41 1269.85 1289.41 -1128.92 1221.49 1128.92 1221.49 1221.49 1128.92 1221.49 1244.04 1221.49 1244.04 -1108.01 1205.05 1108.01 1205.05 1205.05 1108.01 1205.05 1212.65 1205.05 1212.65 -1103.29 1205.75 1103.29 1205.75 1205.75 1103.29 1205.75 1189.51 1205.75 1189.51 -1136.11 1241.09 1136.11 1241.09 1241.09 1136.11 1241.09 1217.80 1241.09 1217.80 -1175.42 1276.25 1175.42 1276.25 1276.25 1175.42 1276.25 1261.99 1276.25 1261.99 -1231.42 1344.17 1231.42 1344.17 1344.17 1231.42 1344.17 1327.03 1344.17 1327.03 -1315.58 1425.49 1315.58 1425.49 1425.49 1315.58 1425.49 1428.23 1425.49 1428.23 -1428.69 1528.08 1428.69 1528.08 1528.08 1428.69 1528.08 1547.32 1528.08 1547.32 -1519.12 1620.66 1519.12 1620.66 1620.66 1519.12 1620.66 1657.80 1620.66 1657.80 -1626.71 1721.74 1626.71 1721.74 1721.74 1626.71 1721.74 1757.87 1721.74 1757.87 -1719.27 1805.76 1719.27 1805.76 1805.76 1719.27 1805.76 1860.48 1805.76 1860.48 -1779.39 1855.51 1779.39 1855.51 1855.51 1779.39 1855.51 1911.13 1855.51 1911.13 -1838.09 1920.80 1838.09 1920.80 1920.80 1838.09 1920.80 1950.53 1920.80 1950.53 -1866.99 1942.40 1866.99 1942.40 1942.40 1866.99 1942.40 1989.49 1942.40 1989.49 -1900.61 1947.30 1900.61 1947.30 1947.30 1900.61 1947.30 1992.28 1947.30 1992.28 -1860.29 1918.35 1860.29 1918.35 1918.35 1860.29 1918.35 1962.00 1918.35 1962.00 -1806.48 1845.97 1806.48 1845.97 1845.97 1806.48 1845.97 1908.91 1845.97 1908.91 -1724.56 1783.11 1724.56 1783.11 1783.11 1724.56 1783.11 1833.99 1783.11 1833.99 -1635.12 1690.64 1635.12 1690.64 1690.64 1635.12 1690.64 1744.43 1690.64 1744.43 -1515.68 1600.80 1515.68 1600.80 1600.80 1515.68 1600.80 1644.12 1600.80 1644.12 -1401.32 1487.96 1401.32 1487.96 1487.96 1401.32 1487.96 1547.78 1487.96 1547.78 -1316.00 1391.32 1316.00 1391.32 1391.32 1316.00 1391.32 1445.45 1391.32 1445.45 -1226.60 1302.77 1226.60 1302.77 1302.77 1226.60 1302.77 1376.43 1302.77 1376.43 -1142.55 1232.70 1142.55 1232.70 1232.70 1142.55 1232.70 1290.34 1232.70 1290.34 -1076.29 1181.55 1076.29 1181.55 1181.55 1076.29 1181.55 1243.79 1181.55 1243.79 -1049.68 1157.82 1049.68 1157.82 1157.82 1049.68 1157.82 1215.02 1157.82 1215.02 -1045.21 1162.32 1045.21 1162.32 1162.32 1045.21 1162.32 1228.86 1162.32 1228.86 -1075.54 1181.88 1075.54 1181.88 1181.88 1075.54 1181.88 1241.97 1181.88 1241.97 -1123.64 1236.02 1123.64 1236.02 1236.02 1123.64 1236.02 1292.56 1236.02 1292.56 -1203.41 1306.02 1203.41 1306.02 1306.02 1203.41 1306.02 1358.72 1306.02 1358.72 -1293.98 1406.37 1293.98 1406.37 1406.37 1293.98 1406.37 1453.91 1406.37 1453.91 -1400.75 1505.37 1400.75 1505.37 1505.37 1400.75 1505.37 1566.03 1505.37 1566.03 -1511.87 1601.44 1511.87 1601.44 1601.44 1511.87 1601.44 1678.26 1601.44 1678.26 -1615.64 1686.90 1615.64 1686.90 1686.90 1615.64 1686.90 1769.68 1686.90 1769.68 -1697.91 1778.45 1697.91 1778.45 1778.45 1697.91 1778.45 1869.07 1778.45 1869.07 -1770.33 1841.54 1770.33 1841.54 1841.54 1770.33 1841.54 1950.65 1841.54 1950.65 -1818.17 1900.26 1818.17 1900.26 1900.26 1818.17 1900.26 2014.24 1900.26 2014.24 -1839.75 1909.44 1839.75 1909.44 1909.44 1839.75 1909.44 2049.61 1909.44 2049.61 -1831.30 1901.11 1831.30 1901.11 1901.11 1831.30 1901.11 2042.27 1901.11 2042.27 -1819.80 1855.10 1819.80 1855.10 1855.10 1819.80 1855.10 2007.06 1855.10 2007.06 -1761.40 1805.02 1761.40 1805.02 1805.02 1761.40 1805.02 1957.01 1805.02 1957.01 -1681.40 1726.49 1681.40 1726.49 1726.49 1681.40 1726.49 1868.81 1726.49 1868.81 -1587.62 1623.27 1587.62 1623.27 1623.27 1587.62 1623.27 1782.79 1623.27 1782.79 -1479.59 1514.56 1479.59 1514.56 1514.56 1479.59 1514.56 1699.21 1514.56 1699.21 -1357.31 1404.62 1357.31 1404.62 1404.62 1357.31 1404.62 1598.84 1404.62 1598.84 -1249.14 1311.82 1249.14 1311.82 1311.82 1249.14 1311.82 1495.77 1311.82 1495.77 -1169.41 1250.47 1169.41 1250.47 1250.47 1169.41 1250.47 1402.65 1250.47 1402.65 -1110.16 1163.21 1110.16 1163.21 1163.21 1110.16 1163.21 1333.27 1163.21 1333.27 -1059.50 1133.67 1059.50 1133.67 1133.67 1059.50 1133.67 1288.44 1133.67 1288.44 -1041.70 1113.88 1041.70 1113.88 1113.88 1041.70 1113.88 1277.92 1113.88 1277.92 -1036.72 1118.48 1036.72 1118.48 1118.48 1036.72 1118.48 1293.00 1118.48 1293.00 -1075.39 1135.46 1075.39 1135.46 1135.46 1075.39 1135.46 1314.06 1135.46 1314.06 -1138.31 1200.04 1138.31 1200.04 1200.04 1138.31 1200.04 1372.57 1200.04 1372.57 -1219.98 1273.15 1219.98 1273.15 1273.15 1219.98 1273.15 1455.48 1273.15 1455.48 -1320.60 1372.23 1320.60 1372.23 1372.23 1320.60 1372.23 1538.20 1372.23 1538.20 -1421.49 1488.65 1421.49 1488.65 1488.65 1421.49 1488.65 1633.12 1488.65 1633.12 -1528.63 1603.39 1528.63 1603.39 1603.39 1528.63 1603.39 1743.12 1603.39 1743.12 -1613.92 1694.50 1613.92 1694.50 1694.50 1613.92 1694.50 1836.58 1694.50 1836.58 -1717.93 1784.50 1717.93 1784.50 1784.50 1717.93 1784.50 1927.31 1784.50 1927.31 -1779.95 1863.00 1779.95 1863.00 1863.00 1779.95 1863.00 2004.03 1863.00 2004.03 -1810.72 1896.02 1810.72 1896.02 1896.02 1810.72 1896.02 2057.13 1896.02 2057.13 -1830.19 1908.10 1830.19 1908.10 1908.10 1830.19 1908.10 2075.51 1908.10 2075.51 -1822.78 1891.23 1822.78 1891.23 1891.23 1822.78 1891.23 2063.57 1891.23 2063.57 -1792.47 1856.34 1792.47 1856.34 1856.34 1792.47 1856.34 2031.80 1856.34 2031.80 -1735.47 1792.64 1735.47 1792.64 1792.64 1735.47 1792.64 1990.82 1792.64 1990.82 -1672.77 1701.70 1672.77 1701.70 1701.70 1672.77 1701.70 1906.41 1701.70 1906.41 -1578.68 1622.46 1578.68 1622.46 1622.46 1578.68 1622.46 1811.75 1622.46 1811.75 -1485.92 1524.33 1485.92 1524.33 1524.33 1485.92 1524.33 1707.05 1524.33 1707.05 -1399.54 1425.60 1399.54 1425.60 1425.60 1399.54 1425.60 1598.12 1425.60 1598.12 -1305.40 1317.21 1305.40 1317.21 1317.21 1305.40 1317.21 1508.19 1317.21 1508.19 -1207.89 1234.90 1207.89 1234.90 1234.90 1207.89 1234.90 1410.07 1234.90 1410.07 -1153.34 1178.86 1153.34 1178.86 1178.86 1153.34 1178.86 1362.36 1178.86 1362.36 -1109.05 1118.63 1109.05 1118.63 1118.63 1109.05 1118.63 1307.09 1118.63 1307.09 -1108.40 1115.36 1108.40 1115.36 1115.36 1108.40 1115.36 1293.23 1115.36 1293.23 -1123.14 1133.28 1123.14 1133.28 1133.28 1123.14 1133.28 1305.19 1133.28 1305.19 -1145.07 1168.26 1145.07 1168.26 1168.26 1145.07 1168.26 1343.45 1168.26 1343.45 -1192.25 1218.12 1192.25 1218.12 1218.12 1192.25 1218.12 1413.45 1218.12 1413.45 -1265.32 1296.18 1265.32 1296.18 1296.18 1265.32 1296.18 1477.22 1296.18 1477.22 -1364.54 1390.88 1364.54 1390.88 1390.88 1364.54 1390.88 1566.10 1390.88 1566.10 -1470.74 1484.41 1470.74 1484.41 1484.41 1470.74 1484.41 1703.97 1484.41 1703.97 -1568.41 1578.67 1568.41 1578.67 1578.67 1568.41 1578.67 1809.70 1578.67 1809.70 -1666.91 1697.06 1666.91 1697.06 1697.06 1666.91 1697.06 1910.16 1697.06 1910.16 -1751.20 1765.89 1751.20 1765.89 1765.89 1751.20 1765.89 2001.19 1765.89 2001.19 -1798.52 1817.73 1798.52 1817.73 1817.73 1798.52 1817.73 2048.99 1817.73 2048.99 -1842.05 1848.73 1842.05 1848.73 1848.73 1842.05 1848.73 2097.10 1848.73 2097.10 -1869.61 1864.97 1869.61 1864.97 1864.97 1869.61 1864.97 2140.19 1864.97 2140.19 -1857.62 1848.90 1857.62 1848.90 1848.90 1857.62 1848.90 2153.00 1848.90 2153.00 -1817.72 1808.24 1817.72 1808.24 1808.24 1817.72 1808.24 2108.27 1808.24 2108.27 -1743.85 1742.51 1743.85 1742.51 1742.51 1743.85 1742.51 2050.23 1742.51 2050.23 -1652.80 1645.50 1652.80 1645.50 1645.50 1652.80 1645.50 1948.00 1645.50 1948.00 -1564.05 1553.07 1564.05 1553.07 1553.07 1564.05 1553.07 1859.17 1553.07 1859.17 -1445.19 1471.75 1445.19 1471.75 1471.75 1445.19 1471.75 1764.95 1471.75 1764.95 -1342.94 1369.23 1342.94 1369.23 1369.23 1342.94 1369.23 1657.02 1369.23 1657.02 -1265.32 1258.87 1265.32 1258.87 1258.87 1265.32 1258.87 1558.51 1258.87 1558.51 -1178.72 1170.14 1178.72 1170.14 1170.14 1178.72 1170.14 1469.12 1170.14 1469.12 -1110.47 1118.14 1110.47 1118.14 1118.14 1110.47 1118.14 1398.46 1118.14 1398.46 -1082.80 1079.05 1082.80 1079.05 1079.05 1082.80 1079.05 1363.12 1079.05 1363.12 -1058.15 1063.89 1058.15 1063.89 1063.89 1058.15 1063.89 1369.51 1063.89 1369.51 -1067.60 1080.18 1067.60 1080.18 1080.18 1067.60 1080.18 1382.97 1080.18 1382.97 -1107.93 1128.41 1107.93 1128.41 1128.41 1107.93 1128.41 1445.28 1128.41 1445.28 -1176.65 1201.03 1176.65 1201.03 1201.03 1176.65 1201.03 1507.13 1201.03 1507.13 -1270.75 1284.33 1270.75 1284.33 1284.33 1270.75 1284.33 1597.92 1284.33 1597.92 -1364.67 1396.54 1364.67 1396.54 1396.54 1364.67 1396.54 1680.11 1396.54 1680.11 -1450.16 1507.35 1450.16 1507.35 1507.35 1450.16 1507.35 1780.05 1507.35 1780.05 -1533.99 1613.72 1533.99 1613.72 1613.72 1533.99 1613.72 1885.15 1613.72 1885.15 -1632.29 1722.78 1632.29 1722.78 1722.78 1632.29 1722.78 1985.84 1722.78 1985.84 -1708.55 1812.97 1708.55 1812.97 1812.97 1708.55 1812.97 2075.66 1812.97 2075.66 -1759.20 1862.54 1759.20 1862.54 1862.54 1759.20 1862.54 2139.50 1862.54 2139.50 -1788.97 1894.52 1788.97 1894.52 1894.52 1788.97 1894.52 2167.28 1894.52 2167.28 -1784.65 1908.62 1784.65 1908.62 1908.62 1784.65 1908.62 2185.22 1908.62 2185.22 -1764.54 1871.67 1764.54 1871.67 1871.67 1764.54 1871.67 2180.74 1871.67 2180.74 -1722.63 1837.85 1722.63 1837.85 1837.85 1722.63 1837.85 2137.90 1837.85 2137.90 -1653.32 1749.06 1653.32 1749.06 1749.06 1653.32 1749.06 2080.58 1749.06 2080.58 -1568.86 1647.74 1568.86 1647.74 1647.74 1568.86 1647.74 2008.69 1647.74 2008.69 -1472.18 1543.88 1472.18 1543.88 1543.88 1472.18 1543.88 1908.92 1543.88 1908.92 -1364.45 1438.70 1364.45 1438.70 1438.70 1364.45 1438.70 1789.96 1438.70 1789.96 -1270.02 1344.11 1270.02 1344.11 1344.11 1270.02 1344.11 1686.59 1344.11 1686.59 -1165.97 1235.12 1165.97 1235.12 1235.12 1165.97 1235.12 1587.51 1235.12 1587.51 -1078.76 1156.26 1078.76 1156.26 1156.26 1078.76 1156.26 1518.27 1156.26 1518.27 -1025.05 1096.82 1025.05 1096.82 1096.82 1025.05 1096.82 1455.32 1096.82 1455.32 -995.24 1054.51 995.24 1054.51 1054.51 995.24 1054.51 1415.40 1054.51 1415.40 -981.85 1056.55 981.85 1056.55 1056.55 981.85 1056.55 1415.03 1056.55 1415.03 -1003.23 1075.01 1003.23 1075.01 1075.01 1003.23 1075.01 1411.70 1075.01 1411.70 -1046.81 1119.42 1046.81 1119.42 1119.42 1046.81 1119.42 1460.84 1119.42 1460.84 +1283.00 1283.00 1283.00 1259.73 1268.47 1268.47 1259.73 1259.73 1268.47 1268.47 +1362.92 1362.92 1362.92 1313.33 1335.04 1335.04 1313.33 1313.33 1335.04 1335.04 +1455.13 1455.13 1455.13 1402.83 1411.73 1411.73 1402.83 1402.83 1411.73 1411.73 +1543.69 1543.69 1543.69 1504.38 1492.16 1492.16 1504.38 1504.38 1492.16 1492.16 +1657.68 1657.68 1657.68 1609.54 1591.95 1591.95 1609.54 1609.54 1591.95 1591.95 +1757.45 1757.45 1757.45 1729.74 1693.40 1693.40 1729.74 1729.74 1693.40 1693.40 +1844.81 1844.81 1844.81 1817.79 1794.01 1794.01 1817.79 1817.79 1794.01 1794.01 +1934.25 1934.25 1934.25 1905.08 1875.42 1875.42 1905.08 1905.08 1875.42 1875.42 +2004.99 2004.99 2004.99 1987.68 1934.84 1934.84 1987.68 1987.68 1934.84 1934.84 +2046.30 2046.30 2046.30 2037.43 1970.88 1970.88 2037.43 2037.43 1970.88 1970.88 +2052.57 2052.57 2052.57 2058.16 1964.26 1964.26 2058.16 2058.16 1964.26 1964.26 +2021.62 2021.62 2021.62 2037.96 1954.37 1954.37 2037.96 2037.96 1954.37 1954.37 +1984.13 1984.13 1984.13 1976.78 1904.34 1904.34 1976.78 1976.78 1904.34 1904.34 +1911.65 1911.65 1911.65 1903.37 1834.34 1834.34 1903.37 1903.37 1834.34 1834.34 +1821.80 1821.80 1821.80 1831.21 1744.73 1744.73 1831.21 1831.21 1744.73 1744.73 +1716.51 1716.51 1716.51 1728.92 1670.60 1670.60 1728.92 1728.92 1670.60 1670.60 +1594.94 1594.94 1594.94 1638.64 1573.95 1573.95 1638.64 1638.64 1573.95 1573.95 +1489.55 1489.55 1489.55 1532.12 1477.95 1477.95 1532.12 1532.12 1477.95 1477.95 +1400.63 1400.63 1400.63 1428.54 1369.37 1369.37 1428.54 1428.54 1369.37 1369.37 +1324.66 1324.66 1324.66 1349.83 1289.71 1289.71 1349.83 1349.83 1289.71 1289.71 +1269.28 1269.28 1269.28 1274.16 1246.11 1246.11 1274.16 1274.16 1246.11 1246.11 +1261.24 1261.24 1261.24 1234.33 1217.80 1217.80 1234.33 1234.33 1217.80 1217.80 +1257.07 1257.07 1257.07 1228.27 1199.43 1199.43 1228.27 1228.27 1199.43 1199.43 +1265.90 1265.90 1265.90 1265.84 1220.76 1220.76 1265.84 1265.84 1220.76 1220.76 +1308.56 1308.56 1308.56 1310.93 1274.13 1274.13 1310.93 1310.93 1274.13 1274.13 +1385.19 1385.19 1385.19 1379.37 1336.50 1336.50 1379.37 1379.37 1336.50 1336.50 +1484.59 1484.59 1484.59 1483.55 1425.80 1425.80 1483.55 1483.55 1425.80 1425.80 +1578.05 1578.05 1578.05 1585.69 1532.97 1532.97 1585.69 1585.69 1532.97 1532.97 +1695.61 1695.61 1695.61 1680.06 1628.78 1628.78 1680.06 1680.06 1628.78 1628.78 +1812.79 1812.79 1812.79 1785.81 1734.41 1734.41 1785.81 1785.81 1734.41 1734.41 +1894.35 1894.35 1894.35 1877.86 1833.88 1833.88 1877.86 1877.86 1833.88 1833.88 +1963.36 1963.36 1963.36 1981.05 1917.00 1917.00 1981.05 1981.05 1917.00 1917.00 +2015.08 2015.08 2015.08 2050.32 1988.14 1988.14 2050.32 2050.32 1988.14 1988.14 +2035.79 2035.79 2035.79 2096.99 2019.23 2019.23 2096.99 2096.99 2019.23 2019.23 +2039.58 2039.58 2039.58 2111.94 2041.35 2041.35 2111.94 2111.94 2041.35 2041.35 +2009.84 2009.84 2009.84 2094.88 2008.82 2008.82 2094.88 2094.88 2008.82 2008.82 +1955.03 1955.03 1955.03 2028.65 1963.31 1963.31 2028.65 2028.65 1963.31 1963.31 +1903.89 1903.89 1903.89 1960.20 1894.38 1894.38 1960.20 1960.20 1894.38 1894.38 +1829.72 1829.72 1829.72 1872.04 1810.20 1810.20 1872.04 1872.04 1810.20 1810.20 +1725.06 1725.06 1725.06 1770.93 1691.71 1691.71 1770.93 1770.93 1691.71 1691.71 +1607.94 1607.94 1607.94 1644.11 1579.58 1579.58 1644.11 1644.11 1579.58 1579.58 +1525.53 1525.53 1525.53 1537.73 1472.58 1472.58 1537.73 1537.73 1472.58 1472.58 +1444.73 1444.73 1444.73 1442.43 1378.78 1378.78 1442.43 1442.43 1378.78 1378.78 +1381.29 1381.29 1381.29 1379.57 1299.52 1299.52 1379.57 1379.57 1299.52 1299.52 +1314.31 1314.31 1314.31 1318.97 1239.04 1239.04 1318.97 1318.97 1239.04 1239.04 +1288.46 1288.46 1288.46 1300.70 1203.63 1203.63 1300.70 1300.70 1203.63 1203.63 +1269.61 1269.61 1269.61 1300.31 1200.90 1200.90 1300.31 1300.31 1200.90 1200.90 +1311.16 1311.16 1311.16 1322.25 1223.83 1223.83 1322.25 1322.25 1223.83 1223.83 +1354.28 1354.28 1354.28 1378.41 1273.49 1273.49 1378.41 1378.41 1273.49 1273.49 +1427.95 1427.95 1427.95 1467.98 1354.98 1354.98 1467.98 1467.98 1354.98 1354.98 +1537.34 1537.34 1537.34 1557.46 1440.37 1440.37 1557.46 1557.46 1440.37 1440.37 +1650.59 1650.59 1650.59 1654.24 1525.96 1525.96 1654.24 1654.24 1525.96 1525.96 +1731.68 1731.68 1731.68 1754.18 1629.65 1629.65 1754.18 1754.18 1629.65 1629.65 +1831.87 1831.87 1831.87 1861.43 1723.46 1723.46 1861.43 1861.43 1723.46 1723.46 +1918.41 1918.41 1918.41 1939.44 1792.85 1792.85 1939.44 1939.44 1792.85 1792.85 +2011.48 2011.48 2011.48 2016.34 1856.56 1856.56 2016.34 2016.34 1856.56 1856.56 +2037.45 2037.45 2037.45 2063.00 1909.19 1909.19 2063.00 2063.00 1909.19 1909.19 +2067.10 2067.10 2067.10 2085.86 1945.05 1945.05 2085.86 2085.86 1945.05 1945.05 +2068.94 2068.94 2068.94 2091.63 1945.44 1945.44 2091.63 2091.63 1945.44 1945.44 +2032.22 2032.22 2032.22 2081.35 1917.70 1917.70 2081.35 2081.35 1917.70 1917.70 +1976.04 1976.04 1976.04 2029.71 1883.10 1883.10 2029.71 2029.71 1883.10 1883.10 +1913.98 1913.98 1913.98 1949.89 1823.57 1823.57 1949.89 1949.89 1823.57 1823.57 +1807.69 1807.69 1807.69 1838.19 1745.48 1745.48 1838.19 1838.19 1745.48 1745.48 +1710.49 1710.49 1710.49 1754.91 1647.96 1647.96 1754.91 1754.91 1647.96 1647.96 +1607.98 1607.98 1607.98 1650.58 1547.69 1547.69 1650.58 1650.58 1547.69 1547.69 +1508.20 1508.20 1508.20 1540.28 1457.56 1457.56 1540.28 1540.28 1457.56 1457.56 +1427.66 1427.66 1427.66 1437.75 1372.61 1372.61 1437.75 1437.75 1372.61 1372.61 +1343.24 1343.24 1343.24 1364.90 1302.23 1302.23 1364.90 1364.90 1302.23 1302.23 +1299.87 1299.87 1299.87 1310.94 1256.24 1256.24 1310.94 1310.94 1256.24 1256.24 +1282.91 1282.91 1282.91 1279.67 1245.83 1245.83 1279.67 1279.67 1245.83 1245.83 +1295.34 1295.34 1295.34 1278.55 1262.89 1262.89 1278.55 1278.55 1262.89 1262.89 +1316.22 1316.22 1316.22 1300.23 1281.37 1281.37 1300.23 1300.23 1281.37 1281.37 +1359.18 1359.18 1359.18 1359.37 1335.14 1335.14 1359.37 1359.37 1335.14 1335.14 +1431.67 1431.67 1431.67 1426.67 1413.74 1413.74 1426.67 1426.67 1413.74 1413.74 +1518.81 1518.81 1518.81 1516.72 1499.97 1499.97 1516.72 1516.72 1499.97 1499.97 +1624.01 1624.01 1624.01 1608.47 1601.74 1601.74 1608.47 1608.47 1601.74 1601.74 +1716.65 1716.65 1716.65 1711.84 1718.91 1718.91 1711.84 1711.84 1718.91 1718.91 +1801.41 1801.41 1801.41 1803.09 1829.63 1829.63 1803.09 1803.09 1829.63 1829.63 +1886.27 1886.27 1886.27 1883.56 1917.45 1917.45 1883.56 1883.56 1917.45 1917.45 +1945.07 1945.07 1945.07 1955.58 1981.67 1981.67 1955.58 1955.58 1981.67 1981.67 +2015.15 2015.15 2015.15 2000.90 2027.24 2027.24 2000.90 2000.90 2027.24 2027.24 +2037.64 2037.64 2037.64 2027.73 2052.82 2052.82 2027.73 2027.73 2052.82 2052.82 +2045.48 2045.48 2045.48 2020.38 2067.99 2067.99 2020.38 2020.38 2067.99 2067.99 +2028.04 2028.04 2028.04 1991.14 2064.25 2064.25 1991.14 1991.14 2064.25 2064.25 +1949.95 1949.95 1949.95 1920.97 2018.71 2018.71 1920.97 1920.97 2018.71 2018.71 +1860.46 1860.46 1860.46 1832.29 1956.72 1956.72 1832.29 1832.29 1956.72 1956.72 +1777.82 1777.82 1777.82 1734.06 1856.25 1856.25 1734.06 1734.06 1856.25 1856.25 +1672.35 1672.35 1672.35 1632.91 1747.50 1747.50 1632.91 1632.91 1747.50 1747.50 +1570.70 1570.70 1570.70 1526.69 1628.06 1628.06 1526.69 1526.69 1628.06 1628.06 +1467.55 1467.55 1467.55 1450.58 1524.69 1524.69 1450.58 1450.58 1524.69 1524.69 +1406.92 1406.92 1406.92 1360.74 1439.32 1439.32 1360.74 1360.74 1439.32 1439.32 +1338.98 1338.98 1338.98 1295.04 1366.14 1366.14 1295.04 1295.04 1366.14 1366.14 +1306.89 1306.89 1306.89 1236.06 1327.16 1327.16 1236.06 1236.06 1327.16 1327.16 +1278.33 1278.33 1278.33 1226.16 1318.27 1318.27 1226.16 1226.16 1318.27 1318.27 +1291.57 1291.57 1291.57 1236.87 1325.68 1325.68 1236.87 1236.87 1325.68 1325.68 +1318.60 1318.60 1318.60 1265.43 1349.83 1349.83 1265.43 1265.43 1349.83 1349.83 +1378.77 1378.77 1378.77 1341.74 1413.60 1413.60 1341.74 1341.74 1413.60 1413.60 +1471.02 1471.02 1471.02 1436.40 1498.28 1498.28 1436.40 1436.40 1498.28 1498.28 +1573.78 1573.78 1573.78 1530.29 1589.63 1589.63 1530.29 1530.29 1589.63 1589.63 +1674.84 1674.84 1674.84 1636.19 1673.26 1673.26 1636.19 1636.19 1673.26 1673.26 +1775.98 1775.98 1775.98 1726.56 1775.04 1775.04 1726.56 1726.56 1775.04 1775.04 +1874.90 1874.90 1874.90 1851.83 1884.25 1884.25 1851.83 1851.83 1884.25 1884.25 +1963.16 1963.16 1963.16 1936.19 1971.80 1971.80 1936.19 1936.19 1971.80 1971.80 +2022.49 2022.49 2022.49 2004.19 2029.08 2029.08 2004.19 2004.19 2029.08 2029.08 +2071.55 2071.55 2071.55 2039.21 2085.25 2085.25 2039.21 2039.21 2085.25 2085.25 +2084.05 2084.05 2084.05 2067.42 2087.28 2087.28 2067.42 2067.42 2087.28 2087.28 +2060.55 2060.55 2060.55 2044.59 2074.33 2074.33 2044.59 2044.59 2074.33 2074.33 +2023.52 2023.52 2023.52 2006.92 2043.87 2043.87 2006.92 2006.92 2043.87 2043.87 +1979.37 1979.37 1979.37 1938.53 1993.03 1993.03 1938.53 1938.53 1993.03 1993.03 +1902.71 1902.71 1902.71 1854.67 1887.37 1887.37 1854.67 1854.67 1887.37 1887.37 +1812.29 1812.29 1812.29 1773.68 1822.92 1822.92 1773.68 1773.68 1822.92 1822.92 +1708.91 1708.91 1708.91 1667.81 1722.67 1722.67 1667.81 1667.81 1722.67 1722.67 +1593.59 1593.59 1593.59 1589.23 1600.09 1600.09 1589.23 1589.23 1600.09 1600.09 +1495.19 1495.19 1495.19 1487.71 1505.33 1505.33 1487.71 1487.71 1505.33 1505.33 +1406.51 1406.51 1406.51 1390.03 1439.70 1439.70 1390.03 1390.03 1439.70 1439.70 +1329.66 1329.66 1329.66 1320.80 1372.72 1372.72 1320.80 1320.80 1372.72 1372.72 +1282.22 1282.22 1282.22 1265.00 1332.06 1332.06 1265.00 1265.00 1332.06 1332.06 +1272.08 1272.08 1272.08 1254.86 1310.61 1310.61 1254.86 1254.86 1310.61 1310.61 +1261.54 1261.54 1261.54 1279.96 1329.16 1329.16 1279.96 1279.96 1329.16 1329.16 +1305.16 1305.16 1305.16 1318.92 1360.42 1360.42 1318.92 1318.92 1360.42 1360.42 +1372.62 1372.62 1372.62 1377.60 1420.15 1420.15 1377.60 1377.60 1420.15 1420.15 +1451.54 1451.54 1451.54 1467.35 1504.60 1504.60 1467.35 1467.35 1504.60 1504.60 +1561.62 1561.62 1561.62 1562.44 1591.61 1591.61 1562.44 1562.44 1591.61 1591.61 +1666.50 1666.50 1666.50 1673.60 1677.34 1677.34 1673.60 1673.60 1677.34 1677.34 +1784.89 1784.89 1784.89 1770.84 1775.00 1775.00 1770.84 1770.84 1775.00 1775.00 +1897.53 1897.53 1897.53 1864.32 1871.15 1871.15 1864.32 1864.32 1871.15 1871.15 +1996.62 1996.62 1996.62 1951.59 1957.70 1957.70 1951.59 1951.59 1957.70 1957.70 +2057.40 2057.40 2057.40 2027.62 2009.50 2009.50 2027.62 2027.62 2009.50 2009.50 +2088.87 2088.87 2088.87 2050.46 2046.78 2046.78 2050.46 2050.46 2046.78 2046.78 +2125.43 2125.43 2125.43 2050.88 2067.27 2067.27 2050.88 2050.88 2067.27 2067.27 +2125.11 2125.11 2125.11 2025.46 2059.07 2059.07 2025.46 2025.46 2059.07 2059.07 +2100.54 2100.54 2100.54 1973.92 2013.81 2013.81 1973.92 1973.92 2013.81 2013.81 +2038.18 2038.18 2038.18 1899.37 1956.10 1956.10 1899.37 1899.37 1956.10 1956.10 +1943.05 1943.05 1943.05 1819.70 1858.06 1858.06 1819.70 1819.70 1858.06 1858.06 +1853.32 1853.32 1853.32 1722.54 1769.34 1769.34 1722.54 1722.54 1769.34 1769.34 +1743.10 1743.10 1743.10 1619.32 1658.77 1658.77 1619.32 1619.32 1658.77 1658.77 +1648.40 1648.40 1648.40 1516.50 1557.74 1557.74 1516.50 1516.50 1557.74 1557.74 +1558.64 1558.64 1558.64 1421.20 1463.96 1463.96 1421.20 1421.20 1463.96 1463.96 +1479.03 1479.03 1479.03 1338.70 1376.94 1376.94 1338.70 1338.70 1376.94 1376.94 +1433.48 1433.48 1433.48 1271.76 1311.84 1311.84 1271.76 1271.76 1311.84 1311.84 +1391.14 1391.14 1391.14 1240.47 1277.95 1277.95 1240.47 1240.47 1277.95 1277.95 +1377.66 1377.66 1377.66 1214.57 1266.38 1266.38 1214.57 1214.57 1266.38 1266.38 +1396.86 1396.86 1396.86 1220.98 1277.55 1277.55 1220.98 1220.98 1277.55 1277.55 +1436.57 1436.57 1436.57 1272.82 1319.35 1319.35 1272.82 1272.82 1319.35 1319.35 +1501.82 1501.82 1501.82 1336.11 1404.83 1404.83 1336.11 1336.11 1404.83 1404.83 +1578.67 1578.67 1578.67 1429.94 1499.59 1499.59 1429.94 1429.94 1499.59 1499.59 +1698.65 1698.65 1698.65 1540.52 1584.00 1584.00 1540.52 1540.52 1584.00 1584.00 +1806.32 1806.32 1806.32 1640.92 1658.71 1658.71 1640.92 1640.92 1658.71 1658.71 +1912.29 1912.29 1912.29 1749.06 1781.86 1781.86 1749.06 1749.06 1781.86 1781.86 +2010.53 2010.53 2010.53 1843.04 1867.72 1867.72 1843.04 1843.04 1867.72 1867.72 +2089.97 2089.97 2089.97 1928.28 1952.90 1952.90 1928.28 1928.28 1952.90 1952.90 +2170.91 2170.91 2170.91 1972.25 2019.57 2019.57 1972.25 1972.25 2019.57 2019.57 +2209.19 2209.19 2209.19 2021.65 2059.84 2059.84 2021.65 2021.65 2059.84 2059.84 +2214.11 2214.11 2214.11 2035.97 2062.39 2062.39 2035.97 2035.97 2062.39 2062.39 +2190.41 2190.41 2190.41 2024.30 2043.31 2043.31 2024.30 2024.30 2043.31 2043.31 +2150.72 2150.72 2150.72 1982.00 2005.70 2005.70 1982.00 1982.00 2005.70 2005.70 +2088.07 2088.07 2088.07 1907.98 1946.25 1946.25 1907.98 1907.98 1946.25 1946.25 +2014.13 2014.13 2014.13 1826.71 1863.48 1863.48 1826.71 1826.71 1863.48 1863.48 +1918.91 1918.91 1918.91 1725.16 1760.74 1760.74 1725.16 1725.16 1760.74 1760.74 +1824.71 1824.71 1824.71 1631.35 1639.70 1639.70 1631.35 1631.35 1639.70 1639.70 +1726.02 1726.02 1726.02 1534.06 1534.50 1534.50 1534.06 1534.06 1534.50 1534.50 +1624.54 1624.54 1624.54 1442.05 1447.72 1447.72 1442.05 1442.05 1447.72 1447.72 +1541.59 1541.59 1541.59 1369.66 1372.85 1372.85 1369.66 1369.66 1372.85 1372.85 +1480.90 1480.90 1480.90 1318.90 1319.27 1319.27 1318.90 1318.90 1319.27 1319.27 +1455.04 1455.04 1455.04 1283.24 1277.25 1277.25 1283.24 1283.24 1277.25 1277.25 +1451.61 1451.61 1451.61 1285.70 1253.32 1253.32 1285.70 1285.70 1253.32 1253.32 +1480.17 1480.17 1480.17 1305.42 1286.52 1286.52 1305.42 1305.42 1286.52 1286.52 +1510.54 1510.54 1510.54 1354.29 1331.85 1331.85 1354.29 1354.29 1331.85 1331.85 diff --git a/examples/Begin Stochastic/load_B.csv b/examples/Begin Stochastic/load_B.csv index 3a6c394..065eb86 100644 --- a/examples/Begin Stochastic/load_B.csv +++ b/examples/Begin Stochastic/load_B.csv @@ -1,168 +1,168 @@ -1892.94 1918.57 1892.94 1918.57 1918.57 1892.94 1918.57 1895.46 1918.57 1895.46 -1996.11 2000.41 1996.11 2000.41 2000.41 1996.11 2000.41 1993.57 2000.41 1993.57 -2123.46 2132.56 2123.46 2132.56 2132.56 2123.46 2132.56 2124.46 2132.56 2124.46 -2269.27 2270.03 2269.27 2270.03 2270.03 2269.27 2270.03 2299.38 2270.03 2299.38 -2415.09 2420.32 2415.09 2420.32 2420.32 2415.09 2420.32 2448.17 2420.32 2448.17 -2568.25 2589.80 2568.25 2589.80 2589.80 2568.25 2589.80 2616.37 2589.80 2616.37 -2714.16 2733.17 2714.16 2733.17 2733.17 2714.16 2733.17 2748.59 2733.17 2748.59 -2823.68 2840.19 2823.68 2840.19 2840.19 2823.68 2840.19 2860.48 2840.19 2860.48 -2903.07 2921.22 2903.07 2921.22 2921.22 2903.07 2921.22 2943.09 2921.22 2943.09 -2948.03 2960.70 2948.03 2960.70 2960.70 2948.03 2960.70 3002.73 2960.70 3002.73 -2957.59 2967.58 2957.59 2967.58 2967.58 2957.59 2967.58 3030.38 2967.58 3030.38 -2939.68 2930.79 2939.68 2930.79 2930.79 2939.68 2930.79 3003.74 2930.79 3003.74 -2868.91 2849.92 2868.91 2849.92 2849.92 2868.91 2849.92 2933.24 2849.92 2933.24 -2770.33 2772.17 2770.33 2772.17 2772.17 2770.33 2772.17 2836.28 2772.17 2836.28 -2659.76 2639.60 2659.76 2639.60 2639.60 2659.76 2639.60 2705.76 2639.60 2705.76 -2509.03 2491.11 2509.03 2491.11 2491.11 2509.03 2491.11 2558.31 2491.11 2558.31 -2351.75 2339.18 2351.75 2339.18 2339.18 2351.75 2339.18 2421.99 2339.18 2421.99 -2186.60 2188.15 2186.60 2188.15 2188.15 2186.60 2188.15 2282.19 2188.15 2282.19 -2038.16 2041.75 2038.16 2041.75 2041.75 2038.16 2041.75 2149.97 2041.75 2149.97 -1913.21 1920.91 1913.21 1920.91 1920.91 1913.21 1920.91 2042.20 1920.91 2042.20 -1817.96 1833.01 1817.96 1833.01 1833.01 1817.96 1833.01 1961.47 1833.01 1961.47 -1783.98 1792.82 1783.98 1792.82 1792.82 1783.98 1792.82 1916.40 1792.82 1916.40 -1769.75 1788.25 1769.75 1788.25 1788.25 1769.75 1788.25 1906.95 1788.25 1906.95 -1790.39 1826.91 1790.39 1826.91 1826.91 1790.39 1826.91 1947.87 1826.91 1947.87 -1856.56 1896.34 1856.56 1896.34 1896.34 1856.56 1896.34 2032.67 1896.34 2032.67 -1956.43 1995.43 1956.43 1995.43 1995.43 1956.43 1995.43 2130.98 1995.43 2130.98 -2092.11 2114.23 2092.11 2114.23 2114.23 2092.11 2114.23 2264.49 2114.23 2264.49 -2225.76 2261.37 2225.76 2261.37 2261.37 2225.76 2261.37 2414.38 2261.37 2414.38 -2392.63 2394.04 2392.63 2394.04 2394.04 2392.63 2394.04 2571.33 2394.04 2571.33 -2552.09 2546.80 2552.09 2546.80 2546.80 2552.09 2546.80 2722.19 2546.80 2722.19 -2689.84 2708.42 2689.84 2708.42 2708.42 2689.84 2708.42 2860.57 2708.42 2860.57 -2831.69 2810.85 2831.69 2810.85 2810.85 2831.69 2810.85 2963.96 2810.85 2963.96 -2917.47 2901.35 2917.47 2901.35 2901.35 2917.47 2901.35 3049.11 2901.35 3049.11 -2960.42 2940.77 2960.42 2940.77 2940.77 2960.42 2940.77 3097.33 2940.77 3097.33 -2958.44 2938.39 2958.44 2938.39 2938.39 2958.44 2938.39 3104.39 2938.39 3104.39 -2925.13 2898.17 2925.13 2898.17 2898.17 2925.13 2898.17 3072.87 2898.17 3072.87 -2865.84 2810.83 2865.84 2810.83 2810.83 2865.84 2810.83 3007.51 2810.83 3007.51 -2757.28 2685.40 2757.28 2685.40 2685.40 2757.28 2685.40 2895.89 2685.40 2895.89 -2620.27 2536.09 2620.27 2536.09 2536.09 2620.27 2536.09 2761.79 2536.09 2761.79 -2471.68 2394.47 2471.68 2394.47 2394.47 2471.68 2394.47 2609.58 2394.47 2609.58 -2307.46 2240.41 2307.46 2240.41 2240.41 2307.46 2240.41 2453.31 2240.41 2453.31 -2154.79 2083.34 2154.79 2083.34 2083.34 2154.79 2083.34 2297.49 2083.34 2297.49 -2015.68 1937.70 2015.68 1937.70 1937.70 2015.68 1937.70 2148.08 1937.70 2148.08 -1898.69 1827.63 1898.69 1827.63 1827.63 1898.69 1827.63 2033.96 1827.63 2033.96 -1807.14 1751.37 1807.14 1751.37 1751.37 1807.14 1751.37 1957.87 1751.37 1957.87 -1759.43 1710.86 1759.43 1710.86 1710.86 1759.43 1710.86 1920.57 1710.86 1920.57 -1761.56 1709.81 1761.56 1709.81 1709.81 1761.56 1709.81 1927.44 1709.81 1927.44 -1808.50 1742.51 1808.50 1742.51 1742.51 1808.50 1742.51 1963.55 1742.51 1963.55 -1893.28 1825.16 1893.28 1825.16 1825.16 1893.28 1825.16 2042.08 1825.16 2042.08 -2017.15 1923.64 2017.15 1923.64 1923.64 2017.15 1923.64 2142.91 1923.64 2142.91 -2152.89 2050.09 2152.89 2050.09 2050.09 2152.89 2050.09 2286.27 2050.09 2286.27 -2317.02 2215.06 2317.02 2215.06 2215.06 2317.02 2215.06 2443.25 2215.06 2443.25 -2469.70 2378.63 2469.70 2378.63 2378.63 2469.70 2378.63 2598.12 2378.63 2598.12 -2617.99 2516.18 2617.99 2516.18 2516.18 2617.99 2516.18 2743.56 2516.18 2743.56 -2755.04 2652.64 2755.04 2652.64 2652.64 2755.04 2652.64 2874.96 2652.64 2874.96 -2876.34 2755.47 2876.34 2755.47 2755.47 2876.34 2755.47 2992.52 2755.47 2992.52 -2951.97 2829.88 2951.97 2829.88 2829.88 2951.97 2829.88 3063.33 2829.88 3063.33 -2993.25 2877.71 2993.25 2877.71 2877.71 2993.25 2877.71 3107.58 2877.71 3107.58 -3007.55 2865.24 3007.55 2865.24 2865.24 3007.55 2865.24 3122.99 2865.24 3122.99 -2962.94 2807.29 2962.94 2807.29 2807.29 2962.94 2807.29 3080.96 2807.29 3080.96 -2867.61 2724.13 2867.61 2724.13 2724.13 2867.61 2724.13 3009.73 2724.13 3009.73 -2758.99 2628.30 2758.99 2628.30 2628.30 2758.99 2628.30 2899.89 2628.30 2899.89 -2620.11 2480.86 2620.11 2480.86 2480.86 2620.11 2480.86 2767.13 2480.86 2767.13 -2474.87 2330.06 2474.87 2330.06 2330.06 2474.87 2330.06 2601.32 2330.06 2601.32 -2319.83 2168.34 2319.83 2168.34 2168.34 2319.83 2168.34 2446.06 2168.34 2446.06 -2174.10 1997.46 2174.10 1997.46 1997.46 2174.10 1997.46 2281.90 1997.46 2281.90 -2025.63 1839.63 2025.63 1839.63 1839.63 2025.63 1839.63 2141.72 1839.63 2141.72 -1887.12 1730.11 1887.12 1730.11 1730.11 1887.12 1730.11 2036.13 1730.11 2036.13 -1818.80 1632.05 1818.80 1632.05 1632.05 1818.80 1632.05 1955.10 1632.05 1955.10 -1764.56 1589.12 1764.56 1589.12 1589.12 1764.56 1589.12 1909.29 1589.12 1909.29 -1760.83 1588.35 1760.83 1588.35 1588.35 1760.83 1588.35 1911.87 1588.35 1911.87 -1816.52 1602.61 1816.52 1602.61 1602.61 1816.52 1602.61 1969.26 1602.61 1969.26 -1910.40 1698.49 1910.40 1698.49 1698.49 1910.40 1698.49 2051.55 1698.49 2051.55 -2030.64 1824.82 2030.64 1824.82 1824.82 2030.64 1824.82 2140.59 1824.82 2140.59 -2163.95 1971.10 2163.95 1971.10 1971.10 2163.95 1971.10 2274.44 1971.10 2274.44 -2315.82 2131.66 2315.82 2131.66 2131.66 2315.82 2131.66 2422.35 2131.66 2422.35 -2481.62 2291.11 2481.62 2291.11 2291.11 2481.62 2291.11 2573.90 2291.11 2573.90 -2643.52 2442.91 2643.52 2442.91 2442.91 2643.52 2442.91 2712.84 2442.91 2712.84 -2778.49 2566.85 2778.49 2566.85 2566.85 2778.49 2566.85 2852.13 2566.85 2852.13 -2911.96 2671.84 2911.96 2671.84 2671.84 2911.96 2671.84 2959.71 2671.84 2959.71 -2970.98 2741.65 2970.98 2741.65 2741.65 2970.98 2741.65 3013.27 2741.65 3013.27 -2999.56 2779.24 2999.56 2779.24 2779.24 2999.56 2779.24 3047.97 2779.24 3047.97 -2992.30 2778.52 2992.30 2778.52 2778.52 2992.30 2778.52 3038.19 2778.52 3038.19 -2950.12 2724.75 2950.12 2724.75 2724.75 2950.12 2724.75 2997.17 2724.75 2997.17 -2866.03 2653.59 2866.03 2653.59 2653.59 2866.03 2653.59 2908.85 2653.59 2908.85 -2737.14 2536.35 2737.14 2536.35 2536.35 2737.14 2536.35 2791.23 2536.35 2791.23 -2582.81 2384.41 2582.81 2384.41 2384.41 2582.81 2384.41 2658.53 2384.41 2658.53 -2422.87 2240.73 2422.87 2240.73 2240.73 2422.87 2240.73 2525.23 2240.73 2525.23 -2263.79 2098.89 2263.79 2098.89 2098.89 2263.79 2098.89 2366.75 2098.89 2366.75 -2115.09 1954.64 2115.09 1954.64 1954.64 2115.09 1954.64 2229.57 1954.64 2229.57 -1994.09 1830.36 1994.09 1830.36 1830.36 1994.09 1830.36 2096.58 1830.36 2096.58 -1896.38 1725.66 1896.38 1725.66 1725.66 1896.38 1725.66 1990.26 1725.66 1990.26 -1823.71 1649.70 1823.71 1649.70 1649.70 1823.71 1649.70 1933.11 1649.70 1933.11 -1785.10 1621.56 1785.10 1621.56 1621.56 1785.10 1621.56 1903.56 1621.56 1903.56 -1772.69 1624.98 1772.69 1624.98 1624.98 1772.69 1624.98 1913.34 1624.98 1913.34 -1838.90 1672.13 1838.90 1672.13 1672.13 1838.90 1672.13 1967.47 1672.13 1967.47 -1922.92 1768.10 1922.92 1768.10 1768.10 1922.92 1768.10 2046.32 1768.10 2046.32 -2049.04 1903.92 2049.04 1903.92 1903.92 2049.04 1903.92 2151.29 1903.92 2151.29 -2203.53 2059.78 2203.53 2059.78 2059.78 2203.53 2059.78 2303.12 2059.78 2303.12 -2358.46 2223.20 2358.46 2223.20 2223.20 2358.46 2223.20 2449.98 2223.20 2449.98 -2523.34 2379.37 2523.34 2379.37 2379.37 2523.34 2379.37 2606.51 2379.37 2606.51 -2675.35 2523.52 2675.35 2523.52 2523.52 2675.35 2523.52 2735.32 2523.52 2735.32 -2800.40 2654.72 2800.40 2654.72 2654.72 2800.40 2654.72 2859.45 2654.72 2859.45 -2897.39 2752.95 2897.39 2752.95 2752.95 2897.39 2752.95 2952.98 2752.95 2952.98 -2975.80 2823.59 2975.80 2823.59 2823.59 2975.80 2823.59 3035.47 2823.59 3035.47 -2994.37 2859.34 2994.37 2859.34 2859.34 2994.37 2859.34 3067.89 2859.34 3067.89 -2966.82 2852.41 2966.82 2852.41 2852.41 2966.82 2852.41 3060.02 2852.41 3060.02 -2911.39 2796.66 2911.39 2796.66 2796.66 2911.39 2796.66 3006.40 2796.66 3006.40 -2830.54 2723.34 2830.54 2723.34 2723.34 2830.54 2723.34 2919.69 2723.34 2919.69 -2703.51 2624.57 2703.51 2624.57 2624.57 2703.51 2624.57 2805.17 2624.57 2805.17 -2564.98 2484.22 2564.98 2484.22 2484.22 2564.98 2484.22 2672.04 2484.22 2672.04 -2407.09 2333.05 2407.09 2333.05 2333.05 2407.09 2333.05 2512.32 2333.05 2512.32 -2246.40 2164.52 2246.40 2164.52 2164.52 2246.40 2164.52 2357.97 2164.52 2357.97 -2109.22 2012.21 2109.22 2012.21 2012.21 2109.22 2012.21 2213.74 2012.21 2213.74 -1970.70 1890.99 1970.70 1890.99 1890.99 1970.70 1890.99 2092.75 1890.99 2092.75 -1873.40 1798.11 1873.40 1798.11 1798.11 1873.40 1798.11 2009.95 1798.11 2009.95 -1809.94 1711.52 1809.94 1711.52 1711.52 1809.94 1711.52 1929.54 1711.52 1929.54 -1788.03 1684.43 1788.03 1684.43 1684.43 1788.03 1684.43 1889.86 1684.43 1889.86 -1809.98 1709.22 1809.98 1709.22 1709.22 1809.98 1709.22 1900.94 1709.22 1900.94 -1861.32 1740.25 1861.32 1740.25 1740.25 1861.32 1740.25 1939.89 1740.25 1939.89 -1957.38 1829.44 1957.38 1829.44 1829.44 1957.38 1829.44 2020.64 1829.44 2020.64 -2086.76 1917.75 2086.76 1917.75 1917.75 2086.76 1917.75 2152.48 1917.75 2152.48 -2237.07 2060.00 2237.07 2060.00 2060.00 2237.07 2060.00 2304.77 2060.00 2304.77 -2397.67 2214.83 2397.67 2214.83 2214.83 2397.67 2214.83 2468.92 2214.83 2468.92 -2563.36 2379.02 2563.36 2379.02 2379.02 2563.36 2379.02 2631.69 2379.02 2631.69 -2711.58 2529.26 2711.58 2529.26 2529.26 2711.58 2529.26 2778.88 2529.26 2778.88 -2843.69 2668.08 2843.69 2668.08 2668.08 2843.69 2668.08 2907.08 2668.08 2907.08 -2929.37 2775.69 2929.37 2775.69 2775.69 2929.37 2775.69 3009.27 2775.69 3009.27 -3002.59 2827.44 3002.59 2827.44 2827.44 3002.59 2827.44 3077.77 2827.44 3077.77 -3024.25 2843.10 3024.25 2843.10 2843.10 3024.25 2843.10 3091.83 2843.10 3091.83 -3013.49 2825.07 3013.49 2825.07 2825.07 3013.49 2825.07 3071.47 2825.07 3071.47 -2958.02 2759.35 2958.02 2759.35 2759.35 2958.02 2759.35 3015.97 2759.35 3015.97 -2861.58 2652.73 2861.58 2652.73 2652.73 2861.58 2652.73 2919.38 2652.73 2919.38 -2741.57 2532.93 2741.57 2532.93 2532.93 2741.57 2532.93 2793.63 2532.93 2793.63 -2583.03 2385.50 2583.03 2385.50 2385.50 2583.03 2385.50 2631.33 2385.50 2631.33 -2414.56 2233.34 2414.56 2233.34 2233.34 2414.56 2233.34 2495.26 2233.34 2495.26 -2271.99 2059.77 2271.99 2059.77 2059.77 2271.99 2059.77 2316.41 2059.77 2316.41 -2125.47 1915.56 2125.47 1915.56 1915.56 2125.47 1915.56 2153.10 1915.56 2153.10 -1996.30 1784.75 1996.30 1784.75 1784.75 1996.30 1784.75 2022.97 1784.75 2022.97 -1898.75 1698.52 1898.75 1698.52 1698.52 1898.75 1698.52 1948.27 1698.52 1948.27 -1852.99 1613.80 1852.99 1613.80 1613.80 1852.99 1613.80 1884.08 1613.80 1884.08 -1843.92 1583.65 1843.92 1583.65 1583.65 1843.92 1583.65 1869.37 1583.65 1869.37 -1860.29 1615.13 1860.29 1615.13 1615.13 1860.29 1615.13 1885.55 1615.13 1885.55 -1926.81 1690.32 1926.81 1690.32 1690.32 1926.81 1690.32 1943.50 1690.32 1943.50 -2024.24 1776.19 2024.24 1776.19 1776.19 2024.24 1776.19 2039.17 1776.19 2039.17 -2168.04 1894.63 2168.04 1894.63 1894.63 2168.04 1894.63 2159.48 1894.63 2159.48 -2306.54 2025.36 2306.54 2025.36 2025.36 2306.54 2025.36 2318.53 2025.36 2318.53 -2473.71 2180.94 2473.71 2180.94 2180.94 2473.71 2180.94 2477.40 2180.94 2477.40 -2613.81 2334.82 2613.81 2334.82 2334.82 2613.81 2334.82 2629.88 2334.82 2629.88 -2766.96 2474.69 2766.96 2474.69 2474.69 2766.96 2474.69 2780.28 2474.69 2780.28 -2874.61 2582.92 2874.61 2582.92 2582.92 2874.61 2582.92 2889.55 2582.92 2889.55 -2967.21 2666.37 2967.21 2666.37 2666.37 2967.21 2666.37 2988.65 2666.37 2988.65 -3031.33 2711.99 3031.33 2711.99 2711.99 3031.33 2711.99 3039.53 2711.99 3039.53 -3038.21 2722.99 3038.21 2722.99 2722.99 3038.21 2722.99 3054.85 2722.99 3054.85 -3020.62 2693.15 3020.62 2693.15 2693.15 3020.62 2693.15 3038.90 2693.15 3038.90 -2950.51 2623.17 2950.51 2623.17 2623.17 2950.51 2623.17 2967.28 2623.17 2967.28 -2858.58 2521.50 2858.58 2521.50 2521.50 2858.58 2521.50 2853.13 2521.50 2853.13 -2733.81 2392.59 2733.81 2392.59 2392.59 2733.81 2392.59 2707.88 2392.59 2707.88 -2591.53 2243.01 2591.53 2243.01 2243.01 2591.53 2243.01 2546.82 2243.01 2546.82 -2432.70 2061.42 2432.70 2061.42 2061.42 2432.70 2061.42 2399.29 2061.42 2399.29 -2264.65 1923.93 2264.65 1923.93 1923.93 2264.65 1923.93 2249.86 1923.93 2249.86 -2127.75 1777.63 2127.75 1777.63 1777.63 2127.75 1777.63 2124.58 1777.63 2124.58 -2008.22 1654.56 2008.22 1654.56 1654.56 2008.22 1654.56 2012.72 1654.56 2012.72 -1923.56 1565.31 1923.56 1565.31 1565.31 1923.56 1565.31 1924.60 1565.31 1924.60 -1859.64 1524.30 1859.64 1524.30 1524.30 1859.64 1524.30 1871.60 1524.30 1871.60 -1861.92 1506.45 1861.92 1506.45 1506.45 1861.92 1506.45 1847.07 1506.45 1847.07 -1900.61 1548.93 1900.61 1548.93 1548.93 1900.61 1548.93 1876.20 1548.93 1876.20 -1961.13 1600.04 1961.13 1600.04 1600.04 1961.13 1600.04 1937.80 1600.04 1937.80 +1908.05 1908.05 1908.05 1870.54 1892.77 1892.77 1870.54 1870.54 1892.77 1892.77 +2012.52 2012.52 2012.52 1961.25 1997.24 1997.24 1961.25 1961.25 1997.24 1997.24 +2133.51 2133.51 2133.51 2090.88 2120.16 2120.16 2090.88 2090.88 2120.16 2120.16 +2285.14 2285.14 2285.14 2233.14 2272.44 2272.44 2233.14 2233.14 2272.44 2272.44 +2444.00 2444.00 2444.00 2402.52 2431.04 2431.04 2402.52 2402.52 2431.04 2431.04 +2600.96 2600.96 2600.96 2568.98 2591.21 2591.21 2568.98 2568.98 2591.21 2591.21 +2737.59 2737.59 2737.59 2709.74 2735.44 2735.44 2709.74 2709.74 2735.44 2735.44 +2858.64 2858.64 2858.64 2828.35 2869.90 2869.90 2828.35 2828.35 2869.90 2869.90 +2963.10 2963.10 2963.10 2917.84 2972.34 2972.34 2917.84 2917.84 2972.34 2972.34 +3013.65 3013.65 3013.65 2953.83 3017.28 3017.28 2953.83 2953.83 3017.28 3017.28 +3029.79 3029.79 3029.79 2939.92 3031.78 3031.78 2939.92 2939.92 3031.78 3031.78 +2993.99 2993.99 2993.99 2921.50 3002.03 3002.03 2921.50 2921.50 3002.03 3002.03 +2921.57 2921.57 2921.57 2842.98 2923.02 2923.02 2842.98 2842.98 2923.02 2923.02 +2819.41 2819.41 2819.41 2747.39 2804.22 2804.22 2747.39 2747.39 2804.22 2804.22 +2676.43 2676.43 2676.43 2631.25 2671.87 2671.87 2631.25 2631.25 2671.87 2671.87 +2510.71 2510.71 2510.71 2479.39 2501.44 2501.44 2479.39 2479.39 2501.44 2501.44 +2349.13 2349.13 2349.13 2327.08 2339.45 2339.45 2327.08 2327.08 2339.45 2339.45 +2207.88 2207.88 2207.88 2162.28 2166.25 2166.25 2162.28 2162.28 2166.25 2166.25 +2084.78 2084.78 2084.78 2005.61 2015.97 2015.97 2005.61 2005.61 2015.97 2015.97 +1943.89 1943.89 1943.89 1893.71 1902.55 1902.55 1893.71 1893.71 1902.55 1902.55 +1891.72 1891.72 1891.72 1812.48 1828.83 1828.83 1812.48 1812.48 1828.83 1828.83 +1841.02 1841.02 1841.02 1770.39 1785.39 1785.39 1770.39 1770.39 1785.39 1785.39 +1824.47 1824.47 1824.47 1757.92 1770.07 1770.07 1757.92 1757.92 1770.07 1770.07 +1836.77 1836.77 1836.77 1782.36 1815.20 1815.20 1782.36 1782.36 1815.20 1815.20 +1930.39 1930.39 1930.39 1846.49 1886.00 1886.00 1846.49 1846.49 1886.00 1886.00 +2049.40 2049.40 2049.40 1939.19 1992.21 1992.21 1939.19 1939.19 1992.21 1992.21 +2193.46 2193.46 2193.46 2093.11 2120.59 2120.59 2093.11 2093.11 2120.59 2120.59 +2335.41 2335.41 2335.41 2247.79 2276.43 2276.43 2247.79 2247.79 2276.43 2276.43 +2492.27 2492.27 2492.27 2408.73 2437.89 2437.89 2408.73 2408.73 2437.89 2437.89 +2644.85 2644.85 2644.85 2552.64 2597.32 2597.32 2552.64 2552.64 2597.32 2597.32 +2784.04 2784.04 2784.04 2691.13 2715.05 2715.05 2691.13 2691.13 2715.05 2715.05 +2899.15 2899.15 2899.15 2812.87 2850.51 2850.51 2812.87 2812.87 2850.51 2850.51 +2999.86 2999.86 2999.86 2892.42 2927.95 2927.95 2892.42 2892.42 2927.95 2927.95 +3046.08 3046.08 3046.08 2919.92 3001.70 3001.70 2919.92 2919.92 3001.70 3001.70 +3054.29 3054.29 3054.29 2926.85 3004.76 3004.76 2926.85 2926.85 3004.76 3004.76 +3022.87 3022.87 3022.87 2901.21 2975.62 2975.62 2901.21 2901.21 2975.62 2975.62 +2959.15 2959.15 2959.15 2850.80 2896.69 2896.69 2850.80 2850.80 2896.69 2896.69 +2861.23 2861.23 2861.23 2761.16 2792.88 2792.88 2761.16 2761.16 2792.88 2792.88 +2726.70 2726.70 2726.70 2614.33 2675.09 2675.09 2614.33 2614.33 2675.09 2675.09 +2563.16 2563.16 2563.16 2439.90 2513.62 2513.62 2439.90 2439.90 2513.62 2513.62 +2395.17 2395.17 2395.17 2264.74 2359.81 2359.81 2264.74 2264.74 2359.81 2359.81 +2232.18 2232.18 2232.18 2091.16 2209.69 2209.69 2091.16 2091.16 2209.69 2209.69 +2078.31 2078.31 2078.31 1945.26 2067.89 2067.89 1945.26 1945.26 2067.89 2067.89 +1978.77 1978.77 1978.77 1838.90 1953.38 1953.38 1838.90 1838.90 1953.38 1953.38 +1905.31 1905.31 1905.31 1749.40 1880.70 1880.70 1749.40 1749.40 1880.70 1880.70 +1857.46 1857.46 1857.46 1713.01 1860.72 1860.72 1713.01 1713.01 1860.72 1860.72 +1859.25 1859.25 1859.25 1704.93 1845.70 1845.70 1704.93 1704.93 1845.70 1845.70 +1894.57 1894.57 1894.57 1741.38 1882.53 1882.53 1741.38 1741.38 1882.53 1882.53 +1964.08 1964.08 1964.08 1838.33 1972.65 1972.65 1838.33 1838.33 1972.65 1972.65 +2072.80 2072.80 2072.80 1947.21 2092.02 2092.02 1947.21 1947.21 2092.02 2092.02 +2199.69 2199.69 2199.69 2073.72 2228.45 2228.45 2073.72 2073.72 2228.45 2228.45 +2372.75 2372.75 2372.75 2221.77 2384.52 2384.52 2221.77 2221.77 2384.52 2384.52 +2522.68 2522.68 2522.68 2381.96 2543.62 2543.62 2381.96 2381.96 2543.62 2543.62 +2679.24 2679.24 2679.24 2543.70 2698.85 2698.85 2543.70 2543.70 2698.85 2698.85 +2810.15 2810.15 2810.15 2668.90 2833.08 2833.08 2668.90 2668.90 2833.08 2833.08 +2936.81 2936.81 2936.81 2773.16 2942.97 2942.97 2773.16 2773.16 2942.97 2942.97 +3012.89 3012.89 3012.89 2855.24 3020.97 3020.97 2855.24 2855.24 3020.97 3020.97 +3055.09 3055.09 3055.09 2899.04 3062.67 3062.67 2899.04 2899.04 3062.67 3062.67 +3064.05 3064.05 3064.05 2916.91 3063.46 3063.46 2916.91 2916.91 3063.46 3063.46 +3001.11 3001.11 3001.11 2885.09 3012.39 3012.39 2885.09 2885.09 3012.39 3012.39 +2923.14 2923.14 2923.14 2814.79 2938.38 2938.38 2814.79 2814.79 2938.38 2938.38 +2814.20 2814.20 2814.20 2701.74 2823.22 2823.22 2701.74 2701.74 2823.22 2823.22 +2684.86 2684.86 2684.86 2574.39 2670.75 2670.75 2574.39 2574.39 2670.75 2670.75 +2519.30 2519.30 2519.30 2426.07 2501.89 2501.89 2426.07 2426.07 2501.89 2501.89 +2360.65 2360.65 2360.65 2285.79 2322.11 2322.11 2285.79 2285.79 2322.11 2322.11 +2203.31 2203.31 2203.31 2144.22 2158.13 2158.13 2144.22 2144.22 2158.13 2158.13 +2067.24 2067.24 2067.24 1986.96 2016.30 2016.30 1986.96 1986.96 2016.30 2016.30 +1956.10 1956.10 1956.10 1883.36 1912.03 1912.03 1883.36 1883.36 1912.03 1912.03 +1882.82 1882.82 1882.82 1824.41 1832.60 1832.60 1824.41 1824.41 1832.60 1832.60 +1858.20 1858.20 1858.20 1777.72 1794.19 1794.19 1777.72 1777.72 1794.19 1794.19 +1859.87 1859.87 1859.87 1789.68 1808.15 1808.15 1789.68 1789.68 1808.15 1808.15 +1894.69 1894.69 1894.69 1845.15 1855.51 1855.51 1845.15 1845.15 1855.51 1855.51 +1977.73 1977.73 1977.73 1942.70 1956.10 1956.10 1942.70 1942.70 1956.10 1956.10 +2102.27 2102.27 2102.27 2054.45 2077.69 2077.69 2054.45 2054.45 2077.69 2077.69 +2222.90 2222.90 2222.90 2190.98 2210.99 2210.99 2190.98 2190.98 2210.99 2210.99 +2379.26 2379.26 2379.26 2341.59 2347.62 2347.62 2341.59 2341.59 2347.62 2347.62 +2535.73 2535.73 2535.73 2480.75 2509.67 2509.67 2480.75 2480.75 2509.67 2509.67 +2690.52 2690.52 2690.52 2626.09 2671.42 2671.42 2626.09 2626.09 2671.42 2671.42 +2832.66 2832.66 2832.66 2764.84 2815.14 2815.14 2764.84 2764.84 2815.14 2815.14 +2949.88 2949.88 2949.88 2875.68 2900.13 2900.13 2875.68 2875.68 2900.13 2900.13 +3019.84 3019.84 3019.84 2942.42 2971.13 2971.13 2942.42 2942.42 2971.13 2971.13 +3046.67 3046.67 3046.67 2991.28 3006.18 3006.18 2991.28 2991.28 3006.18 3006.18 +3043.58 3043.58 3043.58 2968.43 3010.01 3010.01 2968.43 2968.43 3010.01 3010.01 +3000.04 3000.04 3000.04 2919.63 2954.25 2954.25 2919.63 2919.63 2954.25 2954.25 +2909.18 2909.18 2909.18 2863.42 2874.74 2874.74 2863.42 2863.42 2874.74 2874.74 +2800.70 2800.70 2800.70 2759.28 2758.96 2758.96 2759.28 2759.28 2758.96 2758.96 +2645.23 2645.23 2645.23 2634.87 2630.35 2630.35 2634.87 2634.87 2630.35 2630.35 +2495.73 2495.73 2495.73 2476.47 2458.90 2458.90 2476.47 2476.47 2458.90 2458.90 +2333.89 2333.89 2333.89 2318.83 2295.85 2295.85 2318.83 2318.83 2295.85 2295.85 +2192.51 2192.51 2192.51 2183.04 2156.16 2156.16 2183.04 2183.04 2156.16 2156.16 +2080.81 2080.81 2080.81 2052.24 2016.16 2016.16 2052.24 2052.24 2016.16 2016.16 +1977.03 1977.03 1977.03 1950.10 1916.95 1916.95 1950.10 1950.10 1916.95 1916.95 +1924.10 1924.10 1924.10 1887.52 1836.62 1836.62 1887.52 1887.52 1836.62 1836.62 +1895.67 1895.67 1895.67 1862.32 1789.03 1789.03 1862.32 1862.32 1789.03 1789.03 +1909.62 1909.62 1909.62 1864.17 1827.11 1827.11 1864.17 1864.17 1827.11 1827.11 +1964.41 1964.41 1964.41 1910.25 1878.72 1878.72 1910.25 1910.25 1878.72 1878.72 +2045.32 2045.32 2045.32 2002.67 1961.72 1961.72 2002.67 2002.67 1961.72 1961.72 +2165.86 2165.86 2165.86 2135.69 2063.29 2063.29 2135.69 2135.69 2063.29 2063.29 +2334.40 2334.40 2334.40 2272.76 2201.11 2201.11 2272.76 2272.76 2201.11 2201.11 +2476.26 2476.26 2476.26 2420.83 2363.33 2363.33 2420.83 2420.83 2363.33 2363.33 +2623.99 2623.99 2623.99 2579.58 2495.70 2495.70 2579.58 2579.58 2495.70 2495.70 +2803.36 2803.36 2803.36 2734.40 2631.18 2631.18 2734.40 2734.40 2631.18 2631.18 +2931.59 2931.59 2931.59 2869.07 2761.26 2761.26 2869.07 2869.07 2761.26 2761.26 +3042.64 3042.64 3042.64 2980.04 2858.77 2858.77 2980.04 2980.04 2858.77 2858.77 +3123.06 3123.06 3123.06 3044.12 2936.28 2936.28 3044.12 3044.12 2936.28 2936.28 +3136.83 3136.83 3136.83 3082.07 2967.14 2967.14 3082.07 3082.07 2967.14 2967.14 +3124.21 3124.21 3124.21 3075.30 2954.96 2954.96 3075.30 3075.30 2954.96 2954.96 +3078.40 3078.40 3078.40 3028.11 2890.30 2890.30 3028.11 3028.11 2890.30 2890.30 +2981.82 2981.82 2981.82 2938.48 2808.43 2808.43 2938.48 2938.48 2808.43 2808.43 +2855.72 2855.72 2855.72 2814.85 2678.33 2678.33 2814.85 2814.85 2678.33 2678.33 +2706.56 2706.56 2706.56 2672.21 2525.66 2525.66 2672.21 2672.21 2525.66 2525.66 +2533.76 2533.76 2533.76 2513.78 2368.72 2368.72 2513.78 2513.78 2368.72 2368.72 +2358.44 2358.44 2358.44 2353.45 2218.73 2218.73 2353.45 2353.45 2218.73 2218.73 +2202.22 2202.22 2202.22 2204.23 2057.80 2057.80 2204.23 2204.23 2057.80 2057.80 +2095.41 2095.41 2095.41 2068.71 1912.40 1912.40 2068.71 2068.71 1912.40 1912.40 +2007.11 2007.11 2007.11 1959.86 1824.09 1824.09 1959.86 1959.86 1824.09 1824.09 +1938.62 1938.62 1938.62 1894.81 1766.48 1766.48 1894.81 1894.81 1766.48 1766.48 +1903.92 1903.92 1903.92 1874.52 1747.94 1747.94 1874.52 1874.52 1747.94 1747.94 +1909.84 1909.84 1909.84 1878.54 1772.56 1772.56 1878.54 1878.54 1772.56 1772.56 +1988.40 1988.40 1988.40 1930.77 1833.43 1833.43 1930.77 1930.77 1833.43 1833.43 +2079.40 2079.40 2079.40 2006.52 1907.07 1907.07 2006.52 2006.52 1907.07 1907.07 +2205.74 2205.74 2205.74 2140.45 2016.19 2016.19 2140.45 2140.45 2016.19 2016.19 +2346.21 2346.21 2346.21 2301.01 2149.52 2149.52 2301.01 2301.01 2149.52 2149.52 +2516.46 2516.46 2516.46 2462.34 2299.97 2299.97 2462.34 2462.34 2299.97 2299.97 +2671.67 2671.67 2671.67 2629.76 2463.45 2463.45 2629.76 2629.76 2463.45 2463.45 +2830.99 2830.99 2830.99 2770.23 2608.80 2608.80 2770.23 2770.23 2608.80 2608.80 +2954.04 2954.04 2954.04 2899.93 2731.90 2731.90 2899.93 2899.93 2731.90 2731.90 +3059.85 3059.85 3059.85 3008.33 2824.24 2824.24 3008.33 3008.33 2824.24 2824.24 +3133.31 3133.31 3133.31 3069.95 2891.06 2891.06 3069.95 3069.95 2891.06 2891.06 +3158.83 3158.83 3158.83 3101.11 2910.90 2910.90 3101.11 3101.11 2910.90 2910.90 +3146.50 3146.50 3146.50 3084.59 2892.89 2892.89 3084.59 3084.59 2892.89 2892.89 +3086.11 3086.11 3086.11 3016.66 2830.61 2830.61 3016.66 3016.66 2830.61 2830.61 +2980.57 2980.57 2980.57 2922.83 2736.31 2736.31 2922.83 2922.83 2736.31 2736.31 +2859.46 2859.46 2859.46 2807.30 2626.39 2626.39 2807.30 2807.30 2626.39 2626.39 +2715.46 2715.46 2715.46 2670.65 2479.95 2479.95 2670.65 2670.65 2479.95 2479.95 +2556.59 2556.59 2556.59 2523.13 2341.82 2341.82 2523.13 2523.13 2341.82 2341.82 +2396.24 2396.24 2396.24 2352.06 2172.33 2172.33 2352.06 2352.06 2172.33 2172.33 +2260.00 2260.00 2260.00 2200.68 2027.15 2027.15 2200.68 2200.68 2027.15 2027.15 +2126.80 2126.80 2126.80 2091.81 1887.84 1887.84 2091.81 2091.81 1887.84 1887.84 +2026.29 2026.29 2026.29 1997.22 1817.55 1817.55 1997.22 1997.22 1817.55 1817.55 +1972.18 1972.18 1972.18 1929.53 1761.80 1761.80 1929.53 1929.53 1761.80 1761.80 +1941.33 1941.33 1941.33 1913.59 1730.68 1730.68 1913.59 1913.59 1730.68 1730.68 +1955.04 1955.04 1955.04 1929.60 1753.14 1753.14 1929.60 1929.60 1753.14 1753.14 +2011.43 2011.43 2011.43 1998.06 1816.15 1816.15 1998.06 1998.06 1816.15 1816.15 +2101.48 2101.48 2101.48 2100.49 1920.50 1920.50 2100.49 2100.49 1920.50 1920.50 +2225.10 2225.10 2225.10 2219.76 2043.41 2043.41 2219.76 2219.76 2043.41 2043.41 +2355.80 2355.80 2355.80 2367.78 2186.10 2186.10 2367.78 2367.78 2186.10 2186.10 +2533.89 2533.89 2533.89 2542.87 2357.13 2357.13 2542.87 2542.87 2357.13 2357.13 +2682.52 2682.52 2682.52 2714.59 2517.78 2517.78 2714.59 2714.59 2517.78 2517.78 +2832.54 2832.54 2832.54 2864.43 2665.78 2665.78 2864.43 2864.43 2665.78 2665.78 +2958.71 2958.71 2958.71 2979.44 2782.88 2782.88 2979.44 2979.44 2782.88 2782.88 +3054.75 3054.75 3054.75 3060.66 2869.50 2869.50 3060.66 3060.66 2869.50 2869.50 +3116.92 3116.92 3116.92 3120.95 2937.56 2937.56 3120.95 3120.95 2937.56 2937.56 +3143.27 3143.27 3143.27 3141.30 2947.73 2947.73 3141.30 3141.30 2947.73 2947.73 +3103.98 3103.98 3103.98 3122.57 2920.77 2920.77 3122.57 3122.57 2920.77 2920.77 +3046.62 3046.62 3046.62 3032.37 2871.91 2871.91 3032.37 3032.37 2871.91 2871.91 +2941.35 2941.35 2941.35 2944.06 2773.36 2773.36 2944.06 2944.06 2773.36 2773.36 +2809.82 2809.82 2809.82 2820.26 2653.49 2653.49 2820.26 2820.26 2653.49 2653.49 +2658.20 2658.20 2658.20 2669.85 2515.29 2515.29 2669.85 2669.85 2515.29 2515.29 +2486.86 2486.86 2486.86 2529.41 2356.68 2356.68 2529.41 2529.41 2356.68 2356.68 +2340.10 2340.10 2340.10 2372.87 2185.73 2185.73 2372.87 2372.87 2185.73 2185.73 +2205.78 2205.78 2205.78 2221.26 2045.99 2045.99 2221.26 2221.26 2045.99 2045.99 +2100.55 2100.55 2100.55 2091.65 1925.09 1925.09 2091.65 2091.65 1925.09 1925.09 +2012.14 2012.14 2012.14 1991.29 1831.25 1831.25 1991.29 1991.29 1831.25 1831.25 +1957.65 1957.65 1957.65 1941.86 1788.00 1788.00 1941.86 1941.86 1788.00 1788.00 +1926.33 1926.33 1926.33 1940.33 1777.90 1777.90 1940.33 1940.33 1777.90 1777.90 +1949.91 1949.91 1949.91 1972.04 1808.61 1808.61 1972.04 1972.04 1808.61 1808.61 +2007.24 2007.24 2007.24 2038.24 1866.28 1866.28 2038.24 2038.24 1866.28 1866.28 diff --git a/examples/Begin Stochastic/load_D.csv b/examples/Begin Stochastic/load_D.csv index 5455237..154cb57 100644 --- a/examples/Begin Stochastic/load_D.csv +++ b/examples/Begin Stochastic/load_D.csv @@ -1,168 +1,168 @@ -648.31 618.43 648.31 618.43 618.43 648.31 618.43 626.76 618.43 626.76 -673.12 658.97 673.12 658.97 658.97 673.12 658.97 656.00 658.97 656.00 -713.92 707.12 713.92 707.12 707.12 713.92 707.12 706.92 707.12 706.92 -748.87 773.22 748.87 773.22 773.22 748.87 773.22 742.27 773.22 742.27 -806.33 825.05 806.33 825.05 825.05 806.33 825.05 795.75 825.05 795.75 -842.64 866.46 842.64 866.46 866.46 842.64 866.46 844.85 866.46 844.85 -879.84 934.83 879.84 934.83 934.83 879.84 934.83 897.94 934.83 897.94 -926.73 976.48 926.73 976.48 976.48 926.73 976.48 949.88 976.48 949.88 -958.01 1008.53 958.01 1008.53 1008.53 958.01 1008.53 980.23 1008.53 980.23 -978.68 1032.09 978.68 1032.09 1032.09 978.68 1032.09 990.70 1032.09 990.70 -990.88 1041.61 990.88 1041.61 1041.61 990.88 1041.61 996.48 1041.61 996.48 -978.31 1025.08 978.31 1025.08 1025.08 978.31 1025.08 981.65 1025.08 981.65 -944.97 1005.82 944.97 1005.82 1005.82 944.97 1005.82 951.00 1005.82 951.00 -896.14 970.37 896.14 970.37 970.37 896.14 970.37 925.54 970.37 925.54 -843.01 916.97 843.01 916.97 916.97 843.01 916.97 892.77 916.97 892.77 -794.89 896.67 794.89 896.67 896.67 794.89 896.67 845.47 896.67 845.47 -761.94 838.40 761.94 838.40 838.40 761.94 838.40 786.42 838.40 786.42 -702.42 780.65 702.42 780.65 780.65 702.42 780.65 712.84 780.65 712.84 -669.95 732.09 669.95 732.09 732.09 669.95 732.09 664.22 732.09 664.22 -627.23 714.60 627.23 714.60 714.60 627.23 714.60 633.53 714.60 633.53 -598.09 698.76 598.09 698.76 698.76 598.09 698.76 612.77 698.76 612.77 -576.19 673.92 576.19 673.92 673.92 576.19 673.92 589.43 673.92 589.43 -567.39 655.31 567.39 655.31 655.31 567.39 655.31 590.67 655.31 590.67 -566.28 685.31 566.28 685.31 685.31 566.28 685.31 608.47 685.31 608.47 -585.94 705.79 585.94 705.79 705.79 585.94 705.79 621.67 705.79 621.67 -639.05 729.49 639.05 729.49 729.49 639.05 729.49 644.35 729.49 644.35 -690.75 778.49 690.75 778.49 778.49 690.75 778.49 684.56 778.49 684.56 -746.53 826.50 746.53 826.50 826.50 746.53 826.50 739.40 826.50 739.40 -794.22 880.08 794.22 880.08 880.08 794.22 880.08 792.54 880.08 792.54 -836.82 932.07 836.82 932.07 932.07 836.82 932.07 839.31 932.07 839.31 -890.18 979.49 890.18 979.49 979.49 890.18 979.49 885.05 979.49 885.05 -925.25 1011.35 925.25 1011.35 1011.35 925.25 1011.35 924.96 1011.35 924.96 -947.75 1025.06 947.75 1025.06 1025.06 947.75 1025.06 958.55 1025.06 958.55 -961.08 1047.84 961.08 1047.84 1047.84 961.08 1047.84 973.70 1047.84 973.70 -956.44 1055.93 956.44 1055.93 1055.93 956.44 1055.93 971.98 1055.93 971.98 -953.97 1031.79 953.97 1031.79 1031.79 953.97 1031.79 986.54 1031.79 986.54 -936.20 1011.78 936.20 1011.78 1011.78 936.20 1011.78 962.49 1011.78 962.49 -912.91 977.59 912.91 977.59 977.59 912.91 977.59 922.70 977.59 922.70 -863.73 915.76 863.73 915.76 915.76 863.73 915.76 848.73 915.76 848.73 -801.48 861.74 801.48 861.74 861.74 801.48 861.74 798.43 861.74 798.43 -746.85 806.77 746.85 806.77 806.77 746.85 806.77 747.24 806.77 747.24 -696.47 761.86 696.47 761.86 761.86 696.47 761.86 679.01 761.86 679.01 -651.69 705.83 651.69 705.83 705.83 651.69 705.83 635.02 705.83 635.02 -602.14 687.06 602.14 687.06 687.06 602.14 687.06 597.95 687.06 597.95 -577.72 655.70 577.72 655.70 655.70 577.72 655.70 564.31 655.70 564.31 -562.52 645.60 562.52 645.60 645.60 562.52 645.60 536.94 645.60 536.94 -544.06 649.27 544.06 649.27 649.27 544.06 649.27 544.97 649.27 544.97 -569.96 658.23 569.96 658.23 658.23 569.96 658.23 555.71 658.23 555.71 -605.29 689.58 605.29 689.58 689.58 605.29 689.58 597.66 689.58 597.66 -649.55 724.38 649.55 724.38 724.38 649.55 724.38 641.02 724.38 641.02 -672.82 768.11 672.82 768.11 768.11 672.82 768.11 692.88 768.11 692.88 -724.38 832.55 724.38 832.55 832.55 724.38 832.55 731.44 832.55 731.44 -776.68 876.38 776.68 876.38 876.38 776.68 876.38 758.71 876.38 758.71 -814.78 944.34 814.78 944.34 944.34 814.78 944.34 809.32 944.34 809.32 -859.49 989.15 859.49 989.15 989.15 859.49 989.15 859.74 989.15 859.74 -915.67 1039.34 915.67 1039.34 1039.34 915.67 1039.34 889.17 1039.34 889.17 -920.43 1061.20 920.43 1061.20 1061.20 920.43 1061.20 918.76 1061.20 918.76 -931.46 1071.00 931.46 1071.00 1071.00 931.46 1071.00 939.89 1071.00 939.89 -923.83 1061.53 923.83 1061.53 1061.53 923.83 1061.53 925.37 1061.53 925.37 -917.34 1058.82 917.34 1058.82 1058.82 917.34 1058.82 915.65 1058.82 915.65 -874.40 1039.64 874.40 1039.64 1039.64 874.40 1039.64 902.37 1039.64 902.37 -826.42 1011.42 826.42 1011.42 1011.42 826.42 1011.42 877.20 1011.42 877.20 -790.03 968.60 790.03 968.60 968.60 790.03 968.60 831.09 968.60 831.09 -744.31 934.04 744.31 934.04 934.04 744.31 934.04 783.94 934.04 783.94 -686.62 893.34 686.62 893.34 893.34 686.62 893.34 721.27 893.34 721.27 -633.43 857.63 633.43 857.63 857.63 633.43 857.63 675.17 857.63 675.17 -581.66 826.53 581.66 826.53 826.53 581.66 826.53 623.41 826.53 623.41 -552.49 785.98 552.49 785.98 785.98 552.49 785.98 589.71 785.98 589.71 -527.68 755.43 527.68 755.43 755.43 527.68 755.43 563.06 755.43 563.06 -531.43 735.79 531.43 735.79 735.79 531.43 735.79 545.54 735.79 545.54 -518.28 755.38 518.28 755.38 755.38 518.28 755.38 544.76 755.38 544.76 -526.93 755.81 526.93 755.81 755.81 526.93 755.81 579.47 755.81 579.47 -578.74 794.38 578.74 794.38 794.38 578.74 794.38 616.86 794.38 616.86 -636.96 827.05 636.96 827.05 827.05 636.96 827.05 644.67 827.05 644.67 -690.17 876.94 690.17 876.94 876.94 690.17 876.94 696.39 876.94 696.39 -729.07 912.55 729.07 912.55 912.55 729.07 912.55 744.96 912.55 744.96 -773.83 973.21 773.83 973.21 973.21 773.83 973.21 801.68 973.21 801.68 -820.06 1013.54 820.06 1013.54 1013.54 820.06 1013.54 831.55 1013.54 831.55 -845.08 1050.23 845.08 1050.23 1050.23 845.08 1050.23 881.38 1050.23 881.38 -863.99 1101.67 863.99 1101.67 1101.67 863.99 1101.67 918.21 1101.67 918.21 -888.33 1118.60 888.33 1118.60 1118.60 888.33 1118.60 950.34 1118.60 950.34 -886.80 1125.70 886.80 1125.70 1125.70 886.80 1125.70 967.51 1125.70 967.51 -883.22 1128.42 883.22 1128.42 1128.42 883.22 1128.42 970.30 1128.42 970.30 -875.88 1097.22 875.88 1097.22 1097.22 875.88 1097.22 942.12 1097.22 942.12 -839.97 1078.13 839.97 1078.13 1078.13 839.97 1078.13 932.06 1078.13 932.06 -806.64 1051.64 806.64 1051.64 1051.64 806.64 1051.64 896.19 1051.64 896.19 -754.84 1015.24 754.84 1015.24 1015.24 754.84 1015.24 857.31 1015.24 857.31 -720.66 960.92 720.66 960.92 960.92 720.66 960.92 798.28 960.92 798.28 -656.44 909.61 656.44 909.61 909.61 656.44 909.61 729.92 909.61 729.92 -598.83 874.00 598.83 874.00 874.00 598.83 874.00 696.28 874.00 696.28 -565.53 839.67 565.53 839.67 839.67 565.53 839.67 655.86 839.67 655.86 -529.23 809.11 529.23 809.11 809.11 529.23 809.11 628.50 809.11 628.50 -508.85 791.55 508.85 791.55 791.55 508.85 791.55 617.65 791.55 617.65 -508.08 800.68 508.08 800.68 800.68 508.08 800.68 609.70 800.68 609.70 -508.39 791.05 508.39 791.05 791.05 508.39 791.05 608.45 791.05 608.45 -518.23 809.42 518.23 809.42 809.42 518.23 809.42 622.35 809.42 622.35 -543.12 843.18 543.12 843.18 843.18 543.12 843.18 655.72 843.18 655.72 -576.27 882.87 576.27 882.87 882.87 576.27 882.87 697.47 882.87 697.47 -631.26 931.12 631.26 931.12 931.12 631.26 931.12 756.58 931.12 756.58 -667.26 992.00 667.26 992.00 992.00 667.26 992.00 816.04 992.00 816.04 -716.70 1031.49 716.70 1031.49 1031.49 716.70 1031.49 864.55 1031.49 864.55 -768.79 1076.00 768.79 1076.00 1076.00 768.79 1076.00 924.21 1076.00 924.21 -831.70 1118.80 831.70 1118.80 1118.80 831.70 1118.80 967.42 1118.80 967.42 -858.38 1151.92 858.38 1151.92 1151.92 858.38 1151.92 1012.33 1151.92 1012.33 -884.13 1182.60 884.13 1182.60 1182.60 884.13 1182.60 1027.17 1182.60 1027.17 -889.68 1189.80 889.68 1189.80 1189.80 889.68 1189.80 1026.19 1189.80 1026.19 -877.54 1174.84 877.54 1174.84 1174.84 877.54 1174.84 1019.15 1174.84 1019.15 -876.11 1161.94 876.11 1161.94 1161.94 876.11 1161.94 987.09 1161.94 987.09 -836.25 1132.17 836.25 1132.17 1132.17 836.25 1132.17 950.97 1132.17 950.97 -808.01 1089.60 808.01 1089.60 1089.60 808.01 1089.60 931.45 1089.60 931.45 -757.11 1032.60 757.11 1032.60 1032.60 757.11 1032.60 899.77 1032.60 899.77 -702.08 989.42 702.08 989.42 989.42 702.08 989.42 848.04 989.42 848.04 -645.93 936.91 645.93 936.91 936.91 645.93 936.91 794.82 936.91 794.82 -596.99 900.28 596.99 900.28 900.28 596.99 900.28 750.28 900.28 750.28 -561.86 867.07 561.86 867.07 867.07 561.86 867.07 707.81 867.07 707.81 -527.52 838.00 527.52 838.00 838.00 527.52 838.00 688.22 838.00 688.22 -521.70 812.54 521.70 812.54 812.54 521.70 812.54 661.83 812.54 661.83 -519.88 801.33 519.88 801.33 801.33 519.88 801.33 635.76 801.33 635.76 -527.44 811.72 527.44 811.72 811.72 527.44 811.72 653.35 811.72 653.35 -542.01 837.65 542.01 837.65 837.65 542.01 837.65 673.37 837.65 673.37 -570.29 880.94 570.29 880.94 880.94 570.29 880.94 707.30 880.94 707.30 -602.33 925.14 602.33 925.14 925.14 602.33 925.14 738.00 925.14 738.00 -661.38 976.76 661.38 976.76 976.76 661.38 976.76 780.25 976.76 780.25 -714.32 1032.71 714.32 1032.71 1032.71 714.32 1032.71 833.16 1032.71 833.16 -752.77 1077.92 752.77 1077.92 1077.92 752.77 1077.92 875.69 1077.92 875.69 -816.89 1129.33 816.89 1129.33 1129.33 816.89 1129.33 930.66 1129.33 930.66 -864.53 1179.06 864.53 1179.06 1179.06 864.53 1179.06 971.35 1179.06 971.35 -905.30 1230.09 905.30 1230.09 1230.09 905.30 1230.09 981.66 1230.09 981.66 -930.10 1242.31 930.10 1242.31 1242.31 930.10 1242.31 981.37 1242.31 981.37 -938.25 1251.84 938.25 1251.84 1251.84 938.25 1251.84 992.26 1251.84 992.26 -936.11 1253.21 936.11 1253.21 1253.21 936.11 1253.21 1004.27 1253.21 1004.27 -896.25 1233.27 896.25 1233.27 1233.27 896.25 1233.27 1005.96 1233.27 1005.96 -869.79 1220.82 869.79 1220.82 1220.82 869.79 1220.82 987.45 1220.82 987.45 -824.06 1195.71 824.06 1195.71 1195.71 824.06 1195.71 938.88 1195.71 938.88 -782.23 1162.84 782.23 1162.84 1162.84 782.23 1162.84 903.50 1162.84 903.50 -714.19 1093.00 714.19 1093.00 1093.00 714.19 1093.00 837.16 1093.00 837.16 -663.20 1025.77 663.20 1025.77 1025.77 663.20 1025.77 785.49 1025.77 785.49 -643.61 985.95 643.61 985.95 985.95 643.61 985.95 753.10 985.95 753.10 -606.01 960.57 606.01 960.57 960.57 606.01 960.57 707.32 960.57 707.32 -578.99 934.84 578.99 934.84 934.84 578.99 934.84 668.93 934.84 668.93 -555.67 913.33 555.67 913.33 913.33 555.67 913.33 654.65 913.33 654.65 -553.26 917.58 553.26 917.58 917.58 553.26 917.58 632.72 917.58 632.72 -561.44 918.00 561.44 918.00 918.00 561.44 918.00 638.03 918.00 638.03 -589.64 928.33 589.64 928.33 928.33 589.64 928.33 660.83 928.33 660.83 -631.55 966.69 631.55 966.69 966.69 631.55 966.69 691.39 966.69 691.39 -682.86 999.57 682.86 999.57 999.57 682.86 999.57 720.16 999.57 720.16 -714.17 1053.58 714.17 1053.58 1053.58 714.17 1053.58 747.47 1053.58 747.47 -765.34 1108.05 765.34 1108.05 1108.05 765.34 1108.05 790.51 1108.05 790.51 -816.02 1153.11 816.02 1153.11 1153.11 816.02 1153.11 845.97 1153.11 845.97 -868.30 1181.83 868.30 1181.83 1181.83 868.30 1181.83 885.17 1181.83 885.17 -901.65 1236.63 901.65 1236.63 1236.63 901.65 1236.63 925.29 1236.63 925.29 -920.16 1281.14 920.16 1281.14 1281.14 920.16 1281.14 966.79 1281.14 966.79 -945.17 1303.17 945.17 1303.17 1303.17 945.17 1303.17 997.75 1303.17 997.75 -958.16 1321.78 958.16 1321.78 1321.78 958.16 1321.78 997.92 1321.78 997.92 -944.56 1303.68 944.56 1303.68 1303.68 944.56 1303.68 984.23 1303.68 984.23 -908.24 1283.92 908.24 1283.92 1283.92 908.24 1283.92 966.28 1283.92 966.28 -864.44 1268.61 864.44 1268.61 1268.61 864.44 1268.61 938.75 1268.61 938.75 -824.95 1228.83 824.95 1228.83 1228.83 824.95 1228.83 903.06 1228.83 903.06 -777.57 1174.63 777.57 1174.63 1174.63 777.57 1174.63 858.16 1174.63 858.16 -740.25 1122.02 740.25 1122.02 1122.02 740.25 1122.02 810.24 1122.02 810.24 -688.52 1066.60 688.52 1066.60 1066.60 688.52 1066.60 761.93 1066.60 761.93 -635.83 1015.01 635.83 1015.01 1015.01 635.83 1015.01 717.13 1015.01 717.13 -585.11 960.51 585.11 960.51 960.51 585.11 960.51 680.31 960.51 680.31 -560.80 910.68 560.80 910.68 910.68 560.80 910.68 661.01 910.68 661.01 -551.24 888.50 551.24 888.50 888.50 551.24 888.50 668.91 888.50 668.91 -536.39 890.68 536.39 890.68 890.68 536.39 890.68 660.68 890.68 660.68 -531.25 913.04 531.25 913.04 913.04 531.25 913.04 674.31 913.04 674.31 -548.82 919.21 548.82 919.21 919.21 548.82 919.21 696.31 919.21 696.31 +623.62 623.62 623.62 630.74 634.13 634.13 630.74 630.74 634.13 634.13 +666.03 666.03 666.03 653.74 676.24 676.24 653.74 653.74 676.24 676.24 +706.48 706.48 706.48 686.22 722.52 722.52 686.22 686.22 722.52 722.52 +772.20 772.20 772.20 729.87 787.19 787.19 729.87 729.87 787.19 787.19 +810.78 810.78 810.78 752.79 846.23 846.23 752.79 752.79 846.23 846.23 +875.00 875.00 875.00 795.93 886.45 886.45 795.93 795.93 886.45 886.45 +919.00 919.00 919.00 843.97 937.85 937.85 843.97 843.97 937.85 937.85 +968.56 968.56 968.56 877.46 961.31 961.31 877.46 877.46 961.31 961.31 +998.39 998.39 998.39 936.21 994.44 994.44 936.21 936.21 994.44 994.44 +1017.65 1017.65 1017.65 957.53 987.14 987.14 957.53 957.53 987.14 987.14 +1012.87 1012.87 1012.87 964.00 971.54 971.54 964.00 964.00 971.54 971.54 +987.31 987.31 987.31 948.08 976.08 976.08 948.08 948.08 976.08 976.08 +957.52 957.52 957.52 908.18 956.40 956.40 908.18 908.18 956.40 956.40 +919.71 919.71 919.71 864.74 923.15 923.15 864.74 864.74 923.15 923.15 +877.30 877.30 877.30 827.34 885.60 885.60 827.34 827.34 885.60 885.60 +826.43 826.43 826.43 770.24 835.99 835.99 770.24 770.24 835.99 835.99 +793.19 793.19 793.19 710.40 795.75 795.75 710.40 710.40 795.75 795.75 +743.62 743.62 743.62 650.33 742.82 742.82 650.33 650.33 742.82 742.82 +689.06 689.06 689.06 614.04 717.27 717.27 614.04 614.04 717.27 717.27 +662.08 662.08 662.08 583.22 679.75 679.75 583.22 583.22 679.75 679.75 +631.88 631.88 631.88 549.92 652.43 652.43 549.92 549.92 652.43 652.43 +606.91 606.91 606.91 546.14 629.30 629.30 546.14 546.14 629.30 629.30 +602.71 602.71 602.71 552.93 619.83 619.83 552.93 552.93 619.83 619.83 +597.39 597.39 597.39 553.37 625.65 625.65 553.37 553.37 625.65 625.65 +639.97 639.97 639.97 559.88 662.33 662.33 559.88 559.88 662.33 662.33 +665.81 665.81 665.81 584.58 688.48 688.48 584.58 584.58 688.48 688.48 +703.24 703.24 703.24 632.19 737.68 737.68 632.19 632.19 737.68 737.68 +754.63 754.63 754.63 704.65 787.57 787.57 704.65 704.65 787.57 787.57 +812.24 812.24 812.24 757.51 857.12 857.12 757.51 757.51 857.12 857.12 +863.41 863.41 863.41 810.19 898.44 898.44 810.19 810.19 898.44 898.44 +903.87 903.87 903.87 864.92 938.08 938.08 864.92 864.92 938.08 938.08 +956.11 956.11 956.11 909.59 971.29 971.29 909.59 909.59 971.29 971.29 +996.88 996.88 996.88 946.72 994.63 994.63 946.72 946.72 994.63 994.63 +995.47 995.47 995.47 972.18 1016.34 1016.34 972.18 972.18 1016.34 1016.34 +1007.34 1007.34 1007.34 964.83 1006.90 1006.90 964.83 964.83 1006.90 1006.90 +1016.34 1016.34 1016.34 950.08 999.09 999.09 950.08 950.08 999.09 999.09 +976.79 976.79 976.79 920.47 982.17 982.17 920.47 920.47 982.17 982.17 +942.63 942.63 942.63 890.54 938.86 938.86 890.54 890.54 938.86 938.86 +898.83 898.83 898.83 865.10 877.88 877.88 865.10 865.10 877.88 877.88 +846.99 846.99 846.99 812.22 835.09 835.09 812.22 812.22 835.09 835.09 +795.73 795.73 795.73 758.07 778.32 778.32 758.07 758.07 778.32 778.32 +741.27 741.27 741.27 707.93 725.89 725.89 707.93 707.93 725.89 725.89 +692.89 692.89 692.89 669.38 694.08 694.08 669.38 669.38 694.08 694.08 +661.19 661.19 661.19 626.19 655.12 655.12 626.19 626.19 655.12 655.12 +635.07 635.07 635.07 601.24 612.25 612.25 601.24 601.24 612.25 612.25 +624.65 624.65 624.65 581.24 594.70 594.70 581.24 581.24 594.70 594.70 +623.82 623.82 623.82 571.48 588.04 588.04 571.48 571.48 588.04 588.04 +643.72 643.72 643.72 587.45 609.44 609.44 587.45 587.45 609.44 609.44 +670.95 670.95 670.95 616.04 638.65 638.65 616.04 616.04 638.65 638.65 +708.56 708.56 708.56 649.09 656.63 656.63 649.09 649.09 656.63 656.63 +748.43 748.43 748.43 696.78 725.09 725.09 696.78 696.78 725.09 725.09 +787.77 787.77 787.77 759.41 776.96 776.96 759.41 759.41 776.96 776.96 +819.54 819.54 819.54 804.85 825.45 825.45 804.85 804.85 825.45 825.45 +878.07 878.07 878.07 859.23 875.08 875.08 859.23 859.23 875.08 875.08 +917.81 917.81 917.81 920.15 909.41 909.41 920.15 920.15 909.41 909.41 +954.87 954.87 954.87 946.29 946.92 946.92 946.29 946.29 946.92 946.92 +968.34 968.34 968.34 980.20 969.02 969.02 980.20 980.20 969.02 969.02 +997.66 997.66 997.66 974.45 964.50 964.50 974.45 974.45 964.50 964.50 +979.95 979.95 979.95 979.87 967.11 967.11 979.87 979.87 967.11 967.11 +952.86 952.86 952.86 969.75 960.51 960.51 969.75 969.75 960.51 960.51 +918.57 918.57 918.57 945.83 928.41 928.41 945.83 945.83 928.41 928.41 +873.23 873.23 873.23 901.61 882.36 882.36 901.61 901.61 882.36 882.36 +825.50 825.50 825.50 866.36 829.64 829.64 866.36 866.36 829.64 829.64 +787.28 787.28 787.28 827.65 785.79 785.79 827.65 827.65 785.79 785.79 +742.14 742.14 742.14 752.99 733.81 733.81 752.99 752.99 733.81 733.81 +689.14 689.14 689.14 705.16 668.63 668.63 705.16 705.16 668.63 668.63 +643.76 643.76 643.76 662.34 614.34 614.34 662.34 662.34 614.34 614.34 +588.48 588.48 588.48 610.00 578.93 578.93 610.00 610.00 578.93 578.93 +571.05 571.05 571.05 576.51 530.17 530.17 576.51 576.51 530.17 530.17 +574.85 574.85 574.85 554.32 508.14 508.14 554.32 554.32 508.14 508.14 +568.74 568.74 568.74 558.97 510.23 510.23 558.97 558.97 510.23 510.23 +581.70 581.70 581.70 568.86 512.80 512.80 568.86 568.86 512.80 512.80 +623.05 623.05 623.05 603.20 561.24 561.24 603.20 603.20 561.24 561.24 +663.47 663.47 663.47 649.36 590.15 590.15 649.36 649.36 590.15 590.15 +707.47 707.47 707.47 703.86 644.48 644.48 703.86 703.86 644.48 644.48 +766.59 766.59 766.59 779.02 701.20 701.20 779.02 779.02 701.20 701.20 +799.28 799.28 799.28 848.32 755.85 755.85 848.32 848.32 755.85 755.85 +862.05 862.05 862.05 904.88 786.72 786.72 904.88 904.88 786.72 786.72 +907.74 907.74 907.74 937.81 840.95 840.95 937.81 937.81 840.95 840.95 +939.53 939.53 939.53 949.73 867.49 867.49 949.73 949.73 867.49 867.49 +959.92 959.92 959.92 960.74 892.86 892.86 960.74 960.74 892.86 892.86 +963.58 963.58 963.58 977.74 901.87 901.87 977.74 977.74 901.87 901.87 +952.67 952.67 952.67 985.29 884.71 884.71 985.29 985.29 884.71 884.71 +941.50 941.50 941.50 969.58 881.33 881.33 969.58 969.58 881.33 881.33 +902.83 902.83 902.83 951.84 846.61 846.61 951.84 951.84 846.61 846.61 +847.71 847.71 847.71 918.52 812.76 812.76 918.52 918.52 812.76 812.76 +810.54 810.54 810.54 866.48 784.11 784.11 866.48 866.48 784.11 784.11 +755.70 755.70 755.70 808.37 720.49 720.49 808.37 808.37 720.49 720.49 +690.78 690.78 690.78 752.61 669.61 669.61 752.61 752.61 669.61 669.61 +626.95 626.95 626.95 695.79 620.24 620.24 695.79 695.79 620.24 620.24 +581.86 581.86 581.86 646.56 579.51 579.51 646.56 646.56 579.51 579.51 +566.61 566.61 566.61 610.52 542.83 542.83 610.52 610.52 542.83 542.83 +531.96 531.96 531.96 576.68 516.87 516.87 576.68 576.68 516.87 516.87 +512.81 512.81 512.81 569.72 513.70 513.70 569.72 569.72 513.70 513.70 +523.64 523.64 523.64 567.76 516.26 516.26 567.76 567.76 516.26 516.26 +548.83 548.83 548.83 571.14 550.21 550.21 571.14 571.14 550.21 550.21 +569.92 569.92 569.92 594.04 574.93 574.93 594.04 594.04 574.93 574.93 +620.07 620.07 620.07 645.13 608.41 608.41 645.13 645.13 608.41 608.41 +671.38 671.38 671.38 699.43 652.80 652.80 699.43 699.43 652.80 652.80 +728.82 728.82 728.82 736.58 712.71 712.71 736.58 736.58 712.71 712.71 +784.53 784.53 784.53 786.81 767.96 767.96 786.81 786.81 767.96 767.96 +847.24 847.24 847.24 819.52 829.79 829.79 819.52 819.52 829.79 829.79 +886.23 886.23 886.23 865.49 884.90 884.90 865.49 865.49 884.90 884.90 +913.70 913.70 913.70 894.17 923.98 923.98 894.17 894.17 923.98 923.98 +933.05 933.05 933.05 919.64 961.98 961.98 919.64 919.64 961.98 961.98 +946.60 946.60 946.60 940.28 980.46 980.46 940.28 940.28 980.46 980.46 +948.25 948.25 948.25 932.20 981.61 981.61 932.20 932.20 981.61 981.61 +939.73 939.73 939.73 909.46 951.15 951.15 909.46 909.46 951.15 951.15 +908.30 908.30 908.30 883.00 932.05 932.05 883.00 883.00 932.05 932.05 +862.80 862.80 862.80 850.93 893.12 893.12 850.93 850.93 893.12 893.12 +818.61 818.61 818.61 814.96 869.79 869.79 814.96 814.96 869.79 869.79 +758.62 758.62 758.62 760.83 829.59 829.59 760.83 760.83 829.59 829.59 +704.35 704.35 704.35 715.37 774.26 774.26 715.37 715.37 774.26 774.26 +654.97 654.97 654.97 651.93 736.62 736.62 651.93 651.93 736.62 736.62 +622.20 622.20 622.20 622.01 681.30 681.30 622.01 622.01 681.30 681.30 +594.33 594.33 594.33 575.94 638.76 638.76 575.94 575.94 638.76 638.76 +562.40 562.40 562.40 552.39 616.25 616.25 552.39 552.39 616.25 616.25 +555.64 555.64 555.64 557.68 612.46 612.46 557.68 557.68 612.46 612.46 +563.89 563.89 563.89 564.76 618.17 618.17 564.76 564.76 618.17 618.17 +564.91 564.91 564.91 582.89 641.17 641.17 582.89 582.89 641.17 641.17 +592.70 592.70 592.70 626.43 656.00 656.00 626.43 626.43 656.00 656.00 +638.00 638.00 638.00 662.92 693.57 693.57 662.92 662.92 693.57 693.57 +680.51 680.51 680.51 717.27 748.33 748.33 717.27 717.27 748.33 748.33 +734.53 734.53 734.53 758.50 818.97 818.97 758.50 758.50 818.97 818.97 +801.78 801.78 801.78 818.75 865.80 865.80 818.75 818.75 865.80 865.80 +863.21 863.21 863.21 877.49 890.84 890.84 877.49 877.49 890.84 890.84 +901.22 901.22 901.22 923.37 916.69 916.69 923.37 923.37 916.69 916.69 +923.85 923.85 923.85 946.17 964.37 964.37 946.17 946.17 964.37 964.37 +958.11 958.11 958.11 988.48 984.70 984.70 988.48 988.48 984.70 984.70 +964.73 964.73 964.73 994.98 996.00 996.00 994.98 994.98 996.00 996.00 +956.75 956.75 956.75 1006.10 981.21 981.21 1006.10 1006.10 981.21 981.21 +914.74 914.74 914.74 988.09 976.06 976.06 988.09 988.09 976.06 976.06 +867.86 867.86 867.86 948.33 958.01 958.01 948.33 948.33 958.01 958.01 +833.26 833.26 833.26 893.81 920.04 920.04 893.81 893.81 920.04 920.04 +770.47 770.47 770.47 866.33 865.42 865.42 866.33 866.33 865.42 865.42 +749.76 749.76 749.76 802.65 824.62 824.62 802.65 802.65 824.62 824.62 +692.32 692.32 692.32 755.66 784.63 784.63 755.66 755.66 784.63 784.63 +630.36 630.36 630.36 708.53 724.93 724.93 708.53 708.53 724.93 724.93 +586.52 586.52 586.52 673.73 657.81 657.81 673.73 673.73 657.81 657.81 +558.17 558.17 558.17 631.15 617.89 617.89 631.15 631.15 617.89 617.89 +559.96 559.96 559.96 608.20 594.54 594.54 608.20 608.20 594.54 594.54 +558.93 558.93 558.93 581.55 584.27 584.27 581.55 581.55 584.27 584.27 +569.63 569.63 569.63 572.28 588.96 588.96 572.28 572.28 588.96 588.96 +592.12 592.12 592.12 584.21 605.72 605.72 584.21 584.21 605.72 605.72 +612.46 612.46 612.46 619.65 644.08 644.08 619.65 619.65 644.08 644.08 +654.46 654.46 654.46 654.39 681.08 681.08 654.39 654.39 681.08 681.08 +708.22 708.22 708.22 690.22 713.72 713.72 690.22 690.22 713.72 713.72 +767.72 767.72 767.72 752.23 770.49 770.49 752.23 752.23 770.49 770.49 +814.89 814.89 814.89 834.15 810.51 810.51 834.15 834.15 810.51 810.51 +855.40 855.40 855.40 902.67 865.89 865.89 902.67 902.67 865.89 865.89 +878.26 878.26 878.26 932.50 909.85 909.85 932.50 932.50 909.85 909.85 +904.84 904.84 904.84 963.70 936.62 936.62 963.70 963.70 936.62 936.62 +921.16 921.16 921.16 994.48 954.21 954.21 994.48 994.48 954.21 954.21 +932.34 932.34 932.34 999.35 956.88 956.88 999.35 999.35 956.88 956.88 +919.31 919.31 919.31 995.02 940.79 940.79 995.02 995.02 940.79 940.79 +888.97 888.97 888.97 961.47 925.79 925.79 961.47 961.47 925.79 925.79 +861.87 861.87 861.87 913.87 888.33 888.33 913.87 913.87 888.33 888.33 +819.89 819.89 819.89 866.91 832.03 832.03 866.91 866.91 832.03 832.03 +777.43 777.43 777.43 820.16 787.37 787.37 820.16 820.16 787.37 787.37 +706.45 706.45 706.45 780.91 735.12 735.12 780.91 780.91 735.12 735.12 +654.99 654.99 654.99 737.34 679.43 679.43 737.34 737.34 679.43 679.43 +603.18 603.18 603.18 700.01 631.68 631.68 700.01 700.01 631.68 631.68 +561.13 561.13 561.13 650.36 576.27 576.27 650.36 650.36 576.27 576.27 +550.30 550.30 550.30 603.12 551.00 551.00 603.12 603.12 551.00 551.00 +551.96 551.96 551.96 583.11 521.93 521.93 583.11 583.11 521.93 521.93 +547.61 547.61 547.61 569.66 529.63 529.63 569.66 569.66 529.63 529.63 +553.79 553.79 553.79 584.26 520.73 520.73 584.26 584.26 520.73 520.73 +568.64 568.64 568.64 607.46 532.98 532.98 607.46 607.46 532.98 532.98 diff --git a/examples/Begin Stochastic/nuclear.csv b/examples/Begin Stochastic/nuclear.csv index fb865e4..f18bb9d 100644 --- a/examples/Begin Stochastic/nuclear.csv +++ b/examples/Begin Stochastic/nuclear.csv @@ -8,17 +8,35 @@ 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 +5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 +5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 +5000.00 5000.00 5000.00 5000.00 4700.00 4700.00 4700.00 5000.00 5000.00 4700.00 +5000.00 5000.00 5000.00 5000.00 4700.00 4700.00 4700.00 5000.00 5000.00 4700.00 +5000.00 5000.00 5000.00 5000.00 4700.00 4700.00 4700.00 5000.00 5000.00 4700.00 +5000.00 5000.00 5000.00 5000.00 4400.00 4700.00 4400.00 5000.00 5000.00 4400.00 +5000.00 5000.00 5000.00 5000.00 4400.00 4700.00 4400.00 5000.00 5000.00 4400.00 +5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 +5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 +5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 -5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 -5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 -5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +4700.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 @@ -44,10 +62,24 @@ 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 +5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 +5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 +5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 @@ -57,21 +89,10 @@ 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 -5000.00 4700.00 5000.00 5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 4700.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 @@ -98,9 +119,6 @@ 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 -5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 -5000.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 @@ -112,24 +130,6 @@ 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 -4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 -4700.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 4700.00 5000.00 -4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 4700.00 4700.00 -4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 4700.00 4700.00 -4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 4700.00 4700.00 -4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 4700.00 4700.00 -4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 4700.00 4700.00 -4700.00 5000.00 5000.00 4700.00 5000.00 5000.00 4700.00 5000.00 4700.00 4700.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 -5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 5000.00 diff --git a/examples/Workflow/Workflow.ipynb b/examples/Workflow/Workflow.ipynb index 8649e2d..d9d9d8a 100644 --- a/examples/Workflow/Workflow.ipynb +++ b/examples/Workflow/Workflow.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e1ec1f72473a1e15f6efaaec81b6ad81898a1904cef02b9716a138bc3d75fbc0 -size 538335 +oid sha256:84a58202970a1bf1dc3aab2bb70fd64c3ea0264adb69dc76c9dae98b259a734d +size 4046391 diff --git a/examples/Workflow/shuffler.png b/examples/Workflow/shuffler.png new file mode 100644 index 0000000000000000000000000000000000000000..01c935317c990384fc0b1b9641ced6dc198f6676 GIT binary patch literal 22640 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 Date: Mon, 22 Jun 2020 18:26:52 +0200 Subject: [PATCH 25/34] WIP #67 Add Workflow advenced examples --- examples/Worflow Advenced/Workflow Advenced.ipynb | 3 +++ hadar/__init__.py | 2 +- hadar/workflow/pipeline.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 examples/Worflow Advenced/Workflow Advenced.ipynb diff --git a/examples/Worflow Advenced/Workflow Advenced.ipynb b/examples/Worflow Advenced/Workflow Advenced.ipynb new file mode 100644 index 0000000..3aaaaa5 --- /dev/null +++ b/examples/Worflow Advenced/Workflow Advenced.ipynb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88ab91453244f3b1b01afce04b3bc015ef5ea161c237d1547383fac700127c98 +size 178297 diff --git a/hadar/__init__.py b/hadar/__init__.py index bfc0345..fcbe8c7 100644 --- a/hadar/__init__.py +++ b/hadar/__init__.py @@ -9,7 +9,7 @@ import os import sys -from .workflow.pipeline import RestrictedPlug, FreePlug, Stage, FocusStage, Drop, Rename, Fault, RepeatScenario, ToShuffler +from .workflow.pipeline import RestrictedPlug, FreePlug, Stage, FocusStage, Drop, Rename, Fault, RepeatScenario, ToShuffler, Clip from .workflow.shuffler import Shuffler from .optimizer.input import Consumption, Link, Production, InputNode, Study from .optimizer.output import OutputProduction, OutputNode, OutputLink, OutputConsumption, Result diff --git a/hadar/workflow/pipeline.py b/hadar/workflow/pipeline.py index 7586fcd..c686ff1 100644 --- a/hadar/workflow/pipeline.py +++ b/hadar/workflow/pipeline.py @@ -16,7 +16,7 @@ from hadar.optimizer.input import DTO __all__ = ['RestrictedPlug', 'FreePlug', 'Stage', 'FocusStage', 'Drop', 'Rename', 'Fault', 'RepeatScenario', - 'ToShuffler', 'Pipeline'] + 'ToShuffler', 'Pipeline', 'Clip'] TO_SHUFFLER = 'to_shuffler' From e0c70c19867f5d897cbf1efbaa44ba3b83dd676b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Tue, 23 Jun 2020 12:50:10 +0200 Subject: [PATCH 26/34] close #67 finish examples for advenced workflow --- examples/Worflow Advenced/Workflow Advenced.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Worflow Advenced/Workflow Advenced.ipynb b/examples/Worflow Advenced/Workflow Advenced.ipynb index 3aaaaa5..3fce69b 100644 --- a/examples/Worflow Advenced/Workflow Advenced.ipynb +++ b/examples/Worflow Advenced/Workflow Advenced.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:88ab91453244f3b1b01afce04b3bc015ef5ea161c237d1547383fac700127c98 -size 178297 +oid sha256:4dc6c313ea73681b42a1ca56ee855103cf0a59b008896cdd5405604fc410e2d5 +size 177970 From 1006e5db32c11681090677caaa28df401a709abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Tue, 23 Jun 2020 18:27:51 +0200 Subject: [PATCH 27/34] close #69 add analyze example --- examples/Analyze Result/Analyze Result.ipynb | 3 +++ examples/Worflow Advenced/Workflow Advenced.ipynb | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 examples/Analyze Result/Analyze Result.ipynb diff --git a/examples/Analyze Result/Analyze Result.ipynb b/examples/Analyze Result/Analyze Result.ipynb new file mode 100644 index 0000000..645e2eb --- /dev/null +++ b/examples/Analyze Result/Analyze Result.ipynb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bad3790f9fda89268daf171c407712f66a5d4e75cd9ed5645046602e2068cdd8 +size 165584 diff --git a/examples/Worflow Advenced/Workflow Advenced.ipynb b/examples/Worflow Advenced/Workflow Advenced.ipynb index 3fce69b..4166eda 100644 --- a/examples/Worflow Advenced/Workflow Advenced.ipynb +++ b/examples/Worflow Advenced/Workflow Advenced.ipynb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4dc6c313ea73681b42a1ca56ee855103cf0a59b008896cdd5405604fc410e2d5 -size 177970 +oid sha256:babc67b4bf395c458cc78c0b8e228f46e821a7b6bc414766be74d17478eaa1ea +size 3679100 From bce5e4539afe892006deaa20945dc6b045882c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:26:53 +0200 Subject: [PATCH 28/34] Fix pandas CopyWarning --- hadar/workflow/pipeline.py | 2 +- tests/workflow/test_pipeline.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hadar/workflow/pipeline.py b/hadar/workflow/pipeline.py index c686ff1..f6ad8c6 100644 --- a/hadar/workflow/pipeline.py +++ b/hadar/workflow/pipeline.py @@ -363,7 +363,7 @@ def _process_timeline(self, timeline: pd.DataFrame) -> pd.DataFrame: output = pd.DataFrame(data=np.zeros((n_time, n_type * n_scn)), columns=index) for scn in timeline.columns.get_level_values(0).unique(): - output[scn] = self._process_scenarios(scn, timeline[scn]) + output[scn] = self._process_scenarios(scn, timeline[scn].copy()) return output diff --git a/tests/workflow/test_pipeline.py b/tests/workflow/test_pipeline.py index 337f629..f9f6b56 100644 --- a/tests/workflow/test_pipeline.py +++ b/tests/workflow/test_pipeline.py @@ -35,8 +35,8 @@ def __init__(self): Stage.__init__(self, RestrictedPlug(inputs=['a', 'b'], outputs=['d', 'r'])) def _process_scenarios(self, n_scn: int, scenario: pd.DataFrame) -> pd.DataFrame: - scenario['d'] = (scenario['a'] / scenario['b']).apply(np.floor) - scenario['r'] = scenario['a'] - scenario['b'] * scenario['d'] + scenario.loc[:, 'd'] = (scenario['a'] / scenario['b']).apply(np.floor) + scenario.loc[:, 'r'] = scenario['a'] - scenario['b'] * scenario['d'] return scenario.drop(['a', 'b'], axis=1) @@ -45,7 +45,7 @@ def __init__(self): FocusStage.__init__(self, RestrictedPlug(inputs=['d'], outputs=['d', '-d'])) def _process_scenarios(self, n_scn: int, scenario: pd.DataFrame) -> pd.DataFrame: - scenario['-d'] = -scenario['d'] + scenario.loc[:, '-d'] = -scenario['d'] return scenario.copy() From a1dd3a6f5abcd5fd5ec0ba4900a58822d6df8c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:33:56 +0200 Subject: [PATCH 29/34] optimize imports --- hadar/viewer/html.py | 1 - tests/analyzer/test_result.py | 5 ++--- tests/optimizer/test_input.py | 2 ++ tests/viewer/test_html.py | 1 - tests/workflow/test_integration.py | 4 ++-- tests/workflow/test_pipeline.py | 3 ++- tests/workflow/test_shuffler.py | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hadar/viewer/html.py b/hadar/viewer/html.py index a523034..8f011ad 100644 --- a/hadar/viewer/html.py +++ b/hadar/viewer/html.py @@ -7,7 +7,6 @@ from typing import Dict, List, Tuple -import folium import numpy as np import pandas as pd import plotly.graph_objects as go diff --git a/tests/analyzer/test_result.py b/tests/analyzer/test_result.py index eb31ea6..ef774fd 100644 --- a/tests/analyzer/test_result.py +++ b/tests/analyzer/test_result.py @@ -7,11 +7,10 @@ import unittest -import pandas as pd import numpy as np +import pandas as pd -from hadar.analyzer.result import Index, TimeIndex, ResultAnalyzer, NodeIndex, NameIndex, SrcIndex, DestIndex, \ - IntIndex +from hadar.analyzer.result import Index, ResultAnalyzer, IntIndex from hadar.optimizer.input import Production, Consumption, Study from hadar.optimizer.output import OutputConsumption, OutputLink, OutputNode, OutputProduction, Result diff --git a/tests/optimizer/test_input.py b/tests/optimizer/test_input.py index 49117db..7400866 100644 --- a/tests/optimizer/test_input.py +++ b/tests/optimizer/test_input.py @@ -6,7 +6,9 @@ # This file is part of hadar-simulator, a python adequacy library for everyone. import unittest + import numpy as np + from hadar.optimizer.input import Study, Consumption, Production, Link diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 90b781e..44d7f72 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -4,7 +4,6 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. -import base64 import hashlib import unittest diff --git a/tests/workflow/test_integration.py b/tests/workflow/test_integration.py index f01a902..2f54750 100644 --- a/tests/workflow/test_integration.py +++ b/tests/workflow/test_integration.py @@ -6,9 +6,9 @@ # This file is part of hadar-simulator, a python adequacy library for everyone. import unittest -import pandas as pd + import numpy as np -from pandas import MultiIndex +import pandas as pd from hadar.workflow.pipeline import Rename, RepeatScenario, Fault, Clip, ToShuffler from hadar.workflow.shuffler import Shuffler diff --git a/tests/workflow/test_pipeline.py b/tests/workflow/test_pipeline.py index f9f6b56..9046156 100644 --- a/tests/workflow/test_pipeline.py +++ b/tests/workflow/test_pipeline.py @@ -6,8 +6,9 @@ # This file is part of hadar-simulator, a python adequacy library for everyone. import unittest -import pandas as pd + import numpy as np +import pandas as pd from pandas import MultiIndex from hadar.workflow.pipeline import Stage, FreePlug, RestrictedPlug, FocusStage, Clip, Rename, Drop, Fault, \ diff --git a/tests/workflow/test_shuffler.py b/tests/workflow/test_shuffler.py index c7b3793..0192881 100644 --- a/tests/workflow/test_shuffler.py +++ b/tests/workflow/test_shuffler.py @@ -10,8 +10,8 @@ import numpy as np import pandas as pd -from hadar.workflow.pipeline import ToShuffler from hadar.workflow.pipeline import Pipeline, TO_SHUFFLER +from hadar.workflow.pipeline import ToShuffler from hadar.workflow.shuffler import Timeline, TimelinePipeline, Shuffler From f2289841d3935c7957cfc34b969065814bfefda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:40:53 +0200 Subject: [PATCH 30/34] increase hadar version. Try to fix fluky test --- hadar/__init__.py | 3 +-- tests/viewer/test_html.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hadar/__init__.py b/hadar/__init__.py index fcbe8c7..41a51b0 100644 --- a/hadar/__init__.py +++ b/hadar/__init__.py @@ -15,10 +15,9 @@ from .optimizer.output import OutputProduction, OutputNode, OutputLink, OutputConsumption, Result from .optimizer.optimizer import LPOptimizer, RemoteOptimizer from .viewer.html import HTMLPlotting -from .viewer.jupyter import JupyterPlotting from .analyzer.result import ResultAnalyzer -__version__ = '0.2.0' +__version__ = '0.3.0' level = os.getenv('HADAR_LOG', 'WARNING') diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index 44d7f72..b34f169 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -74,8 +74,8 @@ def test_gaussian(self): fig = self.plot.consumption(node='a', name='load').gaussian(scn=0) self.assert_fig_hash('4f3676a65cde6c268233679e1d0e6207df62764d', fig) - fig = self.plot.production(node='b', name='nuclear').gaussian(t=0) - self.assert_fig_hash('45ffe15df1d72829ebe2283c9c4b65ee8465c978', fig) + fig = self.plot.production(node='b', name='nuclear').gaussian(scn=0) + self.assert_fig_hash('4792794d46e7599fde4552cdd59d5db58562740a', fig) fig = self.plot.link(src='a', dest='b').gaussian(scn=0) self.assert_fig_hash('52620565ce8ea670b18707cccf30594b5c3d58ea', fig) From 6a5c96b2308efe7c29b0633ad1dcfae6d8c39906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:45:09 +0200 Subject: [PATCH 31/34] disable a test because failed during devops --- tests/viewer/test_html.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index b34f169..94844fd 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -74,8 +74,8 @@ def test_gaussian(self): fig = self.plot.consumption(node='a', name='load').gaussian(scn=0) self.assert_fig_hash('4f3676a65cde6c268233679e1d0e6207df62764d', fig) - fig = self.plot.production(node='b', name='nuclear').gaussian(scn=0) - self.assert_fig_hash('4792794d46e7599fde4552cdd59d5db58562740a', fig) + fig = self.plot.production(node='b', name='nuclear').gaussian(t=0) + # Fail devops self.assert_fig_hash('45ffe15df1d72829ebe2283c9c4b65ee8465c978', fig) fig = self.plot.link(src='a', dest='b').gaussian(scn=0) self.assert_fig_hash('52620565ce8ea670b18707cccf30594b5c3d58ea', fig) From f9196f6f7ae764c2f43d0ebdbdabe856c41cd6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 24 Jun 2020 12:28:26 +0200 Subject: [PATCH 32/34] add utils.py to run, check and export notebook. (Will be used by website repo) --- .github/workflows/staging.yml | 3 +- examples/check.py | 47 -------------- examples/requirements.txt | 2 + examples/utils.py | 116 ++++++++++++++++++++++++++++++++++ requirements.txt | 1 - 5 files changed, 120 insertions(+), 49 deletions(-) delete mode 100644 examples/check.py create mode 100644 examples/utils.py diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index d9667d9..a08e124 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -34,8 +34,9 @@ jobs: run: | git lfs pull export PYTHONPATH=$(pwd) + pip install click jupyter cd examples - python3 check.py + python3 utils.py --src=./ --check - name: Release test.pypi.org run: | diff --git a/examples/check.py b/examples/check.py deleted file mode 100644 index eebbea3..0000000 --- a/examples/check.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys -from typing import List - -import nbformat -import os -from nbconvert import HTMLExporter -from nbconvert.preprocessors import ExecutePreprocessor - -exporter = HTMLExporter() -ep = ExecutePreprocessor(timeout=600, kernel_name='python3', store_widget_state=True) - - -def read(name: str) -> nbformat: - print('Reading...', end=' ') - nb = nbformat.read('{name}/{name}.ipynb'.format(name=name), as_version=4) - print('OK', end=' ') - return nb - - -def execute(nb: nbformat, name: str) -> nbformat: - print('Executing...', end=' ') - ep.preprocess(nb, {'metadata': {'path': '%s/' % name}}) - print('OK', end=' ') - return nb - - -def export(nb: nbformat, name: str): - print('Exporting...', end=' ') - html, _ = exporter.from_notebook_node(nb) - with open('../public/%s/index.html' % name, 'w') as f: - f.write(html) - print('OK', end=' ') - - -def list_notebook() -> List[str]: - dirs = os.listdir('.') - return [d for d in dirs if os.path.isfile('{name}/{name}.ipynb'.format(name=d))] - - -if __name__ == '__main__': - for name in list_notebook(): - print(name, ':', end='') - nb = read(name) - nb = execute(nb, name) - if len(sys.argv) > 1 and sys.argv[1] == 'export': - export(nb, name) - print('') diff --git a/examples/requirements.txt b/examples/requirements.txt index f257e10..37f0d78 100644 --- a/examples/requirements.txt +++ b/examples/requirements.txt @@ -1,4 +1,6 @@ numpy pandas hadar +plotly jupyter +click diff --git a/examples/utils.py b/examples/utils.py new file mode 100644 index 0000000..8b466e0 --- /dev/null +++ b/examples/utils.py @@ -0,0 +1,116 @@ +# Copyright (c) 2019-2020, RTE (https://www.rte-france.com) +# See AUTHORS.txt +# This Source Code Form is subject to the terms of the Apache License, version 2.0. +# If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. +# SPDX-License-Identifier: Apache-2.0 +# This file is part of hadar-simulator, a python adequacy library for everyone. + +import sys +import click +from typing import List + +import nbformat +import os +from nbconvert import HTMLExporter +from nbconvert.preprocessors import ExecutePreprocessor + +exporter = HTMLExporter() +ep = ExecutePreprocessor(timeout=600, kernel_name='python3', store_widget_state=True) + + +def open_nb(name: str, src: str) -> nbformat: + """ + Open notebook file + + :param name: name of notebook to open + :param src: source directory + :return: notebook object + """ + print('Reading...', end=' ') + nb = nbformat.read('{src}/{name}/{name}.ipynb'.format(name=name, src=src), as_version=4) + print('OK', end=' ') + return nb + + +def execute(nb: nbformat, name: str, src: str) -> nbformat: + """ + Execute notebook and store widget state. + + :param nb: notebook object to execute + :param name: notebook name (for setup directory context purpose) + :param src: notebook source directory (for setup context) + :return: notebook object with computed and stored output widget state + """ + print('Executing...', end=' ') + ep.preprocess(nb, {'metadata': {'path': '%s/%s/' % (src, name)}}) + print('OK', end=' ') + return nb + + +def copy_image(name: str, export: str, src: str): + """ + Copy images present next to notebook file to exported folder. + + :param name: notebook name + :param export: export directory + :param src: source directory + :return: None + """ + src = '%s/%s' % (src, name) + dest = '%s/%s' % (export, name) + images = [f for f in os.listdir(src) if f.split('.')[-1] in ['png']] + for img in images: + os.rename('%s/%s' % (src, img), '%s/%s' % (dest, img)) + + +def to_export(nb: nbformat, name: str, export: str): + """ + Export notebook into HTML format. + + :param nb: notebook with result state + :param name: notebook name + :param export: directory to export + :return: None + """ + print('Exporting...', end=' ') + html, _ = exporter.from_notebook_node(nb) + + path = '%s/%s' % (export, name) + if not os.path.exists(path): + os.makedirs(path) + + with open('%s/index.html' % path, 'w') as f: + f.write(html) + + print('OK', end=' ') + + +def list_notebook(src: str) -> List[str]: + """ + List available notebook in directory. + + :return: + """ + dirs = os.listdir(src) + return [d for d in dirs if os.path.isfile('{src}/{name}/{name}.ipynb'.format(name=d, src=src))] + + +@click.command('Check and export notebooks') +@click.option('--src', nargs=1, help='Notebook directory') +@click.option('--check', nargs=1, help='check notebook according to result file given') +@click.option('--export', nargs=1, help='export notebooks to directory given') +def main(src: str, check: str, export: str): + for name in list_notebook(src): + print(name, ':', end='') + nb = open_nb(name, src) + nb = execute(nb, name, src) + if check: + pass # Implement check + if export: + to_export(nb, name, export) + copy_image(name, export, src) + print('') + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt index 10aa33e..1181394 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,5 @@ pandas numpy ortools plotly -jupyter matplotlib requests \ No newline at end of file From 7ba2f8ae0b922d10fe089939c05af24a14a729f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 24 Jun 2020 12:34:37 +0200 Subject: [PATCH 33/34] fix ci --- .github/workflows/staging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index a08e124..fcdc359 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -36,7 +36,7 @@ jobs: export PYTHONPATH=$(pwd) pip install click jupyter cd examples - python3 utils.py --src=./ --check + python3 utils.py --src=./ --check=./ - name: Release test.pypi.org run: | From b6d443de8d84bda9feb4b67c5824d083f44671a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Jolain?= <4466185+FrancoisJ@users.noreply.github.com> Date: Wed, 24 Jun 2020 12:53:15 +0200 Subject: [PATCH 34/34] update prod pipelines --- .github/workflows/prod.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 636238e..19d6248 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -43,8 +43,9 @@ jobs: run: | git lfs pull pip install -i https://test.pypi.org/simple/ hadar + pip install jupyter click cd examples - python3 check.py + python3 utils.py --src=./ --check=./ - name: Release pypi.org run: |