17#ifndef __dwi_sdeconv_msmt_csd_h__
18#define __dwi_sdeconv_msmt_csd_h__
31#define DEFAULT_MSMTCSD_LMAX 8
32#define DEFAULT_MSMTCSD_NORM_LAMBDA 1.0e-10
33#define DEFAULT_MSMTCSD_NEG_LAMBDA 1.0e-10
49 Shared (
const Header& dwi_header) :
57 void parse_cmdline_options()
62 lmax = parse_ints<uint32_t> (opt[0][0]);
68 solution_min_norm_regularisation = opt[0][0];
71 constraint_min_norm_regularisation = opt[0][0];
78 lmax_response.clear();
79 for (
const auto& s : files) {
84 throw Exception (
e,
"File \"" + s +
"\" is not a valid response function file");
86 responses.push_back (std::move (r));
89 response_files = files;
103 lmax = lmax_response;
104 for (
size_t t = 0; t != num_tissues(); ++t) {
108 if (lmax.size() != num_tissues())
109 throw Exception (
"Number of lmaxes specified (" +
str(lmax.size()) +
") does not match number of tissues (" +
str(num_tissues()) +
")");
110 for (
const auto i : lmax) {
112 throw Exception (
"Each value of lmax must be a non-negative even integer");
116 for (
size_t t = 0; t != num_tissues(); ++t) {
117 if (
size_t(responses[t].rows()) != num_shells())
118 throw Exception (
"number of rows in response functions must match number of b-value shells; "
119 "number of shells is " +
str(num_shells()) +
", but file \"" + response_files[t] +
"\" contains " +
str(responses[t].rows()) +
" rows");
121 responses[t].conservativeResizeLike (Eigen::MatrixXd::Zero (num_shells(),
Math::ZSH::NforL (lmax[t])));
129 uint32_t maxlmax = 0;
130 for (
size_t i = 0; i < num_tissues(); i++) {
132 maxlmax = std::max (maxlmax, lmax[i]);
135 INFO (
"initialising multi-tissue CSD for " +
str(num_tissues()) +
" tissue types, with " +
str (nparams) +
" parameters");
137 Eigen::MatrixXd C = Eigen::MatrixXd::Zero (grad.rows(), nparams);
140 for (
size_t i = 0; i != size_t(grad.rows()); i++)
141 dwilist.push_back(i);
145 for (ssize_t i = 0; i < SHT.rows(); i++)
146 for (ssize_t j = 0; j < SHT.cols(); j++)
147 if (std::isnan (SHT(i,j)))
153 Eigen::VectorXd DSH_ = DSH__.row(0);
154 Eigen::VectorXd DSH (maxlmax/2+1);
156 for (ssize_t i = 0; i < DSH_.size(); i++)
157 if (DSH_[i] != 0.0) {
163 for (
size_t tissue_idx = 0; tissue_idx < num_tissues(); ++tissue_idx) {
164 const size_t tissue_lmax = lmax[tissue_idx];
166 const size_t tissue_nmzero = tissue_lmax/2+1;
168 for (
size_t shell_idx = 0; shell_idx < num_shells(); ++shell_idx) {
169 Eigen::VectorXd response_ = responses[tissue_idx].row (shell_idx);
170 response_ = (response_.array() / DSH.head (tissue_nmzero).array()).matrix();
171 Eigen::VectorXd fconv (tissue_n);
172 int li = 0;
int mi = 0;
173 for (
int l = 0; l <= int(tissue_lmax); l+=2) {
174 for (
int m = -l; m <= l; m++) {
175 fconv[mi] = response_[li];
181 for (
size_t idx = 0; idx < vols.size(); idx++) {
182 Eigen::VectorXd SHT_(SHT.row (vols[idx]).head (tissue_n));
183 SHT_ = (SHT_.array()*fconv.array()).matrix();
184 C.row (vols[idx]).segment (pbegin, tissue_n) = SHT_;
197 for (
size_t i = 0; i != num_tissues(); i++) {
199 m[i] = HR_dirs.rows();
207 Eigen::MatrixXd A (Eigen::MatrixXd::Zero (M, N));
208 size_t b_m = 0;
size_t b_n = 0;
209 for (
size_t i = 0; i != num_tissues(); i++) {
210 A.block (b_m,b_n,m[i],n[i]) = HR_SHT.block (0,0,m[i],n[i]);
215 solution_min_norm_regularisation, constraint_min_norm_regularisation);
217 INFO (
"Multi-shell, multi-tissue CSD initialised successfully");
221 size_t num_shells()
const {
return shells.count(); }
222 size_t num_tissues()
const {
return responses.size(); }
225 const Eigen::MatrixXd grad;
227 Eigen::MatrixXd HR_dirs;
232 double solution_min_norm_regularisation, constraint_min_norm_regularisation;
237 void prepare_responses() {
238 for (
size_t t = 0; t != num_tissues(); ++t) {
239 Eigen::MatrixXd& r (responses[t]);
241 for (
size_t row = 0; row < size_t(r.rows()); row++) {
242 for (
size_t col = 0; col < size_t(r.cols()); col++) {
244 n = std::max (n, col+1);
248 r.conservativeResize (r.rows(), n);
262 MSMT_CSD (
const Shared& shared_data) :
264 shared (shared_data),
265 solver (shared.problem) { }
267 void operator() (
const Eigen::VectorXd& data, Eigen::VectorXd& output) {
268 niter = solver (output, data);
272 const Shared& shared;
VectorType1 & delta(VectorType1 &delta_vec, const VectorType2 &unit_dir, int lmax)
size_t NforL(int lmax)
the number of (even-degree) coefficients for the given value of lmax
Eigen::Matrix< typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic > init_transform(const MatrixType &dirs, const int lmax)
form the SH->amplitudes matrix
size_t NforL(int lmax)
the number of (even-degree) coefficients for the given value of lmax
size_t LforN(int N)
returns the largest lmax given N parameters
#define DEFAULT_MSMTCSD_LMAX
#define DEFAULT_MSMTCSD_NORM_LAMBDA
#define DEFAULT_MSMTCSD_NEG_LAMBDA
const vector< ParsedOption > get_options(const std::string &name)
return all command-line options matching name
void init(int argc, const char *const *argv)
initialise MRtrix and parse command-line arguments
Eigen::MatrixXd electrostatic_repulsion_300()
const App::OptionGroup MSMT_CSD_options
Eigen::MatrixXd get_DW_scheme(const Header &header, BValueScalingBehaviour bvalue_scaling=BValueScalingBehaviour::Auto)
get the fully-interpreted DW gradient encoding matrix
Eigen::MatrixXd gen_direction_matrix(const MatrixType &grad, const IndexVectorType &dwi)
convert the DW encoding matrix in grad into a azimuth/elevation direction set, using only the DWI vol...
Eigen::Matrix< ValueType, Eigen::Dynamic, Eigen::Dynamic > load_matrix(const std::string &filename)
read matrix data into an Eigen::Matrix filename
std::string str(const T &value, int precision=0)