HorizontalMixer.h
Go to the documentation of this file.
1 // This file is part of the MercuryDPM project (https://www.mercurydpm.org).
2 // Copyright (c), The MercuryDPM Developers Team. All rights reserved.
3 // License: BSD 3-Clause License; see the LICENSE file in the root directory.
4 
5 #include "Mercury3D.h"
7 #include "Walls/RestrictedWall.h"
8 #include "Walls/InfiniteWall.h"
11 #include "Walls/HorizontalScrew.h"
13 
14 #ifndef HorizontalMixer_h
15 #define HorizontalMixer_h
16 
17 class HorizontalMixer : public Mercury3D
18 {
19 private:
27  HorizontalScrew* screw = nullptr;
39  std::vector<unsigned> bladeMounts_;
44 
45 public:
49  bool haveOuterWalls = true;
50 
51 
52 public:
53 
59  {
63  }
64 
66  void setScrewWalls(const ParticleSpecies* s, Mdouble screwCenter,
67  Mdouble screwBaseHeight, Mdouble screwBaseRadius, Mdouble screwTopHeight,
68  Mdouble windingLength, Mdouble minR, Mdouble lowerR, Mdouble diffR, Mdouble thickness)
69  {
70  //Screws are dx=2200 apart, outerTopHeight height 1236, bottom height 110 (plus cap)
71  //winding width 411
72  Vec3D start = Vec3D(screwCenter, 0, screwBaseHeight);
73  Mdouble length = screwTopHeight-screwBaseHeight;
74  Mdouble numTurns = length/windingLength;
75  //create a screw that increases its length clockwise, just like (sin(t),cos(t), t).
76  // screw starts at height 0.11 until 1.197, distance 1.1 from the center in negative x-direction, making one turn each 0.411.
77  // rotation speed 1.0, thickness as small as possible, radius function is piecewise linear, decreasing from 0.6 to 0.4.
78  // screw starts at height 0.11 until 1.197, making one turn each 0.411.
80  (HorizontalScrew(start, length, minR, lowerR, diffR, numTurns, rotationSpeed/2.0/constants::pi, thickness, s));
81  //todo: change orientation of one screw
83  if (screw) screw->move_time(40);
84 
85  Mdouble sinA2Max = 0.25;
86  auto baseScrew = wallHandler.copyAndAddObject
87  (HorizontalBaseScrew(Vec3D(screwCenter,0,0),Vec3D(0,0,1),
88  {{Vec3D(0,0,-1),Vec3D(0,0,screwBaseHeight)},
89  {Vec3D(-1,0,0),Vec3D(screwBaseRadius,0,0)}},s,sinA2Max,timeMin));
90  baseScrew->setAngularVelocity(Vec3D(0,0,rotationSpeed));
91  //baseScrew->rotate(Vec3D(0,0,100));
92 
93  }
94 
96  virtual void setScrewCore(const ParticleSpecies* s, Mdouble screwCenter, Mdouble screwBaseHeight,
97  Mdouble coreTopHeight, Mdouble coreTopRadius,
98  Mdouble coreBottomHeight, Mdouble coreBottomRadius)
99  {
100  //the inner, thinner core cylinder in the screw
101  auto screwCore = wallHandler.copyAndAddObject
102  (AxisymmetricIntersectionOfWalls(Vec3D(screwCenter,0,0),Vec3D(0,0,1),
103  {{Vec3D(-.3,0,-1),Vec3D(coreTopRadius,0,coreTopHeight)},//slightly slant top, so particles roll off
104  {Vec3D(-1,0,0),Vec3D(coreTopRadius,0,0)}},s));
105  screwCore->setAngularVelocity(Vec3D(0,0,rotationSpeed));
106 
107  //the bottom, thicker core cylinder in the screw
108  auto screwBottom = wallHandler.copyAndAddObject
109  (AxisymmetricIntersectionOfWalls(Vec3D(screwCenter,0,0),Vec3D(0,0,1),
110  {{Vec3D(0,0,-1),Vec3D(0,0,coreBottomHeight)},
111  {Vec3D(-1,0,0),Vec3D(coreBottomRadius,0,0)}},s));
112  screwBottom->setAngularVelocity(Vec3D(0,0,rotationSpeed));
113  }
114 
116  virtual void setOuterWalls(const ParticleSpecies* s, Mdouble outerBaseRadius, Mdouble screwCenter, Mdouble outerTopCenter,
117  Mdouble outerTopRadius, Mdouble outerTopHeight)
118  {
119  //cylindrical wall
120  Vec3D normal = (Vec3D(outerTopCenter,0,outerTopHeight)-Vec3D(screwCenter,0,0));
121  normal.normalise();
122  Vec3D position = Vec3D(screwCenter,0,0);
123  Vec3D normalWall = Vec3D(outerTopHeight,0,outerBaseRadius-outerTopRadius);
124  normalWall.normalise();
125  Vec3D positionWall = Vec3D(outerBaseRadius,0,0);
126  AxisymmetricIntersectionOfWalls outerWall(position, normal, {{normalWall,positionWall}},s);
127  auto rightSide = wallHandler.copyAndAddObject(outerWall);
128 
129  //bottom plate
130  auto bottomPlate = wallHandler.copyAndAddObject
131  (InfiniteWall(Vec3D(0,0,-1),Vec3D(0,0,getZMin()),s));
132  }
133 
134  void setupInitialConditions() override
135  {
138 
139  // First, we define the screw
140  // bottom radius 0.974, outerTopHeight 1210, center-bottom x=1.21, center-outerTopHeight x=1.3385
141  Mdouble screwCenter = 1.21; //changed from 1.1
142  Mdouble screwBaseHeight = 0.11; //same
143  Mdouble screwTopHeight = 1.5; //changed from 1.155 //max. Height of the screw/somehow, screw is still felt on top of the core
144  Mdouble windingLength = 0.5; //changed from 0.411
145  Mdouble minR = 0.54;//change from 0.4 //radius in upper part
146  Mdouble lowerR = 1.195; //change from 0.6 ??//radius in upper part
147  Mdouble diffR = -0.6; //changed from -0.3 //radius in upper part
148  Mdouble thickness = 0.5*particleRadius; //needs change?
149 
150  //bottom screw core radius 270, outerTopHeight height 336
151  //outerTopHeight screw core radius ~170, outerTopHeight height 1236
152  Mdouble coreTopHeight = 1.5; //changed from 1236
153  Mdouble coreTopRadius = 0.17; //same
154  Mdouble coreBottomHeight = .491; //changed from 0.356
155  Mdouble coreBottomRadius = 0.27; //same
156  Mdouble screwBaseRadius = 1.0; //changed from 0.9
157 
158  //the cylindrical container:
159  Mdouble outerBaseRadius =1.208; //changed from 0.974
160  Mdouble outerTopCenter = screwCenter;// should be 1.3385, but for that I need to correct the implementation of orientation
161  Mdouble outerTopRadius =1.329; //changed from 1.21
162  Mdouble outerTopHeight = 1.995; // changed from 2.252
163 
164  setXMax(screwCenter+outerTopRadius);
165  setYMax(outerTopRadius);
166  setZMax(outerTopHeight);
167  setXMin(screwCenter-outerTopRadius);
168  setYMin(-getYMax());
169  setZMin(0.0);
170 
171  setScrewWalls(s, screwCenter, screwBaseHeight, screwBaseRadius, screwTopHeight, windingLength, minR, lowerR, diffR, thickness);
172  setScrewCore(s, screwCenter, screwBaseHeight, coreTopHeight, coreTopRadius, coreBottomHeight, coreBottomRadius);
173  if (haveOuterWalls) setOuterWalls(s, outerBaseRadius, screwCenter, outerTopCenter, outerTopRadius, outerTopHeight);
174 
175  //introduceSingleParticle(Vec3D(screwCenter,0.5*coreTopRadius,coreTopHeight));
176  //introduceParticlesAtWall();
178 
179  setGravity(Vec3D(0,0,-9.8));
180  }
181 
183  /* Simple run settings
184  * Nx*Ny*Nz particles are created evenly spaced between [xmin,xmax]*[ymin,ymax]*[zmin,zmax] and checked for contact with the screw
185  */
189  p0.setSpecies(s);
190  p0.setVelocity(Vec3D(0.0, 0.0, 0.0));
191  p0.setRadius(particleRadius);
192  p0.setPosition(p+Vec3D(0,0,particleRadius));
194  logger(INFO, "Inserted single particle ");
195  }
196 
198  /* Simple run settings
199  * Nx*Ny*Nz particles are created evenly spaced between [xmin,xmax]*[ymin,ymax]*[zmin,zmax] and checked for contact with the screw
200  */
204  p0.setSpecies(s);
205  p0.setVelocity(Vec3D(0.0, 0.0, 0.0));
206  p0.setRadius(2.0*particleRadius);
208  p1.setSpecies(s);
209  p1.setVelocity(Vec3D(0.0, 0.0, 0.0));
210  p1.setRadius(particleRadius);
211 
212  //number of particles that fit in domain
213  Mdouble distance;
214  Vec3D normal;
215  Vec3D p;
216  Mdouble minDistance;
217  unsigned counter = 0;
218  for (p.X = getXMin() + particleRadius; p.X < getXMax(); p.X += 2.0 * particleRadius)
219  for (p.Y = getYMin() + particleRadius; p.Y < getYMax(); p.Y += 2.0 * particleRadius)
220  for (p.Z = getZMin() + particleRadius; p.Z < fillHeight_; p.Z += 2.0 * particleRadius)
221  {
222  minDistance = p0.getRadius();
223  p0.setPosition(p);
224  for (auto w : wallHandler) {
225  //if touching the wall
226  if (w->getDistanceAndNormal(p0, distance, normal) && distance<minDistance)
227  {
228  minDistance=distance;
229  if (distance<0) break;
230  p1.setPosition(p0.getPosition()+(distance-1.0001*particleRadius)*normal);
231  }
232  }
233  if (minDistance<p0.getRadius() && minDistance>0)
234  {
236  counter++;
237  }
238  }
239  logger(INFO, "Inserted particles: %", counter);
240  }
241 
242  void introduceParticlesInDomain(Mdouble polydispersity=1) {
243  /* Simple run settings
244  * Nx*Ny*Nz particles are created evenly spaced between [xmin,xmax]*[ymin,ymax]*[zmin,zmax] and checked for contact with the screw
245  */
249  p0.setSpecies(s);
250  p0.setVelocity(Vec3D(0.0, 0.0, 0.0));
251  p0.setRadius(particleRadius);
252 
253  //CHANGED BY BERT need ~ 1.5 times cubic packing fraction to get HCP packing, assume particles are more HCP packed than cubic
254  Mdouble distance;
255  Vec3D normal;
256  Vec3D p;
257  Mdouble minDistance;
258  unsigned counter = 0;
259  for (p.X = getXMin() + particleRadius; p.X < getXMax(); p.X += 2.0 * particleRadius)
260  for (p.Y = getYMin() + particleRadius; p.Y < getYMax(); p.Y += 2.0 * particleRadius)
261  for (p.Z = getZMin() + particleRadius; p.Z < fillHeight_; p.Z += 2.0 * particleRadius) //Changed Cubic to HCP here
262  {
263  bool touch = false;
264  p0.setPosition(p);
265  for (auto w : wallHandler) {
266  //if touching the wall
267  if (w->getDistanceAndNormal(p0, distance, normal))
268  {
269  touch = true;
270  break;
271  }
272  }
273  if (!touch) {
275  p0.setRadius(random.getRandomNumber(particleRadius/polydispersity,particleRadius));
276  counter++;
277  }
278  }
279  logger(INFO, "Inserted particles: %", counter);
280  }
281 
282  void printTime () const override
283  {
284  logger(INFO, "t=%3.6, tmax=%3.6, EneRatio=%3.6", getTime(), getTimeMax(),
286  }
287 
288  void actionsAfterTimeStep () override {
289  if (screw) screw->move_time(getTimeStep());
290  }
291 
292  void writeScript() {
293  logger(INFO,"Writing matlab script % to color the particles",getName() + ".m");
294  helpers::writeToFile(getName() + ".m", "cd " + helpers::getPath() + "\n"
295  "%% read in first file, to get the initial positions\n"
296  "f = fopen('" + getName() + "_7.vtu');\n"
297  "% header\n"
298  "line = textscan(f,'%s %s %s %s %s %s %s',1,'Delimiter','\\n');\n"
299  "% number of particles\n"
300  "N = textscan(line{5}{1}(24:end),'%d',1); N=N{1};\n"
301  "% positions\n"
302  "P = textscan(f,'%f %f %f',N);\n"
303  "%scatter(P{1},P{2})\n"
304  "fclose(f);\n"
305  "%% define a new speciesIndex, based on position, to color particles\n"
306  "index = 1000*P{1};\n"
307  "%% read in second file, a write out again with modified index\n"
308  "f = fopen('" + getName() + "_250.vtu');\n"
309  "g = fopen('Particle.vtu','w');\n"
310  "% header\n"
311  "line = textscan(f,'%s',3*N+15,'Delimiter','\\n');\n"
312  "for i=1:length(line{1}), fprintf(g,'%s\\n',line{1}{i}); end\n"
313  "% i/o indSpecies\n"
314  "textscan(f,'%f',N,'Delimiter','\\n');\n"
315  "fprintf(g,'%f\\n',index);\n"
316  "% footer\n"
317  "line = textscan(f,'%s','Delimiter','\\n');\n"
318  "for i=1:length(line{1}), fprintf(g,'%s\\n',line{1}{i}); end\n"
319  "fclose(f);\n"
320  "fclose(g);");
321  }
322 };
323 
324 #endif
@ MULTIPLE_FILES
each time-step will be written into/read from separate files numbered consecutively: name_....
@ NO_FILE
file will not be created/read
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
@ INFO
Vector3f p0
Definition: MatrixBase_all.cpp:2
Vector3f p1
Definition: MatrixBase_all.cpp:2
RowVector3d w
Definition: Matrix_resize_int.cpp:3
float * p
Definition: Tutorial_Map_using.cpp:9
Use AxisymmetricIntersectionOfWalls to Screw Screw::read Screw::read Screw::read define axisymmetric ...
Definition: AxisymmetricIntersectionOfWalls.h:105
std::enable_if<!std::is_pointer< U >::value, U * >::type copyAndAddObject(const U &object)
Creates a copy of a Object and adds it to the BaseHandler.
Definition: BaseHandler.h:360
T * getObject(const unsigned int id)
Gets a pointer to the Object at the specified index in the BaseHandler.
Definition: BaseHandler.h:621
void setAngularVelocity(const Vec3D &angularVelocity)
set the angular velocity of the BaseInteractble.
Definition: BaseInteractable.cc:338
Mdouble getXMin() const
If the length of the problem domain in x-direction is XMax - XMin, then getXMin() returns XMin.
Definition: DPMBase.h:603
Mdouble getXMax() const
If the length of the problem domain in x-direction is XMax - XMin, then getXMax() returns XMax.
Definition: DPMBase.h:610
SpeciesHandler speciesHandler
A handler to that stores the species type i.e. LinearViscoelasticSpecies, etc.
Definition: DPMBase.h:1433
File fStatFile
An instance of class File to handle in- and output into a .fstat file.
Definition: DPMBase.h:1489
void setYMin(Mdouble newYMin)
Sets the value of YMin, the lower bound of the problem domain in the y-direction.
Definition: DPMBase.cc:1025
Mdouble getYMin() const
If the length of the problem domain in y-direction is YMax - YMin, then getYMin() returns YMin.
Definition: DPMBase.h:616
Mdouble getTimeStep() const
Returns the simulation time step.
Definition: DPMBase.cc:1241
const std::string & getName() const
Returns the name of the file. Does not allow to change it though.
Definition: DPMBase.cc:377
Mdouble getTime() const
Returns the current simulation time.
Definition: DPMBase.cc:799
Mdouble getKineticEnergy() const
Returns the global kinetic energy stored in the system.
Definition: DPMBase.cc:1535
WallHandler wallHandler
An object of the class WallHandler. Contains pointers to all the walls created.
Definition: DPMBase.h:1453
void setYMax(Mdouble newYMax)
Sets the value of YMax, the upper bound of the problem domain in the y-direction.
Definition: DPMBase.cc:1182
void setZMin(Mdouble newZMin)
Sets the value of ZMin, the lower bound of the problem domain in the z-direction.
Definition: DPMBase.cc:1049
void setXMax(Mdouble newXMax)
Sets the value of XMax, the upper bound of the problem domain in the x-direction.
Definition: DPMBase.cc:1156
ParticleHandler particleHandler
An object of the class ParticleHandler, contains the pointers to all the particles created.
Definition: DPMBase.h:1443
void setZMax(Mdouble newZMax)
Sets the value of ZMax, the upper bound of the problem domain in the z-direction.
Definition: DPMBase.cc:1208
void setParticlesWriteVTK(bool writeParticlesVTK)
Sets whether particles are written in a VTK file.
Definition: DPMBase.cc:933
RNG random
This is a random generator, often used for setting up the initial conditions etc.....
Definition: DPMBase.h:1438
Mdouble getYMax() const
If the length of the problem domain in y-direction is YMax - YMin, then getYMax() returns XMax.
Definition: DPMBase.h:622
void setXMin(Mdouble newXMin)
Sets the value of XMin, the lower bound of the problem domain in the x-direction.
Definition: DPMBase.cc:1001
Mdouble getTimeMax() const
Returns the maximum simulation duration.
Definition: DPMBase.cc:879
void setGravity(Vec3D newGravity)
Sets a new value for the gravitational acceleration.
Definition: DPMBase.cc:1374
Mdouble getElasticEnergy() const
Returns the global elastic energy within the system.
Definition: DPMBase.cc:1521
Mdouble getZMin() const
If the length of the problem domain in z-direction is ZMax - ZMin, then getZMin() returns ZMin.
Definition: DPMBase.h:628
void setFileType(FileType fileType)
Sets the type of file needed to write into or read from. File::fileType_.
Definition: File.cc:193
A HorizontalBaseScrew is a copy of AxisymmetricIntersectionOfWalls, with an additional,...
Definition: HorizontalBaseScrew.h:18
Definition: HorizontalMixer.h:18
HorizontalMixer(Mdouble particleRadius, Mdouble rotationSpeed, Mdouble timeMin, Mdouble fillHeight)
Constructor, turns off fstat output by default.
Definition: HorizontalMixer.h:57
void introduceParticlesAtWall()
Definition: HorizontalMixer.h:197
void printTime() const override
Displays the current simulation time and the maximum simulation duration.
Definition: HorizontalMixer.h:282
void actionsAfterTimeStep() override
A virtual function which allows to define operations to be executed after time step.
Definition: HorizontalMixer.h:288
void introduceParticlesInDomain(Mdouble polydispersity=1)
Definition: HorizontalMixer.h:242
virtual void setOuterWalls(const ParticleSpecies *s, Mdouble outerBaseRadius, Mdouble screwCenter, Mdouble outerTopCenter, Mdouble outerTopRadius, Mdouble outerTopHeight)
sets other walls that define the outer boundary
Definition: HorizontalMixer.h:116
virtual void setScrewCore(const ParticleSpecies *s, Mdouble screwCenter, Mdouble screwBaseHeight, Mdouble coreTopHeight, Mdouble coreTopRadius, Mdouble coreBottomHeight, Mdouble coreBottomRadius)
sets four walls, leftScrewCore, rightScrewCore, leftScrewBottom, rightScrewBottom
Definition: HorizontalMixer.h:96
void setupInitialConditions() override
This function allows to set the initial conditions for our problem to be solved, by default particle ...
Definition: HorizontalMixer.h:134
void introduceSingleParticle(Vec3D p)
Definition: HorizontalMixer.h:182
std::vector< unsigned > bladeMounts_
The index number of all mounted blades (the blades mounts are numbered 0-11, with the i-th blade moun...
Definition: HorizontalMixer.h:39
Mdouble fillHeight_
Definition: HorizontalMixer.h:43
void setScrewWalls(const ParticleSpecies *s, Mdouble screwCenter, Mdouble screwBaseHeight, Mdouble screwBaseRadius, Mdouble screwTopHeight, Mdouble windingLength, Mdouble minR, Mdouble lowerR, Mdouble diffR, Mdouble thickness)
sets four walls, leftScrew, rightScrew, leftBaseScrew, rightBaseScrew
Definition: HorizontalMixer.h:66
Mdouble timeMin
The time where the screw begins to spin.
Definition: HorizontalMixer.h:35
Mdouble rotationSpeed
The rotation speed of the screw.
Definition: HorizontalMixer.h:31
void writeScript()
Definition: HorizontalMixer.h:292
Mdouble particleRadius
The mean radius of the particles in the feeder.
Definition: HorizontalMixer.h:23
bool haveOuterWalls
Definition: HorizontalMixer.h:49
HorizontalScrew * screw
Pointer to the right screw.
Definition: HorizontalMixer.h:27
This function defines an Archimedes' screw in the z-direction from a (constant) starting point,...
Definition: HorizontalScrew.h:18
void move_time(Mdouble dt)
Rotate the HorizontalScrew for a period dt, so that the offset_ changes with omega_*dt.
Definition: HorizontalScrew.cc:253
A infinite wall fills the half-space {point: (position_-point)*normal_<=0}.
Definition: InfiniteWall.h:27
This adds on the hierarchical grid code for 3D problems.
Definition: Mercury3D.h:16
void clear() override
Empties the whole ParticleHandler by removing all BaseParticle.
Definition: ParticleHandler.cc:971
Definition: ParticleSpecies.h:16
Mdouble getRandomNumber()
This is a random generating routine can be used for initial positions.
Definition: RNG.cc:123
A spherical particle is the most simple particle used in MercuryDPM.
Definition: SphericalParticle.h:16
Definition: Kernel/Math/Vector.h:30
void normalise()
Makes this Vec3D unit length.
Definition: Vector.cc:103
void setWriteVTK(FileType)
Sets whether walls are written into a VTK file.
Definition: WallHandler.cc:445
RealScalar s
Definition: level1_cplx_impl.h:130
void normal(const Vector< double > &x, Vector< double > &normal)
Definition: free_surface_rotation.cc:65
const Mdouble pi
Definition: ExtendedMath.h:23
std::string getPath()
Definition: FileIOHelpers.cc:206
bool writeToFile(const std::string &filename, const std::string &filecontent)
Writes a string to a file.
Definition: FileIOHelpers.cc:29
void start(const unsigned &i)
(Re-)start i-th timer
Definition: oomph_utilities.cc:243