Skip to content

Commit 722b526

Browse files
authored
Merge pull request #125 from paulsaxe/main
Added support for containers
2 parents 4f37dc2 + 1250200 commit 722b526

File tree

9 files changed

+228
-128
lines changed

9 files changed

+228
-128
lines changed

HISTORY.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
=======
22
History
33
=======
4+
2024.1.16 -- Added support for containers.
5+
* Added access to the new PM6-ORG parameterization and made it the default, though PM7
6+
is still preferred for materials simulation. PM6-ORG handle organic and biomolecules
7+
well.
8+
* Made the Lewis structure analysis more robust and added information to the output.
9+
* Provided an option for the Lewis structure calculation to set the charge of the
10+
system to that calculaed by the Lewis structure.
11+
* Added support for containers
12+
* Made default to run serially, since parallel doesn't provide much benefit.
13+
* Fixed bug in analysis if optimization doesn't converge.
14+
415
2023.12.18 -- Added readonly flag
516
* Added a flag to prepare the input but not run the calculation.
617

devtools/conda-envs/test_env.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ dependencies:
1010

1111
# SEAMM
1212
- molsystem
13-
- psutil
1413
- requests
1514
- seamm
1615
- tabulate
@@ -28,5 +27,8 @@ dependencies:
2827

2928
# Pip-only installs
3029
- pip:
30+
# SEAMM
31+
- seamm-exec
32+
3133
# Documentation
3234
- sphinx-copybutton

mopac_step/energy_parameters.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,25 @@ class EnergyParameters(seamm.Parameters):
4343
),
4444
},
4545
"hamiltonian": {
46-
"default": "PM7",
46+
"default": "PM6-ORG",
4747
"kind": "enumeration",
4848
"default_units": "",
4949
"enumeration": (
50-
"AM1",
51-
"MNDO",
52-
"MNDOD",
53-
"PM3",
50+
"PM7",
51+
"PM7-TS",
52+
"PM6-ORG",
5453
"PM6",
5554
"PM6-D3",
5655
"PM6-DH+",
5756
"PM6-DH2",
5857
"PM6-DH2X",
5958
"PM6-D3H4",
6059
"PM6-D3H4X",
61-
"PM7",
62-
"PM7-TS",
60+
"PM3",
6361
"RM1",
62+
"AM1",
63+
"MNDO",
64+
"MNDOD",
6465
),
6566
"format_string": "s",
6667
"description": "Hamiltonian:",

mopac_step/lewis_structure.py

Lines changed: 86 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""Setup and run MOPAC for the Lewis structure"""
44

55
import calendar
6+
import configparser
67
import datetime
78
import json # noqa: F401
89
import logging
@@ -16,7 +17,6 @@
1617

1718
import mopac_step
1819
import seamm
19-
import seamm_util
2020
import seamm_util.printing as printing
2121
from seamm_util.printing import FormattedText as __
2222

@@ -85,22 +85,8 @@ def run(self):
8585
printer.normal(self.header)
8686
printer.normal("")
8787

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
10490

10591
extra_keywords = ["AUX(MOS=10,XP,XS,PRECISION=3)"]
10692

@@ -170,16 +156,30 @@ def run(self):
170156
files = {"mopac.dat": text}
171157
self.logger.debug("mopac.dat:\n" + files["mopac.dat"])
172158
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+
177174
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,
180179
files=files,
181180
return_files=return_files,
182-
env=env,
181+
in_situ=True,
182+
shell=True,
183183
)
184184

185185
if not result:
@@ -192,13 +192,6 @@ def run(self):
192192
"\n\nOutput from MOPAC\n\n" + result["mopac.out"]["data"] + "\n\n"
193193
)
194194

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-
202195
# Analyze the results
203196
self.analyze()
204197

@@ -270,28 +263,45 @@ def analyze(self, indent="", lines=[], n_calculations=None):
270263
charge = None
271264
n_atoms = configuration.n_atoms
272265
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 = {}
273272
neighbors = data["neighbors"] = [[] for i in range(n_atoms)]
274273
bonds = data["bonds"] = {"i": [], "j": [], "bondorder": []}
275274
lone_pairs = data["lone pairs"] = [0] * n_atoms
276275
have_lewis_structure = False
276+
charge_error = False
277277
for line in lines:
278278
line = line.strip()
279279
if "MOLECULAR POINT GROUP" in line:
280280
point_group = line.split()[-1]
281281

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_}
282291
if "COMPUTED CHARGE ON SYSTEM" in line:
283292
charge = int(line.split()[4].rstrip(","))
284293
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])
295305
if "TOPOGRAPHY OF SYSTEM" in line:
296306
next(lines)
297307
next(lines)
@@ -348,6 +358,16 @@ def analyze(self, indent="", lines=[], n_calculations=None):
348358
data["charge"] = charge
349359
if point_group is not None:
350360
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
351371

352372
self.logger.debug(f"Point group = {point_group}")
353373
self.logger.debug(f" Charge = {charge}")
@@ -382,8 +402,31 @@ def analyze(self, indent="", lines=[], n_calculations=None):
382402
# Generate the printed output if requested
383403
text = ""
384404
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+
)
387430

388431
if P["atom cutoff"] == "no printing":
389432
pass

mopac_step/lewis_structure_parameters.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ class LewisStructureParameters(seamm.Parameters):
3030
"description": "Replace bonds in structure:",
3131
"help_text": "Replace the bonds on the structure.",
3232
},
33+
"adjust charge": {
34+
"default": "no",
35+
"kind": "boolean",
36+
"default_units": "",
37+
"enumeration": ("yes", "no"),
38+
"format_string": "s",
39+
"description": "Adjust charge on structure:",
40+
"help_text": "Adjust the charge on the structure.",
41+
},
3342
"ignore errors": {
3443
"default": "no",
3544
"kind": "boolean",

mopac_step/metadata.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1999,7 +1999,37 @@
19991999
"calculation": ["Lewis structure"],
20002000
"description": "net charge",
20012001
"dimensionality": "scalar",
2002-
"type": "float",
2002+
"type": "int",
2003+
},
2004+
"sum of positive charges": {
2005+
"calculation": ["Lewis structure"],
2006+
"description": "sum of positive charges",
2007+
"dimensionality": "scalar",
2008+
"type": "int",
2009+
},
2010+
"sum of negative charges": {
2011+
"calculation": ["Lewis structure"],
2012+
"description": "sum of negative charges",
2013+
"dimensionality": "scalar",
2014+
"type": "int",
2015+
},
2016+
"n sigma bonds": {
2017+
"calculation": ["Lewis structure"],
2018+
"description": "number of sigma bonds",
2019+
"dimensionality": "scalar",
2020+
"type": "int",
2021+
},
2022+
"n pi bonds": {
2023+
"calculation": ["Lewis structure"],
2024+
"description": "number of pi bonds",
2025+
"dimensionality": "scalar",
2026+
"type": "int",
2027+
},
2028+
"n lone pairs": {
2029+
"calculation": ["Lewis structure"],
2030+
"description": "number of lone pairs",
2031+
"dimensionality": "scalar",
2032+
"type": "int",
20032033
},
20042034
"neighbors": {
20052035
"calculation": ["Lewis structure"],

0 commit comments

Comments
 (0)