/*----------------------------------------------------------------------* | ctor (public) mwgee 10/05| *----------------------------------------------------------------------*/ MOERTEL::Overlap::Overlap(MOERTEL::Segment& sseg, MOERTEL::Segment& mseg, MOERTEL::Interface& inter, bool exactvalues, int outlevel) : inter_(inter), sseg_(sseg), mseg_(mseg), outputlevel_(outlevel), overlap_(false), havemxi_(false), havesxi_(false), havelines_(false), havesxim_(false), havelinem_(false), exactvalues_(exactvalues) { if ( (sseg.Type()!=MOERTEL::Segment::seg_BiLinearTri && sseg.Type()!=MOERTEL::Segment::seg_BiLinearQuad ) || (mseg.Type()!=MOERTEL::Segment::seg_BiLinearTri && mseg.Type()!=MOERTEL::Segment::seg_BiLinearQuad ) ) { std::cout << "***ERR*** MOERTEL::Overlap::Overlap:\n" << "***ERR*** Overlap of other then bilinear triangles/quads not yet implemented\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; exit(EXIT_FAILURE); } p_.clear(); s_.clear(); }
/*----------------------------------------------------------------------* | mwgee 08/05| | 2D case: | | this method evaluates the function | | F(eta) = ( Ni * xim - xs ) dot gs | | with Ni shape functions of slave segment | | xm nodal coords of master node | | xs nodal coords of slave nodes on segment | | njs nodal outward normal of nodes xs (slave side) | *----------------------------------------------------------------------*/ double MOERTEL::Projector::evaluate_F_2D_SegmentOrthogonal_to_g(MOERTEL::Node& node, MOERTEL::Segment& seg, double eta, double &gap, double* g) { // check the type of function on the segment // Here, we need 1D functions set as function id 0 MOERTEL::Function::FunctionType type = seg.FunctionType(0); if (type != MOERTEL::Function::func_Linear1D) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::evaluate_F_2D_SegmentOrthogonal_to_g:\n" << "***ERR*** function is of wrong type\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } // evaluate the first function set on segment at eta int nsnode = seg.Nnode(); double val[100]; seg.EvaluateFunction(0,&eta,val,nsnode,NULL); // get nodal coords and normals of master nodes and interpolate them double Nx[2]; Nx[0] = Nx[1] = 0.0; MOERTEL::Node** mnodes = seg.Nodes(); if (!mnodes) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::evaluate_F_2D_SegmentOrthogonal_to_g:\n" << "***ERR*** segment " << seg.Id() << " ptr to it's nodes is zero\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } for (int i=0; i<nsnode; ++i) { const double* X = mnodes[i]->X(); Nx[0] += val[i]*X[0]; Nx[1] += val[i]*X[1]; } // subtract xs from interpolated coords Nx const double* X = node.X(); Nx[0] -= X[0]; Nx[1] -= X[1]; // calculate F double F = Nx[0]*g[0] + Nx[1]*g[1]; gap = (Nx[0] * g[0] + Nx[1] * g[1]); // gap = ((Nx[0] - X[0]) * g[0] + (Nx[1] - X[1]) * g[1]) // / sqrt(g[0] * g[0] + g[1] * g[1]); // ||gap|| cos theta return F; }
/*----------------------------------------------------------------------* | build nodal normal mwgee 07/05| *----------------------------------------------------------------------*/ bool MOERTEL::Node::BuildAveragedNormal() { // get segments adjacent to me int nseg = Nseg(); int* sid = SegmentIds(); for (int i=0; i<3; ++i) n_[i] = 0.0; double weight = 0.0; #if 0 std::cout << "Building normal for node\n" << *this; #endif for (int i=0; i<nseg; ++i) { MOERTEL::Segment* seg = segptr_[i]; #if 0 std::cout << "Now averaging from Segment\n" << *seg; std::cout << "Finished writing segment data." << std::endl; #endif if (!seg) { std::stringstream oss; oss << "***ERR*** MOERTEL::Node::BuildAveragedNormal:\n" << "***ERR*** Node " << Id() << ": Segment " << sid[i] << " not found -> fatal\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } double* n = seg->BuildNormalAtNode(Id()); double wgt = seg->Area(); // add weighted normal to n_ for (int i=0; i<3; ++i) n_[i] += wgt*n[i]; // add weight to total weight weight += wgt; delete [] n; n = NULL; } // for (int i=0; i<nseg; ++i) double length = sqrt(n_[0]*n_[0]+n_[1]*n_[1]+n_[2]*n_[2]); for (int i=0; i<3; ++i) n_[i] /= length; #if 0 std::cout << "Node " << Id() << ":" << " normal is " << std::setw(15) << n_[0] << " "<< std::setw(15) << n_[1] << " " << std::setw(15) << n_[2] << std::endl; #endif return true; }
/*----------------------------------------------------------------------* | mwgee 08/05| | 2D case: | | this method evaluates the function | | gradF(eta) = | | ( Ni,eta * xis ) * ( Ni,eta * xis ) | | with Ni,eta derivative of shape functions of segment | | Ni,Nj shape functions of segment | | xis nodal coords of segment's nodes i (slave side) | *----------------------------------------------------------------------*/ double MOERTEL::Projector::evaluate_gradF_2D_SegmentOrthogonal_to_g( MOERTEL::Node& node, MOERTEL::Segment& seg, double eta, double* g) { // check the type of function on the segment // Here, we need 1D functions set as function id 0 MOERTEL::Function::FunctionType type = seg.FunctionType(0); if (type != MOERTEL::Function::func_Linear1D) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::evaluate_gradF_2D_SegmentOrthogonal_to_g:\n" << "***ERR*** function is of wrong type\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } // evaluate function and derivatives of the first function set on segment at eta int nmnode = seg.Nnode(); double deriv[200]; seg.EvaluateFunction(0,&eta,NULL,nmnode,deriv); // intermediate data: // Nxeta = Ni,eta * xi // get nodal coords and normals of nodes and interpolate them double Nxeta[2]; Nxeta[0] = Nxeta[1] = 0.0; MOERTEL::Node** mnodes = seg.Nodes(); if (!mnodes) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::evaluate_gradF_2D_SegmentOrthogonal_to_g:\n" << "***ERR*** segment " << seg.Id() << " ptr to it's nodes is zero\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } for (int i=0; i<nmnode; ++i) { const double* X = mnodes[i]->X(); Nxeta[0] += deriv[i]*X[0]; Nxeta[1] += deriv[i]*X[1]; } // calculate gradF double gradF = Nxeta[0]*g[0] + Nxeta[1]*g[1]; return gradF; }
/*----------------------------------------------------------------------* | mwgee 08/05| *----------------------------------------------------------------------*/ bool MOERTEL::Projector::ProjectNodetoSegment_SegmentOrthogonal(MOERTEL::Node& node, MOERTEL::Segment& seg, double xi[], double &gap) { #if 0 std::cout << "----- Projector: Node " << node.Id() << " Segment " << seg.Id() << std::endl; #endif if (IsTwoDimensional()) { // we do a newton iteration for the projection coordinates xi // set starting value to the middle of the segment double eta = 0.0; int i = 0; double F=0.0,dF=0.0,deta=0.0; for (i=0; i<10; ++i) { F = evaluate_F_2D_SegmentOrthogonal(node,seg,eta,gap); if (abs(F) < 1.0e-10) break; dF = evaluate_gradF_2D_SegmentOrthogonal(node,seg,eta); deta = (-F)/dF; eta += deta; } if (abs(F)>1.0e-10) { if (OutLevel()>3) std::cout << "MOERTEL: ***WRN*** MOERTEL::Projector::ProjectNodetoSegment_SegmentOrthogonal:\n" << "MOERTEL: ***WRN*** Newton iteration failed to converge\n" << "MOERTEL: ***WRN*** #iterations = " << i << std::endl << "MOERTEL: ***WRN*** F(eta) = " << F << " gradF(eta) = " << dF << " eta = " << eta << " delta(eta) = " << deta << "\n" << "MOERTEL: ***WRN*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; } #if 0 std::cout << "#iterations = " << i << " F = " << F << " eta = " << eta << std::endl; #endif xi[0] = eta; return true; } else { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::ProjectNodetoSegment_SegmentOrthogonal:\n" << "***ERR*** 3D projection not yet impl.\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } return true; }
/*----------------------------------------------------------------------* | project nodes master to slave along slave cont. normal field | *----------------------------------------------------------------------*/ bool MOERTEL::Interface::ProjectNodes_MastertoSlave_NormalField() { if (!IsComplete()) { std::stringstream oss; oss << "***ERR*** MOERTEL::Interface::ProjectNodes_MastertoSlave_NormalField:\n" << "***ERR*** Complete() not called on interface " << Id() << "\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } if (!lComm()) return true; int mside = MortarSide(); int sside = OtherSide(mside); // iterate over all nodes of the master side and project those belonging to me std::map<int,Teuchos::RCP<MOERTEL::Node> >::iterator mcurr; for (mcurr=rnode_[mside].begin(); mcurr!=rnode_[mside].end(); ++mcurr) { Teuchos::RCP<MOERTEL::Node> mnode = mcurr->second; if (NodePID(mnode->Id()) != lComm()->MyPID()) continue; const double* mx = mnode->X(); double mindist = 1.0e+20; Teuchos::RCP<MOERTEL::Node> closenode = Teuchos::null; // find a node on the slave side that is closest to me std::map<int,Teuchos::RCP<MOERTEL::Node> >::iterator scurr; for (scurr=rnode_[sside].begin(); scurr!=rnode_[sside].end(); ++scurr) { Teuchos::RCP<MOERTEL::Node> snode = scurr->second; const double* sx = snode->X(); // build distance | snode->X() - mnode->X() | double dist = 0.0; for (int i=0; i<3; ++i) dist += (mx[i]-sx[i])*(mx[i]-sx[i]); dist = sqrt(dist); if (dist < mindist) { mindist = dist; closenode = snode; } } if (closenode == Teuchos::null) { std::stringstream oss; oss << "***ERR*** MOERTEL::Interface::ProjectNodes_MastertoSlave_NormalField:\n" << "***ERR*** Weired: for master node " << mnode->Id() << " no closest master node found\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } #if 0 cout << "snode " << *mnode; cout << "closenode " << *closenode; #endif // get segments attached to closest node closenode int nseg = closenode->Nseg(); MOERTEL::Segment** segs = closenode->Segments(); // create a projection operator MOERTEL::Projector projector(IsOneDimensional(),OutLevel()); // loop these segments and find best projection double bestdist[2]; const double tol = 0.2; double bestgap = 0.0, gap; bestdist[0] = bestdist[1] = 1.0e+20; MOERTEL::Segment* bestseg = NULL; for (int i=0; i<nseg; ++i) { // project the master node on the slave segment along the segments interpolated normal field double xi[2]; xi[0] = xi[1] = 0.0; projector.ProjectNodetoSegment_SegmentNormal(*mnode,*(segs[i]),xi,gap); // check whether xi is better then previous projections if (IsOneDimensional()) { if (abs(xi[0]) < abs(bestdist[0])) { bestdist[0] = xi[0]; bestdist[1] = xi[1]; bestseg = segs[i]; bestgap = gap; } } else { double third = 1./3.; // it's 'inside' with some tolerance if ( xi[0]<=1.+tol && xi[1]<=abs(1.-xi[0])+tol && xi[0]>=0.-tol && xi[1]>=0.-tol ) { // it's better in both directions if ( sqrt((xi[0]-third)*(xi[0]-third)) < sqrt((bestdist[0]-third)*(bestdist[0]-third)) && sqrt((xi[1]-third)*(xi[1]-third)) < sqrt((bestdist[1]-third)*(bestdist[1]-third)) ) { bestdist[0] = xi[0]; bestdist[1] = xi[1]; bestseg = segs[i]; bestgap = gap; } //it's better in one direction and 'in' in the other else if ( (sqrt((xi[0]-third)*(xi[0]-third))<sqrt((bestdist[0]-third)*(bestdist[0]-third)) && xi[1]<=abs(1.-xi[0])+tol && xi[1]>=0.-tol ) || (sqrt((xi[1]-third)*(xi[1]-third))<sqrt((bestdist[1]-third)*(bestdist[1]-third)) && xi[0]<=1.+tol && xi[0]>=0.-tol ) ) { bestdist[0] = xi[0]; bestdist[1] = xi[1]; bestseg = segs[i]; bestgap = gap; } } } } // for (int i=0; i<nseg; ++i) // check whether the bestseg/bestdist are inside that segment // (with some tolerance of 20%) bool ok = false; if (IsOneDimensional()) { if (abs(bestdist[0]) < 1.1) ok = true; } else { if (bestdist[0]<=1.+tol && bestdist[1]<=abs(1.-bestdist[0])+tol && bestdist[0]>=0.-tol && bestdist[1]>=0.-tol) ok = true; } if (ok) // the projection is good { // build the interpolated normal and overwrite the mnode normal with -n int nsnode = bestseg->Nnode(); MOERTEL::Node** snodes = bestseg->Nodes(); std::vector<double> val(nsnode); bestseg->EvaluateFunction(0,bestdist,&val[0],nsnode,NULL); double NN[3]; NN[0] = NN[1] = NN[2] = 0.0; for (int i=0; i<nsnode; ++i) { const double* N = snodes[i]->N(); for (int j=0; j<3; ++j) NN[j] -= val[i]*N[j]; } val.clear(); mnode->SetN(NN); // create projected node and store it in mnode MOERTEL::ProjectedNode* pnode = new MOERTEL::ProjectedNode(*mnode,bestdist,bestseg); mnode->SetProjectedNode(pnode); mnode->SetGap(bestgap); } else // this mnode does not have a valid projection { if (OutLevel()>6) cout << "MOERTEL: ***WRN***: Projection m->s: Node " << mnode->Id() << " does not have projection\n"; mnode->SetProjectedNode(NULL); } } // for (scurr=rnode_[mside].begin(); scurr!=rnode_[mside].end(); ++scurr) // loop all master nodes again and make the projection and the new normal redundant int bsize = 7*rnode_[mside].size(); std::vector<double> bcast(bsize); for (int proc=0; proc<lComm()->NumProc(); ++proc) { int blength = 0; if (proc==lComm()->MyPID()) { for (mcurr=rnode_[mside].begin(); mcurr!=rnode_[mside].end(); ++mcurr) { Teuchos::RCP<MOERTEL::Node> mnode = mcurr->second; if (proc != NodePID(mnode->Id())) continue; // cannot have a projection on a node i don't own Teuchos::RCP<MOERTEL::ProjectedNode> pnode = mnode->GetProjectedNode(); if (pnode == Teuchos::null) continue; // this node does not have a projection const double* xi = pnode->Xi(); const double* N = mnode->N(); bcast[blength] = (double)pnode->Id(); ++blength; if (pnode->Segment()) bcast[blength] = (double)pnode->Segment()->Id(); else bcast[blength] = -0.1; ++blength; bcast[blength] = xi[0]; ++blength; bcast[blength] = xi[1]; ++blength; bcast[blength] = N[0]; ++blength; bcast[blength] = N[1]; ++blength; bcast[blength] = N[2]; ++blength; bcast[blength] = pnode->Gap(); ++blength; } if (blength > bsize) { std::stringstream oss; oss << "***ERR*** MOERTEL::Interface::ProjectNodes_MastertoSlave_NormalField:\n" << "***ERR*** Overflow in communication buffer occured\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } } lComm()->Broadcast(&blength,1,proc); lComm()->Broadcast(&bcast[0],blength,proc); if (proc!=lComm()->MyPID()) { int i; for (i=0; i<blength;) { int nid = (int)bcast[i]; ++i; double sid = bcast[i]; ++i; double* xi = &bcast[i]; ++i; ++i; double* n = &bcast[i]; ++i; ++i; ++i; double gap = bcast[i]; ++i; Teuchos::RCP<MOERTEL::Node> mnode = GetNodeView(nid); Teuchos::RCP<MOERTEL::Segment> seg = Teuchos::null; if (sid != -0.1) seg = GetSegmentView((int)sid); if (mnode == Teuchos::null) { std::stringstream oss; oss << "***ERR*** MOERTEL::Interface::ProjectNodes_MastertoSlave_NormalField:\n" << "***ERR*** Cannot get view of node\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } mnode->SetN(n); MOERTEL::ProjectedNode* pnode = new MOERTEL::ProjectedNode(*mnode,xi,seg.get()); mnode->SetProjectedNode(pnode); mnode->SetGap(gap); } if (i != blength) { std::stringstream oss; oss << "***ERR*** MOERTEL::Interface::ProjectNodes_MastertoSlave_NormalField:\n" << "***ERR*** Mismatch in dimension of recv buffer\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } } } // for (int proc=0; proc<lComm()->NumProc(); ++proc) bcast.clear(); return true; }
/*----------------------------------------------------------------------* | mwgee 08/05| *----------------------------------------------------------------------*/ bool MOERTEL::Projector::ProjectNodetoSegment_Orthogonal_to_Slave( MOERTEL::Node& snode, MOERTEL::Segment& seg, double xi[], double &gap, MOERTEL::Segment& sseg) { #if 0 std::cout << "----- Projector: Node " << snode.Id() << " Segment " << seg.Id() << std::endl; std::cout << " orthogonal to Slave Segment " << sseg.Id() << std::endl; #endif if (IsTwoDimensional()) { // get the local node id of snode on sseg int lid = sseg.GetLocalNodeId(snode.Id()); if (lid<0) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::ProjectNodetoSegment_Orthogonal_to_Slave:\n" << "***ERR*** local node id could not be found\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } // get coordinate of local node lid double lidxi; sseg.LocalCoordinatesOfNode(lid,&lidxi); // build tangent vector in xi double g[2]; sseg.Metric(&lidxi,g,NULL); // we do a newton iteration for the projection coordinates xi // set starting value to the middle of the segment double eta = 0.0; int i = 0; double F=0.0,dF=0.0,deta=0.0; for (i=0; i<10; ++i) { F = evaluate_F_2D_SegmentOrthogonal_to_g(snode,seg,eta,gap,g); if (abs(F) < 1.0e-10) break; dF = evaluate_gradF_2D_SegmentOrthogonal_to_g(snode,seg,eta,g); deta = (-F)/dF; eta += deta; } if (abs(F)>1.0e-10) { if (OutLevel()>3) std::cout << "MOERTEL: ***WRN*** MOERTEL::Projector::ProjectNodetoSegment_Orthogonal_to_Slave:\n" << "MOERTEL: ***WRN*** Newton iteration failed to converge\n" << "MOERTEL: ***WRN*** #iterations = " << i << std::endl << "MOERTEL: ***WRN*** F(eta) = " << F << " gradF(eta) = " << dF << " eta = " << eta << " delta(eta) = " << deta << "\n" << "MOERTEL: ***WRN*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; } #if 0 std::cout << "#iterations = " << i << " F = " << F << " eta = " << eta << std::endl; #endif xi[0] = eta; return true; } else { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::ProjectNodetoSegment_Orthogonal_to_Slave:\n" << "***ERR*** 3D projection not impl.\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } return true; }
/*----------------------------------------------------------------------* | mwgee 07/05| | modded by gah 07/2010 | *----------------------------------------------------------------------*/ bool MOERTEL::Projector::ProjectNodetoSegment_NodalNormal(MOERTEL::Node& node, MOERTEL::Segment& seg, double xi[], double &gap) { bool ok = true; // 2D version of the problem if (IsTwoDimensional()) { #if 0 std::cout << "----- Projector: Node " << node.Id() << " Segment " << seg.Id() << std::endl; std::cout << "Segment\n" << seg; MOERTEL::Node** nodes = seg.Nodes(); std::cout << *nodes[0]; std::cout << *nodes[1]; #endif // we do a newton iteration for the projection coordinates xi // set starting value to the middle of the segment double eta = 0.0; int i = 0; double F=0.0,dF=0.0,deta=0.0; for (i=0; i<10; ++i) { F = evaluate_F_2D_NodalNormal(node,seg,eta,gap); if (abs(F) < 1.0e-10) break; dF = evaluate_gradF_2D_NodalNormal(node,seg,eta); deta = (-F)/dF; eta += deta; } if (abs(F)>1.0e-9) { ok = false; if (OutLevel()>3) std::cout << "MOERTEL: ***WRN*** MOERTEL::Projector::ProjectNodetoSegment_NodalNormal:\n" << "MOERTEL: ***WRN*** Newton iteration failed to converge\n" << "MOERTEL: ***WRN*** #iterations = " << i << std::endl << "MOERTEL: ***WRN*** F(eta) = " << F << " gradF(eta) = " << dF << " eta = " << eta << " delta(eta) = " << deta << "\n" << "MOERTEL: ***WRN*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; } #if 0 std::cout << "#iterations = " << i << " F = " << F << " eta = " << eta << std::endl; #endif xi[0] = eta; return ok; } // 3D version of the problem else { #if 0 std::cout << "----- Projector: Node " << node.Id() << " Segment " << seg.Id() << std::endl; std::cout << "Segment " << seg; MOERTEL::Node** nodes = seg.Nodes(); std::cout << *nodes[0]; std::cout << *nodes[1]; std::cout << *nodes[2]; #endif // we do a newton iteration for the projection coordinates xi // set starting value to the middle of the segment double eta[2]; if (seg.Nnode()==3) eta[0] = eta[1] = 1./3.; else eta[0] = eta[1] = 0.; double alpha = 0.0; int i=0; double F[3], dF[3][3], deta[3]; double eps; for (i=0; i<30; ++i) { evaluate_FgradF_3D_NodalNormal(F,dF,node,seg,eta,alpha,gap); eps = MOERTEL::dot(F,F,3); if (eps < 1.0e-10) break; // std::cout << eps << std::endl; MOERTEL::solve33(dF,deta,F); eta[0] -= deta[0]; eta[1] -= deta[1]; alpha -= deta[2]; } if (eps>1.0e-10) { ok = false; if (OutLevel()>3) std::cout << "MOERTEL: ***WRN*** MOERTEL::Projector::ProjectNodetoSegment_NodalNormal:\n" << "MOERTEL: ***WRN*** 3D Newton iteration failed to converge\n" << "MOERTEL: ***WRN*** #iterations = " << i << std::endl << "MOERTEL: ***WRN*** eps = " << eps << " eta[3] = " << eta[0] << "/" << eta[1] << "/" << alpha << "\n" << "MOERTEL: ***WRN*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; } #if 0 if (i>10) std::cout << "#iterations = " << i << " eps = " << eps << " eta = " << eta[0] << "/" << eta[1] << std::endl; #endif xi[0] = eta[0]; xi[1] = eta[1]; } // return ok; }
/*----------------------------------------------------------------------* | mwgee 07/05| | 2D case: | | this method evaluates the function | | gradF(eta) = | | ( Ni,eta * xis ) * ( Nj nyjs ) | | + ( Ni * xis - xm ) * ( Nj,eta * nyjs) | | - ( Ni,eta * yis ) * ( Nj nxjs ) | | - ( Ni * yis - ym ) * ( Nj,eta * nxjs) | | with Ni,eta derivative of shape functions of segment | | Ni,Nj shape functions of segment | | xis,yis nodal coords of segment's nodes i (slave side) | | xm,ym nodal coords of master node | | nxjs,nyjs outward normals of node j (slave side) | *----------------------------------------------------------------------*/ double MOERTEL::Projector::evaluate_gradF_2D_SegmentNormal(MOERTEL::Node& node, MOERTEL::Segment& seg, double eta) { // check the type of function on the segment // Here, we need 1D functions set as function id 0 MOERTEL::Function::FunctionType type = seg.FunctionType(0); if (type != MOERTEL::Function::func_Linear1D) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::evaluate_gradF_2D_SegmentNormal:\n" << "***ERR*** function is of wrong type\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } // evaluate function and derivatives of the first function set on segment at eta int nsnode = seg.Nnode(); double val[100]; double deriv[200]; seg.EvaluateFunction(0,&eta,val,nsnode,deriv); // several intermediate data: // Nx = Ni * xi // Nxeta = Ni,eta * xi // NN = Nj * nj // NNeta = Nj,eta * nj // get nodal coords and normals of nodes and interpolate them double Nx[2]; Nx[0] = Nx[1] = 0.0; double Nxeta[2]; Nxeta[0] = Nxeta[1] = 0.0; double NN[2]; NN[0] = NN[1] = 0.0; double NNeta[2]; NNeta[0] = NNeta[1] = 0.0; MOERTEL::Node** snodes = seg.Nodes(); if (!snodes) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::evaluate_gradF_2D_SegmentNormal:\n" << "***ERR*** segment " << seg.Id() << " ptr to it's nodes is zero\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } for (int i=0; i<nsnode; ++i) { const double* X = snodes[i]->X(); Nx[0] += val[i]*X[0]; Nx[1] += val[i]*X[1]; Nxeta[0] += deriv[i]*X[0]; Nxeta[1] += deriv[i]*X[1]; const double* N = snodes[i]->N(); NN[0] += val[i]*N[0]; NN[1] += val[i]*N[1]; NNeta[0] += deriv[i]*N[0]; NNeta[1] += deriv[i]*N[1]; } // get master node coords const double* xm = node.X(); // calculate gradF double gradF = Nxeta[0]*NN[1] + (Nx[0] - xm[0])*NNeta[1] - Nxeta[1]*NN[0] - (Nx[1] - xm[1])*NNeta[0]; return gradF; }
/*----------------------------------------------------------------------* | mwgee 07/05| | modded gah 07/2010 | | 2D case: | | this function evaluates the function | | F(eta) = ( Ni * xim - xs ) cross ns , | | with Ni shape functions of segment | | xim nodal coords of segment's nodes (master side) | | xs nodal coords of node (slave side) | | ns outward normal of node (slave side) | *----------------------------------------------------------------------*/ double MOERTEL::Projector::evaluate_F_2D_NodalNormal(MOERTEL::Node& node, MOERTEL::Segment& seg, double eta, double &gap) { // check the type of function on the segment // Here, we need 1D functions set as function id 0 MOERTEL::Function::FunctionType type = seg.FunctionType(0); if (type != MOERTEL::Function::func_Linear1D) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::evaluate_F_2D_NodalNormal:\n" << "***ERR*** function is of wrong type\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } // evaluate the first function set on segment at eta int nmnode = seg.Nnode(); double val[100]; seg.EvaluateFunction(0,&eta,val,nmnode,NULL); // get nodal coords of nodes and interpolate them double Nx[2]; Nx[0] = Nx[1] = 0.0; MOERTEL::Node** mnodes = seg.Nodes(); if (!mnodes) { std::stringstream oss; oss << "***ERR*** MOERTEL::Projector::evaluate_F_2D_NodalNormal:\n" << "***ERR*** segment " << seg.Id() << " ptr to it's nodes is zero\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; throw ReportError(oss); } // Here, Nx[0] and Nx[1] are the coordinates of the guess at the root for (int i=0; i<nmnode; ++i) { const double* X = mnodes[i]->X(); Nx[0] += val[i]*X[0]; Nx[1] += val[i]*X[1]; } // subtract xs (Coordinates of the slave node) const double* X = node.X(); Nx[0] -= X[0]; Nx[1] -= X[1]; // get the normal of node const double* n = node.N(); // calculate F double F = Nx[0]*n[1] - Nx[1]*n[0]; gap = Nx[0] * n[0] + Nx[1] * n[1]; // Do we need to divide by the length of the normal??? GAH // // gap = (Nx[0] * n[0] + Nx[1] * n[1]) // / sqrt(n[0] * n[0] + n[1] * n[1]); // ||gap|| cos theta #if 0 std::cout << "node " << node.Id() << " seg " << seg.Id() << " n[0] " << n[0] << " n[1] " << n[1] << std::endl; std::cout << "X[0] " << X[0] << " X[1] " << X[1] << std::endl; std::cout << "Nx[0] " << Nx[0] << " Nx[1] " << Nx[1] << " gap " << gap << std::endl; std::cout << "norm " << sqrt(n[0] * n[0] + n[1] * n[1]) << std::endl; #endif return F; }