LCOV - code coverage report
Current view: top level - src - ace_c_api.cpp (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:3a1353c) Lines: 92.6 % 121 112
Test Date: 2025-12-05 06:41:32 Functions: 100.0 % 4 4

            Line data    Source code
       1              : /*----------------------------------------------------------------------------*/
       2              : /*  CP2K: A general program to perform molecular dynamics simulations         */
       3              : /*  Copyright 2000-2025 CP2K developers group <https://cp2k.org>              */
       4              : /*                                                                            */
       5              : /*  SPDX-License-Identifier: GPL-2.0-or-later                                 */
       6              : /*----------------------------------------------------------------------------*/
       7              : 
       8              : #if defined(__ACE)
       9              : 
      10              : // tested with lammps-user-pace-v.2023.11.25.fix2
      11              : #define COMPUTE_B_GRAD
      12              : #define EXTRA_C_PROJECTIONS
      13              : 
      14              : #if 0
      15              : #include <stdio.h>
      16              : #endif
      17              : #include <string>
      18              : 
      19              : #include "ace-evaluator/ace_c_basis.h"
      20              : #include "ace-evaluator/ace_evaluator.h"
      21              : #include "ace-evaluator/ace_recursive.h"
      22              : #include "ace-evaluator/ace_version.h"
      23              : #include "ace/ace_b_basis.h"
      24              : 
      25              : struct ACEData {
      26              :   ACECTildeBasisSet *basis_set;
      27              :   ACERecursiveEvaluator *ace;
      28              :   Array1D<DOUBLE_TYPE> *virial;
      29              :   Array2D<DOUBLE_TYPE> *forces;
      30              : };
      31              : 
      32            6 : bool hasEnding(std::string const &fullString, std::string const &ending) {
      33            6 :   if (fullString.length() >= ending.length()) {
      34            6 :     return (0 == fullString.compare(fullString.length() - ending.length(),
      35            6 :                                     ending.length(), ending));
      36              :   } else {
      37              :     return false;
      38              :   }
      39              : }
      40              : 
      41            6 : extern "C" void AcePotInitialize(int ntypec, const char *symbolsc, int nlen,
      42              :                                  const char *potential_file_name, double *rcutc,
      43              :                                  void **acedata_ptr) {
      44              : 
      45              : // avoid mixing C++ I/O with Fortran I/O, TODO: return this data so it can
      46              : // be printed on the Fortran side.
      47              : #if 0
      48              :   printf("---PACE initialization----\n");
      49              : 
      50              :   printf("ACE version: %d.%d.%d\n", VERSION_YEAR, VERSION_MONTH, VERSION_DAY);
      51              : #endif
      52              : 
      53            6 :   std::string potential_file_name_str(potential_file_name);
      54              :   // trim potential_file_name
      55            6 :   potential_file_name_str.erase(
      56            6 :       potential_file_name_str.find_last_not_of(" \n\r\t") + 1);
      57              : 
      58            6 :   std::string symbols_str(symbolsc, ntypec * 2);
      59            6 :   std::vector<std::string> elements;
      60           18 :   for (int i = 0; i < ntypec; i++) {
      61           12 :     auto el_str = symbols_str.substr(2 * i, 2);
      62           12 :     el_str.erase(el_str.find_last_not_of(" \n\r\t") + 1);
      63           12 :     elements.push_back(el_str);
      64           12 :   }
      65            6 :   if (ntypec != elements.size())
      66            0 :     throw std::runtime_error(
      67            0 :         "Number of elements and elements list are inconsistent");
      68              : 
      69              : #if 0
      70              :   printf("Number of atom types:                       %d\n", ntypec);
      71              :   printf("Element mapping:                            ");
      72              :   for (int i = 0; i < ntypec; i++)
      73              :     printf(" `%s`", elements[i].c_str());
      74              :   printf("\n");
      75              : #endif
      76              : 
      77              :     // Elements are contained in a string of length 2*ntypec
      78              :     // Each element has two chars in the string
      79              :     // The sequence of the elements in the string corresponds to their mapping,
      80              :     // i.e., the first element in the string is element 1, the second element in
      81              :     // the string is element 2, the third element in the string is element 3,
      82              :     // ...
      83              : 
      84              : #if 0
      85              :   printf("Filename:                                   '%s'\n",
      86              :          potential_file_name_str.c_str());
      87              : #endif
      88              : 
      89            6 :   ACEData *aceData;
      90              : 
      91            6 :   if (hasEnding(potential_file_name_str, ".yaml")) {
      92            6 :     ACEBBasisSet bBasisSet = ACEBBasisSet(potential_file_name_str);
      93            6 :     ACECTildeBasisSet cTildeBasisSet = bBasisSet.to_ACECTildeBasisSet();
      94            6 :     aceData = new ACEData;
      95            6 :     aceData->basis_set = new ACECTildeBasisSet(cTildeBasisSet);
      96            6 :   } else if (hasEnding(potential_file_name_str, ".yace")) {
      97            0 :     aceData = new ACEData;
      98            0 :     aceData->basis_set = new ACECTildeBasisSet(potential_file_name_str.c_str());
      99              :   } else {
     100            0 :     throw std::invalid_argument("Unrecognized file format: '" +
     101            0 :                                 potential_file_name_str + "'");
     102              :   }
     103            6 :   aceData->ace = new ACERecursiveEvaluator();
     104            6 :   aceData->ace->set_recursive(true);
     105              : 
     106           12 :   aceData->ace->element_type_mapping.init(1 + ntypec);
     107              :   //    ace->element_type_mapping = {0,1,0}; // 0->0, 1(CP2k)-> 1(ACE),
     108              :   //    2(CP2k)-> 0(ACE)
     109           18 :   for (int i = 1; i <= ntypec; i++) {
     110           12 :     auto elemname = elements.at(i - 1);
     111           12 :     SPECIES_TYPE mu = aceData->basis_set->get_species_index_by_name(elemname);
     112           12 :     if (mu != -1) {
     113              : #if 0
     114              :       printf("Mapping CP2K atom type #%d(%s) -> ACE species type #%d\n", i,
     115              :              elemname.c_str(), mu);
     116              : #endif
     117              :       // set up CP2K atom type to ACE species mapping for ace evaluator
     118           12 :       aceData->ace->element_type_mapping(i) = mu;
     119              :     } else {
     120            0 :       throw std::runtime_error("Element " + elemname +
     121            0 :                                " is not supported by ACE-potential from file " +
     122            0 :                                potential_file_name_str);
     123              :     }
     124           12 :   }
     125              : 
     126              :   // the cutoffs of all pairs are stored in a ntypec*ntypec array
     127              :   // the index 0 corresponds to element 1
     128              :   // the index 1 corresponds to element 2
     129              :   // the index 2 corresponds to element 3, ...
     130              :   int k = 0;
     131           18 :   for (int i = 1; i <= ntypec; i++) {
     132           36 :     for (int j = 1; j <= ntypec; j++) {
     133           24 :       rcutc[k] = aceData->basis_set->radial_functions->cut(
     134           24 :           aceData->ace->element_type_mapping(i),
     135           24 :           aceData->ace->element_type_mapping(j));
     136           24 :       k++;
     137              :     }
     138              :   }
     139              : 
     140            6 :   aceData->ace->set_basis(*aceData->basis_set, 1);
     141            6 :   aceData->virial = new Array1D<DOUBLE_TYPE>(6, "virial");
     142            6 :   aceData->forces = new Array2D<DOUBLE_TYPE>(1, 3, "forces");
     143            6 :   *acedata_ptr = (void *)aceData;
     144              : #if 0
     145              :   printf("---Done PACE initialization----\n");
     146              : #endif
     147            6 : }
     148              : 
     149            6 : extern "C" void AcePotFinalize(void **acedata_ptr) {
     150            6 :   ACEData *aceData = (ACEData *)*acedata_ptr;
     151            6 :   delete aceData->basis_set;
     152            6 :   delete aceData->ace;
     153           12 :   delete aceData->virial;
     154           12 :   delete aceData->forces;
     155            6 :   delete aceData;
     156            6 : }
     157              : 
     158          206 : extern "C" void AcePotCompute(int natomc, int nghostc, int neic, int *neiatc,
     159              :                               int *originc, int *nlistc, int *attypec,
     160              :                               double *atposc, double *forcec, double *virialc,
     161              :                               double *energyc, void **acedata_ptr) {
     162          206 :   ACEData *aceData = (ACEData *)*acedata_ptr;
     163              :   // re-point double **x (LAMMPS/C style of 2D array) to atposc
     164          206 :   int tot_nat = natomc + nghostc;
     165          206 :   double **x = new double *[tot_nat];
     166       291357 :   for (int i = 0; i < tot_nat; i++) {
     167       291151 :     x[i] = &atposc[3 * i];
     168              :   }
     169              : 
     170          206 :   std::vector<int> numneigh(natomc, 0);
     171        39596 :   for (int i = 0; i < natomc; i++) {
     172        39390 :     numneigh[i] = neiatc[i + 1] - neiatc[i];
     173              :   }
     174              : 
     175              :   // determine the maximum number of neighbours
     176              :   int i, jnum;
     177              :   int max_jnum = 0;
     178              :   int nei = 0;
     179        39596 :   for (i = 0; i < natomc; i++) {
     180        39390 :     jnum = numneigh[i];
     181        39390 :     nei = nei + jnum;
     182        39390 :     if (jnum > max_jnum)
     183              :       max_jnum = jnum;
     184              :   }
     185              : 
     186          206 :   aceData->ace->resize_neighbours_cache(max_jnum);
     187              : 
     188          206 :   double dx, dy, dz, fx, fy, fz;
     189              : 
     190              :   // resize forces array
     191          206 :   if (aceData->forces->get_dim(0) < natomc)
     192            6 :     aceData->forces->resize(natomc, 3);
     193              : 
     194          206 :   aceData->forces->fill(0);
     195          206 :   aceData->virial->fill(0);
     196              : 
     197              :   // main loop over atoms
     198        39596 :   for (i = 0; i < natomc; i++) {
     199        39390 :     jnum = numneigh[i];
     200              : 
     201        39390 :     const int *jlist = &nlistc[neiatc[i]];
     202              : 
     203        39390 :     aceData->ace->compute_atom(i, x, attypec, jnum, jlist);
     204              : 
     205        39390 :     energyc[i] = aceData->ace->e_atom;
     206              : 
     207        39390 :     const double xtmp = x[i][0];
     208        39390 :     const double ytmp = x[i][1];
     209        39390 :     const double ztmp = x[i][2];
     210              : 
     211      4260152 :     for (int jj = 0; jj < jnum; jj++) {
     212      4220762 :       int j = jlist[jj];
     213              : 
     214      4220762 :       dx = x[j][0] - xtmp;
     215      4220762 :       dy = x[j][1] - ytmp;
     216      4220762 :       dz = x[j][2] - ztmp;
     217              : 
     218      4220762 :       fx = aceData->ace->neighbours_forces(jj, 0);
     219      4220762 :       fy = aceData->ace->neighbours_forces(jj, 1);
     220      4220762 :       fz = aceData->ace->neighbours_forces(jj, 2);
     221              : 
     222      4220762 :       (*aceData->forces)(i, 0) += fx;
     223      4220762 :       (*aceData->forces)(i, 1) += fy;
     224      4220762 :       (*aceData->forces)(i, 2) += fz;
     225              : 
     226              :       // virial f_dot_r, identical to LAMMPS virial_fdotr_compute
     227      4220762 :       (*aceData->virial)(0) += dx * fx;
     228      4220762 :       (*aceData->virial)(1) += dy * fy;
     229      4220762 :       (*aceData->virial)(2) += dz * fz;
     230      4220762 :       (*aceData->virial)(3) += dx * fy;
     231      4220762 :       (*aceData->virial)(4) += dx * fz;
     232      4220762 :       (*aceData->virial)(5) += dy * fz;
     233              : 
     234              :       // update forces only for real atoms
     235      4220762 :       if (j < natomc) {
     236      1723464 :         (*aceData->forces)(j, 0) -= fx;
     237      1723464 :         (*aceData->forces)(j, 1) -= fy;
     238      1723464 :         (*aceData->forces)(j, 2) -= fz;
     239              :       } else {
     240              :         // map ghost j into true_j within periodic cell
     241      2497298 :         int true_j = originc[j];
     242      2497298 :         (*aceData->forces)(true_j, 0) -= fx;
     243      2497298 :         (*aceData->forces)(true_j, 1) -= fy;
     244      2497298 :         (*aceData->forces)(true_j, 2) -= fz;
     245              :       }
     246              :     }
     247              :   }
     248              : 
     249              :   double ene = 0.0;
     250        39596 :   for (int i = 0; i < natomc; i++) {
     251        39390 :     ene += energyc[i];
     252              : 
     253        39390 :     forcec[3 * i] = (*aceData->forces)(i, 0);
     254        39390 :     forcec[3 * i + 1] = (*aceData->forces)(i, 1);
     255        39390 :     forcec[3 * i + 2] = (*aceData->forces)(i, 2);
     256              :   }
     257              : 
     258              :   // copy virials
     259         1442 :   for (int i = 0; i < 6; i++) {
     260         1236 :     virialc[i] = (*aceData->virial)(i);
     261              :   }
     262              : 
     263          206 :   delete[] x;
     264          206 : }
     265              : 
     266              : #endif // defined(__ACE)
     267              : 
     268              : // EOF
        

Generated by: LCOV version 2.0-1