Transform::Transform( const std::string nodeName ) : vgd::node::GeometricalTransformation( nodeName ) { // Add field addField( new FCenterType(getFCenter()) ); addField( new FScaleOrientationType(getFScaleOrientation()) ); addField( new FScaleFactorType(getFScaleFactor()) ); addField( new FRotationType(getFRotation()) ); addField( new FTranslationType(getFTranslation()) ); // Link link( getDFNode() ); }
void calculateGeomCoefficients(pEntity face, double *Cij, double *Dij, double &vol){ // Cij_x = Cij[0]; Dij_x = Dij[0]; // Cij_y = Cij[1]; Dij_y = Dij[1]; // Cik_x = Cij[2]; Dij_x = Dij[2]; // Cik_y = Cij[3]; Dij_y = Dij[3]; // Cjk_x = Cij[4]; Dij_x = Dij[4]; // Cjk_y = Cij[5]; Dij_y = Dij[5]; int i, pos, id0, id1; double faceCenter[3], edgeCenter[3], IJ[2], innerprod, sign; double I[3], J[3], v[2]; pEntity edge; pos = 0; getFCenter(face,faceCenter); for (i=0; i<3; i++){ // loop over all three face's edges to calculate Cij and Dij edge = F_edge(face, i); edgeCenter[0] = .0; edgeCenter[1] = .0; E_center(edge,edgeCenter); // get edge middle point V_coord(edge->get(0,0),I); // get node I coordinate V_coord(edge->get(0,1),J); // get node J coordinate id0 = EN_id(edge->get(0,0)); // get node I ID id1 = EN_id(edge->get(0,1)); // get node J ID sign = ( id0 > id1 )?-1.0:1.0; // vector IJ must point from the smaller vertex ID to the greater IJ[0] = sign*(J[0]-I[0]); // edge vector, used as a reference vector IJ[1] = sign*(J[1]-I[1]); v[0] = edgeCenter[0]-faceCenter[0]; // reference vector v[1] = edgeCenter[1]-faceCenter[1]; innerprod = v[1]*IJ[0] + (-v[0])*IJ[1]; // Cij must point as if I inside the CV and J outside if ( innerprod <= .0 ){ v[0] = -v[0]; v[1] = -v[1]; } Cij[pos] = v[1]; Cij[pos+1] = -v[0]; Dij[pos] = -(J[1]-I[1])/2.0; // Dij vector is orthogonal to edge (it's unknown Dij orientation) Dij[pos+1] = (J[0]-I[0])/2.0; v[0] = edgeCenter[0]-faceCenter[0]; // reference vector v[1] = edgeCenter[1]-faceCenter[1]; innerprod = Dij[pos]*v[0] + Dij[pos+1]*v[1]; // Dij must point to outside element if ( innerprod <= .0 ){ Dij[pos] = -Dij[pos]; Dij[pos+1] = -Dij[pos+1]; } pos += 2; } vol = F_area(face)/3.0; // calculate node control volume }
// 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 getFCenter(pFace face, double *center){ vector<pVertex> vertex; M_GetVertices(face,vertex); getFCenter(vertex[0],vertex[1],vertex[2],center); vertex.clear(); }
void Transform::setCenter( const vgm::Vec3f center ) { getFieldRW<FCenterType>(getFCenter())->setValue( center ); }
const vgm::Vec3f Transform::getCenter( void ) const { return ( getFieldRO<FCenterType>(getFCenter())->getValue() ); }
// 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; }