diff --git a/src/test/gtest_constraint_imu.cpp b/src/test/gtest_constraint_imu.cpp
index b6312643991eccc3c37953f70668c1470f7ad85f..2c97fcae038b35a02b847c0ddf6ffece834cf8d5 100644
--- a/src/test/gtest_constraint_imu.cpp
+++ b/src/test/gtest_constraint_imu.cpp
@@ -1358,9 +1358,24 @@ class ConstraintIMU_biasTest : public testing::Test
         VectorXs x0;
         Vector3s p0, v0;
         Quaternions q0, q;
+        Matrix<Scalar, 9, 9> P0;
         Vector6s motion, data, bias_real, bias_preint, bias_null;
+        Vector6s bias_0, bias_1;
         Vector3s a, w, am, wm;
 
+        VectorXs D_exact, x_exact;
+        VectorXs D_preint_imu, D_corrected_imu;
+        VectorXs x_preint_imu, x_corrected_imu;
+        VectorXs D_preint, D_corrected;
+        VectorXs x_preint, x_corrected;
+        VectorXs D_optim, x_optim;
+        Matrix<Scalar, 9, 6> J_b;
+        Vector9s step;
+
+        bool p0_fixed, q0_fixed, v0_fixed;
+        bool p1_fixed, q1_fixed, v1_fixed;
+
+
 
     virtual void SetUp( )
     {
@@ -1392,10 +1407,15 @@ class ConstraintIMU_biasTest : public testing::Test
         bias_null.setZero();
 
         x0.resize(10);
+        D_preint.resize(10);
+        D_corrected.resize(10);
 
     }
 
-    virtual void TearDown( ) { }
+    virtual void TearDown( )
+    {
+        //
+    }
 
     /* Create IMU data from body motion
      * Input:
@@ -1414,6 +1434,16 @@ class ConstraintIMU_biasTest : public testing::Test
         return data;
     }
 
+    void setFixedBlocks()
+    {
+        KF_0->getPPtr()->setFixed(p0_fixed);
+        KF_0->getOPtr()->setFixed(q0_fixed);
+        KF_0->getVPtr()->setFixed(v0_fixed);
+        KF_1->getPPtr()->setFixed(p1_fixed);
+        KF_1->getOPtr()->setFixed(q1_fixed);
+        KF_1->getVPtr()->setFixed(v1_fixed);
+    }
+
 
 
     /* Integrate acc and angVel motion, obtain Delta_preintegrated
@@ -1492,56 +1522,13 @@ class ConstraintIMU_biasTest : public testing::Test
         return Delta;
     }
 
-};
-
-TEST_F(ConstraintIMU_biasTest, VarB1B2_InvarP1Q1V1P2Q2V2_initOK)
-{
-
-         // ==================================== INITIAL CONDITIONS
-        t0 = 0;
-        dt = 0.01;
-        num_integrations = 50;
-        DT = num_integrations * dt;
-
-        p0 << 0,0,0;
-        q0.setIdentity();
-        v0 << 0,0,0;
-        MatrixXs  P0(9,9); P0.setIdentity() * 0.01;
-
-        x0  << p0, q0.coeffs(), v0;
-        KF_0 = problem->setPrior(x0, P0, t0);
-        C_0  = processor_imu->getOriginPtr();
-        CM_1 = processor_imu->getLastPtr();
-        KF_1 = CM_1->getFramePtr();
-
-        // bias
-        bias_real  << .001, .002, .003, -.001, -.002, -.003;
-        bias_preint = -bias_real;
-
-        processor_imu->getLastPtr()->setCalibrationPreint(bias_preint);
-
-        // ===================================== MOTION params
-        a << 1,2,3;
-        w << 1,2,3;
-
-        WOLF_TRACE("w * DT (rather be lower than 1.507 approx) = ", w.transpose() * DT); // beware if w*DT is large (>~ 1.507) then Jacobian for correction is poor
-
-        motion << a, w;
-
-        // ===================================== INTEGRATE EXACTLY with no bias at all
-        VectorXs D_exact = integrateDelta(num_integrations, q0, motion, bias_null, bias_null, dt);
-        VectorXs x_exact = imu::composeOverState(x0, D_exact, DT );
-
-        WOLF_TRACE("D_exact      : ", D_exact.transpose() );
-        WOLF_TRACE("X_exact      : ", x_exact.transpose() );
-
-        // ===================================== INTEGRATE USING PROCESSOR
-        VectorXs D_preint(10), D_corrected(10);
-
+    void integrateWithProcessor(int N, const TimeStamp& t0, const Quaternions q0, const VectorXs& motion, const VectorXs& bias_real, const VectorXs& bias_preint, Scalar dt, VectorXs& D_preint, VectorXs& D_corrected)
+    {
+        data = motion2data(motion, q0, bias_real);
         capture_imu = std::make_shared<CaptureIMU>(t0, sensor_imu, data, sensor_imu->getNoiseCov());
         q = q0;
         t = t0;
-        for (int i= 0; i < num_integrations; i++)
+        for (int i= 0; i < N; i++)
         {
             t   += dt;
             data = motion2data(motion, q, bias_real);
@@ -1554,75 +1541,179 @@ TEST_F(ConstraintIMU_biasTest, VarB1B2_InvarP1Q1V1P2Q2V2_initOK)
 
             D_preint    = processor_imu->getLastPtr()->getDeltaPreint();
             D_corrected = processor_imu->getLastPtr()->getDeltaCorrected(bias_real);
-
         }
+    }
 
-        // ========================================== INTEGRATE USING IMU_TOOLS
-        VectorXs D_preint_imu, D_corrected_imu;
-        Matrix<Scalar, 9, 6> J_b;
+    bool configure()
+    {
+        DT      = num_integrations * dt;
+        x0     << p0, q0.coeffs(), v0;
+        P0      .setIdentity() * 0.01;
+        KF_0    = problem->setPrior(x0, P0, t0);
+        C_0     = processor_imu->getOriginPtr();
+        CM_1    = processor_imu->getLastPtr();
+        KF_1    = CM_1->getFramePtr();
+        motion << a, w;
+
+        processor_imu->getLastPtr()->setCalibrationPreint(bias_preint);
+
+        return true;
+    }
+
+    void integrateAll()
+    {
+        // ===================================== INTEGRATE EXACTLY WITH IMU_TOOLS with no bias at all
+        D_exact = integrateDelta(num_integrations, q0, motion, bias_null, bias_null, dt);
+        x_exact = imu::composeOverState(x0, D_exact, DT );
+
+
+        // ===================================== INTEGRATE USING IMU_TOOLS
+        // pre-integrate
         D_preint_imu = integrateDelta(num_integrations, q0, motion, bias_real, bias_preint, dt, J_b);
 
         // correct perturbated
-        Vector9s step = J_b * (bias_real - bias_preint);
+        step = J_b * (bias_real - bias_preint);
         D_corrected_imu = imu::plus(D_preint_imu, step);
 
-        WOLF_TRACE("D_preint     : ", D_preint       .transpose() );
-        WOLF_TRACE("D_preint_imu : ", D_preint_imu   .transpose() );
-        ASSERT_MATRIX_APPROX(D_preint, D_preint_imu, 1e-8);
+        // compose states
+        x_preint_imu    = imu::composeOverState(x0, D_preint_imu    , DT );
+        x_corrected_imu = imu::composeOverState(x0, D_corrected_imu , DT );
 
-        WOLF_TRACE("D_correct    : ", D_corrected    .transpose() );
-        WOLF_TRACE("D_correct_imu: ", D_corrected_imu.transpose() );
-        ASSERT_MATRIX_APPROX(D_corrected, D_corrected_imu, 1e-8);
+        // ===================================== INTEGRATE USING PROCESSOR
 
-        WOLF_TRACE("X_preint     : ", imu::composeOverState(x0, D_preint       , DT ).transpose() );
-        WOLF_TRACE("X_preint_imu : ", imu::composeOverState(x0, D_preint_imu   , DT ).transpose() );
+        integrateWithProcessor(num_integrations, t0, q0, motion, bias_real, bias_preint, dt, D_preint, D_corrected);
 
-        WOLF_TRACE("X_correct    : ", imu::composeOverState(x0, D_corrected    , DT ).transpose() );
-        WOLF_TRACE("X_correct_imu: ", imu::composeOverState(x0, D_corrected_imu, DT ).transpose() );
-        ASSERT_MATRIX_APPROX(imu::composeOverState(x0, D_corrected     , DT ), x_exact, 1e-5);
-        ASSERT_MATRIX_APPROX(imu::composeOverState(x0, D_corrected_imu , DT ), x_exact, 1e-5);
+        // compose states
+        x_preint        = imu::composeOverState(x0, D_preint        , DT );
+        x_corrected     = imu::composeOverState(x0, D_corrected     , DT );
+    }
 
-        // ================================ SET KF AND SOLVE
+    void buildProblem()
+    {
+        // ===================================== SET KF in Wolf tree
         FrameBasePtr KF = problem->emplaceFrame(KEY_FRAME, x_exact, t);
         processor_imu->keyFrameCallback(KF, 0.01);
 
         KF_1 = problem->getLastKeyFramePtr();
         C_1  = KF_1->getCaptureList().back();
 
-        KF_0->getPPtr()->fix();
-        KF_0->getOPtr()->fix();
-        KF_0->getVPtr()->fix();
-        KF_1->getPPtr()->fix();
-        KF_1->getOPtr()->fix();
-        KF_1->getVPtr()->fix();
+        // ===================================== SET BOUNDARY CONDITIONS
+        setFixedBlocks();
+    }
+
+    string solveProblem(int verbose = 1)
+    {
+        string report = ceres_manager->solve(verbose);
 
-        string report = ceres_manager->solve(2);
+        bias_0 = C_0->getCalibration();
+        bias_1 = C_1->getCalibration();
 
-        Vector6s bias_0 = C_0->getCalibration();
-        Vector6s bias_1 = C_1->getCalibration();
+        // ===================================== CHECK INTEGRATED STATE WITH SOLVED BIAS
+        step        = J_b * (bias_0 - bias_preint);
+        D_optim     = imu::plus(D_preint, step);
+        x_optim     = imu::composeOverState(x0, D_optim, DT);
 
-        WOLF_TRACE("bias preint  : ", bias_preint.transpose());
-        WOLF_TRACE("bias real    : ", bias_real  .transpose());
-        WOLF_TRACE("bias optim 0 : ", bias_0     .transpose());
-        WOLF_TRACE("bias optim 1 : ", bias_1     .transpose());
+        return report;
+    }
 
-        ASSERT_MATRIX_APPROX(bias_0, bias_real, 1e-4);
-        ASSERT_MATRIX_APPROX(bias_1, bias_real, 1e-4);
+    string run(int verbose)
+    {
+        string report;
+        configure();
+        integrateAll();
+        buildProblem();
+        report = solveProblem(verbose);
+        return report;
+    }
 
-        // ============================= CHECK INTEGRATED STATE WITH SOLVED BIAS
-        step = J_b * (bias_0 - bias_preint);
-        VectorXs D_optim = imu::plus(D_preint, step);
-        VectorXs x_optim = imu::composeOverState(x0, D_optim, DT);
 
-        WOLF_TRACE("D_optim      : ", D_optim.transpose());
-        WOLF_TRACE("X_optim      : ", x_optim.transpose());
-        WOLF_TRACE("X_optim error: ", (x_exact - x_optim).transpose());
+};
 
-        ASSERT_MATRIX_APPROX(x_optim, x_exact, 1e-5);
+TEST_F(ConstraintIMU_biasTest, VarB1B2V2_InvarP1Q1V1P2Q2)
+{
 
-        cout << report << endl;
+    // ================================================================================================================ //
+    // ==================================== INITIAL CONDITIONS -- USER OPTIONS ======================================== //
+    // ================================================================================================================ //
+    //
+    // ---------- time
+    t0                  = 0;
+    dt                  = 0.01;
+    num_integrations    = 50;
+
+    // ---------- initial pose
+    p0                 << 0,0,0;
+    q0                  .setIdentity();
+    v0                 << 0,0,0;
+
+    // ---------- bias
+    bias_real          << .001, .002, .003,    -.001, -.002, -.003;
+    bias_preint         = -bias_real;
+
+    // ---------- motion params
+    a                  << 1,2,3;
+    w                  << 1,2,3;
+
+    // ---------- fix boundaries
+    p0_fixed       = true;
+    q0_fixed       = true;
+    v0_fixed       = true;
+    p1_fixed       = true;
+    q1_fixed       = true;
+    v1_fixed       = false;
+    //
+    // ===================================== INITIAL CONDITIONS -- USER INPUT ENDS HERE =============================== //
+    // ================================================================================================================ //
+
+
+    // ===================================== RUN ALL
+    string report = run(1);
+    cout << report << endl;
+
+    WOLF_TRACE("w * DT (rather be lower than 1.507 approx) = ", w.transpose() * DT); // beware if w*DT is large (>~ 1.507) then Jacobian for correction is poor
+
+    // ===================================== CHECK ALL (SEE RESULTS SECTION BELOW FOT THE MEANING OF ALL VARIABLES)
+
+    // check delta and state integrals
+    ASSERT_MATRIX_APPROX(D_preint       , D_preint_imu      , 1e-8 );
+    ASSERT_MATRIX_APPROX(D_corrected    , D_corrected_imu   , 1e-8 );
+    ASSERT_MATRIX_APPROX(D_corrected_imu, D_exact           , 1e-5 );
+    ASSERT_MATRIX_APPROX(D_corrected    , D_exact           , 1e-5 );
+    ASSERT_MATRIX_APPROX(x_corrected_imu, x_exact           , 1e-5 );
+    ASSERT_MATRIX_APPROX(x_corrected    , x_exact           , 1e-5 );
+
+    // check optimal solutions
+    ASSERT_MATRIX_APPROX(bias_0 , bias_real , 1e-4 );
+    ASSERT_MATRIX_APPROX(bias_1 , bias_real , 1e-4 );
+    ASSERT_MATRIX_APPROX(D_optim, D_exact   , 1e-5 );
+    ASSERT_MATRIX_APPROX(x_optim, x_exact   , 1e-5 );
+
+
+    // ===================================== PRINT RESULTS
+    WOLF_TRACE("D_exact      : ", D_exact            .transpose() ); // exact delta integrated, with absolutely no bias
+    WOLF_TRACE("D_preint     : ", D_preint           .transpose() ); // pre-integrated delta using processor
+    WOLF_TRACE("D_preint_imu : ", D_preint_imu       .transpose() ); // pre-integrated delta using imu_tools
+    WOLF_TRACE("D_correct    : ", D_corrected        .transpose() ); // corrected delta using processor
+    WOLF_TRACE("D_correct_imu: ", D_corrected_imu    .transpose() ); // corrected delta using imu_tools
+    WOLF_TRACE("D_optim      : ", D_optim            .transpose() ); // corrected delta using optimum bias after solving
+
+    WOLF_TRACE("bias real    : ", bias_real          .transpose() ); // real bias
+    WOLF_TRACE("bias preint  : ", bias_preint        .transpose() ); // bias used during pre-integration
+    WOLF_TRACE("bias optim 0 : ", bias_0             .transpose() ); // solved bias at KF_0
+    WOLF_TRACE("bias optim 1 : ", bias_1             .transpose() ); // solved bias at KF_1
+
+    // states at the end of integration, i.e., at KF_1
+    WOLF_TRACE("X_exact      : ", x_exact            .transpose() ); // exact state
+    WOLF_TRACE("X_preint     : ", x_preint           .transpose() ); // state using delta preintegrated by processor
+    WOLF_TRACE("X_preint_imu : ", x_preint_imu       .transpose() ); // state using delta preintegrated by imu_tools
+    WOLF_TRACE("X_correct    : ", x_corrected        .transpose() ); // corrected state vy processor
+    WOLF_TRACE("X_correct_imu: ", x_corrected_imu    .transpose() ); // corrected state by imu_tools
+    WOLF_TRACE("X_optim      : ", x_optim            .transpose() ); // optimal state after solving
+    WOLF_TRACE("X_optim error: ", (x_exact - x_optim).transpose() ); // error of optimal state w.r.t. exact state
 }
 
+
+
 // tests with following conditions :
 //  var(b1,b2),        invar(p1,q1,v1,p2,q2,v2),    factor : imu(p,q,v)