Feature: Basic Reliability Model Implementation for Performance Model Classes - #833
Conversation
elenya-grant
left a comment
There was a problem hiding this comment.
Left some big-picture comments! Happy to chat through anything if you'd like! Thanks!
| to a quarterly downtime event and 0.25 is equivalent to an every 4 years downtime event. | ||
| For all events the timing of the first event will be sampled within the first year or | ||
| interval period to offset events from being based on January 1st in an 8760. | ||
| downtime (int | float | dict): Either fixed length of each downtime, in hours, or a |
There was a problem hiding this comment.
could we name this downtime_hrs or something? Also - can these models be updated to handle varying timesteps? It seems like a lot of logic is intended for hourly? If so - I think we should should make dt an input parameter too.
There was a problem hiding this comment.
This could be tricky, but I'll add it to the to do section.
There was a problem hiding this comment.
The downtime durations are now individual models, with dt and n_timesteps fully incorporated.
| merge_shared_inputs(self.options["tech_config"]["model_inputs"], "performance"), | ||
| additional_cls_name=self.__class__.__name__, | ||
| ) | ||
| if self.options["tech_config"]["model_inputs"]["reliability"]: |
There was a problem hiding this comment.
do we need to use self.options["tech_config"]["model_inputs"].get("reliability", False) here?
There was a problem hiding this comment.
Not exactly, but that did get me thinking on a better way to use use_reliability, so I appreciate the question!
| self.reliability_model = None | ||
| self.use_reliability = False |
There was a problem hiding this comment.
Could these be parameters in the NaturalGasPerformanceConfig? So a user can input reliability_model and use_reliability? Where the __attrs_post_init__ checks that reliability_model is provided if use_reliability is True?
There was a problem hiding this comment.
That's a good question, it didn't dawn on me that a user could want to provide a definition, but not use it. Though it could be easier to iterate on a problem by simply turning it on/off instead of commenting out a whole section of the inputs. I'll also add this to the to do section.
There was a problem hiding this comment.
I forgot to comment, but this is now included with control over the results application being provided in the performance model itself.
…nts in every model
johnjasa
left a comment
There was a problem hiding this comment.
Thanks for this, Rob! I've pushed up small-ish changes directly, one about actually assigning the demand value within the NG component, the other changing the sampling spacing. Take a look and feel free to undo anything there.
Then I've left two comments that may elucidate changes for this PR, follow-on PRs, or never. Regardless, I'm approving so we can get this in by tomorrow!
|
|
||
|
|
||
| # generated from np.random.SeedSequence().entropy | ||
| rng = np.random.default_rng(279299947538423226929715083173412195503) |
There was a problem hiding this comment.
Oh wait, I do have a not-a-joke comment/question about this, though!
The module-level rng is shared across every model in the process, and PerformanceReliability.run() resamples on every compute(). As a result, availability changes between OpenMDAO iterations: two back-to-back run() calls gave mean availability 1.0 and then 0.9945. That could introduce noise when running an optimization with finite differences that might be tough to track down. Is there a different way to set this rng seed, or am I misunderstanding?
| return np.ceil( | ||
| rng.lognormal(self.mean, self.sigma, size=(self.mean.shape[0], 100)) | ||
| / self.simulation.n_timesteps_in_hour | ||
| ).astype(int) |
There was a problem hiding this comment.
If I'm reading the numpy docs correctly, this mean and sigma value are for the underlying normal distribution and not the literal distribution (i.e. hours): https://numpy.org/doc/2.2/reference/random/generated/numpy.random.Generator.lognormal.html#numpy.random.Generator.lognormal
Does that change how we should write this expression here? i.e. do we need to resample in some way? Maybe you already accounted for that but I thought to check!
There was a problem hiding this comment.
Good catch, I didn't match the docstrings to the NumPy docstrings, I'll update it.
Integration of Basic Reliability Modeling
This is a timestep and simulation duration agnostic, WOMBAT-lite reliability model to calculate the availability of a system or collection of systems.
The
PerformanceReliabilityclass enables users to create iid models with separate distributions to simulate failure and maintenance related downtime events using either a Weibull distribution or fixed interval distributionFeatures:
WeibullReliabilityto sample a Weibull distribution for time to next downtime events like WOMBAT's failure modelFixedIntervalReliabilityto create evenly spaced downtime events like WOMBAT's maintenance modelavailability_typethe system-level availability can be calculated as collection of systems (e.g., wind farm) modeled as components taking the average availability across components or a single system (e.g., 1 natural gas turbine) taking the minimum availability across components.UniformDowntime), lognormal distribution (LogNormalDowntime), or fixed duration (FixedDowntime) model.burn_incontrol when in the lifetime of a system the events are taken from instead of repeatedly simulating the first year of operations.BaseDowntimeandBaseReliabilityfor creating new distributions for event frequency and durations.Working example
Section 1: Type of Contribution
Section 2: Draft PR Checklist
TODO: (see other feedback/considerations for what I'm considering or other aspects I could be missing)
Ramping up/down production from 0-1/1-0fn_timestepsas an input to the model in place of using module levelN_TIMESTEPS = 8760.dtas an input to the model for duration of the simulation in place ofN_TIMESTEPS = 8760.use_reliabilityfor a performance model to toggle its usage or check that a model has been provided if using during model initialization.hoursto use adtbasis naming/input schemeType of Reviewer Feedback Requested (on Draft PR)
Structural feedback: Anything is welcome
Implementation feedback: Should the reliability slot into the performance in a more streamlined way? Any other feedback is welcome.
Other feedback/considerations for the finalized PR: It would be great to get feedback on the importance of the following items and any preferred approaches.
better control over random seeding- fixed unless there is a good reason to provide user-level controluncertainty quantification- getting well ahead of ourselvesramping before/after downtime events- better follow-on featuren_timestepsfrom the plant configurationmodel.calculate_availability()?All of the above final considerations were implemented.
Section 3: General PR Checklist
docs/files are up-to-date, or added when necessaryCHANGELOG.md"A complete thought. [PR XYZ]((https://github.com/NatLabRockies/H2Integrate/pull/XYZ)", where
XYZshould be replaced with the actual number.Section 4: Related Issues
Section 5: Impacted Areas of the Software
Section 5.1: New Files
h2integrate/reliability/utilities.pyupdate_dimensions: Checkn_componentsand any passed arguments to either broadcast the input arrays or updaten_componentsfor consistency within a model.calculate_simulation_years: Calculates the length of the simulation period, in years based ondtandn_timesteps.calculate_annual_timesteps: Calculates the rounded up number of timesteps in a year based ondt.calculate_hourly_timesteps: Calculates the rounded up number of timesteps in an hour based ondt.h2integrate/reliability/models.pycreate_reliability_model: Match-case statement to initialize a new reliability model forPerformanceReliabilitycreate_downtime_model: Match-case statement to initialize a new downtime model forBaseReliabilitySimulationConfig: Standardizes the simulation parameters for reuse and computes additional values to handle varying timestep lengths and numberBaseDowntime: abstract base class providing the base attributes and required setup for implemented downtime models.BaseReliability: abstract base class providing the base attributes and required setup for implemented reliability models.PerformanceReliability: WOMBAT-lite style reliability to model both failure and maintenance type events.FixedDowntime: Fixed inteval downtime duration model.UniformDowntime: Uniform distribution-based downtime duration model.LogNormalDowntime: Lognormal distribution-based downtime duration model.WeibullReliability: Weibull distribution-based time to next downtime event model.FixedIntervalReliability: Fixed interval time to next downtime event model.Section 5.2: Modified Files
h2integrate/converters/natural_gas/natural_gas_cc_ct.pyNaturalGasPerformanceModel: Addsuse_reliability(defaultFalse) andreliability_model(defaultNone) to optionally apply thePerformanceReliability.availabilityto thenatural_gas_demandas a limiting factor for production. The availability was not applied to the production because demand is the usage of natural gas to determine the amount of energy produced, so we limit the operational capacity of the natural gas power plant with minimal modification of the actual model.Section 6: Additional Supporting Information
Only the natural gas model has an active implementation of the reliability modeling to limit the amount of modified code in a single PR. Any further modeling implementations can be made as follow-on PRs where more consideration can be made for the intricacies of the performance models.
Section 7: Test Results, if applicable
Tests pass.
Section 8 (Optional): New Model Checklist
docs/developer_guide/coding_guidelines.mdattrsclass to define theConfigto load in attributes for the modelBaseConfigorCostModelBaseConfiginitialize()method,setup()method,compute()methodCostModelBaseClass__init__.pyfile to ensure it is properly imported and used insupported_models.pysupported_models.pycreate_financial_modelinh2integrate_model.pytest_all_examples.pydocs/user_guide/model_overview.mddocs/section<model_name>.mdis added to the_toc.ymlgenerate_class_hierarchy.pyto update the class hierarchy diagram indocs/developer_guide/class_structure.md