//		MPI code in C++.
//		See [Gropp/Lusk/Skjellum, "Using MPI", p.33/41 etc.]
//		and  /opt/mpich/include/mpi2c++/comm.h  for details

#include "geom.h"
#include "par_geom.h"
#include "vdop.h"

#include <cassert>
#include <cmath>
#include <iostream>
#include <mpi.h>            // MPI
//#include <omp.h>            // OpenMP, for E9 it is not necessary
using namespace std;


int main(int argc, char **argv )
{
    MPI_Init(&argc, &argv);
    MPI_Comm const icomm(MPI_COMM_WORLD);
    //omp_set_num_threads(1);                   // don't use OMP parallelization for a start
//
   {
       int np;
       MPI_Comm_size(icomm, &np);

       assert(4 == np);                  // example is only provided for 4 MPI processes
   }
// #####################################################################
// ---- Read the f.e. mesh and the mapping of elements to MPI processes
    //Mesh const mesh_c("square_4.txt");    //    Files square_4.txt and square_4_sd.txt  are needed
    ParMesh const mesh("square",icomm);
    
    int const numprocs = mesh.NumProcs();
    int const myrank   = mesh.MyRank();
    if ( 0 == myrank ) {
        cout << "\n There are " << numprocs << " processes running.\n \n";
    }
        
    int const check_rank=0;               // choose the MPI process you would like to check the mesh
    //if ( check_rank == myrank ) mesh.Debug();
    //if ( check_rank == myrank ) mesh.DebugEdgeBased();
    
// ---- allocate local vectors and check skalar product and vector accumulation
    vector<double> xl(mesh.Nnodes(), 1.0);
    mesh.SetValues(xl, [](double x, double y) -> double {return x * x * std::sin(2.5 * M_PI * y);} );
    
    //E9
    if (myrank == check_rank){
        cout << "E9" << endl;
    }

    double ss = mesh.dscapr(xl,xl);
    if (myrank == check_rank){
        cout << myrank << " : scalar : " << ss << endl << endl;
    }

    mesh.VecAccu(xl);

    //E10
    if (myrank == check_rank){
        cout << "E10" << endl;
    }
    vector<int> xl_int(mesh.Nnodes(), 1);

    // check accumulation (by console output)
    mesh.VecAccu(xl_int);

    vector<double> coords = mesh.GetCoords();
    if (check_rank == myrank){
        for (size_t i = 0; i < coords.size(); i += 2){
            cout << "(" << coords[i] << ", " << coords[i + 1] << "):\t" << xl_int[i/2] << endl;
        }
    }

    //E11
    if (myrank == check_rank){
        cout << "E11" << endl;
    }
    int global_nodes = mesh.GlobalNodes();
    if (check_rank == myrank){
        cout << "Global nodes: " << global_nodes << endl;
    }

    //E12
    if (myrank == check_rank){
        cout << "E12" << endl;
    }
    vector<double> xl_new(mesh.Nnodes(), 1.0);

    mesh.Average(xl_new);












    MPI_Finalize();
    return 0;
}


