Beispiel #1
0
void run() {

  value_type cluster_forming_threshold = get_option_value ("threshold", NAN);
  value_type tfce_dh = get_option_value ("tfce_dh", DEFAULT_TFCE_DH);
  value_type tfce_H = get_option_value ("tfce_h", DEFAULT_TFCE_H);
  value_type tfce_E = get_option_value ("tfce_e", DEFAULT_TFCE_E);
  int num_perms = get_option_value ("nperms", DEFAULT_PERMUTATIONS);
  int nperms_nonstationary = get_option_value ("nperms_nonstationary", DEFAULT_PERMUTATIONS_NONSTATIONARITY);
  
  bool do_26_connectivity = get_options("connectivity").size();
  bool do_nonstationary_adjustment = get_options ("nonstationary").size();

  // Read filenames
  std::vector<std::string> subjects;
  {
    std::string folder = Path::dirname (argument[0]);
    std::ifstream ifs (argument[0].c_str());
    std::string temp;
    while (getline (ifs, temp))
      subjects.push_back (Path::join (folder, temp));
  }

  // Load design matrix:
  Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> design = load_matrix<value_type> (argument[1]);
  if (design.rows() != (ssize_t)subjects.size())
    throw Exception ("number of input files does not match number of rows in design matrix");

  // Load contrast matrix:
  Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> contrast = load_matrix<value_type> (argument[2]);
  if (contrast.cols() != design.cols())
    throw Exception ("the number of contrasts does not equal the number of columns in the design matrix");

  // Load Mask
  auto header = Header::open (argument[3]);
  auto mask_image = header.get_image<value_type>();

  Filter::Connector connector (do_26_connectivity);
  std::vector<std::vector<int> > mask_indices = connector.precompute_adjacency (mask_image);

  const size_t num_vox = mask_indices.size();
  Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> data (num_vox, subjects.size());


  {
    // Load images
    ProgressBar progress("loading images", subjects.size());
    for (size_t subject = 0; subject < subjects.size(); subject++) {
      LogLevelLatch log_level (0);
      auto input_image = Image<float>::open(subjects[subject]).with_direct_io (3);
      check_dimensions (input_image, mask_image, 0, 3);
      int index = 0;
      std::vector<std::vector<int> >::iterator it;
      for (it = mask_indices.begin(); it != mask_indices.end(); ++it) {
        input_image.index(0) = (*it)[0];
        input_image.index(1) = (*it)[1];
        input_image.index(2) = (*it)[2];
        data (index++, subject) = input_image.value();
      }
      progress++;
    }
  }

  Header output_header (header);
  output_header.datatype() = DataType::Float32;
  output_header.keyval()["num permutations"] = str(num_perms);
  output_header.keyval()["26 connectivity"] = str(do_26_connectivity);
  output_header.keyval()["nonstationary adjustment"] = str(do_nonstationary_adjustment);
  if (std::isfinite (cluster_forming_threshold)) {
    output_header.keyval()["threshold"] = str(cluster_forming_threshold);
  } else {
    output_header.keyval()["tfce_dh"] = str(tfce_dh);
    output_header.keyval()["tfce_e"] = str(tfce_E);
    output_header.keyval()["tfce_h"] = str(tfce_H);
  }

  std::string prefix (argument[4]);

  std::string cluster_name (prefix);
  if (std::isfinite (cluster_forming_threshold))
     cluster_name.append ("cluster_sizes.mif");
  else
    cluster_name.append ("tfce.mif");

  auto cluster_image = Image<value_type>::create (cluster_name, output_header);
  auto tvalue_image = Image<value_type>::create (prefix + "tvalue.mif", output_header);
  auto fwe_pvalue_image = Image<value_type>::create (prefix + "fwe_pvalue.mif", output_header);
  auto uncorrected_pvalue_image = Image<value_type>::create (prefix + "uncorrected_pvalue.mif", output_header);
  Image<value_type> cluster_image_neg;
  Image<value_type> fwe_pvalue_image_neg;
  Image<value_type> uncorrected_pvalue_image_neg;

  Eigen::Matrix<value_type, Eigen::Dynamic, 1> perm_distribution (num_perms);
  std::shared_ptr<Eigen::Matrix<value_type, Eigen::Dynamic, 1> > perm_distribution_neg;
  std::vector<value_type> default_cluster_output (num_vox, 0.0);
  std::shared_ptr<std::vector<value_type> > default_cluster_output_neg;
  std::vector<value_type> tvalue_output (num_vox, 0.0);
  std::shared_ptr<std::vector<double> > empirical_tfce_statistic;
  std::vector<value_type> uncorrected_pvalue (num_vox, 0.0);
  std::shared_ptr<std::vector<value_type> > uncorrected_pvalue_neg;


  bool compute_negative_contrast = get_options("negative").size() ? true : false;
  if (compute_negative_contrast) {
    std::string cluster_neg_name (prefix);
    if (std::isfinite (cluster_forming_threshold))
       cluster_neg_name.append ("cluster_sizes_neg.mif");
    else
      cluster_neg_name.append ("tfce_neg.mif");
    cluster_image_neg = Image<value_type>::create (cluster_neg_name, output_header);
    perm_distribution_neg.reset (new Eigen::Matrix<value_type, Eigen::Dynamic, 1> (num_perms));
    default_cluster_output_neg.reset (new std::vector<value_type> (num_vox, 0.0));
    fwe_pvalue_image_neg = Image<value_type>::create (prefix + "fwe_pvalue_neg.mif", output_header);
    uncorrected_pvalue_neg.reset (new std::vector<value_type> (num_vox, 0.0));
    uncorrected_pvalue_image_neg = Image<value_type>::create (prefix + "uncorrected_pvalue_neg.mif", output_header);
  }

  { // Do permutation testing:
    Math::Stats::GLMTTest glm (data, design, contrast);

    // Suprathreshold clustering
    if (std::isfinite (cluster_forming_threshold)) {
      if (do_nonstationary_adjustment)
        throw Exception ("nonstationary adjustment is not currently implemented for threshold-based cluster analysis");
      Stats::Cluster::ClusterSize cluster_size_test (connector, cluster_forming_threshold);

      Stats::PermTest::precompute_default_permutation (glm, cluster_size_test, empirical_tfce_statistic,
                                                       default_cluster_output, default_cluster_output_neg, tvalue_output);



      Stats::PermTest::run_permutations (glm, cluster_size_test, num_perms, empirical_tfce_statistic,
                                         default_cluster_output, default_cluster_output_neg,
                                         perm_distribution, perm_distribution_neg,
                                         uncorrected_pvalue, uncorrected_pvalue_neg);
    // TFCE
    } else {
      Stats::TFCE::Enhancer tfce_integrator (connector, tfce_dh, tfce_E, tfce_H);
      if (do_nonstationary_adjustment) {
        empirical_tfce_statistic.reset (new std::vector<double> (num_vox, 0.0));
        Stats::PermTest::precompute_empirical_stat (glm, tfce_integrator, nperms_nonstationary, *empirical_tfce_statistic);
      }

      Stats::PermTest::precompute_default_permutation (glm, tfce_integrator, empirical_tfce_statistic,
                                                       default_cluster_output, default_cluster_output_neg, tvalue_output);

      Stats::PermTest::run_permutations (glm, tfce_integrator, num_perms, empirical_tfce_statistic,
                                         default_cluster_output, default_cluster_output_neg,
                                         perm_distribution, perm_distribution_neg,
                                         uncorrected_pvalue, uncorrected_pvalue_neg);
    }
  }

  save_matrix (perm_distribution, prefix + "perm_dist.txt");

  std::vector<value_type> pvalue_output (num_vox, 0.0);
  Math::Stats::statistic2pvalue (perm_distribution, default_cluster_output, pvalue_output);
  {
    ProgressBar progress ("generating output");
    for (size_t i = 0; i < num_vox; i++) {
      for (size_t dim = 0; dim < cluster_image.ndim(); dim++)
        tvalue_image.index(dim) = cluster_image.index(dim) = fwe_pvalue_image.index(dim) = uncorrected_pvalue_image.index(dim) = mask_indices[i][dim];
      tvalue_image.value() = tvalue_output[i];
      cluster_image.value() = default_cluster_output[i];
      fwe_pvalue_image.value() = pvalue_output[i];
      uncorrected_pvalue_image.value() = uncorrected_pvalue[i];
    }
  }
  {
    if (compute_negative_contrast) {
      save_matrix (*perm_distribution_neg, prefix + "perm_dist_neg.txt");
      std::vector<value_type> pvalue_output_neg (num_vox, 0.0);
      Math::Stats::statistic2pvalue (*perm_distribution_neg, *default_cluster_output_neg, pvalue_output_neg);

      ProgressBar progress ("generating negative contrast output");
      for (size_t i = 0; i < num_vox; i++) {
        for (size_t dim = 0; dim < cluster_image.ndim(); dim++)
          cluster_image_neg.index(dim) = fwe_pvalue_image_neg.index(dim) = uncorrected_pvalue_image_neg.index(dim) = mask_indices[i][dim];
        cluster_image_neg.value() = (*default_cluster_output_neg)[i];
        fwe_pvalue_image_neg.value() = pvalue_output_neg[i];
        uncorrected_pvalue_image_neg.value() = (*uncorrected_pvalue_neg)[i];
      }
    }

  }
}
Beispiel #2
0
void run() {

  const value_type cluster_forming_threshold = get_option_value ("threshold", NaN);
  const value_type tfce_dh = get_option_value ("tfce_dh", DEFAULT_TFCE_DH);
  const value_type tfce_H = get_option_value ("tfce_h", DEFAULT_TFCE_H);
  const value_type tfce_E = get_option_value ("tfce_e", DEFAULT_TFCE_E);
  const bool use_tfce = !std::isfinite (cluster_forming_threshold);
  int num_perms = get_option_value ("nperms", DEFAULT_NUMBER_PERMUTATIONS);
  int nperms_nonstationary = get_option_value ("nperms_nonstationary", DEFAULT_NUMBER_PERMUTATIONS_NONSTATIONARITY);

  const bool do_26_connectivity = get_options("connectivity").size();
  const bool do_nonstationary_adjustment = get_options ("nonstationary").size();

  // Read filenames
  vector<std::string> subjects;
  {
    std::string folder = Path::dirname (argument[0]);
    std::ifstream ifs (argument[0].c_str());
    std::string temp;
    while (getline (ifs, temp))
      subjects.push_back (Path::join (folder, temp));
  }

  // Load design matrix
  const matrix_type design = load_matrix<value_type> (argument[1]);
  if (design.rows() != (ssize_t)subjects.size())
    throw Exception ("number of input files does not match number of rows in design matrix");

  // Load permutations file if supplied
  auto opt = get_options("permutations");
  vector<vector<size_t> > permutations;
  if (opt.size()) {
    permutations = Math::Stats::Permutation::load_permutations_file (opt[0][0]);
    num_perms = permutations.size();
    if (permutations[0].size() != (size_t)design.rows())
       throw Exception ("number of rows in the permutations file (" + str(opt[0][0]) + ") does not match number of rows in design matrix");
  }

  // Load non-stationary correction permutations file if supplied
  opt = get_options("permutations_nonstationary");
  vector<vector<size_t> > permutations_nonstationary;
  if (opt.size()) {
    permutations_nonstationary = Math::Stats::Permutation::load_permutations_file (opt[0][0]);
    nperms_nonstationary = permutations.size();
    if (permutations_nonstationary[0].size() != (size_t)design.rows())
      throw Exception ("number of rows in the nonstationary permutations file (" + str(opt[0][0]) + ") does not match number of rows in design matrix");
  }

  // Load contrast matrix
  const matrix_type contrast = load_matrix<value_type> (argument[2]);
  if (contrast.cols() != design.cols())
    throw Exception ("the number of contrasts does not equal the number of columns in the design matrix");

  auto mask_header = Header::open (argument[3]);
  // Load Mask and compute adjacency
  auto mask_image = mask_header.get_image<value_type>();
  Filter::Connector connector (do_26_connectivity);
  vector<vector<int> > mask_indices = connector.precompute_adjacency (mask_image);
  const size_t num_vox = mask_indices.size();

  matrix_type data (num_vox, subjects.size());

  {
    // Load images
    ProgressBar progress("loading images", subjects.size());
    for (size_t subject = 0; subject < subjects.size(); subject++) {
      LogLevelLatch log_level (0);
      auto input_image = Image<float>::open (subjects[subject]); //.with_direct_io (3); <- Should be inputting 3D images?
      check_dimensions (input_image, mask_image, 0, 3);
      int index = 0;
      vector<vector<int> >::iterator it;
      for (it = mask_indices.begin(); it != mask_indices.end(); ++it) {
        input_image.index(0) = (*it)[0];
        input_image.index(1) = (*it)[1];
        input_image.index(2) = (*it)[2];
        data (index++, subject) = input_image.value();
      }
      progress++;
    }
  }
  if (!data.allFinite())
    WARN ("input data contains non-finite value(s)");

  Header output_header (mask_header);
  output_header.datatype() = DataType::Float32;
  output_header.keyval()["num permutations"] = str(num_perms);
  output_header.keyval()["26 connectivity"] = str(do_26_connectivity);
  output_header.keyval()["nonstationary adjustment"] = str(do_nonstationary_adjustment);
  if (use_tfce) {
    output_header.keyval()["tfce_dh"] = str(tfce_dh);
    output_header.keyval()["tfce_e"] = str(tfce_E);
    output_header.keyval()["tfce_h"] = str(tfce_H);
  } else {
    output_header.keyval()["threshold"] = str(cluster_forming_threshold);
  }

  const std::string prefix (argument[4]);
  bool compute_negative_contrast = get_options("negative").size();

  vector_type default_cluster_output (num_vox);
  std::shared_ptr<vector_type> default_cluster_output_neg;
  vector_type tvalue_output (num_vox);
  vector_type empirical_enhanced_statistic;
  if (compute_negative_contrast)
    default_cluster_output_neg.reset (new vector_type (num_vox));

  Math::Stats::GLMTTest glm (data, design, contrast);

  std::shared_ptr<Stats::EnhancerBase> enhancer;
  if (use_tfce) {
    std::shared_ptr<Stats::TFCE::EnhancerBase> base (new Stats::Cluster::ClusterSize (connector, cluster_forming_threshold));
    enhancer.reset (new Stats::TFCE::Wrapper (base, tfce_dh, tfce_E, tfce_H));
  } else {
    enhancer.reset (new Stats::Cluster::ClusterSize (connector, cluster_forming_threshold));
  }

  if (do_nonstationary_adjustment) {
    if (!use_tfce)
      throw Exception ("nonstationary adjustment is not currently implemented for threshold-based cluster analysis");
    empirical_enhanced_statistic = vector_type::Zero (num_vox);
    if (permutations_nonstationary.size()) {
      Stats::PermTest::PermutationStack permutations (permutations_nonstationary, "precomputing empirical statistic for non-stationarity adjustment...");
      Stats::PermTest::precompute_empirical_stat (glm, enhancer, permutations, empirical_enhanced_statistic);
    } else {
      Stats::PermTest::PermutationStack permutations (nperms_nonstationary, design.rows(), "precomputing empirical statistic for non-stationarity adjustment...", false);
      Stats::PermTest::precompute_empirical_stat (glm, enhancer, permutations, empirical_enhanced_statistic);
    }

    save_matrix (empirical_enhanced_statistic, prefix + "empirical.txt");
  }

  Stats::PermTest::precompute_default_permutation (glm, enhancer, empirical_enhanced_statistic,
                                                   default_cluster_output, default_cluster_output_neg, tvalue_output);

  {
    ProgressBar progress ("generating pre-permutation output", (compute_negative_contrast ? 3 : 2) + contrast.cols() + 3);
    {
      auto tvalue_image = Image<float>::create (prefix + "tvalue.mif", output_header);
      write_output (tvalue_output, mask_indices, tvalue_image);
    }
    ++progress;
    {
      auto cluster_image = Image<float>::create (prefix + (use_tfce ? "tfce.mif" : "cluster_sizes.mif"), output_header);
      write_output (default_cluster_output, mask_indices, cluster_image);
    }
    ++progress;
    if (compute_negative_contrast) {
      assert (default_cluster_output_neg);
      auto cluster_image_neg = Image<float>::create (prefix + (use_tfce ? "tfce_neg.mif" : "cluster_sizes_neg.mif"), output_header);
      write_output (*default_cluster_output_neg, mask_indices, cluster_image_neg);
      ++progress;
    }
    auto temp = Math::Stats::GLM::solve_betas (data, design);
    for (ssize_t i = 0; i < contrast.cols(); ++i) {
      auto beta_image = Image<float>::create (prefix + "beta" + str(i) + ".mif", output_header);
      write_output (temp.row(i), mask_indices, beta_image);
      ++progress;
    }
    {
      const auto temp = Math::Stats::GLM::abs_effect_size (data, design, contrast);
      auto abs_effect_image = Image<float>::create (prefix + "abs_effect.mif", output_header);
      write_output (temp.row(0), mask_indices, abs_effect_image);
    }
    ++progress;
    {
      const auto temp = Math::Stats::GLM::std_effect_size (data, design, contrast);
      auto std_effect_image = Image<float>::create (prefix + "std_effect.mif", output_header);
      write_output (temp.row(0), mask_indices, std_effect_image);
    }
    ++progress;
    {
      const auto temp = Math::Stats::GLM::stdev (data, design);
      auto std_dev_image = Image<float>::create (prefix + "std_dev.mif", output_header);
      write_output (temp.row(0), mask_indices, std_dev_image);
    }
  }

  if (!get_options ("notest").size()) {

    vector_type perm_distribution (num_perms);
    std::shared_ptr<vector_type> perm_distribution_neg;
    vector_type uncorrected_pvalue (num_vox);
    std::shared_ptr<vector_type> uncorrected_pvalue_neg;

    if (compute_negative_contrast) {
      perm_distribution_neg.reset (new vector_type (num_perms));
      uncorrected_pvalue_neg.reset (new vector_type (num_vox));
    }

    if (permutations.size()) {
      Stats::PermTest::run_permutations (permutations, glm, enhancer, empirical_enhanced_statistic,
                                         default_cluster_output, default_cluster_output_neg,
                                         perm_distribution, perm_distribution_neg,
                                         uncorrected_pvalue, uncorrected_pvalue_neg);
    } else {
      Stats::PermTest::run_permutations (num_perms, glm, enhancer, empirical_enhanced_statistic,
                                         default_cluster_output, default_cluster_output_neg,
                                         perm_distribution, perm_distribution_neg,
                                         uncorrected_pvalue, uncorrected_pvalue_neg);
    }

    save_matrix (perm_distribution, prefix + "perm_dist.txt");
    if (compute_negative_contrast) {
      assert (perm_distribution_neg);
      save_matrix (*perm_distribution_neg, prefix + "perm_dist_neg.txt");
    }

    ProgressBar progress ("generating output", compute_negative_contrast ? 4 : 2);
    {
      auto uncorrected_pvalue_image = Image<float>::create (prefix + "uncorrected_pvalue.mif", output_header);
      write_output (uncorrected_pvalue, mask_indices, uncorrected_pvalue_image);
    }
    ++progress;
    {
      vector_type fwe_pvalue_output (num_vox);
      Math::Stats::Permutation::statistic2pvalue (perm_distribution, default_cluster_output, fwe_pvalue_output);
      auto fwe_pvalue_image = Image<float>::create (prefix + "fwe_pvalue.mif", output_header);
      write_output (fwe_pvalue_output, mask_indices, fwe_pvalue_image);
    }
    ++progress;
    if (compute_negative_contrast) {
      assert (uncorrected_pvalue_neg);
      assert (perm_distribution_neg);
      auto uncorrected_pvalue_image_neg = Image<float>::create (prefix + "uncorrected_pvalue_neg.mif", output_header);
      write_output (*uncorrected_pvalue_neg, mask_indices, uncorrected_pvalue_image_neg);
      ++progress;
      vector_type fwe_pvalue_output_neg (num_vox);
      Math::Stats::Permutation::statistic2pvalue (*perm_distribution_neg, *default_cluster_output_neg, fwe_pvalue_output_neg);
      auto fwe_pvalue_image_neg = Image<float>::create (prefix + "fwe_pvalue_neg.mif", output_header);
      write_output (fwe_pvalue_output_neg, mask_indices, fwe_pvalue_image_neg);
    }
  }

}