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

Cleanup: parameters: extra=forbid, optimize: battery, inverter optional #361

Merged
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
13 changes: 10 additions & 3 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,25 @@ jobs:

- name: Login to Docker Hub
uses: docker/login-action@v3
# skip for pull requests
if: ${{ github.event_name != 'pull_request' }}
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

- name: Login to GHCR
uses: docker/login-action@v3
# skip for pull requests
if: ${{ github.event_name != 'pull_request' }}
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# skip for pull requests
if: ${{ github.event_name != 'pull_request' }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand All @@ -114,21 +120,22 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,"push=${{ github.event_name != 'pull_request' }}","annotation-index.org.opencontainers.image.description=${{ env.EOS_REPO_DESCRIPTION }}"
#push: ${{ github.event_name != 'pull_request' }}

- name: Generate artifact attestation DockerHub
uses: actions/attest-build-provenance@v2
if: ${{ github.event_name != 'pull_request' }}
with:
subject-name: docker.io/${{ env.DOCKERHUB_REPO }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: ${{ github.event_name != 'pull_request' }}
push-to-registry: true

- name: Generate artifact attestation GitHub
uses: actions/attest-build-provenance@v2
if: ${{ github.event_name != 'pull_request' }}
with:
subject-name: ${{ env.GHCR_REPO }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: ${{ github.event_name != 'pull_request' }}
push-to-registry: true

- name: Export digest
run: |
Expand Down
36 changes: 29 additions & 7 deletions openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -6108,6 +6108,7 @@
"default": 100
}
},
"additionalProperties": false,
"type": "object",
"required": [
"capacity_wh"
Expand Down Expand Up @@ -6231,6 +6232,7 @@
"description": "An array of floats representing the total load (consumption) in watts for different time intervals."
}
},
"additionalProperties": false,
"type": "object",
"required": [
"pv_prognose_wh",
Expand Down Expand Up @@ -6326,6 +6328,7 @@
"description": "An integer representing the usage duration of a household device in hours."
}
},
"additionalProperties": false,
"type": "object",
"required": [
"consumption_wh",
Expand All @@ -6338,11 +6341,14 @@
"max_power_wh": {
"type": "number",
"exclusiveMinimum": 0.0,
"title": "Max Power Wh",
"default": 10000
"title": "Max Power Wh"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"max_power_wh"
],
"title": "InverterParameters"
},
"OptimizationParameters": {
Expand All @@ -6351,13 +6357,24 @@
"$ref": "#/components/schemas/EnergieManagementSystemParameters"
},
"pv_akku": {
"$ref": "#/components/schemas/SolarPanelBatteryParameters"
"anyOf": [
{
"$ref": "#/components/schemas/SolarPanelBatteryParameters"
},
{
"type": "null"
}
]
},
"inverter": {
"$ref": "#/components/schemas/InverterParameters",
"default": {
"max_power_wh": 10000.0
}
"anyOf": [
{
"$ref": "#/components/schemas/InverterParameters"
},
{
"type": "null"
}
]
},
"eauto": {
"anyOf": [
Expand Down Expand Up @@ -6417,10 +6434,12 @@
"description": "Can be `null` or contain a previous solution (if available)."
}
},
"additionalProperties": false,
"type": "object",
"required": [
"ems",
"pv_akku",
"inverter",
"eauto"
],
"title": "OptimizationParameters"
Expand Down Expand Up @@ -6507,6 +6526,7 @@
"description": "Can be `null` or contain an object representing the start of washing (if applicable)."
}
},
"additionalProperties": false,
"type": "object",
"required": [
"ac_charge",
Expand Down Expand Up @@ -8834,6 +8854,7 @@
"description": "Used Electricity Price, including predictions"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"Last_Wh_pro_Stunde",
Expand Down Expand Up @@ -8917,6 +8938,7 @@
"default": 100
}
},
"additionalProperties": false,
"type": "object",
"required": [
"capacity_wh"
Expand Down
48 changes: 39 additions & 9 deletions single_test_optimization.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import argparse
import cProfile
import json
import pstats
import sys
import time
from typing import Any

import numpy as np

Expand Down Expand Up @@ -295,7 +297,9 @@ def prepare_optimization_parameters() -> OptimizationParameters:
)


def run_optimization(real_world: bool = False, start_hour: int = 0, verbose: bool = False) -> dict:
def run_optimization(
real_world: bool, start_hour: int, verbose: bool, seed: int, parameters_file: str, ngen: int
) -> Any:
"""Run the optimization problem.

Args:
Expand All @@ -306,7 +310,10 @@ def run_optimization(real_world: bool = False, start_hour: int = 0, verbose: boo
dict: Optimization result as a dictionary
"""
# Prepare parameters
if real_world:
if parameters_file:
with open(parameters_file, "r") as f:
parameters = OptimizationParameters(**json.load(f))
elif real_world:
parameters = prepare_optimization_real_parameters()
else:
parameters = prepare_optimization_parameters()
Expand All @@ -318,12 +325,12 @@ def run_optimization(real_world: bool = False, start_hour: int = 0, verbose: boo
# Initialize the optimization problem using the default configuration
config_eos = get_config()
config_eos.merge_settings_from_dict({"prediction_hours": 48, "optimization_hours": 48})
opt_class = optimization_problem(verbose=verbose, fixed_seed=42)
opt_class = optimization_problem(verbose=verbose, fixed_seed=seed)

# Perform the optimisation based on the provided parameters and start hour
result = opt_class.optimierung_ems(parameters=parameters, start_hour=start_hour)
result = opt_class.optimierung_ems(parameters=parameters, start_hour=start_hour, ngen=ngen)

return result.model_dump()
return result.model_dump_json()


def main():
Expand All @@ -339,6 +346,19 @@ def main():
parser.add_argument(
"--start-hour", type=int, default=0, help="Starting hour for optimization (default: 0)"
)
parser.add_argument(
"--parameters-file",
type=str,
default="",
help="Load optimization parameters from json file (default: unset)",
)
parser.add_argument("--seed", type=int, default=42, help="Use fixed random seed (default: 42)")
parser.add_argument(
"--ngen",
type=int,
default=400,
help="Number of generations during optimization process (default: 400)",
)

args = parser.parse_args()

Expand All @@ -351,12 +371,16 @@ def main():
real_world=args.real_world,
start_hour=args.start_hour,
verbose=args.verbose,
seed=args.seed,
parameters_file=args.parameters_file,
ngen=args.ngen,
)
# Print profiling statistics
stats = pstats.Stats(profiler)
stats.strip_dirs().sort_stats("cumulative").print_stats(200)
# Print result
print("\nOptimization Result:")
if args.verbose:
print("\nOptimization Result:")
print(result)

except Exception as e:
Expand All @@ -367,12 +391,18 @@ def main():
try:
start_time = time.time()
result = run_optimization(
real_world=args.real_world, start_hour=args.start_hour, verbose=args.verbose
real_world=args.real_world,
start_hour=args.start_hour,
verbose=args.verbose,
seed=args.seed,
parameters_file=args.parameters_file,
ngen=args.ngen,
)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"\nElapsed time: {elapsed_time:.4f} seconds.")
print("\nOptimization Result:")
if args.verbose:
print(f"\nElapsed time: {elapsed_time:.4f} seconds.")
print("\nOptimization Result:")
print(result)

except Exception as e:
Expand Down
64 changes: 0 additions & 64 deletions src/akkudoktoreos/class_home_appliance.py

This file was deleted.

6 changes: 3 additions & 3 deletions src/akkudoktoreos/core/ems.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from akkudoktoreos.core.coreabc import ConfigMixin, PredictionMixin, SingletonMixin
from akkudoktoreos.core.logging import get_logger
from akkudoktoreos.core.pydantic import PydanticBaseModel
from akkudoktoreos.core.pydantic import ParametersBaseModel, PydanticBaseModel
from akkudoktoreos.devices.battery import Battery
from akkudoktoreos.devices.generic import HomeAppliance
from akkudoktoreos.devices.inverter import Inverter
Expand All @@ -18,7 +18,7 @@
logger = get_logger(__name__)


class EnergieManagementSystemParameters(PydanticBaseModel):
class EnergieManagementSystemParameters(ParametersBaseModel):
pv_prognose_wh: list[float] = Field(
description="An array of floats representing the forecasted photovoltaic output in watts for different time intervals."
)
Expand Down Expand Up @@ -50,7 +50,7 @@ def validate_list_length(self) -> Self:
return self


class SimulationResult(PydanticBaseModel):
class SimulationResult(ParametersBaseModel):
"""This object contains the results of the simulation and provides insights into various parameters over the entire forecast period."""

Last_Wh_pro_Stunde: list[Optional[float]] = Field(description="TBD")
Expand Down
4 changes: 4 additions & 0 deletions src/akkudoktoreos/core/pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,7 @@ def from_series(cls, series: pd.Series, tz: Optional[str] = None) -> "PydanticDa
dtype=str(series.dtype),
tz=tz,
)


class ParametersBaseModel(PydanticBaseModel):
model_config = ConfigDict(extra="forbid")
3 changes: 2 additions & 1 deletion src/akkudoktoreos/devices/battery.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pydantic import BaseModel, Field, field_validator

from akkudoktoreos.core.logging import get_logger
from akkudoktoreos.core.pydantic import ParametersBaseModel
from akkudoktoreos.devices.devicesabc import DeviceBase
from akkudoktoreos.utils.utils import NumpyEncoder

Expand All @@ -24,7 +25,7 @@ def initial_soc_percentage_field(description: str) -> int:
return Field(default=0, ge=0, le=100, description=description)


class BaseBatteryParameters(BaseModel):
class BaseBatteryParameters(ParametersBaseModel):
"""Base class for battery parameters with fields for capacity, efficiency, and state of charge."""

capacity_wh: int = Field(
Expand Down
Loading
Loading