// Compute the granular "stress" Matrix3 PeriodicBCComputeStressStrain::calcGranularStress(const DEMParticlePArray& particles, const DEMContactArray& contacts, const OrientedBox& spatialDomain) { Matrix3 stress(0.0); // Basic component (Love-Weber) for (const auto& contact : contacts) { auto p1Center = contact.getP1()->currentPosition(); auto p2Center = contact.getP2()->currentPosition(); auto direction = -(p1Center - p2Center); auto force = contact.getNormalForce() + contact.getTangentForce(); stress += Dyad(force, direction); } // Component needed if # of particles in RVE is small // **TODO** // Inertial component (Nicot, 2013) Matrix3 inertial(0.0); for (const auto& particle : particles) { Vec momentJ = particle->getMomentJ(); Matrix3 localInertialTensor(momentJ.x(), 0.0, 0.0, 0.0, momentJ.y(), 0.0, 0.0, 0.0, momentJ.z()); Vec ax_a = particle->currentAxisA(); Vec ax_b = particle->currentAxisB(); Vec ax_c = particle->currentAxisC(); Matrix3 Q(ax_a.x(), ax_b.x(), ax_c.x(), ax_a.y(), ax_b.y(), ax_c.y(), ax_a.z(), ax_b.z(), ax_c.z()); Matrix3 chi = Q.Transpose() * localInertialTensor * Q; Vec omega = particle->currentAngularVelocity(); Vec localOmegaDot = particle->angularAcceleration(); Vec omegaDot = Q.Transpose() * localOmegaDot; inertial -= (chi * dot(omega, omega)); inertial += (Dyad(omega, omega) * chi); Matrix3 permu(0.0); for (int j = 0; j < 3; ++j) { permu(0,j) = omegaDot[1] * chi(j,2) - omega[2] * chi(j,1); permu(1,j) = omegaDot[2] * chi(j,0) - omega[0] * chi(j,2); permu(2,j) = omegaDot[0] * chi(j,1) - omega[1] * chi(j,0); } inertial += permu; } stress -= inertial; stress /= spatialDomain.volume(); return stress; }
ErrorCode TreeValidator::visit( EntityHandle node, int depth, bool& descend ) { ErrorCode rval; descend = true; Range contents; rval = instance->get_entities_by_handle( node, contents ); if (MB_SUCCESS != rval) return error(node, "Error getting contents of tree node. Corrupt tree?"); entity_count += contents.size(); if (surfaces) { // if no longer in subtree for previous surface, clear if (depth <= surface_depth) surface_depth = -1; EntityHandle surface = 0; Range::iterator surf_iter = contents.lower_bound( MBENTITYSET ); if (surf_iter != contents.end()) { surface = *surf_iter; contents.erase( surf_iter ); } if (surface) { if (surface_depth >=0) { ++multiple_surface_count; print( node, "Multiple surfaces in encountered in same subtree." ); } else { surface_depth = depth; surface_handle = surface; } } } std::vector<EntityHandle> children; rval = tool->get_moab_instance()->get_child_meshsets( node, children ); if (MB_SUCCESS != rval || (!children.empty() && children.size() != 2)) return error(node, "Error getting children. Corrupt tree?"); OrientedBox box; rval = tool->box( node, box ); if (MB_SUCCESS != rval) return error(node, "Error getting oriented box from tree node. Corrupt tree?"); if (children.empty() && contents.empty()) { ++empty_leaf_count; print( node, "Empty leaf node.\n" ); } else if (!children.empty() && !contents.empty()) { ++non_empty_non_leaf_count; print( node, "Non-leaf node is not empty." ); } if (surfaces && children.empty() && surface_depth < 0) { ++missing_surface_count; print( node, "Reached leaf node w/out encountering any surface set."); } double dot_epsilon = epsilon*(box.axis[0]+box.axis[1]+box.axis[2]).length(); if (box.axis[0] % box.axis[1] > dot_epsilon || box.axis[0] % box.axis[2] > dot_epsilon || box.axis[1] % box.axis[2] > dot_epsilon ) { ++non_ortho_count; print (node, "Box axes are not orthogonal"); } if (!children.empty()) { for (int i = 0; i < 2; ++i) { OrientedBox other_box; rval = tool->box( children[i], other_box ); if (MB_SUCCESS != rval) return error( children[i], " Error getting oriented box from tree node. Corrupt tree?" ); // else if (!box.contained( other_box, epsilon )) { // ++child_outside_count; // print( children[i], "Parent box does not contain child box." ); // char string[64]; // sprintf(string, " Volume ratio is %f", other_box.volume()/box.volume() ); // print( children [i], string ); // } else { double vol_ratio = other_box.volume()/box.volume(); if (vol_ratio > 2.0) { char string[64]; sprintf(string, "child/parent volume ratio is %f", vol_ratio ); print( children[i], string ); sprintf(string, " child/parent area ratio is %f", other_box.area()/box.area() ); print( children[i], string ); } } } } bool bad_element = false; bool bad_element_handle = false; bool bad_element_conn = false; bool duplicate_element = false; int num_outside = 0; bool boundary[6] = { false, false, false, false, false, false }; for (Range::iterator it = contents.begin(); it != contents.end(); ++it) { EntityType type = instance->type_from_handle( *it ); int dim = CN::Dimension( type ); if (dim != 2) { bad_element = true; continue; } const EntityHandle* conn; int conn_len; rval = instance->get_connectivity( *it, conn, conn_len ); if (MB_SUCCESS != rval) { bad_element_handle = true; continue; } std::vector<CartVect> coords(conn_len); rval = instance->get_coords( conn, conn_len, coords[0].array() ); if (MB_SUCCESS != rval) { bad_element_conn = true; continue; } bool outside = false; for (std::vector<CartVect>::iterator j = coords.begin(); j != coords.end(); ++j) { if (!box.contained( *j, epsilon )) outside = true; else for (int d = 0; d < 3; ++d) { #if MB_ORIENTED_BOX_UNIT_VECTORS double n = box.axis[d] % (*j - box.center); if (fabs(n - box.length[d]) <= epsilon) boundary[2*d] = true; if (fabs(n + box.length[d]) <= epsilon) boundary[2*d+1] = true; #else double ln = box.axis[d].length(); CartVect v1 = *j - box.center - box.axis[d]; CartVect v2 = *j - box.center + box.axis[d]; if (fabs(v1 % box.axis[d]) <= ln * epsilon) boundary[2*d] = true; if (fabs(v2 % box.axis[d]) <= ln * epsilon) boundary[2*d+1] = true; #endif } } if (outside) ++num_outside; if (!seen.insert(*it).second) { duplicate_element = true; ++duplicate_entity_count; } } CartVect alength( box.axis[0].length(), box.axis[1].length(), box.axis[2].length() ); #if MB_ORIENTED_BOX_UNIT_VECTORS CartVect length = box.length; #else CartVect length = alength; #endif if (length[0] > length[1] || length[0] > length[2] || length[1] > length[2]) { ++unsorted_axis_count; print( node, "Box axes are not ordered from shortest to longest." ); } #if MB_ORIENTED_BOX_UNIT_VECTORS if (fabs(alength[0] - 1.0) > epsilon || fabs(alength[1] - 1.0) > epsilon || fabs(alength[2] - 1.0) > epsilon) { ++non_unit_count; print( node, "Box axes are not unit vectors."); } #endif #if MB_ORIENTED_BOX_OUTER_RADIUS if (fabs(length.length() - box.radius) > tolerance) { ++bad_outer_radius_count; print( node, "Box has incorrect outer radius."); } #endif if (depth+1 < settings.max_depth && contents.size() > (unsigned)(4*settings.max_leaf_entities)) { char string[64]; sprintf(string, "leaf at depth %d with %u entities", depth, (unsigned)contents.size() ); print( node, string ); } bool all_boundaries = true; for (int f = 0; f < 6; ++f) all_boundaries = all_boundaries && boundary[f]; if (bad_element) { ++entity_invalid_count; print( node, "Set contained an entity with an inappropriate dimension." ); } if (bad_element_handle) { ++error_count; print( node, "Error querying face contained in set."); } if (bad_element_conn) { ++error_count; print( node, "Error querying connectivity of element."); } if (duplicate_element) { print( node, "Elements occur in multiple leaves of tree."); } if (num_outside > 0) { ++entity_outside_count; num_entities_outside += num_outside; if (printing) stream << instance->id_from_handle( node ) << ": " << num_outside << " elements outside box." << std::endl; } else if (!all_boundaries && !contents.empty()) { ++loose_box_count; print( node, "Box does not fit contained elements tightly." ); } return MB_SUCCESS; }