Source code for Utils.inputParser
# MIT License
#
# Copyright (c) 2025 Isacks-Co contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import argparse
import ast
import logging
import sys
from .logger import loggerSetup
[docs]
class SingleMetavarHelpFormatter(argparse.HelpFormatter):
"""Formatter to only get one metavar"""
def _format_action_invocation(self, action):
if not action.option_strings:
return super()._format_action_invocation(action)
opts = ', '.join(action.option_strings)
metavar = action.metavar or (action.type.__name__.upper() if action.type else None)
if metavar:
return f'{opts} {metavar}'
else:
return opts
[docs]
class InputParser():
def __init__(self, args=sys.argv):
self.argparser = argparse.ArgumentParser(prog="MolecularDynamics.py",
usage='%(prog)s <settings> [options]',
description="Molecular dynamics program developed by Isacks & Co",
formatter_class=lambda prog: SingleMetavarHelpFormatter(prog,
max_help_position=50,
width=100))
self.addArguments()
self.input_args = args
self.args = vars(self.argparser.parse_args(args[1:]))
loggerSetup(self.args["debug"])
[docs]
def addArguments(self):
""" Whenever a new setting is added, add the corresponding flag here."""
# Positional arguments
self.argparser.add_argument("-PE", "--Physical_environment", help="Dict of temperature and pressure")
self.argparser.add_argument("-SC", "--Simulations_config", help="Simulation-specific settings")
self.argparser.add_argument("-IS", "--Input_structure", help="Initial structure of material to be simulated")
self.argparser.add_argument("-CQ", "--Compute_quantities", help="List of abbreviations for quantities to compute")
#self.argparser.add_argument("input_structure", help="Path for atomic configuration")
self.argparser.add_argument("input_settings", help="Path to settings file")
# Options (flags), to add a new flag make sure to follow the format below with -<abbrev.>, --<Full name>, etc.
self.argparser.add_argument("-E", "--Ensemble", metavar="<ENSEMBLE>", type=str, help="Ensemble (NVE, NPT, NVT)")
self.argparser.add_argument("-T", "--Temperature", metavar="<TEMPERATURE>", type=float, help="Temperature in K")
self.argparser.add_argument("-P", "--Pressure", metavar="<PRESSURE>", type=float, help="Pressure in Pa")
self.argparser.add_argument("-PBC", metavar="<PBC>", type=self.parseList, help="PBC in each direction as a list of booleans")
self.argparser.add_argument("-POT", "--Potential", metavar="<POTENTIAL>", type=str,
help="Potential as a string (EMT, LJ, MACE)")
self.argparser.add_argument("-TS", "--Timestep", metavar="<TIMESTEP>", type=float,
help="Timestep as a float (fs)")
self.argparser.add_argument("-C", "--Compressibility", metavar="<TIMESTEP>", type=float,
help="Compressibility as a float (GPA)")
self.argparser.add_argument("-ยต", "--Friction", metavar="<FRICTION>", type=float,
help="Friction coefficent as a float (For NVT)")
self.argparser.add_argument("-TD", "--Tdamp", metavar="<TDAMP>", type=float, help="Tdamp as a float (For NPT)")
self.argparser.add_argument("-PD", "--Pdamp", metavar="<PDAMP>", type=float, help="Pdamp as a float (For NPT)")
self.argparser.add_argument("-S", "--Supercells", metavar="<SUPERCELL>", type=self.parseList,
help="Repetition of input cell e.g [3,3,3], use [1,1,1] for only unit cell")
self.argparser.add_argument("-O", "--Output_file", metavar="<PATH>", type=str,
help="Path to where the output file will be written")
self.argparser.add_argument("-N", "--Number_of_steps", metavar="<NUMBER_OF_STEPS>", type=str,
help="Total number of timesteps as an integer")
self.argparser.add_argument("--debug", action="store_true", help="Debug")
self.argparser.add_argument("-FE", "--Find_equilibrium", type=bool, help="Bool of whether to find equilibrium or not")
[docs]
def parseList(self, arg):
"""Help function to make sure list arguments are working."""
try:
value = ast.literal_eval(arg)
if type(value) == list:
return value
else:
raise argparse.ArgumentTypeError("Input must be a list")
except Exception:
raise argparse.ArgumentTypeError(f"Invalid list: {arg} (Can't be blank spaces in the list)")
if __name__ == "__main__":
parser = InputParser()
args = parser.argparser.parse_args()
settings_dict = vars(args)
print(settings_dict)