AMS driver and engines

The AMS driver is a new program introduced in the 2018 release that unifies the way in which different computational engines of Amsterdam Modelling Suite are called. You can find more information about the AMS driver in the corresponding part of the documentation.

Preparing input

Note

Input files handling in the AMS driver is case insensitive.

The input file for the AMS driver consists of keys and values organized in blocks and subblocks:

Task GeometryOptimization

GeometryOptimization
    Convergence
        Gradients 1.0e-4
    End
End

Properties
   NormalModes true
End

System
    Atoms
        C       0.00000000       0.00000000       0.00000000
        H       0.63294000      -0.63294000      -0.63294000
        H      -0.63294000       0.63294000      -0.63294000
        H       0.63294000       0.63294000       0.63294000
        H      -0.63294000      -0.63294000       0.63294000
    End
End

Engine DFTB
    Model DFTB3
    ResourcesDir DFTB.org/3ob-3-1
EndEngine

Such a structure can be reflected in a natural way by a multi-level character of Settings. The example input file presented above can be generated by:

s = Settings()
#AMS driver input
s.input.ams.Task = 'GeometryOptimization'
s.input.ams.GeometryOptimization.Convergence.Gradients = 1.0e-4
s.input.ams.Properties.NormalModes = 'true'
#DFTB engine input
s.input.DFTB.Model = 'DFTB3'
s.input.DFTB.ResourcesDir = 'DFTB.org/3ob-3-1'

m = Molecule('methane.xyz')
j = AMSJob(molecule=m, settings=s)
j.run()

If an entry is a regular key-value pair it is printed in one line (like Task GeometryOptimization above). If an entry is a nested Settings instance it is printed as a block and entries inside this instance correspond to the contents of that block.

One of the blocks is special: the engine block. It defines the computational engine used to perform the task defined in all other blocks. The contents of the engine block are not processed by the AMS driver, but rather passed to the corresponding engine instead. Because of that every AMS input file can be seen as composed of two distinct parts: the engine input (everything inside the engine block) and the driver input (everything apart from the engine block). That distinction is reflected by how a Settings instance for AMSJob is structured. As we can see, the input branch of job settings is divided into two branches: the ams branch for the driver input and the DFTB branch for the engine input.

Note

In general, PLAMS will use all the contents of the ams branch (spelling not case-sensitive) to construct the driver input and the contents of every other branch to construct a separate engine block with the same name as the branch (like DFTB in the example above). In the present moment only applications with a single engine block are implemented in the AMS driver, but that will most likely change in the near future.

The contents of each branch of myjob.settings.input are translated to a string using the same logic:

  • Entries within each block (including the top level) are listed in the alphabetical order.

  • Both keys and values are kept in their original case.

  • Strings used as values can contain spaces and all kinds of special characters, including new lines. They are printed in an unchanged form in the input file.

  • If you need to put a key without any value, you can use True or an empty string as a value:

    s.input.ams.block.key = True
    s.input.ams.otherkey = ''
    
    ### translates to:
    
    block
      key
    end
    
    otherkey
    
  • If a value of a key is False or None the key is omitted.

  • En empty Settings instance produces an empty block:

    s.input.ams.emptyblock = Settings()
    s.input.ams.otherblock #short syntax equivalent to the line above
    
    ### translates to:
    
    emptyblock
    end
    
    otherblock
    end
    
  • More instances of the same key within one block can be achieved by using a list of values instead of a single value:

    s.input.ams.constraints.atom = [1,5,4]
    s.input.ams.constraints.block = ['ligand', 'residue']
    
    ### translates to:
    
    constraints
      atom 1
      atom 5
      atom 4
      block ligand
      block residue
    end
    
  • Some blocks require (or allow) something to be put in the header line, next to the block name. Special key _h is helpful in these situations:

    s.input.ams.block._h = 'header=very important'
    s.input.ams.block.key1 = 'value1'
    s.input.ams.block.key2 = 'value2'
    
    ### translates to:
    
    someblock header=very important
      key1 value1
      key2 value2
    end
    
  • Another kind of special key can be used to override the default alphabetic ordering of entries within a block, or just to insert arbitrary strings into the block:

    s.input.ams.block._1 = 'entire line that has to be the first line of block'
    s.input.ams.block._2 = 'second line'
    s.input.ams.block._4 = 'I will not be printed'
    s.input.ams.block.key1 = 'value1'
    s.input.ams.block.key2 = 'value2'
    
    ### translates to:
    
    block
      entire line that has to be the first line of block
      second line
      key1 value1
      key2 value2
    end
    
  • If a value of a key needs to be a path to some KF file with results of a previous AMS calculation, an instance of AMSJob or AMSResults (or directly KFFile) can be used (see AMSJob.get_input() for details):

    oldjob = AMSJob(...)
    oldjob.run()
    newjob = AMSJob(...)
    newjob.settings.input.ams.loadsystem.file = oldjob
    newjob.settings.input.ams.loadengine = (oldjob, 'dftb')
    
    ### translates to:
    
    loadengine /home/user/plams_workdir/oldjob/dftb.rkf
    
    loadsystem
      file = /home/user/plams_workdir/oldjob/ams.rkf
    end
    
  • Convert AMS text-style input to a Settings object (this requires that the SCM python package is installed):

    text = '''
    Task GeometryOptimization
    Engine DFTB
       Model GFN1-xTB
    EndEngine
    '''
    
    sett = AMSJob.from_input(text).settings
    print(sett)
    
    # output:
    
    input:
          dftb:
               model:       GFN1-xTB
          ams:
               task:        GeometryOptimization
    

Note

The algorithm translating Settings contents into an input file does not check the correctness of the given data - it simply takes keys and values from Settings and prints them in the text file. Due to that you are not going to be warned if you make a typo, use a wrong keyword or improper syntax.

Preparing runscript

Runscripts for the AMS driver are very simple (see AMSJob.get_runscript()). The only adjustable option (apart from usual pre, post, shebang and stdout_redirect which are common for all single jobs) is myjob.settings.runscript.nproc, indicating the number of parallel processes to run AMS with (like with -n flag or NSCM environmental variable).

Molecule handling

There are several ways in which the description of the simulated system can be supplied to AMSJob. The most convenient one is simply by passing a Molecule instance:

mol = Molecule('/path/to/some/file.xyz')
myjob = AMSJob(name='test', molecule=mol, settings=...)

or:

mol = Molecule('/path/to/some/file.xyz')
myjob = AMSJob(...)
myjob.molecule = mol

A Molecule instance stored as the molecule attribute is automatically processed during the input file preparation and printed in the proper format (see AMS manual for details). Various details of this process can be adjusted based on attributes of the supplied Molecule. If mol.lattice is nonempty, the information about periodicity vectors is printed to the lattice subblock of the system block. If the supplied lattice consists of 1 or 2 vectors that do not follow the convention requied by AMS (1D – vector aligned with X axis; 2D – vectors aligned with XY plane) the whole system is rotated to meet these criteria. If mol.properties.charge exists, it is used as the charge key in the system block.

Moreover, each Atom present in the supplied Molecule has its own properties attribute that can be used to adjust the details of the line generated for this atom in the atoms block:

  • The atomic symbol is generated based on the atomic number stored in the atnum attribute of the Atom. The atomic number of 0 corresponds to the “dummy atom” for which the symbol is empty.
  • If atom.properties.ghost exists and is True, the atomic symbol is prefixed with Gh..
  • If atom.properties.name exists, the name is added after the atomic symbol, separated by a single dot.
  • Leading, trailing and double dots are removed from the atomic symbol.
  • If atom.properties.suffix exists, it is placed at the end of the line, after the numerical coordinates (it should ba a string)

Example:

mol = Molecule('xyz/Ethanol.xyz')
mol[1].properties.ghost = True
mol[2].properties.name = 'D'
mol[3].properties.ghost = True
mol[3].properties.name = 'T'
mol[4].properties.atnum = 0
mol[4].properties.name = 'J.XYZ'
mol[5].properties.atnum = 0
mol[5].properties.name = 'J.ASD'
mol[5].properties.ghost = True
mol[6].properties.suffix = 'whatever text'
myjob = AMSJob(molecule=mol)

The corresponding fragment of the input file produced by the above code:

system
  atoms
      1      Gh.C       0.01247       0.02254       1.08262
      2       C.D      -0.00894      -0.01624      -0.43421
      3    Gh.H.T      -0.49334       0.93505       1.44716
      4     J.XYZ       1.05522       0.04512       1.44808
      5  Gh.J.ASD      -0.64695      -1.12346       2.54219
      6         H       0.50112      -0.91640      -0.80440   whatever text
      7         H       0.49999       0.86726      -0.84481
      8         H      -1.04310      -0.02739      -0.80544
      9         O      -0.66442      -1.15471       1.56909
  end
end

Another, more cumbersome way to provide the system information to AMSJob is to manually populate the system block in job settings:

s = Settings()
s.input.ams.system.atoms._1 = 'H     0.0    0.0     0.0'
s.input.ams.system.atoms._2 = 'O     1.0    0.0     0.0'
s.input.ams.system.charge = 1.0
#other settings adjustments
myjob = AMSJob(settings=s)

An alternative way of supplying molecular coordinates is to use the GeometryFile key in the system block:

s = Settings()
s.input.ams.system.geometryfile = '/path/to/some/file.xyz'
#other settings adjustments
myjob = AMSJob(settings=s)

Currently only the extended XYZ format is supported.

Finally, one could use the LoadSystem top-level key and point to an existing .rkf file with results of some previous calculation:

s = Settings()
s.input.loadsystem = '/path/to/some/ams.rkf'
#other settings adjustments
myjob = AMSJob(settings=s)

Multiple molecules

The AMS driver allows multiple occurences of the system block in the input file. Different system blocks are distinguished by their names defined in the header of the block:

system protein
    atoms
    ...
    end
end
system ligand
    atoms
    ...
    end
end

The system without such a name is considered the main system.

Multiple systems can be used in AMSJob by setting the molecule attribute to a dictionary, instead of a single Molecule. Such a dictionary should have strings as keys and Molecule instances as values. The main system should have '' (an empty string) as a key.

Other methods of providing the contents of the system block mentioned above can also be used to provide multiple system blocks. myjob.settings.input.ams.system can be a list containg multiple Settings instances, one for each system. Each such instance can be have manually filled atoms block or use the geometryfile key. Special header _h key can be used to set headers and hence names of different system blocks. Multiple instances of the LoadSystem key (also provided as a list, also with _h headers) can also be used.

All the methods mentioned above (molecule attribute, GeometryFile, LoadSystem, manual system block preparation) can be combined in any configuration. In case of a conflict, the data stored in settings.input.ams.system takes precedence over molecule. It is, however, the user’s responsibility to make sure that among all the systems provided there is exactly one main system (without a name).

AMSJob API

class AMSJob(name='plamsjob', molecule=None, settings=None, depend=None)[source]

A class representing a single computation with AMS driver. The corresponding results type is AMSResults.

run(jobrunner=None, jobmanager=None, watch=False, **kwargs)[source]

Run the job using jobmanager and jobrunner (or defaults, if None).

If watch is set to True, the contents of the AMS driver logfile will be forwarded line by line to the PLAMS logfile (and stdout), allowing for an easier monitoring of the running job. Not that the forwarding of the AMS driver logfile will cause make the call to this method block until the job’s execution has finished, even when using a parallel JobRunner.

Other keyword arguments (**kwargs) are stored in run branch of job’s settings.

Returned value is the AMSResults instance associated with this job.

get_input()[source]

Generate the input file. This method is just a wrapper around _serialize_input().

Each instance of AMSJob or AMSResults present as a value in settings.input branch is replaced with an absolute path to ams.rkf file of that job.

If you need to use a path to some engine specific .rkf file rather than the main ams.rkf file, you can to it by supplying a tuple (x, name) where x is an instance of AMSJob or AMSResults and name is a string with the name of the .rkf file you want. For example, (myjob, 'dftb') will transform to the absolute path to dftb.rkf file in myjob’s folder, if such a file is present.

Instances of KFFile are replaced with absolute paths to corresponding files.

get_runscript()[source]

Generate the runscript. Returned string is of the form:

unset AMS_SWITCH_LOGFILE_AND_STDOUT
AMS_JOBNAME=jobname AMS_RESULTSDIR=. $AMSBIN/ams [-n nproc] <jobname.in [>jobname.out]

-n flag is added if settings.runscript.nproc exists. [>jobname.out] is used based on settings.runscript.stdout_redirect. If settings.runscript.preamble_lines exists, those lines will be added to the runscript verbatim before the execution of AMS.

check()[source]

Check if termination status variable from General section of main KF file equals NORMAL TERMINATION.

get_errormsg()[source]

Tries to get an error message for a failed job. This method returns None for successful jobs.

hash_input()[source]

Calculate the hash of the input file.

All instances of AMSJob or AMSResults present as values in settings.input branch are replaced with hashes of corresponding job’s inputs. Instances of KFFile are replaced with absolute paths to corresponding files.

get_task()[source]

Returns the AMS Task from the job’s settings. If it does not exist, returns None.

classmethod load_external(path, settings=None, molecule=None, finalize=False, fmt='ams')[source]

Load an external job from path.

In this context an “external job” is an execution of some external binary that was not managed by PLAMS, and hence does not have a .dill file. It can also be used in situations where the execution was started with PLAMS, but the Python process was terminated before the execution finished, resulting in steps 9-12 of Running a job not happening.

All the files produced by your computation should be placed in one folder and path should be the path to this folder or a file in this folder. The name of the folder is used as a job name. Input, output, error and runscript files, if present, should have names defined in _filenames class attribute (usually [jobname].in, [jobname].out, [jobname].err and [jobname].run). It is not required to supply all these files, but in most cases one would like to use at least the output file, in order to use methods like grep_output() or get_output_chunk(). If path is an instance of an AMSJob, that instance is returned.

This method is a class method, so it is called via class object and it returns an instance of that class:

>>> a = AMSJob.load_external(path='some/path/jobname')
>>> type(a)
scm.plams.interfaces.adfsuite.ams.AMSJob

You can supply Settings and Molecule instances as settings and molecule parameters, they will end up attached to the returned job instance. If you don’t do this, PLAMS will try to recreate them automatically using methods recreate_settings() and recreate_molecule() of the corresponding Results subclass. If no Settings instance is obtained in either way, the defaults from config.job are copied.

You can set the finalize parameter to True if you wish to run the whole _finalize() on the newly created job. In that case PLAMS will perform the usual check() to determine the job status (successful or failed), followed by cleaning of the job folder (Cleaning job folder), postrun() and pickling (Pickling). If finalize is False, the status of the returned job is copied.

fmt : str

One of ‘ams’, ‘qe’, ‘vasp’, or ‘any’.

‘ams’: load a finished AMS job

‘qe’: convert a Quantum ESPRESSO .out file to ams.rkf and qe.rkf and load from those files

‘vasp’: convert a VASP OUTCAR file to ams.rkf and vasp.rkf and load from those files (see more below)

‘any’: auto-detect the format.

This method can also be used to convert a finished VASP job to an AMSJob. If you supply the path to a folder containing OUTCAR, then a subdirectory will be created in this folder called AMSJob. In the AMSJob subdirectory, two files will be created: ams.rkf and vasp.rkf, that contain some of the results from the VASP calculation. If the AMSJob subdirectory already exists, the existing ams.rkf and vasp.rkf files will be reused. NOTE: the purpose of loading VASP data this way is to let you call for example job.results.get_energy() etc., not to run new VASP calculations!

classmethod from_input(text_input: str, **kwargs) → scm.plams.interfaces.adfsuite.ams.AMSJob[source]

Creates an AMSJob from AMS-style text input. This function requires that the SCM Python package is installed (if not, it will raise an ImportError).

text_input : a multi-line string

Returns: An AMSJob instance

Example:

text = '''
Task GeometryOptimization
Engine DFTB
    Model GFN1-xTB
EndEngine
'''

job = AMSJob.from_input(text)

Note

If molecule is included in the keyword arguments to this method, the text_input may not contain any System blocks. In other words, the molecules to be used either need to come from the text_input, or the keyword argument, but not both.

If settings is included in the keyword arguments to this method, the Settings created from the text_input will be soft updated with the settings from the keyword argument. In other word, the text_input takes precedence over the settings keyword argument.

classmethod from_inputfile(filename: str, heredoc_delimit: str = 'eor', **kwargs) → scm.plams.interfaces.adfsuite.ams.AMSJob[source]

Construct an AMSJob instance from an AMS inputfile or runfile.

If a runscript is provide than this method will attempt to extract the input file based on the heredoc delimiter (see heredoc_delimit).

static settings_to_mol(s: scm.plams.core.settings.Settings) → dict[source]

Pop the s.input.ams.system block from a settings instance and convert it into a dictionary of molecules.

The provided settings should be in the same style as the ones produced by the SCM input parser. Dictionary keys are taken from the header of each system block. The existing s.input.ams.system block is removed in the process, assuming it was present in the first place.

AMSResults API

class AMSResults(*args, **kwargs)[source]

A specialized Results subclass for accessing the results of AMSJob.

collect()[source]

Collect files present in the job folder. Use parent method from Results, then create an instance of KFFile for each .rkf file present in the job folder. Collect these files in rkfs dictionary, with keys being filenames without .rkf extension.

The information about .rkf files generated by engines is taken from the main ams.rkf file.

This method is called automatically during the final part of the job execution and there is no need to call it manually.

refresh()[source]

Refresh the contents of files list.

Use the parent method from Results, then look at KFFile instances present in rkfs dictionary and check if they point to existing files. If not, try to reinstantiate them with current job path (that can happen while loading a pickled job after the entire job folder was moved).

engine_names()[source]

Return a list of all names of engine specific .rkf files. The identifier of the main result file ('ams') is not present in the returned list, only engine specific names are listed.

rkfpath(file='ams')[source]

Return the absolute path of a chosen .rkf file.

The file argument should be the identifier of the file to read. It defaults to 'ams'. To access a file called something.rkf you need to call this function with file='something'. If there exists only one engine results .rkf file, you can call this function with file='engine' to access this file.

readrkf(section, variable, file='ams')[source]

Read data from section/variable of a chosen .rkf file.

The file argument should be the identifier of the file to read. It defaults to 'ams'. To access a file called something.rkf you need to call this function with file='something'. If there exists only one engine results .rkf file, you can call this function with file='engine' to access this file.

The type of the returned value depends on the type of variable defined inside KF file. It can be: single int, list of ints, single float, list of floats, single boolean, list of booleans or string.

Note

If arguments section or variable are incorrect (not present in the chosen file), the returned value is None. Please mind the fact that KF files are case sensitive.

read_rkf_section(section, file='ams')[source]

Return a dictionary with all variables from a given section of a chosen .rkf file.

The file argument should be the identifier of the file to read. It defaults to 'ams'. To access a file called something.rkf you need to call this function with file='something'. If there exists only one engine results .rkf file, you can call this function with file='engine' to access this file.

Note

If section is not present in the chosen file, the returned value is an empty dictionary. Please mind the fact that KF files are case sensitive.

get_rkf_skeleton(file='ams')[source]

Return a dictionary with the structure of a chosen .rkf file. Each key corresponds to a section name with the value being a set of variable names present in that section.

The file argument should be the identifier of the file to read. It defaults to 'ams'. To access a file called something.rkf you need to call this function with file='something'. If there exists only one engine results .rkf file, you can call this function with file='engine' to access this file.

get_molecule(section, file='ams')[source]

Return a Molecule instance stored in a given section of a chosen .rkf file.

The file argument should be the identifier of the file to read. It defaults to 'ams'. To access a file called something.rkf you need to call this function with file='something'. If there exists only one engine results .rkf file, you can call this function with file='engine' to access this file.

All data used by this method is taken from the chosen .rkf file. The molecule attribute of the corresponding job is ignored.

get_input_molecule()[source]

Return a Molecule instance with the initial coordinates.

All data used by this method is taken from ams.rkf file. The molecule attribute of the corresponding job is ignored.

get_main_molecule()[source]

Return a Molecule instance with the final coordinates.

All data used by this method is taken from ams.rkf file. The molecule attribute of the corresponding job is ignored.

get_main_ase_atoms()[source]

Return an ase.Atoms instance with the final coordinates.

An alternative is to call toASE(results.get_main_molecule()) to convert a Molecule to ASE Atoms.

All data used by this method is taken from ams.rkf file. The molecule attribute of the corresponding job is ignored.

get_history_molecule(step)[source]

Return a Molecule instance with coordinates taken from a particular step in the History section of ams.rkf file.

All data used by this method is taken from ams.rkf file. The molecule attribute of the corresponding job is ignored.

is_valid_stepnumber(main, step)[source]

Check if the requested step number is in the results file

get_system_version(main, step)[source]

Determine which Molecule version is requested

get_history_variables(history_section='History')[source]

Return a set of keynames stored in the specified history section of the ams.rkf file.

The history_section argument should be a string representing the name of the history section (``History`` or ``MDHistory``)

get_history_property(varname, history_section='History')[source]

Return the values of varname in the history section history_section.

get_property_at_step(step, varname, history_section='History')[source]

Return the value of varname in the history section history_section at step *step.

get_atomic_temperatures_at_step(step, history_section='MDHistory')[source]

Get all the atomic temperatures for step step

Note: Numbering of steps starts at 1

get_engine_results(engine=None)[source]

Return a dictionary with contents of AMSResults section from an engine results .rkf file.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_engine_properties(engine=None)[source]

Return a dictionary with all the entries from Properties section from an engine results .rkf file.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_energy(unit='au', engine=None)[source]

Return final energy, expressed in unit.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_gradients(energy_unit='au', dist_unit='au', engine=None)[source]

Return the gradients of the final energy, expressed in energy_unit / dist_unit.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_stresstensor(engine=None)[source]

Return the final stress tensor, expressed in atomic units.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_hessian(engine=None)[source]

Return the Hessian matrix, i.e. the second derivative of the total energy with respect to the nuclear coordinates, expressed in atomic units.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_elastictensor(engine=None)[source]

Return the elastic tensor, expressed in atomic units.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_frequencies(unit='cm^-1', engine=None)[source]

Return a numpy array of vibrational frequencies, expressed in unit.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_charges(engine=None)[source]

Return the atomic charges, expressed in atomic units.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_dipolemoment(engine=None)[source]

Return the electric dipole moment, expressed in atomic units.

The engine argument should be the identifier of the file you wish to read. To access a file called something.rkf you need to call this function with engine='something'. The engine argument can be omitted if there’s only one engine results file in the job folder.

get_dipolegradients(engine=None)[source]

Return the nuclear gradients of the electric dipole moment, expressed in atomic units. This is a (3*numAtoms x 3) matrix.

get_timings()[source]

Return a dictionary with timing statistics of the job execution. Returned dictionary contains keys cpu, system and elapsed. The values are corresponding timings, expressed in seconds.

get_pesscan_results(molecules=True)[source]

For PESScan jobs, this functions extracts information about the scan coordinates and energies.

molecules : bool
Whether to return a Molecule at each PES point.

Returns a dictionary, with the following keys:

‘RaveledScanCoords’: a list of str with the names of the scan coordinates: [‘sc_1_1’,’sc_1_2’,’sc_2_1’,’sc_2_2’,…]

‘nRaveledScanCoords’: the length of the previous list

‘RaveledUnits’: a list of str with the units: [‘bohr’, ‘bohr’, ‘radian’, ‘bohr’, …]

‘RaveledPESCoords’: a nested list with the values of the scan coordinates: [[val_1_1_1,val_1_1_2,…],[val_1_2_1,val_1_2_2,…],[val_2_1_1,val_2_1_2,…],[val_2_2_1,val_2_2_2]]

‘ScanCoords’: a nested list: [[‘sc_1_1’,’sc_1_2’],[‘sc_2_1’,’sc_2_2’],…]

‘nScanCoords’: length of the previous list

‘Units’: a nested list with the units: [[‘bohr’, ‘bohr’],[‘radian’, ‘bohr’], …]

‘OrigScanCoords’: a list of str in the newline-separated format stored on the .rkf file: [‘sc_1_1nsc_1_2’,’sc_2_1nsc_2_2’,…]

‘nPESPoints’: int, number of PES points

‘PES’: list of float, the energies at each PES point

‘Converged’: list of bool, whether the geometry optimization at each PES point converged

‘Molecules’: list of Molecule, the structure at each PES point. Only if the property molecules == True

‘HistoryIndices’: list of int, the indices (1-based) in the History section which correspond to the Molecules and PES.

‘Properties’: list of dict. The dictionary keys are what can be found on the AMSResults section of the engine .rkf file. These will only be populated if “CalcPropertiesAtPESPoints” is set to Yes when running the PES scan.

get_neb_results(molecules=True, unit='au')[source]

Returns a dictionary with results from a NEB calculation.

molecules : bool
Whether to include the ‘Molecules’ key in the return result
unit : str
Energy unit for the Energies, LeftBarrier, RightBarrier, and ReactionEnergy
Returns: dict

‘nImages’: number of images (excluding end points)

‘nIterations’: number of iterations

‘Energies’: list of energies (including end points)

‘Climbing’: bool, whether climbing image NEB was used

‘LeftBarrier’: float, left reaction barrier

‘RightBarrier’: float, right reaction barrier

‘ReactionEnergy’: float, reaction energy

‘HistoryIndices’: list of int, same length as ‘Energies’, contains indices in the History section

‘Molecules’: list of Molecule (including end points)

recreate_molecule()[source]

Recreate the input molecule for the corresponding job based on files present in the job folder. This method is used by load_external().

If ams.rkf is present in the job folder, extract data from the InputMolecule section.

recreate_settings()[source]

Recreate the input Settings instance for the corresponding job based on files present in the job folder. This method is used by load_external().

If ams.rkf is present in the job folder, extract user input and parse it back to a Settings instance using scm.input_parser module. Remove the system branch from that instance.

ok()[source]

Check if the execution of the associated job was successful or not. See Job.ok for more information.

get_errormsg()[source]

Tries to get an an error message for a associated job. This method returns None if the associated job was successful. See Job.get_errormsg for more information.

name

Retrun the job.name of the job associated with this results instance.

get_energy_landscape()[source]

Returns the energy landscape obtained from a PESExploration job run by the AMS driver. The energy landscape is a set of stationary PES points (local minima and transition states).

The returned object is of the type AMSResults.EnergyLandscape and offers convenient access to the states’ energies, geometries as well as the information on which transition states connect which minima.

el = results.get_energy_landscape()
print(el)

for state in el:
    print(f"Energy = {state.energy}")
    print(f"Is transition state = {state.isTS}")
    print("Geometry:", state.molecule)
    if state.isTS:
        print(f"Forward  barrier: {state.energy - state.reactants.energy}")
        print(f"Backward barrier: {state.energy - state.products.energy}")