Ejemplo n.º 1
0
void Problem::readLastVectorALETimeAdvance ( vectorPtr_Type fluidDisp,
                                             const std::string loadInitSol)
{
    using namespace LifeV;

    typedef FSIOperator::mesh_Type        mesh_Type;

    //We still need to load the last vector for ALE
    std::string iterationString = loadInitSol;
    fluidDisp.reset (new vector_Type (M_fsi->FSIOper()->mmFESpace().map(), LifeV::Unique) );

    //Setting the exporterData to read: ALE problem
    LifeV::ExporterData<mesh_Type> initSolFluidDisp  (LifeV::ExporterData<mesh_Type>::VectorField, "f-displacement." + iterationString, M_fsi->FSIOper()->mmFESpacePtr(), fluidDisp, UInt (0), LifeV::ExporterData<mesh_Type>::UnsteadyRegime );

    //Initializing
    *fluidDisp *= 0.0;

    //Reading
    M_importerFluid->readVariable (initSolFluidDisp); //Fluid df

    //Output
    std::cout << "Norm of the df " << fluidDisp->norm2() << std::endl;

    //This is ugly but it's the only way I have figured out at the moment
    if ( M_data->method().compare ("monolithicGI") == 0 )
    {
        //Don't be scared by the ten. The goal of 10 is just to make the first if fail
        M_fsi->FSIOper()->setALEVectorInStencil ( fluidDisp, 10, true );
    }

    //Setting the vector in the stencil
    M_fsi->FSIOper()->ALETimeAdvance()->shiftRight ( *fluidDisp );
}
void
TimeIterationPolicyLinear<mesh_Type, AssemblyPolicy, SolverPolicy>::
iterate ( vectorPtr_Type solution,
          bcContainerPtr_Type bchandler,
          const Real& currentTime )
{
    Real rhsIterNorm ( 0.0 );

    //
    // STEP 1: Updating the system
    //
    displayer().leaderPrint ( "Updating the system... " );
    *M_rhs = 0.0;
    M_systemMatrix.reset ( new matrix_Type ( *M_solutionMap ) );
    AssemblyPolicy::assembleSystem ( M_systemMatrix, M_rhs, solution, SolverPolicy::preconditioner() );
    displayer().leaderPrint ( "done\n" );

    //
    // STEP 2: Applying the boundary conditions
    //
    displayer().leaderPrint ( "Applying BC... " );
    bcManage ( *M_systemMatrix, *M_rhs, *uFESpace()->mesh(), uFESpace()->dof(), *bchandler, uFESpace()->feBd(), 1.0, currentTime );
    M_systemMatrix->globalAssemble();
    displayer().leaderPrint ( "done\n" );

    // Extra information if we want to know the exact residual
    if ( M_computeResidual )
    {
        rhsIterNorm = M_rhs->norm2();
    }

    //
    // STEP 3: Solving the system
    //
    displayer().leaderPrint ( "Solving the system... \n" );
    SolverPolicy::solve ( M_systemMatrix, M_rhs, solution );

    if ( M_computeResidual )
    {
        vector_Type Ax ( solution->map() );
        vector_Type res ( *M_rhs );
        M_systemMatrix->matrixPtr()->Apply ( solution->epetraVector(), Ax.epetraVector() );
        res.epetraVector().Update ( -1, Ax.epetraVector(), 1 );
        Real residual;
        res.norm2 ( &residual );
        residual /= rhsIterNorm;
        displayer().leaderPrint ( "Scaled residual: ", residual, "\n" );
    }
}
Ejemplo n.º 3
0
void
InitPolicyInterpolation< mesh_Type >::
initSimulation ( bcContainerPtr_Type /*bchandler*/,
                 vectorPtr_Type solution )
{
    ASSERT ( problem()->hasExactSolution(), "Error: You cannot use the interpolation method if the problem has not an analytical solution." );

    Real currentTime = initialTime() - timestep() * bdf()->order();
    UInt pressureOffset = uFESpace()->fieldDim() * uFESpace()->dof().numTotalDof();

    vectorPtr_Type velocity;
    velocity.reset ( new vector_Type ( uFESpace()->map(), Unique ) );

    vectorPtr_Type pressure;
    pressure.reset ( new vector_Type ( pFESpace()->map(), Unique ) );

    *solution = 0.0;
    uFESpace()->interpolate ( problem()->uexact(), *velocity, currentTime );
    pFESpace()->interpolate ( problem()->pexact(), *pressure, currentTime );
    solution->add ( *velocity );
    solution->add ( *pressure, pressureOffset );
    bdf()->setInitialCondition ( *solution );

    currentTime += timestep();
    for ( ; currentTime <=  initialTime() + timestep() / 2.0; currentTime += timestep() )
    {
        *solution = 0.0;
        *velocity = 0.0;
        *pressure = 0.0;

        uFESpace()->interpolate ( problem()->uexact(), *velocity, currentTime );
        pFESpace()->interpolate ( problem()->pexact(), *pressure, currentTime );
        solution->add ( *velocity );
        solution->add ( *pressure, pressureOffset );

        // Updating bdf
        bdf()->shiftRight ( *solution );
    }
}
Ejemplo n.º 4
0
Real
LinearSolver::computeResidual ( vectorPtr_Type solutionPtr )
{
    if ( !M_operator || !M_rhs )
    {
        M_displayer->leaderPrint ( "SLV-  WARNING: LinearSolver can not compute the residual if the operator and the RHS are not set!\n" );
        return -1;
    }

    vector_Type Ax ( solutionPtr->map() );
    vector_Type residual ( *M_rhs );

    M_operator->Apply ( solutionPtr->epetraVector(), Ax.epetraVector() );

    residual.epetraVector().Update ( 1, Ax.epetraVector(), -1 );

    Real residualNorm;

    residual.norm2 ( &residualNorm );

    return residualNorm;
}
Ejemplo n.º 5
0
void
FSISolver::initialize(vectorPtr_Type u0, vectorPtr_Type v0)
{
    if (!u0.get())
    {
        u0.reset(new vector_Type(*M_oper->couplingVariableMap()));
        M_oper->initialize(*u0); // couplingVariableMap()
        M_oper->initializeBDF(*u0);
    }
    else
    {
        M_oper->initialize(*u0); // couplingVariableMap()//copy
        M_oper->initializeBDF(*u0);
    }
    if (!v0.get())
        M_oper->setSolutionDerivative(*u0); // couplingVariableMap()//copy
    //        M_oper->setSolutionDerivative(u0); // couplingVariableMap()//copy
    else
        M_oper->setSolutionDerivative(*v0);
    //M_oper->setSolutionDerivative(v0);
    //M_oper->setupBDF(*M_lambda);
}
Ejemplo n.º 6
0
void Problem::readLastVectorSolidTimeAdvance ( vectorPtr_Type solidDisp,
                                               LifeV::UInt iterInit,
                                               std::string iterationString)
{
    using namespace LifeV;

    typedef FSIOperator::mesh_Type        mesh_Type;

    //Reading another vector for the solidTimeAdvance since its BDF has the same order
    //as the other ones but since the orderDerivative = 2, the size of the stencil is
    //orderBDF + 1

    solidDisp.reset (new vector_Type (M_fsi->FSIOper()->dFESpace().map(), LifeV::Unique) );
    *solidDisp *= 0.0;
    LifeV::ExporterData<mesh_Type> initSolSolidDisp  (LifeV::ExporterData<mesh_Type>::VectorField, "s-displacement." + iterationString, M_fsi->FSIOper()->dFESpacePtr(), solidDisp, UInt (0), LifeV::ExporterData<mesh_Type>::UnsteadyRegime );

    M_importerSolid->readVariable (initSolSolidDisp); //Solid d

    M_fsi->FSIOper()->setSolidVectorInStencil ( solidDisp, iterInit );
}
void MonolithicBlockComposedDN::coupler (mapPtr_Type& map,
                                         const std::map<ID, ID>& locDofMap,
                                         const vectorPtr_Type& numerationInterface,
                                         const Real& timeStep,
                                         const Real& coefficient,
                                         const Real& rescaleFactor)
{
    UInt totalDofs ( map->map (Unique)->NumGlobalElements() );
    UInt solidAndFluid (M_offset[solid] + M_FESpace[solid]->map().map (Unique)->NumGlobalElements() );

    matrixPtr_Type coupling (new matrix_Type (*map) );
    couplingMatrix ( coupling,  (*M_couplingFlags) [solid], M_FESpace, M_offset, locDofMap, numerationInterface, timeStep, 1., coefficient, rescaleFactor);
    coupling->insertValueDiagonal ( 1., M_offset[fluid], M_offset[solid] );
    coupling->insertValueDiagonal ( 1., solidAndFluid, totalDofs );
    M_coupling.push_back (coupling);

    coupling.reset (new matrix_Type (*map) );
    couplingMatrix ( coupling,  (*M_couplingFlags) [fluid], M_FESpace, M_offset, locDofMap, numerationInterface, timeStep, 1., coefficient, rescaleFactor);
    coupling->insertValueDiagonal ( 1. , M_offset[solid], solidAndFluid );
    coupling->insertValueDiagonal ( 1. , solidAndFluid + nDimensions * numerationInterface->map().map (Unique)->NumGlobalElements(), totalDofs );
    M_coupling.push_back (coupling);

}
Ejemplo n.º 8
0
void Problem::restartFSI (  GetPot const& data_file)
{

    using namespace LifeV;

    typedef FSIOperator::mesh_Type        mesh_Type;

    //Creating the pointer to the filter
    std::string const importerType =  data_file ( "importer/type", "ensight");
    std::string const fluidName    =  data_file ( "importer/fluid/filename", "fluid");
    std::string const solidName    =  data_file ( "importer/solid/filename", "solid");

    std::string const loadInitSol      = data_file ( "importer/initSol", "00000");
    std::string const loadInitSolFD    = data_file ("importer/initSolFD", "-1");
    std::string iterationString;

    M_Tstart  = data_file ( "fluid/time_discretization/initialtime", 0.);

    std::cout << "The file for fluid is    : " << fluidName << std::endl;
    std::cout << "The file for solid is    : " << solidName << std::endl;
    std::cout << "The importerType is      : " << importerType << std::endl;
    std::cout << "The iteration is         : " << loadInitSol << std::endl;
    std::cout << "For the fluid disp is    : " << loadInitSolFD << std::endl;
    std::cout << "Starting time            : " << M_Tstart << std::endl;

    //At the moment the restart works only if BDF methods are used in time.
    // For Newmark method a almost new implementation is needed

    std::string methodFluid = data_file ( "fluid/time_discretization/method", "Newmark");
    std::string methodSolid = data_file ( "solid/time_discretization/method", "Newmark");
    std::string methodALE = data_file ( "mesh_motion/time_discretization/method", "Newmark");

#ifdef HAVE_HDF5
    if (importerType.compare ("hdf5") == 0)
    {
        M_importerFluid.reset ( new  hdf5Filter_Type ( data_file, fluidName) );
        M_importerSolid.reset ( new  hdf5Filter_Type ( data_file, solidName) );
    }
    else
#endif
    {
        if (importerType.compare ("none") == 0)
        {
            M_importerFluid.reset ( new ExporterEmpty<mesh_Type > ( data_file, M_fsi->FSIOper()->uFESpace().mesh(), "fluid", M_fsi->FSIOper()->uFESpace().map().comm().MyPID() ) );
            M_importerSolid.reset ( new ExporterEmpty<mesh_Type > ( data_file, M_fsi->FSIOper()->dFESpace().mesh(), "solid", M_fsi->FSIOper()->uFESpace().map().comm().MyPID() ) );
        }
        else
        {
            M_importerFluid.reset ( new  ensightFilter_Type ( data_file, fluidName) );
            M_importerSolid.reset ( new  ensightFilter_Type ( data_file, solidName) );
        }
    }

    M_importerFluid->setMeshProcId (M_fsi->FSIOper()->uFESpace().mesh(), M_fsi->FSIOper()->uFESpace().map().comm().MyPID() );
    M_importerSolid->setMeshProcId (M_fsi->FSIOper()->dFESpace().mesh(), M_fsi->FSIOper()->dFESpace().map().comm().MyPID() );

    //Each of the vectors of the stencils has the dimension of the big vector
    //Performing a cycle of the size of the timeAdvance classes for each problem
    //The size of TimeAdvanceClass depends on the order of the BDF (data file)

    //The hypothesis used for this method is that the three TimeAdvance classes have the same size
    iterationString = loadInitSol;

    UInt iterInit;

    vectorPtr_Type vel;
    vectorPtr_Type pressure;
    vectorPtr_Type solidDisp;
    vectorPtr_Type fluidDisp;

    for (iterInit = 0; iterInit < M_fsi->FSIOper()->fluidTimeAdvance()->size(); iterInit++ )
    {

        //It should work just initializing the timeAdvance classes
        //Three stencils are needed (Fluid-Structure-Geometric)
        vel.reset (new vector_Type (M_fsi->FSIOper()->uFESpace().map(), LifeV::Unique) );
        pressure.reset (new vector_Type (M_fsi->FSIOper()->pFESpace().map(), LifeV::Unique) );
        solidDisp.reset (new vector_Type (M_fsi->FSIOper()->dFESpace().map(), LifeV::Unique) );

        //First the three fields are read at the same time
        //Creating the exporter data for the fields
        //Fluid
        LifeV::ExporterData<mesh_Type> initSolFluidVel   (LifeV::ExporterData<mesh_Type>::VectorField, std::string ("f-velocity." + iterationString), M_fsi->FSIOper()->uFESpacePtr(), vel, UInt (0), LifeV::ExporterData<mesh_Type>::UnsteadyRegime );
        LifeV::ExporterData<mesh_Type> initSolFluidPress (LifeV::ExporterData<mesh_Type>::ScalarField, std::string ("f-pressure." + iterationString), M_fsi->FSIOper()->pFESpacePtr(), pressure, UInt (0), LifeV::ExporterData<mesh_Type>::UnsteadyRegime );

        //Structure
        LifeV::ExporterData<mesh_Type> initSolSolidDisp  (LifeV::ExporterData<mesh_Type>::VectorField, "s-displacement." + iterationString, M_fsi->FSIOper()->dFESpacePtr(), solidDisp, UInt (0), LifeV::ExporterData<mesh_Type>::UnsteadyRegime );

        //Initialization of the vectors used to read
        *vel *= 0.0;
        *pressure *= 0.0;
        *solidDisp *= 0.0;

        //load of the solutions
        M_importerFluid->readVariable (initSolFluidVel);  //Fluid u
        M_importerFluid->readVariable (initSolFluidPress); //Fluid p
        M_importerSolid->readVariable (initSolSolidDisp); //Solid d

        std::cout << "Norm of the vel " << vel->norm2() << std::endl;
        std::cout << "Norm of the pressure " << pressure->norm2() << std::endl;
        std::cout << "Norm of the solid " << solidDisp->norm2() << std::endl;

        //We send the vectors to the FSIMonolithic class using the interface of FSIOper
        M_fsi->FSIOper()->setVectorInStencils (vel, pressure, solidDisp, iterInit )
        ;
        //Updating string name
        int iterations = std::atoi (iterationString.c_str() );
        iterations--;

        std::ostringstream iter;
        iter.fill ( '0' );
        iter << std::setw (5) << ( iterations );
        iterationString = iter.str();
    }

    readLastVectorSolidTimeAdvance ( solidDisp, iterInit, iterationString );

    //For the ALE timeAdvance, one should be careful on the vectors that are used
    //to compute the RHSFirstDerivative. That is why we first load the stencil using previous
    //vectors and then we read the last one
    iterationString = loadInitSol;
    int iterationStartALE = std::atoi (iterationString.c_str() );
    iterationStartALE--;

    std::ostringstream iter;
    iter.fill ( '0' );
    iter << std::setw (5) << ( iterationStartALE );
    iterationString = iter.str();

    std::cout << "The load init sol is: " << loadInitSol << std::endl;
    std::cout << "The first read sol is: " << iterationString << std::endl;

    for (iterInit = 0; iterInit < M_fsi->FSIOper()->ALETimeAdvance()->size(); iterInit++ )
    {
        //Reset the pointer
        fluidDisp.reset (new vector_Type (M_fsi->FSIOper()->mmFESpace().map(), LifeV::Unique) );

        //Setting the exporterData to read: ALE problem
        LifeV::ExporterData<mesh_Type> initSolFluidDisp  (LifeV::ExporterData<mesh_Type>::VectorField, "f-displacement." + iterationString, M_fsi->FSIOper()->mmFESpacePtr(), fluidDisp, UInt (0), LifeV::ExporterData<mesh_Type>::UnsteadyRegime );

        //Initializing
        *fluidDisp *= 0.0;

        //Reading
        M_importerFluid->readVariable (initSolFluidDisp); //Fluid df

        //Output
        std::cout << "Norm of the df " << fluidDisp->norm2() << std::endl;

        //Setting the vector in the stencil
        M_fsi->FSIOper()->setALEVectorInStencil ( fluidDisp, iterInit, false );

        //Updating string name
        int iterations = std::atoi (iterationString.c_str() );
        iterations--;

        std::ostringstream iter;
        iter.fill ( '0' );
        iter << std::setw (5) << ( iterations );
        iterationString = iter.str();
    }

    //Initializing the vector for the RHS terms of the formulas
    M_fsi->FSIOper()->finalizeRestart();

    //Need to read still one vector and shiftright it.
    readLastVectorALETimeAdvance ( fluidDisp, loadInitSol );

    //This are used to export the loaded solution to check it is correct.
    vel.reset (new vector_Type (M_fsi->FSIOper()->uFESpace().map(), LifeV::Unique) );
    pressure.reset (new vector_Type (M_fsi->FSIOper()->pFESpace().map(), LifeV::Unique) );
    fluidDisp.reset (new vector_Type (M_fsi->FSIOper()->mmFESpace().map(), LifeV::Unique) );
    M_velAndPressure.reset ( new vector_Type ( M_fsi->FSIOper()->fluid().getMap(), M_importerFluid->mapType() ) );
    M_velAndPressure->subset (*pressure, pressure->map(), UInt (0), (UInt) 3 * M_fsi->FSIOper()->uFESpace().dof().numTotalDof() );
    *M_velAndPressure += *vel;

    M_fluidDisp.reset     ( new vector_Type ( *fluidDisp, M_importerFluid->mapType() ) );

    M_solidDisp.reset     ( new vector_Type ( *solidDisp, M_importerSolid->mapType() ) );


}
void
TimeIterationPolicyNonlinear<mesh_Type, AssemblyPolicy, SolverPolicy>::
iterate ( vectorPtr_Type solution,
          bcContainerPtr_Type bchandler,
          const Real& currentTime )
{
    int subiter = 0;

    Real normRhs ( 0.0 );
    Real nonLinearResidual ( 0.0 );
    Real rhsIterNorm ( 0.0 );

    do
    {
        //
        // STEP 1: Updating the system
        //
        displayer().leaderPrint ( "Updating the system... " );
        *M_rhs = 0.0;
        M_systemMatrix.reset ( new matrix_Type ( *M_solutionMap ) );
        AssemblyPolicy::assembleSystem ( M_systemMatrix, M_rhs, solution, SolverPolicy::preconditioner() );
        displayer().leaderPrint ( "done\n" );

        //
        // STEP 2: Applying the boundary conditions
        //
        displayer().leaderPrint ( "Applying BC... " );
        bcManage ( *M_systemMatrix, *M_rhs, *uFESpace()->mesh(), uFESpace()->dof(), *bchandler, uFESpace()->feBd(), 1.0, currentTime );
        M_systemMatrix->globalAssemble();
        displayer().leaderPrint ( "done\n" );

        // Norm of the rhs needed for the nonlinear convergence test
        if ( subiter == 0 )
        {
            normRhs = M_rhs->norm2();
        }

        //
        // STEP 3: Computing the residual
        //

        // Computing the RHS as RHS=b-Ax_k
        vector_Type Ax ( solution->map() );
        M_systemMatrix->matrixPtr()->Apply ( solution->epetraVector(), Ax.epetraVector() );

        Ax.epetraVector().Update (-1, M_rhs->epetraVector(), 1);
        nonLinearResidual = Ax.norm2();

        displayer().leaderPrint ( "Nonlinear residual          : ", nonLinearResidual, "\n" );
        displayer().leaderPrint ( "Nonlinear residual (scaled) : ", nonLinearResidual / normRhs, "\n" );

        if ( nonLinearResidual > M_nonLinearTolerance * normRhs )
        {
            displayer().leaderPrint ( "---\nSubiteration [", ++subiter, "]\n" );

            // Extra information if we want to know the exact residual
            if ( M_computeResidual )
            {
                rhsIterNorm = M_rhs->norm2();
            }

            //
            // Solving the system
            //
            displayer().leaderPrint ( "Solving the system... \n" );
            *solution = 0.0;
            SolverPolicy::solve ( M_systemMatrix, M_rhs, solution );
            // int numIter = SolverPolicy::solve( M_systemMatrix, M_rhs, solution );
            // numIterSum += numIter; //

            if ( M_computeResidual )
            {
                vector_Type Ax ( solution->map() );
                vector_Type res ( *M_rhs );
                M_systemMatrix->matrixPtr()->Apply ( solution->epetraVector(), Ax.epetraVector() );
                res.epetraVector().Update ( -1, Ax.epetraVector(), 1 );
                Real residual;
                res.norm2 ( &residual );
                residual /= rhsIterNorm;
                displayer().leaderPrint ( "Scaled residual: ", residual, "\n" );
            }
        }
    }
    while ( nonLinearResidual > M_nonLinearTolerance * normRhs );

    displayer().leaderPrint ( "Nonlinear iterations           : ", subiter, "\n" );
}
Ejemplo n.º 10
0
// ===================================================
// Methods
// ===================================================
Int
LinearSolver::solve ( vectorPtr_Type solutionPtr )
{
    // Build preconditioners if needed
    bool retry ( true );
    if ( !isPreconditionerSet() || !M_reusePreconditioner  )
    {
        buildPreconditioner();

        // There will be no retry if the preconditioner is recomputed
        retry = false;
    }
    else
    {
        if ( !M_silent )
        {
            M_displayer->leaderPrint ( "SLV-  Reusing precond ...\n" );
        }
    }

    if ( M_rhs.get() == 0 || M_operator == 0 )
    {
        M_displayer->leaderPrint ( "SLV-  ERROR: LinearSolver failed to set up correctly!\n" );
        return -1;
    }

    // Setup the Solver Operator
    setupSolverOperator();

    // Reset status informations
    bool failure = false;
    this->resetStatus();
    M_solverOperator->resetStatus();

    // Solve the linear system
    LifeChrono chrono;
    chrono.start();

    M_solverOperator->ApplyInverse ( M_rhs->epetraVector(), solutionPtr->epetraVector() );
    M_converged         = M_solverOperator->hasConverged();
    M_lossOfPrecision   = M_solverOperator->isLossOfAccuracyDetected();
    chrono.stop();
    if ( !M_silent )
    {
        M_displayer->leaderPrintMax ( "SLV-  Solution time: " , chrono.diff(), " s." );
    }

    // Getting informations post-solve
    Int numIters = M_solverOperator->numIterations();

    // Second run recomputing the preconditioner
    // This is done only if the preconditioner has not been
    // already recomputed and if it is a LifeV preconditioner.
    if ( M_converged != SolverOperator_Type::yes
            && retry
            && M_preconditioner )
    {
        M_displayer->leaderPrint ( "SLV-  Iterative solver failed, numiter = " , numIters, "\n" );
        M_displayer->leaderPrint ( "SLV-  retrying:\n" );

        buildPreconditioner();

        // Solving again, but only once (retry = false)
        chrono.start();
        M_solverOperator->ApplyInverse ( M_rhs->epetraVector(), solutionPtr->epetraVector() );
        M_converged         = M_solverOperator->hasConverged();
        M_lossOfPrecision   = M_solverOperator->isLossOfAccuracyDetected();
        chrono.stop();
        if ( !M_silent )
        {
            M_displayer->leaderPrintMax ( "SLV-  Solution time: " , chrono.diff(), " s." );
        }
    }

    if ( M_lossOfPrecision == SolverOperator_Type::yes )
    {
        M_displayer->leaderPrint ( "SLV-  WARNING: Loss of accuracy detected!\n" );
        failure = true;
    }

    if ( M_converged == SolverOperator_Type::yes )
    {
        if ( !M_silent )
        {
            M_displayer->leaderPrint ( "SLV-  Convergence in " , numIters, " iterations\n" );
        }
        M_maxNumItersReached = SolverOperator_Type::no;
    }
    else
    {
        M_displayer->leaderPrint ( "SLV-  WARNING: Solver failed to converged to the desired precision!\n" );
        M_maxNumItersReached = SolverOperator_Type::yes;
        failure = true;
    }

    // If quitOnFailure is enabled and if some problems occur
    // the simulation is stopped
    if ( M_quitOnFailure && failure )
    {
        exit ( -1 );
    }

    // Reset the solver to free the internal pointers
    M_solverOperator->resetSolver();

    // If the number of iterations reaches the threshold of maxIterForReuse
    // we reset the preconditioners to force to solver to recompute it next
    // time
    if ( numIters > M_maxItersForReuse )
    {
        resetPreconditioner();
    }

    return numIters;
}