LCOV - code coverage report
Current view: top level - src - ace_c_api.cpp (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:21ef868) Lines: 92.6 % 121 112
Test Date: 2026-08-14 07:04:57 Functions: 100.0 % 4 4

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

Generated by: LCOV version 2.0-1