Git Product home page Git Product logo

denspart's Introduction

DensPart

DensPart is an atoms-in-molecules density partitioning program. At the moment, it only features one method to partition the density, namely the Minimal Basis Iterative Stockholder (MBIS) scheme. See http://dx.doi.org/10.1021/acs.jctc.6b00456

Disclaimer: This implementation is a prototype and is not extensively tested yet. Future revisions may break backward compatibility of the API and file formats.

Minimal setup

Required dependencies:

Install (with dependencies):

pip install git+https://github.com/theochem/grid.git
pip install git+https://github.com/theochem/denspart.git

(There are no releases yet.)

Usage

One needs to construct a density.npz file, which is used as input for the denspart script. (The optional dependencies below provide convenient tools to make such files.)

The file density.npz uses the NumPy ZIP (NPZ) format, which is a simple container file format for arrays. More details on NPZ can be found here in the NumPy documentation. The file density.npz should contain at least the following arrays:

  • points: Quadrature grid points, shape (npoint, 3).
  • weights: Quadrature grid weights, shape (npoint, ).
  • density: Electron density at the grid points, shape (npoint, ).
  • atnums: Atomic numbers, shape (natom, ).
  • atcoords: Nuclear coordinates, shape (natom, 3).
  • cellvecs: (Optional) One, two or three cell vectors (rows) defining periodic boundary conditions, shape (nvec, 3).

All data are assumed to be in atomic units.

With a density.npz file, one can perform the partitioning as follows:

denspart density.npz results.npz

The output is stored in results.npz, and contains the following arrays. (These may be subject to change in future code revisions.)

  • Copied from the input file density.npz:

    • atnums: Atomic numbers, shape (natom, ).
    • atcoords: Nuclear coordinates, shape (natom, 3).
  • General outputs:

    • atnfn: The number of pro-density basis functions on each atom, shape (natom, ).

    • atnpar: The number of pro-density parameters for each atom, shape (natom, ).

    • charges: atomic partial charges, shape (natom,).

    • multipole_moments: Multipole moments (using spherical harmonics), for l going from 1 to 4, shape (natom, (lmax + 1)**2 - 1). The moments are in HORTON 2 order.

      c10 c11 s11
      c20 c21 s21 c22 s22
      c30 c31 s31 c32 s32 c33 s33
      c40 c41 s41 c42 s42 c43 s43 c44 s44
      

      In this list, the prefix c denotes cosine-like real spherical harmonics and s denotes the sine-like functions. The first digit refers to the degree l and the second to the order m.

    • propars: The pro-density parameters, shape (sum(atnpar), ).

    • radial_moments: Expectation values of r**n, for n going from 0 to 4, shape (natom, 5).

  • MBIS-specific outputs:

    • core_charges: MBIS core charges, shape (natom,).
    • valence_charges: MBIS valence charges, shape (natom,).
    • valence_widths: MBIS valence widths, shape (natom,).
  • Algorithm settings:

    • gtol: A stopping condition that was used for the optimization of the pro-density parameters. This is a threshold on the gradient of the extended KL divergence.
    • maxiter: A stopping condition that was used for the optimization of the pro-density parameters. This is the maximum number of iterations allowed in SciPy's trust-constr minimizer.
    • density_cutoff: A density cutoff parameter that was used to determine the cutoff radii for the local integration grids.

The arrays in the results.npz file can be accessed in Python as follows:

import numpy as np
results = np.load("results.npz")
print("charges", results["charges"])

# From here, one can convert data to other formats:
# - CSV
np.savetxt("charges.csv", results["charges"], delimiter=",")
# - JSON
import json
json.dump(results["charges"].tolist(), open("charges.json", "w"))

# One can also easily post-process the results with some scripting:
# - Molecular dipole moment predicted by the atomic charges.
print(np.dot(results["atcoords"].T, results["charges"]))
# - Contribution to the molecular dipole moment due to the atomic dipoles.
#   (This includes a reordering the spherical harmonics.)
print(results["multipole_moments"][:, [1, 2, 0]].sum(axis=0))

Optional dependencies and interfaces to quantum chemistry codes

IOData

See https://github.com/theochem/iodata

Install as follows:

pip install git+https://github.com/theochem/iodata.git

When IOData is installed, the npz output of the partitioning can be converted into an extended XYZ file as follows:

denspart-write-extxyz results.npz results.xyz

IOData and GBasis

In order to derive a density.npz from several wavefunction file formats (wfn, wfx, molden, fchk, ...), one needs install a two dependencies:

Install as follows:

pip install git+https://github.com/theochem/iodata.git
pip install git+https://github.com/theochem/gbasis.git

Once these are installed, one can compute densities on a grid from a wavefunction file. For example:

denspart-from-horton3 some-file.fchk density.npz

A minimal working example showing how to partition a density from a Gaussian FCHK can be found in examples/horton3.

GPAW

One may also derive a density.npz file from a GPAW calculation. When GPAW is installed, one can run:

denspart-from-gpaw some-file.gpw density.npz

A minimal working example can be found in examples/gpaw. Note that you may have to add mpirun in front of the command. However, the conversion does not yet support parallel execution and thus only works for the case of a single process, even when using mpirun.

ADF (AMS 2021.202)

One may also derive a density.npz from an ADF AMSJob. When AMS is installed, you can install denspart in the AMS Python environment as follows:

# If needed:
source ${ADFHOME}/amsbashrc.sh
# Avoid setting ADF and AMS environment variables manually, because these may change
# with different versions of AMS.

amspython -m pip install git+https://github.com/theochem/grid.git
amspython -m pip install git+https://github.com/theochem/denspart.git
# For writing the extended XYZ file:
amspython -m pip install git+https://github.com/theochem/iodata.git

Then, the conversion and partitioning are done as follows:

amspython -m denspart.adapters.adf ams.results density.npz
amspython -m denspart density.npz results.npz
amspython -m denspart.utils.write_extxyz results.npz results.xyz

where ams.results is the directory with output files. You need to disable symmetry and write out the TAPE10 file. More details can be found the the denspart.adapters.adf module. A minimal working example can be found in examples/adf.

Psi4

By adding a few lines to the Psi4 input script, it will write an NPZ file with Psi4's built-in molecular quadrature grids:

energy, wfn = psi4.energy(return_wfn=True)
from denspart.adapters.psi4 import write_density_npz
write_density_npz(wfn)

Symmetry is not supported, so you need to set the point group to c1 when specifying the geometry. A minimal working example can be found in examples/psi4.

Development setup

The development environment is configured as follows. It is assumed that you have direnv installed. (If not, you can manually the virtual environment.)

# Clone git repo, assuming you have ssh access to github
git clone [email protected]:theochem/denspart.git
cd denspart
# Create a virtual environment with all dependencies needed for testing
python -m venv venv
cat > .envrc << 'EOL'
source venv/bin/activate
export GPAW_SETUP_PATH=${PWD}/venv/share/gpaw-setups-0.9.20000
EOL
direnv allow
pip install -U pip
pip install -e .
# Mandatory dependency, but not yet included in setup.py
pip install --upgrade git+https://github.com/theochem/grid.git
# Development tools
pip install --upgrade pre-commit ruff black
# Extra dependency for testing adapters
pip install --upgrade git+https://github.com/theochem/iodata.git
pip install --upgrade git+https://github.com/theochem/gbasis.git
pip install --upgrade git+https://github.com/tovrstra/pytest-regressions@npz
pip install --upgrade ase
# (Make sure BLAS and LibXC are installed, so GPAW can link to them.)
# Fedora: sudo dnf install libxc-devel blas-devel
pip install --upgrade gpaw
# Install GPAW pseudopotentials
gpaw install-data venv/share

To run all tests locally:

pre-commit run --all
pytest

denspart's People

Contributors

dependabot[bot] avatar farnazh avatar kzinovjev avatar pre-commit-ci[bot] avatar rubengoeminne avatar tovrstra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

denspart's Issues

how to make MBIS work with def2-ECP?

Quick question: for atoms with ECP, e.g., Iodine atoms in def2-ECP basis, the electron density distribution is heavily modified by ECP compared to other all-electron basis. The projection to the minimal Slater basis then fails due to the incompatible functional forms between a slater basis and ECP density distribution. Is there a known workaround to circumvent this problem?

MBIS charges from fchk

Hi, I was wondering if I could receive some guidance on how to get MBIS charges from a directory of fchk files. I am running into some issues, that are definitely user error and could use some help.
Best,
Kate

sj keyword in GPAW

sj keyword in GPAW prevents denspart-from-gpaw from generating the density.npz

sj provides parameters for the Solvation Jellium Model, which sets a charge on the atomistic model and a counter-charge on the jellium. Such model allows to generating cube files and (supposedly) obtaining the MBIS charges.

See https://wiki.fysik.dtu.dk/gpaw/tutorialsexercises/electrostatics/sjm/solvated_jellium_method.html#solvated-jellium-method
and https://wiki.fysik.dtu.dk/gpaw/documentation/sjm/sjm.html

Analysis of cube files

Apparently the denspart works with specific formats, except for a more general cube format.
What data and metadata is missing in the cube that is needed to evaluate the MBIS?

The definition of cutoff radius of density

def get_cutoff_radius(self, density_cutoff):
if density_cutoff <= 0.0:
return np.inf
population, exponent = self.pars
return (np.log(population) - np.log(density_cutoff)) / exponent

Is the prefactor $\frac{\alpha^3_{Ai}}{8 \pi}$ missed in the definition of the cutoff radius of radial density?

$$\rho_{Ai}^0(\vec{r}) = N_{Ai} f_{Ai}(\vec{r}) = \frac{N_{Ai} \alpha^3_{Ai}}{8\pi}e^{-\alpha_{Ai}|\vec{r}-\vec{R}_A|}$$

underflow encountered in exp

Hi, I am using the latest denspart to compute the MBIS charge for NaCl+ molecule and I got an underflow floating point error. Could you help me to figure out how to solve it? I have attached the npz input file of my system here.

density.npz.zip

MBIS partitioning --
Building local grids
Integral of density: 27.0000312435445
Optimization
#Iter  #Call         ekld          kld  -constraint     grad.rms  cputime (s)
-----  -----  -----------  -----------  -----------  -----------  -----------
    1      1    0.9464229   -0.0535358   9.9996e-01   2.7860e-01    0.0008520
    2      2    0.9201671    0.2156242   7.0454e-01   4.8488e-01    0.0004890
    3      3    0.5248671   -0.0043593   5.2923e-01   3.0010e-01    0.0003740
    4      4    0.4227335   -0.1046833   5.2742e-01   1.0734e-01    0.0003590
    5      5    0.4141565   -0.1132869   5.2744e-01   9.2535e-02    0.0003790
    6      6    0.3621397   -0.1258460   4.8799e-01   4.7860e-02    0.0005020
    7      6    0.3621397   -0.1258460   4.8799e-01   4.7860e-02    0.0005020
    8      7    0.3476923   -0.0592254   4.0692e-01   3.8484e-02    0.0004180
    9      8    0.3385307    0.0251115   3.1342e-01   3.0207e-02    0.0004790
   10      9    0.3288468    0.1784912   1.5036e-01   1.3023e-02    0.0003790
   11      9    0.3288468    0.1784912   1.5036e-01   1.3023e-02    0.0003790
   12     10    0.3270108    0.2639925   6.3018e-02   5.3819e-03    0.0004440
   13     11    0.3261740    0.3118730   1.4301e-02   4.2858e-03    0.0004120
   14     12    0.3260905    0.3015101   2.4580e-02   3.1220e-03    0.0003650
Traceback (most recent call last):
  File "/chemtools/bin/denspart", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/__main__.py", line 50, in main
    pro_model, localgrids = optimize_reduce_pro_model(
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/vh.py", line 51, in optimize_reduce_pro_model
    pro_model, localgrids = optimize_pro_model(
                            ^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/vh.py", line 153, in optimize_pro_model
    optresult = minimize(
                ^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_minimize.py", line 746, in minimize
    res = _minimize_trustregion_constr(fun, x0, args, jac, hess, hessp,
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py", line 528, in _minimize_trustregion_constr
    _, result = tr_interior_point(
                ^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_trustregion_constr/tr_interior_point.py", line 321, in tr_interior_point
    z, state = equality_constrained_sqp(
               ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_trustregion_constr/equality_constrained_sqp.py", line 161, in equality_constrained_sqp
    f_next, b_next = fun_and_constr(x_next)
                     ^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_trustregion_constr/tr_interior_point.py", line 82, in function_and_constraints
    f = self.fun(x)
        ^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_differentiable_functions.py", line 324, in fun
    self._update_x(x)
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_differentiable_functions.py", line 282, in _update_x
    self._update_hess()
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_differentiable_functions.py", line 315, in _update_hess
    self._update_grad()
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_differentiable_functions.py", line 306, in _update_grad
    self.g = self._wrapped_grad(self.x, f0=self.f)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_differentiable_functions.py", line 41, in wrapped
    return np.atleast_1d(grad(np.copy(x), *args))
                         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_optimize.py", line 83, in derivative
    self._compute_if_needed(x, *args)
  File "/chemtools/lib/python3.11/site-packages/scipy/optimize/_optimize.py", line 73, in _compute_if_needed
    fg = self.fun(x, *args)
         ^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/vh.py", line 462, in ekld
    pro = pro_model.compute_density(grid, localgrids, cache)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/vh.py", line 380, in compute_density
    np.add.at(pro, localgrid.indices, fn.compute(localgrid.points, cache))
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/mbis.py", line 98, in compute
    exp = self._compute_exp(exponent, dists, cache)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/mbis.py", line 86, in _compute_exp
    return compute_cached(
           ^^^^^^^^^^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/cache.py", line 66, in compute_cached
    result = func()
             ^^^^^^
  File "/chemtools/lib/python3.11/site-packages/denspart/mbis.py", line 90, in <lambda>
    func=(lambda: np.exp(-exponent * dists)),
                  ^^^^^^^^^^^^^^^^^^^^^^^^^
FloatingPointError: underflow encountered in exp

Explicitly adding a constraint does not work

By adding constraints explicitly, i.e., $\sum_{A,i} c_{Ai} = \int \rho(\vec{r}) d\vec{r} = N_{mol}$, we cannot necessarily obtain the same result. This equality constraint may be too strict for the minimizer.

    with np.errstate(all="raise"):
        # The errstate is changed to detect potentially nasty numerical issues.
        # Optimize parameters within the bounds.

        A = np.zeros((len(pars0), len(pars0)), float)
        A[0, 0:-1:2] = 1
        b = np.zeros((len(pars0, )))
        b[0] = pop
        print(A, b)
        constraint = LinearConstraint(A, lb=b, ub=b, keep_feasible=True)
        bounds = sum([fn.bounds for fn in pro_model.fns], [])

        optresult = minimize(
            cost_grad,
            pars0,
            method="trust-constr",
            jac=True,
            hess=SR1(),
            bounds=bounds,
            constraints=constraint,
            callback=callback,
            options={"gtol": gtol, "maxiter": maxiter},
        )

output:

  126      6    2.0664675    2.0664675  -0.0000e+00   6.1163e-01    0.0484080
-----  -----  -----------  -----------  -----------  -----------  -----------
Optimizer message: "`xtol` termination condition is satisfied."
Total charge:             -2.3269698e-06
Sum atomic charges:       -2.3269698e-06
Promodel
 ifn iatom  atn       parameters...
   0     0    8       1.32925343     18.58879411
   1     0    8       4.66929957      3.48991506
   2     1    1       2.86085588      1.14814615
   3     2    1       1.14059344      1.89308011
Computing additional properties
Sum of charges:  -2.326969790633626e-06
AIM charges: [ 2.001447   -1.86085588 -0.14059344]

Without the constrain, the output is:

   50     44    0.2242531    0.2242531   4.4487e-08   6.7676e-09    0.0521780
-----  -----  -----------  -----------  -----------  -----------  -----------
Optimizer message: "`gtol` termination condition is satisfied."
Total charge:             -2.3269698e-06
Sum atomic charges:       -2.3714572e-06
Promodel
 ifn iatom  atn       parameters...
   0     0    8       1.48539364     18.89318746
   1     0    8       7.05783539      2.68722754
   2     1    1       0.72838059      2.76389621
   3     2    1       0.72839276      2.76387596
Computing additional properties
Sum of charges:  -2.371457152872125e-06
AIM charges: [-0.54322902  0.27161941  0.27160724]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.