void MLBSTrackingFilter<  ShOrder, NumImageFeatures >::AfterThreadedGenerateData()
{
    MITK_INFO << "Generating polydata ";
    BuildFibers(false);
    MITK_INFO << "done";

    m_EndTime = std::chrono::system_clock::now();
    std::chrono::hours   hh = std::chrono::duration_cast<std::chrono::hours>(m_EndTime - m_StartTime);
    std::chrono::minutes mm = std::chrono::duration_cast<std::chrono::minutes>(m_EndTime - m_StartTime);
    std::chrono::seconds ss = std::chrono::duration_cast<std::chrono::seconds>(m_EndTime - m_StartTime);
    mm %= 60;
    ss %= 60;
    MITK_INFO << "Tracking took " << hh.count() << "h, " << mm.count() << "m and " << ss.count() << "s";
}
  void
      GlobalTractographyFilter< TInputOdfImage, TInputROIImage >
      ::GenerateData(){

    // input qball image
    m_ItkQBallImage = dynamic_cast<InputQBallImageType*>(this->GetInput(0));

    // approximationscoeffizienten der
    // teilchenkorrelationen im orientierungsraum
    // 4er vektor
    ComputeFiberCorrelation();

    // image sizes and spacing
    int qBallImageSize[4] = {QBALL_ODFSIZE,
                   m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(0),
                   m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(1),
                   m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(2)};
    double qBallImageSpacing[3] = {m_ItkQBallImage->GetSpacing().GetElement(0),m_ItkQBallImage->GetSpacing().GetElement(1),m_ItkQBallImage->GetSpacing().GetElement(2)};

    // make sure image has enough slices
    if (qBallImageSize[1]<3 || qBallImageSize[2]<3 || qBallImageSize[3]<3)
    {
      MITK_INFO << "image size < 3 not supported";
      return;
    }

    // calculate rotation matrix
    vnl_matrix_fixed<double, 3, 3>  directionMatrix = m_ItkQBallImage->GetDirection().GetVnlMatrix();
    vnl_vector_fixed<double, 3> d0 = directionMatrix.get_column(0); d0.normalize();
    vnl_vector_fixed<double, 3> d1 = directionMatrix.get_column(1); d1.normalize();
    vnl_vector_fixed<double, 3> d2 = directionMatrix.get_column(2); d2.normalize();
    directionMatrix.set_column(0, d0);
    directionMatrix.set_column(1, d1);
    directionMatrix.set_column(2, d2);
    vnl_matrix_fixed<double, 3, 3> I = directionMatrix*directionMatrix.transpose();
    if(!I.is_identity(mitk::eps)){
      MITK_INFO << "Image direction is not a rotation matrix. Tracking not possible!";
      return;
    }

    // generate local working copy of image buffer
    int bufferSize = qBallImageSize[0]*qBallImageSize[1]*qBallImageSize[2]*qBallImageSize[3];
    float* qBallImageBuffer = (float*) m_ItkQBallImage->GetBufferPointer();
    float* workingQballImage = new float[bufferSize];
    for (int i=0; i<bufferSize; i++)
      workingQballImage[i] = qBallImageBuffer[i];

    // perform mean subtraction on odfs
    if (m_SubtractMean)
    {
      float sum = 0;
      for (int i=0; i<bufferSize; i++)
      {
        if (qBallImageSize[0]>0 && i%qBallImageSize[0] == 0 && i>0)
        {
          sum /= qBallImageSize[0];
          for (int j=i-qBallImageSize[0]; j<i; j++){
            workingQballImage[j] -= sum;
          }
          sum = 0;
        }
        sum += workingQballImage[i];
      }
    }

    // mask image
    int maskImageSize[3];
    float *mask;
    if(m_MaskImage.IsNotNull())
    {
      mask = (float*) m_MaskImage->GetBufferPointer();
      maskImageSize[0] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(0);
      maskImageSize[1] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(1);
      maskImageSize[2] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(2);
    }
    else
    {
      mask = 0;
      maskImageSize[0] = qBallImageSize[1];
      maskImageSize[1] = qBallImageSize[2];
      maskImageSize[2] = qBallImageSize[3];
    }
    int mask_oversamp_mult = maskImageSize[0]/qBallImageSize[1];

    // load lookuptable
    ifstream BaryCoords;
    BaryCoords.open("FiberTrackingLUTBaryCoords.bin", ios::in | ios::binary);
    float* coords;
    if (BaryCoords.is_open())
    {
      float tmp;
      coords = new float [1630818];
      BaryCoords.seekg (0, ios::beg);
      for (int i=0; i<1630818; i++)
      {
        BaryCoords.read((char *)&tmp, sizeof(tmp));
        coords[i] = tmp;
      }
      BaryCoords.close();
    }
    else
    {
      MITK_INFO << "Unable to open barycoords file";
      return;
    }

    ifstream Indices;
    Indices.open("FiberTrackingLUTIndices.bin", ios::in | ios::binary);
    int* ind;
    if (Indices.is_open())
    {
      int tmp;
      ind = new int [1630818];
      Indices.seekg (0, ios::beg);
      for (int i=0; i<1630818; i++)
      {
        Indices.read((char *)&tmp, 4);
        ind[i] = tmp;
      }
      Indices.close();
    }
    else
    {
      MITK_INFO << "Unable to open indices file";
      return;
    }

    // initialize sphere interpolator with lookuptables
    SphereInterpolator *sinterp = new SphereInterpolator(coords, ind, QBALL_ODFSIZE, 301, 0.5);

    // get paramters
    float minSpacing;
    if(qBallImageSpacing[0]<qBallImageSpacing[1] && qBallImageSpacing[0]<qBallImageSpacing[2])
      minSpacing = qBallImageSpacing[0];
    else if (qBallImageSpacing[1] < qBallImageSpacing[2])
      minSpacing = qBallImageSpacing[1];
    else
      minSpacing = qBallImageSpacing[2];

    if(m_ParticleLength == 0)
      m_ParticleLength = 1.5*minSpacing;
    if(m_ParticleWidth == 0)
      m_ParticleWidth = 0.5*minSpacing;
    if(m_ParticleWeight == 0)
      m_ParticleWeight = 0.01;
    m_CurrentStep = 0;
    m_Memory = 0;

    float cellsize = 2*m_ParticleLength;
    float curvatureHardThreshold = 0.7;
    float alpha = log(m_TempEnd/m_TempStart);
    m_Steps = m_NumIt/10000;
    if (m_Steps<10)
      m_Steps = 10;
    if (m_Steps>m_NumIt)
    {
      MITK_INFO << "not enough iterations!";
      return;
    }
    unsigned long singleIts = (unsigned long)((1.0*m_NumIt) / (1.0*m_Steps));

    // setup metropolis hastings sampler
    MITK_INFO << "itkGlobalTractographyFilter: setting up MH-sampler";
    if (m_Sampler!=NULL)
      delete m_Sampler;
    m_Sampler = new RJMCMC(NULL, 0, workingQballImage, qBallImageSize, qBallImageSpacing, cellsize);

    // setup energy computer
    MITK_INFO << "itkGlobalTractographyFilter: setting up Energy-computer";
    EnergyComputer encomp(workingQballImage,qBallImageSize,qBallImageSpacing,sinterp,&(m_Sampler->m_ParticleGrid),mask,mask_oversamp_mult, directionMatrix);
    encomp.setParameters(m_ParticleWeight,m_ParticleWidth,m_ChempotConnection*m_ParticleLength*m_ParticleLength,m_ParticleLength,curvatureHardThreshold,m_InexBalance,m_Chempot2);
    m_Sampler->SetEnergyComputer(&encomp);
    m_Sampler->SetParameters(m_TempStart,singleIts,m_ParticleLength,curvatureHardThreshold,m_ChempotParticle);

    // main loop
    for( int step = 0; step < m_Steps; step++ )
    {
      if (m_AbortTracking)
        break;

      m_CurrentStep = step+1;
      float temperature = m_TempStart * exp(alpha*(((1.0)*step)/((1.0)*m_Steps)));
      MITK_INFO << "iterating step " << m_CurrentStep;

      m_Sampler->SetTemperature(temperature);
      m_Sampler->Iterate(&m_ProposalAcceptance, &m_NumConnections, &m_NumParticles, &m_AbortTracking);

      MITK_INFO << "proposal acceptance: " << 100*m_ProposalAcceptance << "%";
      MITK_INFO << "particles: " << m_NumParticles;
      MITK_INFO << "connections: " << m_NumConnections;
      MITK_INFO << "progress: " << 100*(float)step/m_Steps << "%";

      if (m_BuildFibers)
      {
        int numPoints = m_Sampler->m_ParticleGrid.pcnt;
        float* points = new float[numPoints*m_Sampler->m_NumAttributes];
        m_Sampler->WriteOutParticles(points);
        BuildFibers(points, numPoints);
        delete points;
        m_BuildFibers = false;
      }
    }

    int numPoints = m_Sampler->m_ParticleGrid.pcnt;
    float* points = new float[numPoints*m_Sampler->m_NumAttributes];
    m_Sampler->WriteOutParticles(points);
    BuildFibers(points, numPoints);
    delete points;

    delete sinterp;
    delete coords;
    delete ind;
    delete workingQballImage;
    m_AbortTracking = true;
    m_BuildFibers = false;

    MITK_INFO << "done generate data";
  }
void MLBSTrackingFilter< NumImageFeatures >::AfterThreadedGenerateData()
{
    MITK_INFO << "Generating polydata ";
    BuildFibers(false);
    MITK_INFO << "done";
}
double MLBSTrackingFilter< NumImageFeatures >::FollowStreamline(ThreadIdType threadId, itk::Point<double, 3> pos, vnl_vector_fixed<double,3> dir, FiberType* fib, double tractLength, bool front)
{
    vnl_vector_fixed<double,3> dirOld = dir;
    dirOld = dir;

    for (int step=0; step< m_MaxLength/2; step++)
    {
        while (m_PauseTracking){}
        if (m_DemoMode)
        {
            m_Mutex.Lock();
            m_BuildFibersReady++;
            m_Tractogram.push_back(*fib);
            BuildFibers(true);
            m_Stop = true;
            m_Mutex.Unlock();
            while (m_Stop){}
        }

        // get new position
        CalculateNewPosition(pos, dir);

        // is new position inside of image and mask
        if (!IsValidPosition(pos) || m_AbortTracking)   // if not end streamline
        {
            return tractLength;
        }
        else    // if yes, add new point to streamline
        {
            tractLength +=  m_StepSize;
            if (front)
                fib->push_front(pos);
            else
                fib->push_back(pos);

            if (m_AposterioriCurvCheck)
            {
                int curv = CheckCurvature(fib, front);  // TODO: Move into classification ???
                if (curv>0)
                {
                    tractLength -= m_StepSize*curv;
                    while (curv>0)
                    {
                        if (front)
                            fib->pop_front();
                        else
                            fib->pop_back();
                        curv--;
                    }
                    return tractLength;
                }
            }

            if (tractLength>m_MaxTractLength)
                return tractLength;
        }

        dir = GetNewDirection(pos, dirOld);

        if (dir.magnitude()<0.0001)
            return tractLength;
    }
    return tractLength;
}