LCOV - code coverage report
Current view: top level - src/start - libcp2k_unittest.c (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 87.3 % 142 124
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 1 1

            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              : #include "libcp2k.h"
       9              : #include "mpiwrap/cp_mpi.h"
      10              : #include <math.h>
      11              : #include <stdio.h>
      12              : #include <stdlib.h>
      13              : 
      14              : /*******************************************************************************
      15              :  * \brief Unit test of the C-interface provided via libcp2k.h
      16              :  * \author Ole Schuett
      17              :  ******************************************************************************/
      18            2 : int main() {
      19              : 
      20            2 :   printf("Unit test starts ...\n");
      21              : 
      22              :   // test cp2k_get_version()
      23            2 :   printf("Testing cp_c_get_version(): ");
      24            2 :   char version_str[100];
      25            2 :   cp2k_get_version(version_str, 100);
      26            2 :   printf("%s.\n", version_str);
      27              : 
      28            2 :   cp2k_init();
      29            2 :   const int rank = cp_mpi_comm_rank(cp_mpi_get_comm_world());
      30              : 
      31              :   // create simple input file
      32            2 :   const char *inp_fn = "H2.inp";
      33            2 :   FILE *f;
      34            2 :   if (rank == 0) {
      35            1 :     f = fopen(inp_fn, "w");
      36            1 :     fprintf(f, "&FORCE_EVAL\n");
      37            1 :     fprintf(f, "  METHOD Quickstep\n");
      38            1 :     fprintf(f, "  STRESS_TENSOR ANALYTICAL\n");
      39            1 :     fprintf(f, "  &DFT\n");
      40            1 :     fprintf(f, "    BASIS_SET_FILE_NAME BASIS_SET\n");
      41            1 :     fprintf(f, "    POTENTIAL_FILE_NAME POTENTIAL\n");
      42            1 :     fprintf(f, "    LSD\n");
      43            1 :     fprintf(f, "    &MGRID\n");
      44            1 :     fprintf(f, "      CUTOFF 140\n");
      45            1 :     fprintf(f, "    &END MGRID\n");
      46            1 :     fprintf(f, "    &QS\n");
      47            1 :     fprintf(f, "      EPS_DEFAULT 1.0E-8\n");
      48            1 :     fprintf(f, "    &END QS\n");
      49            1 :     fprintf(f, "    &SCF\n");
      50            1 :     fprintf(f, "      EPS_DIIS 0.1\n");
      51            1 :     fprintf(f, "      EPS_SCF 1.0E-4\n");
      52            1 :     fprintf(f, "      IGNORE_CONVERGENCE_FAILURE\n");
      53            1 :     fprintf(f, "      MAX_DIIS 4\n");
      54            1 :     fprintf(f, "      MAX_SCF 3\n");
      55            1 :     fprintf(f, "      SCF_GUESS atomic\n");
      56            1 :     fprintf(f, "    &END SCF\n");
      57            1 :     fprintf(f, "    &XC\n");
      58            1 :     fprintf(f, "      &XC_FUNCTIONAL Pade\n");
      59            1 :     fprintf(f, "      &END XC_FUNCTIONAL\n");
      60            1 :     fprintf(f, "    &END XC\n");
      61            1 :     fprintf(f, "  &END DFT\n");
      62            1 :     fprintf(f, "  &SUBSYS\n");
      63            1 :     fprintf(f, "    &CELL\n");
      64            1 :     fprintf(f, "      ABC 8.0 4.0 4.0\n");
      65            1 :     fprintf(f, "    &END CELL\n");
      66            1 :     fprintf(f, "    &COORD\n");
      67            1 :     fprintf(f, "    H     0.000000  0.000000  0.000000\n");
      68            1 :     fprintf(f, "    H     1.000000  0.000000  0.000000\n");
      69            1 :     fprintf(f, "    &END COORD\n");
      70            1 :     fprintf(f, "    &KIND H\n");
      71            1 :     fprintf(f, "      BASIS_SET DZV-GTH-PADE\n");
      72            1 :     fprintf(f, "      POTENTIAL GTH-PADE-q1\n");
      73            1 :     fprintf(f, "    &END KIND\n");
      74            1 :     fprintf(f, "  &END SUBSYS\n");
      75            1 :     fprintf(f, "&END FORCE_EVAL\n");
      76            1 :     fprintf(f, "&GLOBAL\n");
      77            1 :     fprintf(f, "  PRINT_LEVEL SILENT\n");
      78            1 :     fprintf(f, "  PROJECT libcp2k_unittest_H2\n");
      79            1 :     fprintf(f, "&END GLOBAL\n");
      80            1 :     fclose(f);
      81              :   }
      82            2 :   cp_mpi_barrier(cp_mpi_get_comm_world());
      83              : 
      84              :   // use input file to create a force environment
      85            2 :   force_env_t force_env;
      86            2 :   cp2k_create_force_env(&force_env, inp_fn, "__STD_OUT__");
      87            2 :   int scf_status = 99;
      88            2 :   cp2k_get_scf_convergence(force_env, &scf_status);
      89            2 :   if (scf_status != -1) {
      90            0 :     printf("SCF status must be unavailable before calculation\n");
      91            0 :     return (-1);
      92              :   }
      93            2 :   cp2k_calc_energy_force(force_env);
      94            2 :   cp2k_get_scf_convergence(force_env, &scf_status);
      95            2 :   if (scf_status != 0) {
      96            0 :     printf("The deliberately truncated SCF must report non-convergence\n");
      97            0 :     return (-1);
      98              :   }
      99              : 
     100              :   // Stress is a column-major, pressure-positive potential tensor.
     101            2 :   double stress[9];
     102            2 :   int stress_available = 0;
     103            2 :   cp2k_get_stress_tensor(force_env, stress, &stress_available);
     104            2 :   if (!stress_available) {
     105            0 :     printf("Missing analytical stress\n");
     106            0 :     return (-1);
     107              :   }
     108            8 :   for (int i = 0; i < 3; ++i) {
     109           24 :     for (int j = 0; j < 3; ++j) {
     110           18 :       if (!isfinite(stress[3 * j + i]) ||
     111           18 :           fabs(stress[3 * j + i] - stress[3 * i + j]) > 1e-10) {
     112            0 :         printf("Invalid stress tensor\n");
     113            0 :         return (-1);
     114              :       }
     115              :     }
     116              :   }
     117              : 
     118              :   // check energy
     119            2 :   double energy;
     120            2 :   cp2k_get_potential_energy(force_env, &energy);
     121            2 :   printf("\n ENERGY: %.12f\n", energy);
     122            2 :   if (fabs(-1.118912797546392 - energy) / fabs(energy) > 1e-13) {
     123            0 :     printf("Wrong energy\n");
     124            0 :     return (-1);
     125              :   }
     126              : 
     127              :   // Geometry and velocity updates invalidate the last SCF status.
     128            2 :   double positions[6], cell[9], velocities[6] = {0};
     129            2 :   cp2k_get_positions(force_env, positions, 6);
     130            2 :   cp2k_set_positions(force_env, positions, 6);
     131            2 :   cp2k_get_scf_convergence(force_env, &scf_status);
     132            2 :   if (scf_status != -1)
     133              :     return (-1);
     134            2 :   cp2k_calc_energy(force_env);
     135            2 :   cp2k_get_cell(force_env, cell);
     136            2 :   cp2k_set_cell(force_env, cell);
     137            2 :   cp2k_get_scf_convergence(force_env, &scf_status);
     138            2 :   if (scf_status != -1)
     139              :     return (-1);
     140            2 :   cp2k_calc_energy(force_env);
     141            2 :   cp2k_set_velocities(force_env, velocities, 6);
     142            2 :   cp2k_get_scf_convergence(force_env, &scf_status);
     143            2 :   if (scf_status != -1)
     144              :     return (-1);
     145            2 :   cp2k_destroy_force_env(force_env);
     146              :   // A library caller has not already opened output in the Fortran runtime.
     147              :   // run_input must create, close, and subsequently append to the named file.
     148            2 :   const char *run_out = "libcp2k_unittest_run.out";
     149            2 :   cp2k_run_input_comm(inp_fn, run_out,
     150            2 :                       cp_mpi_comm_c2f(cp_mpi_get_comm_world()));
     151            2 :   cp_mpi_barrier(cp_mpi_get_comm_world());
     152            2 :   long first_size = 0;
     153            2 :   if (rank == 0) {
     154            1 :     f = fopen(run_out, "r");
     155            1 :     if (f == NULL) {
     156            0 :       printf("run_input did not create its output file\n");
     157            0 :       return (-1);
     158              :     }
     159            1 :     fseek(f, 0, SEEK_END);
     160            1 :     first_size = ftell(f);
     161            1 :     fclose(f);
     162              :   }
     163            2 :   cp2k_run_input(inp_fn, run_out);
     164            2 :   cp_mpi_barrier(cp_mpi_get_comm_world());
     165            2 :   if (rank == 0) {
     166            1 :     f = fopen(run_out, "r");
     167            1 :     if (f == NULL) {
     168            0 :       printf("run_input output file disappeared\n");
     169            0 :       return (-1);
     170              :     }
     171            1 :     fseek(f, 0, SEEK_END);
     172            1 :     const long second_size = ftell(f);
     173            1 :     fclose(f);
     174            1 :     if (first_size <= 0 || second_size <= first_size) {
     175            0 :       printf("run_input did not append output\n");
     176            0 :       return (-1);
     177              :     }
     178              :   }
     179              : 
     180              :   // run_input must leave the surrounding library runtime usable.
     181            2 :   cp2k_create_force_env(&force_env, inp_fn, "__STD_OUT__");
     182            2 :   cp2k_calc_energy_force(force_env);
     183            2 :   cp2k_get_potential_energy(force_env, &energy);
     184            2 :   if (fabs(-1.118912797546392 - energy) / fabs(energy) > 1e-13) {
     185            0 :     printf("Wrong energy after run_input\n");
     186            0 :     return (-1);
     187              :   }
     188            2 :   cp2k_destroy_force_env(force_env);
     189              : 
     190              :   // clean up
     191            2 :   cp2k_finalize();
     192            2 :   if (rank == 0) {
     193            1 :     remove(inp_fn);
     194            1 :     remove(run_out);
     195              :   }
     196              : 
     197            2 :   printf("Unit test finished, found no errors\n");
     198            2 :   return (0);
     199              : }
     200              : 
     201              : // EOF
        

Generated by: LCOV version 2.0-1