faunus
spherocylinder.h
1 #pragma once
2 
3 #include "potentials_base.h"
4 #include "units.h"
5 
12 namespace Faunus::SpheroCylinder {
13 
21 inline Point vec_perpproject(const Point& a, const Point& b)
22 {
23  return a - b * a.dot(b);
24 }
25 
45 Point mindist_segment2segment(const Point& dir1, double halfl1, const Point& dir2, double halfl2,
46  const Point& r_cm);
47 
53 [[maybe_unused]] inline Point mindist_segment2point(const Point& segment_direction,
54  const double half_length,
55  const Point& separation)
56 {
57  const auto c = segment_direction.dot(separation);
58  double d;
59  if (c > half_length) {
60  d = half_length;
61  }
62  else {
63  d = (c > -half_length) ? c : -half_length;
64  }
65  return -separation + (segment_direction * d);
66 }
67 
72 int find_intersect_plane(const Cigar& part1, const Cigar& part2, const Point& r_cm,
73  const Point& w_vec, double cutoff_squared, double cospatch,
74  std::array<double, 5>& intersections);
75 
79 int test_intrpatch(const Cigar& part1, Point& vec, double cospatch, double ti,
80  std::array<double, 5>& intersections);
81 
88 int find_intersect_planec(const Cigar& part1, const Cigar& part2, const Point& r_cm,
89  const Point& w_vec, double rcut2, double cospatch,
90  std::array<double, 5>& intersections);
91 
96 int psc_intersect(const Cigar& particle1, const Cigar& particle2, const Point& r_cm,
97  std::array<double, 5>& intersections, double cutoff_squared);
98 
102 int cpsc_intersect(const Cigar& part1, const Cigar& part2, const Point& r_cm,
103  std::array<double, 5>& intersections, double rcut2);
104 
105 inline double fanglscale(const double a, const Cigar& cigar)
106 {
107  // a = r_ij * n_i
108  if (a <= cigar.pcanglsw) {
109  return 0.0;
110  }
111  if (a >= cigar.pcangl) {
112  return 1.0;
113  }
114  return 0.5 - ((cigar.pcanglsw + cigar.pcangl) * 0.5 - a) / (cigar.pcangl - cigar.pcanglsw);
115 }
116 
117 } // namespace Faunus::SpheroCylinder
118 
119 // --------------------
120 
121 namespace Faunus::pairpotential {
122 
125 {
126  public:
127  double operator()(const Particle& particle1, const Particle& particle2,
128  [[maybe_unused]] double d,
129  const Point& center_to_center_distance) const override
130  {
131  assert(particle1.hasExtension() && particle2.hasExtension());
132  auto minimum_distance_squared =
134  particle1.ext->scdir, particle1.ext->half_length, particle2.ext->scdir,
135  particle1.ext->half_length, center_to_center_distance)
136  .squaredNorm();
137  const auto contact_distance = 0.5 * (particle1.traits().sigma + particle2.traits().sigma);
138  if (minimum_distance_squared < contact_distance * contact_distance) {
139  return pc::infty;
140  }
141  return 0.0;
142  }
143 
145  void to_json(json& j) const override;
146  void from_json(const json& j) override;
147 };
148 
155 template <pairpotential::RequirePairPotential PatchPotential,
156  pairpotential::RequirePairPotential CylinderPotential>
158 {
159  private:
160  PatchPotential patch_potential;
161  CylinderPotential cylinder_potential;
162 
163  public:
164  CigarWithSphere();
165  void to_json(json& j) const override;
166  void from_json(const json& j) override;
167 
168  inline double operator()(const Particle& cigar, const Particle& sphere,
169  [[maybe_unused]] double distance_squared,
170  const Point& center_separation) const override
171  {
172  assert(cigar.hasExtension());
173  const auto c = cigar.getExt().scdir.dot(center_separation);
174  double contt;
175  if (c > cigar.ext->half_length) {
176  contt = cigar.ext->half_length;
177  }
178  else {
179  if (c > -cigar.ext->half_length) {
180  contt = c;
181  }
182  else {
183  contt = -cigar.ext->half_length;
184  }
185  }
186  const Point distvec = -center_separation + (cigar.ext->scdir * contt);
187  if (cigar.traits().sphero_cylinder.type == SpheroCylinderData::PatchType::None &&
188  sphere.traits().sphero_cylinder.type == SpheroCylinderData::PatchType::None) {
189  return cylinder_potential(cigar, sphere, distvec.squaredNorm(), Point::Zero());
190  }
191 
192  // patchy interaction
193  const auto cutoff_squared = patch_potential.cutOffSquared(cigar.id, sphere.id);
194  // scaling function: angular dependence of patch1
195  const Point vec1 = SpheroCylinder::vec_perpproject(distvec, cigar.ext->scdir).normalized();
196  const auto s = vec1.dot(cigar.ext->patchdir);
197  const auto f1 = SpheroCylinder::fanglscale(s, cigar.getExt());
198 
199  // scaling function for the length of spherocylinder within cutoff
200  const auto ndist_squared = distvec.dot(distvec);
201  const auto t = sqrt(cutoff_squared - ndist_squared); // TODO cutoff
202  double f0;
203  if (contt + t > cigar.ext->half_length) {
204  f0 = cigar.ext->half_length;
205  }
206  else {
207  f0 = contt + t;
208  }
209  if (contt - t < -cigar.ext->half_length) {
210  f0 -= -cigar.ext->half_length;
211  }
212  else {
213  f0 -= contt - t;
214  }
215  return f1 * (f0 + 1.0) * patch_potential(cigar, sphere, ndist_squared, Point::Zero()) +
216  cylinder_potential(cigar, sphere, ndist_squared, Point::Zero());
217  }
218 };
219 
233 template <pairpotential::RequirePairPotential PatchPotential,
234  pairpotential::RequirePairPotential CylinderPotential>
236 {
237  private:
238  PatchPotential patch_potential;
239  CylinderPotential cylinder_potential;
240 
241  [[nodiscard]] double patchyPatchyEnergy(const Particle& particle1, const Particle& particle2,
242  const Point& center_separation) const;
243 
244  [[nodiscard]] double isotropicIsotropicEnergy(const Particle& particle1,
245  const Particle& particle2,
246  const Point& center_separation) const;
247 
248  public:
249  CigarWithCigar();
250  void to_json(json& j) const override;
251  void from_json(const json& j) override;
252 
253  inline double operator()(const Particle& particle1, const Particle& particle2,
254  [[maybe_unused]] double center_separation_squared,
255  const Point& center_separation) const override
256  {
257  assert(particle1.hasExtension() && particle2.hasExtension());
258  if (particle1.traits().sphero_cylinder.type != SpheroCylinderData::PatchType::None &&
259  particle2.traits().sphero_cylinder.type != SpheroCylinderData::PatchType::None) {
260  return patchyPatchyEnergy(particle1, particle2, center_separation);
261  }
262  return isotropicIsotropicEnergy(particle1, particle2, center_separation);
263  }
264 };
265 
277 template <pairpotential::RequirePairPotential PatchPotential,
278  pairpotential::RequirePairPotential CylinderPotential,
279  pairpotential::RequirePairPotential SphereWithSphere = CylinderPotential>
281 {
282  private:
283  SphereWithSphere sphere_sphere; // pair potential between spheres
284  CigarWithCigar<PatchPotential, CylinderPotential> cigar_cigar; // pair potential between cigars
286  cigar_sphere; // pair potential cigar <-> sphere
287 
288  public:
289  inline double operator()(const Particle& a, const Particle& b,
290  [[maybe_unused]] double distance_squared,
291  const Point& distance) const override
292  {
293  const double small_number = 1e-6;
294  const auto a_is_sphere = !a.hasExtension() || a.ext->half_length < small_number;
295  const auto b_is_sphere = !a.hasExtension() || b.ext->half_length < small_number;
296 
297  if (!a_is_sphere && !b_is_sphere) {
298  return cigar_cigar(a, b, distance_squared, distance);
299  }
300  if (a_is_sphere && b_is_sphere) {
301  return sphere_sphere(a, b, distance_squared, distance);
302  }
303  if (b_is_sphere) {
304  return cigar_sphere(a, b, distance_squared, distance);
305  }
306  return cigar_sphere(b, a, distance_squared, distance);
307  }
308 
309  void to_json([[maybe_unused]] json& j) const override;
310  void from_json(const json& j) override;
312 };
313 
314 } // namespace Faunus::pairpotential
Point mindist_segment2point(const Point &segment_direction, const double half_length, const Point &separation)
Definition: spherocylinder.h:53
Point mindist_segment2segment(const Point &dir1, const double half_length1, const Point &dir2, const double half_length2, const Point &r_cm)
Calculate minimum distance between two line segments.
Definition: spherocylinder.cpp:15
nlohmann::json json
JSON object.
Definition: json_support.h:10
double pcangl
Cosine of AtomData::patch_angle (speed optimization)
Definition: particle.h:132
Eigen::Vector3d Point
3D vector used for positions, velocities, forces etc.
Definition: coordinates.h:7
int cpsc_intersect(const Cigar &cigar1, const Cigar &cigar2, const Point &r_cm, std::array< double, 5 > &intersections, const double cutoff_squared)
Intersection of PSC2 with cylindrical patch of PSC1 and return them (CPSC)
Definition: spherocylinder.cpp:429
int find_intersect_plane(const Cigar &part1, const Cigar &part2, const Point &r_cm, const Point &w_vec, const double cutoff_squared, const double cospatch, std::array< double, 5 > &intersections)
Finds intersections of spherocylinder and plane defined by vector "w_vec" and if they are in all-way ...
Definition: spherocylinder.cpp:102
Hard-sphere pair potential for spherocylinders.
Definition: spherocylinder.h:124
int find_intersect_planec(const Cigar &part1, const Cigar &part2, const Point &r_cm, const Point &w_vec, double rcut2, double cospatch, std::array< double, 5 > &intersections)
Intersect of plane.
Definition: spherocylinder.cpp:182
Template for interactions between patchy sphero-cylinders (PSCs) interactions.
Definition: spherocylinder.h:235
ParticleExtension & getExt()
get/create extension
Definition: particle.h:240
double operator()(const Particle &particle1, const Particle &particle2, [[maybe_unused]] double d, const Point &center_to_center_distance) const override
Pair energy in units of kT.
Definition: spherocylinder.h:127
Point vec_perpproject(const Point &a, const Point &b)
Calculate perpendicular projection of the first vector versus the second vector.
Definition: spherocylinder.h:21
double pcanglsw
Cosine of switch angle from AtomData (speed optimization)
Definition: particle.h:131
Set pair potential between cigar-cigar, sphere-sphere, cigar-sphere.
Definition: spherocylinder.h:280
Patchy sphero cylinder a.k.a.Sphero-cylinder properties.
Definition: particle.h:122
The algorithms found here are mainly direct conversions from Robert Vacha&#39;s spherocylinder C code (~2...
Definition: spherocylinder.cpp:5
std::unique_ptr< ParticleExtension > ext
Point to extended properties.
Definition: particle.h:224
int id
Particle id/type.
Definition: particle.h:225
Particle class for storing positions, id, and other properties.
Definition: particle.h:220
const AtomData & traits() const
get properties from AtomData
Definition: particle.cpp:183
bool hasExtension() const
check if particle has extensions (dipole etc.)
Definition: particle.cpp:249
int test_intrpatch(const Cigar &part1, Point &vec, double cospatch, double ti, std::array< double, 5 > &intersections)
Finds if vector "vec" has angular intersection w.
Definition: spherocylinder.cpp:147
concept RequirePairPotential
Concept matching a particle pair potential derived from Potential::PairPotentialBase ...
Definition: potentials_base.h:180
auto distance(T1 first, T2 last)
Distance between two arbitrary contiguous iterators.
Definition: iteratorsupport.h:7
Namespace for particle pair-potentials.
Definition: analysis.h:18
Base for all pair-potentials.
Definition: potentials_base.h:131
Pair potential between a patchy sphero-cylinder (first particle) and a sphere (second particle) ...
Definition: spherocylinder.h:157
int psc_intersect(const Cigar &particle1, const Cigar &particle2, const Point &r_cm, std::array< double, 5 > &intersections, const double cutoff_squared)
Intersections of spherocylinder2 with a all-way patch of spherocylinder1 and return them (PSC) ...
Definition: spherocylinder.cpp:231