wisdem / wombat Goto Github PK
View Code? Open in Web Editor NEWWindfarm Operations & Maintenance cost-Benefit Analysis Tool
Home Page: https://wisdem.github.io/WOMBAT/
License: Apache License 2.0
Windfarm Operations & Maintenance cost-Benefit Analysis Tool
Home Page: https://wisdem.github.io/WOMBAT/
License: Apache License 2.0
Pandas 2.0 has greatly decreased the runtime performance of WOMBAT due to significantly slower indexing and search. Initial tests confirm that Polars is significantly faster at the exact operations required in the simulation, and so it'd be beneficial to convert the weather dataframe, specifically. Below is an example of extracting a single row from the weather profile in both pandas and polars.
I was running the how_to
jupyter notebook (see the code that I ran below) and encounter the following errors. I think the issue is that the code expects the first column of the event log file to have the column names. I can resolve this issue by setting the read_option to be ReadOptions(autogenerate_column_names=True)
, but then another error popped up as the code is expecting the some fixed column names such as date_time
.
Code
from time import perf_counter
from wombat import Simulation
from wombat.core.library import load_yaml, DINWOODIE
library_path = DINWOODIE
config = load_yaml(library_path / "project/config", "base.yaml")
sim = Simulation.from_config(config)
sim.env.cleanup_log_files()
start = perf_counter()
sim.run()
end = perf_counter()
timing = end - start
print(f"Run time: {timing / 60:,.2f} minutes")
Error Message
ValueError Traceback (most recent call last)
Cell In[2], line 2
1 start = perf_counter()
----> 2 sim.run()
3 end = perf_counter()
4 timing = end - start
File ~/miniconda3/envs/wisdem/lib/python3.10/site-packages/wombat/core/simulation_api.py:326, in Simulation.run(self, until, create_metrics, save_metrics_inputs)
324 self.save_metrics_inputs()
325 if create_metrics:
--> 326 self.initialize_metrics()
File ~/miniconda3/envs/wisdem/lib/python3.10/site-packages/wombat/core/simulation_api.py:330, in Simulation.initialize_metrics(self)
328 def initialize_metrics(self) -> None:
329 """Instantiates the ``metrics`` attribute after the simulation is run."""
--> 330 events = self.env.load_events_log_dataframe()
331 operations = self.env.load_operations_log_dataframe()
332 power_potential, power_production = self.env.power_production_potential_to_csv(
333 windfarm=self.windfarm, operations=operations, return_df=True
334 )
File ~/miniconda3/envs/wisdem/lib/python3.10/site-packages/wombat/core/environment.py:679, in WombatEnvironment.load_events_log_dataframe(self)
671 convert_options = pa.csv.ConvertOptions(
672 timestamp_parsers=["%Y-%m-%d %H:%M:%S.%f", "%Y-%m-%d %H:%M:%S"]
673 )
674 parse_options = pa.csv.ParseOptions(delimiter="|")
675 log_df = pa.csv.read_csv(
676 self.events_log_fname,
677 convert_options=convert_options,
678 parse_options=parse_options,
--> 679 ).to_pandas()
680 if not pd.api.types.is_datetime64_any_dtype(log_df.datetime):
681 log_df.datetime = pd.to_datetime(
682 log_df.datetime, yearfirst=True, format="mixed"
683 )
File ~/miniconda3/envs/wisdem/lib/python3.10/site-packages/pyarrow/array.pxi:837, in pyarrow.lib._PandasConvertible.to_pandas()
File ~/miniconda3/envs/wisdem/lib/python3.10/site-packages/pyarrow/table.pxi:4114, in pyarrow.lib.Table._to_pandas()
File ~/miniconda3/envs/wisdem/lib/python3.10/site-packages/pyarrow/pandas_compat.py:819, in table_to_blockmanager(options, table, categories, ignore_metadata, types_mapper)
816 ext_columns_dtypes = _get_extension_dtypes(table, [], types_mapper)
818 _check_data_column_metadata_consistency(all_columns)
--> 819 columns = _deserialize_column_index(table, all_columns, column_indexes)
820 blocks = _table_to_blocks(options, table, categories, ext_columns_dtypes)
822 axes = [columns, index]
File ~/miniconda3/envs/wisdem/lib/python3.10/site-packages/pyarrow/pandas_compat.py:938, in _deserialize_column_index(block_table, all_columns, column_indexes)
935 columns = _reconstruct_columns_from_metadata(columns, column_indexes)
937 # ARROW-1751: flatten a single level column MultiIndex for pandas 0.21.0
--> 938 columns = _flatten_single_level_multiindex(columns)
940 return columns
File ~/miniconda3/envs/wisdem/lib/python3.10/site-packages/pyarrow/pandas_compat.py:1184, in _flatten_single_level_multiindex(index)
1182 # Cheaply check that we do not somehow have duplicate column names
1183 if not index.is_unique:
-> 1184 raise ValueError('Found non-unique column index')
1186 return pd.Index(
1187 [levels[_label] if _label != -1 else None for _label in labels],
1188 dtype=dtype,
1189 name=index.names[0]
1190 )
1191 return index
ValueError: Found non-unique column index
First 4 lines of the event log file (note no column names)
2023-06-20 21:56:06.625773|2003-01-01 00:00:00|0|S00T1|subassemblies created: ['turbine']|windfarm initialization|initialization|S00T1|S00T1|||1.0|1|0|0|na|na|0|0|0|0|0|0
2023-06-20 21:56:06.657014|2003-01-01 00:00:00|0|S00T2|subassemblies created: ['turbine']|windfarm initialization|initialization|S00T2|S00T2|||1.0|1|0|0|na|na|0|0|0|0|0|0
2023-06-20 21:56:06.685828|2003-01-01 00:00:00|0|S00T3|subassemblies created: ['turbine']|windfarm initialization|initialization|S00T3|S00T3|||1.0|1|0|0|na|na|0|0|0|0|0|0
Weather profiles that have more columns than ["datetime", "windspeed", "wave_height"]
will cause an error here: https://github.com/WISDEM/WOMBAT/blob/main/wombat/core/environment.py#L520.
A simple fix such as the following could allow for more robust workflows using WOMBAT:
wind, wave, hour, *_ = self.weather.values[start:end].T
If CTVs are always on site, the total duration of all activities should be equal to the simulation period. This isn't the case. Comparing the cumulative CTV activity duration and the env_time, it looks like the CTV is allowing 2x each weather delay to elapse before it tries to do anything. This also appears to be true for vessels that are not always on site.
Have a way to reference power curves in NREL/turbine-models to allow for quick access to a variety of power curves.
A model to post-hoc apply aggregate model losses (wake, electrical, etc.) would be ideal to better translate between the power production model and what is typically seen in operational analyses.
Potentially consider providing date, or set of dates for when to trigger a timeout instead of a fixed time frequency. This allows maintenance to be scheduled in particular times of year.
Enable the ability to model sea surface icing or turbine icing for crew accessibility/safety constraints. This would require humidity, temperature, and visibility constraints (helicopter access).
I seem to have found a small bug in which the random seed I set in my configuration file is not being used in the simulation.
I created my simulation using Simulation() rather than the Simulation.from_config(). Unlike when using the from_config function, when using the default class initialization my random seed loads correctly as part of the Simulation.config attribute but is not applied to the Simulation.random_seed attribute directly. When Simulation._setup_simulation() calls, it passes only the random_seed attribute on the simulation object, not the version from the config attribute, when it instantiates the WombatEnvironment class. As a result, the environment detects no random seed.
Apologies if I have misunderstood something, but it seems like this is probably not the desired behaviour. Everything works fine if I pass the random seed directly as a parameter into the Simulation() function, or if I load using from_config(), so it seems to just be this one case which has the problem.
I am using WOMBAT v0.9.3.
Consider a flag in a failure/maintenance model that can allow certain operations, such as a mooring or substructure repair, that can have crew working while the turbine is operating.
Functionality to enable multiple service crews in one servicing equipment, particularly for offshore wind scenarios would enable more realistic crew transfer vessel functionality
In line 1304 of post_processor.py, the datatypes have to be cast after creation.
To better understand the effect of model uncertainty, it would be great to have the ability to model a probability distribution surrounding the failure rates in the model.
It would be great if any operations at site wouldn't start until the next shift if less than an hour or two of work will be done on that task in the current shift.
Alternatively, it could make sense for shifts to be continuous with a rotating crew for x number of days until a vessel refresh is required, with a default of a single shift to maintain compatibility with land-based servicing regimes.
A major innovation in offshore wind will be tow-to-port repairs, and should be considered for the next batch of model updates.
After some external review it would be best to revamp the tow-to-port model now that it works and does pretty well overall compare to other models.
To better understand the tradeoffs in weather conditions, it would be ideal to have a probabilistic weather model, as opposed to a fixed weather model. In addition, it would enable more robust model comparison for various global regions with some predefined inputs to be used for weather profile generation instead of creating/downloading and modifying unique weather profiles.
To simplify revisiting a simulation's outputs, a new method should be added to wombat.core.simulation.Simulation
that saves the data that wombat.core.post_processor.Metrics
relies on for inputs with names like:
Metrics.from_simulation_output()
Simulation.save_metrics_inputs()
Provide an easy to use CLI for users in place of writing a script to run simulations.
When export and array cables have an operating reduction in the range of (0, 1), this does not have an impact on turbine, substation, or farm operating capacity, availability, or downtime.
Hi
Trying to reproduce the corewind tow to port case. Before starting my own simulations.
When running it I get a simulation failed message as below.
Is this something that has been experienced before?
Regards
Filip
library_path = Path(r."WOMBAT\library\corewind")
config = load_yaml("corewind/project/config", "morro_bay_tow_to_port.yaml")
sim = Simulation(library_path=library_path, config=config, random_seed=2023)
sim.run()
Simulation failed at hour 118,560.500503, simulation time: 2015-07-12 00:30:02
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File [~\OneDrive](http://localhost:8888/lab/tree/~/OneDrive) [Deducted] - \wombat\core\repair_management.py:264, in RepairManager._run_equipment_requests(self, request)
263 return
--> 264 self.invalidate_system(system, tow=True)
265 yield self.env.process(self.port.run_tow_to_port(request))
File [~\OneDrive](http://localhost:8888/lab/tree/~/OneDrive) - [Deducted] \wombat\core\repair_management.py:532, in RepairManager.invalidate_system(self, system, tow)
530 self.systems_in_tow.append(system.id)
531 _ = self.systems_waiting_for_tow.pop(
--> 532 self.systems_waiting_for_tow.index(system.id)
533 )
ValueError: 'WTG_0607' is not in list
The above exception was the direct cause of the following exception:
ValueError Traceback (most recent call last)
Cell In[35], line 4
1 # Timing for a demonstration of performance
2 start = perf_counter()
----> 4 sim.run()
6 end = perf_counter()
8 timing = end - start
File [~\OneDrive](http://localhost:8888/lab/tree/~/OneDrive [Deducted] wombat\core\simulation_api.py:348, in Simulation.run(self, until, create_metrics, save_metrics_inputs)
325 def run(
326 self,
327 until: int | float | Event | None = None,
328 create_metrics: bool = True,
329 save_metrics_inputs: bool = True,
330 ):
331 """Calls ``WombatEnvironment.run()`` and gathers the results for
332 post-processing. See ``wombat.simulation.WombatEnvironment.run`` or
333 ``simpy.Environment.run`` for more details.
(...)
346 False, the data will not be saved, by default True.
347 """
--> 348 self.env.run(until=until)
349 if save_metrics_inputs:
350 self.save_metrics_inputs()
File [~\OneDrive](http://localhost:8888/lab/tree/~/OneDrive [Deducted]/wombat\core\environment.py:247, in WombatEnvironment.run(self, until)
242 self._operations_csv.close()
243 print(
244 f"Simulation failed at hour {self.now:,.6f},"
245 f" simulation time: {self.simulation_time}"
246 )
--> 247 raise e
249 # Ensure all logged events make it to their target file
250 self._events_writer.writerows(self._events_buffer)
File [~\OneDrive](http://localhost:8888/lab/tree/~/OneDrive [Deducted] wombat\core\environment.py:234, in WombatEnvironment.run(self, until)
232 until = self.max_run_time
233 try:
--> 234 super().run(until=until)
235 except BaseException as e:
236 # Flush the logs to so the simulation up to the point of failure is logged
237 self._events_writer.writerows(self._events_buffer)
File [~\miniconda3\envs\wombat39\lib\site-packages\simpy\core.py:246](http://localhost:8888/lab/tree/~/miniconda3/envs/wombat39/lib/site-packages/simpy/core.py#line=245), in Environment.run(self, until)
244 try:
245 while True:
--> 246 self.step()
247 except StopSimulation as exc:
248 return exc.args[0] # == until.value
File [~\miniconda3\envs\wombat39\lib\site-packages\simpy\core.py:204](http://localhost:8888/lab/tree/~/miniconda3/envs/wombat39/lib/site-packages/simpy/core.py#line=203), in Environment.step(self)
202 exc = type(event._value)(*event._value.args)
203 exc.__cause__ = event._value
--> 204 raise exc
ValueError: 'WTG_0607' is not in list
When a failure occurs with a 100% operation reduction, but does not require a replacement, the repair does not return the subsystem to operational and instead the subsystem remains broken for the entire simulation.
A more detailed description of the behavior can be found here : https://forums.nrel.gov/t/wombat-shut-down-i-e-100-operation-reduction-without-replacement/6552
When an array cable string splits into two diverging upstream paths, the upstream cable/turbine connections don't resolve correctly. Likely a customized graph model is required for this scenario instead of a sequentially defined, CSV-based model.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.