/* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/ Sandia National Laboratories LAMMPS development team: developers@lammps.org Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Ngoc Cuong Nguyen (MIT) and Andrew Rohskopf (SNL) ------------------------------------------------------------------------- */ // POD header file #include "mlpod.h" // LAMMPS header files #include "comm.h" #include "error.h" #include "math_const.h" #include "math_special.h" #include "memory.h" #include "tokenizer.h" #include using namespace LAMMPS_NS; using MathConst::MY_PI; using MathSpecial::cube; using MathSpecial::powint; #define MAXLINE 1024 MLPOD::podstruct::podstruct() : twobody{4, 8, 6}, threebody{4, 8, 5, 4}, fourbody{0, 0, 0, 0}, pbc(nullptr), elemindex(nullptr), quadratic22{0, 0}, quadratic23{0, 0}, quadratic24{0, 0}, quadratic33{0, 0}, quadratic34{0, 0}, quadratic44{0, 0}, cubic234{0, 0, 0}, cubic333{0, 0, 0}, cubic444{0, 0, 0}, besselparams(nullptr), coeff(nullptr), Phi2(nullptr), Phi3(nullptr), Phi4(nullptr), Lambda2(nullptr), Lambda3(nullptr), Lambda4(nullptr), snapelementradius{0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5}, snapelementweight{1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0} { snaptwojmax = 0; snapchemflag = 0; snaprfac0 = 0.99363; } MLPOD::podstruct::~podstruct() { delete[] pbc; delete[] elemindex; delete[] besselparams; } MLPOD::MLPOD(LAMMPS *_lmp, const std::string &pod_file, const std::string &coeff_file) : Pointers(_lmp) { // read pod input file to podstruct read_pod(pod_file); // read pod coefficient file to podstruct if (coeff_file != "") read_coeff_file(coeff_file); if (pod.snaptwojmax > 0) InitSnap(); } MLPOD::~MLPOD() { // deallocate pod arrays memory->destroy(pod.coeff); if (pod.ns2 > 0) { memory->destroy(pod.Phi2); memory->destroy(pod.Lambda2); } if (pod.ns3 > 0) { memory->destroy(pod.Phi3); memory->destroy(pod.Lambda3); } if (pod.ns4 > 0) { memory->destroy(pod.Phi4); memory->destroy(pod.Lambda4); } // deallocate snap arrays if used if (pod.snaptwojmax > 0) { memory->destroy(sna.map); memory->destroy(sna.idx_max); memory->destroy(sna.idxz); memory->destroy(sna.idxb); memory->destroy(sna.idxb_block); memory->destroy(sna.idxu_block); memory->destroy(sna.idxz_block); memory->destroy(sna.idxcg_block); memory->destroy(sna.rootpqarray); memory->destroy(sna.cglist); memory->destroy(sna.fac); memory->destroy(sna.bzero); memory->destroy(sna.wjelem); memory->destroy(sna.radelem); memory->destroy(sna.rcutsq); } } // clang-format off void MLPOD::podMatMul(double *c, double *a, double *b, int r1, int c1, int c2) { int i, j, k; for(j = 0; j < c2; j++) for(i = 0; i < r1; i++) c[i + r1*j] = 0.0; for(j = 0; j < c2; j++) for(i = 0; i < r1; i++) for(k = 0; k < c1; k++) c[i + r1*j] += a[i + r1*k] * b[k + c1*j]; } void MLPOD::podArrayFill(int* output, int start, int length) { for (int j = 0; j < length; ++j) output[j] = start + j; } void MLPOD::podArraySetValue(double *y, double a, int n) { for (int i=0; icreate(xij, N, "pod:xij"); memory->create(S, N*ns, "pod:S"); memory->create(Q, N*ns, "pod:Q"); memory->create(A, ns*ns, "pod:A"); memory->create(b, ns, "pod:ns"); for (int i=0; i= max(1,3*N-1) int info = 1; // = 0: successful exit std::vector work(lwork); DSYEV(&chv, &chu, &ns, A, &ns, b, work.data(), &lwork, &info); // order eigenvalues and eigenvectors from largest to smallest for (int j=0; jdestroy(xij); memory->destroy(S); memory->destroy(A); memory->destroy(b); memory->destroy(Q); } void MLPOD::read_pod(const std::string &pod_file) { pod.nbesselpars = 3; delete[] pod.besselparams; pod.besselparams = new double[3]; delete[] pod.pbc; pod.pbc = new int[3]; pod.besselparams[0] = 0.0; pod.besselparams[1] = 2.0; pod.besselparams[2] = 4.0; pod.nelements = 0; pod.onebody = 1; pod.besseldegree = 3; pod.inversedegree = 6; pod.quadraticpod = 0; pod.rin = 0.5; pod.rcut = 4.6; pod.snaptwojmax = 0; pod.snapchemflag = 0; pod.snaprfac0 = 0.99363; sna.twojmax = 0; sna.ntypes = 0; std::string podfilename = pod_file; FILE *fppod; if (comm->me == 0) { fppod = utils::open_potential(podfilename,lmp,nullptr); if (fppod == nullptr) error->one(FLERR,"Cannot open POD coefficient file {}: ", podfilename, utils::getsyserror()); } // loop through lines of POD file and parse keywords char line[MAXLINE],*ptr; int eof = 0; while (true) { if (comm->me == 0) { ptr = fgets(line,MAXLINE,fppod); if (ptr == nullptr) { eof = 1; fclose(fppod); } } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) break; MPI_Bcast(line,MAXLINE,MPI_CHAR,0,world); // words = ptrs to all words in line // strip single and double quotes from words std::vector words; try { words = Tokenizer(utils::trim_comment(line),"\"' \t\n\r\f").as_vector(); } catch (TokenizerException &) { // ignore } if (words.size() == 0) continue; auto keywd = words[0]; if (keywd == "species") { pod.nelements = words.size()-1; for (int ielem = 1; ielem <= pod.nelements; ielem++) { pod.species.push_back(words[ielem]); } } if (keywd == "pbc") { if (words.size() != 4) error->one(FLERR,"Improper POD file.", utils::getsyserror()); pod.pbc[0] = utils::inumeric(FLERR,words[1],false,lmp); pod.pbc[1] = utils::inumeric(FLERR,words[2],false,lmp); pod.pbc[2] = utils::inumeric(FLERR,words[3],false,lmp); } if ((keywd != "#") && (keywd != "species") && (keywd != "pbc")) { if (words.size() != 2) error->one(FLERR,"Improper POD file.", utils::getsyserror()); if (keywd == "rin") pod.rin = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "rcut") pod.rcut = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "bessel_scaling_parameter1") pod.besselparams[0] = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "bessel_scaling_parameter2") pod.besselparams[1] = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "bessel_scaling_parameter3") pod.besselparams[2] = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "bessel_polynomial_degree") pod.besseldegree = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "inverse_polynomial_degree") pod.inversedegree = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "onebody") pod.onebody = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "twobody_bessel_polynomial_degree") pod.twobody[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "twobody_inverse_polynomial_degree") pod.twobody[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "twobody_number_radial_basis_functions") pod.twobody[2] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "threebody_bessel_polynomial_degree") pod.threebody[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "threebody_inverse_polynomial_degree") pod.threebody[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "threebody_number_radial_basis_functions") pod.threebody[2] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "threebody_number_angular_basis_functions") pod.threebody[3] = utils::inumeric(FLERR,words[1],false,lmp)-1; if (keywd == "fourbody_bessel_polynomial_degree") pod.fourbody[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_inverse_polynomial_degree") pod.fourbody[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_number_radial_basis_functions") pod.fourbody[2] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_snap_twojmax") pod.snaptwojmax = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_snap_chemflag") pod.snapchemflag = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_snap_rfac0") pod.snaprfac0 = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_snap_neighbor_weight1") pod.snapelementweight[0] = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_snap_neighbor_weight2") pod.snapelementweight[1] = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_snap_neighbor_weight3") pod.snapelementweight[2] = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_snap_neighbor_weight4") pod.snapelementweight[3] = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "fourbody_snap_neighbor_weight5") pod.snapelementweight[4] = utils::numeric(FLERR,words[1],false,lmp); if (keywd == "quadratic_pod_potential") pod.quadraticpod = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic22_number_twobody_basis_functions") pod.quadratic22[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic22_number_twobody_basis_functions") pod.quadratic22[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic23_number_twobody_basis_functions") pod.quadratic23[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic23_number_threebody_basis_functions") pod.quadratic23[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic24_number_twobody_basis_functions") pod.quadratic24[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic24_number_fourbody_basis_functions") pod.quadratic24[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic33_number_threebody_basis_functions") pod.quadratic33[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic33_number_threebody_basis_functions") pod.quadratic33[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic34_number_threebody_basis_functions") pod.quadratic34[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic34_number_fourbody_basis_functions") pod.quadratic34[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic44_number_fourbody_basis_functions") pod.quadratic44[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "quadratic44_number_fourbody_basis_functions") pod.quadratic44[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "cubic234_number_twobody_basis_functions") pod.cubic234[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "cubic234_number_threebody_basis_functions") pod.cubic234[1] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "cubic234_number_fourbody_basis_functions") pod.cubic234[2] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "cubic333_number_threebody_basis_functions") pod.cubic333[0] = utils::inumeric(FLERR,words[1],false,lmp); if (keywd == "cubic444_number_fourbody_basis_functions") pod.cubic444[0] = utils::inumeric(FLERR,words[1],false,lmp); } } pod.twobody[0] = pod.besseldegree; pod.twobody[1] = pod.inversedegree; pod.threebody[0] = pod.besseldegree; pod.threebody[1] = pod.inversedegree; // number of snapshots pod.ns2 = pod.nbesselpars*pod.twobody[0] + pod.twobody[1]; pod.ns3 = pod.nbesselpars*pod.threebody[0] + pod.threebody[1]; pod.ns4 = pod.nbesselpars*pod.fourbody[0] + pod.fourbody[1]; for (int i = 0; i < pod.nbesselpars; i++) if (fabs(pod.besselparams[i]) < 1e-3) pod.besselparams[i] = 1e-3; // allocate memory for eigenvectors and eigenvalues if (pod.ns2 > 0) { memory->create(pod.Phi2, pod.ns2*pod.ns2, "pod:pod_Phi2"); memory->create(pod.Lambda2, pod.ns2, "pod:pod_Lambda2"); } if (pod.ns3 > 0) { memory->create(pod.Phi3, pod.ns3*pod.ns3, "pod:pod_Phi3"); memory->create(pod.Lambda3, pod.ns3, "pod:pod_Lambda3"); } if (pod.ns4 > 0) { memory->create(pod.Phi4, pod.ns4*pod.ns4, "pod:pod_Phi4"); memory->create(pod.Lambda4, pod.ns4, "pod:pod_Lambda4"); } if (pod.ns2 > 0) { podeigenvaluedecomposition(pod.Phi2, pod.Lambda2, pod.besselparams, pod.rin, pod.rcut, pod.twobody[0], pod.twobody[1], pod.nbesselpars, 2000); // /* Print eigenvalues */ // print_matrix( "Eigenvalues for two-body potential:", 1, pod.ns2, pod.Lambda2, 1 ); // // /* Print eigenvectors */ // print_matrix( "Eigenvectors for two-body potential:", pod.ns2, pod.ns2, pod.Phi2, pod.ns2); } if (pod.ns3 > 0) { podeigenvaluedecomposition(pod.Phi3, pod.Lambda3, pod.besselparams, pod.rin, pod.rcut, pod.threebody[0], pod.threebody[1], pod.nbesselpars, 2000); } if (pod.ns4 > 0) { podeigenvaluedecomposition(pod.Phi4, pod.Lambda4, pod.besselparams, pod.rin, pod.rcut, pod.fourbody[0], pod.fourbody[1], pod.nbesselpars, 2000); } // number of chemical combinations pod.nc2 = pod.nelements*(pod.nelements+1)/2; pod.nc3 = pod.nelements*pod.nelements*(pod.nelements+1)/2; pod.nc4 = pod.snapchemflag ? pod.nelements*pod.nelements*pod.nelements*pod.nelements : pod.nelements; // number of basis functions and descriptors for one-body potential if (pod.onebody==1) { pod.nbf1 = 1; pod.nd1 = pod.nelements; } else { pod.nbf1 = 0; pod.nd1 = 0; } // number of basis functions and descriptors for two-body potential pod.nbf2 = pod.twobody[2]; pod.nd2 = pod.nbf2*pod.nc2; // number of basis functions and descriptors for three-body potential pod.nrbf3 = pod.threebody[2]; pod.nabf3 = pod.threebody[3]; pod.nbf3 = pod.nrbf3*(1 + pod.nabf3); pod.nd3 = pod.nbf3*pod.nc3; // number of basis functions and descriptors for four-body potential int twojmax = pod.snaptwojmax; int idxb_count = 0; if (twojmax > 0) { for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) if (j >= j1) idxb_count++; } pod.nbf4 = idxb_count; pod.nd4 = pod.nbf4*pod.nc4; if (pod.quadraticpod==1) { pod.quadratic23[0] = pod.nbf2; pod.quadratic23[1] = pod.nbf3; } pod.quadratic22[0] = MIN(pod.quadratic22[0], pod.nbf2); pod.quadratic22[1] = MIN(pod.quadratic22[1], pod.nbf2); pod.quadratic23[0] = MIN(pod.quadratic23[0], pod.nbf2); pod.quadratic23[1] = MIN(pod.quadratic23[1], pod.nbf3); pod.quadratic24[0] = MIN(pod.quadratic24[0], pod.nbf2); pod.quadratic24[1] = MIN(pod.quadratic24[1], pod.nbf4); pod.quadratic33[0] = MIN(pod.quadratic33[0], pod.nbf3); pod.quadratic33[1] = MIN(pod.quadratic33[1], pod.nbf3); pod.quadratic34[0] = MIN(pod.quadratic34[0], pod.nbf3); pod.quadratic34[1] = MIN(pod.quadratic34[1], pod.nbf4); pod.quadratic44[0] = MIN(pod.quadratic44[0], pod.nbf4); pod.quadratic44[1] = MIN(pod.quadratic44[1], pod.nbf4); pod.cubic234[0] = MIN(pod.cubic234[0], pod.nbf2); pod.cubic234[1] = MIN(pod.cubic234[1], pod.nbf3); pod.cubic234[2] = MIN(pod.cubic234[2], pod.nbf4); pod.cubic333[0] = MIN(pod.cubic333[0], pod.nbf3); pod.cubic333[1] = MIN(pod.cubic333[0], pod.nbf3); pod.cubic333[2] = MIN(pod.cubic333[0], pod.nbf3); pod.cubic444[0] = MIN(pod.cubic444[0], pod.nbf4); pod.cubic444[1] = MIN(pod.cubic444[0], pod.nbf4); pod.cubic444[2] = MIN(pod.cubic444[0], pod.nbf4); // number of descriptors for quadratic POD potentials pod.nd22 = pod.quadratic22[0]*pod.quadratic22[1]*pod.nc2*pod.nc2; pod.nd23 = pod.quadratic23[0]*pod.quadratic23[1]*pod.nc2*pod.nc3; pod.nd24 = pod.quadratic24[0]*pod.quadratic24[1]*pod.nc2*pod.nc4; pod.nd33 = pod.quadratic33[0]*pod.quadratic33[1]*pod.nc3*pod.nc3; pod.nd34 = pod.quadratic34[0]*pod.quadratic34[1]*pod.nc3*pod.nc4; pod.nd44 = pod.quadratic44[0]*pod.quadratic44[1]*pod.nc4*pod.nc4; int nq; nq = pod.quadratic22[0]*pod.nc2; pod.nd22 = nq*(nq+1)/2; nq = pod.quadratic33[0]*pod.nc3; pod.nd33 = nq*(nq+1)/2; nq = pod.quadratic44[0]*pod.nc4; pod.nd44 = nq*(nq+1)/2; // number of descriptors for cubic POD potentials pod.nd234 = pod.cubic234[0]*pod.cubic234[1]*pod.cubic234[2]*pod.nc2*pod.nc3*pod.nc4; nq = pod.cubic333[0]*pod.nc3; pod.nd333 = nq*(nq+1)*(nq+2)/6; nq = pod.cubic444[0]*pod.nc4; pod.nd444 = nq*(nq+1)*(nq+2)/6; // total number of descriptors for all POD potentials pod.nd = pod.nd1 + pod.nd2 + pod.nd3 + pod.nd4 + pod.nd22 + pod.nd23 + pod.nd24 + pod.nd33 + pod.nd34 + pod.nd44 + pod.nd234 + pod.nd333 + pod.nd444; pod.nd1234 = pod.nd1 + pod.nd2 + pod.nd3 + pod.nd4; int nelements = pod.nelements; delete[] pod.elemindex; pod.elemindex = new int[nelements*nelements]; int k = 1; for (int i=0; i < nelements; i++) { for (int j=i; j < nelements; j++) { pod.elemindex[i + nelements*j] = k; pod.elemindex[j + nelements*i] = k; k += 1; } } if (comm->me == 0) { utils::logmesg(lmp, "**************** Begin of POD Potentials ****************\n"); utils::logmesg(lmp, "species: "); for (int i=0; ime == 0) { fpcoeff = utils::open_potential(coefffilename,lmp,nullptr); if (fpcoeff == nullptr) error->one(FLERR,"Cannot open POD coefficient file {}: ", coefffilename, utils::getsyserror()); } // check format for first line of file char line[MAXLINE],*ptr; int eof = 0; int nwords = 0; while (nwords == 0) { if (comm->me == 0) { ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; fclose(fpcoeff); } } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) break; MPI_Bcast(line,MAXLINE,MPI_CHAR,0,world); // strip comment, skip line if blank nwords = utils::count_words(utils::trim_comment(line)); } if (nwords != 2) error->all(FLERR,"Incorrect format in POD coefficient file"); // strip single and double quotes from words int ncoeffall; std::string tmp_str; try { ValueTokenizer words(utils::trim_comment(line),"\"' \t\n\r\f"); tmp_str = words.next_string(); ncoeffall = words.next_int(); } catch (TokenizerException &e) { error->all(FLERR,"Incorrect format in POD coefficient file: {}", e.what()); } // loop over single block of coefficients and insert values in pod.coeff memory->create(pod.coeff, ncoeffall, "pod:pod_coeff"); for (int icoeff = 0; icoeff < ncoeffall; icoeff++) { if (comm->me == 0) { ptr = fgets(line,MAXLINE,fpcoeff); if (ptr == nullptr) { eof = 1; fclose(fpcoeff); } } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) error->all(FLERR,"Incorrect format in POD coefficient file"); MPI_Bcast(line,MAXLINE,MPI_CHAR,0,world); try { ValueTokenizer coeff(utils::trim_comment(line)); if (coeff.count() != 1) error->all(FLERR,"Incorrect format in POD coefficient file"); pod.coeff[icoeff] = coeff.next_double(); } catch (TokenizerException &e) { error->all(FLERR,"Incorrect format in POD coefficient file: {}", e.what()); } } if (comm->me == 0) { if (!eof) fclose(fpcoeff); } } /*********************************************************************************************************/ void MLPOD::linear_descriptors(double *gd, double *efatom, double *y, double *tmpmem, int *atomtype, int *alist, int *pairlist, int * /*pairnum*/, int *pairnumsum, int *tmpint, int natom, int Nij) { int dim = 3; int nelements = pod.nelements; int nbesselpars = pod.nbesselpars; int nrbf2 = pod.nbf2; int nabf3 = pod.nabf3; int nrbf3 = pod.nrbf3; int nd1 = pod.nd1; int nd2 = pod.nd2; int nd3 = pod.nd3; int nd4 = pod.nd4; int nd1234 = nd1+nd2+nd3+nd4; int *pdegree2 = pod.twobody; int *elemindex = pod.elemindex; double rin = pod.rin; double rcut = pod.rcut; double *Phi2 = pod.Phi2; double *besselparams = pod.besselparams; double *fatom1 = &efatom[0]; double *fatom2 = &efatom[dim*natom*(nd1)]; double *fatom3 = &efatom[dim*natom*(nd1+nd2)]; double *fatom4 = &efatom[dim*natom*(nd1+nd2+nd3)]; double *eatom1 = &efatom[dim*natom*(nd1+nd2+nd3+nd4)]; double *eatom2 = &efatom[dim*natom*(nd1+nd2+nd3+nd4)+natom*nd1]; double *eatom3 = &efatom[dim*natom*(nd1+nd2+nd3+nd4)+natom*(nd1+nd2)]; double *eatom4 = &efatom[dim*natom*(nd1+nd2+nd3+nd4)+natom*(nd1+nd2+nd3)]; podArraySetValue(fatom1, 0.0, (1+dim)*natom*(nd1+nd2+nd3+nd4)); double *rij = &tmpmem[0]; // 3*Nij int *ai = &tmpint[0]; // Nij int *aj = &tmpint[Nij]; // Nij int *ti = &tmpint[2*Nij]; // Nij int *tj = &tmpint[3*Nij]; // Nij podNeighPairs(rij, y, ai, aj, ti, tj, pairlist, pairnumsum, atomtype, alist, natom, dim); // peratom descriptors for one-body, two-body, and three-body linear potentials poddesc(eatom1, fatom1, eatom2, fatom2, eatom3, fatom3, rij, Phi2, besselparams, &tmpmem[3*Nij], rin, rcut, pairnumsum, atomtype, ai, aj, ti, tj, elemindex, pdegree2, nbesselpars, nrbf2, nrbf3, nabf3, nelements, Nij, natom); if (pod.snaptwojmax > 0) snapdesc(eatom4, fatom4, rij, &tmpmem[3*Nij], atomtype, ai, aj, ti, tj, natom, Nij); // global descriptors for one-body, two-body, three-body, and four-bodt linear potentials podArraySetValue(tmpmem, 1.0, natom); char cht = 'T'; double one = 1.0, zero = 0.0; int inc1 = 1; DGEMV(&cht, &natom, &nd1234, &one, eatom1, &natom, tmpmem, &inc1, &zero, gd, &inc1); } void MLPOD::quadratic_descriptors(double* d23, double *dd23, double* d2, double *d3, double* dd2, double *dd3, int M2, int M3, int N) { for (int m3 = 0; m3 0) energy += quadratic_coefficients(c2, d2, coeff22, pod.quadratic22, nc2); // calculate energy for quadratic23 potential if (nd23 > 0) energy += quadratic_coefficients(c2, c3, d2, d3, coeff23, pod.quadratic23, nc2, nc3); // calculate energy for quadratic24 potential if (nd24 > 0) energy += quadratic_coefficients(c2, c4, d2, d4, coeff24, pod.quadratic24, nc2, nc4); // calculate energy for quadratic33 potential if (nd33 > 0) energy += quadratic_coefficients(c3, d3, coeff33, pod.quadratic33, nc3); // calculate energy for quadratic34 potential if (nd34 > 0) energy += quadratic_coefficients(c3, c4, d3, d4, coeff34, pod.quadratic34, nc3, nc4); // calculate energy for quadratic44 potential if (nd44 > 0) energy += quadratic_coefficients(c4, d4, coeff44, pod.quadratic44, nc4); // calculate energy for cubic234 potential if (nd234 > 0) energy += cubic_coefficients(c2, c3, c4, d2, d3, d4, coeff234, pod.cubic234, nc2, nc3, nc4); // calculate energy for cubic333 potential if (nd333 > 0) energy += cubic_coefficients(c3, d3, coeff333, pod.cubic333, nc3); // calculate energy for cubic444 potential if (nd444 > 0) energy += cubic_coefficients(c4, d4, coeff444, pod.cubic444, nc4); // calculate effective POD coefficients for (int i=0; i< nd1234; i++) c1[i] += coeff[i]; // calculate force = gdd * c1 char chn = 'N'; double one = 1.0, zero = 0.0; int inc1 = 1; DGEMV(&chn, &nforce, &nd1234, &one, gdd, &nforce, c1, &inc1, &zero, force, &inc1); return energy; } double MLPOD::energyforce_calculation(double *force, double *gd, double *gdd, double *coeff, double *y, int *atomtype, int *alist, int *pairlist, int *pairnum, int *pairnumsum, int *tmpint, int natom, int Nij) { int dim = 3; int nd1234 = pod.nd1+pod.nd2+pod.nd3+pod.nd4; double *tmpmem = &gdd[dim*natom*nd1234+natom*nd1234]; // calculate POD and SNAP descriptors and their derivatives linear_descriptors(gd, gdd, y, tmpmem, atomtype, alist, pairlist, pairnum, pairnumsum, tmpint, natom, Nij); // calculate energy and force double energy = 0.0; energy = calculate_energyforce(force, gd, gdd, coeff, &gdd[dim*natom*nd1234], natom); return energy; } void MLPOD::podNeighPairs(double *xij, double *x, int *ai, int *aj, int *ti, int *tj, int *pairlist, int *pairnumsum, int *atomtype, int *alist, int inum, int dim) { for (int ii=0; ii j) ik = lk + s; k = aj[ik]; // atom k typek = tj[ik] - 1; xik1 = yij[0+dim*ik]; // xk - xi xik2 = yij[1+dim*ik]; // xk - xi xik3 = yij[2+dim*ik]; // xk - xi riksq = xik1*xik1 + xik2*xik2 + xik3*xik3; rik = sqrt(riksq); xdot = xij1*xik1 + xij2*xik2 + xij3*xik3; costhe = xdot/(rij*rik); costhe = costhe > 1.0 ? 1.0 : costhe; costhe = costhe < -1.0 ? -1.0 : costhe; xdot = costhe*(rij*rik); sinthe = sqrt(1.0 - costhe*costhe); sinthe = sinthe > 1e-12 ? sinthe : 1e-12; theta = acos(costhe); dtheta = -1.0/sinthe; tm1 = 1.0/(rij*rijsq*rik); tm2 = 1.0/(rij*riksq*rik); dct1 = (xik1*rijsq - xij1*xdot)*tm1; dct2 = (xik2*rijsq - xij2*xdot)*tm1; dct3 = (xik3*rijsq - xij3*xdot)*tm1; dct4 = (xij1*riksq - xik1*xdot)*tm2; dct5 = (xij2*riksq - xik2*xdot)*tm2; dct6 = (xij3*riksq - xik3*xdot)*tm2; for (int p=0; p = j1) idxb_count++; int idxb_max = idxb_count; idx_max[2] = idxb_max; idxb_count = 0; for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) if (j >= j1) { idxb[idxb_count*3 + 0] = j1; idxb[idxb_count*3 + 1] = j2; idxb[idxb_count*3 + 2] = j; idxb_count++; } idxb_count = 0; for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) { if (j >= j1) { idxb_block[j + j2*jdim + j1*jdim*jdim] = idxb_count; idxb_count++; } } // index list for zlist int idxz_count = 0; for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) for (int mb = 0; 2*mb <= j; mb++) for (int ma = 0; ma <= j; ma++) idxz_count++; int idxz_max = idxz_count; idx_max[3] = idxz_max; idxz_count = 0; for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) { idxz_block[j + j2*jdim + j1*jdim*jdim] = idxz_count; for (int mb = 0; 2*mb <= j; mb++) for (int ma = 0; ma <= j; ma++) { idxz[idxz_count*10 + 0] = j1; idxz[idxz_count*10 + 1] = j2; idxz[idxz_count*10 + 2] = j; idxz[idxz_count*10 + 3] = MAX(0, (2 * ma - j - j2 + j1) / 2); idxz[idxz_count*10 + 4] = (2 * ma - j - (2 * idxz[idxz_count*10 + 3] - j1) + j2) / 2; idxz[idxz_count*10 + 5] = MIN(j1, (2 * ma - j + j2 + j1) / 2) - idxz[idxz_count*10 + 3] + 1; idxz[idxz_count*10 + 6] = MAX(0, (2 * mb - j - j2 + j1) / 2); idxz[idxz_count*10 + 7] = (2 * mb - j - (2 * idxz[idxz_count*10 + 6] - j1) + j2) / 2; idxz[idxz_count*10 + 8] = MIN(j1, (2 * mb - j + j2 + j1) / 2) - idxz[idxz_count*10 + 6] + 1; const int jju = idxu_block[j] + (j+1)*mb + ma; idxz[idxz_count*10 + 9] = jju; idxz_count++; } } }; void snapInitRootpqArray(double *rootpqarray, int twojmax) { int jdim = twojmax + 1; for (int p = 1; p <= twojmax; p++) for (int q = 1; q <= twojmax; q++) rootpqarray[p*jdim + q] = sqrt(((double) p)/q); }; double snapDeltacg(double *factorial, int j1, int j2, int j) { double sfaccg = factorial[(j1 + j2 + j) / 2 + 1]; return sqrt(factorial[(j1 + j2 - j) / 2] * factorial[(j1 - j2 + j) / 2] * factorial[(-j1 + j2 + j) / 2] / sfaccg); }; void snapInitClebschGordan(double *cglist, double *factorial, int twojmax) { double sum,dcg,sfaccg; int m, aa2, bb2, cc2; int ifac; int idxcg_count = 0; for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) { for (int m1 = 0; m1 <= j1; m1++) { aa2 = 2 * m1 - j1; for (int m2 = 0; m2 <= j2; m2++) { bb2 = 2 * m2 - j2; m = (aa2 + bb2 + j) / 2; if(m < 0 || m > j) { cglist[idxcg_count] = 0.0; idxcg_count++; continue; } sum = 0.0; for (int z = MAX(0, MAX(-(j - j2 + aa2) / 2, -(j - j1 - bb2) / 2)); z <= MIN((j1 + j2 - j) / 2, MIN((j1 - aa2) / 2, (j2 + bb2) / 2)); z++) { ifac = z % 2 ? -1 : 1; sum += ifac / (factorial[z] * factorial[(j1 + j2 - j) / 2 - z] * factorial[(j1 - aa2) / 2 - z] * factorial[(j2 + bb2) / 2 - z] * factorial[(j - j2 + aa2) / 2 + z] * factorial[(j - j1 - bb2) / 2 + z]); } cc2 = 2 * m - j; dcg = snapDeltacg(factorial, j1, j2, j); sfaccg = sqrt(factorial[(j1 + aa2) / 2] * factorial[(j1 - aa2) / 2] * factorial[(j2 + bb2) / 2] * factorial[(j2 - bb2) / 2] * factorial[(j + cc2) / 2] * factorial[(j - cc2) / 2] * (j + 1)); cglist[idxcg_count] = sum * dcg * sfaccg; idxcg_count++; } } } } void snapInitSna(double *rootpqarray, double *cglist, double *factorial, int *idx_max, int *idxz, int *idxz_block, int *idxb, int *idxb_block, int *idxu_block, int *idxcg_block, int twojmax) { snapBuildIndexList(idx_max, idxz, idxz_block, idxb, idxb_block, idxu_block, idxcg_block, twojmax); snapInitRootpqArray(rootpqarray, twojmax); snapInitClebschGordan(cglist, factorial, twojmax); } void MLPOD::snapSetup(int twojmax, int ntypes) { sna.twojmax = twojmax; sna.ntypes = ntypes; int jdim = twojmax + 1; int jdimpq = twojmax + 2; memory->create(sna.map, ntypes+1, "pod:sna_map"); memory->create(sna.idxcg_block, jdim*jdim*jdim, "pod:sna_idxcg_block"); memory->create(sna.idxz_block, jdim*jdim*jdim, "pod:sna_idxz_block"); memory->create(sna.idxb_block, jdim*jdim*jdim, "pod:sna_idxb_block"); memory->create(sna.idxu_block, jdim, "pod:sna_idxu_block"); memory->create(sna.idx_max, 5, "pod:sna_idx_max"); int idxb_count = 0; for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) if (j >= j1) idxb_count++; int idxz_count = 0; for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) for (int mb = 0; 2*mb <= j; mb++) for (int ma = 0; ma <= j; ma++) idxz_count++; int idxcg_count = 0; for(int j1 = 0; j1 <= twojmax; j1++) for(int j2 = 0; j2 <= j1; j2++) for(int j = j1 - j2; j <= MIN(twojmax, j1 + j2); j += 2) { for (int m1 = 0; m1 <= j1; m1++) for (int m2 = 0; m2 <= j2; m2++) idxcg_count++; } memory->create(sna.idxz, idxz_count*10, "pod:sna_idxz"); memory->create(sna.idxb, idxb_count*3, "pod:sna_idxb"); memory->create(sna.rcutsq, (ntypes+1)*(ntypes+1), "pod:sna_rcutsq"); memory->create(sna.radelem, ntypes+1, "pod:sna_radelem"); memory->create(sna.wjelem, ntypes+1, "pod:sna_wjelem"); memory->create(sna.rootpqarray, jdimpq*jdimpq, "pod:sna_rootpqarray"); memory->create(sna.cglist, idxcg_count, "pod:sna_cglist"); memory->create(sna.bzero, jdim, "pod:sna_bzero"); memory->create(sna.fac, 168, "pod:sna_fac"); for (int i=0; i rcutij) { sfac = 0.0; dsfac = 0.0; } else { double rcutfac0 = MY_PI / (rcutij - rmin0); sfac = 0.5 * (cos((r - rmin0) * rcutfac0) + 1.0); dsfac = -0.5 * sin((r - rmin0) * rcutfac0) * rcutfac0; } } sfac *= wjelem[tj[ij]]; dsfac *= wjelem[tj[ij]]; double r0inv, dr0invdr; double a_r, a_i, b_r, b_i; double da_r[3], da_i[3], db_r[3], db_i[3]; double dz0[3], dr0inv[3]; double rootpq; int jdim = twojmax + 1; r0inv = 1.0 / sqrt(r * r + z0 * z0); a_r = r0inv * z0; a_i = -r0inv * z; b_r = r0inv * y; b_i = -r0inv * x; dr0invdr = -cube(r0inv) * (r + z0 * dz0dr); dr0inv[0] = dr0invdr * ux; dr0inv[1] = dr0invdr * uy; dr0inv[2] = dr0invdr * uz; dz0[0] = dz0dr * ux; dz0[1] = dz0dr * uy; dz0[2] = dz0dr * uz; for (int k = 0; k < 3; k++) { da_r[k] = dz0[k] * r0inv + z0 * dr0inv[k]; da_i[k] = -z * dr0inv[k]; } da_i[2] += -r0inv; for (int k = 0; k < 3; k++) { db_r[k] = y * dr0inv[k]; db_i[k] = -x * dr0inv[k]; } db_i[0] += -r0inv; db_r[1] += r0inv; Sr[ij+0*ijnum] = 1.0; Si[ij+0*ijnum] = 0.0; Srx[ij+0*ijnum] = 0.0; Six[ij+0*ijnum] = 0.0; Sry[ij+0*ijnum] = 0.0; Siy[ij+0*ijnum] = 0.0; Srz[ij+0*ijnum] = 0.0; Siz[ij+0*ijnum] = 0.0; for (int j = 1; j <= twojmax; j++) { int jju = idxu_block[j]; int jjup = idxu_block[j-1]; // fill in left side of matrix layer from previous layer for (int mb = 0; 2*mb <= j; mb++) { Sr[ij+jju*ijnum] = 0.0; Si[ij+jju*ijnum] = 0.0; Srx[ij+jju*ijnum] = 0.0; Six[ij+jju*ijnum] = 0.0; Sry[ij+jju*ijnum] = 0.0; Siy[ij+jju*ijnum] = 0.0; Srz[ij+jju*ijnum] = 0.0; Siz[ij+jju*ijnum] = 0.0; for (int ma = 0; ma < j; ma++) { rootpq = rootpqarray[(j - ma)*jdim + (j - mb)]; int njju = ij+jju*ijnum; int njju1 = ij+(jju+1)*ijnum; int njjup = ij+jjup*ijnum; double u_r = Sr[njjup]; double u_i = Si[njjup]; double ux_r = Srx[njjup]; double ux_i = Six[njjup]; double uy_r = Sry[njjup]; double uy_i = Siy[njjup]; double uz_r = Srz[njjup]; double uz_i = Siz[njjup]; Sr[njju] += rootpq * (a_r * u_r + a_i * u_i); Si[njju] += rootpq * (a_r * u_i - a_i * u_r); Srx[njju] += rootpq * (da_r[0] * u_r + da_i[0] * u_i + a_r * ux_r + a_i * ux_i); Six[njju] += rootpq * (da_r[0] * u_i - da_i[0] * u_r + a_r * ux_i - a_i * ux_r); Sry[njju] += rootpq * (da_r[1] * u_r + da_i[1] * u_i + a_r * uy_r + a_i * uy_i); Siy[njju] += rootpq * (da_r[1] * u_i - da_i[1] * u_r + a_r * uy_i - a_i * uy_r); Srz[njju] += rootpq * (da_r[2] * u_r + da_i[2] * u_i + a_r * uz_r + a_i * uz_i); Siz[njju] += rootpq * (da_r[2] * u_i - da_i[2] * u_r + a_r * uz_i - a_i * uz_r); rootpq = rootpqarray[(ma + 1)*jdim + (j - mb)]; Sr[njju1] = -rootpq * (b_r * u_r + b_i * u_i); Si[njju1] = -rootpq * (b_r * u_i - b_i * u_r); Srx[njju1] = -rootpq * (db_r[0] * u_r + db_i[0] * u_i + b_r * ux_r + b_i * ux_i); Six[njju1] = -rootpq * (db_r[0] * u_i - db_i[0] * u_r + b_r * ux_i - b_i * ux_r); Sry[njju1] = -rootpq * (db_r[1] * u_r + db_i[1] * u_i + b_r * uy_r + b_i * uy_i); Siy[njju1] = -rootpq * (db_r[1] * u_i - db_i[1] * u_r + b_r * uy_i - b_i * uy_r); Srz[njju1] = -rootpq * (db_r[2] * u_r + db_i[2] * u_i + b_r * uz_r + b_i * uz_i); Siz[njju1] = -rootpq * (db_r[2] * u_i - db_i[2] * u_r + b_r * uz_i - b_i * uz_r); jju++; jjup++; } jju++; } jju = idxu_block[j]; jjup = jju+(j+1)*(j+1)-1; int mbpar = 1; for (int mb = 0; 2*mb <= j; mb++) { int mapar = mbpar; for (int ma = 0; ma <= j; ma++) { int njju = ij+jju*ijnum; int njjup = ij+jjup*ijnum; if (mapar == 1) { Sr[njjup] = Sr[njju]; Si[njjup] = -Si[njju]; if (j%2==1 && mb==(j/2)) { Srx[njjup] = Srx[njju]; Six[njjup] = -Six[njju]; Sry[njjup] = Sry[njju]; Siy[njjup] = -Siy[njju]; Srz[njjup] = Srz[njju]; Siz[njjup] = -Siz[njju]; } } else { Sr[njjup] = -Sr[njju]; Si[njjup] = Si[njju]; if (j%2==1 && mb==(j/2)) { Srx[njjup] = -Srx[njju]; Six[njjup] = Six[njju]; Sry[njjup] = -Sry[njju]; Siy[njjup] = Siy[njju]; Srz[njjup] = -Srz[njju]; Siz[njjup] = Siz[njju]; } } mapar = -mapar; jju++; jjup--; } mbpar = -mbpar; } } for (int j = 0; j <= twojmax; j++) { int jju = idxu_block[j]; for (int mb = 0; 2*mb <= j; mb++) for (int ma = 0; ma <= j; ma++) { int ijk = ij+jju*ijnum; Srx[ijk] = dsfac * Sr[ijk] * ux + sfac * Srx[ijk]; Six[ijk] = dsfac * Si[ijk] * ux + sfac * Six[ijk]; Sry[ijk] = dsfac * Sr[ijk] * uy + sfac * Sry[ijk]; Siy[ijk] = dsfac * Si[ijk] * uy + sfac * Siy[ijk]; Srz[ijk] = dsfac * Sr[ijk] * uz + sfac * Srz[ijk]; Siz[ijk] = dsfac * Si[ijk] * uz + sfac * Siz[ijk]; jju++; } } for (int k=0; k 1e-20) { rij[ninside*3 + 0] = delx; rij[ninside*3 + 1] = dely; rij[ninside*3 + 2] = delz; idxi[ninside] = ii; ai[ninside] = gi; aj[ninside] = gj; ti[ninside] = itype; tj[ninside] = atomtype[gj]; ninside++; pairnumsum[ii+1] += 1; } } } pairnumsum[0] = 0; for (int ii=0; ii j) ik = lk + s; typek = tj[ik] - 1; xik1 = yij[0+dim*ik]; // xk - xi xik2 = yij[1+dim*ik]; // xk - xi xik3 = yij[2+dim*ik]; // xk - xi s riksq = xik1*xik1 + xik2*xik2 + xik3*xik3; rik = sqrt(riksq); xdot = xij1*xik1 + xij2*xik2 + xij3*xik3; costhe = xdot/(rij*rik); costhe = costhe > 1.0 ? 1.0 : costhe; costhe = costhe < -1.0 ? -1.0 : costhe; theta = acos(costhe); for (int p=0; p rcutij) { sfac = 0.0; } else { double rcutfac0 = MY_PI / (rcutij - rmin0); sfac = 0.5 * (cos((r - rmin0) * rcutfac0) + 1.0); } } sfac *= wjelem[tj[ij]]; double r0inv; double a_r, a_i, b_r, b_i; double rootpq; int jdim = twojmax + 1; r0inv = 1.0 / sqrt(r * r + z0 * z0); a_r = r0inv * z0; a_i = -r0inv * z; b_r = r0inv * y; b_i = -r0inv * x; Sr[ij+0*ijnum] = 1.0; Si[ij+0*ijnum] = 0.0; for (int j = 1; j <= twojmax; j++) { int jju = idxu_block[j]; int jjup = idxu_block[j-1]; // fill in left side of matrix layer from previous layer for (int mb = 0; 2*mb <= j; mb++) { Sr[ij+jju*ijnum] = 0.0; Si[ij+jju*ijnum] = 0.0; for (int ma = 0; ma < j; ma++) { rootpq = rootpqarray[(j - ma)*jdim + (j - mb)]; int njju = ij+jju*ijnum; int njju1 = ij+(jju+1)*ijnum; int njjup = ij+jjup*ijnum; double u_r = Sr[njjup]; double u_i = Si[njjup]; Sr[njju] += rootpq * (a_r * u_r + a_i * u_i); Si[njju] += rootpq * (a_r * u_i - a_i * u_r); rootpq = rootpqarray[(ma + 1)*jdim + (j - mb)]; Sr[njju1] = -rootpq * (b_r * u_r + b_i * u_i); Si[njju1] = -rootpq * (b_r * u_i - b_i * u_r); jju++; jjup++; } jju++; } jju = idxu_block[j]; jjup = jju+(j+1)*(j+1)-1; int mbpar = 1; for (int mb = 0; 2*mb <= j; mb++) { int mapar = mbpar; for (int ma = 0; ma <= j; ma++) { int njju = ij+jju*ijnum; int njjup = ij+jjup*ijnum; if (mapar == 1) { Sr[njjup] = Sr[njju]; Si[njjup] = -Si[njju]; } else { Sr[njjup] = -Sr[njju]; Si[njjup] = Si[njju]; } mapar = -mapar; jju++; jjup--; } mbpar = -mbpar; } } for (int k=0; k 0) snapdesc_ij(eatom4, rij, tmpmem, atomtype, idxi, ti, tj, natom, Nij); // global descriptors for one-body, two-body, three-body, and four-bodt linear potentials podArraySetValue(tmpmem, 1.0, natom); char cht = 'T'; double one = 1.0; int inc1 = 1; DGEMV(&cht, &natom, &nd1234, &one, eatom1, &natom, tmpmem, &inc1, &one, gd, &inc1); } double MLPOD::calculate_energy(double *effectivecoeff, double *gd, double *coeff) { int nd1 = pod.nd1; int nd2 = pod.nd2; int nd3 = pod.nd3; int nd4 = pod.nd4; int nd1234 = nd1+nd2+nd3+nd4; int nd22 = pod.nd22; int nd23 = pod.nd23; int nd24 = pod.nd24; int nd33 = pod.nd33; int nd34 = pod.nd34; int nd44 = pod.nd44; int nd234 = pod.nd234; int nd333 = pod.nd333; int nd444 = pod.nd444; int nc2 = pod.nc2; int nc3 = pod.nc3; int nc4 = pod.nc4; // two-body, three-body, and four-body descriptors double *d2 = &gd[nd1]; double *d3 = &gd[nd1+nd2]; double *d4 = &gd[nd1+nd2+nd3]; // quadratic and cubic POD coefficients double *coeff22 = &coeff[nd1234]; double *coeff23 = &coeff[nd1234+nd22]; double *coeff24 = &coeff[nd1234+nd22+nd23]; double *coeff33 = &coeff[nd1234+nd22+nd23+nd24]; double *coeff34 = &coeff[nd1234+nd22+nd23+nd24+nd33]; double *coeff44 = &coeff[nd1234+nd22+nd23+nd24+nd33+nd34]; double *coeff234 = &coeff[nd1234+nd22+nd23+nd24+nd33+nd34+nd44]; double *coeff333 = &coeff[nd1234+nd22+nd23+nd24+nd33+nd34+nd44+nd234]; double *coeff444 = &coeff[nd1234+nd22+nd23+nd24+nd33+nd34+nd44+nd234+nd333]; // calculate energy for linear potentials double energy = 0.0; for (int i=0; i< nd1234; i++) { effectivecoeff[i] = 0.0; energy += coeff[i]*gd[i]; } // effective POD coefficients for calculating force double *c2 = &effectivecoeff[nd1]; double *c3 = &effectivecoeff[nd1+nd2]; double *c4 = &effectivecoeff[nd1+nd2+nd3]; // calculate energy for quadratic22 potential if (nd22 > 0) energy += quadratic_coefficients(c2, d2, coeff22, pod.quadratic22, nc2); // calculate energy for quadratic23 potential if (nd23 > 0) energy += quadratic_coefficients(c2, c3, d2, d3, coeff23, pod.quadratic23, nc2, nc3); // calculate energy for quadratic24 potential if (nd24 > 0) energy += quadratic_coefficients(c2, c4, d2, d4, coeff24, pod.quadratic24, nc2, nc4); // calculate energy for quadratic33 potential if (nd33 > 0) energy += quadratic_coefficients(c3, d3, coeff33, pod.quadratic33, nc3); // calculate energy for quadratic34 potential if (nd34 > 0) energy += quadratic_coefficients(c3, c4, d3, d4, coeff34, pod.quadratic34, nc3, nc4); // calculate energy for quadratic44 potential if (nd44 > 0) energy += quadratic_coefficients(c4, d4, coeff44, pod.quadratic44, nc4); // calculate energy for cubic234 potential if (nd234 > 0) energy += cubic_coefficients(c2, c3, c4, d2, d3, d4, coeff234, pod.cubic234, nc2, nc3, nc4); // calculate energy for cubic333 potential if (nd333 > 0) energy += cubic_coefficients(c3, d3, coeff333, pod.cubic333, nc3); // calculate energy for cubic444 potential if (nd444 > 0) energy += cubic_coefficients(c4, d4, coeff444, pod.cubic444, nc4); // calculate effective POD coefficients for (int i=0; i< nd1234; i++) effectivecoeff[i] += coeff[i]; return energy; } double MLPOD::calculate_energy(double *energycoeff, double *forcecoeff, double *gd, double *gdall, double *coeff) { int nd1 = pod.nd1; int nd2 = pod.nd2; int nd3 = pod.nd3; int nd4 = pod.nd4; int nd1234 = nd1+nd2+nd3+nd4; int nd22 = pod.nd22; int nd23 = pod.nd23; int nd24 = pod.nd24; int nd33 = pod.nd33; int nd34 = pod.nd34; int nd44 = pod.nd44; int nd234 = pod.nd234; int nd333 = pod.nd333; int nd444 = pod.nd444; int nc2 = pod.nc2; int nc3 = pod.nc3; int nc4 = pod.nc4; // quadratic and cubic POD coefficients double *coeff22 = &coeff[nd1234]; double *coeff23 = &coeff[nd1234+nd22]; double *coeff24 = &coeff[nd1234+nd22+nd23]; double *coeff33 = &coeff[nd1234+nd22+nd23+nd24]; double *coeff34 = &coeff[nd1234+nd22+nd23+nd24+nd33]; double *coeff44 = &coeff[nd1234+nd22+nd23+nd24+nd33+nd34]; double *coeff234 = &coeff[nd1234+nd22+nd23+nd24+nd33+nd34+nd44]; double *coeff333 = &coeff[nd1234+nd22+nd23+nd24+nd33+nd34+nd44+nd234]; double *coeff444 = &coeff[nd1234+nd22+nd23+nd24+nd33+nd34+nd44+nd234+nd333]; // sum global descriptors over all MPI ranks MPI_Allreduce(gd, gdall, nd1234, MPI_DOUBLE, MPI_SUM, world); for (int i=0; i< nd1234; i++) { energycoeff[i] = 0.0; forcecoeff[i] = 0.0; } // effective POD coefficients for calculating force double *c2 = &forcecoeff[nd1]; double *c3 = &forcecoeff[nd1+nd2]; double *c4 = &forcecoeff[nd1+nd2+nd3]; // effective POD coefficients for calculating energy double *ce2 = &energycoeff[nd1]; double *ce3 = &energycoeff[nd1+nd2]; double *ce4 = &energycoeff[nd1+nd2+nd3]; // two-body, three-body, and four-body descriptors double *d2 = &gdall[nd1]; double *d3 = &gdall[nd1+nd2]; double *d4 = &gdall[nd1+nd2+nd3]; // calculate energy for quadratic22 potential if (nd22 > 0) quadratic_coefficients(ce2, c2, d2, coeff22, pod.quadratic22, nc2); // calculate energy for quadratic23 potential if (nd23 > 0) quadratic_coefficients(ce2, ce3, c2, c3, d2, d3, coeff23, pod.quadratic23, nc2, nc3); // calculate energy for quadratic24 potential if (nd24 > 0) quadratic_coefficients(ce2, ce4, c2, c4, d2, d4, coeff24, pod.quadratic24, nc2, nc4); // calculate energy for quadratic33 potential if (nd33 > 0) quadratic_coefficients(ce3, c3, d3, coeff33, pod.quadratic33, nc3); // calculate energy for quadratic34 potential if (nd34 > 0) quadratic_coefficients(ce3, ce4, c3, c4, d3, d4, coeff34, pod.quadratic34, nc3, nc4); // calculate energy for quadratic44 potential if (nd44 > 0) quadratic_coefficients(ce4, c4, d4, coeff44, pod.quadratic44, nc4); // calculate energy for cubic234 potential if (nd234 > 0) cubic_coefficients(ce2, ce3, ce4, c2, c3, c4, d2, d3, d4, coeff234, pod.cubic234, nc2, nc3, nc4); // calculate energy for cubic333 potential if (nd333 > 0) cubic_coefficients(ce3, c3, d3, coeff333, pod.cubic333, nc3); // calculate energy for cubic444 potential if (nd444 > 0) cubic_coefficients(ce4, c4, d4, coeff444, pod.cubic444, nc4); // calculate effective POD coefficients for (int i=0; i< nd1234; i++) { energycoeff[i] += coeff[i]; forcecoeff[i] += coeff[i]; } // calculate energy double energy = 0.0; for (int i=0; i< nd1234; i++) energy += energycoeff[i]*gd[i]; return energy; } void MLPOD::pod2body_force(double *force, double *fij, double *coeff2, int *ai, int *aj, int *ti, int *tj, int *elemindex, int nelements, int nbf, int /*natom*/, int N) { int nelements2 = nelements*(nelements+1)/2; for (int n=0; n j) ik = lk + s; k = aj[ik]; // atom k typek = tj[ik] - 1; xik1 = yij[0+dim*ik]; // xk - xi xik2 = yij[1+dim*ik]; // xk - xi xik3 = yij[2+dim*ik]; // xk - xi s riksq = xik1*xik1 + xik2*xik2 + xik3*xik3; rik = sqrt(riksq); xdot = xij1*xik1 + xij2*xik2 + xij3*xik3; costhe = xdot/(rij*rik); costhe = costhe > 1.0 ? 1.0 : costhe; costhe = costhe < -1.0 ? -1.0 : costhe; xdot = costhe*(rij*rik); sinthe = sqrt(1.0 - costhe*costhe); sinthe = sinthe > 1e-12 ? sinthe : 1e-12; theta = acos(costhe); dtheta = -1.0/sinthe; tm1 = 1.0/(rij*rijsq*rik); tm2 = 1.0/(rij*riksq*rik); dct1 = (xik1*rijsq - xij1*xdot)*tm1; dct2 = (xik2*rijsq - xij2*xdot)*tm1; dct3 = (xik3*rijsq - xij3*xdot)*tm1; dct4 = (xij1*riksq - xik1*xdot)*tm2; dct5 = (xij2*riksq - xik2*xdot)*tm2; dct6 = (xij3*riksq - xik3*xdot)*tm2; for (int p=0; p 0) pod4body_force(force, rij, coeff4, tmpmem, atomtype, idxi, ai, aj, ti, tj, natom, Nij); } double MLPOD::energyforce_calculation(double *force, double *podcoeff, double *effectivecoeff, double *gd, double *rij, double *tmpmem, int *pairnumsum, int *atomtype, int *idxi, int *ai, int *aj, int *ti, int *tj, int natom, int Nij) { int nd1234 = pod.nd1+pod.nd2+pod.nd3+pod.nd4; double *eatom = &tmpmem[0]; podArraySetValue(gd, 0.0, nd1234); linear_descriptors_ij(gd, eatom, rij, &tmpmem[natom*nd1234], pairnumsum, atomtype, idxi, ti, tj, natom, Nij); // Need to do MPI_Allreduce on gd for parallel double energy = calculate_energy(effectivecoeff, gd, podcoeff); podArraySetValue(force, 0.0, 3*natom); calculate_force(force, effectivecoeff, rij, tmpmem, pairnumsum, atomtype, idxi, ai, aj, ti, tj, natom, Nij); return energy; } void MLPOD::pod2body_force(double **force, double *fij, double *coeff2, int *ai, int *aj, int *ti, int *tj, int *elemindex, int nelements, int nbf, int /*natom*/, int N) { int nelements2 = nelements*(nelements+1)/2; for (int n=0; n j) ik = lk + s; k = aj[ik]; // atom k typek = tj[ik] - 1; xik1 = yij[0+dim*ik]; // xk - xi xik2 = yij[1+dim*ik]; // xk - xi xik3 = yij[2+dim*ik]; // xk - xi s riksq = xik1*xik1 + xik2*xik2 + xik3*xik3; rik = sqrt(riksq); xdot = xij1*xik1 + xij2*xik2 + xij3*xik3; costhe = xdot/(rij*rik); costhe = costhe > 1.0 ? 1.0 : costhe; costhe = costhe < -1.0 ? -1.0 : costhe; xdot = costhe*(rij*rik); sinthe = pow(1.0 - costhe*costhe, 0.5); sinthe = sinthe > 1e-12 ? sinthe : 1e-12; theta = acos(costhe); dtheta = -1.0/sinthe; tm1 = 1.0/(rij*rijsq*rik); tm2 = 1.0/(rij*riksq*rik); dct1 = (xik1*rijsq - xij1*xdot)*tm1; dct2 = (xik2*rijsq - xij2*xdot)*tm1; dct3 = (xik3*rijsq - xij3*xdot)*tm1; dct4 = (xij1*riksq - xik1*xdot)*tm2; dct5 = (xij2*riksq - xik2*xdot)*tm2; dct6 = (xij3*riksq - xik3*xdot)*tm2; for (int p=0; p 0) pod4body_force(force, rij, coeff4, tmpmem, atomtype, idxi, ai, aj, ti, tj, natom, Nij); }