#!/usr/bin/env amspython # coding: utf-8 # Lets see how two alanine molecules orient themselves using CREST conformer generation. # To do this we will constrain the system in a spherical region using the `SphericalWall` constraint. # We start by setting up a system of two alanine molecules in a relatively small space. # ## Initial imports import scm.plams as plams import sys from scm.conformers import ConformersJob from scm.conformers.plams.plot import plot_conformers import numpy as np import matplotlib.pyplot as plt import os # this line is not required in AMS2025+ plams.init() # ## Single alanine molecule smiles = "CC(N)C(=O)O" alanine = plams.from_smiles(smiles) plams.plot_molecule(alanine) # ## Initial system: alanine dimer # Pack two alanine molecules in a sphere with a density of 0.5 kg/L. density = 0.5 mol = plams.packmol(alanine, n_molecules=2, density=density, sphere=True) # Translate the molecule to be centered around the origin (needed for SphericalWall later): mol.translate(-np.array(mol.get_center_of_mass())) plams.plot_molecule(mol, rotation="0x,0y,90z") # ## Calculation setup # To determine the radius of the `SphericalWall` we measure the size of the initial dimer. dists = plams.distance_array(mol, mol) max_dist = np.max(dists) diameter = 1.33 * max_dist radius = diameter / 2 print(f"Largest distance between atoms: {max_dist:.3f} ang.") print(f"Radius: {radius:.3f} ang.") # Now we can set up the Crest conformer generation job, with the appropriate spherical wall constraining the molecules close together. settings = plams.Settings() settings.input.ams.EngineAddons.WallPotential.Enabled = "Yes" settings.input.ams.EngineAddons.WallPotential.Radius = radius settings.input.ams.Generator.Method = "CREST" settings.input.ams.Output.KeepWorkDir = "Yes" settings.input.ams.GeometryOptimization.MaxConvergenceTime = "High" settings.input.ams.Generator.CREST.NCycles = 3 # at most 3 CREST cycles for this demo settings.input.GFNFF = plams.Settings() # ## Run the conformers job # Now we can run the conformer generation job. job = ConformersJob(molecule=mol, settings=settings) job.run() # ConformersJob.load_external("plams_workdir/conformers/conformers.rkf") # load from disk instead of running the job rkf = job.results.rkfpath() print(f"Conformers stored in {rkf}") # This job will run for approximately 15 minutes. # ## Results # Here we plot the three lowest-energy conformers. plot_conformers(job) # You can also open the conformers in AMSmovie to browse all conformers 1000+ conformers: # Finally in AMS2025+, you can also inspect the conformer data using the JobAnalysis tool. try: from scm.plams import JobAnalysis ja = ( JobAnalysis(standard_fields=None) .add_job(job) .add_field( "Id", lambda j: list(range(1, len(j.results.get_conformers()) + 1)), display_name="Conformer Id", expansion_depth=1, ) .add_field( "Energies", lambda j: j.results.get_relative_energies("kcal/mol"), display_name="E", expansion_depth=1, fmt=".2f", ) .add_field( "Populations", lambda j: j.results.get_boltzmann_distribution(298), display_name="P", expansion_depth=1, fmt=".3f", ) ) # Pretty-print if running in a notebook if "ipykernel" in sys.modules: ja.display_table(max_rows=20) else: print(ja.to_table()) except ImportError: pass