Skip to content

Commit

Permalink
Merge branch 'main' into kt/availability
Browse files Browse the repository at this point in the history
  • Loading branch information
pesap authored Aug 23, 2024
2 parents 15a2a2f + dee6edc commit afbb988
Show file tree
Hide file tree
Showing 10 changed files with 362 additions and 49 deletions.
29 changes: 14 additions & 15 deletions .github/workflows/python-app.yaml → .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ on:
branches:
- main

permissions:
pull-requests: write
contents: write
env:
DEFAULT_PYTHON: "3.12"
DEFAULT_OS: ubuntu-latest

jobs:
pytest:
strategy:
matrix:
python-version: ["3.11", "3.12"]
os: [ubuntu-latest, windows-latest]
permissions:
pull-requests: write
contents: write

runs-on: ${{ matrix.os }}
steps:
Expand All @@ -31,20 +34,16 @@ jobs:
python -m pip install '.[dev]'
- name: Running package tests
run: |
python -m pytest -vvl
python -m pytest -vvl --cov --cov-report=xml
# - name: Coverage comment
# id: coverage_comment
# uses: py-cov-action/python-coverage-comment-action@v3
# - name: codecov
# uses: codecov/[email protected]
# if: ${{ matrix.os == env.DEFAULT_OS && matrix.python-version == env.DEFAULT_PYTHON }}
# with:
# GITHUB_TOKEN: ${{ github.token }}
#
# - name: Store Pull Request comment to be posted
# uses: actions/upload-artifact@v4
# if: steps.coverage_comment.outputs.COMMENT_FILE_WRITTEN == 'true'
# with:
# name: python-coverage-comment-action
# path: python-coverage-comment-action.txt
# token: ${{ secrets.CODECOV_TOKEN }}
# name: r2x-test
# fail_ci_if_error: false
# verbose: true

pre-commit:
runs-on: ubuntu-latest
Expand Down
32 changes: 13 additions & 19 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.version]
path = "src/r2x/__version__.py"

[project]
name = "r2x"
version = "v1.0.0"
dynamic = ["version"]
authors = [
{ name = "Pedro Sanchez", email = "[email protected]" },
{ name = "Obika Kodi", email = "[email protected]" },
Expand All @@ -13,14 +16,20 @@ authors = [
description = "ReEDS to X parser"
requires-python = ">=3.11"
classifiers = [
"Programming Language :: Python :: 3",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Topic :: Software Development :: Build Tools",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Operating System :: OS Independent",
]
dependencies = [
"jsonschema~=4.23",
"loguru~=0.7.2",
"pandas~=2.2",
"infrasys>=0.1.0",
"plexosdb>=0.0.2",
"polars~=1.1.0",
"pyyaml~=6.0.1",
"rich~=13.7.1",
Expand Down Expand Up @@ -65,21 +74,6 @@ ignore_missing_imports=true
module = "polars"
follow_imports = "skip"

# Setuptools configuration
[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
where = ["src"]
include = ["*"]

# Setuptools configuration
[tool.setuptools.dynamic]
readme = { file = ["README.md"], content-type = "text/markdown" }

[tool.setuptools.package-data]
"*" = ["*.json", "*.csv", "*.xml", ".sql"]

[tool.ruff]
line-length = 110
target-version = "py311"
Expand Down
2 changes: 1 addition & 1 deletion src/r2x/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# This file containts the version # noqa: D100
__version__ = "v0.5.2"
__version__ = "v1.0.0rc0"
__data_model_version__ = "0.0.1"
1 change: 1 addition & 0 deletions src/r2x/defaults/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"Flexibility",
"Regulation"
],
"device_inference_string": {},
"distribution_losses": 1,
"generator_map": {},
"heatrate_fits_file": "heatrate_generic_fits.csv",
Expand Down
1 change: 1 addition & 0 deletions src/r2x/defaults/plexos_input.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"plexos_device_map": {},
"plexos_fuel_map": {},
"plexos_property_map": {
"Charge Efficiency": "charge_efficiency",
"Commit": "must_run",
Expand Down
4 changes: 4 additions & 0 deletions src/r2x/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ class ModelError(Exception):

class MultipleFilesError(Exception):
pass


class ParserError(Exception):
pass
51 changes: 38 additions & 13 deletions src/r2x/parser/plexos.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from r2x.api import System
from r2x.config import Scenario
from r2x.enums import ACBusTypes, ReserveDirection, ReserveType, PrimeMoversType
from r2x.exceptions import ModelError
from r2x.exceptions import ModelError, ParserError
from plexosdb import PlexosSQLite
from plexosdb.enums import ClassEnum, CollectionEnum
from r2x.model import (
Expand Down Expand Up @@ -126,12 +126,22 @@ class PlexosParser(PCMParser):
def __init__(self, *args, xml_file: str | None = None, **kwargs) -> None:
super().__init__(*args, **kwargs)
assert self.config.run_folder

self.run_folder = Path(self.config.run_folder)
self.system = System(name=self.config.name)
self.property_map = self.config.defaults["plexos_property_map"]
self.device_map = self.config.defaults["plexos_device_map"]
self.prime_mover_map = self.config.defaults["tech_fuel_pm_map"]
self.fuel_map = self.config.defaults["plexos_fuel_map"]
self.device_match_string = self.config.defaults["device_inference_string"]

# TODO(pesap): Rename exceptions to include R2X
# https://github.com/NREL/R2X/issues/5
# R2X needs at least one of this maps defined to correctly work.
if not self.fuel_map and not self.device_map and not self.device_match_string:
msg = (
"Neither `plexos_fuel_map` or `plexos_device_map` or `device_match_string` was provided. "
"To fix, provide any of the mappings."
)
raise ParserError(msg)

# Populate databse from XML file.
xml_file = xml_file or self.run_folder / self.config.fmap["xml_file"]["fname"]
Expand All @@ -155,7 +165,6 @@ def __init__(self, *args, xml_file: str | None = None, **kwargs) -> None:
def build_system(self) -> System:
"""Create infrasys system."""
logger.info("Building infrasys system using {}", self.__class__.__name__)
# self.append_to_db = self.config.defaults.get("append_to_existing_database", False)

# If we decide to change the engine for handling the data we can do it here.
object_data = self._plexos_table_data()
Expand Down Expand Up @@ -470,10 +479,16 @@ def _construct_generators(self):
generator_name = generator_name[0]
generator_fuel_type = generator_fuel_map.get(generator_name)
logger.trace("Parsing generator = {} with fuel type = {}", generator_name, generator_fuel_type)

# Get prime mover map from fuel
generator_prime_mover = self.fuel_map.get(generator_fuel_type, "")

# First we check if there is a mapping one the name, if not, we try to use the prime
# mover map for the fuel and if not we infer the model by the name and a string.
model_map = (
self.config.device_map.get(generator_name, "")
or self.config.fuel_map.get(generator_fuel_type, "")
or self._infer_model_type(generator_name)
self.device_map.get(generator_name, "") or generator_prime_mover["device"]
if generator_prime_mover
else None or self._infer_model_type(generator_name)
)

if getattr(R2X_MODELS, model_map, None) is None:
Expand Down Expand Up @@ -511,15 +526,15 @@ def _construct_generators(self):

# Add prime mover mapping
mapped_records["prime_mover_type"] = (
self.prime_mover_map[generator_fuel_type].get("type")
if generator_fuel_type in self.prime_mover_map.keys()
else self.prime_mover_map["default"].get("type")
self.fuel_map[generator_fuel_type].get("type")
if generator_fuel_type in self.fuel_map.keys()
else self.fuel_map["default"].get("type")
)
mapped_records["prime_mover_type"] = PrimeMoversType[mapped_records["prime_mover_type"]]
mapped_records["fuel"] = (
self.prime_mover_map[generator_fuel_type].get("fuel")
if generator_fuel_type in self.prime_mover_map.keys()
else self.prime_mover_map["default"].get("fuel")
self.fuel_map[generator_fuel_type].get("fuel")
if generator_fuel_type in self.fuel_map.keys()
else self.fuel_map["default"].get("fuel")
)

match model_map:
Expand Down Expand Up @@ -670,6 +685,10 @@ def _construct_batteries(self):

def _add_buses_to_batteries(self):
batteries = [battery["name"] for battery in self.system.to_records(GenericBattery)]
if not batteries:
msg = "No battery objects found on the system. Skipping adding membership to buses."
logger.warning(msg)
return
generator_memberships = self.db.get_memberships(
*batteries,
object_class=ClassEnum.Battery,
Expand All @@ -694,6 +713,10 @@ def _add_buses_to_batteries(self):
def _add_battery_reserves(self):
reserve_map = self.system.get_component(ReserveMap, name="contributing_generators")
batteries = [battery["name"] for battery in self.system.to_records(GenericBattery)]
if not batteries:
msg = "No battery objects found on the system. Skipping adding membership to buses."
logger.warning(msg)
return
generator_memberships = self.db.get_memberships(
*batteries,
object_class=ClassEnum.Battery,
Expand Down Expand Up @@ -797,6 +820,8 @@ def _construct_interfaces(self, default_model=TransmissionInterface):
return

def _select_model_name(self):
# TODO(pesap): Handle exception if no model name found
# https://github.com/NREL/R2X/issues/10
query = f"""
select obj.name
from t_object as obj
Expand Down
1 change: 1 addition & 0 deletions src/r2x/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ def update_dict(base_dict: dict, override_dict: ChainMap | dict | None = None) -
"model_map",
"tech_fuel_pm_map",
"device_map",
"plexos_fuel_map",
]
for key, value in override_dict.items():
if key in base_dict and all(replace_key not in key for replace_key in _replace_keys):
Expand Down
Loading

0 comments on commit afbb988

Please sign in to comment.