void PeriodicFlow<_Tesselation>::interpolate(Tesselation& Tes, Tesselation& NewTes) { CellHandle oldCell; RTriangulation& Tri = Tes.Triangulation(); for (VCellIterator cellIt=NewTes.cellHandles.begin(); cellIt!=NewTes.cellHandles.end(); cellIt++){ CellHandle& newCell = *cellIt; if (newCell->info().Pcondition || newCell->info().isGhost) continue; CVector center ( 0,0,0 ); if (newCell->info().fictious()==0) for ( int k=0;k<4;k++ ) center= center + 0.25* (Tes.vertex(newCell->vertex(k)->info().id())->point()-CGAL::ORIGIN); else { Real boundPos=0; int coord=0; for ( int k=0;k<4;k++ ) { if (!newCell->vertex (k)->info().isFictious) center= center+0.3333333333*(Tes.vertex(newCell->vertex(k)->info().id())->point()-CGAL::ORIGIN); else { coord=boundary (newCell->vertex(k)->info().id()).coordinate; boundPos=boundary (newCell->vertex(k)->info().id()).p[coord]; } } center=CVector(coord==0?boundPos:center[0],coord==1?boundPos:center[1],coord==2?boundPos:center[2]); } oldCell = Tri.locate(Point(center[0],center[1],center[2])); //FIXME: should use getInfo newCell->info().p() = oldCell->info().shiftedP(); } // Tes.Clear();//Don't reset to avoid segfault when getting pressure in scripts just after interpolation }
/****************************************************************************** * /// Determines whether the given tetrahedral cell is a ghost cell (or an invalid cell). ******************************************************************************/ bool DelaunayTessellation::isGhostCell(CellHandle cell) const { // Find head vertex with the lowest index. const auto& p0 = cell->vertex(0)->point(); int headVertex = p0.index(); if(headVertex == -1) { OVITO_ASSERT(!isValidCell(cell)); return true; } bool isGhost = p0.isGhost(); for(int v = 1; v < 4; v++) { const auto& p = cell->vertex(v)->point(); if(p.index() == -1) { OVITO_ASSERT(!isValidCell(cell)); return true; } if(p.index() < headVertex) { headVertex = p.index(); isGhost = p.isGhost(); } } OVITO_ASSERT(isValidCell(cell)); return isGhost; }
/** * Returns unity normal to contact surface between given cells * (must be neighbors). Direction of normal is from "from" to "to" */ static RealD contactNormal(const CellHandle from, const CellHandle to) { int oppositeVertexIndex = from->index(to); VertexHandle cw = from->vertex(Triangulation::cw(oppositeVertexIndex)); VertexHandle ccw = from->vertex(Triangulation::ccw(oppositeVertexIndex)); RealD along = realD(cw->point()) - realD(ccw->point()); return linal::normalize( linal::perpendicularClockwise(along)); }
static int otherVertexIndex( const CellHandle cell, const VertexHandle a, const VertexHandle b) { /// return index of that vertex of cell, which is not a, b for (int i = 0; i < CELL_SIZE; i++) { VertexHandle d = cell->vertex(i); if ( (d != a) && (d != b) ) { return i; } } THROW_BAD_MESH("Cell contains equal vertices"); }
/** * The point q must lie inside the triangle t. * Find the edge of t which is crossed by the ray qp. * Write the result as a pair of vertices to a,b (or NULLs if not found). * Degenerate cases are not handled. */ static void findCrossedInsideOutFacet( const CellHandle t, const Real2 q, const Real2 p, VertexHandle& a, VertexHandle& b, const real eps) { a = NULL; b = NULL; for (int i = 0; i < CELL_SIZE; i++) { VertexHandle a1 = t->vertex((i + 1) % CELL_SIZE); VertexHandle b1 = t->vertex((i + 2) % CELL_SIZE); if (linal::angleContains(q, realD(a1), realD(b1), p, eps)) { a = a1; b = b1; break; } } }
void Foam::DelaunayMeshTools::drawDelaunayCell ( Ostream& os, const CellHandle& c, label offset ) { // Supply offset as tet number offset *= 4; os << "# cell index: " << label(c->cellIndex()) << " INT_MIN = " << INT_MIN << endl; os << "# circumradius " << mag(c->dual() - topoint(c->vertex(0)->point())) << endl; for (int i = 0; i < 4; i++) { os << "# index / type / procIndex: " << label(c->vertex(i)->index()) << " " << label(c->vertex(i)->type()) << " " << label(c->vertex(i)->procIndex()) << ( CGAL::indexedVertexOps::uninitialised(c->vertex(i)) ? " # This vertex is uninitialised!" : "" ) << endl; meshTools::writeOBJ(os, topoint(c->vertex(i)->point())); } os << "f " << 1 + offset << " " << 3 + offset << " " << 2 + offset << nl << "f " << 2 + offset << " " << 3 + offset << " " << 4 + offset << nl << "f " << 1 + offset << " " << 4 + offset << " " << 3 + offset << nl << "f " << 1 + offset << " " << 2 + offset << " " << 4 + offset << endl; // os << "# cicumcentre " << endl; // meshTools::writeOBJ(os, c->dual()); // os << "l " << 1 + offset << " " << 5 + offset << endl; }
static VertexHandle otherVertex( const CellHandle cell, const VertexHandle a, const VertexHandle b) { /// return that vertex of cell, which is not a, b return cell->vertex(otherVertexIndex(cell, a, b)); }
static CellHandle neighborThrough( const CellHandle cell, const VertexHandle a, const VertexHandle b) { /// return neighbor cell that shares with given cell vertices a, b return cell->neighbor(otherVertexIndex(cell, a, b)); }
/** The center of the given cell */ static RealD center(const CellHandle t) { RealD a = realD(t->vertex(0)); RealD b = realD(t->vertex(1)); RealD c = realD(t->vertex(2)); return (a + b + c) / 3; }
/** Is the cell with a small layer around contains the point */ static bool contains(const CellHandle ch, const RealD& q, const real eps) { RealD a = realD(ch->vertex(0)); RealD b = realD(ch->vertex(1)); RealD c = realD(ch->vertex(2)); return linal::triangleContains(a, b, c, q, eps); }
static real minimalCellHeight(const CellHandle ch) { return linal::minimalHeight( realD(ch->vertex(0)->point()), realD(ch->vertex(1)->point()), realD(ch->vertex(2)->point())); }
void PeriodicFlow<_Tesselation>::computePermeability() { if (debugOut) cout << "----Computing_Permeability (Periodic)------" << endl; RTriangulation& Tri = T[currentTes].Triangulation(); VSolidTot = 0, Vtotalissimo = 0, vPoral = 0, sSolidTot = 0, vTotalPorosity=0, vPoralPorosity=0; CellHandle neighbourCell; double k=0, distance = 0, radius = 0; int surfneg=0; int NEG=0, POS=0, pass=0; Real meanK=0, STDEV=0, meanRadius=0, meanDistance=0; Real infiniteK=1e3; double volume_sub_pore = 0.f; VectorCell& cellHandles= T[currentTes].cellHandles; for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){ CellHandle& cell = *cellIt; Point& p1 = cell->info(); if (cell->info().blocked) { this->setBlocked(cell);} if (cell->info().isGhost) {cerr<<"skipping a ghost"<<endl; continue;} for (int j=0; j<4; j++){ neighbourCell = cell->neighbor(j); Point& p2 = neighbourCell->info(); if (!Tri.is_infinite(neighbourCell) /*&& (neighbour_cell->info().isvisited==ref || computeAllCells)*/) { //compute and store the area of sphere-facet intersections for later use VertexHandle W [3]; for (int kk=0; kk<3; kk++) { W[kk] = cell->vertex(facetVertices[j][kk]); } Sphere& v0 = W[0]->point(); Sphere& v1 = W[1]->point(); Sphere& v2 = W[2]->point(); #ifdef USE_FAST_MATH //FIXME : code not compiling,, do the same as in "else" assert((W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point())>=0 && (W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point())<=1); for (int jj=0;jj<3;jj++) cell->info().facetSphereCrossSections[j][jj]=0.5*W[jj]->point().weight()*Wm3::FastInvCos1((W[permut3[jj][1]]->point()-W[permut3[jj][0]]->point())*(W[permut3[jj][2]]->point()-W[permut3[jj][0]]->point())); #else cell->info().facetSphereCrossSections[j]=CVector( W[0]->info().isFictious ? 0 : 0.5*v0.weight()*acos((v1-v0)*(v2-v0)/sqrt((v1-v0).squared_length()*(v2-v0).squared_length())), W[1]->info().isFictious ? 0 : 0.5*v1.weight()*acos((v0-v1)*(v2-v1)/sqrt((v1-v0).squared_length()*(v2-v1).squared_length())), W[2]->info().isFictious ? 0 : 0.5*v2.weight()*acos((v0-v2)*(v1-v2)/sqrt((v1-v2).squared_length()*(v2-v0).squared_length()))); #endif //FIXME: it should be possible to skip completely blocked cells, currently the problem is it segfault for undefined areas //if (cell->info().blocked) continue;//We don't need permeability for blocked cells, it will be set to zero anyway pass+=1; CVector l = p1 - p2; distance = sqrt(l.squared_length()); if (!rAverage) radius = 2* this->computeHydraulicRadius(cell, j); else radius = (this->computeEffectiveRadius(cell, j)+this->computeEquivalentRadius(cell,j))*0.5; if (radius<0) NEG++; else POS++; if (radius==0) { cout << "INS-INS PROBLEM!!!!!!!" << endl; } Real fluidArea=0; int test=0; if (distance!=0) { if (minPermLength>0 && distanceCorrection) distance=max(minPermLength*radius,distance); const CVector& Surfk = cell->info().facetSurfaces[j]; Real area = sqrt(Surfk.squared_length()); const CVector& crossSections = cell->info().facetSphereCrossSections[j]; Real S0=0; S0=checkSphereFacetOverlap(v0,v1,v2); if (S0==0) S0=checkSphereFacetOverlap(v1,v2,v0); if (S0==0) S0=checkSphereFacetOverlap(v2,v0,v1); //take absolute value, since in rare cases the surface can be negative (overlaping spheres) fluidArea=abs(area-crossSections[0]-crossSections[1]-crossSections[2]+S0); cell->info().facetFluidSurfacesRatio[j]=fluidArea/area; // kFactor<0 means we replace Poiseuille by Darcy localy, yielding a particle size-independent bulk conductivity if (kFactor>0) cell->info().kNorm()[j]= kFactor*(fluidArea * pow(radius,2)) / (8*viscosity*distance); else cell->info().kNorm()[j]= -kFactor * area / distance; meanDistance += distance; meanRadius += radius; meanK += (cell->info().kNorm())[j]; if (k<0 && debugOut) {surfneg+=1; cout<<"__ k<0 __"<<k<<" "<<" fluidArea "<<fluidArea<<" area "<<area<<" "<<crossSections[0]<<" "<<crossSections[1]<<" "<<crossSections[2] <<" "<<W[0]->info().id()<<" "<<W[1]->info().id()<<" "<<W[2]->info().id()<<" "<<p1<<" "<<p2<<" test "<<test<<endl;} } else {cout <<"infinite K2! surfaces will be missing (FIXME)"<<endl; k = infiniteK;} //Will be corrected in the next loop if (!neighbourCell->info().isGhost) (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]= (cell->info().kNorm())[j]; //The following block is correct but not very usefull, since all values are clamped below with MIN and MAX, skip for now // else {//find the real neighbor connected to our cell through periodicity // CellHandle true_neighbour_cell = cellHandles[neighbour_cell->info().baseIndex]; // for (int ii=0;ii<4;ii++) // if (true_neighbour_cell->neighbor(ii)->info().index == cell->info().index){ // (true_neighbour_cell->info().kNorm())[ii]=(cell->info().kNorm())[j]; break; // } // } if(permeabilityMap){ CellHandle c = cell; cell->info().s = cell->info().s + k*distance/fluidArea*this->volumePoreVoronoiFraction (c,j); volume_sub_pore += this->volumePoreVoronoiFraction (c,j); } } } // cell->info().isvisited = !ref; if(permeabilityMap){ cell->info().s = cell->info().s/volume_sub_pore; volume_sub_pore = 0.f; } // } } if (debugOut) cout<<"surfneg est "<<surfneg<<endl; meanK /= pass; meanRadius /= pass; meanDistance /= pass; Real globalK=kFactor*meanDistance*vPoral/(sSolidTot*8.*viscosity);//An approximate value of macroscopic permeability, for clamping local values below if (debugOut) { cout << "PassCompK = " << pass << endl; cout << "meanK = " << meanK << endl; cout << "globalK = " << globalK << endl; cout << "maxKdivKmean*globalK = " << maxKdivKmean*globalK << endl; cout << "minKdivKmean*globalK = " << minKdivKmean*globalK << endl; cout << "meanTubesRadius = " << meanRadius << endl; cout << "meanDistance = " << meanDistance << endl; } pass=0; if (clampKValues) for (VCellIterator cellIt=T[currentTes].cellHandles.begin(); cellIt!=T[currentTes].cellHandles.end(); cellIt++){ CellHandle& cell = *cellIt; for (int j=0; j<4; j++) { neighbourCell = cell->neighbor(j); if (!Tri.is_infinite(neighbourCell) /*&& neighbour_cell->info().isvisited==ref*/) { pass++; (cell->info().kNorm())[j] = max(minKdivKmean*globalK, min((cell->info().kNorm())[j], maxKdivKmean*globalK)); (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]=(cell->info().kNorm())[j]; if (!neighbourCell->info().isGhost) (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]= (cell->info().kNorm())[j]; else {//find the real neighbor connected to our cell through periodicity, as we want exactly the same permeability without rounding errors CellHandle& true_neighbourCell = cellHandles[neighbourCell->info().baseIndex]; for (int ii=0;ii<4;ii++) if (true_neighbourCell->neighbor(ii)->info().index == cell->info().index){ (true_neighbourCell->info().kNorm())[ii]=(cell->info().kNorm())[j]; break; } } } } } if (debugOut) cout << "PassKcorrect = " << pass << endl; if (debugOut) cout << "POS = " << POS << " NEG = " << NEG << " pass = "******"k_stdev.txt" ,std::ios::out); pass=0; FiniteCellsIterator cellEnd = Tri.finite_cells_end(); for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) { for (int j=0; j<4; j++) { neighbourCell = cell->neighbor(j); if (!Tri.is_infinite(neighbourCell) /*&& neighbour_cell->info().isvisited==ref*/) { pass++; STDEV += pow(((cell->info().kNorm())[j]-meanK),2); } } } STDEV = sqrt(STDEV/pass); if (debugOut) cout << "PassSTDEV = " << pass << endl; cout << "STATISTIC K" << endl; double k_min = 0, k_max = meanK + KOptFactor*STDEV; cout << "Kmoy = " << meanK << " Standard Deviation = " << STDEV << endl; cout << "kmin = " << k_min << " kmax = " << k_max << endl; pass=0; for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) { for (int j=0; j<4; j++) { neighbourCell = cell->neighbor(j); if (!Tri.is_infinite(neighbourCell) /*&& neighbour_cell->info().isvisited==ref*/) { pass+=1; if ((cell->info().kNorm())[j]>k_max) { (cell->info().kNorm())[j]=k_max; (neighbourCell->info().kNorm())[Tri.mirror_index(cell, j)]= (cell->info().kNorm())[j]; } k_opt_file << KOptFactor << " " << (cell->info().kNorm())[j] << endl; } } } if (debugOut) cout << "PassKopt = " << pass << endl; } if (debugOut) { FiniteVerticesIterator verticesEnd = Tri.finite_vertices_end(); Real Vgrains = 0; int grains=0; for (FiniteVerticesIterator vIt = Tri.finite_vertices_begin(); vIt != verticesEnd; vIt++) { if (!vIt->info().isFictious && !vIt->info().isGhost) { grains +=1; Vgrains += 1.33333333 * M_PI * pow(vIt->point().weight(),1.5); } } cout<<grains<<"grains - " <<"vTotal = " << vTotal << " Vgrains = " << Vgrains << " vPoral1 = " << (vTotal-Vgrains) << endl; cout << "Vtotalissimo = " << Vtotalissimo/2 << " VSolidTot = " << VSolidTot/2 << " vPoral2 = " << vPoral/2 << " sSolidTot = " << sSolidTot << endl<< endl; if (!rAverage) cout << "------Hydraulic Radius is used for permeability computation------" << endl << endl; else cout << "------Average Radius is used for permeability computation------" << endl << endl; cout << "-----computed_Permeability Periodic-----" << endl; } }