Active Learning: Ru/H Part 3, Gas Snapshots
*******************************************

MLPotential Active Learning ParAMS M3GNet Surface Chemistry Molecular
Dynamics

Continue the Ru/H workflow by generating gas-phase and interface
snapshots, replaying them with the reference method, and adding the
results to the training data. Run parts 1 and 2 first.

**Additional files required by this example:** "common_ru_h.py"

**Requires:** AMS2026 or later

**Required AMS Packages:** m3gnet

-[ Related examples ]-

* Active Learning: Ru/H Part 1, Initial Reference Scans

* Active Learning: Ru/H Part 2, Surface PES Scans

* Active Learning: Ru/H Part 4, Initial Training

* Import ParAMS Training Data with ResultsImporter

-[ Related tutorials ]-

* Simple Active Learning tutorial

-[ Related documentation ]-

* Molecular Dynamics task

* MLPotential engine

* ResultsImporter overview

[image]


Initial imports
===============

   import scm.plams as plams
   from scm.params import ResultsImporter
   from scm.plams import Settings, AMSJob, log, Molecule, packmol_on_slab
   from pathlib import Path
   import matplotlib.pyplot as plt

   # common_ru_h.py must exist in the current working directory
   from common_ru_h import (
       rotation,
       dft_settings,
       QEKPointsConfig,
       m3gnet_up_settings,
       replay_settings,
       slice_slab,
       check_installation,
   )

   # register dependencies for AMSjobs, to support submitting this notebook directly to a cluster in AMS2025+
   # dependency: {}  common_ru_h.py
   # dependency: {}  reference_data_2


Initialize PLAMS working directory
==================================

   old_ref_dir = "reference_data_2"
   check_installation(old_ref_dir)
   new_ref_dir = "reference_data_3"
   ri = ResultsImporter.from_yaml(old_ref_dir)
   plams.init()

   Current AMS version: 2024.102
   05-31 14:23:05 m3gnet is installed: M3GNet ML Backend v[0.2.4] - build:0 [06668e0a45ce742d8f66ff23484b8a1e]
   05-31 14:23:06 qe is installed: Quantum ESPRESSO (AMSPIPE) v[7.1] - build:115 [777d72eb480fe4d632a003cc62e9c1cb]
   PLAMS working folder: /path/to/plams_workdir.003


Construct the Ru(10-10)/H2(gas) interface
=========================================

For details about the construction of the slab, see the previous
notebook.

   optimized_bulk = ri.job_collection["hcp_lattopt_Ru_dft"].molecule
   slab_100 = slice_slab(
       optimized_bulk, miller=(1, 0, 0), thickness=7.0, cell_z=15, ref_atom=0
   )
   slab_100 = slab_100.supercell(3, 2, 1)
   for at in slab_100:
       at.properties = Settings()  # remove details about supercell generation
   plams.plot_molecule(slab_100, rotation=rotation)
   plt.title("Ru(10-10)");

   [image: image generated from notebook][image]

Now use the "packmol_slab" function to add hydrogen molecules:

   from scm.plams import packmol_on_slab

   h2_mol = plams.from_smiles("[HH]")
   density = 0.3  # approximate density of the gas phase in g/cm^3
   slab_100_H2_gas_raw = packmol_on_slab(slab_100, h2_mol, density=density)
   slab_100_H2_gas = plams.preoptimize(
       slab_100_H2_gas_raw, settings=m3gnet_up_settings(), maxiterations=100
   )

   plams.plot_molecule(slab_100_H2_gas, rotation=rotation, radii=0.8)

   [image: image generated from notebook][image]

Now let’s run some MD:

   mdjob = plams.AMSNVTJob(
       settings=m3gnet_up_settings(),
       name="md_ru10-10_h2_m3gnet",
       temperature=501,
       nsteps=10000,
       molecule=slab_100_H2_gas,
       samplingfreq=100,
   )
   mdjob.run();

   [31.05|14:23:35] JOB md_ru10-10_h2_m3gnet STARTED
   [31.05|14:23:35] JOB md_ru10-10_h2_m3gnet RUNNING
   [31.05|15:08:27] JOB md_ru10-10_h2_m3gnet FINISHED
   [31.05|15:08:28] JOB md_ru10-10_h2_m3gnet SUCCESSFUL

   from scm.params import ResultsImporter

   ri = ResultsImporter.from_yaml(old_ref_dir)

   settings = dft_settings(QEKPointsConfig(3, 3, 1))
   settings += replay_settings(mdjob.results.rkfpath(), frames=[10, 30, 50, 70, 90])

   dft_replay_job = plams.AMSJob(
       settings=settings,
       name="snapshots_from_md_ru10-10_h2_dft",
   )
   dft_replay_job.run(watch=True)

   [31.05|15:08:28] JOB snapshots_from_md_ru10-10_h2_dft STARTED
   [31.05|15:08:28] JOB snapshots_from_md_ru10-10_h2_dft RUNNING
   [31.05|15:08:29] snapshots_from_md_ru10-10_h2_dft: AMS 2024.102  RunTime: May31-2024 15:08:29  ShM Nodes: 1  Procs: 1
   [31.05|15:08:29] snapshots_from_md_ru10-10_h2_dft: Starting trajectory replay ...
   [31.05|15:08:29] snapshots_from_md_ru10-10_h2_dft: Replaying frame #1/5 (#10 in original trajectory)
   ... output trimmed ....
   [31.05|15:45:36] snapshots_from_md_ru10-10_h2_dft: Trajectory replay complete.
   [31.05|15:46:36] snapshots_from_md_ru10-10_h2_dft: Number of QE evaluations: 5
   [31.05|15:46:36] snapshots_from_md_ru10-10_h2_dft: NORMAL TERMINATION
   [31.05|15:46:36] JOB snapshots_from_md_ru10-10_h2_dft FINISHED
   [31.05|15:46:36] JOB snapshots_from_md_ru10-10_h2_dft SUCCESSFUL





   <scm.plams.interfaces.adfsuite.ams.AMSResults at 0x14c005cbf7c0>

   ri.add_trajectory_singlepoints(dft_replay_job, properties=["energy", "forces"])
   ri.store(new_ref_dir)

   ['reference_data_3/job_collection.yaml',
    'reference_data_3/results_importer_settings.yaml',
    'reference_data_3/training_set.yaml']


See also
========


Related examples
----------------

* Active Learning: Ru/H Part 1, Initial Reference Scans

* Active Learning: Ru/H Part 2, Surface PES Scans

* Active Learning: Ru/H Part 4, Initial Training

* Import ParAMS Training Data with ResultsImporter


Related tutorials
-----------------

* Simple Active Learning tutorial


Related documentation
---------------------

* Molecular Dynamics task

* MLPotential engine

* ResultsImporter overview


Python Script
=============

   #!/usr/bin/env python
   # coding: utf-8

   # ## Initial imports

   import scm.plams as plams
   from scm.params import ResultsImporter
   from scm.plams import Settings, AMSJob, log, Molecule, packmol_on_slab
   from pathlib import Path
   import matplotlib.pyplot as plt

   # common_ru_h.py must exist in the current working directory
   from common_ru_h import (
       rotation,
       dft_settings,
       QEKPointsConfig,
       m3gnet_up_settings,
       replay_settings,
       slice_slab,
       check_installation,
   )

   # register dependencies for AMSjobs, to support submitting this notebook directly to a cluster in AMS2025+
   # dependency: {}  common_ru_h.py
   # dependency: {}  reference_data_2


   # ## Initialize PLAMS working directory

   old_ref_dir = "reference_data_2"
   check_installation(old_ref_dir)
   new_ref_dir = "reference_data_3"
   ri = ResultsImporter.from_yaml(old_ref_dir)
   plams.init()


   # ## Construct the Ru(10-10)/H2(gas) interface
   #
   # For details about the construction of the slab, see the previous notebook.

   optimized_bulk = ri.job_collection["hcp_lattopt_Ru_dft"].molecule
   slab_100 = slice_slab(optimized_bulk, miller=(1, 0, 0), thickness=7.0, cell_z=15, ref_atom=0)
   slab_100 = slab_100.supercell(3, 2, 1)
   for at in slab_100:
       at.properties = Settings()  # remove details about supercell generation
   plams.plot_molecule(slab_100, rotation=rotation)
   plt.title("Ru(10-10)")
   plt.gcf().savefig("picture1.png")
   plt.clf()


   # Now use the ``packmol_slab`` function to add hydrogen molecules:

   from scm.plams import packmol_on_slab

   h2_mol = plams.from_smiles("[HH]")
   density = 0.3  # approximate density of the gas phase in g/cm^3
   slab_100_H2_gas_raw = packmol_on_slab(slab_100, h2_mol, density=density)
   slab_100_H2_gas = plams.preoptimize(slab_100_H2_gas_raw, settings=m3gnet_up_settings(), maxiterations=100)


   plams.plot_molecule(slab_100_H2_gas, rotation=rotation, radii=0.8)


   # Now let's run some MD:

   mdjob = plams.AMSNVTJob(
       settings=m3gnet_up_settings(),
       name="md_ru10-10_h2_m3gnet",
       temperature=501,
       nsteps=10000,
       molecule=slab_100_H2_gas,
       samplingfreq=100,
   )
   mdjob.run()
   from scm.params import ResultsImporter

   ri = ResultsImporter.from_yaml(old_ref_dir)


   settings = dft_settings(QEKPointsConfig(3, 3, 1))
   settings += replay_settings(mdjob.results.rkfpath(), frames=[10, 30, 50, 70, 90])

   dft_replay_job = plams.AMSJob(
       settings=settings,
       name="snapshots_from_md_ru10-10_h2_dft",
   )
   dft_replay_job.run(watch=True)


   ri.add_trajectory_singlepoints(dft_replay_job, properties=["energy", "forces"])
   ri.store(new_ref_dir)
