void
ComputeReturnMappingStress::updateQpStress(RankTwoTensor & strain_increment,
                                          RankTwoTensor & stress_new)
{
  if (_output_iteration_info == true)
  {
    _console
      << std::endl
      << "iteration output for ComputeReturnMappingStress solve:"
      << " time=" <<_t
      << " int_pt=" << _qp
      << std::endl;
  }

  RankTwoTensor elastic_strain_increment;

  Real l2norm_delta_stress, first_l2norm_delta_stress;
  unsigned int counter = 0;

  std::vector<RankTwoTensor> inelastic_strain_increment;
  inelastic_strain_increment.resize(_models.size());

  for (unsigned i_rmm = 0; i_rmm < _models.size(); ++i_rmm)
    inelastic_strain_increment[i_rmm].zero();

  RankTwoTensor stress_max, stress_min;

  do
  {
    for (unsigned i_rmm = 0; i_rmm < _models.size(); ++i_rmm)
    {
      _models[i_rmm]->setQp(_qp);

      elastic_strain_increment = strain_increment;

      for (unsigned j_rmm = 0; j_rmm < _models.size(); ++j_rmm)
        if (i_rmm != j_rmm)
          elastic_strain_increment -= inelastic_strain_increment[j_rmm];

      stress_new = _elasticity_tensor[_qp] * (elastic_strain_increment + _elastic_strain_old[_qp]);

      _models[i_rmm]->updateStress(elastic_strain_increment,
                                   inelastic_strain_increment[i_rmm],
                                   stress_new);

      if (i_rmm == 0)
      {
        stress_max = stress_new;
        stress_min = stress_new;
      }
      else
      {
        for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
        {
          for (unsigned int j = 0; j < LIBMESH_DIM; ++j)
          {
            if (stress_new(i,j) > stress_max(i,j))
              stress_max(i,j) = stress_new(i,j);
            else if (stress_min(i,j) > stress_new(i,j))
              stress_min(i,j) = stress_new(i,j);
          }
        }
      }

    }

    // now check convergence in the stress:
    // once the change in stress is within tolerance after each recompute material
    // consider the stress to be converged
    RankTwoTensor delta_stress(stress_max - stress_min);
    l2norm_delta_stress = delta_stress.L2norm();
    if (counter == 0)
      first_l2norm_delta_stress = l2norm_delta_stress;

    if (_output_iteration_info == true)
    {
      _console
        << "stress iteration number = " << counter << "\n"
        << " relative l2 norm delta stress = " << (0 == first_l2norm_delta_stress ? 0 : l2norm_delta_stress/first_l2norm_delta_stress) << "\n"
        << " stress convergence relative tolerance = "  << _relative_tolerance <<"\n"
        << " absolute l2 norm delta stress = " << l2norm_delta_stress << "\n"
        << " stress converengen absolute tolerance = "  << _absolute_tolerance
        << std::endl;
    }
    ++counter;
  }
  while (counter < _max_its &&
          l2norm_delta_stress > _absolute_tolerance &&
          (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance &&
          _models.size() != 1);

  if (counter == _max_its &&
      l2norm_delta_stress > _absolute_tolerance &&
      (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance)
    mooseError("Max stress iteration hit during ComputeReturnMappingStress solve!");

  strain_increment = elastic_strain_increment;
}
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;
}
Exemple #3
0
Real
HEMFluidProperties::molarMass() const
{
  mooseError(name(), ": molarMass is not implemented");
}
void
AddSideSetsFromBoundingBox::modify()
{
  // this modifier is not designed for working with distributed mesh
  _mesh_ptr->errorIfDistributedMesh("BreakBoundaryOnSubdomain");

  // Check that we have access to the mesh
  if (!_mesh_ptr)
    mooseError("_mesh_ptr must be initialized before calling SubdomainBoundingBox::modify()");

  // Reference the the libMesh::MeshBase
  MeshBase & mesh = _mesh_ptr->getMesh();

  // Get a reference to our BoundaryInfo object for later use
  BoundaryInfo & boundary_info = mesh.get_boundary_info();

  bool found_element = false;
  bool found_side_sets = false;

  if (!_boundary_id_overlap)
  {
    // Loop over the elements
    for (const auto & elem : mesh.active_element_ptr_range())
    {
      // boolean if element centroid is in bounding box
      bool contains = _bounding_box.contains_point(elem->centroid());

      // check if active elements are found in the bounding box
      if (contains)
      {
        found_element = true;
        // loop over sides of elements within bounding box
        for (unsigned int side = 0; side < elem->n_sides(); side++)
          // loop over provided boundary vector to check all side sets for all boundary ids
          for (unsigned int boundary_id_number = 0; boundary_id_number < _boundary_id_old.size();
               boundary_id_number++)
            // check if side has same boundary id that you are looking for
            if (boundary_info.has_boundary_id(
                    elem, side, boundary_info.get_id_by_name(_boundary_id_old[boundary_id_number])))
            {
              // assign new boundary value to boundary which meets meshmodifier criteria
              boundary_info.add_side(elem, side, _boundary_id_new);
              found_side_sets = true;
            }
      }
    }
    if (!found_element)
      mooseError("No elements found within the bounding box");

    if (!found_side_sets)
      mooseError("No side sets found on active elements within the bounding box");
  }

  else if (_boundary_id_overlap)
  {
    if (_boundary_id_old.size() < 2)
      mooseError("boundary_id_old out of bounds: ",
                 _boundary_id_old.size(),
                 " Must be 2 boundary inputs or more.");

    bool found_node = false;
    const bool inside = (_location == "INSIDE");

    // Loop over the elements and assign node set id to nodes within the bounding box
    for (auto node = mesh.active_nodes_begin(); node != mesh.active_nodes_end(); ++node)
    {
      // check if nodes are inside of bounding box
      if (_bounding_box.contains_point(**node) == inside)
      {
        // read out boundary ids for nodes
        std::vector<short int> boundary_id_list = boundary_info.boundary_ids(*node);
        std::vector<boundary_id_type> boundary_id_old_list =
            _mesh_ptr->getBoundaryIDs(_boundary_id_old);

        // sort boundary ids on node and sort boundary ids provided in input file
        std::sort(boundary_id_list.begin(), boundary_id_list.end());
        std::sort(boundary_id_old_list.begin(), boundary_id_old_list.end());

        // check if input boundary ids are all contained in the node
        // if true, write new boundary id on respective node
        if (std::includes(boundary_id_list.begin(),
                          boundary_id_list.end(),
                          boundary_id_old_list.begin(),
                          boundary_id_old_list.end()))
        {
          boundary_info.add_node(*node, _boundary_id_new);
          found_node = true;
        }
      }
    }

    if (!found_node)
      mooseError("No nodes found within the bounding box");
  }
}
Exemple #5
0
void
AddExtraNodeset::modify()
{
  // make sure the input is not empty
  bool data_valid = false;
  if (_pars.isParamValid("nodes"))
    if (getParam<std::vector<unsigned int> >("nodes").size() != 0)
      data_valid = true;
  if (_pars.isParamValid("coord"))
  {
    unsigned int n_coord = getParam<std::vector<Real> >("coord").size();
    if (n_coord % _mesh_ptr->dimension() != 0)
      mooseError("Size of node coordinates does not match the mesh dimension");
    if (n_coord !=0)
      data_valid = true;
  }
  if (!data_valid)
    mooseError("Node set can not be empty!");

  // Get the BoundaryIDs from the mesh
  std::vector<BoundaryName> boundary_names = boundaryNames();
  std::vector<BoundaryID> boundary_ids(boundaryIDs().begin(), boundaryIDs().end());

  // Get a reference to our BoundaryInfo object
  BoundaryInfo & boundary_info = _mesh_ptr->getMesh().get_boundary_info();

  // add nodes with their ids
  const std::vector<unsigned int> & nodes = getParam<std::vector<unsigned int> >("nodes");
  for (unsigned int i=0; i<nodes.size(); i++)
    for (unsigned int j=0; j<boundary_ids.size(); ++j)
      boundary_info.add_node(nodes[i], boundary_ids[j]);

  // add nodes with their coordinates
  const std::vector<Real> & coord = getParam<std::vector<Real> >("coord");
  unsigned int dim = _mesh_ptr->dimension();
  unsigned int n_nodes = coord.size() / dim;

  for (unsigned int i=0; i<n_nodes; i++)
  {
    Point p;
    for (unsigned int j=0; j<dim; j++)
      p(j) = coord[i*dim+j];

    const Elem* elem = _mesh_ptr->getMesh().point_locator() (p);
    if (!elem)
      mooseError("Unable to locate the following point within the domain, please check its coordinates:\n" << p);

    bool on_node = false;
    for (unsigned int j=0; j<elem->n_nodes(); j++)
    {
      const Node* node = elem->get_node(j);

      Point q;
      for (unsigned int k=0; k<dim; k++)
        q(k) = (*node)(k);

      if (p.absolute_fuzzy_equals(q, getParam<Real>("tolerance")))
      {
        for (unsigned int j=0; j<boundary_ids.size(); ++j)
          boundary_info.add_node(node, boundary_ids[j]);

        on_node = true;
        break;
      }
    }
    if (!on_node)
      mooseError("Point can not be located!");
  }

  for (unsigned int i=0; i<boundary_ids.size(); ++i)
    boundary_info.sideset_name(boundary_ids[i]) = boundary_names[i];
}
Real SinglePhaseFluidProperties::henryConstant(Real /*temperature*/) const
{
  mooseError(name(), ": henryConstant() is not implemented");
}
Real SinglePhaseFluidProperties::k_from_v_e(Real, Real) const
{
  mooseError(name(), ": ", __PRETTY_FUNCTION__, " not implemented.");
}
Real
MaterialTensorCalculator::getTensorQuantity(const SymmTensor & tensor,
                                            const Point & curr_point,
                                            RealVectorValue &direction)
{
  direction.zero();
  Real value = 0.0;

  switch (_quantity)
  {
    case 0:
      value = MaterialTensorCalculatorTools::component(tensor, _index, direction);
      break;

    case 1:
      value = MaterialTensorCalculatorTools::vonMisesStress(tensor);
      break;

    case 2:
      value = MaterialTensorCalculatorTools::equivalentPlasticStrain(tensor);
      break;

    case 3:
      value = MaterialTensorCalculatorTools::hydrostatic(tensor);
      break;

    case 4:
      value = MaterialTensorCalculatorTools::directionValueTensor(tensor, _direction);
      break;

    case 5:
      value = MaterialTensorCalculatorTools::hoopStress(tensor, _p1, _p2, curr_point, direction);
      break;

    case 6:
      value = MaterialTensorCalculatorTools::radialStress(tensor, _p1, _p2, curr_point, direction);
      break;

    case 7:
      value = MaterialTensorCalculatorTools::axialStress(tensor, _p1, _p2, direction);
      break;

    case 8:
      value = MaterialTensorCalculatorTools::maxPrinciple(tensor, direction);
      break;

    case 9:
      value = MaterialTensorCalculatorTools::midPrinciple(tensor, direction);
      break;

    case 10:
      value = MaterialTensorCalculatorTools::minPrinciple(tensor, direction);
      break;

    case 11:
      value = MaterialTensorCalculatorTools::firstInvariant(tensor);
      break;

    case 12:
      value = MaterialTensorCalculatorTools::secondInvariant(tensor);
      break;

    case 13:
      value = MaterialTensorCalculatorTools::thirdInvariant(tensor);
      break;

    case 14:
      value = MaterialTensorCalculatorTools::triaxialityStress(tensor);
      break;

    case 15:
      value = MaterialTensorCalculatorTools::volumetricStrain(tensor);
      break;

    default:
    mooseError("Unknown quantity in MaterialTensorAux: " + _quantity_moose_enum.operator std::string());
  }
  return value;
}
Exemple #9
0
RealVectorValue
MooseParsedFunction::vectorValue(Real /*t*/, const Point & /*p*/) const
{
  mooseError("The vectorValue method is not defined in ParsedFunction");
}
std::unique_ptr<MeshBase>
SideSetsFromBoundingBoxGenerator::generate()
{
  std::unique_ptr<MeshBase> mesh = std::move(_input);

  // Get a reference to our BoundaryInfo object for later use
  BoundaryInfo & boundary_info = mesh->get_boundary_info();
  boundary_info.build_node_list_from_side_list();

  bool found_element = false;
  bool found_side_sets = false;

  if (!_boundary_id_overlap)
  {
    // Loop over the elements
    for (const auto & elem : mesh->active_element_ptr_range())
    {
      // boolean if element centroid is in bounding box
      bool contains = _bounding_box.contains_point(elem->centroid());

      // check if active elements are found in the bounding box
      if (contains)
      {
        found_element = true;
        // loop over sides of elements within bounding box
        for (unsigned int side = 0; side < elem->n_sides(); side++)
          // loop over provided boundary vector to check all side sets for all boundary ids
          for (unsigned int boundary_id_number = 0; boundary_id_number < _boundary_id_old.size();
               boundary_id_number++)
            // check if side has same boundary id that you are looking for
            if (boundary_info.has_boundary_id(
                    elem, side, boundary_info.get_id_by_name(_boundary_id_old[boundary_id_number])))
            {
              // assign new boundary value to boundary which meets meshmodifier criteria
              boundary_info.add_side(elem, side, _boundary_id_new);
              found_side_sets = true;
            }
      }
    }
    if (!found_element)
      mooseError("No elements found within the bounding box");

    if (!found_side_sets)
      mooseError("No side sets found on active elements within the bounding box");
  }

  else if (_boundary_id_overlap)
  {
    if (_boundary_id_old.size() < 2)
      mooseError("boundary_id_old out of bounds: ",
                 _boundary_id_old.size(),
                 " Must be 2 boundary inputs or more.");

    bool found_node = false;
    const bool inside = (_location == "INSIDE");

    // Loop over the elements and assign node set id to nodes within the bounding box
    for (auto node = mesh->active_nodes_begin(); node != mesh->active_nodes_end(); ++node)
    {
      // check if nodes are inside of bounding box
      if (_bounding_box.contains_point(**node) == inside)
      {
        // read out boundary ids for nodes
        std::vector<boundary_id_type> boundary_id_list;
        boundary_info.boundary_ids(*node, boundary_id_list);
        std::vector<boundary_id_type> boundary_id_old_list =
            MooseMeshUtils::getBoundaryIDs(*mesh, _boundary_id_old, true);

        // sort boundary ids on node and sort boundary ids provided in input file
        std::sort(boundary_id_list.begin(), boundary_id_list.end());
        std::sort(boundary_id_old_list.begin(), boundary_id_old_list.end());

        // check if input boundary ids are all contained in the node
        // if true, write new boundary id on respective node
        if (std::includes(boundary_id_list.begin(),
                          boundary_id_list.end(),
                          boundary_id_old_list.begin(),
                          boundary_id_old_list.end()))
        {
          boundary_info.add_node(*node, _boundary_id_new);
          found_node = true;
        }
      }
    }

    if (!found_node)
      mooseError("No nodes found within the bounding box");
  }

  return dynamic_pointer_cast<MeshBase>(mesh);
}
/*
 *Solves for incremental plastic rate of deformation tensor and stress in unrotated frame.
 *Input: Strain incrment, 4th order elasticity tensor, stress tensor in previous incrmenent and
 *plastic rate of deformation tensor.
 */
void
FiniteStrainRatePlasticMaterial::returnMap(const RankTwoTensor & sig_old, const RankTwoTensor & delta_d, const RankFourTensor & E_ijkl, RankTwoTensor & dp, RankTwoTensor & sig)
{
  RankTwoTensor sig_new, delta_dp, dpn;
  RankTwoTensor flow_tensor, flow_dirn;
  RankTwoTensor resid,ddsig;
  RankFourTensor dr_dsig, dr_dsig_inv;
  Real flow_incr, flow_incr_tmp;
  Real err1, err3, tol1, tol3;
  unsigned int iterisohard, iter, maxiterisohard = 20, maxiter = 50;
  Real eqvpstrain;
  Real yield_stress, yield_stress_prev;

  tol1 = 1e-10;
  tol3 = 1e-6;

  iterisohard = 0;
  eqvpstrain = std::pow(2.0/3.0,0.5) * dp.L2norm();
  yield_stress = getYieldStress(eqvpstrain);

  err3 = 1.1 * tol3;

  while (err3 > tol3 && iterisohard < maxiterisohard) //Hardness update iteration
  {
    iterisohard++;
    iter = 0;
    delta_dp.zero();

    sig_new = sig_old + E_ijkl * delta_d;
    flow_incr=_ref_pe_rate*_dt * std::pow(macaulayBracket(getSigEqv(sig_new) / yield_stress - 1.0), _exponent);

    getFlowTensor(sig_new, yield_stress, flow_tensor);
    flow_dirn = flow_tensor;

    resid = flow_dirn * flow_incr - delta_dp;
    err1 = resid.L2norm();

    while (err1 > tol1  && iter < maxiter) //Stress update iteration (hardness fixed)
    {
      iter++;

      getJac(sig_new, E_ijkl, flow_incr, yield_stress, dr_dsig); //Jacobian
      dr_dsig_inv = dr_dsig.invSymm();

      ddsig = -dr_dsig_inv * resid;

      sig_new += ddsig; //Update stress
      delta_dp -= E_ijkl.invSymm() * ddsig; //Update plastic rate of deformation tensor

      flow_incr_tmp = _ref_pe_rate * _dt * std::pow(macaulayBracket(getSigEqv(sig_new) / yield_stress - 1.0), _exponent);

      if (flow_incr_tmp < 0.0) //negative flow increment not allowed
        mooseError("Constitutive Error-Negative flow increment: Reduce time increment.");

      flow_incr = flow_incr_tmp;

      getFlowTensor(sig_new, yield_stress, flow_tensor);
      flow_dirn = flow_tensor;

      resid = flow_dirn * flow_incr - delta_dp; //Residual

      err1=resid.L2norm();
    }

    if (iter>=maxiter)//Convergence failure
      mooseError("Constitutive Error-Too many iterations: Reduce time increment.\n"); //Convergence failure

    dpn = dp + delta_dp;
    eqvpstrain = std::pow(2.0/3.0, 0.5) * dpn.L2norm();

    yield_stress_prev = yield_stress;
    yield_stress = getYieldStress(eqvpstrain);

    err3 = std::abs(yield_stress-yield_stress_prev);
  }

  if (iterisohard>=maxiterisohard)
    mooseError("Constitutive Error-Too many iterations in Hardness Update:Reduce time increment.\n"); //Convergence failure

  dp = dpn; //Plastic rate of deformation tensor in unrotated configuration
  sig = sig_new;
}
Exemple #12
0
PeacemanBorehole::PeacemanBorehole(const InputParameters & parameters) :
    DiracKernel(parameters),
    _re_constant(getParam<Real>("re_constant")),
    _well_constant(getParam<Real>("well_constant")),
    _borehole_length(getParam<Real>("borehole_length")),
    _borehole_direction(getParam<RealVectorValue>("borehole_direction")),
    _point_file(getParam<std::string>("point_file")),
    _character(getFunction("character")),
    _p_bot(getParam<Real>("bottom_pressure")),
    _unit_weight(getParam<RealVectorValue>("unit_weight")),
    _total_outflow_mass(const_cast<RichardsSumQuantity &>(getUserObject<RichardsSumQuantity>("SumQuantityUO")))
{
    // zero the outflow mass
    _total_outflow_mass.zero();

    // open file
    std::ifstream file(_point_file.c_str());
    if (!file.good())
        mooseError("Error opening file '" + _point_file + "' from a Peaceman-type Borehole.");

    // construct the arrays of radius, x, y and z
    std::vector<Real> scratch;
    while (parseNextLineReals(file, scratch))
    {
        if (scratch.size() >= 2)
        {
            _rs.push_back(scratch[0]);
            _xs.push_back(scratch[1]);
            if (scratch.size() >= 3)
                _ys.push_back(scratch[2]);
            else
                _ys.push_back(0.0);
            if (scratch.size() >= 4)
                _zs.push_back(scratch[3]);
            else
                _zs.push_back(0.0);
        }
    }

    file.close();

    const int num_pts = _zs.size();
    _bottom_point(0) = _xs[num_pts - 1];
    _bottom_point(1) = _ys[num_pts - 1];
    _bottom_point(2) = _zs[num_pts - 1];

    // construct the line-segment lengths between each point
    _half_seg_len.resize(std::max(num_pts-1, 1));
    for (unsigned int i = 0 ; i + 1 < _xs.size(); ++i)
    {
        _half_seg_len[i] = 0.5*std::sqrt(std::pow(_xs[i+1] - _xs[i], 2) + std::pow(_ys[i+1] - _ys[i], 2) + std::pow(_zs[i+1] - _zs[i], 2));
        if (_half_seg_len[i] == 0)
            mooseError("Peaceman-type borehole has a zero-segment length at (x,y,z) = " << _xs[i] << " " << _ys[i] << " " << _zs[i] << "\n");
    }
    if (num_pts == 1)
        _half_seg_len[0] = _borehole_length;

    // construct the rotation matrix needed to rotate the permeability
    _rot_matrix.resize(std::max(num_pts-1, 1));
    for (unsigned int i = 0 ; i + 1 < _xs.size(); ++i)
    {
        const RealVectorValue v2(_xs[i+1] - _xs[i], _ys[i+1] - _ys[i], _zs[i+1] - _zs[i]);
        _rot_matrix[i] = RotationMatrix::rotVecToZ(v2);
    }
    if (num_pts == 1)
        _rot_matrix[0] = RotationMatrix::rotVecToZ(_borehole_direction);
}
Exemple #13
0
Real
PeacemanBorehole::wellConstant(const RealTensorValue & perm, const RealTensorValue & rot, const Real & half_len, const Elem * ele, const Real & rad)
// Peaceman's form for the borehole well constant
{
    if (_well_constant > 0)
        return _well_constant;

    // rot_perm has its "2" component lying along the half segment
    // we want to determine the eigenvectors of rot(0:1, 0:1), since, when
    // rotated back to the original frame we will determine the element
    // lengths along these directions
    const RealTensorValue rot_perm = (rot*perm)*rot.transpose();
    const Real trace2D = rot_perm(0,0) + rot_perm(1,1);
    const Real det2D = rot_perm(0,0)*rot_perm(1,1) - rot_perm(0,1)*rot_perm(1,0);
    const Real sq = std::sqrt(std::max(0.25*trace2D*trace2D - det2D, 0.0)); // the std::max accounts for wierdo precision loss
    const Real eig_val1 = 0.5*trace2D + sq;
    const Real eig_val2 = 0.5*trace2D - sq;
    RealVectorValue eig_vec1, eig_vec2;
    if (sq > std::abs(trace2D)*1E-7) // matrix is not a multiple of the identity (1E-7 accounts for precision in a crude way)
    {
        if (rot_perm(1,0) != 0)
        {
            eig_vec1(0) = eig_val1 - rot_perm(1,1);
            eig_vec1(1) = rot_perm(1,0);
            eig_vec2(0) = eig_val2 - rot_perm(1,1);
            eig_vec2(1) = rot_perm(1,0);
        }
        else if (rot_perm(0,1) != 0)
        {
            eig_vec1(0) = rot_perm(0,1);
            eig_vec1(1) = eig_val1 - rot_perm(0,0);
            eig_vec2(0) = rot_perm(0,1);
            eig_vec2(1) = eig_val2 - rot_perm(0,0);
        }
        else // off diagonal terms are both zero
        {
            eig_vec1(0) = 1;
            eig_vec2(1) = 1;
        }
    }
    else // matrix is basically a multiple of the identity
    {
        eig_vec1(0) = 1;
        eig_vec2(1) = 1;
    }


    // finally, rotate these to original frame and normalise
    eig_vec1 = rot.transpose()*eig_vec1;
    eig_vec1 /= std::sqrt(eig_vec1*eig_vec1);
    eig_vec2 = rot.transpose()*eig_vec2;
    eig_vec2 /= std::sqrt(eig_vec2*eig_vec2);

    // find the "length" of the element in these directions
    // TODO - probably better to use variance than max&min
    Real max1 = eig_vec1*ele->point(0);
    Real max2 = eig_vec2*ele->point(0);
    Real min1 = max1;
    Real min2 = max2;
    Real proj;
    for (unsigned int i = 1; i < ele->n_nodes(); i++)
    {
        proj = eig_vec1*ele->point(i);
        max1 = (max1 < proj) ? proj : max1;
        min1 = (min1 < proj) ? min1 : proj;

        proj = eig_vec2*ele->point(i);
        max2 = (max2 < proj) ? proj : max2;
        min2 = (min2 < proj) ? min2 : proj;
    }
    const Real ll1 = max1 - min1;
    const Real ll2 = max2 - min2;

    const Real r0 = _re_constant*std::sqrt( std::sqrt(eig_val1/eig_val2)*std::pow(ll2, 2) + std::sqrt(eig_val2/eig_val1)*std::pow(ll1, 2)) / ( std::pow(eig_val1/eig_val2, 0.25) + std::pow(eig_val2/eig_val1, 0.25) );

    const Real effective_perm = std::sqrt(det2D);

    const Real halfPi = acos(0.0);

    if (r0 <= rad)
        mooseError("The effective element size (about 0.2-times-true-ele-size) for an element containing a Peaceman-type borehole must be (much) larger than the borehole radius for the Peaceman formulation to be correct.  Your element has effective size " << r0 << " and the borehole radius is " << rad << "\n");

    return 4*halfPi*effective_perm*half_len/std::log(r0/rad);
}
Exemple #14
0
void
ActionWarehouse::addActionBlock(Action * action)
{
  /**
   * Note: This routine uses the XTerm colors directly which is not advised for general purpose output coloring.
   * Most users should prefer using Problem::colorText() which respects the "color_output" option for terminals
   * that do not support coloring.  Since this routine is intended for debugging only and runs before several
   * objects exist in the system, we are just using the constants directly.
   */

  std::string registered_identifier = action->getParams().get<std::string>("registered_identifier");
  std::set<std::string> tasks;

  if (_show_parser)
    Moose::err << COLOR_DEFAULT << "Parsing Syntax:        " << COLOR_GREEN   << action->name() << '\n'
               << COLOR_DEFAULT << "Building Action:       " << COLOR_DEFAULT << action->type() << '\n'
               << COLOR_DEFAULT << "Registered Identifier: " << COLOR_GREEN   << registered_identifier << '\n'
               << COLOR_DEFAULT << "Specific Task:         " << COLOR_CYAN    << action->specificTaskName() << '\n';

  /**
   * We need to see if the current Action satisfies multiple tasks. There are a few cases to consider:
   *
   * 1. The current Action is registered with multiple syntax blocks. In this case we can only use the
   *    current instance to satisfy the specific task listed for this syntax block.  We can detect this
   *    case by inspecting whether it has a "specific task name" set in the Action instance.
   *
   * 2. This action does not have a valid "registered identifier" set in the Action instance. This means
   *    that this Action was not built by the Parser.  It was most likely created through a Meta-Action.
   *    In this case, the ActionFactory itself would have already set the task it found from the build
   *    info used to construct the Action.
   *
   * 3. The current Action is registered with only a single syntax block. In this case we can simply
   *    re-use the current instance to act and satisfy _all_ registered tasks. This is the normal
   *    case where we have a Parser-built Action that does not have a specific task name to satisfy.
   *    We will use the Action "type" to retrieve the list of tasks that this Action may satisfy.
   */
  if (action->specificTaskName() != "")           // Case 1
    tasks.insert(action->specificTaskName());
  else if (registered_identifier == "")           // Case 2
  {
    std::set<std::string> local_tasks = action->getAllTasks();
    mooseAssert(local_tasks.size() == 1, "More than one task inside of the " << action->name());
    tasks.insert(*local_tasks.begin());
  }
  else                                            // Case 3
    tasks = _action_factory.getTasksByAction(action->type());


  //TODO: Now we need to weed out the double registrations!
  for (std::set<std::string>::iterator it = tasks.begin(); it != tasks.end(); ++it)
  {
    const std::string & task = *it;

    // Some error checking
    if (!_syntax.hasTask(task))
      mooseError("A(n) " << task << " is not a registered task");

    // Make sure that the ObjectAction task and Action task are consistent
    // otherwise that means that is action was built by the wrong type
    MooseObjectAction * moa = dynamic_cast<MooseObjectAction *>(action);
    if (moa)
    {
      InputParameters mparams = moa->getObjectParams();

      if (mparams.have_parameter<std::string>("_moose_base"))
      {
        const std::string & base = mparams.get<std::string>("_moose_base");

        if (!_syntax.verifyMooseObjectTask(base, *it))
          mooseError("Task " << *it << " is not registered to build " << base << " derived objects");
      }
      else
        mooseError("Unable to locate registered base parameter for " << moa->getMooseObjectType());
    }

    // Add the current task to current action
    action->appendTask(*it);

    if (_show_parser)
      Moose::err << COLOR_YELLOW << "Adding Action:         " << COLOR_DEFAULT << action->type() << " (" << COLOR_YELLOW << *it << COLOR_DEFAULT << ")\n";

    // Add it to the warehouse
    _action_blocks[*it].push_back(action);
  }

  if (_show_parser)
    Moose::err << std::endl;
}
void
SinglePhaseFluidProperties::mu_drhoT_from_rho_T(Real, Real, Real, Real &, Real &, Real &) const
{
  mooseError(name(), ": mu_drhoT_from_rho_T is not implemented.");
}
Real
PorousFlowFluxLimitedTVDAdvection::computeQpResidual()
{
  mooseError("PorousFlowFluxLimitedTVDAdvection::computeQpResidual() called\n");
  return 0.0;
}
Real SinglePhaseFluidProperties::k_from_rho_T(Real /*density*/, Real /*temperature*/) const
{
  mooseError(name(), ": k_from_rho_T is not implemented.");
}
void
ComputeLinearElasticStress::initialSetup()
{
  if (hasMaterialProperty<RankTwoTensor>(_base_name + "strain_increment"))
    mooseError("This linear elastic stress calculation only works for small strains");
}
Real SinglePhaseFluidProperties::vaporPressure(Real /*temperature*/) const
{
  mooseError(name(), ": vaporPressure() is not implemented");
}
Real NaClFluidProperties::c_from_p_T(Real /*pressure*/, Real /*temperature*/) const
{
  mooseError(name(), ": c() is not implemented");
}
void
SinglePhaseFluidProperties::s_from_h_p(Real, Real, Real &, Real &, Real &) const
{
  mooseError(name(), ": ", __PRETTY_FUNCTION__, " not implemented.");
}
Exemple #22
0
void
GrainTracker::trackGrains()
{
  // Don't track grains if the current simulation step is before the specified tracking step
  if (_t_step < _tracking_step)
    return;

  // Reset Status on active unique grains
  std::vector<unsigned int> map_sizes(_maps_size);
  for (std::map<unsigned int, UniqueGrain *>::iterator grain_it = _unique_grains.begin();
       grain_it != _unique_grains.end(); ++grain_it)
  {
    if (grain_it->second->status != INACTIVE)
    {
      grain_it->second->status = NOT_MARKED;
      map_sizes[grain_it->second->variable_idx]++;
    }
  }

  // Print out info on the number of unique grains per variable vs the incoming bubble set sizes
  if (_t_step > _tracking_step)
  {
    for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
    {
      Moose::out << "\nGrains active index " << map_num << ": " << map_sizes[map_num] << " -> " << _bubble_sets[map_num].size();
      if (map_sizes[map_num] != _bubble_sets[map_num].size())
        Moose::out << "**";
    }
    Moose::out << std::endl;
  }

  std::vector<UniqueGrain *> new_grains; new_grains.reserve(_unique_grains.size());

  // Loop over all the current regions and build our unique grain structures
  for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
  {
    for (std::list<BubbleData>::const_iterator it1 = _bubble_sets[map_num].begin();
         it1 != _bubble_sets[map_num].end(); ++it1)
    {
      std::vector<BoundingSphereInfo *> sphere_ptrs;
      unsigned int curr_var = it1->_var_idx;

      for (std::list<BoundingSphereInfo *>::iterator it2 = _bounding_spheres[map_num].begin();
           it2 != _bounding_spheres[map_num].end(); /* No increment here! */)
      {
        /**
         * See which of the bounding spheres belong to the current region (bubble set) by looking at a
         * member node id.  A single region may have multiple bounding spheres as members if it spans
         * periodic boundaries
         */
        if (it1->_entity_ids.find((*it2)->member_node_id) != it1->_entity_ids.end())
        {
          // Transfer ownership of the bounding sphere info to "sphere_ptrs" which will be stored in the unique grain
          sphere_ptrs.push_back(*it2);
          // Now delete the current BoundingSpherestructure so that it won't be inspected or reused
          _bounding_spheres[map_num].erase(it2++);
        }
        else
          ++it2;
      }

      // Create our new grains from this timestep that we will use to match up against the existing grains
      new_grains.push_back(new UniqueGrain(curr_var, sphere_ptrs, &it1->_entity_ids, NOT_MARKED));
    }
  }

  /**
   * If it's the first time through this routine for the simulation, we will generate the unique grain
   * numbers using a simple counter.  These will be the unique grain numbers that we must track for
   * the remainder of the simulation.
   */
  if (_t_step == _tracking_step)   // Start tracking when the time_step == the tracking_step
  {
    if (_ebsd_reader)
    {
      Real grain_num = _ebsd_reader->getGrainNum();

      std::vector<Point> center_points(grain_num);

      for (unsigned int gr=0; gr < grain_num; ++gr)
      {
        const EBSDReader::EBSDAvgData & d = _ebsd_reader->getAvgData(gr);
        center_points[gr] = d.p;

        Moose::out << "EBSD Grain " << gr << " " << center_points[gr] << '\n';
      }

      // To find the minimum distance we will use the boundingRegionDistance routine.
      // To do that, we need to build BoundingSphereObjects with a few dummy values, radius and node_id will be ignored
      BoundingSphereInfo ebsd_sphere(0, Point(0, 0, 0), 1);
      std::vector<BoundingSphereInfo *> ebsd_vector(1);
      ebsd_vector[0] = &ebsd_sphere;

      std::set<unsigned int> used_indices;
      std::map<unsigned int, unsigned int> error_indices;

      if (grain_num != new_grains.size())
        mooseWarning("Mismatch:\nEBSD centers: " << grain_num << " Grain Tracker Centers: " << new_grains.size());

      unsigned int next_index = grain_num+1;
      for (unsigned int i = 0; i < new_grains.size(); ++i)
      {
        Real min_centroid_diff = std::numeric_limits<Real>::max();
        unsigned int closest_match_idx = 0;

        //Point center_of_mass = centerOfMass(*new_grains[i]);

        for (unsigned int j = 0; j<center_points.size(); ++j)
        {
          // Update the ebsd sphere to be used in the boundingRegionDistance calculation
          ebsd_sphere.b_sphere.center() = center_points[j];

          Real curr_centroid_diff = boundingRegionDistance(ebsd_vector, new_grains[i]->sphere_ptrs, true);
          //Real curr_centroid_diff = (center_points[j] - center_of_mass).size();
          if (curr_centroid_diff <= min_centroid_diff)
          {
            closest_match_idx = j;
            min_centroid_diff = curr_centroid_diff;
          }
        }

        if (used_indices.find(closest_match_idx) != used_indices.end())
        {
          Moose::out << "Re-assigning center " << closest_match_idx << " -> " << next_index << " "
                     << center_points[closest_match_idx] << " absolute distance: " << min_centroid_diff << '\n';
          _unique_grains[next_index] = new_grains[i];

          _unique_grain_to_ebsd_num[next_index] = closest_match_idx+1;

          ++next_index;
        }
        else
        {
          Moose::out << "Assigning center " << closest_match_idx << " "
                     << center_points[closest_match_idx] << " absolute distance: " << min_centroid_diff << '\n';
          _unique_grains[closest_match_idx+1] = new_grains[i];

          _unique_grain_to_ebsd_num[closest_match_idx+1] = closest_match_idx+1;

          used_indices.insert(closest_match_idx);
        }
      }
      if (!error_indices.empty())
      {
        for (std::map<unsigned int, UniqueGrain *>::const_iterator grain_it = _unique_grains.begin(); grain_it != _unique_grains.end(); ++grain_it)
          Moose::out << "Grain " << grain_it->first << ": " << center_points[grain_it->first - 1] << '\n';

        Moose::out << "Error Indices:\n";
        for (std::map<unsigned int, unsigned int>::const_iterator it = error_indices.begin(); it != error_indices.end(); ++it)
          Moose::out << "Grain " << it->first << '(' << it->second << ')' << ": " << center_points[it->second] << '\n';

        mooseError("Error with ESBD Mapping (see above unused indices)");
      }

      print();
    }
    else
    {
      for (unsigned int i = 1; i <= new_grains.size(); ++i)
      {
        new_grains[i-1]->status = MARKED;
        _unique_grains[i] = new_grains[i-1];                   // Transfer ownership of the memory
      }
    }
    return;  // Return early - no matching or tracking to do
  }

  /**
   * To track grains across timesteps, we will loop over our unique grains and link each one up with one of our new
   * unique grains.  The criteria for doing this will be to find the unique grain in the new list with a matching variable
   * index whose centroid is closest to this unique grain.
   */
  std::map<unsigned int, std::vector<unsigned int> > new_grain_idx_to_existing_grain_idx;

  for (std::map<unsigned int, UniqueGrain *>::iterator curr_it = _unique_grains.begin(); curr_it != _unique_grains.end(); ++curr_it)
  {
    if (curr_it->second->status == INACTIVE)                         // Don't try to find matches for inactive grains
      continue;

    unsigned int closest_match_idx;
    // bool found_one = false;
    Real min_centroid_diff = std::numeric_limits<Real>::max();

    for (unsigned int new_grain_idx = 0; new_grain_idx<new_grains.size(); ++new_grain_idx)
    {
      if (curr_it->second->variable_idx == new_grains[new_grain_idx]->variable_idx)  // Do the variables indicies match?
      {
        Real curr_centroid_diff = boundingRegionDistance(curr_it->second->sphere_ptrs, new_grains[new_grain_idx]->sphere_ptrs, true);
        if (curr_centroid_diff <= min_centroid_diff)
        {
          // found_one = true;
          closest_match_idx = new_grain_idx;
          min_centroid_diff = curr_centroid_diff;
        }
      }
    }

    // Keep track of which new grains the existing ones want to map to
    new_grain_idx_to_existing_grain_idx[closest_match_idx].push_back(curr_it->first);
  }

  /**
   * It's possible that multiple existing grains will map to a single new grain.  This will happen any time a grain disappears during this timestep.
   * We need to figure out the rightful owner in this case and inactivate the old grain.
   */
  for (std::map<unsigned int, std::vector<unsigned int> >::iterator it = new_grain_idx_to_existing_grain_idx.begin();
       it != new_grain_idx_to_existing_grain_idx.end(); ++it)
  {
    // If there is only a single mapping - we've found the correct grain
    if (it->second.size() == 1)
    {
      unsigned int curr_idx = (it->second)[0];
      delete _unique_grains[curr_idx];                      // clean-up old grain
      new_grains[it->first]->status = MARKED;               // Mark it
      _unique_grains[curr_idx] = new_grains[it->first];     // transfer ownership of new grain
    }

    // More than one existing grain is mapping to a new one
    else
    {
      Real min_centroid_diff = std::numeric_limits<Real>::max();
      unsigned int min_idx = 0;
      for (unsigned int i = 0; i < it->second.size(); ++i)
      {
        Real curr_centroid_diff = boundingRegionDistance(new_grains[it->first]->sphere_ptrs, _unique_grains[(it->second)[i]]->sphere_ptrs, true);
        if (curr_centroid_diff <= min_centroid_diff)
        {
          min_idx = i;
          min_centroid_diff = curr_centroid_diff;
        }
      }

      // One more time over the competing indices.  We will mark the non-winners as inactive and transfer ownership to the winner (the closest centroid).
      for (unsigned int i = 0; i < it->second.size(); ++i)
      {
        unsigned int curr_idx = (it->second)[i];
        if (i == min_idx)
        {
          delete _unique_grains[curr_idx];                      // clean-up old grain
          new_grains[it->first]->status = MARKED;               // Mark it
          _unique_grains[curr_idx] = new_grains[it->first];     // transfer ownership of new grain
        }
        else
        {
          Moose::out << "Marking Grain " << curr_idx << " as INACTIVE (varible index: "
                    << _unique_grains[curr_idx]->variable_idx <<  ")\n";
          _unique_grains[curr_idx]->status = INACTIVE;
        }
      }
    }
  }


  /**
   * Next we need to look at our new list and see which grains weren't matched up.  These are new grains.
   */
  for (unsigned int i = 0; i < new_grains.size(); ++i)
    if (new_grains[i]->status == NOT_MARKED)
    {
      Moose::out << COLOR_YELLOW
                 << "*****************************************************************************\n"
                 << "Couldn't find a matching grain while working on variable index: " << new_grains[i]->variable_idx
                 << "\nCreating new unique grain: " << _unique_grains.size() + 1
                 << "\n*****************************************************************************\n" << COLOR_DEFAULT;
      new_grains[i]->status = MARKED;
      _unique_grains[_unique_grains.size() + 1] = new_grains[i];   // transfer ownership
    }


  /**
   * Finally we need to mark any grains in the unique list that aren't marked as inactive.  These are the variables that
   * unique grains that didn't match up to any bounding sphere.  Should only happen if it's the last active grain for
   * this particular variable.
   */
  for (std::map<unsigned int, UniqueGrain *>::iterator it = _unique_grains.begin(); it != _unique_grains.end(); ++it)
    if (it->second->status == NOT_MARKED)
    {
      Moose::out << "Marking Grain " << it->first << " as INACTIVE (varible index: "
                    << it->second->variable_idx <<  ")\n";
      it->second->status = INACTIVE;
    }


  // Sanity check to make sure that we consumed all of the bounding sphere datastructures
  for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
    if (!_bounding_spheres[map_num].empty())
      mooseError("BoundingSpheres where not completely used by the GrainTracker");
}
Exemple #23
0
void
ContactAction::act()
{
  if (!_problem->getDisplacedProblem())
    mooseError("Contact requires updated coordinates.  Use the 'displacements = ...' line in the "
               "Mesh block.");

  std::string action_name = MooseUtils::shortName(name());

  std::vector<NonlinearVariableName> displacements;
  if (isParamValid("displacements"))
    displacements = getParam<std::vector<NonlinearVariableName>>("displacements");
  else
  {
    // Legacy parameter scheme for displacements
    if (!isParamValid("disp_x"))
      mooseError("Specify displacement variables using the `displacements` parameter.");
    displacements.push_back(getParam<NonlinearVariableName>("disp_x"));

    if (isParamValid("disp_y"))
    {
      displacements.push_back(getParam<NonlinearVariableName>("disp_y"));
      if (isParamValid("disp_z"))
        displacements.push_back(getParam<NonlinearVariableName>("disp_z"));
    }

    mooseDeprecated("use the `displacements` parameter rather than the `disp_*` parameters (those "
                    "will go away with the deprecation of the Solid Mechanics module).");
  }

  // Determine number of dimensions
  const unsigned int ndisp = displacements.size();

  // convert vector of NonlinearVariableName to vector of VariableName
  std::vector<VariableName> coupled_displacements(ndisp);
  for (unsigned int i = 0; i < ndisp; ++i)
    coupled_displacements[i] = displacements[i];

  if (_current_task == "add_dirac_kernel")
  {
    // MechanicalContactConstraint has to be added after the init_problem task, so it cannot be
    // added for the add_constraint task.
    if (_system == "Constraint")
    {
      InputParameters params = _factory.getValidParams("MechanicalContactConstraint");
      params.applyParameters(parameters(), {"displacements", "formulation"});
      params.set<std::string>("formulation") = _formulation;
      params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area_" + name()};
      params.set<std::vector<VariableName>>("displacements") = coupled_displacements;
      params.set<BoundaryName>("boundary") = _master;
      params.set<bool>("use_displaced_mesh") = true;

      for (unsigned int i = 0; i < ndisp; ++i)
      {
        std::string name = action_name + "_constraint_" + Moose::stringify(i);

        params.set<unsigned int>("component") = i;
        params.set<NonlinearVariableName>("variable") = displacements[i];
        params.set<std::vector<VariableName>>("master_variable") = {coupled_displacements[i]};
        _problem->addConstraint("MechanicalContactConstraint", name, params);
      }
    }

    if (_system == "DiracKernel")
    {
      {
        InputParameters params = _factory.getValidParams("ContactMaster");
        params.applyParameters(parameters(), {"displacements", "formulation"});
        params.set<std::string>("formulation") = _formulation;
        params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area_" + name()};
        params.set<std::vector<VariableName>>("displacements") = coupled_displacements;
        params.set<BoundaryName>("boundary") = _master;
        params.set<bool>("use_displaced_mesh") = true;

        for (unsigned int i = 0; i < ndisp; ++i)
        {
          std::string name = action_name + "_master_" + Moose::stringify(i);
          params.set<unsigned int>("component") = i;
          params.set<NonlinearVariableName>("variable") = displacements[i];
          _problem->addDiracKernel("ContactMaster", name, params);
        }
      }

      {
        InputParameters params = _factory.getValidParams("SlaveConstraint");
        params.applyParameters(parameters(), {"displacements", "formulation"});
        params.set<std::string>("formulation") = _formulation;
        params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area_" + name()};
        params.set<std::vector<VariableName>>("displacements") = coupled_displacements;
        params.set<BoundaryName>("boundary") = _slave;
        params.set<bool>("use_displaced_mesh") = true;

        for (unsigned int i = 0; i < ndisp; ++i)
        {
          std::string name = action_name + "_slave_" + Moose::stringify(i);
          params.set<unsigned int>("component") = i;
          params.set<NonlinearVariableName>("variable") = displacements[i];
          _problem->addDiracKernel("SlaveConstraint", name, params);
        }
      }
    }
  }
}
void
SinglePhaseFluidProperties::s_from_p_T(Real, Real, Real &, Real &, Real &) const
{
  mooseError(name(), ": s_from_p_T is not implemented");
}
void
MechanicalContactConstraint::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);
  }
  RealVectorValue distance_vec(_mesh.node(node->id()) - pinfo->_closest_point);
  const Real penalty = getPenalty(*pinfo);
  RealVectorValue pen_force(penalty * distance_vec);
  RealVectorValue tan_residual(0,0,0);

  switch (_model)
  {
    case 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()] * pinfo->_normal)));
                                //( pen_force + (lagrange_multiplier[node->id()]/distance_vec.size())*distance_vec)));
          break;
        default:
          mooseError("Invalid contact formulation");
          break;
      }
      pinfo->_mech_status=PenetrationInfo::MS_SLIPPING;
      break;
    case CM_COULOMB:
      switch (_formulation)
      {
        case CF_DEFAULT:
          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 +
                                  lagrange_multiplier[node->id()]*distance_vec/distance_vec.size();
          break;
        default:
          mooseError("Invalid contact formulation");
          break;
      }
      break;
    case CM_GLUED:
      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;
      break;
    default:
      mooseError("Invalid or unavailable contact model");
      break;
  }
}
Real
SinglePhaseFluidProperties::criticalDensity() const
{
  mooseError(name(), ": criticalDensity() is not implemented");
}
Exemple #27
0
void
FormattedTable::makeGnuplot(const std::string & base_file, const std::string & format)
{
  // TODO: run this once at end of simulation, right now it runs every iteration
  // TODO: do I need to be more careful escaping column names?
  // Note: open and close the files each time, having open files may mess with gnuplot

  // supported filetypes: ps, png
  std::string extension, terminal;
  if (format == "png")
  {
    extension = ".png";
    terminal = "png";
  }

  else if (format == "ps")
  {
    extension = ".ps";
    terminal = "postscript";
  }

  else if (format == "gif")
  {
    extension = ".gif";
    terminal = "gif";
  }

  else
    mooseError("gnuplot format \"" + format + "\" is not supported.");

  // Write the data to disk
  std::string dat_name = base_file + ".dat";
  std::ofstream datfile;
  datfile.open(dat_name.c_str(), std::ios::trunc | std::ios::out);

  datfile << "# time";
  for (const auto & col_name : _column_names)
    datfile << '\t' << col_name;
  datfile << '\n';

  for (auto & i : _data)
  {
    datfile << i.first;
    for (const auto & col_name : _column_names)
    {
      std::map<std::string, Real> & tmp = i.second;
      datfile << '\t' << tmp[col_name];
    }
    datfile << '\n';
  }
  datfile.flush();
  datfile.close();

  // Write the gnuplot script
  std::string gp_name = base_file + ".gp";
  std::ofstream gpfile;
  gpfile.open(gp_name.c_str(), std::ios::trunc | std::ios::out);

  gpfile << gnuplot::before_terminal << terminal << gnuplot::before_ext << extension
         << gnuplot::after_ext;

  // plot all postprocessors in one plot
  int column = 2;
  for (const auto & col_name : _column_names)
  {
    gpfile << " '" << dat_name << "' using 1:" << column << " title '" << col_name
           << "' with linespoints";
    column++;
    if (column - 2 < static_cast<int>(_column_names.size()))
      gpfile << ", \\\n";
  }
  gpfile << "\n\n";

  // plot the postprocessors individually
  column = 2;
  for (const auto & col_name : _column_names)
  {
    gpfile << "set output '" << col_name << extension << "'\n";
    gpfile << "set ylabel '" << col_name << "'\n";
    gpfile << "plot '" << dat_name << "' using 1:" << column << " title '" << col_name
           << "' with linespoints\n\n";
    column++;
  }

  gpfile.flush();
  gpfile.close();

  // Run the gnuplot script
  /* We aren't going to run gnuplot automatically

    if (!system(NULL))
      mooseError("No way to run gnuplot on this computer");

    std::string command = "gnuplot " + gp_name;
    if (system(command.c_str()))
      mooseError("gnuplot command failed");
  */
}
Real
SinglePhaseFluidProperties::triplePointTemperature() const
{
  mooseError(name(), ": triplePointTemperature() is not implemented");
}
Exemple #29
0
void
PLC_LSH::computeCreep( const SymmTensor & strain_increment,
                       SymmTensor & creep_strain_increment,
                       SymmTensor & stress_new )
{
  // compute deviatoric trial stress
  SymmTensor dev_trial_stress(stress_new);
  dev_trial_stress.addDiag( -dev_trial_stress.trace()/3.0 );

  // compute effective trial stress
  Real dts_squared = dev_trial_stress.doubleContraction(dev_trial_stress);
  Real effective_trial_stress = std::sqrt(1.5 * dts_squared);

  // Use Newton sub-iteration to determine effective creep strain increment

  Real exponential(1);
  if (_has_temp)
  {
    exponential = std::exp(-_activation_energy/(_gas_constant *_temperature[_qp]));
  }
  Real expTime = std::pow(_t, _m_exponent);

  Real del_p = 0;
  unsigned int it = 0;
  Real creep_residual = 10;
  Real norm_creep_residual = 10;
  Real first_norm_creep_residual = 10;

  while (it < _max_its &&
        norm_creep_residual > _absolute_tolerance &&
        (norm_creep_residual/first_norm_creep_residual) > _relative_tolerance)
  {

    Real phi = _coefficient*std::pow(effective_trial_stress - 3*_shear_modulus*del_p, _n_exponent)*
      exponential*expTime;
    Real dphi_ddelp = -3*_coefficient*_shear_modulus*_n_exponent*
      std::pow(effective_trial_stress-3*_shear_modulus*del_p, _n_exponent-1)*exponential*expTime;

    creep_residual = phi - del_p/_dt;
    norm_creep_residual = std::abs(creep_residual);
    if (it == 0)
    {
      first_norm_creep_residual = norm_creep_residual;
    }

    del_p += creep_residual / (1/_dt - dphi_ddelp);

    if (_output_iteration_info == true)
    {
      _console
      << "crp_it="    << it
      << " trl_strs=" << effective_trial_stress
      << " phi="      << phi
      << " dphi="     << dphi_ddelp
      << " del_p="    << del_p
      << " rel_res="  << norm_creep_residual/first_norm_creep_residual
      << " rel_tol="  << _relative_tolerance
      << " abs_res="  << norm_creep_residual
      << " abs_tol="  << _absolute_tolerance
      << std::endl;
    }

    ++it;
  }


  if (it == _max_its &&
     norm_creep_residual > _absolute_tolerance &&
     (norm_creep_residual/first_norm_creep_residual) > _relative_tolerance)
  {
    mooseError("Max sub-newton iteration hit during creep solve!");
  }

  // compute creep and elastic strain increments (avoid potential divide by zero - how should this be done)?
  if (effective_trial_stress < 0.01)
  {
    effective_trial_stress = 0.01;
  }

  creep_strain_increment = dev_trial_stress;
  creep_strain_increment *= (1.5*del_p/effective_trial_stress);

  SymmTensor elastic_strain_increment(strain_increment);
  elastic_strain_increment -= creep_strain_increment;

  // compute stress increment
  stress_new = *elasticityTensor() * elastic_strain_increment;

  // update stress and creep strain
  stress_new += _stress_old;

  _creep_strain[_qp] = creep_strain_increment;
  _creep_strain[_qp] += _creep_strain_old[_qp];

}
void
MultiAppNearestNodeTransfer::execute()
{
  _console << "Beginning NearestNodeTransfer " << _name << std::endl;

  switch (_direction)
  {
    case TO_MULTIAPP:
    {
      FEProblem & from_problem = *_multi_app->problem();
      MooseVariable & from_var = from_problem.getVariable(0, _from_var_name);

      MeshBase * from_mesh = NULL;

      if (_displaced_source_mesh && from_problem.getDisplacedProblem())
      {
        mooseError("Cannot use a NearestNode transfer from a displaced mesh to a MultiApp!");
        from_mesh = &from_problem.getDisplacedProblem()->mesh().getMesh();
      }
      else
        from_mesh = &from_problem.mesh().getMesh();

      SystemBase & from_system_base = from_var.sys();

      System & from_sys = from_system_base.system();
      unsigned int from_sys_num = from_sys.number();

      // Only works with a serialized mesh to transfer from!
      mooseAssert(from_sys.get_mesh().is_serial(), "MultiAppNearestNodeTransfer only works with SerialMesh!");

      unsigned int from_var_num = from_sys.variable_number(from_var.name());

      // EquationSystems & from_es = from_sys.get_equation_systems();

      //Create a serialized version of the solution vector
      NumericVector<Number> * serialized_solution = NumericVector<Number>::build(from_sys.comm()).release();
      serialized_solution->init(from_sys.n_dofs(), false, SERIAL);

      // Need to pull down a full copy of this vector on every processor so we can get values in parallel
      from_sys.solution->localize(*serialized_solution);

      for (unsigned int i=0; i<_multi_app->numGlobalApps(); i++)
      {
        if (_multi_app->hasLocalApp(i))
        {
          MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm());

          // Loop over the master nodes and set the value of the variable
          System * to_sys = find_sys(_multi_app->appProblem(i)->es(), _to_var_name);

          unsigned int sys_num = to_sys->number();
          unsigned int var_num = to_sys->variable_number(_to_var_name);

          NumericVector<Real> & solution = _multi_app->appTransferVector(i, _to_var_name);

          MeshBase * mesh = NULL;

          if (_displaced_target_mesh && _multi_app->appProblem(i)->getDisplacedProblem())
            mesh = &_multi_app->appProblem(i)->getDisplacedProblem()->mesh().getMesh();
          else
            mesh = &_multi_app->appProblem(i)->mesh().getMesh();

          bool is_nodal = to_sys->variable_type(var_num).family == LAGRANGE;

          if (is_nodal)
          {
            MeshBase::const_node_iterator node_it = mesh->local_nodes_begin();
            MeshBase::const_node_iterator node_end = mesh->local_nodes_end();

            for (; node_it != node_end; ++node_it)
            {
              Node * node = *node_it;

              Point actual_position = *node+_multi_app->position(i);

              if (node->n_dofs(sys_num, var_num) > 0) // If this variable has dofs at this node
              {
                // The zero only works for LAGRANGE!
                dof_id_type dof = node->dof_number(sys_num, var_num, 0);

                // Swap back
                Moose::swapLibMeshComm(swapped);

                Real distance = 0; // Just to satisfy the last argument

                MeshBase::const_node_iterator from_nodes_begin = from_mesh->nodes_begin();
                MeshBase::const_node_iterator from_nodes_end   = from_mesh->nodes_end();

                Node * nearest_node = NULL;

                if (_fixed_meshes)
                {
                  if (_node_map.find(node->id()) == _node_map.end())  // Haven't cached it yet
                  {
                    nearest_node = getNearestNode(actual_position, distance, from_nodes_begin, from_nodes_end);
                    _node_map[node->id()] = nearest_node;
                    _distance_map[node->id()] = distance;
                  }
                  else
                  {
                    nearest_node = _node_map[node->id()];
                    //distance = _distance_map[node->id()];
                  }
                }
                else
                  nearest_node = getNearestNode(actual_position, distance, from_nodes_begin, from_nodes_end);

                // Assuming LAGRANGE!
                dof_id_type from_dof = nearest_node->dof_number(from_sys_num, from_var_num, 0);
                Real from_value = (*serialized_solution)(from_dof);

                // Swap again
                swapped = Moose::swapLibMeshComm(_multi_app->comm());

                solution.set(dof, from_value);
              }
            }
          }
          else // Elemental
          {
            MeshBase::const_element_iterator elem_it = mesh->local_elements_begin();
            MeshBase::const_element_iterator elem_end = mesh->local_elements_end();

            for (; elem_it != elem_end; ++elem_it)
            {
              Elem * elem = *elem_it;

              Point centroid = elem->centroid();
              Point actual_position = centroid+_multi_app->position(i);

              if (elem->n_dofs(sys_num, var_num) > 0) // If this variable has dofs at this elem
              {
                // The zero only works for LAGRANGE!
                dof_id_type dof = elem->dof_number(sys_num, var_num, 0);

                // Swap back
                Moose::swapLibMeshComm(swapped);

                Real distance = 0; // Just to satisfy the last argument

                MeshBase::const_node_iterator from_nodes_begin = from_mesh->nodes_begin();
                MeshBase::const_node_iterator from_nodes_end   = from_mesh->nodes_end();

                Node * nearest_node = NULL;

                if (_fixed_meshes)
                {
                  if (_node_map.find(elem->id()) == _node_map.end())  // Haven't cached it yet
                  {
                    nearest_node = getNearestNode(actual_position, distance, from_nodes_begin, from_nodes_end);
                    _node_map[elem->id()] = nearest_node;
                    _distance_map[elem->id()] = distance;
                  }
                  else
                  {
                    nearest_node = _node_map[elem->id()];
                    //distance = _distance_map[elem->id()];
                  }
                }
                else
                  nearest_node = getNearestNode(actual_position, distance, from_nodes_begin, from_nodes_end);

                // Assuming LAGRANGE!
                dof_id_type from_dof = nearest_node->dof_number(from_sys_num, from_var_num, 0);
                Real from_value = (*serialized_solution)(from_dof);

                // Swap again
                swapped = Moose::swapLibMeshComm(_multi_app->comm());

                solution.set(dof, from_value);
              }
            }
          }

          solution.close();
          to_sys->update();

          // Swap back
          Moose::swapLibMeshComm(swapped);
        }
      }

      delete serialized_solution;

      break;
    }
    case FROM_MULTIAPP:
    {
      FEProblem & to_problem = *_multi_app->problem();
      MooseVariable & to_var = to_problem.getVariable(0, _to_var_name);
      SystemBase & to_system_base = to_var.sys();

      System & to_sys = to_system_base.system();

      NumericVector<Real> & to_solution = *to_sys.solution;

      unsigned int to_sys_num = to_sys.number();

      // Only works with a serialized mesh to transfer to!
      mooseAssert(to_sys.get_mesh().is_serial(), "MultiAppNearestNodeTransfer only works with SerialMesh!");

      unsigned int to_var_num = to_sys.variable_number(to_var.name());

      // EquationSystems & to_es = to_sys.get_equation_systems();

      MeshBase * to_mesh = NULL;

      if (_displaced_target_mesh && to_problem.getDisplacedProblem())
        to_mesh = &to_problem.getDisplacedProblem()->mesh().getMesh();
      else
        to_mesh = &to_problem.mesh().getMesh();

      bool is_nodal = to_sys.variable_type(to_var_num) == FEType();

      dof_id_type n_nodes = to_mesh->n_nodes();
      dof_id_type n_elems = to_mesh->n_elem();

      ///// All of the following are indexed off to_node->id() or to_elem->id() /////

      // Minimum distances from each node in the "to" mesh to a node in
      std::vector<Real> min_distances;

      // The node ids in the "from" mesh that this processor has found to be the minimum distances to the "to" nodes
      std::vector<dof_id_type> min_nodes;

      // After the call to maxloc() this will tell us which processor actually has the minimum
      std::vector<unsigned int> min_procs;

      // The global multiapp ID that this processor found had the minimum distance node in it.
      std::vector<unsigned int> min_apps;


      if (is_nodal)
      {
        min_distances.resize(n_nodes, std::numeric_limits<Real>::max());
        min_nodes.resize(n_nodes);
        min_procs.resize(n_nodes);
        min_apps.resize(n_nodes);
      }
      else
      {
        min_distances.resize(n_elems, std::numeric_limits<Real>::max());
        min_nodes.resize(n_elems);
        min_procs.resize(n_elems);
        min_apps.resize(n_elems);
      }

      for (unsigned int i=0; i<_multi_app->numGlobalApps(); i++)
      {
        if (!_multi_app->hasLocalApp(i))
          continue;

        MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm());

        FEProblem & from_problem = *_multi_app->appProblem(i);
        MooseVariable & from_var = from_problem.getVariable(0, _from_var_name);
        SystemBase & from_system_base = from_var.sys();

        System & from_sys = from_system_base.system();

        // Only works with a serialized mesh to transfer from!
        mooseAssert(from_sys.get_mesh().is_serial(), "MultiAppNearestNodeTransfer only works with SerialMesh!");

        // unsigned int from_var_num = from_sys.variable_number(from_var.name());

        // EquationSystems & from_es = from_sys.get_equation_systems();

        MeshBase * from_mesh = NULL;

        if (_displaced_source_mesh && from_problem.getDisplacedProblem())
          from_mesh = &from_problem.getDisplacedProblem()->mesh().getMesh();
        else
          from_mesh = &from_problem.mesh().getMesh();

        MeshTools::BoundingBox app_box = MeshTools::processor_bounding_box(*from_mesh, from_mesh->processor_id());
        Point app_position = _multi_app->position(i);

        Moose::swapLibMeshComm(swapped);

        if (is_nodal)
        {
          MeshBase::const_node_iterator to_node_it = to_mesh->nodes_begin();
          MeshBase::const_node_iterator to_node_end = to_mesh->nodes_end();

          for (; to_node_it != to_node_end; ++to_node_it)
          {
            Node * to_node = *to_node_it;
            dof_id_type to_node_id = to_node->id();

            Real current_distance = 0;

            MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm());

            MeshBase::const_node_iterator from_nodes_begin = from_mesh->local_nodes_begin();
            MeshBase::const_node_iterator from_nodes_end   = from_mesh->local_nodes_end();

            Node * nearest_node = NULL;

            if (_fixed_meshes)
            {
              if (_node_map.find(to_node->id()) == _node_map.end())  // Haven't cached it yet
              {
                nearest_node = getNearestNode(*to_node-app_position, current_distance, from_nodes_begin, from_nodes_end);
                _node_map[to_node->id()] = nearest_node;
                _distance_map[to_node->id()] = current_distance;
              }
              else
              {
                nearest_node = _node_map[to_node->id()];
                current_distance = _distance_map[to_node->id()];
              }
            }
            else
              nearest_node = getNearestNode(*to_node-app_position, current_distance, from_nodes_begin, from_nodes_end);

            Moose::swapLibMeshComm(swapped);

            // TODO: Logic bug when we are using caching.  "current_distance" is set by a call to getNearestNode which is
            // skipped in that case.  We shouldn't be relying on it or stuffing it in another data structure
            if (current_distance < min_distances[to_node->id()])
            {
              min_distances[to_node_id] = current_distance;
              min_nodes[to_node_id] = nearest_node->id();
              min_apps[to_node_id] = i;
            }
          }
        }
        else // Elemental
        {
          MeshBase::const_element_iterator to_elem_it = to_mesh->elements_begin();
          MeshBase::const_element_iterator to_elem_end = to_mesh->elements_end();

          for (; to_elem_it != to_elem_end; ++to_elem_it)
          {
            Elem * to_elem = *to_elem_it;
            dof_id_type to_elem_id = to_elem->id();

            Point actual_position = to_elem->centroid()-app_position;

            Real current_distance = 0;

            MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm());

            MeshBase::const_node_iterator from_nodes_begin = from_mesh->local_nodes_begin();
            MeshBase::const_node_iterator from_nodes_end   = from_mesh->local_nodes_end();

            Node * nearest_node = NULL;

            if (_fixed_meshes)
            {
              if (_node_map.find(to_elem->id()) == _node_map.end())  // Haven't cached it yet
              {
                nearest_node = getNearestNode(actual_position, current_distance, from_nodes_begin, from_nodes_end);
                _node_map[to_elem->id()] = nearest_node;
                _distance_map[to_elem->id()] = current_distance;
              }
              else
              {
                nearest_node = _node_map[to_elem->id()];
                current_distance = _distance_map[to_elem->id()];
              }
            }
            else
              nearest_node = getNearestNode(actual_position, current_distance, from_nodes_begin, from_nodes_end);

            Moose::swapLibMeshComm(swapped);

            // TODO: Logic bug when we are using caching.  "current_distance" is set by a call to getNearestNode which is
            // skipped in that case.  We shouldn't be relying on it or stuffing it in another data structure
            if (current_distance < min_distances[to_elem->id()])
            {
              min_distances[to_elem_id] = current_distance;
              min_nodes[to_elem_id] = nearest_node->id();
              min_apps[to_elem_id] = i;
            }
          }
        }
      }

/*
      // We're going to need serialized solution vectors for each app
      // We could try to only do it for the apps that have mins in them...
      // but it's tough because this is a collective operation... so that would have to be coordinated
      std::vector<NumericVector<Number> *> serialized_from_solutions(_multi_app->numGlobalApps());

      if (_multi_app->hasApp())
      {
        // Swap
        MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm());

        for (unsigned int i=0; i<_multi_app->numGlobalApps(); i++)
        {
          if (!_multi_app->hasLocalApp(i))
            continue;

          FEProblem & from_problem = *_multi_app->appProblem(i);
          MooseVariable & from_var = from_problem.getVariable(0, _from_var_name);
          SystemBase & from_system_base = from_var.sys();

          System & from_sys = from_system_base.system();

          //Create a serialized version of the solution vector
          serialized_from_solutions[i] = NumericVector<Number>::build().release();
          serialized_from_solutions[i]->init(from_sys.n_dofs(), false, SERIAL);

          // Need to pull down a full copy of this vector on every processor so we can get values in parallel
          from_sys.solution->localize(*serialized_from_solutions[i]);
        }

        // Swap back
        Moose::swapLibMeshComm(swapped);
      }
*/

      // We've found the nearest nodes for this processor.  We need to see which processor _actually_ found the nearest though
      _communicator.minloc(min_distances, min_procs);

      // Now loop through min_procs and see if _this_ processor had the actual minimum for any nodes.
      // If it did then we're going to go get the value from that nearest node and transfer its value
      processor_id_type proc_id = processor_id();

      for (unsigned int j=0; j<min_procs.size(); j++)
      {
        if (min_procs[j] == proc_id) // This means that this processor really did find the minumum so we need to transfer the value
        {
          // The zero only works for LAGRANGE!
          dof_id_type to_dof = 0;

          if (is_nodal)
          {
            Node & to_node = to_mesh->node(j);
            to_dof = to_node.dof_number(to_sys_num, to_var_num, 0);
          }
          else
          {
            Elem & to_elem = *to_mesh->elem(j);
            to_dof = to_elem.dof_number(to_sys_num, to_var_num, 0);
          }

          // The app that has the nearest node in it
          unsigned int from_app_num = min_apps[j];

          mooseAssert(_multi_app->hasLocalApp(from_app_num), "Something went very wrong!");

          // Swap
          MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm());

          FEProblem & from_problem = *_multi_app->appProblem(from_app_num);
          MooseVariable & from_var = from_problem.getVariable(0, _from_var_name);
          SystemBase & from_system_base = from_var.sys();

          System & from_sys = from_system_base.system();
          unsigned int from_sys_num = from_sys.number();

          unsigned int from_var_num = from_sys.variable_number(from_var.name());

          // EquationSystems & from_es = from_sys.get_equation_systems();

          MeshBase * from_mesh = NULL;

          if (_displaced_source_mesh && from_problem.getDisplacedProblem())
            from_mesh = &from_problem.getDisplacedProblem()->mesh().getMesh();
          else
            from_mesh = &from_problem.mesh().getMesh();

          Node & from_node = from_mesh->node(min_nodes[j]);

          // Assuming LAGRANGE!
          dof_id_type from_dof = from_node.dof_number(from_sys_num, from_var_num, 0);
          Real from_value = (*from_sys.solution)(from_dof);

          // Swap back
          Moose::swapLibMeshComm(swapped);

          to_solution.set(to_dof, from_value);
        }
      }

      to_solution.close();
      to_sys.update();

      break;
    }
  }

  _console << "Finished NearestNodeTransfer " << _name << std::endl;
}