2 Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
3 (HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
4 the University of Michigan All rights reserved.
6 HOOMD-blue may contain modifications ("Contributions") provided, and to which
7 copyright is held, by various Contributors who have granted The Regents of the
8 University of Michigan the right to modify and/or distribute such Contributions.
10 You may redistribute, use, and create derivate works of HOOMD-blue, in source
11 and binary forms, provided you abide by the following conditions:
13 * Redistributions of source code must retain the above copyright notice, this
14 list of conditions, and the following disclaimer both in the code and
15 prominently in any materials provided with the distribution.
17 * Redistributions in binary form must reproduce the above copyright notice, this
18 list of conditions, and the following disclaimer in the documentation and/or
19 other materials provided with the distribution.
21 * All publications and presentations based on HOOMD-blue, including any reports
22 or published results obtained, in whole or in part, with HOOMD-blue, will
23 acknowledge its use according to the terms posted at the time of submission on:
24 http://codeblue.umich.edu/hoomd-blue/citations.html
26 * Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
27 http://codeblue.umich.edu/hoomd-blue/
29 * Apart from the above required attributions, neither the name of the copyright
30 holder nor the names of HOOMD-blue's contributors may be used to endorse or
31 promote products derived from this software without specific prior written
36 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
37 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
39 WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.
41 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
43 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
46 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 // Maintainer: morozov
54 #pragma warning( push )
55 #pragma warning( disable : 4103 4244 )
58 #include <boost/python.hpp>
59 #include <boost/dynamic_bitset.hpp>
60 using namespace boost
;
61 using namespace boost::python
;
63 #include "HOOMDInitializer.h"
64 #include "EAMForceCompute.h"
67 /*! \file EAMForceCompute.cc
68 \brief Defines the EAMForceCompute class
73 /*! \param sysdef System to compute forces on
74 \param filename Name of EAM potential file to load
75 \param type_of_file Undocumented parameter
77 EAMForceCompute::EAMForceCompute(boost::shared_ptr
<SystemDefinition
> sysdef
, char *filename
, int type_of_file
)
78 : ForceCompute(sysdef
)
80 m_exec_conf
->msg
->notice(5) << "Constructing EAMForceCompute" << endl
;
82 #ifndef SINGLE_PRECISION
83 m_exec_conf
->msg
->error() << "EAM is not supported in double precision" << endl
;
84 throw runtime_error("Error initializing");
89 loadFile(filename
, type_of_file
);
90 // initialize the number of types value
91 m_ntypes
= m_pdata
->getNTypes();
96 EAMForceCompute::~EAMForceCompute()
98 m_exec_conf
->msg
->notice(5) << "Destroying EAMForceCompute" << endl
;
102 type_of_file = 0 => EAM/Alloy
103 type_of_file = 1 => EAM/FS
105 void EAMForceCompute::loadFile(char *filename
, int type_of_file
)
107 unsigned int tmp_int
, type
, i
, j
, k
;
108 double tmp_mass
, tmp
;
111 const unsigned int MAX_TYPE_NUMBER
= 10;
112 const unsigned int MAX_POINT_NUMBER
= 1000000;
114 // Open potential file
116 fp
= fopen(filename
,"r");
119 m_exec_conf
->msg
->error() << "pair.eam: Can not load EAM file" << endl
;
120 throw runtime_error("Error loading file");
122 for(i
= 0; i
< 3; i
++) while(fgetc(fp
) != '\n');
124 int n
= fscanf(fp
, "%d", &m_ntypes
);
125 if (n
!= 1) throw runtime_error("Error parsing eam file");
127 if(m_ntypes
< 1 || m_ntypes
> MAX_TYPE_NUMBER
)
129 m_exec_conf
->msg
->error() << "pair.eam: Invalid EAM file format: Type number is greater than " << MAX_TYPE_NUMBER
<< endl
;
130 throw runtime_error("Error loading file");
132 // temporary array to count used types
133 boost::dynamic_bitset
<> types_set(m_pdata
->getNTypes());
134 //Load names of types.
135 for(i
= 0; i
< m_ntypes
; i
++)
137 n
= fscanf(fp
, "%2s", tmp_str
);
138 if (n
!= 1) throw runtime_error("Error parsing eam file");
140 names
.push_back(tmp_str
);
141 unsigned int tid
= m_pdata
->getTypeByName(tmp_str
);
142 types
.push_back(tid
);
143 types_set
[tid
] = true;
146 //Check that all types of atopms in xml file have description in potential file
147 if(m_pdata
->getNTypes() != types_set
.count())
149 m_exec_conf
->msg
->error() << "pair.eam: not all atom types are defined in EAM potential file!!!" << endl
;
150 throw runtime_error("Error loading file");
154 n
= fscanf(fp
,"%d", &nrho
);
155 if (n
!= 1) throw runtime_error("Error parsing eam file");
157 n
= fscanf(fp
,"%lg", &tmp
);
158 if (n
!= 1) throw runtime_error("Error parsing eam file");
161 rdrho
= (Scalar
)(1.0 / drho
);
162 n
= fscanf(fp
,"%d", &nr
);
163 if (n
!= 1) throw runtime_error("Error parsing eam file");
165 n
= fscanf(fp
,"%lg", &tmp
);
166 if (n
!= 1) throw runtime_error("Error parsing eam file");
169 rdr
= (Scalar
)(1.0 / dr
);
170 n
= fscanf(fp
,"%lg", &tmp
);
171 if (n
!= 1) throw runtime_error("Error parsing eam file");
174 if (nrho
< 1 || nr
< 1 || nrho
> MAX_POINT_NUMBER
|| nr
> MAX_POINT_NUMBER
)
176 m_exec_conf
->msg
->error() << "pair.eam: Invalid EAM file format: Point number is greater than " << MAX_POINT_NUMBER
<< endl
;
177 throw runtime_error("Error loading file");
179 //Resize arrays for tables
180 embeddingFunction
.resize(nrho
* m_ntypes
);
181 electronDensity
.resize( nr
* m_ntypes
* m_ntypes
);
182 pairPotential
.resize( (int)(0.5 * nr
* (m_ntypes
+ 1) * m_ntypes
) );
183 derivativeEmbeddingFunction
.resize(nrho
* m_ntypes
);
184 derivativeElectronDensity
.resize(nr
* m_ntypes
* m_ntypes
);
185 derivativePairPotential
.resize((int)(0.5 * nr
* (m_ntypes
+ 1) * m_ntypes
));
187 for(type
= 0 ; type
< m_ntypes
; type
++)
189 n
= fscanf(fp
, "%d %lg %lg %3s ", &tmp_int
, &tmp_mass
, &tmp
, tmp_str
);
190 if (n
!= 4) throw runtime_error("Error parsing eam file");
192 mass
.push_back(tmp_mass
);
196 for(i
= 0 ; i
< nrho
; i
++)
198 res
= fscanf(fp
, "%lg", &tmp
);
199 embeddingFunction
[types
[type
] * nrho
+ i
] = (Scalar
)tmp
;
202 //If FS we need read N arrays
203 //If Alloy we ned read 1 array, and then duplicate N-1 times.
204 unsigned int count
= 1;
205 if(type_of_file
== 1) count
= m_ntypes
;
207 for(j
= 0; j
< count
; j
++)
209 for(i
= 0 ; i
< nr
; i
++)
211 res
= fscanf(fp
, "%lg", &tmp
);
212 electronDensity
[types
[type
] * m_ntypes
* nr
+ j
* nr
+ i
] = (Scalar
)tmp
;
216 for(j
= 1; j
<= m_ntypes
- count
; j
++)
218 for(i
= 0 ; i
< nr
; i
++)
220 electronDensity
[types
[type
] * m_ntypes
* nr
+ j
* nr
+ i
] = electronDensity
[i
];
227 if(res
== EOF
|| res
== 0)
229 m_exec_conf
->msg
->error() << "pair.eam: EAM file is truncated " << endl
;
230 throw runtime_error("Error loading file");
233 for (k
= 0; k
< m_ntypes
; k
++)
235 for(j
= 0; j
<= k
; j
++)
237 for(i
= 0 ; i
< nr
; i
++)
239 res
= fscanf(fp
, "%lg", &tmp
);
240 pairPotential
[(unsigned int)ceil(0.5 *(2 * m_ntypes
- types
[k
] -1) * types
[k
] + types
[j
]) * nr
+ i
].x
= (Scalar
)tmp
;
253 //Cumpute derivative of Embedding Function and Electron Density.
254 for(type
= 0 ; type
< m_ntypes
; type
++)
256 for(i
= 0 ; i
< nrho
- 1; i
++)
258 derivativeEmbeddingFunction
[i
+ types
[type
] * nrho
] =
259 (embeddingFunction
[i
+ 1 + types
[type
] * nrho
] - embeddingFunction
[i
+ types
[type
] * nrho
]) / drho
;
261 for(j
= 0; j
< m_ntypes
; j
++)
263 for(i
= 0 ; i
< nr
- 1; i
++)
265 derivativeElectronDensity
[types
[type
] * m_ntypes
* nr
+ j
* nr
+ i
] =
266 (electronDensity
[types
[type
] * m_ntypes
* nr
+ j
* nr
+ i
+ 1] -
267 electronDensity
[types
[type
] * m_ntypes
* nr
+ j
* nr
+ i
]) / dr
;
274 //Cumpute derivative of Pair Potential.
276 for (k
= 0; k
< m_ntypes
; k
++)
278 for(j
= 0; j
<= k
; j
++)
280 for(i
= 0 ; i
< nr
; i
++)
282 if((i
+ 1)%nr
== 0) continue;
283 pairPotential
[(unsigned int)ceil(0.5 *(2 * m_ntypes
- types
[k
] -1) * types
[k
]) + types
[j
] * nr
+ i
].y
=
284 (pairPotential
[(unsigned int)ceil(0.5 *(2 * m_ntypes
- types
[k
] -1) * types
[k
]) + types
[j
] * nr
+ i
+ 1].x
- pairPotential
[(unsigned int)ceil(0.5 *(2 * m_ntypes
- types
[k
] -1) * types
[k
]) + types
[j
] * nr
+ i
].x
) / dr
;
292 std::vector
< std::string
> EAMForceCompute::getProvidedLogQuantities()
295 list
.push_back("pair_eam_energy");
299 Scalar
EAMForceCompute::getLogValue(const std::string
& quantity
, unsigned int timestep
)
301 if (quantity
== string("pair_eam_energy"))
304 return calcEnergySum();
308 m_exec_conf
->msg
->error() << "pair.eam: " << quantity
<< " is not a valid log quantity" << endl
;
309 throw runtime_error("Error getting log value");
313 /*! \post The lennard jones forces are computed for the given timestep. The neighborlist's
314 compute method is called to ensure that it is up to date.
316 \param timestep specifies the current time step of the simulation
318 void EAMForceCompute::computeForces(unsigned int timestep
)
320 // start by updating the neighborlist
321 m_nlist
->compute(timestep
);
323 // start the profile for this compute
324 if (m_prof
) m_prof
->push("EAM pair");
327 // depending on the neighborlist settings, we can take advantage of newton's third law
328 // to reduce computations at the cost of memory access complexity: set that flag now
329 bool third_law
= m_nlist
->getStorageMode() == NeighborList::half
;
331 // access the neighbor list
333 ArrayHandle
<unsigned int> h_n_neigh(m_nlist
->getNNeighArray(), access_location::host
, access_mode::read
);
334 ArrayHandle
<unsigned int> h_nlist(m_nlist
->getNListArray(), access_location::host
, access_mode::read
);
335 Index2D nli
= m_nlist
->getNListIndexer();
337 // access the particle data
338 ArrayHandle
<Scalar4
> h_pos(m_pdata
->getPositions(), access_location::host
, access_mode::read
);
339 ArrayHandle
<Scalar4
> h_force(m_force
,access_location::host
, access_mode::overwrite
);
340 ArrayHandle
<Scalar
> h_virial(m_virial
,access_location::host
, access_mode::overwrite
);
341 unsigned int virial_pitch
= m_virial
.getPitch();
343 // there are enough other checks on the input data: but it doesn't hurt to be safe
344 assert(h_force
.data
);
345 assert(h_virial
.data
);
348 // Zero data for force calculation.
349 memset((void*)h_force
.data
,0,sizeof(Scalar4
)*m_force
.getNumElements());
350 memset((void*)h_virial
.data
,0,sizeof(Scalar
)*m_virial
.getNumElements());
352 // get a local copy of the simulation box too
353 const BoxDim
& box
= m_pdata
->getBox();
355 // create a temporary copy of r_cut sqaured
356 Scalar r_cut_sq
= m_r_cut
* m_r_cut
;
358 // tally up the number of forces calculated
363 vector
<Scalar
> atomElectronDensity
;
364 atomElectronDensity
.resize(m_pdata
->getN());
365 vector
<Scalar
> atomDerivativeEmbeddingFunction
;
366 atomDerivativeEmbeddingFunction
.resize(m_pdata
->getN());
367 vector
<Scalar
> atomEmbeddingFunction
;
368 atomEmbeddingFunction
.resize(m_pdata
->getN());
369 unsigned int ntypes
= m_pdata
->getNTypes();
370 for (unsigned int i
= 0; i
< m_pdata
->getN(); i
++)
372 // access the particle's position and type (MEM TRANSFER: 4 scalars)
373 Scalar3 pi
= make_scalar3(h_pos
.data
[i
].x
, h_pos
.data
[i
].y
, h_pos
.data
[i
].z
);
374 unsigned int typei
= __scalar_as_int(h_pos
.data
[i
].w
);
377 assert(typei
< m_pdata
->getNTypes());
379 // loop over all of the neighbors of this particle
380 const unsigned int size
= (unsigned int)h_n_neigh
.data
[i
];
382 for (unsigned int j
= 0; j
< size
; j
++)
384 // increment our calculation counter
387 // access the index of this neighbor (MEM TRANSFER: 1 scalar)
388 unsigned int k
= h_nlist
.data
[nli(i
, j
)];
390 assert(k
< m_pdata
->getN());
392 // calculate dr (MEM TRANSFER: 3 scalars / FLOPS: 3)
393 Scalar3 pk
= make_scalar3(h_pos
.data
[k
].x
, h_pos
.data
[k
].y
, h_pos
.data
[k
].z
);
394 Scalar3 dx
= pi
- pk
;
396 // access the type of the neighbor particle (MEM TRANSFER: 1 scalar
397 unsigned int typej
= __scalar_as_int(h_pos
.data
[k
].w
);
399 assert(typej
< m_pdata
->getNTypes());
401 // apply periodic boundary conditions
402 dx
= box
.minImage(dx
);
404 // start computing the force
405 // calculate r squared (FLOPS: 5)
406 Scalar rsq
= dot(dx
, dx
);;
407 // only compute the force if the particles are closer than the cuttoff (FLOPS: 1)
410 Scalar position_scalar
= sqrt(rsq
) * rdr
;
411 Scalar position
= position_scalar
;
412 unsigned int r_index
= (unsigned int)position
;
413 r_index
= min(r_index
,nr
);
415 atomElectronDensity
[i
] += electronDensity
[r_index
+ nr
* (typei
* ntypes
+ typej
)] + derivativeElectronDensity
[r_index
+ nr
* (typei
* ntypes
+ typej
)] * position
* dr
;
418 atomElectronDensity
[k
] += electronDensity
[r_index
+ nr
* (typej
* ntypes
+ typei
)]
419 + derivativeElectronDensity
[r_index
+ nr
* (typej
* ntypes
+ typei
)] * position
* dr
;
425 for (unsigned int i
= 0; i
< m_pdata
->getN(); i
++)
427 unsigned int typei
= __scalar_as_int(h_pos
.data
[i
].w
);
429 Scalar position
= atomElectronDensity
[i
] * rdrho
;
430 unsigned int r_index
= (unsigned int)position
;
431 r_index
= min(r_index
,nrho
);
432 position
-= (Scalar
)r_index
;
433 atomDerivativeEmbeddingFunction
[i
] = derivativeEmbeddingFunction
[r_index
+ typei
* nrho
];
435 h_force
.data
[i
].w
+= embeddingFunction
[r_index
+ typei
* nrho
] + derivativeEmbeddingFunction
[r_index
+ typei
* nrho
] * position
* drho
;
438 for (unsigned int i
= 0; i
< m_pdata
->getN(); i
++)
440 // access the particle's position and type (MEM TRANSFER: 4 scalars)
441 Scalar3 pi
= make_scalar3(h_pos
.data
[i
].x
, h_pos
.data
[i
].y
, h_pos
.data
[i
].z
);
442 unsigned int typei
= __scalar_as_int(h_pos
.data
[i
].w
);
444 assert(typei
< m_pdata
->getNTypes());
446 // initialize current particle force, potential energy, and virial to 0
452 for (int k
= 0; k
< 6; k
++)
455 // loop over all of the neighbors of this particle
456 const unsigned int size
= (unsigned int)h_n_neigh
.data
[i
];
457 for (unsigned int j
= 0; j
< size
; j
++)
459 // increment our calculation counter
462 // access the index of this neighbor (MEM TRANSFER: 1 scalar)
463 unsigned int k
= h_nlist
.data
[nli(i
, j
)];
465 assert(k
< m_pdata
->getN());
467 // calculate dr (MEM TRANSFER: 3 scalars / FLOPS: 3)
468 Scalar3 pk
= make_scalar3(h_pos
.data
[k
].x
, h_pos
.data
[k
].y
, h_pos
.data
[k
].z
);
469 Scalar3 dx
= pi
- pk
;
471 // access the type of the neighbor particle (MEM TRANSFER: 1 scalar
472 unsigned int typej
= __scalar_as_int(h_pos
.data
[k
].w
);
474 assert(typej
< m_pdata
->getNTypes());
476 // apply periodic boundary conditions
477 dx
= box
.minImage(dx
);
479 // start computing the force
480 // calculate r squared (FLOPS: 5)
481 Scalar rsq
= dot(dx
, dx
);
483 if (rsq
>= r_cut_sq
) continue;
484 Scalar r
= sqrt(rsq
);
485 Scalar inverseR
= 1.0 / r
;
486 Scalar position
= r
* rdr
;
487 unsigned int r_index
= (unsigned int)position
;
488 position
= position
- (Scalar
)r_index
;
489 int shift
= (typei
>=typej
)?(int)(0.5 * (2 * ntypes
- typej
-1)*typej
+ typei
) * nr
:(int)(0.5 * (2 * ntypes
- typei
-1)*typei
+ typej
) * nr
;
490 //r_index = min(r_index,nr - 1);
491 Scalar pair_eng
= (pairPotential
[r_index
+ shift
].x
+
492 pairPotential
[r_index
+ shift
].y
* position
* dr
) * inverseR
;
493 Scalar derivativePhi
= (pairPotential
[r_index
+ shift
].y
- pair_eng
) * inverseR
;
494 Scalar derivativeRhoI
= derivativeElectronDensity
[r_index
+ typei
* nr
];
495 Scalar derivativeRhoJ
= derivativeElectronDensity
[r_index
+ typej
* nr
];
496 Scalar fullDerivativePhi
= atomDerivativeEmbeddingFunction
[i
] * derivativeRhoJ
+
497 atomDerivativeEmbeddingFunction
[k
] * derivativeRhoI
+ derivativePhi
;
498 Scalar pairForce
= - fullDerivativePhi
* inverseR
;
499 // are the virial and potential energy correctly calculated
500 // with respect to double counting?
501 viriali
[0] += dx
.x
*dx
.x
* pairForce
;
502 viriali
[1] += dx
.x
*dx
.y
* pairForce
;
503 viriali
[2] += dx
.x
*dx
.z
* pairForce
;
504 viriali
[3] += dx
.y
*dx
.y
* pairForce
;
505 viriali
[4] += dx
.y
*dx
.z
* pairForce
;
506 viriali
[5] += dx
.z
*dx
.z
* pairForce
;
507 fxi
+= dx
.x
* pairForce
;
508 fyi
+= dx
.y
* pairForce
;
509 fzi
+= dx
.z
* pairForce
;
514 h_force
.data
[k
].x
-= dx
.x
* pairForce
;
515 h_force
.data
[k
].y
-= dx
.y
* pairForce
;
516 h_force
.data
[k
].z
-= dx
.z
* pairForce
;
519 h_force
.data
[i
].x
+= fxi
;
520 h_force
.data
[i
].y
+= fyi
;
521 h_force
.data
[i
].z
+= fzi
;
522 h_force
.data
[i
].w
+= pei
;
523 for (int k
= 0; k
< 6; k
++)
524 h_virial
.data
[k
*virial_pitch
+i
] += viriali
[k
];
527 int64_t flops
= m_pdata
->getN() * 5 + n_calc
* (3+5+9+1+9+6+8);
528 if (third_law
) flops
+= n_calc
* 8;
529 int64_t mem_transfer
= m_pdata
->getN() * (5+4+10)*sizeof(Scalar
) + n_calc
* (1+3+1)*sizeof(Scalar
);
530 if (third_law
) mem_transfer
+= n_calc
*10*sizeof(Scalar
);
531 if (m_prof
) m_prof
->pop(flops
, mem_transfer
);
534 void EAMForceCompute::set_neighbor_list(boost::shared_ptr
<NeighborList
> nlist
)
539 Scalar
EAMForceCompute::get_r_cut()
543 void export_EAMForceCompute()
545 scope in_eam
= class_
<EAMForceCompute
, boost::shared_ptr
<EAMForceCompute
>, bases
<ForceCompute
>, boost::noncopyable
>
546 ("EAMForceCompute", init
< boost::shared_ptr
<SystemDefinition
>, char*, int>())
548 .def("set_neighbor_list", &EAMForceCompute::set_neighbor_list
)
549 .def("get_r_cut", &EAMForceCompute::get_r_cut
)
554 #pragma warning( pop )