Full Code of Total-RD/pymgrid for AI

master 7bf39516e1e9 cached
181 files
1.5 MB
620.4k tokens
1012 symbols
1 requests
Download .txt
Showing preview only (1,599K chars total). Download the full file or copy to clipboard to get everything.
Repository: Total-RD/pymgrid
Branch: master
Commit: 7bf39516e1e9
Files: 181
Total size: 1.5 MB

Directory structure:
gitextract_21zgo62z/

├── .gitattributes
├── .github/
│   └── workflows/
│       ├── build.yml
│       ├── documentation-links.yaml
│       └── garage-compat.yml
├── .gitignore
├── .readthedocs.yaml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── docs/
│   ├── Makefile
│   ├── make.bat
│   ├── requirements.txt
│   └── source/
│       ├── _templates/
│       │   └── autosummary/
│       │       ├── base.rst
│       │       └── class.rst
│       ├── conf.py
│       ├── examples/
│       │   ├── index.rst
│       │   ├── mpc-example.nblink
│       │   ├── quick-start.nblink
│       │   ├── rbc-example.nblink
│       │   └── rl-example.nblink
│       ├── getting_started.rst
│       ├── index.rst
│       └── reference/
│           ├── algos/
│           │   └── index.rst
│           ├── envs/
│           │   └── index.rst
│           ├── forecast/
│           │   └── index.rst
│           ├── general/
│           │   └── index.rst
│           ├── index.rst
│           ├── microgrid.rst
│           └── modules/
│               └── index.rst
├── pymgrid 25 - benchmarks.xlsx
├── pyproject.toml
├── requirements.txt
├── setup.cfg
├── setup.py
├── src/
│   ├── __init__.py
│   └── pymgrid/
│       ├── MicrogridGenerator.py
│       ├── __init__.py
│       ├── _deprecated/
│       │   ├── Environments/
│       │   │   ├── Environment.py
│       │   │   ├── Preprocessing.py
│       │   │   ├── __init__.py
│       │   │   ├── pymgrid_csca.py
│       │   │   ├── pymgrid_csca_old.py
│       │   │   ├── pymgrid_csda.py
│       │   │   └── pymgrid_cspla.py
│       │   ├── __init__.py
│       │   └── non_modular_microgrid.py
│       ├── algos/
│       │   ├── Control.py
│       │   ├── __init__.py
│       │   ├── example.log
│       │   ├── mpc/
│       │   │   ├── __init__.py
│       │   │   └── mpc.py
│       │   ├── priority_list/
│       │   │   ├── __init__.py
│       │   │   ├── priority_list.py
│       │   │   └── priority_list_element.py
│       │   ├── rbc/
│       │   │   ├── __init__.py
│       │   │   ├── _nonmodular_rbc.py
│       │   │   └── rbc.py
│       │   └── saa/
│       │       ├── __init__.py
│       │       └── saa.py
│       ├── convert/
│       │   ├── __init__.py
│       │   ├── convert.py
│       │   ├── get_module.py
│       │   └── to_nonmodular_ops.py
│       ├── data/
│       │   ├── __init__.py
│       │   ├── co2/
│       │   │   ├── __init__.py
│       │   │   ├── co2_caiso.csv
│       │   │   └── co2_duke.csv
│       │   ├── load/
│       │   │   ├── RefBldgFullServiceRestaurantNew2004_v1.3_7.1_6A_USA_MN_MINNEAPOLIS.csv
│       │   │   ├── RefBldgHospitalNew2004_7.1_5.0_3C_USA_CA_SAN_FRANCISCO.csv
│       │   │   ├── RefBldgLargeHotelNew2004_v1.3_7.1_4A_USA_MD_BALTIMORE.csv
│       │   │   ├── RefBldgLargeOfficeNew2004_v1.3_7.1_5A_USA_IL_CHICAGO-OHARE.csv
│       │   │   ├── RefBldgPrimarySchoolNew2004_v1.3_7.1_2A_USA_TX_HOUSTON.csv
│       │   │   └── __init__.py
│       │   ├── pv/
│       │   │   ├── Houston_722430TYA.csv
│       │   │   ├── Minneapolis_726580TYA.csv
│       │   │   ├── NewYork_744860TYA.csv
│       │   │   ├── Raleigh_723060TYA.csv
│       │   │   ├── SanFrancisco_724940TYA.csv
│       │   │   └── __init__.py
│       │   └── scenario/
│       │       ├── __init__.py
│       │       └── pymgrid25/
│       │           ├── microgrid_0/
│       │           │   └── microgrid_0.yaml
│       │           ├── microgrid_1/
│       │           │   └── microgrid_1.yaml
│       │           ├── microgrid_10/
│       │           │   └── microgrid_10.yaml
│       │           ├── microgrid_11/
│       │           │   └── microgrid_11.yaml
│       │           ├── microgrid_12/
│       │           │   └── microgrid_12.yaml
│       │           ├── microgrid_13/
│       │           │   └── microgrid_13.yaml
│       │           ├── microgrid_14/
│       │           │   └── microgrid_14.yaml
│       │           ├── microgrid_15/
│       │           │   └── microgrid_15.yaml
│       │           ├── microgrid_16/
│       │           │   └── microgrid_16.yaml
│       │           ├── microgrid_17/
│       │           │   └── microgrid_17.yaml
│       │           ├── microgrid_18/
│       │           │   └── microgrid_18.yaml
│       │           ├── microgrid_19/
│       │           │   └── microgrid_19.yaml
│       │           ├── microgrid_2/
│       │           │   └── microgrid_2.yaml
│       │           ├── microgrid_20/
│       │           │   └── microgrid_20.yaml
│       │           ├── microgrid_21/
│       │           │   └── microgrid_21.yaml
│       │           ├── microgrid_22/
│       │           │   └── microgrid_22.yaml
│       │           ├── microgrid_23/
│       │           │   └── microgrid_23.yaml
│       │           ├── microgrid_24/
│       │           │   └── microgrid_24.yaml
│       │           ├── microgrid_3/
│       │           │   └── microgrid_3.yaml
│       │           ├── microgrid_4/
│       │           │   └── microgrid_4.yaml
│       │           ├── microgrid_5/
│       │           │   └── microgrid_5.yaml
│       │           ├── microgrid_6/
│       │           │   └── microgrid_6.yaml
│       │           ├── microgrid_7/
│       │           │   └── microgrid_7.yaml
│       │           ├── microgrid_8/
│       │           │   └── microgrid_8.yaml
│       │           └── microgrid_9/
│       │               └── microgrid_9.yaml
│       ├── envs/
│       │   ├── __init__.py
│       │   ├── base/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── skip_init.py
│       │   ├── continuous/
│       │   │   ├── __init__.py
│       │   │   └── continuous.py
│       │   └── discrete/
│       │       ├── __init__.py
│       │       └── discrete.py
│       ├── forecast/
│       │   ├── __init__.py
│       │   └── forecaster.py
│       ├── microgrid/
│       │   ├── __init__.py
│       │   ├── microgrid.py
│       │   ├── reward_shaping/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── battery_discharge_shaper.py
│       │   │   └── pv_curtailment_shaper.py
│       │   ├── trajectory/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── deterministic.py
│       │   │   └── stochastic.py
│       │   └── utils/
│       │       ├── __init__.py
│       │       └── step.py
│       ├── modules/
│       │   ├── __init__.py
│       │   ├── base/
│       │   │   ├── __init__.py
│       │   │   ├── base_module.py
│       │   │   └── timeseries/
│       │   │       ├── __init__.py
│       │   │       └── base_timeseries_module.py
│       │   ├── battery_module.py
│       │   ├── genset_module.py
│       │   ├── grid_module.py
│       │   ├── load_module.py
│       │   ├── module_container.py
│       │   ├── renewable_module.py
│       │   └── unbalanced_energy_module.py
│       ├── utils/
│       │   ├── DataGenerator.py
│       │   ├── __init__.py
│       │   ├── logger.py
│       │   ├── ray.py
│       │   ├── serialize.py
│       │   └── space.py
│       └── version.py
└── tests/
    ├── __init__.py
    ├── conftest.py
    ├── control/
    │   ├── __init__.py
    │   ├── data_generation/
    │   │   ├── __init__.py
    │   │   └── test_data_generator.py
    │   ├── test_control.py
    │   ├── test_mpc.py
    │   └── test_rbc.py
    ├── envs/
    │   ├── __init__.py
    │   ├── test_discrete.py
    │   └── test_trajectory.py
    ├── helpers/
    │   ├── __init__.py
    │   ├── genset_module_testing_utils.py
    │   ├── modular_microgrid.py
    │   └── test_case.py
    ├── microgrid/
    │   ├── __init__.py
    │   ├── modules/
    │   │   ├── __init__.py
    │   │   ├── container_tests/
    │   │   │   ├── __init__.py
    │   │   │   └── test_container.py
    │   │   ├── conversion_test/
    │   │   │   ├── __init__.py
    │   │   │   └── test_modular_conversion.py
    │   │   ├── forecaster_tests/
    │   │   │   ├── __init__.py
    │   │   │   └── test_forecaster.py
    │   │   └── module_tests/
    │   │       ├── test_genset_long_status_changes.py
    │   │       ├── test_genset_module.py
    │   │       ├── test_genset_module_start_up_1_wind_down_1.py
    │   │       ├── test_load_module.py
    │   │       ├── test_renewable_module.py
    │   │       └── timeseries_modules.py
    │   ├── serialize/
    │   │   └── test_microgrid_serialization.py
    │   └── test_microgrid.py
    ├── test_microgridgenerator.py
    └── test_nonmodular_microgrid.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
*.ipynb linguist-vendored

================================================
FILE: .github/workflows/build.yml
================================================
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: build

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.8", "3.9", "3.10"]

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v3
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install flake8 pytest
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        pip install -e .'[dev]'
    - name: Lint with flake8
      run: |
        # stop the build if there are Python syntax errors or undefined names
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
    - name: Test with pytest
      run: |
        pip install pytest
        pip install pytest-cov
        pip install pytest-subtests
        pytest tests/ --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html


================================================
FILE: .github/workflows/documentation-links.yaml
================================================
# .github/workflows/documentation-links.yaml

name: Read the Docs Pull Request Preview
on:
  pull_request_target:
    types:
      - opened

permissions:
  pull-requests: write

jobs:
  documentation-links:
    runs-on: ubuntu-latest
    steps:
      - uses: readthedocs/actions/preview@v1
        with:
          project-slug: "pymgrid"


================================================
FILE: .github/workflows/garage-compat.yml
================================================
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: garage-compat

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.8", "3.9"]

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v3
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install flake8 pytest
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        pip install -e .'[dev]'
    - name: Get garage VERSION
      uses: wei/wget@v1
      with:
        args: -O VERSION https://raw.githubusercontent.com/rlworkgroup/garage/master/VERSION
    - name: Get garage README.md
      uses: wei/wget@v1
      with:
        args: -O README.md https://raw.githubusercontent.com/rlworkgroup/garage/master/README.md
    - name: Get garage setup.py
      uses: wei/wget@v1
      with:
        args: -O garage_setup.py https://raw.githubusercontent.com/rlworkgroup/garage/master/setup.py
    - name: Extract garage dependencies
      run:  |
        python -m garage_setup egg_info
        in_all=false
        while IFS= read -r line; do
          if [[ "$line" == *"[all]"* ]]; then
            in_all=true
          elif [[ "$line" == \[* ]]; then
            in_all=false
          elif [[ $in_all == true ]]; then
            echo $"$line" >> src/garage.egg-info/requires_all.txt
          fi
        done < "src/garage.egg-info/requires.txt"
    - name: Install garage dependencies
      run:  |
        sudo apt install libopenmpi-dev
        cat src/garage.egg-info/requires_all.txt
        python -m pip install -r src/garage.egg-info/requires_all.txt        
    - name: Lint with flake8
      run: |
        # stop the build if there are Python syntax errors or undefined names
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
    - name: Test with pytest
      run: |
        pip install pytest
        pip install pytest-cov
        pip install pytest-subtests
        pytest tests/ --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html


================================================
FILE: .gitignore
================================================
#Ignore what is not python code
notebooks/
.DS_STORE
.idea
*.pkl
pymgrid/__pycache__/
*.ipynb
.ipynb_checkpoints
__pycache__/

.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
docs/source/reference/api/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
*sandbox.py


================================================
FILE: .readthedocs.yaml
================================================
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the version of Python and other tools you might need
build:
  os: ubuntu-20.04
  tools:
    python: "3.8"

sphinx:
   configuration: docs/source/conf.py

python:
   install:
     - method: pip
       path: .
       extra_requirements:
         - all

formats:
  - pdf

================================================
FILE: CHANGELOG.md
================================================



================================================
FILE: CONTRIBUTING.md
================================================



================================================
FILE: LICENSE
================================================
                   GNU LESSER GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.


  This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.

  0. Additional Definitions.

  As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.

  "The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.

  An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.

  A "Combined Work" is a work produced by combining or linking an
Application with the Library.  The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".

  The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.

  The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.

  1. Exception to Section 3 of the GNU GPL.

  You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.

  2. Conveying Modified Versions.

  If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:

   a) under this License, provided that you make a good faith effort to
   ensure that, in the event an Application does not supply the
   function or data, the facility still operates, and performs
   whatever part of its purpose remains meaningful, or

   b) under the GNU GPL, with none of the additional permissions of
   this License applicable to that copy.

  3. Object Code Incorporating Material from Library Header Files.

  The object code form of an Application may incorporate material from
a header file that is part of the Library.  You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:

   a) Give prominent notice with each copy of the object code that the
   Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the object code with a copy of the GNU GPL and this license
   document.

  4. Combined Works.

  You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:

   a) Give prominent notice with each copy of the Combined Work that
   the Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the Combined Work with a copy of the GNU GPL and this license
   document.

   c) For a Combined Work that displays copyright notices during
   execution, include the copyright notice for the Library among
   these notices, as well as a reference directing the user to the
   copies of the GNU GPL and this license document.

   d) Do one of the following:

       0) Convey the Minimal Corresponding Source under the terms of this
       License, and the Corresponding Application Code in a form
       suitable for, and under terms that permit, the user to
       recombine or relink the Application with a modified version of
       the Linked Version to produce a modified Combined Work, in the
       manner specified by section 6 of the GNU GPL for conveying
       Corresponding Source.

       1) Use a suitable shared library mechanism for linking with the
       Library.  A suitable mechanism is one that (a) uses at run time
       a copy of the Library already present on the user's computer
       system, and (b) will operate properly with a modified version
       of the Library that is interface-compatible with the Linked
       Version.

   e) Provide Installation Information, but only if you would otherwise
   be required to provide such information under section 6 of the
   GNU GPL, and only to the extent that such information is
   necessary to install and execute a modified version of the
   Combined Work produced by recombining or relinking the
   Application with a modified version of the Linked Version. (If
   you use option 4d0, the Installation Information must accompany
   the Minimal Corresponding Source and Corresponding Application
   Code. If you use option 4d1, you must provide the Installation
   Information in the manner specified by section 6 of the GNU GPL
   for conveying Corresponding Source.)

  5. Combined Libraries.

  You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:

   a) Accompany the combined library with a copy of the same work based
   on the Library, uncombined with any other library facilities,
   conveyed under the terms of this License.

   b) Give prominent notice with the combined library that part of it
   is a work based on the Library, and explaining where to find the
   accompanying uncombined form of the same work.

  6. Revised Versions of the GNU Lesser General Public License.

  The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.

  Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.

  If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.


================================================
FILE: MANIFEST.in
================================================
global-include *.csv
global-include *.pkl


================================================
FILE: README.md
================================================
# pymgrid

## Important Notice

### The person that has been maintaining pymgrid since 2020 has moved future development to [python-microgrid](https://github.com/ahalev/python-microgrid) for the foreseeable future, a drop in replacement for pymgrid, and pymgrid may not be receiving any future updates. Please open any new issues in python-microgrid.


![Build](https://github.com/Total-RD/pymgrid/workflows/build/badge.svg?dummy=unused)

pymgrid (PYthon MicroGRID) is a python library to generate and simulate a large number of microgrids.

For more context, please see the [presentation](https://www.climatechange.ai/papers/neurips2020/3) done at Climate Change AI
and the [documentation](https://pymgrid.readthedocs.io).

## Installation

The easiest way to install pymgrid is with pip:

`pip install -U pymgrid`

Alternatively, you can install from source. First clone the repo:
 
```bash
git clone https://github.com/Total-RD/pymgrid.git
``` 
Then navigate to the root directory of pymgrid and call

```bash
pip install .
```
## Getting Started

Microgrids are straightforward to generate from scratch. Simply define some modules and pass them
to a microgrid:
```python
import numpy as np
from pymgrid import Microgrid
from pymgrid.modules import GensetModule, BatteryModule, LoadModule, RenewableModule


genset = GensetModule(running_min_production=10,
                      running_max_production=50,
                      genset_cost=0.5)

battery = BatteryModule(min_capacity=0,
                        max_capacity=100,
                        max_charge=50,
                        max_discharge=50,
                        efficiency=1.0,
                        init_soc=0.5)

# Using random data
renewable = RenewableModule(time_series=50*np.random.rand(100))

load = LoadModule(time_series=60*np.random.rand(100),
                  loss_load_cost=10)

microgrid = Microgrid([genset, battery, ("pv", renewable), load])
```

This creates a microgrid with the modules defined above, as well as an unbalanced energy module -- 
which reconciles situations when energy demand cannot be matched to supply.

Printing the microgrid gives us its architecture:

```python
>> microgrid

Microgrid([genset x 1, load x 1, battery x 1, pv x 1, balancing x 1])
```

A microgrid is contained of fixed modules and flex modules. Some modules can be both -- `GridModule`, for example
-- but not at the same time.


A *fixed* module has requires a request of a certain amount of energy ahead of time, and then attempts to 
produce or consume said amount. `LoadModule` is an example of this; you must tell it to consume a certain amount of energy
and it will then do so.

 A *flex* module, on the other hand, is able to adapt to meet demand. `RenewableModule` is an example of this as
 it allows for curtailment of any excess renewable produced.
 
 A microgrid will tell you which modules are which:
 
 ```python
>> microgrid.fixed_modules

{
  "genset": "[GensetModule(running_min_production=10, running_max_production=50, genset_cost=0.5, co2_per_unit=0, cost_per_unit_co2=0, start_up_time=0, wind_down_time=0, allow_abortion=True, init_start_up=True, raise_errors=False, provided_energy_name=genset_production)]",
  "load": "[LoadModule(time_series=<class 'numpy.ndarray'>, loss_load_cost=10, forecaster=NoForecaster, forecast_horizon=0, forecaster_increase_uncertainty=False, raise_errors=False)]",
  "battery": "[BatteryModule(min_capacity=0, max_capacity=100, max_charge=50, max_discharge=50, efficiency=1.0, battery_cost_cycle=0.0, battery_transition_model=None, init_charge=None, init_soc=0.5, raise_errors=False)]"
}

>>microgrid.flex_modules

{
  "pv": "[RenewableModule(time_series=<class 'numpy.ndarray'>, raise_errors=False, forecaster=NoForecaster, forecast_horizon=0, forecaster_increase_uncertainty=False, provided_energy_name=renewable_used)]",
  "balancing": "[UnbalancedEnergyModule(raise_errors=False, loss_load_cost=10, overgeneration_cost=2)]"
}

```


Running the microgrid is straightforward. Simply pass an action for each fixed module to `microgrid.run`. The microgrid
can also provide you a random action by calling `microgrid.sample_action.` Once the microgrid has been run for a
certain number of steps, results can be viewed by calling microgrid.get_log.

```python
>> for j in range(10):
>>    action = microgrid.sample_action(strict_bound=True)
>>    microgrid.run(action)

>> microgrid.get_log(drop_singleton_key=True)

      genset  ...                     balance
      reward  ... fixed_absorbed_by_microgrid
0  -5.000000  ...                   10.672095
1 -14.344353  ...                   50.626726
2  -5.000000  ...                   17.538018
3  -0.000000  ...                   15.492778
4  -0.000000  ...                   35.748724
5  -0.000000  ...                   30.302300
6  -5.000000  ...                   36.451662
7  -0.000000  ...                   66.533872
8  -0.000000  ...                   20.645077
9  -0.000000  ...                   10.632957
```

## Benchmarking

`pymgrid` also comes pre-packaged with a set of 25 microgrids for benchmarking.
The config files for these microgrids are available in `data/scenario/pymgrid25`.
Simply deserialize one of the yaml files to load one of the saved microgrids; for example,
to load the zeroth microgrid:

```python
import yaml
from pymgrid import PROJECT_PATH

yaml_file = PROJECT_PATH / 'data/scenario/pymgrid25/microgrid_0/microgrid_0.yaml'
microgrid = yaml.safe_load(yaml_file.open('r'))
```

Alternatively, `Microgrid.load(yaml_file.open('r'))` will perform the same deserialization.


## Citation

If you use this package for your research, please cite the following paper:

@misc{henri2020pymgrid,
      title={pymgrid: An Open-Source Python Microgrid Simulator for Applied Artificial Intelligence Research}, 
      author={Gonzague Henri, Tanguy Levent, Avishai Halev, Reda Alami and Philippe Cordier},
      year={2020},
      eprint={2011.08004},
      archivePrefix={arXiv},
      primaryClass={cs.AI}
}

You can find it on Arxiv here: https://arxiv.org/abs/2011.08004

## Data

Data in pymgrid are based on TMY3 (data based on representative weather). The PV data comes from DOE/NREL/ALLIANCE (https://nsrdb.nrel.gov/about/tmy.html) and the load data comes from OpenEI (https://openei.org/doe-opendata/dataset/commercial-and-residential-hourly-load-profiles-for-all-tmy3-locations-in-the-united-states)

The CO2 data is from Jacque de Chalendar and his gridemissions API.

## Contributing
Pull requests are welcome for bug fixes. For new features, please open an issue first to discuss what you would like to add.

Please make sure to update tests as appropriate.

## License

This repo is under a GNU LGPL 3.0 (https://github.com/total-sa/pymgrid/edit/master/LICENSE)


================================================
FILE: docs/Makefile
================================================
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS    ?=
SPHINXBUILD   ?= sphinx-build
SOURCEDIR     = source
BUILDDIR      = build

# Put it first so that "make" without argument is like "make help".
help:
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)


================================================
FILE: docs/make.bat
================================================
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
	set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
	echo.
	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
	echo.installed, then set the SPHINXBUILD environment variable to point
	echo.to the full path of the 'sphinx-build' executable. Alternatively you
	echo.may add the Sphinx directory to PATH.
	echo.
	echo.If you don't have Sphinx installed, grab it from
	echo.https://www.sphinx-doc.org/
	exit /b 1
)

if "%1" == "" goto help

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd


================================================
FILE: docs/requirements.txt
================================================
nbsphinx==0.8.10
nbsphinx-link==1.3.0
numpydoc==1.5.0
pydata_sphinx_theme==0.12.0
Sphinx==5.3.0


================================================
FILE: docs/source/_templates/autosummary/base.rst
================================================
{{ objname | escape | underline }}

.. currentmodule:: {{ module }}

.. auto{{ objtype }}:: {{ objname }}


================================================
FILE: docs/source/_templates/autosummary/class.rst
================================================
{{ fullname | escape | underline}}

.. currentmodule:: {{ module }}

.. autoclass:: {{ objname }}

   {% block methods %}

   {% if methods %}
   .. rubric:: {{ _('Methods') }}

   .. autosummary::
      :toctree: generated/

   {% for item in methods %}
       {% if item != "__init__" %}
          ~{{ name }}.{{ item }}
       {% endif %}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block attributes %}
   {% if attributes %}
   .. rubric:: {{ _('Attributes') }}

   .. autosummary::
      :toctree: generated/

   {% for item in attributes %}
      ~{{ name }}.{{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}


================================================
FILE: docs/source/conf.py
================================================
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

import inspect
import os
import sys

from copy import deepcopy
from builtins import object

import pymgrid


# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'pymgrid'
copyright = '2022, TotalEnergies'
author = 'Avishai Halev'
release = pymgrid.__version__
version = pymgrid.__version__

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = [
    'sphinx.ext.duration',
    'sphinx.ext.autodoc',
    'sphinx.ext.coverage',
    'sphinx.ext.autosummary',
    'sphinx.ext.doctest',
    'sphinx.ext.linkcode',
    'sphinx.ext.intersphinx',
    'sphinx.ext.mathjax',
    'nbsphinx',
    'nbsphinx_link',
    'IPython.sphinxext.ipython_console_highlighting'
]

templates_path = ['_templates']
exclude_patterns = []


# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'pydata_sphinx_theme'

html_theme_options = {
    "primary_sidebar_end": ["indices.html", "sidebar-ethical-ads.html"],

    "logo": {
          "image_light": "logo-light.png",
          "image_dark": "logo-dark.png",
       },

    "icon_links": [
            {
                "name": "GitHub",
                "url": "https://github.com/Total-RD/pymgrid",
                "icon": "fa-brands fa-github",
            },
            {
                "name": "PyPI",
                "url": "https://pypi.org/project/pymgrid/",
                "icon": "fa-solid fa-box",
            }
    ]
}


html_static_path = ['_static']


# These are attributes that don't have a __doc__ attribute to read ':meta private:' from.
skip_members = [
    'yaml_flow_style',
    'metadata',
    'render_mode',
    'reward_range',
    'spec'
                ]


def autodoc_skip_member(app, what, name, obj, skip, options):
    if name in skip_members:
        return True

    try:
        doc = obj.__doc__
    except AttributeError:
        return None

    if doc is not None and ':meta private:' in doc:
        return True
    return None


def autodoc_process_signature(app, what, name, obj, options, signature, return_annotation):
    """
    If a class signature is being read from cls.__new__, we want to replace it with the signature from cls.__init__.
    """
    if what == 'class' and signature[1:] in str(inspect.signature(obj.__new__)):
        obj_copy = deepcopy(obj)
        obj_copy.__new__ = object.__new__
        signature = str(inspect.signature(obj_copy))
        return signature, return_annotation


def linkcode_resolve(domain, info):
    """
    Determine the URL corresponding to Python object
    """
    if domain != "py":
        return None

    modname = info["module"]
    fullname = info["fullname"]

    submod = sys.modules.get(modname)
    if submod is None:
        return None

    obj = submod
    for part in fullname.split("."):
        try:
            obj = getattr(obj, part)
        except AttributeError:
            return None

    try:
        fn = inspect.getsourcefile(inspect.unwrap(obj))
    except TypeError:
        try:  # property
            fn = inspect.getsourcefile(inspect.unwrap(obj.fget))
        except (AttributeError, TypeError):
            fn = None
    if not fn:
        return None

    try:
        source, lineno = inspect.getsourcelines(obj)
    except TypeError:
        try:  # property
            source, lineno = inspect.getsourcelines(obj.fget)
        except (AttributeError, TypeError):
            lineno = None
    except OSError:
        lineno = None

    if lineno:
        linespec = f"#L{lineno}-L{lineno + len(source) - 1}"
    else:
        linespec = ""

    fn = os.path.relpath(fn, start=os.path.dirname(pymgrid.__file__))

    return f'https://github.com/Total-RD/pymgrid/tree/v{pymgrid.__version__}/src/pymgrid/{fn}{linespec}'


intersphinx_mapping = {
    'gym': ('https://www.gymlibrary.dev/', None)
}


def setup(app):
    app.connect('autodoc-skip-member', autodoc_skip_member)
    app.connect('autodoc-process-signature', autodoc_process_signature)


================================================
FILE: docs/source/examples/index.rst
================================================
Examples
========

To run the examples, clone the repository:

.. code-block:: bash

    $ git clone https://github.com/Total-RD/pymgrid.git

and use `Jupyter <http://jupyter.readthedocs.org/en/latest/install.html>`_ to open any notebook in
the :code:`notebooks` directory.

.. toctree::
   :maxdepth: 2

   quick-start
   rbc-example
   mpc-example
   rl-example

================================================
FILE: docs/source/examples/mpc-example.nblink
================================================
{
    "path": "../../../notebooks/mpc-example.ipynb"
}

================================================
FILE: docs/source/examples/quick-start.nblink
================================================
{
    "path": "../../../notebooks/quick-start.ipynb"
}


================================================
FILE: docs/source/examples/rbc-example.nblink
================================================
{
    "path": "../../../notebooks/rbc-example.ipynb"
}


================================================
FILE: docs/source/examples/rl-example.nblink
================================================
{
    "path": "../../../notebooks/rl-example.ipynb"
}


================================================
FILE: docs/source/getting_started.rst
================================================
Getting Started
===============

.. _installation:

Installation
------------

The easiest way to install *pymgrid* is with pip:

.. code-block:: console

    $ pip install -U pymgrid

Alternatively, you can install from source. First clone the repo:

.. code-block:: bash

    $ git clone https://github.com/Total-RD/pymgrid.git

Then navigate to the root directory of pymgrid and call

.. code-block:: bash

    $ pip install .

Advanced Installation
---------------------

To use the included model predictive control algorithm <link> on microgrids containing gensets,
additional dependencies are required as the optimization problem becomes mixed integer.

The packages MOSEK and CVXOPT can both handle this case; you can install both by calling

.. code-block:: bash

    $ pip install pymgrid[genset_mpc]

Note that MOSEK requires a license; see https://www.mosek.com/ for details.
Academic and trial licenses are available.

Simple Example
--------------
See :doc:`examples/quick-start` for a simple example to get started.


================================================
FILE: docs/source/index.rst
================================================
.. pymgrid documentation master file, created by
   sphinx-quickstart on Sat Nov 19 12:49:18 2022.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

*********************
pymgrid documentation
*********************

Important Notice
----------------

**The person that has been maintaining pymgrid since 2020 has moved future development to**
`python-microgrid <https://github.com/ahalev/python-microgrid>`__
**for the foreseeable future, a drop in replacement for pymgrid, and pymgrid may not be receiving any future updates.**
**Please open any new issues in python-microgrid. You can also view python-microgrid's documentation**
`at this link <https://python-microgrid.readthedocs.io/en/latest/>`__.

**Version**: |version|

*pymgrid* is a Python library to simulate tertiary control of electrical microgrids. *pymgrid* allows
users to create and customize microgrids of their choosing. These microgrids can then be controlled using a user-defined
algorithm or one of the control algorithms contained in *pymgrid*: rule-based control and model predictive control.

Environments corresponding to the OpenAI-Gym API are also provided, with both continuous and discrete action space
environments available. These environments can be used with your choice of reinforcement learning algorithm to train
a control algorithm.

*pymgrid* attempts to offer the simplest and most intuitive API possible, allowing the user to
focus on their particular application.

See the :doc:`getting_started` section for further information, including instructions on how to
:ref:`install <installation>` the project.

**Useful links**:
`Binary Installers <https://pypi.org/project/pymgrid/>`__ |
`Source Repository <https://github.com/Total-RD/pymgrid>`__


.. note::

   This project is under active development.

Contents
========

.. toctree::
   :maxdepth: 2

   getting_started
   examples/index
   reference/index

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`


================================================
FILE: docs/source/reference/algos/index.rst
================================================
.. _api.control:

Control Algorithms
==================

.. currentmodule:: pymgrid.algos

Control algorithms built into pymgrid, as well as references for external algorithms that can be deployed

Rule Based Control
------------------

Heuristic Algorithm that deploys modules via a priority list.

.. autosummary::
    :toctree: ../api/algos/

    RuleBasedControl


Model Predictive Control
------------------------

Algorithm that depends on a future forecast as well as a model of state transitions to determine optimal controls.


.. autosummary::
    :toctree: ../api/algos/

    ModelPredictiveControl


Reinforcement Learning
----------------------

Algorithms that treat a microgrid as a Markov process, and train a black-box policy by repeated interactions with
the environment. See :doc:`here <../../examples/rl-example>` for an example of using
reinforcement learning to train such an algorithm.



..
   HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages.
   Copied from pandas docs.

   .. currentmodule:: pymgrid.algos.priority_list

   .. autosummary::
      :toctree: ../api/algos/priority_list/
      PriorityListElement

================================================
FILE: docs/source/reference/envs/index.rst
================================================
.. _api.envs:

Reinforcement Learning (RL) Environments
======================

.. currentmodule:: pymgrid.envs

Environment classes using the `OpenAI Gym API <https://www.gymlibrary.dev//>`_ for reinforcement learning.

Discrete
--------

Environment with a discrete action space.


.. autosummary::
    :toctree: ../api/envs/

    DiscreteMicrogridEnv

Continuous
----------

Environment with a discrete action space.


.. autosummary::
    :toctree: ../api/envs/

    ContinuousMicrogridEnv


================================================
FILE: docs/source/reference/forecast/index.rst
================================================
.. _api.forecast:

Forecasting
===========

.. currentmodule:: pymgrid.forecast

Classes available to use for time-series forecasting, as well a class that allows users to define their own forecaster.

.. autosummary::
    :toctree: ../api/forecast/

   get_forecaster
   OracleForecaster
   GaussianNoiseForecaster
   UserDefinedForecaster
   NoForecaster



================================================
FILE: docs/source/reference/general/index.rst
================================================
.. _api.general:

General functions and objects
=============================

.. currentmodule:: pymgrid.modules

ModuleContainer
---------------

Object that store's a microgrid's modules.

.. autosummary::
   :toctree: ../api/general/

   ModuleContainer

ModuleSpace
-----------

Object for module action and observation spaces.

.. currentmodule:: pymgrid.utils.space

.. autosummary::
   :toctree: ../api/general/

   ModuleSpace


================================================
FILE: docs/source/reference/index.rst
================================================
API reference
=============

This page contains an overview of all public *pymgrid* objects and functions.

.. toctree::
   :maxdepth: 2

   microgrid
   modules/index
   forecast/index
   envs/index
   algos/index
   general/index

================================================
FILE: docs/source/reference/microgrid.rst
================================================
.. _api.microgrid:


Microgrid
=================

.. currentmodule:: pymgrid

Constructor
-----------
.. autosummary::
    :toctree: api/microgrid/

    Microgrid

Methods
-------
.. autosummary::

    :toctree: api/microgrid/

    Microgrid.run
    Microgrid.reset
    Microgrid.sample_action
    Microgrid.get_log
    Microgrid.get_forecast_horizon
    Microgrid.get_empty_action

Serialization/IO/Conversion
---------------------------
.. autosummary::

    :toctree: api/microgrid/

    Microgrid.load
    Microgrid.dump
    Microgrid.from_nonmodular
    Microgrid.from_scenario
    Microgrid.to_nonmodular

================================================
FILE: docs/source/reference/modules/index.rst
================================================
.. _api.modules:

Modules
=======

.. currentmodule:: pymgrid.modules

The modules defined here are commonly found in microgrids.
Pass any combination of modules to :ref:`Microgrid <api.microgrid>` to define and run a microgrid.

Timeseries Modules
------------------

Modules that are temporal in nature.



.. autosummary::
    :toctree: ../api/modules/

    GridModule
    LoadModule
    RenewableModule

Non-temporal Modules
--------------------

Modules that do not depend on an underlying timeseries.

.. autosummary::
    :toctree: ../api/modules/

    BatteryModule
    GensetModule

Helper Module
--------------

A module that cleans up after all the other modules are deployed.

.. autosummary::
    :toctree: ../api/modules/

    UnbalancedEnergyModule

================================================
FILE: pyproject.toml
================================================
[tool.pytest.ini_options]
log_cli = true
log_cli_level = "INFO"
log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_cli_date_format = "%Y-%m-%d %H:%M:%S"

================================================
FILE: requirements.txt
================================================
cufflinks>=0.17.3
cvxpy>=1.1.4
gym>=0.15.7
matplotlib>=3.1.1
numpy>=1.19.5
pandas>=1.0.3
plotly>=4.9.0
scipy>=1.5.3
statsmodels>=0.11.1
tqdm>=4.1.0
pyyaml>=1.5

================================================
FILE: setup.cfg
================================================
[metadata]
description-file = README.md

[tool:pytest]
norecursedirs=tests/helpers

================================================
FILE: setup.py
================================================
from pathlib import Path
from setuptools import setup, find_packages

v = {}
exec(open('src/pymgrid/version.py').read(), v)  # read __version__
VERSION = v['__version__']
DESCRIPTION = "A simulator for tertiary control of electrical microgrids"
DOWNLOAD_URL = f"https://github.com/Total-RD/pymgrid/archive/refs/tags/v{VERSION}.tar.gz"
MAINTAINER = "Avishai Halev"
MAINTAINER_EMAIL = "avishaihalev@gmail.com"
LICENSE = "GNU LGPL 3.0"
PROJECT_URLS = {"Source Code": "https://github.com/Total-RD/pymgrid",
                "Documentation": "https://pymgrid.readthedocs.io/en/latest/"}

EXTRAS = dict()
EXTRAS["genset_mpc"] = ["Mosek", "cvxopt"]
EXTRAS["dev"] = [
    "pytest",
    "pytest-subtests",
    "flake8",
    "sphinx",
    "pydata_sphinx_theme",
    "numpydoc",
    "nbsphinx",
    "nbsphinx-link",
    *EXTRAS["genset_mpc"]]

EXTRAS["rtd"] = ["ipython"]

EXTRAS["all"] = list(set(sum(EXTRAS.values(), [])))


setup(
    name="pymgrid",
    package_dir={"": "src"},
    packages=find_packages("src"),
    python_requires=">=3.6",
    version=VERSION,
    maintainer=MAINTAINER,
    maintainer_email=MAINTAINER_EMAIL,
    download_url=DOWNLOAD_URL,
    project_urls=PROJECT_URLS,
    description=DESCRIPTION,
    license=LICENSE,
    long_description=(Path(__file__).parent / "README.md").read_text(),
    long_description_content_type="text/markdown",
    include_package_data=True,
    install_requires=[
        "pandas",
        "numpy",
        "cvxpy",
        "statsmodels",
        "matplotlib",
        "plotly",
        "cufflinks",
        "gym",
        "tqdm",
        "pyyaml"
    ],
    extras_require=EXTRAS
)


================================================
FILE: src/__init__.py
================================================


================================================
FILE: src/pymgrid/MicrogridGenerator.py
================================================
"""
Copyright 2020 Total S.A., Tanguy Levent all rights reserved,
Authors:Gonzague Henri <gonzague.henri@total.com>, Tanguy Levent <>
Permission to use, modify, and distribute this software is given under the
terms of the pymgrid License.
NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
$Date: 2020/06/04 14:54 $
Gonzague Henri
"""
"""
<pymgrid is a Python library to simulate microgrids>
Copyright (C) <2020> <Total S.A.>

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

"""

import numpy as np
import pandas as pd
from pymgrid import NonModularMicrogrid, Microgrid, PROJECT_PATH
from os import listdir
from os.path import isfile, join
import os
import sys
import pickle
from IPython.display import display
from pathlib import Path

# MICROGRID_DEFAULT_CONFIG : {
#     'load_type':'Folder', #or 'File'
#     'load_path': 'default', # or a specific path
#     'pv_type':'Folder', #or 'File'
#     'pv_path': 'default', # or a specific path
#     'co2_type':'Folder', #or 'File'
#     'co2_path': 'default', # or a specific path


#     'parameters':{

#     }, #Dictionary
#     'df_actions':df_actions, #Dataframe
#     'architecture':architecture, #Dictionary
#     'df_status':df_status, #Dictionary
#     'df_actual_generation':df_actual_production,#Dataframe
#     'grid_spec':grid_spec, #value = 0
#     'df_cost':df_cost, #Dataframe of 1 value = 0.0
#     'df_co2': df_co2,
#     'pv':pv, #Dataframe
#     'load': load, #Dataframe
#     'grid_ts':grid_ts, #Dataframe
#     'control_dict': column_actions, #dictionnary
#     'grid_price_import' : grid_price_import_ts,
#     'grid_price_export' : grid_price_export_ts,
#     'grid_co2': grid_co2_ts,
# }

class MicrogridGenerator:
    """
        The class MicrogridGenerator generates a number of microgrids with differerent and randomized paramters based on
        the load and renewable data files in the data folder.

        Parameters
        ----------
            nb_microgrid: int, optional
                Number representing the number of microgrid to be generated.
            random_seed: int, optional
                Seed to be used to generate the needed random numbers to size microgrids.
            timestep: int, optional
                Timestep to be used in the time series.
            path: string
                The path to the pymgrid folder, used to get the data files needed.

        Attributes
        ----------
        self.microgrids= [] # generate a list of microgrid object
        #self.annual_load
        self.nb_microgrids=nb_microgrid
        self.timestep=1
        self.path=path

            microgrids: list
                List that contains all the generated microgrids
            nb_microgrid: int, optional
                Number representing the number of microgrid to be generated.
                this microgrid has one of them
            timestep: int, optional
                Timestep to be used in the time series.
            path: string
                The path to the pymgrid folder, used to get the data files needed.

        Notes
        -----
        Due to the random nature of the implemented process, all the generated microgrids might not make the most sense
        economically or in term of generator sizing. The main idea is to generate realistic-ich microgrids to develop,
        test and compare control algorithms and advance AI research applied to microgrids.

        Examples
        --------
        To create microgrids through MicrogridGenerator:
        >>> m_gen=mg.MicrogridGenerator(nb_microgrid=10)
        >>> m_gen.generate_microgrid()

        To plot informations about the generated microgrids:
        >>> m_gen.print_mg_parameters()
        """


    def __init__(self, nb_microgrid=10,
                 random_seed=42,
                 timestep=1,
                 path=str(Path(__file__).parent)):
        
        np.random.seed(random_seed)
        self.microgrids= [] # generate a list of microgrid object
        #self.annual_load
        self.nb_microgrids=nb_microgrid
        self.timestep=1
        self.path=path


    ###########################################
    #utility functions
    ###########################################
    def _get_random_file(self, path):
        """ Based on a path, and a folder containing data files, return a file chosen randomly."""
        from pathlib import Path
        _path = Path(path)
        data_files = list(_path.glob("*.csv"))
        if not len(data_files):
            raise NameError(f"Unable to find csv data files in {path}")
        return pd.read_csv(np.random.choice(data_files))

    def _scale_ts(self, df_ts, size, scaling_method='sum'):
        """ Scales a time series based on either the sum or the maximum of the time series."""

        actual_ratio=1
        if scaling_method =='sum':
            actual_ratio = size/df_ts.sum()#.values[0]

        if scaling_method == 'max':
            actual_ratio=size / df_ts.max()
        df_ts = df_ts * actual_ratio

        return df_ts

    def _resize_timeseries(self, timeseries, current_time_step, new_time_step):
        """ Change the frequency of a time series. """

        index = pd.date_range('1/1/2015 00:00:00', freq=str(int(current_time_step * 60)) + 'Min',
                              periods=(len(timeseries)))  # , freq='0.9S')

        try:
            timeseries = timeseries.squeeze()
        except AttributeError:
            pass

        try:
            timeseries = timeseries.values
        except AttributeError:
            pass

        unsampled = pd.Series(timeseries, index=index)
        resampled = unsampled.resample(rule=str(int(new_time_step * 60)) + 'Min').mean().interpolate(method='linear')

        return resampled.values

    ###########################################
    # methods to generate timeseries
    ###########################################
    # def load_generator(self, shape, annual_consumption=1): #consumption inMWh
    #     ts_load = np.random(shape)
    #     annual_consumption = annual_consumption

    def _get_pv_ts(self):
        """ Function to get a random PV file."""
        #open pv folder
        # get list of file
        # select randomly rank if file to select in the list

        path = self.path+'/data/pv/'
        return self._get_random_file(path)

    def _get_load_ts(self):
        """ Function to get a random load file. """
        #open load folder
        # get list of file
        # select randomly rank if file to select in the list

        path = self.path+'/data/load/'
        return self._get_random_file(path)

    def _get_wind_ts(self):
        """ Function to get a random wind file. """
        #open load folder
        # get list of file
        # select randomly rank if file to select in the list

        path = self.path+'/data/wind/'
        return self._get_random_file(path)

    def _get_co2_ts(self):
        """ Function to get a random wind file. """
        # open load folder
        # get list of file
        # select randomly rank if file to select in the list

        path = self.path + '/data/co2/'
        return self._get_random_file(path)

    def _get_genset(self, rated_power=1000, pmax=0.9, pmin=0.05):
        """ Function generates a dictionnary with the genset information. """

        polynom=[np.random.rand()*10, np.random.rand(), np.random.rand()/10] #fuel consumption

        genset={
            'polynom':polynom,
            'rated_power':rated_power,
            'pmax':pmax,
            'pmin':pmin,
            'fuel_cost':0.4,
            'co2':2,
        }

        return genset

    def _get_battery(self, capa=1000, duration=4, pcharge=100, pdischarge=100, soc_max=1, soc_min=0.2, efficiency=0.9):
        """ Function generates a dictionnary with the battery information. """
        battery={
            'capa':capa,
            'pcharge':int(np.ceil(capa/duration)),
            'pdischarge':int(np.ceil(capa/duration)),
            'soc_max':soc_max,
            'soc_min':soc_min,
            'efficiency':efficiency,
            'soc_0':min(max(np.random.randn(), soc_min),soc_max),
            'cost_cycle':0.02

        }
        return battery


    def _get_grid_price_ts(self, nb_time_step_per_year, tou=0, rt=0, price=0):
        """ This functions is used to generate time series of import and export prices."""
        if tou == 0  and rt ==0:
            price_ts = [price for i in range(nb_time_step_per_year)]

        return price_ts

    def _get_electricity_tariff(self, scenario):
        """
        Function to generate price time series based on existing tariffs.
        scenario == 1 representes the TOU A-6 2020 summer from PG&E (https://www.pge.com/tariffs/electric.shtml)
        scenario == 2 represents the commercial tariff from France, with a Marseille TOU plage 5 (
        times: https://www.fournisseurs-electricite.com/edf/tarifs/heures-creuses-heures-pleines,
        prices: https://www.cre.fr/Electricite/marche-de-detail-de-l-electricite
        )
        """
        price_import = []
        price_export = np.zeros((8760,))

        if scenario == 1: # PGE A-6 TOU 2020 summer

            for i in range(8760):
                if (i% 24 >= 12 and i%24 <18):
                    price_import.append(0.59)
                elif (i% 24 < 8 or i%24 >=21):
                    price_import.append(0.22)
                else:
                    price_import.append(0.29)


        if scenario == 2: # France Commercial TOU Marseille plage 5
            for i in range(8760):
                if (i% 24 >= 0 and i%24 <5) or (i%24>=14 and i%24<17):
                    price_import.append(0.08)
                else:
                    price_import.append(0.11)

        # if scenario == 3: Belgium

        return price_import, price_export


    def _get_grid(self, rated_power=1000, weak_grid=0, pmin=0.2, price_scenario=0, price_export = 0, price_import =0.3):
        """ Function generates a dictionnary with the grid information. """

        if weak_grid == 1:
            rand_outage_per_day = np.random.randn()*3/4 +0.25
            rand_duration = np.random.randint(low=1, high =8)
            grid_ts = self._generate_weak_grid_profile( rand_outage_per_day, rand_duration,8760/self.timestep)

        else:
            #grid_ts=pd.DataFrame([1+i*0 for i in range(int(np.floor(8760/self.timestep)))], columns=['grid_status'])
            grid_ts = pd.DataFrame(np.ones(int(np.floor(8760 / self.timestep))),
                                   columns=['grid_status'])

        # Make sure grid_ts is of length 8760
        grid_ts = grid_ts.iloc[:8760]

        # price_export = pd.DataFrame(self._get_grid_price_ts(price_export,8760),
        #                            columns=['grid_price_export'])
        # price_import = pd.DataFrame(self._get_grid_price_ts(price_import, 8760),
        #                            columns=['grid_price_import'])

        price_import, price_export = self._get_electricity_tariff(price_scenario)

        grid={
            'grid_power_import':rated_power,
            'grid_power_export':rated_power,
            'grid_ts':grid_ts,
            'grid_price_export':pd.DataFrame(price_export),
            'grid_price_import': pd.DataFrame(price_import),
        }

        return grid

    def _generate_weak_grid_profile(self, outage_per_day, duration_of_outage,nb_time_step_per_year):
        """ Function generates an outage time series to be used in the microgrids with a weak grid. """

        #weak_grid_timeseries = np.random.random_integers(0,1, int(nb_time_step_per_year+1) ) #for a number of time steps, value between 0 and 1
        #generate a timeseries of 8760/timestep points based on np.random seed
        #profile of ones and zeros
        weak_grid_timeseries = np.random.random(int(nb_time_step_per_year+1) ) #for a number of time steps, value between 0 and 1


        weak_grid_timeseries = [0 if weak_grid_timeseries[i] < outage_per_day/24 else 1 for i in range(len(weak_grid_timeseries))]

        timestep=8760/nb_time_step_per_year
        for i in range(len(weak_grid_timeseries)):
            if weak_grid_timeseries[i] == 0:
                for j in range(1, int(duration_of_outage/timestep)):
                    if i-j > 0:
                        weak_grid_timeseries[i-j] = 0
        #print weak_grid_timeseries

        return pd.DataFrame(weak_grid_timeseries, columns=['grid_status']) #[0 if weak_grid_timeseries[i] < h_outage_per_day/24 else 1 for i in range(len(weak_grid_timeseries))]


    ###########################################
    # sizing functions
    ###########################################
    def _size_mg(self, load, size_load=1):
        '''
         Function that returns a dictionnary with the size of each component of a microgrid. We chose to define PV
         penetration as defined by NREL (https://www.nrel.gov/docs/fy12osti/55094.pdf)
         PV penetration = peak PV power / peak load power
         '''
        # generate a list of size based on the number of architecture  generated
        # 2 size the other generators based on the load

        #PV penetration definition by NREL: https: // www.nrel.gov/docs/fy12osti/55094.pdf
        # penetragion = peak pv / peak load
        pv=load.max().values[0]*(np.random.randint(low=30, high=151)/100)

        #battery_size = self._size_battery(load)
        # return a dataframe with the power of each generator, and if applicable the number of generator

        size={
            'pv': pv,
            'load': size_load,
            'battery': self._size_battery(load),
            'genset': self._size_genset(load),
            'grid': int(max(load.values)*2),
        }

        return size

    def _size_genset(self, load, max_operating_loading = 0.9):
        """ Function that returns the maximum power a genset. """
        #random number > 3 < 20
        # polynomial for fuel consumption

        _size_genset = int(np.ceil(np.max(load)/max_operating_loading))

        return _size_genset


    def _size_battery(self, load):
        """ Function that returns the capacity of the battery, equivalent to 3 to 5 hours of mean load. """
        #energy duration
        battery = int(np.ceil(np.random.randint(low=3,high=6)*np.mean(load).item()))
        return battery


    ###########################################
    #generate the microgrid
    ###########################################

    def generate_microgrid(self, modular=True, verbose=False):
        """ Function used to generate the nb_microgrids to append them to the microgrids list. """

        convert = lambda x: x.to_modular() if modular else x

        for i in range(self.nb_microgrids):
            #size=self._size_mg()
            self.microgrids.append(convert(self._create_microgrid()))
        
        if verbose and not modular:
            self.print_mg_parameters()

        return self

    @classmethod
    def load(cls, scenario):
        instance = cls()
        instance.microgrids = [
            Microgrid.load(
                (PROJECT_PATH/ f'data/scenario/{scenario}/microgrid_{j}/microgrid_{j}.yaml').open('r')
            ) for j in range(25)]

        return instance

    def _bin_genset_grid(self):
        rand = np.random.rand()
        bin_genset = 0
        bin_grid = 0

        if rand < 0.33:

            bin_genset = 1

        elif rand >= 0.33 and rand < 0.66:

            bin_grid = 1

        else:

            bin_genset = 1
            bin_grid = 1

        return bin_genset, bin_grid

    def _size_load(self, size_load=None):
        if size_load is None:
            return np.random.randint(low=100,high=100001)
        else:
            return size_load

    def _create_microgrid(self):
        """
        Function used to create one microgrid. First selecting a load file, and a load size  and a randome architecture
        and then size the other components of the microgrid depending on the load size. This function also initializes
        the tracking dataframes to be used in microgrid.
        """

        # get the sizing data
        # create microgrid object and append
        # return the list

        bin_genset, bin_grid = self._bin_genset_grid()

        architecture = {'PV':1, 'battery':1, 'genset':bin_genset, 'grid':bin_grid}
        size_load = self._size_load()
        load = self._scale_ts(self._get_load_ts(), size_load, scaling_method='max') #obtain dataframe of loads
        size = self._size_mg(load, size_load) #obtain a dictionary of mg sizing components
        column_actions=[]
        column_actual_production=[]
        column_cost = []
        grid_ts=[]
        grid_price_export_ts = []
        grid_price_import_ts = []
        grid_co2_ts = []
        df_parameters = pd.DataFrame()
        # df_cost = {'cost':[]}
        df_status = {}
        df_co2 = {'co2':[]}

        df_parameters['load'] = [size_load]
        df_parameters['cost_loss_load'] = 10
        df_parameters['cost_overgeneration'] = 1
        df_parameters['cost_co2'] = 0.1
        #df_cost['cost'] = [0.0]
        df_status['load'] = [np.around(load.iloc[0,0],1)]# --> il y a doublon pour l'instant avec l'architecture PV, -> non si pas de pv la net load est juste la load
        df_status['hour'] = [0]
        column_actual_production.append('loss_load')
        column_actual_production.append('overgeneration')
        column_actions.append('load')
        column_cost.append('loss_load')
        column_cost.append('overgeneration')
        column_cost.append('co2')
        if architecture['PV'] == 1:

            df_parameters['PV_rated_power'] = np.around(size['pv'],2)
            column_actual_production.append('pv_consummed')
            column_actual_production.append('pv_curtailed')
            column_actions.append('pv_consummed')
            column_actions.append('pv_curtailed')
            column_actions.append('pv')
            pv = pd.DataFrame(self._scale_ts(self._get_pv_ts(), size['pv'], scaling_method='max'))
            df_status['pv'] = [np.around( pv.iloc[0].values[0],1)]

        if architecture['battery']==1:

            battery = self._get_battery(capa=size['battery']) #return a dictionary of battery characteristic
            df_parameters['battery_soc_0'] = battery['soc_0']
            df_parameters['battery_power_charge'] = battery['pcharge']
            df_parameters['battery_power_discharge'] = battery['pdischarge']
            df_parameters['battery_capacity'] = battery['capa']
            df_parameters['battery_efficiency'] = battery['efficiency']
            df_parameters['battery_soc_min'] = battery['soc_min']
            df_parameters['battery_soc_max'] = battery['soc_max']
            df_parameters['battery_cost_cycle'] = battery['cost_cycle']
            column_actual_production.append('battery_charge')
            column_actual_production.append('battery_discharge')
            column_actions.append('battery_charge')
            column_actions.append('battery_discharge')
            column_cost.append('battery')
            df_status['battery_soc'] = [battery['soc_0']]

            capa_to_charge = max(
                (df_parameters['battery_soc_max'].values[0] * df_parameters['battery_capacity'].values[0] -
                 df_parameters['battery_soc_0'].iloc[-1] *
                 df_parameters['battery_capacity'].values[0]
                 ) / df_parameters['battery_efficiency'].values[0], 0)

            capa_to_discharge = max((df_parameters['battery_soc_0'].iloc[-1] *
                                     df_parameters['battery_capacity'].values[0]
                                     - df_parameters['battery_soc_min'].values[0] *
                                     df_parameters['battery_capacity'].values[0])
                                     * df_parameters['battery_efficiency'].values[0], 0)

            df_status['capa_to_charge'] = [np.around(capa_to_charge,1)]
            df_status['capa_to_discharge'] = [np.around(capa_to_discharge,1)]



        grid_spec=0

        if architecture['grid']==1:

            rand_weak_grid = np.random.randint(low=0, high=2)
            price_scenario = np.random.randint(low=1, high=3)
            if rand_weak_grid == 1:
                architecture['genset'] = 1
            grid = self._get_grid(rated_power=size['grid'], weak_grid=rand_weak_grid, price_scenario=price_scenario)
            df_parameters['grid_weak'] = rand_weak_grid
            df_parameters['grid_power_import'] = grid['grid_power_import']
            df_parameters['grid_power_export'] = grid['grid_power_export']
            grid_ts = grid['grid_ts']
            #df_parameters['grid_price_import'] = grid['grid_price_import']
            #df_parameters['grid_price_export'] = grid['grid_price_export']
            column_actual_production.append('grid_import')
            column_actual_production.append('grid_export')
            column_actions.append('grid_import')
            column_actions.append('grid_export')
            column_cost.append('grid_import')
            column_cost.append('grid_export')
            df_status['grid_status'] = [grid_ts.iloc[0,0]]
            #todo Switch back to random file to generate the new version of pymgrid25
            grid_co2_ts = self._get_co2_ts() 
            df_status['grid_co2'] = [grid_co2_ts.iloc[0, 0]]

            grid_price_import_ts = grid['grid_price_import']
            grid_price_export_ts = grid['grid_price_export']
            df_status['grid_price_import'] = [grid_price_import_ts.iloc[0, 0]]
            df_status['grid_price_export'] = [grid_price_export_ts.iloc[0, 0]]

        if architecture['genset']==1:
            genset = self._get_genset(rated_power=size['genset'])
            df_parameters['genset_polynom_order'] = len(genset['polynom'])

            for i in range(len(genset['polynom'])):
                df_parameters['genset_polynom_'+str(i)]=genset['polynom'][i]

            df_parameters['genset_rated_power'] = genset['rated_power']
            df_parameters['genset_pmin'] = genset['pmin']
            df_parameters['genset_pmax'] = genset['pmax']
            df_parameters['fuel_cost'] = genset['fuel_cost']
            df_parameters['genset_co2'] = genset['co2']
            column_actual_production.append('genset')
            column_actions.append('genset')
            column_cost.append('genset')

        column_cost.append('total_cost')
        df_actions= {key:[] for key in column_actions}#pd.DataFrame(columns = column_actions, )
        df_actual_production = {key:[] for key in column_actual_production}#pd.DataFrame(columns=column_actual_production)
        df_cost = {key: [] for key in column_cost}

        microgrid_spec={
            'parameters':df_parameters, #Dictionary
            'df_actions':df_actions, #Dataframe
            'architecture':architecture, #Dictionary
            'df_status':df_status, #Dictionary
            'df_actual_generation':df_actual_production,#Dataframe
            'grid_spec':grid_spec, #value = 0
            'df_cost':df_cost, #Dataframe of 1 value = 0.0
            'df_co2': df_co2,
            'pv':pv, #Dataframe
            'load': load, #Dataframe
            'grid_ts':grid_ts, #Dataframe
            'control_dict': column_actions, #dictionnary
            'grid_price_import' : grid_price_import_ts,
            'grid_price_export' : grid_price_export_ts,
            'grid_co2': grid_co2_ts,
        }

        microgrid = NonModularMicrogrid(microgrid_spec)

        return microgrid
    ########################################################
    # PRINT / PLOT FUNCTIONS
    ########################################################

    # function to plot the parameters of all the microgrid generated
    def print_mg_parameters(self, id='all'):
        """ This function is used to print the parameters of all the generated microgrids."""

        if id == 'all':

            if self.microgrids != []:
                parameters = pd.DataFrame()
                for i in range(self.nb_microgrids):
                    parameters = parameters.append(self.microgrids[i].parameters, ignore_index=True)

                pd.options.display.max_columns = None
                display(parameters)

        elif isinstance(id, int) and id < self.nb_microgrids:
            display(self.microgrids[id].parameters)

    def print_all_costs(self):

        #one column ID, one run cost, one rule based, one mpc
        #if train test split, for each train and test
        df_cost = pd.DataFrame()
        for i in range(self.nb_microgrids):

            if self.microgrids[i]._has_train_test_split == False:

                cost_run = self.microgrids[i]._df_record_cost.sum().values
                cost_mpc = np.nan
                cost_rule_based = np.nan

                if self.microgrids[i]._has_run_mpc_baseline == True:
                    cost_mpc = np.around(self.microgrids[i]._baseline_linprog_cost.sum().values[0], 1)

                if self.microgrids[i]._has_run_rule_based_baseline == True:
                    cost_rule_based = np.around(self.microgrids[i]._baseline_priority_list_cost.sum().values[0],1)


            else:
                cost_run = self.microgrids[i]._df_record_cost.sum().values
                cost_mpc = np.nan
                cost_rule_based = np.nan

                if self.microgrids[i]._has_run_mpc_baseline == True:
                    cost_mpc = np.around(self.microgrids[i]._baseline_linprog_cost.iloc[self.microgrids[i]._limit_index:].sum().values[0],1)

                if self.microgrids[i]._has_run_rule_based_baseline == True:
                    cost_rule_based = np.around(self.microgrids[i]._baseline_priority_list_cost.iloc[self.microgrids[i]._limit_index:].sum().values[0],1)

            df_cost =df_cost.append({'ID':i, 'Cost': cost_run, 'Cost (MPC)': cost_mpc, 'Cost (rule-based)':cost_rule_based}, ignore_index=True)

        display(df_cost)


================================================
FILE: src/pymgrid/__init__.py
================================================
from pathlib import Path
from .version import __version__

PROJECT_PATH = Path(__file__).parent

from ._deprecated.non_modular_microgrid import NonModularMicrogrid
from .microgrid import Microgrid
from .MicrogridGenerator import MicrogridGenerator

from .utils import add_pymgrid_yaml_representers

import pymgrid.envs

__all__ = [
    'Microgrid',
    'MicrogridGenerator',
    'NonModularMicrogrid',
    'envs'
]

================================================
FILE: src/pymgrid/_deprecated/Environments/Environment.py
================================================
"""
Copyright 2020 Total S.A
Authors:Gonzague Henri <gonzague.henri@total.com>
Permission to use, modify, and distribute this software is given under the
terms of the pymgrid License.
NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
$Date: 2020/10/21 07:43 $
Gonzague Henri
"""

"""
<pymgrid is a Python library to simulate microgrids>
Copyright (C) <2020> <Total S.A.>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
"""

import numpy as np
import gym
from gym.utils import seeding
from gym.spaces import Space, Discrete, Box
from . import Preprocessing
from pymgrid.algos.saa.saa import SampleAverageApproximation

DEFAULT_CONFIG={
    'microgrid': None, #need to be passed by user
    'training_reward_smoothing':'sqrt', #'peak_load'
    'resampling_on_reset':True,
    'forecast_args':None, #used to init the SAA for resampling on reset
    'baseline_sampling_args':None,
}

def generate_sampler(microgrid, forecast_args):
    """
    Generates an instance of SampleAverageApproximate to use in future sampling.
    :param microgrid:
    :param forecast_args:
    :return:
    """
    if forecast_args is None:
        forecast_args = dict()

    return SampleAverageApproximation(microgrid, **forecast_args)

class Environment(gym.Env):
    """
    Markov Decision Process associated to the microgrid.
        Parameters
        ----------
            microgrid: microgrid, mandatory
                The controlled microgrid.
            random_seed: int, optional
                Seed to be used to generate the needed random numbers to size microgrids.
    """

    def __init__(self, env_config, seed = 42):
        # Set seed
        np.random.seed(seed)

        self.states_normalization = Preprocessing.normalize_environment_states(env_config['microgrid'])

        self.TRAIN = True
        # Microgrid
        self.env_config = env_config
        self.mg = env_config['microgrid']
        # State space
        self.mg.train_test_split()
        #np.zeros(2+self.mg.architecture['grid']*3+self.mg.architecture['genset']*1)
        # Number of states
        self.Ns = len(self.mg._df_record_state.keys())+1
        # Number of actions

        #training_reward_smoothing
        try:
            self.training_reward_smoothing = env_config['training_reward_smoothing']
        except:
            self.training_reward_smoothing = 'sqrt'

        try:
            self.resampling_on_reset = env_config['resampling_on_reset']
        except:
            self.resampling_on_reset = False
        
        if self.resampling_on_reset == True:
            self.forecast_args = env_config['forecast_args']
            self.baseline_sampling_args = env_config['baseline_sampling_args']
            self.saa = generate_sampler(self.mg, self.forecast_args)
        
        self.observation_space = Box(low=-1, high=np.float('inf'), shape=(self.Ns,), dtype=np.float)
        #np.zeros(len(self.mg._df_record_state.keys()))
        # Action space
        self.metadata = {"render.modes": [ "human"]}
        
        self.state, self.reward, self.done, self.info, self.round = None, None, None, None, None
        self.round = None

        # Start the first round
        self.seed()
        self.reset()
        

        try:
            assert (self.observation_space.contains(self.state))
        except AssertionError:
            print("ERROR : INVALID STATE", self.state)

    def get_reward(self):
        if self.TRAIN == True:
            if self.training_reward_smoothing == 'sqrt':
                return -(self.mg.get_cost()**0.5)
            if self.training_reward_smoothing == 'peak_load':
                return -self.mg.get_cost()/self.mg.parameters['load'].values[0]
        return -self.mg.get_cost()

    def get_cost(self):
        return sum(self.mg._df_record_cost['cost'])



    def step(self, action):

        # CONTROL
        if self.done:
            print("WARNING : EPISODE DONE")  # should never reach this point
            return self.state, self.reward, self.done, self.info
        try:
            assert (self.observation_space.contains(self.state))
        except AssertionError:
            print("ERROR : INVALID STATE", self.state)

        try:
            assert (self.action_space.contains(action))
        except AssertionError:
            print("ERROR : INVALD ACTION", action)

        # UPDATE THE MICROGRID
        control_dict = self.get_action(action)
        self.mg.run(control_dict)

        # COMPUTE NEW STATE AND REWARD
        self.state = self.transition()
        self.reward = self.get_reward()
        self.done = self.mg.done
        self.info = {}
        self.round += 1

        return self.state, self.reward, self.done, self.info
        
#         control_dict = self.get_action(action)
#         self.mg.run(control_dict)
#         reward = self.reward()
#         s_ = self.transition()
#         self.state = s_
#         done = self.mg.done
#         self.round += 1
#         return s_, reward, done, {}

    def reset(self, testing=False):
        if "testing" in self.env_config:
            testing = self.env_config["testing"]
        self.round = 1
        # Reseting microgrid
        self.mg.reset(testing=testing)
        if testing == True:
            self.TRAIN = False
        elif self.resampling_on_reset == True:
            Preprocessing.sample_reset(self.mg.architecture['grid'] == 1, self.saa, self.mg, sampling_args=self.sampling_args)
        
        
        self.state, self.reward, self.done, self.info =  self.transition(), 0, False, {}
        
        return self.state


    def get_action(self, action):
        """
        :param action: current action
        :return: control_dict : dicco of controls
        """
        '''
        States are:
        binary variable whether charging or dischargin
        battery power, normalized to 1
        binary variable whether importing or exporting
        grid power, normalized to 1
        binary variable whether genset is on or off
        genset power, normalized to 1
        '''

        control_dict=[]

        return control_dict

    def states(self):  # soc, price, load, pv 'df status?'
        observation_space = []
        return observation_space

    # Transition function
    def transition(self):
        #         net_load = round(self.mg.load - self.mg.pv)
        #         soc = round(self.mg.battery.soc,1)
        #         s_ = (net_load, soc)  # next state
        updated_values = self.mg.get_updated_values()
        updated_values = {x:float(updated_values[x])/self.states_normalization[x] for x in self.states_normalization}  
        updated_values['hour_sin'] = np.sin(2*np.pi*updated_values['hour']) # the hour is already divided by 24 in the line above
        updated_values['hour_cos'] = np.cos(2*np.pi*updated_values['hour'])  
        updated_values.pop('hour', None)

        s_ = np.array(list(updated_values.values()))
        #np.array(self.mg.get_updated_values().values)#.astype(np.float)#self.mg.get_updated_values()
        #s_ = [ s_[key] for key in s_.keys()]
        return s_
    
    def seed (self, seed=None):
        self.np_random, seed = seeding.np_random(seed)
        return [seed]
    
    def render(self, mode="human"):
        txt = "state: " + str(self.state) + " reward: " + str(self.reward) + " info: " + str(self.info)
        print(txt)

    # Mapping between action and the control_dict
    def get_action_continuous(self, action):
        """
        :param action: current action
        :return: control_dict : dicco of controls
        """
        '''
        Actions are:
        binary variable whether charging or dischargin
        battery power, normalized to 1
        binary variable whether importing or exporting
        grid power, normalized to 1
        binary variable whether genset is on or off
        genset power, normalized to 1
        '''

        mg = self.mg
        pv = mg.pv
        load = mg.load
        net_load = load - pv
        capa_to_charge = mg.battery.capa_to_charge
        p_charge_max = mg.battery.p_charge_max
        p_charge = max(0, min(-net_load, capa_to_charge, p_charge_max))

        capa_to_discharge = mg.battery.capa_to_discharge
        p_discharge_max = mg.battery.p_discharge_max
        p_discharge = max(0, min(net_load, capa_to_discharge, p_discharge_max))

        control_dict = {}

        if mg.architecture['battery'] == 1:
            control_dict['battery_charge'] = max(0, action[0] * min(action[1] * mg.battery.capacity,
                                                                    mg.battery.capa_to_charge,
                                                                    mg.battery.p_charge_max))
            control_dict['battery_discharge'] = max(0, (1 - action[0]) * min(action[1] * mg.battery.capacity,
                                                                             mg.battery.capa_to_discharge,
                                                                             mg.battery.p_discharge_max))

        if mg.architecture['grid'] == 1:
            if mg.grid.status == 1:
                control_dict['grid_import'] = max(0, action[2] * min(action[3] * mg.grid.power_import,
                                                                     mg.grid.power_import))
                control_dict['grid_export'] = max(0, (1 - action[2]) * min(action[3] * mg.grid.power_export,
                                                                           mg.grid.power_export))
            else:
                # avoid warnings
                control_dict['grid_import'] = 0
                control_dict['grid_export'] = 0

        if mg.architecture['genset'] == 1:
            control_dict['genset'] = max(0, action[4] * min(action[5] * mg.genset.rated_power,
                                                            mg.genset.rated_power))
        return control_dict

    def get_action_discrete(self, action):
        """
        :param action: current action
        :return: control_dict : dicco of controls
        """
        '''
        Actions are:
        binary variable whether charging or dischargin
        battery power, normalized to 1
        binary variable whether importing or exporting
        grid power, normalized to 1
        binary variable whether genset is on or off
        genset power, normalized to 1
        '''
        control_dict={}

        control_dict['pv_consumed'] = action[0]
        if self.mg.architecture['battery'] == 1:
            control_dict['battery_charge'] = action[1] * action[3]
            control_dict['battery_discharge'] =  action[2] * (1- action[3])

        if self.mg.architecture['genset'] == 1:
            control_dict['genset'] = action[4]

            if self.mg.architecture['grid'] == 1:
                control_dict['grid_import'] = action[5] * action[7]
                control_dict['grid_export'] = action[6] * (1- action[7])

        elif self.mg.architecture['grid'] == 1:
            control_dict['grid_import'] = action[4] * action[6]
            control_dict['grid_export'] = action[5] * (1 - action[6])




        return control_dict

    # Mapping between action and the control_dict
    def get_action_priority_list(self, action):
        """
        :param action: current action
        :return: control_dict : dicco of controls
        """
        '''
        States are:
        binary variable whether charging or dischargin
        battery power, normalized to 1
        binary variable whether importing or exporting
        grid power, normalized to 1
        binary variable whether genset is on or off
        genset power, normalized to 1
        '''

        mg = self.mg
        pv = mg.pv
        load = mg.load
        net_load = load - pv
        capa_to_charge = mg.battery.capa_to_charge
        p_charge_max = mg.battery.p_charge_max
        p_charge = max(0, min(-net_load, capa_to_charge, p_charge_max))

        capa_to_discharge = mg.battery.capa_to_discharge
        p_discharge_max = mg.battery.p_discharge_max
        p_discharge = max(0, min(net_load, capa_to_discharge, p_discharge_max))

        control_dict = {}

        control_dict = self.actions_agent_discret(mg, action)

        return control_dict


    def actions_agent_discret(self, mg, action):
        if mg.architecture['genset'] == 1 and mg.architecture['grid'] == 1:
            control_dict = self.action_grid_genset(mg, action)

        elif mg.architecture['genset'] == 1 and mg.architecture['grid'] == 0:
            control_dict = self.action_genset(mg, action)

        else:
            control_dict = self.action_grid(mg, action)

        return control_dict

    def action_grid(self, mg, action):
        # slack is grid

        pv = mg.pv
        load = mg.load

        net_load = load - pv

        capa_to_charge = mg.battery.capa_to_charge
        p_charge_max = mg.battery.p_charge_max
        p_charge_pv = max(0, min(-net_load, capa_to_charge, p_charge_max))
        p_charge_grid = max(0, min( capa_to_charge, p_charge_max))

        capa_to_discharge = mg.battery.capa_to_discharge
        p_discharge_max = mg.battery.p_discharge_max
        p_discharge = max(0, min(net_load, capa_to_discharge, p_discharge_max))

        # Charge
        if action == 0:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': p_charge_pv,
                            'battery_discharge': 0,
                            'grid_import': 0,
                            'grid_export': max(0, pv - min(pv, load) - p_charge_pv),
                            'genset': 0
                            }
        
        if action == 4:
            load = load + p_charge_grid
            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': p_charge_grid,
                            'battery_discharge': 0,
                            'grid_import': max(0, load - min(pv, load)),
                            'grid_export': max(0, pv - min(pv, load) - p_charge_grid) ,
                            'genset': 0
                            }


        # décharger full
        elif action == 1:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': p_discharge,
                            'grid_import': max(0, load - min(pv, load) - p_discharge),
                            'grid_export': 0,
                            'genset': 0
                            }

        # Import
        elif action == 2:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': 0,
                            'grid_import': max(0, net_load),
                            'grid_export': 0,
                            'genset': 0
                            }
        # Export
        elif action == 3:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': 0,
                            'grid_import': 0,
                            'grid_export': abs(min(net_load, 0)),
                            'genset': 0
                            }

        return control_dict

    def action_grid_genset(self, mg, action):
        # slack is grid

        pv = mg.pv
        load = mg.load

        net_load = load - pv
        status = mg.grid.status  # whether there is an outage or not
        capa_to_charge = mg.battery.capa_to_charge
        p_charge_max = mg.battery.p_charge_max
        p_charge_pv = max(0, min(-net_load, capa_to_charge, p_charge_max))
        p_charge_grid = max(0, min( capa_to_charge, p_charge_max))

        capa_to_discharge = mg.battery.capa_to_discharge
        p_discharge_max = mg.battery.p_discharge_max
        p_discharge = max(0, min(net_load, capa_to_discharge, p_discharge_max))

        capa_to_genset = mg.genset.rated_power * mg.genset.p_max
        p_genset = max(0, min(net_load, capa_to_genset))

        # Charge
        if action == 0:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': p_charge_pv,
                            'battery_discharge': 0,
                            'grid_import': 0,
                            'grid_export': max(0, pv - min(pv, load) - p_charge_pv) * status,
                            'genset': 0
                            }
        if action == 5:
            load = load+p_charge_grid

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': p_charge_grid,
                            'battery_discharge': 0,
                            'grid_import': max(0, load - min(pv, load)) * status,
                            'grid_export': max(0, pv - min(pv, load) - p_charge_grid) * status,
                            'genset': 0
                            }


        # décharger full
        elif action == 1:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': p_discharge,
                            'grid_import': max(0, load - min(pv, load) - p_discharge) * status,
                            'grid_export': 0,
                            'genset': 0
                            }

        # Import
        elif action == 2:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': 0,
                            'grid_import': max(0, net_load) * status,
                            'grid_export': 0,
                            'genset': 0
                            }
        # Export
        elif action == 3:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': 0,
                            'grid_import': 0,
                            'grid_export': abs(min(net_load, 0)) * status,
                            'genset': 0
                            }
        # Genset
        elif action == 4:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': 0,
                            'grid_import': 0,
                            'grid_export': 0,
                            'genset': max(net_load, 0)
                            }

        elif action == 6:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': p_discharge,
                            'grid_import': 0,
                            'grid_export': 0,
                            'genset': max(0, load - min(pv, load) - p_discharge),
                            }

        return control_dict

    def action_genset(self, mg, action):
        # slack is genset

        pv = mg.pv
        load = mg.load

        net_load = load - pv

        capa_to_charge = mg.battery.capa_to_charge
        p_charge_max = mg.battery.p_charge_max
        p_charge = max(0, min(-net_load, capa_to_charge, p_charge_max))

        capa_to_discharge = mg.battery.capa_to_discharge
        p_discharge_max = mg.battery.p_discharge_max
        p_discharge = max(0, min(net_load, capa_to_discharge, p_discharge_max))

        capa_to_genset = mg.genset.rated_power * mg.genset.p_max
        p_genset = max(0, min(net_load, capa_to_genset))

        # Charge
        if action == 0:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': p_charge,
                            'battery_discharge': 0,
                            'grid_import': 0,
                            'grid_export': 0,
                            'genset': 0
                            }


        # décharger full
        elif action == 1:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': p_discharge,
                            'grid_import': 0,
                            'grid_export': 0,
                            'genset': max(0, load - min(pv, load) - p_discharge)
                            }

        # Genset
        elif action == 2:

            control_dict = {'pv_consummed': min(pv, load),
                            'battery_charge': 0,
                            'battery_discharge': 0,
                            'grid_import': 0,
                            'grid_export': 0,
                            'genset': max(0, load - min(pv, load))
                            }

        return control_dict


================================================
FILE: src/pymgrid/_deprecated/Environments/Preprocessing.py
================================================
import pandas as pd

def normalize_environment_states(mg):
    max_values = {}
    for keys in mg._df_record_state:
        if keys == 'hour':
            max_values[keys] = 24
        elif keys == 'capa_to_charge' or keys == 'capa_to_discharge' :
            max_values[keys] = mg.parameters.battery_capacity.values[0]
        elif keys == 'grid_status' or keys == 'battery_soc':
            max_values[keys] = 1
        elif keys == 'grid_co2':
            max_values[keys] = max(mg._grid_co2.values[0])
        elif keys == 'grid_price_import':
            max_values[keys] = max(mg._grid_price_import.values[0]) 
        elif keys == 'grid_price_export':
            max_values[keys] = max(mg._grid_price_import.values[0]) 
        elif keys == 'load':
            max_values[keys] = mg.parameters.load.values[0]
        elif keys == 'pv':
            max_values[keys] = mg.parameters.PV_rated_power.values[0]
        else:
            max_values[keys] = mg.parameters[keys].values[0] 
            
    return max_values

def sample_reset(has_grid, saa, microgrid, sampling_args=None):
    """
    Generates a new sample using an instance of SampleAverageApproximation and
    :param has_grid: bool, whether the microgrid has a grid.
    :param saa:, SampleAverageApproximation
    :param microgrid: Microgrid
    :param sampling_args: arguments to be passed to saa.sample_from_forecasts().
    :return:
    """
    if sampling_args is None:
        sampling_args = dict()

    sample = saa.sample_from_forecasts(n_samples=1, **sampling_args)
    sample = sample[0]

    microgrid._load_ts = pd.DataFrame(sample['load'])
    microgrid._pv_ts = pd.DataFrame(sample['pv'])
    microgrid._df_record_state['load'] = [sample['load'].iloc[0].squeeze()]
    microgrid._df_record_state['pv'] = [sample['pv'].iloc[0].squeeze()]
    if has_grid:
        microgrid._grid_status_ts = pd.DataFrame(sample['grid'])
        microgrid._df_record_state['grid_status'] = [sample['grid'].iloc[0].squeeze()]

================================================
FILE: src/pymgrid/_deprecated/Environments/__init__.py
================================================



================================================
FILE: src/pymgrid/_deprecated/Environments/pymgrid_csca.py
================================================
from abc import ABC
import gym, logging, numpy as np, pandas as pd
from gym import Env
from pymgrid._deprecated.non_modular_microgrid import NonModularMicrogrid
from pymgrid.MicrogridGenerator import MicrogridGenerator
from copy import deepcopy
from pymgrid.algos.saa.saa import SampleAverageApproximation
from pymgrid.algos import ModelPredictiveControl

logger = logging.getLogger(__name__)
LOG = False
DEBUG = True

# If you get a JSON serializable error, turn this on:
JSON_ERROR = False


def sample_reset(has_grid, saa, microgrid, sampling_args=None):
    """
    Generates a new sample using an instance of SampleAverageApproximation and
    :param has_grid: bool, whether the microgrid has a grid.
    :param saa:, SampleAverageApproximation
    :param microgrid: Microgrid
    :param sampling_args: arguments to be passed to saa.sample_from_forecasts().
    :return:
    """
    if sampling_args is None:
        sampling_args = dict()

    sample = saa.sample_from_forecasts(n_samples=1, **sampling_args)
    sample = sample[0]

    microgrid._load_ts = pd.DataFrame(sample['load'])
    microgrid._pv_ts = pd.DataFrame(sample['pv'])
    microgrid._df_record_state['load'] = [sample['load'].iloc[0].squeeze()]
    microgrid._df_record_state['pv'] = [sample['pv'].iloc[0].squeeze()]
    if has_grid:
        microgrid._grid_status_ts = pd.DataFrame(sample['grid'])
        microgrid._df_record_state['grid_status'] = [sample['grid'].iloc[0].squeeze()]


def generate_sampler(microgrid, forecast_args):
    """
    Generates an instance of SampleAverageApproximate to use in future sampling.
    :param microgrid:
    :param forecast_args:
    :return:
    """
    if forecast_args is None:
        forecast_args = dict()

    return SampleAverageApproximation(microgrid, **forecast_args)


class MicrogridEnv(Env, ABC):
    metadata = {'render.modes': ['human']}

    def __init__(self, microgrid, trajectory_len=None, max_episode_len=None):
        """
        :param max_episode_len:
        :param microgrid: Microgrid, the underlying microgrid.
        :param trajectory_len: int, length of a trajectory (to be started at a random index).
            Default None, runs an entire year
        """
        super().__init__()

        if isinstance(microgrid, int) and 0<=microgrid<=25:
            print('Initializing microgrid {} of 25 using 25 microgrids from MicrogridGenerator'.format(microgrid))
            m_gen = MicrogridGenerator(nb_microgrid=25)
            m_gen.generate_microgrid(verbose=False)
            self.microgrid = deepcopy(m_gen.microgrids[microgrid])

        elif isinstance(microgrid, NonModularMicrogrid):
            self.microgrid = deepcopy(microgrid)

        else:
            raise ValueError('microgrid must be of type Microgrid, is {}'.format(type(microgrid)))

        assert self.microgrid._data_length == 8760, 'Microgrid data length should be 8760, is {}'.format(self.microgrid._data_length)

        self.has_grid = self.microgrid.architecture['grid'] == 1
        self.has_genset = self.microgrid.architecture['genset'] == 1

        observation_dim = len(self.microgrid._df_record_state)
        self.observation_space = gym.spaces.Box(low=0, high=np.float('inf'), shape=(observation_dim,), dtype=np.float64)
        self.action_space = None

        self.current_action = None
        self.current_obs = None


        if max_episode_len is None:
            self.microgrid.horizon = 0
        else:
            self.microgrid.horizon = self.microgrid._data_length - max_episode_len

        self.trajectory_len = trajectory_len
        self._short_trajectory_set()


    def _short_trajectory_set(self):
        trajectory_len = self.trajectory_len
        if trajectory_len is not None:
            assert isinstance(trajectory_len, int)
            from numpy.random import randint
            high_range = self.microgrid._data_length - self.microgrid.horizon - trajectory_len

            start_index = randint(low=0, high=high_range)
            self.microgrid._tracking_timestep = start_index
            self.microgrid._data_length = start_index + trajectory_len + self.microgrid.horizon

    def reset(self):
        self.microgrid.reset()
        self._short_trajectory_set()

        initial_state = self.microgrid.get_updated_values()
        observations = np.array(list(initial_state.values()))

        self.current_obs = observations

        return observations

    def step(self, action, **kwargs):
        """
        :param **kwargs:
        :param
            action:
        :return:
            observation, np.ndarray
                If self.has_grid, shape (10,), with values
                        [load, hour, pv, battery_soc, capa_to_charge, capa_to_discharge,
                            grid_status, grid_co2, grid_price_import, grid_price_export]
                Else, shape (6,), with values
                        [load, hour, pv, battery_soc, capa_to_charge, capa_to_discharge]
            reward, float
                The reward (negative cost) of the step
            done, bool
                Whether the episode is complete
            info, dict
                Info

        """
        control_dict = self.get_control_dict(action)
        observation = self.run_control(control_dict)
        reward = -1.0 * self.microgrid.get_cost()
        done = self.microgrid.done
        info = dict()

        self.current_obs = observation
        self.current_action = action

        return observation, reward, done, info

    def get_control_dict(self, action):
        """
        A function that takes an action (discrete or continuous) and returns a control_dict.
            See ContinuousMicrogridEnv for an example.
        """
        return NotImplemented

    def run_control(self, control_dict):
        """
        Given a control_dict, calls microgrid.run(_) and returns the observations.
        :param control_dict:
        :return: observations, np.ndarray
        """
        updated_vals = self.microgrid.run(control_dict)
        observations = np.array(list(updated_vals.values()))

        assert len(observations) == self.observation_space.shape[0]
        return observations


class ContinuousMicrogridEnv(MicrogridEnv):
    """
    Class to run a Microgrid in the format of a gym env. Continuous states, continuous actions.
    """
    def __init__(self, microgrid, standardization=True, trajectory_len=None, max_episode_len=None, **kwargs):
        """
        :param microgrid: Microgrid, the underlying microgrid.
        :param standardization: bool, default True. whether to scale the actions to a factor determined by a run of MPC.
        """
        super().__init__(microgrid, trajectory_len=trajectory_len, max_episode_len=max_episode_len)

        self.logger = kwargs['logger'] if 'logger' in kwargs else None

        action_dim = 5+self.has_genset
        upper_bound, lower_bound = self._get_action_ub_lb()

        self.action_space = gym.spaces.Box(low=lower_bound, high=upper_bound, shape=(action_dim,), dtype=np.float64)

        self.standardization = standardization
        if not JSON_ERROR and self.standardization:
            self.standardizations = self.pre_compute_standardizations()

            # Rescale the action space
            low_new = self.standardize(self.action_space.low, use_proxy='action')
            self.action_space.low = low_new
            high_new = self.standardize(self.action_space.high, use_proxy='action')
            high_new[1] = 0.1 # This is a hard-coded grid_export bound
            self.action_space.high = high_new
        else:
            self.standardizations = None

    def _get_action_ub_lb(self):
        # Upper Bound
        p_max_import = self.microgrid.parameters['grid_power_import'].values[0]
        p_max_export = self.microgrid.parameters['grid_power_export'].values[0]
        p_max_charge = self.microgrid.parameters['battery_power_charge'].values[0]
        p_max_discharge = self.microgrid.parameters['battery_power_discharge'].values[0]
        pv_max = self.microgrid.parameters.PV_rated_power.squeeze()

        upper_bound = [p_max_import, p_max_export, p_max_charge, p_max_discharge, pv_max]

        if self.has_genset:
            p_genset_max = self.microgrid.parameters['genset_rated_power'].values[0] * self.microgrid.parameters['genset_pmax'].values[0]
            upper_bound.insert(0,p_genset_max)

        upper_bound = np.array(upper_bound)

        # Lower Bound

        lower_bound = [0]*5

        if self.has_genset:
            action_dim = 6
            p_genset_min = self.microgrid.parameters['genset_rated_power'].values[0] * \
                           self.microgrid.parameters['genset_pmin'].values[0]
            lower_bound.insert(0, p_genset_min)

        lower_bound = np.array(lower_bound)

        return upper_bound, lower_bound



    def get_values(self, *value_names):
        # TODO Speed this up. Refactor standardizations. nan_to_num takes significant time.
        """
        Helper function. Given a list of value names (e.g., the names of components of the state/actions),
            returns their values in the same order.
        Note: if the env standardizes values, this function returns the unstandarized values.
        :param value_names:
        :return:
        """
        genset_actions = ['genset', 'grid_import', 'grid_export', 'battery_charge', 'battery_discharge', 'pv_consummed']
        no_genset_actions = ['grid_import', 'grid_export', 'battery_charge', 'battery_discharge', 'pv_consummed']

        grid_observations = ['load', 'hour', 'pv', 'battery_soc', 'capa_to_charge', 'capa_to_discharge',
                            'grid_status', 'grid_co2', 'grid_price_import', 'grid_price_export']
        no_grid_observations = ['load', 'hour', 'pv', 'battery_soc', 'capa_to_charge', 'capa_to_discharge']

        if self.current_action is None:
            print('Warning: current_action is None, should only happen on first iteration')
            if self.has_genset:
                self.current_action = np.array([0]*len(genset_actions))
            else:
                self.current_action = np.array([0]*len(no_genset_actions))

            action = self.current_action
            obs = self.current_obs

        elif self.standardization:
            obs_mean, obs_std, action_mean, action_std = self.standardizations
            action = self.standardize(self.current_action, action_mean, action_std, direction='backward')
            obs = self.standardize(self.current_obs, obs_mean, obs_std, direction='backward')
        else:
            action = self.current_action
            obs = self.current_obs

        if self.has_genset:
            actions_dict = dict(zip(genset_actions, action))
        else:
            actions_dict = dict(zip(no_genset_actions, action))
        if self.has_grid:
            obs_dict = dict(zip(grid_observations, obs))
        else:
            obs_dict = dict(zip(no_grid_observations, obs))

        values = []


        for name in value_names:
            if name in actions_dict.keys():
                values.append(actions_dict[name])
            elif name in obs_dict.keys():
                values.append(obs_dict[name])
            else:
                raise ValueError('Value \'{}\' not recognized with current architecture'.format(name))

        return values

    def reset(self):
        observation = super().reset()
        if self.standardization:
            obs_mean, obs_std, action_mean, action_std = self.standardizations
            observation = self.standardize(observation, obs_mean, obs_std, direction='forward')
            self.current_obs = observation

        return observation



    def step(self, action, **kwargs):
        """
        :param **kwargs:
        :param
            action: np.ndarray
                If self.has_genset: shape (6,), with values
                    [genset, grid_import, grid_export, battery_charge, battery_discharge, pv_consummed]
                Else: shape (5,), with values
                    [grid_import, grid_export, battery_charge, battery_discharge, pv_consummed]
        :return:
            observation, np.ndarray
                If self.has_grid, shape (10,), with values
                        [load, hour, pv, battery_soc, capa_to_charge, capa_to_discharge,
                            grid_status, grid_co2, grid_price_import, grid_price_export]
                Else, shape (6,), with values
                        [load, hour, pv, battery_soc, capa_to_charge, capa_to_discharge]
            reward, float
                The reward (negative cost) of the step
            done, bool
                Whether the episode is complete
            info, dict
                Info

        """
        # Actions must be passed in order as defined in pymgrid25 paper
        assert isinstance(action, np.ndarray)

        unscaled_action = action.copy()

        if self.standardization:
            if not isinstance(action, np.ndarray):
                raise TypeError('action must be of type np.ndarray')

            obs_mean, obs_std, action_mean, action_std = self.standardizations

            action = self.standardize(action, action_mean, action_std, direction='backward')

        observation, reward, done, info = super().step(action)

        if self.standardization:
            observation = self.standardize(observation, obs_mean, obs_std, direction='forward')

        self.current_obs = observation
        self.current_action = unscaled_action

        # Do you want to deal w everything in normalized space or unnormalized space

        return observation, reward, done, info


    def standardize(self, data, mean_proxy=None, std_proxy=None, direction='forward', use_proxy=None):
        """
        :param data: np.ndarray, shape (observation_dim,) or (action_dim), observation or action to rescale
        :param mean_proxy: np.ndarray, shape (observation_dim,) or (action_dim), mean to use in rescaling
        :param std_proxy: np.ndarray, shape (observation_dim,) or (action_dim), standard deviation to use in rescaling
        :param direction: str, default 'forward'. One of 'forward' or 'backward', whether to scale to or from standard normal
        :return: np.ndarray, rescaled values.
        """

        if (mean_proxy is None and std_proxy is None and use_proxy is None) or (mean_proxy is not None and use_proxy is not None):
            raise ValueError('Must pass mean_proxy and std_proxy, or use_proxy must be a str in (\'action\', \'obs\'), but not both')
        if mean_proxy is None and std_proxy is None:
            if use_proxy == 'action':
                mean_proxy, std_proxy = [x for x in self.standardizations[2:]]
            elif use_proxy == 'obs':
                mean_proxy, std_proxy = [x for x in self.standardizations[:2]]
            else:
                raise NameError('Unable to recognize use_proxy {}, must be one of \'action\' or \'obs\''.format(use_proxy))


        names = ('data', 'mean_proxy', 'std_proxy')
        vals = (data, mean_proxy, std_proxy)
        dirs = ('forward', 'backward')

        for name, v in zip(names, vals):
            if not isinstance(v, np.ndarray):
                raise TypeError('{} must be of type numpy.ndarray, is {}'.format(name, type(v)))
        if not (data.shape == mean_proxy.shape and mean_proxy.shape == std_proxy.shape):
            raise ValueError('Incompatible shapes of data, mean_proxy, std_proxy. Must be equal, are: {}'.format(
                dict(zip(names, [v.shape for v in vals]))))

        if direction not in dirs:
            raise ValueError('direction must be one of {}'.format(dirs))

        if direction == 'forward':
            return (data-mean_proxy)/std_proxy
        else:
            return data*std_proxy+mean_proxy

    def pre_compute_standardizations(self,alg_to_use='mpc'):
        """
        Runs a control algorithm to pre compute the standardizations for actions/observations to rescale to standard normal (ish).
        :param alg_to_use: str, default 'mpc'. What algorithm to run to compute the standardizations
        :return: tuple len(4,): obs_mean, obs_std, action_mean, action_std
        """

        action_mean = [0]*self.action_space.shape[0]
        action_std = [0]*self.action_space.shape[0]
        obs_mean = [0]*self.observation_space.shape[0]
        obs_std = [0]*self.observation_space.shape[0]

        if alg_to_use == 'mpc':
            old_horizon = self.microgrid.horizon
            self.microgrid.horizon = 24
            MPC = ModelPredictiveControl(self.microgrid)
            mpc_output = MPC.run(max_steps=1000)
            self.microgrid.horizon = old_horizon
            if self.has_genset:

                action_keys = 'genset', 'grid_import, grid_export, battery_charge, battery_discharge, pv_consummed'

                for j, name in enumerate(action_keys):
                    action_mean[j] = np.mean(mpc_output['action'][name])
                    action_std[j] = np.std(mpc_output['action'][name])

                obs_keys = list(self.microgrid._df_record_state.keys())

                for j, name in enumerate(obs_keys):
                    obs_mean[j] = np.mean(mpc_output['status'][name])
                    obs_std[j] = np.std(mpc_output['status'][name])

            else:
                action_keys = 'grid_import', 'grid_export', 'battery_charge', 'battery_discharge', 'pv_consummed'

                for j, name in enumerate(action_keys):
                    action_mean[j] = np.mean(mpc_output['action'][name])
                    action_std[j] = np.std(mpc_output['action'][name])

                obs_keys = list(self.microgrid._df_record_state.keys())

                for j, name in enumerate(obs_keys):
                    obs_mean[j] = np.mean(mpc_output['status'][name])
                    obs_std[j] = np.std(mpc_output['status'][name])
        else:
            raise RuntimeError('algorithm name {} not currently supported'.format(alg_to_use))

        for j in range(len(obs_std)):
            if obs_std[j] < 1.0:
                obs_std[j] = 1.0
        for j in range(len(action_std)):
            if action_std[j] < 1.0:
                action_std[j] = 1.0

        names = ('obs_mean', 'obs_std', 'action_mean', 'action_std')
        outputs = obs_mean, obs_std, action_mean, action_std
        outputs = tuple(np.array(output) for output in outputs)

        for name, output in zip(names,outputs):
            if (output == 0).sum() != 0:
                for j,val in enumerate(output):
                    if val == 0:
                        print('Warning: Zero value in pos {} in {}, may not have been filled properly'.format(j,name))

        return outputs

    def get_control_dict(self, action):
        """
        Given an np.ndarray of actions, parses into a control_dict.
        :param action: np.ndarray, shape (action_dim,)
        :return: dict, control_dict
        """

        if not isinstance(action, np.ndarray):
            raise TypeError('action must be an ndarray, is {}'.format(type(action)))

        if self.has_genset:

            control_dict = {'battery_charge': action[3],
                            'battery_discharge': action[4],
                            'genset': action[0],
                            'grid_import': action[1],
                            'grid_export': action[2],
                            'pv_consummed': action[5]}
        else:
            control_dict = {'battery_charge': action[2],
                            'battery_discharge': action[3],
                            'grid_import': action[0],
                            'grid_export': action[1],
                            'pv_consummed': action[4]}

        return control_dict


class ContinuousMicrogridSampleEnv(ContinuousMicrogridEnv):
    """
    Same as ContinuousMicrogridEnv but uses samples generated from SampleAverageApproximation as states.
    """
    metadata = {'render.modes': ['human']}
    def __init__(self, microgrid, standardization=True,
                 forecast_args=None, baseline_sampling_args=None, max_episode_len=None):

        super().__init__(microgrid, standardization=standardization, max_episode_len=max_episode_len)
        self.forecast_args = forecast_args
        self.baseline_sampling_args = baseline_sampling_args
        self.saa = generate_sampler(self.microgrid, forecast_args)

    def reset(self, sampling_args=None):
        """
        Generates a new sample to use as load/pv/grid data. Then calls parent reset function.
        :param sampling_args:
        :return:
        """
        sample_reset(self.has_grid, self.saa, self.microgrid, sampling_args=sampling_args)
        observations = super().reset()
        return observations


class SafeExpMicrogridEnv(ContinuousMicrogridEnv):
    """
    ContinuousMicrogridEnv but with constraint functionality for safety layer.
    """
    def __init__(self, microgrid,
                 standardization=True,
                 balance_tolerance=1.,
                 scale_constraints=True,
                 only_inequality_constr=True,
                 trajectory_len=None,
                 max_episode_len=None):

        super().__init__(microgrid,
                         standardization=standardization,
                         trajectory_len=trajectory_len,
                         max_episode_len=max_episode_len)

        self.balance_tolerance=balance_tolerance
        self.scale_constraints = scale_constraints
        self.only_inequality_constr = only_inequality_constr

        self.n_constraints = 9 if self.has_genset else 7
        if only_inequality_constr:
            self.n_constraints -= 1

    def get_num_constraints(self):
        """
        Two for energy balance (one equality)
        One each p_charge, p_discharge, p_import, p_export
        Two p_genset if genset
        TODO: do you need pv_curtail and loss_load
        :return:
        """
        return self.n_constraints

    def get_constraint_values(self):
        """
        All constraints are set up here such that we return c_i for constraints of the form c_i<0
        :return:
        """
        inequality_constraints = self._get_inequality_constraints()
        energy_balance = self._get_energy_balance()

        if self.only_inequality_constr:
            constraints = inequality_constraints
            return constraints

        return np.append(inequality_constraints, energy_balance)

    def _get_energy_balance(self):
        if self.has_genset:
            p_import, p_export, p_charge, p_discharge, p_genset, load, pv, pv_consumed = \
                self.get_values('grid_import','grid_export', 'battery_charge', 'battery_discharge','genset','load','pv','pv_consummed')
        else:
            p_import, p_export, p_charge, p_discharge, load, pv, pv_consumed = \
                self.get_values('grid_import', 'grid_export', 'battery_charge', 'battery_discharge', 'load',
                                'pv', 'pv_consummed')

            p_genset = 0

        pv_curtailed = pv-pv_consumed

        energy_balance = np.array(p_import-p_export-p_charge+p_discharge+p_genset-pv_curtailed-load+pv)

        if self.scale_constraints:
            charge_scale_factor = float(self.microgrid.parameters.battery_capacity.squeeze())
            energy_balance /= charge_scale_factor

        return energy_balance

    def _get_inequality_constraints(self):
        constraints = []

        p_charge, p_discharge, p_max_charge, p_max_discharge = self.get_values('battery_charge','battery_discharge',
                                                                                'capa_to_charge','capa_to_discharge')

        if self.scale_constraints:
            charge_scale_factor = float(self.microgrid.parameters.battery_capacity.squeeze())

            constraints.append((p_charge-p_max_charge)/charge_scale_factor)
            constraints.append((p_discharge-p_max_discharge)/charge_scale_factor)
        else:
            constraints.append(p_charge - p_max_charge)
            constraints.append(p_discharge - p_max_discharge)

        p_max_import = self.microgrid.parameters['grid_power_import'].values[0]
        p_max_export = self.microgrid.parameters['grid_power_export'].values[0]
        p_import, p_export, grid_status = self.get_values('grid_import','grid_export','grid_status')

        if self.scale_constraints:
            constraints.append((p_import - p_max_import * grid_status)/p_max_import)
            constraints.append((p_export - p_max_export * grid_status)/p_max_export)
        else:
            constraints.append(p_import-p_max_import*grid_status)
            constraints.append(p_export-p_max_export*grid_status)

        battery_max = self.microgrid.parameters['battery_soc_max'].values[0]
        battery_min = self.microgrid.parameters['battery_soc_min'].values[0]
        battery_soc, = self.get_values('battery_soc')

        if self.scale_constraints:
            constraints.append((battery_soc - battery_max)/battery_max)
            constraints.append((battery_min - battery_soc)/battery_min)
        else:
            constraints.append(battery_soc-battery_max)
            constraints.append(battery_min-battery_soc)

        if self.has_genset:

            p_genset_max = self.microgrid.parameters['genset_rated_power'].values[0] * self.microgrid.parameters['genset_pmax'].values[0]
            p_genset_min = self.microgrid.parameters['genset_rated_power'].values[0] * self.microgrid.parameters['genset_pmin'].values[0]
            p_genset, = self.get_values('genset')

            # TODO what if we want it to be off? For now, this:
            if p_genset<1:
                if self.scale_constraints:
                    constraints.append((p_genset-1)/p_genset_max)
                    constraints.append((-p_genset-self.balance_tolerance)/p_genset_max)
                else:
                    constraints.append(p_genset - 1)
                    constraints.append(-p_genset - self.balance_tolerance)
            else:
                if self.scale_constraints:
                    constraints.append((p_genset - p_genset_max)/p_genset_max)
                    constraints.append((p_genset_min - p_genset)/p_genset_min)
                else:
                    constraints.append(p_genset-p_genset_max)
                    constraints.append(p_genset_min-p_genset)

        constraints = np.array(constraints)

        return constraints


class SafeExpMicrogridSampleEnv(SafeExpMicrogridEnv):
    def __init__(self,
                 microgrid,
                 standardization=True,
                 balance_tolerance=1.,
                 scale_constraints=True,
                 only_inequality_constr=True,
                 forecast_args=None,
                 baseline_sampling_args=None,
                 trajectory_len=None,
                 max_episode_len=None):
        super().__init__(microgrid,
                         standardization=standardization,
                         balance_tolerance=balance_tolerance,
                         scale_constraints=scale_constraints,
                         only_inequality_constr=only_inequality_constr,
                         trajectory_len=trajectory_len,
                         max_episode_len=max_episode_len)

        self.forecast_args = forecast_args
        self.forecast_args = forecast_args
        self.baseline_sampling_args = baseline_sampling_args
        self.saa = generate_sampler(self.microgrid, forecast_args)

    def reset(self, sampling_args=None):
        sample_reset(self.has_grid, self.saa, self.microgrid, sampling_args=sampling_args)
        observations = super().reset()
        return observations



================================================
FILE: src/pymgrid/_deprecated/Environments/pymgrid_csca_old.py
================================================
from pymgrid.Environments.Environment import Environment
import numpy as np
import gym
from gym.utils import seeding
from gym.spaces import Space, Discrete, Box


class MicroGridEnv(Environment):
    """
    Markov Decision Process associated to the microgrid.

        Parameters
        ----------
            microgrid: microgrid, mandatory
                The controlled microgrid.
            random_seed: int, optional
                Seed to be used to generate the needed random numbers to size microgrids.

    """
    def __init__(self, env_config, seed=42):
        super().__init__(env_config, seed)
        self.Na = 4 + self.mg.architecture['grid'] * 3 + self.mg.architecture['genset'] * 1

        action_limits = [int(self.mg._pv_ts.max().values[0]),
                         int(self.mg.parameters['battery_power_charge'].values[0]),
                         int(self.mg.parameters['battery_power_discharge'].values[0]),
                         2,
                         ]
        if self.mg.architecture['genset'] ==1:
            action_limits.append(int(self.mg.parameters['genset_rated_power'].values[0]* self.mg.parameters['genset_pmax'].values[0]))

        if self.mg.architecture['grid'] == 1:
            action_limits.append(int(self.mg.parameters['grid_power_import'].values[0]))
            action_limits.append(int(self.mg.parameters['grid_power_export'].values[0]))
            action_limits.append(2)

        self.action_space = gym.spaces.Tuple([gym.spaces.Discrete(x) for x in action_limits])


    def get_action(self, action):
        return self.get_action_continuous(action)

================================================
FILE: src/pymgrid/_deprecated/Environments/pymgrid_csda.py
================================================
from pymgrid.Environments.Environment import Environment
import numpy as np
import gym
from gym.utils import seeding
from gym.spaces import Space, Discrete, Box


class MicroGridEnv(Environment):
    """
    Markov Decision Process associated to the microgrid.

        Parameters
        ----------
            microgrid: microgrid, mandatory
                The controlled microgrid.
            random_seed: int, optional
                Seed to be used to generate the needed random numbers to size microgrids.

    """
    def __init__(self, env_config, seed=42):
        super().__init__(env_config, seed)
        self.Na = 4 + self.mg.architecture['grid'] * 3 + self.mg.architecture['genset'] * 1

        action_limits = [int(self.mg._pv_ts.max().values[0]),
                         int(self.mg.parameters['battery_power_charge'].values[0]),
                         int(self.mg.parameters['battery_power_discharge'].values[0]),
                         2,
                         ]
        if self.mg.architecture['genset'] ==1:
            action_limits.append(int(self.mg.parameters['genset_rated_power'].values[0]* self.mg.parameters['genset_pmax'].values[0]))

        if self.mg.architecture['grid'] == 1:
            action_limits.append(int(self.mg.parameters['grid_power_import'].values[0]))
            action_limits.append(int(self.mg.parameters['grid_power_export'].values[0]))
            action_limits.append(2)

        self.action_space = gym.spaces.Tuple([gym.spaces.Discrete(x) for x in action_limits])


    def get_action(self, action):
        return self.get_action_discrete(action)

================================================
FILE: src/pymgrid/_deprecated/Environments/pymgrid_cspla.py
================================================
"""
Copyright 2020 Total S.A
Authors:Gonzague Henri <gonzague.henri@total.com>
Permission to use, modify, and distribute this software is given under the
terms of the pymgrid License.
NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
$Date: 2020/10/21 07:43 $
Gonzague Henri
"""

"""
<pymgrid is a Python library to simulate microgrids>
Copyright (C) <2020> <Total S.A.>

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

"""
from pymgrid.Environments.Environment import Environment
import numpy as np
import gym
from gym.utils import seeding
from gym.spaces import Space, Discrete, Box

class MicroGridEnv(Environment):
    """
    Markov Decision Process associated to the microgrid.

        Parameters
        ----------
            microgrid: microgrid, mandatory
                The controlled microgrid.
            random_seed: int, optional
                Seed to be used to generate the needed random numbers to size microgrids.

    """

    def __init__(self, env_config, seed=42):
        super().__init__(env_config, seed)
        self.Na = 2 + self.mg.architecture['grid'] * 3 + self.mg.architecture['genset'] * 1 
        if self.mg.architecture['grid'] == 1 and self.mg.architecture['genset'] == 1:
            self.Na += 1
        self.action_space = Discrete(self.Na)



    def get_action(self, action):
        return self.get_action_priority_list(action)

    




================================================
FILE: src/pymgrid/_deprecated/__init__.py
================================================


================================================
FILE: src/pymgrid/_deprecated/non_modular_microgrid.py
================================================
"""
Copyright 2020 Total S.A., Tanguy Levent all rights reserved,
Authors:Gonzague Henri <gonzague.henri@total.com>, Tanguy Levent <>
Permission to use, modify, and distribute this software is given under the
terms of the pymgrid License.
NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
$Date: 2020/06/04 14:54 $
Gonzague Henri
"""

"""
<pymgrid is a Python library to simulate microgrids>
Copyright (C) <2020> <Total S.A.>

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

"""

import pandas as pd
import numpy as np
from copy import copy
from plotly.offline import init_notebook_mode, iplot
import matplotlib.pyplot as plt
from IPython.display import display
from IPython import get_ipython

def in_ipynb():
    try:
        cfg = get_ipython().config
        if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
            return True
        else:
            return False
    except (NameError, AttributeError):
        return False

if in_ipynb():
    init_notebook_mode(connected=False)

np.random.seed(123)

#cf.set_config_file(offline=True, theme='pearl') #commented for now, issues with parallel processes

DEFAULT_HORIZON = 24 #in hours
DEFAULT_TIMESTEP = 1 #in hours
ZERO = 10**-5

'''
The following classes are used to contain the information related to the different components
of the microgrid. Their main use is for easy access in a notebook.
'''

class Battery:

    """
    The class battery is used to store the information related to the battery in a microgrid. One of the main use for
    this class is for an easy access to information in a notebook using the battery object contained in a microgrid.

    Parameters
    ----------
    param_battery : dataframe
        All the data to initialize the battery.
    capa_to_charge : float
        Represents the amount of energy that a battery can charge before being full.
    capa_to_discharge : float
        Represents the amount of energy available that a battery can discharge before being empty.

    Attributes
    ----------
    soc: float
        Value between 0 and 1 representing the state of charge of the battery (1 being full, 0 being empty)
    capacity: int
        Total energy capacity of the battery (kWh).
    soc_max: float
        Value representing the maximum SOC that a battery can reach
    soc_min: float
        Value representing the minimum SOC that a battery can reach
    p_charge_max: float
        Value representing the maximum charging rate of the battery (kW)
    p_discharge_max: float
        Value representing the maximum discharging rate of the battery (kW)
    efficiency: float
        Value between 0 and 1 representing a one-way efficiency of the battery (considering same efficiency for charging
        and discharging).
    cost_cycle: float
        Value representing the cost of using the battery in $/kWh.
    capa_to_charge : float
        Represents the amount of energy that a battery can charge before being full.
    capa_to_discharge : float
        Represents the amount of energy available that a battery can discharge before being empty.


    Notes
    -----
    Another way to use this information in a notebook is to use /tab/ after /microgrid.battery./ so you can see all the
    battery attributes.

    Examples
    --------
    >>> m_gen=mg.MicrogridGenerator(nb_microgrid=1,path='your_path')
    >>> m_gen.generate_microgrid()
    >>> m_gen.microgrids[0].battery
    You can then add a point and use tab to have suggestion of the different paramterers
    You can access state of charge for example with:
    >>> m_gen.microgrids[0].battery.soc
    """

    def __init__(self, param_battery, capa_to_charge, capa_to_discharge):

        self.soc = param_battery['battery_soc_0'].values[0]
        self.capacity = param_battery['battery_capacity'].values[0]
        self.soc_max = param_battery['battery_soc_max'].values[0]
        self.soc_min = param_battery['battery_soc_min'].values[0]
        self.p_charge_max = param_battery['battery_power_charge'].values[0]
        self.p_discharge_max = param_battery['battery_power_discharge'].values[0]
        self.efficiency = param_battery['battery_efficiency'].values[0]
        self.cost_cycle = param_battery['battery_cost_cycle'].values[0]
        self.capa_to_charge = capa_to_charge
        self.capa_to_discharge = capa_to_discharge



class Genset:
    """
    The class Genset is used to store the information related to the genset in a microgrid. One of the main use for
    this class is for an easy access to information in a notebook using the genset object contained in a microgrid.

    Parameters
    ----------
    param : dataframe
        All the data to initialize the genset.

    Attributes
    ----------
    rated_power: int
        Maximum rater power of the genset.
    p_min: float
        Value representing the minimum operating power of the genset (kW)
    p_max: float
        Value representing the maximum operating power of the genset (kW)
    fuel_cost: float
        Value representing the cost of using the genset in $/kWh.

    Notes
    -----
    Another way to use this information in a notebook is to use /tab/ after /microgrid.genset./ so you can see all the
    genset attributes.

    Examples
    --------
    >>> m_gen=mg.MicrogridGenerator(nb_microgrid=1,path='your_path')
    >>> m_gen.generate_microgrid()
    >>> m_gen.microgrids[0].genset
    You can then add a point and use tab to have suggestion of the different paramaterers
    You can access the maximum power max for example with:
    >>> m_gen.microgrids[0].genset.p_max
    """
    def __init__(self, param):
        self.rated_power = param['genset_rated_power'].values[0]
        self.p_min = param['genset_pmin'].values[0]
        self.p_max = param['genset_pmax'].values[0]
        self.fuel_cost = param['fuel_cost'].values[0]
        self.co2 = param['genset_co2'].values[0]


class Grid:
    """
    The class Grid is used to store the information related to the grid in a microgrid. One of the main use for
    this class is for an easy access to information in a notebook using the grid object contained in a microgrid.

    Parameters
    ----------
    param : dataframe
        All the data to initialize the grid.
    status: int
        Whether the grid is connected or not at the first time step.


    Attributes
    ----------
    power_export: float
        Value representing the maximum export power to the grid (kW)
    power_import: float
        Value representing the maximum import power from the grid (kW)
    price_export: float
        Value representing the cost of exporting to the grid in $/kWh.
    price_import: float
        Value representing the cost of importing to the grid in $/kWh.
    status: int, binary
        Binary value representing whether the grid is connected or not (for example 0 represent a black-out of the
        main grid).

    Notes
    -----
    Another way to use this information in a notebook is to use /tab/ after /microgrid.grid./ so you can see all the
    grid attributes.

    Examples
    --------
    >>> m_gen=mg.MicrogridGenerator(nb_microgrid=1,path='your_path')
    >>> m_gen.generate_microgrid()
    >>> m_gen.microgrids[0].grid
    You can then add a point and use tab to have suggestion of the different paramaterers
    You can access the status of the grid for example with:
    >>> m_gen.microgrids[0].grid.status
    """
    def __init__(self, param, status, price_import, price_export, co2):
        self.power_export = param['grid_power_export'].values[0]
        self.power_import = param['grid_power_import'].values[0]
        self.price_export = price_export #param['grid_price_export'].values[0]
        self.price_import = price_import # param['grid_price_import'].values[0]
        self.status = status
        self.co2 = co2


class NonModularMicrogrid:

    """
    The class microgrid implement a microgrid. It is also used to run the simulation and different benchmarks.

    Parameters
    ----------
    parameters : dataframe
        In parameters we find:
            -'parameters': a dataframe containing all the fixed (not changing with time ) parameters of the microgrid
            -'architecture': a dictionnary containing a binary variable for each possible generator and indicating if
             this microgrid has one of them
            -'load': the load time series
            -'pv': the pv time series
            -'grid_ts': a time series of 1 and 0 indicating whether the grid is available
            -'df_actions': an empty dataframe representing the actions that the microgrid can take
            -'df_status': a dataframe representing the parameters of the microgrid that change with time, with the
             information for the first time step
            -'df_actual_generation': an empty dataframe that is used to store what actually happens in the microgrid
             after control actions are taken
            -'df_cost': dataframe to track the cost of operating the microgrid at each time step
            -'control_dict': an example of the control dictionnary that needs to be passed in run to operate the
             microgrid
    horizon : int, optional
        The horizon considered to control the microgrid, mainly used in the MPC function and to return the forecasting
         values (in hour).
    timestep : int, optional
        Time step the microgrid is operating at (in hour).

    Attributes
    ----------
        parameters: dataframe
            A dataframe containing all the fixed (not changing with time ) parameters of the microgrid
        architecture : dictionary
            A dictionary containing a binary variable for each possible generator and indicating if
            this microgrid has one of them
        _load_ts: dataframe
            The time series of load
        _pv_ts: dataframe
            Time series of PV generation
        pv: float
            The PV production at _run_timestep
        load: float
            The load consumption at _run_timestep
        _next_pv: float
            The PV production at _run_timestep +1
        _next_load: float
            The load consumption at _run_timestep + 1
        _grid_status_ts: dataframe
            A timeseries of binary values indicating whether the grid is connected or not.
        _df_record_control_dict: dataframe
            This dataframe is used to record the control actions taked at each time step.
        _df_record_state : dataframe
            This dataframe is used to record the variable parameters of the microgrid at each time step.
        _df_record_actual_production : dataframe
            This dataframe is used to record the actual generation of the microgrid at each time step.
        _df_record_cost : dataframe
            This dataframe is used to record the cost of operating the microgrid at each time step.
        _df_cost_per_epochs  : dataframe
            In the case we run the simulation through multiple epochs, this dataframe is used to record the cost of
             operating the microgrid at each time step of each epoch.
        horizon : int, optional
            The horizon considered to control the microgrid, mainly used in the MPC function and to return the forecasting
             values (in hour).
        _run_timestep : int
            Time step the microgrid is operating at (in hour).
        _data_length: int
            Represents the number of time steps in PV/Load files (minimum between the 2) that will be used to run the
            simulation.
        done: True or False
            Indicates whether a simulation is done or not
        _has_run_rule_based_baseline: True or False
            Indicates whether the rule based benchmark has already been run or not.
        _has_run_mpc_baseline: True or False
            Indicates whether the MPC benchmark has already been run or not.
        _epoch: int
            Tracks what epoch the microgrid is at
        _zero: float
            Approximate value to 0, used in some comparisons
        control_dict: dictionnary
            Represents the list of control actions to pass in the run function
        battery: object
            Represents all the parameter of the battery, including the value changing with time (in this case it is the
            value at _run_timestep).
        genset: object
            Represents all the parameter of the genset, including the value changing with time (in this case it is the
            value at _run_timestep).
        grid: object
            Represents all the parameter of the grid, including the value changing with time (in this case it is the
            value at _run_timestep).
        benchmarks: algos.Control.Benchmarks
            Benchmark object with the ability to run benchmark algorithms and store/print the results.

    Notes
    -----
    We are trying to keep hidden a lot of what is happening under the hood to simplify using this class for control or
    RL research at the maximum. A few notes, in this class parameters refer to the fixed parameters of the microgrid,
    meaning they don't vary with time. The varying parameters can be found in either the other classes or
    _df_record_state.

    Examples
    --------
    To create microgrids through MicrogridGenerator:
    >>> m_gen=mg.MicrogridGenerator(nb_microgrid=1,path='your_path')
    >>> m_gen.generate_microgrid()
    >>>microgrid = m_gen.microgrid[0]

    To plot informations about the microgrid:
    >>> microgrid.print_info()
    >>> microgrid.print_control_info()

    To compute the benchmarks:
    >>> microgrid.compute_benchmark() # to compute them all
    >>> microgrid.compute_benchmark('mpc_linprog') #to compute only the MPC

    For example, a simple control loop:
    >>> while m_gen.microgrids[0].done == False:
    >>>     load = mg_data['load']
    >>>     pv = mg_data['pv']
    >>>     control_dict = {'battery_charge': 0, 'battery_discharge': 0,'grid_import': max(0, load-pv),'grid_export':0,'pv': min(pv, load),}
    >>>     mg_data = m_gen.microgrids[0].run(control_dict)
    """

    def __init__(self, parameters, horizon=DEFAULT_HORIZON, timestep=DEFAULT_TIMESTEP):
        #list of parameters
        #this is a static dataframe: parameters of the microgrid that do not change with time

        #self._param_check(parameters)

        self.parameters = parameters['parameters']
        self.architecture = parameters['architecture']
        #different timeseries
        self._load_ts=parameters['load']
        self._pv_ts=parameters['pv']

        self.pv = self._pv_ts.iloc[0,0]
        self.load = self._load_ts.iloc[0, 0]
        self._next_load = self._load_ts.iloc[1,0]
        self._next_pv = self._pv_ts.iloc[1,0]
        if parameters['architecture']['grid']==1:
            self._grid_status_ts=parameters['grid_ts'] #time series of outages
            #self.grid_status = self._grid_status_ts.iloc[0, 0]
            self._grid_price_import=parameters['grid_price_import']
            self._grid_price_export=parameters['grid_price_export']
            self._grid_co2 = parameters['grid_co2']

            self._next_grid_status = self._grid_status_ts.iloc[0, 0]
            self._next_grid_price_export = self._grid_price_export.iloc[0, 0]
            self._next_grid_price_import = self._grid_price_import.iloc[0, 0]
            self._next_grid_co2 = self._grid_co2.iloc[0, 0]

        # those dataframe record what is happening at each time step
        self._df_record_control_dict=parameters['df_actions']
        self._df_record_state = parameters['df_status']
        self._df_record_actual_production = parameters['df_actual_generation']
        self._df_record_cost = parameters['df_cost']
        self._df_record_co2 = parameters['df_co2']
        self._df_cost_per_epochs = []
        self.horizon = horizon
        self._tracking_timestep = 0
        self._data_length = min(self._load_ts.shape[0], self._pv_ts.shape[0])
        self.done = False
        self._has_run_rule_based_baseline = False
        self._has_run_mpc_baseline = False
        self._has_train_test_split = False
        self._epoch=0
        self._zero = ZERO
        self.control_dict = parameters['control_dict']
        self._data_set_to_use_default = 'all'
        self._data_set_to_use = 'all'

        if self.architecture['battery'] == 1:
            self.battery = Battery(self.parameters,
                                   self._df_record_state['capa_to_charge'][0],
                                   self._df_record_state['capa_to_discharge'][0])
        if self.architecture['genset'] == 1:
            self.genset = Genset(self.parameters)
        if self.architecture['grid'] == 1:
            self.grid = Grid(self.parameters, self._grid_status_ts.iloc[0,0],
                             self._grid_price_import.iloc[0, 0],
                             self._grid_price_export.iloc[0, 0],
                             self._grid_co2.iloc[0, 0])

    def _param_check(self, parameters):
        """Simple parameter checks"""

        # Check parameters
        if not isinstance(parameters, dict):
            raise TypeError('parameters must be of type dict, is ({})'.format(type(parameters)))


        # Check architecture
        try:
            architecture = parameters['architecture']
        except KeyError:
            print('Dict of parameters does not appear to contain architecture key')
            raise
        if not isinstance(architecture, dict):
            raise TypeError('parameters[\'architecture\'] must be of type dict, is ({})'.format(type(architecture)))

        for key, val in architecture.items():
            if isinstance(val,bool):
                continue
            elif isinstance(val,int) and (val == 0 or val == 1):
                continue
            else:
                raise TypeError('Value ({}) of key ({}) in architecture is of unrecognizable type, '
                                'must be bool or in {{0,1}}, is ({})'.format(val, key, type(val)))

        # Ensure various DataFrames exist and are in fact DataFrames

        keys = ('parameters', 'load', 'pv', 'df_actions', 'df_status', 'df_actual_generation', 'df_cost')

        for key in keys:
            try:
                df = parameters[key]
            except KeyError:
                print('Dict of parameters does not appear to contain {} key'.format(key))
                raise
            if not isinstance(df, pd.DataFrame):
                raise TypeError('parameters[\'{}\'] must be of type pd.DataFrame, is ({})'.format(key, type(df)))



    def set_horizon(self, horizon):
        """Function used to change the horizon of the simulation."""
        self.horizon = horizon

    def set_cost_co2(self, co2_cost):
        """Function used to change the horizon of the simulation."""
        self.parameters['cost_co2'] = co2_cost

    def get_data(self):
        """Function to return the time series used in the microgrid"""
        return self._load_ts, self._pv_ts

    def get_training_testing_data(self):

        if self._has_train_test_split == True:

            return self._limit_index, self._load_train, self._pv_train, self._load_test, self._pv_test

        else:
            print('You have not split the dataset into training and testing sets')

    def get_control_dict(self):
        """ Function that returns the control_dict. """
        return self.control_dict


    def get_parameters(self):
        """ Function that returns the parameters of the microgrid. """
        return self.parameters


    def get_cost(self):
        """ Function that returns the cost associated the operation of the last time step. """
        return self._df_record_cost['total_cost'][-1]

    def get_co2(self):
        """ Function that returns the co2 emissions associated to the operation of the last time step. """
        return self._df_record_co2['co2'][-1]

    def get_updated_values(self):
        """
        Function that returns microgrid parameters that change with time. Depending on the architecture we have:
            - PV production
            - Load
            - Battery state of charge
            - Battery capacity to charge
            - Battery capacity to discharge
            - Whether the grid is connected or not
            - CO2 intensity of the grid
        """
        mg_data = {}

        for i in self._df_record_state:
            mg_data[i] = self._df_record_state[i][-1]

        return mg_data


    def forecast_all(self):
        """ Function that returns the PV, load and grid_status forecasted values for the next horizon. """
        forecast = {
            'pv': self.forecast_pv(),
            'load': self.forecast_load(),
        }
        if self.architecture['grid'] == 1:
            forecast['grid_status'] = self.forecast_grid_status()
            forecast['grid_import'], forecast['grid_export'] = self.forecast_grid_prices()
            forecast['grid_co2'] = self.forecast_grid_co2()

        return forecast


    def forecast_pv(self):
        """ Function that returns the PV forecasted values for the next horizon. """
        forecast = np.nan
        if self._data_set_to_use == 'training':
            forecast=self._pv_train.iloc[self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'testing':
            forecast = self._pv_test.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'all':
            forecast = self._pv_ts.iloc[self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        return forecast


    def forecast_load(self):
        """ Function that returns the load forecasted values for the next horizon. """
        forecast = np.nan
        if self._data_set_to_use == 'training':
            forecast = self._load_train.iloc[self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'testing':
            forecast = self._load_test.iloc[self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'all':
            forecast = self._load_ts.iloc[self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        return forecast

    def forecast_grid_status(self):
        """ Function that returns the grid_status forecasted values for the next horizon. """
        forecast = np.nan
        if self._data_set_to_use == 'training':
            forecast = self._grid_status_train.iloc[
               self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'testing':
            forecast = self._grid_status_test.iloc[
               self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'all':
            forecast = self._grid_status_ts.iloc[
               self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        return forecast

    def forecast_grid_co2(self):
        """ Function that returns the grid_status forecasted values for the next horizon. """
        forecast = np.nan
        if self._data_set_to_use == 'training':
            forecast = self._grid_co2_train.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'testing':
            forecast = self._grid_co2_test.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'all':
            forecast = self._grid_co2.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        return forecast

    def forecast_grid_prices(self):
        """ Function that returns the forecasted import and export prices for the next horizon. """
        forecast_import = np.nan
        forecast_export = np.nan
        if self._data_set_to_use == 'training':
            forecast_import = self._grid_price_import_train.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()
            forecast_export = self._grid_price_export_train.iloc[
                              self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'testing':
            forecast_import = self._grid_price_import_test.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()
            forecast_export = self._grid_price_export_test.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        if self._data_set_to_use == 'all':
            forecast_import = self._grid_price_import.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()
            forecast_export = self._grid_price_export.iloc[
                       self._tracking_timestep:self._tracking_timestep + self.horizon].values.flatten()

        return forecast_import, forecast_export



    #if return whole pv and load ts, the time can be counted in notebook
    def run(self, control_dict):
        """
        Function to 'run' the microgrid and iterate over the dataset.

        Parameters
        ----------
        control_dict : dictionnary
            Dictionnary containing the different control actions we want to apply to the microgrid. Its fields depend
            on the architecture of the microgrid

        Return
        ----------
        self.get_updated_values(): dictionnary
            Return all the parameters that change with time in the microgrid. CF this function for more details.

        Notes
        ----------
        This loop is the main connexion with a user in a notebook. That is where the simulation is ran and where the
        control actions are recorder and applied.

        """

        control_dict['load'] = self.load
        control_dict['pv'] = self.pv

        self._df_record_control_dict = self._record_action(control_dict, self._df_record_control_dict)



        self._df_record_actual_production = self._record_production(control_dict,
                                                                         self._df_record_actual_production,
                                                                    self._df_record_state)

        if self.architecture['grid'] == 1:
            self._df_record_co2 = self._record_co2({ i:self._df_record_actual_production[i][-1] for i in self._df_record_actual_production},
                                                   self._df_record_co2, self.grid.co2)

            self._df_record_cost = self._record_cost({ i:self._df_record_actual_production[i][-1] for i in self._df_record_actual_production},
                                                               self._df_record_cost, self._df_record_co2, self.grid.price_import, self.grid.price_export)
            self._df_record_state = self._update_status({key: value[-1] for key, value in self._df_record_actual_production.items()},
                                                        self._df_record_state, self._next_load, self._next_pv,
                                                        self._next_grid_status, self._next_grid_price_import,
                                                        self._next_grid_price_export, self._next_grid_co2)


        else:
            self._df_record_co2 = self._record_co2({ i:self._df_record_actual_production[i][-1] for i in self._df_record_actual_production},
                                                   self._df_record_co2)

            self._df_record_cost = self._record_cost({ i:self._df_record_actual_production[i][-1] for i in self._df_record_actual_production},
                                                     self._df_record_cost, self._df_record_co2)
            self._df_record_state = self._update_status(control_dict,
                                                        self._df_record_state, self._next_load, self._next_pv)

        if self._tracking_timestep == self._data_length - self.horizon or self._tracking_timestep == self._data_length - 1:
            self.done = True
            return self.get_updated_values()

        self._tracking_timestep += 1
        self.update_variables()

        return self.get_updated_values()


    def train_test_split(self, train_size=0.67, shuffle = False, cancel=False):
        """
        Function to split our data between a training and testing set.

        Parameters
        ----------
        train_size : float, optional
            Value between 0 and 1 reflecting the percentage of the dataset that should be in the training set.
        shuffle: boolean
            Variable to know if the training and testing sets should be shuffled or in the 'temporal' order
            Not implemented yet for shuffle = True
        cancel: boolean
            Variable indicating if the split needs to be reverted, and the data brought back into one dataset

        Attributes
        ----------
        _limit_index : int
            Index that delimit the training and testing sets in the time series
        load_train : dataframe
            Timeseries of load in training set
        pv_train: dataframe
            Timeseries of PV in training set
        load_test : dataframe
            Timeseries of load in testing set
        pv_test: dataframe
            Timeseries of PV in testing set
        grid_status_train: dataframe
            Timeseries of grid_status in training set
        grid_status_test: dataframe
            Timeseries of grid_status in testing set
        grid_price_import_train: dataframe
            Timeseries of price_import in training set
        grid_price_import_test: dataframe
            Timeseries of price_import in testing set
        grid_price_export_train: dataframe
            Timeseries of price_export in training set
        grid_price_export_test: dataframe
            Timeseries of price_export in testing set

        """

        if self._has_train_test_split ==  False:
            self._limit_index = int(np.ceil(self._data_length*train_size))
            self._load_train = self._load_ts.iloc[:self._limit_index]
            self._pv_train = self._pv_ts.iloc[:self._limit_index]

            self._load_test = self._load_ts.iloc[self._limit_index:]
            self._pv_test = self._pv_ts.iloc[self._limit_index:]

            if self.architecture['grid'] == 1:
                self._grid_status_train = self._grid_status_ts.iloc[:self._limit_index]
                self._grid_status_test = self._grid_status_ts.iloc[self._limit_index:]

                self._grid_price_import_train = self._grid_price_import.iloc[:self._limit_index]
                self._grid_price_import_test = self._grid_price_import.iloc[self._limit_index:]

                self._grid_price_export_train = self._grid_price_export.iloc[:self._limit_index]
                self._grid_price_export_test = self._grid_price_export.iloc[self._limit_index:]

                self._grid_co2_train = self._grid_co2.iloc[:self._limit_index]
                self._grid_co2_test = self._grid_co2.iloc[self._limit_index:]

            self._has_train_test_split = True
            self._data_set_to_use_default = 'training'
            self._data_set_to_use = 'training'

        elif self._has_train_test_split ==  True and cancel == True:
            self._has_train_test_split = False
            self._data_set_to_use_default = 'all'
            self._data_set_to_use = 'all'

        self.reset()

    def update_variables(self):
        """ Function that updates the variablers containing the parameters of the microgrid changing with time. """

        if self._data_set_to_use == 'training':
            self.pv = self._pv_train.iloc[self._tracking_timestep, 0]
            self.load = self._load_train.iloc[self._tracking_timestep, 0]

            self._next_pv = self._pv_train.iloc[self._tracking_timestep +1, 0]
            self._next_load = self._load_train.iloc[self._tracking_timestep+1, 0]


        if self._data_set_to_use == 'testing':
            self.pv = self._pv_test.iloc[self._tracking_timestep, 0]
            self.load = self._load_test.iloc[self._tracking_timestep, 0]

            self._next_pv = self._pv_test.iloc[self._tracking_timestep+1, 0]
            self._next_load = self._load_test.iloc[self._tracking_timestep+1, 0]

        if self._data_set_to_use == 'all':
            self.pv = self._pv_ts.iloc[self._tracking_timestep, 0]
            self.load = self._load_ts.iloc[self._tracking_timestep, 0]


            if self._tracking_timestep < self._data_length - 1:
                self._next_pv = self._pv_ts.iloc[self._tracking_timestep+1, 0]
                self._next_load = self._load_ts.iloc[self._tracking_timestep+1, 0]
            else:
                self._next_pv, self._next_load = None, None


        if self.architecture['grid']==1:
            if self._data_set_to_use == 'training':
                self.grid.status = self._grid_status_train.iloc[self._tracking_timestep, 0]
                self.grid.price_import = self._grid_price_import_train.iloc[self._tracking_timestep,0]
                self.grid.price_export = self._grid_price_export_train.iloc[self._tracking_timestep,0]
                self.grid.co2 = self._grid_co2_train.iloc[self._tracking_timestep, 0]

                self._next_grid_status = self._grid_status_train.iloc[self._tracking_timestep +1, 0]
                self._next_grid_price_import = self._grid_price_import_train.iloc[self._tracking_timestep +1, 0]
                self._next_grid_price_export = self._grid_price_export_train.iloc[self._tracking_timestep +1, 0]
                self._next_grid_co2 = self._grid_co2_train.iloc[self._tracking_timestep + 1, 0]

            if self._data_set_to_use == 'testing':
                self.grid.status = self._grid_status_test.iloc[self._tracking_timestep, 0]
                self.grid.price_import = self._grid_price_import_test.iloc[self._tracking_timestep, 0]
                self.grid.price_export = self._grid_price_export_test.iloc[self._tracking_timestep, 0]
                self.grid.co2 = self._grid_co2_test.iloc[self._tracking_timestep, 0]

                self._next_grid_status = self._grid_status_test.iloc[self._tracking_timestep + 1, 0]
                self._next_grid_price_import = self._grid_price_import_test.iloc[self._tracking_timestep + 1, 0]
                self._next_grid_price_export = self._grid_price_export_test.iloc[self._tracking_timestep + 1, 0]
                self._next_grid_co2 = self._grid_co2_test.iloc[self._tracking_timestep + 1, 0]


            if self._data_set_to_use == 'all':
                self.grid.status = self._grid_status_ts.iloc[self._tracking_timestep, 0]
                self.grid.price_import = self._grid_price_import.iloc[self._tracking_timestep, 0]
                self.grid.price_export = self._grid_price_export.iloc[self._tracking_timestep, 0]
                self.grid.co2 = self._grid_co2.iloc[self._tracking_timestep, 0]

                if self._tracking_timestep < self._data_length - 1:
                    self._next_grid_status = self._grid_status_ts.iloc[self._tracking_timestep + 1, 0]
                    self._next_grid_price_import = self._grid_price_import.iloc[self._tracking_timestep + 1, 0]
                    self._next_grid_price_export = self._grid_price_export.iloc[self._tracking_timestep + 1, 0]
                    self._next_grid_co2 = self._grid_co2.iloc[self._tracking_timestep + 1, 0]
                else:
                    self._next_grid_status, self._next_grid_price_import, self._next_grid_price_export, \
                    self._next_grid_co2 = None, None, None, None

        if self.architecture['battery'] == 1:
            self.battery.soc = self._df_record_state['battery_soc'][-1]
            self.battery.capa_to_discharge = self._df_record_state['capa_to_discharge'][-1]
            self.battery.capa_to_charge = self._df_record_state['capa_to_charge'][-1]

    def reset(self, testing=False):
        """This function is used to reset the dataframes that track what is happening in simulation. Mainly used in RL."""
        if self._data_set_to_use == 'training':
            temp_cost = copy(self._df_record_cost)
            temp_cost['epoch'] = self._epoch
            self._df_cost_per_epochs.append(temp_cost)

        self._df_record_control_dict = {i:[] for i in self._df_record_control_dict}
        self._df_record_state = {i:[self._df_record_state[i][0]] for i in self._df_record_state}
        self._df_record_actual_production = {i:[] for i in self._df_record_actual_production}
        self._df_record_cost = {i:[] for i in self._df_record_cost}
        self._df_record_co2 = {i:[] for i in self._df_record_co2}

        self._tracking_timestep = 0

        if testing == True and self._data_set_to_use_default == 'training':
            self._data_set_to_use = 'testing'
            self._data_length = min(self._load_test.shape[0], self._pv_test.shape[0])
        else:
            self._data_set_to_use = self._data_set_to_use_default
            if self._data_set_to_use == 'training':
                self._data_length = min(self._load_train.shape[0], self._pv_train.shape[0])
            else:
                self._data_length = min(self._load_ts.shape[0], self._pv_ts.shape[0])

        self.update_variables()
        self.done = False



        self._epoch+=1


    ########################################################
    # FUNCTIONS TO UPDATE THE INTERNAL DICTIONARIES
    ########################################################


    def _record_action(self, control_dict, df):
        """ This function is used to record the actions taken, before being checked for feasability. """
        if not isinstance(df, dict):
            raise TypeError('We know this should be named differently but df needs to be dict, is {}'.format(type(df)))
        for j in df:
            if j in control_dict.keys():
                df[j].append(control_dict[j])
            else:
                df[j].append({j:0})
        #df = df.append(control_dict,ignore_index=True)

        return df


    def _update_status(self, production_dict, df, next_load, next_pv, next_grid = 0, next_price_import =0, next_price_export = 0, next_co2 = 0):
        """ This function update the parameters of the microgrid that change with time. """
        #self.df_status = self.df_status.append(self.new_row, ignore_index=True)

        if not isinstance(df, dict):
            raise TypeError('We know this should be named differently but df needs to be dict, is {}'.format(type(df)))

        new_dict = {
            'load': next_load,
                    'pv': next_pv,
            'hour':self._tracking_timestep%24,
        }
        new_soc =np.nan
        if self.architecture['battery'] == 1:
            new_soc = df['battery_soc'][-1] + (production_dict['battery_charge'] * self.parameters['battery_efficiency'].values[0]
                                               - production_dict['battery_discharge'] / self.parameters['battery_efficiency'].values[0]) / self.parameters['battery_capacity'].values[0]
            #if col == 'net_load':
            capa_to_charge = max(
                (self.parameters['battery_soc_max'].values[0] * self.parameters['battery_capacity'].values[0] -
                 new_soc *
                 self.parameters['battery_capacity'].values[0]
                 ) * self.parameters['battery_efficiency'].values[0], 0)

            capa_to_discharge = max((new_soc *
                                     self.parameters['battery_capacity'].values[0]
                                     - self.parameters['battery_soc_min'].values[0] *
                                     self.parameters['battery_capacity'].values[0]
                                     ) * self.parameters['battery_efficiency'].values[0], 0)

            new_dict['battery_soc']=new_soc
            new_dict['capa_to_discharge'] = capa_to_discharge
            new_dict['capa_to_charge'] = capa_to_charge

        if self.architecture['grid'] == 1 :
            new_dict['grid_status'] = next_grid
            new_dict['grid_price_import'] = next_price_import
            new_dict['grid_price_export'] = next_price_export
            new_dict['grid_co2'] = next_co2

        for j in df:
            df[j].append(new_dict[j])

        #df = df.append(dict,ignore_index=True)



        return df


    #now we consider all the generators on all the time (mainly concern genset)

    def _check_constraints_genset(self, p_genset):
        """ This function checks that the constraints of the genset are respected."""
        if p_genset < 0:
            p_genset =0
            print('error, genset power cannot be lower than 0')

        if p_genset < self.parameters['genset_rated_power'].values[0] * self.parameters['genset_pmin'].values[0] and p_genset >1:
            p_genset = self.parameters['genset_rated_power'].values[0] * self.parameters['genset_pmin'].values[0]

        if p_genset > self.parameters['genset_rated_power'].values[0] * self.parameters['genset_pmax'].values[0]:
            p_genset = self.parameters['genset_rated_power'].values[0] * self.parameters['genset_pmax'].values[0]

        return p_genset

    def _check_constraints_grid(self, p_import, p_export):
        """ This function checks that the constraints of the grid are respected."""
        if p_import < 0:
            p_import = 0

        if p_export <0:
            p_export = 0

        if p_import > self._zero and p_export > self._zero:
        	pass
            #print ('cannot import and export at the same time')
            #todo how to deal with that?

        if p_import > self.parameters['grid_power_import'].values[0]:
            p_import = self.parameters['grid_power_import'].values[0]

        if p_export > self.parameters['grid_power_export'].values[0]:
            p_export = self.parameters['grid_power_export'].values[0]

        return p_import, p_export

    def _check_constraints_battery(self, p_charge, p_discharge, status):
        """ This function checks that the constraints of the battery are respected."""

        if p_charge < 0:
            p_charge = 0

        if p_discharge < 0:
            p_discharge = 0

        if p_charge > self._zero and p_discharge > self._zero:
            pass

        capa_to_charge = max(
                        (self.parameters['battery_soc_max'].values[0] * self.parameters['battery_capacity'].values[0] -
                         status['battery_soc'][-1] *
                         self.parameters['battery_capacity'].values[0]
                         ) * self.parameters['battery_efficiency'].values[0], 0)

        capa_to_discharge = max((status['battery_soc'][-1] *
                                 self.parameters['battery_capacity'].values[0]
                                 - self.parameters['battery_soc_min'].values[0] *
                                 self.parameters['battery_capacity'].values[0]
                                 ) * self.parameters['battery_efficiency'].values[0], 0)

        if p_charge > capa_to_charge or p_charge > self.parameters['battery_power_charge'].values[0]:
            p_charge = min (capa_to_charge, self.parameters['battery_power_charge'].values[0])


        if p_discharge > capa_to_discharge or p_discharge > self.parameters['battery_power_discharge'].values[0]:
            p_discharge = min (capa_to_discharge, self.parameters['battery_power_discharge'].values[0])

        return p_charge, p_discharge

    def _record_production(self, control_dict, production_dict, status):
        """
        This function records the actual production occuring in the microgrid. Based on the control actions and the
        parameters of the microgrid. This function will check that the control actions respect the constraints of
        the microgrid and then record what generators have produced energy.

        Parameters
        ----------
        control_dict : dictionnary
            Dictionnary representing the control actions taken by an algorithm (either benchmark or in the run function).
        df: dataframe
            Previous version of the record_production dataframe (coming from the run loop, or benchmarks).
        status: dataframe
            One line dataframe representing the changing parameters of the microgrid.

        Notes
        -----
        The mechanism to incure a penalty in case of over-generation is not yet in its final version.
        """
        assert isinstance(production_dict, dict)
        try:
            control_dict.pop('pv_consummed')
        except KeyError:
            pass


        has_grid = self.architecture['grid'] == 1
        has_genset = self.architecture['genset'] == 1
        has_battery = self.architecture['battery'] == 1

        sources = 0.0
        sinks = control_dict['load']

        # Battery
        if has_battery:
            p_charge, p_discharge = self._check_constraints_battery(control_dict['battery_charge'],
                                                                    control_dict['battery_discharge'],
                                                                    status)
            production_dict['battery_charge'].append(p_charge)
            production_dict['battery_discharge'].append(p_discharge)

            sources += p_discharge
            sinks += p_charge

        if has_grid:
            p_import, p_export = self._check_constraints_grid(control_dict['grid_import'],
                                                                    control_dict['grid_export'])
            production_dict['grid_import'].append(p_import)
            production_dict['grid_export'].append(p_export)

            sources += p_import
            sinks += p_export

        if has_genset:
            p_genset = self._check_constraints_genset(control_dict['genset'])
            production_dict['genset'].append(p_genset)
            sources += p_genset

        pv_required = sinks-sources
        pv_available = control_dict['pv']

        if np.abs(pv_required-pv_available) < 1e-3:         # meeting demand
            pv_consumed = pv_available
            loss_load = 0
            pv_curtailed = 0
            overgeneration = 0

        elif pv_required > pv_available:                    # loss load
            pv_consumed = pv_available
            loss_load = pv_required-pv_available
            pv_curtailed = 0
            overgeneration = 0

        elif 0 < pv_required < pv_available:                # curtail pv
            pv_consumed = pv_required
            loss_load = 0
            pv_curtailed = pv_available-pv_required
            overgeneration = 0

        else:                                               # overgeneration. Requires NO pv whatsoever
            assert pv_required < 0
            pv_consumed = 0
            loss_load = 0
            pv_curtailed = pv_available if pv_available > 0 else 0
            overgeneration = -pv_required

        production_dict['pv_consummed'].append(pv_consumed)
        production_dict['loss_load'].append(loss_load)
        production_dict['pv_curtailed'].append(pv_curtailed)
        production_dict['overgeneration'].append(overgeneration)

        return production_dict

    def _record_co2(self, control_dict, df, grid_co2=0):
        """ This function record the cost of operating the microgrid at each time step."""
        co2 = 0

        if self.architecture['genset'] == 1:
            co2 += control_dict['genset'] * self.parameters['genset_co2'].values[0]

        if self.architecture['grid'] == 1:
            co2 += grid_co2 * control_dict['grid_import']

        cost_dict = {'co2': co2}

        df['co2'].append( co2)

        return df

    def _record_cost(self, control_dict, df, df_co2, cost_import=0, cost_export=0):
        """ This function record the cost of operating the microgrid at each time step."""

        if not isinstance(df, dict):
            raise TypeError('We know this should be named differently but df needs to be dict, is {}'.format(type(df)))

        cost_loss_load = control_dict['loss_load'] * self.parameters['cost_loss_load'].values[0]
        cost_overgeneration = control_dict['overgeneration'] * self.parameters['cost_overgeneration'].values[0]

        df['loss_load'].append(cost_loss_load)
        df['overgeneration'].append(cost_overgeneration)

        # cost += control_dict['loss_load'] * self.parameters['cost_loss_load'].values[0]
        # cost += control_dict['overgeneration'] * self.parameters['cost_overgeneration'].values[0]

        if self.architecture['genset'] == 1:
            genset_cost = control_dict['genset'] * self.parameters['fuel_cost'].values[0]
            df['genset'].append(genset_cost)

        if self.architecture['grid'] ==1:
            grid_import_cost = cost_import * control_dict['grid_import']
            grid_export_cost = - cost_export * control_dict['grid_export']
            df['grid_import'].append(grid_import_cost)
            df['grid_export'].append(grid_export_cost)


        if self.architecture['battery'] ==1 :
            battery_cost = (control_dict['battery_charge']+control_dict['battery_discharge'])*self.parameters['battery_cost_cycle'].values[0]
            df['battery'].append(battery_cost)

        co2_cost = self.parameters['cost_co2'].values[0] * df_co2['co2'][-1]
        df['co2'].append(co2_cost)

        total_cost = np.sum([val[-1] for key, val in df.items() if key != 'total_cost'])
        df['total_cost'].append(total_cost)

        return df

    ########################################################
    # PRINT FUNCTIONS
    ########################################################


    def print_load_pv(self):

        print('Load')
        fig1 = self._load_ts.iplot(asFigure=True)
        iplot(fig1)

        print('PV')
        fig2 =self._pv_ts.iplot(asFigure=True)
        iplot(fig2)

    def print_actual_production(self):
        if self._df_record_actual_production != type(pd.DataFrame()):
            df = pd.DataFrame(self._df_record_actual_production)
            fig1 = df.iplot(asFigure=True)
            iplot(fig1)
        else:
            fig1 = self._df_record_actual_production.iplot(asFigure=True)
            iplot(fig1)

    def print_control(self):
        if self._df_record_control_dict != type(pd.DataFrame()):
            df = pd.DataFrame(self._df_record_control_dict)
            fig1 = df.iplot(asFigure=True)
            iplot(fig1)
        else:
            fig1 = self._df_record_control_dict.iplot(asFigure=True)
            iplot(fig1)

    def print_co2(self):
        if self._df_record_co2 != type(pd.DataFrame()):
            df = pd.DataFrame(self._df_record_co2)
            fig1 = df.iplot(asFigure=True)
            iplot(fig1)
        else:
            fig1 = self._df_record_co2.iplot(asFigure=True)
            iplot(fig1)

    def print_cumsum_cost(self):
        if self._df_record_cost != type(pd.DataFrame()):
            df = pd.DataFrame(self._df_record_cost)
            plt.plot(df.cumsum())
            plt.show()
        else:
            plt.plot(self._df_record_cost.cumsum())
            plt.show()



    def print_benchmark_cost(self):
        """
        This function prints the cumulative cost of the different benchmark ran and different part of the dataset
        depending on if split it in train/test or not.
        """
        from pymgrid.algos.Control import Benchmarks
        benchmarks = Benchmarks(self)

        if len(benchmarks.outputs_dict) == 0:
            print('No benchmark algorithms have been run, running all.')
            #self.benchmarks.run_benchmarks()

        if self._has_train_test_split:
            benchmarks.describe_benchmarks(test_split=self._has_train_test_split, test_index=self._limit_index)

        else:
            benchmarks.describe_benchmarks(test_split=False)

    def print_info(self):
        """ This function prints the main information regarding the microgrid."""

        print('Microgrid parameters')
        display(self.parameters)
        print('Architecture:')
        print(self.architecture)
        print('Actions: ')
        print(self._df_record_control_dict.keys())
        print('Control dictionnary:')
        print(self.control_dict)
        print('Status: ')
        print(self._df_record_state.keys())
        print('Has run mpc baseline:')
        print(self._has_run_mpc_baseline)
        print('Has run rule based baseline:')
        print(self._has_run_rule_based_baseline)

    def print_control_info(self):
        """ This function prints the control_dict that needs to be used to control the microgrid"""

        print('you should fill this dictionnary at each time step')
        print('it is included in the mg_data object')
        print('you can copy it by: ctrl = mg_data.control_dict')
        print('or you can use self.get_conrol_dict()')
        print('Control dictionnary:')
        print(self.control_dict)

    def print_updated_parameters(self):
        """ This function prints the last values for the parameters of the microgrid changing with time."""
        state={}
        for i in self._df_record_state:
            state[i] = self._df_record_state[i][-1]

        print(state)

    ########################################################
    # RL UTILITY FUNCTIONS
    ########################################################
    #todo add a forecasting function that add noise to the time series
    #todo forecasting function can be used for both mpc benchmart and rl loop


    #todo verbose
    def penalty(self, coef = 1):
        """Penalty that represents discrepancies between control dict and what really happens. """
        penalty = 0
        for i in self._df_record_control_dict:
            penalty += abs(self._df_record_control_dict[i][-1] - self._df_record_actual_production[i][-1])

        return penalty*coef


    @classmethod
    def from_modular(cls, modular):
        from pymgrid.convert.convert import to_nonmodular
        return to_nonmodular(modular)

    def to_modular(self):
        from pymgrid.convert.convert import to_modular
        return to_modular(self)



================================================
FILE: src/pymgrid/algos/Control.py
================================================

"""
Copyright 2020 Total S.A.
Authors:Gonzague Henri <gonzague.henri@total.com>, Avishai Halev <>
Permission to use, modify, and distribute this software is given under the
terms of the pymgrid License.
NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
$Date: 2020/08/27 08:04 $
Gonzague Henri
"""

"""
<pymgrid is a Python library to simulate microgrids>
Copyright (C) <2020> <Total S.A.>

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

"""
import pandas as pd
import numpy as np
from copy import deepcopy


class HorizonOutput:

    def __init__(self,control_dicts, microgrid, current_step):
        self.df = pd.DataFrame(control_dicts)
        self.microgrid = microgrid
        self.current_step = current_step
        self.cost = self.compute_cost_over_horizon(current_step)
        self.first_dict = control_dicts[0]

    def compute_cost_over_horizon(self, current_step):

        horizon = self.microgrid.horizon
        cost = 0.0

        cost += self.df['loss_load'].sum()*self.microgrid.parameters['cost_loss_load'].values[0]  # loss load

        if self.microgrid.architecture['genset'] == 1:
            cost += self.df['genset'].sum() * self.microgrid.parameters['fuel_cost'].values[0]

        if self.microgrid.architecture['grid'] == 1:
            price_import = self.microgrid._grid_price_import.iloc[current_step:current_step + horizon].values
            price_export = self.microgrid._grid_price_export.iloc[current_step:current_step + horizon].values

            import_cost_vec = price_import.reshape(-1)*self.df['grid_import']
            export_cost_vec = price_export.reshape(-1)*self.df['grid_export']
            grid_cost = import_cost_vec.sum()-export_cost_vec.sum()

            cost += grid_cost

        return cost

    def __eq__(self, other):
        if type(self) != type(other):
            return NotImplemented
        return self.cost == other.cost

    def __lt__(self, other):
        if type(self) != type(other):
            return NotImplemented
        return self.cost < other.cost

    def __gt__(self, other):
        if type(self) != type(other):
            return NotImplemented
        return self.cost > other.cost


class ControlOutput(dict):
    """
    Helper class that allows comparisons between controls by comparing the sum of their resultant costs
    Parameters:
        names: tuple, len 4
            names of each of the dataframes output in MPC
        dfs: tuple, len 4
            DataFrames of the outputs of MPC
        alg_name: str
            Name of the algorithm that produced the output
    Usage: dict-like, e.g.:

     >>>  names = ('action', 'status', 'production', 'cost', 'co2')
     >>>  dfs = (baseline_linprog_action, baseline_linprog_update_status,
     >>>          baseline_linprog_record_production, baseline_linprog_cost) # From MPC
     >>> M = ControlOutput(names, dfs,'mpc')
     >>> actions = M['action'] # returns the dataframe baseline_linprog_action

    """
    def __init__(self, names=None, dfs=None, alg_name=None, empty=False, microgrid=None):

        if not empty:
            if names is None:
                raise TypeError('names cannot be None unless initializing empty and empty=True')
            if dfs is None:
                raise TypeError('dfs cannot be None unless initializing empty and empty=True')
            if alg_name is None:
                raise TypeError('alg_name cannot be None unless initializing empty and empty=True')
        # else:
            # if not isinstance(microgrid,Microgrid.Microgrid):
            #     raise TypeError('microgrid must be a Microgrid if empty is True')

        if not empty:
            names_needed = ('action', 'status', 'production', 'cost', 'co2')
            if any([needed not in names for needed in names_needed]):
                raise ValueError('Names must contain {}, currently contains {}'.format(names,names_needed))

            super(ControlOutput, self).__init__(zip(names, dfs))
            self.alg_name = alg_name
            self.microgrid = microgrid

        else:
            names = ('action', 'status', 'production', 'cost', 'co2')
            baseline_linprog_action = deepcopy(microgrid._df_record_control_dict)
            baseline_linprog_update_status = deepcopy(microgrid._df_record_state)
            baseline_linprog_record_production = deepcopy(microgrid._df_record_actual_production)
            baseline_linprog_cost = deepcopy(microgrid._df_record_cost)
            baseline_linprog_co2 = deepcopy(microgrid._df_record_co2)

            dfs = (baseline_linprog_action, baseline_linprog_update_status,
               baseline_linprog_record_production, baseline_linprog_cost, baseline_linprog_co2)

            super(ControlOutput, self).__init__(zip(names, dfs))
            self.alg_name = alg_name
            self.microgrid = microgrid

    def append(self, other_output, actual_load=None, actual_pv=None, actual_grid = None, slice_to_use=0):
        if isinstance(other_output, ControlOutput):
            for name in self.keys():
                if name not in other_output.keys():
                    raise KeyError('name {} not founds in other_output keys'.format(name))

                self[name].append(other_output[name].iloc[slice_to_use], ignore_index=True)

        elif isinstance(other_output, HorizonOutput):
            action = self['action']
            production = self['production']
            cost = self['cost']
            status = self['status']
            co2 = self['co2']

            action = self.microgrid._record_action(other_output.first_dict, action)
            production = self.microgrid._record_production(other_output.first_dict, production, status)

            last_prod = dict([(key, production[key][-1]) for key in production])

            i = other_output.current_step

            if self.microgrid.architecture['grid'] == 1:
                co2 = self.microgrid._record_co2(
                    last_prod,
                    co2,
                    self.microgrid._grid_co2.iloc[i].values[0]
                )

                status = self.microgrid._update_status(
                    last_prod,
                    status,
                    actual_load,
                    actual_pv,
                    actual_grid,
                    self.microgrid._grid_price_import.iloc[i + 1].values[0],
                    self.microgrid._grid_price_export.iloc[i + 1].values[0],
                    self.microgrid._grid_co2.iloc[i + 1].values[0]
                )

                cost = self.microgrid._record_cost(
                    last_prod,
                    cost,
                    co2,
                    self.microgrid._grid_price_import.iloc[i, 0],
                    self.microgrid._grid_price_export.iloc[i, 0])
            else:

                co2 = self.microgrid._record_co2(
                    last_prod,
                    co2,
                )

                status = self.microgrid._update_status(
                    last_prod,
                    status,
                    actual_load,
                    actual_pv
                )
                cost = self.microgrid._record_cost(
                    last_prod,
                    cost,
                    co2
                )

            self['action'] = action
            self['production'] = production
            self['cost'] = cost
            self['status'] = status
            self['co2'] = co2

    def to_frame(self):
        d = dict()
        max_len = -np.inf
        for k_1, v_1 in self.items():
            for k_2, v_2 in v_1.items():
                if len(v_2) > max_len:
                    max_len = len(v_2)
                d[(k_1, k_2)] = v_2

        for _, v in d.items():
            if len(v) < max_len:
                v.extend([np.nan]*(max_len-len(v)))

        return pd.DataFrame(d)

    def __eq__(self, other):
        if type(self) != type(other):
            return NotImplemented
        return np.sum(self['cost']) == np.sum(other['cost'])

    def __lt__(self, other):
        if type(self) != type(other):
            return NotImplemented
        return np.sum(self['cost']) < np.sum(other['cost'])

    def __gt__(self, other):
        if type(self) != type(other):
            return NotImplemented
        return np.sum(self['cost']) > np.sum(other['cost'])


class Benchmarks:
    """
    Class to run various control algorithms. Currently supports MPC and rule-based control.

    Parameters
    -----------
    microgrid: Microgrid.Microgrid
        microgrid on which to run the benchmarks

    Attributes
    -----------
    microgrid, Microgrid.Microgrid
        microgrid on which to run the benchmarks
    mpc_output: ControlOutput or None, default None
        output of MPC if it has been run, otherwise None
    outputs_dict: dict
        Dictionary of the outputs of all run algorithm. Keys are names of algorithms, any or all of 'mpc' or 'rbc' as of now.
    has_mpc_benchmark: bool, default False
        whether the MPC benchmark has been run or not
    rule_based_output: ControlOutput or None, default None
        output of rule basded control if it has been run, otherwise None
    has_rule_based_benchmark: bool, default False
        whether the rule based benchmark has been run or not

    """
    def __init__(self, microgrid):
        # if not isinstance(microgrid, Microgrid.Microgrid):
        #     raise TypeError('microgrid must be of type Microgrid, is {}'.format(type(microgrid)))

        self.microgrid = microgrid
        self.outputs_dict = dict()

        self.mpc_output = None
        self.has_mpc_benchmark = False
        self.rule_based_output = None
        self.has_rule_based_benchmark = False
        self.saa_output = None
        self.has_saa_benchmark = False

    def run_mpc_benchmark(self, verbose=False, **kwargs):
        """
        Run the MPC benchmark and store the output in self.mpc_output
        :return:
            None
        """
        from pymgrid.algos import ModelPredictiveControl
        MPC = ModelPredictiveControl(self.microgrid)
        self.mpc_output = MPC.run(verbose=verbose, **kwargs)
        self.has_mpc_benchmark = True
        self.outputs_dict[self.mpc_output.alg_name] = self.mpc_output

    def run_rule_based_benchmark(self):
        """
        Run the rule based benchmark and store the output in self.rule_based_output
        :return:
            None
        """
        from pymgrid.algos import RuleBasedControl
        RBC = RuleBasedControl(self.microgrid)
        self.rule_based_output = RBC.run_rule_based()
        self.has_rule_based_benchmark = True
        self.outputs_dict[self.rule_based_output.alg_name] = self.rule_based_output

    def run_saa_benchmark(self, preset_to_use=85, **kwargs):
        from pymgrid.algos.saa import SampleAverageApproximation
        SAA = SampleAverageApproximation(self.microgrid, preset_to_use=preset_to_use, **kwargs)
        self.saa_output = SAA.run(**kwargs)
        self.has_saa_benchmark = True
        self.outputs_dict[self.saa_output.alg_name] = self.saa_output

    def run_benchmarks(self, algo=None, verbose=False, preset_to_use=85, **kwargs):
        """
        Runs both run_mpc_benchmark() and self.run_mpc_benchmark() and stores the results.
        :param verbose: bool, default False
            Whether to describe benchmarks after running.
        :return:
            None
        """

        if algo == 'mpc':
            self.run_mpc_benchmark(verbose=verbose, **kwargs)
        elif algo == 'rbc':
            self.run_rule_based_benchmark()
        elif algo == 'saa':
            self.run_saa_benchmark(preset_to_use=preset_to_use, **kwargs)
        else:
            self.run_mpc_benchmark(verbose=verbose, **kwargs)
            self.run_rule_based_benchmark()
            self.run_saa_benchmark(preset_to_use=preset_to_use, **kwargs)

        if verbose:
            self.describe_benchmarks()

    def describe_benchmarks(self, test_split=False, test_ratio=None, test_index=None, algorithms=None):
        """
        Prints the cost of any and all benchmarks that have been run.
        If test_split==True, must have either a test_ratio or a test_index but not both.

        :param test_split: bool, default False
            Whether to report the cost of the partial tail (e.g. the last third steps) or all steps.
        :param test_ratio: float, default None
            If test_split, the percentage of the data set to report on.
        :param test_index: int, default None
            If test_split, the index to split the data into train/test sets
        :return:
            None
        """
        possible_benchmarks = ('saa', 'mpc', 'rbc')

        if algorithms is not None:
            if any([b_name not in possible_benchmarks for b_name in algorithms]):
                raise ValueError('Unable to recognize one or multiple of list_of_benchmarks: {}, can only contain {}'.format(
                    algorithms, possible_benchmarks))
        else:
            algorithms = possible_benchmarks

        t_vals = []
        for key in self.outputs_dict:
            t_vals.append(len(self.outputs_dict[key]['cost']['total_cost']))

        if not all([t_val == t_vals[0] for t_val in t_vals]):
            raise ValueError('Outputs are of different lengths')

        T = t_vals[0]

        if test_split:
            if test_ratio is None and test_index is None:
                raise ValueError('If test_split, must have either a test_ratio or test_index')
            elif test_ratio is not None and test_index is not None:
                raise ValueError('Cannot have both test_ratio and test_split')
            elif test_ratio is not None and not (0 <= test_ratio <= 1):
                raise ValueError('test_ratio must be in [0,1], is {}'.format(test_ratio))
            elif test_index is not None and test_index > T:
                raise ValueError('test_index cannot be larger than length of output')

        if T != 8736:
            print('length of MPCOutput cost is {}, not 8736, may be invalid'.format(T))

        if not test_split or test_ratio is not None:
            if not test_split:
                test_ratio = 1

            steps = T - int(np.ceil(T * (1 - test_ratio)))
            percent = round(test_ratio * 100, 1)

            if self.has_mpc_benchmark and 'mpc' in algorithms:
                cost = round(np.sum(self.mpc_output['cost']['total_cost'][int(np.ceil(T*(1-test_ratio))):]), 2)
                print('Cost of the last {} steps ({} percent of all steps) using MPC: {}'.format(steps, percent, cost))

            if self.has_rule_based_benchmark and 'rbc' in algorithms:
                cost = round(np.sum(self.rule_based_output['cost']['total_cost'][int(np.ceil(T*(1-test_ratio))):]), 2)
                print('Cost of the last {} steps ({} percent of all steps) using rule-based control: {}'.format(steps, percent, cost))

            if self.has_saa_benchmark and 'saa' in algorithms:
                cost = round(np.sum(self.saa_output['cost']['total_cost'][int(np.ceil(T*(1-test_ratio))):]), 2)
                print('Cost of the last {} steps ({} percent of all steps) using sample-average MPC control: {}'.format(steps, percent, cost))

        else:

            if self.has_mpc_benchmark and 'mpc' in algorithms:
                cost_train = round(np.sum(self.mpc_output['cost']['total_cost'][:test_index]), 2)
                cost_test = round(np.sum(self.mpc_output['cost']['total_cost'][test_index:]), 2)

                print('Test set cost using MPC: {}'.format(cost_test))
                print('Train set cost using MPC: {}'.format(cost_train))

            if self.has_rule_based_benchmark and 'rbc' in algorithms:
                cost_train = round(np.sum(self.rule_based_output['cost']['total_cost'][:test_index]), 2)
                cost_test = round(np.sum(self.rule_based_output['cost']['total_cost'][test_index:]), 2)

                print('Test set cost using RBC: {}'.format(cost_test))
                print('Train set cost using RBC: {}'.format(cost_train))

            if self.has_saa_benchmark and 'saa' in algorithms:
                cost_train = round(np.sum(self.saa_output['cost']['total_cost'][:test_index]), 2)
                cost_test = round(np.sum(self.saa_output['cost']['total_cost'][test_index:]), 2)

                print('Test set cost using SAA: {}'.format(cost_test))
                print('Train set cost using SAA: {}'.format(cost_train))


================================================
FILE: src/pymgrid/algos/__init__.py
================================================
from .mpc.mpc import ModelPredictiveControl
from .rbc.rbc import RuleBasedControl


================================================
FILE: src/pymgrid/algos/example.log
================================================


================================================
FILE: src/pymgrid/algos/mpc/__init__.py
================================================


================================================
FILE: src/pymgrid/algos/mpc/mpc.py
================================================
import time
from copy import deepcopy
from tqdm import tqdm
import cvxpy as cp
import numpy as np
import pandas as pd
from warnings import warn
from scipy.sparse import csr_matrix

try:
    import mosek
except ImportError:
    mosek = None

from pymgrid.algos.Control import ControlOutput, HorizonOutput
from pymgrid.utils.DataGenerator import return_underlying_data
import logging


logger = logging.getLogger(__name__)

"""
Attributes:
-----------
Download .txt
gitextract_21zgo62z/

├── .gitattributes
├── .github/
│   └── workflows/
│       ├── build.yml
│       ├── documentation-links.yaml
│       └── garage-compat.yml
├── .gitignore
├── .readthedocs.yaml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── docs/
│   ├── Makefile
│   ├── make.bat
│   ├── requirements.txt
│   └── source/
│       ├── _templates/
│       │   └── autosummary/
│       │       ├── base.rst
│       │       └── class.rst
│       ├── conf.py
│       ├── examples/
│       │   ├── index.rst
│       │   ├── mpc-example.nblink
│       │   ├── quick-start.nblink
│       │   ├── rbc-example.nblink
│       │   └── rl-example.nblink
│       ├── getting_started.rst
│       ├── index.rst
│       └── reference/
│           ├── algos/
│           │   └── index.rst
│           ├── envs/
│           │   └── index.rst
│           ├── forecast/
│           │   └── index.rst
│           ├── general/
│           │   └── index.rst
│           ├── index.rst
│           ├── microgrid.rst
│           └── modules/
│               └── index.rst
├── pymgrid 25 - benchmarks.xlsx
├── pyproject.toml
├── requirements.txt
├── setup.cfg
├── setup.py
├── src/
│   ├── __init__.py
│   └── pymgrid/
│       ├── MicrogridGenerator.py
│       ├── __init__.py
│       ├── _deprecated/
│       │   ├── Environments/
│       │   │   ├── Environment.py
│       │   │   ├── Preprocessing.py
│       │   │   ├── __init__.py
│       │   │   ├── pymgrid_csca.py
│       │   │   ├── pymgrid_csca_old.py
│       │   │   ├── pymgrid_csda.py
│       │   │   └── pymgrid_cspla.py
│       │   ├── __init__.py
│       │   └── non_modular_microgrid.py
│       ├── algos/
│       │   ├── Control.py
│       │   ├── __init__.py
│       │   ├── example.log
│       │   ├── mpc/
│       │   │   ├── __init__.py
│       │   │   └── mpc.py
│       │   ├── priority_list/
│       │   │   ├── __init__.py
│       │   │   ├── priority_list.py
│       │   │   └── priority_list_element.py
│       │   ├── rbc/
│       │   │   ├── __init__.py
│       │   │   ├── _nonmodular_rbc.py
│       │   │   └── rbc.py
│       │   └── saa/
│       │       ├── __init__.py
│       │       └── saa.py
│       ├── convert/
│       │   ├── __init__.py
│       │   ├── convert.py
│       │   ├── get_module.py
│       │   └── to_nonmodular_ops.py
│       ├── data/
│       │   ├── __init__.py
│       │   ├── co2/
│       │   │   ├── __init__.py
│       │   │   ├── co2_caiso.csv
│       │   │   └── co2_duke.csv
│       │   ├── load/
│       │   │   ├── RefBldgFullServiceRestaurantNew2004_v1.3_7.1_6A_USA_MN_MINNEAPOLIS.csv
│       │   │   ├── RefBldgHospitalNew2004_7.1_5.0_3C_USA_CA_SAN_FRANCISCO.csv
│       │   │   ├── RefBldgLargeHotelNew2004_v1.3_7.1_4A_USA_MD_BALTIMORE.csv
│       │   │   ├── RefBldgLargeOfficeNew2004_v1.3_7.1_5A_USA_IL_CHICAGO-OHARE.csv
│       │   │   ├── RefBldgPrimarySchoolNew2004_v1.3_7.1_2A_USA_TX_HOUSTON.csv
│       │   │   └── __init__.py
│       │   ├── pv/
│       │   │   ├── Houston_722430TYA.csv
│       │   │   ├── Minneapolis_726580TYA.csv
│       │   │   ├── NewYork_744860TYA.csv
│       │   │   ├── Raleigh_723060TYA.csv
│       │   │   ├── SanFrancisco_724940TYA.csv
│       │   │   └── __init__.py
│       │   └── scenario/
│       │       ├── __init__.py
│       │       └── pymgrid25/
│       │           ├── microgrid_0/
│       │           │   └── microgrid_0.yaml
│       │           ├── microgrid_1/
│       │           │   └── microgrid_1.yaml
│       │           ├── microgrid_10/
│       │           │   └── microgrid_10.yaml
│       │           ├── microgrid_11/
│       │           │   └── microgrid_11.yaml
│       │           ├── microgrid_12/
│       │           │   └── microgrid_12.yaml
│       │           ├── microgrid_13/
│       │           │   └── microgrid_13.yaml
│       │           ├── microgrid_14/
│       │           │   └── microgrid_14.yaml
│       │           ├── microgrid_15/
│       │           │   └── microgrid_15.yaml
│       │           ├── microgrid_16/
│       │           │   └── microgrid_16.yaml
│       │           ├── microgrid_17/
│       │           │   └── microgrid_17.yaml
│       │           ├── microgrid_18/
│       │           │   └── microgrid_18.yaml
│       │           ├── microgrid_19/
│       │           │   └── microgrid_19.yaml
│       │           ├── microgrid_2/
│       │           │   └── microgrid_2.yaml
│       │           ├── microgrid_20/
│       │           │   └── microgrid_20.yaml
│       │           ├── microgrid_21/
│       │           │   └── microgrid_21.yaml
│       │           ├── microgrid_22/
│       │           │   └── microgrid_22.yaml
│       │           ├── microgrid_23/
│       │           │   └── microgrid_23.yaml
│       │           ├── microgrid_24/
│       │           │   └── microgrid_24.yaml
│       │           ├── microgrid_3/
│       │           │   └── microgrid_3.yaml
│       │           ├── microgrid_4/
│       │           │   └── microgrid_4.yaml
│       │           ├── microgrid_5/
│       │           │   └── microgrid_5.yaml
│       │           ├── microgrid_6/
│       │           │   └── microgrid_6.yaml
│       │           ├── microgrid_7/
│       │           │   └── microgrid_7.yaml
│       │           ├── microgrid_8/
│       │           │   └── microgrid_8.yaml
│       │           └── microgrid_9/
│       │               └── microgrid_9.yaml
│       ├── envs/
│       │   ├── __init__.py
│       │   ├── base/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── skip_init.py
│       │   ├── continuous/
│       │   │   ├── __init__.py
│       │   │   └── continuous.py
│       │   └── discrete/
│       │       ├── __init__.py
│       │       └── discrete.py
│       ├── forecast/
│       │   ├── __init__.py
│       │   └── forecaster.py
│       ├── microgrid/
│       │   ├── __init__.py
│       │   ├── microgrid.py
│       │   ├── reward_shaping/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── battery_discharge_shaper.py
│       │   │   └── pv_curtailment_shaper.py
│       │   ├── trajectory/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── deterministic.py
│       │   │   └── stochastic.py
│       │   └── utils/
│       │       ├── __init__.py
│       │       └── step.py
│       ├── modules/
│       │   ├── __init__.py
│       │   ├── base/
│       │   │   ├── __init__.py
│       │   │   ├── base_module.py
│       │   │   └── timeseries/
│       │   │       ├── __init__.py
│       │   │       └── base_timeseries_module.py
│       │   ├── battery_module.py
│       │   ├── genset_module.py
│       │   ├── grid_module.py
│       │   ├── load_module.py
│       │   ├── module_container.py
│       │   ├── renewable_module.py
│       │   └── unbalanced_energy_module.py
│       ├── utils/
│       │   ├── DataGenerator.py
│       │   ├── __init__.py
│       │   ├── logger.py
│       │   ├── ray.py
│       │   ├── serialize.py
│       │   └── space.py
│       └── version.py
└── tests/
    ├── __init__.py
    ├── conftest.py
    ├── control/
    │   ├── __init__.py
    │   ├── data_generation/
    │   │   ├── __init__.py
    │   │   └── test_data_generator.py
    │   ├── test_control.py
    │   ├── test_mpc.py
    │   └── test_rbc.py
    ├── envs/
    │   ├── __init__.py
    │   ├── test_discrete.py
    │   └── test_trajectory.py
    ├── helpers/
    │   ├── __init__.py
    │   ├── genset_module_testing_utils.py
    │   ├── modular_microgrid.py
    │   └── test_case.py
    ├── microgrid/
    │   ├── __init__.py
    │   ├── modules/
    │   │   ├── __init__.py
    │   │   ├── container_tests/
    │   │   │   ├── __init__.py
    │   │   │   └── test_container.py
    │   │   ├── conversion_test/
    │   │   │   ├── __init__.py
    │   │   │   └── test_modular_conversion.py
    │   │   ├── forecaster_tests/
    │   │   │   ├── __init__.py
    │   │   │   └── test_forecaster.py
    │   │   └── module_tests/
    │   │       ├── test_genset_long_status_changes.py
    │   │       ├── test_genset_module.py
    │   │       ├── test_genset_module_start_up_1_wind_down_1.py
    │   │       ├── test_load_module.py
    │   │       ├── test_renewable_module.py
    │   │       └── timeseries_modules.py
    │   ├── serialize/
    │   │   └── test_microgrid_serialization.py
    │   └── test_microgrid.py
    ├── test_microgridgenerator.py
    └── test_nonmodular_microgrid.py
Download .txt
SYMBOL INDEX (1012 symbols across 67 files)

FILE: docs/source/conf.py
  function autodoc_skip_member (line 87) | def autodoc_skip_member(app, what, name, obj, skip, options):
  function autodoc_process_signature (line 101) | def autodoc_process_signature(app, what, name, obj, options, signature, ...
  function linkcode_resolve (line 112) | def linkcode_resolve(domain, info):
  function setup (line 168) | def setup(app):

FILE: src/pymgrid/MicrogridGenerator.py
  class MicrogridGenerator (line 61) | class MicrogridGenerator:
    method __init__ (line 112) | def __init__(self, nb_microgrid=10,
    method _get_random_file (line 128) | def _get_random_file(self, path):
    method _scale_ts (line 137) | def _scale_ts(self, df_ts, size, scaling_method='sum'):
    method _resize_timeseries (line 150) | def _resize_timeseries(self, timeseries, current_time_step, new_time_s...
    method _get_pv_ts (line 178) | def _get_pv_ts(self):
    method _get_load_ts (line 187) | def _get_load_ts(self):
    method _get_wind_ts (line 196) | def _get_wind_ts(self):
    method _get_co2_ts (line 205) | def _get_co2_ts(self):
    method _get_genset (line 214) | def _get_genset(self, rated_power=1000, pmax=0.9, pmin=0.05):
    method _get_battery (line 230) | def _get_battery(self, capa=1000, duration=4, pcharge=100, pdischarge=...
    method _get_grid_price_ts (line 246) | def _get_grid_price_ts(self, nb_time_step_per_year, tou=0, rt=0, price...
    method _get_electricity_tariff (line 253) | def _get_electricity_tariff(self, scenario):
    method _get_grid (line 288) | def _get_grid(self, rated_power=1000, weak_grid=0, pmin=0.2, price_sce...
    method _generate_weak_grid_profile (line 321) | def _generate_weak_grid_profile(self, outage_per_day, duration_of_outa...
    method _size_mg (line 346) | def _size_mg(self, load, size_load=1):
    method _size_genset (line 372) | def _size_genset(self, load, max_operating_loading = 0.9):
    method _size_battery (line 382) | def _size_battery(self, load):
    method generate_microgrid (line 393) | def generate_microgrid(self, modular=True, verbose=False):
    method load (line 408) | def load(cls, scenario):
    method _bin_genset_grid (line 417) | def _bin_genset_grid(self):
    method _size_load (line 437) | def _size_load(self, size_load=None):
    method _create_microgrid (line 443) | def _create_microgrid(self):
    method print_mg_parameters (line 609) | def print_mg_parameters(self, id='all'):
    method print_all_costs (line 625) | def print_all_costs(self):

FILE: src/pymgrid/_deprecated/Environments/Environment.py
  function generate_sampler (line 34) | def generate_sampler(microgrid, forecast_args):
  class Environment (line 46) | class Environment(gym.Env):
    method __init__ (line 57) | def __init__(self, env_config, seed = 42):
    method get_reward (line 108) | def get_reward(self):
    method get_cost (line 116) | def get_cost(self):
    method step (line 121) | def step(self, action):
    method reset (line 159) | def reset(self, testing=False):
    method get_action (line 176) | def get_action(self, action):
    method states (line 195) | def states(self):  # soc, price, load, pv 'df status?'
    method transition (line 200) | def transition(self):
    method seed (line 215) | def seed (self, seed=None):
    method render (line 219) | def render(self, mode="human"):
    method get_action_continuous (line 224) | def get_action_continuous(self, action):
    method get_action_discrete (line 277) | def get_action_discrete(self, action):
    method get_action_priority_list (line 315) | def get_action_priority_list(self, action):
    method actions_agent_discret (line 349) | def actions_agent_discret(self, mg, action):
    method action_grid (line 361) | def action_grid(self, mg, action):
    method action_grid_genset (line 434) | def action_grid_genset(self, mg, action):
    method action_genset (line 530) | def action_genset(self, mg, action):

FILE: src/pymgrid/_deprecated/Environments/Preprocessing.py
  function normalize_environment_states (line 3) | def normalize_environment_states(mg):
  function sample_reset (line 27) | def sample_reset(has_grid, saa, microgrid, sampling_args=None):

FILE: src/pymgrid/_deprecated/Environments/pymgrid_csca.py
  function sample_reset (line 18) | def sample_reset(has_grid, saa, microgrid, sampling_args=None):
  function generate_sampler (line 42) | def generate_sampler(microgrid, forecast_args):
  class MicrogridEnv (line 55) | class MicrogridEnv(Env, ABC):
    method __init__ (line 58) | def __init__(self, microgrid, trajectory_len=None, max_episode_len=None):
    method _short_trajectory_set (line 101) | def _short_trajectory_set(self):
    method reset (line 112) | def reset(self):
    method step (line 123) | def step(self, action, **kwargs):
    method get_control_dict (line 154) | def get_control_dict(self, action):
    method run_control (line 161) | def run_control(self, control_dict):
  class ContinuousMicrogridEnv (line 174) | class ContinuousMicrogridEnv(MicrogridEnv):
    method __init__ (line 178) | def __init__(self, microgrid, standardization=True, trajectory_len=Non...
    method _get_action_ub_lb (line 205) | def _get_action_ub_lb(self):
    method get_values (line 237) | def get_values(self, *value_names):
    method reset (line 293) | def reset(self):
    method step (line 304) | def step(self, action, **kwargs):
    method standardize (line 354) | def standardize(self, data, mean_proxy=None, std_proxy=None, direction...
    method pre_compute_standardizations (line 393) | def pre_compute_standardizations(self,alg_to_use='mpc'):
    method get_control_dict (line 459) | def get_control_dict(self, action):
  class ContinuousMicrogridSampleEnv (line 487) | class ContinuousMicrogridSampleEnv(ContinuousMicrogridEnv):
    method __init__ (line 492) | def __init__(self, microgrid, standardization=True,
    method reset (line 500) | def reset(self, sampling_args=None):
  class SafeExpMicrogridEnv (line 511) | class SafeExpMicrogridEnv(ContinuousMicrogridEnv):
    method __init__ (line 515) | def __init__(self, microgrid,
    method get_num_constraints (line 536) | def get_num_constraints(self):
    method get_constraint_values (line 546) | def get_constraint_values(self):
    method _get_energy_balance (line 560) | def _get_energy_balance(self):
    method _get_inequality_constraints (line 581) | def _get_inequality_constraints(self):
  class SafeExpMicrogridSampleEnv (line 645) | class SafeExpMicrogridSampleEnv(SafeExpMicrogridEnv):
    method __init__ (line 646) | def __init__(self,
    method reset (line 669) | def reset(self, sampling_args=None):

FILE: src/pymgrid/_deprecated/Environments/pymgrid_csca_old.py
  class MicroGridEnv (line 8) | class MicroGridEnv(Environment):
    method __init__ (line 20) | def __init__(self, env_config, seed=42):
    method get_action (line 40) | def get_action(self, action):

FILE: src/pymgrid/_deprecated/Environments/pymgrid_csda.py
  class MicroGridEnv (line 8) | class MicroGridEnv(Environment):
    method __init__ (line 20) | def __init__(self, env_config, seed=42):
    method get_action (line 40) | def get_action(self, action):

FILE: src/pymgrid/_deprecated/Environments/pymgrid_cspla.py
  class MicroGridEnv (line 28) | class MicroGridEnv(Environment):
    method __init__ (line 41) | def __init__(self, env_config, seed=42):
    method get_action (line 50) | def get_action(self, action):

FILE: src/pymgrid/_deprecated/non_modular_microgrid.py
  function in_ipynb (line 31) | def in_ipynb():
  class Battery (line 57) | class Battery:
    method __init__ (line 112) | def __init__(self, param_battery, capa_to_charge, capa_to_discharge):
  class Genset (line 127) | class Genset:
    method __init__ (line 162) | def __init__(self, param):
  class Grid (line 170) | class Grid:
    method __init__ (line 211) | def __init__(self, param, status, price_import, price_export, co2):
  class NonModularMicrogrid (line 220) | class NonModularMicrogrid:
    method __init__ (line 343) | def __init__(self, parameters, horizon=DEFAULT_HORIZON, timestep=DEFAU...
    method _param_check (line 403) | def _param_check(self, parameters):
    method set_horizon (line 444) | def set_horizon(self, horizon):
    method set_cost_co2 (line 448) | def set_cost_co2(self, co2_cost):
    method get_data (line 452) | def get_data(self):
    method get_training_testing_data (line 456) | def get_training_testing_data(self):
    method get_control_dict (line 465) | def get_control_dict(self):
    method get_parameters (line 470) | def get_parameters(self):
    method get_cost (line 475) | def get_cost(self):
    method get_co2 (line 479) | def get_co2(self):
    method get_updated_values (line 483) | def get_updated_values(self):
    method forecast_all (line 502) | def forecast_all(self):
    method forecast_pv (line 516) | def forecast_pv(self):
    method forecast_load (line 532) | def forecast_load(self):
    method forecast_grid_status (line 546) | def forecast_grid_status(self):
    method forecast_grid_co2 (line 563) | def forecast_grid_co2(self):
    method forecast_grid_prices (line 580) | def forecast_grid_prices(self):
    method run (line 607) | def run(self, control_dict):
    method train_test_split (line 671) | def train_test_split(self, train_size=0.67, shuffle = False, cancel=Fa...
    method update_variables (line 744) | def update_variables(self):
    method reset (line 818) | def reset(self, testing=False):
    method _record_action (line 856) | def _record_action(self, control_dict, df):
    method _update_status (line 870) | def _update_status(self, production_dict, df, next_load, next_pv, next...
    method _check_constraints_genset (line 921) | def _check_constraints_genset(self, p_genset):
    method _check_constraints_grid (line 935) | def _check_constraints_grid(self, p_import, p_export):
    method _check_constraints_battery (line 956) | def _check_constraints_battery(self, p_charge, p_discharge, status):
    method _record_production (line 989) | def _record_production(self, control_dict, production_dict, status):
    method _record_co2 (line 1082) | def _record_co2(self, control_dict, df, grid_co2=0):
    method _record_cost (line 1098) | def _record_cost(self, control_dict, df, df_co2, cost_import=0, cost_e...
    method print_load_pv (line 1141) | def print_load_pv(self):
    method print_actual_production (line 1151) | def print_actual_production(self):
    method print_control (line 1160) | def print_control(self):
    method print_co2 (line 1169) | def print_co2(self):
    method print_cumsum_cost (line 1178) | def print_cumsum_cost(self):
    method print_benchmark_cost (line 1189) | def print_benchmark_cost(self):
    method print_info (line 1207) | def print_info(self):
    method print_control_info (line 1225) | def print_control_info(self):
    method print_updated_parameters (line 1235) | def print_updated_parameters(self):
    method penalty (line 1251) | def penalty(self, coef = 1):
    method from_modular (line 1261) | def from_modular(cls, modular):
    method to_modular (line 1265) | def to_modular(self):

FILE: src/pymgrid/algos/Control.py
  class HorizonOutput (line 28) | class HorizonOutput:
    method __init__ (line 30) | def __init__(self,control_dicts, microgrid, current_step):
    method compute_cost_over_horizon (line 37) | def compute_cost_over_horizon(self, current_step):
    method __eq__ (line 59) | def __eq__(self, other):
    method __lt__ (line 64) | def __lt__(self, other):
    method __gt__ (line 69) | def __gt__(self, other):
  class ControlOutput (line 75) | class ControlOutput(dict):
    method __init__ (line 94) | def __init__(self, names=None, dfs=None, alg_name=None, empty=False, m...
    method append (line 131) | def append(self, other_output, actual_load=None, actual_pv=None, actua...
    method to_frame (line 202) | def to_frame(self):
    method __eq__ (line 217) | def __eq__(self, other):
    method __lt__ (line 222) | def __lt__(self, other):
    method __gt__ (line 227) | def __gt__(self, other):
  class Benchmarks (line 233) | class Benchmarks:
    method __init__ (line 258) | def __init__(self, microgrid):
    method run_mpc_benchmark (line 272) | def run_mpc_benchmark(self, verbose=False, **kwargs):
    method run_rule_based_benchmark (line 284) | def run_rule_based_benchmark(self):
    method run_saa_benchmark (line 296) | def run_saa_benchmark(self, preset_to_use=85, **kwargs):
    method run_benchmarks (line 303) | def run_benchmarks(self, algo=None, verbose=False, preset_to_use=85, *...
    method describe_benchmarks (line 326) | def describe_benchmarks(self, test_split=False, test_ratio=None, test_...

FILE: src/pymgrid/algos/mpc/mpc.py
  class ModelPredictiveControl (line 55) | class ModelPredictiveControl:
    method __init__ (line 81) | def __init__(self, microgrid, solver=None):
    method has_genset (line 106) | def has_genset(self):
    method _verify_microgrid (line 115) | def _verify_microgrid(self, microgrid):
    method _get_modules (line 130) | def _get_modules(self, modular_microgrid):
    method _get_horizon (line 138) | def _get_horizon(self):
    method _parse_microgrid (line 147) | def _parse_microgrid(self):
    method _parse_nonmodular_microgrid (line 172) | def _parse_nonmodular_microgrid(self):
    method _parse_modular_microgrid (line 199) | def _parse_modular_microgrid(self):
    method _create_problem (line 231) | def _create_problem(self, eta, battery_capacity, fuel_cost, cost_batte...
    method _get_solver (line 376) | def _get_solver(self, mosek_failure=None):
    method _set_parameters (line 401) | def _set_parameters(self, load_vector, pv_vector, grid_vector, import_...
    method run (line 494) | def run(self, max_steps=None, verbose=False):
    method _run_mpc_on_nonmodular (line 517) | def _run_mpc_on_nonmodular(self, forecast_steps=None, verbose=False):
    method _run_mpc_on_modular (line 534) | def _run_mpc_on_modular(self, forecast_steps=None, verbose=False):
    method _get_num_iter (line 553) | def _get_num_iter(self, forecast_steps=None):
    method _run_mpc_on_sample (line 563) | def _run_mpc_on_sample(self, sample, forecast_steps=None, verbose=False):
    method _set_and_solve (line 715) | def _set_and_solve(self,
    method _extract_control_dict (line 799) | def _extract_control_dict(self, return_steps, pv_vector, load_vector):
    method _extract_modular_control (line 866) | def _extract_modular_control(self, load_vector, verbose):
    method _get_modular_state_values (line 898) | def _get_modular_state_values(self):
    method mpc_single_step (line 965) | def mpc_single_step(self, sample, previous_output, current_step):

FILE: src/pymgrid/algos/priority_list/priority_list.py
  class PriorityListAlgo (line 14) | class PriorityListAlgo:
    method get_priority_lists (line 15) | def get_priority_lists(self, remove_redundant_gensets):
    method _remove_redundant_actions (line 40) | def _remove_redundant_actions(self, priority_lists, gensets=False):
    method _remove_redundant_gensets (line 53) | def _remove_redundant_gensets(self, priority_lists):
    method _populate_action (line 69) | def _populate_action(self, priority_list):
    method _consume_in_module (line 118) | def _consume_in_module(self, module_to_deploy, remaining_load):
    method _produce_from_module (line 138) | def _produce_from_module(self, module_action_number, module_to_deploy,...
    method _get_load (line 157) | def _get_load(self):
    method _get_renewable (line 166) | def _get_renewable(self):
    method modules (line 171) | def modules(self):
    method fixed (line 176) | def fixed(self):
    method flex (line 181) | def flex(self):
    method get_empty_action (line 185) | def get_empty_action(self):

FILE: src/pymgrid/algos/priority_list/priority_list_element.py
  class PriorityListElement (line 8) | class PriorityListElement:
    method __eq__ (line 62) | def __eq__(self, other):
    method __lt__ (line 73) | def __lt__(self, other):

FILE: src/pymgrid/algos/rbc/_nonmodular_rbc.py
  class NonModularRuleBasedControl (line 8) | class NonModularRuleBasedControl:
    method __init__ (line 9) | def __init__(self, microgrid):
    method _generate_priority_list (line 15) | def _generate_priority_list(self, architecture, parameters, grid_statu...
    method _run_priority_based (line 48) | def _run_priority_based(self, load, pv, parameters, status, priority_d...
    method run_rule_based (line 181) | def run_rule_based(self, priority_list=0, length=None):

FILE: src/pymgrid/algos/rbc/rbc.py
  class RuleBasedControl (line 7) | class RuleBasedControl(PriorityListAlgo):
    method __init__ (line 26) | def __init__(self, microgrid, priority_list=None, remove_redundant_gen...
    method _get_priority_list (line 31) | def _get_priority_list(self, priority_list, remove_redundant_gensets):
    method _get_action (line 46) | def _get_action(self):
    method reset (line 52) | def reset(self):
    method run (line 64) | def run(self, max_steps=None, verbose=False):
    method get_empty_action (line 95) | def get_empty_action(self):
    method microgrid (line 102) | def microgrid(self):
    method fixed (line 115) | def fixed(self):
    method flex (line 120) | def flex(self):
    method modules (line 125) | def modules(self):
    method priority_list (line 130) | def priority_list(self):

FILE: src/pymgrid/algos/saa/saa.py
  class SampleAverageApproximation (line 10) | class SampleAverageApproximation(SampleGenerator):
    method __init__ (line 41) | def __init__(self, microgrid, control_duration=8760, **forecast_args):
    method run (line 52) | def run(self, n_samples=10, forecast_steps=None, optimal_percentile=0....
    method determine_optimal_actions (line 82) | def determine_optimal_actions(self, outputs=None, percentile=0.5, verb...
    method run_mpc_on_group (line 112) | def run_mpc_on_group(self, samples, forecast_steps=None, optimal_perce...
    method run_deterministic_on_forecast (line 151) | def run_deterministic_on_forecast(self, forecast_steps=None, verbose=F...

FILE: src/pymgrid/convert/convert.py
  function to_modular (line 7) | def to_modular(nonmodular, raise_errors=False):
  function to_nonmodular (line 17) | def to_nonmodular(modular):

FILE: src/pymgrid/convert/get_module.py
  function get_module (line 5) | def get_module(component, nonmodular, raise_errors):
  function get_load_module (line 22) | def get_load_module(nonmodular, raise_errors):
  function get_pv_module (line 30) | def get_pv_module(nonmodular, raise_errors):
  function get_battery_module (line 39) | def get_battery_module(nonmodular, raise_errors):
  function get_genset_module (line 58) | def get_genset_module(nonmodular, raise_errors):
  function get_grid_module (line 75) | def get_grid_module(nonmodular, raise_errors):
  function get_unbalanced_energy_module (line 99) | def get_unbalanced_energy_module(nonmodular, raise_errors):

FILE: src/pymgrid/convert/to_nonmodular_ops.py
  function get_empty_params (line 24) | def get_empty_params():
  function check_viability (line 28) | def check_viability(modular):
  function finalize_params (line 58) | def finalize_params(params_dict):
  function add_params_from_module (line 62) | def add_params_from_module(module, params_dict):
  function add_load_params (line 79) | def add_load_params(load_module, params_dict):
  function add_pv_params (line 89) | def add_pv_params(pv_module, params_dict):
  function add_battery_params (line 99) | def add_battery_params(battery_module, params_dict):
  function add_grid_params (line 123) | def add_grid_params(grid_module, params_dict):
  function add_genset_params (line 148) | def add_genset_params(genset_module, params_dict):
  function add_unbalanced_energy_params (line 172) | def add_unbalanced_energy_params(unbalanced_energy_module, params_dict):
  function _add_empty (line 181) | def _add_empty(params_dict, subdict_name, *keys):
  function _add_to_architecture (line 185) | def _add_to_architecture(params_dict, component):
  function _add_to_parameters (line 191) | def _add_to_parameters(params_dict, **parameters):
  function _add_to_df_actions (line 196) | def _add_to_df_actions(params_dict, *keys):
  function _add_to_df_status (line 200) | def _add_to_df_status(params_dict, **init_status_values):
  function _add_to_df_actual_generation (line 205) | def _add_to_df_actual_generation(params_dict, *keys):
  function _add_to_df_cost (line 209) | def _add_to_df_cost(params_dict, *keys):
  function _add_to_control_dict (line 213) | def _add_to_control_dict(params_dict, *keys):
  function _add_cost_co2 (line 217) | def _add_cost_co2(params_dict, cost_co2):
  function _add_genset_polynom (line 229) | def _add_genset_polynom(params_dict):

FILE: src/pymgrid/envs/base/base.py
  class BaseMicrogridEnv (line 11) | class BaseMicrogridEnv(Microgrid, Env):
    method __new__ (line 65) | def __new__(cls, modules, *args, **kwargs):
    method __init__ (line 85) | def __init__(self,
    method _validate_observation_keys (line 109) | def _validate_observation_keys(self, keys):
    method _get_action_space (line 125) | def _get_action_space(self, remove_redundant_actions=False):
    method _get_observation_space (line 128) | def _get_observation_space(self):
    method reset (line 165) | def reset(self):
    method step (line 169) | def step(self, action, normalized=True):
    method _get_obs (line 211) | def _get_obs(self, obs):
    method render (line 225) | def render(self, mode="human"):
    method unwrapped (line 230) | def unwrapped(self):
    method flat_spaces (line 235) | def flat_spaces(self):
    method from_microgrid (line 253) | def from_microgrid(cls, microgrid, **kwargs):
    method from_nonmodular (line 288) | def from_nonmodular(cls, nonmodular, **kwargs):
    method from_scenario (line 293) | def from_scenario(cls, microgrid_number=0, **kwargs):
    method load (line 302) | def load(cls, stream):

FILE: src/pymgrid/envs/base/skip_init.py
  function skip_init (line 1) | def skip_init(cls, init):

FILE: src/pymgrid/envs/continuous/continuous.py
  class ContinuousMicrogridEnv (line 7) | class ContinuousMicrogridEnv(BaseMicrogridEnv):
    method _get_nested_action_space (line 56) | def _get_nested_action_space(self):
    method _get_action_space (line 60) | def _get_action_space(self):
    method _get_action (line 64) | def _get_action(self, action):
    method step (line 72) | def step(self, action):
    method run (line 76) | def run(self, action, normalized=True):

FILE: src/pymgrid/envs/discrete/discrete.py
  class DiscreteMicrogridEnv (line 10) | class DiscreteMicrogridEnv(BaseMicrogridEnv, PriorityListAlgo):
    method __init__ (line 38) | def __init__(self,
    method _get_action_space (line 60) | def _get_action_space(self, remove_redundant_gensets=False):
    method _get_action (line 82) | def _get_action(self, action_num):
    method remove_action (line 90) | def remove_action(self, action_number):
    method step (line 109) | def step(self, action):
    method sample_action (line 145) | def sample_action(self, strict_bound=False, sample_flex_modules=False):
    method __repr__ (line 148) | def __repr__(self):
    method __str__ (line 151) | def __str__(self):

FILE: src/pymgrid/forecast/forecaster.py
  function get_forecaster (line 10) | def get_forecaster(forecaster,
  class Forecaster (line 91) | class Forecaster:
    method __init__ (line 92) | def __init__(self, observation_space, forecast_shape):
    method _get_forecast_shaped_space (line 97) | def _get_forecast_shaped_space(self, shape):
    method _forecast (line 117) | def _forecast(self, val_c, val_c_n, n):
    method _pad (line 120) | def _pad(self, forecast, n):
    method full_pad (line 133) | def full_pad(self, shape, forecast_horizon):
    method _clip (line 140) | def _clip(self, forecast):
    method observation_space (line 152) | def observation_space(self):
    method observation_space (line 156) | def observation_space(self, value):
    method __eq__ (line 165) | def __eq__(self, other):
    method __call__ (line 172) | def __call__(self, val_c, val_c_n, n):
    method __repr__ (line 189) | def __repr__(self):
  class UserDefinedForecaster (line 193) | class UserDefinedForecaster(Forecaster):
    method __init__ (line 194) | def __init__(self, forecaster_function, observation_space, forecast_sh...
    method _cast_to_arr (line 205) | def _cast_to_arr(self, forecast, val_c_n):
    method _forecast (line 210) | def _forecast(self, val_c, val_c_n, n):
  class OracleForecaster (line 215) | class OracleForecaster(Forecaster):
    method _forecast (line 216) | def _forecast(self, val_c, val_c_n, n):
  class GaussianNoiseForecaster (line 220) | class GaussianNoiseForecaster(Forecaster):
    method __init__ (line 221) | def __init__(self,
    method _get_noise_std (line 237) | def _get_noise_std(self, time_series):
    method _get_noise (line 252) | def _get_noise(self, size):
    method _forecast (line 262) | def _forecast(self, val_c, val_c_n, n):
    method noise_std (line 266) | def noise_std(self):
    method noise_std (line 270) | def noise_std(self, value):
    method __repr__ (line 273) | def __repr__(self):
  class NoForecaster (line 278) | class NoForecaster(Forecaster):
    method _forecast (line 279) | def _forecast(self, val_c, val_c_n, n):
  function _validate_callable_forecaster (line 283) | def _validate_callable_forecaster(forecaster, time_series):
  function _validate_vectorized_forecaster (line 299) | def _validate_vectorized_forecaster(forecaster, val_c, vector_true_forec...
  function _validate_scalar_forecaster (line 328) | def _validate_scalar_forecaster(forecaster, val_c, scalar_true_forecast,...
  function _validate_forecasted_value (line 350) | def _validate_forecasted_value(forecaster_output, true_forecast, val_c, n):
  function vectorize_scalar_forecaster (line 362) | def vectorize_scalar_forecaster(forecaster):

FILE: src/pymgrid/microgrid/microgrid.py
  class Microgrid (line 15) | class Microgrid(yaml.YAMLObject):
    method __init__ (line 100) | def __init__(self,
    method _get_unbalanced_energy_module (line 130) | def _get_unbalanced_energy_module(self,
    method _get_module_container (line 139) | def _get_module_container(self, modules, add_unbalanced_module, loss_l...
    method _check_trajectory_func (line 175) | def _check_trajectory_func(self, trajectory_func):
    method reset (line 205) | def reset(self):
    method _set_trajectory (line 221) | def _set_trajectory(self):
    method run (line 227) | def run(self, control, normalized=True):
    method _get_log_dict (line 327) | def _get_log_dict(self, provided_energy, absorbed_energy, log_dict=Non...
    method get_cost_info (line 334) | def get_cost_info(self):
    method sample_action (line 337) | def sample_action(self, strict_bound=False, sample_flex_modules=False):
    method get_empty_action (line 364) | def get_empty_action(self, sample_flex_modules=False):
    method to_normalized (line 388) | def to_normalized(self, data_dict, act=False, obs=False):
    method from_normalized (line 411) | def from_normalized(self, data_dict, act=False, obs=False):
    method get_log (line 434) | def get_log(self, as_frame=True, drop_singleton_key=False):
    method set_forecaster (line 477) | def set_forecaster(self,
    method get_forecast_horizon (line 553) | def get_forecast_horizon(self):
    method set_module_attr (line 583) | def set_module_attr(self, attr_name, value):
    method current_step (line 615) | def current_step(self):
    method initial_step (line 627) | def initial_step(self):
    method _get_module_initial_step (line 640) | def _get_module_initial_step(self):
    method initial_step (line 649) | def initial_step(self, value):
    method _set_initial_step (line 652) | def _set_initial_step(self, value, modules_only=False):
    method final_step (line 658) | def final_step(self):
    method _get_module_final_step (line 669) | def _get_module_final_step(self):
    method final_step (line 678) | def final_step(self, value):
    method _set_final_step (line 681) | def _set_final_step(self, value, modules_only=False):
    method modules (line 687) | def modules(self):
    method state_dict (line 699) | def state_dict(self, normalized=False):
    method log (line 721) | def log(self):
    method state_series (line 735) | def state_series(self, normalized=False):
    method fixed (line 763) | def fixed(self):
    method flex (line 774) | def flex(self):
    method controllable (line 786) | def controllable(self):
    method module_list (line 797) | def module_list(self):
    method n_modules (line 810) | def n_modules(self):
    method dump (line 820) | def dump(self, stream=None):
    method load (line 848) | def load(cls, stream):
    method to_yaml (line 867) | def to_yaml(cls, dumper, data):
    method from_yaml (line 875) | def from_yaml(cls, loader, node):
    method serialize (line 895) | def serialize(self, dumper_stream):
    method _serialization_data (line 901) | def _serialization_data(self):
    method from_nonmodular (line 911) | def from_nonmodular(cls, nonmodular):
    method to_nonmodular (line 937) | def to_nonmodular(self):
    method from_scenario (line 959) | def from_scenario(cls, microgrid_number=0):
    method _dir_additions (line 982) | def _dir_additions(self):
    method __dir__ (line 988) | def __dir__(self):
    method __getnewargs__ (line 993) | def __getnewargs__(self):
    method __len__ (line 996) | def __len__(self):
    method __eq__ (line 1009) | def __eq__(self, other):
    method __repr__ (line 1018) | def __repr__(self):
    method __getattr__ (line 1023) | def __getattr__(self, item):

FILE: src/pymgrid/microgrid/reward_shaping/base.py
  class BaseRewardShaper (line 6) | class BaseRewardShaper(yaml.YAMLObject):
    method sum_module_val (line 11) | def sum_module_val(info, module_name, module_attr):
    method __call__ (line 19) | def __call__(self, step_info, cost_info):
    method __repr__ (line 22) | def __repr__(self):

FILE: src/pymgrid/microgrid/reward_shaping/battery_discharge_shaper.py
  class BatteryDischargeShaper (line 6) | class BatteryDischargeShaper(BaseRewardShaper):
    method __call__ (line 22) | def __call__(self, step_info, cost_info):

FILE: src/pymgrid/microgrid/reward_shaping/pv_curtailment_shaper.py
  class PVCurtailmentShaper (line 4) | class PVCurtailmentShaper(BaseRewardShaper):
    method __call__ (line 15) | def __call__(self, step_info, cost_info):

FILE: src/pymgrid/microgrid/trajectory/base.py
  class BaseTrajectory (line 7) | class BaseTrajectory(yaml.YAMLObject):
    method __call__ (line 12) | def __call__(self, initial_step, final_step):
    method __repr__ (line 15) | def __repr__(self):
    method __eq__ (line 20) | def __eq__(self, other):

FILE: src/pymgrid/microgrid/trajectory/deterministic.py
  class DeterministicTrajectory (line 4) | class DeterministicTrajectory(BaseTrajectory):
    method __init__ (line 7) | def __init__(self, initial_step, final_step):
    method __call__ (line 11) | def __call__(self, initial_step, final_step):

FILE: src/pymgrid/microgrid/trajectory/stochastic.py
  class StochasticTrajectory (line 6) | class StochasticTrajectory(BaseTrajectory):
    method __call__ (line 9) | def __call__(self, initial_step, final_step):
  class FixedLengthStochasticTrajectory (line 17) | class FixedLengthStochasticTrajectory(BaseTrajectory):
    method __init__ (line 20) | def __init__(self, trajectory_length):
    method __call__ (line 23) | def __call__(self, initial_step, final_step):

FILE: src/pymgrid/microgrid/utils/step.py
  class MicrogridStep (line 4) | class MicrogridStep:
    method __init__ (line 5) | def __init__(self, reward_shaping_func=None, cost_info=None):
    method append (line 13) | def append(self, module_name, obs, reward, done, info):
    method balance (line 33) | def balance(self):
    method output (line 38) | def output(self):
    method shaped_reward (line 41) | def shaped_reward(self):
    method _output_info (line 48) | def _output_info(self):
    method obs (line 52) | def obs(self):
    method reward (line 56) | def reward(self):
    method done (line 60) | def done(self):
    method info (line 64) | def info(self):

FILE: src/pymgrid/modules/base/base_module.py
  class BaseMicrogridModule (line 17) | class BaseMicrogridModule(yaml.YAMLObject):
    method __init__ (line 37) | def __init__(self,
    method _get_action_spaces (line 53) | def _get_action_spaces(self):
    method _get_observation_spaces (line 59) | def _get_observation_spaces(self):
    method reset (line 65) | def reset(self):
    method _raise_error (line 79) | def _raise_error(self, ask_value, available_value, as_source=False, as...
    method step (line 95) | def step(self, action, normalized=True):
    method _unnormalized_step (line 161) | def _unnormalized_step(self, unnormalized_action):
    method as_source (line 173) | def as_source(self, energy_demand):
    method as_sink (line 228) | def as_sink(self, energy_excess):
    method _log (line 276) | def _log(self, state_dict_pre_step, provided_energy=None, absorbed_ene...
    method _update_step (line 292) | def _update_step(self, reset=False):
    method update (line 299) | def update(self, external_energy_change, as_source=False, as_sink=False):
    method sample_action (line 326) | def sample_action(self, strict_bound=False):
    method to_normalized (line 358) | def to_normalized(self, value, act=False, obs=False):
    method from_normalized (line 383) | def from_normalized(self, value, act=False, obs=False):
    method log_dict (line 408) | def log_dict(self):
    method log_frame (line 419) | def log_frame(self):
    method log (line 431) | def log(self):
    method logger (line 445) | def logger(self):
    method logger_last (line 457) | def logger_last(self):
    method logger (line 469) | def logger(self, logger):
    method state_dict (line 473) | def state_dict(self, normalized=False):
    method _state_dict (line 493) | def _state_dict(self):
    method state (line 506) | def state(self):
    method current_step (line 520) | def current_step(self):
    method current_step (line 532) | def current_step(self, value):
    method min_obs (line 537) | def min_obs(self):
    method max_obs (line 554) | def max_obs(self):
    method min_act (line 571) | def min_act(self):
    method max_act (line 588) | def max_act(self):
    method min_production (line 604) | def min_production(self):
    method max_production (line 622) | def max_production(self):
    method max_consumption (line 637) | def max_consumption(self):
    method marginal_cost (line 652) | def marginal_cost(self):
    method production_marginal_cost (line 665) | def production_marginal_cost(self):
    method absorption_marginal_cost (line 669) | def absorption_marginal_cost(self):
    method action_space (line 673) | def action_space(self):
    method observation_space (line 687) | def observation_space(self):
    method is_source (line 701) | def is_source(self):
    method is_sink (line 713) | def is_sink(self):
    method dump (line 724) | def dump(self, stream=None):
    method load (line 752) | def load(cls, stream):
    method from_yaml (line 772) | def from_yaml(cls, loader, node):
    method to_yaml (line 802) | def to_yaml(cls, dumper, data):
    method serialize (line 826) | def serialize(self, dumper_stream):
    method serializable_state_attributes (line 852) | def serializable_state_attributes(self):
    method _serialize_state_attributes (line 867) | def _serialize_state_attributes(self):
    method _serialize_cls_params (line 870) | def _serialize_cls_params(self):
    method deserialize_instance (line 884) | def deserialize_instance(cls, param_dict):
    method deserialize (line 927) | def deserialize(self, serialized_dict):
    method __eq__ (line 959) | def __eq__(self, other):
    method __repr__ (line 968) | def __repr__(self):

FILE: src/pymgrid/modules/base/timeseries/base_timeseries_module.py
  class BaseTimeSeriesMicrogridModule (line 8) | class BaseTimeSeriesMicrogridModule(BaseMicrogridModule):
    method __init__ (line 22) | def __init__(self,
    method _set_time_series (line 58) | def _set_time_series(self, time_series):
    method _sign_check (line 68) | def _sign_check(self, time_series):
    method _get_bounds (line 81) | def _get_bounds(self):
    method _set_state_dict_keys (line 90) | def _set_state_dict_keys(self):
    method _update_step (line 99) | def _update_step(self, reset=False):
    method forecast (line 103) | def forecast(self):
    method _done (line 124) | def _done(self):
    method current_obs (line 128) | def current_obs(self):
    method time_series (line 143) | def time_series(self):
    method time_series (line 156) | def time_series(self, value):
    method min_obs (line 163) | def min_obs(self):
    method max_obs (line 168) | def max_obs(self):
    method min_act (line 173) | def min_act(self):
    method max_act (line 177) | def max_act(self):
    method forecaster (line 181) | def forecaster(self):
    method set_forecaster (line 193) | def set_forecaster(self,
    method forecast_horizon (line 247) | def forecast_horizon(self):
    method forecast_horizon (line 260) | def forecast_horizon(self, value):
    method forecaster_increase_uncertainty (line 276) | def forecaster_increase_uncertainty(self):
    method forecaster_relative_noise (line 295) | def forecaster_relative_noise(self):
    method final_step (line 314) | def final_step(self):
    method final_step (line 318) | def final_step(self, value):
    method _state_dict (line 332) | def _state_dict(self):
    method serialize (line 340) | def serialize(self, dumper_stream):
    method serializable_state_attributes (line 345) | def serializable_state_attributes(self):
    method __len__ (line 348) | def __len__(self):

FILE: src/pymgrid/modules/battery_module.py
  class BatteryModule (line 7) | class BatteryModule(BaseMicrogridModule):
    method __init__ (line 66) | def __init__(self,
    method _init_battery (line 96) | def _init_battery(self, init_charge, init_soc):
    method update (line 108) | def update(self, external_energy_change, as_source=False, as_sink=False):
    method _update_state (line 125) | def _update_state(self, energy_change):
    method get_cost (line 132) | def get_cost(self, energy_change):
    method model_transition (line 149) | def model_transition(self, energy):
    method transition_kwargs (line 191) | def transition_kwargs(self):
    method default_transition_model (line 245) | def default_transition_model(external_energy_change, efficiency, **tra...
    method _state_dict (line 280) | def _state_dict(self):
    method max_production (line 284) | def max_production(self):
    method max_consumption (line 289) | def max_consumption(self):
    method current_charge (line 294) | def current_charge(self):
    method soc (line 309) | def soc(self):
    method min_obs (line 324) | def min_obs(self):
    method max_obs (line 329) | def max_obs(self):
    method min_act (line 333) | def min_act(self):
    method max_act (line 337) | def max_act(self):
    method production_marginal_cost (line 341) | def production_marginal_cost(self):
    method absorption_marginal_cost (line 345) | def absorption_marginal_cost(self):
    method is_source (line 349) | def is_source(self):
    method is_sink (line 353) | def is_sink(self):
    method soc (line 357) | def soc(self, value):
    method current_charge (line 361) | def current_charge(self, value):

FILE: src/pymgrid/modules/genset_module.py
  class GensetModule (line 8) | class GensetModule(BaseMicrogridModule):
    method __init__ (line 61) | def __init__(self,
    method step (line 100) | def step(self, action, normalized=True):
    method get_co2 (line 151) | def get_co2(self, production):
    method get_co2_cost (line 167) | def get_co2_cost(self, production):
    method _get_fuel_cost (line 183) | def _get_fuel_cost(self, production):
    method get_cost (line 188) | def get_cost(self, production):
    method update (line 207) | def update(self, external_energy_change, as_source=False, as_sink=False):
    method _reset_up_down_times (line 216) | def _reset_up_down_times(self):
    method _update_up_down_times (line 229) | def _update_up_down_times(self):
    method update_status (line 235) | def update_status(self, goal_status):
    method _finish_in_progress_change (line 302) | def _finish_in_progress_change(self):
    method _instant_up (line 313) | def _instant_up(self):
    method _instant_down (line 320) | def _instant_down(self):
    method _non_instantaneous_update (line 327) | def _non_instantaneous_update(self, goal_status):
    method sample_action (line 348) | def sample_action(self, strict_bound=False, **kwargs):
    method _raise_error (line 351) | def _raise_error(self, ask_value, available_value, as_source=False, as...
    method next_status (line 360) | def next_status(self, goal_status):
    method next_max_production (line 392) | def next_max_production(self, goal_status):
    method next_min_production (line 409) | def next_min_production(self, goal_status):
    method serializable_state_attributes (line 426) | def serializable_state_attributes(self):
    method _state_dict (line 429) | def _state_dict(self):
    method current_status (line 436) | def current_status(self):
    method goal_status (line 451) | def goal_status(self):
    method max_production (line 466) | def max_production(self):
    method min_production (line 485) | def min_production(self):
    method min_obs (line 504) | def min_obs(self):
    method max_obs (line 508) | def max_obs(self):
    method min_act (line 512) | def min_act(self):
    method max_act (line 516) | def max_act(self):
    method production_marginal_cost (line 520) | def production_marginal_cost(self):
    method is_source (line 524) | def is_source(self):

FILE: src/pymgrid/modules/grid_module.py
  class GridModule (line 8) | class GridModule(BaseTimeSeriesMicrogridModule):
    method __init__ (line 73) | def __init__(self,
    method _check_params (line 103) | def _check_params(self, max_import, max_export, time_series):
    method _get_bounds (line 125) | def _get_bounds(self):
    method update (line 134) | def update(self, external_energy_change, as_source=False, as_sink=False):
    method get_cost (line 143) | def get_cost(self, import_export, as_source, as_sink):
    method get_co2_cost (line 176) | def get_co2_cost(self, import_export, as_source, as_sink):
    method get_co2_production (line 199) | def get_co2_production(self, import_export, as_source, as_sink):
    method as_flex (line 230) | def as_flex(self):
    method as_fixed (line 239) | def as_fixed(self):
    method import_price (line 249) | def import_price(self):
    method export_price (line 262) | def export_price(self):
    method co2_per_kwh (line 275) | def co2_per_kwh(self):
    method grid_status (line 289) | def grid_status(self):
    method current_status (line 302) | def current_status(self):
    method max_production (line 315) | def max_production(self):
    method max_consumption (line 319) | def max_consumption(self):
    method production_marginal_cost (line 323) | def production_marginal_cost(self):
    method absorption_marginal_cost (line 327) | def absorption_marginal_cost(self):
    method is_source (line 331) | def is_source(self):
    method is_sink (line 335) | def is_sink(self):
    method weak_grid (line 339) | def weak_grid(self):
    method __repr__ (line 351) | def __repr__(self):

FILE: src/pymgrid/modules/load_module.py
  class LoadModule (line 8) | class LoadModule(BaseTimeSeriesMicrogridModule):
    method __init__ (line 58) | def __init__(self,
    method _get_bounds (line 82) | def _get_bounds(self):
    method update (line 86) | def update(self, external_energy_change, as_source=False, as_sink=False):
    method sample_action (line 93) | def sample_action(self, strict_bound=False):
    method max_consumption (line 97) | def max_consumption(self):
    method current_load (line 101) | def current_load(self):
    method is_sink (line 114) | def is_sink(self):

FILE: src/pymgrid/modules/module_container.py
  class Container (line 8) | class Container(UserDict):
    method __init__ (line 9) | def __init__(self, *args, **kwargs):
    method containers (line 14) | def containers(self):
    method to_list (line 25) | def to_list(self):
    method to_dict (line 40) | def to_dict(self):
    method to_tuples (line 55) | def to_tuples(self):
    method iterlist (line 71) | def iterlist(self):
    method iterdict (line 84) | def iterdict(self):
    method get_attrs (line 97) | def get_attrs(self, *attrs, unique=False, as_pandas=True):
    method dir_additions (line 197) | def dir_additions(self):
    method __getitem__ (line 209) | def __getitem__(self, item):
    method __getattr__ (line 220) | def __getattr__(self, item):
    method __len__ (line 228) | def __len__(self):
    method __repr__ (line 231) | def __repr__(self):
    method __dir__ (line 237) | def __dir__(self):
    method __contains__ (line 242) | def __contains__(self, item):
  class ModuleContainer (line 246) | class ModuleContainer(Container):
    method __init__ (line 285) | def __init__(self, modules):
    method _get_types_by_name (line 297) | def _get_types_by_name(self):
    method _set_midlevel (line 300) | def _set_midlevel(self):
    method names (line 317) | def names(self):
    method containers (line 321) | def containers(self):
  class ModuleList (line 325) | class ModuleList(UserList):
    method item (line 326) | def item(self):
    method to_list (line 345) | def to_list(self):
  function get_subcontainers (line 355) | def get_subcontainers(modules):

FILE: src/pymgrid/modules/renewable_module.py
  class RenewableModule (line 8) | class RenewableModule(BaseTimeSeriesMicrogridModule):
    method __init__ (line 61) | def __init__(self,
    method update (line 86) | def update(self, external_energy_change, as_source=False, as_sink=False):
    method max_production (line 96) | def max_production(self):
    method current_renewable (line 100) | def current_renewable(self):
    method is_source (line 113) | def is_source(self):

FILE: src/pymgrid/modules/unbalanced_energy_module.py
  class UnbalancedEnergyModule (line 7) | class UnbalancedEnergyModule(BaseMicrogridModule):
    method __init__ (line 13) | def __init__(self,
    method update (line 28) | def update(self, external_energy_change, as_source=False, as_sink=False):
    method get_cost (line 38) | def get_cost(self, energy_amount, as_source, as_sink):
    method _state_dict (line 72) | def _state_dict(self):
    method state (line 76) | def state(self):
    method min_obs (line 80) | def min_obs(self):
    method max_obs (line 84) | def max_obs(self):
    method min_act (line 88) | def min_act(self):
    method max_act (line 92) | def max_act(self):
    method max_production (line 96) | def max_production(self):
    method max_consumption (line 100) | def max_consumption(self):
    method is_source (line 104) | def is_source(self):
    method is_sink (line 108) | def is_sink(self):
    method production_marginal_cost (line 112) | def production_marginal_cost(self):
    method absorption_marginal_cost (line 116) | def absorption_marginal_cost(self):

FILE: src/pymgrid/utils/DataGenerator.py
  function return_underlying_data (line 30) | def return_underlying_data(microgrid):
  class NoisyPVData (line 63) | class NoisyPVData:
    method __init__ (line 64) | def __init__(self, pv_data = None,file_name = None):
    method import_file (line 91) | def import_file(self,file_name):
    method data_munge (line 94) | def data_munge(self, verbose=False):
    method _add_feature_columns (line 124) | def _add_feature_columns(self, num_feature_functions=1, period_scale=1...
    method max_min_curve_interpolate (line 178) | def max_min_curve_interpolate(self, num_feature_functions=1,
    method most_light_curve_eval (line 253) | def most_light_curve_eval(self, max_min, cumulative_hours=None, day_ho...
    method _sample_parabola (line 307) | def _sample_parabola(self,noise_type, noise_parameters, verbose, push_...
    method sample (line 409) | def sample(self,
    method _check_sample (line 505) | def _check_sample(self, stacked_data, verbose=False):
    method plot (line 532) | def plot(self, stacked_data, days_to_plot=(0,10),
  class NoisyLoadData (line 595) | class NoisyLoadData:
    method __init__ (line 596) | def __init__(self, load_data=None, file_name=None):
    method _import_file (line 622) | def _import_file(self, file_name):
    method data_munge (line 625) | def data_munge(self, verbose=False):
    method sample (line 647) | def sample(self, distribution='gaussian', load_variance_scale=1., retu...
    method _check_sample (line 690) | def _check_sample(self,stacked_data,verbose=False):
    method plot (line 715) | def plot(self, sample, days_to_plot=(0, 10)):
  class NoisyGridData (line 727) | class NoisyGridData:
    method __init__ (line 728) | def __init__(self,grid_data,dist_type = 'markov'):
    method learn_distribution (line 747) | def learn_distribution(self):
    method sample (line 785) | def sample(self):
  class SampleGenerator (line 811) | class SampleGenerator:
    method __init__ (line 812) | def __init__(self, microgrid, **forecast_args):
    method create_forecasts (line 826) | def create_forecasts(self, pv_args=None, load_args=None, preset_to_use...
    method test_args (line 864) | def test_args(self, iters_per_set = 3):
    method validate_forecasts (line 886) | def validate_forecasts(self, forecasts=None, aggregate=False):
    method mape (line 900) | def mape(self, actual_vals, forecast_vals):
    method sample_from_forecasts (line 919) | def sample_from_forecasts(self, n_samples=10, **sampling_args):
    method plot (line 957) | def plot(self, var='load', days_to_plot=(0, 10), original=True, foreca...
  class ForecastArgSet (line 993) | class ForecastArgSet(dict):
    method __init__ (line 994) | def __init__(self, pv_param_set=None, load_param_set=None, preset_to_u...
    method update_with_mape (line 1010) | def update_with_mape(self, mape):
    method get_preset (line 1016) | def get_preset(self,forecast_accuracy=50):
    method __eq__ (line 1050) | def __eq__(self, other):
    method __lt__ (line 1056) | def __lt__(self, other):
    method __gt__ (line 1062) | def __gt__(self, other):
  class ForecastArgs (line 1068) | class ForecastArgs:
    method __init__ (line 1069) | def __init__(self, num_pv_noise_params_0, num_pv_std_ratio, num_load_v...
    method pv_parameters (line 1078) | def pv_parameters(self,num_noise_params_0, num_std_ratio, num_push_pea...
    method load_parameters (line 1096) | def load_parameters(self,num_load_variance_scale, max_load_var_scale=2.):
    method combine_sets (line 1103) | def combine_sets(self, pv_params, load_params):

FILE: src/pymgrid/utils/logger.py
  class ModularLogger (line 7) | class ModularLogger(UserDict):
    method __init__ (line 8) | def __init__(self, *args, **kwargs):
    method flush (line 12) | def flush(self):
    method log (line 18) | def log(self, **log_dict):
    method to_dict (line 30) | def to_dict(self):
    method raw (line 33) | def raw(self):
    method to_frame (line 36) | def to_frame(self):
    method serialize (line 39) | def serialize(self, key):
    method __len__ (line 42) | def __len__(self):
    method from_raw (line 46) | def from_raw(cls, raw):

FILE: src/pymgrid/utils/ray.py
  function ray_decorator (line 5) | def ray_decorator(func):

FILE: src/pymgrid/utils/serialize.py
  function add_pymgrid_yaml_representers (line 10) | def add_pymgrid_yaml_representers():
  function dump_data (line 24) | def dump_data(data_dict, stream, yaml_tag):
  function add_path_to_arr_like (line 32) | def add_path_to_arr_like(data_dict, path, yaml_tag):
  function add_numpy_pandas_representers (line 45) | def add_numpy_pandas_representers():
  function add_numpy_pandas_constructors (line 52) | def add_numpy_pandas_constructors():
  function _numpy_represent_floating (line 57) | def _numpy_represent_floating(dumper, data):
  function _numpy_represent_int (line 61) | def _numpy_represent_int(dumper, data):
  function _numpy_arr_representer (line 65) | def _numpy_arr_representer(dumper, data):
  function _pandas_df_representer (line 69) | def _pandas_df_representer(dumper, data):
  function _arr_representer (line 73) | def _arr_representer(dumper, data, r_type):
  function _dump_representation (line 84) | def _dump_representation(data, path, stream_loc):
  function _pandas_df_constructor (line 91) | def _pandas_df_constructor(loader, node):
  function _numpy_arr_constructor (line 108) | def _numpy_arr_constructor(loader, node):
  class NDArraySubclass (line 115) | class NDArraySubclass(np.ndarray):
    method __new__ (line 120) | def __new__(cls, input_array, path=None):
    method __array_finalize__ (line 125) | def __array_finalize__(self, obj):

FILE: src/pymgrid/utils/space.py
  class _PymgridDict (line 10) | class _PymgridDict(Dict):
    method __init__ (line 11) | def __init__(self, d, act_or_obs, normalized=False, seed=None):
    method _extract_builtins (line 22) | def _extract_builtins(self, d, act_or_obs='act', normalized=False):
    method _extract_action_spaces (line 32) | def _extract_action_spaces(self, d):
    method _extract_observation_spaces (line 41) | def _extract_observation_spaces(self, d):
    method _transform_builtins (line 50) | def _transform_builtins(self, d, normalized=False):
    method get_attr (line 77) | def get_attr(self, attr):
    method low (line 81) | def low(self):
    method high (line 85) | def high(self):
    method shape (line 89) | def shape(self):
    method shape (line 93) | def shape(self, value):
    method __getattr__ (line 99) | def __getattr__(self, item):
  class _PymgridSpace (line 111) | class _PymgridSpace(Space):
    method contains (line 116) | def contains(self, x):
    method sample (line 137) | def sample(self, normalized=False):
    method _shape_check (line 142) | def _shape_check(self, val, func):
    method normalize (line 150) | def normalize(self, val):
    method denormalize (line 154) | def denormalize(self, val):
    method normalized (line 158) | def normalized(self):
    method unnormalized (line 162) | def unnormalized(self):
    method __getitem__ (line 165) | def __getitem__(self, item):
    method __repr__ (line 173) | def __repr__(self):
    method __eq__ (line 176) | def __eq__(self, other):
  class ModuleSpace (line 183) | class ModuleSpace(_PymgridSpace):
    method __init__ (line 184) | def __init__(self, unnormalized_low, unnormalized_high, shape=None, dt...
    method normalize (line 207) | def normalize(self, val):
    method denormalize (line 220) | def denormalize(self, val):
    method _bounds_check (line 233) | def _bounds_check(self, val, low, high):
  class MicrogridSpace (line 242) | class MicrogridSpace(_PymgridSpace):
    method __init__ (line 243) | def __init__(self, module_space_dict, act_or_obs, seed=None):
    method _get_spread (line 259) | def _get_spread(self):
    method normalize (line 272) | def normalize(self, val):
    method denormalize (line 283) | def denormalize(self, val):
    method dict_op (line 294) | def dict_op(first, second, op):

FILE: tests/control/data_generation/test_data_generator.py
  function create_pv_test_set (line 8) | def create_pv_test_set():
  class TestNoisyPV (line 22) | class TestNoisyPV(unittest.TestCase):
    method setUp (line 23) | def setUp(self):
    method test_init (line 29) | def test_init(self):
    method test_data_munge (line 35) | def test_data_munge(self):
    method test_add_feature_columns (line 46) | def test_add_feature_columns(self):
  class TestNoisyGrid (line 68) | class TestNoisyGrid(unittest.TestCase):
    method setUp (line 70) | def setUp(self) -> None:
    method test_init (line 84) | def test_init(self):
    method test_bad_grid_data (line 92) | def test_bad_grid_data(self):
    method test_learn_distribution_always_on_naive (line 113) | def test_learn_distribution_always_on_naive(self):
    method test_learn_distribution_always_on_markov (line 121) | def test_learn_distribution_always_on_markov(self):
    method test_learn_distribution_with_outages_naive (line 130) | def test_learn_distribution_with_outages_naive(self):
    method test_learn_distribution_with_outages_markov (line 138) | def test_learn_distribution_with_outages_markov(self):
    method test_sample_always_on_naive (line 147) | def test_sample_always_on_naive(self):
    method test_sample_always_on_markov (line 153) | def test_sample_always_on_markov(self):
    method test_sample_with_outages_naive (line 159) | def test_sample_with_outages_naive(self):
    method test_sample_with_outages_markov (line 178) | def test_sample_with_outages_markov(self):
  class TestNoisyLoad (line 202) | class TestNoisyLoad(unittest.TestCase):
    method setUp (line 203) | def setUp(self) -> None:
    method test_init (line 211) | def test_init(self):
    method test_data_munge (line 216) | def test_data_munge(self):

FILE: tests/control/test_mpc.py
  class TestMPC (line 9) | class TestMPC(TestCase):
    method test_init (line 10) | def test_init(self):
    method test_run_with_load_pv_battery_grid (line 16) | def test_run_with_load_pv_battery_grid(self):
    method test_run_with_load_pv_battery_genset (line 36) | def test_run_with_load_pv_battery_genset(self):
    method test_run_twice_with_load_pv_battery_genset (line 56) | def test_run_twice_with_load_pv_battery_genset(self):
    method test_run_with_load_pv_battery_grid_different_names (line 82) | def test_run_with_load_pv_battery_grid_different_names(self):

FILE: tests/control/test_rbc.py
  class TestRBC (line 9) | class TestRBC(TestCase):
    method setUp (line 10) | def setUp(self) -> None:
    method test_init (line 13) | def test_init(self):
    method test_priority_list (line 18) | def test_priority_list(self):
    method test_run_once (line 25) | def test_run_once(self):
    method test_reset_after_run (line 38) | def test_reset_after_run(self):

FILE: tests/envs/test_discrete.py
  class TestDiscreteEnv (line 10) | class TestDiscreteEnv(TestCase):
    method test_init_from_microgrid (line 12) | def test_init_from_microgrid(self):
    method test_init_from_modules (line 23) | def test_init_from_modules(self):
  class TestDiscreteEnvScenario (line 35) | class TestDiscreteEnvScenario(TestCase):
    method setUp (line 38) | def setUp(self) -> None:
    method test_run_once (line 41) | def test_run_once(self):
    method test_reset_after_run (line 51) | def test_reset_after_run(self):
    method test_run_again_after_reset (line 57) | def test_run_again_after_reset(self):
    method test_action_space (line 73) | def test_action_space(self):
    method test_simple_observation_keys (line 82) | def test_simple_observation_keys(self):
  class TestDiscreteEnvScenario1 (line 98) | class TestDiscreteEnvScenario1(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario2 (line 102) | class TestDiscreteEnvScenario2(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario3 (line 106) | class TestDiscreteEnvScenario3(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario4 (line 110) | class TestDiscreteEnvScenario4(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario5 (line 114) | class TestDiscreteEnvScenario5(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario6 (line 118) | class TestDiscreteEnvScenario6(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario47 (line 122) | class TestDiscreteEnvScenario47(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario8 (line 126) | class TestDiscreteEnvScenario8(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario9 (line 130) | class TestDiscreteEnvScenario9(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario10 (line 134) | class TestDiscreteEnvScenario10(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario11 (line 138) | class TestDiscreteEnvScenario11(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario12 (line 142) | class TestDiscreteEnvScenario12(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario13 (line 146) | class TestDiscreteEnvScenario13(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario14 (line 150) | class TestDiscreteEnvScenario14(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario15 (line 154) | class TestDiscreteEnvScenario15(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario16 (line 158) | class TestDiscreteEnvScenario16(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario17 (line 162) | class TestDiscreteEnvScenario17(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario18 (line 166) | class TestDiscreteEnvScenario18(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario19 (line 170) | class TestDiscreteEnvScenario19(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario20 (line 174) | class TestDiscreteEnvScenario20(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario21 (line 178) | class TestDiscreteEnvScenario21(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario22 (line 182) | class TestDiscreteEnvScenario22(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario23 (line 186) | class TestDiscreteEnvScenario23(TestDiscreteEnvScenario):
  class TestDiscreteEnvScenario24 (line 190) | class TestDiscreteEnvScenario24(TestDiscreteEnvScenario):

FILE: tests/envs/test_trajectory.py
  class TestTrajectory (line 9) | class TestTrajectory(TestCase):
    method check_initial_final_steps (line 11) | def check_initial_final_steps(self,
    method test_none_trajectory (line 29) | def test_none_trajectory(self):
    method test_deterministic_trajectory (line 35) | def test_deterministic_trajectory(self):
    method test_stochastic_trajectory (line 47) | def test_stochastic_trajectory(self):
    method test_bad_trajectory_out_of_range (line 74) | def test_bad_trajectory_out_of_range(self):
    method test_bad_trajectory_bad_signature (line 84) | def test_bad_trajectory_bad_signature(self):
    method test_bad_trajectory_initial_gt_final (line 94) | def test_bad_trajectory_initial_gt_final(self):
    method test_bad_trajectory_scalar_output (line 104) | def test_bad_trajectory_scalar_output(self):
    method test_bad_trajectory_too_many_outputs (line 114) | def test_bad_trajectory_too_many_outputs(self):
    method test_bad_trajectory_wrong_output_types (line 124) | def test_bad_trajectory_wrong_output_types(self):
    method test_correct_trajectory_length (line 134) | def test_correct_trajectory_length(self):
    method test_trajectory_serialization (line 158) | def test_trajectory_serialization(self):

FILE: tests/helpers/genset_module_testing_utils.py
  function get_genset (line 14) | def get_genset(default_parameters=None, **new_params):
  function normalize_production (line 20) | def normalize_production(production, max_production=None):

FILE: tests/helpers/modular_microgrid.py
  function get_modular_microgrid (line 14) | def get_modular_microgrid(remove_modules=(),

FILE: tests/helpers/test_case.py
  class TestCase (line 6) | class TestCase(unittest.TestCase):
    method assertEqual (line 7) | def assertEqual(self, first, second, msg=None) -> None:

FILE: tests/microgrid/modules/container_tests/test_container.py
  class TestContainer (line 5) | class TestContainer(TestCase):
    method test_container_init (line 6) | def test_container_init(self):

FILE: tests/microgrid/modules/conversion_test/test_modular_conversion.py
  class TestToModular (line 6) | class TestToModular(TestCase):
    method setUp (line 7) | def setUp(self) -> None:
    method is_weak_grid (line 19) | def is_weak_grid(microgrid):
    method is_strong_grid (line 23) | def is_strong_grid(microgrid):
    method test_weak_grid_conversion_success (line 26) | def test_weak_grid_conversion_success(self):
    method test_genset_only (line 31) | def test_genset_only(self):

FILE: tests/microgrid/modules/forecaster_tests/test_forecaster.py
  function get_test_inputs (line 23) | def get_test_inputs(n=None, state_components=None, negative=False):
  class TestOracleForecaster (line 35) | class TestOracleForecaster(TestCase):
    method setUp (line 36) | def setUp(self) -> None:
    method test_positive_inputs (line 40) | def test_positive_inputs(self):
    method test_negative_inputs (line 45) | def test_negative_inputs(self):
  class TestGaussianNoiseForecaster (line 51) | class TestGaussianNoiseForecaster(TestCase):
    method test_single_forecast_positive (line 52) | def test_single_forecast_positive(self):
    method test_single_forecast_positive_high_std (line 62) | def test_single_forecast_positive_high_std(self):
    method test_single_forecast_negative (line 72) | def test_single_forecast_negative(self):
    method test_single_forecast_negative_high_std (line 82) | def test_single_forecast_negative_high_std(self):
    method test_multiple_forecast_positive (line 92) | def test_multiple_forecast_positive(self):
    method test_multiple_forecast_positive_high_std (line 104) | def test_multiple_forecast_positive_high_std(self):
    method test_multiple_forecast_negative (line 116) | def test_multiple_forecast_negative(self):
    method test_multiple_forecast_negative_high_std (line 128) | def test_multiple_forecast_negative_high_std(self):
    method test_increasing_uncertainty_positive (line 140) | def test_increasing_uncertainty_positive(self):
    method test_increasing_uncertainty_negative (line 153) | def test_increasing_uncertainty_negative(self):
    method test_bad_shape (line 167) | def test_bad_shape(self):
  class TestUserDefinedForecaster (line 183) | class TestUserDefinedForecaster(TestCase):
    method setUp (line 184) | def setUp(self) -> None:
    method oracle_scalar_forecaster (line 188) | def oracle_scalar_forecaster(val_c, val_c_n, n):
    method get_oracle_forecaster (line 191) | def get_oracle_forecaster(self, negative=False):
    method get_obs_space (line 195) | def get_obs_space(self, negative=False):
    method test_user_defined_oracle_positive (line 205) | def test_user_defined_oracle_positive(self):
    method test_user_defined_oracle_negative (line 213) | def test_user_defined_oracle_negative(self):
    method test_scalar_forecaster (line 221) | def test_scalar_forecaster(self):
    method test_vectorized_forecaster_bad_output_shape (line 229) | def test_vectorized_forecaster_bad_output_shape(self):
    method test_vectorized_forecaster_bad_output_type (line 238) | def test_vectorized_forecaster_bad_output_type(self):
    method test_vectorized_forecaster_bad_output_signs (line 246) | def test_vectorized_forecaster_bad_output_signs(self):
    method test_bad_forecaster (line 260) | def test_bad_forecaster(self):
    method test_scalar_forecaster_bad_output_shape (line 268) | def test_scalar_forecaster_bad_output_shape(self):
  class TestGetForecaster (line 281) | class TestGetForecaster(TestCase):
    method setUp (line 282) | def setUp(self) -> None:
    method test_user_defined_forecaster (line 286) | def test_user_defined_forecaster(self):
    method test_oracle_forecaster (line 294) | def test_oracle_forecaster(self):
    method test_no_forecaster (line 298) | def test_no_forecaster(self):
    method test_gaussian_noise_forecaster_init (line 302) | def test_gaussian_noise_forecaster_init(self):
    method test_gaussian_noise_forecaster_increase_uncertainty_init (line 308) | def test_gaussian_noise_forecaster_increase_uncertainty_init(self):
    method test_gaussian_noise_forecaster_correct_size (line 315) | def test_gaussian_noise_forecaster_correct_size(self):
    method test_gaussian_noise_forecaster_insufficient_true_vals (line 326) | def test_gaussian_noise_forecaster_insufficient_true_vals(self):
    method test_gaussian_noise_forecaster_insufficient_true_vals_increasing_uncertainty (line 336) | def test_gaussian_noise_forecaster_insufficient_true_vals_increasing_u...

FILE: tests/microgrid/modules/module_tests/test_genset_long_status_changes.py
  class TestGensetStartUp2WindDown3OnAtStartUp (line 8) | class TestGensetStartUp2WindDown3OnAtStartUp(TestCase):
    method setUp (line 9) | def setUp(self) -> None:
    method get_genset (line 12) | def get_genset(self, **new_params):
    method turn_on (line 17) | def turn_on(self, genset, unnormalized_production=0.):
    method turn_off (line 23) | def turn_off(self, genset, unnormalized_production=50.):
    method test_on_at_start_up (line 29) | def test_on_at_start_up(self):
    method test_turn_off_step_1 (line 35) | def test_turn_off_step_1(self):
    method test_turn_off_step_2 (line 46) | def test_turn_off_step_2(self):
    method test_turn_off_step_3 (line 60) | def test_turn_off_step_3(self):
    method test_turn_off_step_4_final (line 74) | def test_turn_off_step_4_final(self):
    method test_turn_on_after_turn_off_step_1 (line 91) | def test_turn_on_after_turn_off_step_1(self):
    method test_turn_on_after_turn_off_step_2 (line 118) | def test_turn_on_after_turn_off_step_2(self):
    method test_turn_on_after_turn_off_final (line 147) | def test_turn_on_after_turn_off_final(self):
    method test_turn_off_abortion (line 180) | def test_turn_off_abortion(self):
    method test_turn_on_abortion (line 199) | def test_turn_on_abortion(self):
  class TestManyStatusChanges (line 217) | class TestManyStatusChanges(TestCase):
    method test_many_status_changes (line 219) | def test_many_status_changes(self):

FILE: tests/microgrid/modules/module_tests/test_genset_module.py
  class TestGensetModule (line 7) | class TestGensetModule(TestCase):
    method setUp (line 8) | def setUp(self) -> None:
    method get_genset (line 12) | def get_genset(self, **new_params):
    method test_init_start_up (line 15) | def test_init_start_up(self):
    method test_get_cost_linear (line 21) | def test_get_cost_linear(self):
    method test_get_cost_callable (line 30) | def test_get_cost_callable(self):
    method test_step_out_of_range_goal_status (line 39) | def test_step_out_of_range_goal_status(self):
    method test_step_out_of_normalized_range_production (line 46) | def test_step_out_of_normalized_range_production(self):
    method test_step_incorrect_action_shape (line 53) | def test_step_incorrect_action_shape(self):
    method test_step_unnormalized_production (line 64) | def test_step_unnormalized_production(self):
    method test_step_normalized_production (line 78) | def test_step_normalized_production(self):
    method test_step_immediate_status_change (line 93) | def test_step_immediate_status_change(self):
    method test_step_genset_off_production_request_error_raise (line 110) | def test_step_genset_off_production_request_error_raise(self):
    method test_step_genset_off_production_request_no_error_raise (line 124) | def test_step_genset_off_production_request_no_error_raise(self):
    method test_step_genset_production_request_out_of_range_no_error_raise (line 138) | def test_step_genset_production_request_out_of_range_no_error_raise(se...

FILE: tests/microgrid/modules/module_tests/test_genset_module_start_up_1_wind_down_1.py
  class TestGensetStartUp1WindDown0OffAtStartUp (line 7) | class TestGensetStartUp1WindDown0OffAtStartUp(TestCase):
    method setUp (line 8) | def setUp(self) -> None:
    method get_genset (line 12) | def get_genset(self, new=False, **new_params):
    method warm_up (line 22) | def warm_up(self, genset):
    method test_off_at_start_up (line 29) | def test_off_at_start_up(self):
    method test_warm_up (line 35) | def test_warm_up(self):
    method test_step_start_up_1_exception (line 46) | def test_step_start_up_1_exception(self):
    method test_step_start_up_1_no_exception (line 61) | def test_step_start_up_1_no_exception(self):
    method test_start_up_1_request_below_min_exception_raise (line 76) | def test_start_up_1_request_below_min_exception_raise(self):
    method test_start_up_1_request_below_min_no_exception (line 85) | def test_start_up_1_request_below_min_no_exception(self):
    method test_start_up_1_then_shut_down_exception_raise (line 100) | def test_start_up_1_then_shut_down_exception_raise(self):
    method test_start_up_1_then_shut_down_no_exception (line 110) | def test_start_up_1_then_shut_down_no_exception(self):
  class TestGensetStartUp1WindDown0OnAtStartUp (line 126) | class TestGensetStartUp1WindDown0OnAtStartUp(TestCase):
    method setUp (line 127) | def setUp(self) -> None:
    method get_genset (line 131) | def get_genset(self, new=False, **new_params):
    method warm_up (line 140) | def warm_up(self, genset):
    method test_on_at_start_up (line 147) | def test_on_at_start_up(self):
    method test_warm_up (line 153) | def test_warm_up(self):
    method test_shut_down (line 164) | def test_shut_down(self):

FILE: tests/microgrid/modules/module_tests/test_load_module.py
  class TestLoadModuleNoForecasting (line 13) | class TestLoadModuleNoForecasting(TestTimeseriesModuleNoForecasting):
    method get_module (line 19) | def get_module(self):
    method test_init_current_load (line 22) | def test_init_current_load(self):
    method test_step (line 26) | def test_step(self):
  class TestLoadModuleForecasting (line 38) | class TestLoadModuleForecasting(TestTimeseriesModuleForecasting):
    method get_module (line 43) | def get_module(self):
    method test_step (line 46) | def test_step(self):
  class TestLoadModuleForecastingNegativeVals (line 59) | class TestLoadModuleForecastingNegativeVals(TestTimeSeriesModuleForecast...
  class TestLoadModuleNoForecastingNegativeVals (line 64) | class TestLoadModuleNoForecastingNegativeVals(TestTimeSeriesModuleNoFore...

FILE: tests/microgrid/modules/module_tests/test_renewable_module.py
  class TestRenewableModuleNoForecasting (line 12) | class TestRenewableModuleNoForecasting(TestTimeseriesModuleNoForecasting):
    method get_module (line 16) | def get_module(self):
    method test_init_current_renewable (line 19) | def test_init_current_renewable(self):
    method test_step (line 23) | def test_step(self):
  class TestRenewableModuleForecasting (line 38) | class TestRenewableModuleForecasting(TestTimeseriesModuleForecasting):
    method get_module (line 42) | def get_module(self):
    method test_step (line 45) | def test_step(self):
  class TestRenewableModuleForecastingNegativeVals (line 60) | class TestRenewableModuleForecastingNegativeVals(TestTimeSeriesModuleFor...
  class TestRenewableModuleNoForecastingNegativeVals (line 65) | class TestRenewableModuleNoForecastingNegativeVals(TestTimeSeriesModuleN...

FILE: tests/microgrid/modules/module_tests/timeseries_modules.py
  class TestTimeseriesModule (line 10) | class TestTimeseriesModule(TestCase):
    method setUp (line 16) | def setUp(self) -> None:
    method _get_module_time_series (line 20) | def _get_module_time_series(self):
    method _get_time_series (line 23) | def _get_time_series(self):
    method get_module (line 28) | def get_module(self):
    method test_action_space (line 31) | def test_action_space(self):
    method test_observation_space (line 41) | def test_observation_space(self):
    method test_observations_in_observation_space (line 52) | def test_observations_in_observation_space(self):
  class TestTimeseriesModuleNoForecasting (line 72) | class TestTimeseriesModuleNoForecasting(TestTimeseriesModule):
    method test_init (line 75) | def test_init(self):
  class TestTimeseriesModuleForecasting (line 82) | class TestTimeseriesModuleForecasting(TestTimeseriesModule):
    method test_init (line 85) | def test_init(self):
  class TestTimeSeriesModuleNoForecastingNegativeVals (line 93) | class TestTimeSeriesModuleNoForecastingNegativeVals(TestTimeseriesModule...
    method _get_module_time_series (line 94) | def _get_module_time_series(self):
  class TestTimeSeriesModuleForecastingNegativeVals (line 98) | class TestTimeSeriesModuleForecastingNegativeVals(TestTimeseriesModuleFo...
    method _get_module_time_series (line 99) | def _get_module_time_series(self):

FILE: tests/microgrid/serialize/test_microgrid_serialization.py
  class TestMicrogridSerialization (line 9) | class TestMicrogridSerialization(TestCase):
    method test_serialize_no_modules (line 10) | def test_serialize_no_modules(self):
    method test_serialize_with_renewable (line 17) | def test_serialize_with_renewable(self):

FILE: tests/microgrid/test_microgrid.py
  class TestMicrogrid (line 12) | class TestMicrogrid(TestCase):
    method test_from_scenario (line 13) | def test_from_scenario(self):
    method test_empty_action_without_load (line 22) | def test_empty_action_without_load(self):
    method test_empty_action_with_load (line 32) | def test_empty_action_with_load(self):
    method test_action_space (line 43) | def test_action_space(self):
    method test_action_space_normalize (line 53) | def test_action_space_normalize(self):
    method test_action_space_denormalize (line 64) | def test_action_space_denormalize(self):
    method test_sample_action (line 75) | def test_sample_action(self):
    method test_sample_action_all_modules_populated (line 88) | def test_sample_action_all_modules_populated(self):
    method test_current_step (line 104) | def test_current_step(self):
    method test_current_step_after_reset (line 114) | def test_current_step_after_reset(self):
    method test_set_module_attr_forecast_horizon (line 124) | def test_set_module_attr_forecast_horizon(self):
    method test_set_module_attr_bad_attr_name (line 137) | def test_set_module_attr_bad_attr_name(self):
    method test_get_cost_info (line 143) | def test_get_cost_info(self):
    method test_set_initial_step (line 162) | def test_set_initial_step(self):
  class TestMicrogridLoadPV (line 188) | class TestMicrogridLoadPV(TestCase):
    method setUp (line 189) | def setUp(self):
    method set_ts (line 194) | def set_ts(self):
    method set_microgrid (line 198) | def set_microgrid(self):
    method test_populated_correctly (line 203) | def test_populated_correctly(self):
    method test_current_load_correct (line 208) | def test_current_load_correct(self):
    method test_current_pv_correct (line 216) | def test_current_pv_correct(self):
    method test_sample_action (line 224) | def test_sample_action(self):
    method test_sample_action_with_flex (line 228) | def test_sample_action_with_flex(self):
    method test_state_dict (line 235) | def test_state_dict(self):
    method test_state_series (line 243) | def test_state_series(self):
    method test_to_nonmodular (line 250) | def test_to_nonmodular(self):
    method check_step (line 263) | def check_step(self, microgrid, step_number=0):
    method test_run_one_step (line 311) | def test_run_one_step(self):
    method test_run_n_steps (line 315) | def test_run_n_steps(self):
  class TestMicrogridLoadExcessPV (line 322) | class TestMicrogridLoadExcessPV(TestMicrogridLoadPV):
    method set_ts (line 324) | def set_ts(self):
  class TestMicrogridPVExcessLoad (line 330) | class TestMicrogridPVExcessLoad(TestMicrogridLoadPV):
    method set_ts (line 332) | def set_ts(self):
  class TestMicrogridTwoLoads (line 338) | class TestMicrogridTwoLoads(TestMicrogridLoadPV):
    method set_microgrid (line 339) | def set_microgrid(self):
  class TestMicrogridTwoPV (line 352) | class TestMicrogridTwoPV(TestMicrogridLoadPV):
    method set_microgrid (line 353) | def set_microgrid(self):
  class TestMicrogridTwoEach (line 366) | class TestMicrogridTwoEach(TestMicrogridLoadPV):
    method set_microgrid (line 367) | def set_microgrid(self):
  class TestMicrogridManyEach (line 387) | class TestMicrogridManyEach(TestMicrogridLoadPV):
    method set_microgrid (line 388) | def set_microgrid(self):
  class TestMicrogridManyEachExcessPV (line 416) | class TestMicrogridManyEachExcessPV(TestMicrogridManyEach):
    method set_ts (line 417) | def set_ts(self):
  class TestMicrogridManyEachExcessLoad (line 423) | class TestMicrogridManyEachExcessLoad(TestMicrogridManyEach):
    method set_ts (line 424) | def set_ts(self):
  class TestMicrogridRewardShaping (line 430) | class TestMicrogridRewardShaping(TestMicrogridLoadPV):
    method set_microgrid (line 431) | def set_microgrid(self):
    method reward_shaping_func (line 440) | def reward_shaping_func(energy_info, cost_info):

FILE: tests/test_microgridgenerator.py
  class TestMicogridGenerator (line 24) | class TestMicogridGenerator(unittest.TestCase):
    method setUp (line 26) | def setUp(self):
    method test_get_random_file (line 29) | def test_get_random_file(self):
    method test_scale_ts (line 39) | def test_scale_ts(self):
    method test_get_genset (line 45) | def test_get_genset(self):
    method test_get_battery (line 50) | def test_get_battery(self):
    method test_get_grid_price_ts (line 54) | def test_get_grid_price_ts(self):
    method test_get_grid (line 58) | def test_get_grid(self):
    method test_size_mg (line 62) | def test_size_mg(self):
    method test_size_genset (line 68) | def test_size_genset(self):
    method test_size_battery (line 71) | def test_size_battery(self):
    method test_generate_microgrid (line 76) | def test_generate_microgrid(self):
    method test_create_microgrid (line 81) | def test_create_microgrid(self):

FILE: tests/test_nonmodular_microgrid.py
  class TestNonmodularMicrogrid (line 16) | class TestNonmodularMicrogrid(unittest.TestCase):
    method setUp (line 17) | def setUp(self):
    method random_control (line 22) | def random_control():
    method test_set_horizon (line 30) | def test_set_horizon(self):
    method test_get_updated_values (line 34) | def test_get_updated_values(self):
    method test_forecast_all (line 38) | def test_forecast_all(self):
    method test_forecast_pv (line 43) | def test_forecast_pv(self):
    method test_forecast_load (line 48) | def test_forecast_load(self):
    method test_run (line 53) | def test_run(self):
    method test_train_test_split (line 59) | def test_train_test_split(self):
    method test_reset (line 63) | def test_reset(self):
Condensed preview — 181 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,702K chars).
[
  {
    "path": ".gitattributes",
    "chars": 25,
    "preview": "*.ipynb linguist-vendored"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 1536,
    "preview": "# This workflow will install Python dependencies, run tests and lint with a variety of Python versions\n# For more inform"
  },
  {
    "path": ".github/workflows/documentation-links.yaml",
    "chars": 338,
    "preview": "# .github/workflows/documentation-links.yaml\n\nname: Read the Docs Pull Request Preview\non:\n  pull_request_target:\n    ty"
  },
  {
    "path": ".github/workflows/garage-compat.yml",
    "chars": 2713,
    "preview": "# This workflow will install Python dependencies, run tests and lint with a variety of Python versions\n# For more inform"
  },
  {
    "path": ".gitignore",
    "chars": 347,
    "preview": "#Ignore what is not python code\nnotebooks/\n.DS_STORE\n.idea\n*.pkl\npymgrid/__pycache__/\n*.ipynb\n.ipynb_checkpoints\n__pycac"
  },
  {
    "path": ".readthedocs.yaml",
    "chars": 428,
    "preview": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html f"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "LICENSE",
    "chars": 7652,
    "preview": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007"
  },
  {
    "path": "MANIFEST.in",
    "chars": 42,
    "preview": "global-include *.csv\nglobal-include *.pkl\n"
  },
  {
    "path": "README.md",
    "chars": 6780,
    "preview": "# pymgrid\n\n## Important Notice\n\n### The person that has been maintaining pymgrid since 2020 has moved future development"
  },
  {
    "path": "docs/Makefile",
    "chars": 638,
    "preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line, and also\n# from the "
  },
  {
    "path": "docs/make.bat",
    "chars": 769,
    "preview": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-bu"
  },
  {
    "path": "docs/requirements.txt",
    "chars": 96,
    "preview": "nbsphinx==0.8.10\nnbsphinx-link==1.3.0\nnumpydoc==1.5.0\npydata_sphinx_theme==0.12.0\nSphinx==5.3.0\n"
  },
  {
    "path": "docs/source/_templates/autosummary/base.rst",
    "chars": 106,
    "preview": "{{ objname | escape | underline }}\n\n.. currentmodule:: {{ module }}\n\n.. auto{{ objtype }}:: {{ objname }}\n"
  },
  {
    "path": "docs/source/_templates/autosummary/class.rst",
    "chars": 639,
    "preview": "{{ fullname | escape | underline}}\n\n.. currentmodule:: {{ module }}\n\n.. autoclass:: {{ objname }}\n\n   {% block methods %"
  },
  {
    "path": "docs/source/conf.py",
    "chars": 4482,
    "preview": "# Configuration file for the Sphinx documentation builder.\n#\n# For the full list of built-in configuration values, see t"
  },
  {
    "path": "docs/source/examples/index.rst",
    "chars": 363,
    "preview": "Examples\n========\n\nTo run the examples, clone the repository:\n\n.. code-block:: bash\n\n    $ git clone https://github.com/"
  },
  {
    "path": "docs/source/examples/mpc-example.nblink",
    "chars": 54,
    "preview": "{\n    \"path\": \"../../../notebooks/mpc-example.ipynb\"\n}"
  },
  {
    "path": "docs/source/examples/quick-start.nblink",
    "chars": 55,
    "preview": "{\n    \"path\": \"../../../notebooks/quick-start.ipynb\"\n}\n"
  },
  {
    "path": "docs/source/examples/rbc-example.nblink",
    "chars": 55,
    "preview": "{\n    \"path\": \"../../../notebooks/rbc-example.ipynb\"\n}\n"
  },
  {
    "path": "docs/source/examples/rl-example.nblink",
    "chars": 54,
    "preview": "{\n    \"path\": \"../../../notebooks/rl-example.ipynb\"\n}\n"
  },
  {
    "path": "docs/source/getting_started.rst",
    "chars": 1031,
    "preview": "Getting Started\n===============\n\n.. _installation:\n\nInstallation\n------------\n\nThe easiest way to install *pymgrid* is w"
  },
  {
    "path": "docs/source/index.rst",
    "chars": 2061,
    "preview": ".. pymgrid documentation master file, created by\n   sphinx-quickstart on Sat Nov 19 12:49:18 2022.\n   You can adapt this"
  },
  {
    "path": "docs/source/reference/algos/index.rst",
    "chars": 1215,
    "preview": ".. _api.control:\n\nControl Algorithms\n==================\n\n.. currentmodule:: pymgrid.algos\n\nControl algorithms built into"
  },
  {
    "path": "docs/source/reference/envs/index.rst",
    "chars": 494,
    "preview": ".. _api.envs:\n\nReinforcement Learning (RL) Environments\n======================\n\n.. currentmodule:: pymgrid.envs\n\nEnviron"
  },
  {
    "path": "docs/source/reference/forecast/index.rst",
    "chars": 358,
    "preview": ".. _api.forecast:\n\nForecasting\n===========\n\n.. currentmodule:: pymgrid.forecast\n\nClasses available to use for time-serie"
  },
  {
    "path": "docs/source/reference/general/index.rst",
    "chars": 436,
    "preview": ".. _api.general:\n\nGeneral functions and objects\n=============================\n\n.. currentmodule:: pymgrid.modules\n\nModul"
  },
  {
    "path": "docs/source/reference/index.rst",
    "chars": 231,
    "preview": "API reference\n=============\n\nThis page contains an overview of all public *pymgrid* objects and functions.\n\n.. toctree::"
  },
  {
    "path": "docs/source/reference/microgrid.rst",
    "chars": 610,
    "preview": ".. _api.microgrid:\n\n\nMicrogrid\n=================\n\n.. currentmodule:: pymgrid\n\nConstructor\n-----------\n.. autosummary::\n "
  },
  {
    "path": "docs/source/reference/modules/index.rst",
    "chars": 763,
    "preview": ".. _api.modules:\n\nModules\n=======\n\n.. currentmodule:: pymgrid.modules\n\nThe modules defined here are commonly found in mi"
  },
  {
    "path": "pyproject.toml",
    "chars": 191,
    "preview": "[tool.pytest.ini_options]\nlog_cli = true\nlog_cli_level = \"INFO\"\nlog_cli_format = \"%(asctime)s [%(levelname)8s] %(message"
  },
  {
    "path": "requirements.txt",
    "chars": 159,
    "preview": "cufflinks>=0.17.3\ncvxpy>=1.1.4\ngym>=0.15.7\nmatplotlib>=3.1.1\nnumpy>=1.19.5\npandas>=1.0.3\nplotly>=4.9.0\nscipy>=1.5.3\nstat"
  },
  {
    "path": "setup.cfg",
    "chars": 82,
    "preview": "[metadata]\ndescription-file = README.md\n\n[tool:pytest]\nnorecursedirs=tests/helpers"
  },
  {
    "path": "setup.py",
    "chars": 1630,
    "preview": "from pathlib import Path\nfrom setuptools import setup, find_packages\n\nv = {}\nexec(open('src/pymgrid/version.py').read(),"
  },
  {
    "path": "src/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/MicrogridGenerator.py",
    "chars": 26580,
    "preview": "\"\"\"\nCopyright 2020 Total S.A., Tanguy Levent all rights reserved,\nAuthors:Gonzague Henri <gonzague.henri@total.com>, Tan"
  },
  {
    "path": "src/pymgrid/__init__.py",
    "chars": 414,
    "preview": "from pathlib import Path\nfrom .version import __version__\n\nPROJECT_PATH = Path(__file__).parent\n\nfrom ._deprecated.non_m"
  },
  {
    "path": "src/pymgrid/_deprecated/Environments/Environment.py",
    "chars": 21517,
    "preview": "\"\"\"\nCopyright 2020 Total S.A\nAuthors:Gonzague Henri <gonzague.henri@total.com>\nPermission to use, modify, and distribute"
  },
  {
    "path": "src/pymgrid/_deprecated/Environments/Preprocessing.py",
    "chars": 1991,
    "preview": "import pandas as pd\n\ndef normalize_environment_states(mg):\n    max_values = {}\n    for keys in mg._df_record_state:\n    "
  },
  {
    "path": "src/pymgrid/_deprecated/Environments/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "src/pymgrid/_deprecated/Environments/pymgrid_csca.py",
    "chars": 27816,
    "preview": "from abc import ABC\nimport gym, logging, numpy as np, pandas as pd\nfrom gym import Env\nfrom pymgrid._deprecated.non_modu"
  },
  {
    "path": "src/pymgrid/_deprecated/Environments/pymgrid_csca_old.py",
    "chars": 1616,
    "preview": "from pymgrid.Environments.Environment import Environment\nimport numpy as np\nimport gym\nfrom gym.utils import seeding\nfro"
  },
  {
    "path": "src/pymgrid/_deprecated/Environments/pymgrid_csda.py",
    "chars": 1614,
    "preview": "from pymgrid.Environments.Environment import Environment\nimport numpy as np\nimport gym\nfrom gym.utils import seeding\nfro"
  },
  {
    "path": "src/pymgrid/_deprecated/Environments/pymgrid_cspla.py",
    "chars": 1979,
    "preview": "\"\"\"\nCopyright 2020 Total S.A\nAuthors:Gonzague Henri <gonzague.henri@total.com>\nPermission to use, modify, and distribute"
  },
  {
    "path": "src/pymgrid/_deprecated/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/_deprecated/non_modular_microgrid.py",
    "chars": 55258,
    "preview": "\"\"\"\nCopyright 2020 Total S.A., Tanguy Levent all rights reserved,\nAuthors:Gonzague Henri <gonzague.henri@total.com>, Tan"
  },
  {
    "path": "src/pymgrid/algos/Control.py",
    "chars": 17127,
    "preview": "\n\"\"\"\nCopyright 2020 Total S.A.\nAuthors:Gonzague Henri <gonzague.henri@total.com>, Avishai Halev <>\nPermission to use, mo"
  },
  {
    "path": "src/pymgrid/algos/__init__.py",
    "chars": 82,
    "preview": "from .mpc.mpc import ModelPredictiveControl\nfrom .rbc.rbc import RuleBasedControl\n"
  },
  {
    "path": "src/pymgrid/algos/example.log",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/algos/mpc/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/algos/mpc/mpc.py",
    "chars": 43912,
    "preview": "import time\nfrom copy import deepcopy\nfrom tqdm import tqdm\nimport cvxpy as cp\nimport numpy as np\nimport pandas as pd\nfr"
  },
  {
    "path": "src/pymgrid/algos/priority_list/__init__.py",
    "chars": 99,
    "preview": "from .priority_list_element import PriorityListElement\nfrom .priority_list import PriorityListAlgo\n"
  },
  {
    "path": "src/pymgrid/algos/priority_list/priority_list.py",
    "chars": 7099,
    "preview": "import numpy as np\nimport pandas as pd\n\nfrom abc import abstractmethod\nfrom itertools import permutations\n\n\nfrom gym.spa"
  },
  {
    "path": "src/pymgrid/algos/priority_list/priority_list_element.py",
    "chars": 2783,
    "preview": "from dataclasses import dataclass\nfrom functools import total_ordering\nfrom typing import Tuple, Optional\n\n\n@total_order"
  },
  {
    "path": "src/pymgrid/algos/rbc/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/algos/rbc/_nonmodular_rbc.py",
    "chars": 13272,
    "preview": "import operator\nimport sys\nfrom copy import deepcopy\n\nfrom pymgrid.algos.Control import ControlOutput\n\n\nclass NonModular"
  },
  {
    "path": "src/pymgrid/algos/rbc/rbc.py",
    "chars": 4045,
    "preview": "from copy import deepcopy\nfrom tqdm import tqdm\n\nfrom pymgrid.algos.priority_list import PriorityListAlgo\n\n\nclass RuleBa"
  },
  {
    "path": "src/pymgrid/algos/saa/__init__.py",
    "chars": 43,
    "preview": "from .saa import SampleAverageApproximation"
  },
  {
    "path": "src/pymgrid/algos/saa/saa.py",
    "chars": 7336,
    "preview": "import time\n\nimport numpy as np\nimport pandas as pd\nfrom pymgrid.algos.Control import ControlOutput\nfrom pymgrid.utils.D"
  },
  {
    "path": "src/pymgrid/convert/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/convert/convert.py",
    "chars": 2635,
    "preview": "from pymgrid._deprecated.non_modular_microgrid import NonModularMicrogrid\nfrom pymgrid.microgrid.microgrid import Microg"
  },
  {
    "path": "src/pymgrid/convert/get_module.py",
    "chars": 4368,
    "preview": "import pandas as pd\nfrom pymgrid.modules import LoadModule, RenewableModule, BatteryModule, GridModule, GensetModule, Un"
  },
  {
    "path": "src/pymgrid/convert/to_nonmodular_ops.py",
    "chars": 10537,
    "preview": "from pymgrid.modules import LoadModule, RenewableModule, BatteryModule, GridModule, GensetModule, UnbalancedEnergyModule"
  },
  {
    "path": "src/pymgrid/data/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/data/co2/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "src/pymgrid/data/co2/co2_caiso.csv",
    "chars": 104136,
    "preview": "CO2_CISO_I_kwh\n0.239757908\n0.273658597\n0.270383127\n0.263688693\n0.263670279\n0.256445238\n0.267006115\n0.274550944\n0.267613"
  },
  {
    "path": "src/pymgrid/data/co2/co2_duke.csv",
    "chars": 104183,
    "preview": "CO2_DUK_I_kwh\n0.180924313\n0.18330306\n0.195031339\n0.190779281\n0.165302356\n0.148113168\n0.140914668\n0.143098532\n0.12803687"
  },
  {
    "path": "src/pymgrid/data/load/RefBldgFullServiceRestaurantNew2004_v1.3_7.1_6A_USA_MN_MINNEAPOLIS.csv",
    "chars": 104229,
    "preview": "Electricity:Facility [kW](Hourly)\n22.32153712\n14.64444443\n14.66463229\n14.67616229\n14.82645007\n22.45533704\n38.4123316\n44."
  },
  {
    "path": "src/pymgrid/data/load/RefBldgHospitalNew2004_7.1_5.0_3C_USA_CA_SAN_FRANCISCO.csv",
    "chars": 104172,
    "preview": "Electricity:Facility [kW](Hourly)\n778.0079691\n776.2417501\n779.3573377\n778.7371961\n787.835835\n786.1813539\n853.5088811\n859"
  },
  {
    "path": "src/pymgrid/data/load/RefBldgLargeHotelNew2004_v1.3_7.1_4A_USA_MD_BALTIMORE.csv",
    "chars": 104195,
    "preview": "Electricity:Facility [kW](Hourly)\n148.1716309\n148.5637443\n130.6879266\n130.6690805\n139.2221808\n153.8726234\n256.4756964\n32"
  },
  {
    "path": "src/pymgrid/data/load/RefBldgLargeOfficeNew2004_v1.3_7.1_5A_USA_IL_CHICAGO-OHARE.csv",
    "chars": 104177,
    "preview": "Electricity:Facility [kW](Hourly)\n259.5994047\n254.9422169\n259.2125219\n254.9498296\n271.4424828\n291.6203295\n344.7845507\n32"
  },
  {
    "path": "src/pymgrid/data/load/RefBldgPrimarySchoolNew2004_v1.3_7.1_2A_USA_TX_HOUSTON.csv",
    "chars": 104200,
    "preview": "Electricity:Facility [kW](Hourly)\n55.42814107\n55.42067783\n55.41204556\n55.40128446\n55.60842111\n59.33672134\n60.56892065\n53"
  },
  {
    "path": "src/pymgrid/data/load/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/data/pv/Houston_722430TYA.csv",
    "chars": 25648,
    "preview": "GH illum (lx)\n0\n0\n0\n0\n0\n0\n0\n28\n171\n359\n509\n574\n634\n569\n468\n281\n115\n20\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n26\n147\n243\n333\n372\n402\n2"
  },
  {
    "path": "src/pymgrid/data/pv/Minneapolis_726580TYA.csv",
    "chars": 25324,
    "preview": "GH illum (lx)\n0\n0\n0\n0\n0\n0\n0\n0\n0\n77\n126\n102\n105\n82\n108\n61\n4\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n181\n250\n198\n284\n82\n123\n37\n7\n0"
  },
  {
    "path": "src/pymgrid/data/pv/NewYork_744860TYA.csv",
    "chars": 25244,
    "preview": "GH illum (lx)\n0\n0\n0\n0\n0\n0\n0\n9\n133\n274\n358\n286\n407\n88\n217\n78\n8\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n9\n151\n209\n331\n399\n349\n240\n97\n8"
  },
  {
    "path": "src/pymgrid/data/pv/Raleigh_723060TYA.csv",
    "chars": 25499,
    "preview": "GH illum (lx)\n0\n0\n0\n0\n0\n0\n0\n16\n58\n89\n120\n257\n314\n252\n213\n160\n51\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n3\n33\n82\n115\n133\n156\n144\n123\n"
  },
  {
    "path": "src/pymgrid/data/pv/SanFrancisco_724940TYA.csv",
    "chars": 25574,
    "preview": "GH illum (lx)\n0\n0\n0\n0\n0\n0\n0\n5\n126\n287\n403\n442\n442\n418\n358\n208\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\n5\n117\n278\n367\n468\n487\n393\n32"
  },
  {
    "path": "src/pymgrid/data/pv/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/data/scenario/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_0/microgrid_0.yaml",
    "chars": 2066,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_1/microgrid_1.yaml",
    "chars": 2621,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_10/microgrid_10.yaml",
    "chars": 2640,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_11/microgrid_11.yaml",
    "chars": 2058,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_12/microgrid_12.yaml",
    "chars": 2052,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_13/microgrid_13.yaml",
    "chars": 2613,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_14/microgrid_14.yaml",
    "chars": 2054,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_15/microgrid_15.yaml",
    "chars": 2143,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_16/microgrid_16.yaml",
    "chars": 2100,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_17/microgrid_17.yaml",
    "chars": 2157,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_18/microgrid_18.yaml",
    "chars": 2611,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_19/microgrid_19.yaml",
    "chars": 2166,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_2/microgrid_2.yaml",
    "chars": 2151,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_20/microgrid_20.yaml",
    "chars": 2141,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_21/microgrid_21.yaml",
    "chars": 2151,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_22/microgrid_22.yaml",
    "chars": 2617,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_23/microgrid_23.yaml",
    "chars": 2133,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_24/microgrid_24.yaml",
    "chars": 2628,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_3/microgrid_3.yaml",
    "chars": 2140,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_4/microgrid_4.yaml",
    "chars": 2051,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_5/microgrid_5.yaml",
    "chars": 2146,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_6/microgrid_6.yaml",
    "chars": 2090,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_7/microgrid_7.yaml",
    "chars": 2132,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_8/microgrid_8.yaml",
    "chars": 2640,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/data/scenario/pymgrid25/microgrid_9/microgrid_9.yaml",
    "chars": 2657,
    "preview": "!Microgrid\nfinal_step: 8759\ninitial_step: 0\nmodules:\n- - load\n  - !LoadModule\n    cls_params:\n      final_step: 8759\n   "
  },
  {
    "path": "src/pymgrid/envs/__init__.py",
    "chars": 110,
    "preview": "from .discrete.discrete import DiscreteMicrogridEnv\nfrom .continuous.continuous import ContinuousMicrogridEnv\n"
  },
  {
    "path": "src/pymgrid/envs/base/__init__.py",
    "chars": 35,
    "preview": "from .base import BaseMicrogridEnv\n"
  },
  {
    "path": "src/pymgrid/envs/base/base.py",
    "chars": 10637,
    "preview": "import pandas as pd\n\nfrom gym import Env\nfrom gym.spaces import Box, Dict, Tuple, flatten_space, flatten\nfrom abc import"
  },
  {
    "path": "src/pymgrid/envs/base/skip_init.py",
    "chars": 400,
    "preview": "def skip_init(cls, init):\n    \"\"\"\n    Skip init once on cls, and then revert to original init.\n\n    Parameters\n    -----"
  },
  {
    "path": "src/pymgrid/envs/continuous/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/envs/continuous/continuous.py",
    "chars": 3565,
    "preview": "from gym.spaces import Dict, Tuple, flatten_space\nfrom warnings import warn\n\nfrom pymgrid.envs.base import BaseMicrogrid"
  },
  {
    "path": "src/pymgrid/envs/discrete/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/envs/discrete/discrete.py",
    "chars": 5297,
    "preview": "import yaml\n\nfrom gym.spaces import Discrete\nfrom warnings import warn\n\nfrom pymgrid.algos.priority_list import Priority"
  },
  {
    "path": "src/pymgrid/forecast/__init__.py",
    "chars": 119,
    "preview": "from .forecaster import get_forecaster, OracleForecaster, GaussianNoiseForecaster, UserDefinedForecaster, NoForecaster\n"
  },
  {
    "path": "src/pymgrid/forecast/forecaster.py",
    "chars": 14669,
    "preview": "import numpy as np\nfrom abc import abstractmethod\n\nfrom pandas.api.types import is_number, is_numeric_dtype\n\nfrom pymgri"
  },
  {
    "path": "src/pymgrid/microgrid/__init__.py",
    "chars": 55,
    "preview": "DEFAULT_HORIZON = 23\n\nfrom .microgrid import Microgrid\n"
  },
  {
    "path": "src/pymgrid/microgrid/microgrid.py",
    "chars": 38000,
    "preview": "import numpy as np\nimport pandas as pd\nimport yaml\n\nfrom copy import deepcopy\nfrom warnings import warn\n\nfrom pymgrid.mi"
  },
  {
    "path": "src/pymgrid/microgrid/reward_shaping/__init__.py",
    "chars": 116,
    "preview": "from .pv_curtailment_shaper import PVCurtailmentShaper\nfrom .battery_discharge_shaper import BatteryDischargeShaper\n"
  },
  {
    "path": "src/pymgrid/microgrid/reward_shaping/base.py",
    "chars": 548,
    "preview": "import yaml\n\nfrom abc import abstractmethod\n\n\nclass BaseRewardShaper(yaml.YAMLObject):\n    yaml_dumper = yaml.SafeDumper"
  },
  {
    "path": "src/pymgrid/microgrid/reward_shaping/battery_discharge_shaper.py",
    "chars": 1190,
    "preview": "import numpy as np\n\nfrom pymgrid.microgrid.reward_shaping.base import BaseRewardShaper\n\n\nclass BatteryDischargeShaper(Ba"
  },
  {
    "path": "src/pymgrid/microgrid/reward_shaping/pv_curtailment_shaper.py",
    "chars": 454,
    "preview": "from pymgrid.microgrid.reward_shaping.base import BaseRewardShaper\n\n\nclass PVCurtailmentShaper(BaseRewardShaper):\n    \"\""
  },
  {
    "path": "src/pymgrid/microgrid/trajectory/__init__.py",
    "chars": 129,
    "preview": "from .deterministic import DeterministicTrajectory\nfrom .stochastic import StochasticTrajectory, FixedLengthStochasticTr"
  },
  {
    "path": "src/pymgrid/microgrid/trajectory/base.py",
    "chars": 627,
    "preview": "import inspect\nimport yaml\n\nfrom abc import abstractmethod\n\n\nclass BaseTrajectory(yaml.YAMLObject):\n    yaml_dumper = ya"
  },
  {
    "path": "src/pymgrid/microgrid/trajectory/deterministic.py",
    "chars": 383,
    "preview": "from pymgrid.microgrid.trajectory.base import BaseTrajectory\n\n\nclass DeterministicTrajectory(BaseTrajectory):\n    yaml_t"
  },
  {
    "path": "src/pymgrid/microgrid/trajectory/stochastic.py",
    "chars": 1025,
    "preview": "import numpy as np\n\nfrom pymgrid.microgrid.trajectory.base import BaseTrajectory\n\n\nclass StochasticTrajectory(BaseTrajec"
  },
  {
    "path": "src/pymgrid/microgrid/utils/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/microgrid/utils/step.py",
    "chars": 1860,
    "preview": "import numpy as np\n\n\nclass MicrogridStep:\n    def __init__(self, reward_shaping_func=None, cost_info=None):\n        self"
  },
  {
    "path": "src/pymgrid/modules/__init__.py",
    "chars": 308,
    "preview": "from .battery_module import BatteryModule\nfrom .genset_module import GensetModule\nfrom .grid_module import GridModule\nfr"
  },
  {
    "path": "src/pymgrid/modules/base/__init__.py",
    "chars": 122,
    "preview": "from .base_module import BaseMicrogridModule\nfrom .timeseries.base_timeseries_module import BaseTimeSeriesMicrogridModul"
  },
  {
    "path": "src/pymgrid/modules/base/base_module.py",
    "chars": 29836,
    "preview": "from abc import abstractmethod\nimport inspect\nimport logging\nimport yaml\nimport numpy as np\n\nfrom warnings import warn\n\n"
  },
  {
    "path": "src/pymgrid/modules/base/timeseries/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/pymgrid/modules/base/timeseries/base_timeseries_module.py",
    "chars": 12245,
    "preview": "import numpy as np\n\nfrom pymgrid.microgrid import DEFAULT_HORIZON\nfrom pymgrid.modules.base import BaseMicrogridModule\nf"
  },
  {
    "path": "src/pymgrid/modules/battery_module.py",
    "chars": 12255,
    "preview": "from pymgrid.modules.base import BaseMicrogridModule\nimport numpy as np\nimport yaml\nfrom warnings import warn\n\n\nclass Ba"
  },
  {
    "path": "src/pymgrid/modules/genset_module.py",
    "chars": 18133,
    "preview": "import yaml\nimport numpy as np\nfrom warnings import warn\n\nfrom pymgrid.modules.base import BaseMicrogridModule\n\n\nclass G"
  },
  {
    "path": "src/pymgrid/modules/grid_module.py",
    "chars": 11607,
    "preview": "import numpy as np\nimport yaml\n\nfrom pymgrid.microgrid import DEFAULT_HORIZON\nfrom pymgrid.modules.base import BaseTimeS"
  },
  {
    "path": "src/pymgrid/modules/load_module.py",
    "chars": 3685,
    "preview": "import numpy as np\nimport yaml\n\nfrom pymgrid.microgrid import DEFAULT_HORIZON\nfrom pymgrid.modules.base import BaseTimeS"
  },
  {
    "path": "src/pymgrid/modules/module_container.py",
    "chars": 12815,
    "preview": "import json\nimport pandas as pd\n\nfrom collections import UserDict, UserList\nfrom pymgrid.modules.base import BaseMicrogr"
  },
  {
    "path": "src/pymgrid/modules/renewable_module.py",
    "chars": 3927,
    "preview": "import numpy as np\nimport yaml\n\nfrom pymgrid.microgrid import DEFAULT_HORIZON\nfrom pymgrid.modules.base import BaseTimeS"
  },
  {
    "path": "src/pymgrid/modules/unbalanced_energy_module.py",
    "chars": 3035,
    "preview": "import numpy as np\nimport yaml\n\nfrom pymgrid.modules.base import BaseMicrogridModule\n\n\nclass UnbalancedEnergyModule(Base"
  },
  {
    "path": "src/pymgrid/utils/DataGenerator.py",
    "chars": 46856,
    "preview": "\"\"\"\nCopyright 2020 Total S.A.\nAuthors:Gonzague Henri <gonzague.henri@total.com>, Avishai Halev <>\nPermission to use, mod"
  },
  {
    "path": "src/pymgrid/utils/__init__.py",
    "chars": 53,
    "preview": "from .serialize import add_pymgrid_yaml_representers\n"
  },
  {
    "path": "src/pymgrid/utils/logger.py",
    "chars": 1324,
    "preview": "from collections import UserDict\n\nimport numpy as np\nimport pandas as pd\n\n\nclass ModularLogger(UserDict):\n    def __init"
  },
  {
    "path": "src/pymgrid/utils/ray.py",
    "chars": 632,
    "preview": "import functools\nfrom copy import copy\n\n\ndef ray_decorator(func):\n    \"\"\"\n    ray raises an error when assigning values "
  },
  {
    "path": "src/pymgrid/utils/serialize.py",
    "chars": 3874,
    "preview": "import numpy as np\nimport pandas as pd\nimport yaml\n\nfrom pathlib import Path\n\nTO_CSV_TYPES = np.ndarray, pd.core.generic"
  },
  {
    "path": "src/pymgrid/utils/space.py",
    "chars": 9938,
    "preview": "import operator\nimport numpy as np\nimport warnings\n\nfrom abc import abstractmethod\nfrom gym.spaces import Box, Dict, Spa"
  },
  {
    "path": "src/pymgrid/version.py",
    "chars": 22,
    "preview": "__version__ = '1.2.2'\n"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/conftest.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/control/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/control/data_generation/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/control/data_generation/test_data_generator.py",
    "chars": 9924,
    "preview": "import unittest\nfrom pymgrid.utils.DataGenerator import *\nfrom pandas import Series\nfrom pandas.testing import assert_fr"
  },
  {
    "path": "tests/control/test_control.py",
    "chars": 17,
    "preview": "import unittest\n\n"
  },
  {
    "path": "tests/control/test_mpc.py",
    "chars": 4680,
    "preview": "import numpy as np\n\nfrom tests.helpers.test_case import TestCase\nfrom tests.helpers.modular_microgrid import get_modular"
  },
  {
    "path": "tests/control/test_rbc.py",
    "chars": 1247,
    "preview": "from copy import deepcopy\n\nfrom tests.helpers.test_case import TestCase\nfrom tests.helpers.modular_microgrid import get_"
  },
  {
    "path": "tests/envs/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/envs/test_discrete.py",
    "chars": 5455,
    "preview": "from copy import deepcopy\nfrom math import factorial\n\nfrom tests.helpers.test_case import TestCase\nfrom tests.helpers.mo"
  },
  {
    "path": "tests/envs/test_trajectory.py",
    "chars": 6886,
    "preview": "import numpy as np\n\nfrom tests.helpers.test_case import TestCase\nfrom tests.helpers.modular_microgrid import get_modular"
  },
  {
    "path": "tests/helpers/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/helpers/genset_module_testing_utils.py",
    "chars": 867,
    "preview": "from pymgrid.modules import GensetModule\n\n\ndefault_params = dict(running_min_production=10,\n                            "
  },
  {
    "path": "tests/helpers/modular_microgrid.py",
    "chars": 1830,
    "preview": "import numpy as np\n\nfrom pymgrid import Microgrid\n\nfrom pymgrid.modules import (\n    BatteryModule,\n    GensetModule,\n  "
  },
  {
    "path": "tests/helpers/test_case.py",
    "chars": 853,
    "preview": "import unittest\nimport numpy as np\nfrom warnings import warn\n\n\nclass TestCase(unittest.TestCase):\n    def assertEqual(se"
  },
  {
    "path": "tests/microgrid/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/microgrid/modules/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/microgrid/modules/container_tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/microgrid/modules/container_tests/test_container.py",
    "chars": 397,
    "preview": "from tests.helpers.modular_microgrid import get_modular_microgrid\nfrom tests.helpers.test_case import TestCase\n\n\nclass T"
  },
  {
    "path": "tests/microgrid/modules/conversion_test/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/microgrid/modules/conversion_test/test_modular_conversion.py",
    "chars": 1960,
    "preview": "import numpy as np\n\nfrom tests.helpers.test_case import TestCase\n\n\nclass TestToModular(TestCase):\n    def setUp(self) ->"
  },
  {
    "path": "tests/microgrid/modules/forecaster_tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/microgrid/modules/forecaster_tests/test_forecaster.py",
    "chars": 17797,
    "preview": "import numpy as np\nfrom tests.helpers.test_case import TestCase\nfrom pymgrid.forecast import (\n    get_forecaster, Oracl"
  },
  {
    "path": "tests/microgrid/modules/module_tests/test_genset_long_status_changes.py",
    "chars": 10627,
    "preview": "from tests.helpers.genset_module_testing_utils import get_genset, normalize_production\nfrom tests.helpers.test_case impo"
  },
  {
    "path": "tests/microgrid/modules/module_tests/test_genset_module.py",
    "chars": 6425,
    "preview": "import numpy as np\n\nfrom tests.helpers.genset_module_testing_utils import default_params, get_genset, normalize_producti"
  },
  {
    "path": "tests/microgrid/modules/module_tests/test_genset_module_start_up_1_wind_down_1.py",
    "chars": 7843,
    "preview": "from tests.helpers.genset_module_testing_utils import get_genset, normalize_production\nfrom tests.helpers.test_case impo"
  },
  {
    "path": "tests/microgrid/modules/module_tests/test_load_module.py",
    "chars": 2333,
    "preview": "import numpy as np\n\nfrom pymgrid.modules import LoadModule\n\nfrom tests.microgrid.modules.module_tests.timeseries_modules"
  },
  {
    "path": "tests/microgrid/modules/module_tests/test_renewable_module.py",
    "chars": 2595,
    "preview": "\nfrom pymgrid.modules import RenewableModule\n\nfrom tests.microgrid.modules.module_tests.timeseries_modules import (\n    "
  },
  {
    "path": "tests/microgrid/modules/module_tests/timeseries_modules.py",
    "chars": 3824,
    "preview": "import numpy as np\nfrom abc import abstractmethod\nfrom gym.spaces import Box\n\nfrom pymgrid.utils.space import ModuleSpac"
  },
  {
    "path": "tests/microgrid/serialize/test_microgrid_serialization.py",
    "chars": 763,
    "preview": "import numpy as np\n\nfrom pymgrid import Microgrid\n\nfrom tests.helpers.modular_microgrid import get_modular_microgrid\nfro"
  },
  {
    "path": "tests/microgrid/test_microgrid.py",
    "chars": 18673,
    "preview": "import numpy as np\nimport pandas as pd\n\n\nfrom pymgrid import Microgrid\nfrom pymgrid.modules import LoadModule, Renewable"
  },
  {
    "path": "tests/test_microgridgenerator.py",
    "chars": 2474,
    "preview": "\"\"\"\nCopyright 2020 Total S.A.\nAuthors:Gonzague Henri <gonzague.henri@total.com>\nPermission to use, modify, and distribut"
  },
  {
    "path": "tests/test_nonmodular_microgrid.py",
    "chars": 2071,
    "preview": "\"\"\"\nCopyright 2020 Total S.A.\nAuthors:Gonzague Henri <gonzague.henri@total.com>\nPermission to use, modify, and distribut"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the Total-RD/pymgrid GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 181 files (1.5 MB), approximately 620.4k tokens, and a symbol index with 1012 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!