void GeomData::transferCijData(pMesh theMesh){ dblarray Cij(3,.0); double cij[3], norm; int ndom = getNumDomains(); for (int i=0; i<ndom; i++){ int dom = domainList[i]; int row = 0; EIter eit = M_edgeIter(theMesh); while ( pEdge edge = EIter_next(eit) ){ if ( edgeBelongToDomain(edge,dom) ){ getCij(edge,dom,Cij); norm = getCij_norm(edge,dom); cij[0] = Cij[0]; cij[1] = Cij[1]; cij[2] = Cij[2]; setCij(i,row,cij); setCij_norm(i,row,norm); row++; } } EIter_delete(eit); } }
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { double *C ; double *XYZva, *ind_tra, *XYZvb, *ind_trb, weight, defl ; unsigned int mXYZva, nXYZva, minda, ninda ; unsigned int mXYZvb, nXYZvb, mindb, nindb ; if (nrhs!=6) { mexErrMsgTxt("6 Inputs : XYZva, ind_tra, XYZvb, ind_trb, weight, defl") ; } else if (nlhs>1) { mexErrMsgTxt("1 Outputs : Cij_cog") ; } mXYZva=mxGetM(prhs[0]) ; nXYZva=mxGetN(prhs[0]) ; if (!mxIsNumeric(prhs[0]) || mxIsComplex(prhs[0]) || mxIsSparse(prhs[0]) || (nXYZva!=3)) { mexErrMsgTxt("XYZva must be a matrix : Nverta x 3") ; } minda=mxGetM(prhs[1]) ; ninda=mxGetN(prhs[1]) ; if (!mxIsNumeric(prhs[1]) || mxIsComplex(prhs[1]) || mxIsSparse(prhs[1]) || !(ninda==3)) { mexErrMsgTxt("ind_tra must be a matrix : Ntria x 3") ; } mXYZvb=mxGetM(prhs[2]) ; nXYZvb=mxGetN(prhs[2]) ; if (!mxIsNumeric(prhs[2]) || mxIsComplex(prhs[2]) || mxIsSparse(prhs[2]) || (nXYZvb!=3)) { mexErrMsgTxt("XYZvb must be a matrix : Nvertb") ; } mindb=mxGetM(prhs[3]) ; nindb=mxGetN(prhs[3]) ; if (!mxIsNumeric(prhs[3]) || mxIsComplex(prhs[3]) || mxIsSparse(prhs[3]) || !(nindb==3)) { mexErrMsgTxt("ind_trb must be a matrix : Ntrib x 3") ; } if (!mxIsNumeric(prhs[4]) || mxIsComplex(prhs[4]) || mxIsSparse(prhs[4]) || !mxIsDouble(prhs[4]) || mxGetN(prhs[4])*mxGetM(prhs[4])!=1 ) { mexErrMsgTxt("weight must be a scalar") ; } if (!mxIsNumeric(prhs[5]) || mxIsComplex(prhs[5]) || mxIsSparse(prhs[5]) || !mxIsDouble(prhs[5]) || mxGetN(prhs[5])*mxGetM(prhs[5])!=1 ) { mexErrMsgTxt("defl must be a scalar") ; } plhs[0]=mxCreateDoubleMatrix(minda,mindb,mxREAL) ; C=mxGetPr(plhs[0]) ; XYZva=mxGetPr(prhs[0]) ; ind_tra=mxGetPr(prhs[1]) ; XYZvb=mxGetPr(prhs[2]) ; ind_trb=mxGetPr(prhs[3]) ; weight = mxGetScalar(prhs[4]) ; defl = mxGetScalar(prhs[5]) ; Cij(C,XYZva,mXYZva,ind_tra,minda, XYZvb,mXYZvb,ind_trb,mindb,weight,defl); mxSetPr(plhs[0],C) ; }
// calculates: Cij, Dij and nodal volume int EBFV1_preprocessor_2D(pMesh theMesh, void *pData, int &ndom){ #ifdef TRACKING_PROGRAM_STEPS cout << "TRACKING_PROGRAM_STEPS: EBFV1_preprocessor_2D\tIN\n"; #endif GeomData *pGCData = (GeomData*)pData; pGCData->setMeshDim(theMesh->getDim()); theMesh->modifyState(2,1); // create edge data structure theMesh->modifyState(0,2); // create adjacency around nodes theMesh->modifyState(1,2); // create faces around edge //cout << "Mesh dimension: 2D\n"; int i,j,flag,dom; double edgeCenter[3], I[3], J[3]; std::vector<double> Cij(3), Dij(3); pEntity edge, face, node; /// initialize coefficients initializeCoefficients(theMesh,pGCData); std::set<int> setOfDomain; // for each face, calculate all data needed and attach them to the its edges FIter fit = M_faceIter(theMesh); while ( (face = FIter_next(fit)) ){ // look up only for leave elements (without children) if ( !theMesh->getRefinementDepth(face) ){ dom = EN_getFlag(face); char dom_string[256]; sprintf(dom_string,"dom_str_%d",dom); if (!dom){ throw Exception(__LINE__,__FILE__,"dom = 0\n"); } setOfDomain.insert(dom); // store every new domain double faceCenter[3] = {.0, .0, .0}; getFCenter(face,faceCenter); // loop over all three face's edges to calculate Cij and Dij for (i=0; i<3; i++){ edge = F_edge(face, i); // set edge belonging to domain 'dom' EN_attachDataInt(edge,MD_lookupMeshDataId( dom_string ),1); edgeCenter[0] = edgeCenter[1] = .0; E_center(edge,edgeCenter); // edge centroid V_coord(edge->get(0,0),I); V_coord(edge->get(0,1),J); int id0 = EN_id(edge->get(0,0)); int id1 = EN_id(edge->get(0,1)); // edge vector, used as a reference vector double IJ[2] = {J[0]-I[0], J[1]-I[1]}; // vector IJ must point from the smaller vertex ID to the greater if ( id0 > id1 ){ for (j=0; j<2; j++){ IJ[j] = -IJ[j]; } } // vector: from element center to edge middle point, used as a reference vector double v[2] = {edgeCenter[0]-faceCenter[0],edgeCenter[1]-faceCenter[1]}; // Cij is orthogonal to v for (j=0; j<2; j++){ Cij[j] = .0; } // Cij must point as if I inside the CV and J outside double innerprod = v[1]*IJ[0] + (-v[0])*IJ[1]; if ( innerprod <= .0 ){ for (j=0; j<2; j++){ v[j] = -v[j]; } } // associate Cij coefficient to edge pGCData->getCij(edge,dom,Cij); Cij[0] += v[1]; Cij[1] += -v[0]; pGCData->setCij(edge,dom,Cij); //cout << "Cij = " << Cij[0] << "\t" << Cij[1] << "\t" << Cij[2] << "\n"; #ifdef __ADAPTATION_DEBUG__ if (Cij[0]==.0 && Cij[1]==.0){ char msg[256]; sprintf(msg,"Edge %d-%d has Cij coefficient NULL Cij[0]=Cij[1]=0.0",id0,id1); throw Exception(__LINE__,__FILE__,msg); } #endif } // calculate volume of control volume and associate it to elements nodes const double porosity = .0; double A = F_area(face)/3.0; // element area //cout << "area = " << A << endl; for (j=0; j<3; j++){ node = face->get(0,j); EN_attachDataInt(node,MD_lookupMeshDataId( dom_string ),1); double v1 = pGCData->getVolume(node,dom); double v2 = pGCData->getWeightedVolume(node); v1 += A; v2 += A*porosity; pGCData->setVolume(node,dom,v1); pGCData->setWeightedVolume(node,v2); } } } FIter_delete(fit); int numBE = 0; // Calculate Dij coefficient only for boundary edges. EIter eit = M_edgeIter(theMesh); while ( (edge = EIter_next(eit)) ){ if ( !theMesh->getRefinementDepth(edge) ){ flag = EN_getFlag(edge); std::set<int>::iterator iter = setOfDomain.find( flag ); if (iter == setOfDomain.end()){ // this line is for general (h**o/hetero) adaptation numBE++; double I[3] = {.0,.0,.0}, J[3] = {.0,.0,.0}; V_coord(edge->get(0,0),I); V_coord(edge->get(0,1),J); // Dij vector is orthogonal to edge (it's unknown Dij orientation) Dij[0] = -(J[1]-I[1])/2.0; Dij[1] = (J[0]-I[0])/2.0; // make Dij points to outside domain. First, take face that uses edge and its flag int domains[2] = {0,0}; for (i=0; i<E_numFaces(edge); i++){ face = E_face(edge,i); if (!face){ throw Exception(__LINE__,__FILE__,"Null face!\n"); } domains[i] = EN_getFlag(face); } // that the reference face to make Dij points to outside face = E_face(edge, 0); if (!face){ throw Exception(__LINE__,__FILE__,"Null face!\n"); } // now, get face's center and edge's center double faceCenter[3] = {.0, .0, .0}, edgeCenter[3] = {.0, .0, .0}; getFCenter(face,faceCenter); // element centroid E_center(edge,edgeCenter); // edge centroid // vector: from element center to edge middle point, used as a reference vector double v[2] = {edgeCenter[0]-faceCenter[0],edgeCenter[1]-faceCenter[1]}; // Dij must point to outside element double innerprod = Dij[0]*v[0] + Dij[1]*v[1]; if ( innerprod <= .0 ){ for (j=0; j<2; j++){ Dij[j] = -Dij[j]; } } // associate to edge domains flags to wjich it belongs EN_attachDataInt(edge,MD_lookupMeshDataId("dom1"),domains[0]); EN_attachDataInt(edge,MD_lookupMeshDataId("dom1"),domains[1]); pGCData->setDij(edge,domains[0],domains[1],Dij); } } } EIter_delete(eit); //cout << "preprocessor: Number of Boundary edges = " << numBE << endl; calculateEdgeLength(theMesh,pGCData); calculateCijNorm(theMesh,pGCData,setOfDomain); // For 2-D domains, multiply volume by reservoir height (H) for 2D/3D simulations (physics occurs only on 2-D but reservoir volume is considered) double vt = .0; double vol,wvol; std::set<int>::iterator iter = setOfDomain.begin(); for(;iter!=setOfDomain.end();iter++){ VIter vit = M_vertexIter(theMesh); while (pEntity node = VIter_next(vit)){ // do not divide vol by number of remote copies! vol = pGCData->getVolume(node,*iter); vt += vol; wvol = 0.2*vol; pGCData->setWeightedVolume(node,wvol); } VIter_delete(vit); } pGCData->setTotalReservoirVolume(vt); //cout << "Number of domains: " << setOfDomain.size() << ". They are: "; // for( iter = setOfDomain.begin(); iter!=setOfDomain.end(); iter++){ // cout << *iter << " "; // } // cout << endl; validete_coefficients(theMesh,setOfDomain,pGCData); #ifdef TRACKING_PROGRAM_STEPS cout << "TRACKING_PROGRAM_STEPS: EBFV1_preprocessor_2D\tOUT\n"; #endif return 0; }
void Cterrain::showAndMark(int jmin,int jmax,int imin,int imax,int curDepth) { //检查当前节点是否与视截体相交 //求节点p所表示区域的保守包围盒 // 上面 // p[0]--p[3] // | | // p[1]--p[2] // 下面 // p[4]--p[7] // | | // p[5]--p[6] float xmin=m_range.getMinX()+gridSize*jmin; float xmax=m_range.getMinX()+gridSize*jmax; float zmin=m_range.getMinZ()+gridSize*imin; float zmax=m_range.getMinZ()+gridSize*imax; float ymin=m_range.getMinY(); float ymax=m_range.getMaxY(); float c[3]={(xmax+xmin)/2,(ymin+ymax)/2,(zmin+zmax)/2}; float r=max(xmax-xmin,ymax-ymin)*0.86602540378443864676372317075294;//由于zmax-zmin与xmax-xmin相等,所以不用考虑 //看球体(c,r)是否都在planeList中某个面的反面,如果是则可剔除 bool visible=true; for(int i=0;i<5;i++){//不考虑远平面 const Cplane&plane=this->getModel()->getMeshByIndex(0)->getCamera()->getFrustum().getPlaneByIndex(i); //看球体(c,r)是否在plane的背面 float PND=PND_point_plane(plane, c); if(PND<-r){//如果在背面 //断定为不可见,不用再继续检测 visible=false; break; } }//得到visible if(visible){//如果可见 bool needDiv=false;//是否需要再分 //求needDiv if(imin+1==imax){//无须再分,因为已经无法再分 needDiv=false; }else{//进一步判断 //求c到视点的距离 //指数值越大,LOD效应越明显 float d=square(this->getModel()->getMeshByIndex(0)->getCamera()->getEyePos().x()-c[0]) +square(minf(0.6*(this->getModel()->getMeshByIndex(0)->getCamera()->getEyePos().y()-c[1]),700))//Y乘以一个比1小的系数是为了让LOD对高度变化不敏感 +square(this->getModel()->getMeshByIndex(0)->getCamera()->getEyePos().z()-c[2]); float e=xmax-xmin;//边长 if(d<e*reso)needDiv=true; }//得到needDiv if(needDiv){//继续分 int imid=(imin+imax)>>1;//除2 int jmid=(jmin+jmax)>>1; markmat[imid][jmid]=true; markedElementIndexList.push_back(Cij(imid,jmid)); //对四个孩子继续递归 showAndMark(jmin,jmid,imin,imid,curDepth+1); showAndMark(jmin,jmid,imid,imax,curDepth+1); showAndMark(jmid,jmax,imid,imax,curDepth+1); showAndMark(jmid,jmax,imin,imid,curDepth+1); }else{//不分 const int vIDMat_imin=(int)markmat[0].size()*imin;//vIDMat[imin]; const int vIDMat_imax=(int)markmat[0].size()*imax;//vIDMat[imax]; const int ID0=vIDMat_imin+jmin; const int ID1=vIDMat_imax+jmin; const int ID2=vIDMat_imax+jmax; const int ID3=vIDMat_imin+jmax; this->getModel()->getMeshByIndex(0)->addIDtri(ID0, ID1, ID2); this->getModel()->getMeshByIndex(0)->addIDtri(ID0, ID2, ID3); } }
void Cterrain::getBlocks(int jmin,int jmax,int imin,int imax,int curDepth) { //检查当前节点是否与视截体相交--abc //求节点p所表示区域的保守包围盒--abc // 上面--abc // p[0]--p[3] // | | // p[1]--p[2] // 下面--abc // p[4]--p[7] // | | // p[5]--p[6] float xmin=m_range.getMinX()+gridSize*jmin; float xmax=m_range.getMinX()+gridSize*jmax; float zmin=m_range.getMinZ()+gridSize*imin; float zmax=m_range.getMinZ()+gridSize*imax; float ymin=m_range.getMinY(); float ymax=m_range.getMaxY(); float c[3]={(xmax+xmin)/2,(ymin+ymax)/2,(zmin+zmax)/2}; float r=max(xmax-xmin,ymax-ymin)*0.86602540378443864676372317075294;//由于zmax-zmin与xmax-xmin相等,所以不用考虑--abc //看球体(c,r)是否都在planeList中某个面的反面,如果是则可剔除--abc bool visible=true; for(int i=0;i<5;i++){//不考虑远平面--abc const Cc3dPlane&plane=this->getMesh()->getSubMeshByIndex(0)->getCamera()->getFrustum().getPlaneByIndex(i); //看球体(c,r)是否在plane的背面--abc float PND=directedDistanceFromPointToPlane(plane, c); if(PND<-r){//如果在背面--abc //断定为不可见,不用再继续检测--abc visible=false; break; } }//得到visible if(visible){//如果可见--abc bool needDiv=false;//是否需要再分--abc //求needDiv if(imin+1==imax){//无须再分,因为已经无法再分--abc needDiv=false; }else{//进一步判断--abc //求c到视点的距离--abc float d2=square(this->getMesh()->getSubMeshByIndex(0)->getCamera()->getEyePos().x()-c[0]) /// +square(this->getMesh()->getSubMeshByIndex(0)->getCamera()->getEyePos().y()-c[1]) +square(this->getMesh()->getSubMeshByIndex(0)->getCamera()->getEyePos().z()-c[2]); float e=xmax-xmin;//边长--abc if(d2<square(e*reso))needDiv=true; }//得到needDiv if(needDiv){//继续分--abc int imid=(imin+imax)>>1;//除2 int jmid=(jmin+jmax)>>1; markmat[imid][jmid]=true; markedElementIndexList.push_back(Cij(imid,jmid)); //对四个孩子继续递归--abc getBlocks(jmin,jmid,imin,imid,curDepth+1); getBlocks(jmin,jmid,imid,imax,curDepth+1); getBlocks(jmid,jmax,imid,imax,curDepth+1); getBlocks(jmid,jmax,imin,imid,curDepth+1); }else{//不分--abc CterrainBlock block(imin,imax,jmin,jmax); m_blockList.push_back(block); } }
void validete_coefficients(pMesh theMesh, std::set<int>& setOfDomain, GeomData* pGCData){ #ifdef TRACKING_PROGRAM_STEPS cout << "TRACKING_PROGRAM_STEPS: validate pre-processor coefficient calculation\tIN\n"; #endif cout << setprecision(8) << scientific; pEntity edge; std::vector<double> Cij(3), Dij(3); std::map<int,double*> coeff_sum; std::set<int>::iterator iter = setOfDomain.begin(); for(;iter!=setOfDomain.end(); iter++){ int dom = *iter; // initialize all nodes for domain "dom" double* p; VIter vit = M_vertexIter(theMesh); while (pEntity node = VIter_next(vit)){ p = new double[3]; p[0] = p[1] = p[2] = .0; coeff_sum[EN_id(node)] = p; } VIter_delete(vit); // calculate summation of coefficients EIter eit = M_edgeIter(theMesh); while ( (edge = EIter_next(eit)) ){ int I = EN_id(edge->get(0,0)); int J = EN_id(edge->get(0,1)); pGCData->getCij(edge,dom,Cij); double sign = (I>J)?-1.0:1.0; p = coeff_sum[I]; p[0] += sign*Cij[0]; p[1] += sign*Cij[1]; p[2] += sign*Cij[2]; if (pGCData->getDij(edge,dom,Dij)){ p[0] += Dij[0]; p[1] += Dij[1]; p[2] += Dij[2]; } p = coeff_sum[J]; p[0] += -sign*Cij[0]; p[1] += -sign*Cij[1]; p[2] += -sign*Cij[2]; if (pGCData->getDij(edge,dom,Dij)){ p[0] += Dij[0]; p[1] += Dij[1]; p[2] += Dij[2]; } } EIter_delete(eit); double summation[3] = {.0,.0,.0}; cout << "Domain: " << dom << endl; //cout << "ID:\t" << "Summ:\n"; std::map<int,double*>::iterator miter = coeff_sum.begin(); for(;miter!=coeff_sum.end();miter++){ //int ID = miter->first; p = miter->second; //cout << ID << "\t" << p[0] << " " << p[1] << " " << p[2] << endl; summation[0] += p[0]; summation[1] += p[1]; summation[2] += p[2]; dealloc_DOUBLE_vector(p); } cout << "\n\nSummation of all summations (Cij/Dij): " << summation[0] << " " << summation[1] << " " << summation[2] << "\n"; double vol_control = 0; vit = M_vertexIter(theMesh); while (pEntity node = VIter_next(vit)){ vol_control += pGCData->getVolume(node,dom); } VIter_delete(vit); cout << "Total Volume : " << vol_control << "\n\n\n"; } #ifdef TRACKING_PROGRAM_STEPS cout << "TRACKING_PROGRAM_STEPS: validate pre-processor coefficient calculation\tOUT\n"; #endif }
// Calculates Cij, Dij(boundary faces) and nodal volume. It also works for multi domains meshes int EBFV1_preprocessor_3D(pMesh theMesh, void *pData, int &ndom){ PetscPrintf(PETSC_COMM_WORLD,"Starting EBFV1-3D pre-processor..."); GeomData *pGCData = (GeomData*)pData; pGCData->setMeshDim(theMesh->getDim()); if (theMesh->getDim() != 3){ throw Exception(__LINE__,__FILE__,"Only 3-D meshes are allowed. Exiting...\n"); } theMesh->modifyState(3,2); theMesh->modifyState(2,3); pEntity tetra, edge, face; int i,j,k,K,m; double tCenter[3], eCenter[3], v[3], *vec[2], val, *tetraFCenter[4]; double normal[3], I[3], J[3], IJ[3], proj[3]; // allocate vectors for (i=0; i<4; i++) tetraFCenter[i] = new double[3]; for (i=0; i<2; i++) vec[i] = new double[3]; // Search over all tetrahedra flags set to define domains. Store all flags on a list and initialize Cij vector std::set<int> setOfDomain; std::vector<double> Cij(3,.0); RIter rit = M_regionIter(theMesh); while ( (tetra = RIter_next(rit)) ){ int flag = GEN_tag(tetra->getClassification()); setOfDomain.insert( flag ); for (i=0; i<6; i++){ edge = (pEntity)tetra->get(1,i); pGCData->setCij(edge,flag,Cij); } } RIter_delete(rit); // mark faces (boundary) bool detectBdryFaces = false; std::set<int>::iterator iter = setOfDomain.begin(); for (; iter != setOfDomain.end(); iter++){ int countBDRYFaces = 0; int dom = *iter; char dom_string[256]; sprintf(dom_string,"dom_str_%d",dom); RIter rit = M_regionIter(theMesh); while ( (tetra = RIter_next(rit)) ){ int tetraflag = GEN_tag(tetra->getClassification()); if (tetraflag==dom){ for (i=0;i<4;i++){ face = (pFace)tetra->get(2,i); int faceflag = GEN_tag(face->getClassification()); // if flags are different, then face in on boundary if (faceflag!=tetraflag){ detectBdryFaces = true; countBDRYFaces++; // set edge belonging to domain 'dom' EN_attachDataInt(face,MD_lookupMeshDataId( dom_string ),1); } } } } RIter_delete(rit); } //throw 1; if (!detectBdryFaces){ throw Exception(__LINE__,__FILE__,"Any boundary face (triangles) were detected. Boundary elements MUST have different flag of internal elements."); } /// initialize weighted volume VIter vit = M_vertexIter(theMesh); while (pEntity v = VIter_next(vit)) pGCData->setWeightedVolume(v,0.0); VIter_delete(vit); vector<pVertex> tetraVertex(4), edgeVertex(2); double vt = .0; // total volume // loop over elements // for each element: 1 - calculate Cij for each edge and store them on the respective edge // 2 - calculate element contribution to volume of control volume // PetscPrintf(PETSC_COMM_WORLD,"Loop over tetras - start... ");MPI_Barrier(MPI_COMM_WORLD); rit = M_regionIter(theMesh); while ( (tetra = RIter_next(rit)) ){ // get all four tetrahedron's vertices for (i=0; i<4; i++){ tetraVertex[i] = (pEntity)tetra->get(0,i); } int tetraFaces[4][3] = { {EN_id(tetraVertex[0]),EN_id(tetraVertex[1]),EN_id(tetraVertex[2])}, {EN_id(tetraVertex[0]),EN_id(tetraVertex[1]),EN_id(tetraVertex[3])}, {EN_id(tetraVertex[0]),EN_id(tetraVertex[2]),EN_id(tetraVertex[3])}, {EN_id(tetraVertex[1]),EN_id(tetraVertex[2]),EN_id(tetraVertex[3])}}; getFCenter(tetraVertex[0], tetraVertex[1], tetraVertex[2], tetraFCenter[0]); getFCenter(tetraVertex[0], tetraVertex[1], tetraVertex[3], tetraFCenter[1]); getFCenter(tetraVertex[0], tetraVertex[2], tetraVertex[3], tetraFCenter[2]); getFCenter(tetraVertex[1], tetraVertex[2], tetraVertex[3], tetraFCenter[3]); // get tetrahedron center tCenter[0] = tCenter[1] = tCenter[2] = .0; R_center(tetra,tCenter); double coord1[3]; V_coord(tetraVertex[0],coord1); double coord2[3]; V_coord(tetraVertex[1],coord2); double coord3[3]; V_coord(tetraVertex[2],coord3); double coord4[3]; V_coord(tetraVertex[3],coord4); // step #1: Cij // identify which domain the current tetrahedron belongs to // edges on domain's partition have differents Cij, one for each domain const int dom = GEN_tag(tetra->getClassification()); char dom_string[256]; sprintf(dom_string,"dom_str_%d",dom); markTetraBdryFaces(theMesh,tetra,dom); setOfDomain.insert(dom); // store every new domain for (int pos1=0; pos1<3; pos1++){ for (int pos2=pos1+1; pos2<4; pos2++){ edge = (pEdge)theMesh->getEdge((mVertex*)tetraVertex[pos1],(mVertex*)tetraVertex[pos2]); // set edge belonging to domain 'dom' EN_attachDataInt(edge,MD_lookupMeshDataId( dom_string ),1); //M_GetVertices(edge,edgeVertex); for (i=0; i<2; i++) edgeVertex[i] = (pEntity)edge->get(0,i); // edge's Cij is the sum of two vectors. Both are orthogonals to planes // defined by three vectors. They are: // v - ec->tc: edge center to tetra center // vec[0] - ec->fcr: edge center to right face center // vec[1] - ec->fcl: edge center to left face center // Cij = (v)x(vec[0]) + (v)x(vec[1]), Cij points to outside of control volume // create vector v: for (i=0; i<3; i++) I[i] = J[i]= .0; V_coord(edgeVertex[0],I); V_coord(edgeVertex[1],J); double sign = ( EN_id(edgeVertex[0]) > EN_id(edgeVertex[1]) )?-1.0:1.0; for (i=0; i<3; i++){ IJ[i] = sign*(J[i] - I[i]); } // get edge center eCenter[0] = eCenter[1] = eCenter[2] = .0; for (i=0; i<3; i++){ eCenter[i] = .5*(I[i]+J[i]); } // create vector v: from edge middle point to tetrahedral centroid for (i=0; i<3; i++){ v[i] = tCenter[i] - eCenter[i]; } // search for tetra faces that share the same edge and get their centers. Of course, there are only two faces // sharing the same edge. FMDB can do this job easily, but for 3D big meshes a face structure has a high memory cost. K = 0; // loop over tetra's faces for (i=0; i<4; i++){ // loop over face's vertices for (j=0; j<3; j++){ if (EN_id(edgeVertex[0]) == tetraFaces[i][j]){ for (k=0; k<3; k++){ if (EN_id(edgeVertex[1])==tetraFaces[i][k]){ for (m=0; m<3; m++) vec[K][m] = -eCenter[m] + tetraFCenter[i][m]; K++; } } } } } // IJ vector is a reference to Cij. IJ points from node I to node J // where: I_id < J_id // vec projections on edge IJ must have the same orientation as IJ vector double n = sqrt( IJ[0]*IJ[0] + IJ[1]*IJ[1] + IJ[2]*IJ[2] ) ; // Cij calculation n ; for (j=0; j<3; j++){ Cij[j] = .0; } pGCData->getCij(edge,dom,Cij); double normal1[3], normal2[3]; cross(v,vec[0],normal1); cross(vec[1],v,normal2); for (j=0; j<3; j++){ proj[j] = .0; } for (j=0; j<3; j++){ normal[j] = .5*(normal1[j]+normal2[j]); } val = dot(normal,IJ)/(n*n); for (j=0; j<3; j++){ proj[j] = val*IJ[j]; } double sinal = (dot(proj,IJ)<.0)?-1.:1.; for (j=0; j<3; j++){ Cij[j] += sinal*normal[j]; } pGCData->setCij(edge,dom,Cij); } } // step #2: volume of control volume const double porosity = .0; const double tetraVolume = R_Volume(tetra); const double nodalVolume = .25*tetraVolume; vt = +tetraVolume; for (i=0; i<4; i++){ // total nodal volume double v1 = pGCData->getVolume(tetraVertex[i],dom); v1 += nodalVolume; pGCData->setVolume(tetraVertex[i],dom,v1); double v2 = pGCData->getWeightedVolume(tetraVertex[i]); v2 += nodalVolume*porosity; pGCData->setWeightedVolume(tetraVertex[i],v2); } } RIter_delete(rit); // END TETRAHEDRALS LOOP pGCData->setTotalReservoirVolume(vt); //PetscPrintf(PETSC_COMM_WORLD,"Finished\n");MPI_Barrier(MPI_COMM_WORLD); // deallocate vectors for (i=0; i<4; i++) delete[] tetraFCenter[i]; for (i=0; i<2; i++) delete[] vec[i]; /* * Dij vector calculation. A loop over all boundary (external/internal) faces is made. Depending on how FMDB is used, faces on all * tetrahedrals may be created and they must be filtered. If a face does not belong to boundary it will assume the tetrahedral domain * flag. This value is greater than 3000 and is used to filter them from those provided by mesh file. */ int count = 0; dblarray Dij(3,.0); //PetscPrintf(PETSC_COMM_WORLD,"Loop over boundary faces - start... ");///MPI_Barrier(MPI_COMM_WORLD); if ( M_numFaces(theMesh) != 0 ){ FIter fit = M_faceIter(theMesh); while ( (face = FIter_next(fit)) ){ int flag = GEN_tag(face->getClassification()); iter = setOfDomain.find(flag); // get only faces built over surfaces defined by user in geometric model // it only work if surface flags defined by user are different from those set to tetrahedrals if ( iter==setOfDomain.end() ){ computeDij(theMesh,face,pGCData); } } FIter_delete(fit); } //PetscPrintf(PETSC_COMM_WORLD,"Finished\n");MPI_Barrier(MPI_COMM_WORLD); calculateEdgeLength(theMesh,pGCData); calculateCijNorm(theMesh,pGCData,setOfDomain); identifyBoundaryElements(theMesh,pGCData,setOfDomain); i = 0; ndom = (int)setOfDomain.size(); int *domlist = new int[ndom]; for(iter = setOfDomain.begin(); iter!=setOfDomain.end(); iter++){ domlist[i++] = *iter; } PetscPrintf(PETSC_COMM_WORLD," finished.\n"); cout << "-------------------------------------------------------------------------------------------------------------------------\n\n"; return 0; }