Skip to content

Commit

Permalink
Merge pull request #421 from NREL/dependabot/pip/oauthlib-3.2.2
Browse files Browse the repository at this point in the history
Bump oauthlib from 3.2.1 to 3.2.2
  • Loading branch information
Bill-Becker authored Aug 9, 2023
2 parents 59cc659 + ee7a620 commit 9970994
Show file tree
Hide file tree
Showing 21 changed files with 70,762 additions and 55 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ Classify the change according to the following categories:
##### Removed
### Patches

## Develop 2023-08-07
### Minor Updates
##### Added
- Add `GHP` to `job` app for v3
- Add `/ghp_efficiency_thermal_factors` endpoint to `job` app for v
##### Changed
- Update a couple of GHP functions to use the GhpGhx.jl package instead of previous Julia scripts and data from v2

## v2.14.0
### Minor Updates
##### Fixed
Expand Down
20 changes: 1 addition & 19 deletions ghpghx/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,7 @@ class GHPGHXInputs(models.Model):
ghx_shank_space_inch = models.FloatField(blank=True,
default=2.5, validators=[MinValueValidator(0.5), MaxValueValidator(100.0)],
help_text="Distance between the centerline of the upwards and downwards u-tube legs [in]")

ground_k_by_climate_zone = {
"1A": 1.029,
"2A": 1.348,
"2B": 0.917,
"3A": 1.243,
"3B": 1.364,
"3C": 1.117,
"4A": 1.023,
"4B": 0.972,
"4C": 1.418,
"5A": 1.726,
"5B": 1.177,
"6A": 0.977,
"6B": 0.981,
"7": 1.271,
"8": 1.189
}

# Default for ground_thermal_conductivity_btu_per_hr_ft_f varies by ASHRAE climate zone
ground_thermal_conductivity_btu_per_hr_ft_f = models.FloatField(blank=True,
default=1.18, validators=[MinValueValidator(0.01), MaxValueValidator(15.0)],
help_text="Thermal conductivity of the ground surrounding the borehole field [Btu/(hr-ft-degF)]")
Expand Down
16 changes: 7 additions & 9 deletions ghpghx/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@
import csv
import json
import pandas as pd
import requests
import logging
from django.http import JsonResponse
from django.http import HttpResponse
from django.template import loader
from django.views.decorators.csrf import csrf_exempt
from ghpghx.resources import UUIDFilter
from ghpghx.models import ModelManager, GHPGHXInputs
from reo.utilities import get_climate_zone_and_nearest_city
from reo.src.load_profile import BuiltInProfile

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -115,15 +114,14 @@ def ground_conductivity(request):
latitude = float(request.GET['latitude']) # need float to convert unicode
longitude = float(request.GET['longitude'])

climate_zone, nearest_city, geometric_flag = get_climate_zone_and_nearest_city(latitude, longitude, BuiltInProfile.default_cities)
k_by_zone = copy.deepcopy(GHPGHXInputs.ground_k_by_climate_zone)
k = k_by_zone[climate_zone]
inputs_dict = {"latitude": latitude,
"longitude": longitude}

julia_host = os.environ.get('JULIA_HOST', "julia")
http_jl_response = requests.get("http://" + julia_host + ":8081/ground_conductivity/", json=inputs_dict)

response = JsonResponse(
{
"climate_zone": climate_zone,
"thermal_conductivity": k
}
http_jl_response.json()
)
return response

Expand Down
74 changes: 73 additions & 1 deletion julia_src/http.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,21 @@ function reopt(req::HTTP.Request)
chp_dict = Dict(key=>getfield(model_inputs.s.chp, key) for key in inputs_with_defaults_from_chp)
else
chp_dict = Dict()
end
if haskey(d, "GHP")
inputs_with_defaults_from_ghp = [
:space_heating_efficiency_thermal_factor,
:cooling_efficiency_thermal_factor
]
ghp_dict = Dict(key=>getfield(model_inputs.s.ghp_option_list[1], key) for key in inputs_with_defaults_from_ghp)
else
ghp_dict = Dict()
end
inputs_with_defaults_set_in_julia = Dict(
"Financial" => Dict(key=>getfield(model_inputs.s.financial, key) for key in inputs_with_defaults_from_easiur),
"ElectricUtility" => Dict(key=>getfield(model_inputs.s.electric_utility, key) for key in inputs_with_defaults_from_avert),
"CHP" => chp_dict
"CHP" => chp_dict,
"GHP" => ghp_dict
)
catch e
@error "Something went wrong in REopt optimization!" exception=(e, catch_backtrace())
Expand Down Expand Up @@ -343,6 +353,66 @@ function simulated_load(req::HTTP.Request)
end
end

function ghp_efficiency_thermal_factors(req::HTTP.Request)
d = JSON.parse(String(req.body))

@info "Getting ghp_efficiency_thermal_factors..."
# The REopt.jl function assumes the REopt input dictionary is being mutated, so put in that form
data = Dict([("Site", Dict([("latitude", d["latitude"]), ("longitude", d["longitude"])])),
("SpaceHeatingLoad", Dict([("doe_reference_name", d["doe_reference_name"])])),
("CoolingLoad", Dict([("doe_reference_name", d["doe_reference_name"])])),
("GHP", Dict())])
error_response = Dict()
nearest_city = ""
climate_zone = ""
try
for factor in ["space_heating", "cooling"]
nearest_city, climate_zone = reoptjl.assign_thermal_factor!(data, factor)
end
catch e
@error "Something went wrong in the ghp_efficiency_thermal_factors" exception=(e, catch_backtrace())
error_response["error"] = sprint(showerror, e)
end
if isempty(error_response)
@info "ghp_efficiency_thermal_factors determined."
response = Dict([("doe_reference_name", d["doe_reference_name"]),
("nearest_city", nearest_city),
("climate_zone", climate_zone),
data["GHP"]...])
return HTTP.Response(200, JSON.json(response))
else
@info "An error occured in the ghp_efficiency_thermal_factors endpoint"
return HTTP.Response(500, JSON.json(error_response))
end
end

function ground_conductivity(req::HTTP.Request)
d = JSON.parse(String(req.body))

@info "Getting ground_conductivity..."
error_response = Dict()
nearest_city = ""
climate_zone = ""
ground_thermal_conductivity = 0.01
try
nearest_city, climate_zone = reoptjl.find_ashrae_zone_city(d["latitude"], d["longitude"], get_zone=true)
ground_thermal_conductivity = GhpGhx.ground_k_by_climate_zone[climate_zone]
catch e
@error "Something went wrong in the ground_conductivity" exception=(e, catch_backtrace())
error_response["error"] = sprint(showerror, e)
end
if isempty(error_response)
@info "ground_conductivity determined."
response = Dict([("climate_zone", climate_zone),
("nearest_city", nearest_city),
("thermal_conductivity", ground_thermal_conductivity)])
return HTTP.Response(200, JSON.json(response))
else
@info "An error occured in the ground_conductivity endpoint"
return HTTP.Response(500, JSON.json(error_response))
end
end

function health(req::HTTP.Request)
return HTTP.Response(200, JSON.json(Dict("Julia-api"=>"healthy!")))
end
Expand All @@ -359,5 +429,7 @@ HTTP.@register(ROUTER, "GET", "/emissions_profile", emissions_profile)
HTTP.@register(ROUTER, "GET", "/easiur_costs", easiur_costs)
HTTP.@register(ROUTER, "GET", "/simulated_load", simulated_load)
HTTP.@register(ROUTER, "GET", "/absorption_chiller_defaults", absorption_chiller_defaults)
HTTP.@register(ROUTER, "GET", "/ghp_efficiency_thermal_factors", ghp_efficiency_thermal_factors)
HTTP.@register(ROUTER, "GET", "/ground_conductivity", ground_conductivity)
HTTP.@register(ROUTER, "GET", "/health", health)
HTTP.serve(ROUTER, "0.0.0.0", 8081, reuseaddr=true)
9 changes: 6 additions & 3 deletions reo/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,12 @@ def setup_pv(pv_dict, latitude, longitude, time_steps_per_hour):
client = TestApiClient()
# Update ground thermal conductivity based on climate zone if not user-input
if not ghpghx_post.get("ground_thermal_conductivity_btu_per_hr_ft_f"):
k_by_zone = copy.deepcopy(GHPGHXInputs.ground_k_by_climate_zone)
climate_zone, nearest_city, geometric_flag = get_climate_zone_and_nearest_city(ghpghx_post["latitude"], ghpghx_post["longitude"], BuiltInProfile.default_cities)
ghpghx_post["ground_thermal_conductivity_btu_per_hr_ft_f"] = k_by_zone[climate_zone]
ground_k_inputs = {"latitude": ghpghx_post["latitude"],
"longitude": ghpghx_post["longitude"]}
# Call to the django view endpoint /ghp_efficiency_thermal_factors which calls the http.jl endpoint
ground_k_resp = client.get(f'/dev/ghpghx/ground_conductivity', data=ground_k_inputs)
ground_k_response = json.loads(ground_k_resp.content)
ghpghx_post["ground_thermal_conductivity_btu_per_hr_ft_f"] = ground_k_response["thermal_conductivity"]

# Hybrid
# Determine if location is heating or cooling dominated
Expand Down
2 changes: 2 additions & 0 deletions reopt_api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
dev_api = Api(api_name='dev')
dev_api.register(DevJob())
dev_api.register(FutureCostsAPI())
dev_api.register(GHPGHXJob())
dev_api.register(ERPJob())


Expand Down Expand Up @@ -102,6 +103,7 @@ def page_not_found(request, url):
path('dev/', include('reoptjl.urls')),
path('dev/', include('resilience_stats.urls_v3plus')),
path('dev/', include('futurecosts.urls')),
path('dev/', include('ghpghx.urls')),
re_path(r'', include(dev_api.urls)),

re_path(r'(.*)', page_not_found, name='404'),
Expand Down
17 changes: 16 additions & 1 deletion reoptjl/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
# from reo.src.profiler import Profiler # TODO use Profiler?
from reoptjl.src.run_jump_model import run_jump_model
from reo.exceptions import UnexpectedError, REoptError
from ghpghx.models import GHPGHXInputs
from django.core.exceptions import ValidationError
from reoptjl.models import APIMeta
log = logging.getLogger(__name__)

Expand Down Expand Up @@ -147,9 +149,22 @@ def obj_create(self, bundle, **kwargs):
if test_case.startswith('check_http/'):
bundle.data['APIMeta']['job_type'] = 'Monitoring'

# Validate ghpghx_inputs, if applicable
ghpghx_inputs_validation_errors = []
if bundle.data.get("GHP") is not None and \
bundle.data["GHP"].get("ghpghx_inputs") not in [None, []] and \
bundle.data["GHP"].get("ghpghx_response_uuids") in [None, []]:
for ghpghx_inputs in bundle.data["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 inputs
try:
input_validator = InputValidator(bundle.data)
input_validator = InputValidator(bundle.data, ghpghx_inputs_validation_errors=ghpghx_inputs_validation_errors)
input_validator.clean_fields() # step 1 check field values
if not input_validator.is_valid:
return400(meta, input_validator)
Expand Down
62 changes: 62 additions & 0 deletions reoptjl/migrations/0022_ghpinputs_ghpoutputs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Generated by Django 4.0.7 on 2023-02-09 02:19

import django.contrib.postgres.fields
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import reoptjl.models


class Migration(migrations.Migration):

dependencies = [
('reoptjl', '0021_merge_20230112_1748'),
]

operations = [
migrations.CreateModel(
name='GHPInputs',
fields=[
('meta', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='GHPInputs', serialize=False, to='reoptjl.apimeta')),
('require_ghp_purchase', models.BooleanField(blank=True, default=False, help_text='Force one of the considered GHP design options.', null=True)),
('installed_cost_heatpump_per_ton', models.FloatField(blank=True, default=1075.0, help_text='Installed heating heat pump cost in $/ton (based on peak coincident cooling+heating thermal load)', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000.0)])),
('heatpump_capacity_sizing_factor_on_peak_load', models.FloatField(blank=True, default=1.1, help_text='Factor on peak heating and cooling load served by GHP used for determining GHP installed capacity', null=True, validators=[django.core.validators.MinValueValidator(1.0), django.core.validators.MaxValueValidator(5.0)])),
('installed_cost_ghx_per_ft', models.FloatField(blank=True, default=14.0, help_text='Installed cost of the ground heat exchanger (GHX) in $/ft of vertical piping', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(100.0)])),
('installed_cost_building_hydronic_loop_per_sqft', models.FloatField(blank=True, default=1.7, help_text='Installed cost of the building hydronic loop per floor space of the site', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(100.0)])),
('om_cost_per_sqft_year', models.FloatField(blank=True, default=-0.51, help_text='Annual GHP incremental operations and maintenance costs in $/ft^2-building/year', null=True, validators=[django.core.validators.MinValueValidator(-100.0), django.core.validators.MaxValueValidator(100.0)])),
('building_sqft', models.FloatField(help_text='Building square footage for GHP/HVAC cost calculations', validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(100000000.0)])),
('space_heating_efficiency_thermal_factor', models.FloatField(blank=True, help_text='Heating efficiency factor (annual average) to account for reduced space heating thermal load from GHP retrofit (e.g. reduced reheat)', null=True, validators=[django.core.validators.MinValueValidator(0.001), django.core.validators.MaxValueValidator(1.0)])),
('cooling_efficiency_thermal_factor', models.FloatField(blank=True, help_text='Cooling efficiency factor (annual average) to account for reduced cooling thermal load from GHP retrofit (e.g. reduced reheat)', null=True, validators=[django.core.validators.MinValueValidator(0.001), django.core.validators.MaxValueValidator(1.0)])),
('ghpghx_inputs', django.contrib.postgres.fields.ArrayField(base_field=models.JSONField(null=True), blank=True, default=list, help_text='GhpGhx.jl inputs/POST to ghpghx app', null=True, size=None)),
('ghpghx_response_uuids', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(blank=True), blank=True, default=list, help_text="List of ghp_uuid's (like run_uuid for REopt) from ghpghx app, used to get GhpGhx.jl run data", null=True, size=None)),
('ghpghx_responses', django.contrib.postgres.fields.ArrayField(base_field=models.JSONField(null=True), blank=True, default=list, help_text='ghpghx app response(s) to re-use a previous GhpGhx.jl run without relying on a database entry', null=True, size=None)),
('can_serve_dhw', models.BooleanField(blank=True, default=False, help_text='If GHP can serve the domestic hot water (DHW) portion of the heating load', null=True)),
('macrs_option_years', models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=5, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable')),
('macrs_bonus_fraction', models.FloatField(blank=True, default=0.8, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])),
('macrs_itc_reduction', models.FloatField(blank=True, default=0.5, help_text='Percent of the ITC value by which depreciable basis is reduced', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])),
('federal_itc_fraction', models.FloatField(blank=True, default=0.3, help_text='Percentage of capital costs that are credited towards federal taxes', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])),
('state_ibi_fraction', models.FloatField(blank=True, default=0, help_text='Percentage of capital costs offset by state incentives', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])),
('state_ibi_max', models.FloatField(blank=True, default=10000000000.0, help_text='Maximum dollar value of state percentage-based capital cost incentive', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000000000.0)])),
('utility_ibi_fraction', models.FloatField(blank=True, default=0, help_text='Percentage of capital costs offset by utility incentives', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])),
('utility_ibi_max', models.FloatField(blank=True, default=10000000000.0, help_text='Maximum dollar value of utility percentage-based capital cost incentive', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000000000.0)])),
('federal_rebate_per_ton', models.FloatField(blank=True, default=0, help_text='Federal rebates based on installed capacity of heat pumps', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])),
('state_rebate_per_ton', models.FloatField(blank=True, default=0, help_text='State rebate based on installed capacity of heat pumps', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])),
('state_rebate_max', models.FloatField(blank=True, default=10000000000.0, help_text='Maximum state rebate', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000000000.0)])),
('utility_rebate_per_ton', models.FloatField(blank=True, default=0, help_text='Utility rebate based on installed capacity of heat pumps', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])),
('utility_rebate_max', models.FloatField(blank=True, default=10000000000.0, help_text='Maximum utility rebate', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000000000.0)])),
],
bases=(reoptjl.models.BaseModel, models.Model),
),
migrations.CreateModel(
name='GHPOutputs',
fields=[
('meta', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='GHPOutputs', serialize=False, to='reoptjl.apimeta')),
('ghp_option_chosen', models.IntegerField(blank=True, null=True)),
('ghpghx_chosen_outputs', models.JSONField(null=True)),
('size_heat_pump_ton', models.FloatField(blank=True, null=True)),
('space_heating_thermal_load_reduction_with_ghp_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, null=True, size=None)),
('cooling_thermal_load_reduction_with_ghp_ton', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, null=True, size=None)),
],
bases=(reoptjl.models.BaseModel, models.Model),
),
]
Loading

0 comments on commit 9970994

Please sign in to comment.