1 // ============================================================================= 2 // PROJECT CHRONO - http://projectchrono.org 3 // 4 // Copyright (c) 2014 projectchrono.org 5 // All rights reserved. 6 // 7 // Use of this source code is governed by a BSD-style license that can be found 8 // in the LICENSE file at the top level of the distribution and at 9 // http://projectchrono.org/license-chrono.txt. 10 // 11 // ============================================================================= 12 // Authors: Radu Serban 13 // ============================================================================= 14 // 15 // Utility functions to facilitate the creation of mixtures of granular material 16 // using different samplers for initial positions, geometry shapes, material 17 // properties, etc. 18 // 19 // ============================================================================= 20 21 #ifndef CH_UTILS_GENERATORS_H 22 #define CH_UTILS_GENERATORS_H 23 24 #include <cmath> 25 #include <memory> 26 #include <random> 27 #include <string> 28 #include <utility> 29 #include <vector> 30 31 #include "chrono/core/ChApiCE.h" 32 #include "chrono/core/ChQuaternion.h" 33 #include "chrono/core/ChVector.h" 34 35 #include "chrono/physics/ChBody.h" 36 #include "chrono/physics/ChMaterialSurfaceNSC.h" 37 #include "chrono/physics/ChMaterialSurfaceSMC.h" 38 #include "chrono/physics/ChSystem.h" 39 #include "chrono/physics/ChSystemSMC.h" 40 41 #include "chrono/utils/ChUtilsCreators.h" 42 #include "chrono/utils/ChUtilsGeometry.h" 43 #include "chrono/utils/ChUtilsInputOutput.h" 44 #include "chrono/utils/ChUtilsSamplers.h" 45 46 namespace chrono { 47 namespace utils { 48 49 /// @addtogroup chrono_utils 50 /// @{ 51 52 /// Enumeration of various geometric shapes available for mixtures. 53 enum class MixtureType { SPHERE, ELLIPSOID, BOX, CYLINDER, CONE, CAPSULE, BISPHERE, ROUNDEDCYLINDER }; 54 55 // Forward declarations 56 class Generator; 57 class MixtureIngredient; 58 59 /// Encapsulation of an ingredient of one of the supported types in a mixture. 60 /// Such an object defines size, mass properties and material properties for, all of which can be constant for all 61 /// mixture components of this type or else obtained from associated truncated normal distributions. In addition, a 62 /// mixture ingredient defines the ratio of this particular type in the containing mixture. 63 class ChApi MixtureIngredient { 64 public: 65 MixtureIngredient(Generator* generator, MixtureType type, double ratio); 66 ~MixtureIngredient(); 67 68 void setDefaultMaterial(std::shared_ptr<ChMaterialSurface> mat); 69 void setDefaultDensity(double density); 70 void setDefaultSize(const ChVector<>& size); 71 72 void setDistributionFriction(float friction_mean, float friction_stddev, float friction_min, float friction_max); 73 void setDistributionCohesion(float cohesion_mean, float cohesion_stddev, float cohesion_min, float cohesion_max); 74 void setDistributionYoung(float young_mean, float young_stddev, float young_min, float young_max); 75 void setDistributionPoisson(float poisson_mean, float poisson_stddev, float poisson_min, float poisson_max); 76 void setDistributionRestitution(float restitution_mean, 77 float restitution_stddev, 78 float restitution_min, 79 float restitution_max); 80 void setDistributionDensity(double density_mean, double density_stddev, double density_min, double density_max); 81 void setDistributionSize(double size_mean, 82 double size_stddev, 83 const ChVector<>& size_min, 84 const ChVector<>& size_max); 85 86 /// Class to be used as a callback interface for some user-defined action to be taken each 87 /// time the generator creates and adds a body based on this mixture ingredient to the system. 88 class ChApi AddBodyCallback { 89 public: ~AddBodyCallback()90 virtual ~AddBodyCallback() {} 91 92 /// Callback used to process bodies as they are created and added to the system. 93 virtual void OnAddBody(std::shared_ptr<ChBody> body) = 0; 94 }; 95 96 /// Specify a callback object to be used each time a body is generated using this 97 /// mixture ingredient specification. RegisterAddBodyCallback(std::shared_ptr<AddBodyCallback> callback)98 void RegisterAddBodyCallback(std::shared_ptr<AddBodyCallback> callback) { add_body_callback = callback; } 99 100 private: 101 void freeMaterialDist(); 102 ChVector<> getSize(); 103 double getDensity(); 104 void calcGeometricProps(const ChVector<>& size, double& volume, ChVector<>& gyration); 105 double calcMinSeparation(); 106 107 void setMaterialProperties(std::shared_ptr<ChMaterialSurfaceNSC> mat); 108 void setMaterialProperties(std::shared_ptr<ChMaterialSurfaceSMC> mat); 109 110 Generator* m_generator; 111 112 MixtureType m_type; 113 double m_ratio; 114 double m_cumRatio; 115 116 std::shared_ptr<ChMaterialSurfaceNSC> m_defMaterialNSC; 117 std::shared_ptr<ChMaterialSurfaceSMC> m_defMaterialSMC; 118 119 float m_minFriction, m_maxFriction; 120 float m_minCohesion, m_maxCohesion; 121 float m_minYoung, m_maxYoung; 122 float m_minPoisson, m_maxPoisson; 123 float m_minRestitution, m_maxRestitution; 124 std::normal_distribution<float>* m_frictionDist; 125 std::normal_distribution<float>* m_cohesionDist; 126 std::normal_distribution<float>* m_youngDist; 127 std::normal_distribution<float>* m_poissonDist; 128 std::normal_distribution<float>* m_restitutionDist; 129 130 double m_defDensity; 131 double m_minDensity, m_maxDensity; 132 std::normal_distribution<>* m_densityDist; 133 134 ChVector<> m_defSize; 135 ChVector<> m_minSize, m_maxSize; 136 std::normal_distribution<>* m_sizeDist; 137 138 std::shared_ptr<AddBodyCallback> add_body_callback; 139 140 friend class Generator; 141 }; 142 143 /// Provides functionality for generating sets of bodies with positions drawn from a specified sampler and various 144 /// mixture properties. Bodies can be generated in different bounding volumes (boxes or cylinders) which can be 145 /// degenerate (to a rectangle or circle, repsectively). 146 class ChApi Generator { 147 public: 148 typedef Types<double>::PointVector PointVector; 149 150 Generator(ChSystem* system); 151 ~Generator(); 152 153 /// Add a new mixture ingredient of the specified type and in the given ratio (note that the ratios are normalized 154 /// before creating bodies). 155 std::shared_ptr<MixtureIngredient> AddMixtureIngredient(MixtureType type, double ratio); 156 157 /// Get/Set the identifier that will be assigned to the next body. 158 /// Identifiers are incremented for successively created bodies. getBodyIdentifier()159 int getBodyIdentifier() const { return m_crtBodyId; } setBodyIdentifier(int id)160 void setBodyIdentifier(int id) { m_crtBodyId = id; } 161 162 /// Create bodies, according to the current mixture setup, with initial positions given by the specified sampler in 163 /// the box domain specified by 'pos' and 'hdims'. Optionally, a constant initial linear velocity can be set for all 164 /// created bodies. 165 void CreateObjectsBox(Sampler<double>& sampler, 166 const ChVector<>& pos, 167 const ChVector<>& hdims, 168 const ChVector<>& vel = ChVector<>(0, 0, 0)); 169 170 /// Create bodies, according to the current mixture setup, with initial positions on a uniform grid with given 171 /// separations (in x,y,z directions) in the box domain specified by 'pos' and 'hdims'. Optionally, a constant 172 /// initial linear velocity can be set for all created bodies. 173 void CreateObjectsBox(const ChVector<>& dist, 174 const ChVector<>& pos, 175 const ChVector<>& hdims, 176 const ChVector<>& vel = ChVector<>(0, 0, 0)); 177 178 /// Create bodies, according to the current mixture setup, with initial positions given by the specified sampler in 179 /// the X-aligned cylinder domain specified by 'pos', 'radius' and 'halfHeight'. Optionally, a constant initial 180 /// linear velocity can be set for all created bodies. 181 void CreateObjectsCylinderX(Sampler<double>& sampler, 182 const ChVector<>& pos, 183 float radius, 184 float halfHeight, 185 const ChVector<>& vel = ChVector<>(0, 0, 0)); 186 187 /// Create bodies, according to the current mixture setup, with initial positions given by the specified sampler in 188 /// the Y-aligned cylinder domain specified by 'pos', 'radius' and 'halfHeight'. Optionally, a constant initial 189 /// linear velocity can be set for all created bodies. 190 void CreateObjectsCylinderY(Sampler<double>& sampler, 191 const ChVector<>& pos, 192 float radius, 193 float halfHeight, 194 const ChVector<>& vel = ChVector<>(0, 0, 0)); 195 196 /// Create bodies, according to the current mixture setup, with initial positions given by the specified sampler in 197 /// the Z-aligned cylinder domain specified by 'pos', 'radius' and 'halfHeight'. Optionally, a constant initial 198 /// linear velocity can be set for all created bodies. 199 void CreateObjectsCylinderZ(Sampler<double>& sampler, 200 const ChVector<>& pos, 201 float radius, 202 float halfHeight, 203 const ChVector<>& vel = ChVector<>(0, 0, 0)); 204 205 /// Create bodies, according to the current mixture setup, with initial positions given by the specified sampler in 206 /// the spherical domain specified by 'pos' and 'radius'. Optionally, a constant initial linear velocity can be set 207 /// for all created bodies. 208 void CreateObjectsSphere(Sampler<double>& sampler, 209 const ChVector<>& pos, 210 float radius, 211 const ChVector<>& vel = ChVector<>(0, 0, 0)); 212 213 /// Class to be used as a callback interface for user-defined filtering of initial positions. 214 class ChApi CreateObjectsCallback { 215 public: ~CreateObjectsCallback()216 virtual ~CreateObjectsCallback() {} 217 218 /// Callback used to process the initial position points generated by the underlying sampler. 219 /// The provided vector of boolean flags is set to all 'true'. Set the i-th entry to 'false' 220 /// if a body should not be created at the i-th position. 221 virtual void OnCreateObjects( 222 const PointVectorD& points, ///< vector of positions generated by the sampler 223 std::vector<bool>& flags ///< change to 'false' for positions where a body should not be generated 224 ) = 0; 225 }; 226 227 /// Specify a callback object to be used before creating the bodies. The OnCreateObjects() method of the 228 /// provided callback object will be called before object creation, allowing the user to filter the points 229 /// at which bodies will be initialized. RegisterCreateObjectsCallback(std::shared_ptr<CreateObjectsCallback> callback)230 void RegisterCreateObjectsCallback(std::shared_ptr<CreateObjectsCallback> callback) { m_callback = callback; } 231 232 /// Write information about the bodies created so far to the specified file (CSV format). 233 void writeObjectInfo(const std::string& filename); 234 getTotalNumBodies()235 unsigned int getTotalNumBodies() const { return m_totalNumBodies; } getTotalMass()236 double getTotalMass() const { return m_totalMass; } getTotalVolume()237 double getTotalVolume() const { return m_totalVolume; } 238 239 private: 240 struct BodyInfo { BodyInfoBodyInfo241 BodyInfo(MixtureType t, double density, const ChVector<>& size, const std::shared_ptr<ChBody>& b) 242 : m_type(t), m_density(density), m_size(size), m_body(b) {} 243 MixtureType m_type; 244 double m_density; 245 ChVector<> m_size; 246 std::shared_ptr<ChBody> m_body; 247 }; 248 249 void normalizeMixture(); 250 int selectIngredient(); 251 double calcMinSeparation(double sep); 252 ChVector<> calcMinSeparation(const ChVector<>& sep); 253 void createObjects(const PointVector& points, const ChVector<>& vel); 254 255 ChSystem* m_system; 256 257 std::uniform_real_distribution<> m_mixDist; 258 259 std::vector<std::shared_ptr<MixtureIngredient>> m_mixture; 260 std::vector<BodyInfo> m_bodies; 261 unsigned int m_totalNumBodies; 262 double m_totalMass; 263 double m_totalVolume; 264 265 std::shared_ptr<CreateObjectsCallback> m_callback; 266 267 int m_crtBodyId; 268 269 friend class MixtureIngredient; 270 }; 271 272 /// @} chrono_utils 273 274 } // end namespace utils 275 } // end namespace chrono 276 277 #endif 278