1 """
2 Application-class that implements pyFoamPrepareCase.py
3 """
4 from optparse import OptionGroup
5
6 from .PyFoamApplication import PyFoamApplication
7
8 from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory
9 from PyFoam.Basics.Utilities import rmtree,copytree,execute,remove
10 from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile,WriteParameterFile
11 from PyFoam.Basics.TemplateFile import TemplateFile
12 from PyFoam.Execution.BasicRunner import BasicRunner
13
14 from PyFoam.FoamInformation import foamFork,foamVersion
15
16 from .CommonTemplateFormat import CommonTemplateFormat
17 from .CommonTemplateBehaviour import CommonTemplateBehaviour
18
19 from PyFoam.ThirdParty.six import print_,iteritems
20
21 from PyFoam import configuration
22
23 from os import path,listdir,mkdir
24 from shutil import copymode,copy
25
26 -class PrepareCase(PyFoamApplication,
27 CommonTemplateBehaviour,
28 CommonTemplateFormat):
29
30 parameterOutFile="PyFoamPrepareCaseParameters"
31
32 - def __init__(self,
33 args=None,
34 exactNr=True,
35 interspersed=True,
36 usage="%prog <caseDirectory>",
37 examples=None,
38 nr=1,
39 description=None,
40 **kwargs):
41 self.defaultMeshCreate=configuration().get("PrepareCase","MeshCreateScript")
42 self.defaultCaseSetup=configuration().get("PrepareCase","CaseSetupScript")
43
44 description2="""\
45 Prepares a case for running. This is intended to be the replacement for
46 boiler-plate scripts. The steps done are
47
48 1. Clear old data from the case (including processor directories)
49
50 2. if a folder 0.org is present remove the 0 folder too
51
52 3. go through all folders and for every found file with the extension .template
53 do template expansion using the pyratemp-engine (automatically create variables
54 casePath and caseName)
55
56 4. create a mesh (either by using a script or if a blockMeshDict is present by
57 running blockMesh. If none of these is present assume that there is a valid mesh
58 present)
59
60 5. copy every foo.org that is found to to foo (recursively if directory)
61
62 6. do template-expansion for every file with the extension .postTemplate
63
64 7. execute another preparation script
65
66 The used parameters are written to a file 'PyFoamPrepareCaseParameters' and are used by other utilities
67 """
68 examples2="""\
69 %prog . --paramter-file=parameters.base
70
71 Prepare the current case with the parameters list in parameters.base
72
73 %prog . --paramter-file=parameters.base --values-string="{'visco':1e-3}"
74
75 Changes the value of the parameter visco
76
77 %prog . --no-mesh-create
78
79 Skip the mesh creation phase
80 """
81 PyFoamApplication.__init__(self,
82 args=args,
83 description=description if description else description2,
84 usage=usage,
85 examples=examples if examples else examples2,
86 interspersed=interspersed,
87 nr=nr,
88 exactNr=exactNr,
89 **kwargs)
90
92 output=OptionGroup(self.parser,
93 "Output",
94 "What information should be given")
95 self.parser.add_option_group(output)
96 output.add_option("--fatal",
97 action="store_true",
98 dest="fatal",
99 default=False,
100 help="If non-cases are specified the program should abort")
101 output.add_option("--no-complain",
102 action="store_true",
103 dest="noComplain",
104 default=False,
105 help="Don't complain about non-case-files")
106 output.add_option("--quiet",
107 action="store_false",
108 dest="verbose",
109 default=True,
110 help="Do not report what is being done")
111 output.add_option("--no-write-parameters",
112 action="store_false",
113 dest="writeParameters",
114 default=True,
115 help="Usually a file '"+self.parameterOutFile+"' with a dictionary of the used parameters is written to the case directory. ")
116
117 extensions=OptionGroup(self.parser,
118 "Extensions",
119 "File extensions that are used in actions")
120 self.parser.add_option_group(extensions)
121 extensions.add_option("--template-extension",
122 action="store",
123 dest="templateExt",
124 default=".template",
125 help="Extension for template files. Default: %default")
126 extensions.add_option("--post-template-extension",
127 action="store",
128 dest="postTemplateExt",
129 default=".postTemplate",
130 help="Extension for post-template files. Default: %default")
131 extensions.add_option("--original-extension",
132 action="store",
133 dest="originalExt",
134 default=".org",
135 help="Extension for files and directories that are copied. Default: %default")
136
137 inputs=OptionGroup(self.parser,
138 "Inputs",
139 "Inputs for the templating process")
140 self.parser.add_option_group(inputs)
141
142 inputs.add_option("--parameter-file",
143 action="append",
144 default=[],
145 dest="valuesDicts",
146 help="Name of a dictionary-file in OpenFOAM-format. Can be specified more than once. Values in later files override old values")
147 inputs.add_option("--values-string",
148 action="append",
149 default=[],
150 dest="values",
151 help="String with the values that are to be inserted into the template as a dictionaty in Python-format. Can be specified more than once and overrides values from the parameter-files")
152
153 special=OptionGroup(self.parser,
154 "Special files and directories",
155 "Files and directories that get special treatment")
156 self.parser.add_option_group(special)
157
158 special.add_option("--directories-to-clean",
159 action="append",
160 default=["0"],
161 dest="cleanDirectories",
162 help="Directory from which templates are cleaned (to avoid problems with decomposePar). Can be specified more than once. Default: %default")
163 special.add_option("--overload-directory",
164 action="append",
165 default=[],
166 dest="overloadDirs",
167 help="Before starting the preparation process load files from this directory recursively into this case. Caution: existing files will be overwritten. Can be specified more than once. Directories are then copied in the specified order")
168
169 CommonTemplateFormat.addOptions(self)
170 CommonTemplateBehaviour.addOptions(self)
171
172 stages=OptionGroup(self.parser,
173 "Stages",
174 "Which steps should be executed")
175 self.parser.add_option_group(stages)
176
177 stages.add_option("--only-variables",
178 action="store_true",
179 dest="onlyVariables",
180 default=False,
181 help="Do nothing. Only read the variables")
182
183 stages.add_option("--no-clear",
184 action="store_false",
185 dest="doClear",
186 default=True,
187 help="Do not clear the case")
188
189 stages.add_option("--no-templates",
190 action="store_false",
191 dest="doTemplates",
192 default=True,
193 help="Do not rework the templates")
194
195 stages.add_option("--no-mesh-create",
196 action="store_false",
197 dest="doMeshCreate",
198 default=True,
199 help="Do not execute a script to create a mesh")
200
201 stages.add_option("--no-copy",
202 action="store_false",
203 dest="doCopy",
204 default=True,
205 help="Do not copy original directories")
206
207 stages.add_option("--no-post-templates",
208 action="store_false",
209 dest="doPostTemplates",
210 default=True,
211 help="Do not rework the post-templates")
212
213 stages.add_option("--no-case-setup",
214 action="store_false",
215 dest="doCaseSetup",
216 default=True,
217 help="Do not execute a script to set initial conditions etc")
218
219 stages.add_option("--no-template-clean",
220 action="store_false",
221 dest="doTemplateClean",
222 default=True,
223 help="Do not clean template files from 0-directory")
224
225 scripts=OptionGroup(self.parser,
226 "Scripts",
227 "Specification of scripts to be executed")
228 self.parser.add_option_group(scripts)
229
230 scripts.add_option("--mesh-create-script",
231 action="store",
232 dest="meshCreateScript",
233 default=None,
234 help="Script that is executed after the template expansion to create the mesh. If not specified then the utility looks for "+self.defaultMeshCreate+" and executes this. If this is also not found blockMesh is executed if a blockMeshDict is found")
235 scripts.add_option("--case-setup-script",
236 action="store",
237 dest="caseSetupScript",
238 default=None,
239 help="Script that is executed after the original files have been copied to set initial conditions or similar. If not specified then the utility looks for "+self.defaultCaseSetup+" and executes this.")
240
242 """Go recursivly through directories and copy foo.org to foo"""
243 if self.opts.verbose:
244 print_("Looking for originals in",startDir)
245 for f in listdir(startDir):
246 if f[0]==".":
247 if self.opts.verbose:
248 print_("Skipping",f)
249 continue
250 src=path.join(startDir,f)
251 if path.splitext(f)[1]==self.opts.originalExt:
252 dst=path.join(startDir,path.splitext(f)[0])
253 if path.exists(dst):
254 if self.opts.verbose:
255 print_("Replacing",dst,"with",src)
256 rmtree(dst)
257 else:
258 if self.opts.verbose:
259 print_("Copying",src,"to",dst)
260 copytree(src,dst,force=True)
261 elif path.isdir(src):
262 self.copyOriginals(src)
263
267 """Go recursivly through directories and remove all files that have a specific extension"""
268 if self.opts.verbose:
269 print_("Looking for extension",ext,"in",startDir)
270 for f in listdir(startDir):
271 if f[0]==".":
272 if self.opts.verbose:
273 print_("Skipping",f)
274 continue
275 src=path.join(startDir,f)
276 if path.splitext(f)[1]==ext and not path.isdir(src):
277 if self.opts.verbose:
278 print_("Removing",src)
279 remove(src)
280 elif path.isdir(src):
281 self.cleanExtension(src,ext)
282
287 """Go through the directory recursively and replate foo.template with
288 foo after inserting the values"""
289 if self.opts.verbose:
290 print_("Looking for templates with extension",templateExt,"in ",startDir)
291 for f in listdir(startDir):
292 if f[0]==".":
293 if self.opts.verbose:
294 print_("Skipping",f)
295 continue
296 if path.isdir(path.join(startDir,f)):
297 self.searchAndReplaceTemplates(
298 path.join(startDir,f),
299 values,
300 templateExt)
301 elif path.splitext(f)[1]==templateExt:
302 fName=path.join(startDir,path.splitext(f)[0])
303 if self.opts.verbose:
304 print_("Found template for",fName)
305 t=TemplateFile(name=fName+templateExt,
306 tolerantRender=self.opts.tolerantRender,
307 allowExec=self.opts.allowExec,
308 expressionDelimiter=self.opts.expressionDelimiter,
309 assignmentDebug=self.pickAssignmentDebug(fName),
310 assignmentLineStart=self.opts.assignmentLineStart)
311 t.writeToFile(fName,values)
312 copymode(fName+templateExt,fName)
313
315 """Copy files recursively. Overwrite local copies if they exist"""
316 for f in listdir(there):
317 fSrc=path.join(there,f)
318 fDst=path.join(here,f)
319 if path.isdir(fSrc):
320 if not path.exists(fDst):
321 if self.opts.verbose:
322 print_("Creating directory",fDst)
323 mkdir(fDst)
324 elif not path.isdir(fDst):
325 self.error("Destination path",fDst,"exists, but is no directory")
326 self.overloadDir(fDst,fSrc)
327 elif path.isfile(fSrc):
328 if path.exists(fDst):
329 if not path.isfile(fDst):
330 self.error("Desination",fDst,"exists but is no file")
331 if self.opts.verbose:
332 print_("Copying",fSrc,"to",fDst)
333 copy(fSrc,fDst)
334 else:
335 self.errr("Source file",fSrc,"is neither file nor directory")
336
343
344 - def prepare(self,sol,cName=None,overrideParameters=None):
345 if cName==None:
346 cName=sol.name
347
348 if self.opts.onlyVariables:
349 self.opts.verbose=True
350
351 vals={}
352 vals["casePath"]='"'+path.abspath(cName)+'"'
353 vals["caseName"]='"'+path.basename(path.abspath(cName))+'"'
354 vals["foamVersion"]=foamVersion()
355 vals["foamFork"]=foamFork()
356
357 if self.opts.verbose:
358 print_("Looking for template values",cName)
359 for f in self.opts.valuesDicts:
360 if self.opts.verbose:
361 print_("Reading values from",f)
362 vals.update(ParsedParameterFile(f,
363 noHeader=True,
364 doMacroExpansion=True).getValueDict())
365 for v in self.opts.values:
366 if self.opts.verbose:
367 print_("Updating values",v)
368 vals.update(eval(v))
369
370 if overrideParameters:
371 vals.update(overrideParameters)
372
373 if self.opts.verbose and len(vals)>0:
374 print_("\nUsed values\n")
375 nameLen=max(len("Name"),
376 max(*[len(k) for k in vals.keys()]))
377 format="%%%ds - %%s" % nameLen
378 print_(format % ("Name","Value"))
379 print_("-"*40)
380 for k,v in sorted(iteritems(vals)):
381 print_(format % (k,v))
382 print_("")
383 elif self.opts.verbose:
384 print_("\nNo values specified\n")
385
386 if self.opts.onlyVariables:
387 return
388
389 if self.opts.doClear:
390 if self.opts.verbose:
391 print_("Clearing",cName)
392 sol.clear(processor=True,
393 pyfoam=True,
394 vtk=True,
395 removeAnalyzed=True,
396 keepParallel=False,
397 clearHistory=False,
398 clearParameters=True,
399 additional=["postProcessing"])
400
401 if self.opts.writeParameters:
402 fName=path.join(cName,self.parameterOutFile)
403 if self.opts.verbose:
404 print_("Writing parameters to",fName)
405 with WriteParameterFile(fName,noHeader=True) as w:
406 w.content.update(vals,toString=True)
407 w["foamVersion"]=vals["foamVersion"]
408 w.writeFile()
409
410 self.addToCaseLog(cName)
411
412 for over in self.opts.overloadDirs:
413 if self.opts.verbose:
414 print_("Overloading files from",over)
415 self.overloadDir(sol.name,over)
416
417 zeroOrig=path.join(sol.name,"0.org")
418
419 hasOrig=path.exists(zeroOrig)
420 if not hasOrig:
421 if self.opts.verbose:
422 print_("Not going to clean '0'")
423 self.opts.cleanDirectories.remove("0")
424
425 if self.opts.doCopy:
426 if hasOrig:
427 if self.opts.verbose:
428 print_("Found 0.org. Clearing 0")
429 zeroDir=path.join(sol.name,"0")
430 if path.exists(zeroDir):
431 rmtree(zeroDir)
432 elif self.opts.verbose:
433 print_("No 0-directory")
434
435 if self.opts.verbose:
436 print_("")
437
438 if self.opts.doTemplates:
439 self.searchAndReplaceTemplates(sol.name,
440 vals,
441 self.opts.templateExt)
442
443 if self.opts.verbose:
444 print_("")
445
446 if self.opts.doMeshCreate:
447 if self.opts.meshCreateScript:
448 scriptName=path.join(sol.name,self.opts.meshCreateScript)
449 if not path.exists(scriptName):
450 self.error("Script",scriptName,"does not exist")
451 elif path.exists(path.join(sol.name,self.defaultMeshCreate)):
452 scriptName=path.join(sol.name,self.defaultMeshCreate)
453 else:
454 scriptName=None
455
456 if scriptName:
457 if self.opts.verbose:
458 print_("Executing",scriptName,"for mesh creation")
459 if self.opts.verbose:
460 echo="Mesh: "
461 else:
462 echo=None
463 result="".join(execute([scriptName],workdir=sol.name,echo=echo))
464 open(scriptName+".log","w").write(result)
465 else:
466 if self.opts.verbose:
467 print_("No script for mesh creation found. Looking for 'blockMeshDict'")
468 if sol.blockMesh()!="":
469 if self.opts.verbose:
470 print_(sol.blockMesh(),"found. Executing 'blockMesh'")
471 bm=BasicRunner(argv=["blockMesh","-case",sol.name])
472 bm.start()
473 if not bm.runOK():
474 self.error("Problem with blockMesh")
475 if self.opts.verbose:
476 print_("")
477
478 if self.opts.doCopy:
479 self.copyOriginals(sol.name)
480
481 if self.opts.verbose:
482 print_("")
483
484 if self.opts.doPostTemplates:
485 self.searchAndReplaceTemplates(sol.name,
486 vals,
487 self.opts.postTemplateExt)
488
489 if self.opts.verbose:
490 print_("")
491
492 if self.opts.doCaseSetup:
493 if self.opts.caseSetupScript:
494 scriptName=path.join(sol.name,self.opts.caseSetupScript)
495 if not path.exists(scriptName):
496 self.error("Script",scriptName,"does not exist")
497 elif path.exists(path.join(sol.name,self.defaultCaseSetup)):
498 scriptName=path.join(sol.name,self.defaultCaseSetup)
499 else:
500 scriptName=None
501
502 if scriptName:
503 if self.opts.verbose:
504 print_("Executing",scriptName,"for case setup")
505 if self.opts.verbose:
506 echo="Case:"
507 else:
508 echo=None
509 result="".join(execute([scriptName],workdir=sol.name,echo=echo))
510 open(scriptName+".log","w").write(result)
511 else:
512 if self.opts.verbose:
513 print_("No script for case-setup found. Nothing done")
514 if self.opts.verbose:
515 print_("")
516
517 if self.opts.doTemplateClean:
518 if self.opts.verbose:
519 print_("Clearing templates")
520 for d in self.opts.cleanDirectories:
521 for e in [self.opts.templateExt,self.opts.postTemplateExt]:
522 self.cleanExtension(path.join(sol.name,d),e)
523 if self.opts.verbose:
524 print_("")
525
526 if self.opts.verbose:
527 print_("Case setup finished")
528