@@ -37,8 +37,16 @@ std::unique_ptr<AtomDistribution> AtomDistribution::getAtomDistribution(std::str
3737 distribution = std::make_unique<twoGlobs>();
3838 } else if (atomicDistr == " sc" ) {
3939 distribution = std::make_unique<tiledSimpleCubic>();
40+ } else if (atomicDistr == " ibcc" ) {
41+ distribution = std::make_unique<inscribedBodyCenteredCubic>();
42+ } else if (atomicDistr == " bcc" ) {
43+ distribution = std::make_unique<tiledBodyCenteredCubic>();
44+ } else if (atomicDistr == " ifcc" ) {
45+ distribution = std::make_unique<inscribedFaceCenteredCubic>();
46+ } else if (atomicDistr == " fcc" ) {
47+ distribution = std::make_unique<tiledFaceCenteredCubic>();
4048 } else {
41- plumed_error () << R"( The atomic distribution can be only "line", "cube", "sphere", "globs" and "sc ", the input was ")"
49+ plumed_error () << R"( The atomic distribution can be only "line", "cube", "sphere", "globs", "sc", "ibcc", "bcc", "ifcc", and "fcc ", the input was ")"
4250 << atomicDistr <<' "' ;
4351 }
4452 return distribution;
@@ -188,6 +196,19 @@ void uniformCube::frame(View<Vector> posToUpdate,
188196
189197}
190198
199+ // / A simple correction to getting (in ceil mode) the correct nearest perfect cube
200+ unsigned ceiledPerfectCube (const unsigned N) {
201+ // In some case a perfect cube is not well represented by double
202+ // and will get uncorrectly ceiled up (for example 24389 will result in a 30 and not in 29)
203+
204+ // This assumes that N!=0
205+ const size_t x = std::ceil (std::cbrt (static_cast <double >(N)))-1 ;
206+ if ( x*x*x >= N) {
207+ return x;
208+ }
209+ return x+1 ;
210+ }
211+
191212void tiledSimpleCubic::frame (View<Vector> posToUpdate,
192213 View<double ,9 > box,
193214 unsigned /* step*/ ,
@@ -196,15 +217,7 @@ void tiledSimpleCubic::frame(View<Vector> posToUpdate,
196217 // I do not think that write a spacefilling curve, like Hilbert, Peano or Morton
197218 // could be a good idea, in this case
198219
199- // the lambda is here because in some case a perfect cube is not well represented
200- // by double and will get uncorrectly ceiled up (for example 24389 will result in a 30 and not in 29)
201- const unsigned rmax = [&] {
202- const size_t x = std::ceil (std::cbrt (static_cast <double >(posToUpdate.size ())))-1 ;
203- if ( x*x*x >= posToUpdate.size ()) {
204- return x;
205- }
206- return x+1 ;
207- }();
220+ const unsigned rmax =ceiledPerfectCube (posToUpdate.size ());
208221
209222 auto s=posToUpdate.begin ();
210223 auto e=posToUpdate.end ();
@@ -230,6 +243,170 @@ void tiledSimpleCubic::frame(View<Vector> posToUpdate,
230243
231244}
232245
246+ void inscribedFaceCenteredCubic::frame (View<Vector> posToUpdate,
247+ View<double ,9 > box,
248+ unsigned /* step*/ ,
249+ Random& rng) {
250+ // Here we are exploiting a litte trick:
251+ // if you remove the even or odd atoms from a simple cubic built with our algorithm,
252+ // you get an fcc boxed in a cube
253+ const unsigned rmax = [&] {
254+ auto x = ceiledPerfectCube (2 *posToUpdate.size ());
255+ // rmax needs to be even for this trick to work
256+ if ( x%2 ==0 ) {
257+ return x;
258+ } else {
259+ return x+1 ;
260+ }
261+
262+ }();
263+
264+ auto s=posToUpdate.begin ();
265+ auto e=posToUpdate.end ();
266+ // I am using the iterators:this is slightly faster,
267+ // enough to overcome the cost of the vtable that I added
268+ for (unsigned k=0 ; k<rmax&&s!=e; ++k) {
269+ for (unsigned j=0 ; j<rmax&&s!=e; ++j) {
270+ // we choose to show only the atoms with even index: (i+j+k)%2
271+ // Like this we skip steps and lots of divisions
272+ for (unsigned i=(j+k)%2 ; i<rmax&&s!=e; i+=2 ) {
273+ *s = 0.5 *Vector (i,j,k);
274+ ++s;
275+ }
276+ }
277+ }
278+ box[0 ]=0.5 *rmax;
279+ box[1 ]=0.0 ;
280+ box[2 ]=0.0 ;
281+ box[3 ]=0.0 ;
282+ box[4 ]=0.5 *rmax;
283+ box[5 ]=0.0 ;
284+ box[6 ]=0.0 ;
285+ box[7 ]=0.0 ;
286+ box[8 ]=0.5 *rmax;
287+
288+ }
289+
290+ void tiledFaceCenteredCubic::frame (View<Vector> posToUpdate,
291+ View<double ,9 > box,
292+ unsigned /* step*/ ,
293+ Random& rng) {
294+
295+ const unsigned rmax =ceiledPerfectCube (posToUpdate.size ());
296+
297+ auto s=posToUpdate.begin ();
298+ auto e=posToUpdate.end ();
299+ #define X PLMD ::Versors::xp<double >
300+ #define Y PLMD ::Versors::yp<double >
301+ #define Z PLMD ::Versors::zp<double >
302+ const auto a=sqrt (2 )*0.5 *(X+Y);
303+ const auto b=sqrt (2 )*0.5 *(X+Z);
304+ const auto c=sqrt (2 )*0.5 *(Y+Z);
305+ #undef X
306+ #undef Y
307+ #undef Z
308+ // I am using the iterators:this is slightly faster,
309+ // enough to overcome the cost of the vtable that I added
310+ for (unsigned k=0 ; k<rmax&&s!=e; ++k) {
311+ for (unsigned j=0 ; j<rmax&&s!=e; ++j) {
312+ for (unsigned i=0 ; i<rmax&&s!=e; ++i) {
313+ *s = i*a
314+ +j*b
315+ +k*c;
316+ ++s;
317+ }
318+ }
319+ }
320+
321+ box.subview <0 ,3 >() = a*rmax;
322+ box.subview <3 ,3 >() = b*rmax;
323+ box.subview <6 ,3 >() = c*rmax;
324+
325+ }
326+
327+ void tiledBodyCenteredCubic::frame (View<Vector> posToUpdate,
328+ View<double ,9 > box,
329+ unsigned /* step*/ ,
330+ Random& rng) {
331+ // For the base functionality of this see the comment in the tiledSimpleCubic
332+
333+ const unsigned rmax =ceiledPerfectCube (posToUpdate.size ());
334+
335+ auto s=posToUpdate.begin ();
336+ auto e=posToUpdate.end ();
337+ #define X PLMD ::Versors::xp<double >
338+ #define Y PLMD ::Versors::yp<double >
339+ #define Z PLMD ::Versors::zp<double >
340+ const auto a=0.5 *(-X+Y+Z);
341+ const auto b=0.5 *( X-Y+Z);
342+ const auto c=0.5 *( X+Y-Z);
343+ #undef X
344+ #undef Y
345+ #undef Z
346+ // I am using the iterators:this is slightly faster,
347+ // enough to overcome the cost of the vtable that I added
348+ for (unsigned k=0 ; k<rmax&&s!=e; ++k) {
349+ for (unsigned j=0 ; j<rmax&&s!=e; ++j) {
350+ for (unsigned i=0 ; i<rmax&&s!=e; ++i) {
351+ *s = i*a
352+ +j*b
353+ +k*c;
354+ ++s;
355+ }
356+ }
357+ }
358+
359+ box.subview <0 ,3 >() = a*rmax;
360+ box.subview <3 ,3 >() = b*rmax;
361+ box.subview <6 ,3 >() = c*rmax;
362+
363+ }
364+
365+ void inscribedBodyCenteredCubic::frame (View<Vector> posToUpdate,
366+ View<double ,9 > box,
367+ unsigned /* step*/ ,
368+ Random& rng) {
369+ // Here we are exploiting a litte trick:
370+ // if you remove the even or odd atoms from a simple cubic built with our algorithm,
371+ // you get an bcc boxed in a cube
372+ const unsigned rmax = [&] {
373+ // we take one atoms every 4
374+ auto x = ceiledPerfectCube (4 *posToUpdate.size ());
375+ // rmax needs to be even for this trick to work
376+ if ( x%2 ==0 ) {
377+ return x;
378+ } else {
379+ return x+1 ;
380+ }
381+
382+ }();
383+
384+ auto s=posToUpdate.begin ();
385+ auto e=posToUpdate.end ();
386+ // I am using the iterators:this is slightly faster,
387+ // enough to overcome the cost of the vtable that I added
388+ for (unsigned k=0 ; k<rmax&&s!=e; ++k) {
389+ // we alternate on the z axis the choice between atoms with both i and j even or odd
390+ // The +=2 skips an extra check in the inner body
391+ for (unsigned j=k%2 ; j<rmax&&s!=e; j+=2 ) {
392+ for (unsigned i=k%2 ; i<rmax&&s!=e; i+=2 ) {
393+ *s = 0.5 *Vector (i,j,k);
394+ ++s;
395+ }
396+ }
397+ }
398+ box[0 ]=0.5 *rmax;
399+ box[1 ]=0.0 ;
400+ box[2 ]=0.0 ;
401+ box[3 ]=0.0 ;
402+ box[4 ]=0.5 *rmax;
403+ box[5 ]=0.0 ;
404+ box[6 ]=0.0 ;
405+ box[7 ]=0.0 ;
406+ box[8 ]=0.5 *rmax;
407+
408+ }
409+
233410void fileTraj::rewind () {
234411 auto errormessage=parser.rewind ();
235412 if (errormessage) {
0 commit comments