-
Notifications
You must be signed in to change notification settings - Fork 243
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TSK] Init powerplant production plan API
- Loading branch information
Weber
committed
Sep 15, 2024
1 parent
82c6412
commit c67d445
Showing
11 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*env/ | ||
*__pycache__/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
|
||
# About the API | ||
|
||
## Prerequisite | ||
|
||
Current API was built throught Flask framework. In order to launch Flask server, some dependencies | ||
are needed, and should be installed (see requirements.txt) | ||
|
||
## API using | ||
|
||
Of course, you need to launch the flask server. On root folder, launch app.py. | ||
|
||
### First way : throught script | ||
|
||
Always on the root, a script called *launch_dummy_payload.py* init a request attempt to the server. To use it, | ||
just set the path to your file on the variable file_path, then launch it on CLI. | ||
|
||
### Second way : curl command | ||
|
||
Less convenient, curl command could be use, like this : *curl -X POST http://127.0.0.0:8888/production_plan -H "Content-Type: application/json" -d your_json_values*. Keep in mind that is not the most convenient way for large set of data. In this case, use the first option. | ||
|
||
## Interesting upgrade | ||
|
||
### CO2 cost inclusion | ||
|
||
Could be interesting to add in merit order this cost | ||
|
||
### Production quantity order | ||
|
||
Include production qty in using order, after cost; | ||
By instance, producing load of 400 with two powerplants (efficienty and cost equals) pmin and pmax respectively at 100/300 and 200/450. | ||
It makes sens to use second before, to avoid two powerplants activation (first cannot take the load completely, second is required, | ||
which oversize the asked load: 300 + 200 > 400). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from . import controllers | ||
from . import models | ||
import app | ||
import blue_print |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from flask import Flask | ||
|
||
from blue_print import production_plan_blue_print | ||
|
||
app = Flask(__name__) | ||
app.register_blueprint(production_plan_blue_print) | ||
|
||
if __name__ == "__main__": | ||
app.run(host="127.0.0.0", port=8888) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from flask import Blueprint | ||
from controllers.production_plan_controller import get_production_plan | ||
|
||
production_plan_blue_print = Blueprint("production_plan_blue_print", __name__) | ||
production_plan_blue_print.route("/production_plan", methods=["POST"])( | ||
get_production_plan | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import production_plan_controller |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from flask import request, jsonify | ||
from models.powerplants import ( | ||
init_all_powerplant_units, | ||
get_merit_order_production_plan, | ||
) | ||
|
||
|
||
def get_production_plan(): | ||
request_values = request.json | ||
required_load = request_values.get("load", 0) | ||
powerplant_values = request_values.get("powerplants", {}) | ||
productivity_settings = request_values.get("fuels") | ||
try: | ||
assert ( | ||
isinstance(required_load, float) or isinstance(required_load, int) | ||
) and required_load > 0 | ||
powerplants = init_all_powerplant_units( | ||
powerplant_values, productivity_settings | ||
) | ||
assert len(powerplants) != 0 | ||
load_production = get_merit_order_production_plan(required_load, powerplants) | ||
except AssertionError: | ||
return jsonify( | ||
{"Error": "No valid load or powerplants missing in the given values."} | ||
) | ||
except Exception as e: | ||
return jsonify( | ||
{ | ||
"Error": f"Some troubles append during processing. '{e}'. Please check the values" | ||
} | ||
) | ||
return jsonify(load_production) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
|
||
import requests | ||
import json | ||
from json import JSONDecodeError | ||
|
||
file_path = '' # Your filepath | ||
|
||
data = {} | ||
|
||
try: | ||
with open(file_path, 'r') as file: | ||
data = json.load(file) | ||
headers = {'Content-Type': 'application/json'} | ||
|
||
res = requests.post( | ||
'http://127.0.0.0:8888/production_plan', | ||
json.dumps(data), headers=headers) | ||
if res.ok: | ||
print(res.json()) | ||
|
||
except JSONDecodeError: | ||
print("Given Json file is not valid.") | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import powerplants |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
TYPE_COST_MAPPING = {"gasfired": "gas(euro/MWh)", "turbojet": "kerosine(euro/MWh)"} | ||
|
||
|
||
class PowerPlant: | ||
|
||
def __init__(self, values): | ||
for key, value in values.items(): | ||
setattr(self, key, value) | ||
|
||
def get_producted_load(self, required_load): | ||
# To extend method, depending powerplant type | ||
pass | ||
|
||
|
||
class WindPowerPlant(PowerPlant): | ||
|
||
def __init__(self, values): | ||
super().__init__(values) | ||
self.wind_rate = values.get("wind") | ||
|
||
def get_producted_load(self, required_load): | ||
if required_load <= 0: | ||
return 0 | ||
load_to_product = required_load if self.pmax > required_load else self.pmax | ||
return round(load_to_product * self.wind_rate, 1) | ||
|
||
|
||
class FossilePowerPlant(PowerPlant): | ||
|
||
def __init__(self, values): | ||
super().__init__(values) | ||
theorical_cost = values.get("cost") | ||
self.cost = round(theorical_cost * (1 / (self.efficiency)), 1) | ||
|
||
def get_producted_load(self, required_load): | ||
if required_load <= 0: | ||
return 0 | ||
elif self.pmin < required_load < self.pmax: | ||
return required_load | ||
return self.pmin if required_load < self.pmin else self.pmax | ||
|
||
|
||
def init_all_powerplant_units(powerplant_values, productivity_settings): | ||
powerplants = [] | ||
breakpoint() | ||
for values in powerplant_values: | ||
type = values.get("type") | ||
cost_type = TYPE_COST_MAPPING.get(type, "wind") | ||
values.update( | ||
{ | ||
"cost": productivity_settings.get(cost_type, 0.0), | ||
"wind": productivity_settings.get("wind(%)", 0.0) / 100, | ||
} | ||
) | ||
ToInstanceClass = WindPowerPlant if type == "windturbine" else FossilePowerPlant | ||
powerplant = ToInstanceClass(values) | ||
powerplants.append(powerplant) | ||
return powerplants | ||
|
||
|
||
def get_merit_order_production_plan(required_load, powerplants): | ||
production_plan = [] | ||
ordered_powerplants = sorted(powerplants, key=lambda powerplant: powerplant.cost) | ||
for powerplant in ordered_powerplants: | ||
producted_load = powerplant.get_producted_load(required_load) | ||
production_plan.append({"name": powerplant.name, "p": producted_load}) | ||
required_load = round(required_load - producted_load, 1) | ||
return production_plan |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
black==24.8.0 | ||
blinker==1.8.2 | ||
certifi==2024.8.30 | ||
charset-normalizer==3.3.2 | ||
click==8.1.7 | ||
Flask==3.0.3 | ||
idna==3.9 | ||
itsdangerous==2.2.0 | ||
Jinja2==3.1.4 | ||
MarkupSafe==2.1.5 | ||
mypy-extensions==1.0.0 | ||
packaging==24.1 | ||
pathspec==0.12.1 | ||
platformdirs==4.3.3 | ||
requests==2.32.3 | ||
urllib3==2.2.3 | ||
Werkzeug==3.0.4 |