// Calculate edge loads void Quad2D::CalcEdgeLoads(double *re,int iedge,int ndir,double *fload,int np) { // iedge is edge number (1 ... NumberSides()) int ind1=iedge,ind2,ind3; // assumes corners at 1 ... NumberSides() and midside nodes at // NumberSides+1 ... 2*NumberSides() ind2=ind1+NumberSides(); if(ind1==NumberSides()) ind3=1; else ind3=ind1+1; QuadEdgeLoad(ind1,ind2,ind3,ndir,fload,re,np); }
// If this node has crack tip nodes, move neighboring nodes toward the crack tip void Quad2D::MakeQuarterPointNodes(int crackTip,vector<int> &movedNodes) { // check real corner nodes (in nodes[0] to nodes[NumberSides()] int i,ct=-1;; for(i=0;i<NumberSides();i++) { if(nodes[i]==crackTip) { ct=i; break; } } if(ct<0) return; // edge after ct (assumes midside nodes and ct+NumberSides()) // note hav internal nodes after last midside node as 2*NumberSides()-1 (zero based) if(ct<NumberSides()-1) AdjustMidSideNode(ct,ct+NumberSides(),ct+1,movedNodes); else AdjustMidSideNode(NumberSides()-1,2*NumberSides()-1,0,movedNodes); // edge before ct if(ct>0) AdjustMidSideNode(ct,ct-1+NumberSides(),ct-1,movedNodes); else AdjustMidSideNode(0,2*NumberSides()-1,NumberSides()-1,movedNodes); }
/* Find element (0 based) that touches the element face stating in gridNode First time called, search other elements for the edge, but then store result Assumes nodes[NumberNodes()]=nodes[0] return NO_NEIGHBOR (-1) if no neighbor (i.e., on edge of grid) return UNKNOWN_NEIGHBOR (-2) if gridNode not in this element */ int ElementBase::Neighbor(int gridNode) { int i,edge=-1; // first find which edge (0 to NumberSides()-1) to search? for(i=0;i<NumberSides();i++) { if(nodes[i]==gridNode) { edge=i; break; } } // if edge not found and error because the gridNode is not even in this element if(edge<0) return UNKNOWN_NEIGHBOR; // search for neighbor if needed if(neighbors[edge]==UNKNOWN_NEIGHBOR) { int nextNode=nodes[edge+1]; neighbors[edge]=NO_NEIGHBOR; // search for element with nextNode,gridNode in ccw direction for(i=0;i<nelems;i++) { if(theElements[i]->FindEdge(nextNode,gridNode)>=0) { neighbors[edge]=i; break; } } } // return result return neighbors[edge]; }
/* Use ray crossing algorithm to find out if a point (pt.x,pt.y) is in an element nd is pointer to 1-based array NodalPoints */ short Quad2D::PtInElement(Vector &pt) const { short i,ns=NumberSides(),crossings=0; double d,x1,y1,x2,y2; for(i=0;i<ns;i++) { // start to mid side node x1=nd[nodes[i]]->x; y1=nd[nodes[i]]->y; x2=nd[nodes[i+ns]]->x; y2=nd[nodes[i+ns]]->y; d=(pt.y-y1)*(x2-x1) - (pt.x-x1)*(y2-y1); // get crossing unless both y's on same side of edge if((y1>=pt.y) != (y2>=pt.y)) { crossings+= (y2-y1>=0.) ? d>=0. : d<=0. ; } // if d is 0, check if point is on line (and thus in polygon) if(!d && fmin(x1,x2)<=pt.x && pt.x<=fmax(x1,x2) && fmin(y1,y2)<=pt.y && pt.y<=fmax(y1,y2)) { return(1); } // mid side node to end x1=x2; y1=y2; if(i+1<ns) { x2=nd[nodes[i+1]]->x; y2=nd[nodes[i+1]]->y; } else { x2=nd[nodes[0]]->x; y2=nd[nodes[0]]->y; } d=(pt.y-y1)*(x2-x1) - (pt.x-x1)*(y2-y1); // get crossing unless both y's on same side of egde if((y1>=pt.y) != (y2>=pt.y)) { crossings+= (y2-y1>=0.) ? d>=0. : d<=0. ; } // if d is 0, check if point is on line (and thus in polygon if(!d && fmin(x1,x2)<=pt.x && pt.x<=fmax(x1,x2) && fmin(y1,y2)<=pt.y && pt.y<=fmax(y1,y2)) { return(1); } } return crossings & 0x01; }
/* Calculate area of element (in mm^2 because nodes in mm) nodes is pointer to 0-based array NodalPoints */ double Quad2D::GetArea(void) const { short i,ns=NumberSides(),nn=NumberNodes()-1; double area; area=0.; for(i=0;i<ns-1;i++) { area+=nd[nodes[i]]->x*nd[nodes[i+ns]]->y -nd[nodes[i]]->y*nd[nodes[i+ns]]->x +nd[nodes[i+ns]]->x*nd[nodes[i+1]]->y -nd[nodes[i+ns]]->y*nd[nodes[i+1]]->x; } ns--; area+=nd[nodes[ns]]->x*nd[nodes[nn]]->y -nd[nodes[ns]]->y*nd[nodes[nn]]->x +nd[nodes[nn]]->x*nd[nodes[0]]->y -nd[nodes[nn]]->y*nd[nodes[0]]->x; return area/2.; }
// If needed, create the neighbors array (only done for 2D with cracks) void ElementBase::AllocateNeighborsArray(void) { neighbors = new int[NumberSides()]; int i; for(i=0;i<NumberSides();i++) neighbors[i]=UNKNOWN_NEIGHBOR; }
// return dimensionless location for material points void ElementBase::MPMPoints(short numPerElement,Vector *mpos) const { int i,j,k; double fxn[MaxElNd],row,zrow; if(NumberSides()==4) { switch(numPerElement) { case 4: // ENI or FNI - 2D only mpos[0].x=-.5; mpos[0].y=-.5; mpos[0].z=0.; mpos[1].x=.5; mpos[1].y=-.5; mpos[1].z=0.; mpos[2].x=-.5; mpos[2].y=.5; mpos[2].z=0.; mpos[3].x=.5; mpos[3].y=.5; mpos[3].z=0.; break; case 1: // CM of square or brick mpos[0].x=0.; mpos[0].y=0.; mpos[0].z=0.; break; case 8: // 3D box mpos[0].x=-.5; mpos[0].y=-.5; mpos[0].z=-.5; mpos[1].x=.5; mpos[1].y=-.5; mpos[1].z=-.5; mpos[2].x=-.5; mpos[2].y=.5; mpos[2].z=-.5; mpos[3].x=.5; mpos[3].y=.5; mpos[3].z=-.5; mpos[4].x=-.5; mpos[4].y=-.5; mpos[4].z=.5; mpos[5].x=.5; mpos[5].y=-.5; mpos[5].z=.5; mpos[6].x=-.5; mpos[6].y=.5; mpos[6].z=.5; mpos[7].x=.5; mpos[7].y=.5; mpos[7].z=.5; break; case 9: // 2D k=0; row = -2./3.; for(j=0;j<3;j++) { mpos[k].x=-2./3.; mpos[k].y=row; mpos[k].z=0.; mpos[k+1].x=0.; mpos[k+1].y=row; mpos[k+1].z=0.; mpos[k+2].x=2./3.; mpos[k+2].y=row; mpos[k+2].z=0.; k += 3; row += 2./3.; } break; case 16: // 2D k=0; row = -0.75; for(j=0;j<4;j++) { mpos[k].x=-0.75; mpos[k].y=row; mpos[k].z=0.; mpos[k+1].x=-.25; mpos[k+1].y=row; mpos[k+1].z=0.; mpos[k+2].x=.25; mpos[k+2].y=row; mpos[k+2].z=0.; mpos[k+3].x=.75; mpos[k+3].y=row; mpos[k+3].z=0.; k += 4; row += 0.5; } break; case 25: // 2D k=0; row = -0.8; for(j=0;j<5;j++) { mpos[k].x=-0.8; mpos[k].y=row; mpos[k].z=0.; mpos[k+1].x=-.4; mpos[k+1].y=row; mpos[k+1].z=0.; mpos[k+2].x=0.; mpos[k+2].y=row; mpos[k+2].z=0.; mpos[k+3].x=.4; mpos[k+3].y=row; mpos[k+3].z=0.; mpos[k+4].x=.8; mpos[k+4].y=row; mpos[k+4].z=0.; k += 5; row += 0.4; } break; case 27: // 3D k=0; zrow = -2./3.; for(i=0;i<3;i++) { row = -2./3.; for(j=0;j<3;j++) { mpos[k].x=-2./3.; mpos[k].y=row; mpos[k].z=zrow; mpos[k+1].x=0.; mpos[k+1].y=row; mpos[k+1].z=zrow; mpos[k+2].x=2./3.; mpos[k+2].y=row; mpos[k+2].z=zrow; k += 3; row += 2./3.; } zrow += 2./3.; } break; default: throw CommonException("Invalid number of material points per element.","ElementBase::MPMPoints"); break; } } // covert to x-y-z locations for(k=0;k<numPerElement;k++) { ShapeFunction(&mpos[k],FALSE,fxn,NULL,NULL,NULL); ZeroVector(&mpos[k]); for(j=0;j<NumberNodes();j++) { mpos[k].x+=nd[nodes[j]]->x*fxn[j]; mpos[k].y+=nd[nodes[j]]->y*fxn[j]; mpos[k].z+=nd[nodes[j]]->z*fxn[j]; } } }