Skip to content

Commit

Permalink
Better handling of dimensionless unit (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielhuppmann authored May 28, 2024
1 parent 599ba10 commit 0e4ff4c
Show file tree
Hide file tree
Showing 5 changed files with 12 additions and 27 deletions.
12 changes: 0 additions & 12 deletions ixmp4/core/iamc/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,6 @@
from .variable import VariableRepository


def to_dimensionless(df: pd.DataFrame) -> pd.DataFrame:
if "dimensionless" in df.unit:
raise ValueError(
"Unit name 'dimensionless' is reserved, use an empty string '' instead."
)
df.replace(to_replace={"unit": ""}, value="dimensionless", inplace=True)
return df


class RemoveDataPointFrameSchema(pa.DataFrameModel):
type: Optional[Series[pa.String]] = pa.Field(isin=[t for t in DataPointModel.Type])
step_year: Optional[Series[pa.Int]] = pa.Field(coerce=True, nullable=True)
Expand Down Expand Up @@ -69,7 +60,6 @@ def map_step_column(df: pd.Series):
def normalize_df(df: pd.DataFrame, raw: bool, join_runs: bool) -> pd.DataFrame:
if not df.empty:
df = df.drop(columns=["time_series__id"])
df.unit = df.unit.replace({"dimensionless": ""})
if raw is False:
return convert_to_std_format(df, join_runs)
return df
Expand Down Expand Up @@ -120,7 +110,6 @@ def add(
type: Optional[DataPointModel.Type] = None,
):
df = AddDataPointFrameSchema.validate(df) # type:ignore
df = to_dimensionless(df.copy())
df["run__id"] = self.run.id
df = self._get_or_create_ts(df)
substitute_type(df, type)
Expand All @@ -132,7 +121,6 @@ def remove(
type: Optional[DataPointModel.Type] = None,
):
df = RemoveDataPointFrameSchema.validate(df) # type:ignore
df = to_dimensionless(df.copy())
df["run__id"] = self.run.id
df = self._get_or_create_ts(df)
substitute_type(df, type)
Expand Down
4 changes: 2 additions & 2 deletions ixmp4/core/optimization/scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ def create(self, name: str, value: float, unit: str | Unit | None = None) -> Sca
unit_name = unit
else:
# TODO: provide logging information about None-units being converted
# to dimensionless
dimensionless_unit = self.backend.units.create(name="dimensionless")
# if unit is None, assume that this is a dimensionless scalar (unit = "")
dimensionless_unit = self.backend.units.create(name="")
unit_name = dimensionless_unit.name

try:
Expand Down
18 changes: 6 additions & 12 deletions ixmp4/core/unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@
from ixmp4.data.abstract import Unit as UnitModel


def to_dimensionless(name):
if name == "dimensionless":
raise ValueError(
"Unit name 'dimensionless' is reserved, use an empty string '' instead."
)
return "dimensionless" if name == "" else name


class Unit(BaseModelFacade):
_model: UnitModel
NotUnique = UnitModel.NotUnique
Expand Down Expand Up @@ -71,10 +63,12 @@ def create(
self,
name: str,
) -> Unit:
name = to_dimensionless(name)
if name.strip() == "":
if name != "" and name.strip() == "":
raise ValueError("Using a space-only unit name is not allowed.")

if name == "dimensionless":
raise ValueError(
"Unit name 'dimensionless' is reserved, use an empty string '' instead."
)
model = self.backend.units.create(name)
return Unit(_backend=self.backend, _model=model)

Expand All @@ -92,7 +86,7 @@ def delete(self, x: Unit | int | str):
self.backend.units.delete(id)

def get(self, name: str) -> Unit:
model = self.backend.units.get(to_dimensionless(name))
model = self.backend.units.get(name)
return Unit(_backend=self.backend, _model=model)

def list(self, name: str | None = None) -> list[Unit]:
Expand Down
2 changes: 1 addition & 1 deletion tests/core/test_scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def test_create_scalar(self, test_mp, request):
assert scalar_1.id != scalar_2.id

scalar_3 = run.optimization.scalars.create("Scalar 3", value=1)
assert scalar_3.unit.name == "dimensionless"
assert scalar_3.unit.name == ""

def test_get_scalar(self, test_mp, request):
test_mp = request.getfixturevalue(test_mp)
Expand Down
3 changes: 3 additions & 0 deletions tests/core/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ def test_unit_dimensionless(self, test_mp, request):

assert unit1.id == unit2.id

assert "" in test_mp.units.tabulate().values
assert "" in [unit.name for unit in test_mp.units.list()]

def test_unit_illegal_names(self, test_mp, request):
test_mp = request.getfixturevalue(test_mp)
with pytest.raises(ValueError, match="Unit name 'dimensionless' is reserved,"):
Expand Down

0 comments on commit 0e4ff4c

Please sign in to comment.