<commit_before>#include "../../AST/AST.h"
#include "FixedBits.h"

#include "ConstantBitP_Utility.h"

// To reduce the memory I tried using the constantbv stuff. But because it is not
// inlined it took about twice as long per propagation as does using a boolean array.
// Other options to reduce memory usage are: vector<bool>, dynamic_bitset, or bitMagic.

namespace simplifier
{
  namespace constantBitP
  {

    std::ostream&
    operator<<(std::ostream& output, const FixedBits& h)
    {
      output << "<";
      for (int i = h.getWidth() - 1; i >= 0; i--)
        {
          if (h.isFixed(i))
            output << h.getValue(i);
          else
            output << "-";
        }

      output << ">";

      return output;
    }

    void
    FixedBits::fixToZero()
    {
      for (int i = 0; i < getWidth(); i++)
        {
          setFixed(i, true);
          setValue(i, false);
        }
    }

    BEEV::CBV
    FixedBits::GetBVConst() const
    {
      assert(isTotallyFixed());

      BEEV::CBV result = CONSTANTBV::BitVector_Create(width, true);

      for (int i = 0; i < width; i++)
        {
          if (values[i])
            CONSTANTBV::BitVector_Bit_On(result, i);
        }

      return result;
    }

    //inclusive
    BEEV::CBV
    FixedBits::GetBVConst(int to, int from) const
    {
      assert(to>=from);
      assert(from >=0);
      int resultWidth = to - from + 1;

      BEEV::CBV result = CONSTANTBV::BitVector_Create(resultWidth, true);

      for (int i = from; i <= to; i++)
        {
          if (getValue(i))
            CONSTANTBV::BitVector_Bit_On(result, i - from);
        }

      return result;
    }

    void
    FixedBits::init(const FixedBits& copy)
    {
      width = copy.width;
      fixed = new bool[width];
      values = new bool[width];
      representsBoolean = copy.representsBoolean;

      memcpy(fixed, copy.fixed, width * sizeof(bool));
      memcpy(values, copy.values, width * sizeof(bool));
    }

    bool
    FixedBits::isTotallyFixed() const
    {
      for (int i = 0; i < width; i++)
        {
          if (!fixed[i])
            return false;
        }

      return true;
    }

    FixedBits::FixedBits(int n, bool isbool)
    {
      assert(n > 0);

      fixed = new bool[n];
      values = new bool[n];
      width = n;

      for (int i = 0; i < width; i++)
        {
          fixed[i] = false; // I don't know if there's a default value??
          values[i] = false; // stops it printing out junk.
        }

      representsBoolean = isbool;
      if (isbool)
        assert(1 == width);

      uniqueId = staticUniqueId++;
    }

    // There is no way to represent bottom. So we assume a and b are already at least
    // one step up the lattice.
    FixedBits
    FixedBits::meet(const FixedBits& a, const FixedBits& b)
    {
      assert(a.getWidth() == b.getWidth());
      assert(a.isBoolean() == b.isBoolean());

      FixedBits result(a.getWidth(), a.isBoolean());

      for (int i = 0; i < a.getWidth(); i++)
        {
          if (a.isFixed(i) != b.isFixed(i))
            {
              result.setFixed(i, false);
            }
          else if (a.isFixed(i) && b.isFixed(i) && (a.getValue(i)
              != b.getValue(i)))
            {
              result.setFixed(i, false);
            }
          else if (a.isFixed(i) && b.isFixed(i))
            { // fixed to the same value.
              result.setFixed(i, true);
              result.setValue(i, a.getValue(i));
            }
        }
      return result;
    }

#if 0
    #include "MersenneTwister.h"

    // Getting a new random number is expensive. Not sure why.
    FixedBits FixedBits::createRandom(const int length, const int probabilityOfSetting, MTRand& trand)
      {
        assert( 0 <= probabilityOfSetting);
        assert( 100 >= probabilityOfSetting);

        FixedBits result(length, false);

        // I'm not sure if the random number generator is generating just 32 bit numbers??
        int i = 0;
        int randomV = trand.randInt();

        int pool = 32;

        while (i < length)
          {
            if (pool < 8)
              {
                randomV = trand.randInt();
                pool = 32;
              }

            int val = (randomV & 127);
            randomV >>= 7;
            pool = pool - 7;

            if (val >= 100)
            continue;

            if (val < probabilityOfSetting)
              {
                switch (randomV & 1)
                  {
                    case 0:
                    result.setFixed(i, true);
                    result.setValue(i, false);
                    break;
                    case 1:
                    result.setFixed(i, true);
                    result.setValue(i, true);
                    break;
                    default:
                    BEEV::FatalError(LOCATION "never.");

                  }
                randomV >>= 1;
              }
            i++;

          }
        return result;
      }
#endif

    // In the world of static analysis this is ALPHA.
    FixedBits
    FixedBits::concreteToAbstract(const BEEV::ASTNode& n)
    {
      //cout << n;

      int bitWidth;
      if (BEEV::BITVECTOR_TYPE == n.GetType())
        bitWidth = n.GetValueWidth();
      else
        bitWidth = 1;

      FixedBits output(bitWidth, BEEV::BOOLEAN_TYPE == n.GetType());

      if (BEEV::BITVECTOR_TYPE == n.GetType())
        {
          // loop through testing each of the bits.
          BEEV::CBV cbv = n.GetBVConst();

          for (int j = 0; j < bitWidth; j++)
            {
              output.setFixed(j, true);
              output.setValue(j, CONSTANTBV::BitVector_bit_test(cbv, j));
            }
        }
      else
        {
          if (n.GetKind() == BEEV::TRUE)
            {
              output.setFixed(0, true);
              output.setValue(0, true);
            }
          else if (n.GetKind() == BEEV::FALSE)
            {
              output.setFixed(0, true);
              output.setValue(0, false);
            }
          else
            BEEV::FatalError("Unexpected", n);
        }
      return output;
    }

    FixedBits
    FixedBits::fromUnsignedInt(int width, unsigned val)
    {
      FixedBits output(width, false);

      const unsigned maxWidth = std::max((int) sizeof(unsigned) * 8, width);
      for (unsigned i = 0; i < maxWidth; i++)
        {
          if (i < (unsigned) width && i < sizeof(unsigned) * 8)
            {
              output.setFixed(i, true);
              output.setValue(i, (val & (1 << i)));
            }
          else if (i < (unsigned) width)
            {
              output.setFixed(i, true);
              output.setValue(i, false);

            }
          else // The unsigned value is bigger than the bitwidth of this.
            { // so it can't be represented.
              if (val & (1 << i))
                {
                  BEEV::FatalError(LOCATION "Cant be represented.");
                }
            }
        }
      return output;
    }

    int
    FixedBits::getUnsignedValue() const
    {
      assert(isTotallyFixed());
      assert(getWidth() <= 32);
      int result = 0;

      for (int i = 0; i < width; i++)
        {
          if (getValue(i))
            result += (1 << i);
        }
      return result;
    }

    bool
    FixedBits::updateOK(const FixedBits& o, const FixedBits &n, const int upTo)
    {
      assert (n.getWidth() >= upTo);
      assert (o.getWidth() >= upTo);

      for (int i = 0; i < upTo; i++)
        {
          if (n.isFixed(i) && o.isFixed(i))
            {
              if (n.getValue(i) != o.getValue(i))
                {
                  return false;
                }
            }
          else if (o.isFixed(i) && !n.isFixed(i))
            {
              return false;
            }
        }
      return true;
    }

    // If the oldBits can't become the new bits. While respecting the lattice rules. That's bad.
    // For example. A transfer function shouldn't unfix bits. Or chance the fixed bits value.
    bool
    FixedBits::updateOK(const FixedBits& o, const FixedBits &n)
    {
      if (n.getWidth() != o.getWidth())
        return false;

      for (int i = 0; i < n.getWidth(); i++)
        {
          if (n.isFixed(i) && o.isFixed(i))
            {
              if (n.getValue(i) != o.getValue(i))
                {
                  return false;
                }
            }
          else if (o.isFixed(i) && !n.isFixed(i))
            {
              return false;
            }
        }
      return true;
    }

    // a is "IN" b.
    bool
    FixedBits::in(const FixedBits& a, const FixedBits& b)
    {
      assert(a.getWidth() == b.getWidth());

      for (int i = 0; i < a.getWidth(); i++)
        {
          if (a.isFixed(i) && b.isFixed(i) && (a.getValue(i) != b.getValue(i)))
            {
              return false;
            }
          if (!a.isFixed(i) && b.isFixed(i))
            return false;
        }
      return true;
    }

    // Gets the minimum and maximum unsigned values that are represented by the set "shift".
    void
    FixedBits::getUnsignedMinMax(unsigned &minShift, unsigned &maxShift) const
    {
      const FixedBits& shift = *this;

      // Get the unsigned minimum and maximum of the shift.
      BEEV::CBV minCBV = CONSTANTBV::BitVector_Create(shift.getWidth(), true);
      BEEV::CBV maxCBV = CONSTANTBV::BitVector_Create(shift.getWidth(), true);

      setUnsignedMinMax(shift, minCBV, maxCBV);

      BEEV::CBV maxValue = CONSTANTBV::BitVector_Create(shift.getWidth(), true);
      for (unsigned i = 0; i < sizeof(unsigned) * 8; i++)
        CONSTANTBV::BitVector_Bit_On(maxValue, i);

      if (unsignedCompare(minCBV, maxValue) > 0)
        {
          minShift = UINT_MAX;
        }
      else
        {
          minShift = cbvTOInt(minCBV);
        }

      if (unsignedCompare(maxCBV, maxValue) > 0)
        {
          maxShift = UINT_MAX;
        }
      else
        {
          maxShift = cbvTOInt(maxCBV);
        }

      CONSTANTBV::BitVector_Destroy(maxValue);
      CONSTANTBV::BitVector_Destroy(minCBV);
      CONSTANTBV::BitVector_Destroy(maxCBV);
    }

    bool
    FixedBits::equals(const FixedBits& a, const FixedBits& b, const int upTo)
    {
      assert (a.getWidth() >= upTo);
      assert (b.getWidth() >= upTo);

      for (int i = 0; i < upTo; i++)
        {
          if (a.isFixed(i) != b.isFixed(i))
            {
              return false;
            }
          if (a.isFixed(i))
            if (a.getValue(i) != b.getValue(i))
              return false;
        }
      return true;
    }

    bool
    FixedBits::equals(const FixedBits& a, const FixedBits& b)
    {
      if (a.getWidth() != b.getWidth())
        return false;

      for (int i = 0; i < a.getWidth(); i++)
        {
          if (a.isFixed(i) != b.isFixed(i))
            {
              return false;
            }
          if (a.isFixed(i))
            if (a.getValue(i) != b.getValue(i))
              return false;
        }
      return true;
    }
  }
}
<commit_msg>A fixed version r1547. I missed a bound.<commit_after>#include "../../AST/AST.h"
#include "FixedBits.h"

#include "ConstantBitP_Utility.h"

// To reduce the memory I tried using the constantbv stuff. But because it is not
// inlined it took about twice as long per propagation as does using a boolean array.
// Other options to reduce memory usage are: vector<bool>, dynamic_bitset, or bitMagic.

namespace simplifier
{
  namespace constantBitP
  {

    std::ostream&
    operator<<(std::ostream& output, const FixedBits& h)
    {
      output << "<";
      for (int i = h.getWidth() - 1; i >= 0; i--)
        {
          if (h.isFixed(i))
            output << h.getValue(i);
          else
            output << "-";
        }

      output << ">";

      return output;
    }

    void
    FixedBits::fixToZero()
    {
      for (int i = 0; i < getWidth(); i++)
        {
          setFixed(i, true);
          setValue(i, false);
        }
    }

    BEEV::CBV
    FixedBits::GetBVConst() const
    {
      assert(isTotallyFixed());

      BEEV::CBV result = CONSTANTBV::BitVector_Create(width, true);

      for (int i = 0; i < width; i++)
        {
          if (values[i])
            CONSTANTBV::BitVector_Bit_On(result, i);
        }

      return result;
    }

    //inclusive
    BEEV::CBV
    FixedBits::GetBVConst(int to, int from) const
    {
      assert(to>=from);
      assert(from >=0);
      int resultWidth = to - from + 1;

      BEEV::CBV result = CONSTANTBV::BitVector_Create(resultWidth, true);

      for (int i = from; i <= to; i++)
        {
          if (getValue(i))
            CONSTANTBV::BitVector_Bit_On(result, i - from);
        }

      return result;
    }

    void
    FixedBits::init(const FixedBits& copy)
    {
      width = copy.width;
      fixed = new bool[width];
      values = new bool[width];
      representsBoolean = copy.representsBoolean;

      memcpy(fixed, copy.fixed, width * sizeof(bool));
      memcpy(values, copy.values, width * sizeof(bool));
    }

    bool
    FixedBits::isTotallyFixed() const
    {
      for (int i = 0; i < width; i++)
        {
          if (!fixed[i])
            return false;
        }

      return true;
    }

    FixedBits::FixedBits(int n, bool isbool)
    {
      assert(n > 0);

      fixed = new bool[n];
      values = new bool[n];
      width = n;

      for (int i = 0; i < width; i++)
        {
          fixed[i] = false; // I don't know if there's a default value??
          values[i] = false; // stops it printing out junk.
        }

      representsBoolean = isbool;
      if (isbool)
        assert(1 == width);

      uniqueId = staticUniqueId++;
    }

    // There is no way to represent bottom. So we assume a and b are already at least
    // one step up the lattice.
    FixedBits
    FixedBits::meet(const FixedBits& a, const FixedBits& b)
    {
      assert(a.getWidth() == b.getWidth());
      assert(a.isBoolean() == b.isBoolean());

      FixedBits result(a.getWidth(), a.isBoolean());

      for (int i = 0; i < a.getWidth(); i++)
        {
          if (a.isFixed(i) != b.isFixed(i))
            {
              result.setFixed(i, false);
            }
          else if (a.isFixed(i) && b.isFixed(i) && (a.getValue(i)
              != b.getValue(i)))
            {
              result.setFixed(i, false);
            }
          else if (a.isFixed(i) && b.isFixed(i))
            { // fixed to the same value.
              result.setFixed(i, true);
              result.setValue(i, a.getValue(i));
            }
        }
      return result;
    }

#if 0
    #include "MersenneTwister.h"

    // Getting a new random number is expensive. Not sure why.
    FixedBits FixedBits::createRandom(const int length, const int probabilityOfSetting, MTRand& trand)
      {
        assert( 0 <= probabilityOfSetting);
        assert( 100 >= probabilityOfSetting);

        FixedBits result(length, false);

        // I'm not sure if the random number generator is generating just 32 bit numbers??
        int i = 0;
        int randomV = trand.randInt();

        int pool = 32;

        while (i < length)
          {
            if (pool < 8)
              {
                randomV = trand.randInt();
                pool = 32;
              }

            int val = (randomV & 127);
            randomV >>= 7;
            pool = pool - 7;

            if (val >= 100)
            continue;

            if (val < probabilityOfSetting)
              {
                switch (randomV & 1)
                  {
                    case 0:
                    result.setFixed(i, true);
                    result.setValue(i, false);
                    break;
                    case 1:
                    result.setFixed(i, true);
                    result.setValue(i, true);
                    break;
                    default:
                    BEEV::FatalError(LOCATION "never.");

                  }
                randomV >>= 1;
              }
            i++;

          }
        return result;
      }
#endif

    // In the world of static analysis this is ALPHA.
    FixedBits
    FixedBits::concreteToAbstract(const BEEV::ASTNode& n)
    {
      //cout << n;

      int bitWidth;
      if (BEEV::BITVECTOR_TYPE == n.GetType())
        bitWidth = n.GetValueWidth();
      else
        bitWidth = 1;

      FixedBits output(bitWidth, BEEV::BOOLEAN_TYPE == n.GetType());

      if (BEEV::BITVECTOR_TYPE == n.GetType())
        {
          // loop through testing each of the bits.
          BEEV::CBV cbv = n.GetBVConst();

          for (int j = 0; j < bitWidth; j++)
            {
              output.setFixed(j, true);
              output.setValue(j, CONSTANTBV::BitVector_bit_test(cbv, j));
            }
        }
      else
        {
          if (n.GetKind() == BEEV::TRUE)
            {
              output.setFixed(0, true);
              output.setValue(0, true);
            }
          else if (n.GetKind() == BEEV::FALSE)
            {
              output.setFixed(0, true);
              output.setValue(0, false);
            }
          else
            BEEV::FatalError("Unexpected", n);
        }
      return output;
    }

    FixedBits
    FixedBits::fromUnsignedInt(int width, unsigned val)
    {
      FixedBits output(width, false);

      const unsigned maxWidth = std::max((int) sizeof(unsigned) * 8, width);
      for (unsigned i = 0; i < maxWidth; i++)
        {
          if (i < (unsigned) width && i < sizeof(unsigned) * 8)
            {
              output.setFixed(i, true);
              output.setValue(i, (val & (1 << i)));
            }
          else if (i < (unsigned) width)
            {
              output.setFixed(i, true);
              output.setValue(i, false);

            }
          else // The unsigned value is bigger than the bitwidth of this.
            { // so it can't be represented.
              if (val & (1 << i))
                {
                  BEEV::FatalError(LOCATION "Cant be represented.");
                }
            }
        }
      return output;
    }

    int
    FixedBits::getUnsignedValue() const
    {
      assert(isTotallyFixed());
      assert(getWidth() <= 32);
      int result = 0;

      for (int i = 0; i < width; i++)
        {
          if (getValue(i))
            result += (1 << i);
        }
      return result;
    }

    bool
    FixedBits::updateOK(const FixedBits& o, const FixedBits &n, const int upTo)
    {
      assert (n.getWidth() >= upTo);
      assert (o.getWidth() >= upTo);

      for (int i = 0; i < upTo; i++)
        {
          if (n.isFixed(i) && o.isFixed(i))
            {
              if (n.getValue(i) != o.getValue(i))
                {
                  return false;
                }
            }
          else if (o.isFixed(i) && !n.isFixed(i))
            {
              return false;
            }
        }
      return true;
    }

    // If the oldBits can't become the new bits. While respecting the lattice rules. That's bad.
    // For example. A transfer function shouldn't unfix bits. Or chance the fixed bits value.
    bool
    FixedBits::updateOK(const FixedBits& o, const FixedBits &n)
    {
      if (n.getWidth() != o.getWidth())
        return false;

      for (int i = 0; i < n.getWidth(); i++)
        {
          if (n.isFixed(i) && o.isFixed(i))
            {
              if (n.getValue(i) != o.getValue(i))
                {
                  return false;
                }
            }
          else if (o.isFixed(i) && !n.isFixed(i))
            {
              return false;
            }
        }
      return true;
    }

    // a is "IN" b.
    bool
    FixedBits::in(const FixedBits& a, const FixedBits& b)
    {
      assert(a.getWidth() == b.getWidth());

      for (int i = 0; i < a.getWidth(); i++)
        {
          if (a.isFixed(i) && b.isFixed(i) && (a.getValue(i) != b.getValue(i)))
            {
              return false;
            }
          if (!a.isFixed(i) && b.isFixed(i))
            return false;
        }
      return true;
    }

    // Gets the minimum and maximum unsigned values that are held in the current
    // set. It saturates to UINT_MAX.
    void
    FixedBits::getUnsignedMinMax(unsigned &minShift, unsigned &maxShift) const
    {
      const int bitWidth = this->getWidth();
      int unsignedBW = sizeof(unsigned)*8;

      minShift = 0;
      maxShift = 0;

      bool bigMax = false;
      bool bigMin = false;

      for (int i = unsignedBW; i < bitWidth; i++)
        {
        if  ((*this)[i] == '1' || (*this)[i] == '*')
          bigMax = true;

         if ((*this)[i] == '1')
          bigMin = true;
        }

      for (int i = 0; i < std::min(unsignedBW,bitWidth); i++)
        {
          if ((*this)[i] == '1')
            {
              minShift |= (1 <<i);
              maxShift |= (1 <<i);
            }
          else if ((*this)[i] == '*')
            {
              maxShift |= (1 <<i);
            }
        }

      if (bigMax)
        maxShift = UINT_MAX;

      if (bigMin)
        minShift = UINT_MAX;
    }

    bool
    FixedBits::equals(const FixedBits& a, const FixedBits& b, const int upTo)
    {
      assert (a.getWidth() >= upTo);
      assert (b.getWidth() >= upTo);

      for (int i = 0; i < upTo; i++)
        {
          if (a.isFixed(i) != b.isFixed(i))
            {
              return false;
            }
          if (a.isFixed(i))
            if (a.getValue(i) != b.getValue(i))
              return false;
        }
      return true;
    }

    bool
    FixedBits::equals(const FixedBits& a, const FixedBits& b)
    {
      if (a.getWidth() != b.getWidth())
        return false;

      for (int i = 0; i < a.getWidth(); i++)
        {
          if (a.isFixed(i) != b.isFixed(i))
            {
              return false;
            }
          if (a.isFixed(i))
            if (a.getValue(i) != b.getValue(i))
              return false;
        }
      return true;
    }
  }
}
<|endoftext|>


<commit_before>#include "openMVG/sfm/sfm.hpp"
#include "openMVG/image/image.hpp"
#include "openMVG/image/image_converter.hpp"
#include <openMVG/config.hpp>

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/progress/progress.hpp"

#include <stdlib.h>
#include <stdio.h>
#include <cmath>
#include <iterator>
#include <iomanip>

using namespace openMVG;
using namespace openMVG::cameras;
using namespace openMVG::geometry;
using namespace openMVG::image;
using namespace openMVG::sfm;

class point2d
{
public:
  point2d()
  : x(0), y(0)
  {}

    union {
        struct
        {
            float x, y;
        };
        float m[2];
    };
};

class point3d
{
public:
  point3d()
  : x(0), y(0), z(0)
  {}

    union {
        struct
        {
            float x, y, z;
        };
        float m[3];
    };
};

struct orientedPoint
{
    point3d p; // 3 * float : 3 * 4 = 12 Bytes : (one float is 4 Bytes : 3.4E +/- 38 (7 digits) )
    point3d n; // 2 * float : 2 * 4 = 8  Bytes
    float sim = 0; // 4-Bytes : 3.4E +/- 38 (7 digits)
    // TOTAL: 12 + 8 + 4 = 24 Bytes
};

struct seed_io_block
{
    orientedPoint op;       // 28 bytes
    point3d xax;            // 12 bytes
    point3d yax;            // 12 bytes
    float pixSize;          // 4 bytes
    uint64_t area;          // 8 bytes
    uint64_t segId;         // 8 bytes
    unsigned short ncams;   // 2 bytes
    unsigned short padding[3];
};

struct Seed
{
    seed_io_block s;
    unsigned short camId = 0;
    point2d shift0;
    point2d shift1;
};

typedef std::vector<Seed> SeedVector;
typedef stl::flat_map< size_t, SeedVector> SeedsPerView;

void retrieveSeedsPerView(
    const SfM_Data & sfm_data,
    const Hash_Map<IndexT, IndexT> map_viewIdToContiguous,
    SeedsPerView& outSeedsPerView)
{
  static const double minAngle = 3.0;
  for(const auto& s: sfm_data.structure)
  {
    const IndexT landmarkId = s.first;
    const Landmark& landmark = s.second;
    // For each observation of a 3D landmark, we will export
    // all other observations with an angle > minAngle.
    for(const auto& obsA: landmark.observations)
    {
      const auto& obsACamId_it = map_viewIdToContiguous.find(obsA.first);
      if(obsACamId_it == map_viewIdToContiguous.end())
        continue; // this view cannot be exported to cmpmvs, so we skip the observation
      int obsACamId = obsACamId_it->second;
      const View& viewA = *sfm_data.GetViews().at(obsA.first).get();
      const geometry::Pose3& poseA = sfm_data.GetPoses().at(viewA.id_pose);
      const Pinhole_Intrinsic * intrinsicsA = dynamic_cast<const Pinhole_Intrinsic*>(sfm_data.GetIntrinsics().at(viewA.id_intrinsic).get());

      for(const auto& obsB: landmark.observations)
      {
        // don't export itself
        if(obsA.first == obsB.first)
          continue;
        const auto& obsBCamId_it = map_viewIdToContiguous.find(obsB.first);
        if(obsBCamId_it == map_viewIdToContiguous.end())
          continue; // this view cannot be exported to cmpmvs, so we skip the observation
        const View& viewB = *sfm_data.GetViews().at(obsB.first).get();
        const geometry::Pose3& poseB = sfm_data.GetPoses().at(viewB.id_pose);
        const Pinhole_Intrinsic * intrinsicsB = dynamic_cast<const Pinhole_Intrinsic*>(sfm_data.GetIntrinsics().at(viewB.id_intrinsic).get());

        const double angle = AngleBetweenRay(
          poseA, intrinsicsA, poseB, intrinsicsB, obsA.second.x, obsB.second.x);

        if(angle < minAngle)
          continue;

        Seed seed;
        seed.camId = obsBCamId_it->second - 1; // Get 0-based index this time
        seed.s.ncams = 1;
        seed.s.segId = landmarkId;
        seed.s.op.p.x = landmark.X(0);
        seed.s.op.p.y = landmark.X(1);
        seed.s.op.p.z = landmark.X(2);

        outSeedsPerView[obsACamId].push_back(seed);
      }
    }
  }
}

std::string replaceAll( std::string const& original, std::string const& from, std::string const& to )
{
    std::string results;
    std::string::const_iterator end = original.end();
    std::string::const_iterator current = original.begin();
    std::string::const_iterator next = std::search( current, end, from.begin(), from.end() );
    while ( next != end ) {
        results.append( current, next );
        results.append( to );
        current = next + from.size();
        next = std::search( current, end, from.begin(), from.end() );
    }
    results.append( current, next );
    return results;
}

bool exportToCMPMVS2Format(
  const SfM_Data & sfm_data,
  int scale,
  const std::string & sOutDirectory // Output CMPMVS files directory
  )
{
  // Create basis directory structure
  if (!stlplus::is_folder(sOutDirectory))
  {
    stlplus::folder_create(sOutDirectory);
    bool bOk = stlplus::is_folder(sOutDirectory);
    if (!bOk)
    {
      std::cerr << "Cannot access the output directory: " << sOutDirectory << std::endl;
      return false;
    }
  }

  // Since CMPMVS requires contiguous camera indexes and some views may not have a pose,
  // we reindex the poses to ensure a contiguous pose list.
  Hash_Map<IndexT, IndexT> map_viewIdToContiguous;
  // Export valid views as Projective Cameras:
  for(const auto &iter : sfm_data.GetViews())
  {
    const View * view = iter.second.get();
    if (!sfm_data.IsPoseAndIntrinsicDefined(view))
      continue;
    Intrinsics::const_iterator iterIntrinsic = sfm_data.GetIntrinsics().find(view->id_intrinsic);
    const IntrinsicBase * cam = iterIntrinsic->second.get();
    // View Id re-indexing
    // Need to start at 1 for CMPMVS
    map_viewIdToContiguous.insert(std::make_pair(view->id_view, map_viewIdToContiguous.size() + 1));
  }

  SeedsPerView seedsPerView;
  retrieveSeedsPerView(sfm_data, map_viewIdToContiguous, seedsPerView);

  // Export data
  C_Progress_display my_progress_bar(map_viewIdToContiguous.size(),
                                     std::cout, "\n- Exporting Data -\n");

  // Export views:
  //   - 00001_P.txt (Pose of the reconstructed camera)
  //   - 00001._c.png (undistorted & scaled colored image)
  //   - 00001_seeds.bin (3d points visible in this image)
  #pragma omp parallel for num_threads(3)
  for(int i = 0; i < map_viewIdToContiguous.size(); ++i)
  {
    auto viewIdToContiguous = map_viewIdToContiguous.cbegin();
    std::advance(viewIdToContiguous, i);
    IndexT viewId = viewIdToContiguous->first;
    const View * view = sfm_data.GetViews().at(viewId).get();
    assert(view->id_view == viewId);
    IndexT contiguousViewIndex = map_viewIdToContiguous[view->id_view];
    Intrinsics::const_iterator iterIntrinsic = sfm_data.GetIntrinsics().find(view->id_intrinsic);
    // We have a valid view with a corresponding camera & pose
    assert(map_viewIdToContiguous[view->id_view] == i + 1);

    std::ostringstream baseFilenameSS;
    baseFilenameSS << std::setw(5) << std::setfill('0') << contiguousViewIndex;
    const std::string baseFilename = baseFilenameSS.str();

    // Export camera pose
    {
      const Pose3 pose = sfm_data.GetPoseOrDie(view);
      Mat34 P = iterIntrinsic->second.get()->get_projective_equivalent(pose);
      std::ofstream file(
        stlplus::create_filespec(stlplus::folder_append_separator(sOutDirectory),
        baseFilename + "_P", "txt").c_str());
      file << std::setprecision(10)
           << P(0, 0) / (double)scale << " " << P(0, 1) / (double)scale << " "  << P(0, 2) / (double)scale << " "  << P(0, 3) / (double)scale << "\n"
           << P(1, 0) / (double)scale << " " << P(1, 1) / (double)scale << " "  << P(1, 2) / (double)scale << " "  << P(1, 3) / (double)scale << "\n"
           << P(2, 0) << " " << P(2, 1) << " "  << P(2, 2) << " "  << P(2, 3) << "\n";
      file.close();
    }

    // Export undistort image
    {
      const std::string srcImage = stlplus::create_filespec(sfm_data.s_root_path, view->s_Img_path);

      std::string dstColorImage = stlplus::create_filespec(
        stlplus::folder_append_separator(sOutDirectory), baseFilename + "._c", "png");

      const IntrinsicBase * cam = iterIntrinsic->second.get();
      Image<RGBColor> image;
      ReadImage(srcImage.c_str(), &image);

      // Undistort
      Image<RGBColor> image_ud;
      if (cam->isValid() && cam->have_disto())
      {
        // undistort the image and save it
        UndistortImage(image, cam, image_ud, BLACK);
      }
      else
      {
        image_ud = image;
      }

      // Rescale
      Image<RGBColor> image_ud_scaled;
      if(scale == 1)
      {
        image_ud_scaled = image_ud;
      }
      else if(scale == 2)
      {
        ImageHalfSample(image_ud, image_ud_scaled);
      }
      else if(scale == 4)
      {
        ImageHalfSample(image_ud, image_ud_scaled); // 2
        image_ud = image_ud_scaled;
        ImageHalfSample(image_ud, image_ud_scaled); // 4
      }
      else if(scale == 8)
      {
        ImageHalfSample(image_ud, image_ud_scaled); // 2
        ImageHalfSample(image_ud_scaled, image_ud); // 4
        ImageHalfSample(image_ud, image_ud_scaled); // 8
      }
      else if(scale == 16)
      {
        ImageHalfSample(image_ud, image_ud_scaled); // 2
        ImageHalfSample(image_ud_scaled, image_ud); // 4
        ImageHalfSample(image_ud, image_ud_scaled); // 8
        image_ud = image_ud_scaled;
        ImageHalfSample(image_ud, image_ud_scaled); // 16
      }
      else
      {
        std::cerr << "Rescale not implemented." << std::endl;
        image_ud_scaled = image_ud;
      }
      WriteImage(dstColorImage.c_str(), image_ud_scaled);
    }

    // Export Seeds
    {
      const std::string seedsFilepath = stlplus::create_filespec(
        stlplus::folder_append_separator(sOutDirectory), baseFilename + "_seeds", "bin");
      std::ofstream seedsFile(seedsFilepath, std::ios::binary);

      const int nbSeeds = seedsPerView[contiguousViewIndex].size();
      seedsFile.write((char*)&nbSeeds, sizeof(int));

      for(const Seed& seed: seedsPerView[contiguousViewIndex])
      {
        seedsFile.write((char*)&seed, sizeof(seed_io_block) + sizeof(unsigned short) + 2 * sizeof(point2d)); //sizeof(Seed));
      }
      seedsFile.close();
    }
   #pragma omp critical
    ++my_progress_bar;
  }

  // Write the cmpmvs ini file
  std::ostringstream os;
  os << "[global]" << os.widen('\n')
  << "outDir=\"../../meshes\"" << os.widen('\n')
  << "ncams=" << map_viewIdToContiguous.size() << os.widen('\n')
  << "scale=" << scale << os.widen('\n')
  << "verbose=TRUE" << os.widen('\n')
  << os.widen('\n')

  << "#EOF" << os.widen('\n')
  << os.widen('\n')
  << os.widen('\n');

  std::ofstream file2(
    stlplus::create_filespec(stlplus::folder_append_separator(sOutDirectory),
    "mvs", "ini").c_str());
  file2 << os.str();
  file2.close();

  return true;
}

int main(int argc, char *argv[])
{
  CmdLine cmd;
  std::string sSfM_Data_Filename;
  int scale = 2;
  std::string sOutDir = "";

  cmd.add( make_option('i', sSfM_Data_Filename, "sfmdata") );
  cmd.add( make_option('s', scale, "scale") );
  cmd.add( make_option('o', sOutDir, "outdir") );

  try {
      if (argc == 1) throw std::string("Invalid command line parameter.");
      cmd.process(argc, argv);
  } catch(const std::string& s) {
      std::cerr << "Usage: " << argv[0] << '\n'
      << "[-i|--sfmdata] filename, the SfM_Data file to convert\n"
      << "[-s|--scale] downscale image factor\n"
      << "[-o|--outdir] path\n"
      << std::endl;

      std::cerr << s << std::endl;
      return EXIT_FAILURE;
  }

  sOutDir = stlplus::folder_to_path(sOutDir);

  // Create output dir
  if (!stlplus::folder_exists(sOutDir))
    stlplus::folder_create( sOutDir );

  // Read the input SfM scene
  SfM_Data sfm_data;
  if (!Load(sfm_data, sSfM_Data_Filename, ESfM_Data(ALL)))
  {
    std::cerr << std::endl
      << "The input SfM_Data file \""<< sSfM_Data_Filename << "\" cannot be read." << std::endl;
    return EXIT_FAILURE;
  }

  if (!exportToCMPMVS2Format(sfm_data, scale, stlplus::filespec_to_path(sOutDir, "_tmp_scale" + std::to_string(scale))))
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}
<commit_msg>[software] Avoid useless quotes in CMPMVS export<commit_after>#include "openMVG/sfm/sfm.hpp"
#include "openMVG/image/image.hpp"
#include "openMVG/image/image_converter.hpp"
#include <openMVG/config.hpp>

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/progress/progress.hpp"

#include <stdlib.h>
#include <stdio.h>
#include <cmath>
#include <iterator>
#include <iomanip>

using namespace openMVG;
using namespace openMVG::cameras;
using namespace openMVG::geometry;
using namespace openMVG::image;
using namespace openMVG::sfm;

class point2d
{
public:
  point2d()
  : x(0), y(0)
  {}

    union {
        struct
        {
            float x, y;
        };
        float m[2];
    };
};

class point3d
{
public:
  point3d()
  : x(0), y(0), z(0)
  {}

    union {
        struct
        {
            float x, y, z;
        };
        float m[3];
    };
};

struct orientedPoint
{
    point3d p; // 3 * float : 3 * 4 = 12 Bytes : (one float is 4 Bytes : 3.4E +/- 38 (7 digits) )
    point3d n; // 2 * float : 2 * 4 = 8  Bytes
    float sim = 0; // 4-Bytes : 3.4E +/- 38 (7 digits)
    // TOTAL: 12 + 8 + 4 = 24 Bytes
};

struct seed_io_block
{
    orientedPoint op;       // 28 bytes
    point3d xax;            // 12 bytes
    point3d yax;            // 12 bytes
    float pixSize;          // 4 bytes
    uint64_t area;          // 8 bytes
    uint64_t segId;         // 8 bytes
    unsigned short ncams;   // 2 bytes
    unsigned short padding[3];
};

struct Seed
{
    seed_io_block s;
    unsigned short camId = 0;
    point2d shift0;
    point2d shift1;
};

typedef std::vector<Seed> SeedVector;
typedef stl::flat_map< size_t, SeedVector> SeedsPerView;

void retrieveSeedsPerView(
    const SfM_Data & sfm_data,
    const Hash_Map<IndexT, IndexT> map_viewIdToContiguous,
    SeedsPerView& outSeedsPerView)
{
  static const double minAngle = 3.0;
  for(const auto& s: sfm_data.structure)
  {
    const IndexT landmarkId = s.first;
    const Landmark& landmark = s.second;
    // For each observation of a 3D landmark, we will export
    // all other observations with an angle > minAngle.
    for(const auto& obsA: landmark.observations)
    {
      const auto& obsACamId_it = map_viewIdToContiguous.find(obsA.first);
      if(obsACamId_it == map_viewIdToContiguous.end())
        continue; // this view cannot be exported to cmpmvs, so we skip the observation
      int obsACamId = obsACamId_it->second;
      const View& viewA = *sfm_data.GetViews().at(obsA.first).get();
      const geometry::Pose3& poseA = sfm_data.GetPoses().at(viewA.id_pose);
      const Pinhole_Intrinsic * intrinsicsA = dynamic_cast<const Pinhole_Intrinsic*>(sfm_data.GetIntrinsics().at(viewA.id_intrinsic).get());

      for(const auto& obsB: landmark.observations)
      {
        // don't export itself
        if(obsA.first == obsB.first)
          continue;
        const auto& obsBCamId_it = map_viewIdToContiguous.find(obsB.first);
        if(obsBCamId_it == map_viewIdToContiguous.end())
          continue; // this view cannot be exported to cmpmvs, so we skip the observation
        const View& viewB = *sfm_data.GetViews().at(obsB.first).get();
        const geometry::Pose3& poseB = sfm_data.GetPoses().at(viewB.id_pose);
        const Pinhole_Intrinsic * intrinsicsB = dynamic_cast<const Pinhole_Intrinsic*>(sfm_data.GetIntrinsics().at(viewB.id_intrinsic).get());

        const double angle = AngleBetweenRay(
          poseA, intrinsicsA, poseB, intrinsicsB, obsA.second.x, obsB.second.x);

        if(angle < minAngle)
          continue;

        Seed seed;
        seed.camId = obsBCamId_it->second - 1; // Get 0-based index this time
        seed.s.ncams = 1;
        seed.s.segId = landmarkId;
        seed.s.op.p.x = landmark.X(0);
        seed.s.op.p.y = landmark.X(1);
        seed.s.op.p.z = landmark.X(2);

        outSeedsPerView[obsACamId].push_back(seed);
      }
    }
  }
}

std::string replaceAll( std::string const& original, std::string const& from, std::string const& to )
{
    std::string results;
    std::string::const_iterator end = original.end();
    std::string::const_iterator current = original.begin();
    std::string::const_iterator next = std::search( current, end, from.begin(), from.end() );
    while ( next != end ) {
        results.append( current, next );
        results.append( to );
        current = next + from.size();
        next = std::search( current, end, from.begin(), from.end() );
    }
    results.append( current, next );
    return results;
}

bool exportToCMPMVS2Format(
  const SfM_Data & sfm_data,
  int scale,
  const std::string & sOutDirectory // Output CMPMVS files directory
  )
{
  // Create basis directory structure
  if (!stlplus::is_folder(sOutDirectory))
  {
    stlplus::folder_create(sOutDirectory);
    bool bOk = stlplus::is_folder(sOutDirectory);
    if (!bOk)
    {
      std::cerr << "Cannot access the output directory: " << sOutDirectory << std::endl;
      return false;
    }
  }

  // Since CMPMVS requires contiguous camera indexes and some views may not have a pose,
  // we reindex the poses to ensure a contiguous pose list.
  Hash_Map<IndexT, IndexT> map_viewIdToContiguous;
  // Export valid views as Projective Cameras:
  for(const auto &iter : sfm_data.GetViews())
  {
    const View * view = iter.second.get();
    if (!sfm_data.IsPoseAndIntrinsicDefined(view))
      continue;
    Intrinsics::const_iterator iterIntrinsic = sfm_data.GetIntrinsics().find(view->id_intrinsic);
    const IntrinsicBase * cam = iterIntrinsic->second.get();
    // View Id re-indexing
    // Need to start at 1 for CMPMVS
    map_viewIdToContiguous.insert(std::make_pair(view->id_view, map_viewIdToContiguous.size() + 1));
  }

  SeedsPerView seedsPerView;
  retrieveSeedsPerView(sfm_data, map_viewIdToContiguous, seedsPerView);

  // Export data
  C_Progress_display my_progress_bar(map_viewIdToContiguous.size(),
                                     std::cout, "\n- Exporting Data -\n");

  // Export views:
  //   - 00001_P.txt (Pose of the reconstructed camera)
  //   - 00001._c.png (undistorted & scaled colored image)
  //   - 00001_seeds.bin (3d points visible in this image)
  #pragma omp parallel for num_threads(3)
  for(int i = 0; i < map_viewIdToContiguous.size(); ++i)
  {
    auto viewIdToContiguous = map_viewIdToContiguous.cbegin();
    std::advance(viewIdToContiguous, i);
    IndexT viewId = viewIdToContiguous->first;
    const View * view = sfm_data.GetViews().at(viewId).get();
    assert(view->id_view == viewId);
    IndexT contiguousViewIndex = map_viewIdToContiguous[view->id_view];
    Intrinsics::const_iterator iterIntrinsic = sfm_data.GetIntrinsics().find(view->id_intrinsic);
    // We have a valid view with a corresponding camera & pose
    assert(map_viewIdToContiguous[view->id_view] == i + 1);

    std::ostringstream baseFilenameSS;
    baseFilenameSS << std::setw(5) << std::setfill('0') << contiguousViewIndex;
    const std::string baseFilename = baseFilenameSS.str();

    // Export camera pose
    {
      const Pose3 pose = sfm_data.GetPoseOrDie(view);
      Mat34 P = iterIntrinsic->second.get()->get_projective_equivalent(pose);
      std::ofstream file(
        stlplus::create_filespec(stlplus::folder_append_separator(sOutDirectory),
        baseFilename + "_P", "txt").c_str());
      file << std::setprecision(10)
           << P(0, 0) / (double)scale << " " << P(0, 1) / (double)scale << " "  << P(0, 2) / (double)scale << " "  << P(0, 3) / (double)scale << "\n"
           << P(1, 0) / (double)scale << " " << P(1, 1) / (double)scale << " "  << P(1, 2) / (double)scale << " "  << P(1, 3) / (double)scale << "\n"
           << P(2, 0) << " " << P(2, 1) << " "  << P(2, 2) << " "  << P(2, 3) << "\n";
      file.close();
    }

    // Export undistort image
    {
      const std::string srcImage = stlplus::create_filespec(sfm_data.s_root_path, view->s_Img_path);

      std::string dstColorImage = stlplus::create_filespec(
        stlplus::folder_append_separator(sOutDirectory), baseFilename + "._c", "png");

      const IntrinsicBase * cam = iterIntrinsic->second.get();
      Image<RGBColor> image;
      ReadImage(srcImage.c_str(), &image);

      // Undistort
      Image<RGBColor> image_ud;
      if (cam->isValid() && cam->have_disto())
      {
        // undistort the image and save it
        UndistortImage(image, cam, image_ud, BLACK);
      }
      else
      {
        image_ud = image;
      }

      // Rescale
      Image<RGBColor> image_ud_scaled;
      if(scale == 1)
      {
        image_ud_scaled = image_ud;
      }
      else if(scale == 2)
      {
        ImageHalfSample(image_ud, image_ud_scaled);
      }
      else if(scale == 4)
      {
        ImageHalfSample(image_ud, image_ud_scaled); // 2
        image_ud = image_ud_scaled;
        ImageHalfSample(image_ud, image_ud_scaled); // 4
      }
      else if(scale == 8)
      {
        ImageHalfSample(image_ud, image_ud_scaled); // 2
        ImageHalfSample(image_ud_scaled, image_ud); // 4
        ImageHalfSample(image_ud, image_ud_scaled); // 8
      }
      else if(scale == 16)
      {
        ImageHalfSample(image_ud, image_ud_scaled); // 2
        ImageHalfSample(image_ud_scaled, image_ud); // 4
        ImageHalfSample(image_ud, image_ud_scaled); // 8
        image_ud = image_ud_scaled;
        ImageHalfSample(image_ud, image_ud_scaled); // 16
      }
      else
      {
        std::cerr << "Rescale not implemented." << std::endl;
        image_ud_scaled = image_ud;
      }
      WriteImage(dstColorImage.c_str(), image_ud_scaled);
    }

    // Export Seeds
    {
      const std::string seedsFilepath = stlplus::create_filespec(
        stlplus::folder_append_separator(sOutDirectory), baseFilename + "_seeds", "bin");
      std::ofstream seedsFile(seedsFilepath, std::ios::binary);

      const int nbSeeds = seedsPerView[contiguousViewIndex].size();
      seedsFile.write((char*)&nbSeeds, sizeof(int));

      for(const Seed& seed: seedsPerView[contiguousViewIndex])
      {
        seedsFile.write((char*)&seed, sizeof(seed_io_block) + sizeof(unsigned short) + 2 * sizeof(point2d)); //sizeof(Seed));
      }
      seedsFile.close();
    }
   #pragma omp critical
    ++my_progress_bar;
  }

  // Write the cmpmvs ini file
  std::ostringstream os;
  os << "[global]" << os.widen('\n')
  << "outDir=../../meshes" << os.widen('\n')
  << "ncams=" << map_viewIdToContiguous.size() << os.widen('\n')
  << "scale=" << scale << os.widen('\n')
  << "verbose=TRUE" << os.widen('\n')
  << os.widen('\n')

  << "#EOF" << os.widen('\n')
  << os.widen('\n')
  << os.widen('\n');

  std::ofstream file2(
    stlplus::create_filespec(stlplus::folder_append_separator(sOutDirectory),
    "mvs", "ini").c_str());
  file2 << os.str();
  file2.close();

  return true;
}

int main(int argc, char *argv[])
{
  CmdLine cmd;
  std::string sSfM_Data_Filename;
  int scale = 2;
  std::string sOutDir = "";

  cmd.add( make_option('i', sSfM_Data_Filename, "sfmdata") );
  cmd.add( make_option('s', scale, "scale") );
  cmd.add( make_option('o', sOutDir, "outdir") );

  try {
      if (argc == 1) throw std::string("Invalid command line parameter.");
      cmd.process(argc, argv);
  } catch(const std::string& s) {
      std::cerr << "Usage: " << argv[0] << '\n'
      << "[-i|--sfmdata] filename, the SfM_Data file to convert\n"
      << "[-s|--scale] downscale image factor\n"
      << "[-o|--outdir] path\n"
      << std::endl;

      std::cerr << s << std::endl;
      return EXIT_FAILURE;
  }

  sOutDir = stlplus::folder_to_path(sOutDir);

  // Create output dir
  if (!stlplus::folder_exists(sOutDir))
    stlplus::folder_create( sOutDir );

  // Read the input SfM scene
  SfM_Data sfm_data;
  if (!Load(sfm_data, sSfM_Data_Filename, ESfM_Data(ALL)))
  {
    std::cerr << std::endl
      << "The input SfM_Data file \""<< sSfM_Data_Filename << "\" cannot be read." << std::endl;
    return EXIT_FAILURE;
  }

  if (!exportToCMPMVS2Format(sfm_data, scale, stlplus::filespec_to_path(sOutDir, "_tmp_scale" + std::to_string(scale))))
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of charge propagation module with transient behavior simulation
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "TransientPropagationModule.hpp"

#include <map>
#include <memory>
#include <random>
#include <string>
#include <utility>

#include <Eigen/Core>

#include "core/utils/log.h"
#include "objects/PixelCharge.hpp"
#include "tools/runge_kutta.h"

using namespace allpix;

TransientPropagationModule::TransientPropagationModule(Configuration& config,
                                                       Messenger* messenger,
                                                       std::shared_ptr<Detector> detector)
    : Module(config, detector), detector_(std::move(detector)), messenger_(messenger) {

    // Save detector model
    model_ = detector_->getModel();

    // Require deposits message for single detector:
    messenger_->bindSingle(this, &TransientPropagationModule::deposits_message_, MsgFlags::REQUIRED);

    // Seed the random generator with the module seed
    random_generator_.seed(getRandomSeed());

    // Set default value for config variables
    config_.setDefault<double>("timestep", Units::get(0.01, "ns"));
    config_.setDefault<double>("integration_time", Units::get(25, "ns"));
    config_.setDefault<unsigned int>("charge_per_step", 10);
    config_.setDefault<double>("temperature", 293.15);
    config_.setDefault<bool>("output_plots", false);

    // Copy some variables from configuration to avoid lookups:
    temperature_ = config_.get<double>("temperature");
    timestep_ = config_.get<double>("timestep");
    integration_time_ = config_.get<double>("integration_time");
    output_plots_ = config_.get<bool>("output_plots");

    // Parameterization variables from https://doi.org/10.1016/0038-1101(77)90054-5 (section 5.2)
    electron_Vm_ = Units::get(1.53e9 * std::pow(temperature_, -0.87), "cm/s");
    electron_Ec_ = Units::get(1.01 * std::pow(temperature_, 1.55), "V/cm");
    electron_Beta_ = 2.57e-2 * std::pow(temperature_, 0.66);

    hole_Vm_ = Units::get(1.62e8 * std::pow(temperature_, -0.52), "cm/s");
    hole_Ec_ = Units::get(1.24 * std::pow(temperature_, 1.68), "V/cm");
    hole_Beta_ = 0.46 * std::pow(temperature_, 0.17);

    boltzmann_kT_ = Units::get(8.6173e-5, "eV/K") * temperature_;
}

void TransientPropagationModule::init() {

    auto detector = getDetector();

    // Check for electric field
    if(!detector->hasElectricField()) {
        LOG(WARNING) << "This detector does not have an electric field.";
    }

    if(!detector_->hasWeightingPotential()) {
        throw ModuleError("This module requires a weighting potential.");
    }

    if(output_plots_) {
        induced_charge_histo_ = new TH1D("induced_charge_histo",
                                         "Induced charge per time;Drift time [ns];charge [e]",
                                         static_cast<int>(integration_time_ / timestep_),
                                         0,
                                         static_cast<double>(Units::convert(integration_time_, "ns")));
        induced_charge_e_histo_ = new TH1D("induced_charge_e_histo",
                                           "Induced charge per time;Drift time [ns];charge [e]",
                                           static_cast<int>(integration_time_ / timestep_),
                                           0,
                                           static_cast<double>(Units::convert(integration_time_, "ns")));
        induced_charge_h_histo_ = new TH1D("induced_charge_h_histo",
                                           "Induced charge per time;Drift time [ns];charge [e]",
                                           static_cast<int>(integration_time_ / timestep_),
                                           0,
                                           static_cast<double>(Units::convert(integration_time_, "ns")));
    }
}

void TransientPropagationModule::run(unsigned int) {

    // Create map for all pixels
    std::map<Pixel::Index, Pulse> pixel_map;

    // Loop over all deposits for propagation
    LOG(TRACE) << "Propagating charges in sensor";
    for(auto& deposit : deposits_message_->getData()) {

        // Loop over all charges in the deposit
        unsigned int charges_remaining = deposit.getCharge();

        LOG(DEBUG) << "Set of charge carriers (" << deposit.getType() << ") on "
                   << Units::display(deposit.getLocalPosition(), {"mm", "um"});

        auto charge_per_step = config_.get<unsigned int>("charge_per_step");
        while(charges_remaining > 0) {
            // Define number of charges to be propagated and remove charges of this step from the total
            if(charge_per_step > charges_remaining) {
                charge_per_step = charges_remaining;
            }
            charges_remaining -= charge_per_step;

            // Get position and propagate through sensor
            auto position = deposit.getLocalPosition();

            // Propagate a single charge deposit
            propagate(position, deposit.getType(), charge_per_step, pixel_map);
            LOG(DEBUG) << " Propagated " << charge_per_step << " from " << Units::display(position, {"mm", "um"});
        }
    }

    // Create vector of pixel pulses to return for this detector
    std::vector<PixelCharge> pixel_charges;
    for(auto& pixel_index_pulse : pixel_map) {
        pixel_charges.emplace_back(detector_->getPixel(pixel_index_pulse.first), std::move(pixel_index_pulse.second));
    }

    // Create a new message with pixel pulses
    auto pixel_charge_message = std::make_shared<PixelChargeMessage>(std::move(pixel_charges), detector_);

    // Dispatch the message with pixel charges
    messenger_->dispatchMessage(this, pixel_charge_message);
}

/**
 * Propagation is simulated using a parameterization for the electron mobility. This is used to calculate the electron
 * velocity at every point with help of the electric field map of the detector. A Runge-Kutta integration is applied in
 * multiple steps, adding a random diffusion to the propagating charge every step.
 */
void TransientPropagationModule::propagate(const ROOT::Math::XYZPoint& pos,
                                           const CarrierType& type,
                                           const unsigned int charge,
                                           std::map<Pixel::Index, Pulse>& pixel_map) {

    // Create a runge kutta solver using the electric field as step function
    Eigen::Vector3d position(pos.x(), pos.y(), pos.z());

    // Define a lambda function to compute the carrier mobility
    // NOTE This function is typically the most frequently executed part of the framework and therefore the bottleneck
    auto carrier_mobility = [&](double efield_mag) {
        // Compute carrier mobility from constants and electric field magnitude
        double numerator, denominator;
        if(type == CarrierType::ELECTRON) {
            numerator = electron_Vm_ / electron_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / electron_Ec_, electron_Beta_), 1.0 / electron_Beta_);
        } else {
            numerator = hole_Vm_ / hole_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / hole_Ec_, hole_Beta_), 1.0 / hole_Beta_);
        }
        return numerator / denominator;
    };

    // Define a function to compute the diffusion
    auto carrier_diffusion = [&](double efield_mag, double timestep) -> Eigen::Vector3d {
        double diffusion_constant = boltzmann_kT_ * carrier_mobility(efield_mag);
        double diffusion_std_dev = std::sqrt(2. * diffusion_constant * timestep);

        // Compute the independent diffusion in three
        std::normal_distribution<double> gauss_distribution(0, diffusion_std_dev);
        Eigen::Vector3d diffusion;
        for(int i = 0; i < 3; ++i) {
            diffusion[i] = gauss_distribution(random_generator_);
        }
        return diffusion;
    };

    // Define a lambda function to compute the electron velocity
    auto carrier_velocity = [&](double, Eigen::Vector3d cur_pos) -> Eigen::Vector3d {
        auto raw_field = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(cur_pos));
        // Compute the drift velocity
        Eigen::Vector3d efield(raw_field.x(), raw_field.y(), raw_field.z());

        return static_cast<int>(type) * carrier_mobility(efield.norm()) * efield;
    };

    // Create the runge kutta solver with an RKF5 tableau
    auto runge_kutta = make_runge_kutta(tableau::RK5, carrier_velocity, timestep_, position);

    // Continue propagation until the deposit is outside the sensor
    Eigen::Vector3d last_position = position;
    double last_time = 0;
    bool within_sensor = true;
    while(within_sensor && runge_kutta.getTime() < integration_time_) {

        // Save previous position and time
        last_position = position;
        last_time = runge_kutta.getTime();

        // Execute a Runge Kutta step
        runge_kutta.step();

        // Get the current result
        position = runge_kutta.getValue();

        // Get electric field at current position and fall back to empty field if it does not exist
        auto efield = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(position));

        // Apply diffusion step
        auto diffusion = carrier_diffusion(std::sqrt(efield.Mag2()), timestep_);
        position += diffusion;
        runge_kutta.setValue(position);

        // Check for overshooting outside the sensor and correct for it:
        if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
            LOG(TRACE) << "Found position outside: "
                       << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"});
            // FIXME this simply changes the z coordinate to be within the sensor - maybe we can be more clever
            if(model_->getSensorSize().z() / 2.0 - position.z() < 0) {
                position = Eigen::Vector3d(position.x(), position.y(), model_->getSensorSize().z() / 2.0 - 1e-9);
            } else if(position.z() - model_->getSensorSize().z() / 2.0 < 0) {
                position = Eigen::Vector3d(position.x(), position.y(), -model_->getSensorSize().z() / 2.0 + 1e-9);
            }
            LOG(TRACE) << "New position: " << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"});
            within_sensor = false;
        }

        // Find the nearest pixel
        auto xpixel = static_cast<int>(std::round(position.x() / model_->getPixelSize().x()));
        auto ypixel = static_cast<int>(std::round(position.y() / model_->getPixelSize().y()));
        LOG(TRACE) << "Moving carriers below pixel "
                   << Pixel::Index(static_cast<unsigned int>(xpixel), static_cast<unsigned int>(ypixel)) << " from "
                   << Units::display(static_cast<ROOT::Math::XYZPoint>(last_position), {"um", "mm"}) << " to "
                   << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"}) << ", "
                   << Units::display(runge_kutta.getTime(), "ns");

        // Loop over NxN pixels:
        for(int x = xpixel - 1; x <= xpixel + 1; x++) {
            for(int y = ypixel - 1; y <= ypixel + 1; y++) {
                // Ignore if out of pixel grid
                if(x < 0 || x >= model_->getNPixels().x() || y < 0 || y >= model_->getNPixels().y()) {
                    LOG(TRACE) << "Pixel (" << x << "," << y << ") skipped, outside the grid";
                    continue;
                }

                Pixel::Index pixel_index(static_cast<unsigned int>(x), static_cast<unsigned int>(y));
                auto ramo = detector_->getWeightingPotential(static_cast<ROOT::Math::XYZPoint>(position), pixel_index);
                auto last_ramo =
                    detector_->getWeightingPotential(static_cast<ROOT::Math::XYZPoint>(last_position), pixel_index);

                // Induced charge on electrode is q_int = q * (phi(x1) - phi(x0))
                auto induced = charge * (ramo - last_ramo) * (-static_cast<std::underlying_type<CarrierType>::type>(type));
                LOG(TRACE) << "Pixel " << pixel_index << " dPhi = " << (ramo - last_ramo) << ", induced " << type
                           << " q = " << Units::display(induced, "e");

                // Check if this pulse exists already:
                if(pixel_map.find(pixel_index) == pixel_map.end()) {
                    pixel_map[pixel_index] = Pulse(integration_time_, timestep_);
                }

                // Store induced charge in the respective pixel pulse:
                pixel_map[pixel_index].addCharge(induced, runge_kutta.getTime());

                if(output_plots_ && x == 0 && y == 0) {
                    induced_charge_histo_->Fill(runge_kutta.getTime(), induced);
                    if(type == CarrierType::ELECTRON) {
                        induced_charge_e_histo_->Fill(runge_kutta.getTime(), induced);
                    } else {
                        induced_charge_h_histo_->Fill(runge_kutta.getTime(), induced);
                    }
                }
            }
        }
    }

    // Find proper final position in the sensor
    auto time = runge_kutta.getTime();
    if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
        auto check_position = position;
        check_position.z() = last_position.z();
        if(position.z() > 0 && detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(check_position))) {
            // Carrier left sensor on the side of the pixel grid, interpolate end point on surface
            auto z_cur_border = std::fabs(position.z() - model_->getSensorSize().z() / 2.0);
            auto z_last_border = std::fabs(model_->getSensorSize().z() / 2.0 - last_position.z());
            auto z_total = z_cur_border + z_last_border;
            position = (z_last_border / z_total) * position + (z_cur_border / z_total) * last_position;
            time = (z_last_border / z_total) * time + (z_cur_border / z_total) * last_time;
        } else {
            // Carrier left sensor on any order border, use last position inside instead
            position = last_position;
            time = last_time;
        }
    }
    LOG(TRACE) << "Time: " << Units::display(time, {"ps", "ns"});
}

void TransientPropagationModule::finalize() {
    if(output_plots_) {
        induced_charge_histo_->Write();
        induced_charge_e_histo_->Write();
        induced_charge_h_histo_->Write();
    }
}
<commit_msg>TransientPropagation: adapted cuts to move carriers<commit_after>/**
 * @file
 * @brief Implementation of charge propagation module with transient behavior simulation
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "TransientPropagationModule.hpp"

#include <map>
#include <memory>
#include <random>
#include <string>
#include <utility>

#include <Eigen/Core>

#include "core/utils/log.h"
#include "objects/PixelCharge.hpp"
#include "tools/runge_kutta.h"

using namespace allpix;

TransientPropagationModule::TransientPropagationModule(Configuration& config,
                                                       Messenger* messenger,
                                                       std::shared_ptr<Detector> detector)
    : Module(config, detector), detector_(std::move(detector)), messenger_(messenger) {

    // Save detector model
    model_ = detector_->getModel();

    // Require deposits message for single detector:
    messenger_->bindSingle(this, &TransientPropagationModule::deposits_message_, MsgFlags::REQUIRED);

    // Seed the random generator with the module seed
    random_generator_.seed(getRandomSeed());

    // Set default value for config variables
    config_.setDefault<double>("timestep", Units::get(0.01, "ns"));
    config_.setDefault<double>("integration_time", Units::get(25, "ns"));
    config_.setDefault<unsigned int>("charge_per_step", 10);
    config_.setDefault<double>("temperature", 293.15);
    config_.setDefault<bool>("output_plots", false);

    // Copy some variables from configuration to avoid lookups:
    temperature_ = config_.get<double>("temperature");
    timestep_ = config_.get<double>("timestep");
    integration_time_ = config_.get<double>("integration_time");
    output_plots_ = config_.get<bool>("output_plots");

    // Parameterization variables from https://doi.org/10.1016/0038-1101(77)90054-5 (section 5.2)
    electron_Vm_ = Units::get(1.53e9 * std::pow(temperature_, -0.87), "cm/s");
    electron_Ec_ = Units::get(1.01 * std::pow(temperature_, 1.55), "V/cm");
    electron_Beta_ = 2.57e-2 * std::pow(temperature_, 0.66);

    hole_Vm_ = Units::get(1.62e8 * std::pow(temperature_, -0.52), "cm/s");
    hole_Ec_ = Units::get(1.24 * std::pow(temperature_, 1.68), "V/cm");
    hole_Beta_ = 0.46 * std::pow(temperature_, 0.17);

    boltzmann_kT_ = Units::get(8.6173e-5, "eV/K") * temperature_;
}

void TransientPropagationModule::init() {

    auto detector = getDetector();

    // Check for electric field
    if(!detector->hasElectricField()) {
        LOG(WARNING) << "This detector does not have an electric field.";
    }

    if(!detector_->hasWeightingPotential()) {
        throw ModuleError("This module requires a weighting potential.");
    }

    if(output_plots_) {
        induced_charge_histo_ = new TH1D("induced_charge_histo",
                                         "Induced charge per time;Drift time [ns];charge [e]",
                                         static_cast<int>(integration_time_ / timestep_),
                                         0,
                                         static_cast<double>(Units::convert(integration_time_, "ns")));
        induced_charge_e_histo_ = new TH1D("induced_charge_e_histo",
                                           "Induced charge per time;Drift time [ns];charge [e]",
                                           static_cast<int>(integration_time_ / timestep_),
                                           0,
                                           static_cast<double>(Units::convert(integration_time_, "ns")));
        induced_charge_h_histo_ = new TH1D("induced_charge_h_histo",
                                           "Induced charge per time;Drift time [ns];charge [e]",
                                           static_cast<int>(integration_time_ / timestep_),
                                           0,
                                           static_cast<double>(Units::convert(integration_time_, "ns")));
    }
}

void TransientPropagationModule::run(unsigned int) {

    // Create map for all pixels
    std::map<Pixel::Index, Pulse> pixel_map;

    // Loop over all deposits for propagation
    LOG(TRACE) << "Propagating charges in sensor";
    for(auto& deposit : deposits_message_->getData()) {

        // Loop over all charges in the deposit
        unsigned int charges_remaining = deposit.getCharge();

        LOG(DEBUG) << "Set of charge carriers (" << deposit.getType() << ") on "
                   << Units::display(deposit.getLocalPosition(), {"mm", "um"});

        auto charge_per_step = config_.get<unsigned int>("charge_per_step");
        while(charges_remaining > 0) {
            // Define number of charges to be propagated and remove charges of this step from the total
            if(charge_per_step > charges_remaining) {
                charge_per_step = charges_remaining;
            }
            charges_remaining -= charge_per_step;

            // Get position and propagate through sensor
            auto position = deposit.getLocalPosition();

            // Propagate a single charge deposit
            propagate(position, deposit.getType(), charge_per_step, pixel_map);
            LOG(DEBUG) << " Propagated " << charge_per_step << " from " << Units::display(position, {"mm", "um"});
        }
    }

    // Create vector of pixel pulses to return for this detector
    std::vector<PixelCharge> pixel_charges;
    for(auto& pixel_index_pulse : pixel_map) {
        pixel_charges.emplace_back(detector_->getPixel(pixel_index_pulse.first), std::move(pixel_index_pulse.second));
    }

    // Create a new message with pixel pulses
    auto pixel_charge_message = std::make_shared<PixelChargeMessage>(std::move(pixel_charges), detector_);

    // Dispatch the message with pixel charges
    messenger_->dispatchMessage(this, pixel_charge_message);
}

/**
 * Propagation is simulated using a parameterization for the electron mobility. This is used to calculate the electron
 * velocity at every point with help of the electric field map of the detector. A Runge-Kutta integration is applied in
 * multiple steps, adding a random diffusion to the propagating charge every step.
 */
void TransientPropagationModule::propagate(const ROOT::Math::XYZPoint& pos,
                                           const CarrierType& type,
                                           const unsigned int charge,
                                           std::map<Pixel::Index, Pulse>& pixel_map) {

    // Create a runge kutta solver using the electric field as step function
    Eigen::Vector3d position(pos.x(), pos.y(), pos.z());

    // Define a lambda function to compute the carrier mobility
    // NOTE This function is typically the most frequently executed part of the framework and therefore the bottleneck
    auto carrier_mobility = [&](double efield_mag) {
        // Compute carrier mobility from constants and electric field magnitude
        double numerator, denominator;
        if(type == CarrierType::ELECTRON) {
            numerator = electron_Vm_ / electron_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / electron_Ec_, electron_Beta_), 1.0 / electron_Beta_);
        } else {
            numerator = hole_Vm_ / hole_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / hole_Ec_, hole_Beta_), 1.0 / hole_Beta_);
        }
        return numerator / denominator;
    };

    // Define a function to compute the diffusion
    auto carrier_diffusion = [&](double efield_mag, double timestep) -> Eigen::Vector3d {
        double diffusion_constant = boltzmann_kT_ * carrier_mobility(efield_mag);
        double diffusion_std_dev = std::sqrt(2. * diffusion_constant * timestep);

        // Compute the independent diffusion in three
        std::normal_distribution<double> gauss_distribution(0, diffusion_std_dev);
        Eigen::Vector3d diffusion;
        for(int i = 0; i < 3; ++i) {
            diffusion[i] = gauss_distribution(random_generator_);
        }
        return diffusion;
    };

    // Define a lambda function to compute the electron velocity
    auto carrier_velocity = [&](double, Eigen::Vector3d cur_pos) -> Eigen::Vector3d {
        auto raw_field = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(cur_pos));
        // Compute the drift velocity
        Eigen::Vector3d efield(raw_field.x(), raw_field.y(), raw_field.z());

        return static_cast<int>(type) * carrier_mobility(efield.norm()) * efield;
    };

    // Create the runge kutta solver with an RKF5 tableau
    auto runge_kutta = make_runge_kutta(tableau::RK5, carrier_velocity, timestep_, position);

    // Continue propagation until the deposit is outside the sensor
    Eigen::Vector3d last_position = position;
    double last_time = 0;
    bool within_sensor = true;
    while(within_sensor && runge_kutta.getTime() < integration_time_) {

        // Save previous position and time
        last_position = position;
        last_time = runge_kutta.getTime();

        // Execute a Runge Kutta step
        runge_kutta.step();

        // Get the current result
        position = runge_kutta.getValue();

        // Get electric field at current position and fall back to empty field if it does not exist
        auto efield = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(position));

        // Apply diffusion step
        auto diffusion = carrier_diffusion(std::sqrt(efield.Mag2()), timestep_);
        position += diffusion;
        runge_kutta.setValue(position);

        // Check for overshooting outside the sensor and correct for it:
        if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
            LOG(TRACE) << "Position outside sensor: " << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"nm"});
            // FIXME this simply changes the z coordinate to be within the sensor - maybe we can be more clever
            if(position.z() - model_->getSensorSize().z() / 2.0 > 1e-9) {
                position = Eigen::Vector3d(position.x(), position.y(), model_->getSensorSize().z() / 2.0 - 1e-4);
            } else if(position.z() + model_->getSensorSize().z() / 2.0 < -1e-9) {
                position = Eigen::Vector3d(position.x(), position.y(), -model_->getSensorSize().z() / 2.0 + 1e-4);
            }
            LOG(TRACE) << "Moved carrier to position: "
                       << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"nm"});

            within_sensor = false;
        }

        // Find the nearest pixel
        auto xpixel = static_cast<int>(std::round(position.x() / model_->getPixelSize().x()));
        auto ypixel = static_cast<int>(std::round(position.y() / model_->getPixelSize().y()));
        LOG(TRACE) << "Moving carriers below pixel "
                   << Pixel::Index(static_cast<unsigned int>(xpixel), static_cast<unsigned int>(ypixel)) << " from "
                   << Units::display(static_cast<ROOT::Math::XYZPoint>(last_position), {"um", "mm"}) << " to "
                   << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"}) << ", "
                   << Units::display(runge_kutta.getTime(), "ns");

        // Loop over NxN pixels:
        for(int x = xpixel - 1; x <= xpixel + 1; x++) {
            for(int y = ypixel - 1; y <= ypixel + 1; y++) {
                // Ignore if out of pixel grid
                if(x < 0 || x >= model_->getNPixels().x() || y < 0 || y >= model_->getNPixels().y()) {
                    LOG(TRACE) << "Pixel (" << x << "," << y << ") skipped, outside the grid";
                    continue;
                }

                Pixel::Index pixel_index(static_cast<unsigned int>(x), static_cast<unsigned int>(y));
                auto ramo = detector_->getWeightingPotential(static_cast<ROOT::Math::XYZPoint>(position), pixel_index);
                auto last_ramo =
                    detector_->getWeightingPotential(static_cast<ROOT::Math::XYZPoint>(last_position), pixel_index);

                // Induced charge on electrode is q_int = q * (phi(x1) - phi(x0))
                auto induced = charge * (ramo - last_ramo) * (-static_cast<std::underlying_type<CarrierType>::type>(type));
                LOG(TRACE) << "Pixel " << pixel_index << " dPhi = " << (ramo - last_ramo) << ", induced " << type
                           << " q = " << Units::display(induced, "e");

                // Check if this pulse exists already:
                if(pixel_map.find(pixel_index) == pixel_map.end()) {
                    pixel_map[pixel_index] = Pulse(integration_time_, timestep_);
                }

                // Store induced charge in the respective pixel pulse:
                pixel_map[pixel_index].addCharge(induced, runge_kutta.getTime());

                if(output_plots_ && x == 0 && y == 0) {
                    induced_charge_histo_->Fill(runge_kutta.getTime(), induced);
                    if(type == CarrierType::ELECTRON) {
                        induced_charge_e_histo_->Fill(runge_kutta.getTime(), induced);
                    } else {
                        induced_charge_h_histo_->Fill(runge_kutta.getTime(), induced);
                    }
                }
            }
        }
    }

    // Find proper final position in the sensor
    auto time = runge_kutta.getTime();
    if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
        auto check_position = position;
        check_position.z() = last_position.z();
        if(position.z() > 0 && detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(check_position))) {
            // Carrier left sensor on the side of the pixel grid, interpolate end point on surface
            auto z_cur_border = std::fabs(position.z() - model_->getSensorSize().z() / 2.0);
            auto z_last_border = std::fabs(model_->getSensorSize().z() / 2.0 - last_position.z());
            auto z_total = z_cur_border + z_last_border;
            position = (z_last_border / z_total) * position + (z_cur_border / z_total) * last_position;
            time = (z_last_border / z_total) * time + (z_cur_border / z_total) * last_time;
        } else {
            // Carrier left sensor on any order border, use last position inside instead
            position = last_position;
            time = last_time;
        }
    }
    LOG(TRACE) << "Time: " << Units::display(time, {"ps", "ns"});
}

void TransientPropagationModule::finalize() {
    if(output_plots_) {
        induced_charge_histo_->Write();
        induced_charge_e_histo_->Write();
        induced_charge_h_histo_->Write();
    }
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itk3DSimpleLevelSetsExample.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include <fstream>
#include "itkImageRegionIterator.h"
#include "itkLevelSetFunction.h"
#include "itkSparseFieldLevelSetImageFilter.h"
#include "itkRawImageIO.h"
#include "itkImageFileWriter.h"

extern "C" {
#include "stdio.h"
}

const unsigned int V_WIDTH  = 64;
const unsigned int V_HEIGHT = 64;
const unsigned int V_DEPTH  = 64;

#define T_RADIUS (V_WIDTH/10.0)
#define XY_RADIUS (V_WIDTH/3.0)

#define T_CENTER_X (0.0)
#define T_CENTER_Y (0.0)
#define T_CENTER_Z (0.0)

#define SPH_R_X (0.2f*V_WIDTH)
#define SPH_R_Y (0.2f*V_HEIGHT)
#define SPH_R_Z (0.2f*V_DEPTH)

float torus_full_signed(unsigned x, unsigned y, unsigned z)
{
  float t_dis, dis;
  t_dis = (x - (float)V_WIDTH/2.0)*(x - (float)V_WIDTH/2.0) +
    (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0);
  t_dis = vnl_math_sqrt(t_dis);
  dis = vnl_math_sqrt((t_dis - XY_RADIUS)*(t_dis - XY_RADIUS) +
    (z - (float)V_DEPTH/2.0)*(z - (float)V_DEPTH/2.0));
  return(0.0001f*(T_RADIUS - dis));
}

float sphere(unsigned x, unsigned y, unsigned z)
{
  float dis;
  dis = (x - (float)V_WIDTH/2.0)*(x - (float)V_WIDTH/2.0)
    /(SPH_R_X*SPH_R_X) + (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0)
    /(SPH_R_Y*SPH_R_Y) + (z - (float)V_DEPTH/2.0)*(z - (float)V_DEPTH/2.0)
    /(SPH_R_Z*SPH_R_Z);

  return(1.0f-dis);
}

float two_spheres(unsigned x, unsigned y, unsigned z)
{
  float dis;
  if (x < V_WIDTH/2)
    {
      dis = (x - (float)V_WIDTH/4.0)*(x - (float)V_WIDTH/4.0)
        /(SPH_R_X*SPH_R_X) + (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0)
        /(SPH_R_Y*SPH_R_Y) + (z - (float)V_DEPTH/2.0)*(z - (float)V_DEPTH/2.0)
        /(SPH_R_Z*SPH_R_Z);
      return(1.0f-dis);
    }
  else
    {
      dis = (x - (float)3*V_WIDTH/4.0)*(x - (float)3*V_WIDTH/4.0)
        /(SPH_R_X*SPH_R_X) + (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0)
        /(SPH_R_Y*SPH_R_Y) + (z - (float)V_DEPTH/2.0)*(z - (float)V_DEPTH/2.0)
        /(SPH_R_Z*SPH_R_Z);

      return(1.0f-dis);
    }
}

float cylinder(unsigned x, unsigned y, unsigned z)
{
  float dis;
  dis = (x - (float)V_WIDTH/2.0)*(x - (float)V_WIDTH/2.0)
    /(SPH_R_X*SPH_R_X) + (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0)
    /(SPH_R_Y*SPH_R_Y);
  if ( (z > V_DEPTH/4.0) && (z < 3*V_DEPTH/4.0) )
    return(1.0f - dis);
  else if (z<=V_DEPTH/4.0)
    return(z-V_DEPTH/4.0);
  else
    return((3*V_DEPTH/4.0) - z);
}

float the_torus(unsigned x, unsigned y, unsigned z)
{
  float t_dis, dis;
  t_dis = (x - T_CENTER_X)*(x - T_CENTER_X) + (y - T_CENTER_Y)*(y - T_CENTER_Y);
  t_dis = vnl_math_sqrt(t_dis);
  dis = vnl_math_sqrt((t_dis - XY_RADIUS)*(t_dis - XY_RADIUS)
                      + (z - T_CENTER_Z)*(z - T_CENTER_Z));
  return(T_RADIUS - dis);
}

float the_torus(float x, float y, float z)
{
  float t_dis, dis;
  t_dis = (x - T_CENTER_X)*(x - T_CENTER_X) + (y - T_CENTER_Y)*(y - T_CENTER_Y);
  t_dis = vnl_math_sqrt(t_dis);
  dis = vnl_math_sqrt((t_dis - XY_RADIUS)*(t_dis - XY_RADIUS)
                      + (z - T_CENTER_Z)*(z - T_CENTER_Z));
  return(T_RADIUS - dis);
}

float box(unsigned x, unsigned y, unsigned z)
{
  float X, Y,Z;
  X = vnl_math_abs(x - (float)V_WIDTH/2.0);
  Y = vnl_math_abs(y - (float)V_HEIGHT/2.0);
  Z = vnl_math_abs(z - (float)V_DEPTH/2.0);
  float dis;
  if ((X <= XY_RADIUS) || (Y <= XY_RADIUS) || (Z <= XY_RADIUS) )
    {
      dis = XY_RADIUS - vnl_math_max(X, vnl_math_max( Y, Z));
    }
  else
    {
      dis = -vnl_math_sqrt((X - XY_RADIUS)*(X - XY_RADIUS)
                           +(Y - XY_RADIUS)*(Y - XY_RADIUS)
                           + (Z - XY_RADIUS)*(Z - XY_RADIUS));
    }
  return(dis);
}

float ellipse(unsigned int x, unsigned int y, unsigned int z)
{
  float dis;
  float cx = V_WIDTH/2, cy = V_HEIGHT/2, cz=V_DEPTH/2;
  float r1 = V_WIDTH/3;  //r2 = V_HEIGHT/3, r3=V_DEPTH/4;

  dis=r1-sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy)+(z-cz)*(z-cz));

  return(dis);
}

void evaluate_function(itk::Image<float, 3> *im,
                       float (*f)(unsigned int, unsigned int, unsigned int) )

{
  itk::Image<float, 3>::IndexType idx;

  for(unsigned int z = 0; z < V_DEPTH; ++z)
    {
      idx[2] = z;
      for (unsigned int y = 0; y < V_HEIGHT; ++y)
        {
          idx[1] = y;
          for (unsigned int x = 0; x < V_WIDTH; ++x)
            {
              idx[0] = x;
              im->SetPixel(idx, f(x, y, z) );
            }
        }

    }
}

namespace itk {

class MorphFunction : public LevelSetFunction< Image<float, 3> >
{
public:
  void SetDistanceTransform (Image<float, 3> *d)
    { m_DistanceTransform = d; }

  typedef MorphFunction Self;

  typedef LevelSetFunction< Image<float, 3> > Superclass;
  typedef Superclass::RadiusType RadiusType;

  /**
   * Smart pointer support for this class.
   */
  typedef SmartPointer<Self> Pointer;
  typedef SmartPointer<const Self> ConstPointer;

  /**
   * Run-time type information (and related methods)
   */
  itkTypeMacro( MorphFunction, LevelSetFunction );

  /**
   * Method for creation through the object factory.
   */
  itkNewMacro(Self);

protected:
  ~MorphFunction() {}

  MorphFunction()
  {
      RadiusType r;
      r[0] = r[1] = r[2]= 1;
      Superclass::Initialize(r);
  }

private:
  Image<float, 3>::Pointer m_DistanceTransform;

  virtual ScalarValueType PropagationSpeed(
                    const NeighborhoodType& neighborhood,
                         const FloatOffsetType &
                                ) const
  {
    return m_DistanceTransform->GetPixel( neighborhood.GetIndex() );
  }

};

class MorphFilter : public
SparseFieldLevelSetImageFilter< Image<float, 3>, Image<float, 3> >
{
public:
  typedef MorphFilter Self;

  /**
   * Smart pointer support for this class.
   */
  typedef SmartPointer<Self> Pointer;
  typedef SmartPointer<const Self> ConstPointer;

  /**
   * Run-time type information (and related methods)
   */
  itkTypeMacro( MorphFunction, LevelSetFunction );

  /**
   * Method for creation through the object factory.
   */
  itkNewMacro(Self);

  itkSetMacro(Iterations, unsigned int);

  void SetDistanceTransform(Image<float, 3> *im)
  {
    ((MorphFunction *)(this->GetDifferenceFunction().GetPointer()))
      ->SetDistanceTransform(im);
  }

  void SetCurvatureWeight(float w)
  {
    (dynamic_cast<MorphFunction *>( this->GetDifferenceFunction().GetPointer() ) )->SetCurvatureWeight(w);
  }

protected:
  ~MorphFilter() {}
  MorphFilter()
  {
    MorphFunction::Pointer p = MorphFunction::New();
    p->SetPropagationWeight(-1.0);
    p->SetAdvectionWeight(0.0);
    p->SetCurvatureWeight(1.0);
    this->SetDifferenceFunction(p);

  }
  MorphFilter(const Self &) {}

private:
  unsigned int m_Iterations;

  virtual bool Halt()
  {
    if (this->GetElapsedIterations() == m_Iterations) return true;
    else return false;
  }
};

} //end of itk namespace

int main(int argc, char** argv)
{
  typedef itk::Image<float,3> ImageType;

  try {
    int n;

    itk::RawImageIO<float, 3>::Pointer output_io
      = itk::RawImageIO<float, 3>::New();
    output_io->SetByteOrderToLittleEndian();
    output_io->SetFileTypeToBinary();
    output_io->SetFileDimensionality(3);

    itk::ImageFileWriter<ImageType>::Pointer writer
      = itk::ImageFileWriter<ImageType>::New();
    writer->SetImageIO(output_io);

    // Initialize the initial and target volumes.
    ImageType::Pointer vol_init = ImageType::New();
    ImageType::Pointer vol_target = ImageType::New();

    ImageType::SizeType sz;
    sz[0] = V_WIDTH;
    sz[1] = V_HEIGHT;
    sz[2] = V_DEPTH;

    ImageType::IndexType idx;
    idx[0] = 0;
    idx[1] = 0;
    idx[2] = 0;

    ImageType::RegionType reg;
    reg.SetSize(sz);
    reg.SetIndex(idx);

    vol_init->SetRegions(reg);
    vol_init->Allocate();

    vol_target->SetRegions(reg);
    vol_target->Allocate();

    if (argc < 4)
      {
        std::cout << "Usage:"<<argv[0]
                  <<" number_of_iterations initial_shape target_shape"
                  << std::endl;
        exit(-1);
      }

    n = (int)atoi(argv[1]);
    int init_no   = (int)atoi(argv[2]);
    int target_no = (int)atoi(argv[3]);

    switch(init_no)
      {
      case 1:
        evaluate_function(vol_init, torus_full_signed);
        break;
      case 2:
        evaluate_function(vol_init, sphere);
        break;
      case 3:
        evaluate_function(vol_init, two_spheres);
        break;
      case 4:
        evaluate_function(vol_init, cylinder);
        break;
      case 5:
        evaluate_function(vol_init, box);
        break;
      default:
        evaluate_function(vol_init, sphere);
      }

    switch (target_no)
      {
      case 1:
        evaluate_function(vol_target, torus_full_signed);
        break;
      case 2:
        evaluate_function(vol_target, sphere);
        break;
      case 3:
        evaluate_function(vol_target, two_spheres);
        break;
      case 4:
        evaluate_function(vol_target, cylinder);
        break;
      case 5:
        evaluate_function(vol_target, box);
        break;
      default:
        evaluate_function(vol_target, box);
      }

    itk::ImageRegionIterator<ImageType> itr(vol_target,
                             vol_target->GetRequestedRegion());

    // Squash level sets everywhere but near the zero set.
    for (itr = itr.Begin(); ! itr.IsAtEnd(); ++itr)
      {
        itr.Value() = itr.Value() /vnl_math_sqrt((5.0f +vnl_math_sqr(itr.Value())));

      }

    writer->SetFileName("initial_image_3D.raw");
    writer->SetInput(vol_init);
    writer->Write();

    writer->SetFileName("distance_transform_3D.raw");
    writer->SetInput(vol_target);
    writer->Write();

    itk::MorphFilter::Pointer mf = itk::MorphFilter::New();
    mf->SetDistanceTransform(vol_target);
    mf->SetNumberOfIterations(n);
    mf->SetInput(vol_init);
    mf->SetNumberOfLayers(3);
    mf->SetCurvatureWeight(0.1);
    mf->Update();

    writer->SetFileName("final_image_3D.raw");
    writer->SetInput(mf->GetOutput());
    writer->Write();
  }  catch (itk::ExceptionObject *e)
    {
      std::cout << e << std::endl;
    }

  return 0;
}

<commit_msg>ERR: SetIterations() here was unrelated to the AnisotropicDiffusionFilters.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itk3DSimpleLevelSetsExample.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include <fstream>
#include "itkImageRegionIterator.h"
#include "itkLevelSetFunction.h"
#include "itkSparseFieldLevelSetImageFilter.h"
#include "itkRawImageIO.h"
#include "itkImageFileWriter.h"

extern "C" {
#include "stdio.h"
}

const unsigned int V_WIDTH  = 64;
const unsigned int V_HEIGHT = 64;
const unsigned int V_DEPTH  = 64;

#define T_RADIUS (V_WIDTH/10.0)
#define XY_RADIUS (V_WIDTH/3.0)

#define T_CENTER_X (0.0)
#define T_CENTER_Y (0.0)
#define T_CENTER_Z (0.0)

#define SPH_R_X (0.2f*V_WIDTH)
#define SPH_R_Y (0.2f*V_HEIGHT)
#define SPH_R_Z (0.2f*V_DEPTH)

float torus_full_signed(unsigned x, unsigned y, unsigned z)
{
  float t_dis, dis;
  t_dis = (x - (float)V_WIDTH/2.0)*(x - (float)V_WIDTH/2.0) +
    (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0);
  t_dis = vnl_math_sqrt(t_dis);
  dis = vnl_math_sqrt((t_dis - XY_RADIUS)*(t_dis - XY_RADIUS) +
    (z - (float)V_DEPTH/2.0)*(z - (float)V_DEPTH/2.0));
  return(0.0001f*(T_RADIUS - dis));
}

float sphere(unsigned x, unsigned y, unsigned z)
{
  float dis;
  dis = (x - (float)V_WIDTH/2.0)*(x - (float)V_WIDTH/2.0)
    /(SPH_R_X*SPH_R_X) + (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0)
    /(SPH_R_Y*SPH_R_Y) + (z - (float)V_DEPTH/2.0)*(z - (float)V_DEPTH/2.0)
    /(SPH_R_Z*SPH_R_Z);

  return(1.0f-dis);
}

float two_spheres(unsigned x, unsigned y, unsigned z)
{
  float dis;
  if (x < V_WIDTH/2)
    {
      dis = (x - (float)V_WIDTH/4.0)*(x - (float)V_WIDTH/4.0)
        /(SPH_R_X*SPH_R_X) + (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0)
        /(SPH_R_Y*SPH_R_Y) + (z - (float)V_DEPTH/2.0)*(z - (float)V_DEPTH/2.0)
        /(SPH_R_Z*SPH_R_Z);
      return(1.0f-dis);
    }
  else
    {
      dis = (x - (float)3*V_WIDTH/4.0)*(x - (float)3*V_WIDTH/4.0)
        /(SPH_R_X*SPH_R_X) + (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0)
        /(SPH_R_Y*SPH_R_Y) + (z - (float)V_DEPTH/2.0)*(z - (float)V_DEPTH/2.0)
        /(SPH_R_Z*SPH_R_Z);

      return(1.0f-dis);
    }
}

float cylinder(unsigned x, unsigned y, unsigned z)
{
  float dis;
  dis = (x - (float)V_WIDTH/2.0)*(x - (float)V_WIDTH/2.0)
    /(SPH_R_X*SPH_R_X) + (y - (float)V_HEIGHT/2.0)*(y - (float)V_HEIGHT/2.0)
    /(SPH_R_Y*SPH_R_Y);
  if ( (z > V_DEPTH/4.0) && (z < 3*V_DEPTH/4.0) )
    return(1.0f - dis);
  else if (z<=V_DEPTH/4.0)
    return(z-V_DEPTH/4.0);
  else
    return((3*V_DEPTH/4.0) - z);
}

float the_torus(unsigned x, unsigned y, unsigned z)
{
  float t_dis, dis;
  t_dis = (x - T_CENTER_X)*(x - T_CENTER_X) + (y - T_CENTER_Y)*(y - T_CENTER_Y);
  t_dis = vnl_math_sqrt(t_dis);
  dis = vnl_math_sqrt((t_dis - XY_RADIUS)*(t_dis - XY_RADIUS)
                      + (z - T_CENTER_Z)*(z - T_CENTER_Z));
  return(T_RADIUS - dis);
}

float the_torus(float x, float y, float z)
{
  float t_dis, dis;
  t_dis = (x - T_CENTER_X)*(x - T_CENTER_X) + (y - T_CENTER_Y)*(y - T_CENTER_Y);
  t_dis = vnl_math_sqrt(t_dis);
  dis = vnl_math_sqrt((t_dis - XY_RADIUS)*(t_dis - XY_RADIUS)
                      + (z - T_CENTER_Z)*(z - T_CENTER_Z));
  return(T_RADIUS - dis);
}

float box(unsigned x, unsigned y, unsigned z)
{
  float X, Y,Z;
  X = vnl_math_abs(x - (float)V_WIDTH/2.0);
  Y = vnl_math_abs(y - (float)V_HEIGHT/2.0);
  Z = vnl_math_abs(z - (float)V_DEPTH/2.0);
  float dis;
  if ((X <= XY_RADIUS) || (Y <= XY_RADIUS) || (Z <= XY_RADIUS) )
    {
      dis = XY_RADIUS - vnl_math_max(X, vnl_math_max( Y, Z));
    }
  else
    {
      dis = -vnl_math_sqrt((X - XY_RADIUS)*(X - XY_RADIUS)
                           +(Y - XY_RADIUS)*(Y - XY_RADIUS)
                           + (Z - XY_RADIUS)*(Z - XY_RADIUS));
    }
  return(dis);
}

float ellipse(unsigned int x, unsigned int y, unsigned int z)
{
  float dis;
  float cx = V_WIDTH/2, cy = V_HEIGHT/2, cz=V_DEPTH/2;
  float r1 = V_WIDTH/3;  //r2 = V_HEIGHT/3, r3=V_DEPTH/4;

  dis=r1-sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy)+(z-cz)*(z-cz));

  return(dis);
}

void evaluate_function(itk::Image<float, 3> *im,
                       float (*f)(unsigned int, unsigned int, unsigned int) )

{
  itk::Image<float, 3>::IndexType idx;

  for(unsigned int z = 0; z < V_DEPTH; ++z)
    {
      idx[2] = z;
      for (unsigned int y = 0; y < V_HEIGHT; ++y)
        {
          idx[1] = y;
          for (unsigned int x = 0; x < V_WIDTH; ++x)
            {
              idx[0] = x;
              im->SetPixel(idx, f(x, y, z) );
            }
        }

    }
}

namespace itk {

class MorphFunction : public LevelSetFunction< Image<float, 3> >
{
public:
  void SetDistanceTransform (Image<float, 3> *d)
    { m_DistanceTransform = d; }

  typedef MorphFunction Self;

  typedef LevelSetFunction< Image<float, 3> > Superclass;
  typedef Superclass::RadiusType RadiusType;

  /**
   * Smart pointer support for this class.
   */
  typedef SmartPointer<Self> Pointer;
  typedef SmartPointer<const Self> ConstPointer;

  /**
   * Run-time type information (and related methods)
   */
  itkTypeMacro( MorphFunction, LevelSetFunction );

  /**
   * Method for creation through the object factory.
   */
  itkNewMacro(Self);

protected:
  ~MorphFunction() {}

  MorphFunction()
  {
      RadiusType r;
      r[0] = r[1] = r[2]= 1;
      Superclass::Initialize(r);
  }

private:
  Image<float, 3>::Pointer m_DistanceTransform;

  virtual ScalarValueType PropagationSpeed(
                    const NeighborhoodType& neighborhood,
                         const FloatOffsetType &
                                ) const
  {
    return m_DistanceTransform->GetPixel( neighborhood.GetIndex() );
  }

};

class MorphFilter : public
SparseFieldLevelSetImageFilter< Image<float, 3>, Image<float, 3> >
{
public:
  typedef MorphFilter Self;

  /**
   * Smart pointer support for this class.
   */
  typedef SmartPointer<Self> Pointer;
  typedef SmartPointer<const Self> ConstPointer;

  /**
   * Run-time type information (and related methods)
   */
  itkTypeMacro( MorphFunction, LevelSetFunction );

  /**
   * Method for creation through the object factory.
   */
  itkNewMacro(Self);

  itkSetMacro(Iterations, unsigned int);

  void SetDistanceTransform(Image<float, 3> *im)
  {
    ((MorphFunction *)(this->GetDifferenceFunction().GetPointer()))
      ->SetDistanceTransform(im);
  }

  void SetCurvatureWeight(float w)
  {
    (dynamic_cast<MorphFunction *>( this->GetDifferenceFunction().GetPointer() ) )->SetCurvatureWeight(w);
  }

protected:
  ~MorphFilter() {}
  MorphFilter()
  {
    MorphFunction::Pointer p = MorphFunction::New();
    p->SetPropagationWeight(-1.0);
    p->SetAdvectionWeight(0.0);
    p->SetCurvatureWeight(1.0);
    this->SetDifferenceFunction(p);

  }
  MorphFilter(const Self &) {}

private:
  unsigned int m_Iterations;

  virtual bool Halt()
  {
    if (this->GetElapsedIterations() == m_Iterations) return true;
    else return false;
  }
};

} //end of itk namespace

int main(int argc, char** argv)
{
  typedef itk::Image<float,3> ImageType;

  try {
    int n;

    itk::RawImageIO<float, 3>::Pointer output_io
      = itk::RawImageIO<float, 3>::New();
    output_io->SetByteOrderToLittleEndian();
    output_io->SetFileTypeToBinary();
    output_io->SetFileDimensionality(3);

    itk::ImageFileWriter<ImageType>::Pointer writer
      = itk::ImageFileWriter<ImageType>::New();
    writer->SetImageIO(output_io);

    // Initialize the initial and target volumes.
    ImageType::Pointer vol_init = ImageType::New();
    ImageType::Pointer vol_target = ImageType::New();

    ImageType::SizeType sz;
    sz[0] = V_WIDTH;
    sz[1] = V_HEIGHT;
    sz[2] = V_DEPTH;

    ImageType::IndexType idx;
    idx[0] = 0;
    idx[1] = 0;
    idx[2] = 0;

    ImageType::RegionType reg;
    reg.SetSize(sz);
    reg.SetIndex(idx);

    vol_init->SetRegions(reg);
    vol_init->Allocate();

    vol_target->SetRegions(reg);
    vol_target->Allocate();

    if (argc < 4)
      {
        std::cout << "Usage:"<<argv[0]
                  <<" number_of_iterations initial_shape target_shape"
                  << std::endl;
        exit(-1);
      }

    n = (int)atoi(argv[1]);
    int init_no   = (int)atoi(argv[2]);
    int target_no = (int)atoi(argv[3]);

    switch(init_no)
      {
      case 1:
        evaluate_function(vol_init, torus_full_signed);
        break;
      case 2:
        evaluate_function(vol_init, sphere);
        break;
      case 3:
        evaluate_function(vol_init, two_spheres);
        break;
      case 4:
        evaluate_function(vol_init, cylinder);
        break;
      case 5:
        evaluate_function(vol_init, box);
        break;
      default:
        evaluate_function(vol_init, sphere);
      }

    switch (target_no)
      {
      case 1:
        evaluate_function(vol_target, torus_full_signed);
        break;
      case 2:
        evaluate_function(vol_target, sphere);
        break;
      case 3:
        evaluate_function(vol_target, two_spheres);
        break;
      case 4:
        evaluate_function(vol_target, cylinder);
        break;
      case 5:
        evaluate_function(vol_target, box);
        break;
      default:
        evaluate_function(vol_target, box);
      }

    itk::ImageRegionIterator<ImageType> itr(vol_target,
                             vol_target->GetRequestedRegion());

    // Squash level sets everywhere but near the zero set.
    for (itr = itr.Begin(); ! itr.IsAtEnd(); ++itr)
      {
        itr.Value() = itr.Value() /vnl_math_sqrt((5.0f +vnl_math_sqr(itr.Value())));

      }

    writer->SetFileName("initial_image_3D.raw");
    writer->SetInput(vol_init);
    writer->Write();

    writer->SetFileName("distance_transform_3D.raw");
    writer->SetInput(vol_target);
    writer->Write();

    itk::MorphFilter::Pointer mf = itk::MorphFilter::New();
    mf->SetDistanceTransform(vol_target);
    mf->SetIterations(n);
    mf->SetInput(vol_init);
    mf->SetNumberOfLayers(3);
    mf->SetCurvatureWeight(0.1);
    mf->Update();

    writer->SetFileName("final_image_3D.raw");
    writer->SetInput(mf->GetOutput());
    writer->Write();
  }  catch (itk::ExceptionObject *e)
    {
      std::cout << e << std::endl;
    }

  return 0;
}

<|endoftext|>