Ejemplo n.º 1
0
void Newton::calcJacobian()
{
  // Use analytic Jacobian if available
  matrix_t A = _algLoop->getSystemMatrix();
  if (A.size1() == _dimSys && A.size2() == _dimSys) {
    const double* jac = A.data().begin();
    std::copy(jac, jac + _dimSys*_dimSys, _jac);
    return;
  }

  // Alternatively apply finite differences
  for (int j = 0; j < _dimSys; ++j) {
    // Reset variables for every column
    std::copy(_y, _y + _dimSys, _yHelp);
    double stepsize = 1e-6 * _yNominal[j];

    // Finite differences
    _yHelp[j] += stepsize;

    calcFunction(_yHelp, _fHelp);

    // Build Jacobian in Fortran format
    for (int i = 0; i < _dimSys; ++i)
      _jac[i + j * _dimSys] = (_fHelp[i] - _f[i]) / stepsize;

    _yHelp[j] -= stepsize;
  }
}
Ejemplo n.º 2
0
void RTEuler::doRK1()
{

  calcFunction(_tCurrent, _z, _f);

  for(int i = 0; i < _dimSys; ++i)
    _z[i] += _h * _f[i];
}
Ejemplo n.º 3
0
double GoldenSectionTwo::getMinimum( double val2 )
{
   double x, y=dat2.a, Fxy, Fay, Fxa;

   nOperand = 1;

   do{
     x = getMinimumDat( dat1, y );
     Fxy = calcFunction( x, y );
     if( fabs(Fxy)< Ftol )
         goto DONE;

     nOperand = 2;
     y = getMinimumDat( dat2, x );
     Fxy = calcFunction( y, x );
     if( fabs(Fxy)< Ftol )
        goto DONE;

     nOperand = 1;   // must be tested??????
     Fay = calcFunction( dat1.a, y );
     if( Fay*Fxy > 0)
        dat1.a = x;
     else
        dat1.b = x;

     Fxa = calcFunction( x, dat2.a );
     if( Fxa*Fxy > 0)
        dat2.a = y;
     else
        dat2.b = y;
  }
  while( (dat1.b-dat1.a) > dat1.Xtol || (dat2.b-dat2.a) > dat2.Xtol );

   x = (dat1.a+dat1.b)/2;
   y = (dat2.a+dat2.b)/2;

  DONE:

   nOperand = 1;
   minX = x;
   minY = y;

   return x;
}
Ejemplo n.º 4
0
void Hybrj::calcJacobian(double *fjac)
{
	for(int j=0; j<_dimSys; ++j)
	{
		// Reset variables for every column
		memcpy(_xHelp,_x,_dimSys*sizeof(double));

		// Finite difference
		double delta =sqrt(UROUND*std::max(1e-5,std::abs(_x[j])));
		_xHelp[j] +=delta;

		calcFunction(_xHelp,_fHelp);

		// Build Jacobian in Fortran format
		for(int i=0; i<_dimSys; ++i)
			fjac[i+j*_dimSys] = (_fHelp[i] - _f[i]) /delta;
	}

}
Ejemplo n.º 5
0
void Newton::calcJacobian()
{
	for(int j=0; j<_dimSys; ++j)
	{
		// Reset variables for every column
		memcpy(_yHelp,_y,_dimSys*sizeof(double));
		double stepsize=1.e-6;//+(1.e-6*_yHelp[j]);


		// Finitializee difference
		_yHelp[j] += stepsize;

		calcFunction(_yHelp,_fHelp);

		// Build Jacobian in Fortran format
		for(int i=0; i<_dimSys; ++i)
			_jac[i+j*_dimSys] = (_fHelp[i] - _f[i]) / stepsize;

		_yHelp[j] -=stepsize;
	}
}
Ejemplo n.º 6
0
int Ida::calcJacobian(double t, long int N, N_Vector fHelp, N_Vector errorWeight, N_Vector jthCol, double* y, N_Vector fy, DlsMat Jac)
{
  try
  {
  int l,g;
  double fnorm, minInc, *f_data, *fHelp_data, *errorWeight_data, h, srur, delta_inv;

  f_data = NV_DATA_S(fy);
  errorWeight_data = NV_DATA_S(errorWeight);
  fHelp_data = NV_DATA_S(fHelp);


  //Get relevant info
  _idid = IDAGetErrWeights(_idaMem, errorWeight);
  if (_idid < 0)
    {
      _idid = -5;
      throw std::invalid_argument("IDA::calcJacobian()");
  }
  _idid = IDAGetCurrentStep(_idaMem, &h);
  if (_idid < 0)
    {
      _idid = -5;
      throw std::invalid_argument("IDA::calcJacobian()");
  }

  srur = sqrt(UROUND);

  fnorm = N_VWrmsNorm(fy, errorWeight);
  minInc = (fnorm != 0.0) ?
           (1000.0 * abs(h) * UROUND * N * fnorm) : 1.0;

  for(int j=0;j<N;j++)
  {
    _delta[j] = max(srur*abs(y[j]), minInc/errorWeight_data[j]);
  }
    for(int j=0;j<N;j++)
  {
    _deltaInv[j] = 1/_delta[j];
  }

  // Calculation of the jacobian

 if (_jacobianANonzeros != 0)
 {
  for(int color=1; color <= _maxColors; color++)
  {
      for(int k=0; k < _dimSys; k++)
    {
      if((_colorOfColumn[k] ) == color)
      {
        _ysave[k] = y[k];
        y[k]+= _delta[k];
      }
    }

    calcFunction(t, y, fHelp_data,fHelp_data);

  for (int k = 0; k < _dimSys; k++)
   {
       if((_colorOfColumn[k]) == color)
     {
        y[k] = _ysave[k];

    int startOfColumn = k * _dimSys;
    for (int j = _jacobianALeadindex[k]; j < _jacobianALeadindex[k+1];j++)
      {
        l = _jacobianAIndex[j];
        g = l + startOfColumn;
        Jac->data[g] = (fHelp_data[l] - f_data[l]) * _deltaInv[k];
      }
    }
  }
  }
 }

  /*
  //Calculation of J without colouring
   for (j = 0; j < N; j++)
   {


    //N_VSetArrayPointer(DENSE_COL(Jac,j), jthCol);

     _ysave[j] = y[j];

    y[j] += _delta[j];

    calcFunction(t, y, fHelp_data);

    y[j] = _ysave[j];

    delta_inv = 1.0/_delta[j];
    N_VLinearSum(delta_inv, fHelp, -delta_inv, fy, jthCol);

    for(int i=0; i<_dimSys; ++i)
        {
            Jac->data[i+j*_dimSys] = NV_Ith_S(jthCol,i);
        }

    //DENSE_COL(Jac,j) = N_VGetArrayPointer(jthCol);
  }
  */

 }      //workaround until exception can be catch from c- libraries
  catch (std::exception& ex)
  {
    std::string error = ex.what();
    cerr << "IDA integration error: " << error;
    return 1;
  }


  return 0;
}
Ejemplo n.º 7
0
void Ida::IDACore()
{
  _idid = IDAReInit(_idaMem, _tCurrent, _CV_y,_CV_yp);
  _idid = IDASetStopTime(_idaMem, _tEnd);
  _idid = IDASetInitStep(_idaMem, 1e-12);
  if (_idid < 0)
    throw std::runtime_error("IDA::ReInit");

  bool writeEventOutput = (_settings->getGlobalSettings()->getOutputPointType() == OPT_ALL);
  bool writeOutput = !(_settings->getGlobalSettings()->getOutputPointType() == OPT_NONE);

  while ((_solverStatus & ISolver::CONTINUE) && !_interrupt )
  {
    _cv_rt = IDASolve(_idaMem, _tEnd, &_tCurrent,  _CV_y, _CV_yp, IDA_ONE_STEP);

    _idid = IDAGetNumSteps(_idaMem, &_locStps);
    if (_idid != IDA_SUCCESS)
      throw std::runtime_error("IDAGetNumSteps failed. The ida mem pointer is NULL");

    _idid =IDAGetLastStep(_idaMem, &_h);
    if (_idid != IDA_SUCCESS)
      throw std::runtime_error("IDAGetLastStep failed. The ida mem pointer is NULL");

    //Check if there was at least one output-point within the last solver interval
    //  -> Write output if true
    if (writeOutput)
    {
        writeIDAOutput(_tCurrent, _h, _locStps);
    }

    #ifdef RUNTIME_PROFILING
    MEASURETIME_REGION_DEFINE(idaStepCompletedHandler, "IDAStepCompleted");
    if(MeasureTime::getInstance() != NULL)
    {
        MEASURETIME_START(measuredFunctionStartValues, idaStepCompletedHandler, "IDAStepCompleted");
    }
    #endif

    //set completed step to system and check if terminate was called
    if(_continuous_system->stepCompleted(_tCurrent))
        _solverStatus = DONE;

    #ifdef RUNTIME_PROFILING
    if(MeasureTime::getInstance() != NULL)
    {
        MEASURETIME_END(measuredFunctionStartValues, measuredFunctionEndValues, (*measureTimeFunctionsArray)[5], idaStepCompletedHandler);
    }
    #endif

    // Perform state selection
    bool state_selection = stateSelection();
    if (state_selection)
      _continuous_system->getContinuousStates(_y);

    _zeroFound = false;

    // Check if step was successful
    if (check_flag(&_cv_rt, "IDA", 1))
    {
      _solverStatus = ISolver::SOLVERERROR;
      break;
    }

    // A root was found
    if ((_cv_rt == IDA_ROOT_RETURN) && !isInterrupted())
    {
      // IDA is setting _tCurrent to the time where the first event occurred
      double _abs = fabs(_tLastEvent - _tCurrent);
      _zeroFound = true;

      if ((_abs < 1e-3) && _event_n == 0)
      {
        _tLastEvent = _tCurrent;
        _event_n++;
      }
      else if ((_abs < 1e-3) && (_event_n >= 1 && _event_n < 500))
      {
        _event_n++;
      }
      else if ((_abs >= 1e-3))
      {
        //restart event counter
        _tLastEvent = _tCurrent;
        _event_n = 0;
      }
      else
        throw std::runtime_error("Number of events exceeded  in time interval " + to_string(_abs) + " at time " + to_string(_tCurrent));

      // IDA has interpolated the states at time 'tCurrent'
      _time_system->setTime(_tCurrent);

      // To get steep steps in the result file, two value points (P1 and P2) must be added
      //
      // Y |   (P2) X...........
      //   |        :
      //   |        :
      //   |........X (P1)
      //   |---------------------------------->
      //   |        ^                         t
      //        _tCurrent

      // Write the values of (P1)
      if (writeEventOutput)
      {
		if(_dimAE>0)
		{
			 _continuous_system->evaluateDAE(IContinuous::CONTINUOUS);
        }
		else
		{
		    _continuous_system->evaluateAll(IContinuous::CONTINUOUS);
		}
        writeToFile(0, _tCurrent, _h);
      }

      _idid = IDAGetRootInfo(_idaMem, _zeroSign);

      for (int i = 0; i < _dimZeroFunc; i++)
        _events[i] = bool(_zeroSign[i]);

      if (_mixed_system->handleSystemEvents(_events))
      {
        // State variables were reinitialized, thus we have to give these values to the ida-solver
        // Take care about the memory regions, _z is the same like _CV_y
        _continuous_system->getContinuousStates(_y);
        if(_dimAE>0)
		{
           _mixed_system->getAlgebraicDAEVars(_y+_dimStates);
		   _continuous_system->getRHS(_yp);
		}
		calcFunction(_tCurrent, NV_DATA_S(_CV_y), NV_DATA_S(_CV_yp),_dae_res);

      }
    }

    if ((_zeroFound || state_selection)&& !isInterrupted())
    {
      // Write the values of (P2)
      if (writeEventOutput)
      {
        // If we want to write the event-results, we should evaluate the whole system again
        if(_dimAE>0)
		{
			 _continuous_system->evaluateDAE(IContinuous::CONTINUOUS);
        }
		else
		{
		    _continuous_system->evaluateAll(IContinuous::CONTINUOUS);
		}
        writeToFile(0, _tCurrent, _h);
      }

      _idid = IDAReInit(_idaMem, _tCurrent, _CV_y,_CV_yp);
      if (_idid < 0)
        throw std::runtime_error("IDA::ReInit()");

      // Der Eventzeitpunkt kann auf der Endzeit liegen (Time-Events). In diesem Fall wird der Solver beendet, da IDA sonst eine interne Warnung schmeißt
      if (_tCurrent == _tEnd)
        _cv_rt = IDA_TSTOP_RETURN;
    }

    // Zähler für die Anzahl der ausgegebenen Schritte erhöhen
    ++_outStps;
    _tLastSuccess = _tCurrent;

    if (_cv_rt == IDA_TSTOP_RETURN)
    {
      _time_system->setTime(_tEnd);
      _continuous_system->setContinuousStates(NV_DATA_S(_CV_y));
	  if(_dimAE>0)
	  {
	    _mixed_system->setAlgebraicDAEVars(NV_DATA_S(_CV_y)+_dimStates);
	    _continuous_system->setStateDerivatives(NV_DATA_S(_CV_yp));
		_continuous_system->evaluateDAE(IContinuous::CONTINUOUS);
      }
	  else
	  {
		_continuous_system->evaluateAll(IContinuous::CONTINUOUS);
      }
      if(writeOutput)
         writeToFile(0, _tEnd, _h);

      _accStps += _locStps;
      _solverStatus = DONE;
    }
  }
}
Ejemplo n.º 8
0
/// Method of Golden Section 1D and 2D (reimplemented)
///   xstart, xend, xtol,  parameter x    - start, end, tolerance
///   ftol  function tolerance
///   f_proc function to minimize ( f(x)=>0 )
double GoldenSection::getMinimumDat( GoldenSectionData dat,  double val2 )
{
    if( (dat.b-dat.a) < dat.Xtol)
        goto DONE;
    dat.Fa = calcFunction( dat.a,  val2);
    if( fabs(dat.Fa) < Ftol )
    {
        dat.b = dat.a;
        goto DONE;
    }
    dat.Fb = calcFunction( dat.b, val2);
    if(  fabs(dat.Fb) < Ftol )
    {
        dat.a = dat.b;
        goto DONE;
    }
    if( (dat.Fa*dat.Fb) > 0)
        Error( "GoldenSection",
  "W01PEexec: No result in specified interval! Change interval!");
    dat.x1 = dat.a + .382*(dat.b-dat.a);
    dat.x2 = dat.a + .618*(dat.b-dat.a);
    dat.Fx1 = calcFunction( dat.x1, val2 );
    dat.Fx2 = calcFunction( dat.x2, val2 );
    do
    {
        if( fabs( dat.Fx1 ) < Ftol )
        {
            dat.a = dat.b = dat.x1;
            goto DONE;
        }
        if( fabs( dat.Fx2 ) < Ftol )
        {
            dat.a = dat.b =dat. x2;
            goto DONE;
        }
        if( fabs( dat.Fx1) > fabs( dat.Fx2) )
        {
            dat.a = dat.x1;
            if( (dat.b-dat.a) < dat.Xtol)
                goto DONE;
            dat.x1 = dat.x2;
            dat.Fx1 = dat.Fx2;
            dat.x2 = dat.a + .618*(dat.b-dat.a);
            dat.Fx2 = calcFunction( dat.x2, val2);
        }
        else
        {
            dat.b = dat.x2;
            if( (dat.b-dat.a) < dat.Xtol)
                goto DONE;
            dat.x2 = dat.x1;
            dat.Fx2 = dat.Fx1;
            dat.x1 = dat.a + .382*(dat.b-dat.a);
            dat.Fx1 = calcFunction( dat.x1, val2);
        }
    }
    while( (dat.b-dat.a) > dat.Xtol );
DONE:
    dat.x1 = (dat.a+dat.b)/2;
    return dat.x1;
}
Ejemplo n.º 9
0
void Ida::initialize()
{
  _properties = dynamic_cast<ISystemProperties*>(_system);
  _continuous_system = dynamic_cast<IContinuous*>(_system);
  _event_system = dynamic_cast<IEvent*>(_system);
  _mixed_system = dynamic_cast<IMixedSystem*>(_system);
  _time_system = dynamic_cast<ITime*>(_system);
  IGlobalSettings* global_settings = dynamic_cast<ISolverSettings*>(_idasettings)->getGlobalSettings();
  // Kennzeichnung, dass initialize()() (vor der Integration) aufgerufen wurde
  _idid = 5000;
  _tLastEvent = 0.0;
  _event_n = 0;
  SolverDefaultImplementation::initialize();
  _dimSys = _continuous_system->getDimContinuousStates();
  _dimZeroFunc = _event_system->getDimZeroFunc();

  if (_dimSys <= 0)
  {
    _idid = -1;
    throw std::invalid_argument("Ida::initialize()");
  }
  else
  {
    // Allocate state vectors, stages and temporary arrays
    if (_z)
      delete[] _z;
    if (_zInit)
      delete[] _zInit;
    if (_zWrite)
      delete[] _zWrite;
    if (_zeroSign)
      delete[] _zeroSign;
    if (_absTol)
      delete[] _absTol;
  if(_delta)
    delete [] _delta;
    if(_deltaInv)
    delete [] _deltaInv;
    if(_ysave)
    delete [] _ysave;

    _z = new double[_dimSys];
    _zInit = new double[_dimSys];
    _zWrite = new double[_dimSys];
    _zeroSign = new int[_dimZeroFunc];
    _absTol = new double[_dimSys];
    _delta =new double[_dimSys];
    _deltaInv =new double[_dimSys];
    _ysave =new double[_dimSys];

    memset(_z, 0, _dimSys * sizeof(double));
    memset(_zInit, 0, _dimSys * sizeof(double));
  memset(_ysave, 0, _dimSys * sizeof(double));

    // Counter initialisieren
    _outStps = 0;

    if (_idasettings->getDenseOutput())
    {
      // Ausgabeschrittweite
      _hOut = global_settings->gethOutput();

    }

    // Allocate memory for the solver
    _idaMem = IDACreate();
    if (check_flag((void*) _idaMem, "IDACreate", 0))
    {
      _idid = -5;
      throw std::invalid_argument(/*_idid,_tCurrent,*/"Ida::initialize()");
    }

    //
    // Make Ida ready for integration
    //

    // Set initial values for IDA
    _continuous_system->evaluateAll(IContinuous::CONTINUOUS);
    _continuous_system->getContinuousStates(_zInit);
    memcpy(_z, _zInit, _dimSys * sizeof(double));

    // Get nominal values
    _continuous_system->getNominalStates(_absTol);
    for (int i = 0; i < _dimSys; i++)
      _absTol[i] *= dynamic_cast<ISolverSettings*>(_idasettings)->getATol();

    _CV_y0 = N_VMake_Serial(_dimSys, _zInit);
    _CV_y = N_VMake_Serial(_dimSys, _z);
    _CV_yp = N_VNew_Serial(_dimSys);
    _CV_yWrite = N_VMake_Serial(_dimSys, _zWrite);
    _CV_absTol = N_VMake_Serial(_dimSys, _absTol);

    if (check_flag((void*) _CV_y0, "N_VMake_Serial", 0))
    {
      _idid = -5;
      throw std::invalid_argument("Ida::initialize()");
    }
    calcFunction(_tCurrent, NV_DATA_S(_CV_y0), NV_DATA_S(_CV_yp));
    // Initialize Ida (Initial values are required)
    _idid = IDAInit(_idaMem, CV_fCallback, _tCurrent, _CV_y0, _CV_yp);
    if (_idid < 0)
    {
      _idid = -5;
      throw std::invalid_argument("Ida::initialize()");
    }

    // Set Tolerances
    _idid = IDASVtolerances(_idaMem, dynamic_cast<ISolverSettings*>(_idasettings)->getRTol(), _CV_absTol);    // RTOL and ATOL
    if (_idid < 0)
      throw std::invalid_argument("IDA::initialize()");

    // Set the pointer to user-defined data
    _idid = IDASetUserData(_idaMem, _data);
    if (_idid < 0)
      throw std::invalid_argument("IDA::initialize()");

    _idid = IDASetInitStep(_idaMem, 1e-6);    // INITIAL STEPSIZE
    if (_idid < 0)
      throw std::invalid_argument("Ida::initialize()");


    _idid = IDASetMaxStep(_idaMem, global_settings->getEndTime() / 10.0);       // MAXIMUM STEPSIZE
    if (_idid < 0)
      throw std::invalid_argument("IDA::initialize()");

    _idid = IDASetMaxNonlinIters(_idaMem, 5);      // Max number of iterations
    if (_idid < 0)
      throw std::invalid_argument("IDA::initialize()");
    _idid = IDASetMaxErrTestFails(_idaMem, 100);
    if (_idid < 0)
      throw std::invalid_argument("IDA::initialize()");

    _idid = IDASetMaxNumSteps(_idaMem, 1e3);            // Max Number of steps
    if (_idid < 0)
      throw std::invalid_argument(/*_idid,_tCurrent,*/"IDA::initialize()");

    // Initialize linear solver
  _idid = IDADense(_idaMem, _dimSys);
    if (_idid < 0)
      throw std::invalid_argument("IDA::initialize()");

  // Use own jacobian matrix
  //_idid = CVDlsSetDenseJacFn(_idaMem, &CV_JCallback);
  //if (_idid < 0)
  //    throw std::invalid_argument("IDA::initialize()");

    if (_dimZeroFunc)
    {
      _idid = IDARootInit(_idaMem, _dimZeroFunc, &CV_ZerofCallback);

      memset(_zeroSign, 0, _dimZeroFunc * sizeof(int));
      _idid = IDASetRootDirection(_idaMem, _zeroSign);
      if (_idid < 0)
        throw std::invalid_argument(/*_idid,_tCurrent,*/"IDA::initialize()");
      memset(_zeroSign, -1, _dimZeroFunc * sizeof(int));
      memset(_zeroVal, -1, _dimZeroFunc * sizeof(int));

    }

    initializeColoredJac();
    _ida_initialized = true;

    //
    // IDA is ready for integration
    //
    // BOOST_LOG_SEV(ida_lg::get(), ida_info) << "IDA initialized";
  }
}
Ejemplo n.º 10
0
void Newton::solve()
{
  long int
    dimRHS   = 1,        // Dimension of right hand side of linear system (=b)
    info     = 0;        // Retrun-flag of Fortran code
  int
    totSteps = 0;        // Total number of steps taken
  double
    atol = _newtonSettings->getAtol(),
    rtol = _newtonSettings->getRtol();

  // If initialize() was not called yet
  if (_firstCall)
    initialize();

  // Get current values and residuals from system
  _algLoop->getReal(_y);
  _algLoop->evaluate();
  _algLoop->getRHS(_f);

  // Reset status flag
  _iterationStatus = CONTINUE;

  while (_iterationStatus == CONTINUE) {
    // Check stopping criterion
    if (!_algLoop->isLinear()) {
      _iterationStatus = DONE;
      for (int i = 0; i < _dimSys; ++i) {
        if (std::abs(_f[i]) > atol + rtol * std::abs(_y[i])) {
          _iterationStatus = CONTINUE;
          break;
        }
      }
    }
    if (_iterationStatus == CONTINUE) {
      if (totSteps < _newtonSettings->getNewtMax()) {
        // Determination of Jacobian (Fortran-format)
        if (_algLoop->isLinear() && !_algLoop->isLinearTearing()) {
          const matrix_t& A = _algLoop->getSystemMatrix();
          const double* jac = A.data().begin();
          std::copy(jac, jac + _dimSys*_dimSys, _jac);
          dgesv_(&_dimSys, &dimRHS, _jac, &_dimSys, _iHelp, _f, &_dimSys, &info);
          std::copy(_f, _f + _dimSys, _y);
          _algLoop->setReal(_y);
          if (info != 0)
            throw ModelicaSimulationError(ALGLOOP_SOLVER,
              "error solving linear system (dgesv info: " + to_string(info) + ")");
          else
            _iterationStatus = DONE;
        }
        else if (_algLoop->isLinearTearing()) {
          _algLoop->setReal(_zeroVec);
          _algLoop->evaluate();
          _algLoop->getRHS(_f);

          const matrix_t& A_sparse = _algLoop->getSystemMatrix();
          //m_t A_dense(A_sparse);
          const double* jac = A_sparse.data().begin();
          std::copy(jac, jac + _dimSys*_dimSys, _jac);
          dgesv_(&_dimSys, &dimRHS, _jac, &_dimSys, _iHelp, _f, &_dimSys, &info);
          for (int i = 0; i < _dimSys; i++)
            _y[i] = -_f[i];
          _algLoop->setReal(_y);
          _algLoop->evaluate();
          if (info != 0)
            throw ModelicaSimulationError(ALGLOOP_SOLVER,
              "error solving linear tearing system (dgesv info: " + to_string(info) + ")");
          else
            _iterationStatus = DONE;
        }
        else {
          LogSysVec(_algLoop, "y" + to_string(totSteps), _y);
          LogSysVec(_algLoop, "f" + to_string(totSteps), _f);
          double phi = 0.0; // line search function
          for (int i = 0; i < _dimSys; ++i) {
            phi += _f[i] * _f[i];
          }
          calcJacobian();

          // Solve linear System
          dgesv_(&_dimSys, &dimRHS, _jac, &_dimSys, _iHelp, _f, &_dimSys, &info);

          if (info != 0)
            throw ModelicaSimulationError(ALGLOOP_SOLVER,
              "error solving nonlinear system (iteration: " + to_string(totSteps)
              + ", dgesv info: " + to_string(info) + ")");

          // Increase counter
          ++ totSteps;

          // New iterate
          double lambda = 1.0; // step size
          double alpha = 1e-4; // guard for sufficient decrease
          // first find a feasible step
          while (true) {
            for (int i = 0; i < _dimSys; i++) {
              _yHelp[i] = _y[i] - lambda * _f[i];
              _yHelp[i] = std::min(_yMax[i], std::max(_yMin[i], _yHelp[i]));
            }
            // evaluate function
            try {
              calcFunction(_yHelp, _fHelp);
            }
            catch (ModelicaSimulationError& ex) {
              if (lambda < 1e-10)
                throw ex;
              // reduce step size
              lambda *= 0.5;
              continue;
            }
            break;
          }
          // check for solution, e.g. if a linear system is treated here
          _iterationStatus = DONE;
          for (int i = 0; i < _dimSys; i++) {
            if (std::abs(_fHelp[i]) > atol + rtol * std::abs(_yHelp[i])) {
              _iterationStatus = CONTINUE;
              break;
            }
          }
          // second do line search with quadratic approximation of phi(lambda)
          // C.T.Kelley: Solving Nonlinear Equations with Newton's Method,
          // no 1 in Fundamentals of Algorithms, SIAM 2003. ISBN 0-89871-546-6.
          double phiHelp = 0.0;
          for (int i = 0; i < _dimSys; i++)
            phiHelp += _fHelp[i] * _fHelp[i];
          while (_iterationStatus == CONTINUE) {
            // test half step that also serves as max bound for step reduction
            double lambdaTest = 0.5*lambda;
            for (int i = 0; i < _dimSys; i++) {
              _yTest[i] = _y[i] - lambdaTest * _f[i];
              _yTest[i] = std::min(_yMax[i], std::max(_yMin[i], _yTest[i]));
            }
            calcFunction(_yTest, _fTest);
            double phiTest = 0.0;
            for (int i = 0; i < _dimSys; i++)
              phiTest += _fTest[i] * _fTest[i];
            // check for sufficient decrease of phiHelp
            // and no further decrease with phiTest
            // otherwise minimize quadratic approximation of phi(lambda)
            if (phiHelp > (1.0 - alpha * lambda) * phi ||
                phiTest < (1.0 - alpha * lambda) * phiHelp) {
              long int n = 3;
              long int ipiv[3];
              double bx[] = {phi, phiTest, phiHelp};
              double A[] = {1.0, 1.0, 1.0,
                            0.0, lambdaTest, lambda,
                            0.0, lambdaTest*lambdaTest, lambda*lambda};
              dgesv_(&n, &dimRHS, A, &n, ipiv, bx, &n, &info);
              lambda = std::max(0.1*lambda, -0.5*bx[1]/bx[2]);
              if (!(lambda >= 1e-10))
                throw ModelicaSimulationError(ALGLOOP_SOLVER,
                  "Can't get sufficient decrease of solution");
              if (lambda >= lambdaTest) {
                // upper bound 0.5*lambda
                lambda = lambdaTest;
                std::copy(_yTest, _yTest + _dimSys, _yHelp);
                std::copy(_fTest, _fTest + _dimSys, _fHelp);
                phiHelp = phiTest;
              }
              else {
                for (int i = 0; i < _dimSys; i++) {
                  _yHelp[i] = _y[i] - lambda * _f[i];
                  _yHelp[i] = std::min(_yMax[i], std::max(_yMin[i], _yHelp[i]));
                }
                calcFunction(_yHelp, _fHelp);
                phiHelp = 0.0;
                for (int i = 0; i < _dimSys; i++) {
                  phiHelp += _fHelp[i] * _fHelp[i];
                }
              }
              if (Logger::getInstance()->isOutput(LC_NLS, LL_DEBUG)) {
                std::stringstream ss;
                ss << "Newton: eq" << to_string(_algLoop->getEquationIndex());
                ss << ", time " << _algLoop->getSimTime();
                ss << ": lambda = " << lambda;
                ss << ", phi = " << phi << " --> " << phiHelp;
                Logger::write(ss.str(), LC_NLS, LL_DEBUG);
              }
            }
            // check for sufficient decrease
            if (phiHelp <= (1.0 - alpha * lambda) * phi)
              break;
          }
          // take iterate
          std::copy(_yHelp, _yHelp + _dimSys, _y);
          std::copy(_fHelp, _fHelp + _dimSys, _f);
          phi = phiHelp;
        }
      }
      else
        throw ModelicaSimulationError(ALGLOOP_SOLVER,
          "error solving nonlinear system (iteration limit: " + to_string(totSteps) + ")");
    }
  }
  LogSysVec(_algLoop, "y*", _y);
}
Ejemplo n.º 11
0
void Newton::solve()
{
	long int
		dimRHS    = 1,                    // Dimension of right hand side of linear system (=b)
		irtrn    = 0;                    // Retrun-flag of Fortran code

	int
		totStps    = 0;                    // Total number of steps

	// If initialize() was not called yet
	if (_firstCall)
		initialize();

	// Get initializeial values from system
	_algLoop->getReal(_y);
	//_algLoop->evaluate(command);
	_algLoop->getRHS(_f);


	// Reset status flag
	_iterationStatus = CONTINUE;

	while(_iterationStatus == CONTINUE)
	{
		_iterationStatus = DONE;
		// Check stopping criterion
		calcFunction(_y,_f);
		if(totStps)
		{
			for(int i=0; i<_dimSys; ++i)
			{
				if(fabs(_f[i]) > _newtonSettings->getAtol() +_newtonSettings->getRtol() * ( fabs(_f[i])))
				{
					_iterationStatus = CONTINUE;
					break;
				}
			}
		}
		else
			_iterationStatus = CONTINUE;

		// New right hand side
		//calcFunction(_y,_f);

		if(_iterationStatus == CONTINUE)
		{
			if(totStps < _newtonSettings->getNewtMax())
			{
				// Determination of Jacobian (Fortran-format)
				if(_algLoop->isLinear()&&!_algLoop->isLinearTearing())
				{
					//calcFunction(_yHelp,_fHelp);
					const matrix_t& A = _algLoop->getSystemMatrix();
					const double* jac = A.data().begin();
					memcpy(_jac, jac, _dimSys*_dimSys*sizeof(double));
					dgesv_(&_dimSys,&dimRHS,_jac,&_dimSys,_iHelp,_f,&_dimSys,&irtrn);
					memcpy(_y,_f,_dimSys*sizeof(double));
					_algLoop->setReal(_y);
					if(irtrn != 0)
						throw ModelicaSimulationError(ALGLOOP_SOLVER,"error solving linear tearing system");
					else
						_iterationStatus = DONE;


				}
				else if(_algLoop->isLinearTearing())
				{
					long int dimRHS  = 1;          // Dimension of right hand side of linear system (=b)

					long int irtrn  = 0;          // Retrun-flag of Fortran code

					_algLoop->setReal(_zeroVec);
					_algLoop->evaluate();
					_algLoop->getRHS(_f);


					/*  adaptor_t f_adaptor(_dimSys,_f);
					shared_matrix_t b(_dimSys,1,f_adaptor);*/


					//print_m (b, "b vector");


					const matrix_t& A_sparse = _algLoop->getSystemMatrix();
					//m_t A_dense(A_sparse);

					const double* jac = A_sparse.data().begin();

					/*double* jac = new  double[dimSys*dimSys];
					for(int i=0;i<dimSys;i++)
					for(int j=0;j<dimSys;j++)
					jac[i*_dimSys+j] = A_sparse(i,j);*/


					memcpy(_jac, jac, _dimSys*_dimSys*sizeof(double));


					dgesv_(&_dimSys, &dimRHS, _jac, &_dimSys, _iHelp, _f,&_dimSys,&irtrn);
					// std::vector< int > ipiv (_dimSys);  // pivot vector
					//lapack::gesv (A_sparse, ipiv,b);   // solving the system, b contains x

					for(int i=0; i<_dimSys; i++)
						_f[i]=-_f[i];

					memcpy(_y, _f, _dimSys*sizeof(double));
					_algLoop->setReal(_y);
					_algLoop->evaluate();
					if(irtrn != 0)
						throw ModelicaSimulationError(ALGLOOP_SOLVER,"error solving linear tearing system");
					else
						_iterationStatus = DONE;
				}
				else
				{
					calcJacobian();

					// Solve linear System
					dgesv_(&_dimSys,&dimRHS,_jac,&_dimSys,_iHelp,_f,&_dimSys,&irtrn);

					if(irtrn!=0)
					{
						// TODO: Throw an error message here.
						_iterationStatus = SOLVERERROR;
						break;
					}

					// Increase counter
					++ totStps;

					// New solution
					for(int i=0; i<_dimSys; ++i)
						_y[i] -= _newtonSettings->getDelta() * _f[i];
				}
			}
			else
				_iterationStatus = SOLVERERROR;
		}
	}
}