<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Transient.h"

//Moose includes
#include "Kernel.h"
#include "Factory.h"
#include "SubProblem.h"
#include "ProblemFactory.h"
#include "TimePeriod.h"
#include "TimeScheme.h"
//libMesh includes
#include "implicit_system.h"
#include "nonlinear_implicit_system.h"
#include "transient_system.h"
#include "numeric_vector.h"
#include "o_string_stream.h"

// C++ Includes
#include <iomanip>
#include <iostream>
#include <fstream>

template<>
InputParameters validParams<Transient>()
{
  InputParameters params = validParams<Executioner>();
  std::vector<Real> sync_times(1);
  sync_times[0] = -1;

  params.addParam<Real>("start_time",      0.0,    "The start time of the simulation");
  params.addParam<Real>("end_time",        1.0e30, "The end time of the simulation");
  params.addRequiredParam<Real>("dt", "The timestep size between solves");
  params.addParam<Real>("dtmin",           0.0,    "The minimum timestep size in an adaptive run");
  params.addParam<Real>("dtmax",           1.0e30, "The maximum timestep size in an adaptive run");
  params.addParam<Real>("num_steps",       std::numeric_limits<Real>::max(),     "The number of timesteps in a transient run");
  params.addParam<int> ("n_startup_steps", 0,      "The number of timesteps during startup");
  params.addParam<bool>("trans_ss_check",  false,  "Whether or not to check for steady state conditions");
  params.addParam<Real>("ss_check_tol",    1.0e-08,"Whenever the relative residual changes by less than this the solution will be considered to be at steady state.");
  params.addParam<Real>("ss_tmin",         0.0,    "Minimum number of timesteps to take before checking for steady state conditions.");
  params.addParam<std::vector<Real> >("sync_times", sync_times, "A list of times that will be solved for provided they are within the simulation time");
  params.addParam<std::vector<Real> >("time_t", "The values of t");
  params.addParam<std::vector<Real> >("time_dt", "The values of dt");
  params.addParam<Real>("growth_factor", 2, "Maximum ratio of new to previous timestep sizes following a step that required the time step to be cut due to a failed solve.  For use with 'time_t' and 'time_dt'.");
  params.addParam<Real>("predictor_scale", "The scale factor for the predictor (can range from 0 to 1)");

  params.addParam<std::vector<std::string> >("time_periods", "The names of periods");
  params.addParam<std::vector<Real> >("time_period_starts", "The start times of time periods");
  params.addParam<std::vector<Real> >("time_period_ends", "The end times of time periods");
  params.addParam<bool>("use_AB2", false, "Whether to use the Adams-Bashforth 2 predictor");
  params.addParam<bool>("use_littlef", false, "if a function evaluation should be used or time deriv's in predictors");
  params.addParam<bool>("abort_on_solve_fail", false, "abort if solve not converged rather than cut timestep");
  return params;
}

Transient::Transient(const std::string & name, InputParameters parameters) :
    Executioner(name, parameters),
    _problem(*ProblemFactory::instance()->createFEProblem(_mesh)),
    _t_step(_problem.timeStep()),
    _time(_problem.time()),
    _time_old(_problem.timeOld()),
    _input_dt(getParam<Real>("dt")),
    _dt(_problem.dt()),
    _dt_old(_problem.dtOld()),
    _prev_dt(-1),
    _reset_dt(false),
    _end_time(getParam<Real>("end_time")),
    _dtmin(getParam<Real>("dtmin")),
    _dtmax(getParam<Real>("dtmax")),
    _num_steps(getParam<Real>("num_steps")),
    _n_startup_steps(getParam<int>("n_startup_steps")),
    _trans_ss_check(getParam<bool>("trans_ss_check")),
    _ss_check_tol(getParam<Real>("ss_check_tol")),
    _ss_tmin(getParam<Real>("ss_tmin")),
    _old_time_solution_norm(0.0),
    _converged(true),
    _sync_times(getParam<std::vector<Real> >("sync_times")),
    _remaining_sync_time(true),
    _time_ipol(getParam<std::vector<Real> >("time_t"),
               getParam<std::vector<Real> >("time_dt")),
    _use_time_ipol(_time_ipol.getSampleSize() > 0),
    _growth_factor(getParam<Real>("growth_factor")),
    _cutback_occurred(false),
    _abort(getParam<bool>("abort_on_solve_fail"))
{
  _t_step = 0;
  _dt = 0;
  _time = _time_old = getParam<Real>("start_time");
  _problem.transient(true);
  if (parameters.isParamValid("predictor_scale"))
  {
    Real predscale(getParam<Real>("predictor_scale"));
    if (predscale >= 0.0 and predscale <= 1.0)
    {
      _problem.getNonlinearSystem().setPredictorScale(getParam<Real>("predictor_scale"));
    }
    else
    {
      mooseError("Input value for predictor_scale = "<< predscale << ", outside of permissible range (0 to 1)");
    }
  }

  _problem.getTimeScheme()->_use_AB2 = getParam<bool>("use_AB2");
  _problem.getTimeScheme()->_use_littlef = getParam<bool>("use_littlef");
  if (!_restart_file_base.empty())
    _problem.setRestartFile(_restart_file_base);
}

Transient::~Transient()
{
  // This problem was built by the Factory and needs to be released by this destructor
  delete &_problem;
}

void
Transient::execute()
{
  _problem.initialSetup();

  preExecute();

  // Start time loop...
  while(keepGoing())
  {
    takeStep();
    if (lastSolveConverged())
      endStep();
  }
  postExecute();
}

void
Transient::takeStep(Real input_dt)
{
  if (_converged)
    _problem.copyOldSolutions();
  else
    _problem.restoreSolutions();

  _dt_old = _dt;
  if (input_dt == -1.0)
    _dt = computeConstrainedDT();
  else
    _dt = input_dt;

  _problem.onTimestepBegin();
  if (_converged)
  {
    // Update backward material data structures
    _problem.updateMaterials();
  }

  // Increment time
  _time = _time_old + _dt;

  std::cout<<"DT: "<<_dt<<std::endl;

  std::cout << " Solving time step ";
  {
    OStringStream out;

    OSSInt(out,2,_t_step);
    out << ", time=";
    OSSRealzeroleft(out, 9, 6, _time);
    out <<  "...";
    std::cout << out.str() << std::endl;
  }

  preSolve();

  _problem.timestepSetup();

  // Compute Pre-Aux User Objects (Timestep begin)
  _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::PRE_AUX);

  // Compute TimestepBegin AuxKernels
  _problem.computeAuxiliaryKernels(EXEC_TIMESTEP_BEGIN);

  // Compute Post-Aux User Objects (Timestep begin)
  _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::POST_AUX);

  _problem.solve();

  _converged = _problem.converged();

  // Compute Pre-Aux User Objects
  _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::PRE_AUX);

  postSolve();

  _problem.onTimestepEnd();

  // We know whether or not the nonlinear solver thinks it converged, but we need to see if the executioner concurs
  bool last_solve_converged = lastSolveConverged();

  // If _reset_dt is true, the time step was synced to the user defined value and we dump the solution in an output file
  if (last_solve_converged)
  {
    _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::POST_AUX);
  }
}

void
Transient::endStep()
{
  // Compute the Error Indicators and Markers
  _problem.computeIndicatorsAndMarkers();

  // if _reset_dt is true, force the output no matter what
  _problem.output(_reset_dt);
  _problem.outputPostprocessors(_reset_dt);

#ifdef LIBMESH_ENABLE_AMR
  if (_problem.adaptivity().isOn())
  {
    _problem.adaptMesh();
    _problem.out().meshChanged();
  }
#endif

  _time_old = _time;
  _t_step++;
}

Real
Transient::computeConstrainedDT()
{
  // If this is the first step
  if (_t_step == 0)
  {
    _t_step = 1;
    _dt = _input_dt;
  }

//  // If start up steps are needed
//  if(_t_step == 1 && _n_startup_steps > 1)
//    _dt = _input_dt/(double)(_n_startup_steps);
//  else if (_t_step == 1+_n_startup_steps && _n_startup_steps > 1)
//    _dt = _input_dt;

  Real dt_cur = _dt;
  //After startup steps, compute new dt
  if (_t_step > _n_startup_steps)
    dt_cur = computeDT();

  // Don't let the time step size exceed maximum time step size
  if (dt_cur > _dtmax)
    dt_cur = _dtmax;

  // Don't allow time step size to be smaller than minimum time step size
  if (dt_cur < _dtmin)
    dt_cur = _dtmin;

  // Don't let time go beyond simulation end time
  if (_time + dt_cur > _end_time)
    dt_cur = _end_time - _time;

  // Adjust to a sync time if supplied and skipped over
  if (_remaining_sync_time && _time + dt_cur >= *_curr_sync_time_iter)
  {
    dt_cur = *_curr_sync_time_iter - _time;
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;

    _prev_dt = _dt;

    _reset_dt = true;
  }
  else
  {
    if (_reset_dt)
    {
      if (_use_time_ipol)
        dt_cur = _time_ipol.sample(_time);
      else
        dt_cur = _prev_dt;
      _reset_dt = false;
    }
  }

  return dt_cur;

}

Real
Transient::computeDT()
{
  if (!lastSolveConverged())
  {
    _cutback_occurred = true;
    //std::cout<<"Solve failed... cutting timestep"<<std::endl;
    //return _dt / 2.0;

    // Instead of blindly cutting timestep, respect dtmin.
    if (_dt <= _dtmin)
      mooseError("Solve failed and timestep already at or below dtmin, cannot continue!");

    if (0.5 * _dt >= _dtmin)
      return 0.5 * _dt;

    else // (0.5 * _dt < _dtmin)
      return _dtmin;
  }

  Real dt = _dt;
  if (_use_time_ipol)
  {
    dt = _time_ipol.sample(_time);
    if (_cutback_occurred &&
        dt > _dt * _growth_factor)
    {
      dt = _dt * _growth_factor;
    }
  }

  _cutback_occurred = false;
  return dt;
}

bool
Transient::keepGoing()
{
  // Check for stop condition based upon steady-state check flag:
  if(_converged && _trans_ss_check == true && _time > _ss_tmin)
  {
    // Compute new time solution l2_norm
    Real new_time_solution_norm = _problem.getNonlinearSystem().currentSolution()->l2_norm();

    // Compute l2_norm relative error
    Real ss_relerr_norm = fabs(new_time_solution_norm - _old_time_solution_norm)/new_time_solution_norm;

    // Check current solution relative error norm against steady-state tolerance
    if(ss_relerr_norm < _ss_check_tol)
    {
      std::cout<<"Steady-State Solution Achieved at time: "<<_time<<std::endl;
      return false;
    }
    else // Keep going
    {
      // Update solution norm for next time step
      _old_time_solution_norm = new_time_solution_norm;
      // Print steady-state relative error norm
      std::cout<<"Steady-State Relative Differential Norm: "<<ss_relerr_norm<<std::endl;
    }
  }

  if(!_converged && _abort)
  {
    std::cout<<"Aborting as solve did not converge and input selected to abort"<<std::endl;
    return false;
  }

  // Check for stop condition based upon number of simulation steps and/or solution end time:
  if(_t_step>_num_steps)
    return false;

  if((_time>_end_time) || (fabs(_time-_end_time)<1.e-14))
    return false;

  return true;
}

bool
Transient::lastSolveConverged()
{
  return _converged;
}

void
Transient::preExecute()
{
  // process time periods
  const std::vector<TimePeriod *> _time_periods = _problem.getTimePeriods();
  for (unsigned int i = 0; i < _time_periods.size(); ++i)
    _sync_times.push_back(_time_periods[i]->start());

  const std::vector<Real> & time = getParam<std::vector<Real> >("time_t");
  if (_use_time_ipol)
    _sync_times.insert(_sync_times.end(), time.begin()+1, time.end());          // insert times as sync points except the very first one
  sort(_sync_times.begin(), _sync_times.end());
  _sync_times.erase(std::unique(_sync_times.begin(), _sync_times.end()), _sync_times.end());    // remove duplicates (needs sorted array)

  // Advance to the first sync time if one is provided in sim time range
  _curr_sync_time_iter = _sync_times.begin();
  while (_remaining_sync_time && *_curr_sync_time_iter <= _time)
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;
}
<commit_msg>Solutions are copied/restored in endStep() not at the beginning of the time step (closes #1373)<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Transient.h"

//Moose includes
#include "Kernel.h"
#include "Factory.h"
#include "SubProblem.h"
#include "ProblemFactory.h"
#include "TimePeriod.h"
#include "TimeScheme.h"
//libMesh includes
#include "implicit_system.h"
#include "nonlinear_implicit_system.h"
#include "transient_system.h"
#include "numeric_vector.h"
#include "o_string_stream.h"

// C++ Includes
#include <iomanip>
#include <iostream>
#include <fstream>

template<>
InputParameters validParams<Transient>()
{
  InputParameters params = validParams<Executioner>();
  std::vector<Real> sync_times(1);
  sync_times[0] = -1;

  params.addParam<Real>("start_time",      0.0,    "The start time of the simulation");
  params.addParam<Real>("end_time",        1.0e30, "The end time of the simulation");
  params.addRequiredParam<Real>("dt", "The timestep size between solves");
  params.addParam<Real>("dtmin",           0.0,    "The minimum timestep size in an adaptive run");
  params.addParam<Real>("dtmax",           1.0e30, "The maximum timestep size in an adaptive run");
  params.addParam<Real>("num_steps",       std::numeric_limits<Real>::max(),     "The number of timesteps in a transient run");
  params.addParam<int> ("n_startup_steps", 0,      "The number of timesteps during startup");
  params.addParam<bool>("trans_ss_check",  false,  "Whether or not to check for steady state conditions");
  params.addParam<Real>("ss_check_tol",    1.0e-08,"Whenever the relative residual changes by less than this the solution will be considered to be at steady state.");
  params.addParam<Real>("ss_tmin",         0.0,    "Minimum number of timesteps to take before checking for steady state conditions.");
  params.addParam<std::vector<Real> >("sync_times", sync_times, "A list of times that will be solved for provided they are within the simulation time");
  params.addParam<std::vector<Real> >("time_t", "The values of t");
  params.addParam<std::vector<Real> >("time_dt", "The values of dt");
  params.addParam<Real>("growth_factor", 2, "Maximum ratio of new to previous timestep sizes following a step that required the time step to be cut due to a failed solve.  For use with 'time_t' and 'time_dt'.");
  params.addParam<Real>("predictor_scale", "The scale factor for the predictor (can range from 0 to 1)");

  params.addParam<std::vector<std::string> >("time_periods", "The names of periods");
  params.addParam<std::vector<Real> >("time_period_starts", "The start times of time periods");
  params.addParam<std::vector<Real> >("time_period_ends", "The end times of time periods");
  params.addParam<bool>("use_AB2", false, "Whether to use the Adams-Bashforth 2 predictor");
  params.addParam<bool>("use_littlef", false, "if a function evaluation should be used or time deriv's in predictors");
  params.addParam<bool>("abort_on_solve_fail", false, "abort if solve not converged rather than cut timestep");
  return params;
}

Transient::Transient(const std::string & name, InputParameters parameters) :
    Executioner(name, parameters),
    _problem(*ProblemFactory::instance()->createFEProblem(_mesh)),
    _t_step(_problem.timeStep()),
    _time(_problem.time()),
    _time_old(_problem.timeOld()),
    _input_dt(getParam<Real>("dt")),
    _dt(_problem.dt()),
    _dt_old(_problem.dtOld()),
    _prev_dt(-1),
    _reset_dt(false),
    _end_time(getParam<Real>("end_time")),
    _dtmin(getParam<Real>("dtmin")),
    _dtmax(getParam<Real>("dtmax")),
    _num_steps(getParam<Real>("num_steps")),
    _n_startup_steps(getParam<int>("n_startup_steps")),
    _trans_ss_check(getParam<bool>("trans_ss_check")),
    _ss_check_tol(getParam<Real>("ss_check_tol")),
    _ss_tmin(getParam<Real>("ss_tmin")),
    _old_time_solution_norm(0.0),
    _converged(true),
    _sync_times(getParam<std::vector<Real> >("sync_times")),
    _remaining_sync_time(true),
    _time_ipol(getParam<std::vector<Real> >("time_t"),
               getParam<std::vector<Real> >("time_dt")),
    _use_time_ipol(_time_ipol.getSampleSize() > 0),
    _growth_factor(getParam<Real>("growth_factor")),
    _cutback_occurred(false),
    _abort(getParam<bool>("abort_on_solve_fail"))
{
  _t_step = 0;
  _dt = 0;
  _time = _time_old = getParam<Real>("start_time");
  _problem.transient(true);
  if (parameters.isParamValid("predictor_scale"))
  {
    Real predscale(getParam<Real>("predictor_scale"));
    if (predscale >= 0.0 and predscale <= 1.0)
    {
      _problem.getNonlinearSystem().setPredictorScale(getParam<Real>("predictor_scale"));
    }
    else
    {
      mooseError("Input value for predictor_scale = "<< predscale << ", outside of permissible range (0 to 1)");
    }
  }

  _problem.getTimeScheme()->_use_AB2 = getParam<bool>("use_AB2");
  _problem.getTimeScheme()->_use_littlef = getParam<bool>("use_littlef");
  if (!_restart_file_base.empty())
    _problem.setRestartFile(_restart_file_base);
}

Transient::~Transient()
{
  // This problem was built by the Factory and needs to be released by this destructor
  delete &_problem;
}

void
Transient::execute()
{
  _problem.initialSetup();

  preExecute();

  // NOTE: if you remove this line, you will see a subset of tests failing. Those tests might have a wrong answer and might need to be regolded.
  // The reason is that we actually move the solution back in time before we actually start solving (which I think is wrong).  So this call here
  // is to maintain backward compatibility and so that MOOSE is giving the same answer.  However, we might remove this call and regold the test
  // in the future eventually.
  _problem.copyOldSolutions();

  // Start time loop...
  while(keepGoing())
  {
    takeStep();
    endStep();
  }
  postExecute();
}

void
Transient::takeStep(Real input_dt)
{
  _dt_old = _dt;
  if (input_dt == -1.0)
    _dt = computeConstrainedDT();
  else
    _dt = input_dt;

  _problem.onTimestepBegin();
  if (_converged)
  {
    // Update backward material data structures
    _problem.updateMaterials();
  }

  // Increment time
  _time = _time_old + _dt;

  std::cout<<"DT: "<<_dt<<std::endl;

  std::cout << " Solving time step ";
  {
    OStringStream out;

    OSSInt(out,2,_t_step);
    out << ", time=";
    OSSRealzeroleft(out, 9, 6, _time);
    out <<  "...";
    std::cout << out.str() << std::endl;
  }

  preSolve();

  _problem.timestepSetup();

  // Compute Pre-Aux User Objects (Timestep begin)
  _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::PRE_AUX);

  // Compute TimestepBegin AuxKernels
  _problem.computeAuxiliaryKernels(EXEC_TIMESTEP_BEGIN);

  // Compute Post-Aux User Objects (Timestep begin)
  _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::POST_AUX);

  _problem.solve();

  _converged = _problem.converged();

  // Compute Pre-Aux User Objects
  _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::PRE_AUX);

  postSolve();

  _problem.onTimestepEnd();

  // We know whether or not the nonlinear solver thinks it converged, but we need to see if the executioner concurs
  bool last_solve_converged = lastSolveConverged();

  // If _reset_dt is true, the time step was synced to the user defined value and we dump the solution in an output file
  if (last_solve_converged)
  {
    _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::POST_AUX);
  }
}

void
Transient::endStep()
{
  if (lastSolveConverged())
  {
    // Compute the Error Indicators and Markers
    _problem.computeIndicatorsAndMarkers();

    // if _reset_dt is true, force the output no matter what
    _problem.output(_reset_dt);
    _problem.outputPostprocessors(_reset_dt);

#ifdef LIBMESH_ENABLE_AMR
    if (_problem.adaptivity().isOn())
    {
      _problem.adaptMesh();
      _problem.out().meshChanged();
    }
#endif

    _time_old = _time;
    _t_step++;

    _problem.copyOldSolutions();
  }
  else
    _problem.restoreSolutions();
}

Real
Transient::computeConstrainedDT()
{
  // If this is the first step
  if (_t_step == 0)
  {
    _t_step = 1;
    _dt = _input_dt;
  }

//  // If start up steps are needed
//  if(_t_step == 1 && _n_startup_steps > 1)
//    _dt = _input_dt/(double)(_n_startup_steps);
//  else if (_t_step == 1+_n_startup_steps && _n_startup_steps > 1)
//    _dt = _input_dt;

  Real dt_cur = _dt;
  //After startup steps, compute new dt
  if (_t_step > _n_startup_steps)
    dt_cur = computeDT();

  // Don't let the time step size exceed maximum time step size
  if (dt_cur > _dtmax)
    dt_cur = _dtmax;

  // Don't allow time step size to be smaller than minimum time step size
  if (dt_cur < _dtmin)
    dt_cur = _dtmin;

  // Don't let time go beyond simulation end time
  if (_time + dt_cur > _end_time)
    dt_cur = _end_time - _time;

  // Adjust to a sync time if supplied and skipped over
  if (_remaining_sync_time && _time + dt_cur >= *_curr_sync_time_iter)
  {
    dt_cur = *_curr_sync_time_iter - _time;
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;

    _prev_dt = _dt;

    _reset_dt = true;
  }
  else
  {
    if (_reset_dt)
    {
      if (_use_time_ipol)
        dt_cur = _time_ipol.sample(_time);
      else
        dt_cur = _prev_dt;
      _reset_dt = false;
    }
  }

  return dt_cur;

}

Real
Transient::computeDT()
{
  if (!lastSolveConverged())
  {
    _cutback_occurred = true;
    //std::cout<<"Solve failed... cutting timestep"<<std::endl;
    //return _dt / 2.0;

    // Instead of blindly cutting timestep, respect dtmin.
    if (_dt <= _dtmin)
      mooseError("Solve failed and timestep already at or below dtmin, cannot continue!");

    if (0.5 * _dt >= _dtmin)
      return 0.5 * _dt;

    else // (0.5 * _dt < _dtmin)
      return _dtmin;
  }

  Real dt = _dt;
  if (_use_time_ipol)
  {
    dt = _time_ipol.sample(_time);
    if (_cutback_occurred &&
        dt > _dt * _growth_factor)
    {
      dt = _dt * _growth_factor;
    }
  }

  _cutback_occurred = false;
  return dt;
}

bool
Transient::keepGoing()
{
  // Check for stop condition based upon steady-state check flag:
  if(_converged && _trans_ss_check == true && _time > _ss_tmin)
  {
    // Compute new time solution l2_norm
    Real new_time_solution_norm = _problem.getNonlinearSystem().currentSolution()->l2_norm();

    // Compute l2_norm relative error
    Real ss_relerr_norm = fabs(new_time_solution_norm - _old_time_solution_norm)/new_time_solution_norm;

    // Check current solution relative error norm against steady-state tolerance
    if(ss_relerr_norm < _ss_check_tol)
    {
      std::cout<<"Steady-State Solution Achieved at time: "<<_time<<std::endl;
      return false;
    }
    else // Keep going
    {
      // Update solution norm for next time step
      _old_time_solution_norm = new_time_solution_norm;
      // Print steady-state relative error norm
      std::cout<<"Steady-State Relative Differential Norm: "<<ss_relerr_norm<<std::endl;
    }
  }

  if(!_converged && _abort)
  {
    std::cout<<"Aborting as solve did not converge and input selected to abort"<<std::endl;
    return false;
  }

  // Check for stop condition based upon number of simulation steps and/or solution end time:
  if(_t_step>_num_steps)
    return false;

  if((_time>_end_time) || (fabs(_time-_end_time)<1.e-14))
    return false;

  return true;
}

bool
Transient::lastSolveConverged()
{
  return _converged;
}

void
Transient::preExecute()
{
  // process time periods
  const std::vector<TimePeriod *> _time_periods = _problem.getTimePeriods();
  for (unsigned int i = 0; i < _time_periods.size(); ++i)
    _sync_times.push_back(_time_periods[i]->start());

  const std::vector<Real> & time = getParam<std::vector<Real> >("time_t");
  if (_use_time_ipol)
    _sync_times.insert(_sync_times.end(), time.begin()+1, time.end());          // insert times as sync points except the very first one
  sort(_sync_times.begin(), _sync_times.end());
  _sync_times.erase(std::unique(_sync_times.begin(), _sync_times.end()), _sync_times.end());    // remove duplicates (needs sorted array)

  // Advance to the first sync time if one is provided in sim time range
  _curr_sync_time_iter = _sync_times.begin();
  while (_remaining_sync_time && *_curr_sync_time_iter <= _time)
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;
}
<|endoftext|>


<commit_before>#include <ventura/file_operations.hpp>
#include <ventura/write_file.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <fstream>

#if VENTURA_HAS_ABSOLUTE_PATH_OPERATIONS

#ifdef _WIN32
#define SILICIUM_TEST_ROOT L"C:/"
#else
#define SILICIUM_TEST_ROOT "/"
#endif

namespace
{
	ventura::absolute_path const absolute_root = *ventura::absolute_path::create(SILICIUM_TEST_ROOT);
}

BOOST_AUTO_TEST_CASE(get_current_executable_path)
{
	Si::error_or<ventura::absolute_path> const p = ventura::get_current_executable_path();
	BOOST_REQUIRE(!p.is_error());
	auto const expected = "unit_test"
#ifdef _WIN32
	                      ".exe"
#endif
	    ;
	BOOST_CHECK_EQUAL(expected, p.get().to_boost_path().leaf());
}

BOOST_AUTO_TEST_CASE(get_current_executable_path_throw)
{
	ventura::absolute_path p = ventura::get_current_executable_path(Si::throw_);
	auto const expected = "unit_test"
#ifdef _WIN32
	                      ".exe"
#endif
	    ;
	BOOST_CHECK_EQUAL(expected, p.to_boost_path().leaf());
}

BOOST_AUTO_TEST_CASE(get_current_executable_path_variant)
{
	Si::error_or<ventura::absolute_path> const p = ventura::get_current_executable_path(Si::variant_);
	BOOST_REQUIRE(!p.is_error());
	auto const expected = "unit_test"
#ifdef _WIN32
	                      ".exe"
#endif
	    ;
	BOOST_CHECK_EQUAL(expected, p.get().to_boost_path().leaf());
}

BOOST_AUTO_TEST_CASE(test_file_exists_true)
{
	Si::error_or<bool> const exists = ventura::file_exists(absolute_root);
	BOOST_CHECK(exists.get());
}

BOOST_AUTO_TEST_CASE(test_file_exists_true_throw)
{
	bool exists = ventura::file_exists(absolute_root, Si::throw_);
	BOOST_CHECK(exists);
}

BOOST_AUTO_TEST_CASE(test_file_exists_true_variant)
{
	Si::error_or<bool> const exists = ventura::file_exists(absolute_root, Si::variant_);
	BOOST_CHECK(exists.get());
}

BOOST_AUTO_TEST_CASE(test_file_exists_false)
{
	Si::error_or<bool> const exists =
	    ventura::file_exists(absolute_root / *ventura::path_segment::create("does-not-exist"));
	BOOST_CHECK(!exists.get());
}

BOOST_AUTO_TEST_CASE(test_file_exists_false_throw)
{
	bool exists = ventura::file_exists(absolute_root / *ventura::path_segment::create("does-not-exist"), Si::throw_);
	BOOST_CHECK(!exists);
}

BOOST_AUTO_TEST_CASE(test_file_exists_false_variant)
{
	Si::error_or<bool> const exists =
	    ventura::file_exists(absolute_root / *ventura::path_segment::create("does-not-exist"), Si::variant_);
	BOOST_CHECK(!exists.get());
}

BOOST_AUTO_TEST_CASE(test_rename)
{
	ventura::absolute_path const from = ventura::temporary_directory().get() / ventura::unique_path();
	ventura::create_file(from).move_value();
	ventura::absolute_path const to = ventura::temporary_directory().get() / ventura::unique_path();
	BOOST_CHECK(!ventura::file_exists(to).get());
	boost::system::error_code const error = ventura::rename(from, to);
	BOOST_CHECK(ventura::file_exists(to).get());
	BOOST_CHECK(!error);
}

BOOST_AUTO_TEST_CASE(test_temporary_directory)
{
	Si::error_or<ventura::absolute_path> const p = ventura::temporary_directory();
	BOOST_REQUIRE(!p.is_error());
	BOOST_CHECK(!p.get().empty());
}

BOOST_AUTO_TEST_CASE(test_temporary_directory_throw)
{
	ventura::absolute_path const p = ventura::temporary_directory(Si::throw_);
	BOOST_CHECK(!p.empty());
}

BOOST_AUTO_TEST_CASE(test_temporary_directory_variant)
{
	Si::error_or<ventura::absolute_path> const p = ventura::temporary_directory(Si::variant_);
	BOOST_REQUIRE(!p.is_error());
	BOOST_CHECK(!p.get().empty());
}

BOOST_AUTO_TEST_CASE(test_get_home)
{
	ventura::absolute_path const home = ventura::get_home();
#ifdef _WIN32
	BOOST_CHECK(boost::algorithm::starts_with(to_os_string(home), "C:/Users/"));
	BOOST_CHECK(boost::algorithm::ends_with(to_os_string(home), "/AppData/Local"));
#elif defined(__linux__)
	BOOST_CHECK(boost::algorithm::starts_with(ventura::to_os_string(home), "/home/"));
#else
	// OSX
	BOOST_CHECK(boost::algorithm::starts_with(to_os_string(home), "/Users/"));
#endif
}

BOOST_AUTO_TEST_CASE(test_copy_recursively)
{
	ventura::absolute_path const temp =
	    ventura::temporary_directory(Si::throw_) / ventura::relative_path("silicium-test_copy_recursively");
	ventura::recreate_directories(temp, Si::throw_);
	ventura::absolute_path const from = temp / ventura::relative_path("from");
	ventura::absolute_path const to = temp / ventura::relative_path("to");
	ventura::create_directories(from, Si::throw_);
	auto const expected = Si::make_c_str_range("Hello");
	Si::throw_if_error(ventura::write_file(
	    Si::native_path_string(to_os_string(from / ventura::relative_path("file.txt")).c_str()), expected));
	ventura::copy_recursively(from, to, nullptr, Si::throw_);
	std::ifstream file((to / ventura::relative_path("file.txt")).c_str(), std::ios::binary);
	BOOST_REQUIRE(file);
	std::vector<char> const file_content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
	BOOST_CHECK_EQUAL_COLLECTIONS(file_content.begin(), file_content.end(), expected.begin(), expected.end());
}
#endif
<commit_msg>more tests for copy_recursively<commit_after>#include <ventura/file_operations.hpp>
#include <ventura/write_file.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <fstream>

#if VENTURA_HAS_ABSOLUTE_PATH_OPERATIONS

#ifdef _WIN32
#define SILICIUM_TEST_ROOT L"C:/"
#else
#define SILICIUM_TEST_ROOT "/"
#endif

namespace
{
	ventura::absolute_path const absolute_root = *ventura::absolute_path::create(SILICIUM_TEST_ROOT);
}

BOOST_AUTO_TEST_CASE(get_current_executable_path)
{
	Si::error_or<ventura::absolute_path> const p = ventura::get_current_executable_path();
	BOOST_REQUIRE(!p.is_error());
	auto const expected = "unit_test"
#ifdef _WIN32
	                      ".exe"
#endif
	    ;
	BOOST_CHECK_EQUAL(expected, p.get().to_boost_path().leaf());
}

BOOST_AUTO_TEST_CASE(get_current_executable_path_throw)
{
	ventura::absolute_path p = ventura::get_current_executable_path(Si::throw_);
	auto const expected = "unit_test"
#ifdef _WIN32
	                      ".exe"
#endif
	    ;
	BOOST_CHECK_EQUAL(expected, p.to_boost_path().leaf());
}

BOOST_AUTO_TEST_CASE(get_current_executable_path_variant)
{
	Si::error_or<ventura::absolute_path> const p = ventura::get_current_executable_path(Si::variant_);
	BOOST_REQUIRE(!p.is_error());
	auto const expected = "unit_test"
#ifdef _WIN32
	                      ".exe"
#endif
	    ;
	BOOST_CHECK_EQUAL(expected, p.get().to_boost_path().leaf());
}

BOOST_AUTO_TEST_CASE(test_file_exists_true)
{
	Si::error_or<bool> const exists = ventura::file_exists(absolute_root);
	BOOST_CHECK(exists.get());
}

BOOST_AUTO_TEST_CASE(test_file_exists_true_throw)
{
	bool exists = ventura::file_exists(absolute_root, Si::throw_);
	BOOST_CHECK(exists);
}

BOOST_AUTO_TEST_CASE(test_file_exists_true_variant)
{
	Si::error_or<bool> const exists = ventura::file_exists(absolute_root, Si::variant_);
	BOOST_CHECK(exists.get());
}

BOOST_AUTO_TEST_CASE(test_file_exists_false)
{
	Si::error_or<bool> const exists =
	    ventura::file_exists(absolute_root / *ventura::path_segment::create("does-not-exist"));
	BOOST_CHECK(!exists.get());
}

BOOST_AUTO_TEST_CASE(test_file_exists_false_throw)
{
	bool exists = ventura::file_exists(absolute_root / *ventura::path_segment::create("does-not-exist"), Si::throw_);
	BOOST_CHECK(!exists);
}

BOOST_AUTO_TEST_CASE(test_file_exists_false_variant)
{
	Si::error_or<bool> const exists =
	    ventura::file_exists(absolute_root / *ventura::path_segment::create("does-not-exist"), Si::variant_);
	BOOST_CHECK(!exists.get());
}

BOOST_AUTO_TEST_CASE(test_rename)
{
	ventura::absolute_path const from = ventura::temporary_directory().get() / ventura::unique_path();
	ventura::create_file(from).move_value();
	ventura::absolute_path const to = ventura::temporary_directory().get() / ventura::unique_path();
	BOOST_CHECK(!ventura::file_exists(to).get());
	boost::system::error_code const error = ventura::rename(from, to);
	BOOST_CHECK(ventura::file_exists(to).get());
	BOOST_CHECK(!error);
}

BOOST_AUTO_TEST_CASE(test_temporary_directory)
{
	Si::error_or<ventura::absolute_path> const p = ventura::temporary_directory();
	BOOST_REQUIRE(!p.is_error());
	BOOST_CHECK(!p.get().empty());
}

BOOST_AUTO_TEST_CASE(test_temporary_directory_throw)
{
	ventura::absolute_path const p = ventura::temporary_directory(Si::throw_);
	BOOST_CHECK(!p.empty());
}

BOOST_AUTO_TEST_CASE(test_temporary_directory_variant)
{
	Si::error_or<ventura::absolute_path> const p = ventura::temporary_directory(Si::variant_);
	BOOST_REQUIRE(!p.is_error());
	BOOST_CHECK(!p.get().empty());
}

BOOST_AUTO_TEST_CASE(test_get_home)
{
	ventura::absolute_path const home = ventura::get_home();
#ifdef _WIN32
	BOOST_CHECK(boost::algorithm::starts_with(to_os_string(home), "C:/Users/"));
	BOOST_CHECK(boost::algorithm::ends_with(to_os_string(home), "/AppData/Local"));
#elif defined(__linux__)
	BOOST_CHECK(boost::algorithm::starts_with(ventura::to_os_string(home), "/home/"));
#else
	// OSX
	BOOST_CHECK(boost::algorithm::starts_with(to_os_string(home), "/Users/"));
#endif
}

BOOST_AUTO_TEST_CASE(test_copy_recursively_exists)
{
	ventura::absolute_path const temp =
	    ventura::temporary_directory(Si::throw_) / ventura::relative_path("silicium-test_copy_recursively");
	ventura::recreate_directories(temp, Si::throw_);
	ventura::absolute_path const from = temp / ventura::relative_path("from");
	ventura::absolute_path const to = temp / ventura::relative_path("to");
	ventura::create_directories(from, Si::throw_);
	auto const expected = Si::make_c_str_range("Hello");
	Si::throw_if_error(ventura::write_file(
	    Si::native_path_string(to_os_string(from / ventura::relative_path("file.txt")).c_str()), expected));
	ventura::create_directories(to, Si::throw_);
	ventura::copy_recursively(from, to, nullptr, Si::throw_);
	BOOST_REQUIRE(ventura::file_exists(to).get());
	std::ifstream file((to / ventura::relative_path("file.txt")).c_str(), std::ios::binary);
	BOOST_REQUIRE(file);
	std::vector<char> const file_content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
	BOOST_CHECK_EQUAL_COLLECTIONS(file_content.begin(), file_content.end(), expected.begin(), expected.end());
}

BOOST_AUTO_TEST_CASE(test_copy_recursively_does_not_exist)
{
	ventura::absolute_path const temp =
		ventura::temporary_directory(Si::throw_) / ventura::relative_path("silicium-test_copy_recursively");
	ventura::recreate_directories(temp, Si::throw_);
	ventura::absolute_path const from = temp / ventura::relative_path("from");
	ventura::absolute_path const to = temp / ventura::relative_path("to");
	ventura::create_directories(from, Si::throw_);
	auto const expected = Si::make_c_str_range("Hello");
	Si::throw_if_error(ventura::write_file(
		Si::native_path_string(to_os_string(from / ventura::relative_path("file.txt")).c_str()), expected));
	BOOST_REQUIRE(!ventura::file_exists(to).get());
	ventura::copy_recursively(from, to, nullptr, Si::throw_);
	BOOST_REQUIRE(ventura::file_exists(to).get());
	std::ifstream file((to / ventura::relative_path("file.txt")).c_str(), std::ios::binary);
	BOOST_REQUIRE(file);
	std::vector<char> const file_content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
	BOOST_CHECK_EQUAL_COLLECTIONS(file_content.begin(), file_content.end(), expected.begin(), expected.end());
}

BOOST_AUTO_TEST_CASE(test_copy_recursively_parent_does_not_exist)
{
	ventura::absolute_path const temp =
		ventura::temporary_directory(Si::throw_) / ventura::relative_path("silicium-test_copy_recursively");
	ventura::recreate_directories(temp, Si::throw_);
	ventura::absolute_path const from = temp / ventura::relative_path("from");
	ventura::absolute_path const to = temp / ventura::relative_path("parent/to");
	ventura::create_directories(from, Si::throw_);
	auto const expected = Si::make_c_str_range("Hello");
	Si::throw_if_error(ventura::write_file(
		Si::native_path_string(to_os_string(from / ventura::relative_path("file.txt")).c_str()), expected));
	BOOST_REQUIRE(!ventura::file_exists(to).get());
	ventura::copy_recursively(from, to, nullptr, Si::throw_);
	BOOST_REQUIRE(ventura::file_exists(to).get());
	std::ifstream file((to / ventura::relative_path("file.txt")).c_str(), std::ios::binary);
	BOOST_REQUIRE(file);
	std::vector<char> const file_content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
	BOOST_CHECK_EQUAL_COLLECTIONS(file_content.begin(), file_content.end(), expected.begin(), expected.end());
}
#endif
<|endoftext|>


<commit_before>//******************************************************************************************
//  File: EX_RGB_NeoPixelBus.h
//  Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock
//
//  Summary:  EX_RGB_NeoPixelBus is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities.
//			  It inherits from the st::Executor class.
//
//			  Create an instance of this class in your sketch's global variable section
//			  For Example:  st::EX_RGB_NeoPixelBus executor1("rgbSwitch1", PIN_RGB, PIXEL_COUNT);
//
//			  st::EX_RGB_NeoPixelBus() constructor requires the following arguments
//				- String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name.
//				- byte pin - REQUIRED - the Arduino Pin to be used as a digital output for the RGB strip
//				- byte count - REQUIRED - the number of programmable pixels in the RGB strip
//
//  Change History:
//
//    Date        Who            What
//    ----        ---            ----
//    2016-04-30  Dan Ogorchock  Original Creation
//    2018-08-14  Dan Ogorchock  Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()"
//    2017-08-30  Dan Ogorchock  Modified comment section above to comply with new Parent/Child Device Handler requirements
//    2017-10-06  Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting
//    2020-08-01  Allan (vseven) Modified the EX_RGB_Dim for use with addressable LED strips using the NeoPixelBus library
//
//******************************************************************************************
#include "EX_RGB_NeoPixelBus.h"

#include "Constants.h"
#include "Everything.h"

#include <NeoPixelBus.h>

namespace st
{

//private
	void EX_RGB_NeoPixelBus::writeCommandToOutput()
	{
		uint8_t R;
		uint8_t G;
		uint8_t B;

		if (st::Executor::debug) {
			Serial.println("m_bCurrentState: " + String(m_bCurrentState));
			Serial.println("m_sCurrentHEX: " + String(m_sCurrentHEX));
		}

		if (m_bCurrentState == HIGH){
			// Our status is on so get the RGB value from the hex
			String hexstring = m_sCurrentHEX;
			long number = (long) strtol( &hexstring[1], NULL, 16);
      			// Split them up into r, g, b values
      			R = number >> 16;
      			G = number >> 8 & 0xFF;
      			B = number & 0xFF;
		} else {
			// Status is off so turn off LED
			R = 00;
      			G = 00;
      			B = 00;
		}

		// Any adjustments to the colors can be done here before sending the commands.  For example if red is always too bright reduce it:
		// R = R * 0.95

		// Write to our output

		if (st::Executor::debug) {
			Serial.print(F("subString R:G:B = "));
			Serial.println(String(R) + ":" + String(G) + ":" + String(B));
		}

		// set all pixels to the same color

		RgbColor myColor = RgbColor(R, G, B);

		if (st::Executor::debug) {
			Serial.print(F("Total number of pixels reported by strip: "));
			Serial.println(String(m_nStrip.PixelCount()));
			//Serial.print(F("Color being sent: "));
			//Serial.println(String(myColor.r + myColor.g + myColor.b));
		}

		m_nStrip.ClearTo(myColor);

		if (st::Executor::debug) {
			Serial.println(F("All pixels set.  Sending show command."));
		}

		// then display it
		m_nStrip.Show();
	}

//public
	//constructor
	EX_RGB_NeoPixelBus::EX_RGB_NeoPixelBus(const __FlashStringHelper *name, byte count, byte pin):
		Executor(name),
		m_nStrip(count,pin)
	{

	}

	//destructor
	EX_RGB_NeoPixelBus::~EX_RGB_NeoPixelBus()
	{

	}

	void EX_RGB_NeoPixelBus::init()
	{
		Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off")));

		if (st::Executor::debug) {
			Serial.println("init called. Sending Begin to strip.");
		}
		// On startup make sure strip is turned off
  		m_nStrip.Begin();
		m_nStrip.Show();
	}

	void EX_RGB_NeoPixelBus::beSmart(const String &str)
	{
		String s=str.substring(str.indexOf(' ')+1);
		if (st::Executor::debug) {
			Serial.print(F("EX_RGB_NeoPixelBus::beSmart s = "));
			Serial.println(s);
		}
		if(s==F("on"))
		{
			m_bCurrentState=HIGH;
		}
		else if(s==F("off"))
		{
			m_bCurrentState=LOW;
		}
		else //must be a set color command
		{
			s.trim();
			m_sCurrentHEX = s;
		}

		writeCommandToOutput();

		//Send data to SmartThings/Hubitat
		Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off")));
	}

	void EX_RGB_NeoPixelBus::refresh()
	{
		Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off")));
	}
}<commit_msg>Delete EX_RGB_NeoPixelBus.cpp<commit_after><|endoftext|>


<commit_before>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// Copyright (c) 2012 openMVG contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

//#include "aliceVision/multiview/homographyKernelSolver.hpp"
//#include "aliceVision/robustEstimation/ACRansac.hpp"
//#include "aliceVision/robustEstimation/ACRansacKernelAdaptator.hpp"
//#include "aliceVision/robustEstimation/guidedMatching.hpp"

//#include "aliceVision/matching/IndMatch.hpp"
//#include "aliceVision/matching/IndMatchDecorator.hpp"
#include "aliceVision/sfm/SfMData.hpp"
#include "aliceVision/feature/RegionsPerView.hpp"
#include "aliceVision/matchingImageCollection/GeometricFilterMatrix.hpp"

namespace aliceVision {
namespace matchingImageCollection {

//-- Multiple homography matrices estimation template functor, based on homography growing, used for filter pair of putative correspondences
struct GeometricFilterMatrix_HGrowing : public GeometricFilterMatrix
{
  GeometricFilterMatrix_HGrowing(
    double dPrecision = std::numeric_limits<double>::infinity(),
    size_t iteration = 1024)
    : GeometricFilterMatrix(dPrecision, std::numeric_limits<double>::infinity(), iteration)
    , _maxNbHomographies(10)
    , _minRemainingMatches(20)
    , _similarityTolerance(10)
    , _affinityTolerance(10)
    , _homographyTolerance(5)
    , _minNbPlanarMatches(6)
    , _nbIterations(8)
    , _maxFractionPlanarMatches(0.7)
  {
    _Hs.push_back(Mat3::Identity());
  }
/**
   * @brief Given two sets of image points, it estimates the homography matrix
   * relating them using a robust method (like A Contrario Ransac).
   */
  template<typename Regions_or_Features_ProviderT>
  EstimationStatus geometricEstimation(
    const sfm::SfMData * sfmData,
    const Regions_or_Features_ProviderT& regionsPerView,
    const Pair pairIndex,
    const matching::MatchesPerDescType & putativeMatchesPerType,
    matching::MatchesPerDescType & out_geometricInliersPerType)
  {

    using namespace aliceVision;
    using namespace aliceVision::robustEstimation;
    out_geometricInliersPerType.clear();

    // Get back corresponding view index
    const IndexT iIndex = pairIndex.first;
    const IndexT jIndex = pairIndex.second;

    const std::vector<feature::EImageDescriberType> descTypes = regionsPerView.getCommonDescTypes(pairIndex);
    if(descTypes.empty())
      return EstimationStatus(false, false);

    // Retrieve all 2D features as undistorted positions into flat arrays
    Mat xI, xJ;
    MatchesPairToMat(pairIndex, putativeMatchesPerType, sfmData, regionsPerView, descTypes, xI, xJ);
    std::cout << "Pair id. : " << pairIndex << std::endl;
    std::cout << "|- xI: " << xI.rows() << "x" << xI.cols() << std::endl;
    std::cout << "|- xJ: " << xJ.rows() << "x" << xJ.cols() << std::endl;
    std::size_t nbMatches = xI.cols();

    // (?) make a map
    std::vector<Mat3> homographies;
    std::vector<std::vector<IndexT>> planarMatchesPerH;

    for (IndexT iTransform = 0; iTransform < _maxNbHomographies; ++iTransform)
    {
      for (IndexT iMatch = 0; iMatch < nbMatches; ++iMatch)
      {
        // [TODO] Add 1st improvment

        // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
        std::vector<IndexT> planarMatchesIds;
        Mat3 homographie;

        growHomography(xI, xJ, iMatch ,planarMatchesIds, homographie);

        if (!planarMatchesIds.empty())
        {
          homographies.push_back(homographie);
          planarMatchesPerH.push_back(planarMatchesIds);
        }
      }
    }

    // Check if resection has strong support
    const bool hasStrongSupport = true;
    return EstimationStatus(true, hasStrongSupport);
  }

  /**
   * @brief Geometry_guided_matching
   * @param sfm_data
   * @param regionsPerView
   * @param pairIndex
   * @param dDistanceRatio
   * @param matches
   * @return
   */
  bool Geometry_guided_matching
  (
    const sfm::SfMData * sfmData,
    const feature::RegionsPerView & regionsPerView,
    const Pair imageIdsPair,
    const double dDistanceRatio,
    matching::MatchesPerDescType & matches) override
  {

    /* ... */
    return matches.getNbAllMatches() != 0;
  }

private:

  // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
  //-- See: YASM/relative_pose.h
  void growHomography(const Mat & featuresI,
                      const Mat & featuresJ,
                      const IndexT & matchId,
                      std::vector<IndexT> & planarMatchesIndices,
                      Mat3 & homographie)
  {

    planarMatchesIndices.clear();
    homographie = Mat3::Identity();

    for (IndexT iRefineStep = 0; iRefineStep < _nbIterations; ++iRefineStep)
    {
      if (iRefineStep == 0)
      {
        computeSimilarityFromMatch();
      }
      else if (iRefineStep <= 4)
      {
        estimateAffinity();
      }
      else
      {
        estimateHomography();
      }

      findHomographyInliers();

    }
  }

  /**
   * @brief computeSimilarityFromMatch
   * see: alicevision::sfm::computeSimilarity() [sfm/utils/alignment.cpp]
   *      alicevision::geometry::ACRansac_FindRTS() [geometry/rigidTransformation3D(_test).hpp]
   */
  void computeSimilarityFromMatch()
  {
    std::cout << "computeSimilarityFromMatch" << std::endl;
  }

  /**
   * @brief estimateAffinity
   * see: alicevision::Affine2DFromCorrespondencesLinear() [multiview/affineSolver(_test).hpp]
   */
  void estimateAffinity()
  {
    std::cout << "estimateAffinity" << std::endl;
  }

  /**
   * @brief estimateHomography
   * see: by DLT: alicevision::homography::kernel::FourPointSolver::Solve() [multiview/homographyKernelSolver.hpp]
   *      by RANSAC: alicevision::matchingImageCOllection::geometricEstimation() [matchingImageCollection/GeometricFilterMatrix_H_AC.hpp]
   */
  void estimateHomography()
  {
    std::cout << "estimateHomography" << std::endl;
  }

  /**
   * @brief findHomographyInliers Test the reprojection error
   */
  void findHomographyInliers()
  {
    std::cout << "findHomographyInliers" << std::endl;
  }

  //-- Stored data
  std::vector<Mat3> _Hs;

  //-- Options

  std::size_t _maxNbHomographies; // = MaxHoms
  std::size_t _minRemainingMatches; // = MinInsNum

  // growHomography function:
  std::size_t _similarityTolerance; // = SimTol
  std::size_t _affinityTolerance;   // = AffTol
  std::size_t _homographyTolerance; // = HomTol

  std::size_t _minNbPlanarMatches; // = MinIns
  std::size_t _nbIterations; // = RefIterNum
  std::size_t _maxFractionPlanarMatches; // = StopInsFrac

};

} // namespace matchingImageCollection
} // namespace aliceVision

<commit_msg>[Hgrowing] 'computeSimilarityFromMatch' integration<commit_after>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// Copyright (c) 2012 openMVG contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

//#include "aliceVision/multiview/homographyKernelSolver.hpp"
//#include "aliceVision/robustEstimation/ACRansac.hpp"
//#include "aliceVision/robustEstimation/ACRansacKernelAdaptator.hpp"
//#include "aliceVision/robustEstimation/guidedMatching.hpp"

#include "aliceVision/matching/IndMatch.hpp"
//#include "aliceVision/matching/IndMatchDecorator.hpp"
#include "aliceVision/sfm/SfMData.hpp"
#include "aliceVision/feature/RegionsPerView.hpp"
#include "aliceVision/matchingImageCollection/GeometricFilterMatrix.hpp"

namespace aliceVision {
namespace matchingImageCollection {

//-- Multiple homography matrices estimation template functor, based on homography growing, used for filter pair of putative correspondences
struct GeometricFilterMatrix_HGrowing : public GeometricFilterMatrix
{
  GeometricFilterMatrix_HGrowing(
    double dPrecision = std::numeric_limits<double>::infinity(),
    size_t iteration = 1024)
    : GeometricFilterMatrix(dPrecision, std::numeric_limits<double>::infinity(), iteration)
    , _maxNbHomographies(10)
    , _minRemainingMatches(20)
    , _similarityTolerance(10)
    , _affinityTolerance(10)
    , _homographyTolerance(5)
    , _minNbPlanarMatches(6)
    , _nbIterations(8)
    , _maxFractionPlanarMatches(0.7)
  {
    _Hs.push_back(Mat3::Identity());
  }
/**
   * @brief Given two sets of image points, it estimates the homography matrix
   * relating them using a robust method (like A Contrario Ransac).
   */
  template<typename Regions_or_Features_ProviderT>
  EstimationStatus geometricEstimation(
    const sfm::SfMData * sfmData,
    const Regions_or_Features_ProviderT& regionsPerView,
    const Pair pairIndex,
    const matching::MatchesPerDescType & putativeMatchesPerType,
    matching::MatchesPerDescType & out_geometricInliersPerType)
  {

    using namespace aliceVision;
    using namespace aliceVision::robustEstimation;
    out_geometricInliersPerType.clear();

    // Get back corresponding view index
    const IndexT viewId_I = pairIndex.first;
    const IndexT viewId_J = pairIndex.second;

    const std::vector<feature::EImageDescriberType> descTypes = regionsPerView.getCommonDescTypes(pairIndex);
    if(descTypes.empty())
      return EstimationStatus(false, false);

    // Retrieve all 2D features as undistorted positions into flat arrays
    Mat xI, xJ;
    MatchesPairToMat(pairIndex, putativeMatchesPerType, sfmData, regionsPerView, descTypes, xI, xJ);

    std::cout << "Pair id. : " << pairIndex << std::endl;
    std::cout << "|- putative: " << putativeMatchesPerType.at(feature::EImageDescriberType::SIFT).size() << std::endl;
    std::cout << "|- xI: " << xI.rows() << "x" << xI.cols() << std::endl;
    std::cout << "|- xJ: " << xJ.rows() << "x" << xJ.cols() << std::endl;

    const feature::Regions& regionsSIFT_I = regionsPerView.getRegions(viewId_I, descTypes.at(0));
    const feature::Regions& regionsSIFT_J = regionsPerView.getRegions(viewId_J, descTypes.at(0));
    const std::vector<feature::SIOPointFeature> allFeaturesI = getSIOPointFeatures(regionsSIFT_I);
    const std::vector<feature::SIOPointFeature> allFeaturesJ = getSIOPointFeatures(regionsSIFT_J);

    matching::IndMatches putativeMatchesSIFT = putativeMatchesPerType.at(feature::EImageDescriberType::SIFT);
    std::vector<feature::SIOPointFeature> putativeFeaturesI, putativeFeaturesJ;
    putativeFeaturesI.reserve(putativeMatchesSIFT.size());
    putativeFeaturesJ.reserve(putativeMatchesSIFT.size());

    for (const matching::IndMatch & idMatch : putativeMatchesSIFT)
    {
      putativeFeaturesI.push_back(allFeaturesI.at(idMatch._i));
      putativeFeaturesJ.push_back(allFeaturesJ.at(idMatch._j));
    }

    if (viewId_I == 200563944 && viewId_J == 1112206013) // MATLAB exemple
    {
      std::cout << "|- #matches: " << putativeMatchesSIFT.size() << std::endl;
      std::cout << "|- allFeaturesI : " << allFeaturesI.size() << std::endl;
      std::cout << "|- allFeaturesJ : " << allFeaturesJ.size() << std::endl;
      std::cout << "|- putativeFeaturesI : " << putativeFeaturesI.size() << std::endl;
      std::cout << "|- putativeFeaturesJ : " << putativeFeaturesJ.size() << std::endl;
      //      std::cout << "-------" << std::endl;
      //      std::cout << "xI : " << std::endl;
      //      std::cout << xI << std::endl;
      //      std::cout << "putativeFeaturesI : " << std::endl;
      //      std::cout << putativeFeaturesI << std::endl;

      std::size_t nbMatches = putativeMatchesSIFT.size();

      // (?) make a map
      std::vector<Mat3> homographies;
      std::vector<std::vector<IndexT>> planarMatchesPerH;

      for (IndexT iTransform = 0; iTransform < _maxNbHomographies; ++iTransform)
      {
        for (IndexT iMatch = 0; iMatch < nbMatches; ++iMatch)
        {
          // [TODO] Add 1st improvment

          // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
          std::vector<IndexT> planarMatchesIds;
          Mat3 homographie;

          growHomography(putativeFeaturesI, putativeFeaturesJ, iMatch , planarMatchesIds, homographie);

          if (!planarMatchesIds.empty())
          {
            homographies.push_back(homographie);
            planarMatchesPerH.push_back(planarMatchesIds);
          }
        }
      }
    }

    // Check if resection has strong support
    const bool hasStrongSupport = true;
    return EstimationStatus(true, hasStrongSupport);
  }

  /**
   * @brief Geometry_guided_matching
   * @param sfm_data
   * @param regionsPerView
   * @param pairIndex
   * @param dDistanceRatio
   * @param matches
   * @return
   */
  bool Geometry_guided_matching
  (
    const sfm::SfMData * sfmData,
    const feature::RegionsPerView & regionsPerView,
    const Pair imageIdsPair,
    const double dDistanceRatio,
    matching::MatchesPerDescType & matches) override
  {

    /* ... */
    return matches.getNbAllMatches() != 0;
  }

private:

  // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
  //-- See: YASM/relative_pose.h
  void growHomography(const std::vector<feature::SIOPointFeature> & featuresI,
                      const std::vector<feature::SIOPointFeature> & featuresJ,
                      const IndexT & seedMatchId,
                      std::vector<IndexT> & out_planarMatchesIndices,
                      Mat3 & out_transformation)
  {

    assert(featuresI.size() == featuresJ.size());
    assert(seedMatchId <= featuresI.size());

//    std::cout << "featuresI = " << featuresI << std::endl;
//    std::cout << "featuresI = " << featuresI << std::endl;

    out_planarMatchesIndices.clear();
    out_transformation = Mat3::Identity();

    feature::SIOPointFeature seedFeatureI = featuresI.at(seedMatchId);
    feature::SIOPointFeature seedFeatureJ = featuresJ.at(seedMatchId);
    std::size_t currentTolerance;
    for (IndexT iRefineStep = 0; iRefineStep < _nbIterations; ++iRefineStep)
    {
      if (iRefineStep == 0)
      {
        computeSimilarityFromMatch(seedFeatureI, seedFeatureJ, out_transformation);
        std::cout << "featI: " << seedFeatureI << std::endl;
        std::cout << "featJ: " << seedFeatureJ << std::endl;
        std::cout << "S = " << out_transformation << std::endl;
        getchar();
        currentTolerance = _similarityTolerance;
      }
      else if (iRefineStep <= 4)
      {
        estimateAffinity();
        currentTolerance = _affinityTolerance;
      }
      else
      {
        estimateHomography();
        currentTolerance = _homographyTolerance;
      }

      findHomographyInliers();

    }
  }

  /**
   * @brief computeSimilarityFromMatch
   * see: alicevision::sfm::computeSimilarity() [sfm/utils/alignment.cpp]
   *      alicevision::geometry::ACRansac_FindRTS() [geometry/rigidTransformation3D(_test).hpp]
   */

  void computeSimilarityFromMatch(const feature::SIOPointFeature & feat1,
                                  const feature::SIOPointFeature & feat2,
                                  Mat3 & S)
  {
    computeSimilarityFromMatch(feat1.coords(), feat1.scale(), feat1.orientation(),
                               feat2.coords(), feat2.scale(), feat2.orientation(),
                               S);
  }

  /**
   * @brief computeSimilarityFromMatch
   * Source: https://github.com/fsrajer/yasfm/blob/master/YASFM/relative_pose.cpp#L1649
   * @param coord1
   * @param scale1
   * @param orientation1
   * @param coord2
   * @param scale2
   * @param orientation2
   * @param S
   */
  void computeSimilarityFromMatch(const Vec2f & coord1, double scale1, double orientation1,
                                  const Vec2f & coord2, double scale2, double orientation2,
                                  Mat3 & S)
  {
    double c1 = cos(orientation1),
        s1 = sin(orientation1),
        c2 = cos(orientation2),
        s2 = sin(orientation2);

    Mat3 A1,A2;
    A1 << scale1*c1,scale1*(-s1),coord1(0),
        scale1*s1,scale1*c1,coord1(1),
        0,0,1;
    A2 << scale2*c2,scale2*(-s2),coord2(0),
        scale2*s2,scale2*c2,coord2(1),
        0,0,1;

    S = A2*A1.inverse();
  }

  /**
   * @brief estimateAffinity
   * see: alicevision::Affine2DFromCorrespondencesLinear() [multiview/affineSolver(_test).hpp]
   */
  void estimateAffinity()
  {
//    std::cout << "estimateAffinity" << std::endl;
  }

  /**
   * @brief estimateHomography
   * see: by DLT: alicevision::homography::kernel::FourPointSolver::Solve() [multiview/homographyKernelSolver.hpp]
   *      by RANSAC: alicevision::matchingImageCOllection::geometricEstimation() [matchingImageCollection/GeometricFilterMatrix_H_AC.hpp]
   */
  void estimateHomography()
  {
//    std::cout << "estimateHomography" << std::endl;
  }

  /**
   * @brief findHomographyInliers Test the reprojection error
   */
  void findHomographyInliers()
  {
//    std::cout << "findHomographyInliers" << std::endl;
  }

  //-- Stored data
  std::vector<Mat3> _Hs;

  //-- Options

  std::size_t _maxNbHomographies; // = MaxHoms
  std::size_t _minRemainingMatches; // = MinInsNum

  // growHomography function:
  std::size_t _similarityTolerance; // = SimTol
  std::size_t _affinityTolerance;   // = AffTol
  std::size_t _homographyTolerance; // = HomTol

  std::size_t _minNbPlanarMatches; // = MinIns
  std::size_t _nbIterations; // = RefIterNum
  std::size_t _maxFractionPlanarMatches; // = StopInsFrac

};

} // namespace matchingImageCollection
} // namespace aliceVision

<|endoftext|>


<commit_before>// Application entry point.
//
#include <iostream>
#include <string>

using namespace std;

int main() {
    extern string greeting();  // greeting.cpp
    std::cout << greeting() << endl;
    return EXIT_SUCCESS;
}
<commit_msg>added <cstdlib> header to main.cpp<commit_after>// Application entry point.
//
#include <cstdlib>
#include <iostream>
#include <string>

using namespace std;

int main() {
    extern string greeting();  // greeting.cpp
    std::cout << greeting() << endl;
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */
#include "openthread-core-config.h"

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include <openthread-system.h>
#include <openthread/cli.h>

#include "cli/cli_config.h"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/logging.hpp"
#include "utils/uart.h"

#if OPENTHREAD_POSIX
#include <signal.h>
#include <sys/types.h>
#endif

/**
 * @def OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE
 *
 * The size of CLI UART RX buffer in bytes.
 *
 */
#ifndef OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
#define OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE 640
#else
#define OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE 512
#endif
#endif

/**
 * @def OPENTHREAD_CONFIG_CLI_TX_BUFFER_SIZE
 *
 * The size of CLI message buffer in bytes.
 *
 */
#ifndef OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE
#define OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE 1024
#endif

#if OPENTHREAD_CONFIG_DIAG_ENABLE
#if OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE > OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE
#error "diag output buffer should be smaller than CLI UART tx buffer"
#endif
#if OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE > OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE
#error "diag command line should be smaller than CLI UART rx buffer"
#endif
#endif

#if OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH > OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE
#error "command line should be should be smaller than CLI rx buffer"
#endif

enum
{
    kRxBufferSize = OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE,
    kTxBufferSize = OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE,
};

char     sRxBuffer[kRxBufferSize];
uint16_t sRxLength;

char     sTxBuffer[kTxBufferSize];
uint16_t sTxHead;
uint16_t sTxLength;

uint16_t sSendLength;

#ifdef OT_CLI_UART_LOCK_HDR_FILE

#include OT_CLI_UART_LOCK_HDR_FILE

#else

/**
 * Macro to acquire an exclusive lock of uart cli output
 * Default implementation does nothing
 *
 */
#ifndef OT_CLI_UART_OUTPUT_LOCK
#define OT_CLI_UART_OUTPUT_LOCK() \
    do                            \
    {                             \
    } while (0)
#endif

/**
 * Macro to release the exclusive lock of uart cli output
 * Default implementation does nothing
 *
 */
#ifndef OT_CLI_UART_OUTPUT_UNLOCK
#define OT_CLI_UART_OUTPUT_UNLOCK() \
    do                              \
    {                               \
    } while (0)
#endif

#endif // OT_CLI_UART_LOCK_HDR_FILE

static int     Output(const char *aBuf, uint16_t aBufLength);
static otError ProcessCommand(void);

static void ReceiveTask(const uint8_t *aBuf, uint16_t aBufLength)
{
    static const char sEraseString[]   = {'\b', ' ', '\b'};
    static const char CRNL[]           = {'\r', '\n'};
    static const char sCommandPrompt[] = {'>', ' '};
    const uint8_t *   end;

    end = aBuf + aBufLength;

    for (; aBuf < end; aBuf++)
    {
        switch (*aBuf)
        {
        case '\r':
        case '\n':
            Output(CRNL, sizeof(CRNL));
            if (sRxLength > 0)
            {
                sRxBuffer[sRxLength] = '\0';
                IgnoreError(ProcessCommand());
            }

            Output(sCommandPrompt, sizeof(sCommandPrompt));

            break;

#if OPENTHREAD_POSIX && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
        case 0x03: // ASCII for Ctrl-C
            kill(0, SIGINT);
            break;

        case 0x04: // ASCII for Ctrl-D
            exit(EXIT_SUCCESS);
            break;
#endif

        case '\b':
        case 127:
            if (sRxLength > 0)
            {
                Output(sEraseString, sizeof(sEraseString));
                sRxBuffer[--sRxLength] = '\0';
            }

            break;

        default:
            if (sRxLength < kRxBufferSize - 1)
            {
                Output(reinterpret_cast<const char *>(aBuf), 1);
                sRxBuffer[sRxLength++] = static_cast<char>(*aBuf);
            }

            break;
        }
    }
}

static otError ProcessCommand(void)
{
    otError error = OT_ERROR_NONE;

    while (sRxBuffer[sRxLength - 1] == '\n' || sRxBuffer[sRxLength - 1] == '\r')
    {
        sRxBuffer[--sRxLength] = '\0';
    }

#if OPENTHREAD_CONFIG_LOG_OUTPUT != OPENTHREAD_CONFIG_LOG_OUTPUT_NONE
    /*
     * Note this is here for this reason:
     *
     * TEXT (command) input ... in a test automation script occurs
     * rapidly and often without gaps between the command and the
     * terminal CR
     *
     * In contrast as a human is typing there is a delay between the
     * last character of a command and the terminal CR which executes
     * a command.
     *
     * During that human induced delay a tasklet may be scheduled and
     * the LOG becomes confusing and it is hard to determine when
     * something happened.  Which happened first? the command-CR or
     * the tasklet.
     *
     * Yes, while rare it is a race condition that is hard to debug.
     *
     * Thus this is here to affirmatively LOG exactly when the CLI
     * command is being executed.
     */
#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
    /* TODO: how exactly do we get the instance here? */
#else
    otLogInfoCli("execute command: %s", sRxBuffer);
#endif
#endif
    if (sRxLength > 0)
    {
        otCliInputLine(sRxBuffer);
    }

    sRxLength = 0;

    return error;
}

static void Send(void)
{
    VerifyOrExit(sSendLength == 0);

    if (sTxLength > kTxBufferSize - sTxHead)
    {
        sSendLength = kTxBufferSize - sTxHead;
    }
    else
    {
        sSendLength = sTxLength;
    }

    if (sSendLength > 0)
    {
#if OPENTHREAD_CONFIG_ENABLE_DEBUG_UART
        /* duplicate the output to the debug uart */
        otSysDebugUart_write_bytes(reinterpret_cast<uint8_t *>(sTxBuffer + sTxHead), sSendLength);
#endif
        IgnoreError(otPlatUartSend(reinterpret_cast<uint8_t *>(sTxBuffer + sTxHead), sSendLength));
    }

exit:
    return;
}

static void SendDoneTask(void)
{
    sTxHead = (sTxHead + sSendLength) % kTxBufferSize;
    sTxLength -= sSendLength;
    sSendLength = 0;

    Send();
}

static int Output(const char *aBuf, uint16_t aBufLength)
{
    OT_CLI_UART_OUTPUT_LOCK();
    uint16_t sent = 0;

    while (aBufLength > 0)
    {
        uint16_t remaining = kTxBufferSize - sTxLength;
        uint16_t tail;
        uint16_t sendLength = aBufLength;

        if (sendLength > remaining)
        {
            sendLength = remaining;
        }

        for (uint16_t i = 0; i < sendLength; i++)
        {
            tail            = (sTxHead + sTxLength) % kTxBufferSize;
            sTxBuffer[tail] = *aBuf++;
            aBufLength--;
            sTxLength++;
        }

        Send();

        sent += sendLength;

        if (aBufLength > 0)
        {
            // More to send, so flush what's waiting now
            otError err = otPlatUartFlush();

            if (err == OT_ERROR_NONE)
            {
                // Flush successful, reset the pointers
                SendDoneTask();
            }
            else
            {
                // Flush did not succeed, so abort here.
                break;
            }
        }
    }

    OT_CLI_UART_OUTPUT_UNLOCK();

    return sent;
}

static int CliUartOutput(void *aContext, const char *aFormat, va_list aArguments)
{
    OT_UNUSED_VARIABLE(aContext);

    int rval;

    if (sTxLength == 0)
    {
        rval = vsnprintf(sTxBuffer, kTxBufferSize, aFormat, aArguments);
        VerifyOrExit(rval > 0 && rval < kTxBufferSize, otLogWarnPlat("Failed to format CLI output `%s`", aFormat));
        sTxHead     = 0;
        sTxLength   = static_cast<uint16_t>(rval);
        sSendLength = 0;
    }
    else
    {
        va_list  retryArguments;
        uint16_t tail      = (sTxHead + sTxLength) % kTxBufferSize;
        uint16_t remaining = (sTxHead > tail ? (sTxHead - tail) : (kTxBufferSize - tail));

        va_copy(retryArguments, aArguments);

        rval = vsnprintf(&sTxBuffer[tail], remaining, aFormat, aArguments);

        if (rval < 0)
        {
            otLogWarnPlat("Failed to format CLI output `%s`", aFormat);
        }
        else if (rval < remaining)
        {
            sTxLength += rval;
        }
        else if (rval < kTxBufferSize)
        {
            while (sTxLength != 0)
            {
                otError error;

                Send();

                error = otPlatUartFlush();

                if (error == OT_ERROR_NONE)
                {
                    // Flush successful, reset the pointers
                    SendDoneTask();
                }
                else
                {
                    // Flush did not succeed, so abort here.
                    otLogWarnPlat("Failed to output CLI: %s", otThreadErrorToString(error));
                    ExitNow();
                }
            }
            rval = vsnprintf(sTxBuffer, kTxBufferSize, aFormat, retryArguments);
            OT_ASSERT(rval > 0);
            sTxLength   = static_cast<uint16_t>(rval);
            sTxHead     = 0;
            sSendLength = 0;
        }
        else
        {
            otLogWarnPlat("CLI output `%s` truncated", aFormat);
        }

        va_end(retryArguments);
    }

    Send();

exit:
    return rval;
}

void otPlatUartReceived(const uint8_t *aBuf, uint16_t aBufLength)
{
    ReceiveTask(aBuf, aBufLength);
}

void otPlatUartSendDone(void)
{
    SendDoneTask();
}

extern "C" void otAppCliInit(otInstance *aInstance)
{
    sRxLength   = 0;
    sTxHead     = 0;
    sTxLength   = 0;
    sSendLength = 0;

    IgnoreError(otPlatUartEnable());

    otCliInit(aInstance, CliUartOutput, aInstance);
}
<commit_msg>[cli] fix false alarm when printing empty line (#6499)<commit_after>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */
#include "openthread-core-config.h"

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include <openthread-system.h>
#include <openthread/cli.h>

#include "cli/cli_config.h"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/logging.hpp"
#include "utils/uart.h"

#if OPENTHREAD_POSIX
#include <signal.h>
#include <sys/types.h>
#endif

/**
 * @def OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE
 *
 * The size of CLI UART RX buffer in bytes.
 *
 */
#ifndef OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
#define OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE 640
#else
#define OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE 512
#endif
#endif

/**
 * @def OPENTHREAD_CONFIG_CLI_TX_BUFFER_SIZE
 *
 * The size of CLI message buffer in bytes.
 *
 */
#ifndef OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE
#define OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE 1024
#endif

#if OPENTHREAD_CONFIG_DIAG_ENABLE
#if OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE > OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE
#error "diag output buffer should be smaller than CLI UART tx buffer"
#endif
#if OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE > OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE
#error "diag command line should be smaller than CLI UART rx buffer"
#endif
#endif

#if OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH > OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE
#error "command line should be should be smaller than CLI rx buffer"
#endif

enum
{
    kRxBufferSize = OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE,
    kTxBufferSize = OPENTHREAD_CONFIG_CLI_UART_TX_BUFFER_SIZE,
};

char     sRxBuffer[kRxBufferSize];
uint16_t sRxLength;

char     sTxBuffer[kTxBufferSize];
uint16_t sTxHead;
uint16_t sTxLength;

uint16_t sSendLength;

#ifdef OT_CLI_UART_LOCK_HDR_FILE

#include OT_CLI_UART_LOCK_HDR_FILE

#else

/**
 * Macro to acquire an exclusive lock of uart cli output
 * Default implementation does nothing
 *
 */
#ifndef OT_CLI_UART_OUTPUT_LOCK
#define OT_CLI_UART_OUTPUT_LOCK() \
    do                            \
    {                             \
    } while (0)
#endif

/**
 * Macro to release the exclusive lock of uart cli output
 * Default implementation does nothing
 *
 */
#ifndef OT_CLI_UART_OUTPUT_UNLOCK
#define OT_CLI_UART_OUTPUT_UNLOCK() \
    do                              \
    {                               \
    } while (0)
#endif

#endif // OT_CLI_UART_LOCK_HDR_FILE

static int     Output(const char *aBuf, uint16_t aBufLength);
static otError ProcessCommand(void);

static void ReceiveTask(const uint8_t *aBuf, uint16_t aBufLength)
{
    static const char sEraseString[]   = {'\b', ' ', '\b'};
    static const char CRNL[]           = {'\r', '\n'};
    static const char sCommandPrompt[] = {'>', ' '};
    const uint8_t *   end;

    end = aBuf + aBufLength;

    for (; aBuf < end; aBuf++)
    {
        switch (*aBuf)
        {
        case '\r':
        case '\n':
            Output(CRNL, sizeof(CRNL));
            if (sRxLength > 0)
            {
                sRxBuffer[sRxLength] = '\0';
                IgnoreError(ProcessCommand());
            }

            Output(sCommandPrompt, sizeof(sCommandPrompt));

            break;

#if OPENTHREAD_POSIX && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
        case 0x03: // ASCII for Ctrl-C
            kill(0, SIGINT);
            break;

        case 0x04: // ASCII for Ctrl-D
            exit(EXIT_SUCCESS);
            break;
#endif

        case '\b':
        case 127:
            if (sRxLength > 0)
            {
                Output(sEraseString, sizeof(sEraseString));
                sRxBuffer[--sRxLength] = '\0';
            }

            break;

        default:
            if (sRxLength < kRxBufferSize - 1)
            {
                Output(reinterpret_cast<const char *>(aBuf), 1);
                sRxBuffer[sRxLength++] = static_cast<char>(*aBuf);
            }

            break;
        }
    }
}

static otError ProcessCommand(void)
{
    otError error = OT_ERROR_NONE;

    while (sRxBuffer[sRxLength - 1] == '\n' || sRxBuffer[sRxLength - 1] == '\r')
    {
        sRxBuffer[--sRxLength] = '\0';
    }

#if OPENTHREAD_CONFIG_LOG_OUTPUT != OPENTHREAD_CONFIG_LOG_OUTPUT_NONE
    /*
     * Note this is here for this reason:
     *
     * TEXT (command) input ... in a test automation script occurs
     * rapidly and often without gaps between the command and the
     * terminal CR
     *
     * In contrast as a human is typing there is a delay between the
     * last character of a command and the terminal CR which executes
     * a command.
     *
     * During that human induced delay a tasklet may be scheduled and
     * the LOG becomes confusing and it is hard to determine when
     * something happened.  Which happened first? the command-CR or
     * the tasklet.
     *
     * Yes, while rare it is a race condition that is hard to debug.
     *
     * Thus this is here to affirmatively LOG exactly when the CLI
     * command is being executed.
     */
#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
    /* TODO: how exactly do we get the instance here? */
#else
    otLogInfoCli("execute command: %s", sRxBuffer);
#endif
#endif
    if (sRxLength > 0)
    {
        otCliInputLine(sRxBuffer);
    }

    sRxLength = 0;

    return error;
}

static void Send(void)
{
    VerifyOrExit(sSendLength == 0);

    if (sTxLength > kTxBufferSize - sTxHead)
    {
        sSendLength = kTxBufferSize - sTxHead;
    }
    else
    {
        sSendLength = sTxLength;
    }

    if (sSendLength > 0)
    {
#if OPENTHREAD_CONFIG_ENABLE_DEBUG_UART
        /* duplicate the output to the debug uart */
        otSysDebugUart_write_bytes(reinterpret_cast<uint8_t *>(sTxBuffer + sTxHead), sSendLength);
#endif
        IgnoreError(otPlatUartSend(reinterpret_cast<uint8_t *>(sTxBuffer + sTxHead), sSendLength));
    }

exit:
    return;
}

static void SendDoneTask(void)
{
    sTxHead = (sTxHead + sSendLength) % kTxBufferSize;
    sTxLength -= sSendLength;
    sSendLength = 0;

    Send();
}

static int Output(const char *aBuf, uint16_t aBufLength)
{
    OT_CLI_UART_OUTPUT_LOCK();
    uint16_t sent = 0;

    while (aBufLength > 0)
    {
        uint16_t remaining = kTxBufferSize - sTxLength;
        uint16_t tail;
        uint16_t sendLength = aBufLength;

        if (sendLength > remaining)
        {
            sendLength = remaining;
        }

        for (uint16_t i = 0; i < sendLength; i++)
        {
            tail            = (sTxHead + sTxLength) % kTxBufferSize;
            sTxBuffer[tail] = *aBuf++;
            aBufLength--;
            sTxLength++;
        }

        Send();

        sent += sendLength;

        if (aBufLength > 0)
        {
            // More to send, so flush what's waiting now
            otError err = otPlatUartFlush();

            if (err == OT_ERROR_NONE)
            {
                // Flush successful, reset the pointers
                SendDoneTask();
            }
            else
            {
                // Flush did not succeed, so abort here.
                break;
            }
        }
    }

    OT_CLI_UART_OUTPUT_UNLOCK();

    return sent;
}

static int CliUartOutput(void *aContext, const char *aFormat, va_list aArguments)
{
    OT_UNUSED_VARIABLE(aContext);

    int rval;

    if (sTxLength == 0)
    {
        rval = vsnprintf(sTxBuffer, kTxBufferSize, aFormat, aArguments);
        VerifyOrExit(rval >= 0 && rval < kTxBufferSize, otLogWarnPlat("Failed to format CLI output `%s`", aFormat));
        sTxHead     = 0;
        sTxLength   = static_cast<uint16_t>(rval);
        sSendLength = 0;
    }
    else
    {
        va_list  retryArguments;
        uint16_t tail      = (sTxHead + sTxLength) % kTxBufferSize;
        uint16_t remaining = (sTxHead > tail ? (sTxHead - tail) : (kTxBufferSize - tail));

        va_copy(retryArguments, aArguments);

        rval = vsnprintf(&sTxBuffer[tail], remaining, aFormat, aArguments);

        if (rval < 0)
        {
            otLogWarnPlat("Failed to format CLI output `%s`", aFormat);
        }
        else if (rval < remaining)
        {
            sTxLength += rval;
        }
        else if (rval < kTxBufferSize)
        {
            while (sTxLength != 0)
            {
                otError error;

                Send();

                error = otPlatUartFlush();

                if (error == OT_ERROR_NONE)
                {
                    // Flush successful, reset the pointers
                    SendDoneTask();
                }
                else
                {
                    // Flush did not succeed, so abort here.
                    otLogWarnPlat("Failed to output CLI: %s", otThreadErrorToString(error));
                    ExitNow();
                }
            }
            rval = vsnprintf(sTxBuffer, kTxBufferSize, aFormat, retryArguments);
            OT_ASSERT(rval > 0);
            sTxLength   = static_cast<uint16_t>(rval);
            sTxHead     = 0;
            sSendLength = 0;
        }
        else
        {
            otLogWarnPlat("CLI output `%s` truncated", aFormat);
        }

        va_end(retryArguments);
    }

    Send();

exit:
    return rval;
}

void otPlatUartReceived(const uint8_t *aBuf, uint16_t aBufLength)
{
    ReceiveTask(aBuf, aBufLength);
}

void otPlatUartSendDone(void)
{
    SendDoneTask();
}

extern "C" void otAppCliInit(otInstance *aInstance)
{
    sRxLength   = 0;
    sTxHead     = 0;
    sTxLength   = 0;
    sSendLength = 0;

    IgnoreError(otPlatUartEnable());

    otCliInit(aInstance, CliUartOutput, aInstance);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "Channel.h"

void worker_thread(Channel<std::string>* data)
{
    while(true){
        auto Channeldata = data->get();
        if(Channeldata == "END"){
            break;
        }
        std::cout << "Worker says: " << Channeldata << std::endl;
    }
    std::cout << "Exiting loop" << std::endl;
}

int main()
{
    Channel<std::string>* myChan = new Channel<std::string>;

    myChan->put("Hello");
    myChan->put("World");

    std::thread worker(worker_thread,myChan);

    while (true){
        std::string input;
        std::cin >> input;
        myChan->put(input);
        if(input == "END"){
            break;
        }
    }

    worker.join();
}<commit_msg>Changed to pass channel by reference<commit_after>#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "Channel.h"

void worker_thread(Channel<std::string>& data)
{
    while(true){
        auto Channeldata = data.get();
        if(Channeldata == "END"){
            break;
        }
        std::cout << "Worker says: " << Channeldata << std::endl;
    }
    std::cout << "Exiting loop" << std::endl;
}

int main()
{
    Channel<std::string> myChan;

    myChan.put("Hello");
    myChan.put("World");

    std::thread worker(worker_thread,std::ref(myChan));

    while (true){
        std::string input;
        std::cin >> input;
        myChan.put(input);
        if(input == "END"){
            break;
        }
    }

    worker.join();
}<|endoftext|>


<commit_before>// Copyright (c) 2011-2015 The Cryptonote developers
// Copyright (c) 2016 The Karbowanec developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <QCoreApplication>
#include <QDateTime>
#include <QDir>
#include <QTimer>
#include <QUrl>

#include <CryptoNoteCore/CoreConfig.h>
#include <P2p/NetNodeConfig.h>
#include <Wallet/WalletErrors.h>

#include "CurrencyAdapter.h"
#include "LoggerAdapter.h"
#include "NodeAdapter.h"
#include "Settings.h"

namespace WalletGui {

namespace {

std::vector<std::string> convertStringListToVector(const QStringList& list) {
  std::vector<std::string> result;
  Q_FOREACH (const QString& item, list) {
    result.push_back(item.toStdString());
  }

  return result;
}

}

class InProcessNodeInitializer : public QObject {
  Q_OBJECT
  Q_DISABLE_COPY(InProcessNodeInitializer)

Q_SIGNALS:
  void nodeInitCompletedSignal();
  void nodeInitFailedSignal(int _errorCode);
  void nodeDeinitCompletedSignal();

public:
  InProcessNodeInitializer(QObject* _parent = nullptr) {
  }

  ~InProcessNodeInitializer() {
  }

  void start(Node** _node, const CryptoNote::Currency* currency,  INodeCallback* _callback, Logging::LoggerManager* _loggerManager,
    const CryptoNote::CoreConfig& _coreConfig, const CryptoNote::NetNodeConfig& _netNodeConfig) {
    (*_node) = createInprocessNode(*currency, *_loggerManager, _coreConfig, _netNodeConfig, *_callback);
    try {
      (*_node)->init([this](std::error_code _err) {
          if (_err) {
            Q_EMIT nodeInitFailedSignal(_err.value());
            QCoreApplication::processEvents();
            return;
          }

          Q_EMIT nodeInitCompletedSignal();
          QCoreApplication::processEvents();
        });
    } catch (std::runtime_error& err) {
      Q_EMIT nodeInitFailedSignal(CryptoNote::error::INTERNAL_WALLET_ERROR);
      QCoreApplication::processEvents();
      return;
    }

    delete *_node;
    *_node = nullptr;
    Q_EMIT nodeDeinitCompletedSignal();
  }

  void stop(Node** _node) {
    Q_CHECK_PTR(*_node);
    (*_node)->deinit();
  }
};

NodeAdapter& NodeAdapter::instance() {
  static NodeAdapter inst;
  return inst;
}

NodeAdapter::NodeAdapter() : QObject(), m_node(nullptr), m_nodeInitializerThread(), m_nodeInitializer(new InProcessNodeInitializer) {
  m_nodeInitializer->moveToThread(&m_nodeInitializerThread);

  qRegisterMetaType<CryptoNote::CoreConfig>("CryptoNote::CoreConfig");
  qRegisterMetaType<CryptoNote::NetNodeConfig>("CryptoNote::NetNodeConfig");

  connect(m_nodeInitializer, &InProcessNodeInitializer::nodeInitCompletedSignal, this, &NodeAdapter::nodeInitCompletedSignal, Qt::QueuedConnection);
  connect(this, &NodeAdapter::initNodeSignal, m_nodeInitializer, &InProcessNodeInitializer::start, Qt::QueuedConnection);
  connect(this, &NodeAdapter::deinitNodeSignal, m_nodeInitializer, &InProcessNodeInitializer::stop, Qt::QueuedConnection);
}

NodeAdapter::~NodeAdapter() {
}

quintptr NodeAdapter::getPeerCount() const {
  Q_ASSERT(m_node != nullptr);
  return m_node->getPeerCount();
}

std::string NodeAdapter::convertPaymentId(const QString& _paymentIdString) const {
  Q_CHECK_PTR(m_node);
  try {
    return m_node->convertPaymentId(_paymentIdString.toStdString());
  } catch (std::runtime_error& err) {
  }
  return std::string();
}

QString NodeAdapter::extractPaymentId(const std::string& _extra) const {
  Q_CHECK_PTR(m_node);
  return QString::fromStdString(m_node->extractPaymentId(_extra));
}

CryptoNote::IWalletLegacy* NodeAdapter::createWallet() const {
  Q_CHECK_PTR(m_node);
  return m_node->createWallet();
}

bool NodeAdapter::init() {
  Q_ASSERT(m_node == nullptr);

  QString connection = Settings::instance().getConnection();

  if(connection.compare("embedded") == 0) {

      m_node = nullptr;
      return initInProcessNode();

  } else if(connection.compare("local") == 0) {
      QUrl localNodeUrl = QUrl::fromUserInput(QString("127.0.0.1:%1").arg(Settings::instance().getCurrentLocalDaemonPort()));
      m_node = createRpcNode(CurrencyAdapter::instance().getCurrency(), *this, localNodeUrl.host().toStdString(), localNodeUrl.port());
      QTimer initTimer;
      initTimer.setInterval(3000);
      initTimer.setSingleShot(true);
      initTimer.start();
          m_node->init([this](std::error_code _err) {
              Q_UNUSED(_err);
            });
      QEventLoop waitLoop;
      connect(&initTimer, &QTimer::timeout, &waitLoop, &QEventLoop::quit);
      connect(this, &NodeAdapter::peerCountUpdatedSignal, &waitLoop, &QEventLoop::quit);
      connect(this, &NodeAdapter::localBlockchainUpdatedSignal, &waitLoop, &QEventLoop::quit);
      waitLoop.exec();
      if (initTimer.isActive()) {
        initTimer.stop();
        Q_EMIT nodeInitCompletedSignal();
        return true;
      }

  } else if(connection.compare("remote") == 0) {
      QUrl remoteNodeUrl = QUrl::fromUserInput(Settings::instance().getCurrentRemoteNode());
      m_node = createRpcNode(CurrencyAdapter::instance().getCurrency(), *this, remoteNodeUrl.host().toStdString(), remoteNodeUrl.port());
      QTimer initTimer;
      initTimer.setInterval(3000);
      initTimer.setSingleShot(true);
      initTimer.start();
      m_node->init([this](std::error_code _err) {
          Q_UNUSED(_err);
        });
      QEventLoop waitLoop;
      connect(&initTimer, &QTimer::timeout, &waitLoop, &QEventLoop::quit);
      connect(this, &NodeAdapter::peerCountUpdatedSignal, &waitLoop, &QEventLoop::quit);
      connect(this, &NodeAdapter::localBlockchainUpdatedSignal, &waitLoop, &QEventLoop::quit);
      waitLoop.exec();
      if (initTimer.isActive()) {
        initTimer.stop();
        Q_EMIT nodeInitCompletedSignal();
        return true;
      }

  } else {
            QUrl localNodeUrl = QUrl::fromUserInput(QString("127.0.0.1:%1").arg(CryptoNote::RPC_DEFAULT_PORT));
            m_node = createRpcNode(CurrencyAdapter::instance().getCurrency(), *this, localNodeUrl.host().toStdString(), localNodeUrl.port());
            QTimer initTimer;
            initTimer.setInterval(3000);
            initTimer.setSingleShot(true);
            initTimer.start();
            m_node->init([this](std::error_code _err) {
                Q_UNUSED(_err);
              });
            QEventLoop waitLoop;
            connect(&initTimer, &QTimer::timeout, &waitLoop, &QEventLoop::quit);
            connect(this, &NodeAdapter::peerCountUpdatedSignal, &waitLoop, &QEventLoop::quit);
            connect(this, &NodeAdapter::localBlockchainUpdatedSignal, &waitLoop, &QEventLoop::quit);
            waitLoop.exec();
            if (initTimer.isActive()) {
              initTimer.stop();
              Q_EMIT nodeInitCompletedSignal();
              return true;
            }
            delete m_node;
            m_node = nullptr;
            return initInProcessNode();
        }

}

quint64 NodeAdapter::getLastKnownBlockHeight() const {
  Q_CHECK_PTR(m_node);
  return m_node->getLastKnownBlockHeight();
}

quint64 NodeAdapter::getLastLocalBlockHeight() const {
  Q_CHECK_PTR(m_node);
  return m_node->getLastLocalBlockHeight();
}

QDateTime NodeAdapter::getLastLocalBlockTimestamp() const {
  Q_CHECK_PTR(m_node);
  return QDateTime::fromTime_t(m_node->getLastLocalBlockTimestamp(), Qt::UTC);
}

void NodeAdapter::peerCountUpdated(Node& _node, size_t _count) {
  Q_UNUSED(_node);
  Q_EMIT peerCountUpdatedSignal(_count);
}

void NodeAdapter::localBlockchainUpdated(Node& _node, uint64_t _height) {
  Q_UNUSED(_node);
  Q_EMIT localBlockchainUpdatedSignal(_height);
}

void NodeAdapter::lastKnownBlockHeightUpdated(Node& _node, uint64_t _height) {
  Q_UNUSED(_node);
  Q_EMIT lastKnownBlockHeightUpdatedSignal(_height);
}

bool NodeAdapter::initInProcessNode() {
  Q_ASSERT(m_node == nullptr);
  m_nodeInitializerThread.start();
  CryptoNote::CoreConfig coreConfig = makeCoreConfig();
  CryptoNote::NetNodeConfig netNodeConfig = makeNetNodeConfig();
  Q_EMIT initNodeSignal(&m_node, &CurrencyAdapter::instance().getCurrency(), this, &LoggerAdapter::instance().getLoggerManager(), coreConfig, netNodeConfig);
  QEventLoop waitLoop;
  connect(m_nodeInitializer, &InProcessNodeInitializer::nodeInitCompletedSignal, &waitLoop, &QEventLoop::quit);
  connect(m_nodeInitializer, &InProcessNodeInitializer::nodeInitFailedSignal, &waitLoop, &QEventLoop::exit);
  if (waitLoop.exec() != 0) {
    return false;
  }

  Q_EMIT localBlockchainUpdatedSignal(getLastLocalBlockHeight());
  Q_EMIT lastKnownBlockHeightUpdatedSignal(getLastKnownBlockHeight());
  return true;
}

void NodeAdapter::deinit() {
  if (m_node != nullptr) {
    if (m_nodeInitializerThread.isRunning()) {
      m_nodeInitializer->stop(&m_node);
      QEventLoop waitLoop;
      connect(m_nodeInitializer, &InProcessNodeInitializer::nodeDeinitCompletedSignal, &waitLoop, &QEventLoop::quit, Qt::QueuedConnection);
      waitLoop.exec();
      m_nodeInitializerThread.quit();
      m_nodeInitializerThread.wait();
    } else {
      delete m_node;
      m_node = nullptr;
    }
  }
}

CryptoNote::CoreConfig NodeAdapter::makeCoreConfig() const {
  CryptoNote::CoreConfig config;
  boost::program_options::variables_map options;
  boost::any dataDir = std::string(Settings::instance().getDataDir().absolutePath().toLocal8Bit().data());
  options.insert(std::make_pair("data-dir", boost::program_options::variable_value(dataDir, false)));
  config.init(options);
  return config;
}

CryptoNote::NetNodeConfig NodeAdapter::makeNetNodeConfig() const {
  CryptoNote::NetNodeConfig config;
  boost::program_options::variables_map options;
  boost::any p2pBindIp = Settings::instance().getP2pBindIp().toStdString();
  boost::any p2pBindPort = static_cast<uint16_t>(Settings::instance().getP2pBindPort());
  boost::any p2pExternalPort = static_cast<uint16_t>(Settings::instance().getP2pExternalPort());
  boost::any p2pAllowLocalIp = Settings::instance().hasAllowLocalIpOption();
  boost::any dataDir = std::string(Settings::instance().getDataDir().absolutePath().toLocal8Bit().data());
  boost::any hideMyPort = Settings::instance().hasHideMyPortOption();
  options.insert(std::make_pair("p2p-bind-ip", boost::program_options::variable_value(p2pBindIp, false)));
  options.insert(std::make_pair("p2p-bind-port", boost::program_options::variable_value(p2pBindPort, false)));
  options.insert(std::make_pair("p2p-external-port", boost::program_options::variable_value(p2pExternalPort, false)));
  options.insert(std::make_pair("allow-local-ip", boost::program_options::variable_value(p2pAllowLocalIp, false)));
  std::vector<std::string> peerList = convertStringListToVector(Settings::instance().getPeers());
  if (!peerList.empty()) {
    options.insert(std::make_pair("add-peer", boost::program_options::variable_value(peerList, false)));
  }

  std::vector<std::string> priorityNodeList = convertStringListToVector(Settings::instance().getPriorityNodes());
  if (!priorityNodeList.empty()) {
    options.insert(std::make_pair("add-priority-node", boost::program_options::variable_value(priorityNodeList, false)));
  }

  std::vector<std::string> exclusiveNodeList = convertStringListToVector(Settings::instance().getExclusiveNodes());
  if (!exclusiveNodeList.empty()) {
    options.insert(std::make_pair("add-exclusive-node", boost::program_options::variable_value(exclusiveNodeList, false)));
  }

  std::vector<std::string> seedNodeList = convertStringListToVector(Settings::instance().getSeedNodes());
  if (!seedNodeList.empty()) {
    options.insert(std::make_pair("seed-node", boost::program_options::variable_value(seedNodeList, false)));
  }

  options.insert(std::make_pair("hide-my-port", boost::program_options::variable_value(hideMyPort, false)));
  options.insert(std::make_pair("data-dir", boost::program_options::variable_value(dataDir, false)));
  int size = options.size();
  config.init(options);
  config.setTestnet(Settings::instance().isTestnet());
  return config;
}

}

#include "NodeAdapter.moc"
<commit_msg>Delete NodeAdapter.cpp<commit_after><|endoftext|>