Пример #1
0
void convert_to_xyz(float *P, int n, SHORTIM im)
{
   /////////////////////////////////////////////////////////
   // convert P from (i,j,k) to (x,y,z) coordinates
   float T[16];
   float dum[4]={0.0,0.0,0.0,1.0};

   DIM dim;
   set_dim(dim,im);
   ijk2xyz(T, dim);

   for(int i=0; i<n; i++)
   {
      // note that P is (3 x n)
      dum[0]=P[0*n + i]; 
      dum[1]=P[1*n + i]; 
      dum[2]=P[2*n + i];
      multi(T,4,4,dum,4,1,dum);
      P[0*n + i]=dum[0]; 
      P[1*n + i]=dum[1]; 
      P[2*n + i]=dum[2];
   }
}
Пример #2
0
void FlowAnalysis::addOneParticle(const Real& diameter, const int& mask, const Real& solidRatio, const shared_ptr<Node>& node){
	const auto& dyn(node->getData<DemData>());
	Real V(pow(cellSize,3));
	// all things saved are actually densities over the volume of a single cell
	Vector3r momentum_V(dyn.vel*dyn.mass/V);
	Real Ek_V(dyn.getEk_any(node,/*trans*/true,/*rot*/true,scene)/V);

	size_t fraction=0; // default is the only fraction, which is always present
	// by diameter
	if(!dLim.empty()){
		fraction=std::lower_bound(dLim.begin(),dLim.end(),diameter)-dLim.begin();
	}
	// by particle mask
	if(!masks.empty()){
		bool found=false;
		for(size_t i=0; i<masks.size(); i++){
			if(mask&masks[i]){
				if(found){
					LOG_WARN("Particle with mask "<<mask<<" matching both masks["<<fraction<<"]="<<masks[i]<<" and masks["<<i<<"]="<<masks[i]<<"; only first match used.");
				} else {
					found=true; 
					fraction=i;
				}
			}
		}
		if(!found){ LOG_WARN("Particle not matching any mask, ignoring; set FlowAnalysis.mask to filter those out upfront."); return; }
	}
	// loop over neighboring grid points, add relevant data with weights.
	Vector3i ijk=xyz2ijk(node->pos);
	// it does not matter here if ijk are inside the grid;
	// the enlargedBox test in addCurrentData already pruned cases too far away.
	// The rest is checked in the loop below with validIjkRange;
	// that ensure that even points just touching the grid from outside are accounted for correctly.
	Vector3r n=(node->pos-ijk2xyz(ijk))/cellSize; // normalized coordinate in the cube (0..1)x(0..1)x(0..1)
	if(n.minCoeff()<0 || n.maxCoeff()>1){
		LOG_ERROR("n="<<n.transpose()<<", ijk="<<ijk.transpose()<<", pos="<<node->pos.transpose()<<", ijk2xyz="<<ijk2xyz(ijk));
	}
	// trilinear interpolation
	const Real& x(n[0]); const Real& y(n[1]); const Real& z(n[2]);
	Real X(1-x), Y(1-y), Z(1-z);
	const int& i(ijk[0]); const int& j(ijk[1]); const int& k(ijk[2]);
	int I(i+1), J(j+1), K(k+1);
	// traverse all affected points
	Real weights[]={
		X*Y*Z,x*Y*Z,x*y*Z,X*y*Z,
		X*Y*z,x*Y*z,x*y*z,X*y*z
	};
	// the sum should be equal to one
	assert(abs(weights[0]+weights[1]+weights[2]+weights[3]+weights[4]+weights[5]+weights[6]+weights[7]-1) < 1e-5);
	Vector3i pts[]={
		Vector3i(i,j,k),Vector3i(I,j,k),Vector3i(I,J,k),Vector3i(i,J,k),
		Vector3i(i,j,K),Vector3i(I,j,K),Vector3i(I,J,K),Vector3i(i,J,K)
	};
	Eigen::AlignedBox<int,3> validIjkRange(Vector3i::Zero(),Vector3i(data.shape()[1]-1,data.shape()[2]-1,data.shape()[3]-1));
	for(int ii=0; ii<8; ii++){
		// make sure we are within bounds here
		if(!validIjkRange.contains(pts[ii])) continue;
		// subarray where we write the actual data for this point
		auto pt(data[fraction][pts[ii][0]][pts[ii][1]][pts[ii][2]]); 
		const Real& w(weights[ii]); /* ensured by validIjkRange */ assert(w>0);
		pt[PT_FLOW_X]+=w*momentum_V[0];
		pt[PT_FLOW_Y]+=w*momentum_V[1];
		pt[PT_FLOW_Z]+=w*momentum_V[2];
		pt[PT_VEL_X]+=w*dyn.vel[0];
		pt[PT_VEL_Y]+=w*dyn.vel[1];
		pt[PT_VEL_Z]+=w*dyn.vel[2];
		pt[PT_EK]+=w*Ek_V;
		pt[PT_SUM_WEIGHT]+=w*1.;
		pt[PT_SUM_DIAM]+=w*diameter; // the average is computed later, dividing by PT_SUM_WEIGHT
		if(!isnan(solidRatio)) pt[PT_SUM_SOLID_RATIO]+=w*solidRatio;
		assert(!isnan(pt[PT_FLOW_X]) && !isnan(pt[PT_FLOW_Y]) && !isnan(pt[PT_FLOW_Z]) && !isnan(pt[PT_EK]) && !isnan(pt[PT_SUM_WEIGHT]));
	}
};