Newer
Older
Florian Obersteiner
committed
from enum import IntEnum
"""Default number format for output. Provides the `fmt` parameter of :func:`numpy.savetxt` internally."""
DEFAULT_FIELD_DELIM = ","
"""Default field delimiter"""
DEFAULT_SCALE_FACTOR = 1.0
"""Default variable scale factor"""
DEFAULT_MISSING_VALUE = -9999.0
"""Default variable missing value"""
"""ICARTT File Format Indices (FFI)"""
Christoph Knote
committed
"""ICARTT Variable Types"""
IndependentVariable = 1
IndependentBoundedVariable = 2
AuxiliaryVariable = 3
DependentVariable = 4
def __init__(self, ivar, dvars):
self.varnames = [ivar.shortname] + [x for x in dvars]
Christoph Knote
committed
self.missingValues = {x: dvars[x].miss for x in dvars}
self.missingValues.update({self.ivarname: ivar.miss})
self.default_dtype = np.float64
self.dtypes = [(name, self.default_dtype) for name in self.varnames]
def __getitem__(self, s=slice(None)):
# we can only slice if we have something, so
if self.data is not None:
return self.data[s]
# returns None implicitly if self.data is None
def addFromTxt(self, f, delimiter, max_rows=None):
Christoph Knote
committed
# genfromtxt would warn if file is empty. We do not want that.
with warnings.catch_warnings():
warnings.simplefilter("ignore")
newData = np.genfromtxt(
f,
names=self.varnames,
dtype=self.dtypes,
missing_values=self.missingValues,
usemask=True,
Christoph Knote
committed
max_rows=max_rows,
deletechars="",
).filled(fill_value=np.nan)
self.add(newData)
def add(self, newData):
"""(bulk) add data, providing a (structured) numpy array.
Christoph Knote
committed
Array has to have shape [ (ivar, dvar, dvar, ...), ... ],
missing values have to be set to :obj:`numpy.nan`.
Christoph Knote
committed
:param newData: data to be added
:type newData: numpy.ndarray
"""
if not isinstance(newData, np.ndarray):
raise TypeError("Input data needs to be numpy ndarray.")
Christoph Knote
committed
if newData.dtype.names is None:
try:
newData.dtype = [(name, newData.dtype) for name in self.varnames]
except:
ValueError(
Christoph Knote
committed
"Could not assign names to data structure, are you providing an array containing all variables?"
)
Christoph Knote
committed
self.data = newData
Christoph Knote
committed
self.data = np.append(self.data, newData)
Christoph Knote
committed
for k, miss in self.missingValues.items():
def write(
self, f=sys.stdout, fmt=DEFAULT_NUM_FORMAT, delimiter=DEFAULT_FIELD_DELIM
):
# TODO the fact that we need to clean before writing suggests we need to be more careful what to "add" in the first place!
# single line data is 0D if passed as tuple, savetxt cannot work with 0D. Make 1D.
Christoph Knote
committed
if d.ndim == 0:
d = np.array([d])
# need to squeeze extra dimension added for one liners added as np.array
if len(d.shape) == 2:
d = np.squeeze(d, axis=1)
np.savetxt(f, d, fmt=fmt, delimiter=delimiter)
class DataStore2110(collections.UserDict):
def __init__(self, ivar, ibvar, auxvars, dvars):
self.ivarname = ivar.shortname
self.ibvarname = ibvar.shortname
self.auxvarnames = [x for x in auxvars]
self.dvarnames = [x for x in dvars]
Christoph Knote
committed
self.missingValues = {x: dvars[x].miss for x in dvars}
self.missingValues.update({x: auxvars[x].miss for x in auxvars})
self.missingValues.update({self.ibvarname: ibvar.miss})
self.missingValues.update({self.ivarname: ivar.miss})
self.nauxvarname = self.auxvarnames[0] # convention!
self.ivar = ivar
self.auxvars = auxvars
self.ibvar = ibvar
self.dvars = dvars
def __getitem__(self, s=slice(None)):
# we can only slice if we have something, so
if self.data is not None:
return self.data[s]
# returns None implicitly if self.data is None
def addFromTxt(self, f, delimiter):
Christoph Knote
committed
while f:
auxds = DataStore1001(self.ivar, self.auxvars)
depds = DataStore1001(self.ibvar, self.dvars)
try:
auxds.addFromTxt(f, delimiter, max_rows=1)
Christoph Knote
committed
except:
# we are at the end of the file if this happens
break
ndeprows = int(auxds[self.nauxvarname])
# it is indeed possible to have zero dependent data lines
if ndeprows > 0:
try:
depds.addFromTxt(f, delimiter, max_rows=ndeprows)
except:
raise IOError("Could not read dependent data lines.")
Christoph Knote
committed
ivarValue = float(auxds[self.ivar.shortname])
self.data[ivarValue] = {"AUX": auxds, "DEP": depds}
Christoph Knote
committed
def add(self, newAuxData, newDepData):
"""(bulk) add data, providing (structured) numpy arrays for both the auxiliary and dependent data line(s)
for a given ivar value.
Arrays have to have shape [ (ivar, auxvar, auxvar, ...) ] and
[ (ibvar, depvar, depvar, ...), ... ] for auxiliary and dependent data line(s), respectively.
missing values have to be set to :obj:`numpy.nan`.
:param newAuxData: auxiliary data line to be added
:type newAuxData: numpy.ndarray
:param newDepData: auxiliary data line(s) to be added
:type newDepData: numpy.ndarray
"""
Christoph Knote
committed
auxds = DataStore1001(self.ivar, self.auxvars)
depds = DataStore1001(self.ibvar, self.dvars)
Christoph Knote
committed
auxds.add(newAuxData)
depds.add(newDepData)
Christoph Knote
committed
ivarValue = float(auxds[self.ivar.shortname])
self.data[ivarValue] = {"AUX": auxds, "DEP": depds}
Loading
Loading full blame...