From 0e70ec235c4b2af707406923fc2a8923ed98967d Mon Sep 17 00:00:00 2001 From: Michele Ceriotti Date: Tue, 12 Nov 2024 22:04:41 +0100 Subject: [PATCH] A "direct" FF using the same PES interfaces as the python driver (#390) This is a major restructuring of the python driver and the forcefield block. All PES drivers have been moved to an ipi/pes folder, and their API streamlined with the possibility of providing both lists of arguments and named arguments. A new FFDirect forcefield makes it possible to call the PES from i-PI directly, avoiding the client/server setup that many find confusing. We converted most PES to the new interfaces, but several are possibly broken; these now trigger a warning so that users can check and possibly fix them. --------- Co-authored-by: Yair Litman Co-authored-by: Venkat Kapil --- docs/scripts/help.py | 1 + docs/src/contributing.rst | 8 +- docs/src/getting-started.rst | 26 +- docs/src/index.rst | 4 +- drivers/py/driver.py | 27 +- drivers/py/pes/mace.py | 40 -- drivers/py/pes/metatensor.py | 94 ----- drivers/py/pes/so3lr.py | 42 -- examples/clients/mace/RESTART | 365 ++++++++++++++++++ examples/clients/mace/getmodel.sh | 3 + examples/clients/mace/init.xyz | 1 + examples/clients/mace/input.xml | 37 ++ examples/clients/metatensor/README.md | 14 +- examples/clients/metatensor/create-model.py | 4 +- examples/clients/metatensor/input-direct.xml | 47 +++ examples/clients/metatensor/nickel-lj.pt | Bin 30459 -> 37924 bytes examples/clients/pes/README.md | 8 + examples/clients/pes/harmonic-direct/Makefile | 17 + examples/clients/pes/harmonic-direct/init.xyz | 3 + .../clients/pes/harmonic-direct/input.xml | 38 ++ .../pes/harmonic-direct/test_settings.dat | 0 examples/clients/xtb/config.json | 1 + examples/clients/xtb/run.sh | 2 +- .../implicit_bath_pos-dependent/run.sh | 9 +- examples/init_files/water_64mols.extxyz | 194 ++++++++++ ipi/__init__.py | 1 + ipi/engine/forcefields.py | 89 ++++- ipi/inputs/forcefields.py | 61 ++- ipi/inputs/simulation.py | 31 +- {drivers/py => ipi}/pes/__init__.py | 0 {drivers/py => ipi}/pes/ase.py | 51 ++- {drivers/py => ipi}/pes/bath.py | 27 +- {drivers/py => ipi}/pes/doubledoublewell.py | 66 ++-- {drivers/py => ipi}/pes/doublewell.py | 26 +- .../py => ipi}/pes/doublewell_with_bath.py | 57 +-- .../pes/doublewell_with_friction.py | 59 +-- {drivers/py => ipi}/pes/driverdipole.py | 24 +- {drivers/py => ipi}/pes/dummy.py | 21 +- {drivers/py => ipi}/pes/elphmod.py | 23 +- {drivers/py => ipi}/pes/harmonic.py | 36 +- ipi/pes/mace.py | 53 +++ ipi/pes/metatensor.py | 98 +++++ {drivers/py => ipi}/pes/pet.py | 91 ++--- {drivers/py => ipi}/pes/rascal.py | 52 +-- ipi/pes/so3lr.py | 37 ++ {drivers/py => ipi}/pes/spline.py | 20 +- {drivers/py => ipi}/pes/xtb.py | 48 +-- ipi/utils/io/inputs/__init__.py | 34 ++ ipi/utils/io/inputs/io_xml.py | 3 +- ipi_tests/README.md | 5 +- .../profiling/classical_md_direct/init.xyz | 10 + .../profiling/classical_md_direct/input.xml | 34 ++ ipi_tests/profiling/run_profiling.sh | 2 +- .../simulation.instanton_FINAL_15.ener | 33 -- .../100K_implicit_friction/test_settings.dat | 2 +- setup.py | 9 +- 56 files changed, 1533 insertions(+), 555 deletions(-) delete mode 100644 drivers/py/pes/mace.py delete mode 100644 drivers/py/pes/metatensor.py delete mode 100644 drivers/py/pes/so3lr.py create mode 100644 examples/clients/mace/RESTART create mode 100644 examples/clients/mace/getmodel.sh create mode 120000 examples/clients/mace/init.xyz create mode 100644 examples/clients/mace/input.xml create mode 100644 examples/clients/metatensor/input-direct.xml create mode 100644 examples/clients/pes/README.md create mode 100644 examples/clients/pes/harmonic-direct/Makefile create mode 100644 examples/clients/pes/harmonic-direct/init.xyz create mode 100644 examples/clients/pes/harmonic-direct/input.xml create mode 100644 examples/clients/pes/harmonic-direct/test_settings.dat create mode 100644 examples/clients/xtb/config.json create mode 100644 examples/init_files/water_64mols.extxyz rename {drivers/py => ipi}/pes/__init__.py (100%) rename {drivers/py => ipi}/pes/ase.py (70%) rename {drivers/py => ipi}/pes/bath.py (79%) rename {drivers/py => ipi}/pes/doubledoublewell.py (71%) rename {drivers/py => ipi}/pes/doublewell.py (73%) rename {drivers/py => ipi}/pes/doublewell_with_bath.py (65%) rename {drivers/py => ipi}/pes/doublewell_with_friction.py (71%) rename {drivers/py => ipi}/pes/driverdipole.py (95%) rename {drivers/py => ipi}/pes/dummy.py (71%) rename {drivers/py => ipi}/pes/elphmod.py (55%) rename {drivers/py => ipi}/pes/harmonic.py (60%) create mode 100644 ipi/pes/mace.py create mode 100644 ipi/pes/metatensor.py rename {drivers/py => ipi}/pes/pet.py (53%) rename {drivers/py => ipi}/pes/rascal.py (56%) create mode 100644 ipi/pes/so3lr.py rename {drivers/py => ipi}/pes/spline.py (84%) rename {drivers/py => ipi}/pes/xtb.py (74%) create mode 100644 ipi_tests/profiling/classical_md_direct/init.xyz create mode 100644 ipi_tests/profiling/classical_md_direct/input.xml delete mode 100644 ipi_tests/regression_tests/tests/INSTANTON/100K_implicit_friction/simulation.instanton_FINAL_15.ener diff --git a/docs/scripts/help.py b/docs/scripts/help.py index 541281e7e..3c646b862 100644 --- a/docs/scripts/help.py +++ b/docs/scripts/help.py @@ -87,6 +87,7 @@ "h0": cell.InputCell(), "forcefield": forcefields.InputForceField(), "ffsocket": forcefields.InputFFSocket(), + "ffdirect": forcefields.InputFFDirect(), "fflj": forcefields.InputFFLennardJones(), "ffdebye": forcefields.InputFFDebye(), "ffplumed": forcefields.InputFFPlumed(), diff --git a/docs/src/contributing.rst b/docs/src/contributing.rst index 7b2a9313d..32955b51c 100644 --- a/docs/src/contributing.rst +++ b/docs/src/contributing.rst @@ -1,3 +1,5 @@ +.. _contributing: + Contributing ============ @@ -89,7 +91,11 @@ If your new development in i-PI is directly related to a specific client code or We very much welcome new interfaces and we will be happy to answer your questions. If you want to enable the communication of a new client code with i-PI, it is not difficult: Please check an example of how it was done in ``fortran`` and ``python`` in the `drivers` folder in the repository. - +It is especially simple to add a new potential energy that is evaluated in Python: it is sufficient to add a file in the `ipi/pes` folder, specifying +`__DRIVER_NAME__` (a string that will be used to refer to the PES from the i-PI input or the command line) and `__DRIVER_CLASS__`, the name of the +actual class, that should provide, directly or through inheritance, a `__call__(self, cell, pos)` function and return a tuple with +`(potential, forces, virial, extras)`. See any of the existing PES files to use as templates - it is particularly simple to create a class that +piggybacs on an existing ASE-style calculator. Getting recognition for your contribution diff --git a/docs/src/getting-started.rst b/docs/src/getting-started.rst index fcc32010e..0d8c176ff 100644 --- a/docs/src/getting-started.rst +++ b/docs/src/getting-started.rst @@ -83,9 +83,29 @@ The built-in driver requires a FORTRAN compiler, and can be built as make cd ../.. +Python driver and PES +^^^^^^^^^^^^^^^^^^^^^ + +In addition to the FORTRAN drive, the i-PI distribution contains also a Python +driver, available in `drivers/py` and through the command-line command +`i-pi-py_driver`, which evaluates potential energy surfaces evaluated by simple +driver classes, that can be found in `ipi/pes`. + +These classes are particularly suitable to perform inference with machine-learning +potentials implemented in Python, and it is reasonably simple to add your own, +if you need to (see also the :ref:`contributing` section). + +These PES files can also be used directly, without the need to go through a +client-server interface, using a :ref:`ffdirect` forcefield, including in the +XML input a block similar to + +.. code-block:: + + + harmonic + { k1: 1.0} + -There is also a Python driver available in `drivers/py`, which however has limited -functionalities. Alternative installation using the setup.py module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -266,7 +286,7 @@ The flags do the following: -S: Optional parameter. If given, overwrite the default socket prefix used in the creation of files for the socket communication. - (default "/tmp/ipi_") + (default "/tmp/ipi\_") This code should be fairly simple to extend to other pair-wise interaction potentials, and examples of its use can be seen in the diff --git a/docs/src/index.rst b/docs/src/index.rst index 37b4c4f72..a0eeb385d 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -26,9 +26,8 @@ This documentation is structured as follows: :maxdepth: 2 introduction - onlinereso - features getting-started + features units input-files input-tags @@ -36,6 +35,7 @@ This documentation is structured as follows: output-tags distributed tutorials + onlinereso faq troubleshooting contributing diff --git a/drivers/py/driver.py b/drivers/py/driver.py index aeff7f8e4..98cab93f4 100755 --- a/drivers/py/driver.py +++ b/drivers/py/driver.py @@ -3,12 +3,8 @@ import argparse import numpy as np - -try: - from pes import * -except ImportError: - # when in an installed i-PI package - from ipi._driver.pes import * +from ipi.pes import * +from ipi.utils.io.inputs import read_args_kwargs description = """ Minimal example of a Python driver connecting to i-PI and exchanging energy, forces, etc. @@ -205,8 +201,8 @@ def run_driver( "--mode", type=str, default="dummy", + choices=list(__drivers__.keys()), help="""Type of potential to be used to compute the potential and its derivatives. - Currently implemented: [dummy, harmonic] """, ) parser.add_argument( @@ -227,10 +223,23 @@ def run_driver( args = parser.parse_args() + driver_args, driver_kwargs = read_args_kwargs(args.param) + if args.mode in __drivers__: - d_f = __drivers__[args.mode](args.param, args.verbose) + try: + d_f = __drivers__[args.mode]( + *driver_args, verbose=args.verbose, **driver_kwargs + ) + except ImportError: + # specific errors have already been triggered + raise + except Exception as err: + print(f"Error setting up PES mode {args.mode}") + print(__drivers__[args.mode].__doc__) + print("Error trace: ") + raise err elif args.mode == "dummy": - d_f = Dummy_driver(args.param, args.verbose) + d_f = Dummy_driver(verbose=args.verbose) else: raise ValueError("Unsupported driver mode ", args.mode) diff --git a/drivers/py/pes/mace.py b/drivers/py/pes/mace.py deleted file mode 100644 index 881f9e5cd..000000000 --- a/drivers/py/pes/mace.py +++ /dev/null @@ -1,40 +0,0 @@ -""" An interface for the [MACE](https://github.com/ACEsuit/mace) calculator """ - -import sys -from .ase import ASEDriver - -try: - from mace.calculators import MACECalculator -except: - MACECalculator = None - -__DRIVER_NAME__ = "mace" -__DRIVER_CLASS__ = "MACE_driver" - -ERROR_MSG = """ -MACE driver requires specification of a .json model, -and a template file that describes the chemical makeup of the structure. - -Example: python driver.py -m mace -u -o model.json,template.xyz -""" - - -class MACE_driver(ASEDriver): - def __init__(self, args=None, verbose=False): - if MACECalculator is None: - raise ImportError("Couldn't load mace bindings") - - super().__init__(args, verbose, ERROR_MSG) - - def check_arguments(self): - """Check the arguments requuired to run the driver - - This loads the potential and atoms template in MACE - """ - - super().check_arguments() - - if len(self.args) < 2: - sys.exit(self.error_msg) - - self.ase_calculator = MACECalculator(model_paths=self.args[1], device="cpu") diff --git a/drivers/py/pes/metatensor.py b/drivers/py/pes/metatensor.py deleted file mode 100644 index 271a0c04e..000000000 --- a/drivers/py/pes/metatensor.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -Interface with metatensor -(https://lab-cosmo.github.io/metatensor/latest/atomistic/index.html), that can -be used to perform calculations based on different types of machine learning -potentials -""" - -import sys - -from ipi.utils.messages import warning - -from .ase import ASEDriver - -try: - import metatensor.torch - from metatensor.torch.atomistic.ase_calculator import MetatensorCalculator -except ImportError as e: - warning(f"Could not find or import metatensor.torch: {e}") - MetatensorCalculator = None - -__DRIVER_NAME__ = "metatensor" -__DRIVER_CLASS__ = "MetatensorDriver" - -ERROR_MSG = """ -The metatensor driver requires specification of a .pt TorchScript model and an -ASE-readable template file that describes the chemical makeup of the structure. - -Example: python driver.py -m metatensor -u -o template.xyz,model.pt,device=cpu,\ -extensions=path/to/extensions,check_consistency=False -""" - - -class MetatensorDriver(ASEDriver): - def __init__(self, args=None, verbose=False, error_msg=ERROR_MSG): - super().__init__(args, verbose, error_msg) - - def check_arguments(self): - """Check the arguments required to run the driver - - This loads the potential and atoms template in metatensor - """ - - if MetatensorCalculator is None: - raise ImportError("could not import metatensor.torch, is it installed?") - - metatensor_major, metatensor_minor, *_ = metatensor.torch.__version__.split(".") - metatensor_major = int(metatensor_major) - metatensor_minor = int(metatensor_minor) - - if metatensor_major != 0 or metatensor_minor != 5: - raise ImportError( - "this code is only compatible with metatensor-torch v0.5.x, " - f"found version v{metatensor.torch.__version__} " - f"at '{metatensor.torch.__file__}'" - ) - - super().check_arguments() - - if len(self.args) < 2: - sys.exit(self.error_msg) - self.model_path = self.args[1] - - device = None - extensions_directory = None - check_consistency = False - for arg in self.args[2:]: - if arg.startswith("device="): - device = arg[7:] - elif arg.startswith("extensions="): - extensions_directory = arg[11:] - elif arg.startswith("check_consistency="): - arg = arg[18:] - if arg == "True": - check_consistency = True - elif arg == "False": - check_consistency = False - else: - raise ValueError( - "invalid value for check_consistency, expected True or False, " - f"got {arg}" - ) - - else: - sys.exit(self.error_msg) - - self.ase_calculator = MetatensorCalculator( - self.model_path, - device=device, - extensions_directory=extensions_directory, - check_consistency=check_consistency, - ) - - # Show the model metadata to the users - print(self.ase_calculator.metadata()) diff --git a/drivers/py/pes/so3lr.py b/drivers/py/pes/so3lr.py deleted file mode 100644 index ee9599684..000000000 --- a/drivers/py/pes/so3lr.py +++ /dev/null @@ -1,42 +0,0 @@ -""" An interface for the [SO3LR](https://github.com/general-molecular-simulations/so3lr) calculator """ - -from .ase import ASEDriver - -try: - from so3lr import So3lrCalculator -except: - So3lrCalculator = None - -__DRIVER_NAME__ = "so3lr" -__DRIVER_CLASS__ = "SO3LR_driver" - -ERROR_MSG = """ -SO3LR driver requires a template file that describes the chemical makeup of the structure. - -Optionally, lr_cutoff and dispersion_energy_lr_cutoff_damping can be specified. - -Example: python driver.py -m so3lr -u -o template.xyz,lr_cutoff=12,dispersion_energy_lr_cutoff_damping=2 -""" - - -class SO3LR_driver(ASEDriver): - def __init__(self, args=None, verbose=False): - if So3lrCalculator is None: - raise ImportError("Couldn't load so3lr bindings") - - super().__init__(args, verbose, ERROR_MSG) - - def check_arguments(self): - super().check_arguments() - - args = self.args - - kwargs = {} - if len(args) >= 2: - _ = args[0] # template we don't need - - for arg in args[1:]: - key, value = arg.split("=") - kwargs[key] = float(value) - - self.ase_calculator = So3lrCalculator(**kwargs) diff --git a/examples/clients/mace/RESTART b/examples/clients/mace/RESTART new file mode 100644 index 000000000..3be060e83 --- /dev/null +++ b/examples/clients/mace/RESTART @@ -0,0 +1,365 @@ + + + 31415 + [{"bit_generator": "MT19937", "state": {"key": [795669418, 3354365008, 150463171, 3937589838, 937846891, 734296723, 764622735, 1183299804, 1272117760, 2010368631, 1241689493, 3626464784, 1162653305, 1289276628, 1367499306, 3247908752, 1963981358, 2105964165, 1030412370, 3753156803, 1150834373, 4031974639, 531307719, 4045118304, 2683788309, 116245922, 2731998769, 136843156, 2169419932, 2880162252, 4007512466, 488361195, 401722091, 2070790009, 1569274038, 815594016, 124972808, 474005227, 3249330448, 2100162826, 3174580426, 2683556907, 4048106153, 1785067589, 2389562067, 836361726, 50342815, 267551970, 3029837949, 3708063355, 717650658, 4006537337, 2479145810, 3256975969, 724976954, 2961068974, 1504794639, 1505207924, 2503985603, 311245764, 1337733744, 75442868, 165388908, 4036439509, 85007674, 1868694522, 2350085548, 3505596813, 47545258, 2074303192, 1070457701, 1029840107, 353040402, 1973126927, 1264732370, 2845086742, 2526982946, 711245124, 1767309883, 2553172272, 3804650134, 289756061, 1111550931, 4144472782, 3996394604, 1981950798, 844362391, 3764917697, 3438324015, 2851666299, 2537341468, 2679862414, 1922363332, 666882440, 3941252033, 757464743, 1045369080, 2905858236, 730860388, 1325996640, 3162113550, 2567309825, 1103202741, 3175399181, 2025511874, 2412947386, 3058427547, 227013550, 2159447082, 1067678484, 3425716523, 417688251, 808501564, 3029168553, 776434612, 115305601, 2788751616, 4246589453, 1253335687, 4141730143, 2414042400, 3419716119, 1633385319, 3247093955, 2994012100, 3972147166, 3745802163, 1304644993, 865244793, 3828379540, 692694198, 4224136046, 341321136, 3189881009, 3230663087, 2858154757, 1490950918, 2482160305, 2121120586, 3007482108, 822603820, 611698261, 2765298047, 345565265, 950359221, 1557230050, 709103228, 1186524570, 292929978, 1821072176, 738923492, 4274644, 779539689, 481731554, 1561808887, 4203195225, 1555517680, 3751871402, 1482431159, 2791267293, 3707069758, 3234075511, 2672838488, 1009278333, 1527771451, 3152681530, 2014224365, 148003440, 3882068492, 351078994, 1651963697, 1054663714, 2397065047, 1469924118, 1137039177, 3577753374, 686392654, 3017336343, 1040761223, 365471914, 2744241982, 2232067354, 4292242034, 3280899888, 2970074168, 4021665697, 4032550683, 2848764242, 134774596, 2698474524, 3951539303, 3050877350, 425236979, 3681969874, 536833020, 645868093, 3820567878, 818193000, 3703993042, 2811873296, 200223563, 2261193604, 4002620488, 573051517, 559569805, 1751201194, 3958517026, 3946914696, 843371176, 3401646834, 1276160980, 3113426010, 3652866953, 3777818492, 1153305286, 634988187, 4656920, 4017875503, 4244574051, 3891820314, 1921680474, 1139973881, 26053146, 3540936332, 1190218234, 3858351434, 4215348533, 1192366508, 3769660024, 3473641435, 798054066, 2265876112, 1057572646, 1880763545, 232212048, 1559861968, 2573998448, 879167696, 1381352741, 3800595158, 2698089866, 1949124578, 613088558, 733254358, 1014535932, 904484089, 2246187117, 4044798376, 2066284160, 3744977864, 800089136, 3114088148, 1106568495, 3832704901, 368290159, 1891318290, 2578953184, 623604879, 220664755, 4211596409, 3902639138, 3893193846, 444071368, 3037681030, 417202030, 3408758382, 1941104578, 4235778810, 1412270470, 3337251361, 3965657496, 565829799, 2074175501, 3575557, 105655240, 2090581125, 3306098583, 3395704630, 1923485982, 1800504879, 184025064, 3741358783, 1531109577, 3771712710, 1779168700, 3845470585, 54968271, 958679375, 643136974, 3568839812, 816610774, 269396381, 1071003538, 3955364110, 194687099, 350181071, 1806095246, 3847618589, 3093771598, 4091627518, 2587247322, 3899980915, 1407852399, 1825407665, 2573244759, 1807374193, 3505525555, 3863992055, 1480680373, 1898960191, 1705678055, 743066202, 1640873890, 1502514469, 62759855, 2132297488, 2382508606, 1130137488, 3409343240, 81886173, 218725541, 4201682764, 911613040, 1789780226, 2328217590, 3070595230, 1307451716, 917012100, 2466257247, 2759529868, 4189490536, 3495955071, 3707418358, 1380836129, 3581386770, 680470424, 4156278160, 3183533111, 2255433561, 31125173, 607214606, 3405607994, 2681426217, 4147600795, 3619039237, 763225706, 3096727002, 368528808, 3715678351, 3960812773, 1794416641, 24849552, 2330330218, 4198000056, 944776381, 4016144718, 4015476207, 2542135582, 891526613, 3275670597, 260289596, 1686366879, 811749559, 1930701239, 4106811535, 3486653570, 3757236663, 3058744443, 573883924, 1597973411, 2849367252, 837698365, 4068634250, 1668230932, 372720237, 2224907569, 4138179720, 2153761699, 1142555848, 642912525, 1775227279, 2202501344, 1576309174, 2020529413, 2759079887, 1476875451, 2490373885, 140951714, 3261701581, 2900952306, 2771780919, 3024978145, 3847035909, 2590213672, 3657015728, 2933466694, 2652199769, 779968378, 693587481, 3238084161, 1292859236, 3901198107, 1642771831, 2504839327, 2593018406, 3232082142, 2294577705, 3434756417, 1176324409, 2586064527, 3649392695, 4270213721, 369682239, 1833859305, 3004923589, 2157403691, 2909620342, 4038662021, 530878050, 3727607169, 2581922589, 3325028835, 3492366495, 2778152583, 1317623030, 985094443, 4200028354, 3818659668, 2290320879, 996660363, 4254245440, 3634630451, 2515846723, 3412149142, 713547821, 3915598384, 1722967802, 3031991720, 397851792, 2268486426, 1485982870, 1312405573, 1549720048, 3093342568, 2946875941, 763765622, 2904735136, 2576787606, 1307812616, 1922019727, 3895352419, 3130267707, 3041543726, 4156570049, 2040426037, 4185810248, 3336129979, 1543746434, 4114276353, 968506551, 831488510, 3910628170, 1588848655, 2295202084, 552508107, 2895382473, 3046575372, 1866870955, 705382541, 2784623343, 4182110533, 2827559551, 1027960460, 1950086097, 912710698, 3326002035, 3658909104, 1297039826, 714298744, 3314813781, 3390897113, 4117186502, 4249300284, 2177611878, 3519404052, 1215103020, 888161319, 3639110818, 2770087358, 4230724586, 1084939770, 1124825233, 2642336164, 3102293704, 2636412376, 3895111296, 4015894980, 1480524830, 2283627770, 2896169265, 1525361018, 4252128804, 3188301813, 578157311, 2825512587, 1353889048, 4109758585, 696181235, 715287672, 3344116697, 80143085, 1098959985, 3214960309, 2416526557, 607618034, 70832594, 1701217967, 2165635687, 970104148, 3879061619, 3523994229, 4192455772, 3014553164, 58296115, 3570431746, 2418920482, 3046097006, 366177630, 206133899, 3934812939, 3106058444, 3539689581, 219917426, 299931320, 1588386678, 2497199221, 1214539462, 1239314913, 3984725088, 2692578908, 750931547, 3585571140, 488681398, 1376038242, 560384883, 1332416451, 2912016916, 1884794666, 3769249332, 30846606, 1774556799, 411741744, 2798886417, 4156313896, 1075162039, 501151935, 605601098, 3840102651, 1767398917, 21611012, 2366766995, 3276021819, 379749019, 1353987593, 1364614484, 1303524118, 3975728117, 3671464016, 2958317770, 3854446205, 3411077042, 913017910, 1979049403, 1435107822, 2874429353, 2302569380, 3196830537, 3863113770, 410539094, 1769756413, 3673454397, 870551312, 3979217, 2679612570, 1291584258, 1565027228, 1877575392, 2372846756, 1697524416, 4175015869, 2274297454, 3741847250, 523408423, 4063843078, 2235754156, 3232533841, 2757177941, 2074155385, 386877545, 260349822, 4059210860, 3349159924, 531748356, 174724555, 3122595409, 3660832320, 579592266, 1350622822, 3279112166, 21688457, 2177358206, 3414507844, 3960313028, 2220533609, 3596959752, 808052420, 1362285260, 304161502, 2334325099, 4090228266, 526360154, 3527253401, 4177434316, 3382911628], "pos": 549}}] + + + + [ step, time{picosecond}, conserved{electronvolt}, temperature{kelvin}, kinetic_md{electronvolt}, + potential{electronvolt}, pressure_md{megapascal} ] + + positions + 1 + + 1 + 20000 + +
driver
+
+ + + + + + + 9.50044560e-04 + 4.79612667e-04 + [ 1.00000000e+00 ] + + + + + + 1.08732992e-03 + 4.13413730e+03 + + 2.06706865e+01 + [ 1 ] + + + + + [ 2.11270674e+01, -1.36860295e+01, 1.21309109e+01, 2.13905728e+01, -1.48995535e+01, + 1.07839955e+01, 2.25466837e+01, -1.33494742e+01, 1.32355387e+01, 5.26292258e+00, + 3.03753005e+00, 2.95386440e+00, 4.63759498e+00, 3.75319475e+00, 4.79162448e+00, + 7.05549943e+00, 3.02660946e+00, 3.41089634e+00, 7.68280951e+00, 2.29463670e+00, + 1.15917368e+01, 8.54721344e+00, 1.59180645e+00, 1.01638082e+01, 7.05049810e+00, + 1.18156011e+00, 1.29580753e+01, -1.10555593e+01, -3.38025456e+00, -2.78541863e+00, + -1.11640441e+01, -4.97217119e+00, -4.00393338e+00, -1.28770002e+01, -2.98973666e+00, + -3.18922815e+00, -1.30773732e+00, 2.80916019e+00, 8.78308389e+00, -1.09035460e+00, + 3.24684786e+00, 1.05259695e+01, -2.21290761e+00, 4.33986686e+00, 8.10540613e+00, + 1.84994004e+01, -2.31212286e+00, 1.11324281e+01, 1.71343793e+01, -1.70545212e+00, + 1.00958713e+01, 1.99982592e+01, -1.89798731e+00, 1.02215215e+01, 3.38480627e+00, + -1.02059660e+01, -5.25221279e+00, 4.42576485e+00, -9.68664476e+00, -3.78241580e+00, + 1.68203597e+00, -9.68905088e+00, -5.09542299e+00, -5.21005973e+00, -1.63108694e+01, + -2.04708461e-01, -4.81781665e+00, -1.64227168e+01, -2.03623163e+00, -5.20969305e+00, + -1.45138746e+01, 2.22953104e-01, 1.86595134e+01, -7.56514257e+00, 1.32421462e+01, + 1.75798948e+01, -7.41248045e+00, 1.46026588e+01, 1.86576022e+01, -5.83205625e+00, + 1.25999077e+01, 2.57610855e+00, 5.13558558e+00, 6.81030022e+00, 1.73244179e+00, + 6.50463350e+00, 5.97680624e+00, 1.31691165e+00, 4.10234979e+00, 7.63449444e+00, + 1.39082898e+01, -9.96245939e+00, -3.25461663e+00, 1.51760632e+01, -1.15296706e+01, + -3.37732662e+00, 1.21007828e+01, -1.06523614e+01, -3.82444376e+00, 1.43524418e+01, + -7.39241448e+00, 3.56923216e+00, 1.27091775e+01, -7.73508523e+00, 2.69144356e+00, + 1.40691294e+01, -7.71022717e+00, 5.37580268e+00, -1.00675908e+00, -1.38432193e+01, + -2.97327593e+00, 1.70353123e-01, -1.27373430e+01, -3.84661160e+00, -1.73060924e+00, + -1.47524708e+01, -4.44555342e+00, 1.19729669e+01, 1.20733431e+01, -1.09025244e+01, + 9.99274183e+00, 1.17436895e+01, -1.04749088e+01, 1.18702114e+01, 1.38183802e+01, + -1.18703636e+01, 8.87350781e+00, -2.48453830e+00, 1.15231984e+01, 8.12254908e+00, + -2.17080193e+00, 9.66660045e+00, 7.63740978e+00, -2.25628963e+00, 1.27883558e+01, + 7.00672454e+00, -7.64976099e+00, 9.18220677e+00, 7.32437430e+00, -8.06738688e+00, + 7.37415484e+00, 6.43037804e+00, -9.16811693e+00, 1.00843559e+01, 8.03480627e+00, + -1.37102624e+01, 6.42921056e+00, 7.19894411e+00, -1.29335143e+01, 7.92774287e+00, + 8.66077412e+00, -1.54183582e+01, 6.97959522e+00, 5.38843050e+00, -4.28167030e-01, + -1.51443836e-01, 4.36031236e+00, 6.15179755e-01, 1.11561161e+00, 6.61865298e+00, + 9.53834535e-01, -5.84401180e-01, 1.35501597e+00, 1.42545868e+00, -1.95721393e+00, + 9.18335400e-01, 3.27806467e+00, -1.49220028e+00, -2.33137187e-01, 9.05564928e-01, + -2.84057752e+00, 7.29756827e+00, -1.10870354e+01, 1.57980278e+00, 5.71466230e+00, + -1.17390022e+01, 7.22268454e-01, 6.80927105e+00, -1.17038612e+01, 3.26405193e+00, + -5.01975383e+00, 3.03973079e+00, 5.01794918e+00, -5.32441308e+00, 2.66702778e+00, + 3.16062835e+00, -5.48883063e+00, 4.90714636e+00, 5.28519501e+00, 1.62103241e+01, + -1.76560529e+00, 6.97472841e+00, 1.60801190e+01, -3.24935234e+00, 5.82579474e+00, + 1.77963247e+01, -1.01672498e+00, 6.12825446e+00, 3.80024484e+00, -3.34448566e+00, + 3.35091101e+00, 3.23139426e+00, -4.33013813e+00, 4.76447241e+00, 5.45818342e+00, + -4.06170044e+00, 2.88609058e+00, -2.29106555e+00, 8.27699077e+00, 1.09064600e+00, + -3.59302905e+00, 9.60437448e+00, 8.14797198e-01, -2.46438985e+00, 7.44183939e+00, + -5.48883046e-01, 1.25077487e+01, -1.18739711e+01, 6.65675297e+00, 1.26707463e+01, + -1.01264862e+01, 7.68378868e+00, 1.07093093e+01, -1.23594150e+01, 6.65739810e+00, + 8.60509597e+00, -7.60304481e+00, 4.63854382e+00, 9.02578016e+00, -5.87949593e+00, + 4.07482932e+00, 7.12403922e+00, -8.13379120e+00, 3.51070503e+00, -3.00012077e+00, + -6.53179460e+00, 8.59007709e+00, -3.93905553e+00, -5.85750020e+00, 9.99816090e+00, + -1.75352091e+00, -7.63786023e+00, 9.17090076e+00, 1.20655910e+00, 1.10365477e+01, + -1.09830488e+00, 6.09246061e-01, 1.15808414e+01, 5.61555958e-01, 2.73453294e+00, + 1.20648566e+01, -1.25111478e+00, 2.62638436e+01, 7.27406319e+00, -8.75588526e+00, + 2.56834674e+01, 5.56426063e+00, -8.04139770e+00, 2.82412254e+01, 7.33859615e+00, + -8.38692536e+00, 2.74104908e+00, -1.86292973e+01, -9.19589353e+00, 4.43387362e+00, + -1.87846089e+01, -9.91418570e+00, 1.87855716e+00, -1.89783535e+01, -1.09205196e+01, + 3.97947941e+00, -5.47257104e+00, -6.83899148e+00, 2.77379545e+00, -4.71009592e+00, + -5.43207979e+00, 4.09371918e+00, -3.94218484e+00, -7.84955906e+00, 1.00356554e+01, + -1.76389816e+01, 4.22779892e+00, 1.15089292e+01, -1.81197327e+01, 5.10668667e+00, + 1.01129107e+01, -1.89069149e+01, 2.93228675e+00, 1.77493187e+01, -1.18696630e+01, + 6.15072403e+00, 1.69455996e+01, -1.15938719e+01, 7.68457144e+00, 1.65835561e+01, + -1.12666150e+01, 5.00737837e+00, 1.18087642e+01, -1.60388415e+01, -1.00042403e+01, + 1.28761001e+01, -1.76032488e+01, -1.02550343e+01, 1.22292183e+01, -1.49850429e+01, + -1.12468680e+01, -5.96314832e+00, -6.31887619e+00, 1.34500300e+01, -5.34715059e+00, + -7.72600390e+00, 1.44440780e+01, -6.88656998e+00, -7.10836674e+00, 1.20318716e+01, + 1.10557748e+01, -1.59085722e+01, -5.04387646e+00, 1.01204107e+01, -1.60028369e+01, + -3.54596491e+00, 1.01659085e+01, -1.68147828e+01, -6.31941602e+00, -8.45427460e+00, + -2.65667497e+00, 6.91745263e+00, -6.74375125e+00, -1.90126068e+00, 7.19132870e+00, + -8.96376344e+00, -2.19363418e+00, 5.14498758e+00, -3.89182857e-01, -1.56888753e+01, + 2.32879823e+00, -1.30089714e+00, -1.66343724e+01, 9.12257571e-01, -1.14188798e+00, + -1.46359268e+01, 3.51386876e+00, 9.37211806e+00, 8.54468618e+00, -2.89250979e+00, + 8.78141523e+00, 9.73701187e+00, -4.32302866e+00, 8.41517272e+00, 7.08433969e+00, + -3.31834175e+00, -2.22955499e+00, -7.91668250e-01, -2.38386476e+01, -1.83492868e+00, + -5.00991552e-01, -2.57437208e+01, -2.69880773e+00, -2.55960022e+00, -2.36353985e+01, + 8.27387771e+00, -7.33575688e+00, -5.87942330e+00, 6.35092941e+00, -7.08113274e+00, + -6.27991783e+00, 8.93763592e+00, -6.51719245e+00, -7.49966962e+00, 2.78840510e+00, + -9.64941990e+00, 3.87609500e+00, 2.92156758e+00, -9.98374738e+00, 5.82207066e+00, + 1.38506984e+00, -8.31553711e+00, 4.00615367e+00, 1.07803427e+00, 1.59229763e-01, + 5.61183782e+00, 2.53864873e+00, -5.23310319e-01, 4.94295750e+00, 7.65852377e-01, + 1.80102640e+00, 4.69045864e+00, 9.11194385e+00, 3.31117500e+00, -4.99694516e-01, + 7.69970540e+00, 4.29870451e+00, -9.81299344e-02, 1.04928491e+01, 4.20896687e+00, + 7.07434059e-01, 2.38843651e+00, -9.25719293e+00, -9.78855489e+00, 1.36723765e+00, + -1.07359219e+01, -9.52936754e+00, 3.35064685e+00, -9.18585996e+00, -8.32908184e+00, + -1.43231528e+01, -6.45597217e+00, -4.46118807e-01, -1.35679796e+01, -8.08771676e+00, + 3.00320855e-01, -1.28697145e+01, -5.48665674e+00, -1.07547594e+00, 1.18110613e+01, + -1.16531694e+01, -7.86500448e+00, 1.33622440e+01, -1.18955804e+01, -8.98089540e+00, + 1.20009816e+01, -1.32121475e+01, -6.74890856e+00, -3.45863064e+00, 2.95792643e+00, + -6.42658349e+00, -4.60614013e+00, 4.23189006e+00, -7.22285576e+00, -4.53339575e+00, + 1.42190834e+00, -6.19058161e+00, 3.24364788e+00, 7.02915419e+00, -5.39215348e-01, + 2.39708876e+00, 8.97617965e+00, -4.20126044e-01, 2.22196985e+00, 6.22895666e+00, + 5.56327805e-01, 1.59984204e+01, -5.84287574e+00, 1.86363441e+01, 1.47801353e+01, + -4.84559303e+00, 1.93533925e+01, 1.76828486e+01, -4.66931904e+00, 1.86230162e+01, + 6.08237008e+00, -1.47299814e+01, -3.78247837e+00, 4.78901045e+00, -1.39028545e+01, + -2.67742636e+00, 5.53381502e+00, -1.64397207e+01, -4.20231347e+00, -7.50143750e+00, + -9.10652021e-01, -1.65044874e+00, -8.92524410e+00, -1.77729527e+00, -2.40806154e+00, + -6.42215400e+00, 1.15848502e-01, -2.75045541e+00, 4.89505746e+00, 1.50494897e-01, + -4.99621539e+00, 3.58312493e+00, 7.36814991e-01, -6.02014838e+00, 3.76068453e+00, + -7.84227605e-02, -3.11714262e+00, -6.04596705e+00, -1.16496551e+00, -7.32403541e+00, + -5.59894261e+00, -2.87674427e+00, -6.45698238e+00, -7.57587741e+00, -1.76917601e+00, + -8.43410745e+00, 9.18653546e+00, -2.93498856e+00, 2.68500255e+00, 1.06367956e+01, + -3.65150207e+00, 1.61132687e+00, 8.38250023e+00, -1.93721739e+00, 1.16504700e+00, + 1.81626625e+00, -3.49676977e+00, -2.66477091e+00, 2.53150870e-01, -2.48620331e+00, + -2.85322051e+00, 2.40622962e+00, -3.44596743e+00, -9.93811065e-01, -2.94171379e+00, + -1.15802091e+01, 1.09161095e+01, -1.83503870e+00, -1.27216331e+01, 1.19853877e+01, + -2.68174694e+00, -9.95836912e+00, 1.17372362e+01, 1.20695200e+01, 6.92946961e+00, + 1.49151598e+00, 1.24390565e+01, 7.58521727e+00, 3.11596461e+00, 1.02554837e+01, + 7.32440427e+00, 1.21067003e+00, 1.43493276e+01, -1.57856515e+00, 2.03568985e+00, + 1.33636654e+01, -2.85087860e+00, 2.83623937e+00, 1.35985432e+01, -1.40251297e+00, + 3.14717634e-01, 6.55740268e+00, -8.17481875e-01, 6.81465394e+00, 5.85552908e+00, + -2.29389688e+00, 6.09518757e+00, 6.99006081e+00, 2.96832928e-01, 5.51556803e+00, + -6.87704245e-01, -6.34197738e+00, 3.27981758e+00, -2.52168336e+00, -6.66243631e+00, + 3.19109582e+00, -3.52920568e-01, -4.48559485e+00, 2.57382443e+00, 1.09885570e+01, + 1.20134297e+01, 2.00488702e+01, 9.53804230e+00, 1.09072164e+01, 2.00175146e+01, + 1.20661894e+01, 1.14325396e+01, 1.87478346e+01, 2.15889011e+00, -2.38560921e+01, + 7.86816975e+00, 3.35910665e+00, -2.52233478e+01, 8.24868855e+00, 4.78545613e-01, + -2.46866501e+01, 7.71853200e+00, -6.73627901e-01, -2.15188712e+01, 8.17319475e-01, + -1.90340564e+00, -2.08759741e+01, 1.93195444e+00, 7.31174686e-01, -2.03629864e+01, + 9.02513546e-01 ] + +

+ [ -4.02765830e+00, -3.16023137e+00, -6.88011833e+00, 6.46755190e-01, 1.53026954e+00, + -2.19506763e+00, -1.67835222e+00, -5.32155921e-01, -1.06085925e+00, -2.30471976e+00, + -3.52917704e+00, -3.94006174e+00, -7.34979987e-01, -2.10239481e-01, 7.18707512e-01, + 1.57005590e+00, 2.18516271e-01, 9.25232779e-01, 3.34019920e+00, -1.05455782e+01, + -6.37139586e+00, 1.26402730e-01, 1.25768619e-02, -3.09142555e-01, -8.39207249e-01, + -8.35248753e-01, -8.58037086e-01, 4.08421754e+00, 2.35572425e+00, -4.59257653e+00, + 3.17769176e-01, 2.33664714e+00, -1.33226716e+00, 6.13647976e-02, 9.14908453e-01, + 1.99621940e-01, -5.36433556e-01, 9.78577617e+00, 3.15100532e+00, -7.67098039e-02, + -2.68685188e-01, -2.21983725e+00, -4.40882737e-01, -1.71483915e-01, -7.17212520e-01, + 8.57637765e+00, 2.82256107e+00, 5.53177831e+00, 1.80559963e+00, 2.46786279e+00, + 1.51779938e+00, -2.02623211e+00, -5.78135941e-01, 1.49030327e+00, 1.07439175e+01, + 5.39180849e+00, -5.47784454e+00, 1.58381688e+00, 5.05886077e-01, 3.76803356e-01, + -1.38751615e+00, 2.95688436e-01, 1.58410366e+00, -2.80636045e+00, -4.90422672e+00, + -8.54444216e+00, -1.66361699e+00, 6.62247945e-01, 3.77915326e-01, -6.72869185e-01, + 1.70899114e+00, -1.39645304e+00, -8.89305852e+00, 8.87294193e-01, -6.25731915e+00, + -7.89802389e-01, -1.47434221e+00, 2.03450683e+00, 1.18483688e+00, -1.62130683e+00, + -9.66050236e-01, 1.79957758e+00, -1.91158836e+00, 1.52148414e+00, 1.02392868e+00, + 4.96524210e-01, -3.88683893e-01, 2.97483850e-01, -1.81675060e-01, -5.40274010e-01, + 7.56174836e+00, -4.17216519e+00, -2.04695415e-01, -1.07181836e+00, 4.49563846e-01, + 8.76759186e-01, -3.84162916e-01, -3.88527314e+00, -1.62530511e+00, 5.65454856e+00, + 2.91730118e+00, -3.90989881e+00, 1.54231359e+00, -2.21972512e-01, -4.51045558e-02, + 3.99416478e-01, -1.00950555e+00, 3.39184284e-01, 5.90140476e+00, -3.22770125e+00, + 7.82044643e+00, 2.09317553e-01, 2.68579455e-01, 6.63090432e-01, 1.44255027e+00, + -2.32917987e+00, 2.01606232e-01, -3.12618017e+00, 4.30261848e+00, -2.71378848e+00, + 1.85882366e+00, -1.61633781e-01, 2.64130322e-01, -4.46744495e-01, 1.31080074e+00, + 6.60114040e-01, -8.30310641e+00, 9.25745314e-01, 7.64332400e+00, -2.01002448e+00, + 2.30174903e-01, -1.23201926e+00, 2.66401112e-01, 6.12873234e-01, 1.13792494e+00, + -9.92961866e-01, 1.40104874e+00, -1.54976667e+00, -2.09460862e+00, -1.11318979e+00, + -6.77879296e-01, -1.48922489e+00, 5.77486551e-01, 8.95837254e-02, 7.19296755e-01, + -2.14225094e-01, 5.13432993e+00, 8.13091174e-02, 3.19785272e-01, 2.05804267e+00, + -7.06147577e-01, 1.19400637e+00, -1.09844364e+00, -9.70764522e-01, -9.63044853e+00, + 9.95372411e+00, 1.10906246e+00, -5.38801179e-01, 2.52658243e+00, 4.24814703e-01, + 3.51643210e-01, 2.65609594e-01, 3.20325937e+00, -3.83370547e-01, 5.46853459e+00, + -3.80891311e-01, -5.78597893e-01, 1.00601378e+00, -1.94028707e+00, 8.53963967e-01, + -1.04905411e-01, -2.10817786e-01, 4.75283908e+00, -2.80392819e+00, -5.34639991e-01, + -1.04298964e+00, -2.56306844e-02, -6.25008824e-01, -1.09859980e+00, 5.12861463e-01, + 7.24710437e+00, -6.36295046e+00, -4.66028066e+00, 1.51129191e-01, -3.51535018e-01, + 1.01099172e+00, -5.30210104e-01, -5.26844762e-01, -1.07618887e-01, -1.32849603e+01, + -7.81488092e+00, -1.18072980e+00, -9.30213958e-01, -1.94013976e-01, 6.33616430e-01, + 1.19898755e+00, -2.30617292e+00, 2.61701779e+00, 7.71101489e+00, 1.60726495e+00, + -2.40983274e+00, -1.16338678e+00, 1.88871931e-01, 1.71770472e+00, -4.64385501e-02, + 1.39155166e+00, -1.74835047e+00, -1.41568360e+00, -2.86578718e+00, 5.52999030e+00, + -2.24926040e+00, -3.61432769e-01, -1.12630561e+00, 1.68660194e+00, -2.49880250e+00, + -7.77272175e-01, -3.01543784e+00, 6.03277807e+00, 2.86043016e+00, -2.12976635e-01, + 2.01492967e+00, -1.78760816e+00, -6.61890776e-01, -1.30111518e+00, 9.38199658e-01, + 4.99052574e+00, -3.20148706e+00, -4.28580193e+00, -1.76106567e+00, -2.18336915e+00, + -5.12765262e-01, 1.10394817e+00, -7.30500839e-01, 2.46295960e+00, 1.16724054e+00, + -3.43835368e+00, 3.35366912e+00, -9.52601684e-01, -1.21651126e+00, 1.85209383e+00, + 2.44758034e+00, -1.24989641e+00, -1.42092175e-01, 9.30070829e-02, -1.00986313e+01, + 3.71453120e+00, -1.57124704e+00, -1.57842572e-01, 2.80923890e-01, 9.74670118e-01, + -6.44852652e-01, -8.06646424e-01, -2.64682957e+00, -1.04039827e+01, -1.28501080e+01, + 1.68550729e+00, 6.62379774e-01, -1.08806618e+00, -5.42781546e-02, -2.12338052e+00, + -7.09371750e-01, -2.86715414e+00, -2.89936794e+00, 1.39691277e+00, -7.03065772e-01, + -4.01449140e-01, -4.40156839e-01, -1.39532149e+00, -1.55399108e+00, 2.18289212e-01, + 3.92577101e+00, -6.97357837e+00, 7.06725283e+00, -4.66206715e-01, -1.69782685e+00, + -1.08672806e+00, -2.30218438e+00, 1.65965573e+00, 2.07218951e+00, 4.66525729e+00, + 1.26098992e+01, -4.00067984e+00, -7.35377098e-01, 1.50851886e+00, -1.64387393e+00, + -1.62093913e+00, 1.29255558e+00, 2.57817323e+00, 4.40735433e+00, -1.51360322e+00, + 9.76654291e+00, -2.55092007e+00, 1.55729978e+00, 1.22987852e+00, -1.41074169e+00, + 1.68281967e+00, -4.22655643e+00, -7.24433989e+00, -4.51111007e+00, 3.50913442e-01, + 3.92032331e-01, 1.68475390e+00, -1.38236289e+00, 2.16342139e-01, 4.02620945e-01, + 1.58645468e+00, -2.42720323e+00, -2.88063493e+00, -2.43603217e+00, 6.39552310e-01, + -1.23633810e+00, -1.75135112e+00, -1.61746470e+00, 5.66089197e-01, -1.19265022e+00, + -4.45566252e+00, 1.46674521e+00, -1.62711333e+00, -9.79802117e-01, -2.69954658e+00, + 1.00992706e+00, 4.79890537e-01, -2.24175980e+00, 9.71855533e-01, 5.76489712e+00, + -6.64159634e+00, -1.21802309e+01, -1.07858699e-01, 6.62944859e-01, -1.81036037e+00, + -6.50039954e-01, 7.18291481e-01, 9.49026400e-01, 5.46607017e+00, 8.67055746e+00, + 6.89907713e-01, -8.89380803e-01, 7.82411332e-01, 2.33811329e-01, 1.90045957e+00, + -1.43146248e+00, -1.20403128e+00, 5.34999992e+00, -5.37143672e-01, -7.42224616e-01, + 1.14401389e+00, -2.02676171e+00, 7.25767787e-01, 1.38819101e+00, -1.07684631e+00, + 2.11049922e+00, 4.94613560e+00, -2.47629465e+00, -4.81220995e+00, -3.62407656e+00, + -6.21428478e-01, 2.48121999e+00, 4.89964677e-01, 1.94082430e+00, 1.75503578e-01, + 4.64198784e+00, -5.28542267e+00, 1.87467637e+00, -8.36058746e-01, 2.89787801e-01, + -1.50441306e-01, -1.57859573e+00, -4.54015547e-01, -6.22336881e-01, 7.79080554e+00, + 3.85125618e+00, -2.88449914e+00, 4.03841820e-01, 5.42378712e-01, 1.73163636e+00, + -8.49431866e-01, 4.23521295e-01, 3.47485965e-01, -3.84957440e+00, 4.57855459e+00, + 7.17096730e+00, 1.88463955e+00, 1.71916155e+00, 1.69169705e+00, 1.02318947e+00, + -2.43890026e-01, 3.02909344e-01, 5.14240978e+00, -1.23371036e+00, 1.14767194e+00, + -8.54565063e-01, 1.50345811e+00, -5.15548466e-01, 3.10364515e-02, -7.48013507e-01, + 4.36977353e-01, -7.47807746e+00, 6.27566212e+00, 1.87739418e+00, 1.26082206e+00, + -6.17876533e-02, -6.51088895e-01, -1.28752643e+00, 9.40911536e-02, 2.24710031e-01, + -8.60913146e+00, 3.13634246e+00, -5.22275443e+00, -2.00695888e+00, 3.89703254e-01, + 4.69470837e-02, -1.42436128e+00, 1.09837492e+00, -6.95885886e-01, 2.63575791e+00, + 5.20132739e+00, -2.48589051e+00, -1.06453295e+00, -2.03802874e+00, -8.44154407e-01, + -1.90732616e+00, -4.50714573e-01, 8.73494630e-01, -3.09347871e+00, -2.49271916e+00, + 2.55373723e+00, 2.18455516e+00, -2.15960624e+00, -1.35163423e+00, 1.55154456e+00, + -6.16741959e-02, 5.97961238e-01, -1.29709652e-02, 4.03233615e+00, -2.89978788e+00, + -9.23892726e-01, -9.99338701e-02, -8.88772142e-01, -5.08559082e-01, 1.12082844e+00, + 1.23042350e+00, -5.65678688e+00, 3.90278929e+00, 1.58369961e+00, 1.54060894e+00, + 1.20331859e+00, 3.02411668e+00, 1.97412122e+00, -3.35319919e-01, 1.09255916e-01, + 4.76458711e+00, 3.15184088e+00, -1.21439625e+01, 9.39418898e-01, 1.43614538e-01, + -8.71666677e-01, 6.68427271e-02, 1.02012295e+00, 1.82573777e-01, 5.88240113e-01, + 6.44210105e+00, -5.67351310e-01, -1.85489322e+00, -5.02684523e-01, 6.05553861e-02, + 1.76710710e-01, -2.02505386e+00, -1.41940272e+00, 4.15874511e+00, 1.30142366e+01, + 1.40701259e+00, 1.98563976e+00, 1.23602998e+00, -5.64438487e-01, -1.09987142e+00, + -1.95882860e-01, -1.73178964e+00, -5.59174795e+00, 1.36496200e+01, 3.56245544e+00, + -1.66428666e+00, -2.21370979e-01, 6.37547650e-01, 1.27997883e-01, 4.08643296e-01, + -1.21172144e+00, -4.01016350e-01, -5.57590252e+00, -8.90880408e+00, -2.37565308e+00, + -1.80892597e-01, 2.29027900e+00, 1.00249387e+00, 1.82021769e+00, 3.58229650e-01, + 2.07814011e-01, -6.04090738e+00, -4.42046679e+00, 8.80624118e-01, -1.67505974e-01, + 1.26718922e+00, -1.19360672e-01, 2.28569512e+00, 2.55251102e+00, 5.92740372e+00, + 1.76594769e+01, -5.29238134e-01, -2.21418228e+00, 1.96654873e+00, -1.46373470e+00, + 2.73622576e-02, 3.19472484e+00, 1.81582156e+00, 4.49426744e+00, -4.55970942e+00, + 9.33984742e+00, -6.49580638e-01, -2.29683261e-01, 1.31664350e+00, 2.26546880e-01, + 5.56581079e-01, 2.65156828e-01, -2.09260328e+00, -1.05341376e+00, 3.26833856e+00, + 1.04515423e-01, 1.89093396e+00, 7.92865605e-01, -4.98700350e-02, 1.57796084e+00, + -1.28357407e+00, -4.42784886e+00, -2.42557309e+00, 4.26836218e+00, 1.09690039e+00, + 1.18463101e+00, 1.75466877e+00, -1.14322099e+00, 2.43708040e+00, -1.44543158e+00, + -1.60552469e+00, 4.55175566e-01, -9.25674731e-01, -9.22299171e-01, -1.76795613e+00, + -9.32968169e-01, -1.57739533e+00, -1.20199857e-01, -5.55904036e-01, -1.73947725e+00, + -4.24156667e+00, 5.90537105e+00, -2.62989661e-01, -6.26245215e-01, 4.91116432e-01, + 1.09954587e+00, 1.99217319e+00, 9.78589205e-01, 4.23093659e+00, -4.87338632e+00, + -7.01468491e-01, -8.39465960e-01, 5.88624039e-01, 8.01985241e-02, 2.71379766e+00, + -1.00809113e+00, -2.81042990e-01, -1.20095635e+01, -2.29213926e+00, 3.19024062e+00, + -1.58003258e+00, -2.43456480e+00, 9.72091106e-01, 8.17191111e-01, 1.18797677e+00, + 1.71905046e+00 ] +

+ + [ 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, + 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, + 1.83747161e+03, 2.91643931e+04, 1.83747161e+03, 1.83747161e+03, 2.91643931e+04, + 1.83747161e+03, 1.83747161e+03 ] + + + [ O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H, O, H, H, + O, H, H, O, H, + H, O, H, H, O, + H, H ] + +
+ + [ 1.96756566e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.96756566e+01, + 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.96756566e+01 ] + +
+
diff --git a/examples/clients/mace/getmodel.sh b/examples/clients/mace/getmodel.sh new file mode 100644 index 000000000..31ee1ca0d --- /dev/null +++ b/examples/clients/mace/getmodel.sh @@ -0,0 +1,3 @@ +wget wget https://github.com/ACEsuit/mace-mp/releases/download/mace_mp_0c/mace-small-density-agnesi-stress.model +mv mace-small-density-agnesi-stress.model mace.model + diff --git a/examples/clients/mace/init.xyz b/examples/clients/mace/init.xyz new file mode 120000 index 000000000..0db27c06d --- /dev/null +++ b/examples/clients/mace/init.xyz @@ -0,0 +1 @@ +../../init_files/water_64mols.extxyz \ No newline at end of file diff --git a/examples/clients/mace/input.xml b/examples/clients/mace/input.xml new file mode 100644 index 000000000..72103e52f --- /dev/null +++ b/examples/clients/mace/input.xml @@ -0,0 +1,37 @@ + + + + [ step, time{picosecond}, conserved{electronvolt}, temperature{kelvin}, kinetic_md{electronvolt}, potential{electronvolt}, pressure_md{megapascal} ] + positions + + + 20000 + + 31415 + + +
driver
+
+ + + init.xyz + 300 + + + + + + + + + 100 + + + 0.50 + + + + 300 + + +
diff --git a/examples/clients/metatensor/README.md b/examples/clients/metatensor/README.md index a5b0f23c2..c36c2a1b0 100644 --- a/examples/clients/metatensor/README.md +++ b/examples/clients/metatensor/README.md @@ -10,14 +10,14 @@ machine learning potentials. ## Installation -The code is compatible with metatensor-torch v0.5, which you can install with +The code is compatible with metatensor-torch v0.6, which you can install with ```bash # installĀ all metatensor packages simultaneously pip install "metatensor[torch]" # install packages individually, with explicit control over the installed versions -pip install "metatensor-torch ==0.5.*" "metatensor-operations ==0.2.*" +pip install "metatensor-torch ==0.6.*" "metatensor-operations ==0.2.*" ``` ## Running the example @@ -42,3 +42,13 @@ The options (after `-o`) are as follow: - `check_consistency` controls whether we should run some extra internal consistency checks about data given to the model and data returned by the model. + +## Running with FFDirect + +It is also possible to run the metatensor PES directly, without the need for an external +driver. To do so, you need to use a `` clause in the input, and specify +the appropriate options as a dictionary. Then, you can simply run + +```bash +i-pi input-direct.xml +``` diff --git a/examples/clients/metatensor/create-model.py b/examples/clients/metatensor/create-model.py index f821b73b2..9b442be83 100644 --- a/examples/clients/metatensor/create-model.py +++ b/examples/clients/metatensor/create-model.py @@ -13,7 +13,7 @@ with_extension=False, ) -model.export("nickel-lj.pt") +model.save("nickel-lj.pt") model = metatensor_lj_test.lennard_jones_model( @@ -25,4 +25,4 @@ energy_unit="kcal/mol", with_extension=True, ) -model.export("nickel-lj-extensions.pt", collect_extensions="collected-extensions/") +model.save("nickel-lj-extensions.pt", collect_extensions="collected-extensions/") diff --git a/examples/clients/metatensor/input-direct.xml b/examples/clients/metatensor/input-direct.xml new file mode 100644 index 000000000..9422cd787 --- /dev/null +++ b/examples/clients/metatensor/input-direct.xml @@ -0,0 +1,47 @@ + + + + [step, time{picosecond}, conserved{electronvolt}, temperature{kelvin}, + kinetic_md{electronvolt}, potential{electronvolt}, pressure_md{bar}, + volume{angstrom3}, ensemble_temperature{kelvin}, cell_abcABC] + + x_centroid{angstrom} + + + 1000 +12345 + + + metatensor + {template:nickel.xyz,model:nickel-lj.pt,device:cpu } + + + + + nickel.xyz + 250.0 + + + + + + + + 0.5 + + [ + 4.49e-3, 6.59e-6, 2.79e-4, -8.81e-4, 5.61e-3, + -6.73e-6, 2.08e-9, 1.75e-5, -4.80e-6, 1.03e-5, + -3.59e-4, -1.75e-5, 3.29e-5, 1.24e-4, -2.42e-4, + -2.51e-4, 4.80e-6, -1.24e-4, 6.45e-4, 2.78e-4, + 5.27e-3, -1.03e-5, 2.42e-4, -2.78e-4, 7.49e-3 + ] + + + + + + 250.0 + + + diff --git a/examples/clients/metatensor/nickel-lj.pt b/examples/clients/metatensor/nickel-lj.pt index 9491841ca0bd70e87d0c78be7152f2cf24a0c84a..c9765a0ebbe5dfbe319e8245b90dc8c662ebaca6 100644 GIT binary patch delta 29961 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 I_` clause in the input diff --git a/examples/clients/pes/harmonic-direct/Makefile b/examples/clients/pes/harmonic-direct/Makefile new file mode 100644 index 000000000..7bc94106b --- /dev/null +++ b/examples/clients/pes/harmonic-direct/Makefile @@ -0,0 +1,17 @@ +# Makefile for the "direct" harmonic oscillator example +# +# This file is part of i-PI. +# i-PI Copyright (C) 2014-2015 i-PI developers +# See the "licenses" directory for full license information. + +.PHONY: all clean harmonic +all: harmonic + +IPI:=i-pi + + +harmonic: + $(IPI) input.xml + +clean: + rm -f *simulation.* RESTART EXIT diff --git a/examples/clients/pes/harmonic-direct/init.xyz b/examples/clients/pes/harmonic-direct/init.xyz new file mode 100644 index 000000000..8efa9e7ef --- /dev/null +++ b/examples/clients/pes/harmonic-direct/init.xyz @@ -0,0 +1,3 @@ +1 + +H 0.108 0.000 0.000 diff --git a/examples/clients/pes/harmonic-direct/input.xml b/examples/clients/pes/harmonic-direct/input.xml new file mode 100644 index 000000000..b3b5ba4b6 --- /dev/null +++ b/examples/clients/pes/harmonic-direct/input.xml @@ -0,0 +1,38 @@ + + + [ step, time{picosecond}, conserved{kelvin}, temperature{kelvin}, kinetic_cv{kelvin}, potential{kelvin}, pressure_cv{megapascal}] + positions{angstrom} + forces{piconewton} + + 100 + + 3348 + + + harmonic + { k1:1.0 } + + + + + [ 15., 15.0, 15.0 ] + + init.xyz + 3683.412077 + + + + + + 3683.412077 + + + + + 25 + + 0.003 + + + + diff --git a/examples/clients/pes/harmonic-direct/test_settings.dat b/examples/clients/pes/harmonic-direct/test_settings.dat new file mode 100644 index 000000000..e69de29bb diff --git a/examples/clients/xtb/config.json b/examples/clients/xtb/config.json new file mode 100644 index 000000000..f299cd2e4 --- /dev/null +++ b/examples/clients/xtb/config.json @@ -0,0 +1 @@ +{"method": "GFN2-xTB", "numbers": [6,1,1,1,1], "periodic": false} diff --git a/examples/clients/xtb/run.sh b/examples/clients/xtb/run.sh index 3726ce141..98eea7e55 100644 --- a/examples/clients/xtb/run.sh +++ b/examples/clients/xtb/run.sh @@ -3,5 +3,5 @@ echo "Running i-PI" i-pi input.xml &> log.ipi & sleep 1 echo "Running driver" -i-pi-py_driver -m xtb -o '{"method": "GFN2-xTB", "numbers": [6,1,1,1,1], "periodic": false}' -u -a xtb &> log.xtb +i-pi-py_driver -m xtb -o config.json -u -a xtb &> log.xtb diff --git a/examples/features/ring_polymer_instanton/rates_1D_double_well_with_friction/implicit_bath_pos-dependent/run.sh b/examples/features/ring_polymer_instanton/rates_1D_double_well_with_friction/implicit_bath_pos-dependent/run.sh index 8bc25bc1e..3ee1793d9 100755 --- a/examples/features/ring_polymer_instanton/rates_1D_double_well_with_friction/implicit_bath_pos-dependent/run.sh +++ b/examples/features/ring_polymer_instanton/rates_1D_double_well_with_friction/implicit_bath_pos-dependent/run.sh @@ -5,9 +5,9 @@ wc=500 V0=2085 mass=1837.36223469 - x0=0 epsilon=-1.0 delta=0 + epsilon2=0 deltaQ=1 address=localhost @@ -19,4 +19,9 @@ sleep 3 #Launch driver - i-pi-driver-py -m ${model} -o ${wb},${V0},${mass},${x0},${eta},${epsilon},${delta},${deltaQ} -u -a ${address} + #i-pi-driver-py -m ${model} -o ${wb},${V0},${mass},${x0},${eta},${epsilon},${delta},${deltaQ} -u -a ${address} + arg="w_b=${wb},v0=${V0},m=${mass},delta=${delta},eta0=${eta},eps1=${epsilon},eps2=${epsilon2},deltaQ=${deltaQ}" + + echo ${arg} +# def __init__(self,w_b=None,v0=None,m=None,eta0=None,eps1=None,eps2=None,delta=None,deltaQ=None, *args, **kwargs): + i-pi-driver-py -m ${model} -o ${arg} -u -a ${address} diff --git a/examples/init_files/water_64mols.extxyz b/examples/init_files/water_64mols.extxyz new file mode 100644 index 000000000..7e35fe97f --- /dev/null +++ b/examples/init_files/water_64mols.extxyz @@ -0,0 +1,194 @@ +192 +Lattice="10.4119090601988 0 0 0 10.4119090601988 0 0 0 10.4119090601988" +O 11.18136 -7.24116 6.42199 +H 11.31672 -7.89411 5.71998 +H 11.94205 -7.06097 7.01033 +O 2.78582 1.60883 1.56485 +H 2.45814 1.98676 2.52844 +H 3.72449 1.60021 1.79886 +O 4.06425 1.21834 6.13650 +H 4.52259 0.84151 5.38020 +H 3.73582 0.62974 6.86168 +O -5.85212 -1.78980 -1.47238 +H -5.90795 -2.64483 -2.11048 +H -6.81342 -1.58626 -1.68821 +O -0.69190 1.48298 4.64653 +H -0.57700 1.71944 5.58467 +H -1.16810 2.29631 4.29351 +O 9.78623 -1.22461 5.88911 +H 9.05533 -0.91721 5.33231 +H 10.59603 -1.00085 5.39957 +O 1.78731 -5.40285 -2.77723 +H 2.33162 -5.12910 -2.00467 +H 0.89681 -5.12748 -2.70535 +O -2.75590 -8.62956 -0.10520 +H -2.53979 -8.69428 -1.07891 +H -2.75324 -7.69016 0.12631 +O 9.87767 -4.00367 7.00969 +H 9.30537 -3.91345 7.71858 +H 9.86640 -3.07612 6.67277 +O 1.36270 2.71836 3.60327 +H 0.90987 3.43987 3.16458 +H 0.69390 2.17126 4.04330 +O 7.35720 -5.27057 -1.72224 +H 8.03476 -6.10104 -1.79227 +H 6.40744 -5.61367 -2.01308 +O 7.59285 -3.91299 1.89032 +H 6.71605 -4.09193 1.42394 +H 7.44293 -4.07392 2.84248 +O -0.53502 -7.32429 -1.57639 +H 0.08940 -6.74166 -2.03905 +H -0.92479 -7.79351 -2.35343 +O 6.33684 6.38743 -5.76835 +H 5.27875 6.21603 -5.54541 +H 6.28403 7.30291 -6.28440 +O 4.69882 -1.31516 6.09464 +H 4.31123 -1.15051 5.12558 +H 4.03848 -1.19721 6.76146 +O 3.70821 -4.04859 4.85959 +H 3.88830 -4.26209 3.90588 +H 3.41156 -4.85543 5.33543 +O 4.25159 -7.25513 3.40025 +H 3.80863 -6.84649 4.18355 +H 4.58665 -8.16468 3.69969 +O 2.85185 -0.22288 -0.08384 +H 2.30198 0.32795 0.57462 +H 3.49964 0.50183 -0.31096 +O 0.71578 0.75467 -1.03772 +H 0.48930 1.73621 -0.79676 +H -0.11147 0.47379 -1.50236 +O 3.86173 -5.86884 0.83708 +H 3.02686 -6.20624 0.38164 +H 3.60762 -6.18672 1.72461 +O -2.65909 1.61105 2.65709 +H -2.81796 1.41394 1.66795 +H -2.90099 2.59787 2.79689 +O 8.58320 -0.93140 3.69116 +H 8.51457 -1.71811 3.08024 +H 9.40919 -0.52395 3.22850 +O 2.00819 -1.77043 1.77406 +H 1.71599 -2.29317 2.51221 +H 2.88786 -2.15737 1.53734 +O -1.21196 4.38114 0.57505 +H -1.88725 5.08448 0.43844 +H -1.31330 3.95262 -0.28572 +O 6.62006 -6.28562 3.52156 +H 6.70557 -5.37221 4.07543 +H 5.67024 -6.53243 3.51712 +O 4.55162 -4.02218 2.45618 +H 4.78639 -3.09848 2.15965 +H 3.76492 -4.29938 1.84435 +O -1.58811 -3.45511 4.54425 +H -2.07874 -3.09246 5.28050 +H -0.94080 -4.03592 4.85498 +O 0.63844 5.84407 -0.58258 +H 0.33058 6.12957 0.29606 +H 1.44170 6.38939 -0.65771 +O 13.89937 3.85311 -4.62853 +H 13.58234 2.94223 -4.24959 +H 14.94280 3.89592 -4.43418 +O 1.45155 -9.85714 -4.86694 +H 2.35131 -9.93790 -5.24325 +H 1.00248 -10.03331 -5.77904 +O 2.10425 -2.89321 -3.62158 +H 1.47224 -2.48362 -2.86866 +H 2.18045 -2.09609 -4.16680 +O 5.30876 -9.33887 2.23872 +H 6.09707 -9.59732 2.71391 +H 5.36099 -10.01325 1.53512 +O 9.39110 -6.28070 3.25110 +H 8.98146 -6.14406 4.06255 +H 8.78207 -5.97081 2.67205 +O 6.25165 -8.48610 -5.29389 +H 6.81062 -9.32378 -5.41835 +H 6.47210 -7.92782 -5.96594 +O -3.15468 -3.34260 7.11828 +H -2.83364 -4.08200 7.65508 +H -3.63428 -3.76480 6.37405 +O 5.85238 -8.41894 -2.66855 +H 5.35988 -8.45234 -1.87962 +H 5.37565 -8.88515 -3.35133 +O -4.47590 -1.40335 3.66515 +H -3.56824 -1.01032 3.81598 +H -4.73962 -1.16543 2.71828 +O -0.20781 -8.30570 1.23188 +H -0.68347 -8.80535 0.48392 +H -0.61830 -7.73467 1.86794 +O 4.95749 4.52203 -1.53048 +H 4.64077 5.16432 -2.29082 +H 4.44398 3.75315 -1.76902 +O -1.18170 -0.41798 -12.61310 +H -0.94931 -0.26291 -13.63669 +H -1.43151 -1.36626 -12.50848 +O 4.37654 -3.87984 -3.11203 +H 3.36699 -3.74856 -3.32174 +H 4.73860 -3.44669 -3.96314 +O 1.47263 -5.10769 2.05248 +H 1.54376 -5.28591 3.06801 +H 0.73852 -4.40355 2.11733 +O 0.57171 0.08269 2.96703 +H 1.33511 -0.28899 2.60400 +H 0.39918 0.95384 2.48030 +O 4.82014 1.75266 -0.26475 +H 4.07740 2.26716 -0.04860 +H 5.55096 2.23000 0.36991 +O 1.26659 -4.90102 -5.18088 +H 0.71571 -5.68172 -5.03880 +H 1.78228 -4.86123 -4.40607 +O -7.57618 -3.41768 -0.23405 +H -7.16860 -4.28058 0.15792 +H -6.80151 -2.90991 -0.56491 +O 6.24921 -6.16862 -4.16104 +H 7.07600 -6.28218 -4.74638 +H 6.36108 -6.98816 -3.57694 +O -1.82911 1.56633 -3.40176 +H -2.45012 2.25119 -3.81374 +H -2.40852 0.75307 -3.27997 +O 1.71669 3.71840 -0.28443 +H 1.27373 4.74944 -0.21805 +H 1.17547 3.28611 0.29122 +O 8.46853 -3.09340 9.86116 +H 7.80954 -2.56880 10.22497 +H 9.34209 -2.47122 9.85476 +O 3.21682 -7.79589 -1.99707 +H 2.52837 -7.35831 -1.41162 +H 2.92784 -8.70634 -2.22468 +O -3.96971 -0.48422 -0.87321 +H -4.71266 -0.93801 -1.27585 +H -3.40046 0.07288 -1.44726 +O 2.58880 0.07464 -2.64410 +H 1.88211 0.38311 -3.18472 +H 1.99881 -0.03955 -1.64188 +O -3.19736 -0.62180 -3.87710 +H -2.95370 -1.51924 -3.42177 +H -4.00833 -0.93762 -4.45389 +O 4.86152 -1.55101 1.42393 +H 5.64113 -1.93118 0.83995 +H 4.42948 -1.03684 0.61612 +O 0.96100 -1.84820 -1.40869 +H 0.12950 -1.31463 -1.51719 +H 1.27479 -1.83709 -0.53915 +O -1.55890 -6.13475 5.77682 +H -0.95828 -6.74283 6.34991 +H -1.41913 -5.28777 6.20053 +O 6.38516 3.66860 0.78566 +H 6.58667 4.01604 1.64321 +H 5.42592 3.87325 0.63911 +O 7.59422 -0.83492 1.07614 +H 7.07118 -1.52087 1.49718 +H 7.19591 -0.75122 0.17345 +O 3.47168 -0.43168 3.60482 +H 3.09120 -1.22210 3.21392 +H 3.70663 0.14389 2.92538 +O -0.36322 -3.35602 1.73591 +H -1.32945 -3.51529 1.69406 +H -0.17779 -2.37533 1.36604 +O 5.81550 6.35896 10.60725 +H 5.04874 5.77496 10.58989 +H 6.38013 6.03712 9.91339 +O 1.14085 -12.62231 4.16390 +H 1.78212 -13.35146 4.36508 +H 0.23752 -13.05745 4.08631 +O -0.35190 -11.38652 0.43131 +H -1.00022 -11.03186 1.01782 +H 0.38267 -10.78230 0.46692 diff --git a/ipi/__init__.py b/ipi/__init__.py index 1b337369a..196aa6995 100644 --- a/ipi/__init__.py +++ b/ipi/__init__.py @@ -12,6 +12,7 @@ "inputs", "interfaces", "utils", + "pes", "ipi_global_settings", "install_driver", "read_output", diff --git a/ipi/engine/forcefields.py b/ipi/engine/forcefields.py index 827d92b6a..d764902b6 100644 --- a/ipi/engine/forcefields.py +++ b/ipi/engine/forcefields.py @@ -23,11 +23,9 @@ from ipi.utils.io import read_file from ipi.utils.units import unit_to_internal from ipi.utils.distance import vector_separation +from ipi.pes import __drivers__ -try: - import plumed -except ImportError: - plumed = None +plumed = None class ForceRequest(dict): @@ -391,6 +389,58 @@ def evaluate(self, request): request["status"] = "Done" +class FFDirect(FFEval): + def __init__( + self, + latency=1.0, + offset=0.0, + name="", + pars=None, + dopbc=False, + active=np.array([-1]), + threaded=False, + pes="dummy", + ): + """Initialises FFDirect. + + Args: + latency: The number of seconds the socket will wait before updating + the client list. + offset: A constant offset subtracted from the energy value given by the + client. + name: The name of the forcefield. + pars: A dictionary used to initialize the forcefield, if required. + Of the form {'name1': value1, 'name2': value2, ... }. + dopbc: Decides whether or not to apply the periodic boundary conditions + before sending the positions to the client code. + active: Indexes of active atoms in this forcefield + + """ + + super().__init__(latency, offset, name, pars, dopbc, active, threaded) + + self.pes = pes + try: + self.driver = __drivers__[self.pes](verbose=verbosity.high, **pars) + except ImportError: + # specific errors have already been triggered + raise + except Exception as err: + print(f"Error setting up PES mode {self.pes}") + print(__drivers__[self.pes].__doc__) + print("Error trace: ") + raise err + + def evaluate(self, request): + results = list(self.driver(request["cell"][0], request["pos"].reshape(-1, 3))) + + # ensure forces and virial have the correct shape to fit the results + results[1] = results[1].reshape(-1) + results[2] = results[2].reshape(3, 3) + request["result"] = results + request["status"] = "Done" + + class FFLennardJones(FFEval): """Basic fully pythonic force provider. @@ -409,12 +459,14 @@ class FFLennardJones(FFEval): def __init__( self, - latency=1.0e-3, + latency=1.0, offset=0.0, name="", pars=None, - dopbc=False, - threaded=False, + dopbc=True, + active=np.array([-1]), + threaded=True, + interface=None, ): """Initialises FFLennardJones. @@ -430,7 +482,7 @@ def __init__( # a socket to the communication library is created or linked super(FFLennardJones, self).__init__( - latency, offset, name, pars, dopbc=dopbc, threaded=threaded + latency, offset, name, pars, dopbc=dopbc, threaded=threaded, active=active ) self.epsfour = float(self.pars["eps"]) * 4 self.sixepsfour = 6 * self.epsfour @@ -678,8 +730,11 @@ def __init__( pars: Optional dictionary, giving the parameters needed by the driver. """ + global plumed # a socket to the communication library is created or linked - if plumed is None: + try: + import plumed + except ImportError: raise ImportError( "Cannot find plumed libraries to link to a FFPlumed object/" ) @@ -863,6 +918,14 @@ def __init__( """ + warning( + """ + is deprecated and might be removed in a future release of i-PI. + If you are interested in using it, please help port it to the PES + infrastructure. + """ + ) + from yaff import System, ForceField, log import codecs import locale @@ -955,6 +1018,14 @@ def __init__( """ + warning( + """ + is deprecated and might be removed in a future release of i-PI. + If you are interested in using it, please help port it to the PES + infrastructure. + """ + ) + # a socket to the communication library is created or linked super(FFsGDML, self).__init__( latency, offset, name, pars, dopbc, threaded=threaded diff --git a/ipi/inputs/forcefields.py b/ipi/inputs/forcefields.py index a8fcd6467..f3b8e0757 100644 --- a/ipi/inputs/forcefields.py +++ b/ipi/inputs/forcefields.py @@ -11,6 +11,7 @@ from ipi.engine.forcefields import ( ForceField, FFSocket, + FFDirect, FFLennardJones, FFDebye, FFPlumed, @@ -21,6 +22,7 @@ FFCavPhSocket, ) from ipi.interfaces.sockets import InterfaceSocket +from ipi.pes import __drivers__ import ipi.engine.initializer from ipi.inputs.initializer import * from ipi.utils.inputvalue import * @@ -28,6 +30,7 @@ __all__ = [ "InputFFSocket", + "InputFFDirect", "InputFFLennardJones", "InputFFDebye", "InputFFPlumed", @@ -135,6 +138,8 @@ def store(self, ff): self.activelist.store(ff.active) self.threaded.store(ff.threaded) + _FFCLASS = ForceField + def fetch(self): """Creates a ForceField object. @@ -144,7 +149,7 @@ def fetch(self): super(InputForceField, self).fetch() - return ForceField( + return self._FFCLASS( pars=self.parameters.fetch(), name=self.name.fetch(), latency=self.latency.fetch(), @@ -336,37 +341,58 @@ def check(self): raise ValueError("Negative timeout parameter specified.") -class InputFFLennardJones(InputForceField): +class InputFFDirect(InputForceField): + fields = { + "pes": ( + InputValue, + { + "dtype": str, + "default": "dummy", + "options": list(__drivers__.keys()), + "help": "Type of PES that should be used to evaluate the forcefield", + }, + ), + } + fields.update(InputForceField.fields) + attribs = {} attribs.update(InputForceField.attribs) - default_help = """Simple, internal LJ evaluator without cutoff, neighbour lists or minimal image convention. - Expects standard LJ parameters, e.g. { eps: 0.1, sigma: 1.0 }. """ - default_label = "FFLJ" + default_help = """ Direct potential that evaluates forces through a Python + call, using PES providers from a list of possible external codes. The available + PES interfaces are listed into the `ipi/pes` folder, and are the same available + for the Python driver. The `` field should contain a dictionary + of the specific option of the chosen PES. + """ + default_label = "FFDirect" def store(self, ff): - super(InputFFLennardJones, self).store(ff) + super().store(ff) + self.pes.store(ff.pes) def fetch(self): - super(InputFFLennardJones, self).fetch() + super().fetch() - return FFLennardJones( + return FFDirect( pars=self.parameters.fetch(), name=self.name.fetch(), latency=self.latency.fetch(), offset=self.offset.fetch(), dopbc=self.pbc.fetch(), threaded=self.threaded.fetch(), + pes=self.pes.fetch(), ) - if self.slots.fetch() < 1 or self.slots.fetch() > 5: - raise ValueError( - "Slot number " + str(self.slots.fetch()) + " out of acceptable range." - ) - if self.latency.fetch() < 0: - raise ValueError("Negative latency parameter specified.") - if self.timeout.fetch() < 0.0: - raise ValueError("Negative timeout parameter specified.") + +class InputFFLennardJones(InputForceField): + attribs = {} + attribs.update(InputForceField.attribs) + + default_help = """Simple, internal LJ evaluator without cutoff, neighbour lists or minimal image convention. + Expects standard LJ parameters, e.g. { eps: 0.1, sigma: 1.0 }. """ + default_label = "FFLJ" + + _FFCLASS = FFLennardJones class InputFFdmd(InputForceField): @@ -445,7 +471,7 @@ class InputFFDebye(InputForceField): "default": input_default(factory=np.zeros, args=(0,)), "help": "Specifies the Hessian of the harmonic potential. " "Default units are atomic. Units can be specified only by xml attribute. " - "Implemented options are: 'atomic_unit', 'ev/ang\^2'", + r"Implemented options are: 'atomic_unit', 'ev/ang^2'", "dimension": "hessian", }, ), @@ -747,6 +773,7 @@ class InputFFCommittee(InputForceField): dynamic = { "ffsocket": (InputFFSocket, {"help": InputFFSocket.default_help}), + "ffdirect": (InputFFDirect, {"help": InputFFDirect.default_help}), "fflj": (InputFFLennardJones, {"help": InputFFLennardJones.default_help}), "ffdebye": (InputFFDebye, {"help": InputFFDebye.default_help}), "ffplumed": (InputFFPlumed, {"help": InputFFPlumed.default_help}), diff --git a/ipi/inputs/simulation.py b/ipi/inputs/simulation.py index 56b8666a3..796316d59 100644 --- a/ipi/inputs/simulation.py +++ b/ipi/inputs/simulation.py @@ -159,6 +159,10 @@ class InputSimulation(Input): iforcefields.InputFFSocket, {"help": iforcefields.InputFFSocket.default_help}, ), + "ffdirect": ( + iforcefields.InputFFDirect, + {"help": iforcefields.InputFFDirect.default_help}, + ), "fflj": ( iforcefields.InputFFLennardJones, {"help": iforcefields.InputFFLennardJones.default_help}, @@ -246,6 +250,10 @@ def store(self, simul): _iobj = iforcefields.InputFFSocket() _iobj.store(_obj) self.extra[_ii] = ("ffsocket", _iobj) + elif isinstance(_obj, eforcefields.FFDirect): + _iobj = iforcefields.InputFFDirect() + _iobj.store(_obj) + self.extra[_ii] = ("ffdirect", _iobj) elif isinstance(_obj, eforcefields.FFLennardJones): _iobj = iforcefields.InputFFLennardJones() _iobj.store(_obj) @@ -322,17 +330,18 @@ def fetch(self): # of system objects with the desired properties set # automatically to many values. syslist += v.fetch() - elif ( - k == "ffsocket" - or k == "fflj" - or k == "ffdebye" - or k == "ffdmd" - or k == "ffplumed" - or k == "ffsgdml" - or k == "ffyaff" - or k == "ffcommittee" - or k == "ffcavphsocket" - ): + elif k in [ + "ffsocket", + "ffdirect", + "fflj", + "ffdebye", + "ffdmd", + "ffplumed", + "ffsgdml", + "ffyaff", + "ffcommittee", + "ffcavphsocket", + ]: new_ff = v.fetch() if k == "ffsocket": # overrides ffsocket prefix diff --git a/drivers/py/pes/__init__.py b/ipi/pes/__init__.py similarity index 100% rename from drivers/py/pes/__init__.py rename to ipi/pes/__init__.py diff --git a/drivers/py/pes/ase.py b/ipi/pes/ase.py similarity index 70% rename from drivers/py/pes/ase.py rename to ipi/pes/ase.py index 7d5597a52..567c4e4e7 100644 --- a/drivers/py/pes/ase.py +++ b/ipi/pes/ase.py @@ -1,48 +1,45 @@ """Interface with ASE calculators""" -import sys import numpy as np from .dummy import Dummy_driver from ipi.utils.units import unit_to_internal, unit_to_user from ipi.utils.messages import warning -try: - from ase.io import read -except ImportError: - warning("Could not find or import the ASE module") - MetatensorCalculator = None + +read = None __DRIVER_NAME__ = "ase" __DRIVER_CLASS__ = "ASEDriver" -ERROR_MSG = """ -This ASE driver requires specification of and ASE calculator -and an ASE-readable template file that describes the chemical makeup of the structure. - -Example: python driver.py -m ase -u -o template.xyz,model_parameters -""" - class ASEDriver(Dummy_driver): - """Abstract base class using an arbitrary ASE calculator as i-pi driver""" - - def __init__(self, args=None, verbose=False, error_msg=ERROR_MSG): - super().__init__(args, verbose, error_msg=error_msg) - - def check_arguments(self): + """ + Base class using an arbitrary ASE calculator as i-pi driver. + Should not be called directly as it does not set a calculator. + + Parameters: + :param verbose: bool, whether to print verbose output + :param template: string, ASE-readable filename where to get the structure data from + """ + + def __init__(self, template, *args, **kwargs): + global read + try: + from ase.io import read + except ImportError: + warning("Could not find or import the ASE module") + + self.template = template + super().__init__(*args, **kwargs) + + def check_parameters(self): """Check the arguments required to run the driver This loads the potential and atoms template in metatensor """ - if len(self.args) >= 1: - self.template = self.args[0] - else: - sys.exit(self.error_msg) - self.template_ase = read(self.template) - self.ase_calculator = None def __call__(self, cell, pos): @@ -63,7 +60,9 @@ def __call__(self, cell, pos): structure.calc = self.ase_calculator # Do the actual calculation - properties = structure.get_properties(["energy", "forces", "stress"]) + self.ase_calculator.calculate(atoms=structure) + properties = self.ase_calculator.results + pot = properties["energy"] force = properties["forces"] stress = properties["stress"] diff --git a/drivers/py/pes/bath.py b/ipi/pes/bath.py similarity index 79% rename from drivers/py/pes/bath.py rename to ipi/pes/bath.py index f4d62d95e..c49c63de6 100644 --- a/drivers/py/pes/bath.py +++ b/ipi/pes/bath.py @@ -2,22 +2,29 @@ import numpy as np -__DRIVER_NAME__ = None -__DRIVER_CLASS__ = "driver_tools" +from ipi.utils.messages import verbosity, warning + +__DRIVER_NAME__ = "bath" +__DRIVER_CLASS__ = "Harmonic_Bath_explicit" class Harmonic_Bath_explicit(object): """Explicit description of an Harmonic bath""" - def __init__(self, nbath, parameters): + def __init__(self, nbath, m, eta0, eps1, eps2, deltaQ, w_c, *args, **kwargs): + warning( + "THIS PES HAS NOT BEEN TESTED FOLLOWING CONVERSION TO THE NEW PES API.", + verbosity.low, + ) + super().__init__(*args, **kwargs) + self.nbath = nbath - self.m = parameters["m"] - # self.delta = parameters["delta"] - self.eta0 = parameters["eta0"] - self.eps1 = parameters["eps1"] - self.eps2 = parameters["eps2"] - self.deltaQ = parameters["deltaQ"] - self.w_c = parameters["w_c"] + self.m = m + self.eta0 = eta0 + self.eps1 = eps1 + self.eps2 = eps2 + self.deltaQ = deltaQ + self.w_c = w_c self.set_ci_and_wi() diff --git a/drivers/py/pes/doubledoublewell.py b/ipi/pes/doubledoublewell.py similarity index 71% rename from drivers/py/pes/doubledoublewell.py rename to ipi/pes/doubledoublewell.py index 94b5c90e5..e4f633639 100644 --- a/drivers/py/pes/doubledoublewell.py +++ b/ipi/pes/doubledoublewell.py @@ -28,7 +28,7 @@ class DDW_with_explicit_bath_driver(Dummy_driver): - """Adds to a double-double well (DDW) potential coupled to two (explicit) harmonic baths. + r"""Adds to a double-double well (DDW) potential coupled to two (explicit) harmonic baths. pos[0:2] = DDW pos[2:n//2+1] = bath1 pos[n//2+1:] = bath2 @@ -47,49 +47,61 @@ class DDW_with_explicit_bath_driver(Dummy_driver): ! and ! ! DDW(q1,q2) = DW(q1) + DW(q2) + C(q1q2)^2 - """ - def __init__(self, args=None, verbose=None): - self.error_msg = """\nDW+explicit_bath driver expects 11 arguments.\n - Example: python driver.py -m DoubleWell_with_explicit_bath -o wb1 (cm^-1) V1 (cm^-1) wb2 (cm^-1) V2 (cm^-1) coupling(au) mass delta(\AA) eta0 eps1 eps2 deltaQ omega_c(cm^-1) \n - python driver.py -m DoubleWell -o 500,2085,500,2085,0.1,1837,0.00,1,0,0,1,500\n""" - super(DDW_with_explicit_bath_driver, self).__init__( - args, error_msg=self.error_msg - ) - self.init = False + DW+explicit_bath driver expects 11 arguments.\n + Example: + i-pi-py_driver.py -m DoubleWell_with_explicit_bath -o wb1 (cm^-1) V1 (cm^-1) wb2 (cm^-1) V2 (cm^-1) coupling(au) mass delta(\AA) eta0 eps1 eps2 deltaQ omega_c(cm^-1) \n + i-pi-py_driver.py -m DoubleWell -o 500,2085,500,2085,0.1,1837,0.00,1,0,0,1,500 + """ - def check_arguments(self): - """Function that checks the arguments required to run the driver""" + def __init__( + self, + wb1=None, + v1=None, + wb2=None, + v2=None, + C=None, + m=None, + delta=None, + eta0=None, + eps1=None, + eps2=None, + deltaQ=None, + w_c=None, + *args, + **kwargs + ): + self.init = False try: - param = list(map(float, self.args)) - assert len(param) == 12 - wb1 = param[0] * invcm2au - v1 = param[1] * invcm2au - wb2 = param[2] * invcm2au - v2 = param[3] * invcm2au - self.C = param[4] - self.m = param[5] - self.delta = param[6] * A2au + wb1 = wb1 * invcm2au + v1 = v1 * invcm2au + wb2 = wb2 * invcm2au + v2 = v2 * invcm2au + self.C = C + self.m = m + self.delta = delta * A2au self.bath_parameters = {} self.bath_parameters["m"] = self.m + self.bath_parameters["eta0"] = eta0 + self.bath_parameters["eps1"] = eps1 + self.bath_parameters["eps2"] = eps2 + self.bath_parameters["deltaQ"] = deltaQ + self.bath_parameters["w_c"] = w_c * invcm2au self.bath_parameters["delta"] = self.delta - self.bath_parameters["eta0"] = param[7] - self.bath_parameters["eps1"] = param[8] - self.bath_parameters["eps2"] = param[9] - self.bath_parameters["deltaQ"] = param[10] - self.bath_parameters["w_c"] = param[11] * invcm2au + # def __init__(self, nbath, m, eta0, eps1, eps2, deltaQ, w_c, *args, **kwargs): except: print("Received arguments:") - sys.exit(self.error_msg) + sys.exit(self.__doc__) self.A1 = -0.5 * self.m * (wb1) ** 2 self.B1 = ((self.m**2) * (wb1) ** 4) / (16 * v1) self.A2 = -0.5 * self.m * (wb2) ** 2 self.B2 = ((self.m**2) * (wb2) ** 4) / (16 * v2) + super().__init__(*args, **kwargs) def __call__(self, cell, pos): """DoubleWell potential""" diff --git a/drivers/py/pes/doublewell.py b/ipi/pes/doublewell.py similarity index 73% rename from drivers/py/pes/doublewell.py rename to ipi/pes/doublewell.py index b75dad204..10987414f 100644 --- a/drivers/py/pes/doublewell.py +++ b/ipi/pes/doublewell.py @@ -28,15 +28,14 @@ class DoubleWell_driver(Dummy_driver): - def __init__(self, args=None, verbose=None): - self.error_msg = """\nDW driver accepts 0 or 4 arguments.\nExample: python driver.py -m DoubleWell -o omega_b (cm^-1) V0 (cm^-1) mass(a.u) delta(angs) \n + """ + DW driver accepts 0 or 4 arguments.\nExample: python driver.py -m DoubleWell -o omega_b (cm^-1) V0 (cm^-1) mass(a.u) delta(angs) \n python driver.py -m DoubleWell -o 500,2085,1837,0.00 \n""" - super(DoubleWell_driver, self).__init__(args, error_msg=self.error_msg) - def check_arguments(self): - """Function that checks the arguments required to run the driver""" - self.k = 1837.36223469 * (3800.0 / 219323.0) ** 2 - if self.args == "": + def __init__(self, w_b=None, v0=None, m=None, delta=None, *args, **kwargs): + + if w_b == None or v0 == None or m == None or delta == None: + print("using default values from Craig-JCP-2005") # We used Craig's values (J. Chem. Phys. 122, 084106, 2005) w_b = 500 * invcm2au # Tc = 115K v0 = 2085 * invcm2au @@ -44,17 +43,16 @@ def check_arguments(self): self.delta = 00 else: try: - param = list(map(float, self.args)) - assert len(param) == 4 - w_b = param[0] * invcm2au - v0 = param[1] * invcm2au - m = param[2] - self.delta = param[3] * A2au + w_b = w_b * invcm2au + v0 = v0 * invcm2au + self.delta = delta * A2au except: - sys.exit(self.error_msg) + sys.exit(self.__doc__) + self.k = 1837.36223469 * (3800.0 / 219323.0) ** 2 self.A = -0.5 * m * (w_b) ** 2 self.B = ((m**2) * (w_b) ** 4) / (16 * v0) + super().__init__(*args, **kwargs) def __call__(self, cell, pos): """DoubleWell potential l""" diff --git a/drivers/py/pes/doublewell_with_bath.py b/ipi/pes/doublewell_with_bath.py similarity index 65% rename from drivers/py/pes/doublewell_with_bath.py rename to ipi/pes/doublewell_with_bath.py index d5b8567f2..a79354f8e 100644 --- a/drivers/py/pes/doublewell_with_bath.py +++ b/ipi/pes/doublewell_with_bath.py @@ -30,50 +30,57 @@ class DoubleWell_with_explicit_bath_driver(Dummy_driver): - """Adds to the double well potential an explicit harmonic bath. First dof correpond to the DW, the rest to the bath discretization + r"""Adds to the double well potential an explicit harmonic bath. First dof correpond to the DW, the rest to the bath discretization ! V(q,x1,..,xn) = DW(q) + ! sum_2^(3*N) [ 0.5 m w_i^2(q - (c_i s(q))/(m w_i)^2)^2 ] ! s(q) = q *sd(q) ! sd(q) = [1+eps1*exp( q^2 / (2 deltaQ^2) ) ] + eps2 tanh(q/deltaQ) ! If eps1=eps2=0 then sd(q) =1 and s(q) = q --->Spatially independent bath - """ - def __init__(self, args=None, verbose=None): - self.error_msg = """\nDW+explicit_bath driver expects 9 arguments.\n + DW+explicit_bath driver expects 9 arguments. Example: python driver.py -m DoubleWell_with_explicit_bath -o omega_b (cm^-1) V0 (cm^-1) mass delta(\AA) eta0 eps1 eps2 deltaQ omega_c(cm^-1) \n - python driver.py -m DoubleWell -o 500,2085,1837,0.00,1,0,0,1,500\n""" - super(DoubleWell_with_explicit_bath_driver, self).__init__( - args, error_msg=self.error_msg - ) + python driver.py -m DoubleWell -o 500,2085,1837,0.00,1,0,0,1,500 + """ - self.init = False + def __init__( + self, + w_b=None, + v0=None, + m=None, + delta=None, + eta0=None, + eps1=None, + eps2=None, + deltaQ=None, + w_c=None, + *args, + **kwargs + ): - def check_arguments(self): - """Function that checks the arguments required to run the driver""" + self.init = False try: - param = list(map(float, self.args)) - assert len(param) == 9 - w_b = param[0] * invcm2au - v0 = param[1] * invcm2au - self.m = param[2] - self.delta = param[3] * A2au + w_b = w_b * invcm2au + v0 = v0 * invcm2au + self.m = m + self.delta = delta * A2au self.bath_parameters = {} - self.bath_parameters["m"] = param[2] + self.bath_parameters["m"] = self.m - self.bath_parameters["eta0"] = param[4] - self.bath_parameters["eps1"] = param[5] - self.bath_parameters["eps2"] = param[6] - self.bath_parameters["deltaQ"] = param[7] - self.bath_parameters["w_c"] = param[8] * invcm2au + self.bath_parameters["eta0"] = eta0 + self.bath_parameters["eps1"] = eps1 + self.bath_parameters["eps2"] = eps2 + self.bath_parameters["deltaQ"] = deltaQ + self.bath_parameters["w_c"] = w_c * invcm2au except: - sys.exit(self.error_msg) + sys.exit(self.__doc__) self.A = -0.5 * self.m * (w_b) ** 2 self.B = ((self.m**2) * (w_b) ** 4) / (16 * v0) + super().__init__(*args, **kwargs) def __call__(self, cell, pos): """DoubleWell potential""" @@ -85,7 +92,7 @@ def __call__(self, cell, pos): if not self.init: self.nbath = np.size(x) - self.bath = Harmonic_Bath_explicit(self.nbath, self.bath_parameters) + self.bath = Harmonic_Bath_explicit(self.nbath, **self.bath_parameters) # Harmonic bath pot, fq, fx = self.bath(q, x) diff --git a/drivers/py/pes/doublewell_with_friction.py b/ipi/pes/doublewell_with_friction.py similarity index 71% rename from drivers/py/pes/doublewell_with_friction.py rename to ipi/pes/doublewell_with_friction.py index dfacdb7b8..d456cfb43 100644 --- a/drivers/py/pes/doublewell_with_friction.py +++ b/ipi/pes/doublewell_with_friction.py @@ -1,7 +1,5 @@ """ Harmonic potential """ -import sys - try: from .doublewell import DoubleWell_driver except: @@ -10,6 +8,7 @@ import numpy as np from ipi.utils import units import json +import sys __DRIVER_NAME__ = "DW_friction" @@ -29,42 +28,48 @@ class DoubleWell_with_friction_driver(DoubleWell_driver): - """Adds to the double well potential the calculation of the friction tensor. + r"""Adds to the double well potential the calculation of the friction tensor. friction(q) = eta0 [\partial sd(q) \partial q ]^2 with q = position, and sd(q) = [1+eps1 exp( (q-0)^2 / (2deltaQ^2) ) ] + eps2 tanh(q/deltaQ) - """ - def __init__(self, args=None, verbose=None): - self.error_msg = """\nDW+fric driver expects 8 arguments.\n - Example: python driver.py -m DoubleWell_with_fric -o omega_b (cm^-1) V0 (cm^-1) mass delta(\AA) eta0 eps1 eps2 deltaQ \n - python driver.py -m DoubleWell -o 500,2085,1837,0.00,1,0,0,1\n""" - self.args = args.split(",") - self.verbose = verbose - self.check_arguments() + DW+fric driver expects 8 arguments. + Example: python driver.py -m DoubleWell_with_fric -o omega_b (cm^-1) V0 (cm^-1) mass delta(\AA) eta0 eps1 eps2 deltaQ + python driver.py -m DoubleWell -o 500,2085,1837,0.00,1,0,0,1 + """ - def check_arguments(self): - """Function that checks the arguments required to run the driver""" + def __init__( + self, + w_b=None, + v0=None, + m=None, + eta0=None, + eps1=None, + eps2=None, + delta=None, + deltaQ=None, + *args, + **kwargs + ): - self.k = 1837.36223469 * (3800.0 / 219323.0) ** 2 try: - param = list(map(float, self.args)) - assert len(param) == 8 - w_b = param[0] * invcm2au - v0 = param[1] * invcm2au - m = param[2] - self.delta = param[3] * A2au - self.eta0 = param[4] - self.eps1 = param[5] - self.eps2 = param[6] - self.deltaQ = param[7] + w_b = w_b * invcm2au + v0 = v0 * invcm2au + self.delta = delta * A2au + self.eta0 = eta0 + self.eps1 = eps1 + self.eps2 = eps2 + self.deltaQ = deltaQ + self.k = 1837.36223469 * (3800.0 / 219323.0) ** 2 + self.A = -0.5 * m * (w_b) ** 2 + self.B = ((m**2) * (w_b) ** 4) / (16 * v0) + except: - sys.exit(self.error_msg) + sys.exit(self.__doc__) - self.A = -0.5 * m * (w_b) ** 2 - self.B = ((m**2) * (w_b) ** 4) / (16 * v0) + super().__init__(*args, **kwargs) def check_dimensions(self, pos): """Functions that checks dimensions of the received position""" diff --git a/drivers/py/pes/driverdipole.py b/ipi/pes/driverdipole.py similarity index 95% rename from drivers/py/pes/driverdipole.py rename to ipi/pes/driverdipole.py index be0929042..2a87b9242 100644 --- a/drivers/py/pes/driverdipole.py +++ b/ipi/pes/driverdipole.py @@ -4,6 +4,9 @@ import json import numpy as np import warnings + +from ipi.utils.messages import verbosity, warning + import importlib from .dummy import Dummy_driver @@ -118,6 +121,9 @@ def get_model(instructions, parameters: str): class driverdipole_driver(Dummy_driver): + """The parameters of 'driverdipole_driver' are not correctly formatted. \ + They should be two or three strings, separated by a comma.""" + opts_default = { "dipole": { "send": True, # whether to send the dipole to i-PI @@ -131,19 +137,21 @@ class driverdipole_driver(Dummy_driver): "restart": False, # whether remove the files (if already existing) where the dipole and BEC will be saved. } - def __init__(self, args=None): - self.error_msg = """The parameters of 'driverdipole_driver' are not correctly formatted. \ - They should be two or three strings, separated by a comma.""" + def __init__(self, *args, **kwargs): + warning( + "THIS PES HAS NOT BEEN TESTED FOLLOWING CONVERSION TO THE NEW PES API.", + verbosity.low, + ) self.opts = dict() self.count = 0 - super().__init__(args) + super().__init__(*args, **kwargs) - def check_arguments(self): + def check_parameters(self): """Check the arguments required to run the driver.""" try: - arglist = self.args.split(",") + arglist = self.args except ValueError: - sys.exit(self.error_msg) + sys.exit(self.__doc__) if len(arglist) >= 2: info_file = arglist[0] # json file to properly allocate a 'model' object @@ -154,7 +162,7 @@ def check_arguments(self): print("\tNo options file provided: using the default values") opts_file = None else: - sys.exit(self.error_msg) # to be modified + sys.exit(self._error_msg) # to be modified print("\n\tThe driver is 'driverdipole_driver'") print("\tLoading model ...") diff --git a/drivers/py/pes/dummy.py b/ipi/pes/dummy.py similarity index 71% rename from drivers/py/pes/dummy.py rename to ipi/pes/dummy.py index 457c624a3..83430a93c 100644 --- a/drivers/py/pes/dummy.py +++ b/ipi/pes/dummy.py @@ -6,18 +6,23 @@ class Dummy_driver(object): - """Base class providing the structure of a PES for the python driver.""" + """Base class providing the structure of a PES for the python driver. - def __init__( - self, args="", verbose=False, error_msg="Invalid arguments for the PES" - ): + Command line: + i-pi-py_driver -m dummy [...] + Init arguments: + :param verbose: bool to determine whether the PES should output verbose info. + """ + + def __init__(self, verbose=False, *args, **kwargs): """Initialized dummy drivers""" - self.error_msg = error_msg - self.args = args.split(",") self.verbose = verbose - self.check_arguments() + self.args = args + self.kwargs = kwargs + + self.check_parameters() - def check_arguments(self): + def check_parameters(self): """Dummy function that checks the arguments required to run the driver""" pass diff --git a/drivers/py/pes/elphmod.py b/ipi/pes/elphmod.py similarity index 55% rename from drivers/py/pes/elphmod.py rename to ipi/pes/elphmod.py index efa863131..f4068d1c4 100644 --- a/drivers/py/pes/elphmod.py +++ b/ipi/pes/elphmod.py @@ -3,26 +3,29 @@ import sys from .dummy import Dummy_driver +from ipi.utils.messages import verbosity, warning + __DRIVER_NAME__ = "elphmod" __DRIVER_CLASS__ = "ModelIIIDriver" -ERROR_MSG = """ -A pickled driver instance is required (see elphmod.md.Driver.save). - -Example: python3 driver.py -u -m elphmod -o driver.pickle -""" - class ModelIIIDriver(Dummy_driver): - """Wrapper around elphmod MD driver.""" + """Wrapper around elphmod MD driver. + A pickled driver instance is required (see elphmod.md.Driver.save). - def check_arguments(self): - """Check arguments and load driver instance.""" + Example: python3 driver.py -u -m elphmod -o driver.pickle + """ + def check_parameters(self): + """Check arguments and load driver instance.""" + warning( + "THIS PES HAS NOT BEEN TESTED FOLLOWING CONVERSION TO THE NEW PES API.", + verbosity.low, + ) import elphmod if len(self.args) != 1: - sys.exit(ERROR_MSG) + sys.exit(self.__doc__) self.driver = elphmod.md.Driver.load(self.args[0]) diff --git a/drivers/py/pes/harmonic.py b/ipi/pes/harmonic.py similarity index 60% rename from drivers/py/pes/harmonic.py rename to ipi/pes/harmonic.py index d92f7bac9..df3974815 100644 --- a/drivers/py/pes/harmonic.py +++ b/ipi/pes/harmonic.py @@ -1,33 +1,37 @@ """ Harmonic potential """ -import sys from .dummy import Dummy_driver import numpy as np __DRIVER_NAME__ = "harmonic" __DRIVER_CLASS__ = "Harmonic_driver" -ERROR_MSG = """ -Harmonic driver requires specification of force constant. -Example: python driver.py -m harmonic -u -o 1.3 -""" - class Harmonic_driver(Dummy_driver): - def __init__(self, args=None, verbose=False): - super(Harmonic_driver, self).__init__(args, verbose, error_msg=ERROR_MSG) + """ + Harmonic driver, generating either an isotropic or 3D confining + potential for each atom. + + Command-line: + i-pi-py_driver -m harmonic -u -o 1.3 [...] + i-pi-py_driver -m harmonic -u -o 1.3,2.1,2.3 [...] + + Init parameters: + :param k1: float, spring constant of the oscillator (in a.u.) + :param k2: float, spring constant of the oscillator along y (in a.u.), optional + :param k3: float, spring constant of the oscillator along z (in a.u.), optional + """ - def check_arguments(self): - """Function that checks the arguments required to run the driver""" + def __init__(self, k1, k2=None, k3=None, *args, **kwargs): - if len(self.args) == 1: - self.k = float(self.args[0]) + if k2 == None or k3 == None: + self.k = k1 self.type = "isotropic" - elif len(self.args) == 3: - self.k = np.asarray(list(map(float, self.args))) - self.type = "non-isotropic" else: - sys.exit(self.error_msg) + self.k = np.asarray([k1, k2, k3]) + self.type = "non-isotropic" + + super().__init__(*args, **kwargs) def __call__(self, cell, pos): """Silly harmonic potential""" diff --git a/ipi/pes/mace.py b/ipi/pes/mace.py new file mode 100644 index 000000000..0aea548bb --- /dev/null +++ b/ipi/pes/mace.py @@ -0,0 +1,53 @@ +""" An interface for the [MACE](https://github.com/ACEsuit/mace) calculator """ + +from .ase import ASEDriver + +from ipi.utils.messages import verbosity, warning + +MACECalculator = None + +__DRIVER_NAME__ = "mace" +__DRIVER_CLASS__ = "MACE_driver" + + +class MACE_driver(ASEDriver): + """ + Driver for the MACE MLIPs. + The driver requires specification of a .json model, + and a template file that describes the chemical makeup + of the structure. + + Command-line: + i-pi-py_driver.py -m mace -u -o template=template.xyz,model=model.json + + Parameters: + :param template: string, filename of an ASE-readable structure file + to initialize atomic number and types + :param model: string, filename of the json-formatted model file + """ + + def __init__(self, template, model, device="cpu", *args, **kwargs): + warning( + "THIS PES HAS NOT BEEN TESTED FOLLOWING CONVERSION TO THE NEW PES API.", + verbosity.low, + ) + global MACECalculator + + try: + from mace.calculators import MACECalculator + except: + raise ImportError("Couldn't load mace bindings") + + self.model = model + self.device = device + super().__init__(template, *args, **kwargs) + + def check_parameters(self): + """Check the arguments requuired to run the driver + + This loads the potential and atoms template in MACE + """ + + super().check_parameters() + + self.ase_calculator = MACECalculator(model_paths=self.model, device=self.device) diff --git a/ipi/pes/metatensor.py b/ipi/pes/metatensor.py new file mode 100644 index 000000000..d857c68ad --- /dev/null +++ b/ipi/pes/metatensor.py @@ -0,0 +1,98 @@ +""" +Interface with metatensor +(https://lab-cosmo.github.io/metatensor/latest/atomistic/index.html), that can +be used to perform calculations based on different types of machine learning +potentials +""" + +from ipi.utils.messages import warning + +from .ase import ASEDriver + +MetatensorCalculator = None +mtt = None + +__DRIVER_NAME__ = "metatensor" +__DRIVER_CLASS__ = "MetatensorDriver" + + +class MetatensorDriver(ASEDriver): + """ + Driver for `metatensor` MLIPs + The driver requires specification of a torchscript model, + and a template file that describes the chemical makeup + of the structure. Requires the metatensor-torch library + + Command-line: + i-pi-py_driver -m metatensor -o template=template.xyz,model=model.json [...] + + Parameters: + :param template: string, filename of an ASE-readable structure file + to initialize atomic number and types + :param model: string, filename of the torchscript model file + :param device: string, optional, ["cpu" | "cuda"] + """ + + def __init__( + self, + template, + model, + device="cpu", + extensions="", + check_consistency=False, + *args, + **kwargs, + ): + global MetatensorCalculator, mtt + if MetatensorCalculator is None: + try: + import metatensor.torch as mtt + from metatensor.torch.atomistic.ase_calculator import ( + MetatensorCalculator, + ) + except ImportError as e: + warning(f"Could not find or import metatensor.torch: {e}") + + self.model = model + self.device = device + self.extensions = extensions + self.check_consistency = check_consistency + super().__init__(template, *args, **kwargs) + + def check_parameters(self): + """Check the arguments required to run the driver + + This loads the potential and atoms template in metatensor + """ + + if MetatensorCalculator is None: + raise ImportError("could not import metatensor.torch, is it installed?") + + metatensor_major, metatensor_minor, *_ = mtt.__version__.split(".") + metatensor_major = int(metatensor_major) + metatensor_minor = int(metatensor_minor) + + if metatensor_major != 0 or metatensor_minor < 5: + raise ImportError( + "this code is only compatible with metatensor-torch >= v0.5, " + f"found version v{mtt.__version__} " + f"at '{mtt.__file__}'" + ) + + super().check_parameters() + + self.model_path = self.model + + device = self.device + extensions_directory = self.extensions + check_consistency = self.check_consistency + + self.ase_calculator = MetatensorCalculator( + self.model_path, + device=device, + extensions_directory=extensions_directory, + check_consistency=check_consistency, + ) + + # Show the model metadata to the users + print(self.ase_calculator.metadata()) diff --git a/drivers/py/pes/pet.py b/ipi/pes/pet.py similarity index 53% rename from drivers/py/pes/pet.py rename to ipi/pes/pet.py index f072336e2..7e54c37e3 100644 --- a/drivers/py/pes/pet.py +++ b/ipi/pes/pet.py @@ -1,78 +1,65 @@ """Interface with [PET](https://github.com/serfg/pet) models to run machine learning potentials""" -import sys import numpy as np from .dummy import Dummy_driver from ipi.utils.units import unit_to_internal, unit_to_user from ipi.utils.messages import warning -try: - from pet import SingleStructCalculator as PETCalc - - try: - from ase.io import read - except ImportError: - warning("The PET driver has an ASE dependency") - raise -except ImportError: - warning("Could not find or import the PET module") - PETCalc = None +PETCalc = None +read = None __DRIVER_NAME__ = "pet" __DRIVER_CLASS__ = "PET_driver" class PET_driver(Dummy_driver): - def __init__(self, args=None, verbose=False): - self.error_msg = """ -The PET driver requires (a) a path to the results/experiment_name folder emitted by pet_train - (b) a path to an ase.io.read-able file with a prototype structure - -Other arguments to the pet.SingleStructCalculator class can be optionally -supplied in key=value form after the required arguments. - -Example: python driver.py -m pet -u -o "path/to/results/name,template.xyz,device=cuda" -""" - - super().__init__(args, verbose) - - if PETCalc is None: - raise ImportError("Couldn't load PET bindings") - - def check_arguments(self): + """ + Driver for `PET` MLIPs + The driver requires specification of the folder containing the + outputs from a PET model training, a template file that describes the chemical makeup + of the structure, and optional parameters specific for the PET architecture. + Requires the pet library + + Command-line: + i-pi-py_driver -m pet -o model_path=path_to_results/prefix,template=template.xyz,device=cuda [...] + + Parameters: + :param template: string, filename of an ASE-readable structure file + to initialize atomic number and types + :param model: string, filename of the torchscript model file + :param device: string, optional, ["cpu" | "cuda"] + """ + + def __init__(self, model_path, template, *args, **kwargs): + global PETCalc, read + + try: + from pet import SingleStructCalculator as PETCalc + + try: + from ase.io import read + except ImportError: + warning("The PET driver has an ASE dependency") + raise + except ImportError: + raise ImportError("Could not find or import the PET module") + + self.model_path = model_path + self.template = template + super().__init__(*args, **kwargs) + + def check_parameters(self): """Check the arguments required to run the driver This loads the potential and atoms template in PET """ - args = self.args - - if len(args) >= 2: - self.model_path = args[0] - self.template = args[1] - kwargs = {} - if len(args) > 2: - for arg in args[2:]: - key, value = arg.split("=") - lookup = { - "None": None, - "False": False, - "True": True, - } - - if value in lookup: - value = lookup[value] - - kwargs[key] = value - - else: - sys.exit(self.error_msg) self.template_ase = read(self.template) self.template_ase.arrays["forces"] = np.zeros_like(self.template_ase.positions) self.pet_calc = PETCalc( self.model_path, - **kwargs, + **self.kwargs, ) def __call__(self, cell, pos): diff --git a/drivers/py/pes/rascal.py b/ipi/pes/rascal.py similarity index 56% rename from drivers/py/pes/rascal.py rename to ipi/pes/rascal.py index c7ac7da31..7bef90025 100644 --- a/drivers/py/pes/rascal.py +++ b/ipi/pes/rascal.py @@ -1,45 +1,53 @@ """Interface with librascal to run machine learning potentials""" -import sys from .dummy import Dummy_driver from ipi.utils.mathtools import det_ut3x3 from ipi.utils.units import unit_to_internal, unit_to_user +from ipi.utils.messages import verbosity, warning -try: - from rascal.models.genericmd import GenericMDCalculator as RascalCalc -except: - RascalCalc = None +RascalCalc = None __DRIVER_NAME__ = "rascal" __DRIVER_CLASS__ = "Rascal_driver" -ERROR_MSG = """ -Rascal driver requires specification of a .json model file fitted with librascal, -and a template file that describes the chemical makeup of the structure. -Example: python driver.py -m rascal -u -o model.json,template.xyz -""" - class Rascal_driver(Dummy_driver): - def __init__(self, args=None, verbose=False): - super().__init__(args, verbose, error_msg=ERROR_MSG) + """ + Driver for `librascal` MLIPs + The driver requires specification of the model JSON-formated definition, + and a template file that describes the chemical makeup + of the structure. Requires the librascal library + + Command-line: + i-pi-py_driver -m rascal -o model=model.json,template=template.xyz [...] + + Parameters: + :param template: string, filename of an ASE-readable structure file + to initialize atomic number and types + :param model: string, filename of the torchscript model file + """ - if RascalCalc is None: + def __init__(self, model, template, *args, **kwargs): + global RascalCalc + warning( + "THIS PES HAS NOT BEEN TESTED FOLLOWING CONVERSION TO THE NEW PES API.", + verbosity.low, + ) + try: + from rascal.models.genericmd import GenericMDCalculator as RascalCalc + except: raise ImportError("Couldn't load librascal bindings") + self.model = model + self.template = template - def check_arguments(self): + super().__init__(*args, **kwargs) + + def check_parameters(self): """Check the arguments required to run the driver This loads the potential and atoms template in librascal """ - arglist = self.args - - if len(arglist) == 2: - self.model = arglist[0] - self.template = arglist[1] - else: - sys.exit(self.error_msg) self.rascal_calc = RascalCalc(self.model, True, self.template) diff --git a/ipi/pes/so3lr.py b/ipi/pes/so3lr.py new file mode 100644 index 000000000..c0ee083c5 --- /dev/null +++ b/ipi/pes/so3lr.py @@ -0,0 +1,37 @@ +""" An interface for the [SO3LR](https://github.com/general-molecular-simulations/so3lr) calculator """ + +from .ase import ASEDriver +from ipi.utils.messages import verbosity, warning + +So3lrCalculator = None + +__DRIVER_NAME__ = "so3lr" +__DRIVER_CLASS__ = "SO3LR_driver" + + +class SO3LR_driver(ASEDriver): + """ + SO3LR driver requires a template file that describes the chemical makeup of the structure. + + Optionally, lr_cutoff and dispersion_energy_lr_cutoff_damping can be specified. + + Example: python driver.py -m so3lr -u -o template.xyz,lr_cutoff=12,dispersion_energy_lr_cutoff_damping=2 + """ + + def __init__(self, *args, **kwargs): + warning( + "THIS PES HAS NOT BEEN TESTED FOLLOWING CONVERSION TO THE NEW PES API.", + verbosity.low, + ) + global So3lrCalculator + try: + from so3lr import So3lrCalculator + except: + raise ImportError("Couldn't load so3lr bindings") + + super().__init__(*args, **kwargs) + + def check_parameters(self): + super().check_parameters() + + self.ase_calculator = So3lrCalculator(**self.kwargs) diff --git a/drivers/py/pes/spline.py b/ipi/pes/spline.py similarity index 84% rename from drivers/py/pes/spline.py rename to ipi/pes/spline.py index eb7de4ea4..3adbd0821 100644 --- a/drivers/py/pes/spline.py +++ b/ipi/pes/spline.py @@ -6,6 +6,8 @@ from scipy import interpolate import json +from ipi.utils.messages import verbosity, warning + """Spline driver. This is not a serious interpolation, use it if you know what you are doing. """ factor_coord = 5 mass = 1836 @@ -18,21 +20,27 @@ class Spline_driver(Dummy_driver): - def __init__(self, args=None, verbose=None): - self.error_msg = """\nspline driver requires specification of filename that contains 5 columns (pos, f1,f2,f3,e) to perform 3x1D spline.\nExample: python driver.py -m spline -u -o \n""" - super(Spline_driver, self).__init__(args) + """\nspline driver requires specification of filename that contains 5 columns (pos, f1,f2,f3,e) to perform 3x1D spline.\nExample: python driver.py -m spline -u -o \n""" + + def __init__(self, data_file, *args, **kwargs): + warning( + "THIS PES HAS NOT BEEN TESTED FOLLOWING CONVERSION TO THE NEW PES API.", + verbosity.low, + ) + self.data_file = data_file + super().__init__(*args, **kwargs) self.get_spline() if friction and not SI: self.get_spline_fric() self.k = 1836 * (3800.0 / 219323.0) ** 2 - def check_arguments(self): + def check_parameters(self): """Function that checks the arguments required to run the driver""" try: - data = np.loadtxt(self.args[0]).reshape(-1, 5) + data = np.loadtxt(self.data_file).reshape(-1, 5) except ValueError: - sys.exit(self.error_msg) + sys.exit(self._error_msg) self.data = data def get_spline(self): diff --git a/drivers/py/pes/xtb.py b/ipi/pes/xtb.py similarity index 74% rename from drivers/py/pes/xtb.py rename to ipi/pes/xtb.py index 144a07c67..687c8768b 100644 --- a/drivers/py/pes/xtb.py +++ b/ipi/pes/xtb.py @@ -1,42 +1,40 @@ -""" -Interface with tblite to provide GFN1-xTB and GFN2-xTB calculators. - -Example:: - - python driver.py -m xtb -u -o '{"method": "GFN2-xTB", "numbers": [8,1,1], "periodic": false}' -""" - import numpy as np import json from ipi.utils.units import unit_to_internal, unit_to_user +from ipi.utils.messages import verbosity, warning +from .dummy import Dummy_driver -try: - import tblite.interface as tb -except ImportError: - tb = None - +tb = None __DRIVER_NAME__ = "xtb" __DRIVER_CLASS__ = "TBLiteDriver" -class TBLiteDriver(object): - """Base class providing the structure of a PES for the python driver.""" +class TBLiteDriver(Dummy_driver): + """ + Interface with tblite to provide GFN1-xTB and GFN2-xTB calculators. + + Example:: - def __init__( - self, - args="", - verbose=False, - ): - """Initialized dummy drivers""" + python driver.py -m xtb -u -o config.json + """ - if tb is None: + def __init__(self, json_input, *args, **kwargs): + warning( + "THIS PES HAS NOT BEEN TESTED FOLLOWING CONVERSION TO THE NEW PES API.", + verbosity.low, + ) + config = json.load(open(json_input)) + + global tb + try: + import tblite.interface as tb + except ImportError: raise ModuleNotFoundError( "Could not find tblite for xtb driver. Please install tblite-python with mamba" ) - config = json.loads(args) try: self.method = config["method"] self.numbers = np.asarray(config["numbers"]) @@ -45,7 +43,9 @@ def __init__( self.charge = config.get("charge") self.uhf = config.get("uhf") self.periodic = config.get("periodic") - self.verbosity = 1 if verbose else 0 + self.verbosity = 1 if self.verbose else 0 + + super().__init__(*args, **kwargs) def __call__(self, cell, pos): """ diff --git a/ipi/utils/io/inputs/__init__.py b/ipi/utils/io/inputs/__init__.py index e766bce28..aad0bbbf8 100644 --- a/ipi/utils/io/inputs/__init__.py +++ b/ipi/utils/io/inputs/__init__.py @@ -8,3 +8,37 @@ __all__ = ["io_xml"] + + +def read_value(s): + """Attempt to parse a string to int or float; fallback to string.""" + s = s.strip() + for cast in (int, float): + try: + return cast(s) + except ValueError: + continue + return s + + +def read_args_kwargs(input_str): + """ + Parses a string into positional arguments and keyword arguments. + + Args: + input_str (str): The input string containing comma-separated values and key-value pairs. + + Returns: + tuple: A tuple containing a list of positional arguments and a dictionary of keyword arguments. + """ + args = [] + kwargs = {} + tokens = input_str.split(",") + for token in tokens: + token = token.strip() + if "=" in token: + key, value = token.split("=", 1) + kwargs[key.strip()] = read_value(value) + elif len(token) > 0: + args.append(read_value(token)) + return args, kwargs diff --git a/ipi/utils/io/inputs/io_xml.py b/ipi/utils/io/inputs/io_xml.py index 7ecb2ac68..8fbc0a261 100644 --- a/ipi/utils/io/inputs/io_xml.py +++ b/ipi/utils/io/inputs/io_xml.py @@ -12,6 +12,7 @@ import numpy as np from ipi import ipi_global_settings +from . import read_value __all__ = [ "xml_node", @@ -448,7 +449,7 @@ def mystrip(data): rtuple = list(map(mystrip, s.split(key_split))) if not len(rtuple) == 2: raise ValueError("Format for a key:value format is wrong for item " + s) - rdict[rtuple[0]] = rtuple[1] + rdict[rtuple[0]] = read_value(rtuple[1]) return rdict diff --git a/ipi_tests/README.md b/ipi_tests/README.md index 97b667f3e..152d4a5ac 100644 --- a/ipi_tests/README.md +++ b/ipi_tests/README.md @@ -14,7 +14,10 @@ * To run the unitary, example and regression tests, please use i-pi/bin/i-pi-tests. For details of usage call it with "-h" option. - * In some situations it is desirable to perform regresion/examples tests only for a selected set. + * The tests can be customized to an extent by including a `test_settings.dat` file that specifies how to run the test, + mostly by describing the driver that should be used. See some of the existing files as examples. + + * In some situations it is desirable to perform regression/examples tests only for a selected set. For these cases, we also provide more flexible scripts for performing the regresion tests and testing the provided examples. See i-pi/ipi_tests/regression_tests/test_run.py and i-pi/ipi_tests/examples/test_examples.py, respectively. For details of usage call them with "-h" option. diff --git a/ipi_tests/profiling/classical_md_direct/init.xyz b/ipi_tests/profiling/classical_md_direct/init.xyz new file mode 100644 index 000000000..f2f3870f8 --- /dev/null +++ b/ipi_tests/profiling/classical_md_direct/init.xyz @@ -0,0 +1,10 @@ +8 +# CELL(abcABC): 50.0 50.0 50.0 90.00000 90.00000 90.00000 +H 0 0 0 +H 0 0 1 +H 0 0 2 +H 0 0 3 +H 0 0 4 +H 0 0 5 +H 0 0 6 +H 0 0 7 diff --git a/ipi_tests/profiling/classical_md_direct/input.xml b/ipi_tests/profiling/classical_md_direct/input.xml new file mode 100644 index 000000000..21d038b66 --- /dev/null +++ b/ipi_tests/profiling/classical_md_direct/input.xml @@ -0,0 +1,34 @@ + + + dummy + 1.00000000e-04 + + 10000 + + positions + [ step, time, conserved, temperature, kinetic_md, potential, pressure_md, volume ] + + + 18885 + + + + + + + init.xyz + [10.0, 0, 0, 0, 10.0, 0, 0, 0, 10.0] + [1.0] + 1 + + + 1 + + + False + + 0.01 + + + + diff --git a/ipi_tests/profiling/run_profiling.sh b/ipi_tests/profiling/run_profiling.sh index c475445c0..b8ae0bfb8 100755 --- a/ipi_tests/profiling/run_profiling.sh +++ b/ipi_tests/profiling/run_profiling.sh @@ -1,5 +1,5 @@ #!/bin/bash -# usage: run_profile.sh [-p] natoms [ndriver] +# usage: run_profiling.sh [-p] natoms [ndriver] # run a mock simulation using an natoms box, -p activates yappi profiling # Default value for natoms diff --git a/ipi_tests/regression_tests/tests/INSTANTON/100K_implicit_friction/simulation.instanton_FINAL_15.ener b/ipi_tests/regression_tests/tests/INSTANTON/100K_implicit_friction/simulation.instanton_FINAL_15.ener deleted file mode 100644 index 6a2a6e394..000000000 --- a/ipi_tests/regression_tests/tests/INSTANTON/100K_implicit_friction/simulation.instanton_FINAL_15.ener +++ /dev/null @@ -1,33 +0,0 @@ -#Bead Energy (eV) -0 -0.11866259790715851 -1 -0.11691012681205774 -2 -0.11342166079444242 -3 -0.1082351949410836 -4 -0.10141984639090063 -5 -0.09308898239047224 -6 -0.08341517679588735 -7 -0.0726445585426023 -8 -0.06110741669327686 -9 -0.049221487325502286 -10 -0.03748445701371601 -11 -0.026453159043353814 -12 -0.016708861462551 -13 -0.008810819030011201 -14 -0.0032433701350644724 -15 -0.0003644451312916968 -16 -0.0003644451319317277 -17 -0.0032433701369415356 -18 -0.008810819032999921 -19 -0.016708861466452396 -20 -0.026453159047914718 -21 -0.03748445701864777 -22 -0.04922148733051311 -23 -0.06110741669809458 -24 -0.07264455854700659 -25 -0.0834151767997177 -26 -0.09308898239364362 -27 -0.10141984639339816 -28 -0.10823519494296141 -29 -0.11342166079580748 -30 -0.11691012681305872 -31 -0.11866259790797011 diff --git a/ipi_tests/regression_tests/tests/INSTANTON/100K_implicit_friction/test_settings.dat b/ipi_tests/regression_tests/tests/INSTANTON/100K_implicit_friction/test_settings.dat index 42ec12ec1..0d6ab5051 100644 --- a/ipi_tests/regression_tests/tests/INSTANTON/100K_implicit_friction/test_settings.dat +++ b/ipi_tests/regression_tests/tests/INSTANTON/100K_implicit_friction/test_settings.dat @@ -1,6 +1,6 @@ driver_model DW_friction driver_code python -flags -o 500,2085,1837.36223469,0,1.5,-1.0,0,1 +flags -o 'w_b=500,v0=2085,m=1837.36223469,delta=0,eta0=1.5,eps1=-1.0,eps2=0,deltaQ=1' address localhost port 33335 socket_mode unix diff --git a/setup.py b/setup.py index bf8364962..e865e9c79 100644 --- a/setup.py +++ b/setup.py @@ -6,13 +6,6 @@ scripts = [str(p) for p in Path("bin").iterdir() if p.name != "i-pi-driver"] setup( - packages=[ - *find_packages(exclude=["ipi_tests*"]), - "ipi._driver", - "ipi._driver.pes", - ], - package_dir={ - "ipi._driver": "drivers/py", - }, + packages=[*find_packages(exclude=["ipi_tests*"])], scripts=scripts, )