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, " &DFT\n");
39 1 : fprintf(f, " BASIS_SET_FILE_NAME BASIS_SET\n");
40 1 : fprintf(f, " POTENTIAL_FILE_NAME POTENTIAL\n");
41 1 : fprintf(f, " LSD\n");
42 1 : fprintf(f, " &MGRID\n");
43 1 : fprintf(f, " CUTOFF 140\n");
44 1 : fprintf(f, " &END MGRID\n");
45 1 : fprintf(f, " &QS\n");
46 1 : fprintf(f, " EPS_DEFAULT 1.0E-8\n");
47 1 : fprintf(f, " &END QS\n");
48 1 : fprintf(f, " &SCF\n");
49 1 : fprintf(f, " EPS_DIIS 0.1\n");
50 1 : fprintf(f, " EPS_SCF 1.0E-4\n");
51 1 : fprintf(f, " IGNORE_CONVERGENCE_FAILURE\n");
52 1 : fprintf(f, " MAX_DIIS 4\n");
53 1 : fprintf(f, " MAX_SCF 3\n");
54 1 : fprintf(f, " SCF_GUESS atomic\n");
55 1 : fprintf(f, " &END SCF\n");
56 1 : fprintf(f, " &XC\n");
57 1 : fprintf(f, " &XC_FUNCTIONAL Pade\n");
58 1 : fprintf(f, " &END XC_FUNCTIONAL\n");
59 1 : fprintf(f, " &END XC\n");
60 1 : fprintf(f, " &END DFT\n");
61 1 : fprintf(f, " &SUBSYS\n");
62 1 : fprintf(f, " &CELL\n");
63 1 : fprintf(f, " ABC 8.0 4.0 4.0\n");
64 1 : fprintf(f, " &END CELL\n");
65 1 : fprintf(f, " &COORD\n");
66 1 : fprintf(f, " H 0.000000 0.000000 0.000000\n");
67 1 : fprintf(f, " H 1.000000 0.000000 0.000000\n");
68 1 : fprintf(f, " &END COORD\n");
69 1 : fprintf(f, " &KIND H\n");
70 1 : fprintf(f, " BASIS_SET DZV-GTH-PADE\n");
71 1 : fprintf(f, " POTENTIAL GTH-PADE-q1\n");
72 1 : fprintf(f, " &END KIND\n");
73 1 : fprintf(f, " &END SUBSYS\n");
74 1 : fprintf(f, "&END FORCE_EVAL\n");
75 1 : fprintf(f, "&GLOBAL\n");
76 1 : fprintf(f, " PRINT_LEVEL SILENT\n");
77 1 : fprintf(f, " PROJECT libcp2k_unittest_H2\n");
78 1 : fprintf(f, "&END GLOBAL\n");
79 1 : fclose(f);
80 : }
81 2 : cp_mpi_barrier(cp_mpi_get_comm_world());
82 :
83 : // use input file to create a force environment
84 2 : force_env_t force_env;
85 2 : cp2k_create_force_env(&force_env, inp_fn, "__STD_OUT__");
86 2 : int scf_status = 99;
87 2 : cp2k_get_scf_convergence(force_env, &scf_status);
88 2 : if (scf_status != -1) {
89 0 : printf("SCF status must be unavailable before calculation\n");
90 0 : return (-1);
91 : }
92 2 : cp2k_calc_energy_force(force_env);
93 2 : cp2k_get_scf_convergence(force_env, &scf_status);
94 2 : if (scf_status != 0) {
95 0 : printf("The deliberately truncated SCF must report non-convergence\n");
96 0 : return (-1);
97 : }
98 :
99 : // check energy
100 2 : double energy;
101 2 : cp2k_get_potential_energy(force_env, &energy);
102 2 : printf("\n ENERGY: %.12f\n", energy);
103 2 : if (fabs(-1.118912797546392 - energy) / fabs(energy) > 1e-13) {
104 0 : printf("Wrong energy\n");
105 0 : return (-1);
106 : }
107 :
108 : // Geometry and velocity updates invalidate the last SCF status.
109 2 : double positions[6], cell[9], velocities[6] = {0};
110 2 : cp2k_get_positions(force_env, positions, 6);
111 2 : cp2k_set_positions(force_env, positions, 6);
112 2 : cp2k_get_scf_convergence(force_env, &scf_status);
113 2 : if (scf_status != -1)
114 : return (-1);
115 2 : cp2k_calc_energy(force_env);
116 2 : cp2k_get_cell(force_env, cell);
117 2 : cp2k_set_cell(force_env, cell);
118 2 : cp2k_get_scf_convergence(force_env, &scf_status);
119 2 : if (scf_status != -1)
120 : return (-1);
121 2 : cp2k_calc_energy(force_env);
122 2 : cp2k_set_velocities(force_env, velocities, 6);
123 2 : cp2k_get_scf_convergence(force_env, &scf_status);
124 2 : if (scf_status != -1)
125 : return (-1);
126 2 : cp2k_destroy_force_env(force_env);
127 : // A library caller has not already opened output in the Fortran runtime.
128 : // run_input must create, close, and subsequently append to the named file.
129 2 : const char *run_out = "libcp2k_unittest_run.out";
130 2 : cp2k_run_input_comm(inp_fn, run_out,
131 2 : cp_mpi_comm_c2f(cp_mpi_get_comm_world()));
132 2 : cp_mpi_barrier(cp_mpi_get_comm_world());
133 2 : long first_size = 0;
134 2 : if (rank == 0) {
135 1 : f = fopen(run_out, "r");
136 1 : if (f == NULL) {
137 0 : printf("run_input did not create its output file\n");
138 0 : return (-1);
139 : }
140 1 : fseek(f, 0, SEEK_END);
141 1 : first_size = ftell(f);
142 1 : fclose(f);
143 : }
144 2 : cp2k_run_input(inp_fn, run_out);
145 2 : cp_mpi_barrier(cp_mpi_get_comm_world());
146 2 : if (rank == 0) {
147 1 : f = fopen(run_out, "r");
148 1 : if (f == NULL) {
149 0 : printf("run_input output file disappeared\n");
150 0 : return (-1);
151 : }
152 1 : fseek(f, 0, SEEK_END);
153 1 : const long second_size = ftell(f);
154 1 : fclose(f);
155 1 : if (first_size <= 0 || second_size <= first_size) {
156 0 : printf("run_input did not append output\n");
157 0 : return (-1);
158 : }
159 : }
160 :
161 : // run_input must leave the surrounding library runtime usable.
162 2 : cp2k_create_force_env(&force_env, inp_fn, "__STD_OUT__");
163 2 : cp2k_calc_energy_force(force_env);
164 2 : cp2k_get_potential_energy(force_env, &energy);
165 2 : if (fabs(-1.118912797546392 - energy) / fabs(energy) > 1e-13) {
166 0 : printf("Wrong energy after run_input\n");
167 0 : return (-1);
168 : }
169 2 : cp2k_destroy_force_env(force_env);
170 :
171 : // clean up
172 2 : cp2k_finalize();
173 2 : if (rank == 0) {
174 1 : remove(inp_fn);
175 1 : remove(run_out);
176 : }
177 :
178 2 : printf("Unit test finished, found no errors\n");
179 2 : return (0);
180 : }
181 :
182 : // EOF
|