Skip to content

Commit

Permalink
Bugfix and improvements
Browse files Browse the repository at this point in the history
* Bugfix: Fixed issue with the initial seamm.ini file, created if it is missing from the installation.
* Added the ability to set the number of points in the trajectories rather than the sampling rate.
* Added diagnositic information and timings to available results.
  • Loading branch information
paulsaxe committed Jul 25, 2024
1 parent 9d34b41 commit 1e3e231
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 74 deletions.
7 changes: 7 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
=======
History
=======
2024.7.25 -- Bugfix and improvements
* Bugfix: Fixed issue with the initial seamm.ini file, created if it is missing from
the installation.
* Added the ability to set the number of points in the trajectories rather than the
sampling rate.
* Added diagnositic information and timings to available results.

2024.7.21.1 -- Minor internal change for GUI
* Switched to new functionality in the SEAMM widgets to simplify the layout of the
trajectories panel.
Expand Down
21 changes: 20 additions & 1 deletion lammps_step/energy.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ def header(self):
"""A printable header for this section of output"""
return "Step {}: {}".format(".".join(str(e) for e in self._id), self.title)

@property
def results(self):
"""The storage for the results in the main LAMMPS step."""
return self.flowchart.parent._results

@property
def version(self):
"""The semantic version of this module."""
Expand Down Expand Up @@ -180,6 +185,20 @@ def analyze(self, indent="", data={}, table=None, output=[], **kwargs):
energy = float(tmp[i])
data["energy"] = energy
data["energy,units"] = "kcal/mol"
if line.startswith("Loop time of"):
try:
tmp = line.split()
_time = round(float(tmp[3]), 2)
_procs = int(tmp[5])
_steps = int(tmp[8])
_natoms = int(tmp[11])
_type = self._calculation
self.results[f"t_{_type}"] = _time
self.results[f"np_{_type}"] = _procs
self.results[f"steps_{_type}"] = _steps
self.results[f"natoms_{_type}"] = _natoms
except Exception as _e:
print(f"LAMMPS loop time: {_e}")

# See if forces have been dumped
wdir = Path(self.directory)
Expand Down Expand Up @@ -226,6 +245,6 @@ def analyze(self, indent="", data={}, table=None, output=[], **kwargs):
# Put any requested results into variables or tables
self.store_results(
configuration=configuration,
data=data,
data=data | self.results,
create_tables=self.parameters["create tables"].get(),
)
173 changes: 100 additions & 73 deletions lammps_step/lammps.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from seamm_ff_util import tabulate_angle
import seamm_util
import seamm_util.printing as printing
from seamm_util import CompactJSONEncoder
from seamm_util import CompactJSONEncoder, Configuration
from seamm_util.printing import FormattedText as __

# from pymbar import timeseries
Expand Down Expand Up @@ -171,6 +171,8 @@ def __init__(
self._trajectory = []
self._data = {}

self._results = {} # Sotrage for computational and timing results

super().__init__(
flowchart=flowchart, title="LAMMPS", extension=extension, logger=logger
)
Expand All @@ -185,6 +187,11 @@ def git_revision(self):
"""The git version of this module."""
return lammps_step.__git_revision__

@property
def results(self):
"""The storage for results."""
return self._results

@staticmethod
def box_to_cell(lx, ly, lz, xy, xz, yz):
"""Convert the LAMMPS box definition to cell parameters."""
Expand Down Expand Up @@ -261,53 +268,56 @@ def create_parser(self):
action="store_true",
help="whether to write out html files for graphs, etc.",
)
parser.add_argument(
parser_name,
"--modules",
nargs="*",
default=None,
help="the environment modules to load for LAMMPS",
)
parser.add_argument(
parser_name,
"--gpu-modules",
nargs="*",
default=None,
help="the environment modules to load for the GPU version of LAMMPS",
)
parser.add_argument(
parser_name,
"--lammps-path",
default=None,
help="the path to the LAMMPS executables",
)
parser.add_argument(
parser_name,
"--lammps-serial",
default="lmp_serial",
help="the serial version of LAMMPS",
)
parser.add_argument(
parser_name,
"--lammps-mpi",
default="lmp_mpi",
help="the mpi version of LAMMPS",
)
parser.add_argument(
parser_name,
"--cmd-args",
default="",
help="the command-line arguments for LAMMPS, e.g. '-k on'",
)
parser.add_argument(
parser_name,
"--gpu-cmd-args",
default="",
help="the command-line arguments for GPU version of LAMMPS, e.g. '-k on'",
)
parser.add_argument(
parser_name, "--mpiexec", default="mpiexec", help="the mpi executable"
)
if False:
parser.add_argument(
parser_name,
"--modules",
nargs="*",
default=None,
help="the environment modules to load for LAMMPS",
)
parser.add_argument(
parser_name,
"--gpu-modules",
nargs="*",
default=None,
help="the environment modules to load for the GPU version of LAMMPS",
)
parser.add_argument(
parser_name,
"--lammps-path",
default=None,
help="the path to the LAMMPS executables",
)
parser.add_argument(
parser_name,
"--lammps-serial",
default="lmp_serial",
help="the serial version of LAMMPS",
)
parser.add_argument(
parser_name,
"--lammps-mpi",
default="lmp_mpi",
help="the mpi version of LAMMPS",
)
parser.add_argument(
parser_name,
"--cmd-args",
default="",
help="the command-line arguments for LAMMPS, e.g. '-k on'",
)
parser.add_argument(
parser_name,
"--gpu-cmd-args",
default="",
help=(
"the command-line arguments for GPU version of LAMMPS, e.g. '-k on'"
),
)
parser.add_argument(
parser_name, "--mpiexec", default="mpiexec", help="the mpi executable"
)

return result

Expand Down Expand Up @@ -382,6 +392,9 @@ def run(self):
self.logger.error("LAMMPS run(): there is no structure!")
raise RuntimeError("LAMMPS run(): there is no structure!")

# Initialize storage
self._results = {}

next_node = super().run(printer)

# Get the options
Expand Down Expand Up @@ -661,44 +674,51 @@ def _execute_single_sim(self, files, np=1, return_files=None):
ini_dir = Path(self.global_options["root"]).expanduser()
path = ini_dir / "lammps.ini"

if path.exists():
full_config.read(ini_dir / "lammps.ini")
full_config.set("local", "_origin_", f"{ini_dir / 'lammps.ini'}")

# If the section we need doesn't exists, get the default
if not path.exists() or executor_type not in full_config:
# If the config file doesn't exists, get the default
if not path.exists():
resources = importlib.resources.files("lammps_step") / "data"
ini_text = (resources / "lammps.ini").read_text()
full_config.read_string(ini_text)
full_config.set("local", "_origin_", "lammps default ini file")
txt_config = Configuration(path)
txt_config.from_string(ini_text)

# Work out the conda info needed
txt_config.set_value("local", "conda", os.environ["CONDA_EXE"])
txt_config.set_value("local", "conda-environment", "seamm-lammps")
txt_config.save()
printer.normal(f"Wrote the LAMMPS configuration file to {path}")
printer.normal("")

full_config.read(ini_dir / "lammps.ini")

# Getting desperate! Look for an executable in the path
if executor_type not in full_config:
path = shutil.which("lmp")
if path is None:
mpi_path = shutil.which("mpirun")
if path is None or mpi_path is None:
raise RuntimeError(
f"No section for '{executor_type}' in LAMMPS ini file "
f"({ini_dir / 'lammps.ini'}), nor in the defaults, nor "
"in the path!"
)
else:
full_config.add_section(executor_type)
full_config.set(executor_type, "installation", "local")
txt_config = Configuration(path)
txt_config.add_section(executor_type)
txt_config.set_value(executor_type, "installation", "local")
txt_config.set_value(
executor_type,
"code",
f"{mpi_path} -np {{NTASKS}} {path}",
)
txt_config.set_value(
executor_type,
"python",
f"mpirun -np {{NTASKS}} {shutil.which('python')}",
)
txt_config.save()
printer.normal(f"Wrote the LAMMPS configuration file to {path}")
printer.normal("")
full_config.read(ini_dir / "lammps.ini")
full_config.set(executor_type, "code", str(path))

# And we may need python!
full_config.set("local", "items", f"{full_config.items('local')}")
if not full_config.has_option(executor_type, "python"):
full_config.set(executor_type, "python", "mpirun -np {NTASKS} python")
full_config.set(executor_type, "_python source_", "default value")

# If the ini file does not exist, write it out!
if not path.exists():
with path.open("w") as fd:
full_config.write(fd)
printer.normal(f"Wrote the LAMMPS configuration file to {path}")
printer.normal("")

config = dict(full_config.items(executor_type))
# Use the matching version of the seamm-mopac image by default.
config["version"] = self.version
Expand Down Expand Up @@ -1675,6 +1695,13 @@ def analyze(self, indent="", nodes=None, **kwargs):
sections[section] = []
elif section is not None:
sections[section].append(line)
if line.startswith("Total wall time:"):
try:
h, m, s = line.split()[3].split(":")
_time = 3600 * float(h) + 60 * float(m) + float(s)
self.results["t_lammps_wall"] = _time
except Exception as _e:
print(f"Wall time exception {_e}")

for node in nodes:
for value in node.description:
Expand Down
98 changes: 98 additions & 0 deletions lammps_step/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,4 +486,102 @@
"type": "float",
"units": "",
},
# Timings
"t_lammps_wall": {
"calculation": [
"energy",
"minimization",
"nve",
"nvt",
"npt",
],
"description": "The wall clock time for LAMMPS",
"dimensionality": "scalar",
"type": "float",
"units": "s",
},
"t_nve": {
"calculation": ["nve"],
"description": "The time for the NVE step",
"dimensionality": "scalar",
"type": "float",
"units": "s",
},
"np_nve": {
"calculation": ["nve"],
"description": "The number of processors for the NVE step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
"nsteps_nve": {
"calculation": ["nve"],
"description": "The number of steps in the NVE step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
"natoms_nve": {
"calculation": ["nve"],
"description": "The number of atoms in the NVE step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
"t_nvt": {
"calculation": ["nvt"],
"description": "The time for the NVT step",
"dimensionality": "scalar",
"type": "float",
"units": "s",
},
"np_nvt": {
"calculation": ["nvt"],
"description": "The number of processors for the NVT step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
"nsteps_nvt": {
"calculation": ["nvt"],
"description": "The number of steps in the NVT step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
"natoms_nvt": {
"calculation": ["nvt"],
"description": "The number of atoms in the NVT step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
"t_npt": {
"calculation": ["npt"],
"description": "The time for the NPT step",
"dimensionality": "scalar",
"type": "float",
"units": "s",
},
"np_npt": {
"calculation": ["npt"],
"description": "The number of processors for the NPT step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
"nsteps_npt": {
"calculation": ["npt"],
"description": "The number of steps in the NPT step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
"natoms_npt": {
"calculation": ["npt"],
"description": "The number of atoms in the NPT step",
"dimensionality": "scalar",
"type": "integer",
"units": "s",
},
}

0 comments on commit 1e3e231

Please sign in to comment.