3
3
"""Setup and run MOPAC for the Lewis structure"""
4
4
5
5
import calendar
6
+ import configparser
6
7
import datetime
7
8
import json # noqa: F401
8
9
import logging
16
17
17
18
import mopac_step
18
19
import seamm
19
- import seamm_util
20
20
import seamm_util .printing as printing
21
21
from seamm_util .printing import FormattedText as __
22
22
@@ -85,22 +85,8 @@ def run(self):
85
85
printer .normal (self .header )
86
86
printer .normal ("" )
87
87
88
- # Access the options and find the executable
89
- options = self .options
90
-
91
- if options ["mopac_path" ] == "" :
92
- mopac_exe = seamm_util .check_executable (options ["mopac_exe" ])
93
- else :
94
- mopac_exe = (
95
- Path (options ["mopac_path" ]).expanduser ().resolve ()
96
- / options ["mopac_exe" ]
97
- )
98
- mopac_path = Path (mopac_exe ).parent .expanduser ().resolve ()
99
-
100
- env = {
101
- "LD_LIBRARY_PATH" : str (mopac_path ),
102
- "OMP_NUM_THREADS" : "1" ,
103
- }
88
+ # Access the options
89
+ seamm_options = self .global_options
104
90
105
91
extra_keywords = ["AUX(MOS=10,XP,XS,PRECISION=3)" ]
106
92
@@ -170,16 +156,30 @@ def run(self):
170
156
files = {"mopac.dat" : text }
171
157
self .logger .debug ("mopac.dat:\n " + files ["mopac.dat" ])
172
158
os .makedirs (self .directory , exist_ok = True )
173
- for filename in files :
174
- with open (os .path .join (self .directory , filename ), mode = "w" ) as fd :
175
- fd .write (files [filename ])
176
- local = seamm .ExecLocal ()
159
+
160
+ executor = self .flowchart .executor
161
+
162
+ # Read configuration file for MOPAC
163
+ ini_dir = Path (seamm_options ["root" ]).expanduser ()
164
+ full_config = configparser .ConfigParser ()
165
+ full_config .read (ini_dir / "mopac.ini" )
166
+ executor_type = executor .name
167
+ if executor_type not in full_config :
168
+ raise RuntimeError (
169
+ f"No section for '{ executor_type } ' in MOPAC ini file "
170
+ f"({ ini_dir / 'mopac.ini' } )"
171
+ )
172
+ config = dict (full_config .items (executor_type ))
173
+
177
174
return_files = ["mopac.arc" , "mopac.out" , "mopac.aux" ]
178
- result = local .run (
179
- cmd = [str (mopac_exe ), "mopac.dat" ],
175
+ result = executor .run (
176
+ cmd = ["{code}" , "mopac.dat" , ">" , "stdout.txt" , "2>" , "stderr.txt" ],
177
+ config = config ,
178
+ directory = self .directory ,
180
179
files = files ,
181
180
return_files = return_files ,
182
- env = env ,
181
+ in_situ = True ,
182
+ shell = True ,
183
183
)
184
184
185
185
if not result :
@@ -192,13 +192,6 @@ def run(self):
192
192
"\n \n Output from MOPAC\n \n " + result ["mopac.out" ]["data" ] + "\n \n "
193
193
)
194
194
195
- for filename in result ["files" ]:
196
- with open (os .path .join (self .directory , filename ), mode = "w" ) as fd :
197
- if result [filename ]["data" ] is not None :
198
- fd .write (result [filename ]["data" ])
199
- else :
200
- fd .write (result [filename ]["exception" ])
201
-
202
195
# Analyze the results
203
196
self .analyze ()
204
197
@@ -270,28 +263,45 @@ def analyze(self, indent="", lines=[], n_calculations=None):
270
263
charge = None
271
264
n_atoms = configuration .n_atoms
272
265
point_group = None
266
+ n_sigma_bonds = None
267
+ n_lone_pairs = None
268
+ n_pi_bonds = None
269
+ sum_positive_charges = None
270
+ sum_negative_charges = None
271
+ ions = {}
273
272
neighbors = data ["neighbors" ] = [[] for i in range (n_atoms )]
274
273
bonds = data ["bonds" ] = {"i" : [], "j" : [], "bondorder" : []}
275
274
lone_pairs = data ["lone pairs" ] = [0 ] * n_atoms
276
275
have_lewis_structure = False
276
+ charge_error = False
277
277
for line in lines :
278
278
line = line .strip ()
279
279
if "MOLECULAR POINT GROUP" in line :
280
280
point_group = line .split ()[- 1 ]
281
281
282
+ if "Ion Atom No. Type Charge" in line :
283
+ for line in lines :
284
+ line = line .strip ()
285
+ if not line :
286
+ continue
287
+ if "COMPUTED CHARGE ON SYSTEM" in line :
288
+ break
289
+ ion , atom , type_ , charge = line .split ()
290
+ ions [int (atom ) - 1 ] = {"charge" : int (charge ), "type" : type_ }
282
291
if "COMPUTED CHARGE ON SYSTEM" in line :
283
292
charge = int (line .split ()[4 ].rstrip ("," ))
284
293
if "THIS IS THE SAME AS THE CHARGE DEFINED" not in line :
285
- if no_error or fallback :
286
- self .logger .warning (
287
- f"The charge on the system { configuration .charge } is not "
288
- f"the same as Lewis structure indicates: { charge } "
289
- )
290
- else :
291
- raise RuntimeError (
292
- f"The charge on the system { configuration .charge } is not "
293
- f"the same as Lewis structure indicates: { charge } "
294
- )
294
+ charge_error = True
295
+ if "SIGMA BONDS" in line :
296
+ n_sigma_bonds = int (line .split ()[2 ])
297
+ if "LONE PAIRS" in line :
298
+ n_lone_pairs = int (line .split ()[2 ])
299
+ if "PI BONDS" in line :
300
+ n_pi_bonds = int (line .split ()[2 ])
301
+ if "SUM OF POSITIVE CHARGES" in line :
302
+ sum_positive_charges = int (line .split ()[4 ])
303
+ if "SUM OF NEGATIVE CHARGES" in line :
304
+ sum_negative_charges = int (line .split ()[4 ])
295
305
if "TOPOGRAPHY OF SYSTEM" in line :
296
306
next (lines )
297
307
next (lines )
@@ -348,6 +358,16 @@ def analyze(self, indent="", lines=[], n_calculations=None):
348
358
data ["charge" ] = charge
349
359
if point_group is not None :
350
360
data ["point group" ] = point_group
361
+ if n_sigma_bonds is not None :
362
+ data ["n sigma bonds" ] = n_sigma_bonds
363
+ if n_lone_pairs is not None :
364
+ data ["n lone pairs" ] = n_lone_pairs
365
+ if n_pi_bonds is not None :
366
+ data ["n pi bonds" ] = n_pi_bonds
367
+ if sum_positive_charges is not None :
368
+ data ["sum positive charges" ] = sum_positive_charges
369
+ if sum_negative_charges is not None :
370
+ data ["sum negative charges" ] = sum_negative_charges
351
371
352
372
self .logger .debug (f"Point group = { point_group } " )
353
373
self .logger .debug (f" Charge = { charge } " )
@@ -382,8 +402,31 @@ def analyze(self, indent="", lines=[], n_calculations=None):
382
402
# Generate the printed output if requested
383
403
text = ""
384
404
if P ["atom cutoff" ] != "no printing" :
385
- text += f"Point group symmetry: { point_group } \n "
386
- text += f" Net charge: { charge } \n "
405
+ text += f" Point group symmetry: { point_group } \n "
406
+ text += f" Net charge: { charge } \n "
407
+ text += f"Sum of positive charges: { sum_positive_charges } \n "
408
+ text += f"Sum of negative charges: { sum_negative_charges } \n "
409
+ text += f" Number of sigma bonds: { n_sigma_bonds } \n "
410
+ text += f" Number of pi bonds: { n_pi_bonds } \n "
411
+ text += f" Number of lone pairs: { n_lone_pairs } \n "
412
+ text += "\n "
413
+ if charge_error :
414
+ if P ["adjust charge" ]:
415
+ configuration .charge = charge
416
+ text += (
417
+ "The total charge on the system has been adjusted to "
418
+ f"{ configuration .charge } .\n "
419
+ )
420
+ elif no_error or fallback :
421
+ text += (
422
+ f"The charge on the system { configuration .charge } is not "
423
+ f"the same as Lewis structure indicates: { charge } \n "
424
+ )
425
+ else :
426
+ raise RuntimeError (
427
+ f"The charge on the system { configuration .charge } is not "
428
+ f"the same as Lewis structure indicates: { charge } "
429
+ )
387
430
388
431
if P ["atom cutoff" ] == "no printing" :
389
432
pass
0 commit comments