Example 4: Example of atom-type symmetry-constrained parametrization using aspirin

../../_images/aspirin.png

In this example we will parametrize aspirin while constraining the optimization of the parameters to the atom-type symmetries defined by AMBER. In the parametrization we will use a data set of conformations (and respective eneriges and forces) obtained using a Born-Oppenheimer MD at the DFTB level of theory (including D3 dispersion correction).

Serial Version

# ParaMol imports
from ParaMol.Utils.settings import *
from ParaMol.System.system import *
from ParaMol.MM_engines.openmm import *
from ParaMol.QM_engines.qm_engine import *
from ParaMol.Tasks.parametrization import *
from ParaMol.Utils.Symmetrizers.amber_symmetrizer import *

# --------------------------------------------------------- #
#                         Preparation                       #
# --------------------------------------------------------- #
# Create the OpenMM engine for aspirin
openmm_system = OpenMMEngine(init_openmm=True, topology_format='AMBER', top_file='aspirin.prmtop', crd_format='AMBER', crd_file='aspirin.inpcrd')

# Create ParaMol System
aspirin = ParaMolSystem(name="aspirin", engine=openmm_system, n_atoms=21)

# Create ParaMol's force field representation and ask to parametrize bonds, angles and torsions
aspirin.force_field.create_force_field(opt_bonds=True, opt_angles=True, opt_torsions=True)

# Create ParaMol settings instance
paramol_settings = Settings()

# The objective function will contain a energy, force and regularization term
paramol_settings.properties["include_energies"] = True
paramol_settings.properties["include_forces"] = True
paramol_settings.properties["include_regularization"] = True

# Read conformations, energies and forces from NETCDF ParaMol file format
aspirin.read_data("aspirin_reference_data.nc")
# --------------------------------------------------------- #
#                Symmetrize ParaMol ForceField              #
# --------------------------------------------------------- #
# Symmetry ParaMol ForceField so that it respects atom-type symmetries
amber_symmetrizer = AmberSymmetrizer(top_file="aspirin.prmtop")
amber_symmetrizer.get_symmetries(aspirin.force_field)
amber_symmetrizer.symmetrize_force_field(aspirin.force_field)

# Write symmetrized Force-Field to file
aspirin.force_field.write_ff_file("aspirin_sym.ff")
# --------------------------------------------------------- #
#                       Parametrization                     #
# --------------------------------------------------------- #
parametrization = Parametrization()
systems, parameter_space, objective_function, optimizer = parametrization.run_task(paramol_settings, [aspirin])

# Write ParaMol Force Field file with final parameters
aspirin.force_field.write_ff_file("aspirin_symm_opt.ff")

# Update AMBER symmetrizer with new parameters
amber_symmetrizer.update_term_types_parameters(parameter_space.optimizable_parameters)

# Write AMBER topology file (.prmtop)
amber_symmetrizer.save("aspirin_opt.prmtop")
amber_symmetrizer.save_frcmod("aspirin_opt.frcmod")


Parallel version

It is also possible to parallelize the calculation of the objective function using, for example, 4 cpus. In order to do this, the following changes have to be made:

# ParaMol imports
from ParaMol.Utils.settings import *
from ParaMol.System.system import *
from ParaMol.MM_engines.openmm import *
from ParaMol.QM_engines.qm_engine import *
from ParaMol.Tasks.parametrization import *
from ParaMol.Utils.Symmetrizers.amber_symmetrizer import *

# --------------------------------------------------------- #
#                         Preparation                       #
# --------------------------------------------------------- #
# Create the OpenMM engine for aspirin
openmm_system = OpenMMEngine(init_openmm=True, topology_format='AMBER', top_file='aspirin.prmtop', crd_format='AMBER', crd_file='aspirin.inpcrd')

# Create ParaMol System
# Note that number of cpus was set to 4
aspirin = ParaMolSystem(name="aspirin", engine=openmm_system, n_atoms=21, n_cpus=4)

# Create ParaMol's force field representation and ask to parametrize bonds, angles and torsions
aspirin.force_field.create_force_field(opt_bonds=True, opt_angles=True, opt_torsions=True)

# Create ParaMol settings instance
paramol_settings = Settings()

# The objective function will contain a energy, force and regularization term
paramol_settings.properties["include_energies"] = True
paramol_settings.properties["include_forces"] = True
paramol_settings.properties["include_regularization"] = True

# Set the objective function to be calculated in parallel
paramol_settings.objective_function["parallel"] = True

# Read conformations, energies and forces from NETCDF ParaMol file format
aspirin.read_data("aspirin_reference_data.nc")
# --------------------------------------------------------- #
#                Symmetrize ParaMol ForceField              #
# --------------------------------------------------------- #
# Symmetry ParaMol ForceField so that it respects atom-type symmetries
amber_symmetrizer = AmberSymmetrizer(top_file="aspirin.prmtop")
amber_symmetrizer.get_symmetries(aspirin.force_field)
amber_symmetrizer.symmetrize_force_field(aspirin.force_field)

# Write symmetrized Force-Field to file
aspirin.force_field.write_ff_file("aspirin_sym.ff")
# --------------------------------------------------------- #
#                       Parametrization                     #
# --------------------------------------------------------- #
parametrization = Parametrization()
systems, parameter_space, objective_function, optimizer = parametrization.run_task(paramol_settings, [aspirin])

# Write ParaMol Force Field file with final parameters
aspirin.force_field.write_ff_file("aspirin_symm_opt.ff")

# Update AMBER symmetrizer with new parameters
amber_symmetrizer.update_term_types_parameters(parameter_space.optimizable_parameters)

# Write AMBER topology file (.prmtop)
amber_symmetrizer.save("aspirin_opt.prmtop")
amber_symmetrizer.save_frcmod("aspirin_opt.frcmod")