public void Reset()
        {
            *testout << "ParallelMeshTopology::Reset" << "\n";

            NgMPI_Comm comm   = mesh.GetCommunicator();
            int        id     = comm.Rank();
            int        ntasks = comm.Size();

            if (ntasks == 1)
            {
                return;
            }

            int ned = mesh.GetTopology().GetNEdges();
            int nfa = mesh.GetTopology().GetNFaces();

            if (glob_edge.Size() != ned)
            {
                glob_edge.SetSize(ned);
                glob_face.SetSize(nfa);
                glob_edge = -1;
                glob_face = -1;

                loc2distedge.ChangeSize(ned);
                loc2distface.ChangeSize(nfa);
            }

            if (glob_vert.Size() != mesh.GetNV())
            {
                SetNV(mesh.GetNV());
                SetNE(mesh.GetNE());
            }
        }
        public void UpdateCoarseGrid()
        {
            // cout << "UpdateCoarseGrid" << endl;
            // if (is_updated) return;

            NgMPI_Comm comm   = mesh.GetCommunicator();
            int        id     = comm.Rank();
            int        ntasks = comm.Size();

            if (ntasks == 1)
            {
                return;
            }

            Reset();
//C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:
//	  static int timer = NgProfiler::CreateTimer("UpdateCoarseGrid");
            NgProfiler.RegionTimer reg = new NgProfiler.RegionTimer(UpdateCoarseGrid_timer);


            (*testout) << "UPDATE COARSE GRID PARALLEL TOPOLOGY " << "\n";
            if (id == 0)
            {
                PrintMessage(1, "update parallel topology");
            }


            // UpdateCoarseGridGlobal();



            // MPI_Barrier (MPI_COMM_WORLD);

            MPI_Group MPI_GROUP_comm = new MPI_Group();
            MPI_Group MPI_LocalGroup = new MPI_Group();
            MPI_Comm  MPI_LocalComm  = new MPI_Comm();

            int[] process_ranks = { 0 };
            MPI_Comm_group(comm, MPI_GROUP_comm);
            MPI_Group_excl(MPI_GROUP_comm, 1, process_ranks, MPI_LocalGroup);
            MPI_Comm_create(comm, MPI_LocalGroup, MPI_LocalComm);

            if (id == 0)
            {
                return;
            }

            MeshTopology topology = mesh.GetTopology();

            Array <int> cnt_send = new Array <int>(ntasks - 1);


            // update new vertices after mesh-refinement
            if (mesh.mlbetweennodes.Size() > 0)
            {
                // cout << "UpdateCoarseGrid - vertices" << endl;
                int newnv = mesh.mlbetweennodes.Size();
                loc2distvert.ChangeSize(mesh.mlbetweennodes.Size());

                /*
                 *      for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++)
                 *            {
                 *              PointIndex v1 = mesh.mlbetweennodes[pi][0];
                 *              PointIndex v2 = mesh.mlbetweennodes[pi][1];
                 *              if (mesh.mlbetweennodes[pi][0] != PointIndex::BASE-1)
                 *                    for (int dest = 1; dest < ntasks; dest++)
                 *                      if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2))
                 *                            SetDistantPNum(dest, pi);
                 *            }
                 */

                bool changed = true;
                while (changed)
                {
                    changed = false;

                    // build exchange vertices
                    cnt_send = 0;
                    foreach (PointIndex pi in mesh.Points().Range())
                    {
                        foreach (int dist in GetDistantPNums(pi - PointIndex.BASE))
                        {
                            cnt_send[dist - 1]++;
                        }
                    }
                    TABLE <int> dest2vert = new TABLE <int>(cnt_send);
                    foreach (PointIndex pi in mesh.Points().Range())
                    {
                        foreach (int dist in GetDistantPNums(pi - PointIndex.BASE))
                        {
                            dest2vert.Add(dist - 1, pi);
                        }
                    }


                    for (PointIndex pi = PointIndex.BASE; pi < newnv + PointIndex.BASE; pi++)
                    {
                        PointIndex v1 = mesh.mlbetweennodes[pi][0];
                        PointIndex v2 = mesh.mlbetweennodes[pi][1];
                        if (mesh.mlbetweennodes[pi][0] != PointIndex.BASE - 1)
                        {
                            // for (int dest = 1; dest < ntasks; dest++)
                            foreach (int dest in GetDistantPNums(v1 - PointIndex.BASE))
                            {
                                if (IsExchangeVert(dest, new netgen.PointIndex(v1)) && IsExchangeVert(dest, new netgen.PointIndex(v2)))
                                {
                                    cnt_send[dest - 1]++;
                                }
                            }
                        }
                    }

                    TABLE <int> dest2pair = new TABLE <int>(cnt_send);
                    // for (int dest = 1; dest < ntasks; dest++)
                    for (PointIndex pi = PointIndex.BASE; pi < newnv + PointIndex.BASE; pi++)
                    {
                        PointIndex v1 = mesh.mlbetweennodes[pi][0];
                        PointIndex v2 = mesh.mlbetweennodes[pi][1];
                        if (mesh.mlbetweennodes[pi][0] != PointIndex.BASE - 1)
                        {
                            foreach (int dest in GetDistantPNums(v1 - PointIndex.BASE))
                            {
                                if (IsExchangeVert(dest, new netgen.PointIndex(v1)) && IsExchangeVert(dest, new netgen.PointIndex(v2)))
                                {
                                    dest2pair.Add(dest - 1, pi);
                                }
                            }
                        }
                    }

                    cnt_send = 0;
                    int v1;
                    int v2;
                    for (PointIndex pi = PointIndex.BASE; pi < newnv + PointIndex.BASE; pi++)
                    {
                        PointIndex v1 = mesh.mlbetweennodes[pi][0];
                        PointIndex v2 = mesh.mlbetweennodes[pi][1];
                        if (mesh.mlbetweennodes[pi][0] != PointIndex.BASE - 1)
                        {
                            foreach (int dest in GetDistantPNums(v1 - PointIndex.BASE))
                            {
                                if (IsExchangeVert(dest, new netgen.PointIndex(v2)))
                                {
                                    cnt_send[dest - 1] += 2;
                                }
                            }
                        }
                    }

                    TABLE <int> send_verts = new TABLE <int>(cnt_send);

                    Array <int, PointIndex.BASE> loc2exchange = new Array <int, PointIndex.BASE>(mesh.GetNV());
                    for (int dest = 1; dest < ntasks; dest++)
                    {
                        if (dest != id)
                        {
                            loc2exchange = -1;
                            int cnt = 0;

                            /*
                             * for (PointIndex pi : mesh.Points().Range())
                             * if (IsExchangeVert(dest, pi))
                             *  loc2exchange[pi] = cnt++;
                             */
                            foreach (PointIndex pi in dest2vert[dest - 1])
                            {
                                loc2exchange[pi] = cnt++;
                            }

                            // for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++)
                            foreach (PointIndex pi in dest2pair[dest - 1])
                            {
                                PointIndex v1 = mesh.mlbetweennodes[pi][0];
                                PointIndex v2 = mesh.mlbetweennodes[pi][1];
                                if (mesh.mlbetweennodes[pi][0] != PointIndex.BASE - 1)
                                {
                                    if (IsExchangeVert(dest, new netgen.PointIndex(v1)) && IsExchangeVert(dest, new netgen.PointIndex(v2)))
                                    {
                                        send_verts.Add(dest - 1, loc2exchange[v1]);
                                        send_verts.Add(dest - 1, loc2exchange[v2]);
                                    }
                                }
                            }
                        }
                    }

                    TABLE <int> recv_verts = new TABLE <int>(ntasks - 1);
                    netgen.GlobalMembers.MyMPI_ExchangeTable(send_verts, recv_verts, MPI_TAG_MESH + 9, MPI_LocalComm);

                    for (int dest = 1; dest < ntasks; dest++)
                    {
                        if (dest != id)
                        {
                            loc2exchange = -1;
                            int cnt = 0;

                            /*
                             * for (PointIndex pi : mesh.Points().Range())
                             * if (IsExchangeVert(dest, pi))
                             *  loc2exchange[pi] = cnt++;
                             */
                            foreach (PointIndex pi in dest2vert[dest - 1])
                            {
                                loc2exchange[pi] = cnt++;
                            }

                            FlatArray <int> recvarray = recv_verts[dest - 1];
                            for (int ii = 0; ii < recvarray.Size(); ii += 2)
                            {
                                foreach (PointIndex pi in dest2pair[dest - 1])
                                {
                                    // for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++)
                                    PointIndex v1 = mesh.mlbetweennodes[pi][0];
                                    PointIndex v2 = mesh.mlbetweennodes[pi][1];
                                    if (mesh.mlbetweennodes[pi][0] != PointIndex.BASE - 1)
                                    {
                                        INDEX_2 re = new INDEX_2(recvarray[ii], recvarray[ii + 1]);
                                        INDEX_2 es = new INDEX_2(loc2exchange[v1], loc2exchange[v2]);
                                        if (es == re && !IsExchangeVert(dest, new netgen.PointIndex(pi)))
                                        {
                                            SetDistantPNum(dest, new netgen.PointIndex(pi));
                                            changed = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            Array <int> sendarray = new Array <int>();
            Array <int> recvarray = new Array <int>();

            // cout << "UpdateCoarseGrid - edges" << endl;

            // static int timerv = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex vertices");
//C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:
//	  static int timere = NgProfiler::CreateTimer("UpdateCoarseGrid - ex edges");
//C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:
//	  static int timerf = NgProfiler::CreateTimer("UpdateCoarseGrid - ex faces");


            NgProfiler.StartTimer(UpdateCoarseGrid_timere);


            int nfa = topology.GetNFaces();
            int ned = topology.GetNEdges();

            // build exchange vertices
            cnt_send = 0;
            foreach (PointIndex pi in mesh.Points().Range())
            {
                foreach (int dist in GetDistantPNums(pi - PointIndex.BASE))
                {
                    cnt_send[dist - 1]++;
                }
            }
            TABLE <int> dest2vert = new TABLE <int>(cnt_send);

            foreach (PointIndex pi in mesh.Points().Range())
            {
                foreach (int dist in GetDistantPNums(pi - PointIndex.BASE))
                {
                    dest2vert.Add(dist - 1, pi);
                }
            }

            // exchange edges
            cnt_send = 0;
            int v1;
            int v2;

            for (int edge = 1; edge <= ned; edge++)
            {
                topology.GetEdgeVertices(edge, ref v1, ref v2);
                for (int dest = 1; dest < ntasks; dest++)
                {
                    if (IsExchangeVert(dest, v1) && IsExchangeVert(dest, v2))
                    {
                        cnt_send[dest - 1] += 1;
                    }
                }
            }

            TABLE <int> dest2edge = new TABLE <int>(cnt_send);

            foreach (int v in cnt_send)
            {
                v *= 2;
            }
            TABLE <int> send_edges = new TABLE <int>(cnt_send);

            for (int edge = 1; edge <= ned; edge++)
            {
                topology.GetEdgeVertices(edge, ref v1, ref v2);
                for (int dest = 1; dest < ntasks; dest++)
                {
                    if (IsExchangeVert(dest, v1) && IsExchangeVert(dest, v2))
                    {
                        dest2edge.Add(dest - 1, edge);
                    }
                }
            }


            Array <int, PointIndex.BASE> loc2exchange = new Array <int, PointIndex.BASE>(mesh.GetNV());

            for (int dest = 1; dest < ntasks; dest++)
            {
                loc2exchange = -1;
                int cnt = 0;
                foreach (PointIndex pi in dest2vert[dest - 1])
                {
                    loc2exchange[pi] = cnt++;
                }

                foreach (int edge in dest2edge[dest - 1])
                {
                    topology.GetEdgeVertices(edge, ref v1, ref v2);
                    if (IsExchangeVert(dest, v1) && IsExchangeVert(dest, v2))
                    {
                        send_edges.Add(dest - 1, loc2exchange[v1]);
                        send_edges.Add(dest - 1, loc2exchange[v2]);
                    }
                }
            }

            // cout << "UpdateCoarseGrid - edges mpi-exchange" << endl;
            TABLE <int> recv_edges = new TABLE <int>(ntasks - 1);

            netgen.GlobalMembers.MyMPI_ExchangeTable(send_edges, recv_edges, MPI_TAG_MESH + 9, MPI_LocalComm);
            // cout << "UpdateCoarseGrid - edges mpi-exchange done" << endl;

            /*
             * for (int dest = 1; dest < ntasks; dest++)
             * {
             * auto ex2loc = dest2vert[dest-1];
             * FlatArray<int> recvarray = recv_edges[dest-1];
             *  for (int ii = 0; ii < recvarray.Size(); ii+=2)
             *    for (int edge : dest2edge[dest-1])
             *      {
             *            topology.GetEdgeVertices (edge, v1, v2);
             *            INDEX_2 re(ex2loc[recvarray[ii]],
             *               ex2loc[recvarray[ii+1]]);
             *            INDEX_2 es(v1, v2);
             *            if (es == re)
             *      SetDistantEdgeNum(dest, edge);
             *      }
             * }
             */

            for (int dest = 1; dest < ntasks; dest++)
            {
                var ex2loc = dest2vert[dest - 1];
                if (ex2loc.Size() == 0)
                {
                    continue;
                }

                INDEX_2_CLOSED_HASHTABLE <int> vert2edge = new INDEX_2_CLOSED_HASHTABLE <int>((uint)(2 * dest2edge[dest - 1].Size() + 10));
                foreach (int edge in dest2edge[dest - 1])
                {
                    topology.GetEdgeVertices(edge, ref v1, ref v2);
                    vert2edge.Set(new INDEX_2(v1, v2), edge);
                }

                FlatArray <int> recvarray = recv_edges[dest - 1];
                for (int ii = 0; ii < recvarray.Size(); ii += 2)
                {
                    INDEX_2 re = new INDEX_2(ex2loc[recvarray[ii]], ex2loc[recvarray[ii + 1]]);
                    if (vert2edge.Used(re))
                    {
                        SetDistantEdgeNum(dest, vert2edge.Get(re));
                    }
                }
            }



            NgProfiler.StopTimer(UpdateCoarseGrid_timere);

            // MPI_Barrier (MPI_LocalComm);

            // cout << "UpdateCoarseGrid - faces" << endl;
            if (mesh.GetDimension() == 3)
            {
                NgProfiler.StartTimer(UpdateCoarseGrid_timerf);
                Array <int> verts = new Array <int>();

                // exchange faces
                cnt_send = 0;
                for (int face = 1; face <= nfa; face++)
                {
                    topology.GetFaceVertices(face, verts);
                    for (int dest = 1; dest < ntasks; dest++)
                    {
                        if (dest != id)
                        {
                            if (IsExchangeVert(dest, verts[0]) && IsExchangeVert(dest, verts[1]) && IsExchangeVert(dest, verts[2]))
                            {
                                cnt_send[dest - 1]++;
                            }
                        }
                    }
                }

                TABLE <int> dest2face = new TABLE <int>(cnt_send);
                for (int face = 1; face <= nfa; face++)
                {
                    topology.GetFaceVertices(face, verts);
                    for (int dest = 1; dest < ntasks; dest++)
                    {
                        if (dest != id)
                        {
                            if (IsExchangeVert(dest, verts[0]) && IsExchangeVert(dest, verts[1]) && IsExchangeVert(dest, verts[2]))
                            {
                                dest2face.Add(dest - 1, face);
                            }
                        }
                    }
                }

                foreach (int c in cnt_send)
                {
                    c *= 3;
                }
                TABLE <int> send_faces = new TABLE <int>(cnt_send);
                Array <int, PointIndex.BASE> loc2exchange = new Array <int, PointIndex.BASE>(mesh.GetNV());
                for (int dest = 1; dest < ntasks; dest++)
                {
                    if (dest != id)
                    {
                        /*
                         * loc2exchange = -1;
                         * int cnt = 0;
                         * for (PointIndex pi : mesh.Points().Range())
                         * if (IsExchangeVert(dest, pi))
                         * loc2exchange[pi] = cnt++;
                         */
                        if (dest2vert[dest - 1].Size() == 0)
                        {
                            continue;
                        }

                        loc2exchange = -1;
                        int cnt = 0;
                        foreach (PointIndex pi in dest2vert[dest - 1])
                        {
                            loc2exchange[pi] = cnt++;
                        }

                        foreach (int face in dest2face[dest - 1])
                        {
                            topology.GetFaceVertices(face, verts);
                            if (IsExchangeVert(dest, verts[0]) && IsExchangeVert(dest, verts[1]) && IsExchangeVert(dest, verts[2]))
                            {
                                send_faces.Add(dest - 1, loc2exchange[verts[0]]);
                                send_faces.Add(dest - 1, loc2exchange[verts[1]]);
                                send_faces.Add(dest - 1, loc2exchange[verts[2]]);
                            }
                        }
                    }
                }

                // cout << "UpdateCoarseGrid - faces mpi-exchange" << endl;
                TABLE <int> recv_faces = new TABLE <int>(ntasks - 1);
                netgen.GlobalMembers.MyMPI_ExchangeTable(send_faces, recv_faces, MPI_TAG_MESH + 9, MPI_LocalComm);
                // cout << "UpdateCoarseGrid - faces mpi-exchange done" << endl;

                /*
                 * for (int dest = 1; dest < ntasks; dest++)
                 * if (dest != id)
                 *  {
                 *    loc2exchange = -1;
                 *    int cnt = 0;
                 *    for (PointIndex pi : dest2vert[dest-1])
                 *    loc2exchange[pi] = cnt++;
                 *
                 *    FlatArray<int> recvarray = recv_faces[dest-1];
                 *    for (int ii = 0; ii < recvarray.Size(); ii+=3)
                 *    for (int face : dest2face[dest-1])
                 *      {
                 *        topology.GetFaceVertices (face, verts);
                 *        INDEX_3 re(recvarray[ii], recvarray[ii+1], recvarray[ii+2]);
                 *        INDEX_3 es(loc2exchange[verts[0]], loc2exchange[verts[1]], loc2exchange[verts[2]]);
                 *        if (es == re)
                 *          SetDistantFaceNum(dest, face);
                 *      }
                 *  }
                 */


                for (int dest = 1; dest < ntasks; dest++)
                {
                    var ex2loc = dest2vert[dest - 1];
                    if (ex2loc.Size() == 0)
                    {
                        continue;
                    }

                    INDEX_3_CLOSED_HASHTABLE <int> vert2face = new INDEX_3_CLOSED_HASHTABLE <int>(2 * dest2face[dest - 1].Size() + 10);
                    foreach (int face in dest2face[dest - 1])
                    {
                        topology.GetFaceVertices(face, verts);
                        vert2face.Set(new INDEX_3(verts[0], verts[1], verts[2]), face);
                    }

                    FlatArray <int> recvarray = recv_faces[dest - 1];
                    for (int ii = 0; ii < recvarray.Size(); ii += 3)
                    {
                        INDEX_3 re = new INDEX_3(ex2loc[recvarray[ii]], ex2loc[recvarray[ii + 1]], ex2loc[recvarray[ii + 2]]);
                        if (vert2face.Used(re))
                        {
                            SetDistantFaceNum(dest, vert2face.Get(re));
                        }
                    }
                }



                /*
                 * Array<int,1> glob2loc;
                 *
                 * int maxface = 0;
                 * for (int face = 1; face <= nfa; face++)
                 * maxface = max (maxface, GetGlobalFaceNum (face));
                 *
                 * // glob2loc.SetSize (nfaglob);
                 * glob2loc.SetSize (maxface);
                 * glob2loc = -1;
                 *
                 * for (int loc = 1; loc <= nfa; loc++)
                 * glob2loc[GetGlobalFaceNum(loc)] = loc;
                 *
                 * cnt_send = 0;
                 * Array<int> verts;
                 * for (int face = 1; face <= nfa; face++)
                 * {
                 *  topology.GetFaceVertices (face, verts);
                 *  for (int dest = 1; dest < ntasks; dest++)
                 *    if (IsExchangeVert (dest, verts[0]) &&
                 *      IsExchangeVert (dest, verts[1]) &&
                 *      IsExchangeVert (dest, verts[2]))
                 *    {
                 *      cnt_send[dest-1]+=2;
                 *    }
                 * }
                 *
                 * TABLE<int> send_faces(cnt_send);
                 * for (int face = 1; face <= nfa; face++)
                 * {
                 *  topology.GetFaceVertices (face, verts);
                 *  for (int dest = 1; dest < ntasks; dest++)
                 *    {
                 *    if (IsExchangeVert (dest, verts[0]) &&
                 *        IsExchangeVert (dest, verts[1]) &&
                 *        IsExchangeVert (dest, verts[2]))
                 *      {
                 *        send_faces.Add (dest-1, GetGlobalFaceNum(face));
                 *        send_faces.Add (dest-1, face);
                 *      }
                 *    }
                 * }
                 * TABLE<int> recv_faces(ntasks-1);
                 * MyMPI_ExchangeTable (send_faces, recv_faces, MPI_TAG_MESH+8, MPI_LocalComm);
                 *
                 * for (int sender = 1; sender < ntasks; sender ++)
                 * if (id != sender)
                 *  {
                 *    FlatArray<int> recvarray = recv_faces[sender-1];
                 *
                 *    for (int ii = 0; ii < recvarray.Size(); )
                 *    {
                 *      int globf = recvarray[ii++];
                 *      int distf = recvarray[ii++];
                 *
                 *      if (globf <= maxface)
                 *        {
                 *          int locf = glob2loc[globf];
                 *          if (locf != -1)
                 *            SetDistantFaceNum (sender, locf);
                 *        }
                 *    }
                 *  }
                 */

                NgProfiler.StopTimer(UpdateCoarseGrid_timerf);
            }
            // cout << "UpdateCoarseGrid - done" << endl;

            is_updated = true;
        }