|  | @@ -4,6 +4,7 @@
 | 
	
		
			
				|  |  |  #include SCTL_INCLUDE(common.hpp)
 | 
	
		
			
				|  |  |  #include SCTL_INCLUDE(morton.hpp)
 | 
	
		
			
				|  |  |  #include SCTL_INCLUDE(comm.hpp)
 | 
	
		
			
				|  |  | +#include SCTL_INCLUDE(matrix.hpp) // TODO: fix issues when this is before #Include <comm.hpp>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include <fstream>
 | 
	
		
			
				|  |  |  #include <algorithm>
 | 
	
	
		
			
				|  | @@ -22,18 +23,14 @@ struct VTUData {
 | 
	
		
			
				|  |  |    Vector<int32_t> offset;
 | 
	
		
			
				|  |  |    Vector<uint8_t> types;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  void WriteVTK(const std::string& fname, Comm comm = Comm::Self()) const {
 | 
	
		
			
				|  |  | +  void WriteVTK(const std::string& fname, const Comm& comm = Comm::Self()) const {
 | 
	
		
			
				|  |  |      typedef typename VTUData::VTKReal VTKReal;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    Integer rank = comm.Rank();
 | 
	
		
			
				|  |  | -    Integer np = comm.Size();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      Long value_dof = 0;
 | 
	
		
			
				|  |  |      {  // Write vtu file.
 | 
	
		
			
				|  |  |        std::ofstream vtufile;
 | 
	
		
			
				|  |  |        {  // Open file for writing.
 | 
	
		
			
				|  |  |          std::stringstream vtufname;
 | 
	
		
			
				|  |  | -        vtufname << fname << std::setfill('0') << std::setw(6) << rank << ".vtu";
 | 
	
		
			
				|  |  | +        vtufname << fname << std::setfill('0') << std::setw(6) << comm.Rank() << ".vtu";
 | 
	
		
			
				|  |  |          vtufile.open(vtufname.str().c_str());
 | 
	
		
			
				|  |  |          if (vtufile.fail()) return;
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -44,7 +41,7 @@ struct VTUData {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          Vector<int32_t> mpi_rank;
 | 
	
		
			
				|  |  |          {  // Set  mpi_rank
 | 
	
		
			
				|  |  | -          Integer new_myrank = rank;
 | 
	
		
			
				|  |  | +          Integer new_myrank = comm.Rank();
 | 
	
		
			
				|  |  |            mpi_rank.ReInit(pt_cnt);
 | 
	
		
			
				|  |  |            for (Long i = 0; i < mpi_rank.Dim(); i++) mpi_rank[i] = new_myrank;
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -86,7 +83,7 @@ struct VTUData {
 | 
	
		
			
				|  |  |          vtufile << "        <DataArray type=\"Int32\" Name=\"offsets\" format=\"appended\" offset=\"" << data_size << "\" />\n";
 | 
	
		
			
				|  |  |          data_size += sizeof(uint32_t) + offset.Dim() * sizeof(int32_t);
 | 
	
		
			
				|  |  |          vtufile << "        <DataArray type=\"UInt8\" Name=\"types\" format=\"appended\" offset=\"" << data_size << "\" />\n";
 | 
	
		
			
				|  |  | -        data_size += sizeof(uint32_t) + types.Dim() * sizeof(uint8_t);
 | 
	
		
			
				|  |  | +        //data_size += sizeof(uint32_t) + types.Dim() * sizeof(uint8_t);
 | 
	
		
			
				|  |  |          vtufile << "      </Cells>\n";
 | 
	
		
			
				|  |  |          //---------------------------------------------------------------------------
 | 
	
		
			
				|  |  |          vtufile << "    </Piece>\n";
 | 
	
	
		
			
				|  | @@ -134,7 +131,7 @@ struct VTUData {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        vtufile.close();  // close file
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    if (!rank) {  // Write pvtu file
 | 
	
		
			
				|  |  | +    if (!comm.Rank()) {  // Write pvtu file
 | 
	
		
			
				|  |  |        std::ofstream pvtufile;
 | 
	
		
			
				|  |  |        {  // Open file for writing
 | 
	
		
			
				|  |  |          std::stringstream pvtufname;
 | 
	
	
		
			
				|  | @@ -166,7 +163,7 @@ struct VTUData {
 | 
	
		
			
				|  |  |            // char *fname_ = (char*)strrchr(vtupath.str().c_str(), '/') + 1;
 | 
	
		
			
				|  |  |            // std::string fname_ =
 | 
	
		
			
				|  |  |            // boost::filesystem::path(fname).filename().string().
 | 
	
		
			
				|  |  | -          for (Integer i = 0; i < np; i++) pvtufile << "      <Piece Source=\"" << fname_ << std::setfill('0') << std::setw(6) << i << ".vtu\"/>\n";
 | 
	
		
			
				|  |  | +          for (Integer i = 0; i < comm.Size(); i++) pvtufile << "      <Piece Source=\"" << fname_ << std::setfill('0') << std::setw(6) << i << ".vtu\"/>\n";
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          pvtufile << "  </PUnstructuredGrid>\n";
 | 
	
		
			
				|  |  |          pvtufile << "</VTKFile>\n";
 | 
	
	
		
			
				|  | @@ -174,9 +171,106 @@ struct VTUData {
 | 
	
		
			
				|  |  |        pvtufile.close();  // close file
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  template <class ElemLst> void AddElems(const ElemLst elem_lst, Integer order, const Comm& comm = Comm::Self()) {
 | 
	
		
			
				|  |  | +    constexpr Integer COORD_DIM = ElemLst::CoordDim();
 | 
	
		
			
				|  |  | +    constexpr Integer ElemDim = ElemLst::ElemDim();
 | 
	
		
			
				|  |  | +    using CoordBasis = typename ElemLst::CoordBasis;
 | 
	
		
			
				|  |  | +    using CoordType = typename ElemLst::CoordType;
 | 
	
		
			
				|  |  | +    Long N0 = coord.Dim() / COORD_DIM;
 | 
	
		
			
				|  |  | +    Long NElem = elem_lst.NElem();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Matrix<CoordType> nodes = VTK_Nodes<CoordType, ElemDim>(order);
 | 
	
		
			
				|  |  | +    Integer Nnodes = sctl::pow<ElemDim,Integer>(order);
 | 
	
		
			
				|  |  | +    SCTL_ASSERT(nodes.Dim(0) == ElemDim);
 | 
	
		
			
				|  |  | +    SCTL_ASSERT(nodes.Dim(1) == Nnodes);
 | 
	
		
			
				|  |  | +    { // Set coord
 | 
	
		
			
				|  |  | +      Matrix<CoordType> vtk_coord;
 | 
	
		
			
				|  |  | +      auto M = CoordBasis::SetupEval(nodes);
 | 
	
		
			
				|  |  | +      CoordBasis::Eval(vtk_coord, elem_lst.ElemVector(), M);
 | 
	
		
			
				|  |  | +      for (Long k = 0; k < NElem; k++) {
 | 
	
		
			
				|  |  | +        for (Integer i = 0; i < Nnodes; i++) {
 | 
	
		
			
				|  |  | +          constexpr Integer dim = (COORD_DIM < 3 ? COORD_DIM : 3);
 | 
	
		
			
				|  |  | +          for (Integer j = 0; j < dim; j++) {
 | 
	
		
			
				|  |  | +            coord.PushBack((VTUData::VTKReal)vtk_coord[k*COORD_DIM+j][i]);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          for (Integer j = dim; j < 3; j++) {
 | 
	
		
			
				|  |  | +            coord.PushBack((VTUData::VTKReal)0);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (ElemLst::ElemDim() == 2) {
 | 
	
		
			
				|  |  | +      for (Long k = 0; k < NElem; k++) {
 | 
	
		
			
				|  |  | +        for (Integer i = 0; i < order-1; i++) {
 | 
	
		
			
				|  |  | +          for (Integer j = 0; j < order-1; j++) {
 | 
	
		
			
				|  |  | +            Long idx = k*Nnodes + i*order + j;
 | 
	
		
			
				|  |  | +            connect.PushBack(N0+idx);
 | 
	
		
			
				|  |  | +            connect.PushBack(N0+idx+1);
 | 
	
		
			
				|  |  | +            connect.PushBack(N0+idx+order+1);
 | 
	
		
			
				|  |  | +            connect.PushBack(N0+idx+order);
 | 
	
		
			
				|  |  | +            offset.PushBack(connect.Dim());
 | 
	
		
			
				|  |  | +            types.PushBack(9);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      // TODO
 | 
	
		
			
				|  |  | +      SCTL_ASSERT(false);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  template <class ElemLst, class ValueBasis> void AddElems(const ElemLst elem_lst, const Vector<ValueBasis>& elem_value, Integer order, const Comm& comm = Comm::Self()) {
 | 
	
		
			
				|  |  | +    constexpr Integer ElemDim = ElemLst::ElemDim();
 | 
	
		
			
				|  |  | +    using ValueType = typename ValueBasis::ValueType;
 | 
	
		
			
				|  |  | +    Long NElem = elem_lst.NElem();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Integer dof = (NElem==0 ? 0 : elem_value.Dim() / NElem);
 | 
	
		
			
				|  |  | +    SCTL_ASSERT(elem_value.Dim() == NElem * dof);
 | 
	
		
			
				|  |  | +    AddElems(elem_lst, order, comm);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Matrix<ValueType> nodes = VTK_Nodes<ValueType, ElemDim>(order);
 | 
	
		
			
				|  |  | +    Integer Nnodes = sctl::pow<ElemDim,Integer>(order);
 | 
	
		
			
				|  |  | +    SCTL_ASSERT(nodes.Dim(0) == ElemDim);
 | 
	
		
			
				|  |  | +    SCTL_ASSERT(nodes.Dim(1) == Nnodes);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    { // Set value
 | 
	
		
			
				|  |  | +      Matrix<ValueType> vtk_value;
 | 
	
		
			
				|  |  | +      auto M = ValueBasis::SetupEval(nodes);
 | 
	
		
			
				|  |  | +      ValueBasis::Eval(vtk_value, elem_value, M);
 | 
	
		
			
				|  |  | +      for (Long k = 0; k < NElem; k++) {
 | 
	
		
			
				|  |  | +        for (Integer i = 0; i < Nnodes; i++) {
 | 
	
		
			
				|  |  | +          for (Integer j = 0; j < dof; j++) {
 | 
	
		
			
				|  |  | +            value.PushBack((VTUData::VTKReal)vtk_value[k*dof+j][i]);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private:
 | 
	
		
			
				|  |  | +    template <class CoordType, Integer ELEM_DIM> static Matrix<CoordType> VTK_Nodes(Integer order) {
 | 
	
		
			
				|  |  | +      Matrix<CoordType> nodes;
 | 
	
		
			
				|  |  | +      if (ELEM_DIM == 2) {
 | 
	
		
			
				|  |  | +        Integer Nnodes = order*order;
 | 
	
		
			
				|  |  | +        nodes.ReInit(ELEM_DIM, Nnodes);
 | 
	
		
			
				|  |  | +        for (Integer i = 0; i < order; i++) {
 | 
	
		
			
				|  |  | +          for (Integer j = 0; j < order; j++) {
 | 
	
		
			
				|  |  | +            //nodes[0][i*order+j] = i / (CoordType)(order-1);
 | 
	
		
			
				|  |  | +            //nodes[1][i*order+j] = j / (CoordType)(order-1);
 | 
	
		
			
				|  |  | +            nodes[0][i*order+j] = 0.5 - 0.5 * sctl::cos<CoordType>((2*i+1) * const_pi<CoordType>() / (2*order));
 | 
	
		
			
				|  |  | +            nodes[1][i*order+j] = 0.5 - 0.5 * sctl::cos<CoordType>((2*j+1) * const_pi<CoordType>() / (2*order));
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        // TODO
 | 
	
		
			
				|  |  | +        SCTL_ASSERT(false);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      return nodes;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  | +template <Integer DIM> class Tree {
 | 
	
		
			
				|  |  |    public:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      struct NodeAttr {
 | 
	
	
		
			
				|  | @@ -194,12 +288,11 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |        return DIM;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    Tree(const Comm& comm_ = Comm::Self()) {
 | 
	
		
			
				|  |  | -      comm = comm_;
 | 
	
		
			
				|  |  | +    Tree(const Comm& comm_ = Comm::Self()) : comm(comm_) {
 | 
	
		
			
				|  |  |        Integer rank = comm.Rank();
 | 
	
		
			
				|  |  |        Integer np = comm.Size();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      Vector<Real> coord;
 | 
	
		
			
				|  |  | +      Vector<double> coord;
 | 
	
		
			
				|  |  |        { // Set coord
 | 
	
		
			
				|  |  |          Long N0 = 1;
 | 
	
		
			
				|  |  |          while (sctl::pow<DIM,Long>(N0) < np) N0++;
 | 
	
	
		
			
				|  | @@ -210,7 +303,7 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |          for (Long i = start; i < end; i++) {
 | 
	
		
			
				|  |  |            Long  idx = i;
 | 
	
		
			
				|  |  |            for (Integer k = 0; k < DIM; k++) {
 | 
	
		
			
				|  |  | -            coord[(i-start)*DIM+k] = (idx % N0) / (Real)N0;
 | 
	
		
			
				|  |  | +            coord[(i-start)*DIM+k] = (idx % N0) / (double)N0;
 | 
	
		
			
				|  |  |              idx /= N0;
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -242,7 +335,7 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |        return comm;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    void UpdateRefinement(const Vector<Real>& coord, Long M = 1, bool balance21 = 0, bool periodic = 0) {
 | 
	
		
			
				|  |  | +    template <class Real> void UpdateRefinement(const Vector<Real>& coord, Long M = 1, bool balance21 = 0, bool periodic = 0) {
 | 
	
		
			
				|  |  |        Integer np = comm.Size();
 | 
	
		
			
				|  |  |        Integer rank = comm.Rank();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -552,14 +645,14 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          Vector<Long> cnt_tmp;
 | 
	
		
			
				|  |  | -        Vector<Real> data_tmp;
 | 
	
		
			
				|  |  | +        Vector<char> data_tmp;
 | 
	
		
			
				|  |  |          for (const auto& pair : node_data) {
 | 
	
		
			
				|  |  |            const std::string& data_name = pair.first;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |            Long dof;
 | 
	
		
			
				|  |  | -          Iterator<Vector<Real>> data_;
 | 
	
		
			
				|  |  | +          Iterator<Vector<char>> data_;
 | 
	
		
			
				|  |  |            Iterator<Vector<Long>> cnt_;
 | 
	
		
			
				|  |  | -          GetData(data_, cnt_, data_name);
 | 
	
		
			
				|  |  | +          GetData_(data_, cnt_, data_name);
 | 
	
		
			
				|  |  |            { // Set dof
 | 
	
		
			
				|  |  |              StaticArray<Long,2> Nl, Ng;
 | 
	
		
			
				|  |  |              Nl[0] = data_->Dim();
 | 
	
	
		
			
				|  | @@ -595,7 +688,7 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    void AddData(const std::string& name, const Vector<Real>& data, const Vector<Long>& cnt) {
 | 
	
		
			
				|  |  | +    template <class ValueType> void AddData(const std::string& name, const Vector<ValueType>& data, const Vector<Long>& cnt) {
 | 
	
		
			
				|  |  |        Long dof;
 | 
	
		
			
				|  |  |        { // Check dof
 | 
	
		
			
				|  |  |          StaticArray<Long,2> Nl, Ng;
 | 
	
	
		
			
				|  | @@ -609,36 +702,29 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |        if (dof) SCTL_ASSERT(cnt.Dim() == node_mid.Dim());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        SCTL_ASSERT(node_data.find(name) == node_data.end());
 | 
	
		
			
				|  |  | -      node_data[name] = data;
 | 
	
		
			
				|  |  | -      node_cnt [name] =  cnt;
 | 
	
		
			
				|  |  | +      node_data[name].ReInit(data.Dim()*sizeof(ValueType), (Iterator<char>)data.begin(), true);
 | 
	
		
			
				|  |  | +      node_cnt [name] = cnt;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    void GetData(Iterator<Vector<Real>>& data, ConstIterator<Vector<Long>>& cnt, const std::string& name) {
 | 
	
		
			
				|  |  | -      auto data_ = node_data.find(name);
 | 
	
		
			
				|  |  | -      const auto cnt_ = node_cnt.find(name);
 | 
	
		
			
				|  |  | -      SCTL_ASSERT(data_ != node_data.end());
 | 
	
		
			
				|  |  | -      SCTL_ASSERT( cnt_ != node_cnt .end());
 | 
	
		
			
				|  |  | -      data = Ptr2Itr<Vector<Real>>(&data_->second,1);
 | 
	
		
			
				|  |  | -      cnt  = Ptr2ConstItr<Vector<Long>>(& cnt_->second,1);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    void GetData(ConstIterator<Vector<Real>>& data, ConstIterator<Vector<Long>>& cnt, const std::string& name) const {
 | 
	
		
			
				|  |  | +    template <class ValueType> void GetData(Vector<ValueType>& data, Vector<Long>& cnt, const std::string& name) const {
 | 
	
		
			
				|  |  |        const auto data_ = node_data.find(name);
 | 
	
		
			
				|  |  |        const auto cnt_ = node_cnt.find(name);
 | 
	
		
			
				|  |  |        SCTL_ASSERT(data_ != node_data.end());
 | 
	
		
			
				|  |  |        SCTL_ASSERT( cnt_ != node_cnt .end());
 | 
	
		
			
				|  |  | -      data = Ptr2ConstItr<Vector<Real>>(&data_->second,1);
 | 
	
		
			
				|  |  | -      cnt  = Ptr2ConstItr<Vector<Long>>(& cnt_->second,1);
 | 
	
		
			
				|  |  | +      data.ReInit(data_->second.Dim()/sizeof(ValueType), (Iterator<ValueType>)data_->second.begin(), false);
 | 
	
		
			
				|  |  | +      SCTL_ASSERT(data.Dim()*(Long)sizeof(ValueType) == data_->second.Dim());
 | 
	
		
			
				|  |  | +      cnt .ReInit( cnt_->second.Dim(), (Iterator<Long>)cnt_->second.begin(), false);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    void ReduceBroadcast(const std::string& name) {
 | 
	
		
			
				|  |  | +    template <class ValueType> void ReduceBroadcast(const std::string& name) {
 | 
	
		
			
				|  |  |        Integer np = comm.Size();
 | 
	
		
			
				|  |  |        Integer rank = comm.Rank();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        Vector<Long> dsp;
 | 
	
		
			
				|  |  | -      Iterator<Vector<Real>> data_;
 | 
	
		
			
				|  |  | +      Iterator<Vector<char>> data_;
 | 
	
		
			
				|  |  |        Iterator<Vector<Long>> cnt_;
 | 
	
		
			
				|  |  | -      GetData(data_, cnt_, name);
 | 
	
		
			
				|  |  | -      Vector<Real>& data = *data_;
 | 
	
		
			
				|  |  | +      GetData_(data_, cnt_, name);
 | 
	
		
			
				|  |  | +      Vector<ValueType> data(data_->Dim()/sizeof(ValueType), (Iterator<ValueType>)data_->begin(), false);
 | 
	
		
			
				|  |  |        Vector<Long>& cnt = *cnt_;
 | 
	
		
			
				|  |  |        scan(dsp, cnt);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -693,7 +779,7 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |            scan(recv_data_dsp, recv_data_cnt);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        Vector<Real> send_buff, recv_buff;
 | 
	
		
			
				|  |  | +        Vector<ValueType> send_buff, recv_buff;
 | 
	
		
			
				|  |  |          Vector<Long> send_buff_cnt(np), send_buff_dsp(np);
 | 
	
		
			
				|  |  |          Vector<Long> recv_buff_cnt(np), recv_buff_dsp(np);
 | 
	
		
			
				|  |  |          { // Set send_buff, send_buff_cnt, send_buff_dsp, recv_buff, recv_buff_cnt, recv_buff_dsp
 | 
	
	
		
			
				|  | @@ -747,6 +833,32 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +      Broadcast<ValueType>(name);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    template <class ValueType> void Broadcast(const std::string& name) {
 | 
	
		
			
				|  |  | +      Integer np = comm.Size();
 | 
	
		
			
				|  |  | +      Integer rank = comm.Rank();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      Vector<Long> dsp;
 | 
	
		
			
				|  |  | +      Iterator<Vector<char>> data_;
 | 
	
		
			
				|  |  | +      Iterator<Vector<Long>> cnt_;
 | 
	
		
			
				|  |  | +      GetData_(data_, cnt_, name);
 | 
	
		
			
				|  |  | +      Vector<ValueType> data(data_->Dim()/sizeof(ValueType), (Iterator<ValueType>)data_->begin(), false);
 | 
	
		
			
				|  |  | +      Vector<Long>& cnt = *cnt_;
 | 
	
		
			
				|  |  | +      scan(dsp, cnt);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      Long dof;
 | 
	
		
			
				|  |  | +      { // Set dof
 | 
	
		
			
				|  |  | +        StaticArray<Long,2> Nl, Ng;
 | 
	
		
			
				|  |  | +        Nl[0] = data.Dim();
 | 
	
		
			
				|  |  | +        Nl[1] = omp_par::reduce(cnt.begin(), cnt.Dim());
 | 
	
		
			
				|  |  | +        comm.Allreduce((ConstIterator<Long>)Nl, (Iterator<Long>)Ng, 2, Comm::CommOp::SUM);
 | 
	
		
			
				|  |  | +        dof = Ng[0] / std::max<Long>(Ng[1],1);
 | 
	
		
			
				|  |  | +        SCTL_ASSERT(Nl[0] == Nl[1] * dof);
 | 
	
		
			
				|  |  | +        SCTL_ASSERT(Ng[0] == Ng[1] * dof);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        { // Broadcast
 | 
	
		
			
				|  |  |          const Vector<Morton<DIM>>& send_mid = user_mid;
 | 
	
		
			
				|  |  |          const Vector<Long>& send_node_cnt = user_cnt;
 | 
	
	
		
			
				|  | @@ -782,7 +894,7 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |            scan(recv_data_dsp, recv_data_cnt);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        Vector<Real> send_buff, recv_buff;
 | 
	
		
			
				|  |  | +        Vector<ValueType> send_buff, recv_buff;
 | 
	
		
			
				|  |  |          Vector<Long> send_buff_cnt(np), send_buff_dsp(np);
 | 
	
		
			
				|  |  |          Vector<Long> recv_buff_cnt(np), recv_buff_dsp(np);
 | 
	
		
			
				|  |  |          { // Set send_buff, send_buff_cnt, send_buff_dsp, recv_buff, recv_buff_cnt, recv_buff_dsp
 | 
	
	
		
			
				|  | @@ -837,9 +949,10 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |            Long N1 = (end_idx ? dsp[end_idx-1] + cnt[end_idx-1] : 0) * dof;
 | 
	
		
			
				|  |  |            Long Ns = (Nsplit ? recv_data_dsp[Nsplit-1] + recv_data_cnt[Nsplit-1] : 0) * dof;
 | 
	
		
			
				|  |  |            if (N0 != Ns || recv_buff.Dim() != N0+data.Dim()-N1) { // resize data and preserve non-ghost data
 | 
	
		
			
				|  |  | -            Vector<Real> data_new(recv_buff.Dim() + N1-N0);
 | 
	
		
			
				|  |  | -            memcopy(data_new.begin() + Ns, data.begin() + N0, N1-N0);
 | 
	
		
			
				|  |  | -            data.Swap(data_new);
 | 
	
		
			
				|  |  | +            Vector<char> data_new((recv_buff.Dim() + N1-N0) * sizeof(ValueType));
 | 
	
		
			
				|  |  | +            memcopy(data_new.begin() + Ns * sizeof(ValueType), data_->begin() + N0 * sizeof(ValueType), (N1-N0) * sizeof(ValueType));
 | 
	
		
			
				|  |  | +            data_->Swap(data_new);
 | 
	
		
			
				|  |  | +            data.ReInit(data_->Dim()/sizeof(ValueType), (Iterator<ValueType>)data_->begin(), false);
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |            memcopy(cnt.begin(), recv_data_cnt.begin(), start_idx);
 | 
	
	
		
			
				|  | @@ -903,12 +1016,12 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    protected:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    void GetData(Iterator<Vector<Real>>& data, Iterator<Vector<Long>>& cnt, const std::string& name) {
 | 
	
		
			
				|  |  | +    void GetData_(Iterator<Vector<char>>& data, Iterator<Vector<Long>>& cnt, const std::string& name) {
 | 
	
		
			
				|  |  |        auto data_ = node_data.find(name);
 | 
	
		
			
				|  |  |        const auto cnt_ = node_cnt.find(name);
 | 
	
		
			
				|  |  |        SCTL_ASSERT(data_ != node_data.end());
 | 
	
		
			
				|  |  |        SCTL_ASSERT( cnt_ != node_cnt .end());
 | 
	
		
			
				|  |  | -      data = Ptr2Itr<Vector<Real>>(&data_->second,1);
 | 
	
		
			
				|  |  | +      data = Ptr2Itr<Vector<char>>(&data_->second,1);
 | 
	
		
			
				|  |  |        cnt  = Ptr2Itr<Vector<Long>>(& cnt_->second,1);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -931,7 +1044,7 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |      Vector<NodeAttr> node_attr;
 | 
	
		
			
				|  |  |      Vector<NodeLists> node_lst;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    std::map<std::string, Vector<Real>> node_data;
 | 
	
		
			
				|  |  | +    std::map<std::string, Vector<char>> node_data;
 | 
	
		
			
				|  |  |      std::map<std::string, Vector<Long>> node_cnt;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      Vector<Morton<DIM>> user_mid;
 | 
	
	
		
			
				|  | @@ -940,7 +1053,7 @@ template <class Real, Integer DIM> class Tree {
 | 
	
		
			
				|  |  |      Comm comm;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree : public BaseTree {
 | 
	
		
			
				|  |  | +template <class Real, Integer DIM, class BaseTree = Tree<DIM>> class PtTree : public BaseTree {
 | 
	
		
			
				|  |  |    public:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      PtTree(const Comm& comm = Comm::Self()) : BaseTree(comm) {}
 | 
	
	
		
			
				|  | @@ -948,8 +1061,8 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |      ~PtTree() {
 | 
	
		
			
				|  |  |        #ifdef SCTL_MEMDEBUG
 | 
	
		
			
				|  |  |        for (auto& pair : data_pt_name) {
 | 
	
		
			
				|  |  | -        ConstIterator<Vector<Real>> data;
 | 
	
		
			
				|  |  | -        ConstIterator<Vector<Long>> cnt;
 | 
	
		
			
				|  |  | +        Vector<Real> data;
 | 
	
		
			
				|  |  | +        Vector<Long> cnt;
 | 
	
		
			
				|  |  |          this->GetData(data, cnt, pair.second);
 | 
	
		
			
				|  |  |          SCTL_ASSERT(scatter_idx.find(pair.second) != scatter_idx.end());
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -992,9 +1105,9 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |            if (pair.second == pt_name) {
 | 
	
		
			
				|  |  |              const auto& data_name = pair.first;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            Iterator<Vector<Real>> data;
 | 
	
		
			
				|  |  | +            Iterator<Vector<char>> data;
 | 
	
		
			
				|  |  |              Iterator<Vector<Long>> cnt;
 | 
	
		
			
				|  |  | -            this->GetData(data, cnt, data_name);
 | 
	
		
			
				|  |  | +            this->GetData_(data, cnt, data_name);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              { // Update data
 | 
	
		
			
				|  |  |                Long dof = 0;
 | 
	
	
		
			
				|  | @@ -1014,7 +1127,7 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |                offset *= dof;
 | 
	
		
			
				|  |  |                count *= dof;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -              Vector<Real> data_(count, data->begin() + offset);
 | 
	
		
			
				|  |  | +              Vector<char> data_(count, data->begin() + offset);
 | 
	
		
			
				|  |  |                comm.PartitionN(data_, pt_mid_.Dim());
 | 
	
		
			
				|  |  |                data->Swap(data_);
 | 
	
		
			
				|  |  |              }
 | 
	
	
		
			
				|  | @@ -1046,9 +1159,9 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |        AddParticleData(name, name, coord);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        { // Set node_cnt
 | 
	
		
			
				|  |  | -        Iterator<Vector<Real>> data_;
 | 
	
		
			
				|  |  | +        Iterator<Vector<char>> data_;
 | 
	
		
			
				|  |  |          Iterator<Vector<Long>> cnt_;
 | 
	
		
			
				|  |  | -        this->GetData(data_,cnt_,name);
 | 
	
		
			
				|  |  | +        this->GetData_(data_,cnt_,name);
 | 
	
		
			
				|  |  |          cnt_[0].ReInit(node_mid.Dim());
 | 
	
		
			
				|  |  |          for (Long i = 0; i < node_mid.Dim(); i++) {
 | 
	
		
			
				|  |  |            Long start = std::lower_bound(pt_mid_.begin(), pt_mid_.end(), node_mid[i]) - pt_mid_.begin();
 | 
	
	
		
			
				|  | @@ -1065,19 +1178,19 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |        SCTL_ASSERT(data_pt_name.find(data_name) == data_pt_name.end());
 | 
	
		
			
				|  |  |        data_pt_name[data_name] = particle_name;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      Iterator<Vector<Real>> data_;
 | 
	
		
			
				|  |  | +      Iterator<Vector<char>> data_;
 | 
	
		
			
				|  |  |        Iterator<Vector<Long>> cnt_;
 | 
	
		
			
				|  |  |        this->AddData(data_name, Vector<Real>(), Vector<Long>());
 | 
	
		
			
				|  |  | -      this->GetData(data_,cnt_,data_name);
 | 
	
		
			
				|  |  | +      this->GetData_(data_,cnt_,data_name);
 | 
	
		
			
				|  |  |        { // Set data_[0]
 | 
	
		
			
				|  |  | -        data_[0] = data;
 | 
	
		
			
				|  |  | +        data_[0].ReInit(data.Dim()*sizeof(Real), (Iterator<char>)data.begin(), true);
 | 
	
		
			
				|  |  |          this->GetComm().ScatterForward(data_[0], scatter_idx[particle_name]);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        if (data_name != particle_name) { // Set cnt_[0]
 | 
	
		
			
				|  |  | -        Iterator<Vector<Real>> pt_coord;
 | 
	
		
			
				|  |  | -        Iterator<Vector<Long>> pt_cnt;
 | 
	
		
			
				|  |  | +        Vector<Real> pt_coord;
 | 
	
		
			
				|  |  | +        Vector<Long> pt_cnt;
 | 
	
		
			
				|  |  |          this->GetData(pt_coord, pt_cnt, particle_name);
 | 
	
		
			
				|  |  | -        cnt_[0] = pt_cnt[0];
 | 
	
		
			
				|  |  | +        cnt_[0] = pt_cnt;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1094,14 +1207,14 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        Long dof;
 | 
	
		
			
				|  |  |        Vector<Long> dsp;
 | 
	
		
			
				|  |  | -      ConstIterator<Vector<Long>> cnt_;
 | 
	
		
			
				|  |  | -      ConstIterator<Vector<Real>> data_;
 | 
	
		
			
				|  |  | +      Vector<Long> cnt_;
 | 
	
		
			
				|  |  | +      Vector<Real> data_;
 | 
	
		
			
				|  |  |        this->GetData(data_, cnt_, data_name);
 | 
	
		
			
				|  |  | -      SCTL_ASSERT(cnt_->Dim() == node_mid.Dim());
 | 
	
		
			
				|  |  | -      BaseTree::scan(dsp, cnt_[0]);
 | 
	
		
			
				|  |  | +      SCTL_ASSERT(cnt_.Dim() == node_mid.Dim());
 | 
	
		
			
				|  |  | +      BaseTree::scan(dsp, cnt_);
 | 
	
		
			
				|  |  |        { // Set dof
 | 
	
		
			
				|  |  |          Long Nn = node_mid.Dim();
 | 
	
		
			
				|  |  | -        StaticArray<Long,2> Ng, Nl = {data_->Dim(), dsp[Nn-1]+cnt_[0][Nn-1]};
 | 
	
		
			
				|  |  | +        StaticArray<Long,2> Ng, Nl = {data_.Dim(), dsp[Nn-1]+cnt_[Nn-1]};
 | 
	
		
			
				|  |  |          comm.Allreduce((ConstIterator<Long>)Nl, (Iterator<Long>)Ng, 2, Comm::CommOp::SUM);
 | 
	
		
			
				|  |  |          dof = Ng[0] / std::max<Long>(Ng[1],1);
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -1111,8 +1224,8 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |          Long N0 = std::lower_bound(node_mid.begin(), node_mid.end(), mins[rank]) - node_mid.begin();
 | 
	
		
			
				|  |  |          Long N1 = std::lower_bound(node_mid.begin(), node_mid.end(), (rank+1==np ? Morton<DIM>().Next() : mins[rank+1])) - node_mid.begin();
 | 
	
		
			
				|  |  |          Long start = dsp[N0] * dof;
 | 
	
		
			
				|  |  | -        Long end = (N1<dsp.Dim() ? dsp[N1] : dsp[N1-1]+cnt_[0][N1-1]) * dof;
 | 
	
		
			
				|  |  | -        data.ReInit(end-start, (Iterator<Real>)data_->begin()+start, true);
 | 
	
		
			
				|  |  | +        Long end = (N1<dsp.Dim() ? dsp[N1] : dsp[N1-1]+cnt_[N1-1]) * dof;
 | 
	
		
			
				|  |  | +        data.ReInit(end-start, data_.begin()+start, true);
 | 
	
		
			
				|  |  |          comm.ScatterReverse(data, scatter_idx_, Nlocal_ * dof);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -1148,20 +1261,20 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |          SCTL_ASSERT(data_pt_name.find(data_name) != data_pt_name.end());
 | 
	
		
			
				|  |  |          std::string particle_name = data_pt_name.find(data_name)->second;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        ConstIterator<Vector<Real>> pt_coord = NullIterator<Vector<Real>>();
 | 
	
		
			
				|  |  | -        ConstIterator<Vector<Real>> pt_value = NullIterator<Vector<Real>>();
 | 
	
		
			
				|  |  | -        ConstIterator<Vector<Long>> pt_cnt = NullIterator<Vector<Long>>();
 | 
	
		
			
				|  |  | +        Vector<Real> pt_coord;
 | 
	
		
			
				|  |  | +        Vector<Real> pt_value;
 | 
	
		
			
				|  |  | +        Vector<Long> pt_cnt;
 | 
	
		
			
				|  |  |          Vector<Long> pt_dsp;
 | 
	
		
			
				|  |  |          Long value_dof = 0;
 | 
	
		
			
				|  |  |          { // Set pt_coord, pt_cnt, pt_dsp
 | 
	
		
			
				|  |  |            this->GetData(pt_coord, pt_cnt, particle_name);
 | 
	
		
			
				|  |  | -          Tree<Real,DIM>::scan(pt_dsp, pt_cnt[0]);
 | 
	
		
			
				|  |  | +          Tree<DIM>::scan(pt_dsp, pt_cnt);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          if (particle_name != data_name) { // Set pt_value, value_dof
 | 
	
		
			
				|  |  | -          ConstIterator<Vector<Long>> pt_cnt = NullIterator<Vector<Long>>();
 | 
	
		
			
				|  |  | +          Vector<Long> pt_cnt;
 | 
	
		
			
				|  |  |            this->GetData(pt_value, pt_cnt, data_name);
 | 
	
		
			
				|  |  | -          Long Npt = omp_par::reduce(pt_cnt->begin(), pt_cnt->Dim());
 | 
	
		
			
				|  |  | -          value_dof = pt_value->Dim() / std::max<Long>(Npt,1);
 | 
	
		
			
				|  |  | +          Long Npt = omp_par::reduce(pt_cnt.begin(), pt_cnt.Dim());
 | 
	
		
			
				|  |  | +          value_dof = pt_value.Dim() / std::max<Long>(Npt,1);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          Vector<VTKReal> &coord = vtu_data.coord;
 | 
	
	
		
			
				|  | @@ -1177,14 +1290,14 @@ template <class Real, Integer DIM, class BaseTree = Tree<Real,DIM>> class PtTree
 | 
	
		
			
				|  |  |          value.SetZero();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          SCTL_ASSERT(node_mid.Dim() == node_attr.Dim());
 | 
	
		
			
				|  |  | -        SCTL_ASSERT(node_mid.Dim() == pt_cnt->Dim());
 | 
	
		
			
				|  |  | +        SCTL_ASSERT(node_mid.Dim() == pt_cnt.Dim());
 | 
	
		
			
				|  |  |          for (Long i = 0; i < node_mid.Dim(); i++) {
 | 
	
		
			
				|  |  |            if (!show_ghost && node_attr[i].Ghost) continue;
 | 
	
		
			
				|  |  |            if (!node_attr[i].Leaf) continue;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -          for (Long j = 0; j < pt_cnt[0][i]; j++) {
 | 
	
		
			
				|  |  | -            ConstIterator<Real> pt_coord_ = pt_coord->begin() + (pt_dsp[i] + j) * DIM;
 | 
	
		
			
				|  |  | -            ConstIterator<Real> pt_value_ = (value_dof ? pt_value->begin() + (pt_dsp[i] + j) * value_dof : NullIterator<Real>());
 | 
	
		
			
				|  |  | +          for (Long j = 0; j < pt_cnt[i]; j++) {
 | 
	
		
			
				|  |  | +            ConstIterator<Real> pt_coord_ = pt_coord.begin() + (pt_dsp[i] + j) * DIM;
 | 
	
		
			
				|  |  | +            ConstIterator<Real> pt_value_ = (value_dof ? pt_value.begin() + (pt_dsp[i] + j) * value_dof : NullIterator<Real>());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              for (Integer k = 0; k < DIM; k++) coord.PushBack((VTKReal)pt_coord_[k]);
 | 
	
		
			
				|  |  |              for (Integer k = DIM; k < 3; k++) coord.PushBack(0);
 |