void MixedGradientPressureWeakPeriodic :: computeStress(FloatArray &sigmaDev, FloatArray &tractions, double rve_size) { FloatMatrix mMatrix; FloatArray normal, coords, t; int nsd = domain->giveNumberOfSpatialDimensions(); Set *set = this->giveDomain()->giveSet(this->set); const IntArray &boundaries = set->giveBoundaryList(); // Reminder: sigma = int t * n dA, where t = sum( C_i * n t_i ). // This loop will construct sigma in matrix form. FloatMatrix sigma; for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) { Element *el = this->giveDomain()->giveElement( boundaries.at(pos * 2 - 1) ); int boundary = boundaries.at(pos * 2); FEInterpolation *interp = el->giveInterpolation(); // Geometry interpolation. The displacements or velocities must have the same interpolation scheme (on the boundary at least). int maxorder = this->order + interp->giveInterpolationOrder() * 3; std :: unique_ptr< IntegrationRule >ir( interp->giveBoundaryIntegrationRule(maxorder, boundary) ); for ( GaussPoint *gp: *ir ) { const FloatArray &lcoords = gp->giveNaturalCoordinates(); FEIElementGeometryWrapper cellgeo(el); double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo); // Compute v_m = d_dev . x interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo); this->constructMMatrix(mMatrix, coords, normal); t.beProductOf(mMatrix, tractions); sigma.plusDyadUnsym(t, coords, detJ * gp->giveWeight()); } } sigma.times(1. / rve_size); double pressure = 0.; for ( int i = 1; i <= nsd; i++ ) { pressure += sigma.at(i, i); } pressure /= 3; // Not 100% sure about this for 2D cases. if ( nsd == 3 ) { sigmaDev.resize(6); sigmaDev.at(1) = sigma.at(1, 1) - pressure; sigmaDev.at(2) = sigma.at(2, 2) - pressure; sigmaDev.at(3) = sigma.at(3, 3) - pressure; sigmaDev.at(4) = 0.5 * ( sigma.at(2, 3) + sigma.at(3, 2) ); sigmaDev.at(5) = 0.5 * ( sigma.at(1, 3) + sigma.at(3, 1) ); sigmaDev.at(6) = 0.5 * ( sigma.at(1, 2) + sigma.at(2, 1) ); } else if ( nsd == 2 ) { sigmaDev.resize(3); sigmaDev.at(1) = sigma.at(1, 1) - pressure; sigmaDev.at(2) = sigma.at(2, 2) - pressure; sigmaDev.at(3) = 0.5 * ( sigma.at(1, 2) + sigma.at(2, 1) ); } else { sigmaDev.resize(1); sigmaDev.at(1) = sigma.at(1, 1) - pressure; } }
void MixedGradientPressureWeakPeriodic :: integrateTractionDev(FloatArray &answer, Element *el, int boundary, const FloatMatrix &ddev) { // Computes the integral: int dt . dx dA FloatMatrix mMatrix; FloatArray normal, coords, vM_dev; FEInterpolation *interp = el->giveInterpolation(); // Geometry interpolation. The displacements or velocities must have the same interpolation scheme (on the boundary at least). int maxorder = this->order + interp->giveInterpolationOrder() * 3; std :: unique_ptr< IntegrationRule >ir( interp->giveBoundaryIntegrationRule(maxorder, boundary) ); answer.clear(); for ( GaussPoint *gp: *ir ) { const FloatArray &lcoords = gp->giveNaturalCoordinates(); FEIElementGeometryWrapper cellgeo(el); double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo); // Compute v_m = d_dev . x interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo); vM_dev.beProductOf(ddev, coords); this->constructMMatrix(mMatrix, coords, normal); answer.plusProduct(mMatrix, vM_dev, detJ * gp->giveWeight()); } }
void MixedGradientPressureWeakPeriodic :: integrateTractionXTangent(FloatMatrix &answer, Element *el, int boundary) { // Computes the integral: int dt . dx_m dA FloatMatrix mMatrix; FloatArray normal, coords, vM_vol; FEInterpolation *interp = el->giveInterpolation(); // Geometry interpolation. The displacements or velocities must have the same interpolation scheme (on the boundary at least). int maxorder = this->order + interp->giveInterpolationOrder() * 3; std :: unique_ptr< IntegrationRule >ir( interp->giveBoundaryIntegrationRule(maxorder, boundary) ); FloatArray tmpAnswer; for ( GaussPoint *gp: *ir ) { const FloatArray &lcoords = gp->giveNaturalCoordinates(); FEIElementGeometryWrapper cellgeo(el); double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo); interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo); vM_vol.beScaled(1.0/3.0, coords); this->constructMMatrix(mMatrix, coords, normal); tmpAnswer.plusProduct(mMatrix, vM_vol, detJ * gp->giveWeight()); } answer.resize(tmpAnswer.giveSize(), 1); answer.setColumn(tmpAnswer, 1); }
void MixedGradientPressureWeakPeriodic :: integrateTractionVelocityTangent(FloatMatrix &answer, Element *el, int boundary) { // Computes the integral: int dt . dv dA FloatArray normal, n, coords; FloatMatrix nMatrix, mMatrix; FEInterpolation *interp = el->giveInterpolation(); // Geometry interpolation. The displacements or velocities must have the same interpolation scheme (on the boundary at least). int maxorder = this->order + interp->giveInterpolationOrder() * 3; std :: unique_ptr< IntegrationRule >ir( interp->giveBoundaryIntegrationRule(maxorder, boundary) ); int nsd = this->giveDomain()->giveNumberOfSpatialDimensions(); answer.clear(); for ( GaussPoint *gp: *ir ) { const FloatArray &lcoords = gp->giveNaturalCoordinates(); FEIElementGeometryWrapper cellgeo(el); double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo); interp->boundaryEvalN(n, boundary, lcoords, cellgeo); interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo); // Construct the basis functions for the tractions: this->constructMMatrix(mMatrix, coords, normal); nMatrix.beNMatrixOf(n, nsd); answer.plusProductUnsym( mMatrix, nMatrix, detJ * gp->giveWeight() ); } }
void SurfaceTensionBoundaryCondition :: computeLoadVectorFromElement(FloatArray &answer, Element *e, int side, TimeStep *tStep) { FEInterpolation *fei = e->giveInterpolation(); if ( !fei ) { OOFEM_ERROR("No interpolation or default integration available for element."); } std :: unique_ptr< IntegrationRule > iRule( fei->giveBoundaryIntegrationRule(fei->giveInterpolationOrder()-1, side) ); int nsd = e->giveDomain()->giveNumberOfSpatialDimensions(); if ( side == -1 ) { side = 1; } answer.clear(); if ( nsd == 2 ) { FEInterpolation2d *fei2d = static_cast< FEInterpolation2d * >(fei); ///@todo More of this grunt work should be moved to the interpolation classes IntArray bnodes; fei2d->boundaryGiveNodes(bnodes, side); int nodes = bnodes.giveSize(); FloatMatrix xy(2, nodes); for ( int i = 1; i <= nodes; i++ ) { Node *node = e->giveNode(bnodes.at(i)); ///@todo This should rely on the xindex and yindex in the interpolator.. xy.at(1, i) = node->giveCoordinate(1); xy.at(2, i) = node->giveCoordinate(2); } FloatArray tmp; // Integrand FloatArray es; // Tangent vector to curve FloatArray dNds; if ( e->giveDomain()->isAxisymmetric() ) { FloatArray N; FloatArray gcoords; for ( GaussPoint *gp: *iRule ) { fei2d->edgeEvaldNds( dNds, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); fei->boundaryEvalN( N, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double J = fei->boundaryGiveTransformationJacobian( side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); fei->boundaryLocal2Global( gcoords, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double r = gcoords(0); // First coordinate is the radial coord. es.beProductOf(xy, dNds); tmp.resize( 2 * nodes); for ( int i = 0; i < nodes; i++ ) { tmp(2 * i) = dNds(i) * es(0) * r + N(i); tmp(2 * i + 1) = dNds(i) * es(1) * r; } answer.add(- 2 * M_PI * gamma * J * gp->giveWeight(), tmp); } } else { for ( GaussPoint *gp: *iRule ) { double t = e->giveCrossSection()->give(CS_Thickness, gp); fei2d->edgeEvaldNds( dNds, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double J = fei->boundaryGiveTransformationJacobian( side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); es.beProductOf(xy, dNds); tmp.resize( 2 * nodes); for ( int i = 0; i < nodes; i++ ) { tmp(2 * i) = dNds(i) * es(0); tmp(2 * i + 1) = dNds(i) * es(1); //B.at(1, 1+i*2) = B.at(2, 2+i*2) = dNds(i); } //tmp.beTProductOf(B, es); answer.add(- t * gamma * J * gp->giveWeight(), tmp); } } } else if ( nsd == 3 ) { FEInterpolation3d *fei3d = static_cast< FEInterpolation3d * >(fei); FloatArray n, surfProj; FloatMatrix dNdx, B; for ( GaussPoint *gp: *iRule ) { fei3d->surfaceEvaldNdx( dNdx, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double J = fei->boundaryEvalNormal( n, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); // [I - n(x)n] in voigt form: surfProj = {1. - n(0)*n(0), 1. - n(1)*n(1), 1. - n(2)*n(2), - n(1)*n(2), - n(0)*n(2), - n(0)*n(1), }; // Construct B matrix of the surface nodes B.resize(6, 3 * dNdx.giveNumberOfRows()); for ( int i = 1; i <= dNdx.giveNumberOfRows(); i++ ) { B.at(1, 3 * i - 2) = dNdx.at(i, 1); B.at(2, 3 * i - 1) = dNdx.at(i, 2); B.at(3, 3 * i - 0) = dNdx.at(i, 3); B.at(5, 3 * i - 2) = B.at(4, 3 * i - 1) = dNdx.at(i, 3); B.at(6, 3 * i - 2) = B.at(4, 3 * i - 0) = dNdx.at(i, 2); B.at(6, 3 * i - 1) = B.at(5, 3 * i - 0) = dNdx.at(i, 1); } answer.plusProduct(B, surfProj, -gamma * J * gp->giveWeight() ); } } }
void SurfaceTensionBoundaryCondition :: computeTangentFromElement(FloatMatrix &answer, Element *e, int side, TimeStep *tStep) { FEInterpolation *fei = e->giveInterpolation(); if ( !fei ) { OOFEM_ERROR("No interpolation available for element."); } std :: unique_ptr< IntegrationRule > iRule( fei->giveBoundaryIntegrationRule(fei->giveInterpolationOrder()-1, side) ); int nsd = e->giveDomain()->giveNumberOfSpatialDimensions(); int nodes = e->giveNumberOfNodes(); if ( side == -1 ) { side = 1; } answer.clear(); if ( nsd == 2 ) { FEInterpolation2d *fei2d = static_cast< FEInterpolation2d * >(fei); ///@todo More of this grunt work should be moved to the interpolation classes FloatMatrix xy(2, nodes); Node *node; for ( int i = 1; i <= nodes; i++ ) { node = e->giveNode(i); xy.at(1, i) = node->giveCoordinate(1); xy.at(2, i) = node->giveCoordinate(2); } FloatArray tmpA(2 *nodes); FloatArray es; // Tangent vector to curve FloatArray dNds; FloatMatrix B(2, 2 *nodes); B.zero(); if ( e->giveDomain()->isAxisymmetric() ) { FloatArray N; FloatArray gcoords; FloatArray tmpB(2 *nodes); for ( GaussPoint *gp: *iRule ) { fei2d->edgeEvaldNds( dNds, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); fei->boundaryEvalN( N, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double J = fei->boundaryGiveTransformationJacobian( side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); fei->boundaryLocal2Global( gcoords, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double r = gcoords(0); // First coordinate is the radial coord. es.beProductOf(xy, dNds); // Construct the different matrices in the integrand; for ( int i = 0; i < nodes; i++ ) { tmpA(i * 2 + 0) = dNds(i) * es(0); tmpA(i * 2 + 1) = dNds(i) * es(1); tmpB(i * 2 + 0) = N(i); tmpB(i * 2 + 1) = 0; B(i * 2, 0) = B(i * 2 + 1, 1) = dNds(i); } double dV = 2 *M_PI *gamma *J *gp->giveWeight(); answer.plusDyadUnsym(tmpA, tmpB, dV); answer.plusDyadUnsym(tmpB, tmpA, dV); answer.plusProductSymmUpper(B, B, r * dV); answer.plusDyadUnsym(tmpA, tmpA, -r * dV); } } else { for ( GaussPoint *gp: *iRule ) { double t = e->giveCrossSection()->give(CS_Thickness, gp); ///@todo The thickness is not often relevant or used in FM. fei2d->edgeEvaldNds( dNds, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double J = fei->boundaryGiveTransformationJacobian( side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); es.beProductOf(xy, dNds); // Construct the different matrices in the integrand; for ( int i = 0; i < nodes; i++ ) { tmpA(i * 2 + 0) = dNds(i) * es(0); tmpA(i * 2 + 1) = dNds(i) * es(1); B(i * 2, 0) = B(i * 2 + 1, 1) = dNds(i); } double dV = t * gamma * J * gp->giveWeight(); answer.plusProductSymmUpper(B, B, dV); answer.plusDyadSymmUpper(tmpA, -dV); } } answer.symmetrized(); } else if ( nsd == 3 ) { FEInterpolation3d *fei3d = static_cast< FEInterpolation3d * >(fei); OOFEM_ERROR("3D tangents not implemented yet."); //FloatMatrix tmp(3 *nodes, 3 *nodes); FloatMatrix dNdx; FloatArray n; for ( GaussPoint *gp: *iRule ) { fei3d->surfaceEvaldNdx( dNdx, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); /*double J = */ fei->boundaryEvalNormal( n, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); //double dV = gamma * J * gp->giveWeight(); for ( int i = 0; i < nodes; i++ ) { //tmp(3*i+0) = dNdx(i,0) - (dNdx(i,0)*n(0)* + dNdx(i,1)*n(1) + dNdx(i,2)*n(2))*n(0); //tmp(3*i+1) = dNdx(i,1) - (dNdx(i,0)*n(0)* + dNdx(i,1)*n(1) + dNdx(i,2)*n(2))*n(1); //tmp(3*i+2) = dNdx(i,2) - (dNdx(i,0)*n(0)* + dNdx(i,1)*n(1) + dNdx(i,2)*n(2))*n(2); } //answer.plusProductSymmUpper(A,B, dV); ///@todo Derive expressions for this. } } else { OOFEM_WARNING("Only 2D or 3D is possible!"); } }
void PrescribedGradientBCNeumann :: integrateTangent(FloatMatrix &oTangent, Element *e, int iBndIndex) { FloatArray normal, n; FloatMatrix nMatrix, E_n; FloatMatrix contrib; Domain *domain = e->giveDomain(); XfemElementInterface *xfemElInt = dynamic_cast< XfemElementInterface * >( e ); FEInterpolation *interp = e->giveInterpolation(); // Geometry interpolation int nsd = e->giveDomain()->giveNumberOfSpatialDimensions(); // Interpolation order int order = interp->giveInterpolationOrder(); IntegrationRule *ir = NULL; IntArray edgeNodes; FEInterpolation2d *interp2d = dynamic_cast< FEInterpolation2d * >( interp ); if ( interp2d == NULL ) { OOFEM_ERROR("failed to cast to FEInterpolation2d.") } interp2d->computeLocalEdgeMapping(edgeNodes, iBndIndex); const FloatArray &xS = * ( e->giveDofManager( edgeNodes.at(1) )->giveCoordinates() ); const FloatArray &xE = * ( e->giveDofManager( edgeNodes.at( edgeNodes.giveSize() ) )->giveCoordinates() ); if ( xfemElInt != NULL && domain->hasXfemManager() ) { std :: vector< Line >segments; std :: vector< FloatArray >intersecPoints; xfemElInt->partitionEdgeSegment(iBndIndex, segments, intersecPoints); MaterialMode matMode = e->giveMaterialMode(); ir = new DiscontinuousSegmentIntegrationRule(1, e, segments, xS, xE); int numPointsPerSeg = 1; ir->SetUpPointsOnLine(numPointsPerSeg, matMode); } else { ir = interp->giveBoundaryIntegrationRule(order, iBndIndex); } oTangent.clear(); for ( GaussPoint *gp: *ir ) { FloatArray &lcoords = * gp->giveNaturalCoordinates(); FEIElementGeometryWrapper cellgeo(e); // Evaluate the normal; double detJ = interp->boundaryEvalNormal(normal, iBndIndex, lcoords, cellgeo); interp->boundaryEvalN(n, iBndIndex, lcoords, cellgeo); // If cracks cross the edge, special treatment is necessary. // Exploit the XfemElementInterface to minimize duplication of code. if ( xfemElInt != NULL && domain->hasXfemManager() ) { // Compute global coordinates of Gauss point FloatArray globalCoord; interp->boundaryLocal2Global(globalCoord, iBndIndex, lcoords, cellgeo); // Compute local coordinates on the element FloatArray locCoord; e->computeLocalCoordinates(locCoord, globalCoord); xfemElInt->XfemElementInterface_createEnrNmatrixAt(nMatrix, locCoord, * e, false); } else { // Evaluate the velocity/displacement coefficients nMatrix.beNMatrixOf(n, nsd); } if ( nsd == 3 ) { OOFEM_ERROR("not implemented for nsd == 3.") } else if ( nsd == 2 ) { E_n.resize(4, 2); E_n.at(1, 1) = normal.at(1); E_n.at(1, 2) = 0.0; E_n.at(2, 1) = 0.0; E_n.at(2, 2) = normal.at(2); E_n.at(3, 1) = normal.at(2); E_n.at(3, 2) = 0.0; E_n.at(4, 1) = 0.0; E_n.at(4, 2) = normal.at(1); } else { E_n.clear(); } contrib.beProductOf(E_n, nMatrix); oTangent.add(detJ * gp->giveWeight(), contrib); } delete ir; }