// 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;
}
예제 #2
0
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;
}