/*
* Performant implementation of atomic cluster expansion and interface to LAMMPS
*
* Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1,
* Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1,
* Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1
*
* ^1: Ruhr-University Bochum, Bochum, Germany
* ^2: University of Cambridge, Cambridge, United Kingdom
* ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA
* ^4: University of British Columbia, Vancouver, BC, Canada
*
*
* See the LICENSE file.
* This FILENAME is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
// Created by Lysogorskiy Yury on 28.04.2020.
#include "ace_abstract_basis.h"
////embedding function
////case nemb = 1 only implementation
////F = sign(x)*( ( 1 - exp(-(w*x)^3) )*abs(x)^m + ((1/w)^(m-1))*exp(-(w*x)^3)*abs(x) )
//// !! no prefactor wpre
void Fexp(DOUBLE_TYPE x, DOUBLE_TYPE m, DOUBLE_TYPE &F, DOUBLE_TYPE &DF) {
DOUBLE_TYPE w = 1.e6;
DOUBLE_TYPE eps = 1e-10;
DOUBLE_TYPE lambda = pow(1.0 / w, m - 1.0);
if (abs(x) > eps) {
DOUBLE_TYPE g;
DOUBLE_TYPE a = abs(x);
DOUBLE_TYPE am = pow(a, m);
DOUBLE_TYPE w3x3 = pow(w * a, 3);
DOUBLE_TYPE sign_factor = (signbit(x) ? -1 : 1);
if (w3x3 > 30.0)
g = 0.0;
else
g = exp(-w3x3);
DOUBLE_TYPE omg = 1.0 - g;
F = sign_factor * (omg * am + lambda * g * a);
DOUBLE_TYPE dg = -3.0 * w * w * w * a * a * g;
DF = m * pow(a, m - 1.0) * omg - am * dg + lambda * dg * a + lambda * g;
} else {
F = lambda * x;
DF = lambda;
}
}
//Scaled-shifted embedding function
//F = sign(x)*( ( 1 - exp(-(w*x)^3) )*abs(x)^m + ((1/w)^(m-1))*exp(-(w*x)^3)*abs(x) )
// !! no prefactor wpre
void FexpShiftedScaled(DOUBLE_TYPE rho, DOUBLE_TYPE mexp, DOUBLE_TYPE &F, DOUBLE_TYPE &DF) {
DOUBLE_TYPE eps = 1e-10;
DOUBLE_TYPE a, xoff, yoff, nx, exprho;
if (abs(mexp - 1.0) < eps) {
F = rho;
DF = 1;
} else {
a = abs(rho);
exprho = exp(-a);
nx = 1. / mexp;
xoff = pow(nx, (nx / (1.0 - nx))) * exprho;
yoff = pow(nx, (1 / (1.0 - nx))) * exprho;
DOUBLE_TYPE sign_factor = (signbit(rho) ? -1 : 1);
F = sign_factor * (pow(xoff + a, mexp) - yoff);
DF = yoff + mexp * (-xoff + 1.0) * pow(xoff + a, mexp - 1.);
}
}
void ACEAbstractBasisSet::inner_cutoff(DOUBLE_TYPE rho_core, DOUBLE_TYPE rho_cut, DOUBLE_TYPE drho_cut,
DOUBLE_TYPE &fcut, DOUBLE_TYPE &dfcut) {
DOUBLE_TYPE rho_low = rho_cut - drho_cut;
if (rho_core >= rho_cut) {
fcut = 0;
dfcut = 0;
} else if (rho_core <= rho_low) {
fcut = 1;
dfcut = 0;
} else {
fcut = 0.5 * (1 + cos(M_PI * (rho_core - rho_low) / drho_cut));
dfcut = -0.5 * sin(M_PI * (rho_core - rho_low) / drho_cut) * M_PI / drho_cut;
}
}
void ACEAbstractBasisSet::FS_values_and_derivatives(Array1D &rhos, DOUBLE_TYPE &value,
Array1D &derivatives, DENSITY_TYPE ndensity) {
DOUBLE_TYPE F, DF = 0, wpre, mexp;
for (int p = 0; p < ndensity; p++) {
wpre = FS_parameters.at(p * ndensity + 0);
mexp = FS_parameters.at(p * ndensity + 1);
if (this->npoti == "FinnisSinclair")
Fexp(rhos(p), mexp, F, DF);
else if (this->npoti == "FinnisSinclairShiftedScaled")
FexpShiftedScaled(rhos(p), mexp, F, DF);
value += F * wpre; // * weight (wpre)
derivatives(p) = DF * wpre;// * weight (wpre)
}
}
void ACEAbstractBasisSet::_clean() {
delete[] elements_name;
elements_name = nullptr;
delete radial_functions;
radial_functions = nullptr;
}
ACEAbstractBasisSet::ACEAbstractBasisSet(const ACEAbstractBasisSet &other) {
ACEAbstractBasisSet::_copy_scalar_memory(other);
ACEAbstractBasisSet::_copy_dynamic_memory(other);
}
ACEAbstractBasisSet &ACEAbstractBasisSet::operator=(const ACEAbstractBasisSet &other) {
if (this != &other) {
// deallocate old memory
ACEAbstractBasisSet::_clean();
//copy scalar values
ACEAbstractBasisSet::_copy_scalar_memory(other);
//copy dynamic memory
ACEAbstractBasisSet::_copy_dynamic_memory(other);
}
return *this;
}
ACEAbstractBasisSet::~ACEAbstractBasisSet() {
ACEAbstractBasisSet::_clean();
}
void ACEAbstractBasisSet::_copy_scalar_memory(const ACEAbstractBasisSet &src) {
deltaSplineBins = src.deltaSplineBins;
FS_parameters = src.FS_parameters;
npoti = src.npoti;
nelements = src.nelements;
rankmax = src.rankmax;
ndensitymax = src.ndensitymax;
nradbase = src.nradbase;
lmax = src.lmax;
nradmax = src.nradmax;
cutoffmax = src.cutoffmax;
spherical_harmonics = src.spherical_harmonics;
rho_core_cutoffs = src.rho_core_cutoffs;
drho_core_cutoffs = src.drho_core_cutoffs;
E0vals = src.E0vals;
}
void ACEAbstractBasisSet::_copy_dynamic_memory(const ACEAbstractBasisSet &src) {//allocate new memory
if (src.elements_name == nullptr)
throw runtime_error("Could not copy ACEAbstractBasisSet::elements_name - array not initialized");
elements_name = new string[nelements];
//copy
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
elements_name[mu] = src.elements_name[mu];
}
radial_functions = src.radial_functions->clone();
}
SPECIES_TYPE ACEAbstractBasisSet::get_species_index_by_name(const string &elemname) {
for (SPECIES_TYPE t = 0; t < nelements; t++) {
if (this->elements_name[t] == elemname)
return t;
}
return -1;
}