M3GNet Custom Model
*******************

MLPotential ParAMS M3GNet Geometry Optimization

Use a custom M3GNet model directory (for example, one you may have
created using ParAMS or Simple Active Learning) in AMS via PLAMS. The
example shows a lattice optimization of bulk Ruthenium.

**Requires:** AMS2026 or later

**Required AMS Packages:** m3gnet

-[ Related examples ]-

* M3GNet Universal Potential: M3GNet-UP-2022

* Benchmarking ML Potentials for Hydrocarbon Isomerization Energies

* NEB for Li diffusion in layered LiTiS2 (M3GNet)

-[ Related tutorials ]-

* M3GNet cohesive energy tutorial

* Simple Active Learning tutorial

-[ Related documentation ]-

* MLPotential engine

* Lattice optimization

[image]


Custom M3GNet model example (bulk Ru)
=====================================

Use a custom M3GNet model (trained by ParAMS or Simple Active
Learning) by pointing to a parameter directory. The example below uses
the RuH parameters for bulk Ru (hexagonal system).

   from ase.build import bulk
   from scm.base import ChemicalSystem
   from scm.plams import view

   ru = ChemicalSystem.from_ase_atoms(bulk("Ru", a=2.7, c=4.28))
   print("Lattice angles: ", ru.lattice.get_angles(unit="degree"))
   view(ru, direction="tilt_x", height=150, width=150)

   Lattice angles:  [ 90.  90. 120.]

[image]

   from scm.plams import Settings, AMSJob

   s2 = Settings()
   s2.runscript.nproc = 1
   s2.input.ams.Task = "GeometryOptimization"
   s2.input.ams.GeometryOptimization.OptimizeLattice = "Yes"
   s2.input.ams.GeometryOptimization.Convergence.Quality = "Basic"
   s2.input.MLPotential.Model = "Custom"
   s2.input.MLPotential.Backend = "m3gnet"
   # ams can handle environment variables when parsing the input - no need to expand it here
   s2.input.MLPotential.ParameterDir = "$AMSHOME/atomicdata/MLPotential/M3GNet/RuH"

   job2 = AMSJob(settings=s2, molecule=ru, name="m3gnet_custom_ru")
   job2.run()

   energy2 = job2.results.get_energy(unit="eV")
   print(f"Custom M3GNet (RuH params): final energy {energy2:.3f} eV")

   [10.02|08:31:56] JOB m3gnet_custom_ru STARTED
   [10.02|08:31:56] JOB m3gnet_custom_ru RUNNING
   [10.02|08:32:06] JOB m3gnet_custom_ru FINISHED
   [10.02|08:32:06] JOB m3gnet_custom_ru SUCCESSFUL
   Custom M3GNet (RuH params): final energy -5131.675 eV

   optimized_ru = job2.results.get_main_system()
   density = optimized_ru.density(unit="g/cm3")
   print(f"{density=:.2f} g/cm3")

   density=12.49 g/cm3

A lattice optimization may introduce a small amount of noise in the
lattice:

   print(optimized_ru.lattice.get_angles(unit="degree"))

   [ 89.99999993  89.99999998 119.99999996]

For symmetric systems it’s a good idea to symmetrize the cell after a
lattice optimization:

   optimized_ru.symmetrize_cell()
   print(optimized_ru.lattice.get_angles(unit="degree"))

   [ 90.  90. 120.]


See also
========


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

* M3GNet Universal Potential: M3GNet-UP-2022

* Benchmarking ML Potentials for Hydrocarbon Isomerization Energies

* NEB for Li diffusion in layered LiTiS2 (M3GNet)


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

* M3GNet cohesive energy tutorial

* Simple Active Learning tutorial


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

* MLPotential engine

* Lattice optimization


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

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

   # ## Custom M3GNet model example (bulk Ru)
   # Use a custom M3GNet model (trained by ParAMS or Simple Active Learning) by pointing to a parameter directory. The example below uses the RuH parameters for bulk Ru (hexagonal system).

   from ase.build import bulk
   from scm.base import ChemicalSystem
   from scm.plams import view

   ru = ChemicalSystem.from_ase_atoms(bulk("Ru", a=2.7, c=4.28))
   print("Lattice angles: ", ru.lattice.get_angles(unit="degree"))
   view(ru, direction="tilt_x", height=150, width=150, picture_path="picture1.png")


   from scm.plams import Settings, AMSJob

   s2 = Settings()
   s2.runscript.nproc = 1
   s2.input.ams.Task = "GeometryOptimization"
   s2.input.ams.GeometryOptimization.OptimizeLattice = "Yes"
   s2.input.ams.GeometryOptimization.Convergence.Quality = "Basic"
   s2.input.MLPotential.Model = "Custom"
   s2.input.MLPotential.Backend = "m3gnet"
   # ams can handle environment variables when parsing the input - no need to expand it here
   s2.input.MLPotential.ParameterDir = "$AMSHOME/atomicdata/MLPotential/M3GNet/RuH"

   job2 = AMSJob(settings=s2, molecule=ru, name="m3gnet_custom_ru")
   job2.run()

   energy2 = job2.results.get_energy(unit="eV")
   print(f"Custom M3GNet (RuH params): final energy {energy2:.3f} eV")


   optimized_ru = job2.results.get_main_system()
   density = optimized_ru.density(unit="g/cm3")
   print(f"{density=:.2f} g/cm3")


   # A lattice optimization may introduce a small amount of noise in the lattice:

   print(optimized_ru.lattice.get_angles(unit="degree"))


   # For symmetric systems it's a good idea to symmetrize the cell after a lattice optimization:

   optimized_ru.symmetrize_cell()
   print(optimized_ru.lattice.get_angles(unit="degree"))
