diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e7df597c..4b96257ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,11 @@ Classify the change according to the following categories: ##### Removed ### Patches +## v3.9.3 +### Minor Updates +#### Changed +- Set **reopt_version** in **APIMeta** and **ERPMeta** programatically based on actual REopt.jl package version in Julia environment instead of hardcoded so doesn't need to be updated by hand + ## v3.9.2 #### Added - Added attribute `thermal_efficiency` to the arguments of http endpoint `chp_defaults` diff --git a/julia_src/http.jl b/julia_src/http.jl index 631da7486..6e8bbd544 100644 --- a/julia_src/http.jl +++ b/julia_src/http.jl @@ -22,13 +22,13 @@ end function reopt(req::HTTP.Request) d = JSON.parse(String(req.body)) error_response = Dict() - settings = d["Settings"] if !isempty(get(d, "api_key", "")) ENV["NREL_DEVELOPER_API_KEY"] = pop!(d, "api_key") else ENV["NREL_DEVELOPER_API_KEY"] = test_nrel_developer_api_key delete!(d, "api_key") end + settings = d["Settings"] solver_name = get(settings, "solver_name", "HiGHS") if solver_name == "Xpress" && !(xpress_installed=="True") solver_name = "HiGHS" @@ -140,23 +140,22 @@ function reopt(req::HTTP.Request) if isempty(error_response) @info "REopt model solved with status $(results["status"])." + response = Dict( + "results" => results, + "reopt_version" => string(pkgversion(reoptjl)) + ) if results["status"] == "error" - response = Dict( - "results" => results - ) if !isempty(inputs_with_defaults_set_in_julia) response["inputs_with_defaults_set_in_julia"] = inputs_with_defaults_set_in_julia end return HTTP.Response(400, JSON.json(response)) else - response = Dict( - "results" => results, - "inputs_with_defaults_set_in_julia" => inputs_with_defaults_set_in_julia - ) + response["inputs_with_defaults_set_in_julia"] = inputs_with_defaults_set_in_julia return HTTP.Response(200, JSON.json(response)) end else @info "An error occured in the Julia code." + error_response["reopt_version"] = string(pkgversion(reoptjl)) return HTTP.Response(500, JSON.json(error_response)) end end @@ -169,9 +168,11 @@ function erp(req::HTTP.Request) results = Dict() try results = reoptjl.backup_reliability(erp_inputs) + results["reopt_version"] = string(pkgversion(reoptjl)) catch e @error "Something went wrong in the ERP Julia code!" exception=(e, catch_backtrace()) error_response["error"] = sprint(showerror, e) + error_response["reopt_version"] = string(pkgversion(reoptjl)) end GC.gc() if isempty(error_response) diff --git a/reoptjl/api.py b/reoptjl/api.py index 4753f096e..e2a6264b7 100644 --- a/reoptjl/api.py +++ b/reoptjl/api.py @@ -98,7 +98,6 @@ def obj_create(self, bundle, **kwargs): meta = { "run_uuid": run_uuid, "api_version": 3, - "reopt_version": "0.47.2", "status": "Validating..." } bundle.data.update({"APIMeta": meta}) diff --git a/reoptjl/models.py b/reoptjl/models.py index e9419054b..7b6aeb964 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -176,6 +176,7 @@ class APIMeta(BaseModel, models.Model): created = models.DateTimeField(auto_now_add=True) reopt_version = models.TextField( blank=True, + null=True, default="", help_text="Version number of the Julia package for REopt that is used to solve the problem." ) diff --git a/reoptjl/src/run_jump_model.py b/reoptjl/src/run_jump_model.py index 6499068ff..34ab85812 100644 --- a/reoptjl/src/run_jump_model.py +++ b/reoptjl/src/run_jump_model.py @@ -69,6 +69,7 @@ def run_jump_model(run_uuid): if response.status_code == 500: raise REoptFailedToStartError(task=name, message=response_json["error"], run_uuid=run_uuid, user_uuid=user_uuid) results = response_json["results"] + reopt_version = response_json["reopt_version"] if results["status"].strip().lower() != "error": inputs_with_defaults_set_in_julia = response_json["inputs_with_defaults_set_in_julia"] time_dict["pyjulia_run_reopt_seconds"] = time.time() - t_start @@ -107,6 +108,7 @@ def run_jump_model(run_uuid): profiler.profileEnd() # TODO save profile times + APIMeta.objects.filter(run_uuid=run_uuid).update(reopt_version=reopt_version) if status.strip().lower() != 'error': update_inputs_in_database(inputs_with_defaults_set_in_julia, run_uuid) process_results(results, run_uuid) diff --git a/reoptjl/test/test_job_endpoint.py b/reoptjl/test/test_job_endpoint.py index 5ac8f3dc9..8a41b24ce 100644 --- a/reoptjl/test/test_job_endpoint.py +++ b/reoptjl/test/test_job_endpoint.py @@ -25,6 +25,7 @@ def test_multiple_outages(self): run_uuid = r.get('run_uuid') resp = self.api_client.get(f'/v3/job/{run_uuid}/results') r = json.loads(resp.content) + self.assertIn("reopt_version", r.keys()) results = r["outputs"] self.assertEqual(np.array(results["Outages"]["unserved_load_series_kw"]).shape, (1,2,5)) self.assertEqual(np.array(results["Outages"]["generator_fuel_used_per_outage_gal"]).shape, (1,2)) diff --git a/resilience_stats/api.py b/resilience_stats/api.py index fbe66104b..754247fe4 100644 --- a/resilience_stats/api.py +++ b/resilience_stats/api.py @@ -62,7 +62,6 @@ def obj_create(self, bundle, **kwargs): meta_dict = { "run_uuid": erp_run_uuid, - "reopt_version": "0.45.0", "status": "Validating..." } @@ -450,7 +449,8 @@ def process_erp_results(results: dict, run_uuid: str) -> None: #TODO: get success or error status from julia meta = ERPMeta.objects.get(run_uuid=run_uuid) meta.status = 'Completed' #results.get("status") - meta.save(update_fields=['status']) + meta.reopt_version = results.pop("reopt_version") + meta.save(update_fields=['status','reopt_version']) ERPOutputs.create(meta=meta, **results).save() diff --git a/resilience_stats/models.py b/resilience_stats/models.py index f3aeb4b91..7da62888d 100644 --- a/resilience_stats/models.py +++ b/resilience_stats/models.py @@ -84,6 +84,7 @@ class ERPMeta(BaseModel, models.Model): created = models.DateTimeField(auto_now_add=True) reopt_version = models.TextField( blank=True, + null=True, default="", help_text="Version number of the REopt Julia package that is used to calculate reliability." ) diff --git a/resilience_stats/tests/test_erp.py b/resilience_stats/tests/test_erp.py index fcd284360..c9730e5a4 100644 --- a/resilience_stats/tests/test_erp.py +++ b/resilience_stats/tests/test_erp.py @@ -66,7 +66,9 @@ def test_erp_long_duration_battery(self): r_sim = json.loads(resp.content) erp_run_uuid = r_sim.get('run_uuid') resp = self.get_results_sim(erp_run_uuid) - results_sim = json.loads(resp.content)["outputs"] + r = json.loads(resp.content) + self.assertIn("reopt_version", r.keys()) + results_sim = r["outputs"] expected_result = ([1]*79)+[0.999543,0.994178,0.9871,0.97774,0.965753,0.949429,0.926712,0.899543,0.863584,0.826712,0.785616,0.736416,0.683105,0.626256,0.571005,0.519064,0.47226,0.429909,0.391553,0.357306,0] #TODO: resolve bug where unlimted fuel markov portion of results goes to zero 1 timestep early