// Copyright (C) 2025 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#define BOOST_TEST_MODULE testLocalCutsGridAdapt2D
#define BOOST_TEST_DYN_LINK
#include <memory>
#include <iostream>
#include <fstream>
#include <boost/test/unit_test.hpp>
#include "StOpt/regression/LocalConstRegressionGeners.h"
#include "StOpt/regression/ContinuationCutsGridAdaptNonConcaveGeners.h"

#if defined   __linux
#include <fenv.h>
#define enable_abort_on_floating_point_exception() feenableexcept(FE_DIVBYZERO | FE_INVALID)
#endif

using namespace std;
using namespace Eigen;
using namespace StOpt;

BOOST_AUTO_TEST_CASE(testLocalCutsAsInDP)
{
#if defined   __linux
    enable_abort_on_floating_point_exception();
#endif

    /// function to maximize on grid [-5,5] \times [-5,5]
    //   max  -(x+y)+ xi
    //   xi <= x+ y

    // grid for storage
    double xMin = -5;
    double xMax = 5.;
    int nbMeshX = 10;
    double yMin = -5;
    double yMax = 5.;
    int nbMeshY = 10 ;

    // nb stock points
    int sizeForStock  = (nbMeshX + 1) * (nbMeshY + 1);

    // grid
    shared_ptr< GridAdapt2D > grid2D = make_shared<GridAdapt2D>(xMin, xMax, nbMeshX, yMin, yMax, nbMeshY);


    int nbSimul = 2;
    ArrayXXd  toRegressCut(sizeForStock, 3 * nbSimul);
    ArrayXXd x = ArrayXXd::Zero(1, nbSimul);
    for (int is  = 0;  is < nbSimul; ++is)
    {
        for (int j = 0; j < nbMeshY + 1; ++j)
            for (int i = 0; i < nbMeshX + 1; ++i)
            {
                int istock = i + j * (nbMeshX + 1);
                toRegressCut(istock, is) =  2 * (xMin + i + yMin + j); // value of the VB
                toRegressCut(istock, is + nbSimul) = 1; // cut value is 1 in x
                toRegressCut(istock, is + 2 * nbSimul) = 1; // cut value is 1 in y
            }
    }
    // conditional expectation
    ArrayXi nbMesh(1);
    nbMesh(0) = 1;
    shared_ptr<LocalConstRegression> localRegressor = make_shared<LocalConstRegression>(false, x, nbMesh);

    // creation continuation value object
    ContinuationCutsGridAdaptNonConcave  contCut(grid2D, localRegressor,  toRegressCut.transpose());

    // points that can be reached : all
    ArrayXXd   hypStock(2, 2);
    hypStock(0, 0) = xMin;
    hypStock(0, 1) = xMax;
    hypStock(1, 0) = yMin;
    hypStock(1, 1) = yMax;


    // one simulation
    vector< pair <shared_ptr< StOpt::GridAdaptBase>, shared_ptr<ArrayXXd>  > >  meshsAndCuts = contCut.getCutsASim(hypStock, 0);

    cout << " meshsAndCuts.size()" << meshsAndCuts.size() << endl ;
    BOOST_CHECK_EQUAL(meshsAndCuts.size(), (nbMeshX * nbMeshY));

    for (const auto &aMeshAndCuts : meshsAndCuts)
    {
        // cout << " meshsAndCuts "  << aMeshAndCuts.second << endl ;
        // cout << " PT " << aMeshAndCuts.first->getXCoord(0) << " a " <<  aMeshAndCuts.first->getYCoord(0) << endl ;
        shared_ptr<GridAdapt2D> const pGrid2D = dynamic_pointer_cast<GridAdapt2D>(aMeshAndCuts.first);
        BOOST_CHECK_EQUAL((*aMeshAndCuts.second)(0, 0), pGrid2D->getXCoord(0) + pGrid2D->getYCoord(0));
        BOOST_CHECK_EQUAL((*aMeshAndCuts.second)(1, 0), 1.);
        BOOST_CHECK_EQUAL((*aMeshAndCuts.second)(2, 0), 1.);
    }

}

/// the solution here is concave
/// calculating conditional ùmeshes while gathering should lead to a single grid
BOOST_AUTO_TEST_CASE(testLocalCutsAndGridAgregatingConcaveCase)
{
#if defined   __linux
    enable_abort_on_floating_point_exception();
#endif

    /// function to maximize on grid [-5,5] \times [-5,5]
    //   max  -(x+y)+ xi
    //   xi <= x+ y

    // grid for storage
    double xMin = -5;
    double xMax = 5;
    int nbMeshX = 10;
    double yMin = -5;
    double yMax = 5;
    int nbMeshY = 10 ;

    // grid
    shared_ptr< GridAdapt2D > grid2D = make_shared<GridAdapt2D>(xMin, xMax, nbMeshX, yMin, yMax, nbMeshY);

    // refine in [-2,-1] \times [-2,-1)  and [0,2] \time [1,3] but 2 times
    list< pair<shared_ptr< Mesh2D>, shared_ptr< vector< ArrayXi > > > >  meshes = grid2D->getMeshes();
    for (auto &mesh : meshes)
    {
        if (((mesh.first->getXL() >= -2) && (mesh.first->getXR() <= -1) && (mesh.first->getYB() >= -2) && (mesh.first->getYT() <= -1)) ||
                ((mesh.first->getXL() >= 0) && (mesh.first->getXR() <= 2) && (mesh.first->getYB() >= 1) && (mesh.first->getYT() <= 3)))
            grid2D->splitMesh(mesh);
    }

    BOOST_CHECK_EQUAL(grid2D->getNbPoints(), 142);
    meshes = grid2D->getMeshes();
    // in [0,2] \time [1,3] again
    for (auto &mesh : meshes)
    {
        if ((mesh.first->getXL() >= 0) && (mesh.first->getXR() <= 2) && (mesh.first->getYB() >= 1) && (mesh.first->getYT() <= 3))
            grid2D->splitMesh(mesh);
    }
    BOOST_CHECK_EQUAL(grid2D->getNbPoints(), 198);


    // get all points
    vector< ArrayXd > vecPoints = grid2D->getPoints();
    int nbSimul = 2;
    ArrayXXd  toRegressCut(vecPoints.size(), 3 * nbSimul);
    ArrayXXd x = ArrayXXd::Zero(1, nbSimul);
    for (int is  = 0;  is < nbSimul; ++is)
    {
        for (size_t i = 0  ; i < vecPoints.size();  ++i)
        {
            // f(x,y)= concave and increasing
            toRegressCut(i, is) = - pow(vecPoints[i][0] - 5, 2) - pow(vecPoints[i][1] - 5, 2.) + 100.  ; // value of the VB
            toRegressCut(i, is + nbSimul) =  -2 * vecPoints[i][0];
            toRegressCut(i, is + 2 * nbSimul) =  -2 * vecPoints[i][1];
        }
    }

    // conditional expectation
    ArrayXi nbMesh(1);
    nbMesh(0) = 1;
    shared_ptr<LocalConstRegression> localRegressor = make_shared<LocalConstRegression>(false, x, nbMesh);

    // creation continuation value object
    ContinuationCutsGridAdaptNonConcave  contCut(grid2D, localRegressor,  toRegressCut.transpose());

    // first gather all points
    ArrayXXd   hypStock(2, 2);
    hypStock(0, 0) = xMin;
    hypStock(0, 1) = xMax;
    hypStock(1, 0) = yMin;
    hypStock(1, 1) = yMax;


    // one simulation
    vector< pair <shared_ptr< StOpt::GridAdaptBase>, shared_ptr<ArrayXXd>  > >  meshsAndCuts = contCut.getCutsConcGatherASim(hypStock, 0, false);

    BOOST_CHECK_EQUAL(meshsAndCuts.size(), 1);
    BOOST_CHECK_EQUAL(meshsAndCuts[0].first->getNbPoints(), grid2D->getNbPoints());


}


/// the solution here is NOT concave anymore
/// calculating conditional meshes while gathering should lead to some grids
BOOST_AUTO_TEST_CASE(testLocalCutsAndGridAgregatingNotConcaveCase)
{
#if defined   __linux
    enable_abort_on_floating_point_exception();
#endif

    /// function to maximize on grid [-5,5] \times [-5,5]
    //   max  -(x+y)+ xi
    //   xi <= x+ y

    // grid for storage
    double xMin =  0;
    double xMax = 5;
    int nbMeshX = 5;
    double yMin = 0;
    double yMax = 5;
    int nbMeshY = 5 ;

    // grid
    shared_ptr< GridAdapt2D > grid2D = make_shared<GridAdapt2D>(xMin, xMax, nbMeshX, yMin, yMax, nbMeshY);

    // refine [0,2] \time [1,3] but 2 times
    list< pair<shared_ptr< Mesh2D>, shared_ptr< vector< ArrayXi > > > >  meshes = grid2D->getMeshes();
    for (auto &mesh : meshes)
    {
        if ((mesh.first->getXL() >= 0) && (mesh.first->getXR() <= 2) && (mesh.first->getYB() >= 1) && (mesh.first->getYT() <= 3))
            grid2D->splitMesh(mesh);
    }

    meshes = grid2D->getMeshes();
    // in [0,2] \time [1,3] again
    for (auto &mesh : meshes)
    {
        if ((mesh.first->getXL() >= 0) && (mesh.first->getXR() <= 2) && (mesh.first->getYB() >= 1) && (mesh.first->getYT() <= 3))
            grid2D->splitMesh(mesh);
    }

    meshes = grid2D->getMeshes();
    // at last refine in [1,2] [1,2]
    for (auto &mesh : meshes)
    {
        if ((mesh.first->getXL() >= 1) && (mesh.first->getXR() <= 2) && (mesh.first->getYB() >= 1) && (mesh.first->getYT() <= 2))
            grid2D->splitMesh(mesh);
    }

    meshes = grid2D->getMeshes();
    // at last refine in [3,5] [2,4]
    for (auto &mesh : meshes)
    {
        if ((mesh.first->getXL() >= 3) && (mesh.first->getXR() <= 5) && (mesh.first->getYB() >= 2) && (mesh.first->getYT() <= 4))
            grid2D->splitMesh(mesh);
    }



    // get all points
    vector< ArrayXd > vecPoints = grid2D->getPoints();
    int nbSimul = 2;
    ArrayXXd  toRegressCut(vecPoints.size(), 3 * nbSimul);
    ArrayXXd x = ArrayXXd::Zero(1, nbSimul);
    double x1NCMin = 0.75;
    double x1NCMax = 1.75;
    double y1NCMin = 1.25;
    double y1NCMax = 2.;
    double x2NCMin = 1.;
    double x2NCMax = 2;
    double y2NCMin = 2.5;
    double y2NCMax = 4.;
    double x3NCMin = 3.5;
    double x3NCMax = 4.5;
    double y3NCMin = 2.5;
    double y3NCMax = 3.5;

    for (int is  = 0;  is < nbSimul; ++is)
    {
        for (size_t i = 0  ; i < vecPoints.size();  ++i)
        {
            // Concavity rupture
            if (((vecPoints[i][0] >= x1NCMin - 1e-7) && (vecPoints[i][0] <= x1NCMax + 1e-7) && (vecPoints[i][1] >= y1NCMin - 1e-7) && (vecPoints[i][1] <= y1NCMax + 1e-7))
                    || ((vecPoints[i][0] >= x2NCMin - 1e-7) && (vecPoints[i][0] <= x2NCMax + 1e-7) && (vecPoints[i][1] >= y2NCMin - 1e-7) && (vecPoints[i][1] <= y2NCMax + 1e-7))
                    || ((vecPoints[i][0] >= x3NCMin - 1e-7) && (vecPoints[i][0] <= x3NCMax + 1e-7) && (vecPoints[i][1] >= y3NCMin - 1e-7) && (vecPoints[i][1] <= y3NCMax + 1e-7)))
            {
                toRegressCut(i, is) = log(vecPoints[i][0]) + log(vecPoints[i][1])  ; // value of the VB
                toRegressCut(i, is + nbSimul) = 1. / vecPoints[i][0];
                toRegressCut(i, is + 2 * nbSimul) =  1. / vecPoints[i][1];
            }
            else
            {
                toRegressCut(i, is) = - 2 * pow(vecPoints[i][0] - xMax, 2) - 2 * pow(vecPoints[i][1] - yMax, 2.)  ; // value of the VB
                toRegressCut(i, is + nbSimul) = -4 * (vecPoints[i][0] - xMax);
                toRegressCut(i, is + 2 * nbSimul) =  -4 * (vecPoints[i][1] - yMax);
            }
        }
    }

    // conditional expectation
    ArrayXi nbMesh(1);
    nbMesh(0) = 1;
    shared_ptr<LocalConstRegression> localRegressor = make_shared<LocalConstRegression>(false, x, nbMesh);

    // creation continuation value object
    ContinuationCutsGridAdaptNonConcave  contCut(grid2D, localRegressor,  toRegressCut.transpose());

    // first gather all points
    ArrayXXd   hypStock(2, 2);
    hypStock(0, 0) = xMin;
    hypStock(0, 1) = xMax;
    hypStock(1, 0) = yMin;
    hypStock(1, 1) = yMax;


    // one simulation
    vector< pair <shared_ptr< StOpt::GridAdaptBase>, shared_ptr<ArrayXXd>  > >  meshsAndCuts = contCut.getCutsConcGatherASim(hypStock, 0, false);

    cout << " NB GRIDS " << meshsAndCuts.size() << " Initial grid nb points " << grid2D->getNbPoints() <<  endl ;
    vector< ArrayXd >  points;
    points.reserve(grid2D->getNbPoints());
    for (const auto   &gridAndCuts : meshsAndCuts)
    {
        for (const auto &pt : gridAndCuts.first->getPoints())
        {
            bool bAdd = true;
            for (const auto &ptSt : points)
            {
                if (fabs(ptSt[0] - pt[0]) + fabs(ptSt[1] - pt[1]) < tiny)
                {
                    bAdd = false;
                    break;
                }
            }
            if (bAdd)
            {
                points.push_back(pt);
            }
        }
    }
    // missing points
    vector< ArrayXd >  pointsG = grid2D->getPoints();
    for (const auto &pt : pointsG)
    {
        bool bPres = false;
        for (const auto &ptSt : points)
        {
            if (fabs(ptSt[0] - pt[0]) + fabs(ptSt[1] - pt[1]) < tiny)
            {
                bPres = true;
                break;
            }
        }
        if (!bPres)
            cout << " MISSING POINTS IN GRID x :" << pt[0] << " y: " << pt[1] << endl;
    }
    BOOST_CHECK_EQUAL(static_cast<int>(points.size()), grid2D->getNbPoints());
    // check that grids points are the same
    vector< ArrayXd >  pointsInit = grid2D->getPoints();
    for (const auto &ptInt : pointsInit)
    {
        bool bPres = false;
        for (const auto &pt : points)
        {
            if (fabs(ptInt[0] - pt[0]) + fabs(ptInt[1] - pt[1]) < tiny)
            {
                bPres = true;
                break;
            }
        }
        BOOST_CHECK(bPres);
    }

    ofstream gridsFile("Grids.txt");
    for (const auto   &gridAndCuts : meshsAndCuts)
    {
        shared_ptr<GridAdapt2D> const pGrid2D = dynamic_pointer_cast<GridAdapt2D>(gridAndCuts.first);
        gridsFile <<  pGrid2D->getXMin() << " " << pGrid2D->getYMin() <<   "   " <<  pGrid2D->getXMax() - pGrid2D->getXMin();
        gridsFile << " " <<  pGrid2D->getYMax() - pGrid2D->getYMin() << endl ;
    }
    gridsFile.close();
    ofstream initialMeshFile("GridInit.txt");
    list< pair<shared_ptr< Mesh2D>, shared_ptr< vector< ArrayXi > > > >  meshesAndPos = grid2D->getMeshes();
    for (const auto &mesh : meshesAndPos)
    {
        initialMeshFile << mesh.first->getXL() <<  " " <<  mesh.first->getYB() << "  " <<   mesh.first->getXR() -  mesh.first->getXL() ;
        initialMeshFile << " "  <<  mesh.first->getYT() -  mesh.first->getYB() << endl ;
        cout <<  mesh.first->getXL() <<  " " <<  mesh.first->getYB() << "  " <<   mesh.first->getXR() -  mesh.first->getXL();
        cout <<  " "  <<  mesh.first->getYT() -  mesh.first->getYB() ;
        for (const auto &it : *mesh.second)
            cout << " ( " << it[0]  << " ," << it[1] << " ) ";
        cout << endl ;
    }
    initialMeshFile.close();
    ofstream nonConcaveZoneFile("NonConcaveZone.txt"); //not concave on [1,1.5] \times [1.5,1.75] and   [1.5,3] \times [2.5 ,3 ]
    nonConcaveZoneFile << x1NCMin << "  " << y1NCMin << " " << x1NCMax - x1NCMin << " " <<  y1NCMax - y1NCMin << endl ;
    nonConcaveZoneFile << x2NCMin << "  " << y2NCMin << " " << x2NCMax - x2NCMin << " " <<  y2NCMax - y2NCMin << endl ;
    nonConcaveZoneFile << x3NCMin << "  " << y3NCMin << " " << x3NCMax - x3NCMin << " " <<  y3NCMax - y3NCMin << endl ;
    nonConcaveZoneFile.close();

    // get all non concave regions
    vector< shared_ptr< StOpt::GridAdaptBase> >  meshNotConcave = contCut.getMeshNotConcASim(hypStock, 0, false);
    ofstream nonConMeshes("MeshNotConv.txt");
    for (const auto &mesh : meshNotConcave)
    {
        shared_ptr<GridAdapt2D> const pGrid2D = dynamic_pointer_cast<GridAdapt2D>(mesh);
        nonConMeshes << pGrid2D->getXMin() <<  " " <<  pGrid2D->getYMin() << "  " <<   pGrid2D->getXMax() -  pGrid2D->getXMin() << " "  <<  pGrid2D->getYMax() -  pGrid2D->getYMin() << endl ;
    }


}



// The function to approximate is defined on [0,1] * [0,1]
// It is defined as  f(x,y)=  g(x)+ g(y) with
// g(x)= log(1+x) for x < 1/3
// g(x)=  -log(4./3.) +2*log(1+x) for x in [1/3,2/3]
// g(x)=  -log(4/3.) -2 log(5/3) +4 log(1+1) for x >= 2/3.
// This function is concave by parts.

// calculate VB value and derivatives
Array3d  analVBAndDeriv(const double &x, const double &y)
{
    Array3d ret ;

    double fx ;
    double fy;
    double dfx;
    double dfy;

    if (x < 1. / 3)
    {
        fx = log(1 + x);
        dfx = 1. / (1. + x);
    }
    else if (x < 2 / 3.)
    {
        fx = -log(4. / 3) + 2 * log(1 + x);
        dfx = 2. / (1. + x);
    }
    else
    {
        fx = - log(4. / 3) - 2 * log(5. / 3.) + 4 * log(1 + x);
        dfx = 4. / (1 + x);
    }
    if (y < 1. / 3)
    {
        fy = log(1 + y);
        dfy = 1. / (1. + y);
    }
    else if (y < 2 / 3.)
    {
        fy = -log(4. / 3) + 2 * log(1 + y);
        dfy = 2. / (1. + y);
    }
    else
    {
        fy = - log(4. / 3) - 2 * log(5. / 3.) + 4 * log(1 + y);
        dfy = 4. / (1 + y);
    }
    ret(0) = fx + fy;
    ret(1) = dfx;
    ret(2) =  dfy;
    return ret;
}

BOOST_AUTO_TEST_CASE(testLocalCutsAndGridAgregatingConcaveByPartCase)
{
#if defined   __linux
    enable_abort_on_floating_point_exception();
#endif

    // grid for storage
    double xMin =  0;
    double xMax = 1;
    int nbMeshX = 10;
    double yMin = 0;
    double yMax = 1.;
    int nbMeshY = 10 ;

    // grid
    shared_ptr< GridAdapt2D > grid2D = make_shared<GridAdapt2D>(xMin, xMax, nbMeshX, yMin, yMax, nbMeshY);

    // refine in [1./6,5.6] in each direction
    list< pair<shared_ptr< Mesh2D>, shared_ptr< vector< ArrayXi > > > >  meshes = grid2D->getMeshes();
    for (auto &mesh : meshes)
    {
        if ((mesh.first->getXL() >= 1. / 6.) && (mesh.first->getXR() <= 5. / 6) && (mesh.first->getYB() >= 1. / 6.) && (mesh.first->getYT() <= 5. / 6.))
            grid2D->splitMesh(mesh);
    }

    meshes = grid2D->getMeshes();
    // in [1/4,5./12] \cup [7./12,3./4]  in each direction
    for (auto &mesh : meshes)
    {
        if ((((mesh.first->getXL() >= 1. / 4.) && (mesh.first->getXR() <= 5. / 12)) || ((mesh.first->getXL() >= 7. / 12.) && (mesh.first->getXR() <= 3. / 4))) &&
                (((mesh.first->getYB() >=  1. / 4.) && (mesh.first->getYT() <= 5. / 12)) || ((mesh.first->getYB() >=  7. / 12.) && (mesh.first->getYT() <= 3. / 4.))))
            grid2D->splitMesh(mesh);
    }

    meshes = grid2D->getMeshes();

    // gain refine in [1/4,5./12] \cup [7./12,3./4]  in each direction
    for (auto &mesh : meshes)
    {
        if ((((mesh.first->getXL() >= 1. / 4.) && (mesh.first->getXR() <= 5. / 12)) || ((mesh.first->getXL() >= 7. / 12.) && (mesh.first->getXR() <= 3. / 4))) &&
                (((mesh.first->getYB() >=  1. / 4.) && (mesh.first->getYT() <= 5. / 12)) || ((mesh.first->getYB() >=  7. / 12.) && (mesh.first->getYT() <= 3. / 4.))))
            grid2D->splitMesh(mesh);
    }


    // get all points
    vector< ArrayXd > vecPoints = grid2D->getPoints();
    int nbSimul = 2;
    // to store  vb and its derivatives
    ArrayXXd  toRegressCut(vecPoints.size(), 3 * nbSimul);
    // uncertainties set to 0
    ArrayXXd x = ArrayXXd::Zero(1, nbSimul);

    for (size_t i = 0  ; i < vecPoints.size();  ++i)
    {
        Array3d valAndDer = analVBAndDeriv(vecPoints[i][0], vecPoints[i][1]);
        for (int is  = 0;  is < nbSimul; ++is)
        {
            toRegressCut(i, is) = valAndDer(0); // value of the VB
            toRegressCut(i, is + nbSimul) = valAndDer(1) ; // x derivative
            toRegressCut(i, is + 2 * nbSimul) = valAndDer(2) ; // y derivatives
        }
    }

    // conditional expectation
    ArrayXi nbMesh(1);
    nbMesh(0) = 1;
    shared_ptr<LocalConstRegression> localRegressor = make_shared<LocalConstRegression>(false, x, nbMesh);

    // creation continuation value object
    ContinuationCutsGridAdaptNonConcave  contCut(grid2D, localRegressor,  toRegressCut.transpose());

    // first gather all points
    ArrayXXd   hypStock(2, 2);
    hypStock(0, 0) = xMin;
    hypStock(0, 1) = xMax;
    hypStock(1, 0) = yMin;
    hypStock(1, 1) = yMax;


    // one simulation
    vector< pair <shared_ptr< StOpt::GridAdaptBase>, shared_ptr<ArrayXXd>  > >  meshsAndCuts = contCut.getCutsConcGatherASim(hypStock, 0, false);

    cout << " NB GRIDS " << meshsAndCuts.size() << " Initial grid nb points " << grid2D->getNbPoints() <<  endl ;
    vector< ArrayXd >  points;
    points.reserve(grid2D->getNbPoints());
    for (const auto   &gridAndCuts : meshsAndCuts)
    {
        for (const auto &pt : gridAndCuts.first->getPoints())
        {
            bool bAdd = true;
            for (const auto &ptSt : points)
            {
                if (fabs(ptSt[0] - pt[0]) + fabs(ptSt[1] - pt[1]) < tiny)
                {
                    bAdd = false;
                    break;
                }
            }
            if (bAdd)
            {
                points.push_back(pt);
            }
        }
    }
    // missing points
    vector< ArrayXd >  pointsG = grid2D->getPoints();
    for (const auto &pt : pointsG)
    {
        bool bPres = false;
        for (const auto &ptSt : points)
        {
            if (fabs(ptSt[0] - pt[0]) + fabs(ptSt[1] - pt[1]) < tiny)
            {
                bPres = true;
                break;
            }
        }
        if (!bPres)
            cout << " MISSING POINTS IN GRID x :" << pt[0] << " y: " << pt[1] << endl;
    }
    BOOST_CHECK_EQUAL(static_cast<int>(points.size()), grid2D->getNbPoints());

    // check that grids points are the same
    vector< ArrayXd >  pointsInit = grid2D->getPoints();
    for (const auto &ptInt : pointsInit)
    {
        bool bPres = false;
        for (const auto &pt : points)
        {
            if (fabs(ptInt[0] - pt[0]) + fabs(ptInt[1] - pt[1]) < tiny)
            {
                bPres = true;
                break;
            }
        }
        BOOST_CHECK(bPres);
    }

    ofstream gridsFile("Grids1.txt");
    for (const auto   &gridAndCuts : meshsAndCuts)
    {
        shared_ptr<GridAdapt2D> const pGrid2D = dynamic_pointer_cast<GridAdapt2D>(gridAndCuts.first);
        gridsFile <<  pGrid2D->getXMin() << " " << pGrid2D->getYMin() <<   "   " <<  pGrid2D->getXMax() - pGrid2D->getXMin();
        gridsFile << " " <<  pGrid2D->getYMax() - pGrid2D->getYMin() << endl ;
    }
    gridsFile.close();
    ofstream initialMeshFile("GridInit1.txt");
    list< pair<shared_ptr< Mesh2D>, shared_ptr< vector< ArrayXi > > > >  meshesAndPos = grid2D->getMeshes();
    for (const auto &mesh : meshesAndPos)
    {
        initialMeshFile << mesh.first->getXL() <<  " " <<  mesh.first->getYB() << "  " <<   mesh.first->getXR() -  mesh.first->getXL() ;
        initialMeshFile << " "  <<  mesh.first->getYT() -  mesh.first->getYB() << endl ;
        cout <<  mesh.first->getXL() <<  " " <<  mesh.first->getYB() << "  " <<   mesh.first->getXR() -  mesh.first->getXL();
        cout <<  " "  <<  mesh.first->getYT() -  mesh.first->getYB() ;
        for (const auto &it : *mesh.second)
            cout << " ( " << it[0]  << " ," << it[1] << " ) ";
        cout << endl ;
    }
    initialMeshFile.close();

    // get all non concave regions
    vector< shared_ptr< StOpt::GridAdaptBase> >  meshNotConcave = contCut.getMeshNotConcASim(hypStock, 0, false);
    ofstream nonConMeshes("MeshNotConv1.txt");
    for (const auto &mesh : meshNotConcave)
    {
        shared_ptr<GridAdapt2D> const pGrid2D = dynamic_pointer_cast<GridAdapt2D>(mesh);
        nonConMeshes << pGrid2D->getXMin() <<  " " <<  pGrid2D->getYMin() << "  " <<   pGrid2D->getXMax() -  pGrid2D->getXMin() << " "  <<  pGrid2D->getYMax() -  pGrid2D->getYMin() << endl ;
    }


}
