Simpatico  v1.10
MonoclinicBoundary.h
1 #ifndef SIMP_MONOCLINIC_BOUNDARY_H
2 #define SIMP_MONOCLINIC_BOUNDARY_H
3 
4 /*
5 * Util Package - C++ Utilities for Scientific Computation
6 *
7 * Copyright 2010 - 2017, The Regents of the University of Minnesota
8 * Distributed under the terms of the GNU General Public License.
9 */
10 
11 #include <util/crystal/LatticeSystem.h> // member
12 #include <util/containers/FSArray.h> // member template
13 #include <util/space/Vector.h> // member template argument
14 #include <util/space/IntVector.h> // inline methods
15 #include <util/space/Dimension.h> // member template argument
16 #include <util/global.h> // asserts in inline methods
17 
18 #include <cmath>
19 #include <iostream>
20 
21 class MonoclinicBoundaryTest;
22 
23 namespace Util {
24  class Random;
25  #ifdef UTIL_MPI
26  template <class T> void send(MPI::Comm& comm, T& data, int dest, int tag);
27  template <class T> void recv(MPI::Comm& comm, T& data, int source, int tag);
28  template <class T> void bcast(MPI::Intracomm& comm, T& data, int root);
29  #endif
30 }
31 
32 namespace Simp
33 {
34 
35  using namespace Util;
36 
43  {
44 
45  public:
46 
51 
60  void setMonoclinic(const Vector &lengths, const double d);
61 
67  void setOrthorhombic(const Vector &lengths);
68 
75  template <class Archive>
76  void serialize(Archive& ar, const unsigned int version);
77 
79 
80 
89  void shift(Vector &r) const;
90 
106  void shift(Vector &r, IntVector& shift) const;
107 
119  void shiftGen(Vector &r) const;
120 
134  void shiftGen(Vector &r, IntVector& shift) const;
135 
149  void applyShift(Vector &r, int i, int t) const;
150 
152 
154 
162  double distanceSq(const Vector &r1, const Vector &r2) const;
163 
172  double distanceSq(const Vector &r1, const Vector &r2, IntVector& shift)
173  const;
174 
187  double distanceSq(const Vector &r1, const Vector &r2, Vector &dr) const;
188 
190 
192 
202  void transformCartToGen(const Vector& Rc, Vector& Rg) const;
203 
210  void transformGenToCart(const Vector& Rg, Vector& Rc) const;
211 
213 
215 
222 
232  const Vector& lengths() const;
233 
239  double length(int i) const;
240 
244  double minLength() const;
245 
249  double volume() const;
250 
256  const Vector& bravaisBasisVector(int i) const;
257 
263  const Vector& reciprocalBasisVector(int i) const;
264 
271  void randomPosition(Random &random, Vector &r) const;
272 
276  bool isValid();
277 
279 
280  private:
281 
283  Vector minima_;
284 
286  Vector maxima_;
287 
289  Vector l_;
290 
292  double d_;
293 
295  Vector halfL_;
296 
298  Vector invL_;
299 
301  Vector lengths_;
302 
304  double volume_;
305 
307  double c3_;
308 
310  double e_;
311 
313  double minLength_;
314 
318  FSArray<Vector, Dimension> bravaisBasisVectors_;
319 
323  FSArray<Vector, Dimension> reciprocalBasisVectors_;
324 
328  LatticeSystem lattice_;
329 
330  // friends:
331 
333  friend class ::MonoclinicBoundaryTest;
334 
336  friend std::istream& operator >> (std::istream& in,
337  MonoclinicBoundary& boundary);
338 
340  friend std::ostream& operator << (std::ostream& out,
341  const MonoclinicBoundary& boundary);
342 
343  #ifdef UTIL_MPI
344  friend void Util::send<>(MPI::Comm& comm, Simp::MonoclinicBoundary& data,
345  int dest, int tag);
346 
347  friend void Util::recv<>(MPI::Comm& comm, Simp::MonoclinicBoundary& data,
348  int source, int tag);
349 
350  friend void Util::bcast<>(MPI::Intracomm& comm, Simp::MonoclinicBoundary& data,
351  int root);
352  #endif
353 
357  void reset();
358 
359  };
360 
361  // Inline method definitions
362 
363  /*
364  * Return Vector of lengths by const reference.
365  */
366  inline const Vector& MonoclinicBoundary::lengths() const
367  { return lengths_; }
368 
369  /*
370  * Get length = maximum - minimum in direction i.
371  */
372  inline double MonoclinicBoundary::length(int i) const
373  { return lengths_[i]; }
374 
375  /*
376  * Return region volume.
377  */
378  inline double MonoclinicBoundary::volume() const
379  { return volume_; }
380 
381  /*
382  * Return Bravais lattice basis vector number i.
383  */
385  { return bravaisBasisVectors_[i]; }
386 
387  /*
388  * Return reciprocal lattice basis vector number i.
389  */
391  { return reciprocalBasisVectors_[i]; }
392 
393  /*
394  * Return the maximum validity range of the distances.
395  */
396  inline double MonoclinicBoundary::minLength() const
397  { return minLength_; }
398 
399  /*
400  * Shift Vector r to periodic cell, R[axis] < r[axis] < maxima_[axis].
401  */
402  inline void MonoclinicBoundary::shift(Vector& r) const
403  {
404  if(r[0] >= maxima_[0]) {
405  r[0] -= l_[0];
406  assert(r[0] < maxima_[0]);
407  } else
408  if (r[0] < minima_[0]) {
409  r[0] += l_[0];
410  assert(r[0] >= minima_[0]);
411  }
412  if(r[1] >= maxima_[1]) {
413  r[1] -= l_[1];
414  r[2] -= d_;
415  assert(r[1] < l_[1]);
416  } else
417  if (r[1] < minima_[1]) {
418  r[1] += l_[1];
419  r[2] += d_;
420  assert(r[1] >= minima_[1]);
421  }
422  double u2 = r[2] + c3_*r[1];
423  if(u2 >= maxima_[2]) {
424  r[2] -= l_[2];
425  assert(r[2] + c3_*r[1] >= minima_[2]);
426  } else
427  if (u2 < minima_[2]) {
428  r[2] += l_[2];
429  assert(r[2] + c3_*r[1] >= minima_[2]);
430  }
431  }
432 
433  /*
434  * Shift Vector r to periodic cell, R[axis] < r[axis] < maxima_[axis].
435  */
437  {
438  if (r[0] >= maxima_[0]) {
439  r[0] -= l_[0];
440  ++(shift[0]);
441  assert(r[0] < maxima_[0]);
442  } else
443  if (r[0] < minima_[0]) {
444  r[0] += l_[0];
445  --(shift[0]);
446  assert(r[0] >= minima_[0]);
447  }
448  if (r[1] >= maxima_[1]) {
449  r[1] -= l_[1];
450  r[2] -= d_;
451  ++(shift[1]);
452  assert(r[1] < l_[1]);
453  } else
454  if (r[1] < minima_[1]) {
455  r[1] += l_[1];
456  r[2] += d_;
457  --(shift[1]);
458  assert(r[1] >= minima_[1]);
459  }
460  double u2 = r[2] + c3_*r[1];
461  if (u2 >= maxima_[2]) {
462  r[2] -= l_[2];
463  ++(shift[2]);
464  assert(r[2] + c3_*r[1] < maxima_[2]);
465  } else
466  if (u2 < minima_[2]) {
467  r[2] += l_[2];
468  --(shift[2]);
469  assert(r[2] + c3_*r[1] >= minima_[2]);
470  }
471  }
472 
473  /*
474  * Shift Cartesian Vector r by multiple t of a Bravais lattice vector.
475  */
476  inline void MonoclinicBoundary::applyShift(Vector &r, int i, int t) const
477  {
478  switch (i) {
479  case 0:
480  r[0] += t*l_[0];
481  break;
482  case 1:
483  r[1] += t*l_[1];
484  r[2] += t*d_;
485  break;
486  case 2:
487  r[2] += t*l_[2];
488  break;
489  }
490  }
491 
492  /*
493  * Shift generalized Vector r to primitive unit cell.
494  */
495  inline void MonoclinicBoundary::shiftGen(Vector& r) const
496  {
497  for (int i = 0; i < Dimension; ++i) {
498  if( r[i] >= 1.0 ) {
499  r[i] = r[i] - 1.0;
500  assert(r[i] < 1.0);
501  } else
502  if ( r[i] < 0.0 ) {
503  r[i] = r[i] + 1.0;
504  assert(r[i] >= 0.0);
505  }
506  }
507  }
508 
509  /*
510  * Shift generalized Vector r to primitive cell, 0 < r[axis] < 1.0.
511  */
512  inline
514  {
515  for (int i = 0; i < Dimension; ++i) {
516  if (r[i] >= 1.0) {
517  r[i] = r[i] - 1.0;
518  ++(shift[i]);
519  assert(r[i] < 1.0);
520  } else
521  if (r[i] < 0.0) {
522  r[i] = r[i] + 1.0;
523  --(shift[i]);
524  assert(r[i] >= 0.0);
525  }
526  }
527  }
528 
529  /*
530  * Calculate minimum-image squared distance.
531  */
532  inline
533  double MonoclinicBoundary::distanceSq(const Vector &r1, const Vector &r2,
534  IntVector& translate) const
535  {
536 
537  double dx = r1[0] - r2[0];
538  if ( fabs(dx) > halfL_[0] ) {
539  if (dx > 0.0) {
540  dx -= l_[0];
541  translate[0] = -1;
542  } else {
543  dx += l_[0];
544  translate[0] = +1;
545  }
546  assert(fabs(dx) <= halfL_[0]);
547  } else {
548  translate[0] = 0;
549  }
550 
551  double dy = r1[1] - r2[1];
552  double dz = r1[2] - r2[2];
553  double u2 = dz + c3_*dy;
554  if ( fabs(dy) > halfL_[1] ) {
555  if (dy > 0.0) {
556  dy -= l_[1];
557  dz -= d_;
558  translate[1] = -1;
559  } else {
560  dy += l_[1];
561  dz += d_;
562  translate[1] = +1;
563  }
564  assert(fabs(dy) <= halfL_[1]);
565  } else {
566  translate[1] = 0;
567  }
568 
569  if ( fabs(u2) > halfL_[2]) {
570  if (u2 > 0.0) {
571  dz -= l_[2];
572  translate[2] = -1;
573  } else {
574  dz += l_[2];
575  translate[2] = +1;
576  }
577  assert(fabs(dz + c3_*dy) <= halfL_[2]);
578  } else {
579  translate[2] = 0;
580  }
581  return dx*dx+dy*dy+dz*dz;
582  }
583 
584  /*
585  * Compute minimum image squared distance and separation.
586  */
587  inline
589  const Vector &r2) const
590  {
591 
592  double dx = r1[0] - r2[0];
593  if ( fabs(dx) > halfL_[0] ) {
594  if (dx > 0.0) {
595  dx -= l_[0];
596  } else {
597  dx += l_[0];
598  }
599  assert(fabs(dx) <= halfL_[0]);
600  }
601 
602  double dy = r1[1] - r2[1];
603  double dz = r1[2] - r2[2];
604  double u2 = dz + c3_*dy;
605  if ( fabs(dy) > halfL_[1] ) {
606  if (dy > 0.0) {
607  dy -= l_[1];
608  dz -= d_;
609  } else {
610  dy += l_[1];
611  dz += d_;
612  }
613  assert(fabs(dy) <= halfL_[1]);
614  }
615 
616  if ( fabs(u2) > halfL_[2]) {
617  if (u2 > 0.0) {
618  dz -= l_[2];
619  } else {
620  dz += l_[2];
621  }
622  assert(fabs(dz+c3_*dy) <= halfL_[2]);
623  }
624 
625  return dx*dx+dy*dy+dz*dz;
626  }
627 
628  /*
629  * Calculate squared distance and separation vector by mininum convention.
630  */
631  inline
632  double MonoclinicBoundary::distanceSq(const Vector &r1, const Vector &r2,
633  Vector &dr) const
634  {
635 
636  double dx = r1[0] - r2[0];
637  if (fabs(dx) > halfL_[0]) {
638  if (dx > 0.0) {
639  dx -= l_[0];
640  } else {
641  dx += l_[0];
642  }
643  assert(fabs(dx) <= halfL_[0]);
644  }
645 
646  double dy = r1[1] - r2[1];
647  double dz = r1[2] - r2[2];
648  double u2 = dz + c3_*dy;
649 
650  if (fabs(dy) > halfL_[1]) {
651  if (dy > 0.0) {
652  dy -= l_[1];
653  dz -= d_;
654  } else {
655  dy += l_[1];
656  dz += d_;
657  }
658  assert(fabs(dy) <= halfL_[1]);
659  }
660 
661  if (fabs(u2) > halfL_[2]) {
662  if (u2 > 0.0) {
663  dz -= l_[2];
664  } else {
665  dz += l_[2];
666  }
667  assert(fabs(dz+c3_*dy) <= halfL_[2]);
668  }
669 
670  dr[0] = dx;
671  dr[1] = dy;
672  dr[2] = dz;
673 
674  return (dx*dx + dy*dy + dz*dz);
675  }
676 
684  std::istream& operator >> (std::istream& in, MonoclinicBoundary& boundary);
685 
693  std::ostream& operator << (std::ostream& out,
694  const MonoclinicBoundary& boundary);
695 
700  { return lattice_; }
701 
705  inline
707  const
708  {
709  Rg[0] = Rc[0] * invL_[0];
710  Rg[1] = Rc[1] * invL_[1];
711  Rg[2] = (Rc[2] + c3_ *Rc[1]) * invL_[2];
712  }
713 
717  inline
719  const
720  {
721  Rc[0] = Rg[0]*l_[0];
722  Rc[1] = Rg[1]*l_[1];
723  Rc[2] = Rg[2]*l_[2] + Rg[1]*d_;
724  }
725 
726  /*
727  * Serialize an OrthorhombicBoundary to/from an archive.
728  */
729  template <class Archive> void
730  MonoclinicBoundary::serialize(Archive& ar, const unsigned int version)
731  {
732  ar & l_;
733  ar & d_;
734  if (Archive::is_loading()) {
735  reset();
736  isValid();
737  }
738  }
739 
740 }
741 
742 #ifdef UTIL_MPI
743 #include <util/mpi/MpiSendRecv.h>
744 #include <util/mpi/MpiTraits.h>
745 
746 namespace Util
747 {
748 
749  using namespace Simp;
750 
754  template <>
755  void send<MonoclinicBoundary>(MPI::Comm& comm, MonoclinicBoundary& data,
756  int dest, int tag);
757 
761  template <>
762  void recv<MonoclinicBoundary>(MPI::Comm& comm, MonoclinicBoundary& data,
763  int source, int tag);
764 
768  template <>
769  void bcast<MonoclinicBoundary>(MPI::Intracomm& comm,
770  MonoclinicBoundary& data, int root);
771 
775  template <>
777  {
778  public:
779  static MPI::Datatype type;
780  static bool hasType;
781  };
782 
783 }
784 #endif // ifdef UTIL_MPI
785 #endif // ifndef UTIL_MONOCLINIC_BOUNDARY_H
const int Dimension
Dimensionality of space.
Definition: Dimension.h:19
friend std::ostream & operator<<(std::ostream &out, const MonoclinicBoundary &boundary)
ostream inserter
A Vector is a Cartesian vector.
Definition: Vector.h:75
void applyShift(Vector &r, int i, int t) const
Shift Cartesian Vector r by multiple t of a Bravais lattice vector.
const Vector & bravaisBasisVector(int i) const
Return Bravais lattice vector i.
void recv(MPI::Comm &comm, T &data, int source, int tag)
Receive a single T value.
Definition: MpiSendRecv.h:116
static bool hasType
Is the MPI type initialized?
void serialize(Archive &ar, const unsigned int version)
Serialize to/from an archive.
void transformGenToCart(const Vector &Rg, Vector &Rc) const
Transform Vector of generalized coordinates to Cartesian coordinates.
void setOrthorhombic(const Vector &lengths)
Invalid function for monoclinic - throws Exception.
File containing preprocessor macros for error handling.
Classes used by all simpatico molecular simulations.
void send(MPI::Comm &comm, T &data, int dest, int tag)
Send a single T value.
Definition: MpiSendRecv.h:97
void bcast< MonoclinicBoundary >(MPI::Intracomm &comm, MonoclinicBoundary &data, int root)
Broadcast an MonoclinicBoundary via MPI.
double length(int i) const
Get distance across primitive cell along reciprocal basis vector i.
A fixed capacity (static) contiguous array with a variable logical size.
Definition: FSArray.h:37
void shift(Vector &r) const
Shift Vector r to its image within the primary unit cell.
void bcast(MPI::Intracomm &comm, T &data, int root)
Broadcast a single T value.
Definition: MpiSendRecv.h:134
Utility classes for scientific computation.
Definition: accumulators.mod:1
Default MpiTraits class.
Definition: MpiTraits.h:39
void recv< MonoclinicBoundary >(MPI::Comm &comm, MonoclinicBoundary &data, int source, int tag)
Receive an MonoclinicBoundary via MPI.
void transformCartToGen(const Vector &Rc, Vector &Rg) const
Transform Vector of Cartesian coordinates to generalized coordinates.
friend std::istream & operator>>(std::istream &in, MonoclinicBoundary &boundary)
istream extractor
void send< MonoclinicBoundary >(MPI::Comm &comm, MonoclinicBoundary &data, int dest, int tag)
Send an MonoclinicBoundary via MPI.
void setMonoclinic(const Vector &lengths, const double d)
Set unit cell dimensions for orthorhombic boundary.
LatticeSystem
Enumeration of the 7 possible Bravais lattice systems.
Definition: LatticeSystem.h:29
void shiftGen(Vector &r) const
Shift generalized Vector r to its primary image.
A monoclinic periodic unit cell.
static MPI::Datatype type
MPI Datatype.
void randomPosition(Random &random, Vector &r) const
Generate random Cartesian position within the primary unit cell.
This file contains templates for global functions send<T>, recv<T> and bcast<T>.
bool isValid()
Return true if valid, or throw Exception.
An IntVector is an integer Cartesian vector.
Definition: IntVector.h:73
Random number generator.
Definition: Random.h:46
const Vector & lengths() const
Get Vector of distances between faces of primitive cell.
double distanceSq(const Vector &r1, const Vector &r2) const
Return square distance between r1 and r2, with minimum image convention.
const Vector & reciprocalBasisVector(int i) const
Return reciprocal lattice basis vector i.
LatticeSystem latticeSystem()
Return actual lattice system.
double minLength() const
Get minimum length across primitive unit cell.
double volume() const
Return unit cell volume.