diff --git a/docs/ESDS-RFC-029v2.pdf b/docs/ESDS-RFC-029v2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..544d060dd0318347c95829dfcdc64dc2a5b85374 Binary files /dev/null and b/docs/ESDS-RFC-029v2.pdf differ diff --git a/icartt/__init__.py b/icartt/__init__.py index 57872f23c281dbc5def94f58add02677dd1e1934..d540827dbc0de2c16a84b69e9e66d91448c19390 100644 --- a/icartt/__init__.py +++ b/icartt/__init__.py @@ -1 +1 @@ -from .dataset import Variable, Dataset \ No newline at end of file +from .dataset import Dataset, SimpleNormalComments, StandardNormalComments \ No newline at end of file diff --git a/icartt/dataset.py b/icartt/dataset.py index c620eb2ae4a31e32d3c543d9474b371a1efc5381..be9f8fc9112fb220c692d92d50c1e70ac7b7b85f 100644 --- a/icartt/dataset.py +++ b/icartt/dataset.py @@ -1,7 +1,107 @@ import datetime import sys +import collections +import copy +import math +from functools import total_ordering -class Variable: +IMPLEMENTED_FORMATS = [ 1001, 2110 ] + +class SimpleNormalComments(collections.UserList): + @property + def data(self): + return self.contents + def __init__(self, contents=[]): + self.contents = contents + +class StandardNormalComments(SimpleNormalComments): + @property + def data(self): + return [ k + ": " + str(v) for k, v in self.keywords.items() ] + self.freeform + [ self.shortnames ] + def ingest(self, raw): + # last line is always shortname + self.shortnames = raw.pop() + + # rest is either keyword, or free form + for l in raw: + is_keyword = False + for k in self.keywords: + if l.startswith(k + ":"): + self.keywords[k] = l.replace(k + ":", "").strip() + is_keyword = True + break + if not is_keyword: + self.freeform.append(l) + + def __init__(self, contents=[]): + self.freeform = [] + self.keywords = { + "PI_CONTACT_INFO": "N/A", + "PLATFORM": "N/A", + "LOCATION": "N/A", + "ASSOCIATED_DATA": "N/A", + "INSTRUMENT_INFO": "N/A", + "DATA_INFO": "N/A", + "UNCERTAINTY": -1, + "ULOD_FLAG": "N/A", + "ULOD_VALUE": "N/A", + "LLOD_FLAG": "N/A", + "LLOD_VALUE": "N/A", + "DM_CONTACT_INFO": "N/A", + "PROJECT_INFO": "N/A", + "STIPULATIONS_ON_USE": "N/A", + "OTHER_COMMENTS": "N/A", + "REVISION": 0, + "R0": "N/A" + } + self.shortnames = [] + + if not contents is []: + self.ingest(contents) + +class Data_1001(collections.UserList): + def write(self, prnt=lambda x: sys.stdout.write(x)): + for line in zip(zip(self.ivar), *self.dvar): + prnt([ line[0][0] ] + [ x[1] for x in line[1:] ]) + + def extract_items(self, raw): + for cur in range(len(raw)): + self.ivar.append_value_from_string_ivar(raw[cur][0]) + nul = [ var.append_value_from_string(raw[cur][0], raw[cur][i+1]) for i, var in enumerate(self.dvar) ] + + def __init__(self, raw=[], ivar=None, dvar=None): + self.ivar = ivar + self.dvar = dvar + # + self.extract_items(raw) + +class Data_2110(Data_1001): + def write(self, prnt=lambda x: sys.stdout.write(x)): + for ivar in self.ivar: + prnt( [ ivar ] + [ a[1] for auxvar in self.auxvar for a in auxvar if a[0] == ivar ] ) + for ibvar in [ b[0][1] for b in self.dvar[0] if b[0][0] == ivar ]: + prnt([ ibvar ] + [ d[1] for dvar in self.dvar for d in dvar if (d[0][0] == ivar) and (d[0][1] == ibvar) ]) + + def extract_items(self, raw): + cur = 0 + while cur < len(raw): + self.ivar.append_value_from_string_ivar(raw[cur][0]) + nul = [ var.append_value_from_string_ibvar(raw[cur][0], raw[cur][i+1]) for i, var in enumerate(self.auxvar) ] + nprimary = int(self.auxvar[0][-0][1]) + for i in range(nprimary): + self.ibvar.append_value_from_string_ibvar(raw[cur][0], raw[i+1][0]) + nul = [ var.append_value_from_string(raw[cur][0], raw[i+1][0], raw[i+1][j+1]) for j, var in enumerate(self.dvar) ] + cur += 1 + nprimary + + def __init__(self, raw=[], ivar=None, ibvar=None, auxvar=None, dvar=None): + self.ivar = ivar + self.ibvar = ibvar + self.auxvar = auxvar + self.dvar = dvar + # + self.extract_items(raw) + +class Variable_1001(collections.UserList): ''' A Variable is a ICARTT variable description with name, units, scale and missing value. ''' @@ -10,18 +110,49 @@ class Variable: ''' Return variable description string as it appears in an ICARTT file ''' - return self.splitChar.join( [self.name, self.units, self.units ] ) - def __init__(self, name, units, scale=1.0, miss=-9999999): + toplot = [self.name, self.units ] + if self.units != self.longname: + toplot += [ self.longname ] + return self.splitChar.join( toplot ) + + def __add__(self, other): + # for doing 'data += something' + for item in other: + self.data.append(item) + return self + + def _sanitize(self, x): + return float(x.strip().replace(self.miss, 'NaN')) + + def append_value_from_string_ivar(self, ivar): + self.data.append(self._sanitize(ivar)) + + def append_value_from_string(self, ivar, dvar): + self.data.append( ( self._sanitize(ivar), self._sanitize(dvar) ) ) + + def __init__(self, name, units, longname, values=[], scale=1.0, miss=-99999, splitChar=","): #: Name - self.name = name + self.name = name #: Units - self.units = units + self.units = units + #: Long name + self.longname = longname + #: Values + self.data = [] #: Scale factor - self.scale = scale + self.scale = scale #: Missing value (string, just as it appears in the ICARTT file) - self.miss = str(miss) + self.miss = str(miss) #: Split character for description string - self.splitChar = ',' + self.splitChar = splitChar + +class Variable_2110(Variable_1001): + def append_value_from_string_ibvar(self, ivar, ibvar): + self.data.append( ( self._sanitize(ivar) , self._sanitize(ibvar) ) ) + + def append_value_from_string(self, ivar, ibvar, dvar): + self.data.append( ( ( self._sanitize(ivar), self._sanitize(ibvar) ) , self._sanitize(dvar) ) ) + class Dataset: ''' @@ -33,9 +164,11 @@ class Dataset: ''' Header line count ''' - total = 12 + self.ndvar + 1 + self.nscom + 1 + self.nncom + total = -1 + if self.format == 1001: + total = 14 + self.ndvar + self.nscom + self.nncom if self.format == 2110: - total += self.nauxvar + 5 + total = 16 + self.nivar + self.nauxvar + self.ndvar + self.nscom + self.nncom return total @property def ndvar(self): @@ -44,6 +177,12 @@ class Dataset: ''' return len(self.DVAR) @property + def nivar(self): + ''' + Independent variable count + ''' + return 1 + (0 if self.IBVAR is None else 1) + @property def nauxvar(self): ''' Auxiliary variables count @@ -52,9 +191,9 @@ class Dataset: @property def nvar(self): ''' - Variable count (independent + dependent) + Variable count (independent + dependent + auxiliary) ''' - return self.ndvar + 1 + return len(self.VAR) @property def nscom(self): ''' @@ -70,9 +209,12 @@ class Dataset: @property def VAR(self): ''' - Variables (independent and dependent) + Variables (independent + dependent + auxiliary) ''' - return [ self.IVAR ] + self.DVAR + vars = [ self.IVAR ] + self.DVAR + if self.format == 2110: + vars = [ self.IBVAR ] + vars + self.AUXVAR + return vars @property def varnames(self): ''' @@ -93,17 +235,17 @@ class Dataset: ict = icartt.Dataset() ict['O3'] ''' - idx = self.index(name) - if idx == -1: + var = [ x for x in self.VAR if x.name == name ] + if not len(var) == 1: raise Exception("{:s} not found in data".format(name)) - return [ x[idx] for x in self.data ] + return var[0] def units(self, name): ''' Units of variable ''' res = [ x.units for x in self.VAR if x.name == name ] - if len(res) is 0: + if len(res) == 0: res = [ '' ] return res[0] @@ -112,7 +254,7 @@ class Dataset: Index of variable in data array ''' res = [ i for i, x in enumerate(self.VAR) if x.name == name ] - if len(res) is 0: + if len(res) == 0: res = [ -1 ] return res[0] @@ -134,20 +276,20 @@ class Dataset: # Mission name (usually the mission acronym). prnt(self.mission) # File volume number, number of file volumes (these integer values are used when the data require more than one file per day; for data that require only one file these values are set to 1, 1) - comma delimited. - prnt(self.splitChar.join([ str(self.VOL), str(self.NVOL) ])) + prnt(self.splitChar.join([ str(self.volume), str(self.nvolumes) ])) # UTC date when data begin, UTC date of data reduction or revision - comma delimited (yyyy, mm, dd, yyyy, mm, dd). - prnt(self.splitChar.join([ datetime.datetime.strftime(x, "%Y, %m, %d") for x in [ self.dateValid, self.dateRevised ] ])) + prnt(self.splitChar.join([ datetime.datetime.strftime(x, self.splitChar.join(["%Y","%m","%d"])) for x in [ self.dateValid, self.dateRevised ] ])) # Data Interval (This value describes the time spacing (in seconds) between consecutive data records. It is the (constant) interval between values of the independent variable. For 1 Hz data the data interval value is 1 and for 10 Hz data the value is 0.1. All intervals longer than 1 second must be reported as Start and Stop times, and the Data Interval value is set to 0. The Mid-point time is required when it is not at the average of Start and Stop times. For additional information see Section 2.5 below.). - prnt("0") - # Description or name of independent variable (This is the name chosen for the start time. It always refers to the number of seconds UTC from the start of the day on which measurements began. It should be noted here that the independent variable should monotonically increase even when crossing over to a second day.). - prnt(self.IVAR.desc) + prnt(self.dataInterval) if self.format == 2110: # Description or name of independent (bound) variable (This is the name chosen for the start time. It always refers to the number of seconds UTC from the start of the day on which measurements began. It should be noted here that the independent variable should monotonically increase even when crossing over to a second day.). prnt(self.IBVAR.desc) + # Description or name of independent variable (This is the name chosen for the start time. It always refers to the number of seconds UTC from the start of the day on which measurements began. It should be noted here that the independent variable should monotonically increase even when crossing over to a second day.). + prnt(self.IVAR.desc) # Number of variables (Integer value showing the number of dependent variables: the total number of columns of data is this value plus one.). prnt(self.ndvar) # Scale factors (1 for most cases, except where grossly inconvenient) - comma delimited. - prnt(self.splitChar.join( [ "{:6.3f}".format(x.scale) for x in self.DVAR ])) + prnt(self.splitChar.join( [ "{:.1g}".format(x.scale) for x in self.DVAR ])) # Missing data indicators (This is -9999 (or -99999, etc.) for any missing data condition, except for the main time (independent) variable which is never missing) - comma delimited. prnt(self.splitChar.join( [ str(x.miss) for x in self.DVAR ])) # Variable names and units (Short variable name and units are required, and optional long descriptive name, in that order, and separated by commas. If the variable is unitless, enter the keyword "none" for its units. Each short variable name and units (and optional long name) are entered on one line. The short variable name must correspond exactly to the name used for that variable as a column header, i.e., the last header line prior to start of data.). @@ -156,7 +298,7 @@ class Dataset: # Number of variables (Integer value showing the number of dependent variables: the total number of columns of data is this value plus one.). prnt(self.nauxvar) # Scale factors (1 for most cases, except where grossly inconvenient) - comma delimited. - prnt(self.splitChar.join( [ "{:6.3f}".format(x.scale) for x in self.AUXVAR ])) + prnt(self.splitChar.join( [ "{:.1g}".format(x.scale) for x in self.AUXVAR ])) # Missing data indicators (This is -9999 (or -99999, etc.) for any missing data condition, except for the main time (independent) variable which is never missing) - comma delimited. prnt(self.splitChar.join( [ str(x.miss) for x in self.AUXVAR ])) # Variable names and units (Short variable name and units are required, and optional long descriptive name, in that order, and separated by commas. If the variable is unitless, enter the keyword "none" for its units. Each short variable name and units (and optional long name) are entered on one line. The short variable name must correspond exactly to the name used for that variable as a column header, i.e., the last header line prior to start of data.). @@ -171,55 +313,75 @@ class Dataset: # Normal comments (SUPPORTING information: This is the place for investigators to more completely describe the data and measurement parameters. The supporting information structure is described below as a list of key word: value pairs. Specifically include here information on the platform used, the geo-location of data, measurement technique, and data revision comments. Note the non-optional information regarding uncertainty, the upper limit of detection (ULOD) and the lower limit of detection (LLOD) for each measured variable. The ULOD and LLOD are the values, in the same units as the measurements that correspond to the flags -7777s and -8888s within the data, respectively. The last line of this section should contain all the short variable names on one line. The key words in this section are written in BOLD below and must appear in this section of the header along with the relevant data listed after the colon. For key words where information is not needed or applicable, simply enter N/A.). nul = [ prnt(x) for x in self.NCOM ] # data! - nul = [ prnt(self.splitChar.join( [ str(y) for y in x ] )) for x in self.data ] + def prnt_data(vars): + prnt( self.splitChar.join([ str(x) for x in vars ]) ) + + nul = self.data.write(prnt=prnt_data) - def make_filename(self): + def make_filename(self, date_format='%Y%m%d'): ''' Create ICARTT-compliant file name based on the information contained in the dataset ''' - return self.dataID + "_" +self.locationID + "_" +datetime.datetime.strftime(self.dateValid, '%Y%m%d') + "_" +"R" + self.revision + ".ict" - - # sanitize function - def __readline(self, do_split=True): - dmp = self.input_fhandle.readline().replace('\n', '').replace('\r','') - if do_split: - dmp = [word.strip(' ') for word in dmp.split(self.splitChar) ] - return dmp + fn = self.dataID + "_" +self.locationID + "_" +datetime.datetime.strftime(self.dateValid, date_format) + fn += "_R" + str(self.revision) if not self.revision is None else "" + fn += "_L" + str(self.launch) if not self.launch is None else "" + fn += "_V" + str(self.volume) if self.nvolumes > 1 else "" + + return fn + ".ict" def read_header(self): ''' Read the ICARTT header (from file) - ''' + ''' + class Filehandle_with_linecounter: + def __init__(self, f, splitChar): + self.f = f + self.line = 0 + self.splitChar = splitChar + def readline(self, do_split=True): + self.line += 1 + dmp = self.f.readline().replace('\n', '').replace('\r','') + if do_split: + dmp = [ word.strip(' ') for word in dmp.split(self.splitChar) ] + return dmp + if self.input_fhandle.closed: self.input_fhandle = open(self.input_fhandle.name) - + + f = Filehandle_with_linecounter(self.input_fhandle, self.splitChar) + # line 1 - Number of lines in header, file format index (most files use # 1001) - comma delimited. - self.format = int(self.__readline()[1]) + dmp = f.readline() + self.format = int(dmp[1]) + if len(dmp) > 2: + self.version = dmp[2] + + assert self.format in IMPLEMENTED_FORMATS, "ICARTT format {:d} not implemented".format(self.format) # line 2 - PI last name, first name/initial. - self.PI = self.__readline(do_split=False) + self.PI = f.readline(do_split=False) # line 3 - Organization/affiliation of PI. - self.organization = self.__readline(do_split=False) + self.organization = f.readline(do_split=False) # line 4 - Data source description (e.g., instrument name, platform name, # model name, etc.). - self.dataSource = self.__readline(do_split=False) + self.dataSource = f.readline(do_split=False) # line 5 - Mission name (usually the mission acronym). - self.mission = self.__readline(do_split=False) + self.mission = f.readline(do_split=False) # line 6 - File volume number, number of file volumes (these integer values # are used when the data require more than one file per day; for data that # require only one file these values are set to 1, 1) - comma delimited. - dmp = self.__readline() - self.VOL = int(dmp[0]) - self.NVOL = int(dmp[1]) + dmp = f.readline() + self.volume = int(dmp[0]) + self.nvolumes = int(dmp[1]) # line 7 - UTC date when data begin, UTC date of data reduction or revision # - comma delimited (yyyy, mm, dd, yyyy, mm, dd). - dmp = self.__readline() + dmp = f.readline() self.dateValid = datetime.datetime.strptime("".join([ "{:s}".format(x) for x in dmp[0:3] ]), '%Y%m%d') self.dateRevised = datetime.datetime.strptime("".join([ "{:s}".format(x) for x in dmp[3:6] ]), '%Y%m%d') @@ -231,30 +393,35 @@ class Dataset: # value is set to 0. The Mid-point time is required when it is not at the # average of Start and Stop times. For additional information see Section # 2.5 below.). - self.dataInterval = float(self.__readline()[0]) - + self.dataInterval = float(f.readline()[0]) + + Variable = Variable_1001 if self.format == 1001 else Variable_2110 # line 9 - Description or name of independent variable (This is the name # chosen for the start time. It always refers to the number of seconds UTC # from the start of the day on which measurements began. It should be noted # here that the independent variable should monotonically increase even when # crossing over to a second day. - dmp = self.__readline() - self.IVAR = Variable(dmp[0], dmp[1]) + if self.format == 2110: + dmp = f.readline() + self.IBVAR = Variable(dmp[0], dmp[1], dmp[2 if len(dmp) > 2 else 1], splitChar=self.splitChar) + dmp = f.readline() + self.IVAR = Variable(dmp[0], dmp[1], dmp[2 if len(dmp) > 2 else 1], splitChar=self.splitChar) + # line 10 - Number of variables (Integer value showing the number of # dependent variables: the total number of columns of data is this value # plus one.). - ndvar = int(self.__readline()[0]) + ndvar = int(f.readline()[0]) # line 11- Scale factors (1 for most cases, except where grossly # inconvenient) - comma delimited. - dvscale = [ float(x) for x in self.__readline() ] + dvscale = [ float(x) for x in f.readline() ] # line 12 - Missing data indicators (This is -9999 (or -99999, etc.) for # any missing data condition, except for the main time (independent) # variable which is never missing) - comma delimited. - dvmiss = [ x for x in self.__readline() ] + dvmiss = [ x for x in f.readline() ] # no float casting here, as we need to do string comparison lateron when reading data... # line 13 - Variable names and units (Short variable name and units are @@ -264,31 +431,69 @@ class Dataset: # entered on one line. The short variable name must correspond exactly to # the name used for that variable as a column header, i.e., the last header # line prior to start of data.). - dmp = self.__readline() + dmp = f.readline() dvname = [ dmp[0] ] dvunits = [ dmp[1] ] + dvlongname = [ dmp[2 if len(dmp) > 2 else 1] ] for i in range(1, ndvar): - dmp = self.__readline() - dvname += [ dmp[0] ] - dvunits += [ dmp[1] ] + dmp = f.readline() + dvname += [ dmp[0] ] + dvunits += [ dmp[1] ] + dvlongname += [ dmp[2 if len(dmp) > 2 else 1] ] + + self.DVAR = [ Variable(name, unit, longname, scale=scale, miss=miss, splitChar=self.splitChar) for name, unit, longname, scale, miss in zip(dvname, dvunits, dvlongname, dvscale, dvmiss) ] - self.DVAR = [ Variable(name, unit, scale, miss) for name, unit, scale, miss in zip(dvname, dvunits, dvscale, dvmiss) ] + if self.format == 2110: + # line 10 - Number of variables (Integer value showing the number of + # dependent variables: the total number of columns of data is this value + # plus one.). + navar = int(f.readline()[0]) + + # line 11- Scale factors (1 for most cases, except where grossly + # inconvenient) - comma delimited. + avscale = [ float(x) for x in f.readline() ] + + # line 12 - Missing data indicators (This is -9999 (or -99999, etc.) for + # any missing data condition, except for the main time (independent) + # variable which is never missing) - comma delimited. + avmiss = [ x for x in f.readline() ] + # no float casting here, as we need to do string comparison lateron when reading data... + + # line 13 - Variable names and units (Short variable name and units are + # required, and optional long descriptive name, in that order, and separated + # by commas. If the variable is unitless, enter the keyword "none" for its + # units. Each short variable name and units (and optional long name) are + # entered on one line. The short variable name must correspond exactly to + # the name used for that variable as a column header, i.e., the last header + # line prior to start of data.). + dmp = f.readline() + avname = [ dmp[0] ] + avunits = [ dmp[1] ] + avlongname = [ dmp[2 if len(dmp) > 2 else 1] ] + + for i in range(1, navar): + dmp = f.readline() + avname += [ dmp[0] ] + avunits += [ dmp[1] ] + avlongname += [ dmp[2 if len(dmp) > 2 else 1] ] + + self.AUXVAR = [ Variable(name, unit, longname, scale=scale, miss=miss, splitChar=self.splitChar) for name, unit, longname, scale, miss in zip(avname, avunits, avlongname, avscale, avmiss) ] # line 14 + nvar - Number of SPECIAL comment lines (Integer value # indicating the number of lines of special comments, NOT including this # line.). - nscom = int(self.__readline()[0]) + nscom = int(f.readline()[0]) # line 15 + nvar - Special comments (Notes of problems or special # circumstances unique to this file. An example would be comments/problems # associated with a particular flight.). - self.SCOM = [ self.__readline(do_split=False) for i in range(0, nscom) ] + self.SCOM = [ f.readline(do_split=False) for i in range(0, nscom) ] # line 16 + nvar + nscom - Number of Normal comments (i.e., number of # additional lines of SUPPORTING information: Integer value indicating the # number of lines of additional information, NOT including this line.). - nncom = int(self.__readline()[0]) + nncom = int(f.readline()[0]) # line 17 + nvar + nscom - Normal comments (SUPPORTING information: This is # the place for investigators to more completely describe the data and @@ -305,13 +510,18 @@ class Dataset: # this section of the header along with the relevant data listed after the # colon. For key words where information is not needed or applicable, simply # enter N/A.). - self.NCOM = [ self.__readline(do_split=False) for i in range(0, nncom) ] - + raw_ncom = [ f.readline(do_split=False) for i in range(0, nncom) ] + try: + self.NCOM = StandardNormalComments(raw_ncom) + except: + warnings.warn("Normal comments do not adhere to ICARTT v2.0 standard.") + self.NCOM = SimpleNormalComments(raw_ncom) + + self.nheader_file = f.line + + del f self.input_fhandle.close() - def __nan_miss_float(self, raw): - return [ float(x.replace(self.VAR[i].miss, 'NaN')) for i, x in enumerate(raw) ] - def read_data(self): ''' Read ICARTT data (from file) @@ -319,10 +529,15 @@ class Dataset: if self.input_fhandle.closed: self.input_fhandle = open(self.input_fhandle.name) - nul = [ self.input_fhandle.readline() for i in range(self.nheader) ] - - self.data = [ self.__nan_miss_float(line.split(self.splitChar)) for line in self.input_fhandle ] + nul = [ self.input_fhandle.readline() for i in range(self.nheader_file) ] + if self.format == 1001: + self.data = Data_1001([ line.split(self.splitChar) for line in self.input_fhandle ], ivar=self.IVAR, dvar=self.DVAR) + elif self.format == 2110: + self.data = Data_2110([ line.split(self.splitChar) for line in self.input_fhandle ], ivar=self.IVAR, ibvar=self.IBVAR, auxvar=self.AUXVAR, dvar=self.DVAR) + else: + print("Unknown format") + self.input_fhandle.close() def read_first_and_last(self): @@ -333,14 +548,14 @@ class Dataset: if self.input_fhandle.closed: self.input_fhandle = open(self.input_fhandle.name) - nul = [ self.input_fhandle.readline() for i in range(self.nheader) ] + nul = [ self.input_fhandle.readline() for i in range(self.nheader_file) ] first = self.input_fhandle.readline() - self.data = [ self.__nan_miss_float(first.split(self.splitChar)) ] + self.data = Data_1001([ first.split(self.splitChar) ], ivar=self.IVAR, dvar=self.DVAR) for line in self.input_fhandle: pass last = line - self.data += [ self.__nan_miss_float(last.split(',')) ] + self.data += [ last.split(self.splitChar) ] self.input_fhandle.close() @@ -358,42 +573,52 @@ class Dataset: :param string splitChar: the splitting character used to separate fields in a line ''' self.format = 1001 + self.version = "unknown" - self.revision = '0' self.dataID = 'dataID' self.locationID = 'locationID' + self.revision = 0 + self.launch = None + self.volume = 1 + self.nvolumes = 1 + self.PI = 'Mustermann, Martin' self.organization = 'Musterinstitut' self.dataSource = 'Musterdatenprodukt' self.mission = 'MUSTEREX' - self.VOL = 1 - self.NVOL = 1 self.dateValid = datetime.datetime.today() self.dateRevised = datetime.datetime.today() self.dataInterval = 0.0 - self.IVAR = Variable('Time_Start', + self.IVAR = Variable_1001('Time_Start', + 'seconds_from_0_hours_on_valid_date', 'seconds_from_0_hours_on_valid_date', - 1.0, -9999999) + scale=1.0, miss=-9999999, splitChar=splitChar) self.DVAR = [ - Variable('Time_Stop', + Variable_1001('Time_Stop', 'seconds_from_0_hours_on_valid_date', - 1.0, -9999999), - Variable('Some_Variable', + 'seconds_from_0_hours_on_valid_date', + scale=1.0, miss=-9999999, splitChar=splitChar), + Variable_1001('Some_Variable', + 'ppbv', 'ppbv', - 1.0, -9999999) + scale=1.0, miss=-9999999, splitChar=splitChar) ] self.SCOM = [] self.NCOM = [] - - self.data = [ [1.0, 2.0, 45.0], [2.0, 3.0, 36.0] ] - + + self.data = Data_1001([]) + # for 2210 self.IBVAR = None self.AUXVAR = [] - + self.splitChar = splitChar - + + # Standard v2.0 for normal comments requires all keywords present, + # might not be the case - then reading data will fail + self.nheader_file = -1 + # read data if f is not None if f is not None: if isinstance(f, str): diff --git a/setup.py b/setup.py index e24031db07d9a6995d826a63f1b02cefee36ca72..08a071ba40a2aa8bafd04794eebedb4f2bc3dd38 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,5 @@ setup(name='icartt', 'Topic :: Utilities' ], keywords='', -# python_requires='<3', packages=['icartt'], zip_safe=False)