1
2 """Reads configuration-files that define defaults for various PyFoam-Settings
3
4 Also hardcodes defaults for the settings"""
5
6 from PyFoam.ThirdParty.six.moves import configparser
7 from PyFoam.ThirdParty.six import iteritems,PY3
8
9 from PyFoam.Infrastructure.Hardcoded import globalConfigFile,userConfigFile,globalDirectory,userDirectory,globalConfigDir,userConfigDir
10
11 from os import path
12 import glob,re
13
14 _defaults={
15 "Network": {
16 "startServerPort" : "18000",
17 "nrServerPorts" : "100",
18 "portWait" : "1.",
19 "socketTimeout" : "1.",
20 "socketRetries" : "10",
21 },
22 "Metaserver": {
23 "port" : "17999",
24 "ip" : "192.168.1.11",
25 "checkerSleeping" : "30.",
26 "searchServers" : "192.168.1.0/24,192.168.0.0/24",
27 "webhost" : "127.0.0.1:9000",
28 "doWebsync" : "True",
29 "websyncInterval" : "300.",
30 },
31 "IsAlive": {
32 "maxTimeStart" : "30.",
33 "isLivingMargin" : "1.1"
34 },
35 "Logging": {
36 "default" : "INFO",
37 "server" : "INFO",
38 },
39 "OpenFOAM": {
40 "Forks" : 'openfoam,extend',
41 "DirPatterns-openfoam" : '"^OpenFOAM-([0-9]\.[0-9].*)$","^openfoam([0-9]+)$"',
42 "DirPatterns-extend" : '"^foam-extend-([0-9]\.[0-9].*)$"',
43 "Installation-openfoam" : "~/OpenFOAM",
44 "Installation-extend" : "~/foam",
45 "AdditionalInstallation-openfoam" : '"~/OpenFOAM"',
46 "Version" : "1.5",
47 },
48 "MPI": {
49
50
51 "OpenMPI_add_prefix":"False",
52 "options_OPENMPI_pre": '["--mca","pls","rsh","--mca","pls_rsh_agent","rsh"]',
53 "options_OPENMPI_post":'["-x","PATH","-x","LD_LIBRARY_PATH","-x","WM_PROJECT_DIR","-x","PYTHONPATH","-x","FOAM_MPI_LIBBIN","-x","MPI_BUFFER_SIZE","-x","MPI_ARCH_PATH"]'
54 },
55 "Paths": {
56 "python" : "/usr/bin/python",
57 "bash" : "/bin/bash",
58 "paraview" : "paraview",
59 },
60 "ClusterJob": {
61 "useFoamMPI":'["1.5"]',
62 "path":"/opt/openmpi/bin",
63 "ldpath":"/opt/openmpi/lib",
64 "doAutoReconstruct":"True",
65 "useMachineFile":"True",
66 },
67 "Debug": {
68
69 },
70 "Execution":{
71 "controlDictRestoreWait":"60.",
72 },
73 "CaseBuilder":{
74 "descriptionPath": eval('["'+path.curdir+'","'+path.join(userDirectory(),"caseBuilderDescriptions")+'","'+path.join(globalDirectory(),"caseBuilderDescriptions")+'"]'),
75 },
76 "Formats":{
77 "error" : "bold,red,standout",
78 "warning" : "under",
79 "source" : "red,bold",
80 "destination" : "blue,bold",
81 "difference" : "green,back_black,bold",
82 "question" : "green,standout",
83 "input" : "cyan,under",
84 },
85 "CommandOptionDefaults":{
86 "sortListCases":"mtime",
87 },
88 "Plotting":{
89 "preferredImplementation":"gnuplot",
90 },
91 "OutfileCollection": {
92 "maximumOpenFiles":"100",
93 },
94 "SolverOutput": {
95 "timeRegExp": "^(Time =|Iteration:) (.+)$",
96 },
97 "Clearing": {
98 "additionalPatterns":"[]",
99 },
100 "postRunHook_WriteMySqlite" : {
101 "enabled":False,
102 "module":"WriteToSqliteDatabase",
103 "createDatabase":False,
104 "database":"~/databaseOfAllMyRuns.db",
105 },
106 "postRunHook_SendToPushover" : {
107 "enabled":False,
108 "minRunTime":600,
109 "useSSL":True,
110 "module":"SendToWebservice",
111 "host":"api.pushover.net:443",
112 "method":"POST",
113 "url":"/1/messages",
114 "param_token":"invalid_get_yourself_one_at_pushover.net",
115 "param_user":"invalid_get_yourself_an_account_at_pushover.net",
116 "param_title":"<!--(if OK)-->Finished<!--(else)-->Failed<!--(end)-->: |-casename-| (|-solver-|)",
117 "param_message":"""Case |-casefullname-| ended after |-wallTime-|s
118 Last timestep: t=|-time-|
119 Machine: |-hostname-|
120 Full command: |-commandLine-|""",
121 "header_Content-type": "application/x-www-form-urlencoded",
122 "templates":"title message"
123 },
124 "postRunHook_mailToMe" : {
125 "enabled":False,
126 "minRunTime":600,
127 "module":"MailToAddress",
128 "to":"nobody@here.there",
129 "from":"a_concerned_user@your.local.machine",
130 "smtpServer":"smtp.server.that.doesnt.need.authentication'",
131 "subject":"<!--(if OK)-->Finished<!--(else)-->Failed<!--(end)-->: |-casename-| (|-solver-|)",
132 "message":"""Case |-casefullname-| ended after |-wallTime-|s
133 Last timestep: t=|-time-|
134 Machine: |-hostname-|
135 Full command: |-commandLine-|""",
136 "mailFields_Reply-To": "nobody@nowhere.com",
137 },
138 "Cloning" : {
139 "addItem":"[]",
140 "noForceSymlink":"[]",
141 },
142 "PrepareCase" : {
143 "MeshCreateScript":"meshCreate.sh",
144 "CaseSetupScript":"caseSetup.sh",
145 },
146 }
147
149 """Wraps a Confguration so that the section automatically becomes the
150 first argument"""
151
153 self.conf=conf
154 self.section=section
155
157 f=getattr(self.conf,name)
158 def curried(*args,**kwargs):
159 return f(*((self.section,)+args),**kwargs)
160 return curried
161
163 """Reads the settings from files (if existing). Otherwise uses hardcoded
164 defaults"""
165
167 """Constructs the ConfigParser and fills it with the hardcoded defaults"""
168 configparser.ConfigParser.__init__(self)
169
170 for section,content in iteritems(_defaults):
171 self.add_section(section)
172 for key,value in iteritems(content):
173 self.set(section,key,str(value))
174
175 self.read(self.configFiles())
176
177 self.validSections={}
178 for s in self.sections():
179 minusPos=s.find('-')
180 if minusPos<0:
181 name=s
182 else:
183 name=s[:minusPos]
184 try:
185 self.validSections[name].append(s)
186 except KeyError:
187 self.validSections[name]=[s]
188
189 for name,sections in iteritems(self.validSections):
190 if not name in sections:
191 print("Invalid configuration for",name,"there is no default section for it in",sections)
192
194 """Return a proxy object that makes it possible to avoid the section
195 specification"""
196 return ConfigurationSectionProxy(self,section)
197
199 """Get the best-fitting section that has that option"""
200
201 from PyFoam import foamVersionString
202
203 try:
204 if len(self.validSections[section])==1 or foamVersionString()=="":
205 return section
206 except KeyError:
207 return section
208
209 result=section
210 fullName=section+"-"+foamVersionString()
211
212 for s in self.validSections[section]:
213 if fullName.find(s)==0 and len(s)>len(result):
214 if self.has_option(s,option):
215 result=s
216
217 return result
218
227
229 """Return a list with the configurationfiles that are going to be used"""
230 files=[]
231
232 for t,f in self.configSearchPath():
233 if path.exists(f):
234 if t=="file":
235 files.append(f)
236 elif t=="directory":
237 for ff in glob.glob(path.join(f,"*.cfg")):
238 files.append(ff)
239 else:
240 error("Unknown type",t,"for the search entry",f)
241
242 return files
243
244 - def addFile(self,filename,silent=False):
251
253 """Dumps the contents in INI-Form
254 @return: a string with the contents"""
255 result=""
256 for section in self.sections():
257 result+="[%s]\n" % (section)
258 for key,value in self.items(section):
259 result+="%s: %s\n" % (key,value)
260 result+="\n"
261
262 return result
263
264 - def getList(self,section,option,default="",splitchar=",",stripQuotes=True):
265 """Get a list of strings (in the original they are separated by commas)
266 @param section: the section
267 @param option: the option
268 @param default: if set and the option is not found, then this value is used
269 @param splitchar: the character by which the values are separated
270 @param stripQuotes: remove quotes if present"""
271
272 val=self.get(section,option,default=default)
273 if val=="":
274 return []
275 else:
276 result=[]
277 for v in val.split(splitchar):
278 if v[0]=='"' and v[-1]=='"':
279 result.append(v[1:-1])
280 else:
281 result.append(v)
282 return result
283
284 - def getboolean(self,section,option,default=None):
285 """Overrides the original implementation from ConfigParser
286 @param section: the section
287 @param option: the option
288 @param default: if set and the option is not found, then this value is used"""
289
290 try:
291 return configparser.ConfigParser.getboolean(self,
292 self.bestSection(section,option),
293 option)
294 except configparser.NoOptionError:
295 if default!=None:
296 return default
297 else:
298 raise
299
300 - def getint(self,section,option,default=None):
301 """Overrides the original implementation from ConfigParser
302 @param section: the section
303 @param option: the option
304 @param default: if set and the option is not found, then this value is used"""
305
306 try:
307 return int(configparser.ConfigParser.get(self,
308 self.bestSection(section,option),
309 option))
310 except configparser.NoOptionError:
311 if default!=None:
312 return default
313 else:
314 raise
315
316 - def getfloat(self,section,option,default=None):
317 """Overrides the original implementation from ConfigParser
318 @param section: the section
319 @param option: the option
320 @param default: if set and the option is not found, then this value is used"""
321
322 try:
323 return float(configparser.ConfigParser.get(self,
324 self.bestSection(section,option),
325 option))
326 except (configparser.NoOptionError,ValueError):
327 if default!=None:
328 return default
329 else:
330 raise
331
333 """Get an entry and interpret it as a regular expression. Subsitute
334 the usual regular expression value for floating point numbers
335 @param section: the section
336 @param option: the option
337 @param default: if set and the option is not found, then this value is used"""
338 floatRegExp="[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?"
339
340 return re.compile(self.get(section,option).replace("%f%",floatRegExp))
341
342 - def get(self,section,option,default=None):
343 """Overrides the original implementation from ConfigParser
344 @param section: the section
345 @param option: the option
346 @param default: if set and the option is not found, then this value is used"""
347
348 try:
349 return configparser.ConfigParser.get(self,
350 self.bestSection(section,option),
351 option)
352 except configparser.NoOptionError:
353 if default!=None:
354 return default
355 else:
356 raise
357
359 """Gets a debug switch"""
360
361 return self.getboolean("Debug",name,default=False)
362
363
364