//==========================================================================
// Class Definition
//==========================================================================
// ComputeLowReynoldsSDRWallAlgorithm - low Re omega at wall bc; 
//                                      6*nu/(beta*yp^2)
// compute yp locally
//==========================================================================
//--------------------------------------------------------------------------
//-------- constructor -----------------------------------------------------
//--------------------------------------------------------------------------
ComputeLowReynoldsSDRWallAlgorithm::ComputeLowReynoldsSDRWallAlgorithm(
  Realm &realm,
  stk::mesh::Part *part,
  const bool &useShifted)
  : Algorithm(realm, part),
    useShifted_(useShifted),
    betaOne_(realm.get_turb_model_constant(TM_betaOne)),
    wallFactor_(1.0)
{
  // save off fields
  stk::mesh::MetaData & meta_data = realm_.meta_data();
  coordinates_ = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, realm_.get_coordinates_name());
  density_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "density");
  viscosity_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "viscosity");
  exposedAreaVec_ = meta_data.get_field<GenericFieldType>(meta_data.side_rank(), "exposed_area_vector");
  sdrBc_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "wall_model_sdr_bc");
  assembledWallArea_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "assembled_wall_area_sdr");
}
//==========================================================================
// Class Definition
//==========================================================================
// SurfaceForceAndMomentWallFunctionAlgorithm - post process sigma_ijnjdS and 
//                                  tau_wall via lumped nodal projection (area 
//                                  weighed) Driven by SurfaceForceAndMomentAlgDriver
//==========================================================================
//--------------------------------------------------------------------------
//-------- constructor -----------------------------------------------------
//--------------------------------------------------------------------------
SurfaceForceAndMomentWallFunctionAlgorithm::SurfaceForceAndMomentWallFunctionAlgorithm(
  Realm &realm,
  stk::mesh::PartVector &partVec,
  const std::string &outputFileName,
  const int &frequency,
  const std::vector<double > &parameters,
  const bool &useShifted)
  : Algorithm(realm, partVec),
    outputFileName_(outputFileName),
    frequency_(frequency),
    parameters_(parameters),
    useShifted_(useShifted),
    yplusCrit_(11.63),
    elog_(9.8),
    kappa_(realm.get_turb_model_constant(TM_kappa)),
    coordinates_(NULL),
    velocity_(NULL),
    pressure_(NULL),
    pressureForce_(NULL),
    tauWall_(NULL),
    yplus_(NULL),
    bcVelocity_(NULL),
    density_(NULL),
    viscosity_(NULL),
    wallFrictionVelocityBip_(NULL),
    wallNormalDistanceBip_(NULL),
    exposedAreaVec_(NULL),
    assembledArea_(NULL),
    w_(12)
{
  // save off fields
  stk::mesh::MetaData & meta_data = realm_.meta_data();
  coordinates_ = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, realm_.get_coordinates_name());
  velocity_ = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, "velocity");
  pressure_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "pressure");
  pressureForce_ = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, "pressure_force");
  tauWall_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "tau_wall");
  yplus_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "yplus");
  bcVelocity_ = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, "wall_velocity_bc");
  density_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "density");
  viscosity_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "viscosity");
  wallFrictionVelocityBip_ = meta_data.get_field<GenericFieldType>(meta_data.side_rank(), "wall_friction_velocity_bip");
  wallNormalDistanceBip_ = meta_data.get_field<GenericFieldType>(meta_data.side_rank(), "wall_normal_distance_bip");
  exposedAreaVec_ = meta_data.get_field<GenericFieldType>(meta_data.side_rank(), "exposed_area_vector");
  assembledArea_ = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "assembled_area_force_moment_wf");

  // error check on params
  const size_t nDim = meta_data.spatial_dimension();
  if ( parameters_.size() > nDim )
    throw std::runtime_error("SurfaceForce: parameter length wrong; expect nDim");

  // make sure that the wall function params are registered
  if ( NULL == wallFrictionVelocityBip_ )
    throw std::runtime_error("SurfaceForce: wall friction velocity is not registered; wall bcs and post processing must be consistent");

  // deal with file name and banner
  if ( NaluEnv::self().parallel_rank() == 0 ) {
    std::ofstream myfile;
    myfile.open(outputFileName_.c_str());
    myfile << std::setw(w_) 
           << "Time" << std::setw(w_) 
           << "Fpx"  << std::setw(w_) << "Fpy" << std::setw(w_)  << "Fpz" << std::setw(w_) 
           << "Fvx"  << std::setw(w_) << "Fvy" << std::setw(w_)  << "Fxz" << std::setw(w_) 
           << "Mtx"  << std::setw(w_) << "Mty" << std::setw(w_)  << "Mtz" << std::setw(w_) 
           << "Y+min" << std::setw(w_) << "Y+max"<< std::endl;
    myfile.close();
  }
 }