pnictogen icon indicating copy to clipboard operation
pnictogen copied to clipboard

⚛️ A Python library and a command-line tool that creates input files for computational chemistry packages

.. |build-badge| image:: https://travis-ci.org/schneiderfelipe/pnictogen.svg?branch=master :target: https://travis-ci.org/schneiderfelipe/pnictogen :alt: Travis CI Status

.. |pypi-badge| image:: https://badge.fury.io/py/pnictogen.svg :target: https://badge.fury.io/py/pnictogen :alt: PyPI Version

|build-badge| |pypi-badge|

Welcome to pnictogen

pnictogen_ is both a library and a command-line tool that helps composing input files for computational chemistry packages. It is based on Jinja2_, a modern and friendly templating language for Python:

.. code:: bash

$ cat new_template.ORCA.inp
# {{ molecule.name }}
! Opt

* xyz {{ molecule.charge }} {{ molecule.mult }}
{{ molecule.to_string("xyz") }}
*
$ pnictogen new_template.ORCA.inp data/water.xyz
data/water.inp written
$ cat data/water.inp
# A water molecule
! Opt

* xyz 0 1
O          0.05840        0.05840        0.00000
H          1.00961       -0.06802        0.00000
H         -0.06802        1.00961        0.00000
*

.. _pnictogen: https://github.com/schneiderfelipe/pnictogen .. _Jinja2: http://jinja.pocoo.org/docs/latest/

Installation

You can get pnictogen directly from PyPI:

.. code:: bash

$ pip install -U pnictogen

The above will install the the version from PyPI, which is recommended.

For the development version, clone this repository and run:

.. code:: bash

$ pip install -U -e .

Tutorial

pnictogen can currently create boilerplates for ADF <https://www.scm.com/product/adf/>, DALTON <http://daltonprogram.org/>, GAMESS (US) <http://www.msg.ameslab.gov/GAMESS/GAMESS.html>, GAMESS-UK <http://www.cfs.dl.ac.uk/>, Gaussian <http://www.gaussian.com/>, Jaguar <https://www.schrodinger.com/jaguar>, Molpro <http://www.molpro.net/>, MOPAC <http://openmopac.net/>, MPQC <http://www.mpqc.org/>, NWChem <http://www.nwchem-sw.org/index.php/Main_Page>, ORCA <https://orcaforum.cec.mpg.de/>, Psi <http://psicode.org/>, Q-Chem <http://q-chem.com/>_ and ZINDO <https://comp.chem.umn.edu/zindo-mn/>_:

.. code:: bash

$ pnictogen -g new_template.MOPAC.mop
new_template.MOPAC.mop written
$ cat new_template.MOPAC.mop
CHARGE={{ molecule.charge }} MS={{ (molecule.mult - 1)/2 }}
{{ molecule.name }}

{{ molecule.to_string("mop") }}

(pnictogen -g new_template.inp creates a blank file.)

You can either create and edit a boilerplate template or start fresh. Once you have a template, generating inputs is easy:

.. code:: bash

$ pnictogen new_template.ORCA.inp data/co.xyz data/water.xyz
data/co.inp written
data/water.inp written

(Wildcards are allowed, e.g., pnictogen new_template.ORCA.inp *.xyz works.)

Since pnictogen is built on top of Pybel <https://open-babel.readthedocs.io/en/latest/UseTheLibrary/Python_PybelAPI.html>, so it is able to read anything Open Babel <http://openbabel.org/wiki/Main_Page> reads. Check the list of all available file formats here <https://open-babel.readthedocs.io/en/latest/FileFormats/Overview.html>_.

Templates

You can use the full Jinja2 syntax within templates (check here <http://jinja.pocoo.org/docs/2.10/templates/>_ its documentation for details).

Besides this, pnictogen also understands a special delimiter (--@) that allows one to generate many inputs from a single file:

.. code:: bash

$ cat repo/MOPAC.mop
{% for molecule in molecule %}
--@{{ loop.index }}
CHARGE={{ molecule.charge }} MS={{ (molecule.mult - 1)/2 }}
{{ molecule.name }}

{{ molecule.to_string("mop") }}

{% endfor %}
$ pnictogen repo/MOPAC.mop data/pentane_conformers.xyz
data/pentane_conformers_1.mop written
data/pentane_conformers_2.mop written
data/pentane_conformers_3.mop written
data/pentane_conformers_4.mop written
data/pentane_conformers_5.mop written
data/pentane_conformers_6.mop written
data/pentane_conformers_7.mop written

The rest of the line after --@ is aways added to the name of the inputs after an underscore (_).

In the example above, data/pentane_conformers.xyz contains seven conformers of pentane, so seven inputs were generated (the counting is provided by loop.index):

.. code:: bash

$ cat data/pentane_conformers_5.mop
CHARGE=0 MS=0.0
C5H12

C   1.23923 1  1.46892 1 -1.23930 1
C   1.24920 1  0.57161 1  0.00000 1
C  -0.00000 1 -0.31179 1 -0.00000 1
C  -1.24920 1  0.57161 1 -0.00000 1
C  -2.49842 1 -0.31168 1  0.01981 1
H   1.23217 1  0.84960 1 -2.13625 1
H   0.34926 1  2.09811 1 -1.22516 1
H   2.12917 1  2.09831 1 -1.23936 1
H   2.13917 1 -0.05758 1 -0.01415 1
H   1.25625 1  1.19094 1  0.89694 1
H  -0.00000 1 -0.94109 1 -0.89000 1
H  -0.00000 1 -0.94109 1  0.89000 1
H  -1.24217 1  1.21085 1  0.88286 1
H  -1.25629 1  1.19089 1 -0.89697 1
H  -2.50545 1 -0.95092 1 -0.86305 1
H  -2.49134 1 -0.93096 1  0.91678 1
H  -3.38842 1  0.31762 1  0.01981 1

Example: energy decomposition analysis (EDA) with ADF

Imagine we want to do energy decomposition analysis <https://doi.org/10.1002/wcms.71>_ on the following water dimer:

.. code:: bash

    $ cat water-dimer.xyz
    6

    O          0.12908       -0.26336        0.64798
    H          0.89795        0.28805        0.85518
    H          0.10833       -0.20468       -0.33302
    O          0.31020        0.07569       -2.07524
    H          0.64083       -0.57862       -2.71449
    H         -0.26065        0.64232       -2.62218

The following template uses both molecule.split() and molecule.to_string("xyz") functions to generate ADF inputs in bulk:

.. code:: bash

$ cat split.ADF.in
{% set frags = molecule.split([range(3), range(3, 6)]) %}
--@eda
ATOMS Cartesian
{% for frag in frags %}
{{ frag.to_string("xyz", dialect="adf", fragment_id="f{}".format(loop.index)) }}
{% endfor %}
End

Fragments
{% for frag in frags %}
 f{{ loop.index }} {{ input_prefix }}_f{{ loop.index }}.t21
{% endfor %}
End

{% for frag in frags %}
--@f{{ loop.index }}
ATOMS Cartesian
{{ frag.to_string("xyz") }}
End

{% endfor %}
$ pnictogen split.ADF.in data/water-dimer.xyz
data/water-dimer_eda.in written
data/water-dimer_f1.in written
data/water-dimer_f2.in written

The above creates inputs like the following:

.. code:: bash

$ cat water-dimer_eda.in
ATOMS Cartesian
O          0.12908       -0.26336        0.64798       f=f1
H          0.89795        0.28805        0.85518       f=f1
H          0.10833       -0.20468       -0.33302       f=f1
O          0.31020        0.07569       -2.07524       f=f2
H          0.64083       -0.57862       -2.71449       f=f2
H         -0.26065        0.64232       -2.62218       f=f2
End

Fragments
f1 data/water-dimer_f1.t21
f2 data/water-dimer_f2.t21
End

$ cat water-dimer_f1.in
ATOMS Cartesian
O          0.12908       -0.26336        0.64798
H          0.89795        0.28805        0.85518
H          0.10833       -0.20468       -0.33302
End