Jaguar

The Jaguar package has modules to help set up and run quantum-mechanical calculations using Jaguar and to parse the results. To use Jaguar productively and meaningfully, one should be familiar with the Jaguar Reference Manual: The manual documents the many different runtime options Jaguar supports. Some of these options are critical for a given scientific question, such as the choice of running the calculation in solution-phase or gas-phase. Others are more technical in nature, such as the choice of algorithm or convergence criteria to use when solving various equations. The full array of options may be overwhelming initially, and the defaults may sometimes be inappropriate. So to get started, the documentation provides some recommendations for computational settings to calculate different chemical properties.

The traditional way to launch Jaguar jobs is from the GUI, or alternatively from a command line invocation such as $SCHRODINGER/jaguar run h2o.in where h2o.in is a Jaguar input file. The Jaguar documentation explains in detail how to write a Jaguar input file and launch jobs from the command line. A simple input file for a water molecule might look like this:

&gen
basis = cc-pVDZ
dftname = M06-2X
igeopt = 1
&
entry_name: h2o
&zmat
O1     -0.0593430000000  -0.0069230000000   0.0000000000000
H2      0.5618730000000  -0.7247900000000   0.0000000000000
H3      0.3799410000000   0.8346600000000   0.0000000000000
&

When a command like this is launched, Jaguar will run and generate output files with names derived from the input file by default, in this case, h2o.out and h2o.01.mae (among others). The former is an ASCII file which may be inspected by eye or through other command line tools, and the latter Maestro file may be imported into the GUI to view the results of the calculation. In the following, we show how Jaguar jobs like this can be set up, launched, and the output files parsed to analyze the results inside a Python program. We also show how jobs may be chained together in simple ways to create a workflow.

Example 1: Setting up jobs

The JaguarInput class is very useful for setting up Jaguar jobs from Structure objects:

from schrodinger.structure import StructureReader
from schrodinger.application.jaguar import validation
from schrodinger.application.jaguar.input import JaguarInput

# Configure runtime options via input keyword/value pairs and verify them
options = {
           "basis": "cc-pVDZ",   # basis set
           "dftname": "M06-2X",  # DFT functional
           "igeopt": "1",        # Toggle geometry optimization
          }
for k, v in options.items():
    try:
        validation.keyword_value_pair_is_valid(k, v)
    except validation.JaguarKeywordException as e:
        print(e)
        raise

# Either use an existing Structure instance, or read one from a Maestro file
st = next(StructureReader("h2o.mae"))

# Initialise a JaguarInput instance from a Structure instance
ji = JaguarInput(structure=st, genkeys=options)
print("Requested non-default options are:\n", ji.getNonDefault())

# Write input files
ji.saveAs("geopt.in")

This script will generate two files: geopt.in and geopt.mae. These may be used to run a Jaguar job similar to the one at the top of this section.

Example 2: Launching jobs and parsing the output

The JaguarOutput class is very useful for parsing results from a Jaguar job. Using the input file generated from Example 1, the following will launch a Jaguar geometry optimization and analyze the output:

from schrodinger.job.jobcontrol import launch_job
from schrodinger.application.jaguar.output import JaguarOutput

# Launch via cmdline under jobcontrol
run_command = ["jaguar", "run", "geopt.in"]
print("\nRunning Jaguar under jobcontrol...")
job = launch_job(run_command)
job.wait()

# Programatically access results using the JaguarOutput class
jo = JaguarOutput("geopt.out")
print("Calculation finished!")
print(f"\nstatus OK = {jo.status == jo.OK}")
print(f"time = {jo.duration}")
print(f"basis set = {jo.basis}")
print(f"DFT functional = {jo.functional}")
print(f"Final SCF energy = {jo.scf_energy} hartrees")

# Final optimized structure is available from JaguarOutput
opt_st1 = jo.getStructure()
# Convergence path is available from JaguarOutput
opt_sts = jo.getStructures()
print(f"\nNumber of geopt steps = {len(opt_sts)}")

The Jaguar job generates two main output files: geopt.out and geopt.01.mae. The script parses the geopt.out file and prints some of the results. It also extracts the final Structure object corresponding to the optimized geometry generated by the Jaguar calculation, as well as the intermediate geometries Jaguar found during the optimization.

Example 3: Chaining jobs using the restart file

One can use a similar pattern to launch a restart job from a previous Jaguar job. In this example, we take the restart file from Example 2, which has the optimized geometry and the wavefunction from that calculation, and then run a new Jaguar job using it as input, requesting polarizabilities to be calculated additionally this time:

from schrodinger.job.jobcontrol import launch_job
from schrodinger.application.jaguar.input import JaguarInput
from schrodinger.application.jaguar.output import JaguarOutput

# Initialise a JaguarInput instance from a Jaguar restart file
ji = JaguarInput("geopt.01.in", name="restart")
ji.setValue("igeopt", 0)   # Turn off geometry optimization
ji.setValue("ipolar", -1)  # Request polarizabilities
print("Requested non-default options are:\n", ji.getNonDefault())

# Write input file and launch via cmdline under jobcontrol
ji.save()
run_command = ["jaguar", "run", "restart.in"]
print("\nRunning Jaguar under jobcontrol...")
job = launch_job(run_command)
job.wait()

# Programatically access results using the JaguarOutput class
jo = JaguarOutput("restart.out")
print("Calculation finished!")
print(f"\nstatus OK = {jo.status == jo.OK}")
print(f"time = {jo.duration}")
print(f"basis set = {jo.basis}")
print(f"DFT functional = {jo.functional}")
print(f"Final SCF energy = {jo.scf_energy} hartrees")
print(f"Polarizability = {jo.last_results.polar_alpha}")

Example 4: Setting up a constrained geometry optimization

One can also adapt this pattern to do a constrained geometry optimization. e.g. the following code snippet will fix the distance between atoms 1 and 2:

from schrodinger.infra import mm
from schrodinger.application.jaguar.input import JaguarInput

# Initialise a JaguarInput instance from a Jaguar input file
ji = JaguarInput("geopt.in", name="constraint")
# Fix the distance between atoms 1 and 2 in the optimization
ji.setConstraint(mm.MMJAG_COORD_DISTANCE, [1, 2], None)

Example 5: Running Jaguar jobs in parallel batches

The easiest way to launch Jaguar jobs in parallel inside a Python script is to leverage the native parallel functionality of the “jaguar run” command. e.g. to launch three Jaguar jobs simultaneously to a queued host “bolt_cpu”, one can use:

run_command = ["jaguar", "run", "job1.in", "job2.in",
               "job3".in", "-jobname", "batch", "-HOST", "bolt_cpu"]
job = launch_job(run_command)
job.wait()

One may combine this with the -PARALLEL command line flag to allow jobs to run with multiple OpenMP threads additionally, per the usual behaviour for command line jobs. See $SCHRODINGER/jaguar run –help for more details.