MercuryDPM  Alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Screw.cc
Go to the documentation of this file.
1 //Copyright (c) 2013-2014, The MercuryDPM Developers Team. All rights reserved.
2 //For the list of developers, see <http://www.MercuryDPM.org/Team>.
3 //
4 //Redistribution and use in source and binary forms, with or without
5 //modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name MercuryDPM nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 //DISCLAIMED. IN NO EVENT SHALL THE MERCURYDPM DEVELOPERS TEAM BE LIABLE FOR ANY
19 //DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include "Screw.h"
27 #include "array"
28 #include "InteractionHandler.h"
29 #include "Math/ExtendedMath.h"
30 #include "Particles/BaseParticle.h"
31 using mathsFunc::square;
38 {
39  start_.setZero();
40  l_ = 1.0;
41  maxR_ = 1.0;
42  n_ = 1.0;
43  omega_ = 1.0;
44  offset_ = 0.0;
45  thickness_ = 0.0;
46  logger(DEBUG, "Screw() constructor finished.");
47 }
48 
52 Screw::Screw(const Screw& other)
53  : BaseWall(other)
54 {
55  start_ = other.start_;
56  l_ = other.l_;
57  maxR_ = other.maxR_;
58  n_ = other.n_;
59  omega_ = other.omega_;
60  thickness_ = other.thickness_;
61  offset_ = other.offset_;
62  logger(DEBUG, "Screw(const Screw&) copy constructor finished.");
63 }
64 
75 Screw::Screw(Vec3D start, Mdouble l, Mdouble r, Mdouble n, Mdouble omega, Mdouble thickness)
76 {
77  start_ = start;
78  l_ = l;
79  maxR_ = r;
80  n_ = n;
81  omega_ = omega;
82  thickness_ = thickness;
83  offset_ = 0.0;
84  logger(DEBUG, "Screw(Vec3D, Mdouble, Mdouble, Mdouble, Mdouble, Mdouble) constructor finished.");
85 }
86 
88 {
89  logger(DEBUG, "~Screw() finished, destroyed the Screw.");
90 }
91 
96 {
97  return new Screw(*this);
98 }
99 
111 bool Screw::getDistanceAndNormal(const BaseParticle& p, Mdouble& distance, Vec3D& normal_return) const
112 {
113  Mdouble RSquared = square(p.getPosition().X - start_.X) + square(p.getPosition().Y - start_.Y);
114  Mdouble Z = p.getPosition().Z - start_.Z;
115  //first do a simple check if particle is within the cylindrical hull of the screw
116  if (RSquared > square(maxR_ + p.getWallInteractionRadius() + thickness_)
117  || Z > l_ + p.getWallInteractionRadius() + thickness_
118  || Z < - p.getWallInteractionRadius() - thickness_)
119  {
120  //std::cout << "failed " << p.getPosition() << std::endl;
121  return false;
122  }
123 
124  //else:
125  Mdouble R = sqrt(RSquared);
126  Mdouble A = atan2(p.getPosition().Y - start_.Y, p.getPosition().X - start_.X);
127 
128  //after subtracting the start position and transforming the particle position from (XYZ) into (RAZ)
129  //coordinates, we compute the distance to the wall at, located at (r,a,z)=(r,2*pi*(offset+N*q+k/2),q*L), 0<q<1.
130 
131  //To find the contact point we have to minimize (with respect to r and q)
132  //distance^2=(x-x0-r*cos(2*pi*(offset+N*q)))^2+(y-y0-r*sin(2*pi*(offset+N*q)))^2+(z-z0-q*L)^2
133  //Using polar coordinates (i.e. x-x0=R*cos(A), y-y0=R*sin(A) and Z=z-z0)
134  //distance^2=R^2+r^2-2*R*r*cos(A-2*pi*(offset+N*q))+(Z-q*L)^2
135 
136  //Assumption: d(distance)/dr=0 at minDistance (should there be also a q-derivative?)
137  //Differentiate with respect to r and solve for zero:
138  //0=2*r-2*R*cos(A-2*pi*(offset+N*q)
139  //r=R*cos(A-2*pi*(offset+N*q))
140 
141  //Substitue back
142  //distance^2=R^2+R^2*cos^2(A-2*pi*(offset+N*q))-2*R^2*cos^2(A-2*pi*(offset+N*q))+(Z-q*L)^2
143  //distance^2=R^2*sin^2(A-2*pi*(offset+N*q))+(Z-q*L)^2
144 
145  //So we have to minimize:
146  //distance^2=R^2*sin^2(A-2*pi*(offset+N*q))^2 + (Z-q*L)^2 = f(q)
147  //f'(q)=(-2*pi*N)*R^2*sin(2*A-4*pi*(offset+N*q)) + 2*L*(Z-q*L) (D[Sin[x]^2,x]=Sin[2x])
148  //f''(q)=(4*pi^2*N^2)*R^2*cos(2*A-4*pi*(offset+N*q)) - 2*L*L
149  //For this we use the Euler algoritm
150 
151  Mdouble q; //Current guess
152  Mdouble dd; //Derivative at current guess
153  Mdouble ddd; //Second derivative at current guess
154  Mdouble q0 = Z / l_; //assume closest point q0 is at same z-location as the particle
155 
156  //Set initial q to the closest position on the screw with the same angle as A
157  //The initial guess will be in the minimum of the sin closest to q0
158  //Minima of the sin are at
159  //A-2*pi*(offset+N*q)=k*pi (k=integer)
160  //q=A/(2*pi*N)-k/(2*N)-offset/N (k=integer)
161 
162  Mdouble k = round(A / constants::pi - 2.0 * (offset_ + n_ * q0)); // k: |A-a(q0)-k*pi|=min
163  q = A / (2.0 * constants::pi * n_) - k / (2.0 * n_) - offset_ / n_; // q: a(q)=A
164 
165  //Now apply Newton's method
166  do
167  {
168  Mdouble arg = 2.0 * A - 4.0 * constants::pi * (n_ * q + offset_);
169  dd = -2.0 * constants::pi * n_ * RSquared * sin(arg) - 2.0 * l_ * (Z - q * l_);
170  ddd = 8.0 * constants::sqr_pi * n_ * n_ * RSquared * cos(arg) + 2.0 * l_ * l_;
171  q -= dd / ddd;
172  } while (fabs(dd / ddd) > 1e-14);
173 
174  //Calculate r
175  Mdouble r = R * cos(2.0 * constants::pi * (offset_ + n_ * q) - A);
176 
177  //Check if the location is actually on the screw:
178  //First posibility is that the radius is too large:
179  if (fabs(r) > maxR_) //Left boundary of the coil
180  {
181  r = mathsFunc::sign(r) * maxR_;
182  unsigned int steps = 0;
183  //This case reduces to the coil problem
184  do
185  {
186  dd = -4.0 * R * r * constants::pi * n_ * sin(A - 2.0 * constants::pi * (n_ * q + offset_)) - 2.0 * l_ * (Z - q * l_);
187  ddd = 8.0 * R * r * constants::sqr_pi * n_ * n_ * cos(A - 2.0 * constants::pi * (n_ * q + offset_)) + 2.0 * l_ * l_;
188  q -= dd / ddd;
189  steps++;
190  } while (fabs(dd / ddd) > 1e-14);
191  }
192  //Second possibility is that it occured before the start of after the end
193  if (q < 0)
194  {
195  q = 0;
196  r = R * cos(A - 2.0 * constants::pi * (offset_ + q * n_));
197  if (fabs(r) > maxR_)
198  {
199  r = mathsFunc::sign(r) * maxR_;
200  }
201  }
202  else if (q > 1)
203  {
204  q = 1;
205  r = R * cos(A - 2.0 * constants::pi * (offset_ + q * n_));
206  if (fabs(r) > maxR_)
207  {
208  r = mathsFunc::sign(r) * maxR_;
209  }
210  }
211 
212  Mdouble distanceSquared = R * R * pow(sin(A - 2 * constants::pi * (offset_ + n_ * q)), 2) + pow(Z - q * l_, 2);
213  //If distance is too large there is no contact
214  if (distanceSquared >= square(p.getWallInteractionRadius() + thickness_))
215  {
216  return false;
217  }
218 
219  Vec3D ContactPoint;
220  distance = sqrt(distanceSquared) - thickness_;
221  ContactPoint.X = start_.X + r * cos(2.0 * constants::pi * (offset_ + n_ * q));
222  ContactPoint.Y = start_.Y + r * sin(2.0 * constants::pi * (offset_ + n_ * q));
223  ContactPoint.Z = start_.Z + q * l_;
224  normal_return = (ContactPoint - p.getPosition());
225  normal_return.normalize();
226  return true;
227 }
228 
233 {
234  offset_ += omega_ * dt;
235 }
236 
240 void Screw::read(std::istream& is)
241 {
242  BaseWall::read(is);
243  std::string dummy;
244  is >> dummy >> start_
245  >> dummy >> l_
246  >> dummy >> maxR_
247  >> dummy >> n_
248  >> dummy >> omega_
249  >> dummy >> thickness_
250  >> dummy >> offset_;
251 }
252 
259 void Screw::oldRead(std::istream& is)
260 {
261  std::string dummy;
262  is >> dummy >> start_
263  >> dummy >> l_
264  >> dummy >> maxR_
265  >> dummy >> n_
266  >> dummy >> omega_
267  >> dummy >> offset_;
268 }
269 
273 void Screw::write(std::ostream& os) const
274 {
275  BaseWall::write(os);
276  os << " start " << start_
277  << " Length " << l_
278  << " Radius " << maxR_
279  << " Revolutions " << n_
280  << " Omega " << omega_
281  << " Thickness " << thickness_
282  << " Offset " << offset_;
283 }
284 
288 std::string Screw::getName() const
289 {
290  return "Screw";
291 }
292 
293 void Screw::writeVTK (std::string filename) const
294 {
295  std::vector<Vec3D> vertices;
296  std::vector<std::array<unsigned,3>> faces;
297  getTriangulation (vertices, faces);
298 
299  std::stringstream file;
300  file << "# vtk DataFile Version 2.0\n"
301  << getName() << "\n"
302  "ASCII\n"
303  "DATASET UNSTRUCTURED_GRID\n"
304  "POINTS " << vertices.size() << " double\n";
305  for (const auto& vertex : vertices)
306  file << vertex << '\n';
307  file << "\nCELLS " << faces.size() << ' ' << 4*faces.size() << "\n";
308  for (const auto& face : faces)
309  file << "3 " << face[0] << ' ' << face[1] << ' ' << face[2] << '\n';
310  file << "\nCELL_TYPES " << faces.size() << "\n";
311  for (const auto& face : faces)
312  file << "5\n";
313  helpers::writeToFile(filename,file.str());
314 }
315 
316 void Screw::getTriangulation (std::vector<Vec3D>& vertices, std::vector<std::array<unsigned,3>>& faces, unsigned nr, unsigned nz) const
317 {
318  //add vertices
319  vertices.reserve(nr*nz);
320  Vec3D vertex;
321  for (Mdouble iz=0; iz<nz; iz++) {
322  for (Mdouble ir=0; ir<nr; ir++) {
323  Mdouble q = iz/(nz-1); //angular direction
324  Mdouble r = ir/(nr-1)*maxR_;
325  vertex.X = start_.X - r * cos(2.0 * constants::pi * (offset_ + n_ * q));
326  vertex.Y = start_.Y - r * sin(2.0 * constants::pi * (offset_ + n_ * q));
327  vertex.Z = start_.Z + q * l_;
328  vertices.push_back(vertex);
329  }
330  }
331  //reserve space for faces
332  faces.reserve(2*(nr-1)*(nz-1));
333  std::array<unsigned,3> face;
334  for (unsigned iz=0; iz<nz-1; iz++) {
335  for (unsigned ir=0; ir<nr-1; ir++) {
336  //first face 0 1 nr
337  faces.push_back({iz*nr+ir,iz*nr+(ir+1),(iz+1)*nr+ir});
338  //second face 1 nr+1 nr
339  faces.push_back({iz*nr+(ir+1),(iz+1)*nr+(ir+1),(iz+1)*nr+ir});
340  }
341  }
342 }
bool writeToFile(std::string filename, std::string filecontent)
Writes a string to a file.
Definition: Helpers.cc:418
Mdouble X
the vector components
Definition: Vector.h:52
void read(std::istream &is) override
Reads a Screw from an input stream, for example a restart file.
Definition: Screw.cc:240
Mdouble maxR_
The outer radius of the Screw.
Definition: Screw.h:113
This function defines an Archimedes' screw in the z-direction from a (constant) starting point...
Definition: Screw.h:38
Logger< MERCURY_LOGLEVEL > logger("MercuryKernel")
void getTriangulation(std::vector< Vec3D > &vertex, std::vector< std::array< unsigned, 3 >> &face, unsigned nr=5, unsigned nz=15) const
Definition: Screw.cc:316
void normalize()
Makes this Vec3D unit length.
Definition: Vector.cc:214
bool getDistanceAndNormal(const BaseParticle &P, Mdouble &distance, Vec3D &normal_return) const final
Compute the distance from the Screw for a given BaseParticle and return if there is a collision...
Definition: Screw.cc:111
~Screw()
Default destructor.
Definition: Screw.cc:87
double Mdouble
void setZero()
Sets all elements to zero.
Definition: Vector.cc:52
int sign(T val)
This is a sign function, it returns -1 for negative numbers, 1 for positive numbers and 0 for 0...
Definition: ExtendedMath.h:83
void move_time(Mdouble dt)
Rotate the Screw for a period dt, so that the offset_ changes with omega_*dt.
Definition: Screw.cc:232
T square(T val)
squares a number
Definition: ExtendedMath.h:91
const Vec3D & getPosition() const
Returns the position of this BaseInteractable.
Mdouble getWallInteractionRadius() const
Returns the interaction radius for interaction with walls. See also BaseParticle::getInteractionRadiu...
Mdouble cos(Mdouble x)
Definition: ExtendedMath.cc:60
std::string getName() const final
Returns the name of the object, here the string "Screw".
Definition: Screw.cc:288
void writeVTK(std::string filename) const
Definition: Screw.cc:293
Vec3D start_
The centre of the lower end of the screw.
Definition: Screw.h:105
Mdouble sin(Mdouble x)
Definition: ExtendedMath.cc:42
Mdouble offset_
The angle that describes how much the Screw has turned, going from 0 to 1 for a rotation.
Definition: Screw.h:125
const Mdouble pi
Definition: ExtendedMath.h:42
Mdouble l_
The length of the Screw.
Definition: Screw.h:109
Screw * copy() const final
Copy this screw and return a pointer to the copy.
Definition: Screw.cc:95
Basic class for walls.
Definition: BaseWall.h:44
void write(std::ostream &os) const override
Writes this Screw to an output stream, for example a restart file.
Definition: Screw.cc:273
Mdouble Y
Definition: Vector.h:52
Mdouble n_
The number of revelations.
Definition: Screw.h:117
Screw()
Default constructor: make a screw with default parameters.
Definition: Screw.cc:37
Mdouble thickness_
The thickness of the Screw.
Definition: Screw.h:129
Mdouble omega_
Rotation speed in rev/s.
Definition: Screw.h:121
Implementation of a 3D vector (by Vitaliy).
Definition: Vector.h:45
void write(std::ostream &os) const
Function that writes a BaseWall to an output stream, usually a restart file.
Definition: BaseWall.cc:68
Mdouble Z
Definition: Vector.h:52
const Mdouble sqr_pi
Definition: ExtendedMath.h:44
void oldRead(std::istream &is)
Reads a Screw in the old style from an input stream, for example a restart file old style...
Definition: Screw.cc:259
void read(std::istream &is)
Function that reads a BaseWall from an input stream, usually a restart file.
Definition: BaseWall.cc:60