void ContactMaster::updateContactSet(bool beginning_of_step) { std::map<dof_id_type, PenetrationInfo *>::iterator it = _penetration_locator._penetration_info.begin(), end = _penetration_locator._penetration_info.end(); for (; it!=end; ++it) { const dof_id_type slave_node_num = it->first; PenetrationInfo * pinfo = it->second; // Skip this pinfo if there are no DOFs on this node. if ( ! pinfo || pinfo->_node->n_comp(_sys.number(), _vars(_component)) < 1 ) continue; if (beginning_of_step) { pinfo->_locked_this_step = 0; pinfo->_starting_elem = it->second->_elem; pinfo->_starting_side_num = it->second->_side_num; pinfo->_starting_closest_point_ref = it->second->_closest_point_ref; pinfo->_contact_force_old = pinfo->_contact_force; pinfo->_accumulated_slip_old = pinfo->_accumulated_slip; pinfo->_frictional_energy_old = pinfo->_frictional_energy; } const Real contact_pressure = -(pinfo->_normal * pinfo->_contact_force) / nodalArea(*pinfo); const Real distance = pinfo->_normal * (pinfo->_closest_point - _mesh.node(slave_node_num)); // Capture if ( ! pinfo->isCaptured() && MooseUtils::absoluteFuzzyGreaterEqual(distance, 0, _capture_tolerance)) { pinfo->capture(); // Increment the lock count every time the node comes back into contact from not being in contact. if (_formulation == CF_KINEMATIC) ++pinfo->_locked_this_step; } // Release else if (_model != CM_GLUED && pinfo->isCaptured() && _tension_release >= 0 && -contact_pressure >= _tension_release && pinfo->_locked_this_step < 2) { pinfo->release(); pinfo->_contact_force.zero(); } if (_formulation == CF_AUGMENTED_LAGRANGE && pinfo->isCaptured()) pinfo->_lagrange_multiplier -= getPenalty(*pinfo) * distance; } }
Real SlaveConstraint::computeQpJacobian() { // TODO: for the default formulation, // we should subtract off the existing Jacobian weighted by the effect of the normal PenetrationInfo * pinfo = _point_to_info[_current_point]; const Node * node = pinfo->_node; // long int dof_number = node->dof_number(0, _var.number(), 0); // RealVectorValue jac_vec; // Build up jac vector // for (unsigned int i=0; i<_dim; i++) // { // unsigned int dof_row = _dof_data._var_dof_indices[_var_num][_i]; // unsigned int dof_col = _dof_data._var_dof_indices[_var_num][_j]; // Real jac_value = _jacobian_copy(dof_row, dof_col); // } // Real jac_mag = pinfo->_normal(_component) * jac_value; /* return _test[_i][_qp] * ( (1e8*-_phi[_j][_qp]) -_jacobian_copy(dof_number, dof_number) ); */ RealVectorValue normal(pinfo->_normal); Real penalty = _penalty; if (_normalize_penalty) penalty *= nodalArea(*pinfo); Real term(0); if ( CM_FRICTIONLESS == _model ) { const Real nnTDiag = normal(_component) * normal(_component); term = penalty * nnTDiag; const RealGradient & A1( pinfo->_dxyzdxi [0] ); RealGradient A2; RealGradient d2; if ( _mesh_dimension == 3 ) { A2 = pinfo->_dxyzdeta[0]; d2 = pinfo->_d2xyzdxideta[0]; } else { A2.zero(); d2.zero(); } const RealVectorValue distance_vec(_mesh.node(node->id()) - pinfo->_closest_point); const Real ATA11( A1 * A1 ); const Real ATA12( A1 * A2 ); const Real ATA22( A2 * A2 ); const Real D11( -ATA11 ); const Real D12( -ATA12 + d2 * distance_vec ); const Real D22( -ATA22 ); Real invD11(0); Real invD12(0); Real invD22(0); if ( _mesh_dimension == 3) { const Real detD( D11*D22 - D12*D12 ); invD11 = D22/detD; invD12 = -D12/detD; invD22 = D11/detD; } else if ( _mesh_dimension == 2 ) { invD11 = 1 / D11; } const Real AinvD11( A1(0)*invD11 + A2(0)*invD12 ); const Real AinvD12( A1(0)*invD12 + A2(0)*invD22 ); const Real AinvD21( A1(1)*invD11 + A2(1)*invD12 ); const Real AinvD22( A1(1)*invD12 + A2(1)*invD22 ); const Real AinvD31( A1(2)*invD11 + A2(2)*invD12 ); const Real AinvD32( A1(2)*invD12 + A2(2)*invD22 ); const Real AinvDAT11( AinvD11*A1(0) + AinvD12*A2(0) ); // const Real AinvDAT12( AinvD11*A1(1) + AinvD12*A2(1) ); // const Real AinvDAT13( AinvD11*A1(2) + AinvD12*A2(2) ); // const Real AinvDAT21( AinvD21*A1(0) + AinvD22*A2(0) ); const Real AinvDAT22( AinvD21*A1(1) + AinvD22*A2(1) ); // const Real AinvDAT23( AinvD21*A1(2) + AinvD22*A2(2) ); // const Real AinvDAT31( AinvD31*A1(0) + AinvD32*A2(0) ); // const Real AinvDAT32( AinvD31*A1(1) + AinvD32*A2(1) ); const Real AinvDAT33( AinvD31*A1(2) + AinvD32*A2(2) ); if ( _component == 0 ) term += penalty * ( 1 - nnTDiag + AinvDAT11 ); else if ( _component == 1 ) term += penalty * ( 1 - nnTDiag + AinvDAT22 ); else term += penalty * ( 1 - nnTDiag + AinvDAT33 ); } else if ( CM_GLUED == _model || CM_COULOMB == _model ) { normal.zero(); normal(_component) = 1; term = penalty; } else { mooseError("Invalid or unavailable contact model"); } return _test[_i][_qp] * term * _phi[_j][_qp]; }
Real ContactMaster::computeQpJacobian() { PenetrationInfo * pinfo = _point_to_info[_current_point]; Real penalty = _penalty; if (_normalize_penalty) penalty *= nodalArea(*pinfo); switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_DEFAULT: return 0; break; case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return _test[_i][_qp] * penalty * _phi[_j][_qp] * pinfo->_normal(_component) * pinfo->_normal(_component); break; default: mooseError("Invalid contact formulation"); break; } break; case CM_GLUED: case CM_COULOMB: switch (_formulation) { case CF_DEFAULT: return 0; break; case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return _test[_i][_qp] * penalty * _phi[_j][_qp]; break; default: mooseError("Invalid contact formulation"); break; } break; default: mooseError("Invalid or unavailable contact model"); break; } return 0; /* if (_i != _j) return 0; Node * node = pinfo->_node; RealVectorValue jac_vec; // Build up jac vector for (unsigned int i=0; i<_dim; i++) { long int dof_number = node->dof_number(0, _vars(i), 0); jac_vec(i) = _jacobian_copy(dof_number, dof_number); } Real jac_mag = pinfo->_normal * jac_vec; return _test[_i][_qp]*pinfo->_normal(_component)*jac_mag; */ }
void ContactMaster::computeContactForce(PenetrationInfo * pinfo) { std::map<unsigned int, Real> & lagrange_multiplier = _penetration_locator._lagrange_multiplier; const Node * node = pinfo->_node; RealVectorValue res_vec; // Build up residual vector for (unsigned int i=0; i<_mesh_dimension; ++i) { long int dof_number = node->dof_number(0, _vars(i), 0); res_vec(i) = _residual_copy(dof_number); } const Real area = nodalArea(*pinfo); RealVectorValue distance_vec(_mesh.node(node->id()) - pinfo->_closest_point); RealVectorValue pen_force(_penalty * distance_vec); if (_normalize_penalty) pen_force *= area; RealVectorValue tan_residual(0,0,0); if (_model == CM_FRICTIONLESS) { switch (_formulation) { case CF_DEFAULT: pinfo->_contact_force = -pinfo->_normal * (pinfo->_normal * res_vec); break; case CF_PENALTY: pinfo->_contact_force = pinfo->_normal * (pinfo->_normal * pen_force); break; case CF_AUGMENTED_LAGRANGE: pinfo->_contact_force = (pinfo->_normal * (pinfo->_normal * //( pen_force + (lagrange_multiplier[node->id()]/distance_vec.size())*distance_vec))); ( pen_force + lagrange_multiplier[node->id()] * pinfo->_normal))); break; default: mooseError("Invalid contact formulation"); break; } pinfo->_mech_status=PenetrationInfo::MS_SLIPPING; } else if (_model == CM_COULOMB && _formulation == CF_PENALTY) { distance_vec = pinfo->_incremental_slip + (pinfo->_normal * (_mesh.node(node->id()) - pinfo->_closest_point)) * pinfo->_normal; pen_force = _penalty * distance_vec; if (_normalize_penalty) pen_force *= area; // Frictional capacity // const Real capacity( _friction_coefficient * (pen_force * pinfo->_normal < 0 ? -pen_force * pinfo->_normal : 0) ); const Real capacity( _friction_coefficient * (res_vec * pinfo->_normal > 0 ? res_vec * pinfo->_normal : 0) ); // Elastic predictor pinfo->_contact_force = pen_force + (pinfo->_contact_force_old - pinfo->_normal*(pinfo->_normal*pinfo->_contact_force_old)); RealVectorValue contact_force_normal( (pinfo->_contact_force*pinfo->_normal) * pinfo->_normal ); RealVectorValue contact_force_tangential( pinfo->_contact_force - contact_force_normal ); // Tangential magnitude of elastic predictor const Real tan_mag( contact_force_tangential.size() ); if ( tan_mag > capacity ) { pinfo->_contact_force = contact_force_normal + capacity * contact_force_tangential / tan_mag; pinfo->_mech_status=PenetrationInfo::MS_SLIPPING; } else { pinfo->_mech_status=PenetrationInfo::MS_STICKING; } } else if (_model == CM_GLUED || (_model == CM_COULOMB && _formulation == CF_DEFAULT)) { switch (_formulation) { case CF_DEFAULT: pinfo->_contact_force = -res_vec; break; case CF_PENALTY: pinfo->_contact_force = pen_force; break; case CF_AUGMENTED_LAGRANGE: pinfo->_contact_force = pen_force + lagrange_multiplier[node->id()]*distance_vec/distance_vec.size(); break; default: mooseError("Invalid contact formulation"); break; } pinfo->_mech_status=PenetrationInfo::MS_STICKING; } else { mooseError("Invalid or unavailable contact model"); } }
void ContactMaster::updateContactSet(bool beginning_of_step) { std::set<unsigned int> & has_penetrated = _penetration_locator._has_penetrated; std::map<unsigned int, unsigned> & unlocked_this_step = _penetration_locator._unlocked_this_step; std::map<unsigned int, unsigned> & locked_this_step = _penetration_locator._locked_this_step; std::map<unsigned int, Real> & lagrange_multiplier = _penetration_locator._lagrange_multiplier; std::map<unsigned int, PenetrationInfo *>::iterator it = _penetration_locator._penetration_info.begin(); std::map<unsigned int, PenetrationInfo *>::iterator end = _penetration_locator._penetration_info.end(); for (; it!=end; ++it) { PenetrationInfo * pinfo = it->second; if (!pinfo) { continue; } Real area = nodalArea(*pinfo); const unsigned int slave_node_num = it->first; std::set<unsigned int>::iterator hpit = has_penetrated.find(slave_node_num); if (beginning_of_step) { if (hpit != has_penetrated.end()) pinfo->_penetrated_at_beginning_of_step = true; else pinfo->_penetrated_at_beginning_of_step = false; pinfo->_starting_elem = it->second->_elem; pinfo->_starting_side_num = it->second->_side_num; pinfo->_starting_closest_point_ref = it->second->_closest_point_ref; } if ((_model == CM_FRICTIONLESS && _formulation == CF_DEFAULT) || (_model == CM_COULOMB && _formulation == CF_DEFAULT)) { const Node * node = pinfo->_node; Real resid( -(pinfo->_normal * pinfo->_contact_force) / area ); // _console << locked_this_step[slave_node_num] << " " << pinfo->_distance << std::endl; const Real distance( pinfo->_normal * (pinfo->_closest_point - _mesh.node(node->id()))); if (hpit != has_penetrated.end() && _tension_release >= 0 && resid < -_tension_release && locked_this_step[slave_node_num] < 2) { _console << "Releasing node " << node->id() << " " << resid << " < " << -_tension_release << std::endl; has_penetrated.erase(hpit); pinfo->_contact_force.zero(); pinfo->_mech_status=PenetrationInfo::MS_NO_CONTACT; ++unlocked_this_step[slave_node_num]; } else if (distance > 0) { if (hpit == has_penetrated.end()) { _console << "Capturing node " << node->id() << " " << distance << " " << unlocked_this_step[slave_node_num] << std::endl; ++locked_this_step[slave_node_num]; has_penetrated.insert(slave_node_num); } } } else { if (_formulation == CF_PENALTY) { if (pinfo->_distance >= 0) { if (hpit == has_penetrated.end()) has_penetrated.insert(slave_node_num); } else if (_tension_release < 0 || (pinfo->_contact_force * pinfo->_normal) / area < _tension_release) { // Do nothing. } else { if (hpit != has_penetrated.end()) { has_penetrated.erase(hpit); } pinfo->_contact_force.zero(); pinfo->_mech_status=PenetrationInfo::MS_NO_CONTACT; } } else { if (pinfo->_distance >= 0) { if (hpit == has_penetrated.end()) { has_penetrated.insert(slave_node_num); } } } } if (_formulation == CF_AUGMENTED_LAGRANGE && hpit != has_penetrated.end()) { const RealVectorValue distance_vec(_mesh.node(slave_node_num) - pinfo->_closest_point); Real penalty = _penalty; if (_normalize_penalty) penalty *= area; lagrange_multiplier[slave_node_num] += penalty * pinfo->_normal * distance_vec; } } }