Files
lammps/lib/pace/ace_c_basis.cpp
Yury Lysogorskiy 6a99f5b5c5 WIP:
-  no auto-download of user-pace src yet
-  lib/pace/*.cpp,*.h are provided explicitly yet.
- implement CMake integration in USER-PACE.cmake and in CMakeLists.txt
2021-04-06 17:24:54 +02:00

980 lines
37 KiB
C++

/*
* 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 <http://www.gnu.org/licenses/>.
*/
// Created by Yury Lysogorskiy on 1.04.20.
#include "ace_c_basis.h"
#include "ships_radial.h"
using namespace std;
ACECTildeBasisSet::ACECTildeBasisSet(string filename) {
load(filename);
}
ACECTildeBasisSet::ACECTildeBasisSet(const ACECTildeBasisSet &other) {
ACECTildeBasisSet::_copy_scalar_memory(other);
ACECTildeBasisSet::_copy_dynamic_memory(other);
pack_flatten_basis();
}
ACECTildeBasisSet &ACECTildeBasisSet::operator=(const ACECTildeBasisSet &other) {
if (this != &other) {
_clean();
_copy_scalar_memory(other);
_copy_dynamic_memory(other);
pack_flatten_basis();
}
return *this;
}
ACECTildeBasisSet::~ACECTildeBasisSet() {
ACECTildeBasisSet::_clean();
}
void ACECTildeBasisSet::_clean() {
// call parent method
ACEFlattenBasisSet::_clean();
_clean_contiguous_arrays();
_clean_basis_arrays();
}
void ACECTildeBasisSet::_copy_scalar_memory(const ACECTildeBasisSet &src) {
ACEFlattenBasisSet::_copy_scalar_memory(src);
num_ctilde_max = src.num_ctilde_max;
}
void ACECTildeBasisSet::_copy_dynamic_memory(const ACECTildeBasisSet &src) {//allocate new memory
ACEFlattenBasisSet::_copy_dynamic_memory(src);
if (src.basis_rank1 == nullptr)
throw runtime_error("Could not copy ACECTildeBasisSet::basis_rank1 - array not initialized");
if (src.basis == nullptr) throw runtime_error("Could not copy ACECTildeBasisSet::basis - array not initialized");
basis_rank1 = new ACECTildeBasisFunction *[src.nelements];
basis = new ACECTildeBasisFunction *[src.nelements];
//copy basis arrays
for (SPECIES_TYPE mu = 0; mu < src.nelements; ++mu) {
basis_rank1[mu] = new ACECTildeBasisFunction[src.total_basis_size_rank1[mu]];
for (size_t i = 0; i < src.total_basis_size_rank1[mu]; i++) {
basis_rank1[mu][i] = src.basis_rank1[mu][i];
}
basis[mu] = new ACECTildeBasisFunction[src.total_basis_size[mu]];
for (size_t i = 0; i < src.total_basis_size[mu]; i++) {
basis[mu][i] = src.basis[mu][i];
}
}
//DON"T COPY CONTIGUOUS ARRAY, REBUILD THEM
}
void ACECTildeBasisSet::_clean_contiguous_arrays() {
ACEFlattenBasisSet::_clean_contiguous_arrays();
delete[] full_c_tildes_rank1;
full_c_tildes_rank1 = nullptr;
delete[] full_c_tildes;
full_c_tildes = nullptr;
}
//re-pack the constituent dynamic arrays of all basis functions in contiguous arrays
void ACECTildeBasisSet::pack_flatten_basis() {
compute_array_sizes(basis_rank1, basis);
//1. clean contiguous arrays
_clean_contiguous_arrays();
//2. allocate contiguous arrays
delete[] full_ns_rank1;
full_ns_rank1 = new NS_TYPE[rank_array_total_size_rank1];
delete[] full_ls_rank1;
full_ls_rank1 = new NS_TYPE[rank_array_total_size_rank1];
delete[] full_mus_rank1;
full_mus_rank1 = new SPECIES_TYPE[rank_array_total_size_rank1];
delete[] full_ms_rank1;
full_ms_rank1 = new MS_TYPE[rank_array_total_size_rank1];
delete[] full_c_tildes_rank1;
full_c_tildes_rank1 = new DOUBLE_TYPE[coeff_array_total_size_rank1];
delete[] full_ns;
full_ns = new NS_TYPE[rank_array_total_size];
delete[] full_ls;
full_ls = new LS_TYPE[rank_array_total_size];
delete[] full_mus;
full_mus = new SPECIES_TYPE[rank_array_total_size];
delete[] full_ms;
full_ms = new MS_TYPE[ms_array_total_size];
delete[] full_c_tildes;
full_c_tildes = new DOUBLE_TYPE[coeff_array_total_size];
//3. copy the values from private C_tilde_B_basis_function arrays to new contigous space
//4. clean private memory
//5. reassign private array pointers
//r = 0, rank = 1
size_t rank_array_ind_rank1 = 0;
size_t coeff_array_ind_rank1 = 0;
size_t ms_array_ind_rank1 = 0;
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
for (int func_ind_r1 = 0; func_ind_r1 < total_basis_size_rank1[mu]; ++func_ind_r1) {
ACECTildeBasisFunction &func = basis_rank1[mu][func_ind_r1];
//copy values ns from c_tilde_basis_function private memory to contigous memory part
full_ns_rank1[rank_array_ind_rank1] = func.ns[0];
//copy values ls from c_tilde_basis_function private memory to contigous memory part
full_ls_rank1[rank_array_ind_rank1] = func.ls[0];
//copy values mus from c_tilde_basis_function private memory to contigous memory part
full_mus_rank1[rank_array_ind_rank1] = func.mus[0];
//copy values ctildes from c_tilde_basis_function private memory to contigous memory part
memcpy(&full_c_tildes_rank1[coeff_array_ind_rank1], func.ctildes,
func.ndensity * sizeof(DOUBLE_TYPE));
//copy values mus from c_tilde_basis_function private memory to contigous memory part
memcpy(&full_ms_rank1[ms_array_ind_rank1], func.ms_combs,
func.num_ms_combs *
func.rank * sizeof(MS_TYPE));
//release memory of each ACECTildeBasisFunction if it is not proxy
func._clean();
func.mus = &full_mus_rank1[rank_array_ind_rank1];
func.ns = &full_ns_rank1[rank_array_ind_rank1];
func.ls = &full_ls_rank1[rank_array_ind_rank1];
func.ms_combs = &full_ms_rank1[ms_array_ind_rank1];
func.ctildes = &full_c_tildes_rank1[coeff_array_ind_rank1];
func.is_proxy = true;
rank_array_ind_rank1 += func.rank;
ms_array_ind_rank1 += func.rank *
func.num_ms_combs;
coeff_array_ind_rank1 += func.num_ms_combs * func.ndensity;
}
}
//rank>1, r>0
size_t rank_array_ind = 0;
size_t coeff_array_ind = 0;
size_t ms_array_ind = 0;
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
for (int func_ind = 0; func_ind < total_basis_size[mu]; ++func_ind) {
ACECTildeBasisFunction &func = basis[mu][func_ind];
//copy values mus from c_tilde_basis_function private memory to contigous memory part
memcpy(&full_mus[rank_array_ind], func.mus,
func.rank * sizeof(SPECIES_TYPE));
//copy values ns from c_tilde_basis_function private memory to contigous memory part
memcpy(&full_ns[rank_array_ind], func.ns,
func.rank * sizeof(NS_TYPE));
//copy values ls from c_tilde_basis_function private memory to contigous memory part
memcpy(&full_ls[rank_array_ind], func.ls,
func.rank * sizeof(LS_TYPE));
//copy values mus from c_tilde_basis_function private memory to contigous memory part
memcpy(&full_ms[ms_array_ind], func.ms_combs,
func.num_ms_combs *
func.rank * sizeof(MS_TYPE));
//copy values ctildes from c_tilde_basis_function private memory to contigous memory part
memcpy(&full_c_tildes[coeff_array_ind], func.ctildes,
func.num_ms_combs * func.ndensity * sizeof(DOUBLE_TYPE));
//release memory of each ACECTildeBasisFunction if it is not proxy
func._clean();
func.ns = &full_ns[rank_array_ind];
func.ls = &full_ls[rank_array_ind];
func.mus = &full_mus[rank_array_ind];
func.ctildes = &full_c_tildes[coeff_array_ind];
func.ms_combs = &full_ms[ms_array_ind];
func.is_proxy = true;
rank_array_ind += func.rank;
ms_array_ind += func.rank *
func.num_ms_combs;
coeff_array_ind += func.num_ms_combs * func.ndensity;
}
}
}
void fwrite_c_tilde_b_basis_func(FILE *fptr, ACECTildeBasisFunction &func) {
RANK_TYPE r;
fprintf(fptr, "ctilde_basis_func: ");
fprintf(fptr, "rank=%d ndens=%d mu0=%d ", func.rank, func.ndensity, func.mu0);
fprintf(fptr, "mu=(");
for (r = 0; r < func.rank; ++r)
fprintf(fptr, " %d ", func.mus[r]);
fprintf(fptr, ")\n");
fprintf(fptr, "n=(");
for (r = 0; r < func.rank; ++r)
fprintf(fptr, " %d ", func.ns[r]);
fprintf(fptr, ")\n");
fprintf(fptr, "l=(");
for (r = 0; r < func.rank; ++r)
fprintf(fptr, " %d ", func.ls[r]);
fprintf(fptr, ")\n");
fprintf(fptr, "num_ms=%d\n", func.num_ms_combs);
for (int m_ind = 0; m_ind < func.num_ms_combs; m_ind++) {
fprintf(fptr, "<");
for (r = 0; r < func.rank; ++r)
fprintf(fptr, " %d ", func.ms_combs[m_ind * func.rank + r]);
fprintf(fptr, ">: ");
for (DENSITY_TYPE p = 0; p < func.ndensity; p++)
fprintf(fptr, " %.18f ", func.ctildes[m_ind * func.ndensity + p]);
fprintf(fptr, "\n");
}
}
void ACECTildeBasisSet::save(const string &filename) {
FILE *fptr;
fptr = fopen(filename.c_str(), "w");
fprintf(fptr, "nelements=%d\n", nelements);
//elements mapping
fprintf(fptr, "elements:");
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu)
fprintf(fptr, " %s", elements_name[mu].c_str());
fprintf(fptr, "\n\n");
fprintf(fptr, "lmax=%d\n\n", lmax);
fprintf(fptr, "embedding-function: %s\n", npoti.c_str());
fprintf(fptr, "%ld FS parameters: ", FS_parameters.size());
for (int i = 0; i < FS_parameters.size(); ++i) {
fprintf(fptr, " %f", FS_parameters.at(i));
}
fprintf(fptr, "\n");
//hard-core energy cutoff repulsion
fprintf(fptr, "core energy-cutoff parameters: ");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
fprintf(fptr, "%.18f %.18f\n", rho_core_cutoffs(mu_i), drho_core_cutoffs(mu_i));
// save E0 values
fprintf(fptr, "E0:");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
fprintf(fptr, " %.18f", E0vals(mu_i));
fprintf(fptr, "\n");
fprintf(fptr, "\n");
fprintf(fptr, "radbasename=%s\n", radial_functions->radbasename.c_str());
fprintf(fptr, "nradbase=%d\n", nradbase);
fprintf(fptr, "nradmax=%d\n", nradmax);
fprintf(fptr, "cutoffmax=%f\n", cutoffmax);
fprintf(fptr, "deltaSplineBins=%f\n", deltaSplineBins);
//hard-core repulsion
fprintf(fptr, "core repulsion parameters: ");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j)
fprintf(fptr, "%.18f %.18f\n", radial_functions->prehc(mu_i, mu_j), radial_functions->lambdahc(mu_j, mu_j));
//TODO: radial functions
//radparameter
fprintf(fptr, "radparameter=");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j)
fprintf(fptr, " %.18f", radial_functions->lambda(mu_i, mu_j));
fprintf(fptr, "\n");
fprintf(fptr, "cutoff=");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j)
fprintf(fptr, " %.18f", radial_functions->cut(mu_i, mu_j));
fprintf(fptr, "\n");
fprintf(fptr, "dcut=");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j)
fprintf(fptr, " %.18f", radial_functions->dcut(mu_i, mu_j));
fprintf(fptr, "\n");
fprintf(fptr, "crad=");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) {
for (NS_TYPE k = 0; k < nradbase; k++) {
for (NS_TYPE n = 0; n < nradmax; n++) {
for (LS_TYPE l = 0; l <= lmax; l++) {
fprintf(fptr, " %.18f", radial_functions->crad(mu_i, mu_j, n, l, k));
}
fprintf(fptr, "\n");
}
}
}
fprintf(fptr, "\n");
fprintf(fptr, "rankmax=%d\n", rankmax);
fprintf(fptr, "ndensitymax=%d\n", ndensitymax);
fprintf(fptr, "\n");
//num_c_tilde_max
fprintf(fptr, "num_c_tilde_max=%d\n", num_ctilde_max);
fprintf(fptr, "num_ms_combinations_max=%d\n", num_ms_combinations_max);
//write total_basis_size and total_basis_size_rank1
fprintf(fptr, "total_basis_size_rank1: ");
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
fprintf(fptr, "%d ", total_basis_size_rank1[mu]);
}
fprintf(fptr, "\n");
for (SPECIES_TYPE mu = 0; mu < nelements; mu++)
for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size_rank1[mu]; ++func_ind)
fwrite_c_tilde_b_basis_func(fptr, basis_rank1[mu][func_ind]);
fprintf(fptr, "total_basis_size: ");
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
fprintf(fptr, "%d ", total_basis_size[mu]);
}
fprintf(fptr, "\n");
for (SPECIES_TYPE mu = 0; mu < nelements; mu++)
for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size[mu]; ++func_ind)
fwrite_c_tilde_b_basis_func(fptr, basis[mu][func_ind]);
fclose(fptr);
}
void fread_c_tilde_b_basis_func(FILE *fptr, ACECTildeBasisFunction &func) {
RANK_TYPE r;
int res;
char buf[3][128];
res = fscanf(fptr, " ctilde_basis_func: ");
res = fscanf(fptr, "rank=%s ndens=%s mu0=%s ", buf[0], buf[1], buf[2]);
if (res != 3)
throw invalid_argument("Could not read C-tilde basis function");
func.rank = (RANK_TYPE) stol(buf[0]);
func.ndensity = (DENSITY_TYPE) stol(buf[1]);
func.mu0 = (SPECIES_TYPE) stol(buf[2]);
func.mus = new SPECIES_TYPE[func.rank];
func.ns = new NS_TYPE[func.rank];
func.ls = new LS_TYPE[func.rank];
res = fscanf(fptr, " mu=(");
for (r = 0; r < func.rank; ++r) {
res = fscanf(fptr, "%s", buf[0]);
if (res != 1)
throw invalid_argument("Could not read C-tilde basis function");
func.mus[r] = (SPECIES_TYPE) stol(buf[0]);
}
res = fscanf(fptr, " )"); // ")"
res = fscanf(fptr, " n=("); // "n="
for (r = 0; r < func.rank; ++r) {
res = fscanf(fptr, "%s", buf[0]);
if (res != 1)
throw invalid_argument("Could not read C-tilde basis function");
func.ns[r] = (NS_TYPE) stol(buf[0]);
}
res = fscanf(fptr, " )");
res = fscanf(fptr, " l=(");
for (r = 0; r < func.rank; ++r) {
res = fscanf(fptr, "%s", buf[0]);
if (res != 1)
throw invalid_argument("Could not read C-tilde basis function");
func.ls[r] = (NS_TYPE) stol(buf[0]);
}
res = fscanf(fptr, " )");
res = fscanf(fptr, " num_ms=%s\n", buf[0]);
if (res != 1)
throw invalid_argument("Could not read C-tilde basis function");
func.num_ms_combs = (SHORT_INT_TYPE) stoi(buf[0]);
func.ms_combs = new MS_TYPE[func.rank * func.num_ms_combs];
func.ctildes = new DOUBLE_TYPE[func.ndensity * func.num_ms_combs];
for (int m_ind = 0; m_ind < func.num_ms_combs; m_ind++) {
res = fscanf(fptr, " <");
for (r = 0; r < func.rank; ++r) {
res = fscanf(fptr, "%s", buf[0]);
if (res != 1)
throw invalid_argument("Could not read C-tilde basis function");
func.ms_combs[m_ind * func.rank + r] = stoi(buf[0]);
}
res = fscanf(fptr, " >:");
for (DENSITY_TYPE p = 0; p < func.ndensity; p++) {
res = fscanf(fptr, "%s", buf[0]);
if (res != 1)
throw invalid_argument("Could not read C-tilde basis function");
func.ctildes[m_ind * func.ndensity + p] = stod(buf[0]);
}
}
}
string
format_error_message(const char *buffer, const string &filename, const string &var_name, const string &expected) {
string err_message = "File '" + filename + "': couldn't read '" + var_name + "'";
if (buffer)
err_message = err_message + ", read:'" + buffer + "'";
if (!expected.empty())
err_message = err_message + ". Expected format: '" + expected + "'";
return err_message;
}
void throw_error(const string &filename, const string &var_name, const string expected = "") {
throw invalid_argument(format_error_message(nullptr, filename, var_name, expected));
}
DOUBLE_TYPE stod_err(const char *buffer, const string &filename, const string &var_name, const string expected = "") {
try {
return stod(buffer);
} catch (invalid_argument &exc) {
throw invalid_argument(format_error_message(buffer, filename, var_name, expected).c_str());
}
}
int stoi_err(const char *buffer, const string &filename, const string &var_name, const string expected = "") {
try {
return stoi(buffer);
} catch (invalid_argument &exc) {
throw invalid_argument(format_error_message(buffer, filename, var_name, expected).c_str());
}
}
long int stol_err(const char *buffer, const string &filename, const string &var_name, const string expected = "") {
try {
return stol(buffer);
} catch (invalid_argument &exc) {
throw invalid_argument(format_error_message(buffer, filename, var_name, expected).c_str());
}
}
void ACECTildeBasisSet::load(const string filename) {
int res;
char buffer[1024], buffer2[1024];
string radbasename = "ChebExpCos";
FILE *fptr;
fptr = fopen(filename.c_str(), "r");
if (fptr == NULL)
throw invalid_argument("Could not open file " + filename);
//read number of elements
res = fscanf(fptr, " nelements=");
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "nelements", "nelements=[number]");
nelements = stoi_err(buffer, filename, "nelements", "nelements=[number]");
//elements mapping
elements_name = new string[nelements];
res = fscanf(fptr, " elements:");
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "elements", "elements: Ele1 Ele2 ...");
elements_name[mu] = buffer;
}
// load angular basis - only need spherical harmonics parameter
res = fscanf(fptr, " lmax=%s\n", buffer);
if (res != 1)
throw_error(filename, "lmax", "lmax=[number]");
lmax = stoi_err(buffer, filename, "lmax", "lmax=[number]");
spherical_harmonics.init(lmax);
// reading "embedding-function:"
bool is_embedding_function_specified = false;
res = fscanf(fptr, " embedding-function: %s", buffer);
if (res == 0) {
//throw_error(filename, "E0", " E0: E0-species1 E0-species2 ...");
this->npoti = "FinnisSinclair"; // default values
//printf("Warning! No embedding-function is specified, embedding-function: FinnisSinclair would be assumed\n");
is_embedding_function_specified = false;
} else {
this->npoti = buffer;
is_embedding_function_specified = true;
}
int parameters_size;
res = fscanf(fptr, "%s FS parameters:", buffer);
if (res != 1)
throw_error(filename, "FS parameters size", "[number] FS parameters: par1 par2 ...");
parameters_size = stoi_err(buffer, filename, "FS parameters size", "[number] FS parameters");
FS_parameters.resize(parameters_size);
for (int i = 0; i < FS_parameters.size(); ++i) {
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "FS parameter", "[number] FS parameters: [par1] [par2] ...");
FS_parameters[i] = stod_err(buffer, filename, "FS parameter", "[number] FS parameters: [par1] [par2] ...");
}
if (!is_embedding_function_specified) {
// assuming non-linear potential, and embedding function type is important
for (int j = 1; j < parameters_size; j += 2)
if (FS_parameters[j] != 1.0) { //if not ensure linearity of embedding function parameters
printf("ERROR! Your potential is non-linear\n");
printf("Please specify 'embedding-function: FinnisSinclair' or 'embedding-function: FinnisSinclairShiftedScaled' before 'FS parameters size' line\n");
throw_error(filename, "embedding-function", "FinnisSinclair or FinnisSinclairShiftedScaled");
}
printf("Notice! No embedding-function is specified, but potential has linear embedding, default embedding-function: FinnisSinclair would be assumed\n");
}
//hard-core energy cutoff repulsion
res = fscanf(fptr, " core energy-cutoff parameters:");
if (res != 0)
throw_error(filename, "core energy-cutoff parameters", "core energy-cutoff parameters: [par1] [par2]");
rho_core_cutoffs.init(nelements, "rho_core_cutoffs");
drho_core_cutoffs.init(nelements, "drho_core_cutoffs");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) {
res = fscanf(fptr, "%s %s", buffer, buffer2);
if (res != 2)
throw_error(filename, "core energy-cutoff parameters",
"core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ...");
rho_core_cutoffs(mu_i) = stod_err(buffer, filename, "rho core cutoff",
"core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ...");
drho_core_cutoffs(mu_i) = stod_err(buffer2, filename, "drho_core_cutoff",
"core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ...");
}
// atom energy shift E0 (energy of isolated atom)
E0vals.init(nelements);
// reading "E0:"
res = fscanf(fptr, " E0: %s", buffer);
if (res == 0) {
//throw_error(filename, "E0", " E0: E0-species1 E0-species2 ...");
E0vals.fill(0.0);
} else {
double E0 = atof(buffer);
E0vals(0) = E0;
for (SPECIES_TYPE mu_i = 1; mu_i < nelements; ++mu_i) {
res = fscanf(fptr, " %lf", &E0);
if (res != 1)
throw_error(filename, "E0", " couldn't read one of the E0 values");
E0vals(mu_i) = E0;
}
res = fscanf(fptr, "\n");
if (res != 0)
printf("file %s : format seems broken near E0; trying to continue...\n", filename.c_str());
}
// check which radial basis we need to load
res = fscanf(fptr, " radbasename=%s\n", buffer);
if (res != 1) {
throw_error(filename, "radbasename", "rabbasename=ChebExpCos|ChebPow|ACE.jl.Basic");
} else {
radbasename = buffer;
}
// printf("radbasename = `%s`\n", radbasename.c_str());
if (radbasename == "ChebExpCos" | radbasename == "ChebPow") {
_load_radial_ACERadial(fptr, filename, radbasename);
} else if (radbasename == "ACE.jl.Basic") {
_load_radial_SHIPsBasic(fptr, filename, radbasename);
} else {
throw invalid_argument(
("File '" + filename + "': I don't know how to read radbasename = " + radbasename).c_str());
}
res = fscanf(fptr, " rankmax=");
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "rankmax", "rankmax=[number]");
rankmax = stoi_err(buffer, filename, "rankmax", "rankmax=[number]");
res = fscanf(fptr, " ndensitymax=");
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "ndensitymax", "ndensitymax=[number]");
ndensitymax = stoi_err(buffer, filename, "ndensitymax", "ndensitymax=[number]");
// read the list of correlations to be put into the basis
//num_c_tilde_max
res = fscanf(fptr, " num_c_tilde_max=");
res = fscanf(fptr, "%s\n", buffer);
if (res != 1)
throw_error(filename, "num_c_tilde_max", "num_c_tilde_max=[number]");
num_ctilde_max = stol_err(buffer, filename, "num_c_tilde_max", "num_c_tilde_max=[number]");
res = fscanf(fptr, " num_ms_combinations_max=");
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "num_ms_combinations_max", "num_ms_combinations_max=[number]");
// throw invalid_argument(("File '" + filename + "': couldn't read num_ms_combinations_max").c_str());
num_ms_combinations_max = stol_err(buffer, filename, "num_ms_combinations_max", "num_ms_combinations_max=[number]");
//read total_basis_size_rank1
total_basis_size_rank1 = new SHORT_INT_TYPE[nelements];
basis_rank1 = new ACECTildeBasisFunction *[nelements];
res = fscanf(fptr, " total_basis_size_rank1: ");
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "total_basis_size_rank1", "total_basis_size_rank1: [size_ele1] [size_ele2] ...");
// throw invalid_argument(("File '" + filename + "': couldn't read total_basis_size_rank1").c_str());
total_basis_size_rank1[mu] = stoi_err(buffer, filename, "total_basis_size_rank1",
"total_basis_size_rank1: [size_ele1] [size_ele2] ...");
basis_rank1[mu] = new ACECTildeBasisFunction[total_basis_size_rank1[mu]];
}
for (SPECIES_TYPE mu = 0; mu < nelements; mu++)
for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size_rank1[mu]; ++func_ind) {
fread_c_tilde_b_basis_func(fptr, basis_rank1[mu][func_ind]);
}
//read total_basis_size
res = fscanf(fptr, " total_basis_size: ");
total_basis_size = new SHORT_INT_TYPE[nelements];
basis = new ACECTildeBasisFunction *[nelements];
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "total_basis_size", "total_basis_size: [size_ele1] [size_ele2] ...");
total_basis_size[mu] = stoi_err(buffer, filename, "total_basis_size",
"total_basis_size: [size_ele1] [size_ele2] ...");
basis[mu] = new ACECTildeBasisFunction[total_basis_size[mu]];
}
for (SPECIES_TYPE mu = 0; mu < nelements; mu++)
for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size[mu]; ++func_ind) {
fread_c_tilde_b_basis_func(fptr, basis[mu][func_ind]);
}
fclose(fptr);
// radial_functions->radbasename = radbasename;
radial_functions->setuplookupRadspline();
pack_flatten_basis();
}
void ACECTildeBasisSet::compute_array_sizes(ACECTildeBasisFunction **basis_rank1, ACECTildeBasisFunction **basis) {
//compute arrays sizes
rank_array_total_size_rank1 = 0;
//ms_array_total_size_rank1 = rank_array_total_size_rank1;
coeff_array_total_size_rank1 = 0;
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
if (total_basis_size_rank1[mu] > 0) {
rank_array_total_size_rank1 += total_basis_size_rank1[mu];
ACEAbstractBasisFunction &func = basis_rank1[mu][0];//TODO: get total density instead of density from first function
coeff_array_total_size_rank1 += total_basis_size_rank1[mu] * func.ndensity;
}
}
rank_array_total_size = 0;
coeff_array_total_size = 0;
ms_array_total_size = 0;
max_dB_array_size = 0;
max_B_array_size = 0;
size_t cur_ms_size = 0;
size_t cur_ms_rank_size = 0;
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
cur_ms_size = 0;
cur_ms_rank_size = 0;
for (int func_ind = 0; func_ind < total_basis_size[mu]; ++func_ind) {
auto &func = basis[mu][func_ind];
rank_array_total_size += func.rank;
ms_array_total_size += func.rank * func.num_ms_combs;
coeff_array_total_size += func.ndensity * func.num_ms_combs;
cur_ms_size += func.num_ms_combs;
cur_ms_rank_size += func.rank * func.num_ms_combs;
}
if (cur_ms_size > max_B_array_size)
max_B_array_size = cur_ms_size;
if (cur_ms_rank_size > max_dB_array_size)
max_dB_array_size = cur_ms_rank_size;
}
}
void ACECTildeBasisSet::_clean_basis_arrays() {
if (basis_rank1 != nullptr)
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
delete[] basis_rank1[mu];
basis_rank1[mu] = nullptr;
}
if (basis != nullptr)
for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) {
delete[] basis[mu];
basis[mu] = nullptr;
}
delete[] basis;
basis = nullptr;
delete[] basis_rank1;
basis_rank1 = nullptr;
}
//pack into 1D array with all basis functions
void ACECTildeBasisSet::flatten_basis(C_tilde_full_basis_vector2d &mu0_ctilde_basis_vector) {
_clean_basis_arrays();
basis_rank1 = new ACECTildeBasisFunction *[nelements];
basis = new ACECTildeBasisFunction *[nelements];
delete[] total_basis_size_rank1;
delete[] total_basis_size;
total_basis_size_rank1 = new SHORT_INT_TYPE[nelements];
total_basis_size = new SHORT_INT_TYPE[nelements];
size_t tot_size_rank1 = 0;
size_t tot_size = 0;
for (SPECIES_TYPE mu = 0; mu < this->nelements; ++mu) {
tot_size = 0;
tot_size_rank1 = 0;
for (auto &func: mu0_ctilde_basis_vector[mu]) {
if (func.rank == 1) tot_size_rank1 += 1;
else tot_size += 1;
}
total_basis_size_rank1[mu] = tot_size_rank1;
basis_rank1[mu] = new ACECTildeBasisFunction[tot_size_rank1];
total_basis_size[mu] = tot_size;
basis[mu] = new ACECTildeBasisFunction[tot_size];
}
for (SPECIES_TYPE mu = 0; mu < this->nelements; ++mu) {
size_t ind_rank1 = 0;
size_t ind = 0;
for (auto &func: mu0_ctilde_basis_vector[mu]) {
if (func.rank == 1) { //r=0, rank=1
basis_rank1[mu][ind_rank1] = func;
ind_rank1 += 1;
} else { //r>0, rank>1
basis[mu][ind] = func;
ind += 1;
}
}
}
}
void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr,
const string filename,
const string radbasename) {
int res;
char buffer[1024], buffer2[1024];
res = fscanf(fptr, " nradbase=");
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "nradbase", "nradbase=[number]");
// throw invalid_argument(("File '" + filename + "': couldn't read nradbase").c_str());
nradbase = stoi_err(buffer, filename, "nradbase", "nradbase=[number]");
res = fscanf(fptr, " nradmax=");
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "nradmax", "nradmax=[number]");
nradmax = stoi_err(buffer, filename, "nradmax", "nradmax=[number]");
res = fscanf(fptr, " cutoffmax=");
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "cutoffmax", "cutoffmax=[number]");
cutoffmax = stod_err(buffer, filename, "cutoffmax", "cutoffmax=[number]");
res = fscanf(fptr, " deltaSplineBins=");
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "deltaSplineBins", "deltaSplineBins=[spline density, Angstroms]");
// throw invalid_argument(("File '" + filename + "': couldn't read ntot").c_str());
deltaSplineBins = stod_err(buffer, filename, "deltaSplineBins", "deltaSplineBins=[spline density, Angstroms]");
if (radial_functions == nullptr)
radial_functions = new ACERadialFunctions(nradbase, lmax, nradmax,
deltaSplineBins,
nelements,
cutoffmax, radbasename);
else
radial_functions->init(nradbase, lmax, nradmax,
deltaSplineBins,
nelements,
cutoffmax, radbasename);
//hard-core repulsion
res = fscanf(fptr, " core repulsion parameters:");
if (res != 0)
throw_error(filename, "core repulsion parameters", "core repulsion parameters: [prehc lambdahc] ...");
// throw invalid_argument(("File '" + filename + "': couldn't read core repulsion parameters").c_str());
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) {
res = fscanf(fptr, "%s %s", buffer, buffer2);
if (res != 2)
throw_error(filename, "core repulsion parameters", "core repulsion parameters: [prehc lambdahc] ...");
radial_functions->prehc(mu_i, mu_j) = stod_err(buffer, filename, "core repulsion parameters",
"core repulsion parameters: [prehc lambdahc] ...");
radial_functions->lambdahc(mu_i, mu_j) = stod_err(buffer2, filename, "core repulsion parameters",
"core repulsion parameters: [prehc lambdahc] ...");
}
//read radial functions parameter
res = fscanf(fptr, " radparameter=");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) {
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "radparameter", "radparameter=[param_ele1] [param_ele2]");
radial_functions->lambda(mu_i, mu_j) = stod_err(buffer, filename, "radparameter",
"radparameter=[param_ele1] [param_ele2]");
}
res = fscanf(fptr, " cutoff=");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) {
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "cutoff", "cutoff=[param_ele1] [param_ele2]");
radial_functions->cut(mu_i, mu_j) = stod_err(buffer, filename, "cutoff",
"cutoff=[param_ele1] [param_ele2]");
}
res = fscanf(fptr, " dcut=");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) {
res = fscanf(fptr, " %s", buffer);
if (res != 1)
throw_error(filename, "dcut", "dcut=[param_ele1] [param_ele2]");
radial_functions->dcut(mu_i, mu_j) = stod_err(buffer, filename, "dcut", "dcut=[param_ele1] [param_ele2]");
}
res = fscanf(fptr, " crad=");
for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i)
for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j)
for (NS_TYPE k = 0; k < nradbase; k++)
for (NS_TYPE n = 0; n < nradmax; n++)
for (LS_TYPE l = 0; l <= lmax; l++) {
res = fscanf(fptr, "%s", buffer);
if (res != 1)
throw_error(filename, "crad", "crad=[crad_]...[crad_knl]: nradbase*nrad*(l+1) times");
radial_functions->crad(mu_i, mu_j, n, l, k) = stod_err(buffer, filename, "crad",
"crad=[crad_]...[crad_knl]: nradbase*nrad*(l+1) times");
}
}
void ACECTildeBasisSet::_load_radial_SHIPsBasic(FILE *fptr,
const string filename,
const string radbasename) {
// create a radial basis object, and read it from the file pointer
SHIPsRadialFunctions *ships_radial_functions = new SHIPsRadialFunctions();
ships_radial_functions->fread(fptr);
//mimic ships_radial_functions to ACERadialFunctions
ships_radial_functions->nradial = ships_radial_functions->get_maxn();
ships_radial_functions->nradbase = ships_radial_functions->get_maxn();
nradbase = ships_radial_functions->get_maxn();
nradmax = ships_radial_functions->get_maxn();
cutoffmax = ships_radial_functions->get_rcut();
deltaSplineBins = 0.001;
ships_radial_functions->init(nradbase, lmax, nradmax,
deltaSplineBins,
nelements,
cutoffmax, radbasename);
if (radial_functions) delete radial_functions;
radial_functions = ships_radial_functions;
radial_functions->prehc.fill(0);
radial_functions->lambdahc.fill(1);
radial_functions->lambda.fill(0);
radial_functions->cut.fill(ships_radial_functions->get_rcut());
radial_functions->dcut.fill(0);
radial_functions->crad.fill(0);
}