Skip to content

Commit

Permalink
Merge pull request #438 from NREL/develop
Browse files Browse the repository at this point in the history
Energy Resilience Performance tool, IRA defaults updates, CHP defaults, other minor
  • Loading branch information
Bill-Becker authored Mar 17, 2023
2 parents 88be0ff + b770e92 commit 8a3fc70
Show file tree
Hide file tree
Showing 57 changed files with 3,010 additions and 271 deletions.
4 changes: 2 additions & 2 deletions .github/disabled_cbc_workflows/push_test_cbc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Built-in Tests for Push (Cbc in Ubuntu 18.04)
name: Built-in Tests for Push (Cbc in latest Ubuntu)

on:

Expand All @@ -9,7 +9,7 @@ on:
jobs:

test:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pull_request_tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Built-in Tests for Pull Requests (Xpress in Ubuntu 18.04)
name: Built-in Tests for Pull Requests (Xpress in latest Ubuntu)

on:

Expand All @@ -14,7 +14,7 @@ on:
jobs:

test:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/push_tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Built-in Tests for Push (Xpress in Ubuntu 18.04)
name: Built-in Tests for Push (Xpress in latest Ubuntu)

on:

Expand All @@ -10,7 +10,7 @@ on:
jobs:

test:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion .helm/values.staging.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
appEnv: staging
djangoSettingsModule: reopt_api.staging_settings
djangoSettingsModule: reopt_api.staging_settings
80 changes: 64 additions & 16 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,61 @@ Classify the change according to the following categories:
##### Removed
### Patches


## v2.9.0
### Minor Updates
##### Added
- Energy Resilience and Performance Tool:
- Uses functionality added to the REopt Julia package in v0.27.0 to calculate outage survival reliability metrics for a DER scenario, which can be based on the results of a REopt optimization
- Django models **ERPMeta**, **ERPGeneratorInputs**, **ERPPrimeGeneratorInputs**, **ERPElectricStorageInputs**, **ERPPVInputs**, **ERPOutageInputs**, **ERPOutputs**
- `/erp` endpoint to which users POST ERP inputs (calls `ERPJob()`)
- `/erp/<run_uuid>/results` endpoint that GETs the results of an ERP job (calls `erp_results()`)
- `/erp/help` endpoint that GETs the ERP input field info (calls `erp_help()`)
- `/erp/chp_defaults` endpoint that GETs ERP CHP/prime generator input defaults based on parameters `prime_mover`, `is_chp`, and `size_kw` (calls `erp_chp_prime_gen_defaults()`)
- Tests in `resilience+stats/tests/test_erp.py`
- In job/ app (v3), added Financial **year_one_om_costs_before_tax_bau**, **lifecycle_om_costs_after_tax_bau**
- Added field **production_factor_series** to Django models **WindOutputs** and **PVOutputs**
- In **REoptjlMessageOutputs** added a **has_stacktrace** field to denote if response has a stacktrace error or not. Default is False.
- Added access to the multiple outage stochastic/robust modeling capabilities in REopt.jl. Not all inputs and outputs are exposed, but the following are:
- **SiteInputs**: **min_resil_time_steps**
- **ElectricUtilityInputs**: **outage_start_time_steps**, **outage_durations**, **outage_probabilities**
- **OutageOutputs**: **expected_outage_cost**, **max_outage_cost_per_outage_duration**, **unserved_load_series**, **unserved_load_per_outage**, **microgrid_upgrade_capital_cost**, **generator_fuel_used_per_outage**
- Added test using multiple outage modeling
- Add /dev/schedule_stats endpoint
##### Changed
- Update REopt.jl to v0.28.0 for job app (/dev -> v3)
- `/job/chp_defaults` endpoint updated to take optional electric load metrics for non-heating CHP (Prime Generator in UI)
- Changed `/chp_defaults` input of `existing_boiler_production_type` to `hot_water_or_steam`
- `CHP.size_class` starting at 0 for average of other size_classes
- `CHP.max_size` calculated based on heating load or electric load
- In job/ app (v3), changed Financial **breakeven_cost_of_emissions_reduction_per_tonnes_CO2** to **breakeven_cost_of_emissions_reduction_per_tonne_CO2**
- In job/ app (v3), changed default ElectricLoad **year** to 2022 if user provides load data and 2017 if using CRBD
- Changed `scalar_to_vector` helper function to `scalar_or_monthly_to_8760`
- Changed **GeneratorInputs** fields **fuel_slope_gal_per_kwh** and **fuel_intercept_gal_per_hr** to **electric_efficiency_full_load** and **electric_efficiency_half_load** to represent the same fuel burn curve in a different way consistent with **CHPInputs**
- Updated the following default values to job/ app (v3):
- **federal_itc_fraction** to 0.3 (30%) in models **PVInputs**, **WindInputs**, and **CHPInputs**
- **total_itc_fraction** to 0.3 (30%) in models **HotWaterStorageInputs**, **ColdWaterStorageInputs**, and **ElectricStorageInputs**
- ***macrs_bonus_fraction** to 0.8 (80%) in models **PVInputs**, **WindInputs**, **CHPInputs**, PV, **HotWaterStorageInputs**, **ColdWaterStorageInputs**, and **ElectricStorageInputs**
- **macrs_option_years** to 7 years in models **HotWaterStorageInputs** and **ColdWaterStorageInputs**
- In `reo/nested_inputs.py` v2 inputs (`defaults_dict[2]`), updated the following default values in models **ColdThermalStorageInputs**, **HotThermalStorageInputs**
- **macrs_option_years** to 7 (years)
- **macrs_bonus_pct** to 0.8 (80%)
- In `reo/nested_inputs.py` v2 inputs (`defaults_dict[2]`), updated the following default values:
- ColdTES, HotTES: **macrs_option_years** to 7 (years)
- ColdTES, HotTES: ***macrs_bonus_pct** to 0.8 (80%)
- Updated the following default values to job/ app (v3):
- PV, Wind, Storage, CHP, Hot Water Storage, Cold Water Storage, Electric Storage: **federal_itc_fraction(PV,Wind,CHP)** and **total_itc_fraction(Hot Water Storage, Cold Water Storage, Electric Storage)** to 0.3 (30%)
- PV, Wind, Storage, CHP, Hot Water Storage, Cold Water Storage, Electric Storage: ***macrs_bonus_fraction** to 0.8 (80%)
- Hot Water Storage and Cold Water Storage: **macrs_option_years** to 7 years
Use TransactionTestCase instead of TestCase (this avoids whole test being wrapped in a transaction which leads to a TransactionManagementError when doing a database query in the middle)
- Updated ubuntu-18.04 to ubuntu-latest in GitHub push/pull tests because 18.04 was deprecated in GitHub Actions
##### Fixed
- In reo (v2), calculation of `net_capital_costs_plus_om` was previously missing addition sign for fuel charges. Corrected this equation.

## v2.8.0
### Minor Updates
##### Changed
- In `reo/nested_inputs.py` v2 inputs (`defaults_dict[2]`), updated the following default values:
##### Changed
- In `reo/nested_inputs.py` v2 inputs (`defaults_dict[2]`), updated the following default values:
- PV, Wind, Storage, CHP, GHP: **federal_itc_pct** to 0.30 (30%)
- PV, Wind, Storage, CHP, GHP: ***macrs_bonus_pct** to 0.8 (80%)
- The `ghpghx` app and Julia endpoint in `http.jl` uses the [GhpGhx.jl](https://github.com/NREL/GhpGhx.jl) Julia package instead of internal Julia scripts with git submodule for the `tess.so` file
Expand All @@ -38,26 +89,26 @@ Classify the change according to the following categories:

## v2.7.1
### Minor Updates
### Added
##### Added
- In job/ app (v3): Added **addressable_load_fraction** to SpaceHeatingLoad and DomesticHotWaterLoad inputs.
### Changed
##### Changed
- Changed redis service memory settings to mitigate "out of memory" OOM issue we've been getting on production

## v2.7.0
### Minor Updates
### Changed
##### Changed
- In job/ app (v3): Name changes for many outputs/results. Generally, changes are for energy outputs (not costs) that include "year_one", and are changed to annual_ for scalars and to production_to_, thermal_to_ etc. for time series.
- In job/ app (v3): Changed some _bau outputs to align with REopt.jl outputs
### Added
##### Added
- In job/ app (v3): Added **thermal_production_series_mmbtu_per_hour** to CHP results.
##### Removed
- In job/ app (v3): Removed outputs not reported by REopt.jl
#### Fixed
##### Fixed
- In job/views for `/simulated_load` endpoint: Fixed the data type conversion issues between JSON and Julia

## v2.6.0
### Minor Updates
#### Added
##### Added
1. **REoptjlMessageOutputs** model to capture errors and warnings returned by REoptjl during input processing and post optimization
2. Missing output fields for **ExistingBoilerOutputs** model
3. API test `job\test\posts\all_inputs_test.json` to include all input models in a single API test
Expand All @@ -68,8 +119,7 @@ Classify the change according to the following categories:
- add **HotThermalStorageOutputs**
- add **ColdThermalStorageOutputs**
- `0012_coldthermalstorageinputs....` file used to add new models to the db

#### Changed
##### Changed
1. Default values for the following fields were changed to align them with REopt API v2 (i.e. stable, and REopt.jl) defaults. As-is, these values are aligned with REopt v1 defaults. Units were unchanged.
- **FinancialInputs.elec_cost_escalation_rate_fraction** from 0.023 to 0.019
- **FinancialInputs.offtaker_discount_rate_fraction** from 0.083 to 0.0564
Expand Down Expand Up @@ -102,7 +152,7 @@ In `job/validators.py:
- add time series length validation on **CoolingLoadInputs->thermal_loads_ton** and **CoolingLoadInputs->per_time_step_fractions_of_electric_load**
In `job/views.py`:
- add new input/output models to properly save the inputs/outputs

## v2.4.0
### Minor Updates
##### Added
Expand All @@ -122,6 +172,7 @@ In `job/views.py`:
Lookback charge parameters expected from the URDB API call were changed to the non-caplitalized format, so they are now used properly.

## v2.3.0
### Minor Updates
##### Changed
The following name changes were made in the `job/` endpoint and `julia_src/http.jl`:
- Change "_pct" to "_rate_fraction" for input and output names containing "discount", "escalation", and "tax_pct" (financial terms)
Expand Down Expand Up @@ -419,9 +470,8 @@ The default values changed are:
- `reo`: Fixes database query error the occurs when getting production runs created prior to v1.4.0

## v1.4.0 - 2021-01-29
### Major Updates
### Minor Updates
## Added
##### Added
- `reo`/`reopt.jl`: Coincident peak rates and expected time steps can be specified. There can be a single rate and list of time steps. Or there can be multiple CP periods in a year with different rates, and then a set of time steps is specified for each rate. Peak demand occurring during each set of CP time steps is charged at the corresponding CP rate.

- `reo`: Add a new **ElectricTariff** inputs and outputs:
Expand All @@ -433,7 +483,6 @@ The default values changed are:
- **total_coincident_peak_cost_bau_us_dollars**

## v1.3.0 - 2021-01-28
### Major Updates
### Minor Updates
- `reo`: New output **om_and_replacement_present_cost_after_tax_us_dollars**
- `reo`, `*.jl`: New load **LoadProfileBoilerFuel**
Expand Down Expand Up @@ -471,7 +520,6 @@ The default values changed are:


## v1.2.0 - 2021-01-04
### Major Updates
### Minor Updates
##### Added
- `reo`: new inputs **outage_start_time_step** and **outage_end_time_step** to replace deprecated **outage_start_hour** and **outage_end_hour**. The latter are used as time step indices in the code, so for sub-hourly problems they do not have hourly units. For now **outage_start_hour** and **outage_end_hour** are kept in place to preserve backwards-compatibility. Also note that the new inputs are not zero-indexed.
Expand Down
2 changes: 1 addition & 1 deletion config/gunicorn.conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# Note that the app currently has threading issues, so we explicitly want a
# non-thread worker process model.
worker_class = "sync"
threads = 1
threads = 2

# Log access log details to stdout.
accesslog = '-'
Expand Down
4 changes: 2 additions & 2 deletions job/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ def obj_create(self, bundle, **kwargs):
meta = {
"run_uuid": run_uuid,
"api_version": 3,
"reopt_version": "0.18.0",
"status": "validating..."
"reopt_version": "0.28.0",
"status": "Validating..."
}
bundle.data.update({"APIMeta": meta})

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.0.4 on 2022-10-30 18:37

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


class Migration(migrations.Migration):

dependencies = [
('job', '0010_rename_prod_factor_series_pvinputs_production_factor_series_and_more'),
]

operations = [
migrations.AlterField(
model_name='existingboilerinputs',
name='fuel_cost_per_mmbtu',
field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, validators=[django.core.validators.MinValueValidator(0)]), blank=True, default=list, help_text='The ExistingBoiler default operating cost is zero. Please provide this field to include non-zero BAU heating costs.The `fuel_cost_per_mmbtu` can be a scalar, a list of 12 monthly values, or a time series of values for every time step.If a vector of length 8760, 17520, or 35040 is provided, it is adjusted to match timesteps per hour in the optimization.', size=None),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Generated by Django 4.0.4 on 2022-11-02 00:08

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


class Migration(migrations.Migration):

dependencies = [
('job', '0010_rename_prod_factor_series_pvinputs_production_factor_series_and_more'),
]

operations = [
migrations.CreateModel(
name='OutageOutputs',
fields=[
('meta', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='OutageOutputs', serialize=False, to='job.apimeta')),
('expected_outage_cost', models.FloatField(blank=True, help_text='The expected outage cost over the random outages modeled.', null=True)),
('max_outage_cost_per_outage_duration_series', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True), blank=True, default=list, help_text='The maximum outage cost for every outage duration modeled.', size=None)),
('unserved_load_series', django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True), blank=True, default=list, size=None), blank=True, default=list, size=None), blank=True, default=list, help_text='The amount of unserved load in each outage time step for each outage start time and duration. Outage duration changes along the first dimension, outage start time step along the second, and time step in outage along the third.', size=None)),
('unserved_load_per_outage_series', django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True), blank=True, default=list, size=None), blank=True, default=list, help_text='The total unserved load for each outage start time and duration. Outage duration changes along the first dimension and outage start time changes along the second dimention.', size=None)),
('microgrid_upgrade_capital_cost', models.FloatField(blank=True, help_text='Total capital cost of including technologies in the microgrid.', null=True)),
],
bases=(job.models.BaseModel, models.Model),
),
migrations.AddField(
model_name='electricutilityinputs',
name='outage_durations',
field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(blank=True, validators=[django.core.validators.MinValueValidator(1)]), blank=True, default=list, help_text='One-to-one with outage_probabilities. A list of possible time step durations of the grid outage. This input is used for robust optimization across multiple outages. The maximum (over outage_start_time_steps) of the expected value (over outage_durations with probabilities outage_probabilities) of outage cost is included in the objective function minimized by REopt.', size=None),
),
migrations.AddField(
model_name='electricutilityinputs',
name='outage_probabilities',
field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), blank=True, default=list, help_text='One-to-one with outage_durations. The probability of each duration of the grid outage. Defaults to equal probability for each duration. This input is used for robust optimization across multiple outages. The maximum (over outage_start_time_steps) of the expected value (over outage_durations with probabilities outage_probabilities) of outage cost is included in the objective function minimized by REopt.', size=None),
),
migrations.AddField(
model_name='electricutilityinputs',
name='outage_start_time_steps',
field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(blank=True, validators=[django.core.validators.MinValueValidator(1)]), blank=True, default=list, help_text='A list of time steps that the grid outage may start. This input is used for robust optimization across multiple outages. The maximum (over outage_start_time_steps) of the expected value (over outage_durations with probabilities outage_probabilities) of outage cost is included in the objective function minimized by REopt.', size=None),
),
migrations.AddField(
model_name='siteinputs',
name='min_resil_time_steps',
field=models.IntegerField(blank=True, default=0, help_text='The minimum number consecutive timesteps that load must be fully met once an outage begins. Only applies to multiple outage modeling using inputs outage_start_time_steps and outage_durations.', validators=[django.core.validators.MinValueValidator(0)]),
),
migrations.AlterField(
model_name='financialinputs',
name='value_of_lost_load_per_kwh',
field=models.FloatField(blank=True, default=100, help_text='Value placed on unmet site load during grid outages. Units are US dollars per unmet kilowatt-hour. The value of lost load (VoLL) is used to determine outage costs by multiplying VoLL by unserved load for each outage start time and duration. Only applies when modeling outages using the outage_start_time_steps, outage_durations, and outage_probabilities inputs, and do not apply when modeling a single outage using outage_start_time_step and outage_end_time_step.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000.0)]),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 4.0.4 on 2022-11-04 19:08

import django.contrib.postgres.fields
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('job', '0011_outageoutputs_electricutilityinputs_outage_durations_and_more'),
]

operations = [
migrations.RenameField(
model_name='outageoutputs',
old_name='max_outage_cost_per_outage_duration_series',
new_name='max_outage_cost_per_outage_duration',
),
migrations.RenameField(
model_name='outageoutputs',
old_name='unserved_load_per_outage_series',
new_name='unserved_load_per_outage',
),
migrations.AddField(
model_name='outageoutputs',
name='generator_fuel_used_per_outage',
field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True), blank=True, default=list, help_text='Generator fuel used in each outage modeled.', size=None),
),
]
Loading

0 comments on commit 8a3fc70

Please sign in to comment.