diff --git a/src/coupling/point_association.cc b/src/coupling/point_association.cc
index 300e9e1..21c1ef9 100644
--- a/src/coupling/point_association.cc
+++ b/src/coupling/point_association.cc
@@ -1,588 +1,588 @@
 /**
  * @file   point_association.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Till Junge <till.junge@epfl.ch>
  *
  * @date   Thu Jul 24 14:21:58 2014
  *
  * @brief  Coupling tool to associate point-like DOFs
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * LibMultiScale is free  software: you can redistribute it and/or  modify it
  * under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * LibMultiScale is  distributed in the  hope that it  will be useful, but
  * WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 //#define TIMER
 /* -------------------------------------------------------------------------- */
 #include "point_association.hh"
 #include "filter_geometry.hh"
 #include "geometry_manager.hh"
 #include "lib_bridging.hh"
 #include "lib_continuum.hh"
 #include "lib_md.hh"
 #include "lm_common.hh"
 #include "reference_manager_interface.hh"
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_LIBMULTISCALE__
 
 /* -------------------------------------------------------------------------- */
 template <typename ContainerA, typename ContainerB, UInt Dim>
 PointAssociation<ContainerA, ContainerB, Dim>::PointAssociation(
     const std::string &name, ContainerA &contA, ContainerB &contB)
     : LMObject(name), DofAssociation<ContainerA, ContainerB, Dim>(name, contA,
                                                                   contB),
       pointsAlist("pointsAlist:" + name), pointsBlist("pointsBlist:" + name),
       unmatchedA("unmatchedA:" + name), unmatchedB("unmatchedB:" + name),
       assoc_found(0), tolerance(1e-5), path(""), weight_path(""),
       weights("weights:" + this->getID()),
       weightsA("weightsA:" + this->getID()),
       weightsB("weightsB:" + this->getID()),
       true_disp("ComputeTrueDisplacement:" + this->getID()) {
 
   if (this->in_group_A && this->contA.hasRefManager())
     this->contA.getRefManager()->addSubSet(this->getID() + ":pointsA",
                                            *this->pointsAlist);
 
   if (this->in_group_B && this->contB.hasRefManager())
     this->contB.getRefManager()->addSubSet(this->getID() + ":pointsB",
                                            *this->pointsBlist);
 
   /* registering computes for outer world */
   LM_TOIMPLEMENT;
   // FilterManager::getManager().addObject(&this->pointsAlist, false);
   // FilterManager::getManager().addObject(&this->pointsBlist, false);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename ContainerA, typename ContainerB, UInt Dim>
 PointAssociation<ContainerA, ContainerB, Dim>::~PointAssociation() {
   if (this->grid) {
     delete this->grid;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB, Dim>::init() {
 
   if (this->contA.hasRefManager() && this->contB.hasRefManager())
     LM_FATAL("Not sure what to do if both sides are able to migrate particles");
 
   // Build point lists for both domains
   if (this->in_group_A) {
     this->buildPointList(this->contA, this->unmatchedA);
     this->local_points = this->unmatchedA->size();
     this->buildPositions(this->unmatchedA.getOutput());
   }
   if (this->in_group_B)
     this->buildPointList(this->contB, this->unmatchedB);
 
   DUMP(this->getID() << " : Generating Communication Scheme", DBG_INFO_STARTUP);
   MPI_Barrier(MPI_COMM_WORLD);
   DUMP(this->getID() << " : exchange coarse geometries", DBG_DETAIL);
   this->exchangeGeometries(this->unmatchedA, this->unmatchedB);
   MPI_Barrier(MPI_COMM_WORLD);
 
   DUMP(this->getID() << " : exchange points positions", DBG_DETAIL);
   this->exchangePositions();
   MPI_Barrier(MPI_COMM_WORLD);
 
   if (this->in_group_B) {
     // set the size and assign zero (for help in debugging)
     this->field_buffer.assign(Dim * (this->pointsAlist->size()), 0);
     this->fillGrid();
     this->associate();
   }
 
   MPI_Barrier(MPI_COMM_WORLD);
 
   DUMP(this->getID() << " : ExchangeAssociation", DBG_DETAIL);
   std::vector<UInt> managed;
   this->exchangeAssociationInformation(managed);
 
   if (!this->in_group_A || !this->in_group_B) {
     if (this->in_group_A) {
 
       LM_ASSERT(managed.size() == this->local_points * this->nb_zone_B,
                 "internal error " << managed.size() << " != "
                                   << this->local_points * this->nb_zone_B);
 
       std::vector<std::vector<UInt>> unassociated;
       this->createDuoVectorA("A", managed, unassociated);
       for (UInt i = 0; i < this->nb_zone_B; ++i) {
         LM_ASSERT(unassociated[i].size() == 0,
                   "internal error : "
                       << " for proc " << i << " " << unassociated[i].size()
                       << " points were already associated");
       }
     }
 
     if (this->in_group_B)
       this->createDuoVectorB("B");
   }
 
   if (this->in_group_A) {
     this->filterPointListAForUnmatched();
     LM_ASSERT(this->unmatchedA->size() == this->pointsAlist->size(),
               "internal error " << this->unmatchedA->size()
                                 << " != " << this->pointsAlist->size());
 
     LM_TOIMPLEMENT;
     UInt total_points_from_file;
     // UInt total_points_from_file = this->unmatchedA->getNbPointsInFile();
     UInt total_points = this->local_points;
     this->comm_group_A.allReduce(&total_points, 1, "verif association", OP_SUM);
     if (total_points != total_points_from_file) {
       if (total_points > total_points_from_file) {
         LM_FATAL("This should never happen, not even with a faulty mesh. If "
                  << "you get this message, you're looking at a serious bug.");
       }
       // in this case, need to figure out which points are missing
       LM_FATAL("problem in A association " << total_points
                                            << " != " << total_points_from_file);
     }
   }
   if (this->in_group_B) {
     this->filterPointListBForUnmatched();
     this->local_points = this->pointsBlist->size();
     this->filterAssoc();
     LM_ASSERT(this->unmatchedB->size() == this->pointsBlist->size(),
               "internal error");
 
 #ifndef LM_OPTIMIZED
     LM_TOIMPLEMENT;
     UInt total_points_from_file;
     // UInt total_points_from_file = this->unmatchedB.getNbPointsInFile();
     UInt total_points = this->local_points;
     this->comm_group_B.allReduce(&total_points, 1, "verif association", OP_SUM);
     LM_ASSERT(total_points == total_points_from_file,
               "problem in B association " << total_points
                                           << " != " << total_points_from_file);
 #endif
   }
 
   checkPositionCoherency();
 
   if (this->in_group_A && this->contA.hasRefManager()) {
     try {
       this->contA.getRefManager()->attachObject(this->getDuoVector(),
                                                 *this->pointsAlist);
       DUMP(this->getID() << " : attaching Parent::duo_vector", DBG_INFO);
     } catch (LibMultiScaleException &e) {
     }
   }
   if (this->in_group_B && this->contB.hasRefManager()) {
     try {
       this->contB.getRefManager()->attachObject(this->getDuoVector(),
                                                 *this->pointsBlist);
       DUMP(this->getID() << " : attaching Parent::duo_vector", DBG_INFO);
     } catch (LibMultiScaleException &e) {
     }
   }
 
   // DUMP(this->getID() << ": bounding box of " <<
   //      this->pointsAlist.getID() << " is "
   //      <<  this->pointsAlist.getBoundingBox(),DBG_MESSAGE);
 
   // DUMP(this->getID() << ": bounding box of " <<
   //      this->pointsBlist.getID() << " is "
   //      <<  this->pointsBlist.getBoundingBox(),DBG_MESSAGE);
 
   // generate the weights
   if (weight_path != "") {
     this->computeWeights();
   }
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB, Dim>::computeWeights() {
 
   ComputeExtract c_positions("ComputeExtract:" + this->getID());
   c_positions.setParam("FIELD", _position0);
   c_positions.buildManual(pointsAlist);
   this->weights.setParam("FILENAME", this->weight_path);
   this->weights.init();
   this->weights.buildManual(c_positions);
 
   if (this->in_group_A && !this->in_group_B)
     LM_FATAL("not a parallel routine yet");
   if (this->pointsAlist->size() != this->pointsBlist->size())
     LM_FATAL("inconsistency here");
 
   std::vector<Real> denominator;
 
   // weightsA.resize(this->pointsAlist.nbElem());
   // weightsB.resize(this->pointsAlist.nbElem());
 
   weightsA.assign(this->pointsAlist->size(), 0.);
   weightsB.assign(this->pointsAlist->size(), 0.);
 
   // compute nominator and denominator
   UInt index = 0;
   for (auto &&point : this->pointsAlist) {
     Real mass = point.mass();
     weightsA[index] = weights[index] * mass;
     ++index;
   }
   index = 0;
   for (auto &&point : this->pointsBlist) {
     Real mass = point.mass();
     weightsB[index] = (1. - weights[index]) * mass;
     ++index;
   }
 
   for (UInt index = 0; index < weights.size(); ++index) {
     Real denom = weightsA[index] + weightsB[index];
     weightsA[index] /= denom;
     weightsB[index] /= denom;
   }
 
   LM_TOIMPLEMENT;
   // FilterManager::getManager().addObject(&this->weights, false);
   // FilterManager::getManager().addObject(&this->weightsA, false);
   // FilterManager::getManager().addObject(&this->weightsB, false);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename ContainerA, typename ContainerB, UInt Dim>
 template <typename container, typename PointList>
 void PointAssociation<ContainerA, ContainerB, Dim>::buildPointList(
     container &cont, PointList &pointList) {
 
   casted_component<FilterGeometry>::cast<typename container::ContainerSubset>
       filter_geom("FilterGeom:" + this->getID());
 
   filter_geom.setParam("GEOMETRY", this->geomID);
   filter_geom.setParam("DONOTRESETBOUNDINGBOX", true);
   filter_geom.setParam("DO_NOT_REGISTER", true);
   filter_geom.setParam("BASED_ON_NODES", true);
   filter_geom.setParam("DOF_TYPE", dt_local_master);
   filter_geom.init();
   filter_geom.buildManual(cont);
 
   DUMP("constructed filtergeom with " << filter_geom->size() << " points ",
        DBG_INFO_STARTUP);
   pointList.setParam("PATH", this->path);
   pointList.setParam("TOL", this->tolerance);
   pointList.init();
   pointList.buildManual(filter_geom);
   DUMP("constructed filter_point with " << pointList->size() << " points ",
        DBG_INFO_STARTUP);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB, Dim>::fillGrid() {
   // create my grid
   if (this->grid) {
     this->deleteGrid();
   }
   Geometry &geom = *GeometryManager::getManager().getGeometry(this->geomID);
   Cube cube = geom.getBoundingBox();
   this->grid = new SpatialGridPoint<UInt, Dim>(cube, this->grid_division);
 
   UInt index = 0;
   for (auto &&point : this->unmatchedB) {
     auto position = point.position0();
     // I'ts important to use addAtom here instead of addElement, because here
     // we're sensitive to atoms on the edge of grid_boxes
     this->grid->addAtom(index, position);
     ++index;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt Dim, typename V1, typename V2>
 inline bool coincidence(V1 &pointA, V2 &pointB, const Real &tolerance) {
   Real distance = 0;
   for (UInt dir = 0; dir < Dim; ++dir) {
     distance += fabs(pointA[dir] - pointB[dir]);
   }
   return distance < tolerance;
 }
 /* -------------------------------------------------------------------------- */
 template <UInt Dim, typename V1, typename V2>
 inline Real temp_coincidence(V1 &pointA, V2 &pointB) {
   Real distance = 0;
   for (UInt dir = 0; dir < Dim; ++dir) {
     distance += fabs(pointA[dir] - pointB[dir]);
   }
   return distance;
 }
 /* -------------------------------------------------------------------------- */
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB, Dim>::associate() {
 
   this->assoc.assign(this->local_points, lm_uint_max);
 
   LM_ASSERT(this->positions.size() == this->local_points * Dim,
             "inconsistency " << this->positions.size()
                              << " != " << this->local_points * Dim);
 
   // Loop over all positions of A world
   bool found;
   Real min_dist;
   UInt not_found_counter = 0;
   Real *posA_ptr = &this->positions[0];
   for (UInt indexA = 0; indexA < this->local_points;
        ++indexA, posA_ptr += Dim) {
     // extract the points of pointsBlist which are candidates for association
     VectorView<Dim> positionA(posA_ptr);
     LM_TOIMPLEMENT;
     // auto &&subsetPointsB = this->grid->findSet(positionA);
     found = false;
     min_dist = lm_real_max;
     // loop the candidates
     LM_TOIMPLEMENT;
     // for (auto &&indexB : subsetPointsB) {
     //   auto &&positionB = unmatchedB.get(indexB).position0();
     //   Real dist = temp_coincidence<Dim>(positionA, positionB);
     //   if (dist < min_dist)
     //     min_dist = dist;
     //   if (coincidence<Dim>(positionA, positionB, this->tolerance)) {
     //     this->assoc[indexA] = indexB;
     //     ++this->assoc_found;
     //     found = true;
     //     if (indexA < 10)
     //       DUMP("associate point " << positionA << ", " << indexB
     //                               << " with position " << indexA,
     //            DBG_DETAIL);
     //     break;
     //   }
     // }
     if (!found) {
       ++not_found_counter;
       {
         std::stringstream sstr;
         sstr << not_found_counter << ": couldn't associate point (";
         for (UInt i = 0; i < Dim - 1; ++i)
           sstr << positionA[i] << ", ";
         sstr << positionA[Dim - 1] << "), "
              << "the minimal distance was " << min_dist;
         DUMP(sstr.str(), DBG_INFO);
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB, Dim>::clearAll() {
   this->assoc_found = 0;
   this->assoc.clear();
   delete this->grid;
   pointsAlist->clear();
   pointsBlist->clear();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB,
                       Dim>::filterPointListAForUnmatched() {
 
   this->pointsAlist->clear();
 
   for (UInt i = 0; i < this->assoc.size(); ++i) {
     if (this->assoc[i] != UINT_MAX) {
       DUMP("for container, atom " << i << " becomes "
                                   << this->pointsAlist->size(),
            DBG_ALL);
 
-      this->pointsAlist->add(this->unmatchedA->get(i));
+      this->pointsAlist->push_back(this->unmatchedA->get(i));
     } else {
       DUMP("atom filtered " << i << " " << this->unmatchedA->get(i),
            DBG_DETAIL);
     }
   }
 
   this->pointsAlist->copyContainerInfo(unmatchedA);
   LM_TOIMPLEMENT;
   // this->pointsAlist->copyReleaseInfo(unmatchedA);
 }
 /* -------------------------------------------------------------------------- */
 
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB,
                       Dim>::filterPointListBForUnmatched() {
 
   this->pointsBlist->clear();
 
   UInt counter = 0;
   for (UInt i = 0; i < this->assoc.size(); ++i) {
     if (this->assoc[i] != UINT_MAX) {
       DUMP("for container, atom " << i << " becomes "
                                   << this->pointsBlist->size(),
            DBG_ALL);
 
-      this->pointsBlist->add(unmatchedB->get(this->assoc[i]));
+      this->pointsBlist->push_back(unmatchedB->get(this->assoc[i]));
       this->assoc[i] = counter;
       ++counter;
     } else {
       DUMP("atom filtered " << i, DBG_DETAIL);
     }
   }
   this->pointsBlist->getBoundingBox() = unmatchedB->getBoundingBox();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB, Dim>::checkPositionCoherency() {
 
   // try {
   //   std::stringstream sstr;
   //   sstr << this->getID() << "-duovector-" << current_step << "-" <<
   //   current_stage;
   //   this->getDuoVector().print(sstr.str());
   // }
   // catch (LibMultiScaleException & e){
 
   // }
 
   // extract the position of local atoms
   if (this->in_group_A)
     this->buildPositions(this->pointsAlist.getOutput());
 
   // transport the positions to B side
   this->distributeVectorA2B("temp_positions", this->positions, Dim);
 
   if (this->in_group_B) {
 
     UInt point_idx = 0;
     for (auto &&point : this->pointsBlist) {
 
       auto &&local_pos = point.position0();
 
       std::stringstream sstr;
       for (UInt i = 0; i < Dim; ++i)
         sstr << this->positions[Dim * point_idx + i] << " ";
 
       sstr << " and ";
 
       for (UInt i = 0; i < Dim; ++i)
         sstr << local_pos[i] << " ";
 
       std::string _tmp = sstr.str();
       DUMP("for point " << point_idx << " compare " << _tmp, DBG_DETAIL);
 
       for (UInt k = 0; k < Dim; ++k) {
         if (fabs(this->positions[Dim * point_idx + k] - local_pos[k]) > 1e-5) {
 
           LM_FATAL(this->getID()
                    << ": inconsistency in the communication scheme "
                    << this->positions[Dim * point_idx + k]
                    << " != " << local_pos[k] << " " << point_idx);
         }
       }
       ++point_idx;
     }
   }
   DUMP("position coherency OK", DBG_INFO);
 }
 /* -------------------------------------------------------------------------- */
 
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB, Dim>::updateForMigration() {
 
   DUMP("update migration for " << this->getID(), DBG_INFO);
   DUMP("update local_points " << this->getID(), DBG_INFO);
   STARTTIMER("syncMigration resize");
   // update local number of points
   if (this->in_group_A)
     this->local_points = this->pointsAlist->size();
   // update local number of points
   if (this->in_group_B)
     this->local_points = this->pointsBlist->size();
   this->positions.resize(Dim * this->local_points);
   STOPTIMER("syncMigration resize");
 
   DUMP("synchMigration " << this->getID(), DBG_INFO);
   STARTTIMER("syncMigration duo");
   if ((this->in_group_A && this->contA.hasRefManager()) ||
       (this->in_group_B && !this->contB.hasRefManager()))
     this->synchronizeMigration(this->comm_group_A, this->comm_group_B);
   if ((this->in_group_B && this->contB.hasRefManager()) ||
       (this->in_group_A && !this->contA.hasRefManager()))
     this->synchronizeMigration(this->comm_group_B, this->comm_group_A);
   STOPTIMER("syncMigration duo");
 
   DUMP("update release " << this->getID(), DBG_INFO);
   LM_TOIMPLEMENT; // to review
   // pointsAlist.setRelease(this->contA.getRelease());
   // pointsBlist.setRelease(this->contB.getRelease());
 
   if (check_coherency) {
     DUMP("check position coherency " << this->getID(), DBG_INFO);
     STARTTIMER("check position coherency");
     this->checkPositionCoherency();
     STOPTIMER("check position coherency");
   }
 }
 /* -------------------------------------------------------------------------- */
 /* LMDESC PointAssociation
    This coupler computes the association between point degrees of freedom of
    different domains
 */
 /* LMHERITATE ComputeTrueDisplacement
  */
 
 template <typename ContainerA, typename ContainerB, UInt Dim>
 void PointAssociation<ContainerA, ContainerB, Dim>::declareParams() {
   DofAssociation<ContainerA, ContainerB, Dim>::declareParams();
   this->addSubParsableObject(true_disp);
 
   /* LMKEYWORD TOL
      max distance between two points to consider them coincident
    */
   this->parseKeyword("TOL", tolerance);
 
   /* LMKEYWORD PATH
      file path to the filteratom file
   */
   this->parseKeyword("PATH", path);
 
   /* LMKEYWORD PBC
      Specify if periodic boundary conditions should be considered for each
      direction
   */
   this->parseVectorKeyword("PBC", spatial_dimension, this->pbc);
 
   /* LMKEYWORD CHECK_COHERENCY
      Perform a systematic check of the communication scheme.
      \textbf{Be careful, it is extremely computationally expensive}
   */
   this->parseKeyword("CHECK_COHERENCY", check_coherency, false);
 
   /* LMKEYWORD WEIGHT_PATH
      file path to the python script to generate the weights
   */
   this->parseKeyword("WEIGHT_PATH", weight_path);
 }
 /* -------------------------------------------------------------------------- */
 
 DECLARE_BRIDGING_ATOMIC_CONTINUUM_TEMPLATE(PointAssociation)
 DECLARE_BRIDGING_CONTINUUM_ATOMIC_TEMPLATE(PointAssociation)
 
 __END_LIBMULTISCALE__
diff --git a/src/coupling/template_cadd.cc b/src/coupling/template_cadd.cc
index b0b29ec..3babde5 100644
--- a/src/coupling/template_cadd.cc
+++ b/src/coupling/template_cadd.cc
@@ -1,2075 +1,2075 @@
 /**
  * @file   template_cadd.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Till Junge <till.junge@epfl.ch>
  * @author Jaehyun Cho <jaehyun.cho@epfl.ch>
  *
  * @date   Thu Sep 18 14:51:07 2014
  *
  * @brief  Simple CADD-like coupler
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * LibMultiScale is free  software: you can redistribute it and/or  modify it
  * under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * LibMultiScale is  distributed in the  hope that it  will be useful, but
  * WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 #define TIMER
 /* -------------------------------------------------------------------------- */
 #include "template_cadd.hh"
 #include "lib_bridging.hh"
 #include "lm_common.hh"
 #include <algorithm>
 #include <assert.h>
 #include <cmath>
 #include <fstream>
 #include <iomanip>
 #include <unistd.h>
 #include <utility>
 #include <vector>
 
 #include "mpi.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "compute_extract.hh"
 #include "container_mesh.hh"
 #include "geometry_manager.hh"
 #include "reference_manager_interface.hh"
 
 #include "communicator.hh"
 #include "domain_dd_interface.hh"
 #include "ref_point_data.hh"
 
 /* -------------------------------------------------------------------------- */
 __BEGIN_LIBMULTISCALE__
 
 /* -------------------------------------------------------------------------- */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::mergeDuplicateNodes() {
   for (auto &&nd : this->domA.getContainer().getContainerNodes()) {
     LM_TOIMPLEMENT;
     // UInt nbrs = nd.getNbrOfNeighs();
     UInt nbrs = std::numeric_limits<UInt>::max();
     UInt idx = nd.getIndex();
 
     if (this->md_cube->contains(nd.position()) && nbrs == 2) {
       UInt idx2 = nd.getIndex();
       for (auto &&nd2[[gnu::unused]] : this->domA.getContainer().getContainerNodes()) {
         LM_TOIMPLEMENT;
         //auto dX = nd.position() - nd2.position();
         // Real dist = dX.norm();
         auto dist = std::numeric_limits<Real>::max();
         if ((idx != idx2) && (dist < 1e-2)) {
           this->domA.freenodearm(idx);
           this->domA.freenode(idx);
 
           this->domA.freenodearm(idx2);
           this->domA.freenode(idx2);
         }
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::init() {
 
   // auto &comm = Communicator::getCommunicator();
 
   // fabricating the geometries
   // IteratorDDNodes nodes = this->domA.getContainerNodes().getIterator();
   auto md_geom = GeometryManager::getManager().getGeometry(this->md_geom);
   this->md_cube = std::dynamic_pointer_cast<Cube>(md_geom);
 
   auto dd_geom = GeometryManager::getManager().getGeometry(this->dd_geom);
   this->dd_cube = std::dynamic_pointer_cast<Cube>(dd_geom);
 
   Vector<3u> xmin(this->md_cube->getXmin());
   Vector<3u> xmax(this->md_cube->getXmax());
 
   for (UInt i : {0, 1, 2}) {
     xmin[i] -= this->pad_thickness + this->distance_ddline_from_pad;
     xmax[i] += this->pad_thickness + this->distance_ddline_from_pad;
   }
 
   this->md_cube->setXmin(xmin);
   this->md_cube->setXmax(xmax);
 
   // constructing some flags
   this->detect_simple_bool = false;
   simple_direction = 3;
 
   for (auto &&i : {0, 1, 2}) {
 
     if (this->close_direction[i] != 0)
       this->close_in_infinity = true;
 
     if (this->detect_simple_direction[i] != 0) {
       this->detect_simple_bool = true;
       simple_direction = i;
     }
   }
 
   if (this->aniso) {
     Real c11 = this->elastic_coefs[0];
     Real c12 = this->elastic_coefs[1];
     Real c22 = this->elastic_coefs[4];
     Real c66 = this->elastic_coefs[12];
     Real lambda2 = sqrt(c11 / c22);
 
     this->c11bar = sqrt(c11 * c12);
     this->lambda = sqrt(lambda2);
     this->phi = 0.5 * acos((c12 * c12 + 2.0 * c12 * c66 - c11bar * c11bar) /
                            (2.0 * c11bar * c66));
     if (this->volterra)
       LM_FATAL("cannot be used at the same time with volterra and aniso");
   }
 
   // sending infos on parameters to paradis
   Real maxSeg, burgMag;
   if (this->is_in_dd) {
 
     Vector<Dim> domA_xmin = this->domA.getXmin();
     Vector<Dim> domA_xmax = this->domA.getXmax();
     if ((this->dd_cube->getXmin() - domA_xmin).norm() > 1e-7 ||
         (this->dd_cube->getXmax() - domA_xmax).norm() > 1e-7)
       DUMP("[WARNING] Check DD box lengths defined Libmultiscale configuration "
            "and ParaDis control files",
            DBG_MESSAGE);
 
     this->maxSeg0 = this->domA.getMaxSeg();
     this->minSeg0 = this->domA.getMinSeg();
     this->burgMag0 =
         this->domA.getBurgersMagnitude() * 1e+10; // in angstrom unit
 
     int my_rank_in_DDprocs = this->comm_group_dd.getMyRank();
 
     if (my_rank_in_DDprocs == 0) {
       UInt mdNBprocs = this->comm_group_atomic.size();
       for (UInt i = 0; i < mdNBprocs; ++i) {
         this->comm_group_atomic.send(&maxSeg, 1, i, "maximum length of dd");
         this->comm_group_atomic.send(&burgMag, 1, i,
                                      "burgers vector magnitude");
       }
     }
   }
 
   // receive information on parameters to paradis
   if (this->is_in_atomic) {
     this->comm_group_dd.receive(&maxSeg, 1, 0, "maximum length of dd segments");
     this->comm_group_dd.receive(&burgMag, 1, 0, "burgers vector magnitude");
     this->maxSeg0 = maxSeg;
     this->burgMag0 = burgMag;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::coupling(CouplingStage stage) {
 
   //! Main coupling calls
   if (stage == COUPLING_STEP3) {
     STARTTIMER("applyDetection");
     this->applyDetection();
     STOPTIMER("applyDetection");
 
     STARTTIMER("applyTemplateToPad");
     this->applyTemplateToPad();
     STOPTIMER("applyTemplateToPad");
     return;
   }
 }
 
 /* --------------------------------------------------------------------------
 
    applyDetection does following jobs in two kinds of processors (MD and DD)
 
    MD: 1. compute MD dislocation coordinates (DXA or user-defined compute)
        2. send to DD processor
 
    DD: 1. (at every step) constrain DD nodes located in MD domain
        3. receive the MD dislocation coordinates from MD processor
        4. move DD nodes to the closest MD segements
        5. register the remained MD cores as new DD nodes
        6. check topology - remesh
 
 -------------------------------------------------------------------------- */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::applyDetection() {
 
   UInt num_dislo = 0;
   std::vector<Vector<Dim>> dislocations;
 
   // auto &comm = Communicator::getCommunicator();
   if (this->is_in_atomic) {
     if (current_step % this->detect_freq == 0) {
       UInt my_rank_in_MD = this->comm_group_atomic.getMyRank();
 
       STARTTIMER("detect_cores_by_compute");
       this->detect_cores_by_compute(num_dislo, dislocations);
 
       STOPTIMER("detect_cores_by_compute");
 
       if (my_rank_in_MD == 0) {
         UInt nbDDprocs = this->comm_group_dd.size();
         for (UInt i = 0; i < nbDDprocs; ++i) {
           // int real_rank = this->comm_group_dd.realRank(i);
           // int rank_in_group = this->comm_group_dd.groupRank(real_rank);
           this->comm_group_dd.send(&num_dislo, 1, i,
                                    "number of dislocation cores");
           this->comm_group_dd.send(&dislocations[0], num_dislo * 3, i,
                                    "coordinates of dislocation cores");
         }
       }
     }
   }
 
   if (this->is_in_dd) {
 
     if (current_step % this->detect_freq == 0) {
       STARTTIMER("receiveMDcores");
 
       this->comm_group_atomic.receive(&num_dislo, 1, 0,
                                       "number of dislocation cores");
 
       std::vector<Vector<Dim>> MDs(num_dislo);
 
       this->comm_group_atomic.receive(&MDs[0], num_dislo * 3, 0,
                                       "coordinates of dislocation cores");
 
       if (MDs.size() == 0)
         DUMP("No atoms received!", DBG_MESSAGE);
       STOPTIMER("receiveMDcores");
 
       Real burgMag = this->domA.getBurgersMagnitude();
       burgMag = 1e+10 * burgMag; // in angstrom unit
       Real avgSeg0 = (this->minSeg0 + this->maxSeg0) / 2.;
 
       STARTTIMER("moveSlavedDDNodes");
       for (auto nd : this->domA.getContainer().getContainerNodes()) {
 
         LM_TOIMPLEMENT;
         // UInt nbrs = nd.getNbrOfNeighs();
         UInt nbrs = std::numeric_limits<UInt>::max();
         Vector<Dim> dd_node = nd.position();
 
         if (((nd.getConstraint() == 7) && (nbrs == 2) &&
              this->md_cube->contains(nd.position())) ||
             ((nd.getConstraint() == 7) && (nbrs == 2) &&
              (detect_simple_bool))) {
 
           LM_TOIMPLEMENT;
           // Vector<Dim> nbr1({nd.getNeighborNodeCoord(0, 0),
           //                   nd.getNeighborNodeCoord(0, 1),
           //                   nd.getNeighborNodeCoord(0, 2)});
           // Vector<Dim> nbr2({nd.getNeighborNodeCoord(1, 0),
           //                   nd.getNeighborNodeCoord(1, 1),
           //                   nd.getNeighborNodeCoord(1, 2)});
 
           // not simple detection ????
           if (!detect_simple_bool) {
             Vector<Dim> newX = Vector<Dim>::Zero();
             Real newC = 0.0;
             for (auto &&pos[[gnu::unused]] : MDs) {
               LM_TOIMPLEMENT;
               // Real dist = (pos - dd_node).norm();
               // Real dist1 = (pos - nbr1).norm();
               // Real dist2 = (pos - nbr2).norm();
 
               // if (((dist < avgSeg0) && (dist < dist1) && (dist < dist2)) ||
               //     ((dist1 < avgSeg0) && (dist2 < avgSeg0))) {
               //   newX += pos;
               //   newC += 1.0;
               // }
             }
             if (newC != 0.0) {
               newX /= newC;
               nd.position()[0] = newX[0];
               nd.position()[2] = newX[2];
             }
             nd.unconstrain();
           }
           // simple detection ????
           else {
             Real value = -99999.9;
             for (auto &&pos : MDs) {
               Real dist = this->maxSeg0 * 3.0;
               dist = fabs(dd_node[simple_direction] - pos[simple_direction]);
               if (dist < avgSeg0 * 2.0)
                 value = pos[simple_direction];
             }
             if (value == -99999.9) {
               DUMP("DD node (" << dd_node << ")", DBG_MESSAGE);
               for (auto &&pos : MDs) {
                 DUMP("MD core "
                          << " (" << pos << ")",
                      DBG_MESSAGE);
               }
               LM_FATAL("cannot find the value");
             }
             nd.position()[simple_direction] = value;
           }
         } else if ((nd.getConstraint() == 7) && (nbrs == 1) &&
                    (detect_partial)) {
           bool selected(false);
           for (auto &&pos : MDs) {
             Real dist = sqrt((pos - dd_node).dot(pos - dd_node));
             if (dist < avgSeg0) {
               nd.position()[0] = pos[0];
               nd.position()[2] = pos[2];
               avgSeg0 = dist;
               selected = true;
             }
           }
           if (selected == false)
             DUMP("cannot find the value in partial detection", DBG_MESSAGE);
         }
       }
 
       if (!detect_simple_bool) {
         // merging duplicate nodes
       }
       STOPTIMER("moveSlavedDDNodes");
       STARTTIMER("DDremesh_in_CADD3d");
       this->domA.remesh();
       STOPTIMER("DDremesh_in_CADD3d");
 
       // release or constrain again after coupling step
       for (auto &&nd : this->domA.getContainer().getContainerNodes()) {
 
         if (!detect_simple_bool) {
           if (this->md_cube->contains(nd.position())) {
             nd.constrain();
           } else {
             LM_TOIMPLEMENT;
             // UInt nbrs = nd.getNbrOfNeighs();
             // if (nbrs == 2)
             //   nd.unconstrain();
           }
         }
         if (this->domA.is_it_bound()) {
           if (this->dd_cube->contains(nd.position())) {
             nd.constrain();
           }
         }
       }
     } // if(current_step % ....)
   }   // if(is_in_dd) {
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::detect_cores_by_compute(
     UInt &num_dislo, std::vector<Vector<Dim>> &dislocations) {
 
   LMID id = compute_list[0];
   LM_TOIMPLEMENT;
   // ComputeInterface *my_compute = dynamic_cast<ComputeInterface *>(
   //     FilterManager::getManager().getObject(id));
   // if (!my_compute)
   //   LM_FATAL("invalid compute for detect cores " << compute_list[0]);
   // my_compute->build();
   // UInt n_nodes_xyz = my_compute->size();
   // UInt count = 0;
   // UInt num_dislo0 = 0;
   std::vector<Vector<Dim>> dislo_pos;
 
   Vector<3u> xmin(this->md_cube->getXmin());
   Vector<3u> xmax(this->md_cube->getXmax());
   Real pt = this->distance_ddline_from_pad;
 
   for (UInt i : {0, 1, 2}) {
     xmin[i] -= pt;
     xmax[i] += pt;
   }
 
   Cube dd_cube_extended(Dim);
   dd_cube_extended.setXmin(xmin);
   dd_cube_extended.setXmax(xmax);
 
   LM_TOIMPLEMENT;
   // for (count = 0; count < n_nodes_xyz;) {
   //   Vector<Dim> dd_pos = {my_compute->get(count), my_compute->get(count + 1),
   //                         my_compute->get(count + 2)};
   //   if (dd_cube_extended.contains(dd_pos) || (this->detect_simple_bool)) {
 
   //     dislo_pos.push_back(dd_pos);
   //     dislocations.push_back(dd_pos);
   //     num_dislo0 += 1;
   //   }
   //   count += 3;
   // }
   // num_dislo = num_dislo0;
   // my_compute->empty();
   return;
 }
 
 /* --------------------------------------------------------------------------
 
    applyTemplateToPad does following jobs in two kinds of processors (MD and DD)
 
        7. (at every step) set velocity of PAD atoms to zero
           (initially it was done first)
 
    DD: 1. close DD dislocation structures
        2. compute number of closed DD dislocation loops
        2. send to MD processor (with array form)
 
    MD: 1. receive the informations about DD structures from DD processor
        2. compute offset parallel curves in order to decide template regions
        for each atom...
           for each loop...
              3. compute Barnett displacement fields
              4. compute template displacments when the atom is in the parallel
 curves.
              5. update total displacements
           6. apply total displacements
 
 -------------------------------------------------------------------------- */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::applyTemplateToPad() {
 
   // set to zero force and velocity of the pad
   auto pad = GeometryManager::getManager().getGeometry(pad_geom);
   for (auto &&at : this->domC.getContainer()) {
     if (pad->contains(at.position())) {
       at.velocity() = Vector<Dim>::Zero();
       at.force() = Vector<Dim>::Zero();
     }
   }
 
   // if not the right moment, do nothing
   if (current_step % detect_freq != 0)
     return;
 
   // retreive the dd_points (communication)
   std::vector<JaehyunDDPoint> dd_points = this->sendDDSegments2MD();
 
   if (this->is_in_atomic) {
 
     STARTTIMER("applyDisplacement");
 
     UInt num_dislo = 0;
     std::vector<std::vector<Real>> dislocations;
     // Here, we analyze dd_points data to find out
     // where and how the cores exist
 
     if ((this->aniso) || (this->volterra)) {
 
       for (auto &dd_pt : dd_points) {
         for (UInt j = 0; j < 2; ++j) {
           auto neigh = dd_pt.neighs[j];
           auto burg = neigh.burg * this->burgMag0;
           Real bmag =
               burg[0] * cos(this->angle_between_b_and_x / 180.0 * M_PI) +
               burg[2] * sin(this->angle_between_b_and_x / 180.0 * M_PI);
           bmag = roundf(bmag * 10.0) / 10.0;
           if (bmag / fabs(bmag) > 0) {
             Real idx = dd_pt.idx;
             auto &ddX = dd_pt.X;
             Real nbi = neigh.idx;
             if ((idx >= 0.0) && (nbi < 0.0)) {
               num_dislo += 1;
               std::vector<Real> coord_vector;
               coord_vector.push_back(ddX[0]);
               coord_vector.push_back(ddX[1]);
               coord_vector.push_back(ddX[2]);
               dislocations.push_back(coord_vector);
             }
           }
         }
       }
       DUMP(num_dislo << " straight dislocations will be imposed", DBG_MESSAGE);
       for (UInt i = 0; i < num_dislo; ++i) {
         DUMP("(" << dislocations[i][0] << ", " << dislocations[i][1] << ", "
                  << dislocations[i][2] << ")",
              DBG_MESSAGE);
       }
     }
 
     auto md_ranges = this->md_cube->getXmax() - this->md_cube->getXmin();
     Real mdxlen = md_ranges[0];
     Real mdzlen = md_ranges[2];
     UInt count_true_disp = 0;
 
     // IteratorAtomsSubset it = this->pad_atoms.getIterator();
 
     for (auto &&at : this->pad_atoms) {
       Vector<Dim> disp = at.displacement();
       Vector<Dim> pos0 = at.position0();
       Vector<Dim> pos0_pbc = at.position0();
       Vector<Dim> pos0_pbc0 = at.position0();
 
       if (fabs(disp[2]) > mdzlen / 2.) {
         Real signZ = disp[2] / fabs(disp[2]);
         pos0_pbc[2] = pos0[2] + mdzlen * signZ;
         count_true_disp += 1;
       }
 
       if (fabs(disp[0]) > mdxlen / 2.) {
         Real signX = disp[0] / fabs(disp[0]);
         pos0_pbc[0] = pos0[0] + mdxlen * signX;
       }
 
       for (UInt i = 0; i < 3; ++i) {
         pos0_pbc0[i] = pos0_pbc[i];
       }
 
       if (this->aniso)
         functionifAniso(num_dislo, pos0_pbc, pos0_pbc0, dislocations, at);
 
       else if (this->volterra)
         functionifVolterra(num_dislo, pos0_pbc, pos0_pbc0, dislocations, at);
 
       else
         functionElse(dd_points, pos0_pbc, at);
     }
 
     STOPTIMER("applyDisplacement");
     // this->domC.updatePAD();
   } // if(is_in_atomic ...)
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::ComputeAnalyticDisplacements(
     Vector<Dim> &analytic_disp, Vector<Dim> &B, Vector<Dim> &A,
     Vector<Dim> &burg, Vector<Dim> &pos0) {
   // Compute closure point for given AB segment
   Vector<Dim> C[[gnu::unused]] = Vector<Dim>::Zero();
   LM_TOIMPLEMENT;
   //this->domA.computeClosurePoint(B, A, burg, C);
 
   // Compute point P1, projected point of C on line consisted to A and Ab
   Vector<Dim> P1[[gnu::unused]] = Vector<Dim>::Zero();
   LM_TOIMPLEMENT;
   //this->domA.computeProjectedPoint(B, C, burg, P1);
 
   // Compute point P2, projected point of C on line consisted to B and Bb
   Vector<Dim> P2[[gnu::unused]] = Vector<Dim>::Zero();
   LM_TOIMPLEMENT;
   //this->domA.computeProjectedPoint(A, C, burg, P2);
 
   Vector<Dim> dispPointU1 = Vector<Dim>::Zero();
   LM_TOIMPLEMENT;
   //this->domA.computeBarnett(P2, B, A, burg, dispPointU1, pos0, this->pois0);
 
   analytic_disp += dispPointU1;
 
   Vector<Dim> dispPointU2 = Vector<Dim>::Zero();
   LM_TOIMPLEMENT;
   //this->domA.computeBarnett(P1, B, P2, burg, dispPointU2, pos0, this->pois0);
   analytic_disp += dispPointU2;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::ComputeOffsetParallelCurve(
     std::vector<JaehyunDDPoint> &dd_points) {
 
   for (auto dd_pt : dd_points) {
     std::vector<Real> angles;
     Real count = 2.0;
     auto node_X = dd_pt.X;
 
     UInt slip_case = 3;
     Real avgangle = 0.;
 
     // computes some angle made by the arm in the slip plane
     for (auto &&neigh : dd_pt.neighs) {
       auto &next_X = neigh.X;
       //auto next_normal = neigh.normal;
       Real angle_between_neighbor = 0.0;
       Vector<Dim> segment = next_X - node_X;
 
       // should construct a rotation which puts
       // the normal as the direction Z
       LM_TOIMPLEMENT;
       angle_between_neighbor = atan2(segment[0], segment[1]);
       angles.push_back(angle_between_neighbor);
       avgangle += angle_between_neighbor;
     }
     avgangle /= dd_pt.neighs.size();
 
     Vector<Dim> dX1 = {0.0, 0.0, 0.0};
     Vector<Dim> dX2 = {0.0, 0.0, 0.0};
     computeOffset(node_X, avgangle, dX1, dX2, slip_case);
 
     if (count != 0.0) {
       if (isnan(dX1[0]) || isnan(dX1[1]) || isnan(dX1[2]) || isnan(dX2[0]) ||
           isnan(dX2[1]) || isnan(dX2[2]))
         LM_FATAL("wrong dX1 and dX2");
     }
 
     angles[0] = radian2degree(angles[0]);
     angles[1] = radian2degree(angles[1]);
     avgangle = (angles[0] + angles[1]) / count;
     findCorrectOffsets(avgangle, dX1, dX2, slip_case);
 
     dd_pt.tmp_X = node_X + dX1;
     dd_pt.tmp2_X = node_X + dX2;
   }
   return;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::computeOffset(
     Vector<Dim> &current_node, Real ang, Vector<Dim> &dX1, Vector<Dim> &dX2,
     UInt slip_case) {
   Real rmax = this->core_rcut;
   Real slope = tan(ang);
 
   Real val1 = sqrt(rmax * rmax / (1.0 + slope * slope));
   Real val2 = sqrt(rmax * rmax - rmax * rmax / (1.0 + slope * slope));
   Real val3 = -sqrt(rmax * rmax / (1.0 + slope * slope));
   Real val4 = -sqrt(rmax * rmax - rmax * rmax / (1.0 + slope * slope));
 
   if (slip_case == 0) {
     dX1[0] = 0.0;
     dX1[1] = val1;
     dX1[2] = val2;
     dX2[0] = 0.0;
     dX2[1] = val3;
     dX2[2] = val4;
   } else if (slip_case == 1) {
     dX1[0] = val1;
     dX1[1] = 0.0;
     dX1[2] = val2;
     dX2[0] = val3;
     dX2[1] = 0.0;
     dX2[2] = val4;
   } else if (slip_case == 2) {
     dX1[0] = val1;
     dX1[1] = val2;
     dX1[2] = 0.0;
     dX2[0] = val3;
     dX2[1] = val4;
     dX2[2] = 0.0;
   } else
     LM_FATAL("cannot define angle with neighbor");
   return;
 }
 
 /* --------------------------------------------------------------------------
  */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::findCorrectOffsets(
     Real ang, Vector<Dim> &dX1, Vector<Dim> &dX2, UInt slip_case) {
   Real dev = 1e+5;
   Real saved_i = 1.0;
   Real saved_k = 1.0;
 
   for (int i = -1; i < 3;) {
     for (int k = -1; k < 3;) {
       Real tmp = -1.0;
       if (slip_case == 0)
         tmp = fabs(radian2degree(atan2(dX2[1] * (Real)i, dX2[2] * (Real)k)) -
                    ang);
       else if (slip_case == 1)
         tmp = fabs(radian2degree(atan2(dX2[2] * (Real)i, dX2[0] * (Real)k)) -
                    ang);
       else if (slip_case == 2)
         tmp = fabs(radian2degree(atan2(dX2[0] * (Real)i, dX2[1] * (Real)k)) -
                    ang);
       else
         LM_FATAL("unknown slip_case");
 
       if (tmp < dev) {
         dev = tmp;
         saved_i = (Real)i;
         saved_k = (Real)k;
       }
       k += 2;
     }
     i += 2;
   }
 
   if (slip_case == 0) {
     dX1[0] = dX1[0];
     dX1[1] = dX1[1] * saved_i;
     dX1[2] = dX1[2] * saved_k;
 
     dX2[0] = dX2[0];
     dX2[1] = dX2[1] * saved_i;
     dX2[2] = dX2[2] * saved_k;
   } else if (slip_case == 1) {
     dX1[0] = dX1[0] * saved_k;
     dX1[1] = dX1[1];
     dX1[2] = dX1[2] * saved_i;
 
     dX2[0] = dX2[0] * saved_k;
     dX2[1] = dX2[1];
     dX2[2] = dX2[2] * saved_i;
   } else if (slip_case == 2) {
     dX1[0] = dX1[0] * saved_i;
     dX1[1] = dX1[1] * saved_k;
     dX1[2] = dX1[2];
 
     dX2[0] = dX2[0] * saved_i;
     dX2[1] = dX2[1] * saved_k;
     dX2[2] = dX2[2];
   }
 
   return;
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 bool CADD_template<DomainDD, DomainMD, Dim>::in_side_ellipse(Real pos[],
                                                              Real rmax,
                                                              Real rmin,
                                                              Real *factor) {
   Real eq =
       ((pos[0] / rmax) * (pos[0] / rmax) + (pos[1] / rmin) * (pos[1] / rmin));
   Real val = 1.0 - eq;
   if (val >= 0.0) {
     *factor = sqrt(eq);
     return true;
   } else {
     *factor = sqrt(eq);
     return false;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 bool CADD_template<DomainDD, DomainMD, Dim>::is_it_infinite_connection(
     UInt index0, UInt *index0_infinite) {
 
   int int_index0_infinite;
   bool found = this->domA.getPairedIndex(index0, &int_index0_infinite);
   if (found) {
     *index0_infinite = (UInt)int_index0_infinite;
     return true;
   } else
     return false;
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::shear_strain(RefAtom at,
                                                           Vector<Dim> &disp) {
   Real eps_yx = this->shear_stresses[1] / this->mu0;
   Real eps_yz = this->shear_stresses[3] / this->mu0;
 
   Real eps_xy = this->shear_stresses[0] / this->mu0;
   Real eps_zy = this->shear_stresses[2] / this->mu0;
 
   disp[0] = eps_yx * at.position0()[1];
   disp[1] = eps_xy * at.position0()[0] + eps_zy * at.position0()[2];
   disp[2] = eps_yz * at.position0()[1];
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::tilt_strain(RefAtom at,
                                                          Vector<Dim> &disp) {
   //  Real LX = this->md_box_lengths[0];
   Real LY = this->md_box_lengths[1];
   Real LZ = this->md_box_lengths[2];
 
   // Real LY = fabs(this->md_yrange[1]) + fabs(this->md_yrange[0]);
   // Real LZ = fabs(this->md_zrange[1]) + fabs(this->md_zrange[0]);
 
   Real eps_xy = this->tilt_stresses[0] / this->mu0;
   Real eps_xz = this->tilt_stresses[1] / this->mu0;
   Real eps_yz = this->tilt_stresses[2] / this->mu0;
 
   disp[0] = -1.0 * eps_xy * (at.position0()[1] + LY / 2.0) -
             1.0 * eps_xz * (at.position0()[2] + LZ / 2.0);
   // disp[1] = -1.0*eps_yz*(at.position0(2) + LZ/2.0); // full dislocation
   disp[1] = -1.0 * eps_yz * (at.position0()[2] + LZ / 2.0); // half dislocation
   disp[2] = 0.0;
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::close_dislocation_loop(
     std::vector<JaehyunDDPoint> &dd_points,
     std::vector<JaehyunDDPoint> &dd_points_global) {
 
   bool added_point_in_infinity(false);
   Real maxdist = this->domA.getMaxSeg();
 
   UInt count = 0;
   for (auto &dd_pt_global : dd_points_global) {
 
     Real idx_real = dd_pt_global.idx;
     Real num_neigh = dd_pt_global.num_neigh;
 
     auto crr_X = dd_pt_global.X;
     auto &dd_pt = dd_points[count];
 
     dd_pt.idx = idx_real;
     dd_pt.num_neigh = num_neigh;
     dd_pt.X = crr_X;
 
     for (UInt n = 0; n < num_neigh; ++n) {
       auto neigh = dd_pt_global.neighs[n];
       Real nbr_idx = neigh.idx;
       auto &nbr_X = neigh.X;
 
       auto burg = neigh.burg;
       auto normal = neigh.normal;
 
       auto diff = nbr_X - crr_X;
       Real dist = diff.norm();
 
       UInt nbr_idx0_infinite = 0;
       Real nbr_idx_infinite_real = 0.0;
 
       bool found(false);
       UInt idx0 = (UInt)dd_pt_global.idx0;
 
       if ((this->close_in_infinity) &&
           (is_it_infinite_connection(idx0, &nbr_idx0_infinite)) &&
           (num_neigh == 1)) {
 
         // connectivity over an infinity boundary for single neighbors nodes:
         // frank-read sources
 
         Vector<Dim> nbr_X_infinite;
 
         for (auto &dd_pt_global2 : dd_points_global) {
           Real tmp = dd_pt_global2.idx0;
           UInt nbnbr = dd_pt_global2.num_neigh;
 
           if (((tmp - nbr_idx0_infinite) < 1e-2) && (nbnbr == 1)) {
             nbr_idx_infinite_real = dd_pt_global2.idx;
             nbr_X_infinite = dd_pt_global2.X;
             found = true;
           }
         }
 
         if (!found)
           LM_FATAL("not found a node infinitely connected for idx0 " << idx0);
 
         DUMP("infinity points are considered between "
                  << idx0 << " (" << crr_X << ") and " << nbr_idx0_infinite
                  << " (" << nbr_X_infinite << ") in ("
                  << this->close_direction[0] << ", " << this->close_direction[1]
                  << ", " << this->close_direction[2] << ") direction",
              DBG_MESSAGE);
 
         dd_pt.num_neigh = 2;
         dd_pt.neighs[0].idx = nbr_idx;
         dd_pt.neighs[0].X = nbr_X;
         dd_pt.neighs[0].burg = burg;
         dd_pt.neighs[0].normal = normal;
 
         dd_pt.neighs[1].idx = -1.0 * idx_real - 10000.0;
         for (UInt i : {0, 1, 2}) {
           dd_pt.neighs[1].X[i] = crr_X[i] + this->close_direction[i] * 1E+3;
         }
         dd_pt.neighs[1].burg = burg * -1.;
         dd_pt.neighs[1].normal = normal;
 
         auto &dd_pt_plus1 = *((&dd_pt) + 1);
 
         dd_pt_plus1.idx = -1.0 * idx_real - 10000.0;
         dd_pt_plus1.num_neigh = 2;
 
         for (UInt i : {0, 1, 2}) {
           dd_pt_plus1.X[i] = crr_X[i] + this->close_direction[i] * 1E+3;
         }
         dd_pt_plus1.neighs[0].idx = idx_real;
         dd_pt_plus1.neighs[0].X = crr_X;
         dd_pt_plus1.neighs[0].burg = burg;
         dd_pt_plus1.neighs[0].normal = normal;
         dd_pt_plus1.neighs[1].idx = -1.0 * nbr_idx_infinite_real - 10000.0;
         for (UInt i : {0, 1, 2}) {
           dd_pt_plus1.neighs[1].X[i] =
               nbr_X_infinite[i] + close_direction[i] * 1E+3;
         }
         dd_pt_plus1.neighs[1].burg = burg * -1.;
         dd_pt_plus1.neighs[1].normal = normal;
         added_point_in_infinity = true;
       } else if ((close_in_infinity) && (num_neigh == 2) &&
                  (dist > 5.0 * maxdist)) {
         // connectivity over an infinity boundary for Real neighbors nodes:
         // straight dislocation
         dd_pt.neighs[n].idx = -1.0 * dd_pt.idx - 10000.0;
         for (UInt i : {0, 1, 2}) {
           dd_pt.neighs[n].X[i] = crr_X[i] + this->close_direction[i] * 1E+3;
         }
         dd_pt.neighs[n].burg = burg;
         dd_pt.neighs[n].normal = normal;
 
         auto &dd_pt_plus1 = *((&dd_pt) + 1);
 
         dd_pt_plus1.idx = -1.0 * dd_pt.idx - 10000.0;
         dd_pt_plus1.num_neigh = 2;
         for (auto i : {0, 1, 2}) {
           dd_pt_plus1.X[i] = crr_X[i] + this->close_direction[i] * 1E+3;
         }
 
         dd_pt_plus1.idx0 = dd_pt.idx;
         dd_pt_plus1.neighs[0].X = crr_X;
         dd_pt_plus1.neighs[0].burg = burg * -1.;
         dd_pt_plus1.neighs[0].normal = normal;
 
         dd_pt_plus1.neighs[1].idx = -1.0 * nbr_idx - 10000.0;
         for (auto i : {0, 1, 2}) {
           dd_pt_plus1.neighs[1].X[i] =
               nbr_X[i] + this->close_direction[i] * 1E+3;
         }
         dd_pt_plus1.neighs[1].burg = burg;
         dd_pt_plus1.neighs[1].normal = normal;
 
         DUMP("Implicit infinity connection between "
                  << idx0 << " (" << dd_pt.X << ") and " << dd_pt_plus1.X << " ("
                  << nbr_X << ").",
              DBG_MESSAGE);
 
         added_point_in_infinity = true;
       } else if (num_neigh == 1) {
         //	&& (this->detect_partial)) {
         // straight connection between two single neighbor node: partial
         // detection
         dd_pt.neighs[0].idx = nbr_idx;
         dd_pt.neighs[0].X = nbr_X;
         dd_pt.neighs[0].burg = burg;
         dd_pt.neighs[0].normal = normal;
 
         Real temp_val = 1e+4;
         // IteratorDDNodes nodes_loop3 =
         // this->domA.getContainerNodes().getIterator();
         // Real tmpx,tmpy,tmpz;
 
         for (auto &dd_pt_global2 : dd_points_global) {
           UInt num_neigh0 = dd_pt_global2.num_neigh;
           auto diff = dd_pt_global2.X - crr_X;
           Real dist0 = diff.norm();
 
           if ( // has to be terminated in MD domain
               (num_neigh0 == 1) &&
               // avoid self selection
               (0.1 < dist0) &&
               // find the node minimum distance
               (dist0 < temp_val) &&
               // avoid chosing the node in different slip plane
               (fabs(dd_pt_global2.X[1] - crr_X[1]) < 1.0)) {
 
             temp_val = dist;
             dd_pt.neighs[0].idx = dd_pt_global2.idx;
             dd_pt.neighs[0].X = dd_pt_global2.X;
 
             DUMP("Straight connection between the two fixed DD nodes "
                      << "(" << dd_pt.X << ") and "
                      << "(" << dd_pt_global2.X << ").",
                  DBG_MESSAGE);
           }
         }
 
         dd_pt.num_neigh = 2.0;
         dd_pt.neighs[1].burg = -1.0 * dd_pt.neighs[0].burg;
         dd_pt.neighs[1].normal = dd_pt.neighs[0].normal;
 
       } else {
         // normal connection
         dd_pt.neighs[n].idx = nbr_idx;
         dd_pt.neighs[n].X = nbr_X;
         dd_pt.neighs[n].burg = burg;
         dd_pt.neighs[n].normal = normal;
       }
     }
     if (added_point_in_infinity) {
       count += 2;
       added_point_in_infinity = false;
     } else {
       count += 1;
     }
   }
   return;
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 UInt CADD_template<DomainDD, DomainMD, Dim>::CollectingLocalDDpoints(
     std::vector<JaehyunDDPoint> &dd_points0_local) {
 
   bool problem_in_neigh = false;
 
   int count = 0;
   for (auto &node : this->domA.getContainer().getContainerNodes()) {
     Real idx;
     idx = (Real)node.getIndex();
 
     Real idx0;
     idx0 = (Real)node.getIndex0();
 
     LM_TOIMPLEMENT;
     //int num_neigh = node.getNbrOfNeighs();
     int num_neigh = std::numeric_limits<int>::max();
     
     Vector<Dim> crr_X = {roundf(node.position()[0] * 10.0) / 10.0,
                          roundf(node.position()[1] * 10.0) / 10.0,
                          roundf(node.position()[2] * 10.0) / 10.0};
     if (num_neigh >= 3) {
       DUMP("[collectingLocalDDpoints] problem in DD node idx"
                << idx << " (" << crr_X << "): number of neighbors "
                << num_neigh,
            DBG_MESSAGE);
       num_neigh = 2;
       problem_in_neigh = true;
     }
     dd_points0_local[count].idx = idx;
     dd_points0_local[count].num_neigh = (Real)num_neigh;
     dd_points0_local[count].X = crr_X;
     dd_points0_local[count].idx0 = (Real)idx0;
 
     for (int n = 0; n < num_neigh; ++n) {
       LM_TOIMPLEMENT;
       //Real nbr_idx = (Real)node.getNeighborNodeIndex(n);
 
       // Vector<Dim> nbr_X = {
       //     roundf(node.getNeighborNodeCoord(n, 0) * 10.0) / 10.0,
       //     roundf(node.getNeighborNodeCoord(n, 1) * 10.0) / 10.0,
       //     roundf(node.getNeighborNodeCoord(n, 2) * 10.0) / 10.0};
 
       // Vector<Dim> burg = {node.burgersVectorX(n), node.burgersVectorY(n),
       //                     node.burgersVectorZ(n)};
 
       // Vector<Dim> normal = {node.normalVectorX(n), node.normalVectorY(n),
       //                       node.normalVectorZ(n)};
 
       // auto &neigh = dd_points0_local[count].neighs[n];
 
       // neigh.idx = nbr_idx;
       // neigh.burg = burg;
       // neigh.normal = normal;
     }
   }
 
   if (this->dd_points_out) {
 
     // Communicator &comm = Communicator::getCommunicator();
     UInt my_rank_in_DD = this->comm_group_dd.getMyRank();
     std::stringstream fname0;
     fname0 << this->directory_dd_points << "/local_dd_points0_step"
            << current_step << ".txt.proc" << my_rank_in_DD;
     std::ofstream myfile0;
     for (auto &dd_pt0 : dd_points0_local) {
       if (!myfile0.is_open()) {
         myfile0.open(fname0.str().c_str());
       }
       myfile0 << dd_pt0 << "\t";
     }
     myfile0.close();
   }
   if (problem_in_neigh)
     return 1;
   else
     return 0;
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 bool CADD_template<DomainDD, DomainMD, Dim>::coarse_dislocation_loop(
     std::vector<JaehyunDDPoint> &dd_points,
     std::vector<JaehyunDDPoint> &dd_points0) {
 
   std::vector<UInt> indices;
   Vector<Dim> burg = {0.0, 0.0, 0.0};
   Vector<Dim> norm = {0.0, 0.0, 0.0};
   Real ci = 0.;
   UInt count = 0;
 
   UInt master_count = 0;
   for (UInt i = 0; i < dd_points0.size(); ++i) {
     if (!(std::find(indices.begin(), indices.end(), i) != indices.end())) {
 
       auto &dd_pt = dd_points0[i];
       Real ci0 = dd_pt.idx;
       auto cp0 = dd_pt.X;
 
       if (master_count >= dd_points0.size()) {
         DUMP("[coarse_dislocation_loop] exit 1", DBG_MESSAGE);
         return false;
       }
 
       auto &dd_pt_master = dd_points[master_count];
       auto &dd_pt_master_1 = dd_points[master_count - 1];
       auto &dd_pt_master_2 = dd_points[master_count - count];
 
       dd_pt_master.idx = ci0;       // idx
       dd_pt_master.num_neigh = 2.0; // #nbr
       dd_pt_master.X = cp0;         // x-coord
 
       master_count += 1;
       count += 1;
 
       ci = ci0;
       Vector<Dim> cp = cp0;
 
       indices.push_back(i);
 
       bool loop_start(true);
       bool not_finish(true);
 
       while (not_finish) {
         if (!loop_start) {
           if (is_it_closed(cp, cp0, ci, ci0)) {
             not_finish = false;
 
             if (master_count - 1 >= dd_points0.size()) {
               DUMP("[coarse_dislocation_loop] exit 2", DBG_MESSAGE);
               return false;
             }
 
             dd_pt_master_1.neighs[0].idx = ci0;     // idx-nbr1
             dd_pt_master_1.neighs[0].X = cp0;       // x-coord-nbr1
             dd_pt_master_1.neighs[0].burg = burg;   // bx-nbr1
             dd_pt_master_1.neighs[0].normal = norm; // bx-nbr1
 
             dd_pt_master_2.neighs[1].idx = dd_pt_master_1.idx; // idx-nbr2
             dd_pt_master_2.neighs[1].X = dd_pt_master_1.X;     // x-coord-nbr2
             dd_pt_master_2.neighs[1].burg = -1.0 * burg;       // bx-nbr2
             dd_pt_master_2.neighs[1].normal = norm;            // bx-nbr2
             count = 0;
             break;
           }
         }
         UInt count_inside = 0;
         bool straight(true);
 
         while (straight) {
           auto n1 = dd_pt.neighs[0].X;
           Real b1mag = dd_pt.neighs[0].burg[0] *
                            cos(this->angle_between_b_and_x / 180.0 * M_PI) +
                        dd_pt.neighs[0].burg[2] *
                            sin(this->angle_between_b_and_x / 180.0 * M_PI);
           Real n1idx_real = dd_pt.neighs[1].idx;
           UInt n1idx = (UInt)n1idx_real;
 
           auto n2 = dd_pt.neighs[1].X;
           Real b2mag = dd_pt.neighs[1].burg[0] *
                            cos(this->angle_between_b_and_x / 180.0 * M_PI) +
                        dd_pt.neighs[1].burg[2] *
                            sin(this->angle_between_b_and_x / 180.0 * M_PI);
           Real n2idx_real = dd_pt.neighs[2].idx;
           UInt n2idx = (UInt)n2idx_real;
 
           UInt saved_i = i;
           UInt tmp = find_one_direction(n1, n2, b1mag, b2mag, n1idx, n2idx, &i);
           if ((tmp == 0) && (master_count == 1)) {
             burg = 1.0 * dd_points0[saved_i].neighs[0].burg;
           } else if ((tmp == 1) && (master_count == 1)) {
             burg = -1.0 * dd_points0[saved_i].neighs[0].burg;
           }
           norm = dd_points0[saved_i].neighs[0].normal;
 
           // check whether this local connection is important or not
           Real area_in_yplane1 = AreaTriangle(cp, n1, n2, 1);
 
           Vector<Dim> last_registered_node = dd_pt_master_1.X;
           Vector<Dim> next_node = dd_pt.X;
 
           Real area_in_yplane2 =
               AreaTriangle(last_registered_node, cp, next_node, 1);
 
           if ((area_in_yplane1 > this->min_area) ||
               (area_in_yplane2 > this->min_area) ||
               (fabs(n2[1] - cp[1]) > 1.0) ||
               (fabs(n1[1] - cp[1]) > 1.0)) { // || (dist > this->maxSeg0*10.0)){
 
             if (master_count - 1 >= dd_points0.size() - 1) {
               DUMP("[coarse_dislocation_loop] exit 3", DBG_MESSAGE);
               return false;
             }
             dd_pt_master.neighs[1].idx = dd_pt_master_1.idx; // idx-nbr2
             dd_pt_master.neighs[1].X = dd_pt_master_1.X;     // x-coord-nbr2
             dd_pt_master.neighs[1].burg = -1.0 * burg;       // bx-nbr2
             dd_pt_master.neighs[1].normal = norm;            // nx-nbr2
             dd_pt_master_1.neighs[0].idx = ci;               // idx-nbr1
             dd_pt_master_1.neighs[0].X = cp;                 // x-coord-nbr1
             dd_pt_master_1.neighs[0].burg = 1.0 * burg;      // bx-nbr1
             dd_pt_master_1.neighs[0].normal = norm;          // bx-nbr1
             if (!loop_start) {
               dd_pt_master.idx = ci;        // idx
               dd_pt_master.num_neigh = 2.0; // #nbr
               dd_pt_master.X = cp;          // x-coord
               master_count += 1;
               count += 1;
             }
           }
           loop_start = false;
           indices.push_back(i);
 
           ci = dd_pt.idx;
           cp = dd_pt.X;
           count_inside += 1;
 
           if (is_it_closed(cp, cp0, ci, ci0))
             break;
           if (count_inside >= dd_points0.size()) {
             DUMP("[coarse_dislocation_loop] exit 4", DBG_MESSAGE);
             return false;
           }
         }
         if (master_count >= dd_points0.size()) {
           DUMP("[coarse_dislocation_loop] exit 5", DBG_MESSAGE);
           return false;
         }
       }
       if (master_count >= dd_points0.size()) {
         DUMP("[coarse_dislocation_loop] exit 6", DBG_MESSAGE);
         return false;
       }
     }
     if (master_count >= dd_points0.size()) {
       DUMP("[coarse_dislocation_loop] exit 7", DBG_MESSAGE);
       return false;
     }
   }
 
   return true;
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::SetPadAtoms() {
   UInt registered = 0;
   int my_rank_in_MDprocs = this->comm_group_atomic.getMyRank();
   this->pad_atoms.clear();
   auto ref_manager = this->domC.getContainer().getRefManager();
   auto pad = GeometryManager::getManager().getGeometry(pad_geom);
 
   for (auto &at : this->domC.getContainer()) {
     if (pad->contains(at.position())) {
-      this->pad_atoms.add(at);
+      this->pad_atoms.push_back(at);
       registered += 1;
     }
   }
   this->comm_group_atomic.reduce(&registered, 1, "atoms: registered as PAD",
                                  OP_SUM);
   ref_manager->addSubSet("pad atoms", this->pad_atoms);
   if (my_rank_in_MDprocs == 0) {
     DUMP(registered << " atoms are registered as pad atoms", DBG_MESSAGE);
   }
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::find_indices_for_neighbors(
     std::vector<JaehyunDDPoint> &dd_points) {
   for (auto &dd_pt : dd_points) {
     if (dd_pt.num_neigh != 2)
       LM_FATAL("this is not a proper dislocation network");
 
     for (UInt j = 0; j < 2; ++j) {
       auto neigh = dd_pt.neighs[j];
       Real next_idx = neigh.idx;
       Vector<Dim> next_X = neigh.X;
 
       UInt k = 0;
       for (auto &dd_pt2 : dd_points) {
         Real node_idx = dd_pt2.idx;
         Vector<Dim> normal = dd_pt2.X;
         Real dist = (normal - next_X).norm();
 
         if ((dist < 1e-3) && (fabs(node_idx - next_idx) <= 1e-3)) {
           neigh.idx = (Real)k;
           // break;
           ++k;
         }
       }
     }
   }
 }
 
 // /*
 // --------------------------------------------------------------------------
 // */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::applyDisplacement(
     RefAtom at, Vector<Dim> &dislo_disp) {
 
   Vector<Dim> disp_strain = Vector<Dim>::Zero();
   Vector<Dim> disp_tilt = Vector<Dim>::Zero();
 
   shear_strain(at, disp_strain);
   tilt_strain(at, disp_tilt);
 
   at.position() = at.position0() + dislo_disp - disp_strain + disp_tilt;
 }
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::coordinate_for_2d_template(
     Real angle, Real local_coord[], Real global_coord[],
     Real template_coord[]) {
   template_coord[0] =
       local_coord[0] * local_coord[0] / fabs(local_coord[0] + 1e-8) *
           sin(angle * M_PI / 180.0) +
       local_coord[2] * local_coord[2] / fabs(local_coord[2] + 1e-8) *
           cos(angle * M_PI / 180.0);
   template_coord[1] =
       local_coord[1] * local_coord[1] / fabs(local_coord[1] + 1e-8);
 }
 
 /////// This part below should be removed later
 ////////////////////////////////////
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real CADD_template<DomainDD, DomainMD, Dim>::eval_q_coef(Real *X) {
 
   Real inside = X[0] * X[0] +
                 2.0 * X[0] * X[1] * this->lambda * cos(this->phi) +
                 X[1] * X[1] * this->lambda * this->lambda;
   return sqrt(inside);
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real CADD_template<DomainDD, DomainMD, Dim>::eval_t_coef(Real *X) {
   Real inside = X[0] * X[0] -
                 2.0 * X[0] * X[1] * this->lambda * cos(this->phi) +
                 X[1] * X[1] * this->lambda * this->lambda;
   return sqrt(inside);
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real CADD_template<DomainDD, DomainMD, Dim>::evalArctan(Real X, Real Y) {
   if ((X >= 0.0) && (Y > 0.0)) {
     return atan(Y / X);
   } else if ((X < 0.0) && (Y >= 0.0)) {
     return atan(-Y / -X) + M_PI;
   } else if ((X < 0.0) && (Y < 0.0)) {
     return atan(-Y / -X) - M_PI;
   } else if ((X >= 0.0) && (Y < 0.0)) {
     return atan(Y / X);
   } else {
     LM_FATAL("unexpected case");
   }
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real
 CADD_template<DomainDD, DomainMD, Dim>::computeBeDisplacementAniso(Real b_edge,
                                                                    Real *X) {
 
   Real q = eval_q_coef(X);
   Real t = eval_t_coef(X);
   Real c12 = this->elastic_coefs[1];
   Real c66 = this->elastic_coefs[12];
 
   Real first = 0.0;
   first += evalArctan((X[0] + X[1] * this->lambda * cos(this->phi)),
                       (X[1] * this->lambda * sin(this->phi)));
   first += evalArctan((X[0] - X[1] * this->lambda * cos(this->phi)),
                       (X[1] * this->lambda * sin(this->phi)));
 
   Real second = (this->c11bar * this->c11bar - c12 * c12) /
                 (2.0 * this->c11bar * c66 * sin(2.0 * this->phi)) *
                 floor(log(q / t) * 1e+5) / 1e+5;
 
   Real res = b_edge / (4.0 * M_PI) * (first + second);
   return res;
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real
 CADD_template<DomainDD, DomainMD, Dim>::computeNDisplacementAniso(Real b_edge,
                                                                   Real *X) {
   Real q = eval_q_coef(X);
   Real t = eval_t_coef(X);
   Real c12 = this->elastic_coefs[1];
 
   Real first =
       (this->c11bar - c12) * cos(this->phi) * floor(log(q * t) * 1e+5) / 1e+5;
   Real second =
       (this->c11bar + c12) * sin(this->phi) *
       atan2((X[1] * X[1] * this->lambda * this->lambda * sin(2.0 * this->phi)),
             (X[0] * X[0] -
              this->lambda * this->lambda * X[1] * X[1] * cos(2.0 * this->phi)));
   Real res = -this->lambda * b_edge /
              (4.0 * M_PI * this->c11bar * sin(2.0 * this->phi)) *
              (first - second);
   return res;
 }
 
 /* --------------------------------------------------------------------------
  */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real
 CADD_template<DomainDD, DomainMD, Dim>::computeLDisplacementAniso(Real b_screw,
                                                                   Real *X) {
   Real c44 = this->elastic_coefs[9];
   Real c45 = this->elastic_coefs[10];
   Real c55 = this->elastic_coefs[11];
   Real res = b_screw / 2.0 / M_PI *
              atan2(sqrt(c44 * c55 - c45 * c45) * X[1], c44 * X[0] - c45 * X[1]);
   return res;
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real
 CADD_template<DomainDD, DomainMD, Dim>::computeBeDisplacement(Real b_edge,
                                                               Real *X) {
   Real x_2 = X[0] * X[0];
   Real y_2 = X[1] * X[1];
   Real nu = this->pois0;
 
   Real epsilon = 1e-15;
   Real res = b_edge / (2.0 * M_PI) *
              (atan2(X[1], X[0]) +
               X[0] * X[1] / (2.0 * (1 - nu) * (x_2 + y_2 + epsilon)));
 
   return res;
 }
 
 /* --------------------------------------------------------------------------
  */
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real
 CADD_template<DomainDD, DomainMD, Dim>::computeNDisplacement(Real b_edge,
                                                              Real *X) {
   Real x_2 = X[0] * X[0];
   Real y_2 = X[1] * X[1];
   Real epsilon = 1e-15;
   Real nu = this->pois0;
   // Real b_edge2 = b_edge*b_edge;
   // Real res = -b_edge/(2.0*M_PI)*((1-2.0*nu)/(4.0*(1-nu))*(log((x_2 +
   // y_2+epsilon)/b_edge2))
   //                            + (x_2 - y_2)/
   //                            (4.0*(1-nu)*(x_2 + y_2+epsilon))
   //                            );
   // return res;
   return -b_edge / (2.0 * M_PI) *
          ((1 - 2.0 * nu) / (4.0 * (1 - nu)) * log(x_2 + y_2 + epsilon) +
           (x_2 - y_2) / (4.0 * (1 - nu) * (x_2 + y_2 + epsilon)));
 }
 
 /* --------------------------------------------------------------------------
  */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 inline Real
 CADD_template<DomainDD, DomainMD, Dim>::computeLDisplacement(Real b_screw,
                                                              Real *X) {
   Real res = b_screw / (2.0 * M_PI) * (atan2(X[1], X[0]));
   return res;
 }
 
 /* --------------------------------------------------------------------------
  */
 /* LMDESC CADDTEMPLATE
    CADDTEMPLATE is a simple CADD-like coupler which can deal with straing egde
    dislocations normal to the interface (i.e., 1;3400;0cno elastic problem)
 */
 /* LMEXAMPLE
    COUPLING_CODE
 */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::declareParams() {
   /* LMKEYWORD PAD_GEOM
      Identifier of the pad geom
   */
   this->parseKeyword("PAD_GEOM", this->pad_geom);
   /* LMKEYWORD DETECT_DXA
      Boolean to notify input from DXA results
   */
   this->parseTag("DETECT_DXA", this->detect_dxa, false);
   /* LMKEYWORD MULTIPLE_LOOPS
      Boolean to notify multiple loops
   */
   this->parseTag("MULTIPLE_LOOPS", this->multiple_loops, false);
   /* LMKEYWORD DETECT_PARTIAL
      Boolean to notify input for partially detection dislocation
   */
   this->parseTag("DETECT_PARTIAL", this->detect_partial, false);
   /* LMKEYWORD PRINT_DD_POINTS
      Boolean to print internal data named dd\_points and its offset lines
   */
   this->parseTag("PRINT_DD_POINTS", this->dd_points_out, false);
   /* LMKEYWORD COARSEN_DD
      Boolean to decide to coarse dislocation loop before apply Barnett fields
   */
   this->parseTag("COARSEN_DD", this->coarsen_dd, false);
   /* LMKEYWORD MIN_AREA
      Specifies the minimum area to be coarsed out
   */
   this->parseKeyword("MIN_AREA", this->min_area, 0.0);
   /* LMKEYWORD DIRECTORY_DD_POINTS
      fies the directory dd points are written
   */
   this->parseKeyword("DIRECTORY_DD_POINTS", this->directory_dd_points, "/.");
   /* LMKEYWORD DD_BOUNDARY
      Boolean to set DD boundary
   */
   this->parseTag("DD_BOUNDARY", this->dd_boundary, false);
   /* LMKEYWORD SLIP_PLANE
      Specifies the normal vector to the slip plane
   */
   this->parseVectorKeyword("SLIP_PLANE", 3, this->normal_quant);
   /* LMKEYWORD ANGLE_BETWEEN_B_AND_X
      Specifies the angle between Burgers vector and X(11-2) axis
   */
   this->parseKeyword("ANGLE_BETWEEN_B_AND_X", this->angle_between_b_and_x);
   /* LMKEYWORD MD_GEOM
      Identifier of the MD geometry
   */
   this->parseKeyword("MD_GEOM", this->md_geom);
   /* LMKEYWORD DD_GEOM
      Identifier of the DD geometry
   */
   this->parseKeyword("DD_GEOM", this->dd_geom);
   /* LMKEYWORD UPDATE_FREQUENCY
      Specifies the frequency at which detection computations are performed
   */
   this->parseKeyword("UPDATE_FREQUENCY", this->detect_freq, 50);
   /* LMKEYWORD DETECT_COMPUTE
      Add computes to input to filter
   */
   this->parseKeyword("DETECT_COMPUTE", compute_list);
   /* LMKEYWORD NUM_TEMPLATES
      Specifies the number of templates provided.
   */
   this->parseKeyword("NUM_TEMPLATES", this->num_templates);
   /* LMKEYWORD TEMPLATE_FILE
      Specifies the template file.
   */
   this->parseKeyword("TEMPLATE_FILE", this->templatefilename_list);
   /* LMKEYWORD CORE_RCUT
      Specifies the radius of the region where core template applied
   */
   this->parseKeyword("CORE_RCUT", this->core_rcut);
   /* LMKEYWORD RATIO_OF_PURE_CORE_TEMPLATE
      Specifies the ratio of region where only pure core template is applied
      with respect to ellipse defined by RMAX and RMIN
      where
   */
   this->parseKeyword("RATIO_OF_PURE_CORE_TEMPLATE", this->factor);
   /* LMKEYWORD SHEAR_STRESSES
      Specifies the shear stersses with respect to Y plane.
   */
   this->parseVectorKeyword("SHEAR_STRESSES", 4, this->shear_stresses);
   /* LMKEYWORD TILT_STRESSES
      Specifies the shear stersses imposed by tilting.
   */
   this->parseVectorKeyword("TILT_STRESSES", 3, this->tilt_stresses);
   /* LMKEYWORD SHEAR_MODULUS
      Specifies the shear modulus in Burgers vector direction.
      mega-Pascal unit
   */
   this->parseKeyword("SHEAR_MODULUS", this->mu0);
   /* LMKEYWORD POISSON_RATIO
      Specifies the shear modulus in Burgers vector direction.
      mega-Pascal unit
   */
   this->parseKeyword("POISSON_RATIO", this->pois0);
 
   /* LMKEYWORD DOMAIN_DD
      Specifies the dd domain id
   */
   this->parseKeyword("DOMAIN_DD", this->domdd);
 
   /* LM_KEYWORD DISTANCE_DDLINE_FROM_PAD
      Specify the distance from pad (inner) boudaries to DD constrained nodes.
   */
   this->parseKeyword("DISTANCE_DDLINE_FROM_PAD",
                      this->distance_ddline_from_pad);
   /* LMKEYWORD PAD_THICKNESS
      Specify the thickness of pad zone
   */
   this->parseKeyword("PAD_THICKNESS", this->pad_thickness);
 
   // In case of (0, 0, 1):
   // point1                  point2
   // *----------------------*
   // |                      |       z
   // |                      |      ^
   // |                      |      |
   // o-o-o-x        x-o-o-o-o      +--->x
   /* LMKEYWORD CLOSE_IN_INFINITY
      Specifies the direction in order to close
      dislocation loop
   */
   this->parseVectorKeyword("CLOSE_IN_INFINITY", 3, this->close_direction,
                            VEC_DEFAULTS(0, 0, 0));
   /* LMKEYWORD NUBER_INFINITY_CONNECTION
      Specifies the direction in order to close
      dislocation loop
   */
   this->parseKeyword("NUBER_INFINITY_CONNECTION",
                      this->num_close_loop_in_infinity, 0);
   /* LMKEYWORD MD_BOX_LENGTHS
      Specifies the (original) MD box size
      to specify correct tilt stress values
   */
   this->parseVectorKeyword("MD_BOX_LENGTHS", 3, this->md_box_lengths);
   /* LMKEYWORD DETECT_SIMPLE_DIRECTION
      Specifies the (original) MD box size
      to specify correct tilt stress values
   */
   this->parseVectorKeyword("DETECT_SIMPLE_DIRECTION", 3,
                            this->detect_simple_direction,
                            VEC_DEFAULTS(0, 0, 0));
   // /* LM**KEYWORD NB_SLIPS
   //    Specifies the number of slip planes
   // */
   // this->parseKeyword("NB_SLIPS", this->nb_slips);
   // /* LM**KEYWORD LEN_INTER_SLIPS
   //    Specifies length between two slip planes
   // */
   // this->parseKeyword("LEN_INTER_SLIPS", this->len_inter_slips);
 
   /* LMKEYWORD ANISO
      Boolean to set anisotropicity:
      [1] Elastic Strain Fields and Dislocation Mobility, Volume 31, J.Lothe
      Dislocations in anisotropic media
      [2] Plane-strain discrete dislocation plasticity incorporating
      anisotropic
      elasticity IJSS 48(2), January 2011
   */
   this->parseTag("ANISO", this->aniso, false);
   /* LMKEYWORD VOLTERRA
      TODO
   */
   this->parseTag("VOLTERRA", this->volterra, false);
 
   /* LMKEYWORD ELASTIC_COEFS
      Specify the thirteen elastic coefficients
      of the constitutive matrix of anisotropic media in the following order:
      C11, C12, C13, C21, C22, C23, C31, C32, C33, C44, C45, C55, C66
   */
   this->parseVectorKeyword("ELASTIC_COEFS", 13, this->elastic_coefs,
                            VEC_DEFAULTS(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                                         0.0, 0.0, 0.0, 0.0, 0.0));
 
   LM_TOIMPLEMENT;
   // forward parsable of the core template needs to be done
   // this->addSubParsableObject(this->core_template);
 }
 
 /* ---------------------------------------------------------------------- */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 std::vector<JaehyunDDPoint>
 CADD_template<DomainDD, DomainMD, Dim>::sendDDSegments2MD() {
   // Communicator &comm = Communicator::getCommunicator();
 
   // UInt local_data_length = 26;
   UInt data_length = 33;
   std::vector<JaehyunDDPoint> dd_points;
   std::vector<JaehyunDDPoint> dd_points0;
   UInt num_dd_pts;
   UInt num_dd_pts0;
 
   if (this->is_in_dd) {
     LM_TOIMPLEMENT;
     // UInt my_rank_in_DD = this->comm_group_dd.groupRank(lm_my_proc_id);
     // UInt nbDDprocs = this->comm_group_dd.getNBprocsOnGroup();
 
     // declare data array for (unclosed) dd points in a local processor
     UInt num_dd_pts0_local = this->domA.getNBNodes();
     std::vector<JaehyunDDPoint> dd_points0_local(num_dd_pts0_local);
     // collecting dd points
     UInt collecting = 0;
     collecting = CollectingLocalDDpoints(dd_points0_local);
     this->comm_group_dd.reduce(
         &collecting, 1,
         "boolean to detect any errors occurring in collecting local nodes",
         OP_SUM);
 
     // evaluate total number of points
     UInt num_dd_pts0_global = 0;
     LM_TOIMPLEMENT;
     // MPI_Reduce(&num_dd_pts0_local, &num_dd_pts0_global, 1, MPI_INT, MPI_SUM,
     //            comm.realRank(0, ),
     //            comm.getMpiGroup(this->comm_group_dd));
 
     // declare data array for (unclosed) total dd points only at 0 processor
     std::vector<JaehyunDDPoint> dd_points0_global;
 
     LM_TOIMPLEMENT;
     //    if (my_rank_in_DD == 0) {
     // (unclosed) total dd points
     // dd_points0_global.resize(num_dd_pts0_global);
     //}
 
     // declare data list for number of dd nodal points for all the DDD
     // processors
     std::vector<int> num_dd_pts0_local_list;
 
     LM_TOIMPLEMENT;
     // if (my_rank_in_DD == 0)
     //   num_dd_pts0_local_list.resize(nbDDprocs);
 
     // gather the total local data length into the declared data list
     LM_TOIMPLEMENT;
     // int local_length = num_dd_pts0_local * local_data_length;
     // MPI_Gather(&local_length, 1, MPI_INT, &num_dd_pts0_local_list[0], 1,
     //            MPI_INT, comm.realRank(0, this->comm_group_dd),
     //            comm.getMpiGroup(this->comm_group_dd));
 
     // declear data array for starting number
     std::vector<int> lengths_dd_points_local;
     LM_TOIMPLEMENT;
     // UInt totlen = 0;
     // if (my_rank_in_DD == 0) {
     //   lengths_dd_points_local.resize(nbDDprocs);
     //   lengths_dd_points_local[0] = 0;
     //   totlen += num_dd_pts0_local_list[0];
     //   for (UInt i = 1; i < nbDDprocs; i++) {
     //     lengths_dd_points_local[i] = lengths_dd_points_local[i - 1] + totlen;
     //     totlen = num_dd_pts0_local_list[i];
     //   }
     // }
 
     // gather local dd points to global points
     // inputs: dd_points0_local
     //         local_length
     //         num_dd_pts0_local_list
     //         lengths_dd_points_local
 
     LM_TOIMPLEMENT;
     // MPI_Gatherv(&dd_points0_local[0], // local dd points
     //             local_length,         // local length
     //             MPI_REAL,
     //             &dd_points0_global[0],       // global dd points
     //             &num_dd_pts0_local_list[0],  // number of length list
     //             &lengths_dd_points_local[0], // starting number list
     //             MPI_REAL, comm.realRank(0, this->comm_group_dd),
     //             comm.getMpiGroup(this->comm_group_dd));
 
     LM_TOIMPLEMENT;
     int my_rank_in_DD = std::numeric_limits<int>::max();
     if (my_rank_in_DD == 0) {
 
       UInt num_pairs_in_infinity = this->domA.getNBpairsInfinite();
       UInt num_dd_pts0 = num_dd_pts0_global;
       if (this->close_in_infinity)
         num_dd_pts0 += (num_pairs_in_infinity + num_close_loop_in_infinity) * 2;
 
       // (closed) total dd nodal points
       dd_points0.resize(num_dd_pts0);
 
       close_dislocation_loop(dd_points0, dd_points0_global);
 
       find_indices_for_neighbors(dd_points0);
 
       num_dd_pts = num_dd_pts0;
       // (closed) coarsened dd nodal points
       dd_points.resize(num_dd_pts);
 
       STARTTIMER("coarsening");
       if ((coarsen_dd) and (collecting == 0)) {
         bool coarsen = coarse_dislocation_loop(dd_points, dd_points0);
         if (!coarsen) {
           // in case of fail, copy all dd_points0 into dd_points
           DUMP("[WARNING] Fail to coarse dislocation loop. Total "
                    << num_dd_pts0 << " points",
                DBG_MESSAGE);
           for (UInt i = 0; i < num_dd_pts; ++i) {
             for (UInt j = 0; j < data_length; ++j) {
               dd_points[i * data_length + j] = dd_points0[i * data_length + j];
             }
           }
         } else {
           // in case of success,
           DUMP("Coarse_dislocation_loop end. Reduced from "
                    << num_dd_pts0 << " points to " << num_dd_pts << " points",
                DBG_MESSAGE);
           find_indices_for_neighbors(dd_points);
         }
       } else {
         DUMP("[WARNING] Coarse_dislocation_loop is skipped. coarsen_dd: "
                  << coarsen_dd << " collecting: " << collecting << " Total "
                  << num_dd_pts0 << " points",
              DBG_MESSAGE);
         for (UInt i = 0; i < num_dd_pts; ++i) {
           for (UInt j = 0; j < data_length; ++j) {
             dd_points[i * data_length + j] = dd_points0[i * data_length + j];
           }
         }
       }
 
       STOPTIMER("coarsening");
       ComputeOffsetParallelCurve(dd_points);
       // CorrectIntersetingPoints(num_dd_pts,dd_points);
 
       UInt mdNBprocs = this->comm_group_atomic.size();
       for (UInt i = 0; i < mdNBprocs; ++i) {
         // int real_rank = this->comm_group_atomic.realRank(i);
         int my_rank_in_group = this->comm_group_atomic.getMyRank();
         this->comm_group_atomic.send(&num_dd_pts, 1, my_rank_in_group,
                                      "number of dd points");
         this->comm_group_atomic.send(&num_dd_pts0, 1, my_rank_in_group,
                                      "number of dd points0");
         this->comm_group_atomic.send(&(dd_points[0]), num_dd_pts0 * data_length,
                                      my_rank_in_group, "dd_points (vector)");
       }
     }
 
     // BARRIER
     this->comm_group_dd.synchronize();
   }
 
   if (this->is_in_atomic) {
 
     STARTTIMER("SetPadAtoms");
     SetPadAtoms();
     STOPTIMER("SetPadAtoms");
 
     STARTTIMER("ReceiveDDdata");
     this->comm_group_dd.receive(&num_dd_pts, 1, 0, "number of dd points");
     this->comm_group_dd.receive(&num_dd_pts0, 1, 0, "number of dd points0");
 
     dd_points.resize(num_dd_pts0 * data_length);
 
     this->comm_group_dd.receive(&(dd_points[0]), num_dd_pts0 * data_length, 0,
                                 "dd_points (vector)");
     STOPTIMER("ReceiveDDdata");
 
     std::vector<UInt> indices;
     // UInt count_pad_core = 0;
     // UInt count_pad_around = 0;
     // UInt count_far_field = 0;
     // UInt count_true_disp = 0;
   }
 
   return dd_points;
 }
 
 /* ---------------------------------------------------------------------- */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::functionifAniso(
     UInt num_dislo, Vector<Dim> &pos0_pbc, Vector<Dim> &pos0_pbc0,
     std::vector<std::vector<Real>> &dislocations, RefAtom &at) {
 
   Vector<Dim> analytic_Disp = {0.0, 0.0, 0.0};
   for (UInt nd = 0; nd < num_dislo; ++nd) {
     for (UInt pd = 0; pd < 2; ++pd) {
       if (pd == 0) {
         // pos0_pbc[0] = pos0_pbc0[0] - dislocations[nd][0];
         pos0_pbc[1] = pos0_pbc0[1] - dislocations[nd][1];
         pos0_pbc[2] = pos0_pbc0[2] - (dislocations[nd][2] - 1.0);
       } else if (pd == 1) {
         // pos0_pbc[0] = pos0_pbc0[0] - dislocations[nd][0];
         pos0_pbc[1] = pos0_pbc0[1] - dislocations[nd][1];
         pos0_pbc[2] = pos0_pbc0[2] - (dislocations[nd][2] + 1.0);
       }
 
       Real rotation_matrix[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0};
       Real pos0_pbc_rotate[] = {0.0, 0.0, 0.0};
       for (UInt i = 0; i < 3; ++i) {
         pos0_pbc_rotate[i] = 0.0;
         for (UInt j = 0; j < 3; ++j) {
           pos0_pbc_rotate[i] += rotation_matrix[3 * i + j] * pos0_pbc[j];
         }
       }
 
       Real b_screw =
           this->burgMag0 * cos(this->angle_between_b_and_x / 180.0 * M_PI) / 2.;
       Real b_edge =
           this->burgMag0 * sin(this->angle_between_b_and_x / 180.0 * M_PI) / 2.;
 
       Real analytic_disp[] = {0.0, 0.0, 0.0};
       Real dispV[] = {0.0, 0.0, 0.0};
       analytic_disp[0] = computeBeDisplacementAniso(b_edge, pos0_pbc_rotate);
       analytic_disp[1] = computeNDisplacementAniso(b_edge, pos0_pbc_rotate);
       analytic_disp[2] = computeLDisplacementAniso(b_screw, pos0_pbc_rotate);
 
       for (UInt i = 0; i < 3; ++i) {
         for (UInt j = 0; j < 3; ++j) {
           analytic_Disp[i] += rotation_matrix[3 * j + i] * analytic_disp[j];
         }
       }
       for (UInt i = 0; i < 3; ++i)
         analytic_Disp[i] += dispV[i];
     }
   }
   applyDisplacement(at, analytic_Disp);
 }
 
 /* --------------------------------------------------------------------------
  */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::functionifVolterra(
     UInt num_dislo, Vector<Dim> &pos0_pbc, Vector<Dim> &pos0_pbc0,
     std::vector<std::vector<Real>> &dislocations, RefAtom &at) {
 
   Vector<Dim> analytic_Disp = {0.0, 0.0, 0.0};
 
   for (UInt nd = 0; nd < num_dislo; ++nd) {
 
     for (UInt pd = 0; pd < 2; ++pd) {
       if (pd == 0) {
         // pos0_pbc[0] = pos0_pbc0[0] - dislocations[nd][0];
         pos0_pbc[1] = pos0_pbc0[1] - dislocations[nd][1];
         pos0_pbc[2] = pos0_pbc0[2] - (dislocations[nd][2] - 1.0);
       } else if (pd == 1) {
         // pos0_pbc[0] = pos0_pbc0[0] - dislocations[nd][0];
         pos0_pbc[1] = pos0_pbc0[1] - dislocations[nd][1];
         pos0_pbc[2] = pos0_pbc0[2] - (dislocations[nd][2] + 1.0);
       }
 
       Real rotation_matrix[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0};
       Real pos0_pbc_rotate[] = {0.0, 0.0, 0.0};
       for (UInt i = 0; i < 3; ++i) {
         pos0_pbc_rotate[i] = 0.0;
         for (UInt j = 0; j < 3; ++j) {
           pos0_pbc_rotate[i] += rotation_matrix[3 * i + j] * pos0_pbc[j];
         }
       }
 
       Real b_screw =
           this->burgMag0 * cos(this->angle_between_b_and_x / 180.0 * M_PI) / 2.;
       Real b_edge =
           this->burgMag0 * sin(this->angle_between_b_and_x / 180.0 * M_PI) / 2.;
       Real analytic_disp[] = {0.0, 0.0, 0.0};
       Real dispV[] = {0.0, 0.0, 0.0};
       analytic_disp[0] = computeBeDisplacement(b_edge, pos0_pbc_rotate);
       analytic_disp[1] = computeNDisplacement(b_edge, pos0_pbc_rotate);
       analytic_disp[2] = computeLDisplacement(b_screw, pos0_pbc_rotate);
 
       for (UInt i = 0; i < 3; ++i) {
         for (UInt j = 0; j < 3; ++j) {
           dispV[i] += rotation_matrix[3 * j + i] * analytic_disp[j];
         }
       }
       for (UInt i = 0; i < 3; ++i)
         analytic_Disp[i] += dispV[i];
     }
   }
   applyDisplacement(at, analytic_Disp);
 }
 /* --------------------------------------------------------------------------
  */
 
 template <typename DomainDD, typename DomainMD, UInt Dim>
 void CADD_template<DomainDD, DomainMD, Dim>::functionElse(
     std::vector<JaehyunDDPoint> &dd_points, Vector<Dim> &pos0_pbc,
     RefAtom &at) {
 
   UInt count_pad_core = 0;
   UInt count_far_field = 0;
   UInt count_pad_around = 0;
 
   Vector<Dim> barnett_disp = {0.0, 0.0, 0.0};
   Vector<Dim> dislo_disp = {0.0, 0.0, 0.0};
   Vector<Dim> temp_disp = {0.0, 0.0, 0.0};
 
   for (auto &dd_pt : dd_points) {
     // bool selected = false;
     Vector<Dim> disp_for_segment = {0.0, 0.0, 0.0};
     auto &A = dd_pt.X;
     auto &neigh1 = dd_pt.neighs[0];
     auto &neigh2 = dd_pt.neighs[2];
     auto &pts1 = neigh1.X;
     auto &pts2 = neigh2.X;
     for (UInt j = 0; j < 2; ++j) {
       auto &neigh = dd_pt.neighs[j];
       Vector<Dim> burg = neigh.burg * this->burgMag0;
       Real bmag = burg[0] * cos(this->angle_between_b_and_x / 180.0 * M_PI) +
                   burg[2] * sin(this->angle_between_b_and_x / 180.0 * M_PI);
       bmag = roundf(bmag * 10.0) / 10.0;
 
       if (bmag / fabs(bmag) > 0) {
         auto &B = neigh.X;
         auto &normal = neigh.normal;
         UInt slip_case = 3;
         if (fabs(normal[0]) - 1.0 == 0.0)
           slip_case = 0;
         else if (fabs(normal[1]) - 1.0 == 0.0)
           slip_case = 1;
         else if (fabs(normal[2]) - 1.0 == 0.0)
           slip_case = 2;
         else {
           DUMP("[warning] cannot define slip case", DBG_MESSAGE);
           slip_case = 1;
         }
 
         ComputeAnalyticDisplacements(disp_for_segment, B, A, burg, pos0_pbc);
 
         UInt idx_number = (UInt)neigh.idx;
         auto &pts3 = dd_points[idx_number].tmp_X;
         auto &pts4 = dd_points[idx_number].tmp2_X;
         if (PointInSquare(pts1, pts2, pts3, pts4, pos0_pbc, slip_case)) {
           Real distance = distance_between_line_and_point3D(pos0_pbc, A, B);
           if (distance <= this->core_rcut) {
             bool success(false);
             success = ComputeTemplateDisplacements(temp_disp, A, B, burg,
                                                    normal, pos0_pbc);
             if (!success) {
               barnett_disp += disp_for_segment;
             } else {
               if (distance / this->core_rcut <= this->factor) {
                 ++count_pad_core;
                 barnett_disp += temp_disp + disp_for_segment;
               } else {
                 Real temp_ratio =
                     (this->core_rcut - distance) /
                     (this->core_rcut - this->core_rcut * this->factor);
                 ++count_pad_around;
                 barnett_disp += temp_disp * temp_ratio + disp_for_segment;
               }
             }
           } else {
             barnett_disp += disp_for_segment;
             ++count_far_field;
           }
 
         } else {
           barnett_disp += disp_for_segment;
           ++count_far_field;
         } // if(PointInSquare(pts ... )
       }   // if(bmag/abs(bmag)>0)
     }     // for (UInt j=0; j < num_neigh; ++j){
   }       // for (UInt i=0; i < num_dd_pts;
   dislo_disp = barnett_disp;
   applyDisplacement(at, dislo_disp);
 }
 /* -------------------------------------------------------------------------- */
 
 DECLARE_DD_ATOMIC_TEMPLATE(CADD_template);
 
 __END_LIBMULTISCALE__
diff --git a/src/filter/compute_cadd_template.cc b/src/filter/compute_cadd_template.cc
index d4a7410..26999b2 100644
--- a/src/filter/compute_cadd_template.cc
+++ b/src/filter/compute_cadd_template.cc
@@ -1,429 +1,429 @@
 #include "compute_cadd_template.hh"
 #include "factory_multiscale.hh"
 #include "lib_dd.hh"
 #include "lib_dumper.hh"
 #include "lib_filter.hh"
 #include "lib_md.hh"
 #include "lib_stimulation.hh"
 #include "lm_common.hh"
 #include <Eigen/Dense>
 #include <algorithm>
 #include <fstream>
 #include <pybind11/eigen.h>
 #include <pybind11/pybind11.h>
 #include <pybind11/stl.h>
 
 __BEGIN_LIBMULTISCALE__
 
 /* -------------------------------------------------------------------------- */
 
 void ComputeCADDTemplate::loadNPZ(std::string &filename) {
 
   py::object load = py::module::import("numpy").attr("load");
   auto npz = load(filename);
   auto field_names = npz.attr("files").cast<std::list<std::string>>();
   auto fields = npz.cast<py::dict>().cast<std::map<std::string, py::object>>();
 
   // std::for_each(field_names.begin(), field_names.end(),
   //               [](auto &&v) { std::cout << v << std::endl; });
 
   auto triangles =
       fields["triangles"].cast<Eigen::Array<UInt, Eigen::Dynamic, 3>>();
 
   auto points = fields["points"].cast<Eigen::Array<Real, Eigen::Dynamic, 2>>();
 
   auto corrections =
       fields["correction"].cast<Eigen::Array<Real, Eigen::Dynamic, 3>>();
 
   auto &nodes = mesh.getContainerNodes();
   RefPointData<2> p;
 
   for (UInt i = 0; i < points.rows(); ++i) {
     p = VectorView<2>(&points(i, 0));
-    nodes.add(p);
+    nodes.push_back(p);
   }
 
   for (UInt i = 0; i < corrections.rows(); ++i) {
     auto corr = VectorView<3>(&corrections(i, 0));
     this->corrections.push_back(corr);
   }
 
   auto &elems = mesh.getContainerElems();
 
   for (UInt i = 0; i < triangles.rows(); ++i) {
     RefGenericElem<2> el;
     for (UInt n = 0; n < 3; ++n)
       el.conn.push_back(triangles(i, n));
-    elems.add(el);
+    elems.push_back(el);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 
 ComputeCADDTemplate::ComputeCADDTemplate(const LMID &name)
     : LMObject(name), mesh(this->getID() + ":mesh") {
 
   this->removeInput("input1");
   this->createInput("points");
   this->createInput("segments");
 
   this->inversion = TOP_RIGHT;
   this->search_dim = 1;
   this->tol = -1;
   this->r_cut = -1;
   this->factor[0] = this->factor[1] = 1;
 };
 
 /* -------------------------------------------------------------------------- */
 
 ComputeCADDTemplate::~ComputeCADDTemplate() {}
 
 /* -------------------------------------------------------------------------- */
 
 inline bool is_in_triangle(Vector<2> &a, Vector<2> &b, Vector<2> &c,
                            Vector<2> p) {
   Vector<2> v0;
   Vector<2> v1;
   Vector<2> v2;
   Real u, v;
 
   v0 = c - a;
   v1 = b - a;
   v2 = p - a;
 
   // Compute dot products
   Real dot00 = v0.dot(v0);
   Real dot01 = v0.dot(v1);
   Real dot02 = v0.dot(v2);
   Real dot11 = v1.dot(v1);
   Real dot12 = v1.dot(v2);
 
   // Compute barycentric coordinates
   Real invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
   u = (dot11 * dot02 - dot01 * dot12) * invDenom;
   v = (dot00 * dot12 - dot01 * dot02) * invDenom;
 
   // Check if point is in triangle
   return (u >= -1e-8) && (v >= -1e-8) && (u + v < 1.0 + 1e-8);
 }
 /* -------------------------------------------------------------------------- */
 
 // returns the number of the element an atom is in
 // or -1 if it's outside the template
 inline int ComputeCADDTemplate::findElement(Vector<Dim> &at_coords) {
 
   auto &nodes = this->mesh.getContainerNodes();
 
   int i = 0;
   for (auto &&elem : this->mesh.getContainerElems()) {
 
     auto node1 = nodes[elem.localIndexes()[0]].position0();
     auto node2 = nodes[elem.localIndexes()[1]].position0();
     auto node3 = nodes[elem.localIndexes()[2]].position0();
 
     if (is_in_triangle(node1, node2, node3, at_coords.block<2, 1>(0, 0))) {
       return i;
     }
     ++i;
   }
 
   return UINT_MAX;
 }
 
 /* -------------------------------------------------------------------------- */
 
 void ComputeCADDTemplate::init() { loadNPZ(filename); }
 
 /* -------------------------------------------------------------------------- */
 
 /* LMDESC CADD_TEMPLATE
 
    TODO
 
 */
 
 /* LMEXAMPLE COMPUTE template CADD_TEMPLATE INPUT md TODO
  */
 
 void ComputeCADDTemplate::declareParams() {
 
   ComputeInterface::declareParams();
 
   /* LMKEYWORD FILENAME
      Set the filename containing a core template
   */
   this->parseKeyword("FILENAME", filename);
 
   // /* LMKEYWORD ANGLE_BETWEEN_B_AND_X
   //    Specifies the angle between Burgers vector and X(11-2) axis
   // */
   // this->parseKeyword("ANGLE_BETWEEN_B_AND_X", angle_between_b_and_x);
 }
 /* -------------------------------------------------------------------------- */
 
 void ComputeCADDTemplate::coreDispAtom(Vector<Dim> &pos_core,
                                        Vector<Dim> &disp) {
 
   int elem_num = this->findElement(pos_core);
 
   if (elem_num != -1) {
     Vector<3> coords = {1.0, pos_core[0], pos_core[1]};
     auto &elems = this->mesh.getContainerElems();
     auto &nodes = this->mesh.getContainerNodes();
     auto &elem = elems[elem_num];
 
     auto &node1 = nodes[elem.localIndexes()[0]].position0();
     auto &node2 = nodes[elem.localIndexes()[1]].position0();
     auto &node3 = nodes[elem.localIndexes()[2]].position0();
 
     Eigen::Matrix<Real, 4, 3> Su;
     Su << 1., 0., 0., node1, node2, node3;
     Matrix<3> SxInv;
     auto &&tmp = Su * SxInv * coords;
     disp += tmp.block<3, 1>(1, 0);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename Points, typename Segment>
 std::enable_if_t<Points::Dim == 3u>
 ComputeCADDTemplate::build(Points &points, Segment &segment) {
 
   for (auto &&point : points) {
     computeTemplateDisplacements(point, segment);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename Vec1, typename Vec2>
 Matrix<3u> computeTemplateRotation(Vec1 &&_dd_line_dir,
                                    Vec2 &&_slip_normal_dir) {
 
   Vector<3u> dd_line_dir(_dd_line_dir);
   Vector<3u> slip_normal_dir(_slip_normal_dir);
 
   // construct a rotation where:
   // - the normal to slip plane becomes z
   // - the line direction becomes y
   // - normal to the line in the slip plane becomes x
 
   // checks is the normal is normal to the line direction
 
   LM_ASSERT(std::abs(dd_line_dir.dot(slip_normal_dir)) < 1e-10,
             "normal and line not defined properly");
 
   // construct the first basis vector
   Vector<3u> first_basis_vector = dd_line_dir.cross(slip_normal_dir);
 
   Matrix<3u> Rmat = Matrix<3>::Zero();
   Rmat.block<3, 1>(0, 0) = first_basis_vector;
   Rmat.block<3, 1>(0, 1) = dd_line_dir;
   Rmat.block<3, 1>(0, 2) = slip_normal_dir;
 
   return Rmat.transpose();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename Point, typename ElementType>
 std::enable_if_t<!std::is_same<ElementType, RefGenericDDElem<3>>::value>
 ComputeCADDTemplate::computeTemplateDisplacements(Point &p,
                                                   ElementType &segment) {
   LM_TOIMPLEMENT;
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <typename Point, typename ElementType>
 std::enable_if_t<std::is_same<ElementType, RefGenericDDElem<3>>::value>
 ComputeCADDTemplate::computeTemplateDisplacements(Point &p,
                                                   ElementType &segment) {
 
   auto &&burgers = segment.burgers();
   auto &&normal = segment.normal();
   LM_ASSERT(std::abs(burgers.norm()) > 1e-8,
             "No found burgers vector for neighbors");
 
   auto &&pos0 = p.position0();
   auto conn = segment.localIndexes();
   auto node1 = segment.getNode(0).position();
   auto node2 = segment.getNode(1).position();
 
   // computes the direction of the line
   auto dd_line = node2 - node1;
 
   // computes a unitary vector in the direction of the line
   Vector<Dim> dd_line_direction = dd_line;
   dd_line_direction.normalize();
 
   // computes the relatice position of the atom
   Vector<Dim> pos_atom = pos0 - node1;
 
   // Rmat is a rotation of only the coordinates in the slip plane coordinates
   // This is to be used to convert to/from the reference where the templates
   // were computed
   Matrix<Dim> Rmat = computeTemplateRotation(dd_line_direction, normal);
 
   // project the atom position to the segment
   Vector<Dim> projected_atom_pos =
       pos_atom.dot(dd_line_direction) * dd_line_direction;
 
   // vector from segment to atom position
   Vector<Dim> vec_atom_2_dd_core = pos_atom - projected_atom_pos;
   Vector<Dim> template_coords = Rmat * vec_atom_2_dd_core;
 
   Vector<Dim> disp = Vector<Dim>::Zero();
   this->coreDispAtom(template_coords, disp);
   for (UInt i = 0; i < Dim; ++i)
-    this->add(disp[i]);
+    this->push_back(disp[i]);
 }
 
 /* -------------------------------------------------------------------------- */
 
 //****************
 // part concrening the interpolation between angles
 //****************
 
 // character angle: angle between burgers vector and dislocation line
 // Real dangle = fabs(burgers.dot(dd_line_direction)) / burgers.norm();
 // Real dangle_deg =
 //     std::acos(dangle) * 180.0 / M_PI; // character angle  (degree)
 // Real distance = fabs(90.0 - dangle_deg);
 // Real cangle = distance + 90.0; // change in a range between 90 and 180
 
 // Real closest_angles[2] = {0.0, 0.0};
 // UInt indices_closest_angles[2] = {1, 1};
 // compute_angle_ratio(cangle, indices_closest_angles, closest_angles);
 
 // DO NOT DELETE: displace elsewhere !!!!!
 // contained the displacement of the two templates
 // involved for angle interpolation
 // std::vector<Vector<Dim>> d = {0.0, 0.0};
 
 // DO NOT DELETE: displace elsewhere !!!!!
 // loop two neighboring angle templates for interpolation
 // for (int j = 0; j < 2; ++j) {
 
 // Real tmp_angle = fabs(this->angle_between_b_and_x - cangle);
 // tdisp = Rmat.transpose() * disp_template0;
 
 // tdisp[0] = disp_template0[2] * cos(tmp_angle / 180.0 * M_PI) +
 //            disp_template0[0] * sin(tmp_angle / 180.0 * M_PI);
 // tdisp[1] = disp_template0[1];
 // tdisp[2] = disp_template0[0] * cos(tmp_angle / 180.0 * M_PI) -
 //            disp_template0[2] * sin(tmp_angle / 180.0 * M_PI);
 
 // DO NOT DELETE: displace elsewhere !!!!!
 // in between angles interpolation
 // tdisp[0] = (dx[1] - dx[0]) / (nei_angles[1] - nei_angles[0]) *
 //                (cangle - nei_angles[0]) +
 //            dx[0];
 // tdisp[1] = (dy[1] - dy[0]) / (nei_angles[1] - nei_angles[0]) *
 //                (cangle - nei_angles[0]) +
 //            dy[0];
 // tdisp[2] = (dz[1] - dz[0]) / (nei_angles[1] - nei_angles[0]) *
 //                (cangle - nei_angles[0]) +
 //            dz[0];
 
 // /* --------------------------------------------------------------------------
 // */
 
 // template <typename DomainDD, typename DomainMD, UInt Dim>
 // bool CADD_template<DomainDD, DomainMD, Dim>::PointInSquare(
 //     Vector<Dim> &pts1, Vector<Dim> &pts2, Vector<Dim> &pts3, Vector<Dim>
 //     &pts4,
 //     Vector<Dim> &pts, UInt slip_case) {
 //   Real area0 = 0.0;
 //   Real area1 = AreaTriangle(pts1, pts3, pts4, slip_case);
 //   Real area2 = AreaTriangle(pts4, pts2, pts1, slip_case);
 //   Real area3 = AreaTriangle(pts1, pts2, pts3, slip_case);
 //   Real area4 = AreaTriangle(pts2, pts3, pts4, slip_case);
 //   area0 = (fabs(area1) + fabs(area2) + fabs(area3) + fabs(area4)) / 2.;
 
 //   Vector<2> int_X;
 //   if (intersectTwoD(pts1, pts3, pts2, pts4, int_X, slip_case)) {
 //     Real temp[3] = {0.0, 0.0, 0.0};
 //     for (UInt i = 0; i < 3; ++i) {
 //       temp[i] = pts2[i];
 //       pts2[i] = pts1[i];
 //       pts1[i] = temp[i];
 //     }
 //   }
 
 //   Real tot_area = 0.0;
 //   Real tot_area1 = AreaTriangle(pts, pts1, pts2, slip_case);
 //   Real tot_area2 = AreaTriangle(pts, pts3, pts1, slip_case);
 //   Real tot_area3 = AreaTriangle(pts, pts4, pts3, slip_case);
 //   Real tot_area4 = AreaTriangle(pts, pts2, pts4, slip_case);
 
 //   tot_area =
 //       fabs(tot_area1) + fabs(tot_area2) + fabs(tot_area3) + fabs(tot_area4);
 
 //   if (area0 + 1.0 < tot_area)
 //     return false;
 //   else
 //     return true;
 // }
 
 // template <typename _Input> void ComputeCADDTemplate<_Input>::init() {
 //  if (this->is_in_atomic) {
 //   for (UInt i = 0; i < this->num_templates; ++i) {
 //   //   TwoDTemplate<RefAtom, IteratorAtomsSubset> *single_template =
 //   //       new TwoDTemplate<RefAtom, IteratorAtomsSubset>();
 //   //   this->core_templates.push_back(single_template);
 //   //   this->core_templates[i]->init(this->templatefilename_list[i]);
 //   // }
 //     LM_TOIMPLEMENT;
 //   }
 // }
 
 // this function retreives the two closest angles
 // this is done to make the interpolation between angles easier
 // TODO: review move elsewhere
 inline void compute_angle_ratio(Real angle, UInt *indices_closest_angles,
                                 Real *closest_angles) {
 
   // TO REVIEW;
 
   // to enforce the specific core template
   // if(this->use_specific_template) {
   //   angle = this->specific_template_angle;
   // } else {
 
   // if (angle < 90.0) {
   //   angle = 180.0 - angle;
   // } else if ((180.0 < angle) && (angle <= 270.0)) {
   //   angle = 360.0 - angle;
   // } else if ((270.0 < angle) && (angle <= 360.0)) {
   //   angle = angle - 180.0;
   // }
   // // }
 
   // for (UInt j = 0; j < this->num_templates - 1; ++j) {
   //   two_angles[0] = this->core_templates[j]->get_theta();
   //   two_angles[1] = this->core_templates[j + 1]->get_theta();
   //   two_indices[0] = j;
   //   two_indices[1] = j + 1;
   //   if ((angle - two_angles[0]) * (angle - two_angles[1]) <= 0.0) {
   //     break;
   //   }
   // }
 }
 
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 
 void ComputeCADDTemplate::compute_make_call() {
   DUMP(this->getID() << ": Compute", DBG_INFO);
   call_compute(*this, [&](auto &... args) { this->build(args...); },
                this->getInput("points"), this->getInput("segments"));
 }
 
 /* -------------------------------------------------------------------------- */
 
 __END_LIBMULTISCALE__
diff --git a/src/filter/compute_dislodetection.cc b/src/filter/compute_dislodetection.cc
index 7136b0d..dd5b468 100644
--- a/src/filter/compute_dislodetection.cc
+++ b/src/filter/compute_dislodetection.cc
@@ -1,992 +1,992 @@
 /**
  * @file   compute_dislocdetn.cc
  *
  * @author Max Hodapp <max.hodapp@epfl.ch>
  *
  * @date   Thu Oct 29 2015
  *
  * @brief  Dislocation detection for single crystals
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * LibMultiScale is free  software: you can redistribute it and/or  modify it
  * under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * LibMultiScale is  distributed in the  hope that it  will be useful, but
  * WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* TODO:
  * - check 'Delaunay_Triangulation_3' constructor in CGAL
  *   --> try to avoid redundant memcopies to convert Reals into Points!!
  * - add 2-D compatibility
  * - add compatibility for 1) several dislocation lines, 2) dislocation loops
  * - detection of partial dislocations
  * - detection of dislocations in different crystals (e.g. bcc)
  * - the method for MPI communication should be generalized s.t. they can be
  *   used by all classes which take possibly distributed data as input
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "compute_dislodetection.hh"
 #include "lib_dumper.hh"
 #include "lib_filter.hh"
 #include "lib_md.hh"
 #include "lib_stimulation.hh"
 #include "lm_common.hh"
 /* -------------------------------------------------------------------------- */
 __BEGIN_LIBMULTISCALE__
 
 #define __TOL__ 1e-16 // numerical tolerance
 /* -------------------------------------------------------------------------- */
 // Forward declarations
 
 // Methods are straight-forward modifications from the original CGAL
 // implementation (see 'Fixed_alpha_shape_3.h')
 template <typename OutputIterator>
 OutputIterator get_all_alpha_shape_edges(Ta &tet_alpha, OutputIterator it);
 template <typename OutputIterator>
 OutputIterator get_all_alpha_shape_faces(Ta &tet_alpha, OutputIterator it);
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 /* IMPLEMENTATION - CONSTRUCTOR                                               */
 /* -------------------------------------------------------------------------- */
 
 ComputeDisloDetection::ComputeDisloDetection(const std::string &name)
     : LMObject(name), meshTet(name + "-meshTet") {
   // Add 'meshTet' to filter manager (--> the object is now visible to the
   // parser)
   LM_TOIMPLEMENT;
   // FilterManager::getManager().addObject(&this->meshTet, false);
 };
 
 /* -------------------------------------------------------------------------- */
 
 ComputeDisloDetection::~ComputeDisloDetection() {}
 
 /* -------------------------------------------------------------------------- */
 /* IMPLEMENTATION - PUBLIC MEMBER METHODS                                     */
 /* -------------------------------------------------------------------------- */
 
 /* Main build */
 
 template <typename Cont> void ComputeDisloDetection::build(Cont &cont) {
 
   if (Cont::Dim != 3) {
     LM_FATAL("Dislocation detection only available in 3D!" << std::endl);
   }
 
   auto &output = allocAndGetCastedOutput<ContainerGenericMesh<3>>(
       "detected_segments:" + this->getID());
 
   /* ------------------------------------------------------------------------ */
   // NOTE: Dislocation detection does not run in parallel
   //       ==> gather atomic positions from all other processes
   /* ------------------------------------------------------------------------ */
 
   ComputeExtract positions("ComputeExtract:" + this->getID());
   positions.setParam("FIELD", _position);
   positions.build(cont);
 
   std::vector<Real> pos_buffer;
   this->gatherAllData(pos_buffer, positions, 0); // root process is 0
 
   /* ------------------------------------------------------------------------ */
   // Run dislocation detection only on the root process of the atomistic group
   /* ------------------------------------------------------------------------ */
 
   CommGroup group = this->getCommGroup();
 
   if (group.size() > 1) {
     if (group.getMyRank() == 0) {
       DUMP("Dislocation detection is currently not parallelized!", DBG_MESSAGE);
     } else {
       return;
     }
   }
 
   DUMP("Starting dislocation detection ...", DBG_MESSAGE);
   Real norm2[3];
   // Containers/Lists
   std::vector<Pt> pt_buffer;
   std::list<Vertex_handle> v_l;
   std::list<Cell_handle> c_l;
   /* ------------------------------------------------------------------------ */
   // Delete previous mesh struct
   output.getContainerNodes().clear();
   output.getContainerElems().clear();
   this->meshTet.getContainerNodes().clear();
   this->meshTet.getContainerElems().clear();
   /* ------------------------------------------------------------------------ */
 
   /* Mesh atomistic domain */
 
   //   T tet;
   //
   //   {
   //     std::vector< Real >::iterator pos_it;
   //     for ( pos_it = pos_buffer.begin(); pos_it != pos_buffer.end();
   //     std::advance(pos_it,3) )
   //     {
   //       tet.insert( Pt( pos_it[0], pos_it[1], pos_it[2] ) );
   //     }
   //   }
 
   // Convert full position matrix to 'Point_3'
   // --> CGAL seems to accept only nodes of this type
   // NOTE: intuitively one would like to to do sth like
   //         T tet( pos_buffer.begin(), pos_buffer.end() )
   //       to avoid redundant copy operations and memory capacity
   //       --> however, the second method seems to be faster...
   {
     std::vector<Real>::iterator pos_it;
     for (pos_it = pos_buffer.begin(); pos_it != pos_buffer.end();
          std::advance(pos_it, 3)) {
       pt_buffer.push_back(Pt(pos_it[0], pos_it[1], pos_it[2]));
     }
     pos_buffer.clear();
   }
 
   // Tetrahedralize the atomistic domain
   T tet(pt_buffer.begin(), pt_buffer.end());
 
   pt_buffer.clear();
 
   // Ceck validity of 'tet'
   assert(tet.is_valid());
 
   // Generate the alpha shape from 'tet'
   // NOTE: 'tet' will be destroyed
   Ta tet_alpha(tet, this->alpha);
 
   // Get iterators to the simplices of the alpha shape
   tet_alpha.get_alpha_shape_vertices(std::back_inserter(v_l), Ta::REGULAR);
   tet_alpha.get_alpha_shape_cells(std::back_inserter(c_l), Ta::INTERIOR);
 
   DUMP("-- Tetrahedralization successful! --", DBG_MESSAGE);
   DUMP("Vertices ... " << v_l.size(), DBG_MESSAGE);
   DUMP("Cells ...... " << c_l.size(), DBG_MESSAGE);
   /* ------------------------------------------------------------------------ */
   // Detect distorted tetrahedra
 
   // Normalize the orientation matrix
   norm2[0] = sqrt(this->orient[0] * this->orient[0] +
                   this->orient[1] * this->orient[1] +
                   this->orient[2] * this->orient[2]);
   norm2[1] = sqrt(this->orient[3] * this->orient[3] +
                   this->orient[4] * this->orient[4] +
                   this->orient[5] * this->orient[5]);
   norm2[2] = sqrt(this->orient[6] * this->orient[6] +
                   this->orient[7] * this->orient[7] +
                   this->orient[8] * this->orient[8]);
 
   this->orient[0] /= norm2[0];
   this->orient[3] /= norm2[1];
   this->orient[6] /= norm2[2];
   this->orient[1] /= norm2[0];
   this->orient[4] /= norm2[1];
   this->orient[7] /= norm2[2];
   this->orient[2] /= norm2[0];
   this->orient[5] /= norm2[1];
   this->orient[8] /= norm2[2];
 
   // Assign reference bond vectors
   this->setRefBondVec();
 
   // Run the detection
   this->detect(output, tet_alpha);
   /* ------------------------------------------------------------------------ */
   // Output tetMesh --> skip in test version since mesh cannot yet be visualized
   // inside LM
   this->outputMesh(v_l, c_l);
 }
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 /* IMPLEMENTATION - PRIVATE MEMBER METHODS                                    */
 /* -------------------------------------------------------------------------- */
 
 /* Define the set of ideal reference vectors */
 
 void ComputeDisloDetection::setRefBondVec() {
   if (this->lattice_t == std::string("fcc")) {
     if (this->disloc_t == std::string("full")) {
 
       this->Nref = 18;
       this->bVecRef = new Vec[18];
 
       // First nearest neighbors
       this->bVecRef[0] = Vec(0.5, 0.5, 0.);
       this->bVecRef[1] = Vec(-0.5, -0.5, 0.);
       this->bVecRef[2] = Vec(0.5, 0., 0.5);
       this->bVecRef[3] = Vec(-0.5, 0., -0.5);
       this->bVecRef[4] = Vec(0., 0.5, 0.5);
       this->bVecRef[5] = Vec(0., -0.5, -0.5);
       this->bVecRef[6] = Vec(-0.5, 0.5, 0.);
       this->bVecRef[7] = Vec(0.5, -0.5, 0.);
       this->bVecRef[8] = Vec(-0.5, 0., 0.5);
       this->bVecRef[9] = Vec(0.5, 0., -0.5);
       this->bVecRef[10] = Vec(0., 0.5, -0.5);
       this->bVecRef[11] = Vec(0., -0.5, 0.5);
       // Second nearest neighbors
       this->bVecRef[12] = Vec(1., 0., 0.);
       this->bVecRef[13] = Vec(-1., 0., 0.);
       this->bVecRef[14] = Vec(0., 1., 0.);
       this->bVecRef[15] = Vec(0., -1., 0.);
       this->bVecRef[16] = Vec(0., 0., 1.);
       this->bVecRef[17] = Vec(0., 0., -1.);
 
       // Rotate the reference lattice to the crystals orientation
       for (UInt i = 0; i < 18; ++i)
         this->bVecRef[i] =
             this->a0 * Vec(this->orient[0] * this->bVecRef[i].x() +
                                this->orient[1] * this->bVecRef[i].y() +
                                this->orient[2] * this->bVecRef[i].z(),
                            this->orient[3] * this->bVecRef[i].x() +
                                this->orient[4] * this->bVecRef[i].y() +
                                this->orient[5] * this->bVecRef[i].z(),
                            this->orient[6] * this->bVecRef[i].x() +
                                this->orient[7] * this->bVecRef[i].y() +
                                this->orient[8] * this->bVecRef[i].z());
     } else {
       LM_TOIMPLEMENT; // detection of partial dislocations not yet supported
     }
   } else {
     LM_TOIMPLEMENT; // other lattice types not yet supported
   }
 }
 /* -------------------------------------------------------------------------- */
 
 /* Compute the Burgers vector of a face */
 
 // SHORT:
 //
 // Let a the faces of a tetrahedron be numbered 0,1,2,3. Then the Burgers vector
 // for each face is defined as
 //
 //   burgers_v_0 = v_5_ref - v_6_ref - v_4_ref,
 //   burgers_v_1 = v_2_ref + v_6_ref - v_3_ref,
 //   burgers_v_2 = v_3_ref - v_5_ref - v_1_ref,
 //   burgers_v_3 = v_1_ref + v_4_ref - v_2_ref,
 //
 // where the v_i_ref are the reference vectors corresponding to each of the 6
 // edge vectors of a tetrahedron in the current configuration.
 
 inline Vec
 ComputeDisloDetection::computeBurgersVec(const Cell_handle &ch, // cell handle
                                          const UInt idxFace)    // face index
 {
   switch (idxFace) {
   case 0:
     return (this->bVecRef[ch->info()[4]] - this->bVecRef[ch->info()[5]] -
             this->bVecRef[ch->info()[3]]);
   case 1:
     return (this->bVecRef[ch->info()[1]] + this->bVecRef[ch->info()[5]] -
             this->bVecRef[ch->info()[2]]);
   case 2:
     return (this->bVecRef[ch->info()[2]] - this->bVecRef[ch->info()[4]] -
             this->bVecRef[ch->info()[0]]);
   case 3:
     return (this->bVecRef[ch->info()[0]] + this->bVecRef[ch->info()[3]] -
             this->bVecRef[ch->info()[1]]);
   };
 
   LM_FATAL("Face index " << idxFace << " not valid!" << std::endl
                          << "Range is (0, 1, 2, 3)." << std::endl);
 }
 /* -------------------------------------------------------------------------- */
 
 /* Get remaining distorted faces of tetrahedron which has a distorted face */
 
 // NOTE: dislocation junctions are currently not warranted!
 UInt ComputeDisloDetection::getDistortedFaces(
     Face &fh,              // reference to 2nd distorted face
     const Cell_handle &ch, // cell handle
     const UInt idxFace)    // index of the detected face
 {
   UInt ctr = 0; // nbr of distorted faces
 
   switch (idxFace) {
   case 0:
 
     if (this->computeBurgersVec(ch, 1).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 1);
       ++ctr;
     }
     if (this->computeBurgersVec(ch, 2).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 2);
       ++ctr;
     }
     if (this->computeBurgersVec(ch, 3).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 3);
       ++ctr;
     }
 
     break;
 
   case 1:
 
     if (this->computeBurgersVec(ch, 0).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 0);
       ++ctr;
     }
     if (this->computeBurgersVec(ch, 2).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 2);
       ++ctr;
     }
     if (this->computeBurgersVec(ch, 3).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 3);
       ++ctr;
     }
 
     break;
 
   case 2:
 
     if (this->computeBurgersVec(ch, 0).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 0);
       ++ctr;
     }
     if (this->computeBurgersVec(ch, 1).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 1);
       ++ctr;
     }
     if (this->computeBurgersVec(ch, 3).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 3);
       ++ctr;
     }
 
     break;
 
   case 3:
 
     if (this->computeBurgersVec(ch, 0).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 0);
       ++ctr;
     }
     if (this->computeBurgersVec(ch, 1).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 1);
       ++ctr;
     }
     if (this->computeBurgersVec(ch, 2).squared_length() > __TOL__) {
       fh = std::make_pair(ch, 2);
       ++ctr;
     }
 
     break;
   };
 
   if (ctr > 0)
     return ctr;
   else
     LM_FATAL("Dislocation cannot end within a crystal" << std::endl);
 }
 /* -------------------------------------------------------------------------- */
 
 /* Main method during a dislocation detection */
 
 template <typename Mesh>
 void ComputeDisloDetection::detect(Mesh &mesh, Ta &tet_alpha) {
   UInt idx, size_buffer, Nlines = 0, Nloops = 0;
   std::pair<UInt, UInt> idxVh;
   Real norm2, norm2_buffer;
   // LM
   RefPointData<3> node;
   // LM - Containers/Lists
   std::vector<RefPointData<3>> nodes_buffer;
   // CGAL
   Pt pt_centroid;
   Vec eVec;
   Vertex_handle vh1, vh2;
   Face fh;
   Cell_handle ch;
   // CGAL - Containers/Lists
   std::list<Edge> eh_l;
   std::list<Face> fh_l;
   std::list<Face> fhR_l;
   std::list<Face> fhI_l;
   // CGAL - Iterators
   std::list<Edge>::iterator eh_it;
   std::list<Face>::iterator fh_it;
   Ta::Cell_circulator ch_circ;
   /* ------------------------------------------------------------------------ */
 
   // Get list of all edges & faces from the alpha shape
   get_all_alpha_shape_edges(tet_alpha, std::back_inserter(eh_l));
   get_all_alpha_shape_faces(tet_alpha, std::back_inserter(fh_l));
   // Get list of all faces which are on the boundary of the alpha shape
   tet_alpha.get_alpha_shape_facets(std::back_inserter(fhR_l), Ta::REGULAR);
   // Get list of all faces which are in the interior of the alpha shape
   tet_alpha.get_alpha_shape_facets(std::back_inserter(fhI_l), Ta::INTERIOR);
 
   // Iterate over all edges of the alpha shape
   //   An edge handle is a triple < Cell_handle, int int >, where the
   //   Cell_handle
   //   refers to a cell which contains the edge and the both integers are the
   //   indices
   //   of its vertices
   for (eh_it = eh_l.begin(); eh_it != eh_l.end(); ++eh_it) {
     /* ********************************************************************** */
     // 1) Compute the reference vector the current edge
 
     // First obtain the vertex handles from the edge list ...
     vh1 = (*eh_it).first->vertex((*eh_it).second);
     vh2 = (*eh_it).first->vertex((*eh_it).third);
     // ... then compute the vector p2-p1
     eVec = vh2->point() - vh1->point();
     // Compute the squared l^2-norm for all ev_ref(i)-ev and assigend the
     // element
     // of V_ref which minimzes it
     // assert( Nref != 0 );
     norm2_buffer = Vec(this->bVecRef[0] - eVec).squared_length();
     idx = 0;
     for (UInt i = 1; i < this->Nref; ++i) {
       norm2 = Vec(this->bVecRef[i] - eVec).squared_length();
       if (norm2 < norm2_buffer) {
         norm2_buffer = norm2;
         idx = i;
       }
     }
     /* ********************************************************************** */
     // 2) Store the corresponding reference vector in all cells incident to
     // '*eit'
 
     ch_circ = tet_alpha.incident_cells((*eh_it), (*eh_it).first);
     ch = ch_circ;
     do {
       // Get the indices of each vertex
       idxVh.first = ch_circ->index(vh1);
       idxVh.second = ch_circ->index(vh2);
 
       switch (idxVh.first) {
       case 0:
         switch (idxVh.second) {
         case 1:
           ch_circ->info()[0] = idx;
           break;
         case 2:
           ch_circ->info()[1] = idx;
           break;
         case 3:
           ch_circ->info()[2] = idx;
           break;
         };
         break;
       case 1:
         switch (idxVh.second) {
         case 0:
           ch_circ->info()[0] = idx ^ 1;
           break;
         case 2:
           ch_circ->info()[3] = idx;
           break;
         case 3:
           ch_circ->info()[4] = idx;
           break;
         };
         break;
       case 2:
         switch (idxVh.second) {
         case 0:
           ch_circ->info()[1] = idx ^ 1;
           break;
         case 1:
           ch_circ->info()[3] = idx ^ 1;
           break;
         case 3:
           ch_circ->info()[5] = idx;
           break;
         };
         break;
       case 3:
         switch (idxVh.second) {
         case 0:
           ch_circ->info()[2] = idx ^ 1;
           break;
         case 1:
           ch_circ->info()[4] = idx ^ 1;
           break;
         case 2:
           ch_circ->info()[5] = idx ^ 1;
           break;
         };
         break;
       }
       ch_circ++;
 
     } while (ch_circ != ch);
     /* ********************************************************************** */
   }
   /* ------------------------------------------------------------------------ */
   // 3) Dislocation line tracking
 
   UInt ctr = 0; // counts the number of distorted faces per tetrahedron
   /* ------------------------------------------------------------------------ */
   /* ------------------------------------------------------------------------ */
   while (fhR_l.size() > 0) {
     fh_it = fhR_l.begin(); // set iterator to the first element of the list
 
     // Get the cell and the index of the opposed vertex of the current face
     ch = (*fh_it).first;
     idx = (*fh_it).second;
     /* ********************************************************************** */
     // If the Burgers vector is non-zero ==> mark both cells containing the
     // current face
     //   --> the neighboring cell can simply be accessed via the index of the
     //   opposed vertex
 
     if (this->computeBurgersVec(ch, idx).squared_length() > __TOL__) {
 
       // Check if current cell is an element of the alpha shape
       //   ==> if 'ch' is not interior --> set 'ch' to its opposed neighbor and
       //   update the index of the current face
       if (tet_alpha.classify(ch) != Ta::INTERIOR) {
         ch = ch->neighbor(idx);
         idx = tet_alpha.mirror_facet(*fh_it).second;
       }
 
       // Add the center of mass of the current cell to the list of nodes
       pt_centroid =
           CGAL::centroid(Tet(ch->vertex(0)->point(), ch->vertex(1)->point(),
                              ch->vertex(2)->point(), ch->vertex(3)->point()));
 
       // Push the center of mass to the set of nodes
       node.position()[0] = pt_centroid.x();
       node.position()[1] = pt_centroid.y();
       node.position()[2] = pt_centroid.z();
 
       nodes_buffer.push_back(node);
 
       // Face handle can now be savely removed from the list of boundary faces
       fhR_l.remove(*fh_it);
 
       // Compute the Burgers vectors of the 3 remaining faces
       ctr = getDistortedFaces(fh, ch, idx);
 
       // Abort program if more than 2 faces with non-zero Burgers vector are
       // found
       if (ctr > 1)
         LM_FATAL(std::endl
                  << "Number of faces with non-zero Burgers vector: "
                  << (ctr + 1) << std::endl
                  << "Dislocation junctions not supported yet!" << std::endl);
 
       ctr = 0;
       /* ******************************************************************** */
       // Track the dislocation line through the atomistic domain as long as the
       // subsequent face is in its interior
 
       while (tet_alpha.classify(fh) != Ta::REGULAR) {
         // Get the opposed neighbor and the index of the face thereof
         ch = ch->neighbor(fh.second);
         idx = tet_alpha.mirror_facet(fh).second;
 
         // Add the center of mass of the current cell to the list of nodes
         pt_centroid =
             CGAL::centroid(Tet(ch->vertex(0)->point(), ch->vertex(1)->point(),
                                ch->vertex(2)->point(), ch->vertex(3)->point()));
 
         // Push the center of mass to the set of nodes
         node.position()[0] = pt_centroid.x();
         node.position()[1] = pt_centroid.y();
         node.position()[2] = pt_centroid.z();
 
         nodes_buffer.push_back(node);
 
         // Remove the face from the list of interior faces
         //   --> since there is no iterator pointing to 'fh', perform check if
         //   size is reduced ...
         size_buffer = fhI_l.size();
         fhI_l.remove(fh);
         if (fhI_l.size() == size_buffer) // ... else remove the face handle
                                          // defined w.r.t. the opposed cell
           fhI_l.remove(tet_alpha.mirror_facet(fh));
 
         // Compute the Burgers vectors of the 3 remaining faces
         ctr = getDistortedFaces(fh, ch, idx);
 
         // Abort program if more than 2 faces with non-zero Burgers vector are
         // found
         if (ctr > 1)
           LM_FATAL(std::endl
                    << "Number of faces with non-zero Burgers vector: "
                    << (ctr + 1) << std::endl
                    << "Dislocation junctions not supported yet!" << std::endl);
 
         ctr = 0;
       };
       /* ******************************************************************** */
       // Remove the last face from the list of boundary faces
       size_buffer = fhR_l.size();
       fhR_l.remove(fh);
       if (fhR_l.size() == size_buffer)
         fhR_l.remove(tet_alpha.mirror_facet(fh));
       /* ******************************************************************** */
       // Add the DD nodes to the output container
       if (nodes_buffer.size() > 1)
         outputDD(mesh, nodes_buffer);
       /* ******************************************************************** */
       ++Nlines; // increase the number of detected dislocation lines by 1
     }
     /* ********************************************************************** */
     else {
       fhR_l.remove(*fh_it); // remove the current cell from the list
     }
   };
   /* ------------------------------------------------------------------------ */
   /* ------------------------------------------------------------------------ */
   DUMP("Detected dislocation lines: " << Nlines, DBG_MESSAGE);
   // Test version --> throw error if more than one dislocation line is detected
   if (Nlines > 1)
     LM_FATAL(std::endl
              << "Output of several dislocation lines is currently prohibited!"
              << std::endl);
   /* ------------------------------------------------------------------------ */
   /* ------------------------------------------------------------------------ */
   // Track dislocation loops
 
   while (fhI_l.size() > 0) {
     fh_it = fhI_l.begin(); // set iterator to the first element of the list
 
     // Get the cell and the index of the opposed vertex of the current face
     ch = (*fh_it).first;
     idx = (*fh_it).second;
     /* ********************************************************************** */
     // If the Burgers vector is non-zero ==> mark both cells containing the
     // current face
     //   --> the neighboring cell can simply be accessed via the index of the
     //   opposed vertex
 
     if (this->computeBurgersVec(ch, idx).squared_length() > __TOL__) {
       LM_FATAL(std::endl
                << "Dislocation loop detected." << std::endl
                << "Dislocation loops not supported yet!" << std::endl);
     }
     /* ********************************************************************** */
     else {
       fhI_l.remove(*fh_it); // remove the current cell from the list
     }
   };
   /* ------------------------------------------------------------------------ */
   DUMP("Detected dislocation loops: " << Nloops, DBG_MESSAGE);
   /* ------------------------------------------------------------------------ */
 }
 /* -------------------------------------------------------------------------- */
 
 /* Outputs the DD mesh to the output container */
 
 // NOTE: the point set is divided into sets of equal size. If 'Nnodes' is not
 //       divisible by 'nodesPerSeg' resdiual segments ared added with
 //       'nodesPerSeg-1' nodes per segment
 
 template <typename Mesh>
 void ComputeDisloDetection::outputDD(
     Mesh &mesh, std::vector<RefPointData<3>> &nodes_buffer) {
 
   UInt Nnodes, nodes_buffer_inc;
   UInt Nsegs, Nsegs_res;
   Vector<2, UInt> conn;
   // Containers/Lists
   typename std::vector<RefPointData<3>>::iterator nodes_it;
   // LM
   RefGenericElem<3> el_buffer;
   // LM - Containers/Lists
   auto &nodes = mesh.getContainerNodes();
   auto &elems = mesh.getContainerElems();
   /* ------------------------------------------------------------------------ */
   // Set initial connectivity
   conn[0] = nodes.size() - 1;
   conn[1] = nodes.size();
   /* ------------------------------------------------------------------------ */
 
   /* 1) Get the number of regular and residual segments */
 
   Nnodes = nodes_buffer.size() - 1;
   // Set increment
   if (this->nodesPerSeg > nodes_buffer.size())
     nodes_buffer_inc = Nnodes;
   else
     nodes_buffer_inc = this->nodesPerSeg - 1;
 
   Nsegs = UInt(Nnodes / nodes_buffer_inc);
 
   if (Nnodes - Nsegs * nodes_buffer_inc > 0) {
     ++Nsegs;
     Nsegs_res = nodes_buffer_inc * Nsegs - Nnodes;
     // If the number of residual segments is larger than the number of regular
     // segments ...
     if (Nsegs_res > Nsegs) {
       nodes_buffer_inc =
           UInt((Nsegs + Nnodes) / Nsegs); // ... choose an optimal increment
                                           // (w.r.t. to the (largest possible)
                                           // nbr of nodes per segment) s.t. the
                                           // Nsegs == const.
       // Update the number of resdiual segments
       Nsegs_res = nodes_buffer_inc * Nsegs - Nnodes;
     }
   } else
     Nsegs_res = 0;
   /* ------------------------------------------------------------------------ */
 
   /* 2) Add the nodes to the output container  */
 
   nodes_it = nodes_buffer.begin();
-  nodes.add(*nodes_it);
+  nodes.push_back(*nodes_it);
 
   // Add "regular" nodes
   for (UInt i = 0; i < Nsegs - Nsegs_res; ++i) {
     std::advance(nodes_it, nodes_buffer_inc);
-    nodes.add(*nodes_it);
+    nodes.push_back(*nodes_it);
   }
 
   --nodes_buffer_inc;
 
   // Add "residual" nodes
   for (UInt i = 0; i < Nsegs_res; ++i) {
     std::advance(nodes_it, nodes_buffer_inc);
-    nodes.add(*nodes_it);
+    nodes.push_back(*nodes_it);
   }
   /* ------------------------------------------------------------------------ */
 
   /* 3) Add the connectivity  */
 
   for (UInt i = 0; i < Nsegs; ++i) {
     // Update connectivity
     ++conn[0];
     ++conn[1];
     // Add connectivity to output container
     el_buffer.setConnectivity(conn);
-    elems.add(el_buffer);
+    elems.push_back(el_buffer);
   }
   /* ------------------------------------------------------------------------ */
   // Clear array of buffer nodes
   nodes_buffer.clear();
   /* ------------------------------------------------------------------------ */
 }
 /* -------------------------------------------------------------------------- */
 
 /* Outputs the tetrahedralization to an additional container */
 
 void ComputeDisloDetection::outputMesh(std::list<Vertex_handle> &v_l,
                                        std::list<Cell_handle> &c_l) {
   UInt ctr = 0;
   Vector<4, UInt> conn;
   RefPointData<3> pt_buffer;
   RefGenericElem<3> el_buffer;
   // Containers/Lists
   auto &nodes = this->meshTet.getContainerNodes();
   auto &elems = this->meshTet.getContainerElems();
   // Iterators
   std::list<Vertex_handle>::iterator v_it;
   std::list<Cell_handle>::iterator c_it;
   /* ------------------------------------------------------------------------ */
   // Add nodes
 
   nodes.clear();
   for (v_it = v_l.begin(); v_it != v_l.end(); ++v_it) {
     // Get positions
     pt_buffer.position()[0] = (*v_it)->point().x();
     pt_buffer.position()[1] = (*v_it)->point().y();
     pt_buffer.position()[2] = (*v_it)->point().z();
 
-    nodes.add(pt_buffer);
+    nodes.push_back(pt_buffer);
     // Add corresponding index to info()
     (*v_it)->info() = ctr;
     ++ctr;
   }
   /* ------------------------------------------------------------------------ */
   // Add elements
 
   elems.clear();
   for (c_it = c_l.begin(); c_it != c_l.end(); ++c_it) {
     // Get connectivity via vertex info
     conn[0] = (*c_it)->vertex(0)->info();
     conn[1] = (*c_it)->vertex(1)->info();
     conn[2] = (*c_it)->vertex(2)->info();
     conn[3] = (*c_it)->vertex(3)->info();
 
     el_buffer.setConnectivity(conn);
 
-    elems.add(el_buffer);
+    elems.push_back(el_buffer);
   }
 }
 /* -------------------------------------------------------------------------- */
 
 /* Collect container arrays of Reals by the root process */
 
 // NOTE: this is a quick fix to gather all data on the root process since the
 //       dislocation detection is not parallelized yet!
 // NOTE: the function was is mostly taken from 'compute.cc' and should be
 //       generalized since communications methods are confined to the compute
 //       interface...
 
 void ComputeDisloDetection::gatherAllData(std::vector<Real> &data_recv,
                                           ContainerArray<Real> &data_send,
                                           const UInt root_rank) {
   CommGroup group = this->getCommGroup();
   UInt my_rank = group.getMyRank();
   UInt nb_data = data_send.size();
   std::vector<UInt> nb_data_per_proc;
 
   // #ifndef LM_OPTIMIZED
   //   UInt total_data = this->getTotalNbData(root_rank);
   //   comm.synchronize(group);
   // #endif //LM_OPTIMIZED
 
   //   gather_flag = true;
   //   gather_root_proc = root_rank;
 
   if (root_rank == my_rank) {
     // prepare the array to resizes the sizes
     UInt nb_procs = group.size();
     DUMP("receive " << nb_procs << " procs", DBG_INFO);
     DUMP("my rank is " << my_rank, DBG_INFO);
     nb_data_per_proc.resize(nb_procs);
     for (UInt p = 0; p < nb_procs; ++p) {
       if (p == my_rank)
         nb_data_per_proc[p] = nb_data;
       else {
         DUMP("receive from proc " << p, DBG_INFO);
         group.receive(&nb_data_per_proc[p], 1, p, "gatherData: receive number");
       }
     }
     // compute total size of the gathered data
     UInt tot_size = 0;
     for (UInt p = 0; p < nb_procs; ++p) {
       DUMP("nb_data_per_proc[" << p << "]=" << nb_data_per_proc[p], DBG_INFO);
       tot_size += nb_data_per_proc[p];
     }
 
     // #ifndef LM_OPTIMIZED
     //     LM_ASSERT(total_data == tot_size, "mismatched of global sizes");
     // #endif //LM_OPTIMIZED
 
     // resize the receiving buffer
     data_recv.resize(tot_size);
     // receive the data from the other processors
     UInt offset = 0;
     for (UInt p = 0; p < nb_procs; ++p) {
       // if p is my_rank/root_rank copy the data
       if (p == my_rank) {
         for (UInt i = 0; i < nb_data; ++i) {
           data_recv[offset + i] = (data_send)[i];
         }
       }
       // else receive from distant proc
       else if (nb_data_per_proc[p]) {
         group.receive(&data_recv[offset], nb_data_per_proc[p], p,
                       "gatherData: receive data");
       }
 
       // increment the offset
       offset += nb_data_per_proc[p];
     }
   } else {
     DUMP("send my nb_data = " << nb_data, DBG_INFO);
     // send the amount of data I have
     group.send(&nb_data, 1, root_rank, "gatherData: send number");
     // if there is data to be sent : do so
     if (nb_data != 0)
       group.send(static_cast<std::vector<Real> &>(data_send), root_rank,
                  "gatherData: send data");
   }
 }
 
 /* -------------------------------------------------------------------------- */
 /* LMDESC DISLODETECTION
    Dislocation detection for single crystals based on Stukowski (2014)
 */
 
 /* LMEXAMPLE
    COMPUTE dxa DISLOCDETN INPUT Pa ALPHA 7.5
  */
 
 inline void ComputeDisloDetection::declareParams() {
   /* LMKEYWORD LATTICE_T
      Lattice type (supported: \textit{fcc} - default: \textit{fcc})
   */
   this->parseKeyword("LATTICE_T", this->lattice_t, "fcc");
 
   /* LMKEYWORD A0
      Lattice constant
   */
   this->parseKeyword("A0", this->a0);
 
   /* LMKEYWORD ALPHA
      Maximum squared circumradius for tetrahedrons (defines the alpha shape)
   */
   this->parseKeyword("ALPHA", this->alpha);
 
   /* LMKEYWORD ORIENT
      Orientation of the crystal (default: x [1 2 1], y [-1 0 1], z [1 -1 1])
   */
   this->parseVectorKeyword("ORIENT", 9, this->orient,
                            VEC_DEFAULTS(1., 2., 1., -1., 0., 1., 1., -1., 1.));
 
   /* LMKEYWORD DISLOC_T
      Dislocation type (supported: \textit{full} - default: \textit{full})
   */
   this->parseKeyword("DISLOC_T", this->disloc_t, "full");
 
   /* LMKEYWORD NODES_PER_SEG
      Specify a number of nodes per segment to avoid artificial small segments
      (default is 1).
      {bf NOTE:} fix should be replaced with a curve-fitting procedure in future
      versions
   */
   this->parseKeyword("NODES_PER_SEG", this->nodesPerSeg, 1u);
 };
 
 /* -------------------------------------------------------------------------- */
 /* BACKWARD IMPLEMENTATION                                                    */
 /* -------------------------------------------------------------------------- */
 
 template <typename OutputIterator>
 OutputIterator get_all_alpha_shape_edges(Ta &tet_alpha, OutputIterator it) {
   T::Finite_edges_iterator eh_it =
       tet_alpha
           .finite_edges_begin(); // use tet_alpha since tet will be destroyed!!
   for (; eh_it != tet_alpha.finite_edges_end(); ++eh_it) {
     if ((tet_alpha.classify(*eh_it) == Ta::INTERIOR) ||
         (tet_alpha.classify(*eh_it) == Ta::REGULAR))
       *it++ = *eh_it;
   }
   return it;
 }
 
 template <typename OutputIterator>
 OutputIterator get_all_alpha_shape_faces(Ta &tet_alpha, OutputIterator it) {
   T::Finite_facets_iterator fh_it =
       tet_alpha
           .finite_facets_begin(); // use tet_alpha since tet will be destroyed!!
   for (; fh_it != tet_alpha.finite_facets_end(); ++fh_it) {
     if ((tet_alpha.classify(*fh_it) == Ta::INTERIOR) ||
         (tet_alpha.classify(*fh_it) == Ta::REGULAR))
       *it++ = *fh_it;
   }
   return it;
 }
 /* -------------------------------------------------------------------------- */
 
 DECLARE_COMPUTE_MAKE_CALL(ComputeDisloDetection);
 
 /* -------------------------------------------------------------------------- */
 #undef __TOL__
 /* -------------------------------------------------------------------------- */
 
 __END_LIBMULTISCALE__
diff --git a/src/filter/filter_point.cc b/src/filter/filter_point.cc
index 5ed9059..e76a9c3 100644
--- a/src/filter/filter_point.cc
+++ b/src/filter/filter_point.cc
@@ -1,302 +1,302 @@
 /**
  * @file   filter_point.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Till Junge <till.junge@epfl.ch>
  *
  * @date   Tue Jul 29 17:03:26 2014
  *
  * @brief  This allows to filter a set of DOFs by matching a list of coordinates
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * LibMultiScale is free  software: you can redistribute it and/or  modify it
  * under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * LibMultiScale is  distributed in the  hope that it  will be useful, but
  * WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "filter_point.hh"
 #include "communicator.hh"
 #include "compute_compatibility.hh"
 #include "compute_interface.hh"
 #include "lib_continuum.hh"
 #include "lib_dd.hh"
 #include "lib_md.hh"
 #include "lm_common.hh"
 #include "ref_point_data.hh"
 #include <fstream>
 #include <list>
 #include <sstream>
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_LIBMULTISCALE__
 
 /* -------------------------------------------------------------------------- */
 template <typename Ref>
 inline bool findPointInSet(Ref &point, std::list<UInt> &indices,
                            const std::vector<Real> &positions,
                            const Real &tolerance) {
 
   //static const UInt Dim = Ref::Dim;
 
   std::list<UInt>::iterator index = indices.begin();
   std::list<UInt>::iterator end_index = indices.end();
   Real distance = 0;
   do {
     LM_TOIMPLEMENT;
     //distance = point.computeInitialDistance(&positions.at(Dim * (*index)));
     ++index;
   } while ((distance > tolerance) && (index != end_index));
   if (index == end_index) {
     return false;
   } else {
     indices.erase(--index);
     return true;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <UInt Dim>
 void setPositionsCopy(const std::vector<Real> &positions, Cube cube,
                       Real tolerance, std::vector<Real> &positions_copy) {
 
   auto &&xmax = cube.getXmax();
   auto &&xmin = cube.getXmin();
 
   for (UInt k = 0; k < Dim; ++k) {
     xmax[k] += 2. * tolerance;
     xmin[k] -= 2. * tolerance;
   }
 
   cube.setDimensions(xmin.cast<PhysicalScalar<Length>>(),
                      xmax.cast<PhysicalScalar<Length>>());
 
   UInt _n = positions.size() / Dim;
 
   for (UInt i = 0; i < _n; ++i) {
     Vector<Dim> tmp(&positions[i * Dim]);
     bool test = static_cast<Geometry &>(cube).template contains<Dim>(tmp);
     if (test) {
       for (UInt k = 0; k < Dim; ++k)
         positions_copy.push_back(positions[i * Dim + k]);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 UInt FilterPoint::getNbSharedPoints() {
   LM_TOIMPLEMENT;
   // UInt counter = 0;
   // auto it = this->begin(this->dt);
   // auto end = this->end(this->dt);
   // for (; it != end; ++it) {
   //   auto &&point = *it;
   //   if ((point.getDOFType() & dt_local_master) == false) {
   //     counter++;
   //   }
   // }
   // return counter;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename Cont> void FilterPoint::build(Cont &cont) {
 
   auto &output =
       allocAndGetCastedOutput<typename Cont::ContainerSubset>(this->getID());
 
   std::vector<Real> positions_copy;
   static const UInt Dim = Cont::Dim;
 
   Cube cube(Dim);
 
   auto it = cont.begin(this->dt);
   auto end = cont.end(this->dt);
   for (; it != end; ++it) {
     auto &&point = *it;
     auto &&pos = point.position0();
     cube.extendBoundingBox(pos);
   }
 
   setPositionsCopy<Dim>(this->positions, cube, this->tolerance, positions_copy);
   DUMP(this->getID() << ": positions_copy " << positions_copy.size() << " "
                      << positions.size(),
        DBG_INFO);
 
   output.clear();
 
   std::list<UInt> indices;
   for (UInt i = 0; i < Dim; ++i) {
     // This is a dummy point I add for the findPointInSet algo, cleaned later
     positions_copy.push_back(lm_real_max);
   }
 
   UInt nb_points = positions_copy.size() / Dim;
   for (UInt i = 0; i < nb_points; ++i) {
     indices.push_back(i);
   }
 
   DUMP("number of indices = " << indices.size(), DBG_INFO);
   it = cont.begin(this->dt);
   for (; it != end; ++it) {
     auto &&point = *it;
     if (findPointInSet(point, indices, positions_copy, this->tolerance)) {
-      output.add(point);
+      output.push_back(point);
     }
   }
   // remove dummy point
   indices.pop_back();
   for (UInt i = 0; i < Dim; ++i) {
     positions_copy.pop_back();
   }
 
   nb_points = output.size();
   if (this->dt != dt_local_master) {
     UInt shared = this->getNbSharedPoints();
     DUMP("locally found " << nb_points << " total  of which " << shared
                           << " are shared.",
          DBG_DETAIL);
     nb_points -= shared;
   }
   // Communicator &comm = Communicator::getCommunicator();
   CommGroup group = cont.getCommGroup();
   group.allReduce(&nb_points, 1, "DeviationOperator reduce res", OP_SUM);
 
   if (nb_points == 0) {
     LM_FATAL(this->getID() << ": Could not match any point out of "
                            << positions.size() / Dim);
   }
 
   if (nb_points != positions.size() / Dim) {
 
     std::stringstream sstr;
     sstr << this->getID() << "-found_pos-" << lm_my_proc_id;
     ComputeCompatibility found_positions(sstr.str());
 
     found_positions.name_computed.resize(Dim);
     for (UInt k = 0; k < Dim; ++k) {
       std::stringstream sstr;
       sstr << "pos" << k;
       found_positions.name_computed[k] = sstr.str();
     }
 
     for (UInt i = 0; i < output.getArray().size(); ++i) {
       auto &&point = output.getArray()[i];
       auto &&pos = point.position0();
       found_positions.push_back(pos[0]);
       found_positions.push_back(pos[1]);
       found_positions.push_back(pos[2]);
     }
 
     found_positions.setCommGroup(group);
     LM_TOIMPLEMENT;
     // DumperText error_positions(sstr.str(), found_positions);
     // error_positions.setParam("SEPARATOR", std::string(","));
     // error_positions.setParam("RANK", comm.groupRank(lm_my_proc_id, group));
     // error_positions.manualDump();
 
     LM_FATAL(this->getID() << ": Could match " << nb_points - 1 << " out of "
                            << positions.size() / Dim << " positions"
                            << " locally I found " << output.size()
                            << " points");
   }
 
   dimension = Dim;
 }
 
 /* -------------------------------------------------------------------------- */
 
 FilterPoint::FilterPoint(const LMID &name)
     : LMObject(name), path(""), tolerance(1e-5), dimension(0) {}
 
 /* -------------------------------------------------------------------------- */
 
 FilterPoint::~FilterPoint() {}
 
 /* -------------------------------------------------------------------------- */
 
 void FilterPoint::init() {
   // yeah, could be done more elegantly
   std::ifstream infile(this->path.c_str());
   if (!infile.good()) {
     LM_FATAL("The atom file " << path.c_str()
                               << " could NOT be opened, rdstate = " << std::hex
                               << infile.rdstate() << std::endl
                               << " badbit  = " << infile.bad() << std::endl
                               << " failbit = " << infile.fail() << std::endl
                               << " eofbit  = " << infile.eof() << std::endl
                               << " goodbit = " << infile.good() << std::endl);
   }
   char tmp;
 
   while (infile.good()) {
     tmp = infile.peek();
     switch (tmp) {
     case '#':
       infile.ignore(1024, '\n');
       break;
     default:
       while (infile.good()) {
         this->positions.push_back(0);
         infile >> this->positions.back();
       }
       break;
     }
   }
   if (this->positions.size() == 0)
     LM_FATAL("no valid positions found in file " << this->path.c_str());
   this->positions.pop_back();
   DUMP("found " << this->positions.size() / 3 << " points", DBG_INFO_STARTUP);
 }
 /* -------------------------------------------------------------------------- */
 
 UInt FilterPoint::getNbPointsInFile() {
   return this->positions.size() / dimension;
 }
 
 /* -------------------------------------------------------------------------- */
 
 /* LMDESC POINT
    This filter allows to extract a set of points and/or
    elements contained in a provided point
 */
 
 /* LMHERITANCE filter */
 
 /* LMEXAMPLE FILTER fpoint POINT INPUT md PATH ./my-point-list.txt TOL 1e-5 */
 
 void FilterPoint::declareParams() {
   FilterInterface::declareParams();
   /* LMKEYWORD PATH
      Specify the file containing the points to filter
   */
   this->parseKeyword("PATH", path);
   /* LMKEYWORD TOL
      Specify the file containing the points to filter
   */
   this->parseKeyword("TOL", tolerance, 1e-5);
 }
 
 /* -------------------------------------------------------------------------- */
 
 DECLARE_COMPUTE_MAKE_CALL(FilterPoint);
 
 /* -------------------------------------------------------------------------- */
 
 __END_LIBMULTISCALE__