Standardized Performance Outputs: Generic Storage & Control#493
Standardized Performance Outputs: Generic Storage & Control#493johnjasa merged 88 commits intoNatLabRockies:developfrom
Conversation
…ART into converter_baseclass
johnjasa
left a comment
There was a problem hiding this comment.
Thanks for this, Elenya! I think it's a great step in standardizing some of these storage and control models -- there's a lot of complex interactions here.
I've left some comments and pushed up minor changes. The comments are mostly questions to provoke introspection into the approaches used here or minor suggestions for clarity, nothing too major.
| # Estimate the rated commodity production as the maximum value from the commodity_set_point | ||
| outputs[f"rated_{self.commodity}_production"] = inputs[f"{self.commodity}_set_point"].max() |
There was a problem hiding this comment.
Is this the best way of getting the rated production? If the set point never reaches the actual maximum of the system, is this a problem and could lead to confusing metrics? Legitimately asking, mostly about the generality of this and if it works well in all cases.
There was a problem hiding this comment.
Idk a better way - but this is just a pass-through component. In this case, it'd be better for this to be done in the DemandOpenLoopStorageController instead, but then we wouldn't be consistent about whether these outputs are standardized in performance models vs control strategies which would lead to errors if someone used a controller with the standard outputs with a storage model that has the standard outputs. I think issue #498 explains this though.
There was a problem hiding this comment.
I don't think we should determine rated production this way. I think both the storage and the controller need to require the technology rated production like we do with other systems. For storage, the charge and discharge rates and the rated storage capacity should be given at a minimum I think now that we are using the set_point paradigm, even for the generic pass-through component.
There was a problem hiding this comment.
Does this mean you want the SimpleGenericStorage then to have inputs for charge rate and capacity?
There was a problem hiding this comment.
Yeah, I agree with Jared on this that it makes sense for the controller and performance models to have access to this information. Even if we don't use it, it would need to be here to standardize across models that do use it.
There was a problem hiding this comment.
okay - I added max_charge_rate as an input to the SimpleGenericStorage model and used the max_charge_rate to calculate the capacity factor and rated commodity produced
| # Calculate the total and annual commodity produced | ||
| outputs[f"total_{self.commodity}_produced"] = outputs[f"{self.commodity}_out"].sum() | ||
| outputs[f"annual_{self.commodity}_produced"] = outputs[ | ||
| f"total_{self.commodity}_produced" | ||
| ] * (1 / self.fraction_of_year_simulated) | ||
|
|
||
| # Calculate the maximum commodity production over the simulation | ||
| max_production = ( | ||
| inputs[f"{self.commodity}_set_point"].max() * self.n_timesteps * (self.dt / 3600) | ||
| ) | ||
|
|
||
| outputs["capacity_factor"] = outputs[f"total_{self.commodity}_produced"] / max_production |
There was a problem hiding this comment.
Tagging @jaredthomas68 and @genevievestarke for special attention to this math to make sure it matches what you expect.
There was a problem hiding this comment.
The capacity factor should be based on rated production in the denominator, not max production. Rated production should be a user input to the system (see previous comment).
There was a problem hiding this comment.
Capacity factors for storage systems (at least batteries), as far as I understand, are typically based on the nameplate discharge rate of the system.
cp = total_product_discharged_in_time_period / (name_plate_discharge_rate*time_period_duration) # of course make sure units make senseOf course, the above leads to some fairly low capacity factors, like about 0.167 for a 4 hour battery discharged daily as discussed in the ATB
There was a problem hiding this comment.
@jaredthomas68 - the SimpleGenericStorage has no inputs related to nameplate discharge rate or anything. That information is only available in the DemandOpenLoopStorageController. This is captured in Issue #498.
There was a problem hiding this comment.
this has been updated - please see the new equations to calculate rated_commodity_production and capacity_factor in the SimpleGenericStorage
There was a problem hiding this comment.
I like this change, thank you.
| self.commodity = self.config.commodity_name | ||
| self.commodity_rate_units = self.config.commodity_units | ||
| self.commodity_amount_units = f"({self.commodity_rate_units})*h" |
There was a problem hiding this comment.
Move this to initialize to match other components?
There was a problem hiding this comment.
the tech config is not accessbile at the initialize(). I get this error:
RuntimeError: StorageAutoSizingModel: Option 'tech_config' is required but has not been set.
| self.commodity = self.config.commodity_name | ||
| self.commodity_rate_units = self.config.commodity_units | ||
| self.commodity_amount_units = f"({self.commodity_rate_units})*h" |
There was a problem hiding this comment.
Move to initialize to match other components?
There was a problem hiding this comment.
the tech config is not accessbile at the initialize(). I get this error:
RuntimeError: StorageAutoSizingModel: Option 'tech_config' is required but has not been set.
| # Step 2: Simulate the storage performance based on the sizes calculated | ||
|
|
||
| # Initialize output arrays of charge and discharge | ||
| discharge_storage = np.zeros(self.n_timesteps) | ||
| charge_storage = np.zeros(self.n_timesteps) | ||
| output_array = np.zeros(self.n_timesteps) | ||
|
|
||
| # Initialize state-of-charge value as the soc at t=0 | ||
| soc = deepcopy(commodity_storage_soc[0]) | ||
|
|
||
| # Simulate a basic storage component | ||
| for t, demand_t in enumerate(commodity_demand): | ||
| input_flow = commodity_production[t] | ||
| available_charge = float(commodity_storage_capacity_kg - soc) | ||
| available_discharge = float(soc) | ||
|
|
||
| # If demand is greater than the input, discharge storage | ||
| if demand_t > input_flow: | ||
| # Discharge storage to meet demand. | ||
| discharge_needed = demand_t - input_flow | ||
| discharge = min(discharge_needed, available_discharge, storage_max_fill_rate) | ||
| # Update SOC | ||
| soc -= discharge | ||
|
|
||
| discharge_storage[t] = discharge | ||
| output_array[t] = input_flow + discharge | ||
|
|
||
| # If input is greater than the demand, charge storage | ||
| else: | ||
| # Charge storage with unused input | ||
| unused_input = input_flow - demand_t | ||
| charge = min(unused_input, available_charge, storage_max_fill_rate) | ||
| # Update SOC | ||
| soc += charge | ||
|
|
||
| charge_storage[t] = charge | ||
| output_array[t] = demand_t |
There was a problem hiding this comment.
The overall reason for this code logic to be necessary here is unclear to me. Is it because this component is only meant to be used with the passthrough controller, so we need to actually calculate these charge and discharge timeseries somewhere because it's not done in the controller, and that's here?
This is the biggest question I have where chatting about it might be useful (I just messaged you).
There was a problem hiding this comment.
If the dispatch logic is needed, perhaps the sizing should be part of the controller instead of the storage model? @jmartin4u
There was a problem hiding this comment.
See issue #498. This PR is not intended to fix the discrepancies between the storage control strategies and the storage performance models, but it sure makes those discrepancies more apparent. I agree that this could be refactored in the future but this PR intended to just make consistent outputs from performance models.
There was a problem hiding this comment.
Got it, thanks for tagging the issue
jaredthomas68
left a comment
There was a problem hiding this comment.
Heading in the right direction. We need to correct some math and inputs and also discuss what lives where.
| # Estimate the rated commodity production as the maximum value from the commodity_set_point | ||
| outputs[f"rated_{self.commodity}_production"] = inputs[f"{self.commodity}_set_point"].max() |
There was a problem hiding this comment.
I don't think we should determine rated production this way. I think both the storage and the controller need to require the technology rated production like we do with other systems. For storage, the charge and discharge rates and the rated storage capacity should be given at a minimum I think now that we are using the set_point paradigm, even for the generic pass-through component.
| outputs[f"total_{self.commodity}_produced"] = outputs[f"{self.commodity}_out"].sum() | ||
| outputs[f"annual_{self.commodity}_produced"] = outputs[ | ||
| f"total_{self.commodity}_produced" | ||
| ] * (1 / self.fraction_of_year_simulated) |
There was a problem hiding this comment.
I think just dividing will be more clear
| ] * (1 / self.fraction_of_year_simulated) | |
| ]/self.fraction_of_year_simulated |
| # Calculate the total and annual commodity produced | ||
| outputs[f"total_{self.commodity}_produced"] = outputs[f"{self.commodity}_out"].sum() | ||
| outputs[f"annual_{self.commodity}_produced"] = outputs[ | ||
| f"total_{self.commodity}_produced" | ||
| ] * (1 / self.fraction_of_year_simulated) | ||
|
|
||
| # Calculate the maximum commodity production over the simulation | ||
| max_production = ( | ||
| inputs[f"{self.commodity}_set_point"].max() * self.n_timesteps * (self.dt / 3600) | ||
| ) | ||
|
|
||
| outputs["capacity_factor"] = outputs[f"total_{self.commodity}_produced"] / max_production |
There was a problem hiding this comment.
The capacity factor should be based on rated production in the denominator, not max production. Rated production should be a user input to the system (see previous comment).
| max_production = ( | ||
| inputs[f"{self.commodity}_set_point"].max() * self.n_timesteps * (self.dt / 3600) | ||
| ) |
There was a problem hiding this comment.
We should calculate the maximum theoretical production based on name-plate capacity based on the user inputs (see comment above), not the actual in the given scenario as is being done here.
| # Calculate the total and annual commodity produced | ||
| outputs[f"total_{self.commodity}_produced"] = outputs[f"{self.commodity}_out"].sum() | ||
| outputs[f"annual_{self.commodity}_produced"] = outputs[ | ||
| f"total_{self.commodity}_produced" | ||
| ] * (1 / self.fraction_of_year_simulated) | ||
|
|
||
| # Calculate the maximum commodity production over the simulation | ||
| max_production = ( | ||
| inputs[f"{self.commodity}_set_point"].max() * self.n_timesteps * (self.dt / 3600) | ||
| ) | ||
|
|
||
| outputs["capacity_factor"] = outputs[f"total_{self.commodity}_produced"] / max_production |
There was a problem hiding this comment.
Capacity factors for storage systems (at least batteries), as far as I understand, are typically based on the nameplate discharge rate of the system.
cp = total_product_discharged_in_time_period / (name_plate_discharge_rate*time_period_duration) # of course make sure units make senseOf course, the above leads to some fairly low capacity factors, like about 0.167 for a 4 hour battery discharged daily as discussed in the ATB
| # Step 2: Simulate the storage performance based on the sizes calculated | ||
|
|
||
| # Initialize output arrays of charge and discharge | ||
| discharge_storage = np.zeros(self.n_timesteps) | ||
| charge_storage = np.zeros(self.n_timesteps) | ||
| output_array = np.zeros(self.n_timesteps) | ||
|
|
||
| # Initialize state-of-charge value as the soc at t=0 | ||
| soc = deepcopy(commodity_storage_soc[0]) | ||
|
|
||
| # Simulate a basic storage component | ||
| for t, demand_t in enumerate(commodity_demand): | ||
| input_flow = commodity_production[t] | ||
| available_charge = float(commodity_storage_capacity_kg - soc) | ||
| available_discharge = float(soc) | ||
|
|
||
| # If demand is greater than the input, discharge storage | ||
| if demand_t > input_flow: | ||
| # Discharge storage to meet demand. | ||
| discharge_needed = demand_t - input_flow | ||
| discharge = min(discharge_needed, available_discharge, storage_max_fill_rate) | ||
| # Update SOC | ||
| soc -= discharge | ||
|
|
||
| discharge_storage[t] = discharge | ||
| output_array[t] = input_flow + discharge | ||
|
|
||
| # If input is greater than the demand, charge storage | ||
| else: | ||
| # Charge storage with unused input | ||
| unused_input = input_flow - demand_t | ||
| charge = min(unused_input, available_charge, storage_max_fill_rate) | ||
| # Update SOC | ||
| soc += charge | ||
|
|
||
| charge_storage[t] = charge | ||
| output_array[t] = demand_t |
There was a problem hiding this comment.
If the dispatch logic is needed, perhaps the sizing should be part of the controller instead of the storage model? @jmartin4u
| model.prob.get_val("finance_subgroup_nh3.total_opex_adjusted")[0], rel=1e-6 | ||
| ) | ||
| == 79744581.00552343 | ||
| == 79421959.33317558 |
There was a problem hiding this comment.
I don't think the test values should change for these code changes. Maybe you can convince me though. As I see it all the changes should be more a matter of where calculations are done and what components connect to what rather than changing any actual calculations.
There was a problem hiding this comment.
Section 6 of the PR description has a very thorough explanation of why the values changed.
There was a problem hiding this comment.
That is a very thorough explanation, I'm sold. Thank you.
…/GreenHEART into converter_baseclass_storage
There was a problem hiding this comment.
Overall, I think this looks really great, and I think that this is a great addition to the code!
The two blocking comments I have are
- I think we should add charge/discharge rate and total storage capacity as inputs to the generic storage model
- I think we need to distinguish between input power and dispatched power in the generic storage model. I think it's currently total commodity out instead of just storage commodity out. We may have to add
storage commodity outas an output from the demand open loop controller to differentiate these since the generic storage doesn't have that info.
| # Estimate the rated commodity production as the maximum value from the commodity_set_point | ||
| outputs[f"rated_{self.commodity}_production"] = inputs[f"{self.commodity}_set_point"].max() |
There was a problem hiding this comment.
Yeah, I agree with Jared on this that it makes sense for the controller and performance models to have access to this information. Even if we don't use it, it would need to be here to standardize across models that do use it.
| outputs[f"rated_{self.commodity}_production"] = inputs[f"{self.commodity}_set_point"].max() | ||
|
|
||
| # Calculate the total and annual commodity produced | ||
| outputs[f"total_{self.commodity}_produced"] = outputs[f"{self.commodity}_out"].sum() |
There was a problem hiding this comment.
I think this should be just the discharge:
[x for x in outputs[f"{self.commodity}_out"] if x > 0]
There was a problem hiding this comment.
Then I think the rest of the calculations would work
There was a problem hiding this comment.
Also, is outputs[f"{self.commodity}_out"] just the battery power, or the battery power + the incoming power?
There was a problem hiding this comment.
The DemandOpenLoopStorageController outputs commodity_set_point which is equal to commodity_set_point = incoming power - power_to_charge + power_discharged - excess_power
Since the SimpleGenericStorage is essentially a pass-through component, where commodity_out = commodity_set_point.
There was a problem hiding this comment.
Ok, I think my previous comment is addressed. Based on this CF calculation, I thought this should take only the positive values, but because this is total energy and not just the storage energy, it's always positive. I think this is fine for now, but should be addressed with #521
| commodity (str): | ||
| The name of the commodity being stored (e.g., "electricity", "hydrogen"). | ||
| commodity_rate_units (str): | ||
| The units of the commodity being stored (e.g., "kW", "kg"). |
There was a problem hiding this comment.
Minor doc correction:
| The units of the commodity being stored (e.g., "kW", "kg"). | |
| The flow rate units of the commodity being stored (e.g., "kW", "kg/h"). |
| cost_per_production (float): | ||
| The cost to use the incoming produced commodity (in $/commodity_rate_units). | ||
| cost_per_charge (float): | ||
| The cost per unit of charging the storage (in $/commodity_rate_units). | ||
| cost_per_discharge (float): | ||
| The cost per unit of discharging the storage (in $/commodity_rate_units). | ||
| commodity_met_value (float): | ||
| The penalty for not meeting the desired load demand (in $/commodity_rate_units). |
There was a problem hiding this comment.
These don't appear to all be used, and I'm not sure the ratings make sense. I think this should possibly be addressed in a future PR, but tagging here to keep connected. Related to #527
There was a problem hiding this comment.
I agree about the units, but I believe they are all used in the dispatch. We can chat about where they're being used, if that's helpful!
| @@ -51,7 +60,7 @@ def compute(self, inputs, outputs): | |||
|
|
|||
| # Calculate the maximum commodity production over the simulation | |||
There was a problem hiding this comment.
Comment should be updated to state that it is the max theoretical production
| # Calculate the total and annual commodity produced | ||
| outputs[f"total_{self.commodity}_produced"] = outputs[f"{self.commodity}_out"].sum() | ||
| outputs[f"annual_{self.commodity}_produced"] = outputs[ | ||
| f"total_{self.commodity}_produced" | ||
| ] * (1 / self.fraction_of_year_simulated) | ||
|
|
||
| # Calculate the maximum commodity production over the simulation | ||
| max_production = ( | ||
| inputs[f"{self.commodity}_set_point"].max() * self.n_timesteps * (self.dt / 3600) | ||
| ) | ||
|
|
||
| outputs["capacity_factor"] = outputs[f"total_{self.commodity}_produced"] / max_production |
There was a problem hiding this comment.
I like this change, thank you.
| # Step 2: Simulate the storage performance based on the sizes calculated | ||
|
|
||
| # Initialize output arrays of charge and discharge | ||
| discharge_storage = np.zeros(self.n_timesteps) | ||
| charge_storage = np.zeros(self.n_timesteps) | ||
| output_array = np.zeros(self.n_timesteps) | ||
|
|
||
| # Initialize state-of-charge value as the soc at t=0 | ||
| soc = deepcopy(commodity_storage_soc[0]) | ||
|
|
||
| # Simulate a basic storage component | ||
| for t, demand_t in enumerate(commodity_demand): | ||
| input_flow = commodity_production[t] | ||
| available_charge = float(commodity_storage_capacity_kg - soc) | ||
| available_discharge = float(soc) | ||
|
|
||
| # If demand is greater than the input, discharge storage | ||
| if demand_t > input_flow: | ||
| # Discharge storage to meet demand. | ||
| discharge_needed = demand_t - input_flow | ||
| discharge = min(discharge_needed, available_discharge, storage_max_fill_rate) | ||
| # Update SOC | ||
| soc -= discharge | ||
|
|
||
| discharge_storage[t] = discharge | ||
| output_array[t] = input_flow + discharge | ||
|
|
||
| # If input is greater than the demand, charge storage | ||
| else: | ||
| # Charge storage with unused input | ||
| unused_input = input_flow - demand_t | ||
| charge = min(unused_input, available_charge, storage_max_fill_rate) | ||
| # Update SOC | ||
| soc += charge | ||
|
|
||
| charge_storage[t] = charge | ||
| output_array[t] = demand_t |
There was a problem hiding this comment.
Got it, thanks for tagging the issue
There was a problem hiding this comment.
It looks like you need to backmerge from develop
| @@ -51,7 +60,7 @@ def compute(self, inputs, outputs): | |||
|
|
|||
| # Calculate the maximum commodity production over the simulation | |||
| max_production = ( | |||
There was a problem hiding this comment.
| max_production = ( | |
| rated_production = ( |
genevievestarke
left a comment
There was a problem hiding this comment.
This looks good to me! I suggested on change in the comments to clarify what's being done. Otherwise, good to merge!
| # Pass the commodity_out as the commodity_set_point | ||
| outputs[f"{self.commodity}_out"] = inputs[f"{self.commodity}_set_point"] | ||
|
|
||
| # Estimate the rated commodity production as the maximum value from the commodity_set_point |
There was a problem hiding this comment.
| # Estimate the rated commodity production as the maximum value from the commodity_set_point | |
| # Set the rated commodity production from the max_charg_rate input |
| outputs[f"rated_{self.commodity}_production"] = inputs[f"{self.commodity}_set_point"].max() | ||
|
|
||
| # Calculate the total and annual commodity produced | ||
| outputs[f"total_{self.commodity}_produced"] = outputs[f"{self.commodity}_out"].sum() |
There was a problem hiding this comment.
Ok, I think my previous comment is addressed. Based on this CF calculation, I thought this should take only the positive values, but because this is total energy and not just the storage energy, it's always positive. I think this is fine for now, but should be addressed with #521
johnjasa
left a comment
There was a problem hiding this comment.
Fantastic PR, Elenya, and thank you all for iterating on best approaches until you reached consensus. Love seeing that.
* Ammonia Synloop: Units fix and small changes (#518) * updated electricity units in synloop * added feedstock consumption profiles and updated cost model to use capacity input * added tests/subtests for ammonia synloop * udpated electricity units to kW * fixed nitrogen purge gas calc (#520) * Minor fix in post-processing to save capacity factors (#519) * minor update to sql_to_csv to save capacity factors * simplified logic handling capacity factor in postprocessing * Apply suggestion from @johnjasa --------- Co-authored-by: John Jasa <john.jasa@nrel.gov> * Enable load following optimization dispatch with Pyomo (#407) * include code from usage: pyomo [-h] [--version] {build-extensions,convert,download-extensions,help,install-extras,model-viewer,run,solve,test-solvers} ... This is the main driver for the Pyomo optimization software. options: -h, --help show this help message and exit --version show program's version number and exit subcommands: {build-extensions,convert,download-extensions,help,install-extras,model-viewer,run,solve,test-solvers} build-extensions Build compiled extension modules convert Convert a Pyomo model to another format download-extensions Download compiled extension modules help Print help information. install-extras Install "extra" packages that Pyomo can leverage. model-viewer Run the Pyomo model viewer run Execute a command from the Pyomo bin (or Scripts) directory. solve Optimize a model test-solvers Test Pyomo solvers ------------------------------------------------------------------------- Pyomo supports a variety of modeling and optimization capabilities, which are executed either as subcommands of 'pyomo' or as separate commands. Use the 'help' subcommand to get information about the capabilities installed with Pyomo. Additionally, each subcommand supports independent command-line options. Use the -h option to print details for a subcommand. For example, type pyomo solve -h to print information about the `solve` subcommand. branch that needs to be saved for later * include storage rule file * Halfway there for pyomo opt * Add first objective function * Updated dispatch optimization framework - add hybrid dispatch rule * Adding hybrid linking constraints and connecting variables in pyomo min operating costs framework * Final structural changes * Fix import statement * Fix imports and setter method * First draft of running code * Update example * test * fix precommits * Fixing merge errors * Minor spelling changes * Update example * Update controller problem state method from Elenya * Update example and changelog * Clean up pyomo storage baseclass file * Cleanups to feature/pyomo opt (#2) * refactored DispatchProblemState * updated tech config and removed pysam options file * minor cleanups to DispatchProblemState * minor updates to generic_converter_opt * initial cleanups to hybrid_rule.py * minor cleanups to pyomo_storage_rule_min_operating_cost * extra small cleanups to generic_converter_opt * added storage capacities as inputs to optimized controller * updated use of n_control_window and n_horizon_window * Enable heuristic dispatch to run with new pyomo changes * Clean up added files and example * Adding first tests - do not pass yet * Update docs and rename example * Align naming with develop branch * Update Ex 02 and update pyomo_controllers with naming in develop * updated other example tech configs * ran precommit on some files * precommit on pyomo_controllers.py * Update test formatting * Update pyomo storage rule for test * Fix SOC linking bug * Testing update - partial * Make new test for optimized pyomo dispatch * Update optimal controller test * Update test with new site definition * Update example for merging in develop * Minor updates to optimized dispatch * PR updates from comments * Add last file after merge issue * Update example * Made plots slightly larger * Update h2integrate/control/control_strategies/controller_opt_problem_state.py Apply comment suggestions Co-authored-by: John Jasa <john.jasa@nrel.gov> * Update h2integrate/control/control_strategies/controller_opt_problem_state.py Apply comment suggestions Co-authored-by: John Jasa <john.jasa@nrel.gov> * Update h2integrate/control/control_rules/hybrid_rule.py Apply comment suggestions Co-authored-by: John Jasa <john.jasa@nrel.gov> * Cleaning up pyomo_controllers * Updated docstrings and battery mentions * Initial init docs string and example update * Update note about incentivizing charging in objective function * Update generation and load variable definitions * Update docs/control/pyomo_controllers.md Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> * Update doc strings for updated_initial_soc parameter * Make time_weighting_factor and round_digits not hardcoded * remove round_digits from pyomo_rule_baseclass * Updating controller names * Fixed name check for controllers * Updated optimal controller test * remove unused properties * Update example to run with new class definitions * Fix converter name in test * Fix ruff formatting * Update doc strings for pyomo model classes * Rename files to be more consistent and descriptive * Update comments in the init portions of dispatch for parameters * Remove comment * Add doc strings to optimized dispatch config * Give more details about DispatchProblemState class * Remove todo comments * Update docs with more in-depth dispatch description * Minor typo * Minor pyomo docs updates * Minor pyomo docs updates * Updated pyomo dispatch figure * Minor comments based on PR review * PR feedback --------- Co-authored-by: Jared Thomas <jaredthomas68@gmail.com> Co-authored-by: bayc <christopher.j.bay@gmail.com> Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: kbrunik <kbrunik@gmail.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Co-authored-by: John Jasa <john.jasa@nrel.gov> * Remove `ElectricitySumComp` (follow-on to 463) (#524) * removed usage of ElectricitySumComp * removed ElectricitySumComp * updated test value in test_save_csv_all_results * Linearized H2 Fuel Cell Model (#525) * linearized fuel cell * added fuel cell to supported models * fix units and output all necessary outputs * docs on docs * Review feedback changes * add h2 fuel cell to elec tech * Update docs/technology_models/h2_fuel_cell.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Update h2integrate/converters/hydrogen/h2_fuel_cell.py Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Update docs/technology_models/h2_fuel_cell.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * rename model to note linear performance * docs --------- Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Standardized Performance Outputs: Generic Storage & Control (#493) * added draft of performance model baseclass to set outputs * updated wind models for standardized outputs * minor cleanup to wind pysam * minor cleanup to floris outputs * updated outputs of hydroplant * updated solar pv models for standardized outputs * updated solar resource integration tests with updated solar model outputs * added fraction_of_year_simulated attribute to performance baseclass * updated tests for turbine preprocessing tools * fixed variable naming in test_all_examples for wind and solar * started updating electrolyzer model outputs * minor bugfix to test_sql_timeseries_to_csv for example 2 * fixed save_case_timeseries_as_csv * update to sql_to_csv function just in case * added attribute check in PerformanceModelBaseClass * typo bugfix in refurb period calc in electrolyzer model * added test for solar performance baseclass * added solar test to check that all outputs are set in parent class * commented out unused variables in new solar test * generalized solar unit test so it can be easily used for other components * updated natural gas plant * started updating co2 models * updated grid model * updated asu model * updated grid tests * updated desal model * updated co2 models and tests * updated newest steel models * started updating methanol models but not tested * made it so ResizablePerformanceModelBaseClass inherits PerformanceModelBaseClass * updated electrolyzer model and ammonia synloop model * updated simple ammonia model * updated hopp wrapper * updated steel.py * updated iron mine and dri models * updated geoh2 models * updated battery * added todo comments to storage models * added unit tests to check that outputs are populated * working on updating combiners and h2imodel * updated electrolyzer so test values dont change and other bugfixes so examples run * updated how_to_set_up_an_analysis.md * removed init file from new hydro power test folder * updated remaining failing tests * updated example 28 and iron_wrapper * updated capacity factor strings in run_size_modes files * removed commented out outputs * updated changelog * removed duplicate inheritance of PerformanceModelBaseClass in electrolyzer performance baseclass * updated pysam battery outputs * updated annual outputs to properly account for fraction of year simulated * moved commodity defn to initialize * updates based on reviewer feedback * updated generic storage models and simple controllers * bugfix in simple_storage_autosizing * updated test for post-processing timeseries * added subtest for ex 12 * updated ex 12 test values * removed commented out code * updated changelog * added some comments to generic storage performance models * added more inline and docstring comments * Minor refactoring changes for clarity * updated docstring in generic storage * updated variable name in simple storage autosizing * added charge rate and capacity inputs to simple generic storage * removed capacity as input to simple_generic_storage * update config names for commodity_name, commodity_units and commodity_storage_units * updated ex 9 * minor updates based on feedback * updated changelog * updated inline comment in simple_generic_storage --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Rename examples to avoid clash (#528) * moved example and added test * Simplified test * Standard Combiner Outputs (follow-on to 463) (#501) * updated combiner to have standard outputs * updated h2imodel for connecting techs to the combiner * added inline comments to generic combiner * added integration test for generic combiner * updated commodity_units to commodity_rate_units * fixed issue from merge causing errors * updated commodity_units to commodity_rate_units in splitter * updated combiner inputs in a test * adding docstring and docs about combiner --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Update mcm dependency (#530) * made saving figures and outputs a config option for co2 models * updated oae to have save plots be optional * update mcm dependency to pip * revert environment.yml change * fix merge issue --------- Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> * Update CO2 model documentation (#533) * made saving figures and outputs a config option for co2 models * updated oae to have save plots be optional * update mcm dependency to pip * revert environment.yml change * fix merge issue * update docs * update ci --------- Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> * Iron: Example with independently sized mine and iron/steel plant (#433) * added in-progress refactored iron winning models * updated natural gas dri performance model * updated docs in ng iron performance model * updated iron cost model * updated coefficient paths for rosner iron plant models * updated example 21 and fixed bugs that were found * minor updates to dri cost and perf models * added basic tests for new dri models * removed notes from rosner dri test * double checked water costs and unit conversions and cleaned up some small things * renamed ng iron reduction models and configs * renamed ng iron dri files * updated iron example tech config * added h2 dri cost and performance models * added h2 dri models to supported models * update test values for wombat version bump * update unit test * update docstrings * update feedstocks to be per ton pig iron * refactored DRI performance and cost models to share baseclass * updated electricity to not double count * added test for performance with limited feedstock availability * eaf wip * steel tests wip * undo align * minor update on handling negative exponents in steel eaf cost model * added carbon and lime to pipe * update rosner eaf test * draft update to iron example * updated iron example to include steel eaf * updated doc page and changelog * added small test for example 21 * Fix run_iron.py to actually compare old and new * Comparing old and new models * Old and new models matched up * Cleaning up PR * Less goofy plant config and other cleanup * Going back to old coefficients with electricity in processing cost * Fixed tests, need to document * updated example 21 so iron_ore_consumed is used for transport cost * Some iron-related cleanup * Fixing test --------- Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Co-authored-by: kbrunik <kbrunik@gmail.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> * Enhancement: Error out on duplicate configuration keys (#534) * add duplicate key handling * include all info in final error message and use load_yaml() in include() * remove printing * remove duplicate keys from floris v4 default template * add more implementation details to the docstring * update changelog * place duplicate key error next to YAML loading * add testing for duplicate keys * provide further insight into design/implementation choices and clarify what is being passed through * GeoH2: Arps decline curve (#454) * WIP arps decline curve * update decline curve * update geoh2 and docstring * update test * update to be percent * update documentation * fix changelog * Update h2integrate/converters/hydrogen/geologic/simple_natural_geoh2.py Co-authored-by: Jonathan Martin <94018654+jmartin4u@users.noreply.github.com> * Update h2integrate/converters/hydrogen/geologic/simple_natural_geoh2.py Co-authored-by: Jonathan Martin <94018654+jmartin4u@users.noreply.github.com> * precommit fix * placeholder fix for lifetime simulation * fix failing test units * Fixing model name in example script --------- Co-authored-by: Jonathan Martin <94018654+jmartin4u@users.noreply.github.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: jmartin4 <jonathan.martin@nrel.gov> * fix oae numpy (#535) * fix oae numpy stuff * actual fix * Feedstock units update (#541) * updated MMBtu to MMBtu/h * updated naming for feedstock config inputs * Re-organize "default" logic around `commodity_stream` and finance models (#536) * moved tech-specific hard-coded logic to connect technologies to finance models from connect_technologies() to create_finance_model() --------- Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> * Iron: Adding electrowinning capabilities (#432) * Reading in Stinn input tables * Sucessfully testing Stinn model * Making humbert perf model * Adding humbert/stinn cost model inputs only * Progress on humbert cost * Humbert Stinn complete, not debugged * Debugging electrowinning * Debugging ewinning * Electrowinning cases running, need to add DRI case * Cleanup of old trailing underscores * Fix input csv names * Integrate ewin example with feedstocks * Moving functions out of h2i module and renumbering example * Small fixes to PR * start of unit test * Testing example * Expanding unit tests * fix import * Docstrings begun * Docstrings plus a little reorg * Everything but the docs page * Finished documentation * Split off humbert cost_model * Config docstrings * Refactoring iron ewinning calcs for clarity * Addressing reviews * site -> sites * Updating test values * Added autodoc to the electrowinning docs * updated iron electrowinning tech config * updated plant config for electrowinning example * minor udpates to cost model * minor updates to cost and performance models * fixed initialization error in cost model * removed duplicate costs and updated to use PerformanceModelBaseClass * updated example test values * Addressing elenya comments * feedstocks wip * updating integration * classic units * updated tech config to be compatible with develop * merged changelog * removed hard-coded cost numbers in compute() to config args with default values * Minor cleanup --------- Co-authored-by: Jonathan Martin <94018654+jmartin4nrel@users.noreply.github.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: kbrunik <kbrunik@gmail.com> Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> * Consistently call `prob.get_val()` with units instead of `prob["<variable>"]` (#539) * moved prob calls * Fixing some tests * Updated units for NG * Updated based on PR feedback * Generic transporter model (#540) * added generic transporter and added to supported models * updated generic transporter, added test, and updated iron example * updated doc pages for generic transporter * added error message to h2imodel for invalid tech names * minor typo fix in feedstock documentation * removed more components from pipe and updated iron examples * Changed to using set notation for the reserved techs --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Finance models to represent lifetime performance (#543) * initial lifetime finance reorg with updated lcoh test values * updated combiner output naming for capacity factor so combiners can be daisy-chained * added new error message to check if a default commodity stream was not found * fixed other failing tests * updates to co2 models and new tests * removed hard-codedl logic for handling co2 * minor fix on units input to ProFast * cleaned up doc * minor cleanups * renamed variables in generic combiner * minor other update to generic combiner * minor cleanup --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Maintenance: Test Revamp Phase 1 - Mild Refactor and Test Type Marking (#531) * enable test coverage and update pytest settings * add sort of working file cleanup fixture * convert feedstock to pytest * spacing * convert utilities to pytest * remove last unittest reference * convert finance test to pytest * fix import error and convert DOC to pytest * use correct error for imports not found * add infrastructure to have separate unit, regression, and integration tests * refactor shared fixtures to conftest and mark doc with test type * adopt enforcement of unit, regression, and test marking * mark already modified files * fix marker name gathering * add docstring * add documentation for test development and running * convert oae test to pytest * mark controller tests * mark ammonia converter tests * simplify fixtures and convert to pytest * update docs for openmdao cleanup * update fixtures and mark hopp tests * remove generated output plots * mark geologic h2 and handle temp data better * update fixture usage and mark tests in h2 * update fixture structure and mark iron converter tests * mark methanol tests * mark natural gas tests * mark nitrogen tests * reorg solar fixtures and mark test types * reorg steel converter fixtures and mark test types * mark water power test types * reorg wind converter models fixtures and mark test types * mark wind converter tools test types * remove repetitive .parent * update temp directory usage and mark test types in frameworks * refactor temp_dir to conftest * mark recorder tests and use pytest temp dir factory * mark supported models tests and use general temp_dir for utilities * define temp_dir factory in top-level conftest and import everywhere else * correct temp_dir refactor * fix broken mcm tests and universalize package management * mark new tests * mark finance test types * mark postprocessing tests and use temp_dir fixture * mark preprocessing test types and use temp_dir * refactor himawari tests to reduce repitive setup architecture and mark test type * refactor himawari and open meteosat models to single parameterized test * refactor nrel goes resource model to single parameterized test * combine all resource model tests into single file and convert openmeteo historical to parameterized * convert pv watts integration tests into single parameterized test * move common resource fixtures to resource level conftest * include which for solar vs win * use site config setup for wind and mark wind resource tests * refactor open meteo wind test to use generalized fixtures and mark test types * apply ids and use timezone arg for plant * mark resource utilities tests * mark battery storage tests and unify test folders * mark storage test types, use common fixtures, and parametrize common test routines * mark tools test types * mark transporter test types and reduce repetitive tests and fixtures * mark pip tests * mark examples test types * ignore sqllite cache * bump wombat version and remove remove test coverage options * fix broken tests from lack of temp_dir updating * mark newly merged tests * mark missing integration test * create fixture for temp_dir setup/teardown for example directories * account for resource data and fix broken tests * accept change from kbrunik for model vs technology language Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> * add unit test example to docs and fix subtest comment * add regression test example and integration test pointer * add missing setup/teardown for meteosat nrel api * update commodity units to commodity_rate_units * mark newly merged test * add code coverage workflow draft * consolidate repetitive pytest session functionality * account for differing resource year and file name resource year * update resource year in integration test as well * update naming * remove redundant resource-year update and fix variable typo * mark new tests * Update docs/developer_guide/adding_a_new_technology.md Co-authored-by: genevievestarke <103534902+genevievestarke@users.noreply.github.com> * Update docs/developer_guide/adding_a_new_technology.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Update docs/developer_guide/adding_a_new_technology.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Update docs/developer_guide/adding_a_new_technology.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * add in docs for temporary data retention * remove unlink for redundant cleanup * remove unused parameter * mark finnicky test with xfail * move testing docs to a separate page * add shared fixture commentary * add codecov token * make relative reference * update changelog * add use a generic fenceposting comment to mark docs literalinclude bounds --------- Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: genevievestarke <103534902+genevievestarke@users.noreply.github.com> Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Remove some doc warnings (#550) * Beginning to address doc build warnings * Removing duplicate kwarg docstrings * updated ammonia model to need n2 and electricity inputs (#544) Co-authored-by: John Jasa <johnjasa11@gmail.com> * yamlfix all yaml files; add yamlfix to the pre-commit hook (#551) * add yamlfix to the pre-commit * yamlfix'd all yamls * Update changelog * Rolling back other pre-commit changes * Excluded yamls needed for duplicate keys tests * Excluded yamls needed for duplicate keys tests * Switch to keep style for sequences * Switch to keep style for sequences * Apply suggestions from code review Co-authored-by: Rob Hammond <13874373+RHammond2@users.noreply.github.com> * Applying Rob's suggestions * leave not on malfunctional config and reapply settings --------- Co-authored-by: Rob Hammond <13874373+RHammond2@users.noreply.github.com> * Enhancement: Automatically insert technology names in control strategy definitions (#558) * add tech name to control parameters in setup * remove obselete test and associate files * handle no keys in control parameters and update testing * Add a simple nuclear plant performance and cost model (#538) * Added first pass at a simple nuclear model * Adding nuclear doc page * Added to changelog * Doc cleanup * Fixed OpEx calc for nuclear * Simplifying nuclear test * Addressing PR comments * Marking tests * Updates based on PR feedback * Split out Pyomo Controllers to separate files (#549) * split out pyomo control models * added pyomo controller baseclass * removed n_horizon_window from control strategies * moved round_digits to pyomo base config * other minor updates * fixed failing tests * Update changelog --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Update Natural GeoH2 with Yearly CF (#552) * reformat release updates * bump version * Added PR links to changelog * Tech and system model figures (#554) * tech and system model diagrams * add comment about modularity and custom models * Update docs/intro.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @bayc Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com> * Apply suggestion from @bayc Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com> * correct typo and unify figure specs * typo correction * update changelog --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com> * Removed hard-coded logic for electrolyzer replacement schedule (#555) * draft * updated finances to take in replacement schedules for all techs * updated feedstock and added logic to prevent connecting replacement schedule for transport components * added doc page about naming convention * removed unnecessary elif statement in connect_technologies * added test for new error message * updated inline comments for finance models * Minor refactor and cleanup for replacement cost vars * updated naming for system finance model * reverted change to ex 1 run file --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> --------- Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Co-authored-by: John Jasa <john.jasa@nrel.gov> Co-authored-by: genevievestarke <103534902+genevievestarke@users.noreply.github.com> Co-authored-by: Jared Thomas <jaredthomas68@gmail.com> Co-authored-by: bayc <christopher.j.bay@gmail.com> Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: kbrunik <kbrunik@gmail.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> Co-authored-by: Jonathan Martin <94018654+jmartin4u@users.noreply.github.com> Co-authored-by: jmartin4 <jonathan.martin@nrel.gov> Co-authored-by: Jonathan Martin <94018654+jmartin4nrel@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com>
* Ammonia Synloop: Units fix and small changes (#518) * updated electricity units in synloop * added feedstock consumption profiles and updated cost model to use capacity input * added tests/subtests for ammonia synloop * udpated electricity units to kW * fixed nitrogen purge gas calc (#520) * Minor fix in post-processing to save capacity factors (#519) * minor update to sql_to_csv to save capacity factors * simplified logic handling capacity factor in postprocessing * Apply suggestion from @johnjasa --------- Co-authored-by: John Jasa <john.jasa@nrel.gov> * Enable load following optimization dispatch with Pyomo (#407) * include code from usage: pyomo [-h] [--version] {build-extensions,convert,download-extensions,help,install-extras,model-viewer,run,solve,test-solvers} ... This is the main driver for the Pyomo optimization software. options: -h, --help show this help message and exit --version show program's version number and exit subcommands: {build-extensions,convert,download-extensions,help,install-extras,model-viewer,run,solve,test-solvers} build-extensions Build compiled extension modules convert Convert a Pyomo model to another format download-extensions Download compiled extension modules help Print help information. install-extras Install "extra" packages that Pyomo can leverage. model-viewer Run the Pyomo model viewer run Execute a command from the Pyomo bin (or Scripts) directory. solve Optimize a model test-solvers Test Pyomo solvers ------------------------------------------------------------------------- Pyomo supports a variety of modeling and optimization capabilities, which are executed either as subcommands of 'pyomo' or as separate commands. Use the 'help' subcommand to get information about the capabilities installed with Pyomo. Additionally, each subcommand supports independent command-line options. Use the -h option to print details for a subcommand. For example, type pyomo solve -h to print information about the `solve` subcommand. branch that needs to be saved for later * include storage rule file * Halfway there for pyomo opt * Add first objective function * Updated dispatch optimization framework - add hybrid dispatch rule * Adding hybrid linking constraints and connecting variables in pyomo min operating costs framework * Final structural changes * Fix import statement * Fix imports and setter method * First draft of running code * Update example * test * fix precommits * Fixing merge errors * Minor spelling changes * Update example * Update controller problem state method from Elenya * Update example and changelog * Clean up pyomo storage baseclass file * Cleanups to feature/pyomo opt (#2) * refactored DispatchProblemState * updated tech config and removed pysam options file * minor cleanups to DispatchProblemState * minor updates to generic_converter_opt * initial cleanups to hybrid_rule.py * minor cleanups to pyomo_storage_rule_min_operating_cost * extra small cleanups to generic_converter_opt * added storage capacities as inputs to optimized controller * updated use of n_control_window and n_horizon_window * Enable heuristic dispatch to run with new pyomo changes * Clean up added files and example * Adding first tests - do not pass yet * Update docs and rename example * Align naming with develop branch * Update Ex 02 and update pyomo_controllers with naming in develop * updated other example tech configs * ran precommit on some files * precommit on pyomo_controllers.py * Update test formatting * Update pyomo storage rule for test * Fix SOC linking bug * Testing update - partial * Make new test for optimized pyomo dispatch * Update optimal controller test * Update test with new site definition * Update example for merging in develop * Minor updates to optimized dispatch * PR updates from comments * Add last file after merge issue * Update example * Made plots slightly larger * Update h2integrate/control/control_strategies/controller_opt_problem_state.py Apply comment suggestions Co-authored-by: John Jasa <john.jasa@nrel.gov> * Update h2integrate/control/control_strategies/controller_opt_problem_state.py Apply comment suggestions Co-authored-by: John Jasa <john.jasa@nrel.gov> * Update h2integrate/control/control_rules/hybrid_rule.py Apply comment suggestions Co-authored-by: John Jasa <john.jasa@nrel.gov> * Cleaning up pyomo_controllers * Updated docstrings and battery mentions * Initial init docs string and example update * Update note about incentivizing charging in objective function * Update generation and load variable definitions * Update docs/control/pyomo_controllers.md Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> * Update doc strings for updated_initial_soc parameter * Make time_weighting_factor and round_digits not hardcoded * remove round_digits from pyomo_rule_baseclass * Updating controller names * Fixed name check for controllers * Updated optimal controller test * remove unused properties * Update example to run with new class definitions * Fix converter name in test * Fix ruff formatting * Update doc strings for pyomo model classes * Rename files to be more consistent and descriptive * Update comments in the init portions of dispatch for parameters * Remove comment * Add doc strings to optimized dispatch config * Give more details about DispatchProblemState class * Remove todo comments * Update docs with more in-depth dispatch description * Minor typo * Minor pyomo docs updates * Minor pyomo docs updates * Updated pyomo dispatch figure * Minor comments based on PR review * PR feedback --------- Co-authored-by: Jared Thomas <jaredthomas68@gmail.com> Co-authored-by: bayc <christopher.j.bay@gmail.com> Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: kbrunik <kbrunik@gmail.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Co-authored-by: John Jasa <john.jasa@nrel.gov> * Remove `ElectricitySumComp` (follow-on to 463) (#524) * removed usage of ElectricitySumComp * removed ElectricitySumComp * updated test value in test_save_csv_all_results * Linearized H2 Fuel Cell Model (#525) * linearized fuel cell * added fuel cell to supported models * fix units and output all necessary outputs * docs on docs * Review feedback changes * add h2 fuel cell to elec tech * Update docs/technology_models/h2_fuel_cell.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Update h2integrate/converters/hydrogen/h2_fuel_cell.py Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Update docs/technology_models/h2_fuel_cell.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * rename model to note linear performance * docs --------- Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Standardized Performance Outputs: Generic Storage & Control (#493) * added draft of performance model baseclass to set outputs * updated wind models for standardized outputs * minor cleanup to wind pysam * minor cleanup to floris outputs * updated outputs of hydroplant * updated solar pv models for standardized outputs * updated solar resource integration tests with updated solar model outputs * added fraction_of_year_simulated attribute to performance baseclass * updated tests for turbine preprocessing tools * fixed variable naming in test_all_examples for wind and solar * started updating electrolyzer model outputs * minor bugfix to test_sql_timeseries_to_csv for example 2 * fixed save_case_timeseries_as_csv * update to sql_to_csv function just in case * added attribute check in PerformanceModelBaseClass * typo bugfix in refurb period calc in electrolyzer model * added test for solar performance baseclass * added solar test to check that all outputs are set in parent class * commented out unused variables in new solar test * generalized solar unit test so it can be easily used for other components * updated natural gas plant * started updating co2 models * updated grid model * updated asu model * updated grid tests * updated desal model * updated co2 models and tests * updated newest steel models * started updating methanol models but not tested * made it so ResizablePerformanceModelBaseClass inherits PerformanceModelBaseClass * updated electrolyzer model and ammonia synloop model * updated simple ammonia model * updated hopp wrapper * updated steel.py * updated iron mine and dri models * updated geoh2 models * updated battery * added todo comments to storage models * added unit tests to check that outputs are populated * working on updating combiners and h2imodel * updated electrolyzer so test values dont change and other bugfixes so examples run * updated how_to_set_up_an_analysis.md * removed init file from new hydro power test folder * updated remaining failing tests * updated example 28 and iron_wrapper * updated capacity factor strings in run_size_modes files * removed commented out outputs * updated changelog * removed duplicate inheritance of PerformanceModelBaseClass in electrolyzer performance baseclass * updated pysam battery outputs * updated annual outputs to properly account for fraction of year simulated * moved commodity defn to initialize * updates based on reviewer feedback * updated generic storage models and simple controllers * bugfix in simple_storage_autosizing * updated test for post-processing timeseries * added subtest for ex 12 * updated ex 12 test values * removed commented out code * updated changelog * added some comments to generic storage performance models * added more inline and docstring comments * Minor refactoring changes for clarity * updated docstring in generic storage * updated variable name in simple storage autosizing * added charge rate and capacity inputs to simple generic storage * removed capacity as input to simple_generic_storage * update config names for commodity_name, commodity_units and commodity_storage_units * updated ex 9 * minor updates based on feedback * updated changelog * updated inline comment in simple_generic_storage --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Rename examples to avoid clash (#528) * moved example and added test * Simplified test * Standard Combiner Outputs (follow-on to 463) (#501) * updated combiner to have standard outputs * updated h2imodel for connecting techs to the combiner * added inline comments to generic combiner * added integration test for generic combiner * updated commodity_units to commodity_rate_units * fixed issue from merge causing errors * updated commodity_units to commodity_rate_units in splitter * updated combiner inputs in a test * adding docstring and docs about combiner --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Update mcm dependency (#530) * made saving figures and outputs a config option for co2 models * updated oae to have save plots be optional * update mcm dependency to pip * revert environment.yml change * fix merge issue --------- Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> * Update CO2 model documentation (#533) * made saving figures and outputs a config option for co2 models * updated oae to have save plots be optional * update mcm dependency to pip * revert environment.yml change * fix merge issue * update docs * update ci --------- Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> * Iron: Example with independently sized mine and iron/steel plant (#433) * added in-progress refactored iron winning models * updated natural gas dri performance model * updated docs in ng iron performance model * updated iron cost model * updated coefficient paths for rosner iron plant models * updated example 21 and fixed bugs that were found * minor updates to dri cost and perf models * added basic tests for new dri models * removed notes from rosner dri test * double checked water costs and unit conversions and cleaned up some small things * renamed ng iron reduction models and configs * renamed ng iron dri files * updated iron example tech config * added h2 dri cost and performance models * added h2 dri models to supported models * update test values for wombat version bump * update unit test * update docstrings * update feedstocks to be per ton pig iron * refactored DRI performance and cost models to share baseclass * updated electricity to not double count * added test for performance with limited feedstock availability * eaf wip * steel tests wip * undo align * minor update on handling negative exponents in steel eaf cost model * added carbon and lime to pipe * update rosner eaf test * draft update to iron example * updated iron example to include steel eaf * updated doc page and changelog * added small test for example 21 * Fix run_iron.py to actually compare old and new * Comparing old and new models * Old and new models matched up * Cleaning up PR * Less goofy plant config and other cleanup * Going back to old coefficients with electricity in processing cost * Fixed tests, need to document * updated example 21 so iron_ore_consumed is used for transport cost * Some iron-related cleanup * Fixing test --------- Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Co-authored-by: kbrunik <kbrunik@gmail.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> * Enhancement: Error out on duplicate configuration keys (#534) * add duplicate key handling * include all info in final error message and use load_yaml() in include() * remove printing * remove duplicate keys from floris v4 default template * add more implementation details to the docstring * update changelog * place duplicate key error next to YAML loading * add testing for duplicate keys * provide further insight into design/implementation choices and clarify what is being passed through * GeoH2: Arps decline curve (#454) * WIP arps decline curve * update decline curve * update geoh2 and docstring * update test * update to be percent * update documentation * fix changelog * Update h2integrate/converters/hydrogen/geologic/simple_natural_geoh2.py Co-authored-by: Jonathan Martin <94018654+jmartin4u@users.noreply.github.com> * Update h2integrate/converters/hydrogen/geologic/simple_natural_geoh2.py Co-authored-by: Jonathan Martin <94018654+jmartin4u@users.noreply.github.com> * precommit fix * placeholder fix for lifetime simulation * fix failing test units * Fixing model name in example script --------- Co-authored-by: Jonathan Martin <94018654+jmartin4u@users.noreply.github.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: jmartin4 <jonathan.martin@nrel.gov> * fix oae numpy (#535) * fix oae numpy stuff * actual fix * Feedstock units update (#541) * updated MMBtu to MMBtu/h * updated naming for feedstock config inputs * Re-organize "default" logic around `commodity_stream` and finance models (#536) * moved tech-specific hard-coded logic to connect technologies to finance models from connect_technologies() to create_finance_model() --------- Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> * Iron: Adding electrowinning capabilities (#432) * Reading in Stinn input tables * Sucessfully testing Stinn model * Making humbert perf model * Adding humbert/stinn cost model inputs only * Progress on humbert cost * Humbert Stinn complete, not debugged * Debugging electrowinning * Debugging ewinning * Electrowinning cases running, need to add DRI case * Cleanup of old trailing underscores * Fix input csv names * Integrate ewin example with feedstocks * Moving functions out of h2i module and renumbering example * Small fixes to PR * start of unit test * Testing example * Expanding unit tests * fix import * Docstrings begun * Docstrings plus a little reorg * Everything but the docs page * Finished documentation * Split off humbert cost_model * Config docstrings * Refactoring iron ewinning calcs for clarity * Addressing reviews * site -> sites * Updating test values * Added autodoc to the electrowinning docs * updated iron electrowinning tech config * updated plant config for electrowinning example * minor udpates to cost model * minor updates to cost and performance models * fixed initialization error in cost model * removed duplicate costs and updated to use PerformanceModelBaseClass * updated example test values * Addressing elenya comments * feedstocks wip * updating integration * classic units * updated tech config to be compatible with develop * merged changelog * removed hard-coded cost numbers in compute() to config args with default values * Minor cleanup --------- Co-authored-by: Jonathan Martin <94018654+jmartin4nrel@users.noreply.github.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: kbrunik <kbrunik@gmail.com> Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> * Consistently call `prob.get_val()` with units instead of `prob["<variable>"]` (#539) * moved prob calls * Fixing some tests * Updated units for NG * Updated based on PR feedback * Generic transporter model (#540) * added generic transporter and added to supported models * updated generic transporter, added test, and updated iron example * updated doc pages for generic transporter * added error message to h2imodel for invalid tech names * minor typo fix in feedstock documentation * removed more components from pipe and updated iron examples * Changed to using set notation for the reserved techs --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Finance models to represent lifetime performance (#543) * initial lifetime finance reorg with updated lcoh test values * updated combiner output naming for capacity factor so combiners can be daisy-chained * added new error message to check if a default commodity stream was not found * fixed other failing tests * updates to co2 models and new tests * removed hard-codedl logic for handling co2 * minor fix on units input to ProFast * cleaned up doc * minor cleanups * renamed variables in generic combiner * minor other update to generic combiner * minor cleanup --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Maintenance: Test Revamp Phase 1 - Mild Refactor and Test Type Marking (#531) * enable test coverage and update pytest settings * add sort of working file cleanup fixture * convert feedstock to pytest * spacing * convert utilities to pytest * remove last unittest reference * convert finance test to pytest * fix import error and convert DOC to pytest * use correct error for imports not found * add infrastructure to have separate unit, regression, and integration tests * refactor shared fixtures to conftest and mark doc with test type * adopt enforcement of unit, regression, and test marking * mark already modified files * fix marker name gathering * add docstring * add documentation for test development and running * convert oae test to pytest * mark controller tests * mark ammonia converter tests * simplify fixtures and convert to pytest * update docs for openmdao cleanup * update fixtures and mark hopp tests * remove generated output plots * mark geologic h2 and handle temp data better * update fixture usage and mark tests in h2 * update fixture structure and mark iron converter tests * mark methanol tests * mark natural gas tests * mark nitrogen tests * reorg solar fixtures and mark test types * reorg steel converter fixtures and mark test types * mark water power test types * reorg wind converter models fixtures and mark test types * mark wind converter tools test types * remove repetitive .parent * update temp directory usage and mark test types in frameworks * refactor temp_dir to conftest * mark recorder tests and use pytest temp dir factory * mark supported models tests and use general temp_dir for utilities * define temp_dir factory in top-level conftest and import everywhere else * correct temp_dir refactor * fix broken mcm tests and universalize package management * mark new tests * mark finance test types * mark postprocessing tests and use temp_dir fixture * mark preprocessing test types and use temp_dir * refactor himawari tests to reduce repitive setup architecture and mark test type * refactor himawari and open meteosat models to single parameterized test * refactor nrel goes resource model to single parameterized test * combine all resource model tests into single file and convert openmeteo historical to parameterized * convert pv watts integration tests into single parameterized test * move common resource fixtures to resource level conftest * include which for solar vs win * use site config setup for wind and mark wind resource tests * refactor open meteo wind test to use generalized fixtures and mark test types * apply ids and use timezone arg for plant * mark resource utilities tests * mark battery storage tests and unify test folders * mark storage test types, use common fixtures, and parametrize common test routines * mark tools test types * mark transporter test types and reduce repetitive tests and fixtures * mark pip tests * mark examples test types * ignore sqllite cache * bump wombat version and remove remove test coverage options * fix broken tests from lack of temp_dir updating * mark newly merged tests * mark missing integration test * create fixture for temp_dir setup/teardown for example directories * account for resource data and fix broken tests * accept change from kbrunik for model vs technology language Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> * add unit test example to docs and fix subtest comment * add regression test example and integration test pointer * add missing setup/teardown for meteosat nrel api * update commodity units to commodity_rate_units * mark newly merged test * add code coverage workflow draft * consolidate repetitive pytest session functionality * account for differing resource year and file name resource year * update resource year in integration test as well * update naming * remove redundant resource-year update and fix variable typo * mark new tests * Update docs/developer_guide/adding_a_new_technology.md Co-authored-by: genevievestarke <103534902+genevievestarke@users.noreply.github.com> * Update docs/developer_guide/adding_a_new_technology.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Update docs/developer_guide/adding_a_new_technology.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Update docs/developer_guide/adding_a_new_technology.md Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * add in docs for temporary data retention * remove unlink for redundant cleanup * remove unused parameter * mark finnicky test with xfail * move testing docs to a separate page * add shared fixture commentary * add codecov token * make relative reference * update changelog * add use a generic fenceposting comment to mark docs literalinclude bounds --------- Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: genevievestarke <103534902+genevievestarke@users.noreply.github.com> Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> * Remove some doc warnings (#550) * Beginning to address doc build warnings * Removing duplicate kwarg docstrings * updated ammonia model to need n2 and electricity inputs (#544) Co-authored-by: John Jasa <johnjasa11@gmail.com> * yamlfix all yaml files; add yamlfix to the pre-commit hook (#551) * add yamlfix to the pre-commit * yamlfix'd all yamls * Update changelog * Rolling back other pre-commit changes * Excluded yamls needed for duplicate keys tests * Excluded yamls needed for duplicate keys tests * Switch to keep style for sequences * Switch to keep style for sequences * Apply suggestions from code review Co-authored-by: Rob Hammond <13874373+RHammond2@users.noreply.github.com> * Applying Rob's suggestions * leave not on malfunctional config and reapply settings --------- Co-authored-by: Rob Hammond <13874373+RHammond2@users.noreply.github.com> * Enhancement: Automatically insert technology names in control strategy definitions (#558) * add tech name to control parameters in setup * remove obselete test and associate files * handle no keys in control parameters and update testing * Add a simple nuclear plant performance and cost model (#538) * Added first pass at a simple nuclear model * Adding nuclear doc page * Added to changelog * Doc cleanup * Fixed OpEx calc for nuclear * Simplifying nuclear test * Addressing PR comments * Marking tests * Updates based on PR feedback * Split out Pyomo Controllers to separate files (#549) * split out pyomo control models * added pyomo controller baseclass * removed n_horizon_window from control strategies * moved round_digits to pyomo base config * other minor updates * fixed failing tests * Update changelog --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Update Natural GeoH2 with Yearly CF (#552) * Tech and system model figures (#554) * tech and system model diagrams * add comment about modularity and custom models * Update docs/intro.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @bayc Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com> * Apply suggestion from @bayc Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com> * correct typo and unify figure specs * typo correction * update changelog --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com> * Removed hard-coded logic for electrolyzer replacement schedule (#555) * draft * updated finances to take in replacement schedules for all techs * updated feedstock and added logic to prevent connecting replacement schedule for transport components * added doc page about naming convention * removed unnecessary elif statement in connect_technologies * added test for new error message * updated inline comments for finance models * Minor refactor and cleanup for replacement cost vars * updated naming for system finance model * reverted change to ex 1 run file --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Require a PR link in the CHANGELOG (#572) * update PR template to better describe changelog requirements * update changelog * Update to PySAM Battery so size is changed in compute() (#557) * made storage capacity and charge rate inputs for PySAM Battery model * removed outputs object from pysam battery * fixed logic in PySAM Battery model if not using a pyomo controller * refactored pyomo rule baseclasses to set default values from config * updated heuristic controller to take in storage capacity input * renamed battery outputs for charge and discharge --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Minor cleanup of yamls after tech_name change (#559) * Minor cleanup of yamls after tech_name change * Updates to make more tests pass * Updates to make more tests pass * Renamed percent to fraction for storage (#581) * Renamed percent to fraction for storage * Updated changelog * Reorganizing utilities (#586) * Reorganizing utilities * Updated changelog * Added missing tools file * Added missing tools file * Generic Storage Model that's Compatible with Pyomo Controllers (#571) * Added generic storage model (`StoragePerformanceModel`) that is compatible with Pyomo control strategies * Updated the `simulate()` method of PySAM battery model have same inputs and similar calculations as `StoragePerformanceModel` --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * Moving NREL to NLR API keys and naming throughout (#583) * Moving NREL to NLR API keys and naming throughout * Added to changelog * Moved a few more references from nrel to nlr * Updating a few more NLR references * Fix incorrect system sizing for Papadias hydrogen storage cost models (#588) * Moving NREL to NLR API keys and naming throughout * Added to changelog * Moved a few more references from nrel to nlr * Updating a few more NLR references * Changing hydrogen storage units * Updated changelog * Updated test values based on h2 storage cost bugfix * Fixing examples drift (#584) * Fixing examples drift * Added to changelog * Fixing example notebook * Updating jupytext * Adding test and doc changes (#582) * Adding test and doc changes * Update docs/user_guide/postprocessing_results.md Co-authored-by: genevievestarke <103534902+genevievestarke@users.noreply.github.com> --------- Co-authored-by: genevievestarke <103534902+genevievestarke@users.noreply.github.com> * Update openmdao version constraint in pyproject.toml (#592) * Fixing OM 3.43 related bug (#595) * Fixing OM 3.43 related bug * Added to changelog * Steam Methane Reforming Hydrogen Converter (#594) * SMR wip * test performance * cost regression test * docstrings and changelog * Added hydrogen and electricity unmet * Minor docstring update --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * reorder system when transporters are used (#591) * reorder system when transporters are used * remove battery to steel cable * update changelog * Apply suggestion from @RHammond2 Co-authored-by: Rob Hammond <13874373+RHammond2@users.noreply.github.com> --------- Co-authored-by: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> * Bugfix and Renaming in SMR model (#596) * minor renaming to smr model * fixed bug in smr variable om cost calculation * removed commented out code * Minor: added option to print results in `post_process()` method (#597) * added option to print results in h2i.post_process method * Updated docstring and changelog --------- Co-authored-by: John Jasa <johnjasa11@gmail.com> * reorg changelog and bump version --------- Co-authored-by: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Co-authored-by: John Jasa <john.jasa@nrel.gov> Co-authored-by: genevievestarke <103534902+genevievestarke@users.noreply.github.com> Co-authored-by: Jared Thomas <jaredthomas68@gmail.com> Co-authored-by: bayc <christopher.j.bay@gmail.com> Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: kbrunik <kbrunik@gmail.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: Jared Thomas <jaredthomas68@users.noreply.github.com> Co-authored-by: Jonathan Martin <94018654+jmartin4u@users.noreply.github.com> Co-authored-by: jmartin4 <jonathan.martin@nrel.gov> Co-authored-by: Jonathan Martin <94018654+jmartin4nrel@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Chris Bay <12664940+bayc@users.noreply.github.com>
Standardized Performance Outputs: Generic Storage & Control
This PR is a follow-on to PR #463 and should not be merged in until after #463 is.
This PR updates the generic storage performance models and the control strategies so storage models have the same outputs as converters. There are 3 storage performance models:
h2integrate/storage/battery/pysam_battery.py: This was updated in PR Standardize performance model outputs #463h2integrate/storage/simple_generic_storage.py: basically did nothingh2integrate/storage/simple_storage_auto_sizing.py: calculates storage capacity and charge rate needed to meet a demand.To be consistent with the
pysam_batterymodel, the generic storage performance models needed to output the standardized outputs (like capacity factor, rated production, etc) but these generic performance models did very minimal calculations and did not outputcommodity_out, most calculations were done in the controllers, not the performance models.Basically, the control strategies have been updated to output
commodity_set_pointinstead ofcommodity_out.commodity_set_pointis what the controller tells the performance model is the "target"commodity_out. Since the performance model may not be able to achieve thecommodity_set_point(due to a variety of possible differences in the control model and the performance model, like losses), the performance model outputcommodity_outmay not equal thecommodity_set_point. Thecommodity_set_pointis the input to the storage performance models, which now outputcommodity_out,annual_commodity_production,capacity_factor, etc. The computations now done in some of the storage performance models may be somewhat duplicative of the performance of some controllers, but this ensures that the storage controllers are compatible with any storage performance model.Section 1: Type of Contribution
Section 2: Draft PR Checklist
TODO:
commodity_nametocommodityfor the generic storage performance models and control strategiescommodity_unitstocommodity_rate_unitsfor the generic storage performance models and control strategiesType of Reviewer Feedback Requested (on Draft PR)
Structural feedback:
Implementation feedback:
commodity_set_point?Other feedback:
Section 3: General PR Checklist
docs/files are up-to-date, or added when necessaryCHANGELOG.mdhas been updated to describe the changes made in this PRSection 3: Related Issues
This partially resolves some of Issue #486, and would resolve a step in Issue #485
New issues made: #498, #521
Section 4: Impacted Areas of the Software
Section 4.1: New Files
N/A
Section 4.2: Modified Files
h2integrate/storage/simple_generic_storage.py: addedcommodity_set_pointas an input, updatedcompute()method to better reflect performance of a "pass through" type storage component (this storage model has no inputs related to capacity, which is why thecompute()method basically now acts like a pass-through component)h2integrate/storage/simple_storage_auto_sizing.py: addedcommodity_set_pointas an input, updatedcompute()method to better reflect simple performance of a storage componenth2integrate/control/control_strategies/demand_openloop_controller.py: changed output variable namecommodity_outtocommodity_set_pointh2integrate/control/control_strategies/passthrough_openloop_controller.py: changed output variable namecommodity_outtocommodity_set_pointh2integrate/postprocess/test/test_sql_timeseries_to_csv.py: updated subtest value, see justification in Section 6pytest examples/test/test_all_examples.py::test_ammonia_synloop_example: added subtest for annual ammonia production and updated 3 subtest values that changed, see justification in Section 6.Section 5: Additional Supporting Information
Section 6: Test Results, if applicable
h2integrate/postprocess/test/test_sql_timeseries_to_csv.py::test_save_csv_all_results: subtest for number of columns increased from 35 to 36 because of the new outputcommodity_set_point.Example 1, 2 and 12 use the
"StorageAutoSizingModel", which was changed to actually model the performance of the storage (a outputs a smoothed out profile of the input commodity profile) which was added in lines 128-the end ofh2integrate/storage/simple_storage_auto_sizing.py. The performance of models downstream of the hydrogen system in Example 1 and 2 will not change if the hydrogen production profile changes in shape, only if the total hydrogen produced changes (which it doesn't because the total hydrogen output from the"StorageAutoSizingModel"does not change because the storage is sized such that no hydrogen is curtailed.). Example 12 uses the ammonia synloop model, which is the only model that has performance dependent on the hydrogen production profile, which has changed given the addition of the actual storage performance now simulated in the"StorageAutoSizingModel". This is why values changed in tests that test outputs from the ammonia model in Example 12 and why no test values changed in Example 1 or 2. Below is a more in-depth explanation of why the test values changed in Example 12:pytest examples/test/test_all_examples.py::test_ammonia_synloop_example: subtests for ammonia OpEx, total adjusted OpEx for ammonia finance subgroup, and the LCOA failed, the test values decreased.cat_opex + h2o_opex - o2_opex, all of these are multipliers of the annual ammonia produced. All these opex values increased, but theo2_opexincreased much more than the increase incat_opexandh2o_opexcombined, meaning a net reduction in OpEx.max_hydrogen_capacityof theammonia_synloopmodel is 10589.36 kg/h, this value has not changed.hydrogen_into theammonia_synloopmodel decreased from 12549 kg/h to 9306 kg/h. This indicates that now more hydrogen is being used to make ammonia rather than being "curtailed". The total hydrogen consumed is the same as before (meaning the totalhydrogen_inis the same), but thehydrogen_outof the ammonia model decreased (likely because more hydrogen is being used)"generic_storage_model"as the performance model since this acts like the pass-through controller. This would make the hydrogen into the ammonia model the same as before (equal to the hydrogen out of the electrolyzer model). But - we would have to set the storage capacity and charge rate so that the hydrogen storage cost is the same as before.Section 7 (Optional): New Model Checklist
docs/developer_guide/coding_guidelines.mdattrsclass to define theConfigto load in attributes for the modelBaseConfigorCostModelBaseConfiginitialize()method,setup()method,compute()methodCostModelBaseClasssupported_models.pycreate_financial_modelinh2integrate_model.pytest_all_examples.pydocs/user_guide/model_overview.mddocs/section<model_name>.mdis added to the_toc.yml