/* J_ee Stress Function See declaration in Duda & Hart the matrix M is a (pointcount*DIM)x1 matrix (a parameter vector). --------------------------------------------------*/ double J_ee(matrix M) { double res,d,d_i,sqrt(),res_i,tot_delta,cons_add,Dij(); int i,j,k; static double coeff; res=0.0; tot_delta = 0.0; for (i=1; i<=pointcount; i++) for (j=1 ; j<i; j++) { if (delta[i][j] != LARGE_COEFF) { res_i = Dij(M,i,j) - delta[i][j]; res_i = res_i*res_i; res += res_i; tot_delta += delta[i][j]*delta[i][j]; } } res = res/tot_delta; /* cons_add = parr_coeff*parr_penalty(M) + line_coeff*line_penalty(M,Dim); res += cons_add; */ return(res); }
int main(){ int i,j,k; scanf("%d %d",&ss,&ee); scanf("%d %d",&n,&m); for (i=1;i<=n;i++){ scanf("%s %d %d %d",s1,r+i,&T[i][0],&T[i][1]); if (s1[0]=='B') col[i]=0;else col[i]=1; } memset(gn,0,sizeof(gn)); memset(d,0,sizeof(d)); for (;m>0;m--){ scanf("%d %d %d",&i,&j,&k); g[i][gn[i]++]=j; g[j][gn[j]++]=i; d[i][j]=d[j][i]=k; } if (!Dij(ss,ee)) printf("0\n"); return 0; }
void GeomData::transferDijData(pMesh theMesh){ dblarray Dij(3,.0); double dij[3]; int ndom = getNumDomains(); for (int i=0; i<ndom; i++){ int dom = domainList[i]; int row = 0; if (dim==2){ EIter eit = M_edgeIter(theMesh); while ( pEdge edge = EIter_next(eit) ){ if ( edgeBelongToDomain(edge,dom) ){ if (belongsToBoundary(edge)){ getDij(edge,dom,Dij); dij[0] = Dij[0]; dij[1] = Dij[1]; dij[2] = Dij[2]; setDij(i,row,dij); row++; } } } EIter_delete(eit); } else{ FIter fit = M_faceIter(theMesh); while ( pFace face = FIter_next(fit) ){ if ( faceBelongToDomain(face,dom) ){ if (belongsToBoundary(face)){ getDij(face,dom,dij); setDij(i,row,dij); row++; } } } FIter_delete(fit); } } }
/* DJ_ee differential of the Stress Function See declaration in Duda & Hart the matrix M is a (pointcount*DIM)x1 matrix ----------------------------------------------*/ void DJ_ee(matrix M,matrix D) { int i,j,k,q; double tot_delta,stat_coeff,Dij(); double coeff_i,d_kj; matrix Y_k=NULL,Y_j=NULL,vec_kj=NULL,diff_k=NULL; tot_delta = 0.0; for (i=1; i<=pointcount; i++) for (j=1 ; j<i; j++) if (delta[i][j] != LARGE_COEFF) tot_delta += delta[i][j]*delta[i][j]; stat_coeff = 2.0/tot_delta; for (k=1; k<=pointcount; k++) { Y_k = mtx_ver_cut(M,Sentry(k,Dim),Eentry(k,Dim)); alloc_mtx(&diff_k,Dim,1); for (j=1; j<=pointcount; j++) { if ((j!=k) && (delta[k][j] != LARGE_COEFF) ){ d_kj = Dij(M,k,j); coeff_i = (d_kj - delta[k][j])/d_kj; Y_j = mtx_ver_cut(M,Sentry(j,Dim),Eentry(j,Dim)); vec_kj = sub_mtx(Y_k,Y_j); mul_scalar_in_mtx(vec_kj,coeff_i); add_in_mtx(diff_k,vec_kj,1,1); free_all_mtx(2,&Y_j,&vec_kj); } } mul_scalar_in_mtx(diff_k,stat_coeff); for (q=1; q<=Dim; q++) VecEntry(D,Dim,k,q) = diff_k[q][1] ; free_all_mtx(2,&Y_k,&diff_k); } }
// 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 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; }