# -*- coding: utf-8 -*-
# pylint: disable=no-member
"""
reV-NRWAL analysis module.
This module runs reV data through the NRWAL compute library. This code was
first developed to use a custom offshore wind LCOE equation library but has
since been refactored to analyze any equation library in NRWAL.
Everything in this module operates on the spatiotemporal resolution of the reV
generation output file. This is usually the wind or solar resource resolution
but could be the supply curve resolution after representative profiles is run.
"""
import logging
from warnings import warn
import numpy as np
import pandas as pd
from reV.generation.generation import Gen
from reV.handlers.outputs import Outputs
from reV.utilities import SiteDataField, ResourceMetaField, log_versions
from reV.utilities.exceptions import (
DataShapeError,
OffshoreWindInputError,
OffshoreWindInputWarning,
)
logger = logging.getLogger(__name__)
[docs]class RevNrwal:
"""RevNrwal"""
DEFAULT_META_COLS = (SiteDataField.CONFIG, )
"""Columns from the `site_data` table to join to the output meta data"""
def __init__(self, gen_fpath, site_data, sam_files, nrwal_configs,
output_request, save_raw=True,
meta_gid_col=str(ResourceMetaField.GID), # str() to fix docs
site_meta_cols=None):
"""Framework to handle reV-NRWAL analysis.
``reV`` NRWAL analysis runs ``reV`` data through the NRWAL
compute library. Everything in this module operates on the
spatiotemporal resolution of the ``reV`` generation output file
(usually the wind or solar resource resolution but could also be
the supply curve resolution after representative profiles is
run).
Parameters
----------
gen_fpath : str
Full filepath to HDF5 file with ``reV`` generation or
rep_profiles output. Anything in the `output_request` input
is added to and/or manipulated within this file.
.. Note:: If executing ``reV`` from the command line, this
input can also be ``"PIPELINE"`` to parse the output of
one of the previous step and use it as input to this call.
However, note that duplicate executions of ``reV``
commands prior to this one within the pipeline may
invalidate this parsing, meaning the `gen_fpath` input
will have to be specified manually.
site_data : str | pd.DataFrame
Site-specific input data for NRWAL calculation.If this input
is a string, it should be a path that points to a CSV file.
Otherwise, this input should be a DataFrame with
pre-extracted site data. Rows in this table should match
the `meta_gid_col` in the `gen_fpath` meta data input
sites via a ``gid`` column. A ``config`` column must also be
provided that corresponds to the `nrwal_configs` input. Only
sites with a gid in this file's ``gid`` column will be run
through NRWAL.
sam_files : dict | str
A dictionary mapping SAM input configuration ID(s) to SAM
configuration(s). Keys are the SAM config ID(s) which
correspond to the keys in the `nrwal_configs` input. Values
for each key are either a path to a corresponding SAM
config file or a full dictionary of SAM config inputs. For
example::
sam_files = {
"default": "/path/to/default/sam.json",
"onshore": "/path/to/onshore/sam_config.yaml",
"offshore": {
"sam_key_1": "sam_value_1",
"sam_key_2": "sam_value_2",
...
},
...
}
This input can also be a string pointing to a single SAM
config file. In this case, the ``config`` column of the
CSV points input should be set to ``None`` or left out
completely. See the documentation for the ``reV`` SAM class
(e.g. :class:`reV.SAM.generation.WindPower`,
:class:`reV.SAM.generation.PvWattsv8`,
:class:`reV.SAM.generation.Geothermal`, etc.) for
documentation on the allowed and/or required SAM config file
inputs.
nrwal_configs : dict
A dictionary mapping SAM input configuration ID(s) to NRWAL
configuration(s). Keys are the SAM config ID(s) which
correspond to the keys in the `sam_files` input. Values
for each key are either a path to a corresponding NRWAL YAML
or JSON config file or a full dictionary of NRWAL config
inputs. For example::
nrwal_configs = {
"default": "/path/to/default/nrwal.json",
"onshore": "/path/to/onshore/nrwal_config.yaml",
"offshore": {
"nrwal_key_1": "nrwal_value_1",
"nrwal_key_2": "nrwal_value_2",
...
},
...
}
output_request : list | tuple
List of output dataset names to be written to the
`gen_fpath` file. Any key from the NRWAL configs or any of
the inputs (site_data or sam_files) is available to be
exported as an output dataset. If you want to manipulate a
dset like ``cf_mean`` from `gen_fpath` and include it in the
`output_request`, you should set ``save_raw=True`` and then
use ``cf_mean_raw`` in the NRWAL equations as the input.
This allows you to define an equation in the NRWAL configs
for a manipulated ``cf_mean`` output that can be included in
the `output_request` list.
save_raw : bool, optional
Flag to save an initial ("raw") copy of input datasets from
`gen_fpath` that are also part of the `output_request`. For
example, if you request ``cf_mean`` in output_request but
also manipulate the ``cf_mean`` dataset in the NRWAL
equations, the original ``cf_mean`` will be archived under
the ``cf_mean_raw`` dataset in `gen_fpath`.
By default, ``True``.
meta_gid_col : str, optional
Column label in the source meta data from `gen_fpath` that
contains the unique gid identifier. This will be joined to
the site_data ``gid`` column. By default, ``"gid"``.
site_meta_cols : list | tuple, optional
Column labels from `site_data` to be added to the meta data
table in `gen_fpath`. If ``None``, only the columns in
:attr:`DEFAULT_META_COLS` will be added. Any columns
requested via this input will be considered *in addition to*
the :attr:`DEFAULT_META_COLS`. By default, ``None``.
"""
log_versions(logger)
# delayed NRWAL import to cause less errors with old reV installs
# if not running nrwal.
from NRWAL import NrwalConfig
self._meta_gid_col = meta_gid_col
self._gen_fpath = gen_fpath
self._site_data = site_data
self._output_request = output_request
self._meta_out = None
self._time_index = None
self._save_raw = save_raw
self._nrwal_inputs = self._out = None
self._nrwal_configs = {
k: NrwalConfig(v) for k, v in nrwal_configs.items()
}
self._site_meta_cols = site_meta_cols
if self._site_meta_cols is None:
self._site_meta_cols = list(self.DEFAULT_META_COLS)
else:
self._site_meta_cols = list(self._site_meta_cols)
self._site_meta_cols += list(self.DEFAULT_META_COLS)
self._site_meta_cols = list(set(self._site_meta_cols))
self._site_data = self._parse_site_data()
self._meta_source = self._parse_gen_data()
self._analysis_gids, self._site_data = self._parse_analysis_gids()
pc = Gen.get_pc(
self._site_data[[SiteDataField.GID, SiteDataField.CONFIG]],
points_range=None, sam_configs=sam_files, tech='windpower')
self._project_points = pc.project_points
self._sam_sys_inputs = self._parse_sam_sys_inputs()
meta_gids = self.meta_source[self._meta_gid_col].values
logger.info(
'Finished initializing NRWAL analysis module for "{}" '
"{} through {} with {} total generation points and "
"{} NRWAL analysis points.".format(
self._meta_gid_col,
meta_gids.min(),
meta_gids.max(),
len(self.meta_source),
len(self.analysis_gids),
)
)
def _parse_site_data(self, required_columns=(SiteDataField.GID,
SiteDataField.CONFIG)):
"""Parse the site-specific spatial input data file
Parameters
----------
required_columns : tuple | list
List of column names that must be in the site_data in
order to run the reV NRWAL module.
Returns
-------
site_data : pd.DataFrame
Dataframe of extracted site_data. Each row is an analysis point and
columns are spatial data inputs.
"""
if isinstance(self._site_data, str):
self._site_data = pd.read_csv(self._site_data)
if "dist_l_to_ts" in self._site_data:
if self._site_data["dist_l_to_ts"].sum() > 0:
w = (
'Possible incorrect Offshore data input! "dist_l_to_ts" '
"(distance land to transmission) input is non-zero. "
"Most reV runs set this to zero and input the cost "
"of transmission from landfall tie-in to "
"transmission feature in the supply curve module."
)
logger.warning(w)
warn(w, OffshoreWindInputWarning)
for c in required_columns:
if c not in self._site_data:
msg = 'Did not find required "{}" column in site_data!'.format(
c
)
logger.error(msg)
raise KeyError(msg)
self._site_data = self._site_data.sort_values(SiteDataField.GID)
return self._site_data
def _parse_gen_data(self):
"""Parse generation data and get meta data
Returns
-------
meta : pd.DataFrame
Full meta data from gen_fpath.
"""
with Outputs(self._gen_fpath, mode="r") as out:
meta = out.meta
msg = (
'Could not find "{}" column in source generation h5 file '
"meta data! Available cols: {}".format(
self._meta_gid_col, meta.columns.values.tolist()
)
)
assert self._meta_gid_col in meta, msg
# currently an assumption of sorted gids in the reV gen output
msg = "Source capacity factor meta data is not ordered!"
meta_gids = list(meta[self._meta_gid_col])
assert meta_gids == sorted(meta_gids), msg
return meta
def _parse_analysis_gids(self):
"""Check the intersection of the generation gids and the site_data
input gids.
Returns
-------
analysis_gids : np.ndarray
Array indicating which sites in the source meta data to process
with NRWAL. This is the intersection of the gids in the generation
meta data and the gids in the site_data input.
site_data : pd.DataFrame
The site_data table reduced to only those gids that are in the
analysis_gids
"""
meta_gids = self.meta_source[self._meta_gid_col].values
missing = ~np.isin(meta_gids, self._site_data[SiteDataField.GID])
if any(missing):
msg = (
"{} sites from the generation meta data input were "
'missing from the "site_data" input and will not be '
"run through NRWAL: {}".format(
missing.sum(), meta_gids[missing]
)
)
logger.info(msg)
missing = ~np.isin(self._site_data[SiteDataField.GID], meta_gids)
if any(missing):
missing = self._site_data[SiteDataField.GID].values[missing]
msg = ('{} sites from the "site_data" input were missing from the '
'generation meta data and will not be run through NRWAL: {}'
.format(len(missing), missing))
logger.info(msg)
analysis_gids = (set(meta_gids)
& set(self._site_data[SiteDataField.GID]))
analysis_gids = np.array(sorted(list(analysis_gids)))
# reduce the site data table to only those sites being analyzed
mask = np.isin(self._site_data[SiteDataField.GID], meta_gids)
self._site_data = self._site_data[mask]
return analysis_gids, self._site_data
def _parse_sam_sys_inputs(self):
"""Get the SAM system inputs dict from project points.
Returns
-------
system_inputs : pd.DataFrame
DataFrame of SAM config inputs (columns) for every active nrwal
analysis gid (row). Index is resource gids and there is also a
column "gid" with the copied gids.
"""
system_inputs = {}
for gid in self.analysis_gids:
system_inputs[gid] = self._project_points[gid][1]
system_inputs = pd.DataFrame(system_inputs).T
system_inputs = system_inputs.sort_index()
system_inputs[SiteDataField.GID] = system_inputs.index.values
system_inputs.index.name = SiteDataField.GID
mask = system_inputs[SiteDataField.GID].isin(self.analysis_gids)
system_inputs = system_inputs[mask]
return system_inputs
def _init_outputs(self):
"""Initialize a dictionary of outputs with dataset names as keys and
numpy arrays as values. All datasets are initialized as 1D arrays and
must be overwritten if found to be 2D. Only active analysis sites will
have data in the output, sites that were not found in the site_data
"gid" column will not have data in these output arrays
Returns
-------
out : dict
Dictionary of output data
"""
out = {}
for key in self._output_request:
out[key] = np.full(
len(self.analysis_gids), np.nan, dtype=np.float32
)
if key in self.gen_dsets and not self._save_raw:
msg = (
'Output request "{0}" was also found in '
"the source gen file but save_raw=False! If "
"you are manipulating this "
"dset, make sure you set save_raw=False "
'and reference "{0}_raw" as the '
'input in the NRWAL equations and then define "{0}" '
"as the final manipulated dataset.".format(key)
)
logger.warning(msg)
warn(msg)
elif key in self.gen_dsets:
msg = (
'Output request "{0}" was also found in '
"the source gen file. If you are manipulating this "
'dset, make sure you reference "{0}_raw" as the '
'input in the NRWAL equations and then define "{0}" '
"as the final manipulated dataset.".format(key)
)
logger.info(msg)
if key in self._nrwal_inputs:
out[key] = self._nrwal_inputs[key]
return out
def _preflight_checks(self):
"""Run some preflight checks on the offshore inputs"""
sam_files = {
k: v
for k, v in self._project_points.sam_inputs.items()
if k in self._nrwal_configs
}
for cid, sys_in in sam_files.items():
loss1 = sys_in.get("wind_farm_losses_percent", 0)
loss2 = sys_in.get("turb_generic_loss", 0)
if loss1 != 0 or loss2 != 0:
msg = (
'Wind farm loss for config "{}" is not 0. When using '
"NRWAL for offshore analysis, consider using gross "
"capacity factors from reV generation and applying "
"spatially dependent losses from the NRWAL equations"
.format(cid)
)
logger.info(msg)
available_ids = list(self._nrwal_configs.keys())
requested_ids = list(self._site_data[SiteDataField.CONFIG].values)
missing = set(requested_ids) - set(available_ids)
if any(missing):
msg = (
"The following config ids were requested in the offshore "
"data input but were not available in the NRWAL config "
"input dict: {}".format(missing)
)
logger.error(msg)
raise OffshoreWindInputError(msg)
check_gid_order = (self._site_data[SiteDataField.GID].values
== self._sam_sys_inputs[SiteDataField.GID].values)
msg = 'NRWAL site_data and system input dataframe had bad order'
assert (check_gid_order).all(), msg
missing = [c for c in self._site_meta_cols if c not in self._site_data]
if any(missing):
msg = (
"Could not find requested NRWAL site data pass through "
"columns in offshore input data: {}".format(missing)
)
logger.error(msg)
raise OffshoreWindInputError(msg)
def _get_input_data(self):
"""Get all the input data from the site_data, SAM system configs, and
generation h5 file, formatted together in one dictionary for NRWAL.
Returns
-------
nrwal_inputs : dict
Dictionary mapping required NRWAL input variable names (keys) to 1
or 2D arrays of inputs for all the analysis_gids
"""
logger.info("Setting up input data for NRWAL...")
# preconditions for this to work properly
assert len(self._site_data) == len(self.analysis_gids)
assert len(self._sam_sys_inputs) == len(self.analysis_gids)
all_required = []
for config_id, nrwal_config in self._nrwal_configs.items():
all_required += list(nrwal_config.required_inputs)
all_required = list(set(all_required))
missing_vars = [
var
for var in nrwal_config.required_inputs
if var not in self._site_data
and var not in self.meta_source
and var not in self._sam_sys_inputs
and var not in self.gen_dsets
]
if any(missing_vars):
msg = (
"Could not find required input variables {} "
'for NRWAL config "{}" in either the offshore '
"data or the SAM system data!".format(
missing_vars, config_id
)
)
logger.error(msg)
raise OffshoreWindInputError(msg)
meta_data_vars = [
var for var in all_required if var in self.meta_source
]
logger.info(
"Pulling the following inputs from the gen meta data: {}".format(
meta_data_vars
)
)
nrwal_inputs = {
var: self.meta_source[var].values[self.analysis_mask]
for var in meta_data_vars
}
site_data_vars = [var for var in all_required
if var in self._site_data
and var not in nrwal_inputs]
site_data_vars.append(SiteDataField.CONFIG)
logger.info('Pulling the following inputs from the site_data input: {}'
.format(site_data_vars))
for var in site_data_vars:
nrwal_inputs[var] = self._site_data[var].values
sam_sys_vars = [
var
for var in all_required
if var in self._sam_sys_inputs and var not in nrwal_inputs
]
logger.info(
"Pulling the following inputs from the SAM system "
"configs: {}".format(sam_sys_vars)
)
for var in sam_sys_vars:
nrwal_inputs[var] = self._sam_sys_inputs[var].values
gen_vars = [
var
for var in all_required
if var in self.gen_dsets and var not in nrwal_inputs
]
logger.info(
"Pulling the following inputs from the generation "
"h5 file: {}".format(gen_vars)
)
with Outputs(self._gen_fpath, mode="r") as f:
source_gids = self.meta_source[self._meta_gid_col]
gen_gids = np.where(source_gids.isin(self.analysis_gids))[0]
for var in gen_vars:
shape = f.shapes[var]
if len(shape) == 1:
nrwal_inputs[var] = f[var, gen_gids]
elif len(shape) == 2:
nrwal_inputs[var] = f[var, :, gen_gids]
else:
msg = (
'Data shape for "{}" must be 1 or 2D but '
"received: {}".format(var, shape)
)
logger.error(msg)
raise DataShapeError(msg)
logger.info("Finished setting up input data for NRWAL!")
return nrwal_inputs
@property
def time_index(self):
"""Get the source time index."""
if self._time_index is None:
with Outputs(self._gen_fpath, mode="r") as out:
self._time_index = out.time_index
return self._time_index
@property
def gen_dsets(self):
"""Get the available datasets from the gen source file"""
with Outputs(self._gen_fpath, mode="r") as out:
dsets = out.dsets
return dsets
@property
def meta_source(self):
"""Get the full meta data (onshore + offshore)"""
return self._meta_source
@property
def meta_out(self):
"""Get the combined onshore and offshore meta data."""
if self._meta_out is None:
self._meta_out = self._meta_source.copy()
for col in self._site_meta_cols:
data = self._nrwal_inputs[col]
self._meta_out.loc[self.analysis_mask, col] = data
return self._meta_out
@property
def analysis_mask(self):
"""Get a boolean array to mask the source generation meta data where
True is sites that are to be analyzed by NRWAL.
Returns
-------
np.ndarray
"""
mask = np.isin(
self.meta_source[self._meta_gid_col], self.analysis_gids
)
return mask
@property
def analysis_gids(self):
"""Get an array of gids from the source generation meta data that are
to-be analyzed by nrwal.
Returns
-------
np.ndarray
"""
return self._analysis_gids
@property
def outputs(self):
"""Get a dict of NRWAL outputs. Only active analysis sites will have
data in the output, sites that were not found in the site_data "gid"
column will not have data in these output arrays"""
return self._out
def _save_nrwal_out(self, name, nrwal_out, output_mask):
"""Save a dataset from the nrwal_out dictionary to the self._out
attribute
Parameters
----------
name : str
Dataset name of the nrwal output to be saved.
nrwal_out : dict
Output dictionary from a successfully evaluated NrwalConfig object
containing the dataset with the input name
output_mask : np.ndarray
Boolean array showing which gids in self.analysis_gids should be
assigned data from this NRWAL output. If not all true, there are
probably multiple NrwalConfig objects that map to different sets of
gids.
"""
value = nrwal_out[name]
value = self._value_to_array(value, name)
if len(value.shape) == 1:
self._out[name][output_mask] = value[output_mask]
elif len(value.shape) == 2:
if len(self._out[name].shape) == 1:
if not all(np.isnan(self._out[name])):
msg = (
'Output dataset "{}" was initialized as 1D but was '
"later found to be 2D but was not all NaN!".format(
name
)
)
logger.error(msg)
raise DataShapeError(msg)
# re-initialize the dataset as 2D now that we
# know what the output looks like
out_shape = (len(self.time_index), len(self.analysis_gids))
self._out[name] = np.full(out_shape, np.nan, dtype=np.float32)
self._out[name][:, output_mask] = value[:, output_mask]
else:
msg = (
'Could not make sense of NRWAL output "{}" '
"with shape {}".format(name, value.shape)
)
logger.error(msg)
raise DataShapeError(msg)
def _save_nrwal_misc(self, name, nrwal_config, output_mask):
"""Save miscellaneous output requests from a NRWAL config object (not
NRWAL output dictionary) to the self._out attribute.
Parameters
----------
name : str
Dataset name of the nrwal output to be saved.
nrwal_config : NrwalConfig
NrwalConfig object containing NRWAL Equation objects or something
else that is to be exported to the outputs
output_mask : np.ndarray
Boolean array showing which gids in self.analysis_gids should be
assigned data from this NRWAL output. If not all true, there are
probably multiple NrwalConfig objects that map to different sets of
gids.
"""
from NRWAL import Equation
value = nrwal_config[name]
if isinstance(value, Equation):
msg = (
'Cannot retrieve Equation "{}" from NRWAL. '
"Must be a number!".format(name)
)
assert not any(value.variables), msg
value = value.eval()
value = self._value_to_array(value, name)
self._out[name][output_mask] = value[output_mask]
def _value_to_array(self, value, name):
"""Turn the input into numpy array if it isn't already."""
if np.issubdtype(type(value), np.number):
value *= np.ones(len(self.analysis_gids), dtype=np.float32)
if not isinstance(value, np.ndarray):
msg = (
'NRWAL key "{}" returned bad type of "{}", needs to be '
"numeric or an output array.".format(name, type(value))
)
logger.error(msg)
raise TypeError(msg)
return value
[docs] def run_nrwal(self):
"""Run analysis via the NRWAL analysis library"""
self._preflight_checks()
self.save_raw_dsets()
self._nrwal_inputs = self._get_input_data()
self._out = self._init_outputs()
for i, (cid, nrwal_config) in enumerate(self._nrwal_configs.items()):
output_mask = self._site_data[SiteDataField.CONFIG].values == cid
logger.info('Running NRWAL config {} of {}: "{}" and applying '
'to {} out of {} total sites'
.format(i + 1, len(self._nrwal_configs), cid,
output_mask.sum(), len(output_mask)))
nrwal_out = nrwal_config.eval(inputs=self._nrwal_inputs)
# pylint: disable=C0201
for name in self._out.keys():
if name in nrwal_out:
self._save_nrwal_out(name, nrwal_out, output_mask)
elif name in nrwal_config.keys():
self._save_nrwal_misc(name, nrwal_config, output_mask)
elif name not in self._nrwal_inputs:
msg = (
'Could not find "{}" in the output dict of NRWAL '
"config {}".format(name, cid)
)
logger.warning(msg)
warn(msg)
[docs] def check_outputs(self):
"""Check the nrwal outputs for nan values and raise errors if found."""
for name, arr in self._out.items():
if np.isnan(arr).all():
msg = (
'Output array "{}" is all NaN! Probably was not '
"found in the available NRWAL keys.".format(name)
)
logger.warning(msg)
warn(msg)
elif np.isnan(arr).any():
mask = np.isnan(arr)
nan_meta = self.meta_source[self.analysis_mask][mask]
nan_gids = nan_meta[self._meta_gid_col].values
msg = (
"NaN values ({} out of {}) persist in NRWAL "
'output "{}"!'.format(np.isnan(arr).sum(), len(arr), name)
)
logger.warning(msg)
logger.warning(
"This is the NRWAL meta that is causing NaN "
"outputs: {}".format(nan_meta)
)
logger.warning(
"These are the resource gids causing NaN "
"outputs: {}".format(nan_gids)
)
warn(msg)
[docs] def save_raw_dsets(self):
"""If requested by save_raw=True, archive raw datasets that exist in
the gen_fpath file and are also requested in the output_request"""
if self._save_raw:
with Outputs(self._gen_fpath, "a") as f:
for dset in self._output_request:
dset_raw = "{}_raw".format(dset)
if dset in f and dset_raw not in f:
logger.info(
'Saving raw data from "{}" to "{}"'.format(
dset, dset_raw
)
)
f._add_dset(
dset_raw,
f[dset],
f.dtypes[dset],
attrs=f.attrs[dset],
)
[docs] def write_to_gen_fpath(self):
"""Save NRWAL outputs to input generation fpath file.
Returns
-------
str
Path to output file.
"""
logger.info("Writing NRWAL outputs to: {}".format(self._gen_fpath))
write_all = self.analysis_mask.all()
with Outputs(self._gen_fpath, "a") as f:
meta_attrs = f.attrs["meta"]
del f._h5["meta"]
f._set_meta("meta", self.meta_out, attrs=meta_attrs)
for dset, arr in self._out.items():
if len(arr.shape) == 1:
data = np.full(
len(self.meta_source), np.nan, dtype=np.float32
)
else:
full_shape = (len(self.time_index), len(self.meta_source))
data = np.full(full_shape, np.nan, dtype=np.float32)
dset_attrs = {"scale_factor": 1}
dset_dtype = np.float32
if dset in f.dsets:
logger.info(
'Found "{}" in file, loading data and '
"overwriting data for {} out of {} sites.".format(
dset,
self.analysis_mask.sum(),
len(self.analysis_mask),
)
)
dset_attrs = f.attrs[dset]
dset_dtype = f.dtypes[dset]
if not write_all:
data = f[dset]
if len(arr.shape) == 1:
data[self.analysis_mask] = arr
else:
data[:, self.analysis_mask] = arr
logger.info(
'Writing final "{}" to: {}'.format(dset, self._gen_fpath)
)
f._add_dset(dset, data, dset_dtype, attrs=dset_attrs)
logger.info(
"Finished writing NRWAL outputs to: {}".format(self._gen_fpath)
)
return self._gen_fpath
[docs] def run(self, csv_output=False, out_fpath=None):
"""Run NRWAL analysis.
Parameters
----------
csv_output : bool, optional
Option to write H5 file meta + all requested outputs to
CSV file instead of storing in the HDF5 file directly. This
can be useful if the same HDF5 file is used for multiple
sets of NRWAL runs. Note that all requested output datasets
must be 1-dimensional in order to fir within the CSV output.
.. Important:: This option is not compatible with
``save_raw=True``. If you set ``csv_output=True``, then
the `save_raw` option is forced to be ``False``.
Therefore, make sure that you do not have any references
to "input_dataset_name_raw" in your NRWAL config. If you
need to manipulate an input dataset, save it to a
different output name in the NRWAL config or manually add
an "input_dataset_name_raw" dataset to your generation
HDF5 file before running NRWAL.
By default, ``False``.
out_fpath : str, optional
This option has no effect if ``csv_output=False``.
Otherwise, this should be the full path to output NRWAL CSV
file. The file path does not need to include file ending -
it will be added automatically if missing. If ``None``, the
generation HDF5 filepath will be converted to a CSV out path
by replacing the ".h5" file ending with ".csv".
By default, ``None``.
Returns
-------
str
Path to output file.
"""
if csv_output and self._save_raw:
msg = (
"`save_raw` option not allowed with `csv_output`. Setting"
"`save_raw=False`"
)
logger.warning(msg)
warn(msg)
self._save_raw = False
if any(self.analysis_gids):
self.run_nrwal()
self.check_outputs()
if csv_output:
out_fp = self.write_meta_to_csv(out_fpath)
else:
out_fp = self.write_to_gen_fpath()
logger.info("NRWAL module complete!")
return out_fp