void StartSimulation(FiberfoxParameters<double> parameters, FiberBundleX::Pointer fiberBundle, mitk::DiffusionImage<short>::Pointer refImage, string message)
{
    itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New();
    tractsToDwiFilter->SetUseConstantRandSeed(true);
    tractsToDwiFilter->SetParameters(parameters);
    tractsToDwiFilter->SetFiberBundle(fiberBundle);
    tractsToDwiFilter->Update();

    mitk::DiffusionImage<short>::Pointer testImage = mitk::DiffusionImage<short>::New();
    testImage->SetVectorImage( tractsToDwiFilter->GetOutput() );
    testImage->SetB_Value(parameters.m_Bvalue);
    testImage->SetDirections(parameters.GetGradientDirections());
    testImage->InitializeFromVectorImage();

    if (refImage.IsNotNull())
    {
        bool cond = CompareDwi(testImage->GetVectorImage(), refImage->GetVectorImage());
        if (!cond)
        {
            mitk::IOUtil::SaveBaseData(testImage, "/tmp/testImage.dwi");
            mitk::IOUtil::SaveBaseData(refImage, "/tmp/refImage.dwi");
        }
        MITK_TEST_CONDITION_REQUIRED(cond, message);
    }
    else
    {
        MITK_INFO << "Saving test image to " << message;
        mitk::IOUtil::SaveBaseData(testImage, message);
    }
}
    void StartSimulation(string testFileName)
    {
        mitk::DiffusionImage<short>::Pointer refImage = NULL;
        if (!testFileName.empty())
            CPPUNIT_ASSERT(refImage = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(testFileName)->GetData()));

        itk::AddArtifactsToDwiImageFilter< short >::Pointer artifactsToDwiFilter = itk::AddArtifactsToDwiImageFilter< short >::New();
        artifactsToDwiFilter->SetUseConstantRandSeed(true);
        artifactsToDwiFilter->SetInput(m_InputDwi->GetVectorImage());
        artifactsToDwiFilter->SetParameters(m_Parameters);
        CPPUNIT_ASSERT_NO_THROW(artifactsToDwiFilter->Update());

        mitk::DiffusionImage<short>::Pointer testImage = mitk::DiffusionImage<short>::New();
        testImage->SetVectorImage( artifactsToDwiFilter->GetOutput() );
        testImage->SetB_Value(m_Parameters.m_Bvalue);
        testImage->SetDirections(m_Parameters.GetGradientDirections());
        testImage->InitializeFromVectorImage();

        if (refImage.IsNotNull())
        {
            bool ok = CompareDwi(testImage->GetVectorImage(), refImage->GetVectorImage());
            if (!ok)
            {
                mitk::IOUtil::SaveBaseData(testImage, "/tmp/test2.dwi");
                mitk::IOUtil::SaveBaseData(refImage, "/tmp/ref2.dwi");
            }
            CPPUNIT_ASSERT_MESSAGE(testFileName, ok);
        }
        else
        {
            mitk::IOUtil::SaveBaseData(testImage, "/local/distortions2.dwi");
        }
    }
int mitkFiberfoxSignalGenerationTest(int argc, char* argv[])
{
    MITK_TEST_BEGIN("mitkFiberfoxSignalGenerationTest");

    MITK_TEST_CONDITION_REQUIRED(argc>=19,"check for input data");

    // input fiber bundle
    FiberBundleXReader::Pointer fibReader = FiberBundleXReader::New();
    fibReader->SetFileName(argv[1]);
    fibReader->Update();
    FiberBundleX::Pointer fiberBundle = dynamic_cast<FiberBundleX*>(fibReader->GetOutput());

    // reference diffusion weighted images
    mitk::DiffusionImage<short>::Pointer stickBall = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[2])->GetData());
    mitk::DiffusionImage<short>::Pointer stickAstrosticks = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[3])->GetData());
    mitk::DiffusionImage<short>::Pointer stickDot = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[4])->GetData());
    mitk::DiffusionImage<short>::Pointer tensorBall = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[5])->GetData());
    mitk::DiffusionImage<short>::Pointer stickTensorBall = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[6])->GetData());
    mitk::DiffusionImage<short>::Pointer stickTensorBallAstrosticks = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[7])->GetData());
    mitk::DiffusionImage<short>::Pointer gibbsringing = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[8])->GetData());
    mitk::DiffusionImage<short>::Pointer ghost = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[9])->GetData());
    mitk::DiffusionImage<short>::Pointer aliasing = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[10])->GetData());
    mitk::DiffusionImage<short>::Pointer eddy = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[11])->GetData());
    mitk::DiffusionImage<short>::Pointer linearmotion = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[12])->GetData());
    mitk::DiffusionImage<short>::Pointer randommotion = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[13])->GetData());
    mitk::DiffusionImage<short>::Pointer spikes = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[14])->GetData());
    mitk::DiffusionImage<short>::Pointer riciannoise = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[15])->GetData());
    mitk::DiffusionImage<short>::Pointer chisquarenoise = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[16])->GetData());
    mitk::DiffusionImage<short>::Pointer distortions = dynamic_cast<mitk::DiffusionImage<short>*>(mitk::IOUtil::LoadDataNode(argv[17])->GetData());
    mitk::Image::Pointer mitkFMap = dynamic_cast<mitk::Image*>(mitk::IOUtil::LoadDataNode(argv[18])->GetData());
    typedef itk::Image<double, 3> ItkDoubleImgType;
    ItkDoubleImgType::Pointer fMap = ItkDoubleImgType::New();
    mitk::CastToItkImage<ItkDoubleImgType>(mitkFMap, fMap);

    FiberfoxParameters<double> parameters;
    parameters.m_DoSimulateRelaxation = true;
    parameters.m_SignalScale = 10000;
    parameters.m_ImageRegion = stickBall->GetVectorImage()->GetLargestPossibleRegion();
    parameters.m_ImageSpacing = stickBall->GetVectorImage()->GetSpacing();
    parameters.m_ImageOrigin = stickBall->GetVectorImage()->GetOrigin();
    parameters.m_ImageDirection = stickBall->GetVectorImage()->GetDirection();
    parameters.m_Bvalue = stickBall->GetB_Value();
    parameters.SetGradienDirections(stickBall->GetDirections());

    // intra and inter axonal compartments
    mitk::StickModel<double> stickModel;
    stickModel.SetBvalue(parameters.m_Bvalue);
    stickModel.SetT2(110);
    stickModel.SetDiffusivity(0.001);
    stickModel.SetGradientList(parameters.GetGradientDirections());

    mitk::TensorModel<double> tensorModel;
    tensorModel.SetT2(110);
    stickModel.SetBvalue(parameters.m_Bvalue);
    tensorModel.SetDiffusivity1(0.001);
    tensorModel.SetDiffusivity2(0.00025);
    tensorModel.SetDiffusivity3(0.00025);
    tensorModel.SetGradientList(parameters.GetGradientDirections());

    // extra axonal compartment models
    mitk::BallModel<double> ballModel;
    ballModel.SetT2(80);
    ballModel.SetBvalue(parameters.m_Bvalue);
    ballModel.SetDiffusivity(0.001);
    ballModel.SetGradientList(parameters.GetGradientDirections());

    mitk::AstroStickModel<double> astrosticksModel;
    astrosticksModel.SetT2(80);
    astrosticksModel.SetBvalue(parameters.m_Bvalue);
    astrosticksModel.SetDiffusivity(0.001);
    astrosticksModel.SetRandomizeSticks(true);
    astrosticksModel.SetSeed(0);
    astrosticksModel.SetGradientList(parameters.GetGradientDirections());

    mitk::DotModel<double> dotModel;
    dotModel.SetT2(80);
    dotModel.SetGradientList(parameters.GetGradientDirections());

    // noise models
    mitk::RicianNoiseModel<double>* ricianNoiseModel = new mitk::RicianNoiseModel<double>();
    ricianNoiseModel->SetNoiseVariance(1000000);
    ricianNoiseModel->SetSeed(0);

    // Rician noise
    mitk::ChiSquareNoiseModel<double>* chiSquareNoiseModel = new mitk::ChiSquareNoiseModel<double>();
    chiSquareNoiseModel->SetNoiseVariance(1000000);
    chiSquareNoiseModel->SetSeed(0);

    try {
        // Stick-Ball
        parameters.m_FiberModelList.push_back(&stickModel);
        parameters.m_NonFiberModelList.push_back(&ballModel);
        StartSimulation(parameters, fiberBundle, stickBall, argv[2]);

        // Srick-Astrosticks
        parameters.m_NonFiberModelList.clear();
        parameters.m_NonFiberModelList.push_back(&astrosticksModel);
        StartSimulation(parameters, fiberBundle, stickAstrosticks, argv[3]);

        // Stick-Dot
        parameters.m_NonFiberModelList.clear();
        parameters.m_NonFiberModelList.push_back(&dotModel);
        StartSimulation(parameters, fiberBundle, stickDot, argv[4]);

        // Tensor-Ball
        parameters.m_FiberModelList.clear();
        parameters.m_FiberModelList.push_back(&tensorModel);
        parameters.m_NonFiberModelList.clear();
        parameters.m_NonFiberModelList.push_back(&ballModel);
        StartSimulation(parameters, fiberBundle, tensorBall, argv[5]);

        // Stick-Tensor-Ball
        parameters.m_FiberModelList.clear();
        parameters.m_FiberModelList.push_back(&stickModel);
        parameters.m_FiberModelList.push_back(&tensorModel);
        parameters.m_NonFiberModelList.clear();
        parameters.m_NonFiberModelList.push_back(&ballModel);
        StartSimulation(parameters, fiberBundle, stickTensorBall, argv[6]);

        // Stick-Tensor-Ball-Astrosticks
        parameters.m_NonFiberModelList.push_back(&astrosticksModel);
        StartSimulation(parameters, fiberBundle, stickTensorBallAstrosticks, argv[7]);

        // Gibbs ringing
        parameters.m_FiberModelList.clear();
        parameters.m_FiberModelList.push_back(&stickModel);
        parameters.m_NonFiberModelList.clear();
        parameters.m_NonFiberModelList.push_back(&ballModel);
        parameters.m_DoAddGibbsRinging = true;
        StartSimulation(parameters, fiberBundle, gibbsringing, argv[8]);

        // Ghost
        parameters.m_DoAddGibbsRinging = false;
        parameters.m_KspaceLineOffset = 0.25;
        StartSimulation(parameters, fiberBundle, ghost, argv[9]);

        // Aliasing
        parameters.m_KspaceLineOffset = 0;
        parameters.m_CroppingFactor = 0.4;
        parameters.m_SignalScale = 1000;
        StartSimulation(parameters, fiberBundle, aliasing, argv[10]);

        // Eddy currents
        parameters.m_CroppingFactor = 1;
        parameters.m_SignalScale = 10000;
        parameters.m_EddyStrength = 0.05;
        StartSimulation(parameters, fiberBundle, eddy, argv[11]);

        // Motion (linear)
        parameters.m_EddyStrength = 0.0;
        parameters.m_DoAddMotion = true;
        parameters.m_DoRandomizeMotion = false;
        parameters.m_Translation[1] = 10;
        parameters.m_Rotation[2] = 90;
        StartSimulation(parameters, fiberBundle, linearmotion, argv[12]);

        // Motion (random)
        parameters.m_DoRandomizeMotion = true;
        parameters.m_Translation[1] = 5;
        parameters.m_Rotation[2] = 45;
        StartSimulation(parameters, fiberBundle, randommotion, argv[13]);

        // Spikes
        parameters.m_DoAddMotion = false;
        parameters.m_Spikes = 5;
        parameters.m_SpikeAmplitude = 1;
        StartSimulation(parameters, fiberBundle, spikes, argv[14]);

        // Rician noise
        parameters.m_Spikes = 0;
        parameters.m_NoiseModel = ricianNoiseModel;
        StartSimulation(parameters, fiberBundle, riciannoise, argv[15]);
        delete parameters.m_NoiseModel;

        // Chi-square noise
        parameters.m_NoiseModel = chiSquareNoiseModel;
        StartSimulation(parameters, fiberBundle, chisquarenoise, argv[16]);
        delete parameters.m_NoiseModel;

        // Distortions
        parameters.m_NoiseModel = NULL;
        parameters.m_FrequencyMap = fMap;
        StartSimulation(parameters, fiberBundle, distortions, argv[17]);
    }
    catch (std::exception &e)
    {
        MITK_TEST_CONDITION_REQUIRED(false, e.what());
    }

    // always end with this!
    MITK_TEST_END();
}