~ubuntu-branches/ubuntu/wily/yade/wily

« back to all changes in this revision

Viewing changes to pkg/dem/SpherePack.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitry Shachnev
  • Date: 2014-11-14 12:54:52 UTC
  • mfrom: (20.1.23 sid)
  • Revision ID: package-import@ubuntu.com-20141114125452-t16anreumu4ybg2s
Tags: 1.12.0-2ubuntu1
Add allow-stderr restriction to autopkgtest, to silence a warning
printed by new matplotlib.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// © 2009 Václav Šmilauer <eudoxos@arcig.cz>
2
2
 
3
 
#include<yade/pkg/dem/SpherePack.hpp>
 
3
#include<pkg/dem/SpherePack.hpp>
4
4
 
5
 
#include<yade/core/Omega.hpp>
6
 
#include<yade/core/Scene.hpp>
7
 
#include<yade/pkg/common/Sphere.hpp>
8
 
#include<yade/pkg/dem/Shop.hpp>
 
5
#include<core/Omega.hpp>
 
6
#include<core/Scene.hpp>
 
7
#include<pkg/common/Sphere.hpp>
 
8
#include<pkg/dem/Shop.hpp>
9
9
 
10
10
#include <boost/random/linear_congruential.hpp>
11
11
#include <boost/random/uniform_real.hpp>
12
12
#include <boost/random/variate_generator.hpp>
13
13
 
14
 
#include<yade/core/Timing.hpp>
 
14
#include<core/Timing.hpp>
15
15
 
16
16
// not a serializable in the sense of YADE_PLUGIN
17
17
 
272
272
        return py::make_tuple(edges,cumm);
273
273
}
274
274
 
275
 
/* possible enhacement: proportions parameter, so that the domain is not cube, but box with sides having given proportions */
 
275
 
276
276
long SpherePack::particleSD2(const vector<Real>& radii, const vector<Real>& passing, int numSph, bool periodic, Real cloudPorosity, int seed){
277
 
        typedef Eigen::Matrix<Real,Eigen::Dynamic,Eigen::Dynamic> MatrixXr;
278
 
        typedef Eigen::Matrix<Real,Eigen::Dynamic,1> VectorXr;
279
 
        
280
 
        int dim=radii.size()+1;
281
 
        if(passing.size()!=radii.size()) throw std::invalid_argument("SpherePack.particleSD2: radii and passing must have the same length.");
282
 
        MatrixXr M=MatrixXr::Zero(dim,dim);
283
 
        VectorXr rhs=VectorXr::Zero(dim);
284
 
        /*
285
 
        
286
 
        We know percentages for each fraction (Δpi) and their radii (ri), and want to find
287
 
        the number of sphere for each fraction Ni and total solid volume Vs. For each fraction,
288
 
        we know that the volume is equal to Ni*(4/3*πri³), which must be equal to Vs*Δpi (Δpi is
289
 
        relative solid volume of the i-th fraction).
290
 
 
291
 
        The last equation says that total number of particles (sum of fractions) is equal to N,
292
 
        which is the total number of particles requested by the user.
293
 
 
294
 
           N1     N2     N3    Vs       rhs
295
 
 
296
 
        4/3πr₁³   0      0     -Δp₁   | 0
297
 
          0     4/3πr₂³  0     -Δp₂   | 0
298
 
          0       0    4/3πr₃³ -Δp₃   | 0
299
 
     1       1      1      0     | N
300
 
 
301
 
        */
302
 
        for(int i=0; i<dim-1; i++){
303
 
                M(i,i)=(4/3.)*Mathr::PI*pow(radii[i],3);
304
 
                M(i,dim-1)=-(passing[i]-(i>0?passing[i-1]:0))/100.;
305
 
                M(dim-1,i)=1;
306
 
        }
307
 
        rhs[dim-1]=numSph;
308
 
        // NumsVs=M^-1*rhs: number of spheres and volume of solids
309
 
        VectorXr NumsVs(dim); NumsVs=M.inverse()*rhs;
310
 
        Real Vs=NumsVs[dim-1]; // total volume of solids
311
 
        Real Vtot=Vs/(1-cloudPorosity); // total volume of cell containing the packing
312
 
        Vector3r cellSize=pow(Vtot,1/3.)*Vector3r().Ones(); // for now, assume always cubic sample
313
 
        Real rMean=pow(Vs/(numSph*(4/3.)*Mathr::PI),1/3.); // make rMean such that particleSD will compute the right Vs (called a bit confusingly Vtot anyway) inversely
314
 
        // cerr<<"Vs="<<Vs<<", Vtot="<<Vtot<<", rMean="<<rMean<<endl;
315
 
        // cerr<<"cellSize="<<cellSize<<", rMean="<<rMean<<", numSph="<<numSph<<endl;
316
 
        return particleSD(Vector3r::Zero(),cellSize,rMean,periodic,"",numSph,radii,passing,false);
 
277
        //deprecated (https://bugs.launchpad.net/yade/+bug/1024443)
 
278
        LOG_ERROR("particleSD2() has been removed. Please use makeCloud() instead.");
 
279
        return 1;
317
280
};
318
281
 
319
 
// TODO: header, python wrapper, default params
320
 
 
321
282
// Discrete particle size distribution
322
283
long SpherePack::particleSD(Vector3r mn, Vector3r mx, Real rMean, bool periodic, string name, int numSph, const vector<Real>& radii, const vector<Real>& passing, bool passingIsNotPercentageButCount, int seed){
323
 
        vector<Real> numbers;
324
 
        if(!passingIsNotPercentageButCount){
325
 
                Real Vtot=numSph*4./3.*Mathr::PI*pow(rMean,3.); // total volume of the packing (computed with rMean)
326
 
                
327
 
                // calculate number of spheres necessary per each radius to match the wanted psd
328
 
                // passing has to contain increasing values
329
 
                for (size_t i=0; i<radii.size(); i++){
330
 
                        Real volS=4./3.*Mathr::PI*pow(radii[i],3.);
331
 
                        if (i==0) {numbers.push_back(passing[i]/100.*Vtot/volS);}
332
 
                        else {numbers.push_back((passing[i]-passing[i-1])/100.*Vtot/volS);} // 
333
 
                        cout<<"fraction #"<<i<<" ("<<passing[i]<<"%, r="<<radii[i]<<"): "<<numbers[i]<<" spheres, fraction/cloud volumes "<<volS<<"/"<<Vtot<<endl;
334
 
                }
335
 
        } else {
336
 
                FOREACH(Real p, passing) numbers.push_back(p);
337
 
        }
338
 
 
339
 
        static boost::minstd_rand randGen(seed!=0?seed:(int)TimingInfo::getNow(true));
340
 
        static boost::variate_generator<boost::minstd_rand&, boost::uniform_real<> > rnd(randGen, boost::uniform_real<>(0,1));
341
 
 
342
 
        const int maxTry=1000;
343
 
        Vector3r size=mx-mn;
344
 
        if(periodic)(cellSize=size);
345
 
        for (int ii=(int)radii.size()-1; ii>=0; ii--){
346
 
                Real r=radii[ii]; // select radius
347
 
                for(int i=0; i<numbers[ii]; i++) { // place as many spheres as required by the psd for the selected radius into the free spot
348
 
                        int t;
349
 
                        for(t=0; t<maxTry; ++t){
350
 
                                Vector3r c;
351
 
                                if(!periodic) { for(int axis=0; axis<3; axis++) c[axis]=mn[axis]+r+(size[axis]-2*r)*rnd(); }
352
 
                                else { for(int axis=0; axis<3; axis++) c[axis]=mn[axis]+size[axis]*rnd(); }
353
 
                                size_t packSize=pack.size(); bool overlap=false;
354
 
                                if(!periodic){
355
 
                                        for(size_t j=0; j<packSize; j++){ if(pow(pack[j].r+r,2) >= (pack[j].c-c).squaredNorm()) { overlap=true; break; } }
356
 
                                } else {
357
 
                                        for(size_t j=0; j<packSize; j++){
358
 
                                                Vector3r dr;
359
 
                                                for(int axis=0; axis<3; axis++) dr[axis]=min(cellWrapRel(c[axis],pack[j].c[axis],pack[j].c[axis]+size[axis]),cellWrapRel(pack[j].c[axis],c[axis],c[axis]+size[axis]));
360
 
                                                if(pow(pack[j].r+r,2)>= dr.squaredNorm()){ overlap=true; break; }
361
 
                                        }
362
 
                                }
363
 
                                if(!overlap) { pack.push_back(Sph(c,r)); break; }
364
 
                        }
365
 
                        if (t==maxTry) {
366
 
                                if(numbers[ii]>0) LOG_WARN("Exceeded "<<maxTry<<" tries to insert non-overlapping sphere to packing. Only "<<i<<" spheres were added, although you requested "<<numbers[ii]<<" with radius "<<radii[ii]);
367
 
                                return i;
368
 
                        }
369
 
                }
370
 
        }
371
 
        return pack.size();
 
284
        //deprecated (https://bugs.launchpad.net/yade/+bug/1024443)
 
285
        LOG_ERROR("particleSD() has been removed. Please use makeCloud() instead.");
 
286
        return 1;
372
287
}
373
288
 
374
 
// 2d function
375
289
long SpherePack::particleSD_2d(Vector2r mn, Vector2r mx, Real rMean, bool periodic, string name, int numSph, const vector<Real>& radii, const vector<Real>& passing, bool passingIsNotPercentageButCount, int seed){
376
 
        vector<Real> numbers;
377
 
        if(!passingIsNotPercentageButCount){
378
 
                Real Vtot=numSph*4./3.*Mathr::PI*pow(rMean,3.); // total volume of the packing (computed with rMean)
379
 
                
380
 
                // calculate number of spheres necessary per each radius to match the wanted psd
381
 
                // passing has to contain increasing values
382
 
                for (size_t i=0; i<radii.size(); i++){
383
 
                        Real volS=4./3.*Mathr::PI*pow(radii[i],3.);
384
 
                        if (i==0) {numbers.push_back(passing[i]/100.*Vtot/volS);}
385
 
                        else {numbers.push_back((passing[i]-passing[i-1])/100.*Vtot/volS);} // 
386
 
                        cout<<"fraction #"<<i<<" ("<<passing[i]<<"%, r="<<radii[i]<<"): "<<numbers[i]<<" spheres, fraction/cloud volumes "<<volS<<"/"<<Vtot<<endl;
387
 
                }
388
 
        } else {
389
 
                FOREACH(Real p, passing) numbers.push_back(p);
390
 
        }
391
 
 
392
 
        static boost::minstd_rand randGen(seed!=0?seed:(int)TimingInfo::getNow(true));
393
 
        static boost::variate_generator<boost::minstd_rand&, boost::uniform_real<> > rnd(randGen, boost::uniform_real<>(0,1));
394
 
 
395
 
        const int maxTry=1000;
396
 
        Vector2r size=mx-mn; 
397
 
        //if(periodic)(cellSize=size); in this case, it must be defined in py script as cell needs the third dimension
398
 
        for (int ii=(int)radii.size()-1; ii>=0; ii--){
399
 
                Real r=radii[ii]; // select radius
400
 
                for(int i=0; i<numbers[ii]; i++) { // place as many spheres as required by the psd for the selected radius into the free spot
401
 
                        int t;
402
 
                        for(t=0; t<maxTry; ++t){
403
 
                                Vector3r c;
404
 
                                if(!periodic) { for(int axis=0; axis<2; axis++) c[axis]=mn[axis]+r+(size[axis]-2*r)*rnd(); }
405
 
                                else { for(int axis=0; axis<2; axis++) c[axis]=mn[axis]+size[axis]*rnd(); }
406
 
                                size_t packSize=pack.size(); bool overlap=false;
407
 
                                if(!periodic){
408
 
                                        for(size_t j=0; j<packSize; j++){ if(pow(pack[j].r+r,2) >= (pack[j].c-c).squaredNorm()) { overlap=true; break; } }
409
 
                                } else {
410
 
                                        for(size_t j=0; j<packSize; j++){
411
 
                                                Vector3r dr=Vector3r::Zero();
412
 
                                                for(int axis=0; axis<2; axis++) dr[axis]=min(cellWrapRel(c[axis],pack[j].c[axis],pack[j].c[axis]+size[axis]),cellWrapRel(pack[j].c[axis],c[axis],c[axis]+size[axis]));
413
 
                                                if(pow(pack[j].r+r,2)>= dr.squaredNorm()){ overlap=true; break; }
414
 
                                        }
415
 
                                }
416
 
                                if(!overlap) { pack.push_back(Sph(c,r)); break; }
417
 
                        }
418
 
                        if (t==maxTry) {
419
 
                                if(numbers[ii]>0) LOG_WARN("Exceeded "<<maxTry<<" tries to insert non-overlapping sphere to packing. Only "<<i<<" spheres were added, although you requested "<<numbers[ii]<<" with radius "<<radii[ii]);
420
 
                                return i;
421
 
                        }
422
 
                }
423
 
        }
424
 
        return pack.size();
 
290
        //deprecated (https://bugs.launchpad.net/yade/+bug/1024443)
 
291
        LOG_ERROR("particleSD_2d() has been removed. Please use makeCloud() instead.");
 
292
        return 1;
425
293
}
426
294
 
427
295
long SpherePack::makeClumpCloud(const Vector3r& mn, const Vector3r& mx, const vector<shared_ptr<SpherePack> >& _clumps, bool periodic, int num, int seed){