1 // -*- C++ -*-
2 //
3 // asap_kim_api.cpp: Common interfaces classes for Asap potentials in OpenKIM.
4 //
5 // Copyright (C) 2012-2013 Jakob Schiotz and the Department of Physics,
6 // Technical University of Denmark. Email: schiotz@fysik.dtu.dk
7 //
8 // This file is part of Asap version 3.
9 // Asap is released under the GNU Lesser Public License (LGPL) version 3.
10 // However, the parts of Asap distributed within the OpenKIM project
11 // (including this file) are also released under the Common Development
12 // and Distribution License (CDDL) version 1.0.
13 //
14 // This program is free software: you can redistribute it and/or
15 // modify it under the terms of the GNU Lesser General Public License
16 // version 3 as published by the Free Software Foundation. Permission
17 // to use other versions of the GNU Lesser General Public License may
18 // granted by Jakob Schiotz or the head of department of the
19 // Department of Physics, Technical University of Denmark, as
20 // described in section 14 of the GNU General Public License.
21 //
22 // This program is distributed in the hope that it will be useful,
23 // but WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 // GNU General Public License for more details.
26 //
27 // You should have received a copy of the GNU General Public License
28 // and the GNU Lesser Public License along with this program. If not,
29 // see <http://www.gnu.org/licenses/>.
30
31
32 #include "KimAsapPython.h"
33 #include "asap_kim_api.h"
34 #include "Potential.h"
35 #include "KimNeighborLocator.h"
36 #include "KIM_ModelDriverHeaders.hpp"
37 #include "SymTensor.h"
38 #include "Debug.h"
39 #include <stdlib.h>
40 #include <string.h>
41
AsapKimPotential(KIM::ModelDriverCreate * const modelDriverCreate,bool supportvirial)42 AsapKimPotential::AsapKimPotential(KIM::ModelDriverCreate * const modelDriverCreate,
43 bool supportvirial)
44 {
45 CONSTRUCTOR;
46 int error = 0;
47 int numparamfiles = 0;
48
49 potential = NULL;
50 atoms = NULL;
51
52 // Register the units. Conversion happens in the specific model.
53
54 // Store the parameter file name(s) for later use by reinit.
55 modelDriverCreate->GetNumberOfParameterFiles(&numparamfiles);
56 paramfile_names.resize(numparamfiles);
57 for (int i = 0; i < numparamfiles; ++i)
58 {
59 std::string const * paramFileName;
60 error = modelDriverCreate->GetParameterFileName(i, ¶mFileName);
61 if (error)
62 throw AsapError("AsapKimPotential: Unable to get parameter file name");
63 paramfile_names[i] = *paramFileName;
64 }
65
66 this->supportvirial = supportvirial;
67 error = modelDriverCreate->SetModelNumbering(KIM::NUMBERING::zeroBased);
68 assert(error == 0); // Should not be able to fail.
69
70 // Store pointers - XXXXX FIX THESE !!
71 error = (
72 modelDriverCreate->SetRoutinePointer(
73 KIM::MODEL_ROUTINE_NAME::ComputeArgumentsCreate,
74 KIM::LANGUAGE_NAME::cpp,
75 true,
76 reinterpret_cast<KIM::Function *>(AsapKimPotential::ComputeArgumentsCreate))
77 || modelDriverCreate->SetRoutinePointer(
78 KIM::MODEL_ROUTINE_NAME::ComputeArgumentsDestroy,
79 KIM::LANGUAGE_NAME::cpp,
80 true,
81 reinterpret_cast<KIM::Function *>(AsapKimPotential::ComputeArgumentsDestroy))
82 || modelDriverCreate->SetRoutinePointer(
83 KIM::MODEL_ROUTINE_NAME::Compute,
84 KIM::LANGUAGE_NAME::cpp,
85 true,
86 reinterpret_cast<KIM::Function *>(AsapKimPotential::Compute_static))
87 || modelDriverCreate->SetRoutinePointer(
88 KIM::MODEL_ROUTINE_NAME::Destroy,
89 KIM::LANGUAGE_NAME::cpp,
90 true,
91 reinterpret_cast<KIM::Function *>(AsapKimPotential::Destroy))
92 //|| modelDriverCreate->SetRefreshPointer(
93 // KIM::LANGUAGE_NAME::cpp,
94 // (KIM::Function *)2)
95 );
96 assert(error == 0); // Should not be able to fail.
97 }
98
~AsapKimPotential()99 AsapKimPotential::~AsapKimPotential()
100 {
101 DESTRUCTOR;
102 if (potential != NULL)
103 delete potential;
104 if (atoms != NULL)
105 AsapAtoms_DECREF(atoms);
106 }
107
SetPotential(Potential * pot)108 void AsapKimPotential::SetPotential(Potential *pot)
109 {
110 potential = pot;
111 potential_as_kimmixin = dynamic_cast<PotentialKimMixin*>(pot);
112 assert(potential_as_kimmixin != NULL);
113 }
114
CreateNeighborList(KimAtoms * atoms,double cutoff,double drift)115 PyAsap_NeighborLocatorObject *AsapKimPotential::CreateNeighborList(KimAtoms *atoms,
116 double cutoff,
117 double drift)
118 {
119 int ier;
120 PyAsap_NeighborLocatorObject *nblist;
121 atoms->SetPBC(true, true, true);
122 nblist = PyAsap_NewKimNeighborLocator(atoms, cutoff);
123 return nblist;
124 }
125
126 // static member function
ComputeArgumentsCreate(KIM::ModelCompute const * const modelCompute,KIM::ModelComputeArgumentsCreate * const modelComputeArgumentsCreate)127 int AsapKimPotential::ComputeArgumentsCreate(
128 KIM::ModelCompute const * const modelCompute,
129 KIM::ModelComputeArgumentsCreate * const modelComputeArgumentsCreate)
130 {
131 AsapKimPotential *modelObject;
132 modelCompute->GetModelBufferPointer(reinterpret_cast<void **>(&modelObject));
133
134 return modelObject->potential_as_kimmixin->ComputeArgumentsCreate(
135 modelComputeArgumentsCreate);
136 }
137
138 // static member function
ComputeArgumentsDestroy(KIM::ModelCompute const * const modelCompute,KIM::ModelComputeArgumentsDestroy * const modelComputeArgumentsDestroy)139 int AsapKimPotential::ComputeArgumentsDestroy(
140 KIM::ModelCompute const * const modelCompute,
141 KIM::ModelComputeArgumentsDestroy * const modelComputeArgumentsDestroy)
142 {
143 AsapKimPotential *modelObject;
144 modelCompute->GetModelBufferPointer(reinterpret_cast<void **>(&modelObject));
145
146 return modelObject->potential_as_kimmixin->ComputeArgumentsDestroy(
147 modelComputeArgumentsDestroy);
148 }
149
150
151 // static member function
Destroy(KIM::ModelDestroy * const modelDestroy)152 int AsapKimPotential::Destroy(KIM::ModelDestroy * const modelDestroy)
153 {
154 AsapKimPotential *modelObject;
155 modelDestroy->GetModelBufferPointer(reinterpret_cast<void **>(&modelObject));
156
157 if (modelObject != NULL)
158 {
159 // delete object itself
160 delete modelObject;
161 }
162
163 // everything is good
164 return false;
165 }
166
167
168 // static member function
Compute_static(KIM::ModelCompute const * const modelCompute,KIM::ModelComputeArguments const * const modelComputeArguments)169 int AsapKimPotential::Compute_static(KIM::ModelCompute const * const modelCompute,
170 KIM::ModelComputeArguments const * const modelComputeArguments)
171 {
172 AsapKimPotential * modelObject;
173 modelCompute->GetModelBufferPointer(reinterpret_cast<void **>(&modelObject));
174
175 return modelObject->Compute(modelCompute, modelComputeArguments);
176 }
177
178 #define MYLOG(x) modelCompute->LogEntry(KIM::LOG_VERBOSITY::error, x, __LINE__, __FILE__)
179
Compute(KIM::ModelCompute const * const modelCompute,KIM::ModelComputeArguments const * const modelComputeArguments)180 int AsapKimPotential::Compute(KIM::ModelCompute const * const modelCompute,
181 KIM::ModelComputeArguments const * const modelComputeArguments)
182 {
183 int error;
184 assert(potential != NULL);
185
186 // Information from the atoms
187 int nAtoms = 0;
188 int *nAtoms_p = NULL;
189
190 const double *coords = NULL;
191 const int *particleSpecies = NULL;
192 const int *particleContributing = NULL;
193
194 error =
195 modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::numberOfParticles,
196 &nAtoms_p);
197 if (error)
198 {
199 MYLOG("Failed to get number of atoms.");
200 return error;
201 }
202 assert(nAtoms_p != NULL);
203 nAtoms = *nAtoms_p;
204 assert(nAtoms >= 0);
205
206 error =
207 modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::coordinates,
208 &coords)
209 || modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::particleSpeciesCodes,
210 &particleSpecies)
211 || modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::particleContributing,
212 &particleContributing);
213 if (error)
214 {
215 MYLOG("Failed to get coordinates, species or contribution pointer.");
216 return error;
217 }
218 assert(coords != NULL && particleSpecies != NULL && particleContributing != NULL);
219
220 // Quantities to be computed
221 double *energy = NULL;
222 double *forces = NULL;
223 double *particleEnergy = NULL;
224 double *virial = NULL;
225 double *particleVirial = NULL;
226
227 error =
228 modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::partialEnergy,
229 &energy)
230 || modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::partialParticleEnergy,
231 &particleEnergy)
232 || modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::partialForces,
233 &forces);
234 if (error)
235 {
236 MYLOG("Failed to get energy or force pointer.");
237 return error;
238 }
239 if (supportvirial)
240 {
241 error =(
242 modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::partialVirial,
243 &virial)
244 || modelComputeArguments->GetArgumentPointer(KIM::COMPUTE_ARGUMENT_NAME::partialParticleVirial,
245 &particleVirial)
246 );
247 if (error)
248 {
249 MYLOG("Failed to get virial pointers.");
250 return error;
251 }
252 }
253
254 // Create or update the KIM replacement of the ASAP Atoms access object.
255 if (atoms == NULL)
256 {
257 // First call, create the Atoms interface object
258 atoms = new KimAtoms();
259 assert(atoms != NULL);
260 atoms->ReInit(modelComputeArguments, nAtoms, coords, particleSpecies, particleContributing);
261 try {
262 potential->SetAtoms(NULL, atoms);
263 }
264 catch (AsapError &e)
265 {
266 string msg = e.GetMessage();
267 MYLOG(msg.c_str());
268 return 1;
269 }
270 }
271 else
272 {
273 atoms->ReInit(modelComputeArguments, nAtoms, coords, particleSpecies, particleContributing);
274 }
275
276 // Now do the actual computation
277 try
278 {
279 if (particleEnergy != NULL)
280 {
281 const vector<double> &energies_v = potential->GetPotentialEnergies(NULL);
282 assert(energies_v.size() == nAtoms);
283 for (int i = 0; i < nAtoms; i++)
284 particleEnergy[i] = energies_v[i];
285 }
286 if (energy != NULL)
287 *energy = potential->GetPotentialEnergy(NULL);
288 if (particleVirial != NULL)
289 {
290 const vector<SymTensor> &virials = potential->GetVirials(NULL);
291 assert(virials.size() == nAtoms);
292 const double *virials_ptr = (double *) &virials[0];
293 for (int i = 0; i < 6*(nAtoms); i++)
294 particleVirial[i] = virials_ptr[i];
295 }
296 if (virial != NULL)
297 {
298 SymTensor v = potential->GetVirial(NULL);
299 for (int i = 0; i < 6; i++)
300 virial[i] = v[i];
301 }
302 if (forces != NULL)
303 {
304 const vector<Vec> &forces_v = potential->GetForces(NULL);
305 assert(forces_v.size() == nAtoms);
306 const double *forces_v_ptr = (double *) &forces_v[0];
307 for (int i = 0; i < 3*(nAtoms); i++)
308 forces[i] = forces_v_ptr[i];
309 }
310 }
311 catch (AsapError &e)
312 {
313 string msg = e.GetMessage();
314 MYLOG(msg.c_str());
315 return 1;
316 }
317 return 0;
318 }
319