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,pyFoamSiteVar,siteConfigDir,siteConfigFile
10
11 from os import path,environ
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
230
232 """Return a list with the configurationfiles that are going to be used"""
233 files=[]
234
235 for t,f in self.configSearchPath():
236 if path.exists(f):
237 if t=="file":
238 files.append(f)
239 elif t=="directory":
240 for ff in glob.glob(path.join(f,"*.cfg")):
241 files.append(ff)
242 else:
243 error("Unknown type",t,"for the search entry",f)
244
245 return files
246
247 - def addFile(self,filename,silent=False):
254
256 """Dumps the contents in INI-Form
257 @return: a string with the contents"""
258 result=""
259 for section in sorted(self.sections(),key=lambda x:x.lower()):
260 result+="[%s]\n" % (section)
261 for key,value in sorted(self.items(section),key=lambda x:x[0].lower()):
262 result+="%s: %s\n" % (key,value)
263 result+="\n"
264
265 return result
266
267 - def getList(self,section,option,default="",splitchar=",",stripQuotes=True):
268 """Get a list of strings (in the original they are separated by commas)
269 @param section: the section
270 @param option: the option
271 @param default: if set and the option is not found, then this value is used
272 @param splitchar: the character by which the values are separated
273 @param stripQuotes: remove quotes if present"""
274
275 val=self.get(section,option,default=default)
276 if val=="":
277 return []
278 else:
279 result=[]
280 for v in val.split(splitchar):
281 if v[0]=='"' and v[-1]=='"':
282 result.append(v[1:-1])
283 else:
284 result.append(v)
285 return result
286
287 - def getboolean(self,section,option,default=None):
288 """Overrides the original implementation from ConfigParser
289 @param section: the section
290 @param option: the option
291 @param default: if set and the option is not found, then this value is used"""
292
293 try:
294 return configparser.ConfigParser.getboolean(self,
295 self.bestSection(section,option),
296 option)
297 except configparser.NoOptionError:
298 if default!=None:
299 return default
300 else:
301 raise
302
303 - def getint(self,section,option,default=None):
304 """Overrides the original implementation from ConfigParser
305 @param section: the section
306 @param option: the option
307 @param default: if set and the option is not found, then this value is used"""
308
309 try:
310 return int(configparser.ConfigParser.get(self,
311 self.bestSection(section,option),
312 option))
313 except configparser.NoOptionError:
314 if default!=None:
315 return default
316 else:
317 raise
318
319 - def getfloat(self,section,option,default=None):
320 """Overrides the original implementation from ConfigParser
321 @param section: the section
322 @param option: the option
323 @param default: if set and the option is not found, then this value is used"""
324
325 try:
326 return float(configparser.ConfigParser.get(self,
327 self.bestSection(section,option),
328 option))
329 except (configparser.NoOptionError,ValueError):
330 if default!=None:
331 return default
332 else:
333 raise
334
336 """Get an entry and interpret it as a regular expression. Subsitute
337 the usual regular expression value for floating point numbers
338 @param section: the section
339 @param option: the option
340 @param default: if set and the option is not found, then this value is used"""
341 floatRegExp="[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?"
342
343 return re.compile(self.get(section,option).replace("%f%",floatRegExp))
344
345 - def get(self,section,option,default=None,**kwargs):
346 """Overrides the original implementation from ConfigParser
347 @param section: the section
348 @param option: the option
349 @param default: if set and the option is not found, then this value is used"""
350
351 try:
352 return configparser.ConfigParser.get(self,
353 self.bestSection(section,option),
354 option,
355 **kwargs)
356 except configparser.NoOptionError:
357 if default!=None:
358 return default
359 else:
360 raise
361
363 """Gets a debug switch"""
364
365 return self.getboolean("Debug",name,default=False)
366
367
368