Source code for tcutility.job.nmr

import os
from typing import Tuple

from tcutility.job.adf import ADFJob
from tcutility.job.generic import Job

j = os.path.join


[docs] class NMRJob(Job): """ A job that handles calculation of Nuclear Magnetic Resonance (NMR) chemical shifts. The job will first run an :class:`tcutility.job.adf.ADFJob` calculation at the SAOP/TZ2P level of theory to prepare for the NMR program of AMS. The NMR shifts will be calculated for all atoms and any additional coordinate (NICS). New NICS points can be given using the :meth:`NMRJob.add_nics_point` method. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.pre_nmr_job = ADFJob(*args, **kwargs) self.pre_nmr_job.functional("SAOP") self.pre_nmr_job.basis_set("TZ2P") self.pre_nmr_job.settings.input.adf.save = "TAPE10" self.nics_points = [] def _setup_job(self): os.makedirs(self.workdir, exist_ok=True) # set up the pre_nmr_job self.pre_nmr_job.rundir = self.rundir self.pre_nmr_job.name = self.name + "_pre" self.pre_nmr_job.molecule(self._molecule or self._molecule_path) self.pre_nmr_job.sbatch(**self._sbatch) # we have to add the NICS points in the pre_nmr_job multipole_coords = [] for point in self.nics_points: multipole_coords.append(f" {point[0]} {point[1]} {point[2]} 0.0") self.pre_nmr_job.settings.input.ams.System.ElectrostaticEmbedding.MultipolePotential.Coordinates = "\n" + "\n".join(multipole_coords) + "\n End" # we copy the pre_nmr_job output files to the main job directory self.pre_nmr_job.add_postamble(f'cp {j(self.pre_nmr_job.workdir, "adf.rkf")} {j(self.workdir, "TAPE21")}') self.pre_nmr_job.add_postamble(f'cp {j(self.pre_nmr_job.workdir, "TAPE10")} {j(self.workdir, "TAPE10")}') self.pre_nmr_job.run() # some extra settings for the main job self.dependency(self.pre_nmr_job) # NMR will name the calculation as TAPE21 instead of adf.rkf, so we rename it here self.add_postamble(f'mv {j(self.workdir, "TAPE21")} {j(self.workdir, "adf.rkf")}') # write the input for the NMR job # the ghost block holds the NICS points ghost_block = "\t" if len(self.nics_points) > 0: ghost_block += "Ghosts\n" for point in self.nics_points: ghost_block += f" {point[0]} {point[1]} {point[2]}\n" ghost_block += "SubEnd\n" # write input and runfile with open(self.inputfile_path, "w+") as inpf: inpf.write("NMR\n") inpf.write("\tout all\n") inpf.write(ghost_block + "\n") inpf.write("End\n") with open(self.runfile_path, "w+") as runf: runf.write("#!/bin/sh\n\n") # the shebang is not written by default by ADF runf.write("\n".join(self._preambles) + "\n\n") runf.write(f"$AMSBIN/nmr {self.inputfile_path} < /dev/null\n") runf.write("\n".join(self._postambles)) return True
[docs] def add_nics_point(self, coordinate: Tuple[float, float, float]): """ Add a NICS point to be calculated. Args: coordinate: the (x, y, z) coordinates of a NICS point to calculate the chemical shift for. Has to be given as cartesian coordinates and using unit angstrom. """ self.nics_points.append(coordinate)
if __name__ == "__main__": with NMRJob(test_mode=True) as job: job.molecule(r"D:\Users\Yuman\Desktop\PhD\TCutility\examples\job\water_dimer.xyz") job.add_nics_point([0, 1, 2]) job.add_nics_point([0, 1, 2]) job.add_nics_point([0, 1, 2]) job.add_nics_point([0, 1, 2]) job.add_nics_point([0, 1, 2]) job.add_nics_point([0, 1, 2])