void Quad1MindlinShell3D :: computeBmatrixAt(GaussPoint *gp, FloatMatrix &answer, int li, int ui) { FloatArray n, ns; FloatMatrix dn, dns; const FloatArray &localCoords = * gp->giveNaturalCoordinates(); this->interp.evaldNdx( dn, localCoords, FEIVertexListGeometryWrapper(lnodes) ); this->interp.evalN( n, localCoords, FEIVoidCellGeometry() ); answer.resize(8, 4 * 5); answer.zero(); // enforce one-point reduced integration if requested if ( this->reducedIntegrationFlag ) { FloatArray lc(2); lc.zero(); // set to element center coordinates this->interp.evaldNdx( dns, lc, FEIVertexListGeometryWrapper(lnodes) ); this->interp.evalN( ns, lc, FEIVoidCellGeometry() ); } else { dns = dn; ns = n; } // Note: This is just 5 dofs (sixth column is all zero, torsional stiffness handled separately.) for ( int i = 0; i < 4; ++i ) { ///@todo Check the rows for both parts here, to be consistent with _3dShell material definition // Part related to the membrane (columns represent coefficients for D_u, D_v) answer(0, 0 + i * 5) = dn(i, 0);//eps_x = du/dx answer(1, 1 + i * 5) = dn(i, 1);//eps_y = dv/dy answer(2, 0 + i * 5) = dn(i, 1);//gamma_xy = du/dy+dv/dx answer(2, 1 + i * 5) = dn(i, 0); // Part related to the plate (columns represent the dofs D_w, R_u, R_v) ///@todo Check sign here answer(3 + 0, 2 + 2 + i * 5) = dn(i, 0);// kappa_x = d(fi_y)/dx answer(3 + 1, 2 + 1 + i * 5) =-dn(i, 1);// kappa_y = -d(fi_x)/dy answer(3 + 2, 2 + 2 + i * 5) = dn(i, 1);// kappa_xy=d(fi_y)/dy-d(fi_x)/dx answer(3 + 2, 2 + 1 + i * 5) =-dn(i, 0); // shear strains answer(3 + 3, 2 + 0 + i * 5) = dns(i, 0);// gamma_xz = fi_y+dw/dx answer(3 + 3, 2 + 2 + i * 5) = ns(i); answer(3 + 4, 2 + 0 + i * 5) = dns(i, 1);// gamma_yz = -fi_x+dw/dy answer(3 + 4, 2 + 1 + i * 5) = -ns(i); } }
void Quad1MindlinShell3D :: computeBmatrixAt(GaussPoint *gp, FloatMatrix &answer, int li, int ui) { FloatArray n; FloatMatrix dn; this->interp.evaldNdx(dn, *gp->giveCoordinates(), FEIVertexListGeometryWrapper(4, (const FloatArray **)lnodes)); this->interp.evalN(n, *gp->giveCoordinates(), FEIVoidCellGeometry()); answer.resize(8, 4*5); answer.zero(); // Note: This is just 5 dofs (sixth column is all zero, torsional stiffness handled separately.) for (int i = 0; i < 4; ++i) { ///@todo Check the rows for both parts here, to be consistent with _3dShell material definition // Part related to the membrane (columns represent coefficients for D_u, D_v) answer(0, 0 + i*5) = dn(i,0); answer(1, 1 + i*5) = dn(i,1); answer(2, 0 + i*5) = dn(i,1); answer(2, 1 + i*5) = dn(i,0); // Part related to the plate (columns represent the dofs D_w, R_u, R_v) ///@todo Check sign here answer(3 + 0, 2 + 1 + i*5) = dn(i,0); answer(3 + 1, 2 + 2 + i*5) = dn(i,1); answer(3 + 2, 2 + 1 + i*5) = dn(i,1); answer(3 + 2, 2 + 2 + i*5) = dn(i,0); answer(3 + 3, 2 + 0 + i*5) = -dn(i,1); answer(3 + 3, 2 + 2 + i*5) = n(i); answer(3 + 4, 2 + 0 + i*5) = -dn(i,0); answer(3 + 4, 2 + 1 + i*5) = n(i); } }
void Quad1MindlinShell3D :: computeSurfaceLoadVectorAt(FloatArray &answer, Load *load, int iSurf, TimeStep *tStep, ValueModeType mode) { BoundaryLoad *surfLoad = static_cast< BoundaryLoad * >(load); if ( dynamic_cast< ConstantPressureLoad * >(surfLoad) ) { // Just checking the type of b.c. // EXPERIMENTAL CODE: FloatArray n, gcoords, pressure; answer.resize(24); answer.zero(); for ( GaussPoint *gp: *integrationRulesArray [ 0 ] ) { double dV = this->computeVolumeAround(gp); this->interp.evalN( n, * gp->giveNaturalCoordinates(), FEIVoidCellGeometry() ); this->interp.local2global( gcoords, * gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(this) ); surfLoad->computeValueAt(pressure, tStep, gcoords, mode); answer.at(3) += n.at(1) * pressure.at(1) * dV; answer.at(9) += n.at(2) * pressure.at(1) * dV; answer.at(15) += n.at(3) * pressure.at(1) * dV; answer.at(21) += n.at(4) * pressure.at(1) * dV; } // Second surface is the outside; if ( iSurf == 2 ) { answer.negated(); } } else { OOFEM_ERROR("only supports constant pressure boundary load."); } }
void Quad1MindlinShell3D :: giveInternalForcesVector(FloatArray &answer, TimeStep *tStep, int useUpdatedGpRecord) { // We need to overload this for practical reasons (this 3d shell has all 9 dofs, but the shell part only cares for the first 8) // This elements adds an additional stiffness for the so called drilling dofs, meaning we need to work with all 9 components. FloatMatrix b, d; FloatArray n, strain, stress; FloatArray shellUnknowns(20), drillUnknowns(4), unknowns; this->computeVectorOf(EID_MomentumBalance, VM_Total, tStep, unknowns); // Split this for practical reasons into normal shell dofs and drilling dofs for ( int i = 0; i < 4; ++i ) { shellUnknowns(0 + i*5) = unknowns(0 + i*6); shellUnknowns(1 + i*5) = unknowns(1 + i*6); shellUnknowns(2 + i*5) = unknowns(2 + i*6); shellUnknowns(3 + i*5) = unknowns(3 + i*6); shellUnknowns(4 + i*5) = unknowns(4 + i*6); drillUnknowns(i) = unknowns(5 + i*6); } FloatArray shellForces(20), drillMoment(4); shellForces.zero(); drillMoment.zero(); StructuralCrossSection *cs = this->giveStructuralCrossSection(); double drillCoeff = cs->give(CS_DrillingStiffness); IntegrationRule *iRule = integrationRulesArray [ 0 ]; for ( int i = 0; i < iRule->giveNumberOfIntegrationPoints(); i++ ) { GaussPoint *gp = iRule->getIntegrationPoint(i); this->computeBmatrixAt(gp, b); double dV = this->computeVolumeAround(gp); if ( useUpdatedGpRecord ) { stress = static_cast< StructuralMaterialStatus * >( this->giveMaterial()->giveStatus(gp) )->giveStressVector(); } else { strain.beProductOf(b, shellUnknowns); cs->giveRealStress_Shell(stress, gp, strain, tStep); } shellForces.plusProduct(b, stress, dV); // Drilling stiffness is here for improved numerical properties if (drillCoeff > 0.) { this->interp.evalN(n, *gp->giveCoordinates(), FEIVoidCellGeometry()); for ( int j = 0; j < 4; j++) { n(j) -= 0.25; } double dtheta = n.dotProduct(drillUnknowns); drillMoment.add(drillCoeff * dV * dtheta, n); ///@todo Decide on how to alpha should be defined. } } answer.resize(24); answer.zero(); answer.assemble(shellForces, this->shellOrdering); if (drillCoeff > 0.) { answer.assemble(drillMoment, this->drillOrdering); } }
void Quad1MindlinShell3D :: computeNmatrixAt(GaussPoint *gp, FloatMatrix &answer) // Returns the [3x9] displacement interpolation matrix {N} of the receiver, // evaluated at gp. { FloatArray n; this->interp.evalN(n, *gp->giveCoordinates(), FEIVoidCellGeometry()); answer.beNMatrixOf(n, 3); }
void Quad1MindlinShell3D :: computeEgdeNMatrixAt(FloatMatrix &answer, int iedge, GaussPoint *gp) { IntArray edgeNodes; FloatArray n; this->interp.edgeEvalN( n, iedge, * gp->giveNaturalCoordinates(), FEIVoidCellGeometry() ); this->interp.computeLocalEdgeMapping(edgeNodes, iedge); answer.beNMatrixOf(n, 6); }
void Quad1MindlinShell3D :: computeBodyLoadVectorAt(FloatArray &answer, Load *forLoad, TimeStep *stepN, ValueModeType mode) { // Only gravity load double dV, density; GaussPoint *gp; FloatArray forceX, forceY, forceZ, glob_gravity, gravity, n; if ( ( forLoad->giveBCGeoType() != BodyLoadBGT ) || ( forLoad->giveBCValType() != ForceLoadBVT ) ) { _error("computeBodyLoadVectorAt: unknown load type"); } // note: force is assumed to be in global coordinate system. forLoad->computeComponentArrayAt(glob_gravity, stepN, mode); // Transform the load into the local c.s. gravity.beProductOf(this->lcsMatrix, glob_gravity); ///@todo Check potential transpose here. if ( gravity.giveSize() ) { IntegrationRule *ir = integrationRulesArray [ 0 ]; for ( int i = 0; i < ir->giveNumberOfIntegrationPoints(); ++i) { gp = ir->getIntegrationPoint(i); this->interp.evalN(n, *gp->giveCoordinates(), FEIVoidCellGeometry()); dV = this->computeVolumeAround(gp) * this->giveCrossSection()->give(CS_Thickness); density = this->giveMaterial()->give('d', gp); forceX.add(density * gravity.at(1) * dV, n); forceY.add(density * gravity.at(2) * dV, n); forceZ.add(density * gravity.at(3) * dV, n); } answer.resize(24); answer.zero(); answer.at(1) = forceX.at(1); answer.at(2) = forceY.at(1); answer.at(3) = forceZ.at(1); answer.at(7) = forceX.at(2); answer.at(8) = forceY.at(2); answer.at(9) = forceZ.at(2); answer.at(13) = forceX.at(3); answer.at(14) = forceY.at(3); answer.at(15) = forceZ.at(3); answer.at(19) = forceX.at(4); answer.at(20) = forceY.at(4); answer.at(21) = forceZ.at(4); } else { answer.resize(0); } }
void Quad1MindlinShell3D :: giveInternalForcesVector(FloatArray &answer, TimeStep *tStep, int useUpdatedGpRecord) { // We need to overload this for practical reasons (this 3d shell has all 9 dofs, but the shell part only cares for the first 8) // This elements adds an additional stiffness for the so called drilling dofs, meaning we need to work with all 9 components. FloatMatrix b, d; FloatArray n, strain, stress; FloatArray shellUnknowns, drillUnknowns, unknowns; bool drillCoeffFlag = false; // Split this for practical reasons into normal shell dofs and drilling dofs this->computeVectorOf({D_u, D_v, D_w, R_u, R_v}, VM_Total, tStep, shellUnknowns); this->computeVectorOf({R_w}, VM_Total, tStep, drillUnknowns); FloatArray shellForces, drillMoment; StructuralCrossSection *cs = this->giveStructuralCrossSection(); for ( GaussPoint *gp: *integrationRulesArray [ 0 ] ) { this->computeBmatrixAt(gp, b); double dV = this->computeVolumeAround(gp); double drillCoeff = cs->give(CS_DrillingStiffness, gp); if ( useUpdatedGpRecord ) { stress = static_cast< StructuralMaterialStatus * >( gp->giveMaterialStatus() )->giveStressVector(); } else { strain.beProductOf(b, shellUnknowns); cs->giveGeneralizedStress_Shell(stress, gp, strain, tStep); } shellForces.plusProduct(b, stress, dV); // Drilling stiffness is here for improved numerical properties if ( drillCoeff > 0. ) { this->interp.evalN( n, * gp->giveNaturalCoordinates(), FEIVoidCellGeometry() ); for ( int j = 0; j < 4; j++ ) { n(j) -= 0.25; } double dtheta = n.dotProduct(drillUnknowns); drillMoment.add(drillCoeff * dV * dtheta, n); ///@todo Decide on how to alpha should be defined. drillCoeffFlag = true; } } answer.resize(24); answer.zero(); answer.assemble(shellForces, this->shellOrdering); if ( drillCoeffFlag ) { answer.assemble(drillMoment, this->drillOrdering); } }
void Quad1MindlinShell3D :: computeStiffnessMatrix(FloatMatrix &answer, MatResponseMode rMode, TimeStep *tStep) { // We need to overload this for practical reasons (this 3d shell has all 9 dofs, but the shell part only cares for the first 8) // This elements adds an additional stiffness for the so called drilling dofs, meaning we need to work with all 9 components. FloatMatrix d, b, db; FloatArray n; FloatMatrix shellStiffness(20, 20), drillStiffness(4, 4); shellStiffness.zero(); drillStiffness.zero(); double drillCoeff = this->giveStructuralCrossSection()->give(CS_DrillingStiffness); IntegrationRule *iRule = integrationRulesArray [ 0 ]; for ( int i = 0; i < iRule->giveNumberOfIntegrationPoints(); i++ ) { GaussPoint *gp = iRule->getIntegrationPoint(i); this->computeBmatrixAt(gp, b); double dV = this->computeVolumeAround(gp); this->computeConstitutiveMatrixAt(d, rMode, gp, tStep); db.beProductOf(d, b); shellStiffness.plusProductSymmUpper(b, db, dV); // Drilling stiffness is here for improved numerical properties if (drillCoeff > 0.) { this->interp.evalN(n, *gp->giveCoordinates(), FEIVoidCellGeometry()); for ( int j = 0; j < 4; j++) { n(j) -= 0.25; } drillStiffness.plusDyadSymmUpper(n, drillCoeff * dV); } } shellStiffness.symmetrized(); answer.resize(24, 24); answer.zero(); answer.assemble(shellStiffness, this->shellOrdering); if (drillCoeff > 0.) { drillStiffness.symmetrized(); answer.assemble(drillStiffness, this->drillOrdering); } }
void Quad1MindlinShell3D :: computeBmatrixAt(GaussPoint *gp, FloatMatrix &answer, int li, int ui) { FloatArray n, ns; FloatMatrix dn, dns; const FloatArray &localCoords = gp->giveNaturalCoordinates(); this->interp.evaldNdx( dn, localCoords, FEIVertexListGeometryWrapper(lnodes) ); this->interp.evalN( n, localCoords, FEIVoidCellGeometry() ); answer.resize(8, 4 * 5); answer.zero(); // enforce one-point reduced integration if requested if ( this->reducedIntegrationFlag ) { FloatArray lc(2); lc.zero(); // set to element center coordinates this->interp.evaldNdx( dns, lc, FEIVertexListGeometryWrapper(lnodes) ); this->interp.evalN( ns, lc, FEIVoidCellGeometry() ); } else { dns = dn; ns = n; } // Note: This is just 5 dofs (sixth column is all zero, torsional stiffness handled separately.) for ( int i = 0; i < 4; ++i ) { ///@todo Check the rows for both parts here, to be consistent with _3dShell material definition // Part related to the membrane (columns represent coefficients for D_u, D_v) answer(0, 0 + i * 5) = dn(i, 0);//eps_x = du/dx answer(1, 1 + i * 5) = dn(i, 1);//eps_y = dv/dy answer(2, 0 + i * 5) = dn(i, 1);//gamma_xy = du/dy+dv/dx answer(2, 1 + i * 5) = dn(i, 0); // Part related to the plate (columns represent the dofs D_w, R_u, R_v) ///@todo Check sign here answer(3 + 0, 2 + 2 + i * 5) = dn(i, 0);// kappa_x = d(fi_y)/dx answer(3 + 1, 2 + 1 + i * 5) =-dn(i, 1);// kappa_y = -d(fi_x)/dy answer(3 + 2, 2 + 2 + i * 5) = dn(i, 1);// kappa_xy=d(fi_y)/dy-d(fi_x)/dx answer(3 + 2, 2 + 1 + i * 5) =-dn(i, 0); // shear strains answer(3 + 3, 2 + 0 + i * 5) = dns(i, 0);// gamma_xz = fi_y+dw/dx answer(3 + 3, 2 + 2 + i * 5) = ns(i); answer(3 + 4, 2 + 0 + i * 5) = dns(i, 1);// gamma_yz = -fi_x+dw/dy answer(3 + 4, 2 + 1 + i * 5) = -ns(i); } #if 0 // Experimental MITC4 support. // Based on "Short communication A four-node plate bending element based on mindling/reissner plate theory and a mixed interpolation" // KJ Bathe, E Dvorkin double x1, x2, x3, x4; double y1, y2, y3, y4; double Ax, Bx, Cx, Ay, By, Cy; double r = localCoords[0]; double s = localCoords[1]; x1 = lnodes[0][0]; x2 = lnodes[1][0]; x3 = lnodes[2][0]; x4 = lnodes[3][0]; y1 = lnodes[0][1]; y2 = lnodes[1][1]; y3 = lnodes[2][1]; y4 = lnodes[3][1]; Ax = x1 - x2 - x3 + x4; Bx = x1 - x2 + x3 - x4; Cx = x1 + x2 - x3 - x4; Ay = y1 - y2 - y3 + y4; By = y1 - y2 + y3 - y4; Cy = y1 + y2 - y3 - y4; FloatMatrix jac; this->interp.giveJacobianMatrixAt(jac, localCoords, FEIVertexListGeometryWrapper(lnodes) ); double detJ = jac.giveDeterminant(); double rz = sqrt( sqr(Cx + r*Bx) + sqr(Cy + r*By)) / ( 16 * detJ ); double sz = sqrt( sqr(Ax + s*Bx) + sqr(Ay + s*By)) / ( 16 * detJ ); // TODO: Not sure about this part (the reference is not explicit about these angles. / Mikael // Not sure about the transpose either. OOFEM_WARNING("The MITC4 implementation isn't verified yet. Highly experimental"); FloatArray dxdr = {jac(0,0), jac(0,1)}; dxdr.normalize(); FloatArray dxds = {jac(1,0), jac(1,1)}; dxds.normalize(); double c_b = dxdr(0); //cos(beta); double s_b = dxdr(1); //sin(beta); double c_a = dxds(0); //cos(alpha); double s_a = dxds(1); //sin(alpha); // gamma_xz = "fi_y+dw/dx" in standard formulation answer(6, 2 + 5*0) = rz * s_b * ( (1+s)) - sz * s_a * ( (1+r)); answer(6, 2 + 5*1) = rz * s_b * (-(1+s)) - sz * s_a * ( (1-r)); answer(6, 2 + 5*2) = rz * s_b * (-(1-s)) - sz * s_a * (-(1-r)); answer(6, 2 + 5*3) = rz * s_b * ( (1-s)) - sz * s_a * (-(1+r)); answer(6, 3 + 5*0) = rz * s_b * (y2-y1) * 0.5 * (1+s) - sz * s_a * (y4-y1) * 0.5 * (1+r); // tx1 answer(6, 4 + 5*0) = rz * s_b * (x1-x2) * 0.5 * (1+s) - sz * s_a * (x1-x4) * 0.5 * (1+r); // ty1 answer(6, 3 + 5*1) = rz * s_b * (y2-y1) * 0.5 * (1+s) - sz * s_a * (y3-x2) * 0.5 * (1+r); // tx2 answer(6, 4 + 5*1) = rz * s_b * (x1-x2) * 0.5 * (1+s) - sz * s_a * (x2-x3) * 0.5 * (1+r); // ty2 answer(6, 3 + 5*2) = rz * s_b * (y3-y4) * 0.5 * (1-s) - sz * s_a * (y3-y2) * 0.5 * (1-r); // tx3 answer(6, 4 + 5*2) = rz * s_b * (x4-x3) * 0.5 * (1-s) - sz * s_a * (x2-x3) * 0.5 * (1-r); // ty3 answer(6, 3 + 5*3) = rz * s_b * (y3-y4) * 0.5 * (1-s) - sz * s_a * (y4-y1) * 0.5 * (1-r); // tx4 answer(6, 4 + 5*3) = rz * s_b * (x4-x3) * 0.5 * (1-s) - sz * s_a * (x1-x4) * 0.5 * (1-r); // ty4 // gamma_yz = -fi_x+dw/dy in standard formulation answer(7, 2 + 5*0) = - rz * c_b * ( (1+s)) + sz * c_a * ( (1+r)); answer(7, 2 + 5*1) = - rz * c_b * (-(1+s)) + sz * c_a * ( (1-r)); answer(7, 2 + 5*2) = - rz * c_b * (-(1-s)) + sz * c_a * (-(1-r)); answer(7, 2 + 5*3) = - rz * c_b * ( (1-s)) + sz * c_a * (-(1+r)); answer(7, 3 + 5*0) = - rz * c_b * (y2-y1) * 0.5 * (1+s) + sz * c_a * (y4-y1) * 0.5 * (1+r); // tx1 answer(7, 4 + 5*0) = - rz * c_b * (x1-x2) * 0.5 * (1+s) + sz * c_a * (x1-x4) * 0.5 * (1+r); // ty1 answer(7, 3 + 5*1) = - rz * c_b * (y2-y1) * 0.5 * (1+s) + sz * c_a * (y3-x2) * 0.5 * (1+r); // tx2 answer(7, 4 + 5*1) = - rz * c_b * (x1-x2) * 0.5 * (1+s) + sz * c_a * (x2-x3) * 0.5 * (1+r); // ty2 answer(7, 3 + 5*2) = - rz * c_b * (y3-y4) * 0.5 * (1-s) + sz * c_a * (y3-y2) * 0.5 * (1-r); // tx3 answer(7, 4 + 5*2) = - rz * c_b * (x4-x3) * 0.5 * (1-s) + sz * c_a * (x2-x3) * 0.5 * (1-r); // ty3 answer(7, 3 + 5*3) = - rz * c_b * (y3-y4) * 0.5 * (1-s) + sz * c_a * (y4-y1) * 0.5 * (1-r); // tx4 answer(7, 4 + 5*3) = - rz * c_b * (x4-x3) * 0.5 * (1-s) + sz * c_a * (x1-x4) * 0.5 * (1-r); // ty4 #endif }