diff --git a/blast/src/DCoupledAdjoint.cpp b/blast/src/DCoupledAdjoint.cpp
index 8ea9318add45b1a8ec63c746970f578903e819fb..4cb1449ab6b6acacdaaa12f225c187019582ed4d 100644
--- a/blast/src/DCoupledAdjoint.cpp
+++ b/blast/src/DCoupledAdjoint.cpp
@@ -151,7 +151,7 @@ void CoupledAdjoint::reset()
 void CoupledAdjoint::buildAdjointMatrix(std::vector<std::vector<Eigen::SparseMatrix<double, Eigen::RowMajor>*>> &matrices, Eigen::SparseMatrix<double, Eigen::RowMajor> &matrixAdjoint)
 {
     // Create a list of triplets for the larger matrix
-    std::vector<Eigen::Triplet<double>> triplets;
+    std::deque<Eigen::Triplet<double>> triplets;
 
     // Sanity check
     for (size_t irow = 0; irow < matrices.size(); ++irow)
@@ -192,36 +192,37 @@ void CoupledAdjoint::buildAdjointMatrix(std::vector<std::vector<Eigen::SparseMat
 
 void CoupledAdjoint::run()
 {
-    tms["0-adj_total"].start();
-    tms["1-adj_inviscid"].start();
+    tms["0-Total"].start();
+    tms["1-Derivatives"].start();
+    tms2["1-adj_inviscid"].start();
     gradientswrtInviscidFlow();
-    tms["1-adj_inviscid"].stop();
-    tms["2-adj_mach"].start();
+    tms2["1-adj_inviscid"].stop();
+    tms2["2-adj_mach"].start();
     gradientswrtMachNumber();
-    tms["2-adj_mach"].stop();
-    tms["3-adj_density"].start();
+    tms2["2-adj_mach"].stop();
+    tms2["3-adj_density"].start();
     gradientswrtDensity();
-    tms["3-adj_density"].stop();
-    tms["4-adj_velocity"].start();
+    tms2["3-adj_density"].stop();
+    tms2["4-adj_velocity"].start();
     gradientswrtVelocity();
-    tms["4-adj_velocity"].stop();
-    tms["5-adj_dStar"].start();
+    tms2["4-adj_velocity"].stop();
+    tms2["5-adj_dStar"].start();
     gradientswrtDeltaStar();
-    tms["5-adj_dStar"].stop();
-    tms["6-adj_blw"].start();
+    tms2["5-adj_dStar"].stop();
+    tms2["6-adj_blw"].start();
     gradientswrtBlowingVelocity();
-    tms["6-adj_blw"].stop();
-    tms["7-adj_aoa"].start();
+    tms2["6-adj_blw"].stop();
+    tms2["7-adj_aoa"].start();
     gradientwrtAoA();
-    tms["7-adj_aoa"].stop();
-    tms["8-adj_mesh"].start();
+    tms2["7-adj_aoa"].stop();
+    tms2["8-adj_mesh"].start();
     gradientwrtMesh();
-    tms["8-adj_mesh"].stop();
+    tms2["8-adj_mesh"].stop();
+    tms["1-Derivatives"].stop();
 
     transposeMatrices();
 
-    tms["9-build"].start();
-    // Store pointers to the matrices in a 2D vector
+    tms2["9-build"].start();
     std::vector<std::vector<Eigen::SparseMatrix<double, Eigen::RowMajor>*>> matrices = {
         {&dRphi_phi,    &dRM_phi,    &dRrho_phi,    &dRv_phi,   &dRdStar_phi,   &dRblw_phi},
         {&dRphi_M,      &dRM_M,      &dRrho_M,      &dRv_M,     &dRdStar_M,     &dRblw_M},
@@ -236,7 +237,7 @@ void CoupledAdjoint::run()
     for (const auto& mat1 : matrices[0]) cols += mat1->cols(); // All matrices in a column have the same number of columns
     Eigen::SparseMatrix<double, Eigen::RowMajor> A_adjoint(rows, cols);
     buildAdjointMatrix(matrices, A_adjoint);
-    tms["9-build"].stop();
+    tms2["9-build"].stop();
 
     size_t phiIdx = 0;
     size_t machIdx = dRphi_phi.cols();
@@ -245,10 +246,12 @@ void CoupledAdjoint::run()
     size_t dStarIdx = vIdx + dRv_v.cols();
     size_t blwIdx = dStarIdx + dRdStar_dStar.cols();
 
-    //***** Gradient wrt angle of attack *****//
-    //****************************************//
+    //**************************************************************************//
+    //                      Gradients wrt angle of attack                       //
+    //**************************************************************************//
     // CL
-    tms["10-solveCxAoA"].start();
+    tms["2-Solve"].start();
+    tms2["10-solveCxAoA"].start();
     std::vector<double> rhsCl(A_adjoint.cols(), 0.0);
     for (auto i = phiIdx; i<phiIdx+dCl_phi.size(); ++i)
         rhsCl[i] = dCl_phi[i]; // Only dCl_dphi is non-zero
@@ -297,15 +300,18 @@ void CoupledAdjoint::run()
 
     // Total gradient
     tdCd_AoA = dCd_AoA - dRphi_AoA.transpose()*lambdaCd.segment(phiIdx, dRphi_phi.cols()); // Total gradient
-    tms["10-solveCxAoA"].stop();
-
-    //***** Gradient wrt mesh coordinates *****//
-    //*****************************************//
-    // Ck (cL, cd)
-    // Solution lambdaCl_x of (from augmented Lagrangian, eqn d/dx )
-    // "dCk_x + dRphi_x * lambdaCk_phi + dRdStar_x * lambdaCk_x + dRblw_x * lambdaCk_blw + dRx_x * lambdaCk_x = 0"
-
-    tms["12-solveCxMesh"].start();
+    tms2["10-solveCxAoA"].stop();
+
+    //**************************************************************************//
+    //                     Gradients wrt mesh coordinates                       //
+    //--------------------------------------------------------------------------//
+    // Ck (cL, cd)                                                              //
+    // Solution lambdaCl_x of (from augmented Lagrangian, eqn d/dx )            //
+    // "dCk_x + dRphi_x * lambdaCk_phi + dRdStar_x * lambdaCk_x                 //
+    // + dRblw_x * lambdaCk_blw + dRx_x * lambdaCk_x = 0"                       //
+    //**************************************************************************//
+
+    tms2["12-solveCxMesh"].start();
     Eigen::VectorXd rhsCl_x = dCl_x;
     rhsCl_x -= dRphi_x.transpose() * lambdaCl.segment(phiIdx, dRphi_phi.cols()); // Potential contribution
     rhsCl_x -= dRM_x.transpose() * lambdaCl.segment(machIdx, dRM_M.cols()); // Mach number contribution
@@ -339,8 +345,32 @@ void CoupledAdjoint::run()
             tdCd_x[n->row](m) = lambdaCd_x[isol->pbl->nDim * (n->row) + m];
         }
     }
-    tms["12-solveCxMesh"].stop();
-    //std::cout << tms << std::endl;
+    tms2["12-solveCxMesh"].stop();
+    tms["2-Solve"].stop();
+
+    // Print output
+    // aoa gradients
+    std::cout << "-------------- Adjoint solution --------------" << std::endl;
+    std::cout << std::setw(15) << std::left << "AoA gradients"
+              << std::setw(15) << std::right << "dCl_dAoA"
+              << std::setw(15) << std::right << "dCd_dAoA" << std::endl;
+    std::cout << std::fixed << std::setprecision(5);
+    std::cout << std::setw(15) << std::left << ""
+              << std::setw(15) << std::right << tdCl_AoA
+              << std::setw(15) << std::right << tdCd_AoA << std::endl;
+    // mesh gradients
+    std::cout << std::setw(15) << std::left << "Mesh gradients"
+              << std::setw(15) << std::right << "Norm[dCl_dX]"
+              << std::setw(15) << std::right << "Norm[dCd_dX]" << std::endl;
+    std::cout << std::fixed << std::setprecision(5);
+    std::cout << std::setw(15) << std::left << ""
+              << std::setw(15) << std::right << Eigen::Map<Eigen::VectorXd>(lambdaCl_x.data(), lambdaCl_x.size()).norm()
+              << std::setw(15) << std::right << Eigen::Map<Eigen::VectorXd>(lambdaCd_x.data(), lambdaCd_x.size()).norm() << std::endl;
+
+    std::cout << "--------------- Adjoint timers ---------------" << std::endl;
+    std::cout << tms << "----------------------------------------------" << std::endl;
+    if (vsol->verbose > 2)
+        std::cout << tms2 << "----------------------------------------------" << std::endl;
 }
 
 /**
@@ -350,119 +380,67 @@ void CoupledAdjoint::run()
  */
 void CoupledAdjoint::gradientswrtInviscidFlow()
 {
-    //**** dRphi_phi ****//
+    //**************************************************************************//
+    //                                 dRphi_phi                                //
+    //--------------------------------------------------------------------------//
+    //                               Analytical                                 //
+    //**************************************************************************//
     dRphi_phi = iadjoint->getRu_U();
 
-    //**** dRM_phi, dRrho_phi, dRv_phi ****//
+    //**************************************************************************//
+    //                      dRM_phi, dRrho_phi, dRv_phi                         //
+    //--------------------------------------------------------------------------//
+    //                               Analytical                                 //
+    //**************************************************************************//
     auto pbl = isol->pbl;
-    // Finite difference
-    std::vector<double> Phi_save = isol->phi; // Differential of the independent variable (phi)
-    double deltaPhi = 1.e-8; // perturbation
-
-    std::vector<Eigen::Triplet<double>> tripletsdM;
-    std::vector<Eigen::Triplet<double>> tripletsdrho;
-    std::vector<Eigen::Triplet<double>> tripletsdv;
-
-    for (auto n : pbl->msh->nodes){
-        Phi_save[n->row] = isol->phi[n->row] + deltaPhi;
-
-        // Recompute the quantities on surface nodes.
-        size_t jj = 0; 
-        for (auto sec: vsol->sections[0]){
-            int iReg = 0;
-            if (sec->name == "wake")
-                iReg = 1;
-            else if (sec->name == "upper" || sec->name == "lower")
-                iReg = 0;
-            else
-                throw std::runtime_error("gradientswrtInviscidFlow: Unknown section name");
-            for (size_t iNode = 0; iNode < sec->nNodes; ++iNode){
-                tbox::Node* srfNode = pbl->bBCs[iReg]->nodes[sec->rows[iNode]];
-                double dM = 0.; double drho = 0.;
-                Eigen::Vector3d dv = Eigen::Vector3d::Zero();
-                // Average of the quantity on the elements adjacent to the considered node.
-                for (auto e : pbl->fluid->neMap[srfNode]){
-                    dM += pbl->fluid->mach->eval(*e, Phi_save, 0);
-                    drho += pbl->fluid->rho->eval(*e, Phi_save, 0);
-                    Eigen::VectorXd grad = e->computeGradient(Phi_save, 0);
-                    for (int i = 0; i < grad.size(); ++i)
-                        dv(i) += grad(i);
+
+    std::deque<Eigen::Triplet<double>> T_dM;
+    std::deque<Eigen::Triplet<double>> T_drho;
+    std::deque<Eigen::Triplet<double>> T_dv;
+
+    size_t jj = 0;
+    int iReg = 0;
+    for (auto sec : vsol->sections[0])
+    {
+        if (sec->name == "wake")
+            iReg = 1;
+        else if (sec->name == "upper" || sec->name == "lower")
+            iReg = 0;
+        else
+            throw std::runtime_error("gradientswrtInviscidFlow: Unknown section name");
+        for (size_t iNode = 0; iNode < sec->nNodes; ++iNode)
+        {
+            tbox::Node* srfNode = pbl->bBCs[iReg]->nodes[sec->rows[iNode]];
+            double nAdjElms = static_cast<double>(pbl->fluid->neMap[srfNode].size());
+            for (auto e: pbl->fluid->neMap[srfNode])
+            {
+                // dv/dphi = dv/dgradPhi * dgradPhi/dphi = dgradPhi/dphi = d(gradN_k phi_k) / dphi_j
+                // dM/dphi = dM/dgradPhi * dgradPhi/dphi = dM/dgradPhi * dv/dphi
+                // drho/dphi = drho/dgradPhi * dgradPhi/dphi = drho/dgradPhi * dv/dphi
+                Eigen::MatrixXd gradV = e->getJinv(0) * e->getVCache().getDsf(0);
+                Eigen::VectorXd gradM = isol->pbl->fluid->mach->evalGrad(*e, isol->phi, 0) * e->computeGradient(isol->phi, 0).transpose() * gradV;
+                Eigen::VectorXd gradrho = isol->pbl->fluid->rho->evalGrad(*e, isol->phi, 0) * e->computeGradient(isol->phi, 0).transpose() * gradV;
+                for (size_t k = 0; k < e->nodes.size(); ++k)
+                {
+                    T_dM.push_back(Eigen::Triplet<double>(jj, e->nodes[k]->row, -gradM(k)/nAdjElms));
+                    T_drho.push_back(Eigen::Triplet<double>(jj, e->nodes[k]->row, -gradrho(k)/nAdjElms));
+                    for (int idim = 0; idim < pbl->nDim; ++idim)
+                        T_dv.push_back(Eigen::Triplet<double>(jj*pbl->nDim + idim, e->nodes[k]->row, -gradV(k*pbl->nDim + idim)/nAdjElms));
                 }
-                dM   /= static_cast<double>(pbl->fluid->neMap[srfNode].size());
-                drho /= static_cast<double>(pbl->fluid->neMap[srfNode].size());
-                dv   /= static_cast<double>(pbl->fluid->neMap[srfNode].size());
-
-                // Form triplets
-                // Minus because M = f(phi) and therefore RM = M - f(phi) = 0
-                tripletsdM.push_back(Eigen::Triplet<double>(jj, n->row, -(dM - isol->M[srfNode->row])/deltaPhi));
-                tripletsdrho.push_back(Eigen::Triplet<double>(jj, n->row, -(drho - isol->rho[srfNode->row])/deltaPhi));
-                for (int i = 0; i < pbl->nDim; ++i)
-                    tripletsdv.push_back(Eigen::Triplet<double>(jj*pbl->nDim + i, n->row, -(dv(i) - isol->U[srfNode->row](i))/deltaPhi));
-                jj++;
             }
+            ++jj;
         }
-        // Reset phi
-        Phi_save[n->row] = isol->phi[n->row];
     }
-    // Fill matrices with gradients
-    dRM_phi.setFromTriplets(tripletsdM.begin(), tripletsdM.end());
-    dRrho_phi.setFromTriplets(tripletsdrho.begin(), tripletsdrho.end());
-    dRv_phi.setFromTriplets(tripletsdv.begin(), tripletsdv.end());
-    // Remove zeros
+    dRM_phi.setFromTriplets(T_dM.begin(), T_dM.end());
+    dRrho_phi.setFromTriplets(T_drho.begin(), T_drho.end());
+    dRv_phi.setFromTriplets(T_dv.begin(), T_dv.end());
     dRM_phi.prune(0.); dRrho_phi.prune(0.); dRv_phi.prune(0.);
 
-    // // Analytical
-    // std::vector<Eigen::Triplet<double>> tripletsdM_an;
-
-    // size_t jj = 0;
-    // int iReg = 0;
-    // for (auto sec : vsol->sections[0])
-    // {
-    //     if (sec->name == "wake")
-    //         iReg = 1;
-    //     else if (sec->name == "upper" || sec->name == "lower")
-    //         iReg = 0;
-    //     else
-    //         throw std::runtime_error("gradientswrtInviscidFlow: Unknown section name");
-    //     for (size_t iNode = 0; iNode < sec->nNodes; ++iNode)
-    //     {
-    //         tbox::Node* srfNode = pbl->bBCs[iReg]->nodes[sec->rows[iNode]];
-    //         for (auto e: pbl->fluid->neMap[srfNode])
-    //         {
-    //             // Get pre-computed values
-    //             tbox::Cache &cache = e->getVCache();
-    //             tbox::Gauss &gauss = cache.getVGauss();
-    //             Eigen::VectorXd grad = Eigen::VectorXd::Zero(e->nodes.size());
-    //             for (size_t k = 0; k < gauss.getN(); ++k)
-    //             {
-    //                 // Gauss point and determinant
-    //                 double wdj = gauss.getW(k) * e->getDetJ(k);
-    //                 // Shape functions and solution gradient
-    //                 Eigen::MatrixXd const &dSf = e->getJinv(k) * cache.getDsf(k);
-    //                 Eigen::VectorXd dPhi = e->computeGradient(isol->phi, k);
-    //                 grad += isol->pbl->fluid->mach->evalGrad(*e, isol->phi, k) * dSf.transpose() * dPhi;
-    //             }
-    //             for (size_t k = 0; k < e->nodes.size(); ++k)
-    //             {
-    //                 tripletsdM_an.push_back(Eigen::Triplet<double>(jj, e->nodes[k]->row, -grad(k)/e->nodes.size()));
-    //             }
-    //         }
-    //         ++jj;
-    //     }
-    // }
-    // Eigen::SparseMatrix<double, Eigen::RowMajor> dRM_phi_an(dRM_phi.rows(), dRM_phi.cols());
-    // dRM_phi_an.setFromTriplets(tripletsdM_an.begin(), tripletsdM_an.end());
-    // dRM_phi_an.prune(0.);
-    // writeMatrixToFile(dRM_phi_an, "dRM_phi_an.txt");
-    // writeMatrixToFile(dRM_phi, "dRM_phi.txt");
-    // writeMatrixToFile((dRM_phi_an - dRM_phi), "dif.txt");
-    // std::cout << "written" << std::endl;
-    // std::cout << dRM_phi_an - dRM_phi << std::endl;
-    
-    // throw;
-    
-
-    //**** partials dCl_phi, dCd_phi ****//
+    //**************************************************************************//
+    //                             dCl_phi, dCd_phi                             //
+    //--------------------------------------------------------------------------//
+    //                               Analytical                                 //
+    //**************************************************************************//
     std::vector<std::vector<double>> dCx_phi = iadjoint->computeGradientCoefficientsFlow();
     dCl_phi = Eigen::VectorXd::Map(dCx_phi[0].data(), dCx_phi[0].size());
     dCd_phi = Eigen::VectorXd::Map(dCx_phi[1].data(), dCx_phi[1].size());
@@ -475,10 +453,16 @@ void CoupledAdjoint::gradientswrtInviscidFlow()
  */
 void CoupledAdjoint::gradientswrtMachNumber()
 {
-    /**** dRM_M ****/
+    //**************************************************************************//
+    //                                   dRM_M                                  //
+    //**************************************************************************//
     dRM_M.setIdentity();
 
-    //**** dRdStar_M ****//
+    //**************************************************************************//
+    //                                 dRdStar_M                                //
+    //--------------------------------------------------------------------------//
+    //                         Central finite-difference                        //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T;
     double delta = 1e-6;
     size_t i = 0;
@@ -524,10 +508,16 @@ void CoupledAdjoint::gradientswrtDensity()
     for (auto bBC : isol->pbl->bBCs)
         nEs += bBC->uE.size();                          // Number of blowing elements
 
-    //**** dRrho_rho ****//
+    //**************************************************************************//
+    //                                 dRrho_rho                                //
+    //**************************************************************************//
     dRrho_rho.setIdentity();
 
-    //**** dRblw_rho ****//
+    //**************************************************************************//
+    //                                 dRblw_rho                                //
+    //--------------------------------------------------------------------------//
+    //                               Analytical                                 //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T_blw;
     int offSetElms = 0;
     int offSetNodes = 0;
@@ -560,7 +550,9 @@ void CoupledAdjoint::gradientswrtVelocity()
     for (auto bBC : isol->pbl->bBCs)
         nEs += bBC->uE.size();                          // Number of blowing elements
 
-    /**** dRv_v ****/
+    //**************************************************************************//
+    //                                   dRv_v                                  //
+    //**************************************************************************//
     dRv_v.setIdentity();
 
     //**** Get velocity****/
@@ -583,7 +575,11 @@ void CoupledAdjoint::gradientswrtVelocity()
         }
     }
 
-    //**** dvt_v (analytical) ****//
+    //**************************************************************************//
+    //                                 dvt_v                                    //
+    //--------------------------------------------------------------------------//
+    //                               Analytical                                 //
+    //**************************************************************************//
     Eigen::SparseMatrix<double, Eigen::RowMajor> dVt_v(nNs, nNs * nDim);
     std::deque<Eigen::Triplet<double>> T_vt;
 
@@ -599,7 +595,11 @@ void CoupledAdjoint::gradientswrtVelocity()
     dVt_v.setFromTriplets(T_vt.begin(), T_vt.end());
     dVt_v.prune(0.);
 
-    //**** dRdStar_vt (finite-difference) ****//
+    //**************************************************************************//
+    //                                 dRdStar_vt                               //
+    //--------------------------------------------------------------------------//
+    //                          Central finite-difference                       //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T;
     double delta = 1e-6;
     i = 0;
@@ -630,14 +630,22 @@ void CoupledAdjoint::gradientswrtVelocity()
     dRdStar_vt.setFromTriplets(T.begin(), T.end());
     dRdStar_vt.prune(0.);
 
-    //**** dRdStar_v ****//
+    //**************************************************************************//
+    //                                 dRdStar_v                                //
+    //**************************************************************************//
     dRdStar_v = dRdStar_vt * dVt_v;
     dRdStar_v.prune(0.);
 
-    //**** dRCdf_v ****//
+    //**************************************************************************//
+    //                                   dCdf_v                                 //
+    //**************************************************************************//
     dCd_v = dCd_vt.transpose() * dVt_v; // [1xnNs] x [nNs x nNs*nDim] = [1 x nNs*nDim]
 
-    //**** dRblw_vt (analytical) ****//
+    //**************************************************************************//
+    //                                 dRblw_vt                                 //
+    //--------------------------------------------------------------------------//
+    //                                 Analytical                               //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T_blw;
     int offSetElms = 0;
     int offSetNodes = 0;
@@ -655,7 +663,9 @@ void CoupledAdjoint::gradientswrtVelocity()
     dRblw_vt.setFromTriplets(T_blw.begin(), T_blw.end());
     dRblw_vt.prune(0.);
     
-    //**** dRblw_v ****//
+    //**************************************************************************//
+    //                                   dRblw_v                                //
+    //**************************************************************************//
     dRblw_v = dRblw_vt * dVt_v;
     dRblw_v.prune(0.);
 }
@@ -667,7 +677,11 @@ void CoupledAdjoint::gradientswrtVelocity()
  */
 void CoupledAdjoint::gradientswrtDeltaStar()
 {
-    //**** dRdStar_dStar (finite-difference) ****//
+    //**************************************************************************//
+    //                              dRdStar_dStar                               //
+    //--------------------------------------------------------------------------//
+    //                        Central finite-difference                         //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T;
     double delta = 1e-6;
     double saveDStar = 0.;
@@ -701,7 +715,11 @@ void CoupledAdjoint::gradientswrtDeltaStar()
     dRdStar_dStar -= dRdStar_dStar_dum;
     dRdStar_dStar.prune(0.);
 
-    //**** dRblw_dStar (analytical) ****//
+    //**************************************************************************//
+    //                                 dRblw_dStar                              //
+    //--------------------------------------------------------------------------//
+    //                                 Analytical                               //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T_blw;
     int offSetElms = 0;
     int offSetNodes = 0;
@@ -725,7 +743,11 @@ void CoupledAdjoint::gradientswrtDeltaStar()
  */
 void CoupledAdjoint::gradientswrtBlowingVelocity()
 {
-    /**** dRphi_blw ****/
+    //**************************************************************************//
+    //                                 dRphi_blw                                //
+    //--------------------------------------------------------------------------//
+    //                                 Analytical                               //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T;
 
     size_t jj = 0;
@@ -762,9 +784,19 @@ void CoupledAdjoint::gradientswrtBlowingVelocity()
  * Zeros are: dRM_AoA, dRrho_AoA, dRv_AoA, dRdStar_AoA, dRblw_AoA, dRx_AoA
  */
 void CoupledAdjoint::gradientwrtAoA(){
+    //**************************************************************************//
+    //                              dCl_Aoa dCd_Aoa                             //
+    //--------------------------------------------------------------------------//
+    //                                 Analytical                               //
+    //**************************************************************************//
     std::vector<double> dCx_AoA = iadjoint->computeGradientCoefficientsAoa();
     dCl_AoA = dCx_AoA[0]; dCd_AoA = dCx_AoA[1];
 
+    //**************************************************************************//
+    //                                 dRphi_Aoa                                //
+    //--------------------------------------------------------------------------//
+    //                                 Analytical                               //
+    //**************************************************************************//
     dRphi_AoA = iadjoint->getRu_A();
 }
 
@@ -775,22 +807,43 @@ void CoupledAdjoint::gradientwrtAoA(){
  */
 void CoupledAdjoint::gradientwrtMesh(){
 
-    /**** dCk_dx ****/
+    int nDim = isol->pbl->nDim;
+
+    //**************************************************************************//
+    //                               dCl_x, dCd_x                               //
+    //--------------------------------------------------------------------------//
+    //                                 Analytical                               //
+    //**************************************************************************//
     std::vector<std::vector<double>> dCx_x = iadjoint->computeGradientCoefficientsMesh();
     dCl_x = Eigen::Map<Eigen::VectorXd>(dCx_x[0].data(), dCx_x[0].size());
     dCdp_x = Eigen::Map<Eigen::VectorXd>(dCx_x[1].data(), dCx_x[1].size());
 
-    /**** dRphi_x ****/
+    //**************************************************************************//
+    //                                  dRphi_x                                 //
+    //--------------------------------------------------------------------------//
+    //                                 Analytical                               //
+    //**************************************************************************//
     dRphi_x = iadjoint->getRu_X();
-    /**** dRx_x ****/
+    //**************************************************************************//
+    //                                   dRx_x                                  //
+    //--------------------------------------------------------------------------//
+    //                                 Analytical                               //
+    //**************************************************************************//
     dRx_x = iadjoint->getRx_X();
 
-    /**** dRdStar_x ****/
+    //**************************************************************************//
+    //                            dRdStar_x, dCdf_dx                            //
+    //--------------------------------------------------------------------------//
+    //                         Central finite-difference                        //
+    //--------------------------------------------------------------------------//
+    // We don't do dRdStar_x = dRdStar_loc * dloc_dx because Cdf = f(xi(x), x)  //
+    // and we would have to compute dCdf/dx and dCdf/dloc. Same for deltaStar.  //
+    // It is more computationally expansive to compute                          //
+    // ddeltaStar/dx, ddeltaStar/dloc than ddeltaStar_dx, ddeltaStar_dy         //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T_dStar_x;
     double delta = 1e-8;
-    size_t i = 0;
     int iReg = 0;
-    double saveX = 0.;
     std::vector<Eigen::VectorXd> ddStar(2, Eigen::VectorXd::Zero(dRdStar_M.cols()));
     std::vector<double> dCdf(2, 0.);
     for (auto sec: vsol->sections[0])
@@ -805,7 +858,7 @@ void CoupledAdjoint::gradientwrtMesh(){
         {
             int rowj = isol->pbl->bBCs[iReg]->nodes[sec->rows[j]]->row;
             // x
-            saveX = sec->x[j];
+            double saveX = sec->x[j];
 
             sec->x[j] = saveX + delta;
             sec->computeLocalCoordinates();
@@ -819,36 +872,43 @@ void CoupledAdjoint::gradientwrtMesh(){
             dCdf[1] = vsol->Cdf;
 
             sec->x[j] = saveX;
+            sec->xxExt = sec->loc;
+            sec->computeLocalCoordinates();
 
             for (int k = 0; k < ddStar[0].size(); ++k)
                 T_dStar_x.push_back(Eigen::Triplet<double>(k, rowj*isol->pbl->nDim+0, -(ddStar[0][k] - ddStar[1][k])/(2.*delta)));
             dCdf_x(rowj*isol->pbl->nDim+0) += (dCdf[0] - dCdf[1])/(2.*delta);
             // y
-            saveX = sec->y[j];
+            double saveY = sec->y[j];
 
-            sec->y[j] = saveX + delta;
+            sec->y[j] = saveY + delta;
             sec->computeLocalCoordinates();
             sec->xxExt = sec->loc;
             ddStar[0] = this->runViscous();
             dCdf[0] = vsol->Cdf;
-            sec->y[j] = saveX - delta;
+            sec->y[j] = saveY - delta;
             sec->computeLocalCoordinates();
             sec->xxExt = sec->loc;
             ddStar[1] = this->runViscous();
             dCdf[1] = vsol->Cdf;
 
-            sec->y[j] = saveX;
+            sec->y[j] = saveY;
+            sec->xxExt = sec->loc;
+            sec->computeLocalCoordinates();
 
             for (int k = 0; k < ddStar[0].size(); ++k)
                 T_dStar_x.push_back(Eigen::Triplet<double>(k, rowj*isol->pbl->nDim+1, -(ddStar[0][k] - ddStar[1][k])/(2.*delta)));
             dCdf_x(rowj*isol->pbl->nDim+1) += (dCdf[0] - dCdf[1])/(2.*delta);
-            ++i;
         }
     }
     dRdStar_x.setFromTriplets(T_dStar_x.begin(), T_dStar_x.end());
     dRdStar_x.prune(0.);
 
-    /**** dRblw_x ****/
+    //**************************************************************************//
+    //                                dRblw_x                                   //
+    //--------------------------------------------------------------------------//
+    //                               Analytical                                 //
+    //**************************************************************************//
     std::deque<Eigen::Triplet<double>> T_blw_x;
     int offSetElms = 0;
     for (const auto& sec: vsol->sections[0])
@@ -873,167 +933,69 @@ void CoupledAdjoint::gradientwrtMesh(){
     dRblw_x.setFromTriplets(T_blw_x.begin(), T_blw_x.end());
     dRblw_x.prune(0.);
 
-    /**** dRM_x, dRrho_x, dRv_x ****/
-    double delta_x = 1e-8;
+    //**************************************************************************//
+    //                         dRM_x, dRrho_x, dRv_x                            //
+    //--------------------------------------------------------------------------//
+    //                              Analytical                                  //
+    //**************************************************************************//
     auto pbl = isol->pbl;
-    std::vector<Eigen::Triplet<double>> tripletsdM;
-    std::vector<Eigen::Triplet<double>> tripletsdrho;
-    std::vector<Eigen::Triplet<double>> tripletsdv;
-
-    for (auto n : pbl->msh->nodes){
-        for (int idim = 0; idim < isol->pbl->nDim; ++idim){
-            // Modify node position
-            double save = n->pos[idim];
-            n->pos[idim] = save + delta_x;
-            for (auto e: pbl->msh->elems)
-                if (e->type() == tbox::ElType::LINE2 || e->type() == tbox::ElType::TRI3) e->update();
-
-            // Recompute the quantities on surface nodes.
-            size_t jj = 0; 
-            for (auto sec: vsol->sections[0]){
-                int iReg = 0;
-                if (sec->name == "wake")
-                    iReg = 1;
-                else if (sec->name == "upper" || sec->name == "lower")
-                    iReg = 0;
-                else
-                    throw std::runtime_error("gradientswrtInviscidFlow: Unknown section name");
-                for (size_t iNode = 0; iNode < sec->nNodes; ++iNode){
-                    tbox::Node* srfNode = pbl->bBCs[iReg]->nodes[sec->rows[iNode]];
-                    double dM = 0.; double drho = 0.;
-                    Eigen::Vector3d dv = Eigen::Vector3d::Zero();
-                    // Average of the quantity on the elements adjacent to the considered node.
-                    for (auto e : pbl->fluid->neMap[srfNode]){
-                        dM += pbl->fluid->mach->eval(*e, isol->phi, 0);
-                        drho += pbl->fluid->rho->eval(*e, isol->phi, 0);
-                        Eigen::VectorXd grad = e->computeGradient(isol->phi, 0);
-                        for (int i = 0; i < grad.size(); ++i)
-                            dv(i) += grad(i);
-                    }
-                    dM   /= static_cast<double>(pbl->fluid->neMap[srfNode].size());
-                    drho /= static_cast<double>(pbl->fluid->neMap[srfNode].size());
-                    dv   /= static_cast<double>(pbl->fluid->neMap[srfNode].size());
-
-                    // Form triplets
-                    // Minus because M = f(phi) and therefore RM = M - f(phi) = 0
-                    tripletsdM.push_back(Eigen::Triplet<double>(jj, n->row*pbl->nDim + idim, -(dM - isol->M[srfNode->row])/delta_x));
-                    tripletsdrho.push_back(Eigen::Triplet<double>(jj, n->row*pbl->nDim + idim, -(drho - isol->rho[srfNode->row])/delta_x));
-                    for (int i = 0; i < pbl->nDim; ++i)
-                        tripletsdv.push_back(Eigen::Triplet<double>(jj*pbl->nDim + i, n->row*pbl->nDim + idim, -(dv(i) - isol->U[srfNode->row](i))/delta_x));
-                    jj++;
-                }
-            }
-            // Reset node pos
-            n->pos[idim] = save;
-        }
-    }
-    // Fill matrices with gradients
-    dRM_x.setFromTriplets(tripletsdM.begin(), tripletsdM.end());
-    dRrho_x.setFromTriplets(tripletsdrho.begin(), tripletsdrho.end());
-    dRv_x.setFromTriplets(tripletsdv.begin(), tripletsdv.end());
-    // Remove zeros
-    dRM_x.prune(0.); dRrho_x.prune(0.); dRv_x.prune(0.);
-}
-
-void CoupledAdjoint::setdRdStar_M(std::vector<std::vector<double>> _dRdStar_dM){
-    std::vector<Eigen::Triplet<double>> triplets;
-    for (size_t i = 0; i < _dRdStar_dM.size(); i++){
-        for (size_t j = 0; j < _dRdStar_dM[i].size(); j++){
-            triplets.push_back(Eigen::Triplet<double>(i, j, _dRdStar_dM[i][j]));
-        }
-    }
-    // Set matrix
-    dRdStar_M.setFromTriplets(triplets.begin(), triplets.end());
-    dRdStar_M.prune(0.);
-}
-
-void CoupledAdjoint::setdRdStar_v(std::vector<std::vector<double>> _dRdStar_dv){
-    std::vector<Eigen::Triplet<double>> triplets;
-    for (size_t i = 0; i < _dRdStar_dv.size(); i++){
-        for (size_t j = 0; j < _dRdStar_dv[i].size(); j++){
-            triplets.push_back(Eigen::Triplet<double>(i, j, _dRdStar_dv[i][j]));
-        }
-    }
-    // Set matrix
-    dRdStar_v.setFromTriplets(triplets.begin(), triplets.end());
-    dRdStar_v.prune(0.);
-}
 
-void CoupledAdjoint::setdRdStar_dStar(std::vector<std::vector<double>> _dRdStar_dStar){
-    std::vector<Eigen::Triplet<double>> triplets;
-    for (size_t i = 0; i < _dRdStar_dStar.size(); i++){
-        for (size_t j = 0; j < _dRdStar_dStar[i].size(); j++){
-            triplets.push_back(Eigen::Triplet<double>(i, j, _dRdStar_dStar[i][j]));
-        }
-    }
-    // Set matrix
-    dRdStar_dStar.setFromTriplets(triplets.begin(), triplets.end());
-    dRdStar_dStar.prune(0.);
-}
+    std::deque<Eigen::Triplet<double>> T_dM_x;
+    std::deque<Eigen::Triplet<double>> T_drho_x;
+    std::deque<Eigen::Triplet<double>> T_dv_x;
 
-void CoupledAdjoint::setdRdStar_x(std::vector<std::vector<double>> _dRdStar_x){
-    std::vector<Eigen::Triplet<double>> triplets;
-    for (size_t i = 0; i < _dRdStar_x.size(); i++){
-        for (size_t j = 0; j < _dRdStar_x[i].size(); j++){
-            triplets.push_back(Eigen::Triplet<double>(i, j, _dRdStar_x[i][j]));
-        }
-    }
-    // Set matrix
-    dRdStar_x.setFromTriplets(triplets.begin(), triplets.end());
-    dRdStar_x.prune(0.);
-}
-
-void CoupledAdjoint::setdRblw_rho(std::vector<std::vector<double>> _dRblw_rho){
-    std::vector<Eigen::Triplet<double>> triplets;
-    for (size_t i = 0; i < _dRblw_rho.size(); i++){
-        for (size_t j = 0; j < _dRblw_rho[i].size(); j++){
-            triplets.push_back(Eigen::Triplet<double>(i, j, _dRblw_rho[i][j]));
-        }
-    }
-    // Set matrix
-    dRblw_rho.setFromTriplets(triplets.begin(), triplets.end());
-    dRblw_rho.prune(0.);
-}
-
-void CoupledAdjoint::setdRblw_v(std::vector<std::vector<double>> _dRblw_v){
-    std::vector<Eigen::Triplet<double>> triplets;
-    for (size_t i = 0; i < _dRblw_v.size(); i++){
-        for (size_t j = 0; j < _dRblw_v[i].size(); j++){
-            triplets.push_back(Eigen::Triplet<double>(i, j, _dRblw_v[i][j]));
-        }
-    }
-    // Set matrix
-    dRblw_v.setFromTriplets(triplets.begin(), triplets.end());
-    dRblw_v.prune(0.);
-}
-
-void CoupledAdjoint::setdRblw_dStar(std::vector<std::vector<double>> _dRblw_dStar){
-    std::vector<Eigen::Triplet<double>> triplets;
-    for (size_t i = 0; i < _dRblw_dStar.size(); i++){
-        for (size_t j = 0; j < _dRblw_dStar[i].size(); j++){
-            triplets.push_back(Eigen::Triplet<double>(i, j, _dRblw_dStar[i][j]));
-        }
-    }
-    // Set matrix
-    dRblw_dStar.setFromTriplets(triplets.begin(), triplets.end());
-    dRblw_dStar.prune(0.);
-}
+    int jj = 0;
+    iReg = 0;
 
-void CoupledAdjoint::setdRblw_x(std::vector<std::vector<double>> _dRblw_x){
-    std::vector<Eigen::Triplet<double>> triplets;
-    for (size_t i = 0; i < _dRblw_x.size(); i++){
-        for (size_t j = 0; j < _dRblw_x[i].size(); j++){
-            triplets.push_back(Eigen::Triplet<double>(i, j, _dRblw_x[i][j]));
+    for (auto sec : vsol->sections[0])
+    {
+        if (sec->name == "wake")
+            iReg = 1;
+        else if (sec->name == "upper" || sec->name == "lower")
+            iReg = 0;
+        else
+            throw std::runtime_error("gradientswrtInviscidFlow: Unknown section name");
+        for (size_t iNode = 0; iNode < sec->nNodes; ++iNode)
+        {
+            tbox::Node* srfNode = pbl->bBCs[iReg]->nodes[sec->rows[iNode]];
+            double nAdjElms = static_cast<double>(pbl->fluid->neMap[srfNode].size());
+            for (auto e: pbl->fluid->neMap[srfNode])
+            {
+                // dv/dx = dv/dgradPhi * dgradPhi/dx = dgradPhi/dx = (-J^(-1) * dJ/dx_j)*grad_xPhi
+                // dM/dx = dM/dgradPhi * dgradPhi/dx = dM/dgradPhi * gradPhi * dv/dx
+                // drho/dx = drho/dgradPhi * dgradPhi/dx = drho/dgradPhi * gradPhi * dv/dx
+                for (int inodOnElm = 0; inodOnElm < e->nodes.size(); inodOnElm++)
+                    for (int idim = 0; idim < nDim; ++idim)
+                    {
+                        Eigen::VectorXd gradV = (-e->getJinv(0)) * e->getGradJ(0)[inodOnElm*nDim + idim] * e->computeGradient(isol->phi, 0);
+                        double gradM = pbl->fluid->mach->evalGrad(*e, isol->phi, 0) * e->computeGradient(isol->phi, 0).transpose() * gradV;
+                        double gradrho = pbl->fluid->rho->evalGrad(*e, isol->phi, 0) * e->computeGradient(isol->phi, 0).transpose() * gradV;
+                        T_dM_x.push_back(Eigen::Triplet<double>(jj, e->nodes[inodOnElm]->row*nDim + idim, -gradM/nAdjElms));
+                        T_drho_x.push_back(Eigen::Triplet<double>(jj, e->nodes[inodOnElm]->row*nDim + idim, -gradrho/nAdjElms));
+                        for (int idim2 = 0; idim2 < nDim; idim2++)
+                            T_dv_x.push_back(Eigen::Triplet<double>(jj*nDim + idim2, e->nodes[inodOnElm]->row*nDim + idim, -gradV(idim2)/nAdjElms));
+                    }
+            }
+            ++jj;
         }
     }
-    // Set matrix
-    dRblw_x.setFromTriplets(triplets.begin(), triplets.end());
-    dRblw_x.prune(0.);
+    dRM_x.setFromTriplets(T_dM_x.begin(), T_dM_x.end());
+    dRrho_x.setFromTriplets(T_drho_x.begin(), T_drho_x.end());
+    dRv_x.setFromTriplets(T_dv_x.begin(), T_dv_x.end());
+    dRM_x.prune(0.); dRrho_x.prune(0.); dRv_x.prune(0.);
 }
 
+/**
+ * @brief Run the viscous solver and extract the deltaStar
+ * on all the stations
+ *
+ * @return Eigen::VectorXd deltaStar
+ */
 Eigen::VectorXd CoupledAdjoint::runViscous()
 {
     int exitCode = vsol->run();
+    if (exitCode != 0)
+        std::cout << "vsol terminated with exit code " << exitCode << std::endl;
     
     // Extract deltaStar
     std::vector<Eigen::VectorXd> dStar_p;
@@ -1108,6 +1070,17 @@ void CoupledAdjoint::transposeMatrices(){
 
 }
 
+/**
+ * @brief Write the matrices to files
+ * @param matrix Eigen matrix to write
+ * @param filename Name of the file to write
+ * @return void
+ * 
+ * The matrices are written in a file with the following format:
+ * - The first line contains the column headers
+ * - The following lines contain the matrix data
+ * - The matrix data is written with a precision of 12 digits
+ */
 void CoupledAdjoint::writeMatrixToFile(const Eigen::MatrixXd& matrix, const std::string& filename) {
     std::ofstream file(filename);
     if (file.is_open()) {
diff --git a/blast/src/DCoupledAdjoint.h b/blast/src/DCoupledAdjoint.h
index 086a70d31cd853d8508bf4d59e111bd4d8dac390..2cfa4ab515e890956d72b19bc3cbf31f85fbbc5f 100644
--- a/blast/src/DCoupledAdjoint.h
+++ b/blast/src/DCoupledAdjoint.h
@@ -116,7 +116,8 @@ private:
     Eigen::VectorXd dCdp_x;                ///< Partial derivative of the pressure drag coefficient with respect to the mesh coordinates
     Eigen::VectorXd dCdf_x;                ///< Partial derivative of the friction drag coefficient with respect to the mesh coordinates
 
-    fwk::Timers tms; //< internal timers
+    fwk::Timers tms;    //< internal timers
+    fwk::Timers tms2;   //< internal precise timers
 
 public:
     CoupledAdjoint(std::shared_ptr<dart::Adjoint> iAdjoint, std::shared_ptr<blast::Driver> vSolver);
@@ -125,16 +126,6 @@ public:
     void run();
     void reset();
 
-    void setdRdStar_M(std::vector<std::vector<double>> _dRdStar_M);
-    void setdRdStar_v(std::vector<std::vector<double>> _dRdStar_v);
-    void setdRdStar_dStar(std::vector<std::vector<double>> _dRdStar_dStar);
-    void setdRdStar_x(std::vector<std::vector<double>> _dRdStar_x);
-
-    void setdRblw_rho(std::vector<std::vector<double>> _dRblw_rho);
-    void setdRblw_v(std::vector<std::vector<double>> _dRblw_v);
-    void setdRblw_dStar(std::vector<std::vector<double>> _dRblw_ddStar);
-    void setdRblw_x(std::vector<std::vector<double>> _dRblw_dx);
-
 private:
     void buildAdjointMatrix(std::vector<std::vector<Eigen::SparseMatrix<double, Eigen::RowMajor>*>> &matrices, Eigen::SparseMatrix<double, Eigen::RowMajor> &matrixAdjoint);
 
diff --git a/blast/src/DFluxes.cpp b/blast/src/DFluxes.cpp
index 3cf81cc903ffe961ded40dfeff47b0c1a17bba1d..168b60e94e1cd9263e7a802da3d9e17fe7afcebd 100644
--- a/blast/src/DFluxes.cpp
+++ b/blast/src/DFluxes.cpp
@@ -61,11 +61,8 @@ VectorXd Fluxes::blLaws(size_t iPoint, BoundaryLayer *bl, std::vector<double> u)
 {
     size_t nVar = bl->getnVar();
 
-    MatrixXd timeMatrix = MatrixXd::Zero(5, 5);
-    VectorXd spaceVector = VectorXd::Zero(5);
-
     // Dissipation ratio.
-    double dissipRatio;
+    double dissipRatio = 0.;
     if (bl->name == "wake")
         dissipRatio = 0.9;
     else
@@ -146,39 +143,62 @@ VectorXd Fluxes::blLaws(size_t iPoint, BoundaryLayer *bl, std::vector<double> u)
     double ctEqa = bl->ctEq[iPoint];
     double usa = bl->us[iPoint];
 
+    //--------------------------------------------------------------------------------//
+    // Integral boundary layer equations.                                             //
+
     // Space part.
-    spaceVector(0) = dt_dx + (2 + u[1] - Mea * Mea) * (u[0] / u[3]) * due_dx - cfa / 2;
-    spaceVector(1) = u[0] * dHstar_dx + (2 * Hstar2a + Hstara * (1 - u[1])) * u[0] / u[3] * due_dx - 2 * cda + Hstara * cfa / 2;
-    spaceVector(2) = dN_dx - ax;
-    spaceVector(3) = due_dx - c * (u[1] * dt_dx + u[0] * dH_dx) - dueExt_dx + cExt * ddeltaStarExt_dx;
+    // spaceVector(0) = dt_dx + (2 + u[1] - Mea * Mea) * (u[0] / u[3]) * due_dx - cfa / 2;
+    // spaceVector(1) = u[0] * dHstar_dx + (2 * Hstar2a + Hstara * (1 - u[1])) * u[0] / u[3] * due_dx - 2 * cda + Hstara * cfa / 2;
+    // spaceVector(2) = dN_dx - ax;
+    // spaceVector(3) = due_dx - c * (u[1] * dt_dx + u[0] * dH_dx) - dueExt_dx + cExt * ddeltaStarExt_dx;
+
+    // if (bl->regime[iPoint] == 1)
+    //     spaceVector(4) = (2 * deltaa / u[4]) * dct_dx - 5.6 * (ctEqa - u[4] * dissipRatio) - 2 * deltaa * (4 / (3 * u[1] * u[0]) * (cfa / 2 - (((Hka - 1) / (6.7 * Hka * dissipRatio)) * ((Hka - 1) / (6.7 * Hka * dissipRatio)))) - 1 / u[3] * due_dx);
 
-    if (bl->regime[iPoint] == 1)
-        spaceVector(4) = (2 * deltaa / u[4]) * dct_dx - 5.6 * (ctEqa - u[4] * dissipRatio) - 2 * deltaa * (4 / (3 * u[1] * u[0]) * (cfa / 2 - (((Hka - 1) / (6.7 * Hka * dissipRatio)) * ((Hka - 1) / (6.7 * Hka * dissipRatio)))) - 1 / u[3] * due_dx);
+    // // Time part.
+    // timeMatrix(0, 0) = u[1] / u[3];
+    // timeMatrix(0, 1) = u[0] / u[3];
+    // timeMatrix(0, 3) = u[0] * u[1] / (u[3] * u[3]);
 
-    // Time part.
-    timeMatrix(0, 0) = u[1] / u[3];
-    timeMatrix(0, 1) = u[0] / u[3];
-    timeMatrix(0, 3) = u[0] * u[1] / (u[3] * u[3]);
+    // timeMatrix(1, 0) = (1 + u[1] * (1 - Hstara)) / u[3];
+    // timeMatrix(1, 1) = (1 - Hstara) * u[0] / u[3];
+    // timeMatrix(1, 3) = (2 - Hstara * u[1]) * u[0] / (u[3] * u[3]);
 
-    timeMatrix(1, 0) = (1 + u[1] * (1 - Hstara)) / u[3];
-    timeMatrix(1, 1) = (1 - Hstara) * u[0] / u[3];
-    timeMatrix(1, 3) = (2 - Hstara * u[1]) * u[0] / (u[3] * u[3]);
+    // timeMatrix(2, 2) = 1.;
 
-    timeMatrix(2, 2) = 1.;
+    // timeMatrix(3, 0) = -c * u[1];
+    // timeMatrix(3, 1) = -c * u[0];
+    // timeMatrix(3, 3) = 1.;
 
-    timeMatrix(3, 0) = -c * u[1];
-    timeMatrix(3, 1) = -c * u[0];
-    timeMatrix(3, 3) = 1.;
+    // if (bl->regime[iPoint] == 1)
+    // {
+    //     timeMatrix(4, 3) = 2 * deltaa / (usa * u[3] * u[3]);
+    //     timeMatrix(4, 4) = 2 * deltaa / (u[3] * u[4] * usa);
+    // }
+    // else
+    //     timeMatrix(4, 4) = 1.0;
+    //--------------------------------------------------------------------------------//
 
-    if (bl->regime[iPoint] == 1)
+    VectorXd result = VectorXd::Zero(5);
+
+    if (bl->regime[iPoint] == 0)
     {
-        timeMatrix(4, 3) = 2 * deltaa / (usa * u[3] * u[3]);
-        timeMatrix(4, 4) = 2 * deltaa / (u[3] * u[4] * usa);
+        result[0] = 0.5*(-2.0*u[0]*(1.0*u[1] - 2.0)*(c*(dH_dx*u[0] + dt_dx*u[1]) - cExt*ddeltaStarExt_dx + dueExt_dx - due_dx) + 1.0*(c*u[0]*u[1] + u[3])*(2.0*due_dx*u[0]*(2.*Hstar2a - Hstara*(u[1] - 1)) + 1.0*u[3]*(Hstara*cfa - 4*cda + 2.*dHstar_dx*u[0])) + 1.0*(2.*due_dx*u[0]*(-Mea*Mea + u[1] + 2) + u[3]*(-cfa + 2.*dt_dx))*(1.0*Hstara*c*u[0]*u[1] + 1.0*Hstara*u[3] - 2.0*c*u[0] - 1.0*u[3]))/(c*u[0]*u[1] + u[3]);
+        result[1] = 0.5*(2.0*u[0]*u[1]*(u[1] - 1)*(c*(dH_dx*u[0] + dt_dx*u[1]) - cExt*ddeltaStarExt_dx + dueExt_dx - due_dx) - 1.0*u[1]*(c*u[0]*u[1] + u[3])*(2.*due_dx*u[0]*(2.*Hstar2a - Hstara*(u[1] - 1)) + u[3]*(Hstara*cfa - 4*cda + 2.*dHstar_dx*u[0])) + 1.0*(2.*due_dx*u[0]*(-Mea*Mea + u[1] + 2) + u[3]*(-cfa + 2.*dt_dx))*(-1.0*Hstara*c*u[0]*u[1]*u[1] - 1.0*Hstara*u[1]*u[3] + 2.0*c*u[0]*u[1] + 1.0*u[1]*u[3] + 1.0*u[3]))/(u[0]*(c*u[0]*u[1] + u[3]));
+        result[2] = -1.0*ax + 1.0*dN_dx;
+        result[3] = 1.0*u[3]*(-1.0*c*(dH_dx*u[0] + dt_dx*u[1]) + 0.5*c*(2.*due_dx*u[0]*(-Mea*Mea + u[1] + 2) + u[3]*(-cfa + 2.*dt_dx)) + 1.0*cExt*ddeltaStarExt_dx - 1.0*dueExt_dx + 1.0*due_dx)/(c*u[0]*u[1] + u[3]);
+        result[4] = 0.;
+    }
+    else if (bl->regime[iPoint] == 1)
+    {
+        result[0] = (-u[0]*(u[1] - 2)*(c*(dH_dx*u[0] + dt_dx*u[1]) - cExt*ddeltaStarExt_dx + dueExt_dx - due_dx) + (c*u[0]*u[1] + u[3])*(2.*due_dx*u[0]*(2.*Hstar2a - Hstara*(u[1] - 1)) + u[3]*(Hstara*cfa - 4*cda + 2.*dHstar_dx*u[0]))/2. + (2.*due_dx*u[0]*(-Mea*Mea + u[1] + 2) + u[3]*(-cfa + 2.*dt_dx))*(Hstara*c*u[0]*u[1] + Hstara*u[3] - 2.*c*u[0] - u[3])/2.)/(c*u[0]*u[1] + u[3]);
+        result[1] = (2.*u[0]*u[1]*(u[1] - 1)*(c*(dH_dx*u[0] + dt_dx*u[1]) - cExt*ddeltaStarExt_dx + dueExt_dx - due_dx) - u[1]*(c*u[0]*u[1] + u[3])*(2.*due_dx*u[0]*(2.*Hstar2a - Hstara*(u[1] - 1)) + u[3]*(Hstara*cfa - 4*cda + 2.*dHstar_dx*u[0])) + (2.*due_dx*u[0]*(-Mea*Mea + u[1] + 2) + u[3]*(-cfa + 2.*dt_dx))*(-Hstara*c*u[0]*u[1]*u[1] - Hstara*u[1]*u[3] + 2.*c*u[0]*u[1] + u[1]*u[3] + u[3]))/(2.*u[0]*(c*u[0]*u[1] + u[3]));
+        result[2] = -ax + dN_dx;
+        result[3] = u[3]*(-2.*c*(dH_dx*u[0] + dt_dx*u[1]) + c*(2.*due_dx*u[0]*(-Mea*Mea + u[1] + 2) + u[3]*(-cfa + 2.*dt_dx)) + 2.*cExt*ddeltaStarExt_dx - 2.*dueExt_dx + 2.*due_dx)/(2.*(c*u[0]*u[1] + u[3]));
+        result[4] = (-Hka*Hka*c*deltaa*dissipRatio*dissipRatio*u[0]*u[1]*u[4]*(2.*due_dx*u[0]*(-Mea*Mea + u[1] + 2) + u[3]*(-cfa + 2.*dt_dx))/2. + Hka*Hka*deltaa*dissipRatio*dissipRatio*u[0]*u[1]*u[4]*(c*(dH_dx*u[0] + dt_dx*u[1]) - cExt*ddeltaStarExt_dx + dueExt_dx - due_dx) + usa*(c*u[0]*u[1] + u[3])*(6*Hka*Hka*dct_dx*deltaa*dissipRatio*dissipRatio*u[0]*u[1]*u[3] + 16.8*Hka*Hka*dissipRatio*dissipRatio*u[0]*u[1]*u[3]*u[4]*(-ctEqa + dissipRatio*u[4]) + 2.*deltaa*u[4]*(3*Hka*Hka*dissipRatio*dissipRatio*due_dx*u[0]*u[1] + u[3]*(-2.*Hka*Hka*cfa*dissipRatio*dissipRatio + 0.0891067052795723*(Hka - 1)*(Hka - 1))))/6)/(Hka*Hka*deltaa*dissipRatio*dissipRatio*u[0]*u[1]*(c*u[0]*u[1] + u[3]));
     }
-    else
-        timeMatrix(4, 4) = 1.0;
 
-    return timeMatrix.partialPivLu().solve(spaceVector);
+    return result;
 }
 
 /**