(git:cd590b0)
Loading...
Searching...
No Matches
libcp2k_unittest.c
Go to the documentation of this file.
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 ******************************************************************************/
18int main() {
19
20 printf("Unit test starts ...\n");
21
22 // test cp2k_get_version()
23 printf("Testing cp_c_get_version(): ");
24 char version_str[100];
25 cp2k_get_version(version_str, 100);
26 printf("%s.\n", version_str);
27
28 cp2k_init();
29 const int rank = cp_mpi_comm_rank(cp_mpi_get_comm_world());
30
31 // create simple input file
32 const char *inp_fn = "H2.inp";
33 FILE *f;
34 if (rank == 0) {
35 f = fopen(inp_fn, "w");
36 fprintf(f, "&FORCE_EVAL\n");
37 fprintf(f, " METHOD Quickstep\n");
38 fprintf(f, " STRESS_TENSOR ANALYTICAL\n");
39 fprintf(f, " &DFT\n");
40 fprintf(f, " BASIS_SET_FILE_NAME BASIS_SET\n");
41 fprintf(f, " POTENTIAL_FILE_NAME POTENTIAL\n");
42 fprintf(f, " LSD\n");
43 fprintf(f, " &MGRID\n");
44 fprintf(f, " CUTOFF 140\n");
45 fprintf(f, " &END MGRID\n");
46 fprintf(f, " &QS\n");
47 fprintf(f, " EPS_DEFAULT 1.0E-8\n");
48 fprintf(f, " &END QS\n");
49 fprintf(f, " &SCF\n");
50 fprintf(f, " EPS_DIIS 0.1\n");
51 fprintf(f, " EPS_SCF 1.0E-4\n");
52 fprintf(f, " IGNORE_CONVERGENCE_FAILURE\n");
53 fprintf(f, " MAX_DIIS 4\n");
54 fprintf(f, " MAX_SCF 3\n");
55 fprintf(f, " SCF_GUESS atomic\n");
56 fprintf(f, " &END SCF\n");
57 fprintf(f, " &XC\n");
58 fprintf(f, " &XC_FUNCTIONAL Pade\n");
59 fprintf(f, " &END XC_FUNCTIONAL\n");
60 fprintf(f, " &END XC\n");
61 fprintf(f, " &END DFT\n");
62 fprintf(f, " &SUBSYS\n");
63 fprintf(f, " &CELL\n");
64 fprintf(f, " ABC 8.0 4.0 4.0\n");
65 fprintf(f, " &END CELL\n");
66 fprintf(f, " &COORD\n");
67 fprintf(f, " H 0.000000 0.000000 0.000000\n");
68 fprintf(f, " H 1.000000 0.000000 0.000000\n");
69 fprintf(f, " &END COORD\n");
70 fprintf(f, " &KIND H\n");
71 fprintf(f, " BASIS_SET DZV-GTH-PADE\n");
72 fprintf(f, " POTENTIAL GTH-PADE-q1\n");
73 fprintf(f, " &END KIND\n");
74 fprintf(f, " &END SUBSYS\n");
75 fprintf(f, "&END FORCE_EVAL\n");
76 fprintf(f, "&GLOBAL\n");
77 fprintf(f, " PRINT_LEVEL SILENT\n");
78 fprintf(f, " PROJECT libcp2k_unittest_H2\n");
79 fprintf(f, "&END GLOBAL\n");
80 fclose(f);
81 }
83
84 // use input file to create a force environment
85 force_env_t force_env;
86 cp2k_create_force_env(&force_env, inp_fn, "__STD_OUT__");
87 int scf_status = 99;
88 cp2k_get_scf_convergence(force_env, &scf_status);
89 if (scf_status != -1) {
90 printf("SCF status must be unavailable before calculation\n");
91 return (-1);
92 }
93 cp2k_calc_energy_force(force_env);
94 cp2k_get_scf_convergence(force_env, &scf_status);
95 if (scf_status != 0) {
96 printf("The deliberately truncated SCF must report non-convergence\n");
97 return (-1);
98 }
99
100 // Stress is a column-major, pressure-positive potential tensor.
101 double stress[9];
102 int stress_available = 0;
103 cp2k_get_stress_tensor(force_env, stress, &stress_available);
104 if (!stress_available) {
105 printf("Missing analytical stress\n");
106 return (-1);
107 }
108 for (int i = 0; i < 3; ++i) {
109 for (int j = 0; j < 3; ++j) {
110 if (!isfinite(stress[3 * j + i]) ||
111 fabs(stress[3 * j + i] - stress[3 * i + j]) > 1e-10) {
112 printf("Invalid stress tensor\n");
113 return (-1);
114 }
115 }
116 }
117
118 // check energy
119 double energy;
120 cp2k_get_potential_energy(force_env, &energy);
121 printf("\n ENERGY: %.12f\n", energy);
122 if (fabs(-1.118912797546392 - energy) / fabs(energy) > 1e-13) {
123 printf("Wrong energy\n");
124 return (-1);
125 }
126
127 // Geometry and velocity updates invalidate the last SCF status.
128 double positions[6], cell[9], velocities[6] = {0};
129 cp2k_get_positions(force_env, positions, 6);
130 cp2k_set_positions(force_env, positions, 6);
131 cp2k_get_scf_convergence(force_env, &scf_status);
132 if (scf_status != -1)
133 return (-1);
134 cp2k_calc_energy(force_env);
135 cp2k_get_cell(force_env, cell);
136 cp2k_set_cell(force_env, cell);
137 cp2k_get_scf_convergence(force_env, &scf_status);
138 if (scf_status != -1)
139 return (-1);
140 cp2k_calc_energy(force_env);
141 cp2k_set_velocities(force_env, velocities, 6);
142 cp2k_get_scf_convergence(force_env, &scf_status);
143 if (scf_status != -1)
144 return (-1);
145 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 const char *run_out = "libcp2k_unittest_run.out";
149 cp2k_run_input_comm(inp_fn, run_out,
152 long first_size = 0;
153 if (rank == 0) {
154 f = fopen(run_out, "r");
155 if (f == NULL) {
156 printf("run_input did not create its output file\n");
157 return (-1);
158 }
159 fseek(f, 0, SEEK_END);
160 first_size = ftell(f);
161 fclose(f);
162 }
163 cp2k_run_input(inp_fn, run_out);
165 if (rank == 0) {
166 f = fopen(run_out, "r");
167 if (f == NULL) {
168 printf("run_input output file disappeared\n");
169 return (-1);
170 }
171 fseek(f, 0, SEEK_END);
172 const long second_size = ftell(f);
173 fclose(f);
174 if (first_size <= 0 || second_size <= first_size) {
175 printf("run_input did not append output\n");
176 return (-1);
177 }
178 }
179
180 // run_input must leave the surrounding library runtime usable.
181 cp2k_create_force_env(&force_env, inp_fn, "__STD_OUT__");
182 cp2k_calc_energy_force(force_env);
183 cp2k_get_potential_energy(force_env, &energy);
184 if (fabs(-1.118912797546392 - energy) / fabs(energy) > 1e-13) {
185 printf("Wrong energy after run_input\n");
186 return (-1);
187 }
188 cp2k_destroy_force_env(force_env);
189
190 // clean up
192 if (rank == 0) {
193 remove(inp_fn);
194 remove(run_out);
195 }
196
197 printf("Unit test finished, found no errors\n");
198 return (0);
199}
200
201// EOF
int cp_mpi_comm_c2f(const cp_mpi_comm_t comm)
Wrapper around MPI_Comm_c2f.
Definition cp_mpi.c:164
void cp_mpi_barrier(const cp_mpi_comm_t comm)
Wrapper around MPI_Barrier; a null communicator is a no-op.
Definition cp_mpi.c:210
cp_mpi_comm_t cp_mpi_get_comm_world(void)
Returns MPI_COMM_WORLD.
Definition cp_mpi.c:138
int cp_mpi_comm_rank(const cp_mpi_comm_t comm)
Wrapper around MPI_Comm_rank.
Definition cp_mpi.c:177
static void const int const int i
void cp2k_create_force_env(force_env_t *new_force_env, const char *input_file_path, const char *output_file_path)
Create a new force environment.
void cp2k_run_input_comm(const char *input_file_path, const char *output_file_path, int mpi_comm)
Make a CP2K run with the given input file (custom managed MPI).
void cp2k_run_input(const char *input_file_path, const char *output_file_path)
Make a CP2K run with the given input file.
void cp2k_get_version(char *version_str, int str_length)
Get the CP2K version string.
void cp2k_set_positions(force_env_t force_env, const double *new_pos, int n_el)
Set positions of the particles.
int force_env_t
Definitions for the functions exported in libcp2k.F.
Definition libcp2k.h:22
void cp2k_set_velocities(force_env_t force_env, const double *new_vel, int n_el)
Set velocity of the particles.
void cp2k_init(void)
Initialize CP2K, initializing or attaching to MPI as needed.
void cp2k_get_scf_convergence(force_env_t force_env, int *status)
Query convergence of the last Quickstep SCF, including outer/CDFT loops.
void cp2k_finalize(void)
Finalize CP2K and MPI if CP2K initialized it.
void cp2k_get_positions(force_env_t force_env, double *pos, int n_el)
Get the positions of the particles.
void cp2k_get_stress_tensor(force_env_t force_env, double *stress_tensor, int *available)
Get the potential (not kinetic) stress after cp2k_calc_energy_force().
void cp2k_destroy_force_env(force_env_t force_env)
Destroy/cleanup a force environment.
void cp2k_get_cell(force_env_t force_env, const double *cell)
Get the size of the cell.
void cp2k_set_cell(force_env_t force_env, const double *new_cell)
Set the size of the cell.
void cp2k_calc_energy_force(force_env_t force_env)
Calculate energy and forces of the system.
void cp2k_get_potential_energy(force_env_t force_env, double *e_pot)
Get the potential energy of the system.
void cp2k_calc_energy(force_env_t force_env)
Calculate only the energy of the system.
int main()
Unit test of the C-interface provided via libcp2k.h.