Program Listing for File ecp.cpp

Return to documentation for file (/Users/robertshaw/devfiles/libecpint/src/lib/ecp.cpp)

/*
 *      Copyright (c) 2020 Robert Shaw
 *      This file is a part of Libecpint.
 *
 *      Permission is hereby granted, free of charge, to any person obtaining
 *      a copy of this software and associated documentation files (the
 *      "Software"), to deal in the Software without restriction, including
 *      without limitation the rights to use, copy, modify, merge, publish,
 *      distribute, sublicense, and/or sell copies of the Software, and to
 *      permit persons to whom the Software is furnished to do so, subject to
 *      the following conditions:
 *
 *      The above copyright notice and this permission notice shall be
 *      included in all copies or substantial portions of the Software.
 *
 *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *      EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *      MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *      NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *      LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *      OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *      WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "ecp.hpp"

#include <cmath>
#include <iostream>
#include <algorithm>
#include "pugixml.hpp"
#include "mathutil.hpp"

namespace libecpint {

    // GaussianECP constructor and copy constructor
    GaussianECP::GaussianECP() : n(0), l(0), a(0), d(0) {}
    GaussianECP::GaussianECP(
        const int _n, const int _l, const double _a, const double _d) : n(_n-2), l(_l), a(_a), d(_d) {}
    GaussianECP::GaussianECP(const GaussianECP& other) : n(other.n), l(other.l), a(other.a), d(other.d) {}


    // class ECP

    ECP::ECP() : N(0), L(-1) {
        center_[0] = center_[1] = center_[2] = 0.0;
        min_exp = 1000.0;
        for (int i = 0; i < LIBECPINT_MAX_L + 1; i++) {
             min_exp_l[i] = 1000.0;
             l_starts[i] = 0;
        }
        l_starts[LIBECPINT_MAX_L+1] = 0;
    }

    ECP::ECP(const double *_center) : N(0), L(-1) {
        center_[0] = _center[0];
        center_[1] = _center[1];
        center_[2] = _center[2];
        min_exp = 1000.0;
        for (int i = 0; i < LIBECPINT_MAX_L + 1; i++) {
             min_exp_l[i] = 1000.0;
             l_starts[i] = 0;
        }
        l_starts[LIBECPINT_MAX_L+1] = 0;
    }

    ECP::ECP(const ECP &other) {
        gaussians = other.gaussians;
        N = other.N;
        L = other.L;
        min_exp = other.min_exp;
        for (int i = 0; i < LIBECPINT_MAX_L + 1; i++) {
            min_exp_l[i] = other.min_exp_l[i];
            l_starts[i] = other.l_starts[i];
        }
        l_starts[LIBECPINT_MAX_L+1] = other.l_starts[LIBECPINT_MAX_L+1];
        center_ = other.center_;
    }

    void ECP::addPrimitive(
      const int n, const int l, const double a, const double d, const bool needSort) {
        GaussianECP newEcp(n, l, a, d);
        gaussians.push_back(newEcp);
        N++;
        L = l > L ? l : L;
        min_exp = a < min_exp ? a : min_exp;
        min_exp_l[l] = a < min_exp_l[l] ? a : min_exp_l[l];
        for (int lx = l+1; lx < LIBECPINT_MAX_L + 2; lx++)
            l_starts[lx] += 1;
        if (needSort) sort();
    }

    void ECP::sort() {
        std::sort(gaussians.begin(), gaussians.end(),
        [&] (const GaussianECP& g1, const GaussianECP& g2) {return (g1.l < g2.l);});
    }

    bool ECP::noType1() const {
        bool zero = true;
        for (auto& g : gaussians)
            if (g.l == L && fabs(g.d) > 1e-12) zero = false;
        return zero;
    }

    // Evaluate U_l(r), assuming that gaussians sorted by angular momentum
    double ECP::evaluate(const double r, const int l) const {
        double value = 0.0;
        double r2 = r*r;
        int p;
        for (int i = l_starts[l]; i < l_starts[l+1]; i++) {
            p = gaussians[i].n > -1 ? gaussians[i].n : MAX_POW - gaussians[i].n;
            value += FAST_POW[p](r) * gaussians[i].d * exp(-gaussians[i].a * r2);
        }
        return value;
    }

    void ECP::setPos(const double x, const double y, const double z) {
        center_[0] = x; center_[1] = y; center_[2] = z;
    }

    ECPBasis::ECPBasis() : N(0), maxL(-1) {}

    void ECPBasis::addECP(const ECP &U, const int atom) {
        basis.push_back(U);
        atomList.push_back(atom);
        N++;
        maxL = U.getL() > maxL ? U.getL() : maxL;
    }

  ECP& ECPBasis::getECP(const int i) { return basis[i]; }
  const ECP& ECPBasis::getECP(const int i) const { return basis[i]; }

    int ECPBasis::getECPCore(const int q) const {
        int core = 0;
        auto it = core_electrons.find(q);
        if (it != core_electrons.end()) core = it->second;
        return core;
    }

    void ECPBasis::addECP_from_file(
      const int q, const std::array<double, 3> & coords, const std::string & filename) {
        ECP newECP;
        newECP.center_ = coords;

        std::string atom_name = q < 1 ? "X" : atom_names[q-1];
        pugi::xml_document doc;
        pugi::xml_parse_result result = doc.load_file(filename.c_str());
        pugi::xml_node atom_node = doc.child("root").child(atom_name.c_str());
        int maxl = std::stoi(atom_node.attribute("maxl").value());
        int ncore = std::stoi(atom_node.attribute("ncore").value());

        auto it = core_electrons.find(q);
        if (it == core_electrons.end())
            core_electrons[q] = ncore;

        for (pugi::xml_node shell = atom_node.child("Shell"); shell; shell = shell.next_sibling("Shell")) {

            int l = std::stoi(shell.attribute("lval").value());

            for (pugi::xml_node nxc = shell.child("nxc"); nxc; nxc = nxc.next_sibling("nxc")) {
                int n = std::stoi(nxc.attribute("n").value());
                double x = std::stod(nxc.attribute("x").value());
                double c = std::stod(nxc.attribute("c").value());
                newECP.addPrimitive(n, l, x, c);
            }
        }

        newECP.sort();
        addECP(newECP, 0);
    }
}