@@ -45,22 +45,21 @@ routine names my_perfect_routine
4545keyword names MYPERFECTKEYWORD
4646"""
4747
48- isAngstrom = False
49- CODATAyear = 2010
50-
5148import sys
49+ import tempfile
5250import os
53- sys.path.append(os.path.dirname(__file__))
51+ from copy import deepcopy
52+ import getkw
53+ import re
54+ import subprocess
55+ from codata import CODATAdict
5456
57+ sys.path.append(os.path.dirname(__file__))
5558try:
5659 import docopt
57- except:
60+ except ImportError :
5861 sys.path.append('cmake/lib/docopt')
5962 import docopt
60- from copy import deepcopy
61- import getkw
62- import re
63- import subprocess
6463
6564options = """
6665Usage:
@@ -73,8 +72,8 @@ Options:
7372 -h --help Show this screen.
7473"""
7574
76- import getkw
77- from codata import CODATA, CODATAdict
75+ isAngstrom = False
76+ CODATAyear = 2010
7877
7978allowedSolvents = {'Water' : ('WATER', 'H2O'),
8079 'Propylene Carbonate' : ('PROPYLENE CARBONATE', 'C4H6O3'),
@@ -110,12 +109,12 @@ def iequal(a, b):
110109def convert_to_upper_case(filename):
111110 """
112111 Reads contents of filename and converts them to uppercase.
113- The case-converted contents are written back to filename .
112+ The case-converted contents are written back to a temporary file .
114113 """
115114 contents = ''
116- final = ''
115+ final = ''
117116 with open(filename, 'r') as inputFile:
118- contents = inputFile.readlines()
117+ contents = inputFile.readlines()
119118 # In case the "restart" field is present the case conversion
120119 # has to be done a bit more carefully. The filename argument to
121120 # "restart" should not be touched, whereas the rest of the file
@@ -135,9 +134,14 @@ def convert_to_upper_case(filename):
135134 final = re.sub('FALSE', 'False', final)
136135 final = re.sub('TRUE', 'True', final)
137136
138- # Write to file
139- with open(filename, 'wt') as outputFile:
137+ # Write to temporary file in current working directory
138+ # The temporary file has the name of the input file, joined with a unique id
139+ temp, path = tempfile.mkstemp(prefix=filename + '.', dir=os.getcwd())
140+ with open(path, 'wt') as outputFile:
140141 outputFile.write(final)
142+ os.close(temp)
143+ return path
144+
141145
142146def main():
143147 try:
@@ -164,15 +168,15 @@ def parse_pcm_input(inputFile):
164168 # Set up valid keywords.
165169 valid_keywords = setup_keywords()
166170
167- # Convert to uppercase
168- convert_to_upper_case(inputFile)
171+ # Convert to uppercase and get the path to the temporary file
172+ uppercased = convert_to_upper_case(inputFile)
169173
170174 # Set up a GetKw object and let it parse our input:
171175 # here is where the magic happens.
172- input = getkw.GetkwParser()
173- inkw = input.parseFile(inputFile)
176+ inkw = getkw.GetkwParser().parseFile(uppercased)
177+ # Remove temporary file
178+ os.remove(uppercased)
174179 inkw.sanitize(valid_keywords)
175- topsect = inkw.get_topsect()
176180 inkw.run_callbacks(valid_keywords)
177181
178182 # The parsed, machine-readable file is now saved.
@@ -186,6 +190,7 @@ def parse_pcm_input(inputFile):
186190
187191 return parsedFile
188192
193+
189194def execute(parsedFile):
190195 executable = os.path.join(os.path.dirname(__file__), "run_pcm" + "@CMAKE_EXECUTABLE_SUFFIX@")
191196 if (executable):
@@ -205,12 +210,13 @@ def execute(parsedFile):
205210 print('No executable available for standalone run')
206211 sys.exit(1)
207212
213+
208214def setup_keywords():
209215 """
210216 Sets up sections, keywords and respective callback functions.
211217 """
212218 # Top-level section
213- top = getkw.Section('toplevel', callback = verify_top)
219+ top = getkw.Section('toplevel', callback= verify_top)
214220 top.set_status(True)
215221 # Define units of measure
216222 # Valid values: AU (atomic units) or ANGSTROM
@@ -222,7 +228,7 @@ def setup_keywords():
222228 top.add_kw('CODATA', 'INT', 2010)
223229
224230 # Cavity section
225- cavity = getkw.Section('CAVITY', callback = verify_cavity)
231+ cavity = getkw.Section('CAVITY', callback= verify_cavity)
226232 # Type of the cavity
227233 # Valid values: GEPOL, WAVELET, TSLESS and RESTART
228234 cavity.add_kw('TYPE', 'STR')
@@ -290,11 +296,11 @@ def setup_keywords():
290296 # List of spheres
291297 # Valid for: GePol, TsLess and Wavelet in MODE=EXPLICIT
292298 # Valid values: array of doubles in format [x, y, z, R]
293- cavity.add_kw('SPHERES', 'DBL_ARRAY', callback = verify_spheres)
299+ cavity.add_kw('SPHERES', 'DBL_ARRAY', callback= verify_spheres)
294300 top.add_sect(cavity)
295301
296302 # Medium section
297- medium = getkw.Section('MEDIUM', callback = verify_medium)
303+ medium = getkw.Section('MEDIUM', callback= verify_medium)
298304 # Type of solver
299305 # Valid values: IEFPCM, CPCM, WAVELET or LINEAR
300306 medium.add_kw('SOLVERTYPE', 'STR', 'IEFPCM')
@@ -356,7 +362,7 @@ def setup_keywords():
356362 top.add_sect(medium)
357363
358364 # Green's function section
359- green = getkw.Section('GREEN', callback = verify_green)
365+ green = getkw.Section('GREEN', callback= verify_green)
360366 # Green's function type
361367 # Valid values: VACUUM, UNIFORMDIELECTRIC, SPHERICALDIFFUSE, METALSPHERE, GREENSFUNCTIONSUM
362368 # Default: VACUUM
@@ -450,7 +456,7 @@ def setup_keywords():
450456 # List of geometry and classical point charges
451457 # Valid values: array of doubles in format [x, y, z, Q]
452458 # Notes: charges are always in atomic units
453- molecule.add_kw('GEOMETRY', 'DBL_ARRAY', callback = verify_geometry)
459+ molecule.add_kw('GEOMETRY', 'DBL_ARRAY', callback= verify_geometry)
454460 # Calculate the molecular electrostatic potential (MEP) at the cavity for the given molecule
455461 # Valid values: boolean
456462 # Default: True
@@ -460,7 +466,7 @@ def setup_keywords():
460466 # ChargeDistribution section
461467 # Set a classical charge distribution, inside or outside the cavity
462468 # No additional spheres will be generated.
463- charge_distribution = getkw.Section('CHARGEDISTRIBUTION', callback = verify_charge_distribution)
469+ charge_distribution = getkw.Section('CHARGEDISTRIBUTION', callback= verify_charge_distribution)
464470 # Monopoles
465471 # Valid values: array of doubles in format [x, y, z, Q]
466472 # Notes: charges are always in atomic units
@@ -473,6 +479,7 @@ def setup_keywords():
473479
474480 return top
475481
482+
476483def verify_top(section):
477484 global isAngstrom, CODATAyear
478485 allowed_units = ('AU', 'ANGSTROM')
@@ -489,6 +496,7 @@ def verify_top(section):
489496 print(('CODATA set requested {} is not among the allowed sets: {}'.format(CODATAyear, allowed_codata)))
490497 sys.exit(1)
491498
499+
492500def verify_cavity(section):
493501 allowed = ('GEPOL', 'WAVELET', 'TSLESS', 'RESTART')
494502 type = section.get('TYPE')
@@ -505,7 +513,6 @@ def verify_cavity(section):
505513 if (section['MINDISTANCE'].is_set()):
506514 convert_length_scalar(section['MINDISTANCE'])
507515
508-
509516 if (type.get() == 'GEPOL'):
510517 area = section.get('AREA')
511518 a = area.get()
@@ -514,7 +521,7 @@ def verify_cavity(section):
514521 sys.exit(1)
515522 minRadius = section.get('MINRADIUS')
516523 mr = minRadius.get()
517- if ( mr < 0.4 ):
524+ if (mr < 0.4):
518525 print(('Requested minimal radius for added spheres too small: {}. Minimal value is: 0.4 au'.format(mr)))
519526 sys.exit(1)
520527 elif (type.get() == 'WAVELET'):
@@ -532,16 +539,16 @@ def verify_cavity(section):
532539 if (a < 0.01):
533540 print(('Requested area value too small: {}. Minimal value is: 0.01 au^2'.format(a)))
534541 sys.exit(1)
535- minDistance = section.get('MINDISTANCE')
536- md = minDistance.get()
542+ # minDistance = section.get('MINDISTANCE')
543+ # md = minDistance.get()
537544 # Insert a sanity check on minimal distance!
538- #if ( md < 0.4 ):
545+ # if ( md < 0.4 ):
539546 # print("Requested minimal distance between sampling points too small: {}. Minimal value is: 0.4 au".format(md))
540547 # sys.exit(1)
541- derOrder = section.get('DERORDER')
542- do = derOrder.get()
548+ # derOrder = section.get('DERORDER')
549+ # do = derOrder.get()
543550 # Insert a check on derivative order
544- #if ( do > 4 ):
551+ # if ( do > 4 ):
545552 # print("Invalid derivative order requested: {}. Derivative order has to be within [1, 5]".format(md))
546553 # sys.exit(1)
547554 elif (type.get() == 'RESTART'):
@@ -564,10 +571,10 @@ def verify_cavity(section):
564571 print(('Cavity creation mode requested {} is not among the allowed modes: {}'.format(mode.get(), allowed_modes)))
565572 sys.exit(1)
566573
567- atoms= section.get('ATOMS')
568- at= atoms.get()
574+ atoms = section.get('ATOMS')
575+ at = atoms.get()
569576 radii = section.get('RADII')
570- convert_length_array(radii);
577+ convert_length_array(radii)
571578 r = radii.get()
572579
573580 if (mode.get() == 'ATOMS'):
@@ -580,6 +587,7 @@ def verify_cavity(section):
580587 print('Incoherent input for Atoms keyword. Too many spheres on the same atom(s).')
581588 sys.exit(1)
582589
590+
583591def verify_medium(section):
584592 solvent = section.get('SOLVENT')
585593 explicitSolvent = solvent.get() in allowedSolvents['Explicit']
@@ -598,7 +606,6 @@ def verify_medium(section):
598606 solventFound = False
599607 for i, v in allowedSolvents.items():
600608 if (solvent.get() in v):
601- solventName = i
602609 # Set name to the first value in the value pair
603610 # C++ will look for this name!
604611 solvent.set(v[0])
@@ -660,17 +667,18 @@ def verify_medium(section):
660667 print('A posteriori compression parameter has to be in ]0.0, 1.0[')
661668 sys.exit(1)
662669
670+
663671def verify_green(section):
664- allowed = ('VACUUM', 'UNIFORMDIELECTRIC', 'SPHERICALDIFFUSE', 'ALTERNATESPHERICALDIFFUSE', 'METALSPHERE', 'GREENSFUNCTIONSUM')
672+ allowed = ('VACUUM', 'UNIFORMDIELECTRIC', 'SPHERICALDIFFUSE', 'ALTERNATESPHERICALDIFFUSE', 'METALSPHERE', 'GREENSFUNCTIONSUM')
665673 allowed_der = ('NUMERICAL', 'DERIVATIVE', 'GRADIENT', 'HESSIAN')
666674 allowed_profiles = ('TANH', 'ERF')
667675
668676 green1 = section.fetch_sect('GREEN<ONE>')
669677 green2 = section.fetch_sect('GREEN<TWO>')
670- eps = section.get('EPS')
678+ eps = section.get('EPS')
671679 epsdyn = section.get('EPSDYN')
672680 epsimg = section.get('EPSIMG')
673- epsre = section.get('EPSRE')
681+ epsre = section.get('EPSRE')
674682
675683 convert_length_array(section.get('SPHEREPOSITION'))
676684 position = section.get('SPHEREPOSITION')
@@ -722,6 +730,7 @@ def verify_green(section):
722730 print(('Allowed profiles are: {}'.format(allowed_profiles)))
723731 sys.exit(1)
724732
733+
725734def check_array(name, array, offset):
726735 dim = len(array)
727736 if (dim % offset != 0):
@@ -736,36 +745,43 @@ def check_array(name, array, offset):
736745 array[j+2] /= CODATAdict[CODATAyear].ToAngstrom
737746 j += offset
738747
748+
739749def verify_geometry(keyword):
740750 data = keyword.get()
741751 check_array('GEOMETRY', data, 4)
742752
753+
743754def verify_charge_distribution(section):
744755 mono = section.get('MONOPOLES').get()
745756 check_array('MONOPOLES', mono, 4)
746757 dipole = section.get('DIPOLES').get()
747758 check_array('DIPOLES', dipole, 6)
748759
760+
749761def verify_spheres(keyword):
750- length= len(keyword.get())
762+ length = len(keyword.get())
751763 if (length % 4 != 0):
752764 print('Empty or incoherent Spheres list.')
753765 sys.exit(1)
754766 convert_length_array(keyword)
755767
768+
756769def convert_length_array(keyword):
757- length= len(keyword.get())
770+ length = len(keyword.get())
758771 if (isAngstrom):
759772 for i in range(length):
760773 keyword[i] /= CODATAdict[CODATAyear].ToAngstrom
761774
775+
762776def convert_length_scalar(keyword):
763777 if (isAngstrom):
764778 keyword[0] /= CODATAdict[CODATAyear].ToAngstrom
765779
780+
766781def convert_area_scalar(keyword):
767782 if (isAngstrom):
768783 keyword[0] /= (CODATAdict[CODATAyear].ToAngstrom * CODATAdict[CODATAyear].ToAngstrom)
769784
785+
770786if __name__ == '__main__':
771787 main()
0 commit comments