diff --git a/.helm/values.staging.yaml b/.helm/values.staging.yaml index 78b346218..614e0fafb 100644 --- a/.helm/values.staging.yaml +++ b/.helm/values.staging.yaml @@ -1,6 +1,13 @@ appEnv: staging djangoSettingsModule: reopt_api.staging_settings +djangoReplicas: 3 +djangoMemoryRequest: "2800Mi" +djangoMemoryLimit: "2800Mi" +celeryReplicas: 6 +celeryMemoryRequest: "900Mi" +celeryMemoryLimit: "900Mi" +juliaReplicas: 6 juliaCpuRequest: "1000m" juliaCpuLimit: "4000m" -juliaMemoryRequest: "8000Mi" -juliaMemoryLimit: "8000Mi" \ No newline at end of file +juliaMemoryRequest: "12000Mi" +juliaMemoryLimit: "12000Mi" \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 77ca4fb95..313b490c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,15 @@ Classify the change according to the following categories: ##### Removed ### Patches +## v3.7.0 +### Minor Updates +#### Changed +- Default `Settings.solver_name` = `HiGHS` +- See updates from REopt.jl v0.44.0: https://github.com/NREL/REopt.jl/releases/tag/v0.44.0 +- HiGHS, Cbc, and SCIP solvers use Big M notation constraints only in REopt.jl +#### Deprecated +- End-of-Life for v1 and v2 of the API for external/public interfacing from NREL servers. See https://github.com/NREL/REopt-Analysis-Scripts/discussions/148 for more details. + ## v3.6.1 ### Minor Updates #### Fixed diff --git a/Jenkinsfile b/Jenkinsfile index 1f08e9a4f..9fca0c4e4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -66,21 +66,21 @@ pipeline { WERF_SYNCHRONIZATION = ":local" XPRESS_LICENSE_HOST = credentials("reopt-api-xpress-license-host") LICENSESERVER_URL = credentials("reopt-api-xpress-licenseserver-url") - XPRESS_INSTALLED = "True" + XPRESS_INSTALLED = "False" NREL_ROOT_CERT_URL_ROOT = credentials("reopt-api-nrel-root-cert-url-root") } stages { stage("deploy") { stages { - stage("solver setup") { - steps { - dir("julia_src/licenseserver") { - git url: env.LICENSESERVER_URL - } - sh "cp julia_src/licenseserver/Dockerfile.xpress julia_src/" - } - } + // stage("solver setup") { + // steps { + // dir("julia_src/licenseserver") { + // git url: env.LICENSESERVER_URL + // } + // sh "cp julia_src/licenseserver/Dockerfile.xpress julia_src/" + // } + // } stage("lint") { steps { diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index 6f45d8d7c..875d0f87e 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -841,9 +841,9 @@ uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[deps.REopt]] deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"] -git-tree-sha1 = "d7bdc0d314e0821a8904ba204265345aab1ee8bc" +git-tree-sha1 = "b8e663a9f06eb6a1085ff7de981df2a6246b2b91" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.43.0" +version = "0.44.0" [[deps.Random]] deps = ["SHA", "Serialization"] diff --git a/julia_src/http.jl b/julia_src/http.jl index 147a024b5..8d3a38eaa 100644 --- a/julia_src/http.jl +++ b/julia_src/http.jl @@ -29,11 +29,11 @@ function reopt(req::HTTP.Request) ENV["NREL_DEVELOPER_API_KEY"] = test_nrel_developer_api_key delete!(d, "api_key") end - solver_name = pop!(settings, "solver_name") + solver_name = get(settings, "solver_name", "HiGHS") if solver_name == "Xpress" && !(xpress_installed=="True") solver_name = "HiGHS" - @warn "Changing solver_choice from Xpress to $solver_name because Xpress is not installed. Next time - Specify Settings.solver_choice = 'HiGHS' or 'Cbc' or 'SCIP'" + @warn "Changing solver_name from Xpress to $solver_name because Xpress is not installed. Next time + Specify Settings.solver_name = 'HiGHS' or 'Cbc' or 'SCIP'" end timeout_seconds = pop!(settings, "timeout_seconds") optimality_tolerance = pop!(settings, "optimality_tolerance") diff --git a/reo/api.py b/reo/api.py index 3ff8e72c8..b2b125bd9 100644 --- a/reo/api.py +++ b/reo/api.py @@ -89,108 +89,116 @@ def obj_create(self, bundle, **kwargs): uuidFilter = UUIDFilter(run_uuid) log.addFilter(uuidFilter) log.info('Beginning run setup') + + # End-of-Life for V1 and V2 - as of March 2024 + data['inputs'] = bundle.data + data['messages'] = {} + data['messages']['error'] = "v1 and v2 of the REopt API are NO longer available; End-of-Life. Please use /stable (v3). See https://github.com/NREL/REopt-Analysis-Scripts/discussions/148 for more details." + raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + content_type='application/json', + status=410)) # "Gone" code for "no longer available" - # Validate ghpghx_inputs, if applicable - ghpghx_inputs_validation_errors = [] - if bundle.data["Scenario"]["Site"].get("GHP") is not None and \ - bundle.data["Scenario"]["Site"]["GHP"].get("ghpghx_inputs") not in [None, []] and \ - bundle.data["Scenario"]["Site"]["GHP"].get("ghpghx_response_uuids") in [None, []]: - for ghpghx_inputs in bundle.data["Scenario"]["Site"]["GHP"]["ghpghx_inputs"]: - ghpghxM = GHPGHXInputs(**ghpghx_inputs) - try: - # Validate individual model fields - ghpghxM.clean_fields() - except ValidationError as ve: - ghpghx_inputs_validation_errors += [key + ": " + val[i] + " " for key, val in ve.message_dict.items() for i in range(len(val))] + # # Validate ghpghx_inputs, if applicable + # ghpghx_inputs_validation_errors = [] + # if bundle.data["Scenario"]["Site"].get("GHP") is not None and \ + # bundle.data["Scenario"]["Site"]["GHP"].get("ghpghx_inputs") not in [None, []] and \ + # bundle.data["Scenario"]["Site"]["GHP"].get("ghpghx_response_uuids") in [None, []]: + # for ghpghx_inputs in bundle.data["Scenario"]["Site"]["GHP"]["ghpghx_inputs"]: + # ghpghxM = GHPGHXInputs(**ghpghx_inputs) + # try: + # # Validate individual model fields + # ghpghxM.clean_fields() + # except ValidationError as ve: + # ghpghx_inputs_validation_errors += [key + ": " + val[i] + " " for key, val in ve.message_dict.items() for i in range(len(val))] - try: - input_validator = ValidateNestedInput(bundle.data, ghpghx_inputs_validation_errors=ghpghx_inputs_validation_errors) - except Exception as e: - exc_type, exc_value, exc_traceback = sys.exc_info() - err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ValidateNestedInput', run_uuid=run_uuid) - err.save_to_db() - set_status(data, 'Internal Server Error during input validation. No optimization task has been created. Please check your POST for bad values.') - data['inputs'] = bundle.data - data['messages'] = {} - data['messages']['error'] = err.message # "Unexpected Error." - log.error("Internal Server error: " + err.message) - raise ImmediateHttpResponse(HttpResponse(json.dumps(data), - content_type='application/json', - status=500)) # internal server error - data["inputs"] = input_validator.input_dict - data["messages"] = input_validator.messages - - if not input_validator.isValid: # 400 Bad Request - log.debug("input_validator not valid") - log.debug(json.dumps(data)) - set_status(data, 'Error. No optimization task has been created. See messages for more information. ' \ - 'Note that inputs have default values filled in.') - if saveToDb: - badpost = BadPost(run_uuid=run_uuid, post=json.dumps(bundle.data), errors=str(data['messages'])) - badpost.save() - - raise ImmediateHttpResponse(HttpResponse(json.dumps(data), - content_type='application/json', - status=400)) - log.info('Entering ModelManager') - model_manager = ModelManager() - profiler.profileEnd() - - if saveToDb: - set_status(data, 'Optimizing...') - data['outputs']['Scenario']['Profile']['pre_setup_scenario_seconds'] = profiler.getDuration() - if bundle.request.META.get('HTTP_X_API_USER_ID') or False: - if bundle.request.META.get('HTTP_X_API_USER_ID', '') == '6f09c972-8414-469b-b3e8-a78398874103': - data['outputs']['Scenario']['job_type'] = 'REopt Web Tool' - else: - data['outputs']['Scenario']['job_type'] = 'developer.nrel.gov' - else: - data['outputs']['Scenario']['job_type'] = 'Internal NREL' - test_case = bundle.request.META.get('HTTP_USER_AGENT') or '' - if test_case.startswith('check_http/'): - data['outputs']['Scenario']['job_type'] = 'Monitoring' - try: - model_manager.create_and_save(data) - except Exception as e: - log.error("Could not create and save run_uuid: {}\n Data: {}".format(run_uuid,data)) - exc_type, exc_value, exc_traceback = sys.exc_info() - err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ModelManager.create_and_save', - run_uuid=run_uuid) - err.save_to_db() - set_status(data, "Internal Server Error during saving of inputs. Please see messages.") - data['messages']['error'] = err.message # "Unexpected Error." - log.error("Internal Server error: " + err.message) - raise ImmediateHttpResponse(HttpResponse(json.dumps(data), - content_type='application/json', - status=500)) # internal server error - setup = setup_scenario.s(run_uuid=run_uuid, data=data, api_version=1) - call_back = process_results.s(data=data, meta={'run_uuid': run_uuid, 'api_version': api_version}) - # (use .si for immutable signature, if no outputs were passed from reopt_jobs) - rjm = run_jump_model.s(data=data) - rjm_bau = run_jump_model.s(data=data, bau=True) - - log.info("Starting celery chain") - try: - chain(setup | group(rjm, rjm_bau) | call_back)() - except Exception as e: - if isinstance(e, REoptError): - pass # handled in each task - else: # for every other kind of exception - exc_type, exc_value, exc_traceback = sys.exc_info() - err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='api.py', run_uuid=run_uuid) - err.save_to_db() - set_status(data, 'Internal Server Error. See messages for more.') - if 'messages' not in data.keys(): - data['messages'] = {} - data['messages']['error'] = err.message - log.error("Internal Server error: " + err.message) - raise ImmediateHttpResponse(HttpResponse(json.dumps(data), - content_type='application/json', - status=500)) # internal server error - - log.info("Returning with HTTP 201") - raise ImmediateHttpResponse(HttpResponse(json.dumps({'run_uuid': run_uuid}), - content_type='application/json', status=201)) + # try: + # input_validator = ValidateNestedInput(bundle.data, ghpghx_inputs_validation_errors=ghpghx_inputs_validation_errors) + # except Exception as e: + # exc_type, exc_value, exc_traceback = sys.exc_info() + # err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ValidateNestedInput', run_uuid=run_uuid) + # err.save_to_db() + # set_status(data, 'Internal Server Error during input validation. No optimization task has been created. Please check your POST for bad values.') + # data['inputs'] = bundle.data + # data['messages'] = {} + # data['messages']['error'] = err.message # "Unexpected Error." + # log.error("Internal Server error: " + err.message) + # raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + # content_type='application/json', + # status=500)) # internal server error + # data["inputs"] = input_validator.input_dict + # data["messages"] = input_validator.messages + + # if not input_validator.isValid: # 400 Bad Request + # log.debug("input_validator not valid") + # log.debug(json.dumps(data)) + # set_status(data, 'Error. No optimization task has been created. See messages for more information. ' \ + # 'Note that inputs have default values filled in.') + # if saveToDb: + # badpost = BadPost(run_uuid=run_uuid, post=json.dumps(bundle.data), errors=str(data['messages'])) + # badpost.save() + + # raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + # content_type='application/json', + # status=400)) + # log.info('Entering ModelManager') + # model_manager = ModelManager() + # profiler.profileEnd() + + # if saveToDb: + # set_status(data, 'Optimizing...') + # data['outputs']['Scenario']['Profile']['pre_setup_scenario_seconds'] = profiler.getDuration() + # if bundle.request.META.get('HTTP_X_API_USER_ID') or False: + # if bundle.request.META.get('HTTP_X_API_USER_ID', '') == '6f09c972-8414-469b-b3e8-a78398874103': + # data['outputs']['Scenario']['job_type'] = 'REopt Web Tool' + # else: + # data['outputs']['Scenario']['job_type'] = 'developer.nrel.gov' + # else: + # data['outputs']['Scenario']['job_type'] = 'Internal NREL' + # test_case = bundle.request.META.get('HTTP_USER_AGENT') or '' + # if test_case.startswith('check_http/'): + # data['outputs']['Scenario']['job_type'] = 'Monitoring' + # try: + # model_manager.create_and_save(data) + # except Exception as e: + # log.error("Could not create and save run_uuid: {}\n Data: {}".format(run_uuid,data)) + # exc_type, exc_value, exc_traceback = sys.exc_info() + # err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ModelManager.create_and_save', + # run_uuid=run_uuid) + # err.save_to_db() + # set_status(data, "Internal Server Error during saving of inputs. Please see messages.") + # data['messages']['error'] = err.message # "Unexpected Error." + # log.error("Internal Server error: " + err.message) + # raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + # content_type='application/json', + # status=500)) # internal server error + # setup = setup_scenario.s(run_uuid=run_uuid, data=data, api_version=1) + # call_back = process_results.s(data=data, meta={'run_uuid': run_uuid, 'api_version': api_version}) + # # (use .si for immutable signature, if no outputs were passed from reopt_jobs) + # rjm = run_jump_model.s(data=data) + # rjm_bau = run_jump_model.s(data=data, bau=True) + + # log.info("Starting celery chain") + # try: + # chain(setup | group(rjm, rjm_bau) | call_back)() + # except Exception as e: + # if isinstance(e, REoptError): + # pass # handled in each task + # else: # for every other kind of exception + # exc_type, exc_value, exc_traceback = sys.exc_info() + # err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='api.py', run_uuid=run_uuid) + # err.save_to_db() + # set_status(data, 'Internal Server Error. See messages for more.') + # if 'messages' not in data.keys(): + # data['messages'] = {} + # data['messages']['error'] = err.message + # log.error("Internal Server error: " + err.message) + # raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + # content_type='application/json', + # status=500)) # internal server error + + # log.info("Returning with HTTP 201") + # raise ImmediateHttpResponse(HttpResponse(json.dumps({'run_uuid': run_uuid}), + # content_type='application/json', status=201)) """ NOTES @@ -257,108 +265,116 @@ def obj_create(self, bundle, **kwargs): uuidFilter = UUIDFilter(run_uuid) log.addFilter(uuidFilter) log.info('Beginning run setup') + + # End-of-Life for V1 and V2 - as of March 2024 + data['inputs'] = bundle.data + data['messages'] = {} + data['messages']['error'] = "v1 and v2 of the REopt API are NO longer available; End-of-Life. Please use /stable (v3). See https://github.com/NREL/REopt-Analysis-Scripts/discussions/148 for more details." + raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + content_type='application/json', + status=410)) # "Gone" code for "no longer available" - # Validate ghpghx_inputs, if applicable - ghpghx_inputs_validation_errors = [] - if bundle.data["Scenario"]["Site"].get("GHP") is not None and \ - bundle.data["Scenario"]["Site"]["GHP"].get("ghpghx_inputs") not in [None, []] and \ - bundle.data["Scenario"]["Site"]["GHP"].get("ghpghx_response_uuids") in [None, []]: - for ghpghx_inputs in bundle.data["Scenario"]["Site"]["GHP"]["ghpghx_inputs"]: - ghpghxM = GHPGHXInputs(**ghpghx_inputs) - try: - # Validate individual model fields - ghpghxM.clean_fields() - except ValidationError as ve: - ghpghx_inputs_validation_errors += [key + ": " + val[i] + " " for key, val in ve.message_dict.items() for i in range(len(val))] + # # Validate ghpghx_inputs, if applicable + # ghpghx_inputs_validation_errors = [] + # if bundle.data["Scenario"]["Site"].get("GHP") is not None and \ + # bundle.data["Scenario"]["Site"]["GHP"].get("ghpghx_inputs") not in [None, []] and \ + # bundle.data["Scenario"]["Site"]["GHP"].get("ghpghx_response_uuids") in [None, []]: + # for ghpghx_inputs in bundle.data["Scenario"]["Site"]["GHP"]["ghpghx_inputs"]: + # ghpghxM = GHPGHXInputs(**ghpghx_inputs) + # try: + # # Validate individual model fields + # ghpghxM.clean_fields() + # except ValidationError as ve: + # ghpghx_inputs_validation_errors += [key + ": " + val[i] + " " for key, val in ve.message_dict.items() for i in range(len(val))] - try: - input_validator = ValidateNestedInput(bundle.data, - ghpghx_inputs_validation_errors=ghpghx_inputs_validation_errors, - api_version=2 - ) - except Exception as e: - exc_type, exc_value, exc_traceback = sys.exc_info() - err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ValidateNestedInput', run_uuid=run_uuid) - err.save_to_db() - set_status(data, 'Internal Server Error during input validation. No optimization task has been created. Please check your POST for bad values.') - data['inputs'] = bundle.data - data['messages'] = {} - data['messages']['error'] = err.message # "Unexpected Error." - log.error("Internal Server error: " + err.message) - raise ImmediateHttpResponse(HttpResponse(json.dumps(data), - content_type='application/json', - status=500)) # internal server error - data["inputs"] = input_validator.input_dict - data["messages"] = input_validator.messages - - if not input_validator.isValid: # 400 Bad Request - log.debug("input_validator not valid") - log.debug(json.dumps(data)) - set_status(data, 'Error. No optimization task has been created. See messages for more information. ' \ - 'Note that inputs have default values filled in.') - if saveToDb: - badpost = BadPost(run_uuid=run_uuid, post=json.dumps(bundle.data), errors=str(data['messages'])) - badpost.save() - - raise ImmediateHttpResponse(HttpResponse(json.dumps(data), - content_type='application/json', - status=400)) - log.info('Entering ModelManager') - model_manager = ModelManager() - profiler.profileEnd() - - if saveToDb: - set_status(data, 'Optimizing...') - data['outputs']['Scenario']['Profile']['pre_setup_scenario_seconds'] = profiler.getDuration() - if bundle.request.META.get('HTTP_X_API_USER_ID') or False: - if bundle.request.META.get('HTTP_X_API_USER_ID', '') == '6f09c972-8414-469b-b3e8-a78398874103': - data['outputs']['Scenario']['job_type'] = 'REopt Web Tool' - else: - data['outputs']['Scenario']['job_type'] = 'developer.nrel.gov' - else: - data['outputs']['Scenario']['job_type'] = 'Internal NREL' - test_case = bundle.request.META.get('HTTP_USER_AGENT') or '' - if test_case.startswith('check_http/'): - data['outputs']['Scenario']['job_type'] = 'Monitoring' - try: - model_manager.create_and_save(data) - except Exception as e: - log.error("Could not create and save run_uuid: {}\n Data: {}".format(run_uuid,data)) - exc_type, exc_value, exc_traceback = sys.exc_info() - err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ModelManager.create_and_save', - run_uuid=run_uuid) - err.save_to_db() - set_status(data, "Internal Server Error during saving of inputs. Please see messages.") - data['messages']['error'] = err.message # "Unexpected Error." - log.error("Internal Server error: " + err.message) - raise ImmediateHttpResponse(HttpResponse(json.dumps(data), - content_type='application/json', - status=500)) # internal server error - setup = setup_scenario.s(run_uuid=run_uuid, data=data, api_version=2) - call_back = process_results.s(data=data, meta={'run_uuid': run_uuid, 'api_version': api_version}) - # (use .si for immutable signature, if no outputs were passed from reopt_jobs) - rjm = run_jump_model.s(data=data) - rjm_bau = run_jump_model.s(data=data, bau=True) - - log.info("Starting celery chain") - try: - chain(setup | group(rjm, rjm_bau) | call_back)() - except Exception as e: - if isinstance(e, REoptError): - pass # handled in each task - else: # for every other kind of exception - exc_type, exc_value, exc_traceback = sys.exc_info() - err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='api.py', run_uuid=run_uuid) - err.save_to_db() - set_status(data, 'Internal Server Error. See messages for more.') - if 'messages' not in data.keys(): - data['messages'] = {} - data['messages']['error'] = err.message - log.error("Internal Server error: " + err.message) - raise ImmediateHttpResponse(HttpResponse(json.dumps(data), - content_type='application/json', - status=500)) # internal server error - - log.info("Returning with HTTP 201") - raise ImmediateHttpResponse(HttpResponse(json.dumps({'run_uuid': run_uuid}), - content_type='application/json', status=201)) \ No newline at end of file + # try: + # input_validator = ValidateNestedInput(bundle.data, + # ghpghx_inputs_validation_errors=ghpghx_inputs_validation_errors, + # api_version=2 + # ) + # except Exception as e: + # exc_type, exc_value, exc_traceback = sys.exc_info() + # err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ValidateNestedInput', run_uuid=run_uuid) + # err.save_to_db() + # set_status(data, 'Internal Server Error during input validation. No optimization task has been created. Please check your POST for bad values.') + # data['inputs'] = bundle.data + # data['messages'] = {} + # data['messages']['error'] = err.message # "Unexpected Error." + # log.error("Internal Server error: " + err.message) + # raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + # content_type='application/json', + # status=500)) # internal server error + # data["inputs"] = input_validator.input_dict + # data["messages"] = input_validator.messages + + # if not input_validator.isValid: # 400 Bad Request + # log.debug("input_validator not valid") + # log.debug(json.dumps(data)) + # set_status(data, 'Error. No optimization task has been created. See messages for more information. ' \ + # 'Note that inputs have default values filled in.') + # if saveToDb: + # badpost = BadPost(run_uuid=run_uuid, post=json.dumps(bundle.data), errors=str(data['messages'])) + # badpost.save() + + # raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + # content_type='application/json', + # status=400)) + # log.info('Entering ModelManager') + # model_manager = ModelManager() + # profiler.profileEnd() + + # if saveToDb: + # set_status(data, 'Optimizing...') + # data['outputs']['Scenario']['Profile']['pre_setup_scenario_seconds'] = profiler.getDuration() + # if bundle.request.META.get('HTTP_X_API_USER_ID') or False: + # if bundle.request.META.get('HTTP_X_API_USER_ID', '') == '6f09c972-8414-469b-b3e8-a78398874103': + # data['outputs']['Scenario']['job_type'] = 'REopt Web Tool' + # else: + # data['outputs']['Scenario']['job_type'] = 'developer.nrel.gov' + # else: + # data['outputs']['Scenario']['job_type'] = 'Internal NREL' + # test_case = bundle.request.META.get('HTTP_USER_AGENT') or '' + # if test_case.startswith('check_http/'): + # data['outputs']['Scenario']['job_type'] = 'Monitoring' + # try: + # model_manager.create_and_save(data) + # except Exception as e: + # log.error("Could not create and save run_uuid: {}\n Data: {}".format(run_uuid,data)) + # exc_type, exc_value, exc_traceback = sys.exc_info() + # err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ModelManager.create_and_save', + # run_uuid=run_uuid) + # err.save_to_db() + # set_status(data, "Internal Server Error during saving of inputs. Please see messages.") + # data['messages']['error'] = err.message # "Unexpected Error." + # log.error("Internal Server error: " + err.message) + # raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + # content_type='application/json', + # status=500)) # internal server error + # setup = setup_scenario.s(run_uuid=run_uuid, data=data, api_version=2) + # call_back = process_results.s(data=data, meta={'run_uuid': run_uuid, 'api_version': api_version}) + # # (use .si for immutable signature, if no outputs were passed from reopt_jobs) + # rjm = run_jump_model.s(data=data) + # rjm_bau = run_jump_model.s(data=data, bau=True) + + # log.info("Starting celery chain") + # try: + # chain(setup | group(rjm, rjm_bau) | call_back)() + # except Exception as e: + # if isinstance(e, REoptError): + # pass # handled in each task + # else: # for every other kind of exception + # exc_type, exc_value, exc_traceback = sys.exc_info() + # err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='api.py', run_uuid=run_uuid) + # err.save_to_db() + # set_status(data, 'Internal Server Error. See messages for more.') + # if 'messages' not in data.keys(): + # data['messages'] = {} + # data['messages']['error'] = err.message + # log.error("Internal Server error: " + err.message) + # raise ImmediateHttpResponse(HttpResponse(json.dumps(data), + # content_type='application/json', + # status=500)) # internal server error + + # log.info("Returning with HTTP 201") + # raise ImmediateHttpResponse(HttpResponse(json.dumps({'run_uuid': run_uuid}), + # content_type='application/json', status=201)) \ No newline at end of file diff --git a/reoptjl/api.py b/reoptjl/api.py index 05139d352..ea4348210 100644 --- a/reoptjl/api.py +++ b/reoptjl/api.py @@ -98,7 +98,7 @@ def obj_create(self, bundle, **kwargs): meta = { "run_uuid": run_uuid, "api_version": 3, - "reopt_version": "0.43.0", + "reopt_version": "0.44.0", "status": "Validating..." } bundle.data.update({"APIMeta": meta}) diff --git a/reoptjl/migrations/0055_alter_settings_optimality_tolerance_and_more.py b/reoptjl/migrations/0055_alter_settings_optimality_tolerance_and_more.py new file mode 100644 index 000000000..d1e7d70bf --- /dev/null +++ b/reoptjl/migrations/0055_alter_settings_optimality_tolerance_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.0.7 on 2024-03-28 03:12 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0054_rename_distance_to_emissions_region_meters_electricutilityoutputs_distance_to_avert_emissions_region'), + ] + + operations = [ + migrations.AlterField( + model_name='settings', + name='optimality_tolerance', + field=models.FloatField(default=0.001, help_text="The threshold for the difference between the solution's objective value and the best possible value at which the solver terminates", validators=[django.core.validators.MinValueValidator(5e-06), django.core.validators.MaxValueValidator(0.2)]), + ), + migrations.AlterField( + model_name='settings', + name='solver_name', + field=models.TextField(blank=True, choices=[('HiGHS', 'Highs'), ('Cbc', 'Cbc'), ('SCIP', 'Scip'), ('Xpress', 'Xpress')], default='HiGHS', help_text='Solver used for REopt.jl. Options include HiGHS, Cbc, SCIP, and Xpress'), + ), + migrations.AlterField( + model_name='settings', + name='timeout_seconds', + field=models.IntegerField(default=600, help_text='The number of seconds allowed before the optimization times out.', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(1200)]), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 19bdfba26..2283d816d 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -233,10 +233,10 @@ class TIME_STEP_CHOICES(models.IntegerChoices): FOUR = 4 timeout_seconds = models.IntegerField( - default=420, + default=600, validators=[ MinValueValidator(1), - MaxValueValidator(420) + MaxValueValidator(1200) ], help_text="The number of seconds allowed before the optimization times out." ) @@ -251,7 +251,7 @@ class TIME_STEP_CHOICES(models.IntegerChoices): default=0.001, validators=[ MinValueValidator(5.0e-6), - MaxValueValidator(0.05) + MaxValueValidator(0.20) ], help_text=("The threshold for the difference between the solution's objective value and the best possible " "value at which the solver terminates") @@ -296,7 +296,7 @@ class SOLVERS(models.TextChoices): solver_name = models.TextField( blank=True, - default=SOLVERS.XPRESS, + default=SOLVERS.HIGHS, choices=SOLVERS.choices, help_text=("Solver used for REopt.jl. Options include HiGHS, Cbc, SCIP, and Xpress") ) @@ -1168,7 +1168,7 @@ class ElectricLoadInputs(BaseModel, models.Model): annual_kwh = models.FloatField( validators=[ MinValueValidator(1), - MaxValueValidator(100000000) + MaxValueValidator(10000000000) ], null=True, blank=True, help_text=("Annual site energy consumption from electricity, in kWh, used to scale simulated default building " diff --git a/reoptjl/test/test_job_endpoint.py b/reoptjl/test/test_job_endpoint.py index 8dc8ed566..c945f501b 100644 --- a/reoptjl/test/test_job_endpoint.py +++ b/reoptjl/test/test_job_endpoint.py @@ -33,7 +33,7 @@ def test_multiple_outages(self): self.assertAlmostEqual(sum(sum(np.array(results["Outages"]["unserved_load_per_outage_kwh"]))), 0.0, places=0) # TODO figure out why microgrid_upgrade_capital_cost is about $3000 different locally than on GitHub Actions self.assertAlmostEqual(results["Outages"]["microgrid_upgrade_capital_cost"], 1974429.4, delta=5000.0) - self.assertAlmostEqual(results["Financial"]["lcc"], 59865240.0, delta=5000.0) + self.assertAlmostEqual(results["Financial"]["lcc"], 59865240.0, delta=0.01*results["Financial"]["lcc"]) def test_pv_battery_and_emissions_defaults_from_julia(self): """ diff --git a/werf-giterminism.yaml b/werf-giterminism.yaml index fb1e7fb24..f1802bc8a 100644 --- a/werf-giterminism.yaml +++ b/werf-giterminism.yaml @@ -4,9 +4,9 @@ config: allowEnvVariables: - XPRESS_LICENSE_HOST - NREL_ROOT_CERT_URL_ROOT - dockerfile: - allowUncommitted: - - julia_src/Dockerfile.xpress - allowContextAddFiles: - - julia_src/Dockerfile.xpress - - julia_src/licenseserver + # dockerfile: + # allowUncommitted: + # - julia_src/Dockerfile.xpress + # allowContextAddFiles: + # - julia_src/Dockerfile.xpress + # - julia_src/licenseserver diff --git a/werf.yaml b/werf.yaml index 54450a73c..0e9b7a396 100644 --- a/werf.yaml +++ b/werf.yaml @@ -10,10 +10,10 @@ args: --- image: julia-api context: julia_src/ -dockerfile: Dockerfile.xpress -contextAddFiles: - - Dockerfile.xpress - - licenseserver +dockerfile: Dockerfile +# contextAddFiles: +# - Dockerfile.xpress +# - licenseserver args: XPRESS_LICENSE_HOST: {{ env "XPRESS_LICENSE_HOST" | quote }} NREL_ROOT_CERT_URL_ROOT: {{ env "NREL_ROOT_CERT_URL_ROOT" | quote }}