Skip to content

Commit e2b1034

Browse files
committed
Work on parameter tools (#547)
* work on parameter tools to simplify, deduplicate, add option for prefix and allow namelist parameter also be derived from file * fixes
1 parent 0e4eb8d commit e2b1034

1 file changed

Lines changed: 169 additions & 110 deletions

File tree

Lines changed: 169 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,193 @@
11
import numpy
22

3-
from ConfigParser import ConfigParser
3+
try:
4+
from ConfigParser import ConfigParser
5+
except:
6+
from configparser import ConfigParser
7+
from collections import defaultdict
48

59
try:
610
import f90nml
711
HAS_F90NML=True
812
except:
913
HAS_F90NML=False
10-
from collections import defaultdict
11-
from amuse.units.quantities import new_quantity, to_quantity, is_quantity
1214

15+
from amuse.units.quantities import new_quantity, to_quantity, is_quantity
1316

1417
# CodeWithNamelistParameters
1518
#
1619
# namelist_parameters=(
1720
# dict(name="name", group_name="name", short="codename", dtype="int32", default=64, description="description", ptype="nml" [, set_name="name"]), ...
1821
# )
1922

20-
class CodeWithNamelistParameters(object):
21-
def __init__(self, namelist_parameters):
22-
self._namelist_parameters=dict([((x["short"].lower(),x["group_name"]),x) for x in namelist_parameters])
23-
24-
def define_parameters(self,handler):
25-
for p in self._namelist_parameters.values():
26-
if p["ptype"] in ["nml", "nml+normal"]:
27-
parameter_set_name=p.get("set_name", "parameters_"+p["group_name"])
28-
handler.add_interface_parameter( p["name"], p["description"], p["default"], "before_set_interface_parameter", parameter_set=parameter_set_name)
23+
class _CodeWithFileParameters(object):
24+
_ptypes=None
25+
def write_file(self, inputfile, **kwargs):
26+
raise Exception("not implemented")
27+
def read_file(self, inputfile, rawvals, **kwargs):
28+
raise Exception("not implemented")
2929

30-
def read_namelist_parameters(self, inputfile):
30+
def define_parameters(self, handler):
31+
_tmp=dict()
32+
for p in self._parameters.values():
33+
if p["ptype"] not in self._ptypes:
34+
continue
35+
parameter_set_name=p.get("set_name", self._prefix+p["group_name"] )
36+
if parameter_set_name not in _tmp:
37+
_tmp[parameter_set_name]=[ x.name for x in handler.definitions[parameter_set_name] ]
38+
if not p["name"] in _tmp[parameter_set_name]:
39+
handler.add_interface_parameter( p["name"], p["description"], p["default"],
40+
"before_set_interface_parameter", parameter_set=parameter_set_name)
3141

32-
self._nml_file=inputfile
33-
self._nml_params = f90nml.read(inputfile)
42+
self.set_parameters()
3443

35-
for group, d in self._nml_params.iteritems():
36-
for short, val in d.iteritems():
37-
key=(short.lower(),group.upper())
38-
if key in self._namelist_parameters:
39-
group_name=self._namelist_parameters[key]["group_name"]
40-
name=self._namelist_parameters[key]["name"]
41-
parameter_set_name=self._namelist_parameters[key].get("set_name", "parameters_"+group_name)
42-
parameter_set=getattr(self, parameter_set_name)
43-
if is_quantity(self._namelist_parameters[key]["default"]):
44-
setattr(parameter_set, name, new_quantity(val, to_quantity(self._namelist_parameters[key]["default"]).unit) )
44+
def set_parameters(self):
45+
for p in self._parameters.values():
46+
if p["ptype"] not in self._ptypes:
47+
continue
48+
parameter_set_name=p.get("set_name", None) or self._prefix+p["group_name"]
49+
parameter_set=getattr(self, parameter_set_name)
50+
name=p["name"]
51+
value=p.get("value", p["default"])
52+
setattr(parameter_set, name, value)
53+
54+
def interpret_value(self,value, dtype=None):
55+
raise Exception("not implemented")
56+
57+
def read_parameters(self, inputfile, add_missing_parameters=False):
58+
self._file=inputfile
59+
60+
_nml_params = f90nml.read(inputfile)
61+
62+
rawvals, comments = self._read_file(inputfile)
63+
64+
for key, rawval in rawvals.items():
65+
if key in self._parameters:
66+
group_name=self._parameters[key]["group_name"]
67+
name=self._parameters[key]["name"]
68+
val=self.interpret_value( rawval, dtype=dtype)
69+
if is_quantity(self._parameters[key]["default"]):
70+
self._parameters[key]["value"]=new_quantity(val, to_quantity(self._namelist_parameters[key]["default"]).unit)
4571
else:
46-
setattr(parameter_set, name, val )
72+
self._parameters[key]["value"]=val
4773
else:
48-
print "'%s' of group '%s' not in the namelist_parameters"%(short, group)
49-
50-
def write_namelist_parameters(self, outputfile, do_patch=False, nml_file=None):
51-
patch=defaultdict( dict )
52-
for p in self._namelist_parameters.values():
74+
if not add_missing_parameters:
75+
print("'{0}' of group '{1}' not in the namelist_parameters".format(*key))
76+
else:
77+
value=rawval
78+
description=comments.get(key, "unknown parameter read from {0}".format(inputfile))
79+
self._parameters[key]=dict(
80+
group_name=key[1],
81+
name=key[0],
82+
short_name=key[0],
83+
default=value,
84+
value=value,
85+
short=key[0],
86+
ptype=self._ptypes[0],
87+
dtype=str(type(value)),
88+
description=description
89+
)
90+
91+
def write_parameters(self, outputfile, **options):
92+
93+
rawvals=dict()
94+
95+
for key, p in self._parameters.items():
5396
name=p["name"]
5497
group_name=p["group_name"]
55-
group=patch[group_name]
5698
short=p["short"]
57-
parameter_set_name=p.get("set_name", "parameters_"+group_name)
58-
parameter_set=getattr(self, parameter_set_name)
59-
if getattr(parameter_set, name) is None: # omit if value is None
60-
continue
99+
parameter_set_name=p.get("set_name", group_name)
100+
parameter_set=getattr(self, self._prefix+parameter_set_name)
61101
if is_quantity(p["default"]):
62102
value=to_quantity(getattr(parameter_set, name)).value_in(p["default"].unit)
63103
else:
64-
value=getattr(parameter_set, name)
65-
if isinstance(value,numpy.ndarray):
66-
value=list(value) # necessary until f90nml supports numpy arrays
67-
group[short]=value
104+
value=getattr(parameter_set, name)
105+
106+
rawvals[key]=self.output_format_value(value)
107+
108+
self.write_file(outputfile, rawvals, **options)
109+
110+
class CodeWithNamelistParameters(_CodeWithFileParameters):
111+
"""
112+
Mix-in class to 1) namelist file support to code interfaces and 2) automatically generate
113+
parameter sets from descriptions or namelist files.
114+
115+
This class takes a list of parameter descriptions (optional) and has functions to
116+
read and write namelist files. Every namelist section corresponds to a different
117+
parameter set.
118+
"""
119+
_ptypes=["nml", "nml+normal"]
120+
121+
def __init__(self, _parameters, prefix="parameters_"):
122+
if not HAS_F90NML:
123+
raise Exception("f90nml package not available")
124+
self._parameters=dict([((x["short"].lower(),x["group_name"]),x) for x in _parameters])
125+
self._prefix=prefix
126+
self._file=None
127+
128+
def _read_file(self, inputfile):
129+
_nml_params = f90nml.read(inputfile)
130+
rawvals=dict()
131+
132+
for group, d in _nml_params.items():
133+
for short, val in d.items():
134+
key=(short.lower(),group.upper())
135+
rawvals[key]=val
136+
137+
return rawvals, dict()
138+
139+
def write_file(self, outputfile, rawvals, do_patch=False, nml_file=None):
140+
patch=defaultdict( dict )
141+
142+
for key,rawval in rawvals.items():
143+
if rawval is None: # omit if value is None
144+
continue
145+
if isinstance(rawval,numpy.ndarray):
146+
rawval=list(rawval) # necessary until f90nml supports numpy arrays
147+
patch[key[1]][key[0]]=rawval
68148

69149
if do_patch:
70150
f90nml.patch(nml_file or self._nml_file,patch,outputfile)
71151
else:
72152
f90nml.write(patch, outputfile, force=True)
73153

74-
class CodeWithIniFileParameters(object):
75-
def __init__(self, inifile_parameters=dict()):
76-
self._inifile_parameters=dict([((x["name"],x["group_name"]),x) for x in inifile_parameters])
77-
self._optionxform=str
78-
79-
def define_parameters(self, handler):
80-
_tmp=dict()
81-
for p in self._inifile_parameters.values():
82-
if p["ptype"] in ["ini", "ini+normal"]:
83-
parameter_set_name=p.get("set_name", p["group_name"])
84-
if parameter_set_name not in _tmp:
85-
_tmp[parameter_set_name]=[ x.name for x in handler.definitions[parameter_set_name] ]
86-
if not p["name"] in _tmp[parameter_set_name]:
87-
handler.add_interface_parameter( p["name"], p["description"], p["default"],
88-
"before_set_interface_parameter", parameter_set=parameter_set_name)
89-
90-
self.set_parameters()
154+
def write_namelist_parameters(self, outputfile, do_patch=False, nml_file=None):
155+
return self.write_parameters(outputfile, do_patch=do_patch, nml_file=nml_file)
91156

92-
def set_parameters(self):
93-
for p in self._inifile_parameters.values():
94-
parameter_set_name=p.get("set_name", None) or p["group_name"]
95-
parameter_set=getattr(self, parameter_set_name)
96-
name=p["name"]
97-
value=p.get("value", None) or p["default"]
98-
setattr(parameter_set, name, value)
99-
100-
def read_inifile_parameters(self, configfile):
101-
self._configfile=configfile
157+
def read_namelist_parameters(self, inputfile, add_missing_parameters=False):
158+
return self.read_parameters(inputfile,add_missing_parameters)
159+
160+
def output_format_value(self,value):
161+
return value
162+
163+
164+
class CodeWithIniFileParameters(_CodeWithFileParameters):
165+
"""
166+
Mix-in class to 1) INI-like file support to code interfaces and 2) automatically generate
167+
parameter sets from descriptions or Ini files.
168+
169+
This class takes a list of parameter descriptions (optional) and has functions to
170+
read and write INI files. Every section corresponds to a different parameter set.
171+
"""
172+
_ptypes=["ini", "ini+normal"]
173+
def __init__(self, _parameters=dict(), prefix="ini_"):
174+
self._parameters=dict([((x["name"],x["group_name"]),x) for x in _parameters])
175+
self._optionxform=str
176+
self._prefix=prefix
177+
self._file=None
178+
179+
def read_file(self, inputfile):
102180
parser=ConfigParser()
103181
parser.optionxform=self._optionxform
104-
parser.read(configfile)
182+
parser.read(inputfile)
105183
for section in parser.sections():
106184
group=section
107185
for option in parser.options(section):
108186
key=(option,group)
109-
if key in self._inifile_parameters:
110-
ptype=self._inifile_parameters[key]["ptype"]
111-
dtype=self._inifile_parameters[key]["dtype"]
112-
value=self.interpret_value(parser.get(group, option), dtype=dtype)
113-
if is_quantity(self._inifile_parameters[key]["default"]):
114-
value= new_quantity(val, to_quantity(self._inifile_parameters[key]["default"]).unit)
115-
self._inifile_parameters[key]["value"]=value
116-
else:
117-
value=self.interpret_value(parser.get(group, option))
118-
self._inifile_parameters[key]=dict(
119-
group_name=group,
120-
name=option,
121-
set_name=group,
122-
default=value,
123-
value=value,
124-
short=option,
125-
ptype="ini",
126-
dtype="unknown",
127-
description="unknown parameter read from %s"%configfile
128-
)
187+
188+
rawvals[key]=parser.get(group, option)
189+
190+
return rawvals, dict()
129191

130192
def _convert(self, value, dtype):
131193
if dtype is "bool":
@@ -142,32 +204,29 @@ def interpret_value(self,value, dtype=None):
142204
return [self._convert(x, dtype) for x in value.split(",")]
143205
return self._convert(value, dtype)
144206

145-
def output_format_value(self,value):
146-
if isinstance(value, list):
147-
return ','.join(value)
148-
else:
149-
return value
150-
151-
152-
def write_inifile_parameters(self, outputfile):
207+
def write_file(self, outputfile, rawvals):
153208
parser=ConfigParser()
154209
parser.optionxform=self._optionxform
155210

156-
for p in self._inifile_parameters.values():
157-
name=p["name"]
158-
group_name=p["group_name"]
159-
short=p["short"]
160-
parameter_set_name=p.get("set_name", group_name)
161-
parameter_set=getattr(self, parameter_set_name)
162-
if is_quantity(p["default"]):
163-
value=to_quantity(getattr(parameter_set, name)).value_in(p["default"].unit)
164-
else:
165-
value=self.output_format_value(getattr(parameter_set, name))
166-
if not parser.has_section(group_name):
167-
parser.add_section(group_name)
168-
parser.set(group_name,short,value)
169-
211+
for key, rawval in rawvals.items():
212+
section=key[1]
213+
214+
if not parser.has_section(section):
215+
parser.add_section(section)
216+
217+
if isinstance(rawval, list):
218+
rawval=','.join(rawval)
219+
220+
parser.set(section,short,self.output_format_value(rawval))
221+
170222
f=open(outputfile, "w")
171223
parser.write(f)
172224
f.close()
173225

226+
def output_format_value(self,value):
227+
if isinstance(value, list):
228+
return ','.join(value)
229+
else:
230+
return value
231+
232+

0 commit comments

Comments
 (0)