@@ -45,22 +45,21 @@ routine names my_perfect_routine
45
45
keyword names MYPERFECTKEYWORD
46
46
"""
47
47
48
- isAngstrom = False
49
- CODATAyear = 2010
50
-
51
48
import sys
49
+ import tempfile
52
50
import 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
54
56
57
+ sys.path.append(os.path.dirname(__file__))
55
58
try:
56
59
import docopt
57
- except:
60
+ except ImportError :
58
61
sys.path.append('cmake/lib/docopt')
59
62
import docopt
60
- from copy import deepcopy
61
- import getkw
62
- import re
63
- import subprocess
64
63
65
64
options = """
66
65
Usage:
@@ -73,8 +72,8 @@ Options:
73
72
-h --help Show this screen.
74
73
"""
75
74
76
- import getkw
77
- from codata import CODATA, CODATAdict
75
+ isAngstrom = False
76
+ CODATAyear = 2010
78
77
79
78
allowedSolvents = {'Water' : ('WATER', 'H2O'),
80
79
'Propylene Carbonate' : ('PROPYLENE CARBONATE', 'C4H6O3'),
@@ -110,12 +109,12 @@ def iequal(a, b):
110
109
def convert_to_upper_case(filename):
111
110
"""
112
111
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 .
114
113
"""
115
114
contents = ''
116
- final = ''
115
+ final = ''
117
116
with open(filename, 'r') as inputFile:
118
- contents = inputFile.readlines()
117
+ contents = inputFile.readlines()
119
118
# In case the "restart" field is present the case conversion
120
119
# has to be done a bit more carefully. The filename argument to
121
120
# "restart" should not be touched, whereas the rest of the file
@@ -135,9 +134,14 @@ def convert_to_upper_case(filename):
135
134
final = re.sub('FALSE', 'False', final)
136
135
final = re.sub('TRUE', 'True', final)
137
136
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:
140
141
outputFile.write(final)
142
+ os.close(temp)
143
+ return path
144
+
141
145
142
146
def main():
143
147
try:
@@ -164,15 +168,15 @@ def parse_pcm_input(inputFile):
164
168
# Set up valid keywords.
165
169
valid_keywords = setup_keywords()
166
170
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)
169
173
170
174
# Set up a GetKw object and let it parse our input:
171
175
# 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)
174
179
inkw.sanitize(valid_keywords)
175
- topsect = inkw.get_topsect()
176
180
inkw.run_callbacks(valid_keywords)
177
181
178
182
# The parsed, machine-readable file is now saved.
@@ -186,6 +190,7 @@ def parse_pcm_input(inputFile):
186
190
187
191
return parsedFile
188
192
193
+
189
194
def execute(parsedFile):
190
195
executable = os.path.join(os.path.dirname(__file__), "run_pcm" + "@CMAKE_EXECUTABLE_SUFFIX@")
191
196
if (executable):
@@ -205,12 +210,13 @@ def execute(parsedFile):
205
210
print('No executable available for standalone run')
206
211
sys.exit(1)
207
212
213
+
208
214
def setup_keywords():
209
215
"""
210
216
Sets up sections, keywords and respective callback functions.
211
217
"""
212
218
# Top-level section
213
- top = getkw.Section('toplevel', callback = verify_top)
219
+ top = getkw.Section('toplevel', callback= verify_top)
214
220
top.set_status(True)
215
221
# Define units of measure
216
222
# Valid values: AU (atomic units) or ANGSTROM
@@ -222,7 +228,7 @@ def setup_keywords():
222
228
top.add_kw('CODATA', 'INT', 2010)
223
229
224
230
# Cavity section
225
- cavity = getkw.Section('CAVITY', callback = verify_cavity)
231
+ cavity = getkw.Section('CAVITY', callback= verify_cavity)
226
232
# Type of the cavity
227
233
# Valid values: GEPOL, WAVELET, TSLESS and RESTART
228
234
cavity.add_kw('TYPE', 'STR')
@@ -290,11 +296,11 @@ def setup_keywords():
290
296
# List of spheres
291
297
# Valid for: GePol, TsLess and Wavelet in MODE=EXPLICIT
292
298
# 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)
294
300
top.add_sect(cavity)
295
301
296
302
# Medium section
297
- medium = getkw.Section('MEDIUM', callback = verify_medium)
303
+ medium = getkw.Section('MEDIUM', callback= verify_medium)
298
304
# Type of solver
299
305
# Valid values: IEFPCM, CPCM, WAVELET or LINEAR
300
306
medium.add_kw('SOLVERTYPE', 'STR', 'IEFPCM')
@@ -356,7 +362,7 @@ def setup_keywords():
356
362
top.add_sect(medium)
357
363
358
364
# Green's function section
359
- green = getkw.Section('GREEN', callback = verify_green)
365
+ green = getkw.Section('GREEN', callback= verify_green)
360
366
# Green's function type
361
367
# Valid values: VACUUM, UNIFORMDIELECTRIC, SPHERICALDIFFUSE, METALSPHERE, GREENSFUNCTIONSUM
362
368
# Default: VACUUM
@@ -450,7 +456,7 @@ def setup_keywords():
450
456
# List of geometry and classical point charges
451
457
# Valid values: array of doubles in format [x, y, z, Q]
452
458
# 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)
454
460
# Calculate the molecular electrostatic potential (MEP) at the cavity for the given molecule
455
461
# Valid values: boolean
456
462
# Default: True
@@ -460,7 +466,7 @@ def setup_keywords():
460
466
# ChargeDistribution section
461
467
# Set a classical charge distribution, inside or outside the cavity
462
468
# 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)
464
470
# Monopoles
465
471
# Valid values: array of doubles in format [x, y, z, Q]
466
472
# Notes: charges are always in atomic units
@@ -473,6 +479,7 @@ def setup_keywords():
473
479
474
480
return top
475
481
482
+
476
483
def verify_top(section):
477
484
global isAngstrom, CODATAyear
478
485
allowed_units = ('AU', 'ANGSTROM')
@@ -489,6 +496,7 @@ def verify_top(section):
489
496
print(('CODATA set requested {} is not among the allowed sets: {}'.format(CODATAyear, allowed_codata)))
490
497
sys.exit(1)
491
498
499
+
492
500
def verify_cavity(section):
493
501
allowed = ('GEPOL', 'WAVELET', 'TSLESS', 'RESTART')
494
502
type = section.get('TYPE')
@@ -505,7 +513,6 @@ def verify_cavity(section):
505
513
if (section['MINDISTANCE'].is_set()):
506
514
convert_length_scalar(section['MINDISTANCE'])
507
515
508
-
509
516
if (type.get() == 'GEPOL'):
510
517
area = section.get('AREA')
511
518
a = area.get()
@@ -514,7 +521,7 @@ def verify_cavity(section):
514
521
sys.exit(1)
515
522
minRadius = section.get('MINRADIUS')
516
523
mr = minRadius.get()
517
- if ( mr < 0.4 ):
524
+ if (mr < 0.4):
518
525
print(('Requested minimal radius for added spheres too small: {}. Minimal value is: 0.4 au'.format(mr)))
519
526
sys.exit(1)
520
527
elif (type.get() == 'WAVELET'):
@@ -532,16 +539,16 @@ def verify_cavity(section):
532
539
if (a < 0.01):
533
540
print(('Requested area value too small: {}. Minimal value is: 0.01 au^2'.format(a)))
534
541
sys.exit(1)
535
- minDistance = section.get('MINDISTANCE')
536
- md = minDistance.get()
542
+ # minDistance = section.get('MINDISTANCE')
543
+ # md = minDistance.get()
537
544
# Insert a sanity check on minimal distance!
538
- #if ( md < 0.4 ):
545
+ # if ( md < 0.4 ):
539
546
# print("Requested minimal distance between sampling points too small: {}. Minimal value is: 0.4 au".format(md))
540
547
# sys.exit(1)
541
- derOrder = section.get('DERORDER')
542
- do = derOrder.get()
548
+ # derOrder = section.get('DERORDER')
549
+ # do = derOrder.get()
543
550
# Insert a check on derivative order
544
- #if ( do > 4 ):
551
+ # if ( do > 4 ):
545
552
# print("Invalid derivative order requested: {}. Derivative order has to be within [1, 5]".format(md))
546
553
# sys.exit(1)
547
554
elif (type.get() == 'RESTART'):
@@ -564,10 +571,10 @@ def verify_cavity(section):
564
571
print(('Cavity creation mode requested {} is not among the allowed modes: {}'.format(mode.get(), allowed_modes)))
565
572
sys.exit(1)
566
573
567
- atoms= section.get('ATOMS')
568
- at= atoms.get()
574
+ atoms = section.get('ATOMS')
575
+ at = atoms.get()
569
576
radii = section.get('RADII')
570
- convert_length_array(radii);
577
+ convert_length_array(radii)
571
578
r = radii.get()
572
579
573
580
if (mode.get() == 'ATOMS'):
@@ -580,6 +587,7 @@ def verify_cavity(section):
580
587
print('Incoherent input for Atoms keyword. Too many spheres on the same atom(s).')
581
588
sys.exit(1)
582
589
590
+
583
591
def verify_medium(section):
584
592
solvent = section.get('SOLVENT')
585
593
explicitSolvent = solvent.get() in allowedSolvents['Explicit']
@@ -598,7 +606,6 @@ def verify_medium(section):
598
606
solventFound = False
599
607
for i, v in allowedSolvents.items():
600
608
if (solvent.get() in v):
601
- solventName = i
602
609
# Set name to the first value in the value pair
603
610
# C++ will look for this name!
604
611
solvent.set(v[0])
@@ -660,17 +667,18 @@ def verify_medium(section):
660
667
print('A posteriori compression parameter has to be in ]0.0, 1.0[')
661
668
sys.exit(1)
662
669
670
+
663
671
def verify_green(section):
664
- allowed = ('VACUUM', 'UNIFORMDIELECTRIC', 'SPHERICALDIFFUSE', 'ALTERNATESPHERICALDIFFUSE', 'METALSPHERE', 'GREENSFUNCTIONSUM')
672
+ allowed = ('VACUUM', 'UNIFORMDIELECTRIC', 'SPHERICALDIFFUSE', 'ALTERNATESPHERICALDIFFUSE', 'METALSPHERE', 'GREENSFUNCTIONSUM')
665
673
allowed_der = ('NUMERICAL', 'DERIVATIVE', 'GRADIENT', 'HESSIAN')
666
674
allowed_profiles = ('TANH', 'ERF')
667
675
668
676
green1 = section.fetch_sect('GREEN<ONE>')
669
677
green2 = section.fetch_sect('GREEN<TWO>')
670
- eps = section.get('EPS')
678
+ eps = section.get('EPS')
671
679
epsdyn = section.get('EPSDYN')
672
680
epsimg = section.get('EPSIMG')
673
- epsre = section.get('EPSRE')
681
+ epsre = section.get('EPSRE')
674
682
675
683
convert_length_array(section.get('SPHEREPOSITION'))
676
684
position = section.get('SPHEREPOSITION')
@@ -722,6 +730,7 @@ def verify_green(section):
722
730
print(('Allowed profiles are: {}'.format(allowed_profiles)))
723
731
sys.exit(1)
724
732
733
+
725
734
def check_array(name, array, offset):
726
735
dim = len(array)
727
736
if (dim % offset != 0):
@@ -736,36 +745,43 @@ def check_array(name, array, offset):
736
745
array[j+2] /= CODATAdict[CODATAyear].ToAngstrom
737
746
j += offset
738
747
748
+
739
749
def verify_geometry(keyword):
740
750
data = keyword.get()
741
751
check_array('GEOMETRY', data, 4)
742
752
753
+
743
754
def verify_charge_distribution(section):
744
755
mono = section.get('MONOPOLES').get()
745
756
check_array('MONOPOLES', mono, 4)
746
757
dipole = section.get('DIPOLES').get()
747
758
check_array('DIPOLES', dipole, 6)
748
759
760
+
749
761
def verify_spheres(keyword):
750
- length= len(keyword.get())
762
+ length = len(keyword.get())
751
763
if (length % 4 != 0):
752
764
print('Empty or incoherent Spheres list.')
753
765
sys.exit(1)
754
766
convert_length_array(keyword)
755
767
768
+
756
769
def convert_length_array(keyword):
757
- length= len(keyword.get())
770
+ length = len(keyword.get())
758
771
if (isAngstrom):
759
772
for i in range(length):
760
773
keyword[i] /= CODATAdict[CODATAyear].ToAngstrom
761
774
775
+
762
776
def convert_length_scalar(keyword):
763
777
if (isAngstrom):
764
778
keyword[0] /= CODATAdict[CODATAyear].ToAngstrom
765
779
780
+
766
781
def convert_area_scalar(keyword):
767
782
if (isAngstrom):
768
783
keyword[0] /= (CODATAdict[CODATAyear].ToAngstrom * CODATAdict[CODATAyear].ToAngstrom)
769
784
785
+
770
786
if __name__ == '__main__':
771
787
main()
0 commit comments