Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include optimization parameter #94

Merged
merged 19 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ jobs:
postgres-version: "16"
backend: "sqlite,rest-sqlite"
pandas-version: "2.1.3"
# pandas 2.0.0
# pandas 2.1.0
- python-version: "3.10"
with-pyarrow: true
postgres-version: "16"
backend: "sqlite,rest-sqlite"
pandas-version: "2.0.0"
pandas-version: "2.1.0"

name: py${{ matrix.python-version }} | backend=${{ matrix.backend }} | with-pyarrow=${{ matrix.with-pyarrow }} | pgsql=${{ matrix.postgres-version }} | pandas=${{ matrix.pandas-version }}
runs-on: ubuntu-latest
Expand Down
8 changes: 4 additions & 4 deletions ixmp4/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# flake8: noqa
import importlib.metadata

from ixmp4.core import IndexSet as IndexSet
from ixmp4.core import Model as Model
from ixmp4.core import Parameter as Parameter
from ixmp4.core import Platform as Platform
from ixmp4.core import Region as Region
from ixmp4.core import Run as Run
from ixmp4.core import Scalar as Scalar
from ixmp4.core import Scenario as Scenario
from ixmp4.core import Table as Table
from ixmp4.core import Unit as Unit
from ixmp4.core import Variable as Variable
from ixmp4.core import IndexSet as IndexSet
from ixmp4.core import Scalar as Scalar
from ixmp4.core import Table as Table
from ixmp4.core.exceptions import InconsistentIamcType as InconsistentIamcType
from ixmp4.core.exceptions import IxmpError as IxmpError
from ixmp4.core.exceptions import NotFound as NotFound
Expand Down
1 change: 1 addition & 0 deletions ixmp4/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .optimization.indexset import IndexSet as IndexSet
from .optimization.scalar import Scalar as Scalar
from .optimization.table import Table as Table
from .optimization.parameter import Parameter as Parameter
from .platform import Platform as Platform
from .region import Region as Region
from .run import Run as Run
Expand Down
7 changes: 2 additions & 5 deletions ixmp4/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,6 @@ class OptimizationDataValidationError(IxmpError):
http_error_name = "optimization_data_validation_error"


# == Optimization.Table ==


class OptimizationTableUsageError(IxmpError):
class OptimizationItemUsageError(IxmpError):
http_status_code = 422
http_error_name = "optimization_table_usage_error"
http_error_name = "optimization_item_usage_error"
3 changes: 3 additions & 0 deletions ixmp4/core/optimization/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from ..base import BaseFacade
from .indexset import IndexSetRepository
from .parameter import ParameterRepository
from .scalar import ScalarRepository
from .table import TableRepository

Expand All @@ -11,11 +12,13 @@ class OptimizationData(BaseFacade):
IndexSet, Table, Variable, etc."""

indexsets: IndexSetRepository
parameters: ParameterRepository
scalars: ScalarRepository
tables: TableRepository

def __init__(self, *args, run: Run, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.indexsets = IndexSetRepository(_backend=self.backend, _run=run)
self.parameters = ParameterRepository(_backend=self.backend, _run=run)
self.scalars = ScalarRepository(_backend=self.backend, _run=run)
self.tables = TableRepository(_backend=self.backend, _run=run)
133 changes: 133 additions & 0 deletions ixmp4/core/optimization/parameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from datetime import datetime
from typing import Any, ClassVar, Iterable

import pandas as pd

from ixmp4.core.base import BaseFacade, BaseModelFacade
from ixmp4.data.abstract import Docs as DocsModel
from ixmp4.data.abstract import Parameter as ParameterModel
from ixmp4.data.abstract import Run
from ixmp4.data.abstract.optimization import Column


class Parameter(BaseModelFacade):
_model: ParameterModel
NotFound: ClassVar = ParameterModel.NotFound
NotUnique: ClassVar = ParameterModel.NotUnique

@property
def id(self) -> int:
return self._model.id

@property
def name(self) -> str:
return self._model.name

@property
def run_id(self) -> int:
return self._model.run__id

@property
def data(self) -> dict[str, Any]:
return self._model.data

def add(self, data: dict[str, Any] | pd.DataFrame) -> None:
"""Adds data to an existing Parameter."""
self.backend.optimization.parameters.add_data(
parameter_id=self._model.id, data=data
)
self._model.data = self.backend.optimization.parameters.get(
run_id=self._model.run__id, name=self._model.name
).data

@property
def values(self) -> list:
return self._model.data.get("values", [])

@property
def units(self) -> list:
return self._model.data.get("units", [])

@property
def constrained_to_indexsets(self) -> list[str]:
return [column.indexset.name for column in self._model.columns]

@property
def columns(self) -> list[Column]:
return self._model.columns

@property
def created_at(self) -> datetime | None:
return self._model.created_at

@property
def created_by(self) -> str | None:
return self._model.created_by

@property
def docs(self):
try:
return self.backend.optimization.parameters.docs.get(self.id).description
except DocsModel.NotFound:
return None

@docs.setter
def docs(self, description):
if description is None:
self.backend.optimization.parameters.docs.delete(self.id)
else:
self.backend.optimization.parameters.docs.set(self.id, description)

@docs.deleter
def docs(self):
try:
self.backend.optimization.parameters.docs.delete(self.id)
# TODO: silently failing
except DocsModel.NotFound:
return None

def __str__(self) -> str:
return f"<Parameter {self.id} name={self.name}>"


class ParameterRepository(BaseFacade):
_run: Run

def __init__(self, _run: Run, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._run = _run

def create(
self,
name: str,
constrained_to_indexsets: list[str],
column_names: list[str] | None = None,
) -> Parameter:
model = self.backend.optimization.parameters.create(
name=name,
run_id=self._run.id,
constrained_to_indexsets=constrained_to_indexsets,
column_names=column_names,
)
return Parameter(_backend=self.backend, _model=model)

def get(self, name: str) -> Parameter:
model = self.backend.optimization.parameters.get(run_id=self._run.id, name=name)
return Parameter(_backend=self.backend, _model=model)

def list(self, name: str | None = None) -> Iterable[Parameter]:
parameters = self.backend.optimization.parameters.list(
run_id=self._run.id, name=name
)
return [
Parameter(
_backend=self.backend,
_model=i,
)
for i in parameters
]

def tabulate(self, name: str | None = None) -> pd.DataFrame:
return self.backend.optimization.parameters.tabulate(
run_id=self._run.id, name=name
)
3 changes: 2 additions & 1 deletion ixmp4/data/abstract/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
This module holds a shared datastructure and interface for normalization
between the database and api data models and repositories.
"""
# flake8: noqa

from .base import (
BaseMeta,
Expand Down Expand Up @@ -32,6 +31,8 @@
from .optimization import (
IndexSet,
IndexSetRepository,
Parameter,
ParameterRepository,
Scalar,
ScalarRepository,
Table,
Expand Down
1 change: 1 addition & 0 deletions ixmp4/data/abstract/optimization/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .column import Column
from .indexset import IndexSet, IndexSetRepository
from .parameter import Parameter, ParameterRepository
from .scalar import Scalar, ScalarRepository
from .table import Table, TableRepository
4 changes: 3 additions & 1 deletion ixmp4/data/abstract/optimization/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ class Column(base.BaseModel, Protocol):
"""Unique name of the Column."""
dtype: types.String
"""Type of the Column's data."""
table__id: types.Integer
table__id: types.Mapped[int | None]
"""Foreign unique integer id of a Table."""
parameter__id: types.Mapped[int | None]
"""Foreign unique integer id of a Parameter."""
indexset: types.Mapped[IndexSet]
"""Associated IndexSet."""
constrained_to_indexset: types.Integer
Expand Down
4 changes: 2 additions & 2 deletions ixmp4/data/abstract/optimization/indexset.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def list(self, *, name: str | None = None, **kwargs) -> list[IndexSet]:
# TODO: Update kwargs
\*\*kwargs: any
More filter parameters as specified in
`ixmp4.data.db.iamc.variable.filters.VariableFilter`.
`ixmp4.data.db.optimization.indexset.filter.OptimizationIndexSetFilter`.

Returns
-------
Expand All @@ -112,7 +112,7 @@ def tabulate(self, *, name: str | None = None, **kwargs) -> pd.DataFrame:
# TODO: Update kwargs
\*\*kwargs: any
More filter parameters as specified in
`ixmp4.data.db.iamc.variable.filters.VariableFilter`.
`ixmp4.data.db.optimization.indexset.filter.OptimizationIndexSetFilter`.

Returns
-------
Expand Down
Loading
Loading