Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix and improvements #58

Merged
merged 1 commit into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
},
}
Loading