Skip to content
Draft
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: 4 additions & 0 deletions app/epa/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@
MVS_SA_POST_URL = f"{MVS_API_HOST}/sendjson/openplan/sensitivity-analysis"
MVS_SA_GET_URL = f"{MVS_API_HOST}/check-sensitivity-analysis/"

EZP_API_HOST = env("EZP_API_HOST", default="")
EZP_POST_URL = f"{EZP_API_HOST}/sendjson/"
EZP_GET_URL = f"{EZP_API_HOST}/check/"

# Allow iframes to show in page
X_FRAME_OPTIONS = "SAMEORIGIN"

Expand Down
79 changes: 79 additions & 0 deletions app/projects/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
MVS_GET_URL,
MVS_SA_POST_URL,
MVS_SA_GET_URL,
EZP_POST_URL,
EZP_GET_URL,
)
from dashboard.models import (
FancyResults,
Expand All @@ -24,6 +26,83 @@
logger = logging.getLogger(__name__)


def ezp_simulation_request(data: str):
headers = {"content-type": "application/json"}
payload = data

try:
response = requests.post(
EZP_POST_URL,
data=payload,
headers=headers,
proxies=PROXY_CONFIG,
verify=False,
)

# If the response was successful, no Exception will be raised
response.raise_for_status()
except requests.HTTPError as http_err:
logger.error(f"HTTP error occurred: {http_err}")
return None
except Exception as err:
logger.error(f"Other error occurred: {err}")
return None
else:
logger.info("The simulation was sent successfully to MVS API.")
return json.loads(response.text)


def ezp_simulation_check_status(token):
try:
response = requests.get(EZP_GET_URL + token, proxies=PROXY_CONFIG, verify=False)
response.raise_for_status()
except requests.HTTPError as http_err:
logger.error(f"HTTP error occurred: {http_err}")
return None
except Exception as err:
logger.error(f"Other error occurred: {err}")
return None
else:
logger.info("Success!")
return json.loads(response.text)


def fetch_ezp_simulation_results(simulation):
if simulation.status == PENDING:
response = ezp_simulation_check_status(token=simulation.mvs_token)
try:
simulation.status = response["status"]
simulation.errors = (
json.dumps(response["results"][ERROR])
if simulation.status == ERROR
else None
)
simulation.results = (
response["results"] if simulation.status == DONE else None
)

# simulation.mvs_version = response["mvs_version"]
logger.info(f"The simulation {simulation.id} is finished")
except:
simulation.status = ERROR
simulation.results = None

simulation.elapsed_seconds = (datetime.now() - simulation.start_date).seconds

# Cancel simulation if it has been going on > 48h
max_simulation_seconds = 48 * 60 * 60
if simulation.elapsed_seconds > max_simulation_seconds:
simulation.status = ERROR
simulation.results = None

simulation.end_date = (
datetime.now() if simulation.status in [ERROR, DONE] else None
)
simulation.save()

return simulation.status != PENDING


def mvs_simulation_request(data: dict):
headers = {"content-type": "application/json"}
payload = json.dumps(data)
Expand Down
15 changes: 15 additions & 0 deletions app/projects/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,16 @@
project_export_as_datapackage,
name="project_export_as_datapackage",
),
path(
"scenario/export/datapackage/jsonified/<int:scen_id>",
scenario_export_as_jsonified_datapackage,
name="scenario_export_as_jsonified_datapackage",
),
path(
"scenario/export/datapackage/jsonified/<int:scen_id>/number/<int:n_timestamps>",
scenario_export_as_jsonified_datapackage,
name="scenario_export_as_jsonified_datapackage",
),
path("scenario/upload/<int:proj_id>", scenario_upload, name="scenario_upload"),
# path('scenario/upload/<int:proj_id>', LoadScenarioFromFileView.as_view(), name='scenario_upload'),
# Timeseries Model
Expand Down Expand Up @@ -255,6 +265,11 @@
request_mvs_simulation,
name="request_mvs_simulation",
),
path(
"topology/ezp_simulation/<int:scen_id>",
request_ezp_simulation,
name="request_ezp_simulation",
),
path(
"topology/update_simulation_rating/",
update_simulation_rating,
Expand Down
89 changes: 89 additions & 0 deletions app/projects/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@

from jsonview.decorators import json_view
from django.db.models import Q

from oemof.datapackage.datapackage import export_dp_to_json

from epa.settings import MVS_GET_URL, MVS_LP_FILE_URL, MVS_SA_GET_URL
from .forms import *
from .requests import (
mvs_simulation_request,
fetch_mvs_simulation_results,
ezp_simulation_request,
fetch_ezp_simulation_results,
mvs_sensitivity_analysis_request,
fetch_mvs_sa_results,
parse_mvs_results,
Expand Down Expand Up @@ -1382,6 +1387,25 @@ def scenario_export_as_datapackage(request, scen_id, n_timestamps=None):
return response


@login_required
@require_http_methods(["GET"])
def scenario_export_as_jsonified_datapackage(request, scen_id, n_timestamps=None):
scenario = get_object_or_404(Scenario, id=int(scen_id))

if scenario.project.user != request.user:
raise PermissionDenied

with tempfile.TemporaryDirectory() as temp_dir:
destination_path = Path(temp_dir)
# write the content of the scenario into a temp directory
scenario_folder = scenario.to_datapackage(destination_path, number=n_timestamps)

json_dp = json.loads(export_dp_to_json(scenario_folder))
response = JsonResponse(json_dp, status=200, content_type="application/json")

return response


@login_required
@require_http_methods(["GET"])
def project_export_as_datapackage(request, proj_id, n_timestamps=None):
Expand Down Expand Up @@ -2025,6 +2049,71 @@ def request_mvs_simulation(request, scen_id=0):
return answer


@login_required
@require_http_methods(["GET", "POST"])
def request_ezp_simulation(request, scen_id=0):
if scen_id == 0:
answer = JsonResponse(
{"status": "error", "error": "No scenario id provided"},
status=500,
content_type="application/json",
)
# Load scenario
scenario = Scenario.objects.get(pk=scen_id)
json_dp = scenario_export_as_jsonified_datapackage(request, scen_id)

# if request.method == "POST":
# output_lp_file = request.POST.get("output_lp_file", None)
# if output_lp_file == "on":
# data_clean["simulation_settings"]["output_lp_file"] = "true"

# Make simulation request to eesyplan server
results = ezp_simulation_request(json_dp.text)

if results is None:
error_msg = "Could not communicate with the simulation server."
logger.error(error_msg)
messages.error(request, error_msg)
# TODO redirect to prefilled feedback form / bug form
answer = JsonResponse(
{"status": "error", "error": error_msg},
status=407,
content_type="application/json",
)
else:
# delete existing simulation
Simulation.objects.filter(scenario_id=scen_id).delete()

# Create empty Simulation model object
simulation = Simulation(start_date=datetime.datetime.now(), scenario_id=scen_id)

simulation.mvs_token = (
results["id"] if results["id"] else None
) # TODO change token

if "status" in results.keys() and (
results["status"] == DONE or results["status"] == ERROR
):
simulation.status = results["status"]
simulation.results = results["results"]
simulation.end_date = datetime.datetime.now()
else: # PENDING
simulation.status = results["status"]
# create a task which will update simulation status
# create_or_delete_simulation_scheduler(mvs_token=simulation.mvs_token)

simulation.elapsed_seconds = (
datetime.datetime.now() - simulation.start_date
).seconds
simulation.save()

answer = HttpResponseRedirect(
reverse("scenario_review", args=[scenario.project.id, scen_id])
)

return answer


@json_view
@login_required
@require_http_methods(["POST"])
Expand Down
Loading