Skip to content
Snippets Groups Projects
Commit 474c6e3b authored by Christoph.Knote's avatar Christoph.Knote
Browse files

New InputFile classes to deal with updated (>= 1.7) BOXMOX input files.

parent 752dee29
No related branches found
No related tags found
No related merge requests found
......@@ -3,18 +3,36 @@ import sys
import shutil
import StringIO
import csv
import warnings
import numpy as np
def _mygenfromtxt2(f):
curpos = f.tell()
try:
dialect = csv.Sniffer().sniff(f.read(1048576), delimiters=";, ")
dialect.skipinitialspace = True
f.seek(curpos)
spamreader = csv.reader(f, dialect)
except:
# could not determine dialect, falling back to default.
f.seek(curpos)
spamreader = csv.reader(f, skipinitialspace = True, delimiter=" ")
# twice as fast as np.genfromtxt(..., names=True)
hdr = spamreader.next()
dat = []
for row in spamreader:
dat.append( tuple(map(float, row)) )
return dat, hdr
def _mygenfromtxt(f):
curpos = f.tell()
try:
dialect = csv.Sniffer().sniff(f.read(1048576), delimiters=";, ")
dialect.skipinitialspace = True
f.seek(curpos)
spamreader = csv.reader(f, dialect)
except:
warnings.warn('Could not determine dialect, falling back to default.')
# could not determine dialect, falling back to default.
f.seek(curpos)
spamreader = csv.reader(f, skipinitialspace = True, delimiter=" ")
# twice as fast as np.genfromtxt(..., names=True)
......@@ -24,9 +42,132 @@ def _mygenfromtxt(f):
dat.append( tuple(map(float, row)) )
return np.array(dat, dtype=[(_, float) for _ in hdr])
class InputFile:
def InputFile(fpath=None, version=1.0):
if not fpath is None:
# file format discovery: 3 lines with numbers ==> 1.7
with open(fpath, 'rb') as f:
one = f.readline()
two = f.readline()
tre = f.readline()
try:
test = int(tre)
version = 1.7
except:
version = 1.0
pass
if version >= 1.7:
return InputFile17(fpath=fpath, version=version)
else:
return InputFileOrig(fpath=fpath)
class InputFile17:
'''
A generic BOXMOX input file. Getting and setting of values
A generic BOXMOX input file (>= v 1.7). Getting and setting of values
works like a dictionary::
print(inp['O3'])
inp['O3'] = 0.040
'''
@property
def nvar(self):
'''
Number of variables.
'''
return len( [ x for x in self.keys() ] )
@property
def nanc(self):
'''
Number of ancillary variables.
'''
return len( [ x for x in self.anc.keys() ] )
def __getitem__(self, item):
return [ self.__data[i] for i in item ] if isinstance(item, list) else self.__data[item]
def __setitem__(self, item, values):
if isinstance(item, list):
for i, v in zip(item, values):
self.__data[i] = v
else:
self.__data[item] = values
def keys(self):
return self.__data.keys()
def read(self, fpath):
'''
Read input file from path.
'''
with open(fpath, 'rb') as f:
nvar = int(f.readline().replace(',', ''))
nanc = int(f.readline().replace(',', ''))
self.timeFormat = int(f.readline().replace(',', ''))
dmp, hdr = _mygenfromtxt2(f)
ntime = 0
if not self.timeFormat == 0:
self.timeVar = hdr[0]
self.time = [ x[0] for x in dmp ]
ntime = 1
self.anc = { hdr[i]: [ x[i] for x in dmp ] for i in range(ntime, ntime+nanc) }
self.__data = { hdr[i]: [ x[i] for x in dmp ] for i in range(ntime+nanc, len(dmp[0])) }
def __str__(self):
f = StringIO.StringIO()
self.write(f)
return(f.getvalue())
def write(self, f=sys.stdout, version=1.7):
'''
Write to <f>. <f> can be file handle or other connection. Defaults to sys.stdout.
'''
# possibility to create old version output from new version data
if version >= 1.7:
f.write('{0:1d}'.format(self.nvar) +'\n')
f.write('{0:1d}'.format(self.nanc) +'\n')
else:
f.write('{0:1d}'.format(self.nanc+self.nvar) +'\n')
f.write('{0:1d}'.format(self.timeFormat) +'\n')
data_names = [ key for key in self.keys() ]
anc_names = [ key for key in self.anc.keys() ]
hdr_line = '{0:s}\n' .format(' '.join(anc_names + data_names))
if str(self.timeFormat) != "0" :
hdr_line = self.timeVar + ' ' + hdr_line
f.write(hdr_line)
if isinstance(self.time, list):
for itime, xtime in enumerate(self.time):
line = [ xtime ] + [ self.anc[key][itime] for key in anc_names ] + [ self.__data[key][itime] for key in data_names ]
f.write(' '.join('{0:e}'.format(x) for x in line) + '\n')
else:
data_line = ' '.join( '{0:e}'.format(float(self.anc[x])) for x in self.anc.keys() ) + ' ' + ' '.join( '{0:e}'.format(float(self.__data[x])) for x in self.keys() ) + '\n'
if not self.time is None:
data_line = '{0:e}'.format(float(self.time)) + ' ' + data_line
f.write(data_line)
def __init__(self, fpath=None, version=1.7):
#: Time format (0: constant, 1: seconds since start, 2: hour of diurnal cycle)
self.timeFormat = 0
self.timeVar = 'time'
self.time = None
self.anc = {}
self.__data = {}
self.version = version
#: File path of the underlying file (if it exists (yet))
self.fpath = fpath
if not self.fpath is None:
try:
self.read(self.fpath)
except Exception as e:
print("Reading input file {:s} failed: {:s}".format(self.fpath, str(e)))
class InputFileOrig:
'''
A generic BOXMOX input file (< 1.7). Getting and setting of values
works like a dictionary::
print(inp['O3'])
......@@ -49,6 +190,7 @@ class InputFile:
self.__data[item] = values
def keys(self):
return self.__data.keys()
def read(self, fpath):
'''
Read input file from path.
......@@ -67,11 +209,13 @@ class InputFile:
self.write(f)
return(f.getvalue())
def write(self, f=sys.stdout):
def write(self, f=sys.stdout, version=1.0):
'''
Write to <f>. <f> can be file handle or other connection. Defaults to sys.stdout.
'''
f.write('{0:1d}'.format(self.nvar) +'\n')
if version >= 1.7:
f.write('{0:1d}'.format(0) +'\n')
f.write('{0:1d}'.format(self.timeFormat) +'\n')
column_names = [ key for key in self.keys() if key != self.__timeVar ]
......@@ -91,6 +235,8 @@ class InputFile:
self.__timeVar = 'time'
self.__data = {}
self.version = 0.0
#: File path of the underlying file (if it exists (yet))
self.fpath = fpath
if not self.fpath is None:
......
......@@ -113,6 +113,25 @@ class Experiment:
#: Namelist
self.namelist = Namelist(os.path.join(self.path, 'BOXMOX.nml'))
self.version = self._determineVersion(self.path)
def _determineVersion(self, path):
version = 1.0
versionFile = os.path.join(path, 'VERSION')
if os.path.exists(versionFile):
try:
with open(versionFile, 'rb') as f:
line = f.readline().rstrip()
line = ".".join(line.split(".")[0:min(2, len(line.split(".")))])
# for development only:
if line == "__BOXMOX_VERSION__":
line = 1.7
version = float(line)
except:
version = 1.0
pass
return version
def _populateInput(self):
inputFileNames = [f for f in os.listdir(self.path) if f.endswith('.csv')]
self.input = { x.replace('.csv', '') : InputFile(os.path.join(self.path, x)) for x in inputFileNames }
......@@ -120,7 +139,6 @@ class Experiment:
def __new(self):
try:
s.call(["new_BOXMOX_experiment", self.mechanism, self.path])
# s.check_output(["new_BOXMOX_experiment", "-f", self.mechanism, self.path], stderr=s.STDOUT)
self._populateInput()
except s.CalledProcessError as e:
......@@ -172,7 +190,7 @@ class Experiment:
for type in self.input:
with open( os.path.join(self.path, type + '.csv'), 'wb') as f:
self.input[type].write(f)
self.input[type].write(f, version=self.version)
pwd = os.getcwd()
os.chdir(self.path)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment