Code Monkey home page Code Monkey logo

irc's Introduction

Internal Redundant Coordinates

Build Status codecov GitHub license GitHub top language

DOI

DISCLAMIER: IRC is still in beta. It is integrated in the quantum chemistry code entos.

IRC is a modern C++ library for the determination of internal redundant coordinates (and transformation to and from Cartesian coordinates) for geometry optimization of molecules. The aim of this library is to provide an easy-to-use, flexible and portable implementation of internal redundant coordinates for modern electronic structure codes.

Compilation and Installation

Dependencies

IRC has the following dependencies:

BGL functionality is used determine the connectivity of the molecule and therefore the Boost is a requirement for the library to work.

IRC also needs a linear algebra library. Armadillo and Eigen are supported out-of-the-box, but other linear algebra libraries can be easily added.

For standalone installation and testing, IRC also requires CMake.

Build IRC

Armadillo

  mkdir build && cd build
  cmake -DWITH_ARMA=TRUE ..
  make -j

Eigen

  mkdir build && cd build
  cmake -DWITH_EIGEN=TRUE ..
  make -j

Test

  ctest

Include IRC in your project

IRC is an header-only library and its inclusion is quite straightforward.

With CMake

Libirc installs CMake configuration files that enable use of the library with find_package. The irc CMake target is named irc. Armadillo and Eigen dependencies are resolved at configuration time of this library and the relevant compile definitions and includes are set in the configuration files.

Without CMake

Armadillo

If you are using Armadillo as linear algebra library you just need to include the header files in include/ and define the variable HAVE_ARMA.

Eigen

If you are using Eigen3 as linear algebra library, you need to include the header files in include/ as well as the extension to Eigen3's matrix constructors to support std::initializer_lists located in external/eigen/plugins/. The content of the file Matrix_initializer_list.h must be included Eigen3's matrix class as described here, therefore you need to set the variable EIGEN_MATRIXBASE_PLUGIN to "path_to/Matrix_initializer_list.h". Finally, you have to define the variable HAVE_EIGEN3.

Custom Linear Algebra Library

If your are using a custom linear algebra library supporting the initialization of vectors and matrices from std::initializer_lists, you have to implement the linear algebra functions in include/libirc/linalg.h and you are good to go.

Usage

IRC is mainly based on free functions, therefore every function can be used out-of-the-box. However, a wrapper class IRC with the main functionalities needed in geomerty optimization is provided.

The first step to use IRC is to build a molecule. In IRC a molecule is represented as an std::vector of atoms (irc::atom::Atom<Vector3>):

template <typename Vector3>
using irc::molecule::Molecule<Vector3> = std::vector<irc::atoms::Atom<Vector3>>;

where an atom is simply defined by an atomic number and its position (stored in a three-dimensional vector of type Vector3). In order to use IRC, you will need to implement a function that converts your molecule to an irc::molecule::Molecule:

template<typename Vector3>
irc::molecule::Molecule<Vector3> convert_my_molecule_to_irc_molecule(const MyMolecule&);

Once you have an IRC molecule irc::molecule::Molecule<Vector3>, you can build an irc::IRC<Vector3,Vector,Matrix> object:

irc::IRC<Vector3, Vector, Matrix>(const irc::molecule::Molecule&);

The irc::IRC class provides an initial guess of the Hessian in redundant internal coordinates (Matrix projected_initial_hessian_inv()), a projector for the update Hessian (Matrix projected_hessian_inv(const Matrix &)), the transformation of the gradient from Cartesian to redundant internal coordinates (Vector grad_cartesian_to_projected_irc(const Vector &)) and the transformation from the updated redundant internal coordinates to Cartesian coordinates (Vector irc_to_cartesian(const Vector &, const Vector &, const Vector &x_c_old, size_t, double)). In addition, the transformation from Cartesian to redundant internal coordinates is also provided (Vector cartesian_to_irc(const Vector &)).

User-defined internal coordinates

Tests and Code Coverage

Catch2

Tests are written using the multi-paradigm test framework Catch2. Catch2 is included as a single header file in include/catch.

CTest

Tests are run using the CTest testing tool distributed as a part of CMake.

To run the test use:

  ctest

Code Formatting

The code is formatted using clang-format. The style configuration is based on LLVM style.

To format your code before opening a PR use:

bash tool/clang-format.sh

Contributions

Any contribution to this open-source project is very welcome. If you are considering contributing don't hesitate to contact the main contributors.

You may find beneficial to have a look at the Open Source Guides.

Sources

Papers

  • P. Puly and G. Fogarasi, Geometry optimization in redundant internal coordinates, J. Chem. Phys. 96 2856 (1992).

  • C. Peng, P. Y. Ayala and H. B. Schlegel, Using Redundant Internal Coordinates to Optimize Equilibrium Geometries and Transition States, J. Comp. Chem. 17, 49-56 (1996).

  • V. Bakken and T. Helgaker, The efficient optimization of molecular geometries using redundant internal coordinates, J. Chem. Phys. 117, 9160 (2002).

Books

  • E. Bright Wilson Jr., J. C. Decius and P. C. Cross, Molecular Vibrations: The Theory of Infrared and Raman Vibrational Spectra, Dover Publications Inc. (2003).

irc's People

Contributors

jan-grimo avatar nabbelbabbel avatar peterbygrave avatar rmeli avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar

irc's Issues

Enforce integers in distance and predecessor matrices

The predecessor and distance matrices should only contain integers. The use of double-precision matrices to store integer can mess up with operator== in irc::connectivity::bonds, irc::connectivity::angles and irc::connectivity::dihedrals.

cartesian_to_irc produces 180 degree dihedrals with random sign

Hello, I hope I can explain this right, but I observed the issue as described in the title. Take ethane as an example. it produces the following coordinates:

New internal
  (redundant) coordinates: 28
*************************************
  7 bonds / Å
*************************************
  (   0,   1)        1.4613
  (   0,   2)        1.0941
  (   1,   3)        1.0941
  (   0,   4)        1.0941
  (   1,   5)        1.0941
  (   0,   6)        1.0941
  (   1,   7)        1.0941
*************************************
  12 angles / °:
*************************************
  (   1,   0,   2)  111.84
  (   0,   1,   3)  111.84
  (   1,   0,   4)  111.84
  (   2,   0,   4)  107.00
  (   0,   1,   5)  111.84
  (   3,   1,   5)  107.00
  (   1,   0,   6)  111.84
  (   2,   0,   6)  107.00
  (   4,   0,   6)  107.00
  (   0,   1,   7)  111.84
  (   3,   1,   7)  107.00
  (   5,   1,   7)  107.00
*************************************
  9 dihedrals / °
*************************************
  (   2,   0,   1,   3)   -60.00
  (   3,   1,   0,   4)    60.00
  (   2,   0,   1,   5)   180.00
  (   4,   0,   1,   5)   -60.00
  (   3,   1,   0,   6)   -180.00
  (   5,   1,   0,   6)    60.00
  (   2,   0,   1,   7)    60.00
  (   4,   0,   1,   7)  -180.00
  (   6,   0,   1,   7)   -60.00
*************************************

If you run cartesian_to_iirc successive times the outcome of the 180 dihedral angles flip sign. it may give

 (   2,   0,   1,   5)   180.00
 (   3,   1,   0,   6)  -180.00
 (   4,   0,   1,   7)  -180.00

or sometimes

(   2,   0,   1,   5)  -180.00
(   3,   1,   0,   6)  180.00
(   4,   0,   1,   7)  180.00

but only for the 180 degree case.

As you can imagine this can pay havoc with geometry optimization because dihedrals that have flipped 360 degrees during a geometry optimization step can give rogue values for dq,

one can get dq = 2 pi when it should have been dq = 0, or something very small.

Yesterday, I put a plaster in my own code to detect this flip, so I could work around the issue. Of course, it would be nice to see what the issue in libirc is.

Thus far, I've made the following change; It works in all my tests so far, but not knowing your code base very well I don't if there could be unwanted consequences

In constsnts.h I added

// dihedrals near 2 pi
constexpr double dihedral_near_180_tol{1e-6};

and in connectivity.h I changed the following lines, around 440 thereabouts

// Compute dihedral angle in radians (in the interval [-pi,pi])
  double angle{std::atan2(y, x)};
  
  if (std::fabs(std::fabs(angle) - tools::constants::pi) < tools::constants::dihedral_near_180_tol) 
        angle = std::fabs(angle);

  return angle;

What do you think ?

Best regards.

oh ad thanks for the library, great stuff.

Catch SECTIONs in loops

According to Catch2 documentation, for different SECTIONs every TEST_CASE is restarted. This means that if some SECTIONs are in loops, only the first cycle is executed.

Change name

Redundant internal coordinates is usually used in the literature.

Documentation

Generate documentation and push on gh-pages branch.

Eigen3 not found on Linux with Travis-CI

From Travis-CI

CMake Error at CMakeLists.txt:94 (find_package):
  Could not find a configuration file for package "Eigen3" that is compatible
  with requested version "3.0".
  The following configuration files were considered but not accepted:
    /usr/lib/cmake/eigen3/Eigen3Config.cmake, version: unknown

User-defined bonds, angles and dihedrals might be redundant

User-defined bond are added to the list of bonds, angles and dihedrals obtained from the connectivity of the molecule and therefore might be redundant.

The same problem will arise with constraints: an added constraint can or can not correspond to a bond, angle or dihedral that is obtained from the connectivity.

Interfragments bonds

Contrasting definitions of interfragment bonds.

Peng et al.:

If the molecular system consists of two or more fragments [...], then the shortest distance [d_min] between the fragments is determined; all interfragment distances [d] that are less than the smaller of 1.3 times this distance, or 2 angstrom, are designated as bonds.

This corresponds to the following condition:

d < min(1.3 * d_min, 2 * angstrom_to_bohr)

Bakken and Helgaker:

If two (or more) [...] fragments are found, the shortest bond between two atoms belonging to separate fragments [d_min] defines an interfragment bond coordinate. Other interfragment distances [d] that are either less than 2 angstrom or less than 1.3 times the interfragment bond coordinate constitute the auxiliary interfragment bonds.

This corresponds to the following condition:

d < max(1.3 * d_min, 2 * angstrom_to_bohr)

Eigen 3.4 adds std::initializer_list constructors

Eigen 3.4 adds std::initializer_list constructors and this does not play nicely with the custom constructor defined in libirc/plugins/eigen/.

Trying to compile with Eigen 3.4 results in the following error, given that there are now two constructors with the same signature:

/Users/rmeli/Documents/git/projects/irc/src/test/wilson_test.cpp:92:9: error: call to constructor of 'const Eigen::Matrix<double, -1, -1, 0>' is ambiguous
        {// Rotation for H1
        ^~~~~~~~~~~~~~~~~~~
/usr/local/include/eigen3/Eigen/src/Core/Matrix.h:321:34: note: candidate constructor
    explicit EIGEN_STRONG_INLINE Matrix(const std::initializer_list<std::initializer_list<Scalar>>& list) : Base(list) {}
                                 ^
/Users/rmeli/Documents/git/projects/irc/include/libirc/plugins/eigen/Matrix_initializer_list.h:60:21: note: candidate constructor
EIGEN_STRONG_INLINE Matrix(std::initializer_list<std::initializer_list<_Scalar>> initlist) : Base()
                    ^
/Users/rmeli/Documents/git/projects/irc/src/test/wilson_test.cpp:96:9: error: call to constructor of 'const Eigen::Matrix<double, -1, -1, 0>' is ambiguous
        {// Rotation for O
        ^~~~~~~~~~~~~~~~~~
/usr/local/include/eigen3/Eigen/src/Core/Matrix.h:321:34: note: candidate constructor
    explicit EIGEN_STRONG_INLINE Matrix(const std::initializer_list<std::initializer_list<Scalar>>& list) : Base(list) {}
                                 ^
/Users/rmeli/Documents/git/projects/irc/include/libirc/plugins/eigen/Matrix_initializer_list.h:60:21: note: candidate constructor
EIGEN_STRONG_INLINE Matrix(std::initializer_list<std::initializer_list<_Scalar>> initlist) : Base()
                    ^
/Users/rmeli/Documents/git/projects/irc/src/test/wilson_test.cpp:100:9: error: call to constructor of 'const Eigen::Matrix<double, -1, -1, 0>' is ambiguous
        {// Rotation for H2
        ^~~~~~~~~~~~~~~~~~~
/usr/local/include/eigen3/Eigen/src/Core/Matrix.h:321:34: note: candidate constructor
    explicit EIGEN_STRONG_INLINE Matrix(const std::initializer_list<std::initializer_list<Scalar>>& list) : Base(list) {}
                                 ^
/Users/rmeli/Documents/git/projects/irc/include/libirc/plugins/eigen/Matrix_initializer_list.h:60:21: note: candidate constructor
EIGEN_STRONG_INLINE Matrix(std::initializer_list<std::initializer_list<_Scalar>> initlist) : Base()
                    ^
/Library/Developer/CommandLineTools/SDKs/MacOSX11.3.sdk/usr/include/c++/v1/vector:566:41: note: passing argument to parameter '__il' here
    vector(initializer_list<value_type> __il);
                                        ^
/Users/rmeli/Documents/git/projects/irc/src/test/wilson_test.cpp:170:15: error: call to constructor of 'const mat' (aka 'const Matrix<double, Dynamic, Dynamic>') is ambiguous
    const mat R{{cos(angle_rad), -sin(angle_rad), 0},
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/eigen3/Eigen/src/Core/Matrix.h:321:34: note: candidate constructor
    explicit EIGEN_STRONG_INLINE Matrix(const std::initializer_list<std::initializer_list<Scalar>>& list) : Base(list) {}
                                 ^
/Users/rmeli/Documents/git/projects/irc/include/libirc/plugins/eigen/Matrix_initializer_list.h:60:21: note: candidate constructor
EIGEN_STRONG_INLINE Matrix(std::initializer_list<std::initializer_list<_Scalar>> initlist) : Base()
                    ^
4 errors generated.

Some dihedral angles not found

The search of the shortest path does not work when between two atoms there are two paths of the same length (ring structures).

Relative paths

Get rid of relative paths. Relative paths can be problematic for refactoring and for out of source builds.

Non-template functions need to inlined

The library is header only and needs to have all non template functions as inline e.g.
double pirange_rad(double angle) noexcept

Just found this because I have two .cpp files that #include libirc/irc_*.h

Support for Eigen3

Adding support for Eigen3 is more complicated than predicted since vectors and matrices can't be initialized using std::initializer_list.

Targeted code coverage

Exclude boost, catch and other libraries from code coverage. Code coverage is now unrealistically low.

Wilson matrix is order-dependent

The Wilson matrix and, consequently, the infinitesimal displacements in internal redundant coordinates are dependent on the order of the atoms within the molecules.

New features

After discussing with @peterbygrave new features will be integrated to IRC. The changes are the following:

  • Additional coordinate systems
    • DLC
    • HDLC
    • TRIC
  • Additional initial Hessian model(s)
  • Constraints

This issue is to track the integration, which will likely involve a refactoring of the library to change name (see Issue #15). There is no precise timeline for this, but priority will be given to additional coordinate systems.

Does not compile on intel

Many compiler errors on intel. Seems like it is a bit more strict on constructs like:

auto a{123}; // < evaluates to a std::initializer_list<int> auto a = 123; // < evaluate to a int

https://godbolt.org/g/dMV1Gc

I will fix them in entos whilst I compile on BC4 and port them back

Test Wilson's B matrix

Wilson's B matrix elements can be easily computed by finite differences. This can be used for extensive testing.

Include Boost BGL headers

Include Boost BGL headers within the library to reduce compatibility issues and external dependencies.

transformation::irc_to_cartesian() diverging

Hi,

I have had another look at this library.
After observing strange behavior in some optimizations I have taken a closer look at the function mentioned above.
The cause of the strange behavior might still be my doing in the interfacing code, however, I noticed something odd.

If I interpret a 90° water such as:

3                                                                                
                                                                                 
O      0.0000000000    0.0000000000    0.0000000000                              
H      1.0000000000    0.0000000000    0.0000000000                              
H      0.0000000000    1.0000000000    0.0000000000                              

into IRCs (initializing the IRC class with this geometry), and then modify the internal coordinates a bit (1 gradient descent step using PM3, or a newton step using the approximate Hessian provided by the library) and then back-transform to Cartesian, I am getting this:

3                                                                                
                                                                                 
O      0.0034791746    0.0034791746    0.0000000000                              
H      1.0049698622   -0.0084490368    0.0000000000                              
H     -0.0084490368    1.0049698622    0.0000000000 

Which actually looks fine at first sight, however, a closer look reveals that it is the default first step of the procedure in transformation::irc_to_cartesian(), because the entire thing diverges and that is the fallback. Out of curiosity I added some debug statements an got the RMS of dx and dq being:

# Step RMS(dx) RMS(dq)
 1 9.26589e-03 1.39642e-02
 2 2.25472e+00 3.57957e+00
 3 3.14687e+00 5.03741e+00
 4 5.64083e+00 1.01261e+01
 5 1.01696e+01 1.99239e+01
 6 1.91867e+01 3.92193e+01
 7 37.3121e+01 7.77827e+01
 8 7.36904e+01 1.55023e+02
 9 1.46562e+02 3.09649e+02
10 2.92394e+02 6.19029e+02
11 5.84118e+02 1.23788e+03
12 1.16761e+03 2.47566e+03
13 2.33461e+03 4.95124e+03
14 4.66863e+03 9.90245e+03
15 9.33668e+03 1.98049e+04
16 1.86728e+04 3.96097e+04
17 3.73450e+04 7.92195e+04
18 7.46894e+04 1.58439e+05
19 1.49378e+05 3.16878e+05
20 2.98756e+05 6.33756e+05
21 5.97511e+05 1.26751e+06
22 1.19502e+06 2.53502e+06
23 2.39004e+06 5.07005e+06
24 4.78009e+06 1.01401e+07
25 9.56017e+06 2.02802e+07

across the default 25 steps.
Testing with other molecules showed that I can not converg the back-transformation once. It always diverges and falls back, which works fine for some optimizations.
Given that Bakken and Helgaker describe this as a seldom occuring oddity in their paper, and it happens for water I am confused what is going on here.

FYI I am using:

  • Eigen3 3.3.7 (linking mkl)
  • gcc 8.3.0 (incl. -march=native)
  • boost 1.69.0

Cheers,
Jan

Numerical Wilson B matrix

The numerical Wilson B matrix has elements in different units than the analytical one, because IRC are in degrees instead of radians.

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.