Source code for tests.test_GaussianWriter
import os
from filecmp import cmp
from shutil import copy
from chemsmart.io.gaussian.output import Gaussian16Output
from chemsmart.io.molecules.structure import Molecule
from chemsmart.jobs.gaussian import (
GaussianModredJob,
GaussianOptJob,
GaussianQMMMJob,
GaussianScanJob,
GaussianSinglePointJob,
GaussianTSJob,
)
from chemsmart.jobs.gaussian.settings import GaussianJobSettings
from chemsmart.jobs.gaussian.writer import GaussianInputWriter
from chemsmart.settings.gaussian import GaussianProjectSettings
from chemsmart.utils.utils import cmp_with_ignore
[docs]
class TestGaussianInputWriter:
[docs]
def test_write_opt_job(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_jobrunner_no_scratch,
gaussian_written_opt_file,
):
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
settings = project_settings.opt_settings()
settings.charge = 0
settings.multiplicity = 1
job = GaussianOptJob.from_filename(
filename=single_molecule_xyz_file,
settings=settings,
label="gaussian_opt",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianOptJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "gaussian_opt.com")
assert os.path.isfile(g16_file)
assert cmp(
g16_file, gaussian_written_opt_file, shallow=False
) # writes input file as expected
# job run will result in the job being run and
# the output file copied back to run folder
# job.run()
# assert job.is_complete()
[docs]
def test_write_semiempirical_opt_job(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_jobrunner_no_scratch,
gaussian_written_pm6_opt_file,
):
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
settings = project_settings.opt_settings()
settings.charge = 0
settings.multiplicity = 1
settings.semiempirical = "PM6"
job = GaussianOptJob.from_filename(
filename=single_molecule_xyz_file,
settings=settings,
label="gaussian_pm6_opt",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianOptJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "gaussian_pm6_opt.com")
assert os.path.isfile(g16_file)
assert cmp(
g16_file, gaussian_written_pm6_opt_file, shallow=False
) # writes input file as expected
# job run will result in the job being run and
# the output file copied back to run folder
# job.run()
# assert job.is_complete()
[docs]
def test_write_opt_job_with_route(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_jobrunner_no_scratch,
gaussian_written_opt_file_with_route,
):
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
settings = project_settings.opt_settings()
settings.charge = 0
settings.multiplicity = 1
settings.route_to_be_written = "#p pbepbe/6-31g(d) opt"
settings.title = "Optimisation job with supplied route"
job = GaussianOptJob.from_filename(
filename=single_molecule_xyz_file,
settings=settings,
label="gaussian_opt",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianOptJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "gaussian_opt.com")
assert os.path.isfile(g16_file)
assert cmp(
g16_file, gaussian_written_opt_file_with_route, shallow=False
)
[docs]
def test_write_modred_job(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_jobrunner_no_scratch,
gaussian_written_modred_file,
):
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
settings = project_settings.modred_settings()
settings.charge = 0
settings.multiplicity = 1
settings.modred = [[1, 2], [3, 4, 5]]
job = GaussianModredJob.from_filename(
filename=single_molecule_xyz_file,
settings=settings,
label="gaussian_modred",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianModredJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "gaussian_modred.com")
assert os.path.isfile(g16_file)
assert cmp(g16_file, gaussian_written_modred_file, shallow=False)
[docs]
def test_write_scan_job_multiple_degrees_of_freedom(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_jobrunner_no_scratch,
gaussian_written_scan_multiple_degrees_of_freedom_file,
):
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
settings = project_settings.scan_settings()
settings.charge = 0
settings.multiplicity = 1
settings.modred = {
"coords": [[1, 2], [3, 4, 5]],
"num_steps": [10, 18],
"step_size": [0.1, 5.0],
}
job = GaussianScanJob.from_filename(
filename=single_molecule_xyz_file,
settings=settings,
label="gaussian_scan_multiple_degrees_of_freedom",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianScanJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(
tmpdir, "gaussian_scan_multiple_degrees_of_freedom.com"
)
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_scan_multiple_degrees_of_freedom_file,
shallow=False,
)
[docs]
def test_write_scan_job_single_degree_of_freedom(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_jobrunner_no_scratch,
gaussian_written_scan_single_degree_of_freedom_file,
):
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
settings = project_settings.scan_settings()
settings.charge = 0
settings.multiplicity = 1
settings.modred = {
"coords": [1, 2],
"num_steps": [10],
"step_size": [0.1],
}
job = GaussianScanJob.from_filename(
filename=single_molecule_xyz_file,
settings=settings,
label="gaussian_scan_single_degree_of_freedom",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianScanJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(
tmpdir, "gaussian_scan_single_degree_of_freedom.com"
)
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_scan_single_degree_of_freedom_file,
shallow=False,
)
[docs]
def test_write_scan_job_multiple_degrees_of_freedom_with_constraints(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_jobrunner_no_scratch,
gaussian_written_scan_multiple_degrees_of_freedom_with_constraints_file,
):
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
settings = project_settings.scan_settings()
settings.charge = 0
settings.multiplicity = 1
settings.modred = {
"coords": [
[1, 2],
[3, 4],
[5, 6, 7],
[8, 9, 10],
[11, 12, 13, 14],
],
"num_steps": [10, 12, 18, 15, 36],
"step_size": [0.1, 0.2, 3.0, 4.0, 10.0],
}
job = GaussianScanJob.from_filename(
filename=single_molecule_xyz_file,
settings=settings,
label="gaussian_scan_multiple_degrees_of_freedom_with_constraints",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianScanJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(
tmpdir,
"gaussian_scan_multiple_degrees_of_freedom_with_constraints.com",
)
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_scan_multiple_degrees_of_freedom_with_constraints_file,
shallow=False,
)
[docs]
def test_write_ts_job(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_jobrunner_no_scratch,
gaussian_written_ts_file,
):
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
settings = project_settings.ts_settings()
settings.charge = 0
settings.multiplicity = 1
job = GaussianTSJob.from_filename(
filename=single_molecule_xyz_file,
settings=settings,
label="gaussian_ts",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianTSJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "gaussian_ts.com")
assert os.path.isfile(g16_file)
assert cmp(g16_file, gaussian_written_ts_file, shallow=False)
[docs]
def test_write_qmmm_job(
self,
tmpdir,
single_molecule_xyz_file,
gaussian_yaml_settings_qmmm_project_name,
gaussian_written_qmmm_file,
gaussian_jobrunner_no_scratch,
):
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_qmmm_project_name
)
qmmm_settings = project_settings.qmmm_settings()
qmmm_settings.charge = 0
qmmm_settings.multiplicity = 1
qmmm_settings.charge_total = 0
qmmm_settings.mult_total = 1
qmmm_settings.high_level_atoms = [1, 2, 3]
job = GaussianQMMMJob.from_filename(
filename=single_molecule_xyz_file,
settings=qmmm_settings,
label="gaussian_qmmm",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianQMMMJob)
g16_writer = GaussianInputWriter(job=job)
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "gaussian_qmmm.com")
assert qmmm_settings.high_level_atoms == [1, 2, 3]
with open(g16_file, "r") as f:
g16_content = f.read()
# check that the qmmm section is present in the written file
with open(gaussian_written_qmmm_file, "r") as f:
expected_content = f.read()
assert g16_content == expected_content
assert os.path.isfile(g16_file)
assert cmp(g16_file, gaussian_written_qmmm_file, shallow=False)
[docs]
def test_write_qmmm_input_from_logfile(
self,
tmpdir,
gaussian_yaml_settings_qmmm_project_name,
gaussian_singlet_opt_outfile,
gaussian_jobrunner_no_scratch,
gaussian_written_qmmm_log_file,
):
"""Taking the Gaussian nhc_neutral_singlet.log
output and write qmmm .com"""
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_qmmm_project_name
)
qmmm_settings = project_settings.qmmm_settings()
qmmm_settings.charge = 0
qmmm_settings.multiplicity = 1
qmmm_settings.charge_total = 0
qmmm_settings.real_multiplicity = 1
qmmm_settings.high_level_atoms = [3, 12, 14, 7, 9]
qmmm_settings.medium_level_atoms = [8, 17, 19, 20, 21, 22, 23, 24, 25]
qmmm_settings.bonded_atoms = [(1, 3)]
job_settings = GaussianJobSettings.from_logfile(
gaussian_singlet_opt_outfile
)
keywords = ("charge", "multiplicity", "title")
qmmm_settings = qmmm_settings.merge(job_settings, keywords=keywords)
job = GaussianQMMMJob.from_filename(
filename=gaussian_singlet_opt_outfile,
settings=qmmm_settings,
label="gaussian_qmmm_from_log",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianQMMMJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "gaussian_qmmm_from_log.com")
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_qmmm_log_file,
shallow=False,
)
[docs]
def test_write_opt_input_from_logfile(
self,
tmpdir,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_singlet_opt_outfile,
gaussian_jobrunner_no_scratch,
gaussian_written_ts_from_nhc_singlet_log_file,
):
"""Taking the Gaussian nhc_neutral_singlet.log output
and write aldehyde_opt.com using the settings from the .log file."""
# get project settings
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
ts_settings = project_settings.ts_settings()
job_settings = GaussianJobSettings.from_logfile(
gaussian_singlet_opt_outfile
)
# also merge the title keywords
keywords = ("charge", "multiplicity", "title")
ts_settings = ts_settings.merge(job_settings, keywords=keywords)
job = GaussianTSJob.from_filename(
filename=gaussian_singlet_opt_outfile,
settings=ts_settings,
label="gaussian_ts_from_log",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianTSJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "gaussian_ts_from_log.com")
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_ts_from_nhc_singlet_log_file,
shallow=False,
)
[docs]
def test_write_sp_input_with_solvation_from_logfile(
self,
tmpdir,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_singlet_opt_outfile,
gaussian_jobrunner_no_scratch,
gaussian_written_sp_from_nhc_singlet_log_with_solvent_file,
):
"""Test writing simple .com input file using settings from .log file,
including solvation."""
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
sp_settings = project_settings.sp_settings()
job_settings = GaussianJobSettings.from_logfile(
gaussian_singlet_opt_outfile
)
sp_settings = sp_settings.merge(job_settings)
job = GaussianSinglePointJob.from_filename(
filename=gaussian_singlet_opt_outfile,
settings=sp_settings,
label="gaussian_sp_from_log_with_solvent",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianSinglePointJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(
tmpdir, "gaussian_sp_from_log_with_solvent.com"
)
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_sp_from_nhc_singlet_log_with_solvent_file,
shallow=False,
)
[docs]
def test_write_sp_with_custom_solvation_from_logfile(
self,
tmpdir,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_singlet_opt_outfile,
gaussian_jobrunner_no_scratch,
smd_TBME_solvent_parameters_text_file,
gaussian_written_sp_from_nhc_singlet_log_with_custom_solvent_file,
):
"""Test writing input file from log file.
Simply taking the Gaussian nhc_neutral_singlet.log output and write
gaussian_sp_custom_solv.com using the settings from the .log
file and including custom solvation parameters from file smd_TBME.
"""
smd_TBME_tmp_path = os.path.join(tmpdir, "smd_TBME")
copy(smd_TBME_solvent_parameters_text_file, smd_TBME_tmp_path)
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
sp_settings = project_settings.sp_settings()
sp_settings.solvent_model = "smd"
sp_settings.custom_solvent = smd_TBME_tmp_path
job_settings = GaussianJobSettings.from_logfile(
gaussian_singlet_opt_outfile
)
sp_settings = sp_settings.merge(job_settings)
job = GaussianSinglePointJob.from_filename(
filename=gaussian_singlet_opt_outfile,
settings=sp_settings,
label="gaussian_sp_from_log_with_custom_solvent",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianSinglePointJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(
tmpdir, "gaussian_sp_from_log_with_custom_solvent.com"
)
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_sp_from_nhc_singlet_log_with_custom_solvent_file,
shallow=False,
)
[docs]
def test_write_ts_with_custom_basis_from_logfile(
self,
tmpdir,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_singlet_opt_outfile,
gaussian_jobrunner_no_scratch,
Ni_def2tzvp_PCHOSi_svp_text_file,
gaussian_written_sp_from_nhc_singlet_log_with_custom_basis_file,
):
custom_basis_tmp_path = os.path.join(tmpdir, "custom_basis.txt")
copy(Ni_def2tzvp_PCHOSi_svp_text_file, custom_basis_tmp_path)
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
ts_settings = project_settings.ts_settings()
ts_settings.gen_genecp_file = custom_basis_tmp_path
job_settings = GaussianJobSettings.from_logfile(
gaussian_singlet_opt_outfile
)
ts_settings = ts_settings.merge(job_settings)
job = GaussianTSJob.from_filename(
filename=gaussian_singlet_opt_outfile,
settings=ts_settings,
label="gaussian_sp_from_log_with_custom_basis",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianTSJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(
tmpdir, "gaussian_sp_from_log_with_custom_basis.com"
)
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_sp_from_nhc_singlet_log_with_custom_basis_file,
shallow=False,
)
[docs]
def test_write_ts_with_custom_basis_using_api(
self,
tmpdir,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_ts_genecp_outfile,
gaussian_jobrunner_no_scratch,
gaussian_written_sp_from_nhc_singlet_log_with_custom_basis_from_api_file,
):
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
ts_settings = project_settings.ts_settings()
job_settings = GaussianJobSettings.from_logfile(
gaussian_ts_genecp_outfile
)
ts_settings = ts_settings.merge(job_settings)
# update settings for heavy elements
ts_settings.heavy_elements = ["Pd"]
ts_settings.heavy_elements_basis = "def2-TZVPPD"
ts_settings.light_elements_basis = "def2-SVP"
molecule = Molecule.from_filepath(gaussian_ts_genecp_outfile)
job = GaussianTSJob(
molecule=molecule,
settings=ts_settings,
label="gaussian_sp_from_log_with_custom_basis_from_api",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianTSJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(
tmpdir, "gaussian_sp_from_log_with_custom_basis_from_api.com"
)
# compare the written input file with the expected input file, except
# the line containing the version number
# (basis set exchange api may be different)
assert cmp_with_ignore(
g16_file,
gaussian_written_sp_from_nhc_singlet_log_with_custom_basis_from_api_file,
ignore_string="Version",
)
[docs]
def test_write_modred_with_custom_basis_for_all_elements_in_structure_using_api(
self,
tmpdir,
gaussian_yaml_settings_gas_solv_project_name,
modred_genecp_inputfile,
gaussian_jobrunner_no_scratch,
gaussian_modred_with_custom_basis_for_all_atoms_from_api,
):
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
modred_settings = project_settings.modred_settings()
job_settings = GaussianJobSettings.from_filepath(
modred_genecp_inputfile
)
modred_settings = modred_settings.merge(job_settings)
modred_settings.modred = [[1, 2], [3, 4, 5]]
modred_settings.basis = "genecp"
modred_settings.heavy_elements = [
"C",
"H",
"O",
"N",
"Pd",
"P",
"S",
"F",
"Br",
"I",
]
# more than all elements in the system but will be filtered
# to only those in the system for input preparation
modred_settings.heavy_elements_basis = "def2-TZVPPD"
modred_settings.light_elements_basis = None # light element basis not specified as all use custom basis from heavy_elements_basis
molecule = Molecule.from_filepath(modred_genecp_inputfile)
job = GaussianModredJob(
molecule=molecule,
settings=modred_settings,
label="gaussian_modred_with_custom_basis_for_all_atoms_from_api",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianModredJob)
g16_writer = GaussianInputWriter(job=job)
# write input file
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(
tmpdir,
"gaussian_modred_with_custom_basis_for_all_atoms_from_api.com",
)
assert os.path.isfile(g16_file)
# compare the written input file with the expected input file, except
# the line containing the version number
# (basis set exchange api may be different)
assert cmp_with_ignore(
g16_file,
gaussian_modred_with_custom_basis_for_all_atoms_from_api,
ignore_string="Version",
)
[docs]
def test_write_gaussian_input_from_pbc_logfile(
self,
tmpdir,
gaussian_yaml_settings_gas_solv_project_name,
gaussian_pbc_2d_outputfile,
gaussian_jobrunner_no_scratch,
gaussian_written_opt_from_graphite_2d_pbc_log,
):
project_settings = GaussianProjectSettings.from_project(
gaussian_yaml_settings_gas_solv_project_name
)
opt_settings = project_settings.opt_settings()
file_settings = GaussianJobSettings.from_filepath(
filepath=gaussian_pbc_2d_outputfile
)
opt_settings = opt_settings.merge(file_settings)
molecule = Molecule.from_filepath(gaussian_pbc_2d_outputfile)
g16_outputfile = Gaussian16Output(gaussian_pbc_2d_outputfile)
assert g16_outputfile.list_of_pbc_conditions == [1, 1, 0]
assert g16_outputfile.input_translation_vectors == [
[2.47532, 0.0, 0.0],
[-1.21995, 2.13345, 0.0],
]
job = GaussianSinglePointJob(
molecule=molecule,
settings=opt_settings,
label="graphite_2d_opt_from_log",
jobrunner=gaussian_jobrunner_no_scratch,
)
assert isinstance(job, GaussianSinglePointJob)
g16_writer = GaussianInputWriter(job=job)
g16_writer.write(target_directory=tmpdir)
g16_file = os.path.join(tmpdir, "graphite_2d_opt_from_log.com")
assert os.path.isfile(g16_file)
assert cmp(
g16_file,
gaussian_written_opt_from_graphite_2d_pbc_log,
shallow=False,
)