Real MechanicalContactConstraint::computeQpResidual(Moose::ConstraintType type) { PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()]; Real resid = pinfo->_contact_force(_component); switch (type) { case Moose::Slave: if (_formulation == CF_KINEMATIC) { RealVectorValue distance_vec(*_current_node - pinfo->_closest_point); const Real penalty = getPenalty(*pinfo); RealVectorValue pen_force(penalty * distance_vec); if (_model == CM_FRICTIONLESS) resid += pinfo->_normal(_component) * pinfo->_normal * pen_force; else if (_model == CM_GLUED || _model == CM_COULOMB) resid += pen_force(_component); } return _test_slave[_i][_qp] * resid; case Moose::Master: return _test_master[_i][_qp] * -resid; } return 0; }
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 MechanicalContactConstraint::computeQpOffDiagJacobian(Moose::ConstraintJacobianType type, unsigned int jvar) { PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()]; const Real penalty = getPenalty(*pinfo); unsigned int coupled_component; double normal_component_in_coupled_var_dir = 1.0; if (getCoupledVarComponent(jvar,coupled_component)) normal_component_in_coupled_var_dir = pinfo->_normal(coupled_component); switch (type) { case Moose::SlaveSlave: switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_KINEMATIC: { RealVectorValue jac_vec; for (unsigned int i=0; i<_mesh_dimension; ++i) { dof_id_type dof_number = _current_node->dof_number(0, _vars(i), 0); jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]); } return -pinfo->_normal(_component) * (pinfo->_normal*jac_vec) + (_phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]) * pinfo->_normal(_component) * normal_component_in_coupled_var_dir; } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] * pinfo->_normal(_component) * normal_component_in_coupled_var_dir; default: mooseError("Invalid contact formulation"); } case CM_COULOMB: case CM_GLUED: { double curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars(_component), 0), _connected_dof_indices[_j]); return -curr_jac; } default: mooseError("Invalid or unavailable contact model"); } case Moose::SlaveMaster: switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_KINEMATIC: { Node * curr_master_node = _current_master->get_node(_j); RealVectorValue jac_vec; for (unsigned int i=0; i<_mesh_dimension; ++i) { dof_id_type dof_number = _current_node->dof_number(0, _vars(i), 0); jac_vec(i) = (*_jacobian)(dof_number, curr_master_node->dof_number(0, _vars(_component), 0)); } return -pinfo->_normal(_component)*(pinfo->_normal*jac_vec) - (_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]) * pinfo->_normal(_component) * normal_component_in_coupled_var_dir; } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] * pinfo->_normal(_component) * normal_component_in_coupled_var_dir; default: mooseError("Invalid contact formulation"); } case CM_COULOMB: case CM_GLUED: return 0; default: mooseError("Invalid or unavailable contact model"); } case Moose::MasterSlave: switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_KINEMATIC: { RealVectorValue jac_vec; for (unsigned int i=0; i<_mesh_dimension; ++i) { dof_id_type dof_number = _current_node->dof_number(0, _vars(i), 0); jac_vec(i) = (*_jacobian)(dof_number, _connected_dof_indices[_j]); } return pinfo->_normal(_component)*(pinfo->_normal*jac_vec) * _test_master[_i][_qp]; } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp] * pinfo->_normal(_component) * normal_component_in_coupled_var_dir; default: mooseError("Invalid contact formulation"); } case CM_COULOMB: case CM_GLUED: switch (_formulation) { case CF_KINEMATIC: { double slave_jac = (*_jacobian)(_current_node->dof_number(0, _vars(_component), 0), _connected_dof_indices[_j]); return slave_jac * _test_master[_i][_qp]; } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return 0; default: mooseError("Invalid contact formulation"); } default: mooseError("Invalid or unavailable contact model"); } case Moose::MasterMaster: switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_KINEMATIC: return 0; case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp] * pinfo->_normal(_component) * normal_component_in_coupled_var_dir; default: mooseError("Invalid contact formulation"); } case CM_COULOMB: case CM_GLUED: return 0; default: mooseError("Invalid or unavailable contact model"); } } return 0; }
void MechanicalContactConstraint::computeContactForce(PenetrationInfo * pinfo) { const Node * node = pinfo->_node; RealVectorValue res_vec; // Build up residual vector for (unsigned int i=0; i<_mesh_dimension; ++i) { dof_id_type dof_number = node->dof_number(0, _vars(i), 0); res_vec(i) = _residual_copy(dof_number); } RealVectorValue distance_vec(_mesh.node(node->id()) - pinfo->_closest_point); const Real penalty = getPenalty(*pinfo); RealVectorValue pen_force(penalty * distance_vec); switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_KINEMATIC: 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 + pinfo->_lagrange_multiplier * pinfo->_normal))); break; default: mooseError("Invalid contact formulation"); break; } pinfo->_mech_status=PenetrationInfo::MS_SLIPPING; break; case CM_COULOMB: switch (_formulation) { case CF_KINEMATIC: pinfo->_contact_force = -res_vec; break; case CF_PENALTY: { distance_vec = pinfo->_incremental_slip + (pinfo->_normal * (_mesh.node(node->id()) - pinfo->_closest_point)) * pinfo->_normal; pen_force = penalty * distance_vec; // 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; break; } case CF_AUGMENTED_LAGRANGE: pinfo->_contact_force = pen_force + pinfo->_lagrange_multiplier*distance_vec/distance_vec.size(); break; default: mooseError("Invalid contact formulation"); break; } break; case CM_GLUED: switch (_formulation) { case CF_KINEMATIC: pinfo->_contact_force = -res_vec; break; case CF_PENALTY: pinfo->_contact_force = pen_force; break; case CF_AUGMENTED_LAGRANGE: pinfo->_contact_force = pen_force + pinfo->_lagrange_multiplier*distance_vec/distance_vec.size(); break; default: mooseError("Invalid contact formulation"); break; } pinfo->_mech_status=PenetrationInfo::MS_STICKING; break; default: mooseError("Invalid or unavailable contact model"); break; } }
Real MechanicalContactConstraint::computeQpJacobian(Moose::ConstraintJacobianType type) { PenetrationInfo * pinfo = _penetration_locator._penetration_info[_current_node->id()]; const Real penalty = getPenalty(*pinfo); switch (type) { case Moose::SlaveSlave: switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_DEFAULT: { double curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars(_component), 0), _connected_dof_indices[_j]); //TODO: Need off-diagonal term/s return (-curr_jac + _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]) * pinfo->_normal(_component) * pinfo->_normal(_component); } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: //TODO: Need off-diagonal terms return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp] * pinfo->_normal(_component) * pinfo->_normal(_component); default: mooseError("Invalid contact formulation"); } case CM_COULOMB: case CM_GLUED: switch (_formulation) { case CF_DEFAULT: { double curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars(_component), 0), _connected_dof_indices[_j]); return -curr_jac + _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]; } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return _phi_slave[_j][_qp] * penalty * _test_slave[_i][_qp]; default: mooseError("Invalid contact formulation"); } default: mooseError("Invalid or unavailable contact model"); } case Moose::SlaveMaster: switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_DEFAULT: { Node * curr_master_node = _current_master->get_node(_j); double curr_jac = (*_jacobian)(_current_node->dof_number(0, _vars(_component), 0), curr_master_node->dof_number(0, _vars(_component), 0)); //TODO: Need off-diagonal terms return (-curr_jac - _phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]) * pinfo->_normal(_component) * pinfo->_normal(_component); } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: //TODO: Need off-diagonal terms return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp] * pinfo->_normal(_component) * pinfo->_normal(_component); default: mooseError("Invalid contact formulation"); } case CM_COULOMB: case CM_GLUED: switch (_formulation) { case CF_DEFAULT: { Node * curr_master_node = _current_master->get_node(_j); double curr_jac = (*_jacobian)( _current_node->dof_number(0, _vars(_component), 0), curr_master_node->dof_number(0, _vars(_component), 0)); return -curr_jac - _phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]; } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return -_phi_master[_j][_qp] * penalty * _test_slave[_i][_qp]; default: mooseError("Invalid contact formulation"); } default: mooseError("Invalid or unavailable contact model"); } case Moose::MasterSlave: switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_DEFAULT: { //TODO: Need off-diagonal terms double slave_jac = (*_jacobian)(_current_node->dof_number(0, _vars(_component), 0), _connected_dof_indices[_j]); //TODO: To get off-diagonal terms correct using an approach like this, we would need to assemble in the rows for //all displacement components times their components of the normal vector. return slave_jac * _test_master[_i][_qp] * pinfo->_normal(_component) * pinfo->_normal(_component); } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: //TODO: Need off-diagonal terms return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp] * pinfo->_normal(_component) * pinfo->_normal(_component); default: mooseError("Invalid contact formulation"); } case CM_COULOMB: case CM_GLUED: switch (_formulation) { case CF_DEFAULT: { double slave_jac = (*_jacobian)(_current_node->dof_number(0, _vars(_component), 0), _connected_dof_indices[_j]); return slave_jac * _test_master[_i][_qp]; } case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return -_test_master[_i][_qp] * penalty * _phi_slave[_j][_qp]; default: mooseError("Invalid contact formulation"); } default: mooseError("Invalid or unavailable contact model"); } case Moose::MasterMaster: switch (_model) { case CM_FRICTIONLESS: switch (_formulation) { case CF_DEFAULT: return 0; case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: //TODO: Need off-diagonal terms return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp] * pinfo->_normal(_component) * pinfo->_normal(_component); default: mooseError("Invalid contact formulation"); } case CM_COULOMB: case CM_GLUED: switch (_formulation) { case CF_DEFAULT: return 0; case CF_PENALTY: case CF_AUGMENTED_LAGRANGE: return _test_master[_i][_qp] * penalty * _phi_master[_j][_qp]; default: mooseError("Invalid contact formulation"); } default: mooseError("Invalid or unavailable contact model"); } } return 0; }
void MechanicalContactConstraint::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; 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; } const Node * node = pinfo->_node; const Real area = nodalArea(*pinfo); if ((_model == CM_FRICTIONLESS && _formulation == CF_DEFAULT) || (_model == CM_COULOMB && _formulation == CF_DEFAULT)) { Real resid( -(pinfo->_normal * pinfo->_contact_force) / area ); // Moose::out << 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) { //Moose::out << "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()) { //Moose::out << "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) //Penetrated { if (hpit == has_penetrated.end()) has_penetrated.insert(slave_node_num); } else if (_tension_release < 0 || (pinfo->_contact_force * pinfo->_normal) / area < _tension_release) //In contact and below tension release threshold { // 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 = getPenalty(*pinfo); lagrange_multiplier[slave_node_num] += penalty * pinfo->_normal * distance_vec; } } }