From b255139e63f07daf1c28b97ac5b74a6bd1d63a3e Mon Sep 17 00:00:00 2001
From: Stamatios Sotiropoulos <stam@fmrib.ox.ac.uk>
Date: Thu, 17 May 2012 11:35:57 +0000
Subject: [PATCH] *** empty log message ***

---
 rubix.cc        |  645 +++++++++++++++++++++
 rubix.h         |  209 +++++++
 rubixoptions.cc |   53 ++
 rubixoptions.h  |  195 +++++++
 rubixvox.cc     | 1480 +++++++++++++++++++++++++++++++++++++++++++++++
 rubixvox.h      |  729 +++++++++++++++++++++++
 6 files changed, 3311 insertions(+)
 create mode 100644 rubix.cc
 create mode 100644 rubix.h
 create mode 100644 rubixoptions.cc
 create mode 100644 rubixoptions.h
 create mode 100644 rubixvox.cc
 create mode 100644 rubixvox.h

diff --git a/rubix.cc b/rubix.cc
new file mode 100644
index 0000000..c6a54bc
--- /dev/null
+++ b/rubix.cc
@@ -0,0 +1,645 @@
+/* 
+   RubiX
+   Stamatios Sotiropoulos, Saad Jbabdi and Tim Behrens  - FMRIB Image Analysis Group
+   Copyright (C) 2012 University of Oxford  
+   CCOPYRIGHT  
+*/
+
+
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#define WANT_STREAM
+#define WANT_MATH
+#include <string>
+#include <math.h>
+#include "utils/log.h"
+#include "utils/tracer_plus.h"
+#include "miscmaths/miscprob.h"
+#include "miscmaths/miscmaths.h"
+#include "miscmaths/nonlin.h"
+#include "newimage/newimageall.h"
+#include "stdlib.h"
+#include "rubixoptions.h"
+#include "rubixvox.h"
+#include "rubix.h"
+#include "diffmodels.h"
+
+using namespace RUBIX;
+using namespace Utilities;
+using namespace NEWMAT;
+using namespace NEWIMAGE;
+using namespace MISCMATHS;
+
+
+////////////////////////////////////////////
+//     HRSamples: MCMC SAMPLE STORAGE
+////////////////////////////////////////////
+
+//Store parameters for a certain sample at a certain HR voxel
+void HRSamples::record(const HRvoxel& HRv, int vox, int samp){
+  m_dsamples(samp,vox)=HRv.get_d();
+  m_S0samples(samp,vox)=HRv.get_S0();
+  if (m_rician)
+    m_tausamples(samp,vox)=HRv.get_tau();
+  if (m_modelnum==2)
+    m_d_stdsamples(samp,vox)=HRv.get_d_std();
+
+  for(int f=0; f<m_numfibres; f++){
+    m_thsamples[f](samp,vox)=HRv.fibres()[f].get_th();
+    m_phsamples[f](samp,vox)=HRv.fibres()[f].get_ph();
+    m_fsamples[f](samp,vox)=HRv.fibres()[f].get_f();
+  }
+}
+
+
+//Get the mean samples for a voxel once jumping has finished
+void HRSamples::finish_voxel(int vox){
+
+  m_mean_dsamples(vox)=m_dsamples.Column(vox).Sum()/m_nsamps;
+  m_mean_S0samples(vox)=m_S0samples.Column(vox).Sum()/m_nsamps;
+
+  if (m_rician)
+    m_mean_tausamples(vox)=m_tausamples.Column(vox).Sum()/m_nsamps;
+  if (m_modelnum==2)
+    m_mean_d_stdsamples(vox)=m_d_stdsamples.Column(vox).Sum()/m_nsamps;
+  
+  for(int f=0; f<m_numfibres; f++){  //for each fibre of the voxel
+    m_mean_fsamples[f](vox)=m_fsamples[f].Column(vox).Sum()/m_nsamps;
+
+    SymmetricMatrix m_dyad(3); m_dyad=0;
+    ColumnVector m_vec(3);
+    DiagonalMatrix dyad_D; //eigenvalues
+    Matrix dyad_V; //eigenvectors
+
+    //Get the sum of dyadic tensors across samples
+    for (int n=1; n<=m_nsamps; n++){
+      float th=m_thsamples[f](n,vox);
+      float ph=m_phsamples[f](n,vox);
+      m_vec << sin(th)*cos(ph) << sin(th)*sin(ph)<<cos(th) ;
+      m_dyad << m_dyad+m_vec*m_vec.t(); 
+    }
+    m_dyad=m_dyad/m_nsamps;
+
+    //Eigendecompose the mean dyadic tensor to get the mean orientation across samples
+    EigenValues(m_dyad,dyad_D,dyad_V);
+    int maxeig;
+    if(dyad_D(1)>dyad_D(2)){
+      if(dyad_D(1)>dyad_D(3)) maxeig=1;
+      else maxeig=3;
+    }
+    else{
+      if(dyad_D(2)>dyad_D(3)) maxeig=2;
+      else maxeig=3;
+    }
+    m_dyadic_vectors[f](1,vox)=dyad_V(1,maxeig);
+    m_dyadic_vectors[f](2,vox)=dyad_V(2,maxeig);
+    m_dyadic_vectors[f](3,vox)=dyad_V(3,maxeig);
+  }
+}
+
+
+//save samples for all voxels
+void HRSamples::save(const volume<float>& mask){
+  volume4D<float> tmp;
+  //So that I can sort the output fibres into
+  // files ordered by fibre fractional volume..
+  vector<Matrix> thsamples_out=m_thsamples;
+  vector<Matrix> phsamples_out=m_phsamples;
+  vector<Matrix> fsamples_out=m_fsamples;
+    
+  vector<Matrix> dyadic_vectors_out=m_dyadic_vectors;
+  vector<Matrix> mean_fsamples_out;
+  for(unsigned int f=0;f<m_mean_fsamples.size();f++)
+    mean_fsamples_out.push_back(m_mean_fsamples[f]);
+
+  Log& logger = LogSingleton::getInstance();
+  tmp.setmatrix(m_mean_dsamples,mask);
+  tmp.setDisplayMaximumMinimum(tmp.max(),0);
+  save_volume(tmp[0],logger.appendDir("mean_dsamples"));
+  
+  tmp.setmatrix(m_mean_S0samples,mask);
+  tmp.setDisplayMaximumMinimum(tmp.max(),0);
+  save_volume(tmp[0],logger.appendDir("mean_S0samples"));
+  
+  if (m_rician){
+    tmp.setmatrix(m_mean_tausamples,mask);
+    tmp.setDisplayMaximumMinimum(tmp.max(),0);
+    save_volume(tmp[0],logger.appendDir("mean_tausamples"));
+  }
+
+  if (m_modelnum==2){
+    tmp.setmatrix(m_mean_d_stdsamples,mask);
+    tmp.setDisplayMaximumMinimum(tmp.max(),0);
+    save_volume(tmp[0],logger.appendDir("mean_dstd_samples"));
+  }
+
+  //Sort the output based on mean_fsamples
+  vector<Matrix> sumf;
+  for(int f=0; f<m_numfibres; f++){
+    Matrix tmp=sum(m_fsamples[f],1);
+    sumf.push_back(tmp);
+  }  
+  for(int vox=1;vox<=m_dsamples.Ncols();vox++){
+    vector<pair<float,int> > sfs;
+    pair<float,int> ftmp;
+      
+    for(int f=0; f<m_numfibres; f++){
+      ftmp.first=sumf[f](1,vox);
+      ftmp.second=f;
+      sfs.push_back(ftmp);
+    }
+    sort(sfs.begin(),sfs.end());
+      
+    for(int samp=1;samp<=m_dsamples.Nrows();samp++){
+      for(int f=0; f<m_numfibres; f++){;
+	thsamples_out[f](samp,vox)=m_thsamples[sfs[(sfs.size()-1)-f].second](samp,vox);
+	phsamples_out[f](samp,vox)=m_phsamples[sfs[(sfs.size()-1)-f].second](samp,vox);
+	fsamples_out[f](samp,vox)=m_fsamples[sfs[(sfs.size()-1)-f].second](samp,vox);
+      }
+    }
+      
+    for(int f=0;f<m_numfibres;f++){
+      mean_fsamples_out[f](1,vox)=m_mean_fsamples[sfs[(sfs.size()-1)-f].second](vox);
+      dyadic_vectors_out[f](1,vox)=m_dyadic_vectors[sfs[(sfs.size()-1)-f].second](1,vox);
+      dyadic_vectors_out[f](2,vox)=m_dyadic_vectors[sfs[(sfs.size()-1)-f].second](2,vox);
+      dyadic_vectors_out[f](3,vox)=m_dyadic_vectors[sfs[(sfs.size()-1)-f].second](3,vox);
+    }
+  }
+  
+  tmp.setmatrix(m_dsamples,mask);
+  tmp.setDisplayMaximumMinimum(tmp.max(),tmp.min());
+  save_volume4D(tmp,logger.appendDir("d_samples"));
+
+  // save the sorted fibres
+  for(int f=0; f<m_numfibres; f++){
+    tmp.setmatrix(thsamples_out[f],mask);
+    tmp.setDisplayMaximumMinimum(tmp.max(),tmp.min());
+    string oname="th"+num2str(f+1)+"samples";
+    save_volume4D(tmp,logger.appendDir(oname));
+      
+    tmp.setmatrix(phsamples_out[f],mask);
+    tmp.setDisplayMaximumMinimum(tmp.max(),tmp.min());
+    oname="ph"+num2str(f+1)+"samples";
+    save_volume4D(tmp,logger.appendDir(oname));
+   
+    tmp.setmatrix(fsamples_out[f],mask);
+    tmp.setDisplayMaximumMinimum(1,0);
+    oname="f"+num2str(f+1)+"samples";
+    save_volume4D(tmp,logger.appendDir(oname));
+
+    tmp.setmatrix(mean_fsamples_out[f],mask);
+    tmp.setDisplayMaximumMinimum(1,0);
+    oname="mean_f"+num2str(f+1)+"samples";
+    save_volume(tmp[0],logger.appendDir(oname));
+      
+    tmp.setmatrix(dyadic_vectors_out[f],mask);
+    tmp.setDisplayMaximumMinimum(1,-1);
+    oname="dyads"+num2str(f+1);
+    save_volume4D(tmp,logger.appendDir(oname));
+  }
+}
+
+
+
+
+////////////////////////////////////////////
+//     LRSamples: MCMC SAMPLE STORAGE
+////////////////////////////////////////////
+//Store parameters for a certain sample at a certain LR voxel
+void LRSamples::record(const LRvoxel& LRv, int vox, int samp){
+  m_S0samples(samp,vox)=LRv.get_S0LR();
+
+  if (m_rician)
+    m_tauLRsamples(samp,vox)=LRv.get_tauLR();
+
+  m_lik_energy(samp,vox)=LRv.get_likelihood_energy();
+  m_prior_energy(samp,vox)=LRv.get_prior_energy();
+
+  for(int m=0; m<m_Nmodes; m++){
+    m_thsamples[m](samp,vox)=LRv.PModes()[m].get_th();
+    m_phsamples[m](samp,vox)=LRv.PModes()[m].get_ph();
+    m_ksamples[m](samp,vox)=1.0/LRv.PModes()[m].get_invkappa();
+  }
+}
+
+
+//Get the mean samples for a voxel once jumping has finished
+void LRSamples::finish_voxel(int vox){
+  m_mean_S0samples(vox)=m_S0samples.Column(vox).Sum()/m_nsamps;
+  if (m_rician)
+    m_mean_tausamples(vox)=m_tauLRsamples.Column(vox).Sum()/m_nsamps;
+ 
+  for(int m=0; m<m_Nmodes; m++){
+    m_mean_ksamples[m](vox)=m_ksamples[m].Column(vox).Sum()/m_nsamps;
+
+    DiagonalMatrix dyad_D; //eigenvalues
+    Matrix dyad_V; //eigenvectors
+    ColumnVector m_vec(3); 
+    SymmetricMatrix m_dyad(3); m_dyad=0;
+  
+    for (int n=1; n<=m_nsamps; n++){
+      float th=m_thsamples[m](n,vox);
+      float ph=m_phsamples[m](n,vox);
+      m_vec << sin(th)*cos(ph) << sin(th)*sin(ph)<<cos(th) ;
+      m_dyad << m_dyad+m_vec*m_vec.t(); 
+    }
+    m_dyad=m_dyad/m_nsamps;
+
+    //Eigendecompose the mean dyadic tensor to get the mean orientation across samples
+    EigenValues(m_dyad,dyad_D,dyad_V);
+    int maxeig;
+    if(dyad_D(1)>dyad_D(2)){
+      if(dyad_D(1)>dyad_D(3)) maxeig=1;
+      else maxeig=3;
+    }
+    else{
+      if(dyad_D(2)>dyad_D(3)) maxeig=2;
+      else maxeig=3;
+    }
+    m_dyadic_vectors[m](1,vox)=dyad_V(1,maxeig);
+    m_dyadic_vectors[m](2,vox)=dyad_V(2,maxeig);
+    m_dyadic_vectors[m](3,vox)=dyad_V(3,maxeig);
+  }
+}
+
+
+//save samples for all voxels
+void LRSamples::save(const volume<float>& mask){
+  volume4D<float> tmp;
+  //So that I can sort the output fibres into
+  // files ordered by dispersion..
+  vector<Matrix> thsamples_out=m_thsamples;
+  vector<Matrix> phsamples_out=m_phsamples;
+  vector<Matrix> ksamples_out=m_ksamples;
+    
+  vector<Matrix> dyadic_vectors_out=m_dyadic_vectors;
+  vector<Matrix> mean_ksamples_out;
+  for(unsigned int f=0;f<m_mean_ksamples.size();f++)
+    mean_ksamples_out.push_back(m_mean_ksamples[f]);
+
+  Log& logger = LogSingleton::getInstance();
+  tmp.setmatrix(m_mean_S0samples,mask);
+  tmp.setDisplayMaximumMinimum(tmp.max(),0);
+  save_volume(tmp[0],logger.appendDir("mean_S0LRsamples"));
+  
+  tmp.setmatrix(m_lik_energy,mask);
+  tmp.setDisplayMaximumMinimum(tmp.max(),0);
+  save_volume4D(tmp,logger.appendDir("En_Lik_samples"));
+
+  tmp.setmatrix(m_prior_energy,mask);
+  tmp.setDisplayMaximumMinimum(tmp.max(),0);
+  save_volume4D(tmp,logger.appendDir("En_Prior_samples"));
+
+  if (m_rician){
+    tmp.setmatrix(m_mean_tausamples,mask);
+    tmp.setDisplayMaximumMinimum(tmp.max(),0);
+    save_volume(tmp[0],logger.appendDir("mean_tauLRsamples"));
+  }
+
+  //Sort the output based on mean_invksamples
+  vector<Matrix> sumk;
+  for(int f=0; f<m_Nmodes; f++){
+    Matrix tmp=sum(m_ksamples[f],1);
+    sumk.push_back(tmp);
+  }  
+  for(int vox=1;vox<=m_S0samples.Ncols();vox++){
+    vector<pair<float,int> > sfs;
+    pair<float,int> ftmp;
+      
+    for(int f=0; f<m_Nmodes; f++){
+      ftmp.first=sumk[f](1,vox);
+      ftmp.second=f;
+      sfs.push_back(ftmp);
+    }
+    sort(sfs.begin(),sfs.end());
+      
+    for(int samp=1; samp<=m_nsamps; samp++){
+      for(int f=0; f<m_Nmodes; f++){;
+	thsamples_out[f](samp,vox)=m_thsamples[sfs[(sfs.size()-1)-f].second](samp,vox);
+	phsamples_out[f](samp,vox)=m_phsamples[sfs[(sfs.size()-1)-f].second](samp,vox);
+	ksamples_out[f](samp,vox)=m_ksamples[sfs[(sfs.size()-1)-f].second](samp,vox);
+      }
+    }
+      
+    for(int f=0;f<m_Nmodes;f++){
+      mean_ksamples_out[f](1,vox)=m_mean_ksamples[sfs[(sfs.size()-1)-f].second](vox);
+      dyadic_vectors_out[f](1,vox)=m_dyadic_vectors[sfs[(sfs.size()-1)-f].second](1,vox);
+      dyadic_vectors_out[f](2,vox)=m_dyadic_vectors[sfs[(sfs.size()-1)-f].second](2,vox);
+      dyadic_vectors_out[f](3,vox)=m_dyadic_vectors[sfs[(sfs.size()-1)-f].second](3,vox);
+    }
+  }
+  
+  // save the sorted fibres
+  for(int f=0; f<m_Nmodes; f++){
+    tmp.setmatrix(thsamples_out[f],mask);
+    tmp.setDisplayMaximumMinimum(tmp.max(),tmp.min());
+    string oname="Pth"+num2str(f+1)+"samples";
+    save_volume4D(tmp,logger.appendDir(oname));
+      
+    tmp.setmatrix(phsamples_out[f],mask);
+    tmp.setDisplayMaximumMinimum(tmp.max(),tmp.min());
+    oname="Pph"+num2str(f+1)+"samples";
+    save_volume4D(tmp,logger.appendDir(oname));
+   
+    tmp.setmatrix(ksamples_out[f],mask);
+    tmp.setDisplayMaximumMinimum(1,0);
+    oname="Pk"+num2str(f+1)+"samples";
+    save_volume4D(tmp,logger.appendDir(oname));
+
+    tmp.setmatrix(mean_ksamples_out[f],mask);
+    tmp.setDisplayMaximumMinimum(1,0);
+    oname="mean_Pk"+num2str(f+1)+"samples";
+    save_volume(tmp[0],logger.appendDir(oname));
+      
+    tmp.setmatrix(dyadic_vectors_out[f],mask);
+    tmp.setDisplayMaximumMinimum(1,-1);
+    oname="Pdyads"+num2str(f+1);
+    save_volume4D(tmp,logger.appendDir(oname));
+  }
+}
+
+
+
+//////////////////////////////////////////////////////////////
+//    LRVoxelManager:MCMC HANDLING for a single LR voxel
+/////////////////////////////////////////////////////////////
+
+
+void LRVoxelManager::initialise(){
+  float pvmS0, pvmd,pvmd_std;
+  ColumnVector pvmf,pvmth,pvmph,pvm2invk,pvm2th,pvm2ph,predicted_signal;
+  
+  //Initialise each HR voxel using the HR data
+  float sumd=0, sumd2=0;
+  for (int n=0; n<m_HRvoxnumber.Nrows(); n++){
+    if (opts.modelnum.value()==1){ //Model 1
+
+      PVM_single_c pvm(m_dataHR[n],m_bvecsHR,m_bvalsHR,opts.nfibres.value());
+      pvm.fit(); // this will give th,ph,f in the correct order
+      
+      pvmf  = pvm.get_f();  pvmth = pvm.get_th(); pvmph = pvm.get_ph();
+      pvmS0 = fabs(pvm.get_s0()); pvmd  = pvm.get_d();  predicted_signal=pvm.get_prediction();
+      if(pvmd<0 || pvmd>0.01) pvmd=2e-3;
+
+       // DTI dti1(m_dataHR[n],m_bvecsHR,m_bvalsHR);
+      //dti1.linfit();
+      //pvmS0=fabs(dti1.get_s0());
+
+      m_LRv.set_HRparams(n,pvmd,pvmS0,pvmth,pvmph,pvmf);
+    }
+    else{  //Model 2
+      PVM_multi pvm(m_dataHR[n],m_bvecsHR,m_bvalsHR,opts.nfibres.value());
+      pvm.fit();
+      
+      pvmf  = pvm.get_f();  pvmth = pvm.get_th(); pvmph = pvm.get_ph(); pvmd_std=pvm.get_d_std();
+      pvmS0 =fabs(pvm.get_s0()); pvmd  = pvm.get_d();  predicted_signal=pvm.get_prediction();
+      OUT(pvmf);
+      if(pvmd<0 || pvmd>0.01) pvmd=2e-3;
+      if(pvmd_std<0 || pvmd_std>0.01) pvmd_std=pvmd/10;
+
+      //   DTI dti1(m_dataHR[n],m_bvecsHR,m_bvalsHR);
+      //dti1.linfit();
+      //pvmS0=fabs(dti1.get_s0());
+
+      m_LRv.set_HRparams(n,pvmd,pvmd_std,pvmS0,pvmth,pvmph,pvmf); 
+    } 
+   
+    if (opts.rician.value()){  //If using Rician Energy, initialize tau, using the variance of the initial fit residuals
+      ColumnVector residuals;
+      residuals=m_dataHR[n]-predicted_signal;
+      float tau=1.0/var(residuals).AsScalar();
+      m_LRv.set_tauHR(n,tau);
+    }
+    sumd+=pvmd;
+    sumd2+=pvmd*pvmd;
+  } 
+
+  sumd/=m_HRvoxnumber.Nrows();
+  m_LRv.set_meand(sumd);
+  m_LRv.set_stdevd(sumd/100);//sqrt((sumd2-m_HRvoxnumber.Nrows()*sumd*sumd)/(m_HRvoxnumber.Nrows()-1.0)));
+  
+  m_LRv.set_mean_fsum(0.6);
+  m_LRv.set_stdev_fsum(0.01);
+
+  //Initialise the orientation prior parameters using the LR data
+  if (opts.nmodes.value()>0){
+    PVM_single_c pvm2(m_dataLR,m_bvecsLR,m_bvalsLR,opts.nmodes.value());
+    pvm2.fit();
+    
+    pvm2invk  = pvm2.get_f();   
+    pvm2th = pvm2.get_th();
+    pvm2ph = pvm2.get_ph();
+    for (int m=1; m<=pvm2th.Nrows(); m++)
+      pvm2invk(m)=0.02;
+
+    m_LRv.set_Priorparams(pvm2th,pvm2ph,pvm2invk);
+  }
+
+  //Initialise the rest LR params
+  //DTI dti2(m_dataLR,m_bvecsLR,m_bvalsLR);
+  //dti2.linfit();
+  PVM_single_c pvm3(m_dataLR,m_bvecsLR,m_bvalsLR,1);
+  pvm3.fit();  
+  m_LRv.set_S0LR(fabs(pvm3.get_s0()));
+    
+  if (opts.rician.value()){  //If using Rician Energy, initialize tau, using the variance of the initial fit residuals
+    ColumnVector residuals;
+    predicted_signal=pvm3.get_prediction();
+    residuals=m_dataLR-predicted_signal;
+    float tau=1.0/var(residuals).AsScalar();
+    m_LRv.set_tauLR(tau);
+  } 
+  
+  m_LRv.update_Orient_hyp_prior();
+  m_LRv.initialise_energies(); 
+}
+ 
+
+
+//Run MCMC for an LRvoxel
+void LRVoxelManager::runmcmc(){
+  int count=0, recordcount=0,sample=1;
+ 
+  for(int i=0; i<opts.nburn.value(); i++){   //Burn-In
+    m_LRv.jump();
+    count++;
+    if(count==opts.updateproposalevery.value()){
+      m_LRv.update_proposals();
+      count=0;
+    }
+  }
+    
+  for( int i =0;i<opts.njumps.value();i++){  //Sampling
+    m_LRv.jump();
+    count++;
+    recordcount++;
+    if(recordcount==opts.sampleevery.value()){
+      for (int n=1; n<=m_HRvoxnumber.Nrows(); n++) //for each HR voxel 
+	m_HRsamples.record(m_LRv.HRvoxels()[n-1],(int)m_HRvoxnumber(n),sample);
+      m_LRsamples.record(m_LRv,(int)m_LRvoxnumber,sample);
+      
+      sample++;
+      recordcount=0;
+    }
+    if(count==opts.updateproposalevery.value()){
+      m_LRv.update_proposals();
+      count=0;
+    }
+  }
+
+  for (int n=1; n<=m_HRvoxnumber.Nrows(); n++)   //for each HR voxel 
+    m_HRsamples.finish_voxel((int)m_HRvoxnumber(n)); 
+  m_LRsamples.finish_voxel((int)m_LRvoxnumber);
+      
+}
+
+
+//For a voxel (x,y,z) at Low_res, returns that overlapping HR voxels coordinates
+ReturnMatrix get_HRindices(const int x,const int y,const int z, const int xratio, const int yratio, const int zratio){
+  Matrix HRindices(xratio*yratio*zratio,3);  //num_HR_voxels x 3 coordinates per voxel
+
+  int count=1;
+  for (int Hx=1; Hx<=xratio; Hx++)
+    for (int Hy=1; Hy<=yratio; Hy++)
+      for (int Hz=1; Hz<=zratio; Hz++){
+	HRindices(count,1)=(x+1)*xratio-Hx;
+	HRindices(count,2)=(y+1)*yratio-Hy;
+	HRindices(count,3)=(z+1)*zratio-Hz;
+	count++;
+      }
+
+  HRindices.Release();
+  return HRindices;
+}
+
+
+//Using a Low-Res mask, create an HR mask, after finding the corresponding HR voxels
+volume<float> createHR_mask(const volume<float>& maskLR, const volume4D<float>& dataHR){
+  volume<float> maskHR(dataHR.xsize(),dataHR.ysize(),dataHR.zsize());
+  copybasicproperties(dataHR,maskHR);
+
+  Matrix temp_indices;
+  maskHR=0;
+  float xratio=maskLR.xdim()/dataHR.xdim();
+  float yratio=maskLR.ydim()/dataHR.ydim();
+  float zratio=maskLR.zdim()/dataHR.zdim();
+
+  for (int i=0; i<maskLR.zsize(); i++)
+    for (int j=0; j<maskLR.ysize(); j++)
+      for (int k=0; k<maskLR.xsize(); k++)
+	if (maskLR(k,j,i)!=0){
+	  temp_indices=get_HRindices(k,j,i,(int)xratio,(int)yratio,(int)zratio);
+          for (int n=1; n<=temp_indices.Nrows(); n++)
+	    maskHR.value((int)temp_indices(n,1),(int)temp_indices(n,2),(int)temp_indices(n,3))=1;
+	}
+  return maskHR;
+}
+
+
+
+////////////////////////////////////////////
+//       MAIN
+////////////////////////////////////////////
+  
+int main(int argc, char *argv[])
+{
+  try{  
+    // Setup logging:
+    Log& logger = LogSingleton::getInstance();
+    rubixOptions& opts = rubixOptions::getInstance();
+    opts.parse_command_line(argc,argv,logger);
+    srand(rubixOptions::getInstance().seed.value());
+    Matrix datamLR, bvalsLR,bvecsLR,matrix2volkeyLR;
+    Matrix datamHR, bvalsHR,bvecsHR,matrix2volkeyHR;
+    volume<float> maskLR, maskHR;
+    volume<int> vol2matrixkeyLR, vol2matrixkeyHR;
+
+    bvalsLR=read_ascii_matrix(opts.LRbvalsfile.value());
+    bvecsLR=read_ascii_matrix(opts.LRbvecsfile.value());
+    if(bvecsLR.Nrows()>3) bvecsLR=bvecsLR.t();
+    if(bvalsLR.Nrows()>1) bvalsLR=bvalsLR.t();
+    for(int i=1;i<=bvecsLR.Ncols();i++){
+      float tmpsum=sqrt(bvecsLR(1,i)*bvecsLR(1,i)+bvecsLR(2,i)*bvecsLR(2,i)+bvecsLR(3,i)*bvecsLR(3,i));
+      if(tmpsum!=0){
+	bvecsLR(1,i)=bvecsLR(1,i)/tmpsum;
+	bvecsLR(2,i)=bvecsLR(2,i)/tmpsum;
+	bvecsLR(3,i)=bvecsLR(3,i)/tmpsum;
+      }  
+    }
+
+    bvalsHR=read_ascii_matrix(opts.HRbvalsfile.value());
+    bvecsHR=read_ascii_matrix(opts.HRbvecsfile.value());
+    if(bvecsHR.Nrows()>3) bvecsHR=bvecsHR.t();
+    if(bvalsHR.Nrows()>1) bvalsHR=bvalsHR.t();
+    for(int i=1;i<=bvecsHR.Ncols();i++){
+      float tmpsum=sqrt(bvecsHR(1,i)*bvecsHR(1,i)+bvecsHR(2,i)*bvecsHR(2,i)+bvecsHR(3,i)*bvecsHR(3,i));
+      if(tmpsum!=0){
+	bvecsHR(1,i)=bvecsHR(1,i)/tmpsum;
+	bvecsHR(2,i)=bvecsHR(2,i)/tmpsum;
+	bvecsHR(3,i)=bvecsHR(3,i)/tmpsum;
+      }  
+    }
+    
+    volume4D<float> dataLR,dataHR;
+    read_volume4D(dataLR,opts.LRdatafile.value());
+    read_volume(maskLR,opts.LRmaskfile.value());
+    datamLR=dataLR.matrix(maskLR); 
+    matrix2volkeyLR=dataLR.matrix2volkey(maskLR);
+    vol2matrixkeyLR=dataLR.vol2matrixkey(maskLR);
+ 
+    read_volume4D(dataHR,opts.HRdatafile.value());
+    maskHR=createHR_mask(maskLR, dataHR);
+    save_volume(maskHR,logger.appendDir("HRbrain_mask"));  //Generate and save an HR mask using the LR mask
+    
+    datamHR=dataHR.matrix(maskHR);
+    matrix2volkeyHR=dataHR.matrix2volkey(maskHR);
+    vol2matrixkeyHR=dataHR.vol2matrixkey(maskHR);
+ 
+    float xratio=maskLR.xdim()/maskHR.xdim();
+    float yratio=maskLR.ydim()/maskHR.ydim();
+    float zratio=maskLR.zdim()/maskHR.zdim();
+
+    HRSamples HRsampl(datamHR.Ncols(), opts.njumps.value(), opts.sampleevery.value(), opts.nfibres.value(), opts.rician.value(), opts.modelnum.value());
+    LRSamples LRsampl(datamLR.Ncols(), opts.njumps.value(), opts.sampleevery.value(), opts.nmodes.value(), opts.rician.value());
+
+    //dHR.push_back(datamHR.Column(1)); dHR.push_back(datamHR.Column(2));
+    //dHR.push_back(datamHR.Column(3)); dHR.push_back(datamHR.Column(4));
+    //HRvoxnum<<1<<2<<3<<4; HRweights<<0.25<<0.25<<0.25<<0.25;
+    
+    for(int vox=1;vox<=datamLR.Ncols();vox++){  //For each LR voxel
+      //  if (vox==19){  //vox==6
+      ColumnVector dLR; Matrix HRindices;
+      dLR=datamLR.Column(vox);                  //Find the corresponding HR ones
+      HRindices=get_HRindices((int)matrix2volkeyLR(vox,1),(int)matrix2volkeyLR(vox,2),(int)matrix2volkeyLR(vox,3),(int)xratio,(int)yratio,(int)zratio);
+      //cout<<endl<<"S0LR: "<<dLR(1)<<endl<<endl; //Debugging code
+     
+      ColumnVector HRvoxnum(HRindices.Nrows()), HRweights(HRindices.Nrows()); 
+      vector<ColumnVector> dHR;
+      
+     for (int n=1; n<=HRindices.Nrows(); n++){
+	HRweights(n)=1.0/HRindices.Nrows();
+	HRvoxnum(n)=vol2matrixkeyHR((int)HRindices(n,1),(int)HRindices(n,2),(int)HRindices(n,3));
+	ColumnVector tmp_vec=datamHR.Column((int)HRvoxnum(n));
+ 	//cout<<(int)HRindices(n,1)<<" "<<(int)HRindices(n,2)<<" "<<(int)HRindices(n,3)<<"  S0HR:"<<tmp_vec(1)<<endl;
+	dHR.push_back(datamHR.Column((int)HRvoxnum(n)));
+      }
+      cout <<vox<<"/"<<datamLR.Ncols()<<endl;
+      LRVoxelManager  vm(HRsampl,LRsampl,vox,HRvoxnum, dLR,dHR, bvecsLR, bvalsLR, bvecsHR, bvalsHR, HRweights);
+      vm.initialise();
+      vm.runmcmc();
+      //      } 
+    }
+    HRsampl.save(maskHR);
+    LRsampl.save(maskLR);
+  }
+
+  catch(Exception& e){
+    cerr << endl << e.what() << endl;
+  }
+  catch(X_OptionError& e){
+      cerr << endl << e.what() << endl;
+  }
+
+  return 0;
+}
diff --git a/rubix.h b/rubix.h
new file mode 100644
index 0000000..a97af67
--- /dev/null
+++ b/rubix.h
@@ -0,0 +1,209 @@
+/*  rubix.h: Classes utilized in RubiX MCMC storage and handling  */
+/*  Stamatios Sotiropoulos, FMRIB Analysis Group */
+/*  Copyright (C) 2012 University of Oxford  */
+/*  CCOPYRIGHT  */
+
+
+#if !defined(rubix_h)
+#define rubix_h
+
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#define WANT_STREAM
+#define WANT_MATH
+#include <string>
+#include "miscmaths/miscmaths.h"
+#include "miscmaths/miscprob.h"
+#include "newimage/newimageall.h"
+#include "stdlib.h"
+
+using namespace NEWMAT;
+using namespace MISCMATHS;
+using namespace NEWIMAGE;
+
+namespace RUBIX{
+
+  ////////////////////////////////////////////
+  //       MCMC SAMPLE STORAGE
+  ////////////////////////////////////////////
+  //Storing Samples for parameters of all HR voxels 
+  class HRSamples{
+    Matrix m_dsamples;              //Variables for storing MCMC samples of all voxels in the HRgrid
+    Matrix m_d_stdsamples;
+    Matrix m_S0samples;
+    Matrix m_tausamples;
+    vector<Matrix> m_thsamples;
+    vector<Matrix> m_phsamples;
+    vector<Matrix> m_fsamples;
+  
+    //for storing means
+    RowVector m_mean_dsamples;    //Storing mean_samples for all voxels in the HRgrid
+    RowVector m_mean_d_stdsamples;
+    RowVector m_mean_S0samples;
+    RowVector m_mean_tausamples;
+    vector<Matrix> m_dyadic_vectors;
+    vector<RowVector> m_mean_fsamples;
+  
+    int m_nsamps;
+    const int m_njumps;
+    const int m_sample_every;
+    const int m_numfibres;
+    const bool m_rician;
+    const int m_modelnum;
+    //const string m_logdir;
+    
+  public:
+  HRSamples(int nvoxels, const int njumps, const int sample_every, const int numfibres, const bool rician=false, const int modelnum=1):
+    m_njumps(njumps),m_sample_every(sample_every), m_numfibres(numfibres), m_rician(rician), m_modelnum(modelnum){
+      int count=0;
+      int nsamples=0;
+    
+      for(int i=0;i<m_njumps; i++){
+	count++;
+	if(count==m_sample_every){
+	  count=0; 
+	  nsamples++;
+	}
+      }
+      m_nsamps=nsamples;
+
+      m_dsamples.ReSize(nsamples,nvoxels);  m_dsamples=0;
+      m_S0samples.ReSize(nsamples,nvoxels); m_S0samples=0;
+
+      m_mean_dsamples.ReSize(nvoxels);      m_mean_dsamples=0;
+      m_mean_S0samples.ReSize(nvoxels);     m_mean_S0samples=0;
+      if (m_rician){
+	m_tausamples.ReSize(nsamples,nvoxels);  m_tausamples=0;
+	m_mean_tausamples.ReSize(nvoxels);      m_mean_tausamples=0;
+      }
+      if (m_modelnum==2){
+	m_d_stdsamples.ReSize(nsamples,nvoxels);  m_d_stdsamples=0;
+	m_mean_d_stdsamples.ReSize(nvoxels);      m_mean_d_stdsamples=0;
+      }
+      Matrix tmpvecs(3,nvoxels);  tmpvecs=0;  
+      for(int f=0; f<m_numfibres; f++){
+	m_thsamples.push_back(m_S0samples);   
+	m_phsamples.push_back(m_S0samples);
+	m_fsamples.push_back(m_S0samples);  
+	m_dyadic_vectors.push_back(tmpvecs); 
+	m_mean_fsamples.push_back(m_mean_S0samples);
+      }
+    }
+
+    ~HRSamples(){}
+
+    void record(const HRvoxel& HRv, int vox, int samp); //Store parameters for a certain sample at a certain HR voxel
+    void finish_voxel(int vox);                   //Get the mean samples for a voxel once jumping has finished
+    void save(const volume<float>& mask);         //Save samples for all voxels
+  };
+
+
+
+
+  ////////////////////////////////////////////
+  //       MCMC SAMPLE STORAGE
+  ////////////////////////////////////////////
+  //Storing Samples for parameters at the Low-Res level (e.g. priors, Low-res parameters)
+  class LRSamples{
+    vector<Matrix> m_thsamples;           //Variables for storing MCMC samples of all voxels in the LRgrid
+    vector<Matrix> m_phsamples;
+    vector<Matrix> m_ksamples;
+    Matrix m_S0samples;
+    Matrix m_tauLRsamples;
+    Matrix m_lik_energy;
+    Matrix m_prior_energy;
+
+    //for storing means
+    vector<Matrix> m_dyadic_vectors;
+    vector<RowVector> m_mean_ksamples;
+    RowVector m_mean_S0samples;
+    RowVector m_mean_tausamples;
+
+    int m_nsamps;
+    const int m_njumps;
+    const int m_sample_every;
+    const int m_Nmodes;
+    const bool m_rician;
+    //const string m_logdir;
+    
+  public:
+  LRSamples(int nvoxels, const int njumps, const int sample_every, const int Nmodes, const bool rician=false):
+    m_njumps(njumps),m_sample_every(sample_every), m_Nmodes(Nmodes), m_rician(rician){
+      int count=0;
+      int nsamples=0;
+    
+      for(int i=0;i<m_njumps; i++){
+	count++;
+	if(count==m_sample_every){
+	  count=0; 
+	  nsamples++;
+	}
+      }
+      m_nsamps=nsamples;
+
+      m_S0samples.ReSize(nsamples,nvoxels); m_S0samples=0;
+      m_lik_energy.ReSize(nsamples,nvoxels); m_lik_energy=0;
+      m_prior_energy.ReSize(nsamples,nvoxels); m_prior_energy=0;
+      m_mean_S0samples.ReSize(nvoxels);     m_mean_S0samples=0;
+      if (m_rician){
+	m_tauLRsamples.ReSize(nsamples,nvoxels); m_tauLRsamples=0;
+	m_mean_tausamples.ReSize(nvoxels);     m_mean_tausamples=0;
+      }
+      Matrix tmpvecs(3,nvoxels);  tmpvecs=0;  
+    
+      for(int f=0; f<m_Nmodes; f++){
+	m_thsamples.push_back(m_S0samples);   
+	m_phsamples.push_back(m_S0samples);
+	m_ksamples.push_back(m_S0samples);  
+	m_dyadic_vectors.push_back(tmpvecs); 
+	m_mean_ksamples.push_back(m_mean_S0samples);
+      }
+    }
+
+    ~LRSamples(){}
+
+    void record(const LRvoxel& LRv, int vox, int samp); //Store parameters for a certain sample at a certain LR voxel
+    void finish_voxel(int vox);                   //Get the mean samples for a voxel once jumping has finished
+    void save(const volume<float>& mask);         //Save samples for all voxels
+  };
+
+
+
+  //////////////////////////////////////////////
+  //       MCMC HANDLING for a single LR voxel
+  //////////////////////////////////////////////
+  class LRVoxelManager{
+    rubixOptions& opts;
+    HRSamples& m_HRsamples;         //keep MCMC samples of the parameters of all voxels inferred at High-res grid 
+    LRSamples& m_LRsamples;         //keep MCMC samples of the parameters of all voxels inferred at Low-res grid 
+    int m_LRvoxnumber;
+    ColumnVector m_HRvoxnumber;
+    LRvoxel m_LRv;
+    const ColumnVector& m_dataLR;    //Low-Res Data for the specific LR voxel 
+    const vector<ColumnVector>& m_dataHR; //High-Res Data for all contained HR voxels
+    const Matrix& m_bvecsLR;         //bvecs at Low-Res    (3 x LR_NumPoints)
+    const Matrix& m_bvalsLR;         //bvalues at Low-Res  (1 x HR_NumPoints)
+    const Matrix& m_bvecsHR;         //bvecs at High-Res   (3 x HR_NumPoints)
+    const Matrix& m_bvalsHR;         //bvalues at High-Res (1 x HR_NumPoints)
+    const ColumnVector& m_HRweights; //Holds the volume fraction each HR voxel occupies out of the LR one
+  public:
+    //Constructor
+  LRVoxelManager(HRSamples& Hsamples, LRSamples& Lsamples, int LRvoxnum, ColumnVector& HRvoxnum, 
+		   const ColumnVector& dataLR,const vector<ColumnVector>& dataHR, 
+		 const Matrix& bvecsLR, const Matrix& bvalsLR, const Matrix& bvecsHR, const Matrix& bvalsHR, const ColumnVector& HRweights):
+    opts(rubixOptions::getInstance()), m_HRsamples(Hsamples), m_LRsamples(Lsamples), m_LRvoxnumber(LRvoxnum),m_HRvoxnumber(HRvoxnum), 
+      m_LRv(bvecsHR, bvalsHR, bvecsLR, bvalsLR, dataLR, dataHR, opts.nfibres.value(), opts.nmodes.value(), HRweights, opts.modelnum.value(), opts.fudge.value(),opts.all_ard.value(), opts.no_ard.value(),opts.kappa_ard.value(), opts.fsumPrior.value(), opts. dPrior.value(), opts.rician.value()),
+      m_dataLR(dataLR), m_dataHR(dataHR),m_bvecsLR(bvecsLR), m_bvalsLR(bvalsLR), m_bvecsHR(bvecsHR), m_bvalsHR(bvalsHR), m_HRweights(HRweights) { } 
+    
+    ~LRVoxelManager() { }
+
+    void initialise(); //Initialise all parameters for an LR voxel
+    void runmcmc(); //Run MCMC for an LR voxel 
+};
+
+
+}
+
+
+#endif
diff --git a/rubixoptions.cc b/rubixoptions.cc
new file mode 100644
index 0000000..c915773
--- /dev/null
+++ b/rubixoptions.cc
@@ -0,0 +1,53 @@
+/*  rubixoptions.cc
+
+    Stam Sotiropoulos, FMRIB Image Analysis Group
+
+    Copyright (C) 2012 University of Oxford  */
+
+/*  CCOPYRIGHT  */
+
+#define WANT_STREAM
+#define WANT_MATH
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include "rubixoptions.h"
+#include "utils/log.h"
+#include "utils/tracer_plus.h"
+
+using namespace Utilities;
+
+namespace RUBIX {
+  
+  rubixOptions* rubixOptions::gopt = NULL;
+  
+  void rubixOptions::parse_command_line(int argc, char** argv, Log& logger){
+    Tracer_Plus("RubiXOptions::parse_command_line");
+
+    // do once to establish log directory name
+    for(int a = options.parse_command_line(argc, argv); a < argc; a++);
+  
+    if(help.value() || ! options.check_compulsory_arguments()){
+      options.usage();
+      //throw Exception("Not all of the compulsory arguments have been provided");
+      exit(2);
+    }
+    else{
+      // setup logger directory
+      if(forcedir.value())
+	logger.setthenmakeDir(logdir.value());
+      else
+	logger.makeDir(logdir.value());
+    
+      cout << "Log directory is: " << logger.getDir() << endl;
+    
+      // do again so that options are logged
+      for(int a = 0; a < argc; a++)
+	logger.str() << argv[a] << " ";
+      logger.str() << endl << "---------------------------------------------" << endl << endl;
+    }      
+  }
+
+}
diff --git a/rubixoptions.h b/rubixoptions.h
new file mode 100644
index 0000000..cb8654c
--- /dev/null
+++ b/rubixoptions.h
@@ -0,0 +1,195 @@
+/*  rubixoptions.h
+
+    Stam Sotiropoulos, FMRIB Image Analysis Group
+
+    Copyright (C) 2012 University of Oxford  */
+
+/*  CCOPYRIGHT  */
+
+#if !defined(rubixptions_h)
+#define rubixptions_h
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include "utils/options.h"
+#include "utils/log.h"
+#include "utils/tracer_plus.h"
+//#include "newmatall.h"
+using namespace Utilities;
+
+namespace RUBIX{
+  
+  class rubixOptions {
+  public:
+    static rubixOptions& getInstance();
+    ~rubixOptions() { delete gopt; }
+  
+    Option<bool> verbose;
+    Option<bool> help;
+    Option<string> logdir;
+    Option<bool> forcedir;
+    Option<string> LRdatafile;
+    Option<string> LRmaskfile;
+    Option<string> LRbvecsfile;
+    Option<string> LRbvalsfile;
+    Option<string> HRdatafile;
+    //    Option<string> HRmaskfile;
+    Option<string> HRbvecsfile;
+    Option<string> HRbvalsfile;
+    Option<int> nfibres;
+    Option<int> nmodes;  //number of modes in the orientation prior
+    Option<int> modelnum;
+    Option<float> fudge;
+    Option<int> njumps;
+    Option<int> nburn;
+    Option<int> sampleevery;
+    Option<int> updateproposalevery;
+    Option<int> seed;
+    Option<bool> no_ard;
+    Option<bool> all_ard;
+    Option<bool> kappa_ard;
+    Option<bool> fsumPrior;
+    Option<bool> dPrior;
+    Option<bool> rician;
+    void parse_command_line(int argc, char** argv,  Log& logger);
+  
+  private:
+    rubixOptions();  
+    const rubixOptions& operator=(rubixOptions&);
+    rubixOptions(rubixOptions&);
+
+    OptionParser options; 
+    static rubixOptions* gopt;
+  };
+
+  inline rubixOptions& rubixOptions::getInstance(){
+    if(gopt == NULL)
+      gopt = new rubixOptions();
+   
+    return *gopt;
+  }
+
+  inline rubixOptions::rubixOptions() :
+   verbose(string("-V,--verbose"), false, 
+	   string("switch on diagnostic messages"), 
+	   false, no_argument),
+   help(string("-h,--help"), false,
+	string("display this message"),
+	false, no_argument),
+   logdir(string("--ld,--logdir"), string("logdir"),
+	  string("log directory (default is logdir)"),
+	  false, requires_argument),
+   forcedir(string("--forcedir"),false,string("Use the actual directory name given - i.e. don't add + to make a new directory"),false,no_argument),
+   LRdatafile(string("--dLR"), string("data_LR"),
+	    string("Low-Res data file"),
+	    true, requires_argument),  
+   LRmaskfile(string("--mLR"), string("nodif_brain_mask_LR"),
+	    string("Low-Res mask file"),
+	    true, requires_argument),
+   LRbvecsfile(string("--rLR"), string("bvecs_LR"),
+	     string("Low-Res b vectors file"),
+	     true, requires_argument),  
+   LRbvalsfile(string("--bLR"), string("bvals_LR"),
+	     string("Low-Res b values file"),
+	     true, requires_argument),
+   HRdatafile(string("--dHR"), string("data_HR"),
+	    string("High-Res data file"),
+	    true, requires_argument),  
+   //  HRmaskfile(string("--mHR"), string("nodif_brain_mask_HR"),
+   //	    string("High-Res mask file"),
+   //	    true, requires_argument),
+   HRbvecsfile(string("--rHR"), string("bvecs_HR"),
+	     string("High-Res b vectors file"),
+	     true, requires_argument),  
+   HRbvalsfile(string("--bHR"), string("bvals_HR"),
+	     string("High-Res b values file"),
+	     true, requires_argument),
+   nfibres(string("--nf,--nfibres"),1,
+	   string("Maximum number of fibres to fit in each HR voxel (default 1)"),
+	   false,requires_argument),
+   nmodes(string("--nM,--nmodes"),2,
+	   string("Number of modes for the orientation prior (default 2)"),
+	   false,requires_argument),
+   modelnum(string("--model"),1,
+	    string("\tWhich model to use. 1=mono-exponential (default). 2=continous exponential"),
+	    false,requires_argument),
+   fudge(string("--fudge"),1,
+	 string("\tARD fudge factor"),
+	 false,requires_argument),
+   njumps(string("--nj,--njumps"),1500,
+	  string("Num of jumps to be made by MCMC (default is 1500)"),
+	  false,requires_argument),
+   nburn(string("--bi,--burnin"),0,
+	 string("Total num of jumps at start of MCMC to be discarded (default is 0)"),
+	 false,requires_argument),
+   sampleevery(string("--se"),30,
+	       string("\tNum of jumps for each sample (MCMC) (default is 30)"),
+	       false,requires_argument),
+   updateproposalevery(string("--upe"),40,
+		       string("\tNum of jumps for each update to the proposal density std (MCMC) (default is 40)"),
+		       false,requires_argument),
+   seed(string("--seed"),8665904,string("\tseed for pseudo random number generator"),
+	false,requires_argument),
+   no_ard(string("--noard"),false,string("\tTurn ARD off on all fibres"),
+    	  false,no_argument),
+   all_ard(string("--allard"),false,string("Turn ARD on for all fibres (default: on for all but first)"),
+    	   false,no_argument),
+   kappa_ard(string("--ard_kappa"),false,string("Turn ARD on for the dispersion of all orientation prior modes (default: off)"),
+    	   false,no_argument),
+   fsumPrior(string("--fsumPrior"),false,string("Turn on prior for the fsums across an LR voxel (default: off)"),
+    	   false,no_argument),
+   dPrior(string("--dPrior"),false,string("Turn on prior for the diffusivity across an LR voxel  (default: off)"),
+    	   false,no_argument),
+   rician(string("--rician"),false,string("Use Rician Noise model (default is Gaussian)"),
+    	   false,no_argument),
+   options("RubiX v1.0", "rubix --help (for list of options)\n")
+     {
+       try {
+       options.add(verbose);
+       options.add(help);
+       options.add(logdir);
+       options.add(forcedir);
+       options.add(LRdatafile);
+       options.add(LRmaskfile);
+       options.add(LRbvecsfile);
+       options.add(LRbvalsfile);
+       options.add(HRdatafile);
+       //   options.add(HRmaskfile);
+       options.add(HRbvecsfile);
+       options.add(HRbvalsfile);
+       options.add(nfibres);
+       options.add(nmodes);
+       options.add(modelnum);
+       options.add(fudge);
+       options.add(njumps);
+       options.add(nburn);
+       options.add(sampleevery);
+       options.add(updateproposalevery);
+       options.add(seed);
+       options.add(no_ard);
+       options.add(all_ard);
+       options.add(kappa_ard);
+       options.add(fsumPrior);
+       options.add(dPrior);
+       options.add(rician);
+     }
+     catch(X_OptionError& e) {
+       options.usage();
+       cerr << endl << e.what() << endl;
+     } 
+     catch(std::exception &e) {
+       cerr << e.what() << endl;
+     }    
+     
+   }
+}
+
+#endif
+
+
+
+
+
diff --git a/rubixvox.cc b/rubixvox.cc
new file mode 100644
index 0000000..0e85bcf
--- /dev/null
+++ b/rubixvox.cc
@@ -0,0 +1,1480 @@
+/*  rubixvox.cc: Classes utilized in RubiX    */
+/*  Stamatios Sotiropoulos, FMRIB Analysis Group */
+/*  Copyright (C) 2012 University of Oxford  */
+/*  CCOPYRIGHT  */
+
+
+#include "rubixvox.h"
+
+namespace RUBIX{
+
+//Returns the natural log of the 0th order modified Bessel function of first kind for an argument x
+//Follows the exponential implementation of the Bessel function in Numerical Recipes, Ch. 6
+float logIo(const float x){
+  float y,b;
+
+  b=std::fabs(x);
+  if (b<3.75){
+    float a=x/3.75;
+    a*=a;
+    //Bessel function evaluation
+    y=1.0+a*(3.5156229+a*(3.0899424+a*(1.2067492+a*(0.2659732+a*(0.0360768+a*0.0045813)))));
+    y=std::log(y);
+  }
+  else{
+    float a=3.75/b; 
+    //Bessel function evaluation
+    //y=(exp(b)/sqrt(b))*(0.39894228+a*(0.01328592+a*(0.00225319+a*(-0.00157565+a*(0.00916281+a*(-0.02057706+a*(0.02635537+a*(-0.01647633+a*0.00392377))))))));
+    //Logarithm of Bessel function
+    y=b+std::log((0.39894228+a*(0.01328592+a*(0.00225319+a*(-0.00157565+a*(0.00916281+a*(-0.02057706+a*(0.02635537+a*(-0.01647633+a*0.00392377))))))))/std::sqrt(b));
+  }
+  return y;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+//       RFibre: Models one anisotropic compartment in an HR voxel
+//////////////////////////////////////////////////////////////////////
+
+//Adapt the standard deviation of the proposal distributions during MCMC execution 
+//to avoid over-rejection/over-acceptance of samples
+void RFibre::update_proposals(){  
+  m_th_prop*=sqrt(float(m_th_acc+1)/float(m_th_rej+1));
+  m_th_prop=min(m_th_prop,maxfloat);
+  m_ph_prop*=sqrt(float(m_ph_acc+1)/float(m_ph_rej+1));
+  m_ph_prop=min(m_ph_prop,maxfloat);
+  m_f_prop*=sqrt(float(m_f_acc+1)/float(m_f_rej+1));
+  m_f_prop=min(m_f_prop,maxfloat);
+  m_th_acc=0; 
+  m_th_rej=0;
+  m_ph_acc=0; 
+  m_ph_rej=0;
+  m_f_acc=0; 
+  m_f_rej=0;
+}
+
+
+//Call that after initializing the parameters
+void RFibre::initialise_energies(){
+  compute_th_ph_prior();
+  compute_f_prior();
+  compute_prior();
+  compute_signal();
+}  
+
+
+//conditional prior for th and ph, use hyperparameters
+bool RFibre::compute_th_ph_prior(){
+  m_th_ph_old_prior=m_th_ph_prior;
+  m_th_ph_prior=0;
+  if (m_Orient_hyp_prior.Nrows()!=0){// && m_f>0.05){ //If an informative orientation prior is used   
+    ColumnVector prior_vec(m_Orient_hyp_prior.Nrows());   
+    for (int m=1; m<=m_Orient_hyp_prior.Nrows(); m++){ //for each mode of the prior
+      float ct=m_Orient_hyp_prior(m,5);  
+      float dot=std::min(fabs(m_Orient_hyp_prior(m,1)*m_vec(1)+m_Orient_hyp_prior(m,2)*m_vec(2)+m_Orient_hyp_prior(m,3)*m_vec(3)),1.0);
+      prior_vec(m)=(1.0/m_Orient_hyp_prior(m,4))*dot*dot-ct;                       //This is the argument of the Watson (with the logged normalization constant incorporated) 
+      //m_th_ph_prior=m_th_ph_prior+exp((1.0/m_Orient_hyp_prior(m,4))*dot*dot-ct); //compute the respective Watson pdf, this is numerically unstable
+    }
+    if (m_Orient_hyp_prior.Nrows()==1)  //For one mode the prior energy is -log(exp(prior_vec(1))
+      m_th_ph_prior=-prior_vec(1);                 
+    else{                               //For many modes, instead of calculating -log(Sum(exp(xi))) which is numerically unstable
+      float maxarg=prior_vec.Maximum(); //calculate -m-log(Sum(exp(xi-m))), with m=max(xi)
+      for (int m=1; m<=m_Orient_hyp_prior.Nrows(); m++) //For each mode of the prior
+	m_th_ph_prior=m_th_ph_prior+exp(prior_vec(m)-maxarg);
+      m_th_ph_prior=-maxarg-log(m_th_ph_prior); //Convert to -log Energy
+    }
+    //m_th_ph_prior=m_th_ph_prior-log(0.5*fabs(sin(m_th)));  //Correct with the Jacobian of the transformation! We jump spherical coordinates instead of Cartesian!!
+    m_th_ph_prior=m_th_ph_prior-log(fabs(sin(m_th)/(4*M_PI)));  //Correct with the Jacobian of the transformation! We jump spherical coordinates instead of Cartesian!!
+    return false; //set instant rejection flag to false
+  }
+  else{  //if no orientation prior imposed, use uniform prior
+    if (m_th==0) 
+      m_th_ph_prior=0;
+    else
+      m_th_ph_prior=-log(0.5*fabs(sin(m_th)));
+    return false; //instant rejection flag
+  }
+}
+
+
+//ARD prior on f (if f_ard==true)
+bool RFibre::compute_f_prior(){
+  m_f_old_prior=m_f_prior;
+  if (m_f<=0 || m_f>=1 )
+    return true;
+  else{
+    if(!f_ard)
+      m_f_prior=0;
+    else
+      m_f_prior=std::log(m_f);
+    m_f_prior=m_ardfudge*m_f_prior;
+    return false;
+  }
+}
+
+
+//Compute Joint Prior
+void RFibre::compute_prior(){
+  m_old_prior_en=m_prior_en;
+  m_prior_en=m_th_ph_prior+m_f_prior;
+}
+
+
+//Used when orientation prior params are jumped
+void RFibre::restore_th_ph_prior(){
+  m_th_ph_prior=m_th_ph_old_prior; 
+  m_prior_en=m_old_prior_en; 
+}
+
+
+//Compute model predicted signal at High and Low Res, only due to the anisotropic compartment 
+void RFibre::compute_signal(){
+  m_SignalHR_old=m_SignalHR;
+  m_SignalLR_old=m_SignalLR;
+       
+  if(m_modelnum==1 || m_d_std<1e-5){
+    for (int i=1; i<=m_bvecsHR.Ncols(); i++){
+      float angtmp=m_vec(1)*m_bvecsHR(1,i)+m_vec(2)*m_bvecsHR(2,i)+m_vec(3)*m_bvecsHR(3,i);
+      angtmp=angtmp*angtmp;	  
+      m_SignalHR(i)=exp(-m_d*m_bvalsHR(1,i)*angtmp);
+    }
+
+    for (int i=1; i<=m_bvecsLR.Ncols(); i++){
+      float angtmp=m_vec(1)*m_bvecsLR(1,i)+m_vec(2)*m_bvecsLR(2,i)+m_vec(3)*m_bvecsLR(3,i);
+      angtmp=angtmp*angtmp;	  
+      m_SignalLR(i)=exp(-m_d*m_bvalsLR(1,i)*angtmp);
+    }
+  }
+  else if(m_modelnum==2){
+    float dbeta=m_d/(m_d_std*m_d_std);
+    float dalpha=m_d*dbeta;                            
+    for (int i=1; i<=m_bvecsHR.Ncols(); i++){
+      float angtmp=m_vec(1)*m_bvecsHR(1,i)+m_vec(2)*m_bvecsHR(2,i)+m_vec(3)*m_bvecsHR(3,i);
+      angtmp=angtmp*angtmp;	  
+      m_SignalHR(i)=exp(log(dbeta/(dbeta + m_bvalsHR(1,i)*angtmp))*dalpha);
+    }
+
+    for (int i=1; i<=m_bvecsLR.Ncols(); i++){
+      float angtmp=m_vec(1)*m_bvecsLR(1,i)+m_vec(2)*m_bvecsLR(2,i)+m_vec(3)*m_bvecsLR(3,i);
+      angtmp=angtmp*angtmp;	  
+      m_SignalLR(i)=exp(log(dbeta/(dbeta + m_bvalsLR(1,i)*angtmp))*dalpha);
+    }
+  }
+}
+
+
+
+bool RFibre::propose_th(){
+  m_th_old=m_th;
+  m_th+=normrnd().AsScalar()*m_th_prop;
+  m_vec_old=m_vec;
+  m_vec<<sin(m_th)*cos(m_ph) <<sin(m_th)*sin(m_ph) <<cos(m_th);
+  bool rejflag=compute_th_ph_prior();//inside this it stores the old prior
+  compute_prior();
+  compute_signal();
+  return rejflag;
+}
+
+
+void RFibre::reject_th(){
+  m_th=m_th_old; 
+  m_th_ph_prior=m_th_ph_old_prior; 
+  m_vec=m_vec_old;
+  m_prior_en=m_old_prior_en; 
+  restoreSignals(); 
+  m_th_rej++;
+}
+    
+
+bool RFibre::propose_ph(){
+  m_ph_old=m_ph;
+  m_ph+=normrnd().AsScalar()*m_ph_prop;
+  m_vec_old=m_vec;
+  m_vec<<sin(m_th)*cos(m_ph) <<sin(m_th)*sin(m_ph) <<cos(m_th);
+  bool rejflag=compute_th_ph_prior();//inside this it stores the old prior
+  compute_prior();
+  compute_signal();
+  return rejflag;
+}
+  
+  
+void RFibre::reject_ph(){
+  m_ph=m_ph_old; 
+  m_th_ph_prior=m_th_ph_old_prior; 
+  m_vec=m_vec_old;
+  m_prior_en=m_old_prior_en; 
+  restoreSignals(); 
+  m_ph_rej++;
+}
+    
+
+bool RFibre::propose_f(){
+  m_f_old=m_f;
+  m_f+=normrnd().AsScalar()*m_f_prop;
+  bool rejflag=compute_f_prior();
+  compute_prior();
+  return rejflag;
+}
+
+
+void RFibre::reject_f(){
+  m_f=m_f_old; 
+  m_f_prior=m_f_old_prior;
+  m_prior_en=m_old_prior_en; 
+  m_f_rej++;
+}
+
+
+void RFibre::report() const {
+  OUT(m_th);        OUT(m_th_old);       OUT(m_th_prop);     OUT(m_th_acc);    OUT(m_th_rej);
+  OUT(m_th_ph_prior); OUT(m_th_ph_old_prior);
+  OUT(m_ph);        OUT(m_ph_old);       OUT(m_ph_prop);     OUT(m_ph_acc);    OUT(m_ph_rej);
+  OUT(m_f);         OUT(m_f_old);        OUT(m_f_prop);      OUT(m_f_acc);     OUT(m_f_rej);
+  OUT(m_f_prior);   OUT(m_f_old_prior);
+  OUT(m_prior_en);  OUT(m_old_prior_en);
+}
+
+
+
+
+////////////////////////////////////////////////
+//       HRvoxel
+////////////////////////////////////////////////
+
+//Initialize energies, signals and standard deviations for the proposal distributions
+//Call that after initializing the parameters
+void HRvoxel::initialise_energies_props(){
+  m_S0_prop=m_S0/10.0;
+  m_d_prop=m_d/10.0;
+  for (int f=0; f<m_numfibres; f++)
+    m_fibres[f].initialise_energies();
+  if (m_rician){
+    compute_tau_prior();
+    m_tau_prop=m_tau/2.0;
+  }
+  if (m_modelnum==2){
+    compute_d_std_prior();
+    m_d_std_prop=m_d_std/10.0;
+  }
+  compute_S0_prior();
+  compute_d_prior();
+  if (m_fsumPrior_ON)
+    compute_fsum_prior();
+  compute_prior();
+  compute_iso_signal();                  
+  compute_signal();
+}
+
+ 
+bool HRvoxel::compute_d_prior(){
+  m_d_old_prior=m_d_prior;
+  if(m_d<=0)
+    return true;
+  else{
+    //m_d_prior=0;
+    
+    if (m_dPrior_ON)
+      m_d_prior=0.5*(m_d-m_mean_d)*(m_d-m_mean_d)/(m_stdev_d*m_stdev_d)+log(m_stdev_d); //Use a Gaussian centered around the neighbourhood meand
+    else{  //Use a Gamma Prior centered around 1e-3
+      float alpha=3.0; float beta=2000;
+      m_d_prior=(1.0-alpha)*log(m_d)+beta*m_d; //Gamma_prior: pow(m_d,alpha-1.0)*exp(-beta*m_d)
+    }
+    return false;
+  }
+}
+       
+
+bool HRvoxel::compute_d_std_prior(){
+  m_d_std_old_prior=m_d_std_prior;
+  if(m_d_std<=0 || m_d_std>0.01)
+    return true;
+  else{
+    m_d_std_prior=0;
+    //m_d_std_prior=std::log(m_d_std);
+    return false;
+  }
+}
+
+
+bool HRvoxel::compute_S0_prior(){
+  m_S0_old_prior=m_S0_prior;
+  if(m_S0<0) return true;
+  else{    
+    m_S0_prior=0;
+    return false;
+  }
+}
+
+
+bool HRvoxel::compute_tau_prior(){
+  m_tau_old_prior=m_tau_prior;
+  if(m_tau<=0) return true;
+  else{    
+    m_tau_prior=0;
+    return false;
+  }
+}
+
+
+//Check if sum of volume fractions is >1
+bool HRvoxel::reject_f_sum(){
+  float fsum=0;//m_f0;
+  for(int f=0; f<m_numfibres; f++){
+    fsum+=m_fibres[f].get_f();	
+  }
+  return fsum>1; //true if sum(f) > 1 and therefore, we should reject f
+}
+
+
+//Compute Joint Prior
+void HRvoxel::compute_prior(){ 
+  m_old_prior_en=m_prior_en;
+  m_prior_en=m_d_prior+m_S0_prior;
+  if (m_fsumPrior_ON)
+    m_prior_en=m_prior_en+m_fsum_prior;
+  if(m_rician)
+    m_prior_en=m_prior_en+m_tau_prior;
+  if(m_modelnum==2)
+    m_prior_en=m_prior_en+m_d_std_prior;
+  for(int f=0; f<m_numfibres; f++){
+    m_prior_en=m_prior_en+m_fibres[f].get_prior();
+  } 
+}
+
+
+//Used to update the conditional orientation prior
+//when the prior parameters are jumped
+void HRvoxel::update_th_ph_prior(){
+  for(int f=0; f<m_numfibres; f++){
+    m_fibres[f].compute_th_ph_prior();
+    m_fibres[f].compute_prior();
+  }
+  compute_prior();
+}
+
+
+void HRvoxel::restore_th_ph_prior(){
+  for(int f=0; f<m_numfibres; f++)
+    m_fibres[f].restore_th_ph_prior(); 
+  m_prior_en=m_old_prior_en;
+} 
+
+
+void HRvoxel::update_d_prior(){
+  compute_d_prior();
+  compute_prior();
+}
+
+
+void HRvoxel::restore_d_prior(){
+  m_d_prior=m_d_old_prior;
+  m_prior_en=m_old_prior_en;
+}
+
+
+void HRvoxel::compute_fsum_prior(){
+  m_fsum_old_prior=m_fsum_prior;
+  float fsum=0;
+  for(int f=0; f<m_numfibres; f++){
+    fsum+=m_fibres[f].get_f();	
+  }    //Gaussian centered around LRvox neighbourhood mean
+  m_fsum_prior=0.5*(fsum-m_mean_fsum)*(fsum-m_mean_fsum)/(m_stdev_fsum*m_stdev_fsum)+log(m_stdev_fsum);
+  //m_fsum_prior=0.5*(fsum-0.6)*(fsum-0.6)/(0.1*0.1);
+}
+
+
+void HRvoxel::update_fsum_prior(){
+  compute_fsum_prior();
+  compute_prior();
+}
+
+
+void HRvoxel::restore_fsum_prior(){
+  m_fsum_prior=m_fsum_old_prior;
+  m_prior_en=m_old_prior_en;
+}
+
+
+
+//Compute the predicted signal from the isotropic compartment only
+void HRvoxel::compute_iso_signal(){              
+  m_iso_SignalHR_old=m_iso_SignalHR;
+  m_iso_SignalLR_old=m_iso_SignalLR;
+
+  if(m_modelnum==1 || m_d_std<1e-5){
+    for(int i=1; i<=m_bvecsHR.Ncols(); i++)
+      m_iso_SignalHR(i)=exp(-m_d*m_bvalsHR(1,i));
+    for(int i=1; i<=m_bvecsLR.Ncols(); i++)
+      m_iso_SignalLR(i)=exp(-m_d*m_bvalsLR(1,i));
+  }
+  else if (m_modelnum==2){
+    float dbeta=m_d/(m_d_std*m_d_std);
+    float dalpha=m_d*dbeta;	  
+        
+    for(int i=1; i<=m_bvecsHR.Ncols(); i++)
+      m_iso_SignalHR(i)=exp(log(dbeta/(dbeta+m_bvalsHR(1,i)))*dalpha);
+    for(int i=1; i<=m_bvecsLR.Ncols(); i++)
+      m_iso_SignalLR(i)=exp(log(dbeta/(dbeta+m_bvalsLR(1,i)))*dalpha);
+  }
+}
+
+
+//Compute the total predicted signal at High and Low Res measurement points
+void HRvoxel::compute_signal(){
+  m_SignalHR_old=m_SignalHR;
+  m_SignalLR_old=m_SignalLR;
+  float fsum=0;//m_f0;
+  m_SignalHR=0; m_SignalLR=0;
+  for(int f=0; f<m_numfibres; f++){   //Signal from the anisotropic compartments
+    m_SignalHR=m_SignalHR+m_fibres[f].get_f()*m_fibres[f].getSignalHR();
+    m_SignalLR=m_SignalLR+m_fibres[f].get_f()*m_fibres[f].getSignalLR();
+    fsum+=m_fibres[f].get_f();               //Total anisotropic volume fraction
+  }
+
+  for(int i=1;i<=m_bvecsHR.Ncols();i++)                                     //Add the signal from the isotropic compartment 
+    m_SignalHR(i)=m_S0*(m_SignalHR(i)+(1-fsum)*m_iso_SignalHR(i));//+m_f0); //and multiply by S0 to get the total signal  
+
+  for(int i=1;i<=m_bvecsLR.Ncols();i++)                                     //Add the signal from the isotropic compartment 
+    m_SignalLR(i)=m_S0*(m_SignalLR(i)+(1-fsum)*m_iso_SignalLR(i));//+m_f0); //and multiply by S0 to get the total signal 
+}
+ 
+
+
+bool HRvoxel::propose_d(){
+  bool rejflag;
+  m_d_old=m_d;
+  m_d+=normrnd().AsScalar()*m_d_prop;
+  rejflag=compute_d_prior();
+  for(int f=0; f<m_numfibres; f++)
+    m_fibres[f].compute_signal();
+  compute_iso_signal();        
+  return rejflag;
+}
+
+
+void HRvoxel::reject_d(){
+  m_d=m_d_old; 
+  m_d_prior=m_d_old_prior;
+  for(int f=0; f<m_numfibres; f++)
+    m_fibres[f].restoreSignals();
+  m_iso_SignalHR=m_iso_SignalHR_old;  
+  m_iso_SignalLR=m_iso_SignalLR_old;
+  m_d_rej++;
+}
+
+
+bool HRvoxel::propose_d_std(){
+  bool rejflag;
+  m_d_std_old=m_d_std;
+  m_d_std+=normrnd().AsScalar()*m_d_std_prop;
+  rejflag=compute_d_std_prior();
+  for(int f=0; f<m_numfibres; f++)
+    m_fibres[f].compute_signal();
+  compute_iso_signal();        
+  return rejflag;
+}
+
+
+void HRvoxel::reject_d_std(){
+  m_d_std=m_d_std_old; 
+  m_d_prior=m_d_old_prior;
+  for(int f=0; f<m_numfibres; f++)
+    m_fibres[f].restoreSignals();
+  m_iso_SignalHR=m_iso_SignalHR_old;  
+  m_iso_SignalLR=m_iso_SignalLR_old;
+  m_d_std_rej++;
+}
+
+
+bool HRvoxel::propose_S0(){
+  m_S0_old=m_S0;
+  m_S0+=normrnd().AsScalar()*m_S0_prop;
+  bool rejflag=compute_S0_prior();//inside this it stores the old prior
+  return rejflag;
+}
+
+    
+void HRvoxel::reject_S0(){
+  m_S0=m_S0_old;
+  m_S0_prior=m_S0_old_prior;
+  m_S0_rej++;
+}
+
+
+bool HRvoxel::propose_tau(){
+  m_tau_old=m_tau;
+  m_tau+=normrnd().AsScalar()*m_tau_prop;
+  bool rejflag=compute_tau_prior();//inside this it stores the old prior
+  return rejflag;
+}
+
+    
+void HRvoxel::reject_tau(){
+  m_tau=m_tau_old;
+  m_tau_prior=m_tau_old_prior;
+  m_tau_rej++;
+}
+
+
+void HRvoxel::restore_prior_totsignal(){
+  m_prior_en=m_old_prior_en;
+  m_SignalLR=m_SignalLR_old;
+  m_SignalHR=m_SignalHR_old;
+}
+
+void HRvoxel::restore_prior(){
+  m_prior_en=m_old_prior_en;
+}
+
+
+//Adapt standard deviation of proposal distributions during MCMC execution 
+//to avoid over-rejection/over-acceptance of MCMC samples
+void HRvoxel::update_proposals(){
+  m_d_prop*=sqrt(float(m_d_acc+1)/float(m_d_rej+1));
+  m_d_prop=min(m_d_prop,maxfloat);
+  m_S0_prop*=sqrt(float(m_S0_acc+1)/float(m_S0_rej+1));
+  m_S0_prop=min(m_S0_prop,maxfloat);
+  m_d_acc=0; 
+  m_d_rej=0;
+  m_S0_acc=0; 
+  m_S0_rej=0;
+  if (m_rician){
+    m_tau_prop*=sqrt(float(m_tau_acc+1)/float(m_tau_rej+1));
+    m_tau_prop=min(m_tau_prop,maxfloat);
+    m_tau_acc=0;  m_tau_rej=0;
+  }
+  if(m_modelnum==2){
+    m_d_std_prop*=sqrt(float(m_d_std_acc+1)/float(m_d_std_rej+1));
+    m_d_std_prop=min(m_d_std_prop,maxfloat);
+    m_d_std_acc=0;  m_d_std_rej=0;
+  }
+  for(unsigned int f=0; f<m_fibres.size();f++)
+    m_fibres[f].update_proposals();
+}
+
+
+
+void HRvoxel::report() const{
+  OUT(m_d);           OUT(m_d_old);           OUT(m_d_prop);
+  OUT(m_d_prior);     OUT(m_d_old_prior);     OUT(m_d_acc);          OUT(m_d_rej);
+  OUT(m_d_std);       OUT(m_d_std_old);       OUT(m_d_std_prop);
+  OUT(m_d_std_prior); OUT(m_d_std_old_prior); OUT(m_d_std_acc);      OUT(m_d_std_rej);
+  OUT(m_S0);          OUT(m_S0_old);          OUT(m_S0_prop);        
+  OUT(m_S0_prior);    OUT(m_S0_old_prior);    OUT(m_S0_acc);         OUT(m_S0_rej);
+  OUT(m_prior_en);    OUT(m_old_prior_en);    OUT(m_SignalHR.t());   OUT(m_SignalLR.t());
+  for (int i=0; i<m_numfibres; i++){
+    cout <<"fibre "<<i<<endl;
+    m_fibres[i].report();} 
+}
+
+
+
+
+//Class that models a single mode of the orientation prior
+/////////////////////////////
+//   Orient_Prior_Mode     //
+/////////////////////////////
+
+//Call that after initialising the parameters
+void Orient_Prior_Mode::initialise_energies(){
+  compute_th_prior();
+  compute_ph_prior(); 
+  compute_invkappa_prior(); 
+  compute_prior();   
+}
+
+
+//Uniform Prior on theta
+bool Orient_Prior_Mode::compute_th_prior(){
+  m_th_old_prior=m_th_prior;
+  if(m_th==0){ m_th_prior=0; }
+  else{
+   m_th_prior=-log(fabs(sin(m_th)/2.0));
+  }
+  return false; //instant rejection flag
+}
+
+
+//Uniform Prior on phi
+bool Orient_Prior_Mode::compute_ph_prior(){
+  m_ph_old_prior=m_ph_prior;
+  m_ph_prior=0;
+  return false;
+}
+
+
+//ARD Prior on invkappa
+bool Orient_Prior_Mode::compute_invkappa_prior(){
+  m_invkappa_old_prior=m_invkappa_prior;
+  if(m_invkappa<=0)   
+    return true;
+  else{
+    if (m_kappa_ard)
+      m_invkappa_prior=log(m_invkappa);
+    else
+      m_invkappa_prior=0;
+    return false;
+  }
+}
+
+
+//Compute Joint Prior energy
+void Orient_Prior_Mode::compute_prior(){
+  m_old_prior_en=m_prior_en;
+  m_prior_en=m_th_prior+m_ph_prior+m_invkappa_prior;
+}      
+
+
+//Filter out extreme values of invkappa to ensure calculations are numerically stable 
+void Orient_Prior_Mode::filter_invkappa(){
+  const float MINinvk=1e-7;  //1e-6
+  if (m_invkappa<MINinvk)
+    m_invkappa=MINinvk; 
+}
+
+  
+  
+
+//Compute the normalization constant of a Watson distribution
+//with dispersion index 1/kappa. Use a saddlepoint approximation (see Kume & Wood, 2005)
+float Orient_Prior_Mode::compute_Watson_norm() {
+  float k,ct,R,t,Bm,K2,K3,K4,T;
+  
+  k=1.0/m_invkappa;
+  R=sqrt(4.0*k*k+9.0-4.0*k);
+  t=-0.25*(R+3+2.0*k); 
+  Bm=1.0/(R+3+2*k); 
+  K2=1.0/(2.0*(k+t)*(k+t))+1.0/(t*t);
+  K3=-1.0/((k+t)*(k+t)*(k+t))-2.0/(t*t*t);
+  K4=3.0/((k+t)*(k+t)*(k+t)*(k+t))+6.0/(t*t*t*t);
+  T=K4/(8.0*K2*K2)-5.0*K3*K3/(24.0*K2*K2*K2);
+  //ct=4.0*M_PI*sqrt(Bm/R)*exp(-t+T);
+  ct=-t+T+log(4.0*M_PI*sqrt(Bm/R));   //compute the log of the normalization constant, to avoid exponential overflow
+  return ct;
+}
+
+
+bool Orient_Prior_Mode::propose_th(){
+  m_th_old=m_th;
+  m_th+=normrnd().AsScalar()*m_th_prop;
+  m_vec_old=m_vec;
+  m_vec<<sin(m_th)*cos(m_ph) <<sin(m_th)*sin(m_ph) <<cos(m_th);
+  bool rejflag=compute_th_prior();//inside this it stores the old prior
+  compute_prior();
+  return rejflag;
+}
+
+
+void Orient_Prior_Mode::reject_th(){
+  m_th=m_th_old; 
+  m_th_prior=m_th_old_prior; 
+  m_vec=m_vec_old;
+  m_prior_en=m_old_prior_en; 
+  m_th_rej++;
+}
+    
+
+bool Orient_Prior_Mode::propose_ph(){
+  m_ph_old=m_ph;
+  m_ph+=normrnd().AsScalar()*m_ph_prop;
+  m_vec_old=m_vec;
+  m_vec<<sin(m_th)*cos(m_ph) <<sin(m_th)*sin(m_ph) <<cos(m_th);
+  bool rejflag=compute_ph_prior();//inside this it stores the old prior
+  compute_prior();
+  return rejflag;
+}
+
+
+void Orient_Prior_Mode::reject_ph(){
+  m_ph=m_ph_old; 
+  m_ph_prior=m_ph_old_prior; 
+  m_vec=m_vec_old;
+  m_prior_en=m_old_prior_en; 
+  m_ph_rej++;
+}
+ 
+
+bool Orient_Prior_Mode::propose_invkappa(){
+  m_invkappa_old=m_invkappa;
+  m_invkappa+=normrnd().AsScalar()*m_invkappa_prop;
+  filter_invkappa();
+  m_Watson_norm_old=m_Watson_norm;
+  m_Watson_norm=compute_Watson_norm();
+  bool rejflag=compute_invkappa_prior();
+  compute_prior();
+  return rejflag;
+}
+
+
+void Orient_Prior_Mode::reject_invkappa(){
+  m_invkappa=m_invkappa_old; 
+  m_invkappa_prior=m_invkappa_old_prior;
+  m_Watson_norm=m_Watson_norm_old; 
+  m_prior_en=m_old_prior_en; 
+  m_invkappa_rej++;
+}
+
+
+void Orient_Prior_Mode::update_proposals(){
+  m_th_prop*=sqrt(float(m_th_acc+1)/float(m_th_rej+1));
+  m_th_prop=min(m_th_prop,maxfloat);
+  m_ph_prop*=sqrt(float(m_ph_acc+1)/float(m_ph_rej+1));
+  m_ph_prop=min(m_ph_prop,maxfloat);
+  m_invkappa_prop*=sqrt(float(m_invkappa_acc+1)/float(m_invkappa_rej+1));
+  m_invkappa_prop=min(m_invkappa_prop,maxfloat);
+  m_th_acc=0;  m_th_rej=0;
+  m_ph_acc=0;  m_ph_rej=0;
+  m_invkappa_acc=0; m_invkappa_rej=0;
+}
+
+
+
+
+
+////////////////////////////////////////////////
+//       LRvoxel
+////////////////////////////////////////////////
+
+//Call that after initialising all parameters
+void LRvoxel::initialise_energies(){
+  m_S0LR_prop=m_S0LR/10.0;
+  compute_S0LR_prior();
+
+  if (m_dPrior_ON){
+    m_mean_d_prop=m_mean_d/10.0;
+    m_stdev_d_prop=m_stdev_d/10.0;
+    compute_meand_prior();   compute_stdevd_prior();
+  }
+  if (m_fsumPrior_ON){
+    compute_mean_fsum_prior();   
+    compute_stdev_fsum_prior();
+  }
+
+  if (m_rician){
+    m_tauLR_prop=m_tauLR/2.0;
+    compute_tauLR_prior();
+  }
+  for (int m=0; m<m_Nmodes; m++)
+    m_PModes[m].initialise_energies();
+  for (unsigned int n=0; n<m_dataHR.size(); n++)
+    m_HRvoxels[n].initialise_energies_props();
+  compute_prior();
+  compute_likelihood();
+  compute_posterior();
+  //  cout<<"Likelihood Energy:"<<m_likelihood_en<<endl;
+  //cout<<"Prior Energy:"<<m_prior_en<<endl;
+  //cout<<"Posterior Energy:"<<m_posterior_en<<endl<<endl;
+}
+
+
+//Update the matrix that keeps information
+//on the orientation prior parameters
+void LRvoxel::update_Orient_hyp_prior(){
+  for (int m=0; m<m_Nmodes; m++){
+    ColumnVector temp;
+    temp=m_PModes[m].getVec();
+    m_Orient_hyp_prior(m+1,1)=temp(1);     
+    m_Orient_hyp_prior(m+1,2)=temp(2);
+    m_Orient_hyp_prior(m+1,3)=temp(3);
+    m_Orient_hyp_prior(m+1,4)=m_PModes[m].get_invkappa();
+    m_Orient_hyp_prior(m+1,5)=m_PModes[m].get_Watson_norm();
+  }
+}
+
+
+//Update the matrix that keeps information
+//on the orientation prior parameters. Update only
+//mode M (0<=M<N_modes)
+void LRvoxel::update_Orient_hyp_prior(int M){
+    ColumnVector temp;
+    temp=m_PModes[M].getVec();
+    m_Orient_hyp_prior(M+1,1)=temp(1);     
+    m_Orient_hyp_prior(M+1,2)=temp(2);
+    m_Orient_hyp_prior(M+1,3)=temp(3);
+    m_Orient_hyp_prior(M+1,4)=m_PModes[M].get_invkappa();
+    m_Orient_hyp_prior(M+1,5)=m_PModes[M].get_Watson_norm();
+}
+
+
+
+//Set params for a single HRvoxel with index 0 <= n < N (model 1)
+void LRvoxel::set_HRparams(const int n, const float d, const float S0, const ColumnVector& th, const ColumnVector& ph, const ColumnVector& f){
+  m_HRvoxels[n].set_d(d);
+  m_HRvoxels[n].set_S0(S0);
+  if (m_allard && !m_Noard){
+    m_HRvoxels[n].addfibre(th(1),ph(1),f(1),true);    //ARD on for the first fibre
+  }
+  else{
+    m_HRvoxels[n].addfibre(th(1),ph(1),f(1),false);   //ARD off for the first fibre
+  }
+  for (int m=2; m<=m_numfibres; m++){
+    if (m_Noard){
+      m_HRvoxels[n].addfibre(th(m),ph(m),f(m),false); //ARD off for the other fibres
+    }
+    else{
+      m_HRvoxels[n].addfibre(th(m),ph(m),f(m),true);  //ARD on for the other fibres
+    }
+  }
+}
+
+
+//Set params for a single HRvoxel with index 0 <= n < N (model 2)
+void LRvoxel::set_HRparams(const int n, const float d, const float d_std,const float S0, const ColumnVector& th, const ColumnVector& ph, const ColumnVector& f){
+  m_HRvoxels[n].set_d(d);
+  m_HRvoxels[n].set_d_std(d_std);
+  m_HRvoxels[n].set_S0(S0);
+  if (m_allard && !m_Noard)
+    m_HRvoxels[n].addfibre(th(1),ph(1),f(1),true);  //ARD on for the first fibre
+  else
+    m_HRvoxels[n].addfibre(th(1),ph(1),f(1),false); //ARD off for the first fibre
+  for (int m=2; m<=m_numfibres; m++){
+    if (m_Noard)
+      m_HRvoxels[n].addfibre(th(m),ph(m),f(m),false); //ARD off for the other fibres
+    else
+      m_HRvoxels[n].addfibre(th(m),ph(m),f(m),true);  //ARD on for the other fibres
+  }
+}
+
+
+
+//Set params for all modes of orientation priors
+void LRvoxel::set_Priorparams(const ColumnVector& th, const ColumnVector& ph, const ColumnVector& invkappa){
+  for (int m=1; m<=m_Nmodes; m++){
+    m_PModes[m-1].set_th(th(m));
+    m_PModes[m-1].set_ph(ph(m));
+    m_PModes[m-1].set_invkappa(invkappa(m));
+  }
+}
+
+
+
+bool LRvoxel::propose_S0LR(){
+  m_S0LR_old=m_S0LR;
+  m_S0LR+=normrnd().AsScalar()*m_S0LR_prop;
+  bool rejflag=compute_S0LR_prior();//inside this it stores the old prior
+  return rejflag;
+}
+
+    
+void LRvoxel::reject_S0LR(){
+  m_S0LR=m_S0LR_old;
+  m_S0LR_prior=m_S0LR_old_prior;
+  m_S0LR_rej++;
+}
+
+
+bool LRvoxel::compute_S0LR_prior(){
+  m_S0LR_old_prior=m_S0LR_prior;
+  if(m_S0LR<0) return true;
+  else{    
+    m_S0LR_prior=0;
+    return false;
+  }
+}
+
+
+
+bool LRvoxel::propose_meand(){
+  m_mean_d_old=m_mean_d;
+  m_mean_d+=normrnd().AsScalar()*m_mean_d_prop;
+  bool rejflag=compute_meand_prior();//inside this it stores the old prior
+  return rejflag;
+}
+
+void LRvoxel::reject_meand(){
+  m_mean_d=m_mean_d_old;
+  m_mean_d_prior=m_mean_d_old_prior;
+  m_mean_d_rej++;
+}
+
+
+bool LRvoxel::compute_meand_prior(){
+  m_mean_d_old_prior=m_mean_d_prior;
+  if(m_mean_d<=0) return true;
+  else{    
+    //m_mean_d_prior=0;
+    float alpha=3.0;
+    float beta=2000;  //Gamma_prior centered around 1e-3
+    m_mean_d_prior=(1.0-alpha)*log(m_mean_d)+beta*m_mean_d; //Gamma_prior: pow(m_mean_d,alpha-1.0)*exp(-beta*m_mean_d)
+
+    return false;
+  }
+}
+
+
+bool LRvoxel::propose_stdevd(){
+  m_stdev_d_old=m_stdev_d;
+  m_stdev_d+=normrnd().AsScalar()*m_stdev_d_prop;
+  bool rejflag=compute_stdevd_prior();//inside this it stores the old prior
+  return rejflag;
+}
+
+
+void LRvoxel::reject_stdevd(){
+  m_stdev_d=m_stdev_d_old;
+  m_stdev_d_prior=m_stdev_d_old_prior;
+  m_stdev_d_rej++;
+}
+
+bool LRvoxel::compute_stdevd_prior(){
+  m_stdev_d_old_prior=m_stdev_d_prior;
+  if(m_stdev_d<=0 || m_stdev_d>=0.002) return true;
+  else{    
+    m_stdev_d_prior=0;
+    //m_stdev_d_prior=log(m_stdev_d); //ARD prior
+    return false;
+  }
+}
+
+
+bool LRvoxel::propose_mean_fsum(){
+  m_mean_fsum_old=m_mean_fsum;
+  m_mean_fsum+=normrnd().AsScalar()*m_mean_fsum_prop;
+  bool rejflag=compute_mean_fsum_prior();//inside this it stores the old prior
+  return rejflag;
+}
+
+
+void LRvoxel::reject_mean_fsum(){
+  m_mean_fsum=m_mean_fsum_old;
+  m_mean_fsum_prior=m_mean_fsum_old_prior;
+  m_mean_fsum_rej++;
+}
+
+
+bool LRvoxel::compute_mean_fsum_prior(){
+  m_mean_fsum_old_prior=m_mean_fsum_prior;
+  if(m_mean_fsum<=0 || m_mean_fsum>=1) return true;
+  else{    
+    //m_mean_fsum_prior=0;
+    m_mean_fsum_prior=-log(m_mean_fsum)-log(1-m_mean_fsum);   //Beta distribution with a=b=2: fsum^(a-1)*(1-fsum)^(b-1)
+    return false;
+  }
+}
+
+
+bool LRvoxel::propose_stdev_fsum(){
+  m_stdev_fsum_old=m_stdev_fsum;
+  m_stdev_fsum+=normrnd().AsScalar()*m_stdev_fsum_prop;
+  bool rejflag=compute_stdev_fsum_prior();//inside this it stores the old prior
+  return rejflag;
+}
+
+
+void LRvoxel::reject_stdev_fsum(){
+  m_stdev_fsum=m_stdev_fsum_old;
+  m_stdev_fsum_prior=m_stdev_fsum_old_prior;
+  m_stdev_fsum_rej++;
+}
+
+
+bool LRvoxel::compute_stdev_fsum_prior(){
+  m_stdev_fsum_old_prior=m_stdev_fsum_prior;
+  if(m_stdev_fsum<=0 || m_stdev_fsum>=0.1) return true; //Without restriction to (0,0.1), very large values (e.g. 100's) are preferred for stdev, so that the fsum_prior becomes uniform 
+  else{    
+    m_stdev_fsum_prior=0;      
+    //m_stdev_fsum_prior=log(m_stdev_fsum);      //ARD prior  
+    //m_stdev_fsum_prior=-log(25*m_stdev_fsum)-log(1-5*m_stdev_fsum);      //Beta distribution with a=2,b=2, defined on [0,0.2].  
+    //m_stdev_fsum_prior=-2*log(1-m_stdev_fsum);   //Beta distribution with a=1, b=3. Similar to an ARD, but is naturally restricted to [0,1] 
+    return false;
+  }
+}
+
+
+bool LRvoxel::propose_tauLR(){
+  m_tauLR_old=m_tauLR;
+  m_tauLR+=normrnd().AsScalar()*m_tauLR_prop;
+  bool rejflag=compute_tauLR_prior();//inside this it stores the old prior
+  return rejflag;
+}
+
+    
+void LRvoxel::reject_tauLR(){
+  m_tauLR=m_tauLR_old;
+  m_tauLR_prior=m_tauLR_old_prior;
+  m_tauLR_rej++;
+}
+
+
+bool LRvoxel::compute_tauLR_prior(){
+  m_tauLR_old_prior=m_tauLR_prior;
+  if(m_tauLR<=0) return true;
+  else{    
+    m_tauLR_prior=0;
+    return false;
+  }
+}
+
+
+void LRvoxel::compute_prior(){
+  m_old_prior_en=m_prior_en;  
+  m_prior_en=0;
+
+  m_prior_en=m_S0LR_prior;
+  if (m_rician)
+    m_prior_en+=m_tauLR_prior;
+  for (int m=0; m<m_Nmodes; m++)
+    m_prior_en+=m_PModes[m].get_prior();
+    
+  for (unsigned int m=0; m<m_dataHR.size(); m++)
+    m_prior_en+=m_HRvoxels[m].get_prior();
+  
+  if (m_dPrior_ON)
+    m_prior_en+=m_mean_d_prior+m_stdev_d_prior;
+  if (m_fsumPrior_ON)
+    m_prior_en+=m_mean_fsum_prior+m_stdev_fsum_prior;
+}
+
+
+void LRvoxel::compute_likelihood(){
+  ColumnVector SLRpred, SHRpred, Diff;
+  SLRpred.ReSize(m_bvecsLR.Ncols()); 
+  SHRpred.ReSize(m_bvecsHR.Ncols()); SHRpred=0;
+  float likLR, likHR;
+
+  m_old_likelihood_en=m_likelihood_en;
+
+  if (!m_rician){ //Gaussian Likelihood Energy Calculation
+    //likelihood of Low-Res data 
+    SLRpred=0;
+    for (unsigned int m=0; m<m_dataHR.size(); m++) //add attenuations
+      SLRpred+=m_HRweights(m+1)*m_HRvoxels[m].getSignalLR()/m_HRvoxels[m].get_S0();
+    SLRpred=m_S0LR*SLRpred;
+    SLRpred=m_dataLR-SLRpred;
+    likLR=0.5*m_bvecsLR.Ncols()*log(0.5*SLRpred.SumSquare()); 
+
+    //likelihood of High-Res data
+    likHR=0; 
+    for (unsigned int m=0; m<m_dataHR.size(); m++){
+      SHRpred=m_HRvoxels[m].getSignalHR();
+      SHRpred=m_dataHR[m]-SHRpred;
+      likHR+=log(0.5*SHRpred.SumSquare());
+    }
+    likHR*=0.5*m_bvecsHR.Ncols();      
+
+    m_likelihood_en=likLR+likHR;
+  }
+  else{  //Rician Likelihood Energy Calculation
+    //likelihood of Low-Res data 
+    SLRpred=0;
+    for (unsigned int m=0; m<m_dataHR.size(); m++) //add attenuations
+      SLRpred+=m_HRweights(m+1)*m_HRvoxels[m].getSignalLR()/m_HRvoxels[m].get_S0();
+    SLRpred=m_S0LR*SLRpred;
+    likLR=-m_bvecsLR.Ncols()*log(m_tauLR);  
+    for (int k=1; k<=m_bvecsLR.Ncols(); k++)
+      likLR-=m_logdataLR(k)-0.5*m_tauLR*(m_dataLR(k)*m_dataLR(k)+SLRpred(k)*SLRpred(k))+logIo(m_tauLR*m_dataLR(k)*SLRpred(k));
+
+    //likelihood of High-Res data
+    likHR=0; 
+    for (unsigned int m=0; m<m_dataHR.size(); m++){    
+      float m_tauHR=m_HRvoxels[m].get_tau();
+      SHRpred=m_HRvoxels[m].getSignalHR();
+      likHR+=m_bvecsHR.Ncols()*log(m_tauHR);
+      for (int k=1; k<=m_bvecsHR.Ncols(); k++)
+	likHR+=m_logdataHR[m](k)-0.5*m_tauHR*(m_dataHR[m](k)*m_dataHR[m](k)+SHRpred(k)*SHRpred(k))+logIo(m_tauHR*m_dataHR[m](k)*SHRpred(k));
+    }
+    m_likelihood_en=likLR-likHR;
+  }
+}
+
+
+void LRvoxel::compute_posterior(){
+  m_old_posterior_en=m_posterior_en;
+  m_posterior_en=m_prior_en+m_likelihood_en;
+}
+
+
+//Test whether the candidate state will be accepted 
+bool LRvoxel::test_energy() const{
+  float tmp=exp(m_old_posterior_en-m_posterior_en);
+  return (tmp>unifrnd().AsScalar());
+}
+ 
+
+void LRvoxel::restore_energies(){
+  m_prior_en=m_old_prior_en;
+  m_likelihood_en=m_old_likelihood_en;
+  m_posterior_en=m_old_posterior_en;
+}
+
+
+void LRvoxel::restore_Prior_Posterior(){
+  m_prior_en=m_old_prior_en;
+  m_posterior_en=m_old_posterior_en;
+}
+
+
+void LRvoxel::update_proposals(){
+  for(int m=0; m<m_Nmodes; m++)
+    m_PModes[m].update_proposals();
+  for(unsigned int n=0; n<m_dataHR.size(); n++)
+    m_HRvoxels[n].update_proposals();
+
+  m_S0LR_prop*=sqrt(float(m_S0LR_acc+1)/float(m_S0LR_rej+1));
+  m_S0LR_prop=min(m_S0LR_prop,maxfloat);
+  m_S0LR_acc=0; m_S0LR_rej=0;
+
+  if (m_dPrior_ON){
+    m_mean_d_prop*=sqrt(float(m_mean_d_acc+1)/float(m_mean_d_rej+1));
+    m_mean_d_prop=min(m_mean_d_prop,maxfloat);
+    m_mean_d_acc=0; m_mean_d_rej=0;
+
+    m_stdev_d_prop*=sqrt(float(m_stdev_d_acc+1)/float(m_stdev_d_rej+1));
+    m_stdev_d_prop=min(m_stdev_d_prop,maxfloat);
+    m_stdev_d_acc=0; m_stdev_d_rej=0;
+  }
+
+  if (m_fsumPrior_ON){
+    m_mean_fsum_prop*=sqrt(float(m_mean_fsum_acc+1)/float(m_mean_fsum_rej+1));
+    m_mean_fsum_prop=min(m_mean_fsum_prop,maxfloat);
+    m_mean_fsum_acc=0; m_mean_fsum_rej=0;
+
+    m_stdev_fsum_prop*=sqrt(float(m_stdev_fsum_acc+1)/float(m_stdev_fsum_rej+1));
+    m_stdev_fsum_prop=min(m_stdev_fsum_prop,maxfloat);
+    m_stdev_fsum_acc=0; m_stdev_fsum_rej=0;
+  }
+
+  if (m_rician){
+    m_tauLR_prop*=sqrt(float(m_tauLR_acc+1)/float(m_tauLR_rej+1));
+    m_tauLR_prop=min(m_tauLR_prop,maxfloat);
+    m_tauLR_acc=0; m_tauLR_rej=0;
+  }
+}
+
+
+//Single MCMC iteration with all parameters jumped
+void LRvoxel::jump(){
+
+  //Jump LRvoxel parameters first
+ 
+  if(!propose_S0LR()){    //Try S0LR 
+    compute_prior();
+    compute_likelihood();
+    compute_posterior();
+    if(test_energy()){
+      accept_S0LR();
+    }
+    else{
+      restore_energies();
+      reject_S0LR();
+    }
+  }
+  else 
+    reject_S0LR();
+  
+  if (m_dPrior_ON){
+    if(!propose_meand()){    //Try mean_d 
+      for (unsigned int n=0; n<m_dataHR.size(); n++) //update nuisance_prior for each HR voxel
+	m_HRvoxels[n].update_d_prior();
+    
+      compute_prior();
+      compute_posterior();
+      if(test_energy()){
+	accept_meand();
+      }
+      else{
+	restore_Prior_Posterior();
+	for (unsigned int n=0; n<m_dataHR.size(); n++) //restore nuisance_prior_energy for each HR voxel
+	  m_HRvoxels[n].restore_d_prior();
+	reject_meand();
+      }
+    }
+    else 
+      reject_meand();
+ 
+    if(!propose_stdevd()){    //Try stdev_d 
+      for (unsigned int n=0; n<m_dataHR.size(); n++) //update nuisance_prior energy for each HR voxel
+	m_HRvoxels[n].update_d_prior();
+    
+      compute_prior();
+      compute_posterior();
+      if(test_energy()){
+	accept_stdevd();
+      }
+      else{
+	restore_Prior_Posterior();
+	for (unsigned int n=0; n<m_dataHR.size(); n++) //restore nuisance_prior_energy for each HR voxel
+	  m_HRvoxels[n].restore_d_prior();
+	reject_stdevd();
+      }
+    }
+    else 
+      reject_stdevd();
+  }
+
+  if (m_fsumPrior_ON){
+    if(!propose_mean_fsum()){    //Try mean_fsum
+      for (unsigned int n=0; n<m_dataHR.size(); n++) //update nuisance_prior for each HR voxel
+	m_HRvoxels[n].update_fsum_prior();
+    
+      compute_prior();
+      compute_posterior();
+      if(test_energy()){
+	accept_mean_fsum();
+      }
+      else{
+	restore_Prior_Posterior();
+	for (unsigned int n=0; n<m_dataHR.size(); n++) //restore nuisance_prior_energy for each HR voxel
+	  m_HRvoxels[n].restore_fsum_prior();
+	reject_mean_fsum();
+      }
+    }
+    else 
+      reject_mean_fsum();
+
+    if(!propose_stdev_fsum()){    //Try stdev_fsum 
+      for (unsigned int n=0; n<m_dataHR.size(); n++) //update nuisance_prior energy for each HR voxel
+	m_HRvoxels[n].update_fsum_prior();
+    
+      compute_prior();
+      compute_posterior();
+      if(test_energy()){
+	accept_stdev_fsum();
+      }
+      else{
+	restore_Prior_Posterior();
+	for (unsigned int n=0; n<m_dataHR.size(); n++) //restore nuisance_prior_energy for each HR voxel
+	  m_HRvoxels[n].restore_fsum_prior();
+	reject_stdev_fsum();
+      }
+    }
+    else 
+      reject_stdev_fsum();
+  }
+
+  if (m_rician){
+    if(!propose_tauLR()){    //Try tauLR 
+      compute_prior();
+      compute_likelihood();
+      compute_posterior();
+      if(test_energy()){
+	accept_tauLR();
+      }
+      else{
+	restore_energies();
+	reject_tauLR();
+      }
+    }
+    else 
+      reject_tauLR();
+  }
+
+  //For each mode of the Orientation Prior
+  for(int m=0; m<m_Nmodes; m++){ 
+  
+    if(!m_PModes[m].propose_th()){    //Try theta 
+      update_Orient_hyp_prior(m);
+      for (unsigned int n=0; n<m_dataHR.size(); n++) //update th_ph_prior for each HR voxel
+	m_HRvoxels[n].update_th_ph_prior();
+	
+      compute_prior();
+      //compute_likelihood();
+      compute_posterior();
+      if(test_energy()){
+	m_PModes[m].accept_th();
+      }
+      else{
+	//restore_energies();
+	restore_Prior_Posterior();
+	for (unsigned int n=0; n<m_dataHR.size(); n++) //update th_ph_prior for each HR voxel
+	  m_HRvoxels[n].restore_th_ph_prior();
+	m_PModes[m].reject_th();
+	update_Orient_hyp_prior(m);
+      }
+    }
+    else 
+      m_PModes[m].reject_th();
+    
+
+    if(!m_PModes[m].propose_ph()){    //Try phi 
+      update_Orient_hyp_prior(m);
+      for (unsigned int n=0; n<m_dataHR.size(); n++) //update th_ph_prior for each HR voxel
+	m_HRvoxels[n].update_th_ph_prior();
+	
+      compute_prior();
+      //compute_likelihood();
+      compute_posterior();
+      if(test_energy()){
+	m_PModes[m].accept_ph();
+      }
+      else{
+	//restore_energies();
+	restore_Prior_Posterior();
+	for (unsigned int n=0; n<m_dataHR.size(); n++) //update th_ph_prior for each HR voxel
+	  m_HRvoxels[n].restore_th_ph_prior();
+	m_PModes[m].reject_ph();
+	update_Orient_hyp_prior(m);
+      }
+    }
+    else 
+      m_PModes[m].reject_ph();
+
+
+    if(!m_PModes[m].propose_invkappa()){    //Try invkappa 
+      update_Orient_hyp_prior(m);
+      for (unsigned int n=0; n<m_dataHR.size(); n++) //update th_ph_prior for each HR voxel
+	m_HRvoxels[n].update_th_ph_prior();
+	
+      compute_prior();
+      //compute_likelihood();
+      compute_posterior();
+      if(test_energy()){
+	m_PModes[m].accept_invkappa();
+      }
+      else{
+	//restore_energies();
+	restore_Prior_Posterior();
+	for (unsigned int n=0; n<m_dataHR.size(); n++) //update th_ph_prior for each HR voxel
+	  m_HRvoxels[n].restore_th_ph_prior();
+	m_PModes[m].reject_invkappa();
+	update_Orient_hyp_prior(m);
+      }
+    }
+    else 
+      m_PModes[m].reject_invkappa();
+  } //end Orientation Prior params
+
+
+  //For each HRvoxel
+  for (unsigned int n=0; n<m_dataHR.size(); n++){
+
+    if(!m_HRvoxels[n].propose_d()){    //Try d 
+      m_HRvoxels[n].compute_prior();
+      m_HRvoxels[n].compute_signal();
+      compute_prior();
+      compute_likelihood();
+      compute_posterior();
+      if(test_energy()){
+	m_HRvoxels[n].accept_d();
+      }
+      else{
+	restore_energies();
+	m_HRvoxels[n].restore_prior_totsignal();
+	m_HRvoxels[n].reject_d();
+      }
+    }
+    else 
+      m_HRvoxels[n].reject_d();
+      
+
+    if (m_modelnum==2){
+      if(!m_HRvoxels[n].propose_d_std()){    //Try d_std
+	m_HRvoxels[n].compute_prior();
+	m_HRvoxels[n].compute_signal();
+	compute_prior();
+	compute_likelihood();
+	compute_posterior();
+	if(test_energy()){
+	  m_HRvoxels[n].accept_d_std();
+	}
+	else{
+	  restore_energies();
+	  m_HRvoxels[n].restore_prior_totsignal();
+	  m_HRvoxels[n].reject_d_std();
+	}
+      }
+      else 
+	m_HRvoxels[n].reject_d_std();
+    }
+
+     if(!m_HRvoxels[n].propose_S0()){    //Try S0
+      m_HRvoxels[n].compute_prior();
+      m_HRvoxels[n].compute_signal();
+      compute_prior();
+      compute_likelihood();
+      compute_posterior();
+      if(test_energy())
+	m_HRvoxels[n].accept_S0();
+      else{
+	restore_energies();
+	m_HRvoxels[n].restore_prior_totsignal();
+	m_HRvoxels[n].reject_S0();
+      }
+    }
+    else
+      m_HRvoxels[n].reject_S0();
+      
+    if (m_rician){
+      if(!m_HRvoxels[n].propose_tau()){    //Try tau_HR
+	m_HRvoxels[n].compute_prior();
+	compute_prior();
+	compute_likelihood();
+	compute_posterior();
+	if(test_energy())
+	  m_HRvoxels[n].accept_tau();
+	else{
+	  restore_energies();
+	  m_HRvoxels[n].restore_prior();
+	  m_HRvoxels[n].reject_tau();
+	}
+      }
+      else
+	m_HRvoxels[n].reject_tau();
+    }
+
+    for(int f=0; f<m_numfibres; f++){   //For each fibre in the HR voxel
+      if(!m_HRvoxels[n].propose_th(f)){ //Try theta
+	m_HRvoxels[n].compute_prior();
+	m_HRvoxels[n].compute_signal();
+      	compute_prior();
+	compute_likelihood();
+	compute_posterior();
+	if(test_energy())
+	    m_HRvoxels[n].accept_th(f);
+	else{
+	  restore_energies();
+	  m_HRvoxels[n].restore_prior_totsignal();
+	  m_HRvoxels[n].reject_th(f);
+	}
+      }
+      else 
+	m_HRvoxels[n].reject_th(f);
+	
+	
+      if(!m_HRvoxels[n].propose_ph(f)){ //Try phi
+	m_HRvoxels[n].compute_prior();
+	m_HRvoxels[n].compute_signal();
+      	compute_prior();
+	compute_likelihood();
+	compute_posterior();
+	if(test_energy())
+	    m_HRvoxels[n].accept_ph(f);
+	else{
+	  restore_energies();
+	  m_HRvoxels[n].restore_prior_totsignal();
+	  m_HRvoxels[n].reject_ph(f);
+	}
+      }
+      else 
+	m_HRvoxels[n].reject_ph(f);
+	 
+
+      if(!m_HRvoxels[n].propose_f(f)){  //Try f 
+	if(!m_HRvoxels[n].reject_f_sum()){
+	  m_HRvoxels[n].compute_fsum_prior();
+	  m_HRvoxels[n].compute_prior();
+	  m_HRvoxels[n].compute_signal();
+	  compute_prior();
+	  compute_likelihood();
+	  compute_posterior();
+	  if(test_energy())
+	    m_HRvoxels[n].accept_f(f);
+	  else{
+	    restore_energies();
+	    m_HRvoxels[n].restore_prior_totsignal();
+	    m_HRvoxels[n].restore_fsum_prior();
+	    m_HRvoxels[n].reject_f(f);
+	  }
+	}
+	else   //else for rejectin fsum>1
+	  m_HRvoxels[n].reject_f(f);
+      }
+      else    //else for rejecting rejflag returned from propose_f()
+	m_HRvoxels[n].reject_f(f);
+    } //end anisotropic compartment parameters
+   
+  } //end HR voxel parameters
+}
+
+} //end namespace
diff --git a/rubixvox.h b/rubixvox.h
new file mode 100644
index 0000000..572104a
--- /dev/null
+++ b/rubixvox.h
@@ -0,0 +1,729 @@
+/*  rubixvox.h: Classes utilized in RubiX    */
+
+/*  Stam Sotiropoulos, FMRIB Analysis Group */
+
+/*  Copyright (C) 2012 University of Oxford  */
+
+/*  CCOPYRIGHT  */
+
+#if !defined(rubixvox_h)
+#define rubixvox_h
+
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#define WANT_STREAM
+#define WANT_MATH
+#include <string>
+#include <math.h>
+#include "miscmaths/miscmaths.h"
+#include "miscmaths/miscprob.h"
+#include "stdlib.h"
+#include "utils/log.h"
+
+using namespace std; 
+using namespace NEWMAT;
+using namespace MISCMATHS;
+
+namespace RUBIX{
+  const float maxfloat=1e10;
+  const float minfloat=1e-10;
+  const float maxlogfloat=23;
+  const float minlogfloat=-23;
+
+ //////////////////////////////////////////////////////////////////////
+ //       RFibre: Models one anisotropic compartment in an HR voxel
+ //////////////////////////////////////////////////////////////////////
+ class RFibre{
+    float m_th;                   //Current/candidate MCMC state
+    float m_ph;
+    float m_f;
+    ColumnVector m_vec;           //Holds the current/candidate orientation in cartesian coordinates
+    ColumnVector m_vec_old;
+    float m_th_prop;              //Standard deviation for Gaussian proposal distributions of parameters
+    float m_ph_prop;
+    float m_f_prop;
+    float m_th_old;               //Last accepted value. If a sample is rejected this value is restored
+    float m_ph_old;
+    float m_f_old;
+    float m_th_ph_prior;          //Priors for the model parameters 
+    float m_f_prior;
+    float m_th_ph_old_prior;
+    float m_f_old_prior;
+    float m_prior_en;             //Joint Prior 
+    float m_old_prior_en;
+    int m_th_acc;     
+    int m_th_rej;
+    int m_ph_acc;
+    int m_ph_rej; 
+    int m_f_acc;
+    int m_f_rej;
+    bool f_ard;                     //By default ARD is on, on the volume fraction f
+    ColumnVector m_SignalHR;        //Vector that stores the predicted signal from the anisotropic compartment during the candidate/current MCMC state at High-Res measurement points
+    ColumnVector m_SignalHR_old;
+    ColumnVector m_SignalLR;        //Vector that stores the predicted signal from the anisotropic compartment during the candidate/current MCMC state at Low-Res measurement points 
+    ColumnVector m_SignalLR_old;
+
+    const Matrix& m_Orient_hyp_prior;//Matrix Nmodes x 5 that contains the hyperparameters for the orientation prior 
+                                     //columns 1-3 contains the (x,y,z) coordinates for the mode, 4th column contains the invkappa value, 5th the Watson normalization constant
+    const float m_ardfudge;
+    const float& m_d;
+    const float& m_d_std;
+    const Matrix& m_bvecsHR;        //bvecs at High-Res   (3 x HR_NumPoints)
+    const Matrix& m_bvalsHR;        //bvalues at High-Res (1 x HR_NumPoints)
+    const Matrix& m_bvecsLR;        //bvecs at Low-Res    (3 x LR_NumPoints)
+    const Matrix& m_bvalsLR;        //bvalues at Low-Res  (1 x HR_NumPoints)
+    const int m_modelnum;           //1 for single-shell, 2 for multi-shell model 
+
+ public:
+ //constructor
+ RFibre(const float th, const float ph,const float f, const Matrix& bvecsHR, const Matrix& bvalsHR, 
+	    const Matrix& bvecsLR, const Matrix& bvalsLR, const Matrix& Orient_hyp_prior,
+	const float& d, const float& d_std, const bool ard=true, const int modelnum=1,const float ardfudge=1):
+    m_th(th), m_ph(ph), m_f(f), f_ard(ard), m_Orient_hyp_prior(Orient_hyp_prior),  m_ardfudge(ardfudge), m_d(d),
+      m_d_std(d_std),m_bvecsHR(bvecsHR), m_bvalsHR(bvalsHR), m_bvecsLR(bvecsLR), m_bvalsLR(bvalsLR), m_modelnum(modelnum){
+      m_th_old=m_th; m_ph_old=m_ph;
+      m_vec.ReSize(3);
+      m_vec<<sin(m_th)*cos(m_ph) <<sin(m_th)*sin(m_ph) <<cos(m_th);
+      m_vec_old=m_vec;
+      m_f_old=m_f;
+      m_th_prop=0.2; m_ph_prop=0.2; m_f_prop=m_f/5.0;
+	
+      m_th_ph_prior=0; m_th_ph_old_prior=0;
+      m_f_prior=0; m_f_old_prior=0;
+	
+      m_SignalHR.ReSize(m_bvecsHR.Ncols());  m_SignalHR=0;  m_SignalHR_old=m_SignalHR;
+      m_SignalLR.ReSize(m_bvecsLR.Ncols());  m_SignalLR=0;  m_SignalLR_old=m_SignalLR;
+
+      m_th_acc=0; m_th_rej=0;
+      m_ph_acc=0; m_ph_rej=0;
+      m_f_acc=0; m_f_rej=0;
+    }
+    
+    ~RFibre(){}
+    
+    inline float get_th() const{ return m_th;}
+    inline float get_ph() const{ return m_ph;}
+    inline const ColumnVector& getVec() const { return m_vec; }
+    inline float get_f() const{ return m_f;}
+    //inline void set_th(const float th){ m_th=th;   m_vec<<sin(m_th)*cos(m_ph) <<sin(m_th)*sin(m_ph) <<cos(m_th); }
+    //inline void set_ph(const float ph){ m_ph=ph;   m_vec<<sin(m_th)*cos(m_ph) <<sin(m_th)*sin(m_ph) <<cos(m_th); }
+    //inline void set_f(const float f){ m_f=f; }
+
+    inline const ColumnVector& getSignalHR() const{ return m_SignalHR; }
+    inline const ColumnVector& getSignalLR() const{ return m_SignalLR; }
+    inline void restoreSignals() { m_SignalHR=m_SignalHR_old; m_SignalLR=m_SignalLR_old; }
+    inline float get_prior() const{ return m_prior_en;}
+    
+    void initialise_energies(); //Initialize energies, signals 
+    void update_proposals(); 
+    bool compute_th_ph_prior();
+    bool compute_f_prior();
+    void compute_prior();
+    void compute_signal(); //Compute model predicted signal, only due to the anisotropic compartment 
+    void restore_th_ph_prior();
+
+    bool propose_th();
+    inline void accept_th(){ m_th_acc++; }   
+    void reject_th();
+    
+    bool propose_ph();
+    inline void accept_ph(){ m_ph_acc++; }
+    void reject_ph();
+    
+    bool propose_f();
+    inline void accept_f(){ m_f_acc++; }
+    void reject_f();
+
+    void report() const;
+
+    RFibre& operator=(const RFibre& rhs){
+      m_th=rhs.m_th; m_ph=rhs.m_ph; m_f=rhs.m_f;   
+      m_vec=rhs.m_vec;  m_vec_old=rhs.m_vec_old;   
+      m_th_prop=rhs.m_th_prop; m_ph_prop=rhs.m_ph_prop; m_f_prop=rhs.m_f_prop;
+      m_th_old=rhs.m_th_old; m_ph_old=rhs.m_ph_old; m_f_old=rhs.m_f_old;
+      m_th_ph_prior=rhs.m_th_ph_prior; m_f_prior=rhs.m_f_prior;
+      m_th_ph_old_prior=rhs.m_th_ph_old_prior; m_f_old_prior=rhs.m_f_old_prior;
+      m_prior_en=rhs.m_prior_en; m_old_prior_en=rhs.m_old_prior_en;
+      m_th_acc=rhs.m_th_acc; m_th_rej=rhs.m_th_rej; 
+      m_ph_acc=rhs.m_ph_acc; m_ph_rej=rhs.m_ph_rej;
+      m_f_acc=rhs.m_f_acc;   m_f_rej=rhs.m_f_rej;
+      f_ard=rhs.f_ard;
+      m_SignalHR=rhs.m_SignalHR; m_SignalHR_old=rhs.m_SignalHR_old;
+      m_SignalLR=rhs.m_SignalLR; m_SignalLR_old=rhs.m_SignalLR_old;
+      return *this;
+    } 
+    
+  };
+
+
+
+ //////////////////////////////
+ //       HRvoxel            //
+ //////////////////////////////
+  class HRvoxel{
+    vector<RFibre> m_fibres;
+    float m_d;
+    float m_d_old;
+    float m_d_prop;
+    float m_d_prior; 
+    float m_d_old_prior;
+    float m_d_acc;
+    float m_d_rej;
+ 
+    float m_d_std;
+    float m_d_std_old;
+    float m_d_std_prop;
+    float m_d_std_prior; 
+    float m_d_std_old_prior;
+    float m_d_std_acc;
+    float m_d_std_rej;
+
+    float m_S0;
+    float m_S0_old;
+    float m_S0_prop;
+    float m_S0_prior;
+    float m_S0_old_prior;
+    float m_S0_acc;
+    float m_S0_rej;
+    
+    float m_tau;                    //Noise at a High-res voxel (precision)
+    float m_tau_old;
+    float m_tau_prop;
+    float m_tau_prior;
+    float m_tau_old_prior;
+    float m_tau_acc;
+    float m_tau_rej;
+
+    const float& m_mean_d;        //hyperparameters for d prior
+    const float& m_stdev_d;
+    const float& m_mean_fsum;     //hyperparameters for fsum prior
+    const float& m_stdev_fsum;
+    float m_fsum_prior;
+    float m_fsum_old_prior;
+
+    float m_prior_en;               //Joint Prior
+    float m_old_prior_en;
+    ColumnVector m_iso_SignalHR;    //Vector that stores the predicted signal from the isotropic compartment only
+    ColumnVector m_iso_SignalHR_old; 
+    ColumnVector m_iso_SignalLR;    //Vector that stores the predicted signal from the isotropic compartment only 
+    ColumnVector m_iso_SignalLR_old; 
+ 
+    ColumnVector m_SignalHR;        //Vector that stores the total predicted signal from the specific voxel at High-Res measurement points
+    ColumnVector m_SignalHR_old;
+    ColumnVector m_SignalLR;        //Vector that stores the total predicted signal from the specific voxel at Low-Res measurement points
+    ColumnVector m_SignalLR_old;
+
+    const Matrix& m_Orient_hyp_prior;//Matrix Nmodes x 5 that contains the hyperparameters for the orientation prior 
+    
+    const Matrix& m_bvecsHR;        //bvecs at High-Res   (3 x HR_NumPoints)
+    const Matrix& m_bvalsHR;        //bvalues at High-Res (1 x HR_NumPoints)
+    const Matrix& m_bvecsLR;        //bvecs at Low-Res    (3 x LR_NumPoints)
+    const Matrix& m_bvalsLR;        //bvalues at Low-Res  (1 x HR_NumPoints)
+    const int m_modelnum;           //1 for single-shell, 2 for multi-shell model
+    const int m_numfibres;          //number of fibres in this HR voxel
+    const float m_ardfudge;
+    const bool m_fsumPrior_ON;      //Flag that indicates whether a prior on the fsum will be imposed (based on the LRvox neighbourhood mean)
+    const bool m_dPrior_ON;         //Flag that indicates whether a prior on diffusivity will be imposed (based on the LRvox neighbourhood mean)
+    const bool m_rician;            //indicates whether Rician Noise model is used
+
+    //const ColumnVector& LRvox_inter; //array with indices on LR voxels intersected by this HR
+ 
+  public:
+    //Constructor
+    HRvoxel(const Matrix& bvecsHR, const Matrix& bHR, 
+	    const Matrix& bvecsLR, const Matrix& bLR, 
+	    const Matrix& Orient_hyp_prior,
+	    const float& mean_d, const float& stdev_d, const float& mean_fsum, const float& stdev_fsum,
+	    const int N, const int modelnum=1,const float ardfudge=1, const bool fsumPrior_ON=false, const bool dPrior_ON=false, const bool rician=false):
+    m_mean_d(mean_d), m_stdev_d(stdev_d), m_mean_fsum(mean_fsum), m_stdev_fsum(stdev_fsum),
+    m_Orient_hyp_prior(Orient_hyp_prior), 
+      m_bvecsHR(bvecsHR), m_bvalsHR(bHR), m_bvecsLR(bvecsLR), m_bvalsLR(bLR), m_modelnum(modelnum), m_numfibres(N),  m_ardfudge(ardfudge), m_fsumPrior_ON(fsumPrior_ON), m_dPrior_ON(dPrior_ON), m_rician(rician) {
+      
+      //Initialize vectors that keep the signal from the isotropic compartment
+      m_iso_SignalHR.ReSize(m_bvecsHR.Ncols()); m_iso_SignalHR=0; m_iso_SignalHR_old=m_iso_SignalHR; 
+      m_SignalHR.ReSize(m_bvecsHR.Ncols()); m_SignalHR=0; m_SignalHR_old=m_SignalHR; 
+      m_iso_SignalLR.ReSize(m_bvecsLR.Ncols()); m_iso_SignalLR=0; m_iso_SignalLR_old=m_iso_SignalLR;            
+      m_SignalLR.ReSize(m_bvecsLR.Ncols()); m_SignalLR=0; m_SignalLR_old=m_SignalLR; 
+     
+      m_d_acc=0; m_d_rej=0; m_d_prior=0; m_d_old_prior=0;              
+      m_d_std_acc=0; m_d_std_rej=0; m_d_std_prior=0; m_d_std_old_prior=0;              
+      m_S0_acc=0; m_S0_rej=0; m_S0_prior=0; m_S0_old_prior=0;
+      m_d=0; m_d_old=0;  m_d_std=0; m_d_std_old=0; m_S0=0; m_S0_old=0; 
+      m_tau_acc=0; m_tau_rej=0; m_tau_prior=0; m_tau_old_prior=0; m_tau=0; m_tau_old=0; 
+      m_prior_en=0; m_old_prior_en=0;
+      m_fsum_prior=0; m_fsum_old_prior=0;
+    }
+
+    //Destructor
+    ~HRvoxel(){}
+
+
+    const vector<RFibre>& fibres() const{ return m_fibres; }
+    void addfibre(const float th, const float ph, const float f,const bool use_ard=true) {
+      RFibre fib(th,ph,f,m_bvecsHR,m_bvalsHR,m_bvecsLR,m_bvalsLR,m_Orient_hyp_prior,m_d,m_d_std,use_ard,m_modelnum,m_ardfudge);
+      m_fibres.push_back(fib);
+    }
+	
+    void initialise_energies_props(); //Initialize energies, signals and standard deviations for the proposal distributions
+    inline float get_d() const{ return m_d;}
+    inline void set_d(const float d){ m_d=d; }
+    inline float get_d_std() const{ return m_d_std; }
+    inline void set_d_std(const float d_std){ m_d_std=d_std; }
+    inline float get_S0() const{ return m_S0; }
+    inline void set_S0(const float S0){ m_S0=S0; }
+    inline float get_tau() const{ return m_tau; }
+    inline void set_tau(const float tau){ m_tau=tau; }
+    inline float get_prior() const { return m_prior_en; }
+
+    inline const ColumnVector& getSignalHR() const{ return m_SignalHR; }
+    inline const ColumnVector& getSignalLR() const{ return m_SignalLR; }
+
+    bool compute_d_prior();
+    bool compute_d_std_prior(); 
+    bool compute_S0_prior(); 
+    bool compute_tau_prior(); 
+    bool reject_f_sum();       //Check if sum of volume fractions is >1
+
+    void update_d_prior();
+    void restore_d_prior();
+
+    void compute_fsum_prior();
+    void update_fsum_prior();
+    void restore_fsum_prior();
+
+    void compute_prior();      //Compute Joint Prior energy
+    void compute_iso_signal(); //Compute the predicted signal from the isotropic compartment only
+    void compute_signal();     //Compute the total predicted signal
+
+    bool propose_d();
+    void accept_d(){ m_d_acc++; }
+    void reject_d();
+
+    bool propose_d_std();
+    void accept_d_std(){ m_d_std_acc++; }
+    void reject_d_std();
+
+    bool propose_S0();
+    void accept_S0(){ m_S0_acc++; }
+    void reject_S0();
+
+    bool propose_tau();
+    void accept_tau(){ m_tau_acc++; }
+    void reject_tau();
+
+    bool propose_th(int n){ return m_fibres[n].propose_th(); }  //n is the fibre index from 0 to N-1
+    void accept_th(int n) { m_fibres[n].accept_th(); }
+    void reject_th(int n) { m_fibres[n].reject_th(); }
+    bool propose_ph(int n){ return m_fibres[n].propose_ph(); }  
+    void accept_ph(int n) { m_fibres[n].accept_ph(); }
+    void reject_ph(int n) { m_fibres[n].reject_ph(); }
+    bool propose_f(int n) { return m_fibres[n].propose_f(); }
+    void accept_f(int n)  { m_fibres[n].accept_f(); }
+    void reject_f(int n)  { m_fibres[n].reject_f(); }
+
+    void restore_prior_totsignal();
+    void restore_prior();
+    
+    void update_th_ph_prior();  //Used to update the conditional orientation prior when the prior parameters are jumped
+    void restore_th_ph_prior();
+
+    void update_proposals();   //Adapt standard deviation of proposal distributions during MCMC execution 
+    void report() const;
+
+    HRvoxel& operator=(const HRvoxel& rhs){
+      m_fibres=rhs.m_fibres;
+      m_d=rhs.m_d;   m_d_old=rhs.m_d_old;   m_d_prop=rhs.m_d_prop;
+      m_d_prior=rhs.m_d_prior;   m_d_old_prior=rhs.m_d_old_prior; 
+      m_d_acc=rhs.m_d_acc;       m_d_rej=rhs.m_d_rej;
+      m_d_std=rhs.m_d_std;   m_d_std_old=rhs.m_d_std_old;   m_d_std_prop=rhs.m_d_std_prop;
+      m_d_std_prior=rhs.m_d_std_prior;   m_d_std_old_prior=rhs.m_d_std_old_prior; 
+      m_d_std_acc=rhs.m_d_std_acc;       m_d_std_rej=rhs.m_d_std_rej;
+
+      m_fsum_prior=rhs.m_fsum_prior;     m_fsum_old_prior=rhs.m_fsum_old_prior;
+      m_S0=rhs.m_S0;   m_S0_old=rhs.m_S0_old;   m_S0_prop=rhs.m_S0_prop;
+      m_S0_prior=rhs.m_S0_prior;   m_S0_old_prior=rhs.m_S0_old_prior; 
+      m_S0_acc=rhs.m_S0_acc;       m_S0_rej=rhs.m_S0_rej;
+      m_tau=rhs.m_tau;   m_tau_old=rhs.m_tau_old;   m_tau_prop=rhs.m_tau_prop;
+      m_tau_prior=rhs.m_tau_prior;   m_tau_old_prior=rhs.m_tau_old_prior; 
+      m_tau_acc=rhs.m_tau_acc;       m_tau_rej=rhs.m_tau_rej;
+      m_prior_en=rhs.m_prior_en;   m_old_prior_en=rhs.m_old_prior_en;
+      m_iso_SignalHR=rhs.m_iso_SignalHR;       m_iso_SignalHR_old=rhs.m_iso_SignalHR_old;
+      m_iso_SignalLR=rhs.m_iso_SignalLR;       m_iso_SignalLR_old=rhs.m_iso_SignalLR_old;
+      m_SignalHR=rhs.m_SignalHR;       m_SignalHR_old=rhs.m_SignalHR_old;
+      m_SignalLR=rhs.m_SignalLR;       m_SignalLR_old=rhs.m_SignalLR_old;
+      return *this;
+    }
+
+  };
+
+
+
+
+  /////////////////////////////////////////////////////////////////////////////
+  //     Orient_Prior_Mode: Models a single mode of the orientation prior   ///
+  //     The orientation prior is a sum of Watson distributions centred     ///
+  //     around different modes                                             ///
+  /////////////////////////////////////////////////////////////////////////////
+  class Orient_Prior_Mode{
+    float m_th;
+    float m_th_old;
+    float m_th_prop;
+    float m_th_prior;
+    float m_th_old_prior;
+    float m_th_acc;
+    float m_th_rej;
+
+    float m_ph;
+    float m_ph_old;
+    float m_ph_prop;
+    float m_ph_prior;
+    float m_ph_old_prior;
+    float m_ph_acc;
+    float m_ph_rej;
+
+    float m_invkappa;               //Dispersion Index of a Watson distribution (1/kappa actually)
+    float m_invkappa_old;
+    float m_invkappa_prop;
+    float m_invkappa_prior;
+    float m_invkappa_old_prior;
+    float m_invkappa_acc;
+    float m_invkappa_rej;
+
+    float m_Watson_norm;           //this is a function of current m_kappa
+    float m_Watson_norm_old;
+    ColumnVector m_vec;
+    ColumnVector m_vec_old;
+    float m_prior_en;              //Joint HyperPrior
+    float m_old_prior_en;
+
+    const bool m_kappa_ard;        //Flag for setting ARD on the dispersion index
+  
+  public:
+    //Constructor
+  Orient_Prior_Mode(bool kappa_ard): m_kappa_ard(kappa_ard) {
+     m_th=M_PI/2; m_th_old=m_th;
+     m_ph=0; m_ph_old=m_ph;
+     m_vec.ReSize(3);
+     m_vec<<sin(m_th)*cos(m_ph) <<sin(m_th)*sin(m_ph) <<cos(m_th);
+     m_vec_old=m_vec;
+     m_invkappa=0.02; m_invkappa_old=m_invkappa;
+     m_Watson_norm=compute_Watson_norm(); m_Watson_norm_old=m_Watson_norm;
+     m_th_prop=0.2;  m_ph_prop=0.2; m_invkappa_prop=0.2;
+	
+     m_th_prior=0; m_th_old_prior=0; 
+     m_ph_prior=0; m_ph_old_prior=0; 
+     m_invkappa_prior=0; m_invkappa_old_prior=0;
+     m_prior_en=0; m_old_prior_en=0;
+     
+     m_th_acc=0; m_th_rej=0;
+     m_ph_acc=0; m_ph_rej=0;
+     m_invkappa_acc=0; m_invkappa_rej=0;
+    }
+
+    //Destructor
+    ~Orient_Prior_Mode(){}
+
+    inline float get_th() const{ return m_th;}
+    inline float get_ph() const{ return m_ph;}
+    inline float get_invkappa() const{ return m_invkappa;}
+    inline void set_th(const float th) { m_th=th; m_vec<< sin(m_th)*cos(m_ph) << sin(m_th)*sin(m_ph) << cos(m_th);}
+    inline void set_ph(const float ph) { m_ph=ph; m_vec<< sin(m_th)*cos(m_ph) << sin(m_th)*sin(m_ph) << cos(m_th);}
+    inline void set_invkappa(const float invkappa) { m_invkappa=invkappa; filter_invkappa(); m_Watson_norm=compute_Watson_norm(); }
+    void filter_invkappa();    //Filter out extreme values of invkappa to ensure calculations are numerically stable 
+
+    inline float get_prior() const{ return m_prior_en;}
+    inline const ColumnVector& getVec() const { return m_vec; }
+    inline float get_Watson_norm() const{ return m_Watson_norm; }
+    float compute_Watson_norm();
+    
+    void initialise_energies();
+    bool compute_th_prior();
+    bool compute_ph_prior(); 
+    bool compute_invkappa_prior(); 
+    void compute_prior();      //Compute Joint Prior energy
+    void update_proposals();
+
+    bool propose_th();
+    inline void accept_th(){ m_th_acc++; }   
+    void reject_th();
+    
+    bool propose_ph();
+    inline void accept_ph(){ m_ph_acc++; }
+    void reject_ph();
+    
+    bool propose_invkappa();
+    inline void accept_invkappa(){ m_invkappa_acc++; }
+    void reject_invkappa();
+
+    Orient_Prior_Mode& operator=(const Orient_Prior_Mode& rhs){
+      m_th=rhs.m_th; 
+      m_th_old=rhs.m_th_old;  
+      m_th_prop=rhs.m_th_prop;
+      m_th_prior=rhs.m_th_prior;  m_th_old_prior=rhs.m_th_old_prior;
+      m_th_acc=rhs.m_th_acc;      m_th_rej=rhs.m_th_rej;
+      m_ph=rhs.m_ph; m_ph_old=rhs.m_ph_old;  m_ph_prop=rhs.m_ph_prop;
+      m_ph_prior=rhs.m_ph_prior;  m_ph_old_prior=rhs.m_ph_old_prior;
+      m_ph_acc=rhs.m_ph_acc;      m_ph_rej=rhs.m_ph_rej;
+      m_invkappa=rhs.m_invkappa;  m_invkappa_old=rhs.m_invkappa_old;  m_invkappa_prop=rhs.m_invkappa_prop;
+      m_invkappa_prior=rhs.m_invkappa_prior;  m_invkappa_old_prior=rhs.m_invkappa_old_prior;
+      m_invkappa_acc=rhs.m_invkappa_acc;      m_invkappa_rej=rhs.m_invkappa_rej;
+      m_Watson_norm=rhs.m_Watson_norm;        m_Watson_norm_old=rhs.m_Watson_norm_old;
+      m_vec=rhs.m_vec;           m_vec_old=rhs.m_vec_old; 
+      m_prior_en=rhs.m_prior_en; m_old_prior_en=rhs.m_old_prior_en;
+      return *this;
+    }
+  };
+
+
+
+  //////////////////////////////
+  //       LRvoxel            //
+  //////////////////////////////
+  class LRvoxel{
+    vector<HRvoxel> m_HRvoxels;
+    vector<Orient_Prior_Mode> m_PModes;
+    
+    float m_tauLR;                //models noise at Low-res 
+    float m_tauLR_old;
+    float m_tauLR_prop;
+    float m_tauLR_prior;
+    float m_tauLR_old_prior;
+    float m_tauLR_acc;
+    float m_tauLR_rej;
+
+    float m_S0LR;                 //models S0 intensity at the Low-Res acquisition
+    float m_S0LR_old;
+    float m_S0LR_prop;
+    float m_S0LR_prior;
+    float m_S0LR_old_prior;
+    float m_S0LR_acc;
+    float m_S0LR_rej;
+    Matrix m_Orient_hyp_prior;    //Matrix Nmodes x 5 that contains the hyperparameters for the orientation prior 
+                                  //columns 1-3 contains the (x,y,z) coordinates for the mode, 4th column contains the invkappa value, 5th the Watson normalization constant
+
+    float m_mean_d;               //models mean of d hyperprior for the High-Res voxels intersected by the LR_voxel
+    float m_mean_d_old;
+    float m_mean_d_prop;
+    float m_mean_d_prior;
+    float m_mean_d_old_prior;
+    float m_mean_d_acc;
+    float m_mean_d_rej;
+
+    float m_stdev_d;               //models std_dev of d hyperprior for the High-Res voxels intersected by the LR_voxel
+    float m_stdev_d_old;
+    float m_stdev_d_prop;
+    float m_stdev_d_prior;
+    float m_stdev_d_old_prior;
+    float m_stdev_d_acc;
+    float m_stdev_d_rej;
+
+    float m_mean_fsum;               //models mean of fsum hyperprior for the High-Res voxels intersected by the LR_voxel
+    float m_mean_fsum_old;
+    float m_mean_fsum_prop;
+    float m_mean_fsum_prior;
+    float m_mean_fsum_old_prior;
+    float m_mean_fsum_acc;
+    float m_mean_fsum_rej;
+
+    float m_stdev_fsum;               //models std_dev of fsum hyperprior for the High-Res voxels intersected by the LR_voxel
+    float m_stdev_fsum_old;
+    float m_stdev_fsum_prop;
+    float m_stdev_fsum_prior;
+    float m_stdev_fsum_old_prior;
+    float m_stdev_fsum_acc;
+    float m_stdev_fsum_rej;
+
+    float m_prior_en;             //Joint Prior Energy
+    float m_old_prior_en;
+    float m_likelihood_en;        //Likelihood Energy
+    float m_old_likelihood_en;
+    float m_posterior_en;         //Posterior Energy
+    float m_old_posterior_en;
+   
+    ColumnVector m_logdataLR;       //Log of Low-Res Data for the specific LR voxel (use it in Rician Energy)
+    vector<ColumnVector> m_logdataHR; //Log of High-Res Data for all contained HR voxels (use it in Rician Energy)
+
+    const ColumnVector& m_dataLR;   //Low-Res Data for the specific LR voxel 
+    const vector<ColumnVector>& m_dataHR; //High-Res Data for all contained HR voxels
+    const Matrix& m_bvecsHR;        //bvecs at High-Res   (3 x HR_NumPoints)
+    const Matrix& m_bvalsHR;        //bvalues at High-Res (1 x HR_NumPoints)
+    const Matrix& m_bvecsLR;        //bvecs at Low-Res    (3 x LR_NumPoints)
+    const Matrix& m_bvalsLR;        //bvalues at Low-Res  (1 x HR_NumPoints)
+    const int m_modelnum;           //1 for single-shell, 2 for multi-shell model
+    const int m_numfibres;          //Number of fibres in each HR voxel
+    const int m_Nmodes;             //Number of modes for the Orientation Prior
+    const float m_ardfudge;
+    const bool m_allard;            //Flag for setting ARD on for all fibres in all HR voxels
+    const bool m_Noard;             //Flag for setting ARD off for all fibres in all HR voxels
+    const bool m_kappa_ard;         //Flag for setting ARD on the dispersion index
+    const bool m_fsumPrior_ON;      //Flag for setting on a prior on fsums across intersected HR voxels
+    const bool m_dPrior_ON;         //Flag for setting on a prior on the diffusivity across intersected HR voxels
+    const bool m_rician;            //Flag for using a Rician noise model 
+    const ColumnVector& m_HRweights;//Holds the volume fraction each HR voxel occupies out of the LR one
+ 
+  public:
+    //Constructor
+    LRvoxel(const Matrix& bvecsHR, const Matrix& bHR, 
+	    const Matrix& bvecsLR, const Matrix& bLR, 
+	    const ColumnVector& dataLR, const vector<ColumnVector>& dataHR, const int N, const int Nmodes, const ColumnVector& HRweights, const int modelnum=1, const float ardfudge=1, const bool allard=false, const bool Noard=false, const bool kappa_ard=false, const bool fsumPrior_ON=false, const bool dPrior_ON=false, const bool rician=false):
+      m_dataLR(dataLR), m_dataHR(dataHR),m_bvecsHR(bvecsHR), m_bvalsHR(bHR), m_bvecsLR(bvecsLR), m_bvalsLR(bLR),
+	m_modelnum(modelnum), m_numfibres(N), m_Nmodes(Nmodes), m_ardfudge(ardfudge), m_allard(allard), m_Noard(Noard), m_kappa_ard(kappa_ard), m_fsumPrior_ON(fsumPrior_ON), m_dPrior_ON(dPrior_ON), m_rician(rician), m_HRweights(HRweights) {
+    
+      m_S0LR=0; m_S0LR_old=0; m_S0LR_prior=0; m_S0LR_old_prior=0; m_S0LR_acc=0; m_S0LR_rej=0; m_S0LR_prop=0.2;
+      m_tauLR=0; m_tauLR_old=0; m_tauLR_prior=0; m_tauLR_old_prior=0; m_tauLR_acc=0; m_tauLR_rej=0; m_tauLR_prop=0.2;
+
+      m_mean_d=0; m_mean_d_old=0; m_mean_d_prior=0; m_mean_d_old_prior=0; m_mean_d_acc=0; m_mean_d_rej=0; m_mean_d_prop=0.001;
+      m_stdev_d=0; m_stdev_d_old=0; m_stdev_d_prior=0; m_stdev_d_old_prior=0; m_stdev_d_acc=0; m_stdev_d_rej=0; m_stdev_d_prop=0.001;
+
+      m_mean_fsum=0; m_mean_fsum_old=0; m_mean_fsum_prior=0; m_mean_fsum_old_prior=0; m_mean_fsum_acc=0; m_mean_fsum_rej=0; m_mean_fsum_prop=0.1;
+      m_stdev_fsum=0; m_stdev_fsum_old=0; m_stdev_fsum_prior=0; m_stdev_fsum_old_prior=0; m_stdev_fsum_acc=0; m_stdev_fsum_rej=0; m_stdev_fsum_prop=0.1;
+
+      m_prior_en=0; m_old_prior_en=0; 
+      m_likelihood_en=0; m_old_likelihood_en=0;
+      m_posterior_en=0; m_old_posterior_en=0;
+
+      for (int m=1; m<=m_Nmodes; m++){                //Add Modes for the orientation Prior
+      	Orient_Prior_Mode pMod(m_kappa_ard); 
+      	m_PModes.push_back(pMod);
+      }
+      m_Orient_hyp_prior.ReSize(m_Nmodes,5);
+
+      for (unsigned int m=1; m<=m_dataHR.size(); m++){ //Add HRvoxel Objects
+      	HRvoxel HRv(m_bvecsHR, m_bvalsHR, m_bvecsLR, m_bvalsLR, m_Orient_hyp_prior, m_mean_d, m_stdev_d, m_mean_fsum, m_stdev_fsum, m_numfibres, m_modelnum, m_ardfudge, m_fsumPrior_ON, m_dPrior_ON, m_rician);
+      	
+	m_HRvoxels.push_back(HRv);
+      }
+
+      // ofstream myfile;     //Debugging code
+      //myfile.open("/Users/stam/Rubix_data/Energies.txt", ios::trunc);
+      //myfile.close();
+  
+      if (m_rician){//Store the log of the data for energy calculations
+	m_logdataLR=dataLR; m_logdataHR=dataHR;
+	for (int m=1; m<=dataLR.Nrows(); m++){  
+	  if (dataLR(m)!=0)
+	    m_logdataLR(m)=log(dataLR(m));
+	  else
+	    m_logdataLR(m)=minlogfloat;
+	}
+	for (unsigned int n=0; n<dataHR.size(); n++)
+	  for (int m=1; m<=dataHR[n].Nrows(); m++){
+	    if (dataHR[n](m)!=0)
+	      m_logdataHR[n](m)=log(dataHR[n](m));
+	    else
+	      m_logdataHR[n](m)=minlogfloat;
+	  }
+      }
+    }
+
+    //Destructor
+      ~LRvoxel(){ }
+    
+    const vector<HRvoxel>& HRvoxels() const {return m_HRvoxels;}
+    const vector<Orient_Prior_Mode>& PModes() const {return m_PModes;} 
+
+    void update_Orient_hyp_prior();       //Update the matrix that keeps information on the orientation prior parameters
+    void update_Orient_hyp_prior(int M);  //Update the entry only for a specific Mode 0<=M<N_modes
+    void set_HRparams(const int n, const float d, const float S0, const ColumnVector& th, const ColumnVector& ph, const ColumnVector& f);  //Set params for a single HR voxel
+    void set_HRparams(const int n, const float d, const float d_std,const float S0, const ColumnVector& th, const ColumnVector& ph, const ColumnVector& f);  //Set params for a single HR voxel
+    void set_Priorparams(const ColumnVector& th, const ColumnVector& ph, const ColumnVector& invkappa);  //Set params for all modes of orientation priors
+    float get_S0LR() const { return m_S0LR; }
+    void set_S0LR(const float S0)  { m_S0LR=S0; }
+    float get_tauLR() const { return m_tauLR; }
+    void set_tauLR(const float tau)  { m_tauLR=tau; }
+    void set_tauHR(const int n, const float tau)  { m_HRvoxels[n].set_tau(tau); }
+    float get_likelihood_energy() const { return m_likelihood_en; }
+    float get_prior_energy() const { return m_prior_en; }
+    void initialise_energies();
+    
+    bool propose_S0LR();
+    void accept_S0LR(){ m_S0LR_acc++; }
+    void reject_S0LR();
+    bool compute_S0LR_prior();
+
+    bool propose_tauLR();
+    void accept_tauLR(){ m_tauLR_acc++; }
+    void reject_tauLR();
+    bool compute_tauLR_prior();
+
+    void compute_prior();
+    void compute_likelihood();
+    void compute_posterior();
+    bool test_energy() const;
+    void restore_energies();
+    void restore_Prior_Posterior();
+    void update_proposals();
+    void jump(); //Single MCMC iteration with all parameters jumped
+
+    
+    bool propose_meand();
+    void accept_meand(){ m_mean_d_acc++; }
+    void reject_meand();
+    bool compute_meand_prior();
+    bool propose_stdevd();
+    void accept_stdevd(){ m_stdev_d_acc++; }
+    void reject_stdevd();
+    bool compute_stdevd_prior();
+    void set_meand(const float meand)  { m_mean_d=meand; }
+    void set_stdevd(const float stdevd)  { m_stdev_d=stdevd; }
+    float get_meand() const{ return m_mean_d;}
+    float get_stdevd() const{ return m_stdev_d;}
+
+    bool propose_mean_fsum();
+    void accept_mean_fsum(){ m_mean_fsum_acc++; }
+    void reject_mean_fsum();
+    bool compute_mean_fsum_prior();
+    bool propose_stdev_fsum();
+    void accept_stdev_fsum(){ m_stdev_fsum_acc++; }
+    void reject_stdev_fsum();
+    bool compute_stdev_fsum_prior();
+    void set_mean_fsum(const float fsum)  { m_mean_fsum=fsum; }
+    void set_stdev_fsum(const float stdev_fsum)  { m_stdev_fsum=stdev_fsum; }
+    float get_mean_fsum() const{ return m_mean_fsum;}
+    float get_stdev_fsum() const{ return m_stdev_fsum;}
+
+    
+    LRvoxel& operator=(const LRvoxel& rhs){    
+      m_HRvoxels=rhs.m_HRvoxels;            m_PModes=rhs.m_PModes;
+      m_tauLR=rhs.m_tauLR;                  m_tauLR_old=rhs.m_tauLR_old;
+      m_tauLR_prop=rhs.m_tauLR_prop;
+      m_tauLR_prior=rhs.m_tauLR_prior;      m_tauLR_old_prior=rhs.m_tauLR_old_prior;
+      m_tauLR_acc=rhs.m_tauLR_acc;          m_tauLR_rej=rhs.m_tauLR_rej;
+      m_S0LR=rhs.m_S0LR;                    m_S0LR_old=rhs.m_S0LR_old;
+      m_S0LR_prop=rhs.m_S0LR_prop;
+      m_S0LR_prior=rhs.m_S0LR_prior;        m_S0LR_old_prior=rhs.m_S0LR_old_prior;
+      m_S0LR_acc=rhs.m_S0LR_acc;            m_S0LR_rej=rhs.m_S0LR_rej;
+      m_Orient_hyp_prior=rhs.m_Orient_hyp_prior;
+      m_prior_en=rhs.m_prior_en;            m_old_prior_en=rhs.m_old_prior_en;
+      m_likelihood_en=rhs.m_likelihood_en;  m_old_likelihood_en=rhs.m_old_likelihood_en;
+      m_posterior_en=rhs.m_posterior_en;    m_old_posterior_en=rhs.m_old_posterior_en;
+      m_logdataLR=rhs.m_logdataLR;          m_logdataHR=rhs.m_logdataHR;  
+
+      m_mean_d=rhs.m_mean_d;                m_mean_d_old=rhs.m_mean_d_old;
+      m_mean_d_prop=rhs.m_mean_d_prop;
+      m_mean_d_prior=rhs.m_mean_d_prior;    m_mean_d_old_prior=rhs.m_mean_d_old_prior;
+      m_mean_d_acc=rhs.m_mean_d_acc;        m_mean_d_rej=rhs.m_mean_d_rej;
+      m_stdev_d=rhs.m_stdev_d;              m_stdev_d_old=rhs.m_stdev_d_old;
+      m_stdev_d_prop=rhs.m_stdev_d_prop;
+      m_stdev_d_prior=rhs.m_stdev_d_prior;  m_stdev_d_old_prior=rhs.m_stdev_d_old_prior;
+      m_stdev_d_acc=rhs.m_stdev_d_acc;      m_stdev_d_rej=rhs.m_stdev_d_rej;
+
+      m_mean_fsum=rhs.m_mean_fsum;                m_mean_fsum_old=rhs.m_mean_fsum_old;
+      m_mean_fsum_prop=rhs.m_mean_fsum_prop;
+      m_mean_fsum_prior=rhs.m_mean_fsum_prior;    m_mean_fsum_old_prior=rhs.m_mean_fsum_old_prior;
+      m_mean_fsum_acc=rhs.m_mean_fsum_acc;        m_mean_fsum_rej=rhs.m_mean_fsum_rej;
+      m_stdev_fsum=rhs.m_stdev_fsum;              m_stdev_fsum_old=rhs.m_stdev_fsum_old;
+      m_stdev_fsum_prop=rhs.m_stdev_fsum_prop;
+      m_stdev_fsum_prior=rhs.m_stdev_fsum_prior;  m_stdev_fsum_old_prior=rhs.m_stdev_fsum_old_prior;
+      m_stdev_fsum_acc=rhs.m_stdev_fsum_acc;      m_stdev_fsum_rej=rhs.m_stdev_fsum_rej;
+     
+      return *this;
+    }
+  };
+
+
+
+}
+
+#endif
-- 
GitLab