Tutorial¶
Say that you came up with a new method of assigning partial charges. In this method, the charges on heavy atoms are identical to NPA charges and charges on hydrogen atoms are optimized to best fit the molecular ESP field. This example will walk you through the steps to compute the charges for a trimethylamine cation (NMe3H+) and evaluate fit quality with respect to the actual ESP field.
Note
The full script is available alongside its expected output in the example directory. All necessary input data files are available in the data/NMe3H_plus directory of the GitHub repo. Gaussian input files are currently not available but the analogous input files for a methane molecule are available in the data/methane/prep directory.
Say that you want to use the CHelpG fitting points as the sampling mesh for the molecular ESP field. Gaussian will generate such file when passed the
Pop=CHelpGandIOp(6/50=1)options. The name of the .esp file must be given as the last line of the input file. In this example, the filename was “NMe3H_plus_chelpg.esp”. The code to parse the file is as follows:from repESP.esp_util import parse_gaussian_esp with open("NMe3H_plus_chelpg.esp") as f: gaussian_esp_data = parse_gaussian_esp(f) molecule = gaussian_esp_data.molecule esp_field = gaussian_esp_data.field
Run a Gaussian calculation with the
Pop=NPAoption. The NPA charges can then be parsed from the output file as follows:from repESP.gaussian_format import get_charges_from_log, NpaChargeSectionParser with open("NMe3H_plus_nbo.log") as f: npa_charges = get_charges_from_log(f, NpaChargeSectionParser(), molecule)
Prepare data regarding chemical equivalence relationships between atoms. An Antechamber file (.ac) is required to generate two “respin” files using the
respgenprogram (available from the Antechamber program suite). To generate the files, run in your shell:antechamber -i NMe3H_plus.log -fi gout -o NMe3H_plus.ac -fo ac respgen -i NMe3H_plus.ac -o NMe3H_plus.respin1 -f resp1 respgen -i NMe3H_plus.ac -o NMe3H_plus.respin2 -f resp2
The Equivalence object can then be generated:
from repESP.respin_format import parse_respin, get_equivalence_from_two_stage_resp_ivary with open("NMe3H_plus_mk.respin1") as respin1_file: respin1 = parse_respin(respin1_file) with open("NMe3H_plus_mk.respin2") as respin2_file: respin2 = parse_respin(respin2_file) equivalence = get_equivalence_from_two_stage_resp_ivary(respin1.ivary, respin2.ivary)
Alternatively, if you’re currently unable to generate the “respin” files, equivalence can be specified manually:
from repESP.equivalence import Equivalence equivalence = Equivalence([ None, # C0 None, # H1 1, # H2, equivalenced to H1 1, # H3, equivalenced to H1 0, # C4, equivalenced to C0 1, # H5, equivalenced to H1 1, # H6, equivalenced to H1 1, # H7, equivalenced to H1 0, # C8, equivalenced to C0 1, # H9, equivalenced to H1 1, # H10, equivalenced to H1 1, # H11, equivalenced to H1 None, # N12 None # H13 ])
Perform fitting partial charges on hydrogen atoms. This invokes the
respprogram, so it has to be in yourPATHvariable:from repESP.esp_util import EspData from repESP.resp_wrapper import fit_hydrogens_only esp_data = EspData.from_gaussian(gaussian_esp_data) my_charges = fit_hydrogens_only( esp_data, equivalence, molecule, total_charge=1, # cation, +1 total charge initial_charges=npa_charges # will be used for non-hydrogen atoms )
To reproduce the ESP from your charges, you have to first create a Molecule object identical to the one in the molecule variable but with your new charges instead of CHelpG:
from repESP.charges import AtomWithCoordsAndCharge from repESP.types import Molecule molecule_with_my_charges = Molecule([ AtomWithCoordsAndCharge( atom.atomic_number, atom.coords, my_charge ) for atom, my_charge in zip(molecule.atoms, my_charges) ])
You can then reproduce the ESP field from your partial charges and calculate fit quality:
from repESP.calc_fields import esp_from_charges, calc_rms_error, calc_relative_rms_error reproduced_esp = esp_from_charges(esp_field.mesh, molecule_with_my_charges) rms = calc_rms_error(esp_field.values, reproduced_esp.values) rrms = calc_relative_rms_error(esp_field.values, reproduced_esp.values)
You could also evaluate the fit quality of the original CHelpG and NPA charges for comparison. Extending the script to do that is left as an exercise to the reader. You should find that the fit quality of your charges is better than that of NPA but poorer than that of CHelpG.