Skip to content

Commit ab29dec

Browse files
committed
Merge branch 'scale-peak-loads' into anccr
2 parents df4f358 + 54696b2 commit ab29dec

File tree

8 files changed

+78
-12
lines changed

8 files changed

+78
-12
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ Classify the change according to the following categories:
2626
##### Removed
2727
### Patches
2828

29+
## peak-scaling
30+
### Minor Updates
31+
##### Added
32+
- **ElectricLoad** input **monthly_peaks_kw**. Can be used to scale loads_kw or doe_reference loads to monthly peaks while maintaining monthly energy.
33+
34+
2935
## v3.16.2
3036
### Patches
3137
- Added `CST` and `HighTempThermalStorage` to all/superset inputs test.

julia_src/Manifest.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ git-tree-sha1 = "277df4545cd30a5fc227bf982897ef65d5ea3520"
952952
repo-rev = "elec_util_usage"
953953
repo-url = "https://github.com/NREL/REopt.jl.git"
954954
uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6"
955-
version = "0.55.1"
955+
version = "0.55.0"
956956

957957
[[deps.Random]]
958958
deps = ["SHA"]

julia_src/http.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -560,18 +560,18 @@ function simulated_load(req::HTTP.Request)
560560
end
561561

562562
# Convert vectors which come in as Vector{Any} to Vector{Float} (within Vector{<:Real})
563-
vector_types = ["percent_share", "cooling_pct_share", "monthly_totals_kwh", "monthly_mmbtu",
563+
vector_types = ["percent_share", "cooling_pct_share", "monthly_totals_kwh", "monthly_peaks_kw", "monthly_mmbtu",
564564
"monthly_tonhour", "monthly_fraction", "addressable_load_fraction", "load_profile"]
565565
for key in vector_types
566566
if key in keys(d) && typeof(d[key]) <: Vector{}
567-
d[key] = convert(Vector{Real}, d[key])
567+
d[key] = convert(Vector{Float64}, d[key])
568568
elseif key in keys(d) && key == "addressable_load_fraction"
569569
# Scalar version of input, convert Any to Real
570-
d[key] = convert(Real, d[key])
570+
d[key] = convert(Float64, d[key])
571571
end
572572
end
573573

574-
@info "Getting CRB Loads..."
574+
@info "Getting Loads..."
575575
data = Dict()
576576
error_response = Dict()
577577
try
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Generated by Django 4.2.24 on 2025-10-23 21:21
2+
3+
import django.contrib.postgres.fields
4+
import django.core.validators
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('reoptjl', '0109_remove_ghpoutputs_iterations_auto_guess_and_more'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='electricloadinputs',
17+
name='monthly_peaks_kw',
18+
field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000000.0)]), blank=True, default=list, help_text="Monthly peak power consumption (an array 12 entries long), in kW, used to scale either loads_kw series (with normalize_and_scale_load_profile_input) or the simulated default building load profile for the site's climate zone.Monthly energy is maintained while scaling to the monthly peaks.", size=None),
19+
),
20+
migrations.AlterField(
21+
model_name='electricloadinputs',
22+
name='monthly_totals_kwh',
23+
field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000000.0)]), blank=True, default=list, help_text="Monthly site energy consumption (an array 12 entries long), in kWh, used to scale either loads_kw series (with normalize_and_scale_load_profile_input) or the simulated default building load profile for the site's climate zone", size=None),
24+
),
25+
migrations.AlterField(
26+
model_name='electricloadinputs',
27+
name='normalize_and_scale_load_profile_input',
28+
field=models.BooleanField(blank=True, default=False, help_text='Takes the input loads_kw and normalizes and scales it to the inputs annual_kwh, monthly_totals_kwh, and/or monthly_peaks_kw.'),
29+
),
30+
]

reoptjl/models.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,8 +1387,22 @@ class ElectricLoadInputs(BaseModel, models.Model):
13871387
blank=True
13881388
),
13891389
default=list, blank=True,
1390-
help_text=("Monthly site energy consumption from electricity series (an array 12 entries long), in kWh, used "
1391-
"to scale simulated default building load profile for the site's climate zone")
1390+
help_text=("Monthly site energy consumption (an array 12 entries long), in kWh, used to scale either loads_kw series "
1391+
"(with normalize_and_scale_load_profile_input) or the simulated default building load profile for the site's climate zone")
1392+
)
1393+
monthly_peaks_kw = ArrayField(
1394+
models.FloatField(
1395+
validators=[
1396+
MinValueValidator(0),
1397+
MaxValueValidator(1.0e8)
1398+
],
1399+
blank=True
1400+
),
1401+
default=list, blank=True,
1402+
help_text=("Monthly peak power consumption (an array 12 entries long), in kW, used to scale either loads_kw series "
1403+
"(with normalize_and_scale_load_profile_input) or the simulated default building load profile for the site's climate zone."
1404+
"Monthly energy is maintained while scaling to the monthly peaks."
1405+
)
13921406
)
13931407
loads_kw = ArrayField(
13941408
models.FloatField(blank=True),
@@ -1401,7 +1415,7 @@ class ElectricLoadInputs(BaseModel, models.Model):
14011415
normalize_and_scale_load_profile_input = models.BooleanField(
14021416
blank=True,
14031417
default=False,
1404-
help_text=("Takes the input loads_kw and normalizes and scales it to annual or monthly energy inputs.")
1418+
help_text=("Takes the input loads_kw and normalizes and scales it to the inputs annual_kwh, monthly_totals_kwh, and/or monthly_peaks_kw.")
14051419
)
14061420
critical_loads_kw = ArrayField(
14071421
models.FloatField(blank=True),

reoptjl/test/posts/all_inputs_test.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"doe_reference_name": "MidriseApartment",
3636
"year": 2017,
3737
"monthly_totals_kwh": [],
38+
"monthly_peaks_kw": [],
3839
"loads_kw": [],
3940
"critical_loads_kw": [],
4041
"loads_kw_is_net": true,

reoptjl/test/posts/validator_post.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@
4444
1200,
4545
1200
4646
],
47+
"monthly_peaks_kw": [
48+
1.5,
49+
1.5,
50+
1.5,
51+
1.5,
52+
1.5,
53+
1.5,
54+
1.5,
55+
1.5,
56+
1.5,
57+
1.5,
58+
1.5,
59+
1.5
60+
],
4761
"outage_start_time_step": 11,
4862
"outage_end_time_step": 501,
4963
"critical_load_fraction": 0.5,

reoptjl/views.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,10 +582,10 @@ def simulated_load(request):
582582
# Required for GET - will throw a Missing Error if not included
583583
if request.method == "GET":
584584
valid_keys = ["doe_reference_name","industrial_reference_name","latitude","longitude","load_type","percent_share","annual_kwh",
585-
"monthly_totals_kwh","annual_mmbtu","annual_fraction","annual_tonhour","monthly_tonhour",
585+
"monthly_totals_kwh","monthly_peaks_kw","annual_mmbtu","annual_fraction","annual_tonhour","monthly_tonhour",
586586
"monthly_mmbtu","monthly_fraction","max_thermal_factor_on_peak_load","chiller_cop",
587587
"addressable_load_fraction", "cooling_doe_ref_name", "cooling_pct_share", "boiler_efficiency",
588-
"normalize_and_scale_load_profile_input", "year"]
588+
"normalize_and_scale_load_profile_input", "year", "time_steps_per_hour"]
589589
for key in request.GET.keys():
590590
k = key
591591
if "[" in key:
@@ -658,7 +658,7 @@ def simulated_load(request):
658658
# TODO make year optional?
659659
inputs[field] = data[field]
660660
if inputs["load_type"] == "electric":
661-
for energy in ["annual_kwh", "monthly_totals_kwh"]:
661+
for energy in ["annual_kwh", "monthly_totals_kwh", "monthly_peaks_kw"]:
662662
if data.get(energy) is not None:
663663
inputs[energy] = data.get(energy)
664664
elif inputs["load_type"] in ["space_heating", "domestic_hot_water", "process_heat"]:
@@ -669,7 +669,8 @@ def simulated_load(request):
669669
for energy in ["annual_tonhour", "monthly_tonhour"]:
670670
if data.get(energy) is not None:
671671
inputs[energy] = data.get(energy)
672-
# TODO cooling, not in REopt.jl yet
672+
if len(inputs["load_profile"]) != 8760:
673+
inputs["time_steps_per_hour"] = data["time_steps_per_hour"]
673674

674675
# TODO consider changing all requests to POST so that we don't have to do the weird array processing like percent_share[0], [1], etc?
675676
# json.dump(inputs, open("sim_load_post.json", "w"))

0 commit comments

Comments
 (0)