diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f8fb9f367d39dcbcbe8efb1959f010fc670701a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.nii +*.BRIK +*.HEAD diff --git a/NODDI_toolbox_v1.01/.DS_Store b/NODDI_toolbox_v1.01/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6b31e7fe961b6f9db30bb31b0b1c2449b3896fe3 Binary files /dev/null and b/NODDI_toolbox_v1.01/.DS_Store differ diff --git a/NODDI_toolbox_v1.01/LICENSE.txt b/NODDI_toolbox_v1.01/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..0961e7bf0c499b21316d2a136fbeb531e6de9dd7 --- /dev/null +++ b/NODDI_toolbox_v1.01/LICENSE.txt @@ -0,0 +1,14 @@ +LICENSE for NODDI matlab toolbox: + +The Software is made available for use under the Open Source-approved Artistic Licence 2.0. The Owner draws your attention to the fact that the Software has been developed for and is intended for use in a research environment only. No endorsement can be given for other use including, but not limited to, use in a clinical environment. + +External tools included in NODDI matlab toolbox: + +1. erfi matlab function + * By Per Sundqvist, No license specified + * Downloaded from http://www.mathworks.com/matlabcentral/fileexchange/18238-erfi-function + +2. PARFOR Progress Monitor v2 + * BSD license + * Downloaded from http://www.mathworks.com/matlabcentral/fileexchange/31673-parfor-progress-monitor-v2 + diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/ParforProgMon.m b/NODDI_toolbox_v1.01/ParforProgMonv2/ParforProgMon.m new file mode 100644 index 0000000000000000000000000000000000000000..a1848d23426c68059605aba303187305a8bbe657 --- /dev/null +++ b/NODDI_toolbox_v1.01/ParforProgMonv2/ParforProgMon.m @@ -0,0 +1,63 @@ +% Copyright 2009 The MathWorks, Inc. + +classdef ParforProgMon < handle + + properties ( GetAccess = private, SetAccess = private ) + Port + HostName + end + + properties (Transient, GetAccess = private, SetAccess = private) + JavaBit + end + + methods ( Static ) + function o = loadobj( X ) + % Once we've been loaded, we need to reconstruct ourselves correctly as a + % worker-side object. + o = ParforProgMon( {X.HostName, X.Port} ); + end + end + + methods + function o = ParforProgMon( s, N, progressStepSize, width, height ) + % ParforProgMon Build a Parfor Progress Monitor + % Use the syntax: ParforProgMon( 'Window Title', N, progressStepSize, width, height ) + % where N is the number of iterations in the PARFOR loop + % progressStepSize indicates after how many iterations progress is shown + % width indicates the width of the progress window + % height indicates the width of the progress window + + if nargin == 1 && iscell( s ) + % "Private" constructor used on the workers + o.JavaBit = ParforProgressMonitor.createWorker( s{1}, s{2} ); + o.Port = []; + elseif nargin == 5 + % Normal construction + o.JavaBit = ParforProgressMonitor.createServer( s, N, progressStepSize, width, height ); + o.Port = double( o.JavaBit.getPort() ); + % Get the client host name from pctconfig + cfg = pctconfig; + o.HostName = cfg.hostname; + else + error( 'Public constructor is: ParforProgressMonitor( ''Text'', N, progressStepSize, width, height )' ); + end + end + + function X = saveobj( o ) + % Only keep the Port and HostName + X.Port = o.Port; + X.HostName = o.HostName; + end + + function increment( o ) + % Update the UI + o.JavaBit.increment(); + end + + function delete( o ) + % Close the UI + o.JavaBit.done(); + end + end +end diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/example.m b/NODDI_toolbox_v1.01/ParforProgMonv2/example.m new file mode 100644 index 0000000000000000000000000000000000000000..93c348f635d4940e21e886fb16eef9e727650145 --- /dev/null +++ b/NODDI_toolbox_v1.01/ParforProgMonv2/example.m @@ -0,0 +1,27 @@ +% ParforProgMon - M object to make ParforProgressMonitor objects easier to +% use. Create one of these on the client outside your PARFOR loop with a +% name for the window. Pass it in to the PARFOR loop, and have the workers +% call "increment" at the end of each iteration. This sends notification +% back to the client which then updates the UI. + +% ParforProgMon Build a Parfor Progress Monitor +% Use the syntax: ParforProgMon( 'Window Title', N, progressStepSize, width, height ) +% where N is the number of iterations in the PARFOR loop +% progressStepSize indicates after how many iterations progress is shown +% width indicates the width of the progress window +% height indicates the width of the progress window + +tic +N = 500000; +progressStepSize = 100; +ppm = ParforProgMon('Example: ', N, progressStepSize, 300, 80); + +parfor ii=1:N + rand(100,100); + if mod(ii,progressStepSize)==0 + ppm.increment(); + end +end + +ppm.delete() +toc \ No newline at end of file diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$1.class b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$1.class new file mode 100644 index 0000000000000000000000000000000000000000..abc01f9e56564e2bfb9e468e1bddbb8e2751f3f5 Binary files /dev/null and b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$1.class differ diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgServer$1.class b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgServer$1.class new file mode 100644 index 0000000000000000000000000000000000000000..78e99d373bec1f53a4a42594be3fbb6d0c1a0f0a Binary files /dev/null and b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgServer$1.class differ diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgServer.class b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgServer.class new file mode 100644 index 0000000000000000000000000000000000000000..82801f09c3c4f26ca94e16ecd1849feb1f02c561 Binary files /dev/null and b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgServer.class differ diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgThing.class b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgThing.class new file mode 100644 index 0000000000000000000000000000000000000000..593257c01ca4552b5bdcfc447df3180c874db735 Binary files /dev/null and b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgThing.class differ diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgWorker.class b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgWorker.class new file mode 100644 index 0000000000000000000000000000000000000000..0f2fdff6b99c4575419736c4c265ad7da5aa7b78 Binary files /dev/null and b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor$ProgWorker.class differ diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor.class b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor.class new file mode 100644 index 0000000000000000000000000000000000000000..94e4a8acfad0961d9a0da817ffb61eb1a4254b49 Binary files /dev/null and b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor.class differ diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor.java b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor.java new file mode 100644 index 0000000000000000000000000000000000000000..fa7b5654de5d9cf3b6dfc4c11ca59247ce7e89b9 --- /dev/null +++ b/NODDI_toolbox_v1.01/ParforProgMonv2/java/ParforProgressMonitor.java @@ -0,0 +1,198 @@ +import javax.swing.*; +import java.io.*; +import java.net.*; +import java.util.concurrent.atomic.AtomicBoolean; + +// Copyright 2009 The MathWorks, Inc. + +public class ParforProgressMonitor { + + /** + * Create a "server" progress monitor - this runs on the desktop client and + * pops up the progress monitor UI. + */ + public static ProgServer createServer( String s, int N, int progressStepSize, int width, int height ) + throws IOException { + ProgServer ret = new ProgServer( s, N, progressStepSize, width, height ); + ret.start(); + return ret; + } + + /** + * Create a "worker" progress monitor - runs on the remote lab and sends updates + */ + public static ProgWorker createWorker( String host, int port ) + throws IOException { + return new ProgWorker( host, port ); + } + + /** + * Common interface exposed by both objects + */ + public interface ProgThing { + public void increment(); + public void done(); + } + + /** + * The worker-side object. Simply connects to the server to indicate that a + * quantum of progress has been made. This is a very basic implementation - + * a more sophisticated implementation would use a persistent connection, + * and a SocketChannel on the client with a thread doing a select loop and + * accepting connections etc. + */ + private static class ProgWorker implements ProgThing { + private int fPort; + private String fHost; + private ProgWorker( String host, int port ) { + fHost = host; + fPort = port; + } + + /** + * Connect and disconnect immediately to indicate progress + */ + public void increment() { + try { + Socket s = new Socket( fHost, fPort ); + s.close(); + } catch( Exception e ) { + e.printStackTrace(); + } + } + + /** + * Nothing for us to do here + */ + public void done() { + } + } + + /** + * The client-side object which pops up a window with a + * JProgressBar. Accepts connections from the workers, and then disconnects + * them immediately. Beware, the connection backlog of the ServerSocket + * might be insufficient. + */ + private static class ProgServer implements Runnable, ProgThing { + private JFrame fFrame; + private JProgressBar fBar; + private ServerSocket fSocket; + private int fValue, fN, fStep; + private String title; + private Thread fThread; + private AtomicBoolean fKeepGoing; + + private ProgServer( String s, int N, int progressStepSize, int width, int height ) throws IOException { + // The UI + fFrame = new JFrame( s ); + fBar = new JProgressBar( 0, N ); + fFrame.getContentPane().add( fBar ); + fFrame.pack(); + fFrame.setSize(width,height); + fFrame.setLocationRelativeTo( null ); + fFrame.setVisible( true ); + + // How far we are through - requires synchronized access + fValue = 0; + fN = N; + fStep = progressStepSize; + title = s; + + // Get an anonymous port + fSocket = new ServerSocket( 0 ); + // Set SO_TIMEOUT so that we don't block forever + fSocket.setSoTimeout( 100 ); + + // Our background thread + fThread = new Thread( this ); + fThread.setDaemon( true ); + + // Used to indicate to fThread when it's time to go + fKeepGoing = new AtomicBoolean( true ); + } + + /** + * Don't start the Thread in the constructor + */ + public void start() { fThread.start(); } + + /** + * Loop over accepting connections and updating + */ + public void run() { + while( fKeepGoing.get() ) { + try { + acceptAndIncrement(); + } catch( Exception e ) { + if( fKeepGoing.get() ) { + e.printStackTrace(); + } + } + } + } + + /** + * If there's a connection - accept and then disconnect; increment our count. + */ + private void acceptAndIncrement() throws IOException { + Socket worker; + try { + worker = fSocket.accept(); + } catch( SocketTimeoutException timeout ) { + // don't care about timeouts + return; + } + worker.close(); + increment(); + } + + + /** + * On the EDT, update the progress bar + */ + private void updateBar( final int newVal ) { + SwingUtilities.invokeLater( new Runnable() { + public void run() { + fBar.setValue( fStep*newVal ); + double percentage = 100.0*fStep*newVal/fN; + fFrame.setTitle(title + (int)percentage + "% completed."); + if ( newVal == fBar.getMaximum() ) { + done(); + } + } + } ); + } + + /** + * M-code needs to know which port we got + */ + public int getPort() { + return ((InetSocketAddress)fSocket.getLocalSocketAddress()).getPort(); + } + + /** + * Provide public access to this for pool-close PARFORs + */ + public synchronized void increment() { + fValue++; + updateBar( fValue ); + } + + /** + * Shut it all down + */ + public void done() { + fKeepGoing.set( false ); + try { + fSocket.close(); + } catch( Exception e ) { + e.printStackTrace(); + } + fFrame.dispose(); + } + } + + /** This class isn't useful - use the static methods */ + private ParforProgressMonitor() {} +} \ No newline at end of file diff --git a/NODDI_toolbox_v1.01/ParforProgMonv2/license.txt b/NODDI_toolbox_v1.01/ParforProgMonv2/license.txt new file mode 100644 index 0000000000000000000000000000000000000000..27fd717279ba6894c2a9ae9b9fb29016e4ec1355 --- /dev/null +++ b/NODDI_toolbox_v1.01/ParforProgMonv2/license.txt @@ -0,0 +1,28 @@ +Copyright (c) 2011, Willem-Jan de Goeij +Copyright (c) 2009, The MathWorks, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution + * Neither the name of the The MathWorks, Inc. nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/NODDI_toolbox_v1.01/VERSION b/NODDI_toolbox_v1.01/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..eff316426e0a6bd8cbf00d30be64c9916df10a59 --- /dev/null +++ b/NODDI_toolbox_v1.01/VERSION @@ -0,0 +1,2 @@ +This version of the toolbox is extracted from WUZI r1020. + diff --git a/NODDI_toolbox_v1.01/fitting/CreateROI.m b/NODDI_toolbox_v1.01/fitting/CreateROI.m new file mode 100644 index 0000000000000000000000000000000000000000..ee756489ab6458b5f62338e5fb6e20479a1a41c4 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/CreateROI.m @@ -0,0 +1,83 @@ +function CreateROI(dwifile, maskfile, outputfile) +% +% function CreateROI(dwifile, maskfile) +% +% This function converts 4-D DWI volume into the data format suitable +% for subsequent NODDI fitting. +% +% Inputs: +% +% dwifile: the 4-D DWI volume in NIfTI or Analyze format +% +% maskfile: the brain mask volume in NIfTI or Analyze format which +% specifies the voxels to include for fitting +% +% outputfile: the mat file to store the resulting data for subsequent +% fitting +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +% first check if niftimatlib is available +if (exist('nifti') ~= 2) + error('niftimatlib does not appear to be installed or included in the search path'); + return; +end + +% load the DWI volume +fprintf('loading the DWI volume : %s\n', dwifile); +dwi = nifti(dwifile); +xsize = dwi.dat.dim(1); +ysize = dwi.dat.dim(2); +zsize = dwi.dat.dim(3); +ndirs = dwi.dat.dim(4); + +% convert the data from scanner order to voxel order +dwi = dwi.dat(:,:,:,:); +dwi = permute(dwi,[4 1 2 3]); + +% load the brain mask volume +fprintf('loading the brain mask : %s\n', maskfile); +mask = nifti(maskfile); +mask = mask.dat(:,:,:); + +% create an ROI that is in voxel order and contains just the voxels in the +% brain mask +fprintf('creating the output ROI ...\n'); + +% first get the number of voxels first +% to more efficiently allocate the memory +count=0; +for i=1:xsize + for j=1:ysize + for k=1:zsize + if mask(i,j,k) > 0 + count = count + 1; + mask(i,j,k) = count; + end + end + end +end +roi = zeros(count,ndirs); +idx = zeros(count,3); + +% next construct the ROI +count=0; +for i=1:xsize + for j=1:ysize + for k=1:zsize + if mask(i,j,k) > 0 + count = count + 1; + roi(count,:) = dwi(:,i,j,k); + idx(count,:) = [i j k]; + end + end + end +end + +% save the ROI +fprintf('saving the output ROI as %s\n', outputfile); +save(outputfile, 'roi', 'mask', 'idx'); + +disp('done'); + diff --git a/NODDI_toolbox_v1.01/fitting/DT_DesignMatrix.m b/NODDI_toolbox_v1.01/fitting/DT_DesignMatrix.m new file mode 100644 index 0000000000000000000000000000000000000000..f27307f899c2d2aa83b2028205ff5c8c18bc2b1c --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/DT_DesignMatrix.m @@ -0,0 +1,77 @@ +function X=DT_DesignMatrix(protocol) +% Computes the design matrix for DT fitting using linear least squares. +% +% function X=DT_DesignMatrix(protocol) +% +% protocol is the acquisition protocol. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + + +GAMMA = 2.675987E8; + +if(strcmp(protocol.pulseseq, 'PGSE') || strcmp(protocol.pulseseq, 'STEAM')) + modQ = GAMMA*protocol.smalldel'.*protocol.G'; + q = repmat(modQ, [1,3]).*protocol.grad_dirs; + diffTime = (protocol.delta' - protocol.smalldel'/3); + + % Compute the design matrix + X = [ones(1, length(q)); -diffTime'.*q(:,1)'.*q(:,1)'; -2*diffTime'.*q(:,1)'.*q(:,2)'; -2*diffTime'.*q(:,1)'.*q(:,3)'; -diffTime'.*q(:,2)'.*q(:,2)'; -2*diffTime'.*q(:,2)'.*q(:,3)'; -diffTime'.*q(:,3)'.*q(:,3)']'; + +elseif(strcmp(protocol.pulseseq, 'OGSE')) + q = protocol.grad_dirs; + b = GetB_Values(protocol); + + % Compute the design matrix + X = [ones(1, length(q)); -b.*q(:,1)'.*q(:,1)'; -2*b.*q(:,1)'.*q(:,2)'; -2*b.*q(:,1)'.*q(:,3)'; -b.*q(:,2)'.*q(:,2)'; -2*b.*q(:,2)'.*q(:,3)'; -b.*q(:,3)'.*q(:,3)']'; + +elseif(strcmp(protocol.pulseseq, 'DSE')) + + bValue = GetB_ValuesDSE(protocol.G, protocol.delta1, protocol.delta2, protocol.delta3, protocol.t1, protocol.t2, protocol.t3); + + % Compute the design matrix + X = [ones(1, length(protocol.G)); -bValue.*protocol.grad_dirs(:,1)'.*protocol.grad_dirs(:,1)'; -2*bValue.*protocol.grad_dirs(:,1)'.*protocol.grad_dirs(:,2)'; -2*bValue.*protocol.grad_dirs(:,1)'.*protocol.grad_dirs(:,3)'; -bValue.*protocol.grad_dirs(:,2)'.*protocol.grad_dirs(:,2)'; -2*bValue.*protocol.grad_dirs(:,2)'.*protocol.grad_dirs(:,3)'; -bValue.*protocol.grad_dirs(:,3)'.*protocol.grad_dirs(:,3)']'; + +elseif(strcmp(protocol.pulseseq, 'FullSTEAM')) + + tdd = protocol.gap1 + protocol.gap2 + protocol.TM + 2*protocol.sdelc + 2*protocol.smalldel/3 + 2*protocol.sdelr; + tcc = protocol.TM + 2*protocol.sdelc/3 + 2*protocol.sdelr; + trr = protocol.TM + 2*protocol.sdelr/3; + tdc = protocol.TM + protocol.sdelc + 2*protocol.sdelr; + tdr = protocol.TM + protocol.sdelr; + tcr = protocol.TM + protocol.sdelr; + + qdx = protocol.grad_dirs(:,1)'.*protocol.G.*protocol.smalldel; + qdy = protocol.grad_dirs(:,2)'.*protocol.G.*protocol.smalldel; + qdz = protocol.grad_dirs(:,3)'.*protocol.G.*protocol.smalldel; + qcx = protocol.cG(:,1)'.*protocol.sdelc; + qcy = protocol.cG(:,2)'.*protocol.sdelc; + qcz = protocol.cG(:,3)'.*protocol.sdelc; + qrx = protocol.rG(:,1)'.*protocol.sdelr; + qry = protocol.rG(:,2)'.*protocol.sdelr; + qrz = protocol.rG(:,3)'.*protocol.sdelr; + + Fxx = -GAMMA^2*(qdx.^2.*tdd + qcx.^2.*tcc + qrx.^2.*trr + 2*qdx.*qcx.*tdc + 2*qdx.*qrx.*tdr + 2*qcx.*qrx.*tcr); + Fyy = -GAMMA^2*(qdy.^2.*tdd + qcy.^2.*tcc + qry.^2.*trr + 2*qdy.*qcy.*tdc + 2*qdy.*qry.*tdr + 2*qcy.*qry.*tcr); + Fzz = -GAMMA^2*(qdz.^2.*tdd + qcz.^2.*tcc + qrz.^2.*trr + 2*qdz.*qcz.*tdc + 2*qdz.*qrz.*tdr + 2*qcz.*qrz.*tcr); + Fxy = -GAMMA^2*(qdx.*qdy.*tdd + qcx.*qcy.*tcc + qrx.*qry.*trr + (qdx.*qcy+qdy.*qcx).*tdc + (qdx.*qry+qdy.*qrx).*tdr + (qcx.*qry+qcy.*qrx).*tcr)*2; + Fxz = -GAMMA^2*(qdx.*qdz.*tdd + qcx.*qcz.*tcc + qrx.*qrz.*trr + (qdx.*qcz+qdz.*qcx).*tdc + (qdx.*qrz+qdz.*qrx).*tdr + (qcx.*qrz+qcz.*qrx).*tcr)*2; + Fyz = -GAMMA^2*(qdy.*qdz.*tdd + qcy.*qcz.*tcc + qry.*qrz.*trr + (qdy.*qcz+qdz.*qcy).*tdc + (qdy.*qrz+qdz.*qry).*tdr + (qcy.*qrz+qcz.*qry).*tcr)*2; + + % Compute the design matrix + X = [ones(1, length(protocol.G)); Fxx; Fxy; Fxz; Fyy; Fyz; Fzz]'; +save /tmp/FS_X.mat X; + +elseif(strcmp(protocol.pulseseq, 'GEN')) + + bValue = GENGetB_Values(protocol); + % Compute the design matrix + bValue=bValue'; + X = [ones(1, length(protocol.delta)); -bValue.*protocol.grad_dirs(:,1)'.*protocol.grad_dirs(:,1)'; -2*bValue.*protocol.grad_dirs(:,1)'.*protocol.grad_dirs(:,2)'; -2*bValue.*protocol.grad_dirs(:,1)'.*protocol.grad_dirs(:,3)'; -bValue.*protocol.grad_dirs(:,2)'.*protocol.grad_dirs(:,2)'; -2*bValue.*protocol.grad_dirs(:,2)'.*protocol.grad_dirs(:,3)'; -bValue.*protocol.grad_dirs(:,3)'.*protocol.grad_dirs(:,3)']'; + +else + + error('Not implemented for pulse sequence: %s', protocol.pulseseq); +end + diff --git a/NODDI_toolbox_v1.01/fitting/EstimateSigma.m b/NODDI_toolbox_v1.01/fitting/EstimateSigma.m new file mode 100644 index 0000000000000000000000000000000000000000..93ddd423c09c30d11fc2f23239eb35e0365dc2af --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/EstimateSigma.m @@ -0,0 +1,27 @@ +function sigma = EstimateSigma(signal, protocol, model) +% +% function sigma = EstimateSigma(signal, protocol, model) +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if model.sigma.perVoxel == 1 + sigma = std(signal(protocol.b0_Indices), 1); + % if lower than the minimum SNR + sigmaMin = model.sigma.minSNR*mean(signal(protocol.b0_Indices)); + if sigma < sigmaMin + sigma = sigmaMin; + end +else + if isfield(model.sigma, 'globalSigma') + sigma = model.sigma.globalSigma; + elseif isfield(model.sigma, 'globalSNR') + sigma = model.sigma.globalSNR*mean(signal(protocol.b0_Indices)); + else + disp('You have chosen not to use per voxel sigma estimate'); + error('You need to specify either sigma.globalSigma or sigma.globalSNR for your model'); + end +end + +% apply the scaling parameter that may improve fitting +sigma = sigma/model.sigma.scaling; diff --git a/NODDI_toolbox_v1.01/fitting/FSL2Protocol.m b/NODDI_toolbox_v1.01/fitting/FSL2Protocol.m new file mode 100644 index 0000000000000000000000000000000000000000..be1c271fb1d1e54721030d044ca821d0e52119f7 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/FSL2Protocol.m @@ -0,0 +1,95 @@ +function protocol = FSL2Protocol(bvalfile, bvecfile, b0threshold) +% +% function protocol = FSL2Protocol(bvalfile, bvecfile, b0threshold) +% +% Note: for NODDI, the exact sequence timing is not important. +% this function reverse-engineerings one possible sequence timing +% given the b-values. +% +% b0threshold: optional argument to specify a non-zero value for your b=0 +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if nargin == 2 + b0threshold = 0; +end + +protocol.pulseseq = 'PGSE'; +protocol.schemetype = 'multishellfixedG'; +protocol.teststrategy = 'fixed'; + +% load bval +bval = load(bvalfile); +bval = bval'; + +% set total number of measurements +protocol.totalmeas = length(bval); + +% set the b=0 indices +protocol.b0_Indices = find(bval<=b0threshold); +protocol.numZeros = length(protocol.b0_Indices); + +% find the unique non-zero b-values +B = unique(bval(bval>b0threshold)); + +% set the number of shells +protocol.M = length(B); +for i=1:length(B) + protocol.N(i) = length(find(bval==B(i))); +end + +% maximum b-value in the s/mm^2 unit +maxB = max(B); + +% set maximum G = 40 mT/m +Gmax = 0.04; + +% set smalldel and delta and G +GAMMA = 2.675987E8; +tmp = nthroot(3*maxB*10^6/(2*GAMMA^2*Gmax^2),3); +for i=1:length(B) + protocol.udelta(i) = tmp; + protocol.usmalldel(i) = tmp; + protocol.uG(i) = sqrt(B(i)/maxB)*Gmax; +end + +protocol.delta = zeros(size(bval))'; +protocol.smalldel = zeros(size(bval))'; +protocol.G = zeros(size(bval))'; + +for i=1:length(B) + tmp = find(bval==B(i)); + for j=1:length(tmp) + protocol.delta(tmp(j)) = protocol.udelta(i); + protocol.smalldel(tmp(j)) = protocol.usmalldel(i); + protocol.G(tmp(j)) = protocol.uG(i); + end +end + +% load bvec +bvec = load(bvecfile); +protocol.grad_dirs = bvec'; + +% some systems set vector to zeros for b=0 +% the codes below try to account for this +if isempty(protocol.b0_Indices) + for i=1:protocol.totalmeas + if norm(protocol.grad_dirs(i,:)) == 0 + protocol.G(i) = 0.0; + protocol.b0_Indices = [protocol.b0_Indices i]; + end + end + protocol.numZeros = length(protocol.b0_Indices); +end + +% make the gradient directions for b=0's [1 0 0] +for i=1:length(protocol.b0_Indices) + protocol.grad_dirs(protocol.b0_Indices(i),:) = [1 0 0]; +end + +% make sure the gradient directions are unit vectors +for i=1:protocol.totalmeas + protocol.grad_dirs(i,:) = protocol.grad_dirs(i,:)/norm(protocol.grad_dirs(i,:)); +end + diff --git a/NODDI_toolbox_v1.01/fitting/FitLinearDT.m b/NODDI_toolbox_v1.01/fitting/FitLinearDT.m new file mode 100644 index 0000000000000000000000000000000000000000..411e90ec2202f7d07ed0fba254f97808e37fec81 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/FitLinearDT.m @@ -0,0 +1,55 @@ +function [D, Ep] = FitLinearDT(E, protocol, fitS0) +% Fits the DT model using linear least squares. +% +% D=FitLinearDT(E, protocol, fitS0) +% returns [logS(0) Dxx Dxy Dxz Dyy Dyz Dzz]. +% +% E is the set of measurements. +% +% protocol is the acquisition protocol. +% +% +% fitS0 is a flag for enabling the fitting of S0 +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if (nargin < 3) + fitS0 = 0; +end + +if (isfield(protocol, 'dti_subset')) + E = E(protocol.dti_subset); + protocol.delta = protocol.delta(protocol.dti_subset); + protocol.smalldel = protocol.smalldel(protocol.dti_subset); + protocol.G = protocol.G(protocol.dti_subset); + protocol.grad_dirs = protocol.grad_dirs(protocol.dti_subset,:); + protocol.b0_Indices = intersect(protocol.b0_Indices, protocol.dti_subset); +end + +X = DT_DesignMatrix(protocol); +if fitS0 == 0 + X = X(:,2:end); +end +Xi = pinv(X); + +% We assume that E are all positives +% If not, first filter out the nonpositive values with RemoveNegMeas + +if (fitS0) + D = Xi*log(E); + if (nargout > 1) + Ep = exp(X*D); + end +else + S0 = squeeze(mean(E(protocol.b0_Indices))); + E = E/S0; + D = zeros(7,1); + D(1) = log(S0); + D(2:end) = Xi*log(E); + if (nargout > 1) + Ep = S0*exp(X*D(2:end)); + end +end + diff --git a/NODDI_toolbox_v1.01/fitting/GetSearchGrid.m b/NODDI_toolbox_v1.01/fitting/GetSearchGrid.m new file mode 100644 index 0000000000000000000000000000000000000000..502c48a4bdff8504db5aa319f8b1f4970cca38de --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/GetSearchGrid.m @@ -0,0 +1,654 @@ +function grid = GetSearchGrid(model, material, fix, fixedvals) +% Returns a list of parameter combinations for the specified model +% for the GridSearch function to use in search for the combination +% that best fits a set of measurements. +% +% grid=GetSearchGrid(model, material, fix, fixedvals) +% returns a list of parameter combinations for the model that +% are realistic for a particular material type. +% +% model is a string specifying the model. +% +% material is a string specifying the type of material, which +% determines the range of each parameter in the grid. +% Options are: +% invivo +% invivopreterm +% invivowhitematter +% fixedwhitematter +% +% fix is a list of binary numbers specifying which +% model parameters have fixed values. By default the +% list is all zeros so no parameters are fixed. +% +% fixedvals is an array the same size as fix that specifies +% the fixed values of any fixed parameters. Entries in +% fixedvals in locations where fix has value zero are not +% used. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if(nargin<3) + fix=zeros(6); + fixedvals = zeros(6); +end + +if(strcmp(material, 'invivo')) + fs = [0.0 0.25 0.5 0.75 1.0]; + dpars = [13.0 17.0 21.0]*1E-10; + disos = [10.0 20.0 30.0 50.0]*1E-10; + Rs=[0.5 1 2 4]*1E-6; + irfracs=[0 0.1 0.2 0.3]; + fisos=[0.0 0.25 0.5 0.75 1.0]; + kappas = [0.5 1 2 4 8]; + fic = [0.3 0.5 0.7]; +elseif(strcmp(material, 'exvivo')) + fs = [0.0 0.25 0.5 0.75 1.0]; + dpars = [3.0 4.5 6.0 7.5]*1E-10; + disos = [5.0 10.0 15.0]*1E-10; + Rs=[1 2 4 8]*1E-6; + irfracs=[0 0.1 0.2 0.3]; + fisos=[0.0 0.25 0.5 0.75 1.0]; + kappas = [0.5 1 2 4 8]; + fic = [0.3 0.5 0.7]; +elseif(strcmp(material, 'invivopreterm')) + fs = [0.0 0.1 0.2 0.3]; + dpars = [13.0 17.0 21.0]*1E-10; + disos = [10.0 20.0 30.0 50.0]*1E-10; + Rs=[1 2 4 8]*1E-6; + irfracs=[0 0.1 0.2 0.3]; + fisos=[0.0 0.25 0.5 0.75 1.0]; + kappas = [0.5 1 2 4 8]; + fic = [0.3 0.5 0.7]; +elseif(strcmp(material, 'invivowhitematter')) + fs = [0.5 0.7 0.9]; + dpars = [10.0 13.0 15.0 17.0 19.0 21.0 23.0 25.0]*1E-10; + disos = [10.0 20.0 30.0 50.0]*1E-10; + Rs=[1 2 4 8]*1E-6; + irfracs=[0 0.1 0.2 0.3]; + fisos=[0 0.2 0.4]; + kappas = [4 8 16 32 64 128]; + fic = [0.3 0.5 0.7]; +elseif(strcmp(material, 'postmortemwhitematter')) + fs = [0.5 0.7 0.9]; + dpars = [2.0 3.0 4.0 5.0 6.0]*1E-10; + disos = [5.0 10.0 15.0]*1E-10; + Rs=[1 2 4 8]*1E-6; + irfracs=[0 0.1 0.2 0.3]; + fisos=[0 0.2 0.4]; + kappas = [4 8 16 32 64 128]; + fic = [0.3 0.5 0.7]; +else + error(['Unknown material: ', tissue]); +end + +% Adjust for fixed parameters. The first two parameters are the same for +% all models. +if(fix(1)) + fs = [fixedvals(1)]; +end +if(fix(2)) + dpars = [fixedvals(2)]; +end + +if(strcmp(model, 'CylSingleRadTortGPD')) + if(fix(3)) + Rs = [fixedvals(3)]; + end + + numCombs = length(Rs)*length(fs)*length(dpars); + grid = zeros(3, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + pars = [fs(j) dpars(k) Rs(i)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end +elseif(strcmp(model, 'CylSingleRadGPD')) + if(fix(4)) + Rs = [fixedvals(4)]; + end + + numCombs = length(Rs)*length(fs)*length(dpars); + grid = zeros(4, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + % Set dperp using the standard tortuosity model for + % randomly placed cylinders unless fixed. + dperp = dpars(k)*(1-fs(j)); + if(fix(3)) + dperp = fixedvals(3); + end + pars = [fs(j) dpars(k) dperp Rs(i)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end +elseif(strcmp(model, 'CylSingleRadTortIsoGPD')) + if(fix(3)) + Rs = [fixedvals(3)]; + end + if(fix(4)) + fisos = [fixedvals(4)]; + end + + numCombs = length(Rs)*length(fs)*length(dpars)*length(fisos); + grid = zeros(4, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + for l=1:length(fisos) + pars = [fs(j) dpars(k) Rs(i) fisos(l)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end +elseif(strcmp(model, 'CylSingleRadIsoV_GPD') || strcmp(model, 'CylSingleRadIsoV_GPD_B0')) + if(fix(4)) + Rs = [fixedvals(4)]; + end + if(fix(5)) + fisos = [fixedvals(5)]; + end + if(fix(6)) + disos = [fixedvals(6)]; + end + + numCombs = length(Rs)*length(fs)*length(dpars)*length(fisos)*length(disos); + grid = zeros(6, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + for l=1:length(fisos) + for m=1:length(disos) + % Set dperp using the standard tortuosity model for + % randomly placed cylinders unless fixed. + dperp = dpars(k)*(1-fs(j)); + if(fix(3)) + dperp = fixedvals(3); + end + pars = [fs(j) dpars(k) dperp Rs(i) fisos(l) disos(m)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end +elseif(strcmp(model, 'CylSingleRadTortIsoV_GPD') || strcmp(model, 'CylSingleRadTortIsoV_GPD_B0')) + if(fix(3)) + Rs = [fixedvals(3)]; + end + if(fix(4)) + fisos = [fixedvals(4)]; + end + if(fix(5)) + disos = [fixedvals(5)]; + end + + numCombs = length(Rs)*length(fs)*length(dpars)*length(fisos)*length(disos); + grid = zeros(5, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + for l=1:length(fisos) + for m=1:length(disos) + pars = [fs(j) dpars(k) Rs(i) fisos(l) disos(m)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end +elseif(strcmp(model, 'CylSingleRadIsoDotGPD')) + if(fix(4)) + Rs = [fixedvals(4)]; + end + if(fix(5)) + irfracs = [fixedvals(5)]; + end + numCombs = length(Rs)*length(fs)*length(dpars)*length(irfracs); + grid = zeros(5, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + for l=1:length(irfracs) + dperp = dpars(k)*(1-fs(j)); + pars = [fs(j) dpars(k) dperp Rs(i) irfracs(l)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end +elseif(strcmp(model, 'CylSingleRadIsoResTortIsoV_GPD') || strcmp(model, 'CylSingleRadIsoResTortIsoV_GPD_B0')... + || strcmp(model, 'CylSingleRadIsoStickTortIsoV_GPD') || strcmp(model, 'CylSingleRadIsoStickTortIsoV_GPD_B0')... + || strcmp(model, 'CylSingleRadIsoSphereTortIsoV_GPD') || strcmp(model, 'CylSingleRadIsoSphereTortIsoV_GPD_B0')... + || strcmp(model, 'CylSingleRadIsoDotTortIsoV_GPD') || strcmp(model, 'CylSingleRadIsoDotTortIsoV_GPD_B0')) + if(fix(3)) + Rs = [fixedvals(3)]; + end + if(fix(4)) + irfracs = [fixedvals(4)]; + end + if(fix(5)) + fisos = [fixedvals(5)]; + end + if(fix(6)) + disos = [fixedvals(6)]; + end + + numCombs = length(Rs)*length(fs)*length(dpars)*length(fisos)*length(disos); + grid = zeros(6, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + for l=1:length(fisos) + for m=1:length(disos) + for n=1:length(irfracs) + pars = [fs(j) dpars(k) Rs(i) irfracs(n) fisos(l) disos(m)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end + end +elseif(strcmp(model, 'Stick')) + numCombs = length(fs)*length(dpars); + grid = zeros(3, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + % Set dperp using the standard tortuosity model for + % randomly placed cylinders unless fixed. + dperp = dpars(j)*(1-fs(i)); + if(fix(3)) + dperp = fixedvals(3); + end + pars = [fs(i) dpars(j) dperp]; + grid(:,ind) = pars; + ind = ind + 1; + end + end +elseif(strcmp(model, 'StickIsoV_B0')) + if(fix(4)) + fisos = [fixedvals(4)]; + end + if(fix(5)) + disos = [fixedvals(5)]; + end + + numCombs = length(fs)*length(dpars)*length(fisos)*length(disos); + grid = zeros(5, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(fisos) + for l=1:length(disos) + % Set dperp using the standard tortuosity model for + % randomly placed cylinders unless fixed + dperp = dpars(j)*(1-fs(i)); + if(fix(3)) + dperp = fixedvals(3); + end + pars = [fs(i) dpars(j) dperp fisos(k) disos(l)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end +elseif(strcmp(model, 'StickTortIsoV_B0')) + if(fix(3)) + fisos = [fixedvals(3)]; + end + if(fix(4)) + disos = [fixedvals(4)]; + end + + numCombs = length(fs)*length(dpars)*length(fisos)*length(disos); + grid = zeros(4, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(fisos) + for l=1:length(disos) + pars = [fs(i) dpars(j) fisos(k) disos(l)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end +elseif(strcmp(model, 'WatsonStick') || strcmp(model, 'WatsonSHStick')) + numCombs = length(fs)*length(dpars)*length(kappas); + grid = zeros(4, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(kappas) + % Set dperp using the standard tortuosity model for + % randomly placed cylinders unless fixed. + dperp = dpars(j)*(1-fs(i)); + if(fix(3)) + dperp = fixedvals(3); + end + pars = [fs(i) dpars(j) dperp kappas(k)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end +elseif(strcmp(model, 'WatsonSHStickIsoV_B0')) + if(fix(4)) + kappas = [fixedvals(4)]; + end + if(fix(5)) + fisos = [fixedvals(5)]; + end + if(fix(6)) + disos = [fixedvals(6)]; + end + + numCombs = length(fs)*length(dpars)*length(fisos)*length(disos)*length(kappas); + grid = zeros(6, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(fisos) + for l=1:length(disos) + for m=1:length(kappas) + dperp = dpars(j)*(1-fs(i)); + if(fix(3)) + dperp = fixedvals(3); + end + pars = [fs(i) dpars(j) dperp kappas(m) fisos(k) disos(l)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end +elseif(strcmp(model, 'WatsonSHStickIsoVIsoDot_B0')) + if(fix(5)) + fisos = [fixedvals(5)]; + end + if(fix(6)) + disos = [fixedvals(6)]; + end + if(fix(7)) + irfracs = [fixedvals(7)]; + end + + numCombs = length(fs)*length(dpars)*length(fisos)*length(disos)*length(kappas)*length(irfracs); + grid = zeros(7, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(fisos) + for l=1:length(disos) + for m=1:length(kappas) + for n=1:length(irfracs) + dperp = dpars(j)*(1-fs(i)); + if(fix(3)) + dperp = fixedvals(3); + end + pars = [fs(i) dpars(j) dperp kappas(m) fisos(k) disos(l) irfracs(n)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end + end +elseif(strcmp(model, 'WatsonStickTort') || strcmp(model, 'WatsonSHStickTort')) + numCombs = length(fs)*length(dpars)*length(kappas); + grid = zeros(3, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(kappas) + pars = [fs(i) dpars(j) kappas(k)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end +elseif(strcmp(model, 'WatsonSHStickTortIsoV_B0')) + if(fix(4)) + fisos = [fixedvals(4)]; + end + if(fix(5)) + disos = [fixedvals(5)]; + end + + numCombs = length(fs)*length(dpars)*length(fisos)*length(disos)*length(kappas); + grid = zeros(5, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(fisos) + for l=1:length(disos) + for m=1:length(kappas) + pars = [fs(i) dpars(j) kappas(m) fisos(k) disos(l)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end +elseif(strcmp(model, 'WatsonSHStickTortIsoVIsoDot_B0')) + if(fix(4)) + fisos = [fixedvals(4)]; + end + if(fix(5)) + disos = [fixedvals(5)]; + end + if(fix(6)) + irfracs = [fixedvals(6)]; + end + + numCombs = length(fs)*length(dpars)*length(fisos)*length(disos)*length(kappas)*length(irfracs); + grid = zeros(6, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(fisos) + for l=1:length(disos) + for m=1:length(kappas) + for n=1:length(irfracs) + pars = [fs(i) dpars(j) kappas(m) fisos(k) disos(l) irfracs(n)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end + end +elseif(strcmp(model, 'WatsonSHCylSingleRadTortIsoV_GPD') || strcmp(model, 'WatsonSHCylSingleRadTortIsoV_GPD_B0')) + if(fix(3)) + Rs = [fixedvals(3)]; + end + if(fix(5)) + fisos = [fixedvals(5)]; + end + if(fix(6)) + disos = [fixedvals(6)]; + end + + numCombs = length(Rs)*length(fs)*length(dpars)*length(fisos)*length(disos)*length(kappas); + grid = zeros(6, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + for l=1:length(fisos) + for m=1:length(disos) + for n=1:length(kappas) + pars = [fs(j) dpars(k) Rs(i) kappas(n) fisos(l) disos(m)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end + end +elseif(strcmp(model, 'BinghamCylSingleRadTortIsoV_GPD_B0')) + if(fix(3)) + Rs = [fixedvals(3)]; + end + if(fix(7)) + fisos = [fixedvals(7)]; + end + if(fix(8)) + disos = [fixedvals(8)]; + end + + numCombs = length(Rs)*length(fs)*length(dpars)*length(fisos)*length(disos)*length(kappas); + grid = zeros(8, numCombs); + ind = 1; + for i=1:length(Rs) + for j=1:length(fs) + for k=1:length(dpars) + for l=1:length(fisos) + for m=1:length(disos) + for n=1:length(kappas) + pars = [fs(j) dpars(k) Rs(i) kappas(n) 0 0 fisos(l) disos(m)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end + end +elseif(strcmp(model, 'BinghamStickTortIsoV_B0')) + if(fix(6)) + fisos = [fixedvals(6)]; + end + if(fix(7)) + disos = [fixedvals(7)]; + end + + numCombs = length(fs)*length(dpars)*length(fisos)*length(disos)*length(kappas); + grid = zeros(7, numCombs); + ind = 1; + for i=1:length(fs) + for j=1:length(dpars) + for k=1:length(fisos) + for l=1:length(disos) + for m=1:length(kappas) + pars = [fs(i) dpars(j) kappas(m) 0 0 fisos(k) disos(l)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end +elseif(strcmp(model, 'ExCrossingCylSingleRadGPD')) + R1s = Rs; + R2s = Rs; + if(fix(4)) + R1s = [fixedvals(4)]; + end + + if(fix(5)) + R2s = [fixedvals(5)]; + end + + numCombs = length(R1s)*length(R2s)*length(fs)*length(dpars)*length(fic); + grid = zeros(6, numCombs); + ind = 1; + for i=1:length(R1s) + for j=1:length(R2s) + for k=1:length(fs) + for l=1:length(dpars) + for m=1:length(fic) + % Set dperp using the standard tortuosity model for + % randomly placed cylinders unless fixed. + dperp = dpars(l)*(1-fs(k)); + if(fix(3)) + dperp = fixedvals(3); + end + pars = [fs(k) dpars(l) dperp R1s(i) R2s(j) fic(m)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end +elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotTortIsoV_GPD_B0')) + R1s = Rs; + R2s = Rs; + if(fix(3)) + R1s = [fixedvals(3)]; + end + + if(fix(4)) + R2s = [fixedvals(4)]; + end + + if(fix(6)) + irfracs = [fixedvals(6)]; + end + + if(fix(7)) + fisos = [fixedvals(7)]; + end + + if(fix(8)) + disos = [fixedvals(8)]; + end + + numCombs = length(R1s)*length(R2s)*length(fs)*length(dpars)*length(fic)*length(irfracs)*length(fisos)*length(disos); + grid = zeros(8, numCombs); + ind = 1; + for i=1:length(R1s) + for j=1:length(R2s) + for k=1:length(fs) + for l=1:length(dpars) + for m=1:length(fic) + for n=1:length(irfracs) + for p=1:length(fisos) + for q=1:length(disos) + pars = [fs(k) dpars(l) R1s(i) R2s(j) fic(m) irfracs(n) fisos(p) disos(q)]; + grid(:,ind) = pars; + ind = ind + 1; + end + end + end + end + end + end + end + end +else + error(['Starting combinations not implemented for model: ', model]); +end + diff --git a/NODDI_toolbox_v1.01/fitting/GradDescDecode.m b/NODDI_toolbox_v1.01/fitting/GradDescDecode.m new file mode 100644 index 0000000000000000000000000000000000000000..44e66e28e8f74cb9fd2dfca5f6cc569b4a7e147e --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/GradDescDecode.m @@ -0,0 +1,37 @@ +function params = GradDescDecode(modelname, optoutput) +% +% function params = GradDescDecode(modelname, optoutput) +% +% Encodes raw parameter values to enforce simple constraints during direct fitting. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +parameterStrings = GetParameterStrings(modelname); +params = zeros(1, length(parameterStrings)); + +for i=1:length(parameterStrings) + if (strcmp(parameterStrings(i), 'ficvf') ||... + strcmp(parameterStrings(i), 'fiso') ||... + strcmp(parameterStrings(i), 'irfrac')) + params(i) = sin(optoutput(i))^2; + elseif (strcmp(parameterStrings(i), 'di') ||... + strcmp(parameterStrings(i), 'diso') ||... + strcmp(parameterStrings(i), 'rad') ||... + strcmp(parameterStrings(i), 'kappa') ||... + strcmp(parameterStrings(i), 'b0') ||... + strcmp(parameterStrings(i), 't1')) + params(i) = optoutput(i)^2; + elseif (strcmp(parameterStrings(i), 'dh')) + diIdx = GetParameterIndex(modelname, 'di'); + params(i) = params(diIdx)*sin(optoutput(i))^2; + elseif (strcmp(parameterStrings(i), 'beta')) + kappaIdx = GetParameterIndex(modelname, 'kappa'); + params(i) = params(kappaIdx)*sin(optoutput(i))^2; + elseif (strcmp(parameterStrings(i), 'theta') ||... + strcmp(parameterStrings(i), 'phi') ||... + strcmp(parameterStrings(i), 'psi')) + params(i) = optoutput(i); + end +end + diff --git a/NODDI_toolbox_v1.01/fitting/GradDescEncode.m b/NODDI_toolbox_v1.01/fitting/GradDescEncode.m new file mode 100644 index 0000000000000000000000000000000000000000..24a6a5875131f46186195fefcc174f1135d3af3a --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/GradDescEncode.m @@ -0,0 +1,41 @@ +function optarray = GradDescEncode(modelname, x) +% +% function optarray = GradDescEncode(modelname, x) +% +% Encodes raw parameter values to enforce simple constraints during direct fitting. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +parameterStrings = GetParameterStrings(modelname); +optarray = zeros(1, length(parameterStrings)); + +for i=1:length(parameterStrings) + if (strcmp(parameterStrings(i), 'ficvf') ||... + strcmp(parameterStrings(i), 'fiso') ||... + strcmp(parameterStrings(i), 'irfrac')) + optarray(i) = asin(sqrt(x(i))); + elseif (strcmp(parameterStrings(i), 'di') ||... + strcmp(parameterStrings(i), 'diso') ||... + strcmp(parameterStrings(i), 'rad') ||... + strcmp(parameterStrings(i), 'kappa') ||... + strcmp(parameterStrings(i), 'b0') ||... + strcmp(parameterStrings(i), 't1')) + optarray(i) = sqrt(x(i)); + elseif (strcmp(parameterStrings(i), 'dh')) + diIdx = GetParameterIndex(modelname, 'di'); + optarray(i) = asin(sqrt(x(i)/x(diIdx))); + elseif (strcmp(parameterStrings(i), 'beta')) + kappaIdx = GetParameterIndex(modelname, 'kappa'); + if (x(kappaIdx) == 0) + optarray(i) = 0; + else + optarray(i) = asin(sqrt(x(i)/x(kappaIdx))); + end + elseif (strcmp(parameterStrings(i), 'theta') ||... + strcmp(parameterStrings(i), 'phi') ||... + strcmp(parameterStrings(i), 'psi')) + optarray(i) = x(i); + end +end + diff --git a/NODDI_toolbox_v1.01/fitting/GradDescLimits.m b/NODDI_toolbox_v1.01/fitting/GradDescLimits.m new file mode 100644 index 0000000000000000000000000000000000000000..a9eb11c467c127e72d30d8adb6ac319c039c1e55 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/GradDescLimits.m @@ -0,0 +1,69 @@ +function [min_val max_val] = GradDescLimits(modelname) +% +% function [min_val max_val] = GradDescLimits(modelname) +% +% Returns maximum and minimum settings for the parameters of different +% models to use during direct fitting. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +LARGE = 100000; + +D_MIN = 0.001; +D_MAX = 3; +D_PERP_MIN = 0.001; + +ANGLEMAX=100; + +R_MIN = 0.1; +R_MAX = 5; + +% the values need to account for scaling defined +% in GetScalingFactors.m +K_MIN = 0; +K_MAX = 6.4; + +B_MIN = 0; +B_MAX = 3.2; + +parameterStrings = GetParameterStrings(modelname); +min_val = zeros(1, length(parameterStrings)); +max_val = zeros(1, length(parameterStrings)); + +for i=1:length(parameterStrings) + if (strcmp(parameterStrings(i), 'ficvf') ||... + strcmp(parameterStrings(i), 'fiso') ||... + strcmp(parameterStrings(i), 'irfrac')) + min_val(i) = 0; + max_val(i) = LARGE; + elseif (strcmp(parameterStrings(i), 'di') ||... + strcmp(parameterStrings(i), 'diso')) + min_val(i) = sqrt(D_MIN); + max_val(i) = sqrt(D_MAX); + elseif (strcmp(parameterStrings(i), 'dh')) + min_val(i) = sqrt(D_PERP_MIN); + max_val(i) = LARGE; + elseif (strcmp(parameterStrings(i), 'rad')) + min_val(i) = sqrt(R_MIN); + max_val(i) = sqrt(R_MAX); + elseif (strcmp(parameterStrings(i), 'kappa')) + min_val(i) = sqrt(K_MIN); + max_val(i) = sqrt(K_MAX); + elseif (strcmp(parameterStrings(i), 'beta')) + min_val(i) = sqrt(B_MIN); + max_val(i) = sqrt(B_MAX); + elseif (strcmp(parameterStrings(i), 'theta') ||... + strcmp(parameterStrings(i), 'phi') ||... + strcmp(parameterStrings(i), 'psi')) + min_val(i) = -ANGLEMAX; + max_val(i) = ANGLEMAX; + elseif (strcmp(parameterStrings(i), 'b0')) + min_val(i) = 0.001; + max_val(i) = LARGE; + elseif (strcmp(parameterStrings(i), 't1')) + min_val(i) = 0.1; + max_val(i) = 1; + end +end + diff --git a/NODDI_toolbox_v1.01/fitting/GridSearchRician.m b/NODDI_toolbox_v1.01/fitting/GridSearchRician.m new file mode 100644 index 0000000000000000000000000000000000000000..0a739a9b8c90b86b5d44da8f0875989fd5ddac38 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/GridSearchRician.m @@ -0,0 +1,134 @@ +function [x0, liks] = GridSearchRician(Epn, model, grid, protocol, constants, initSig, fixT1, fibredir) +% Performs a discrete grid search for the combination of parameters +% that best fits a set of measurements for the specified model using a +% Rician noise model. +% +% [x0, liks] = GridSearchRician(Epn, model, grid, protocol, constants, initSig, fibredir) +% returns the parameter combination x0 with the lowest fitting error and a list +% liks of the values of the objective function for each parameter combination in the grid. +% +% model is a string specifying the model. +% +% Epn is the array of measurements. +% +% model is a string specifying the model +% +% grid is the list of parameter combinations to check; typically +% this comes from GetSearchGrid. +% +% protocol contains the protocol for obtaining the measurements. +% +% constants contains values required for the model signal computations. +% +% initSig is the standard deviation of the noise underlying the Rician +% noise model. +% +% fibredir can be specified, but if left out is estimated by fitting the +% diffusion tensor model to the measurements and using the principal +% eigenvalue. +% +% fixT1 is a fixed value for T1 that can be specified. If not +% specified and the model is one that contains T1 as a parameter, +% then T1 is estimated via a linear fit at the same time as the +% diffusion tensor. Note: this may not work particularly well. +% If the DT is a bad fit for the data, this can easily result +% in negative diffusivities etc. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +[junk numCombs] = size(grid); + +% Find the fiber direction and S0 from the best fit DT +if(nargin<8) + if(strcmp(model, 'CylSingleRadIsoDotTortIsoV_GPD_B0T1')) + if(nargin<7) + D = FitLinearDT_T1(Epn, protocol); + % Linear estimate of T1 can occasionally go negative + % from noise. + T1 = max([0 D(8)]); + else + % Correct for the known T1 and fit DT in the normal way. + D = FitLinearDT(Epn.*exp(-fixT1./protocol.TM), protocol); + T1 = fixT1; + end + else + D = FitLinearDT(Epn, protocol); + end + dt = MakeDT_Matrix(D(2), D(3), D(4), D(5), D(6), D(7)); + [evec, eval] = eig(dt); + % try to deal with non-positive definite tensors + [eigs, ind] = sort(abs([eval(1, 1) eval(2, 2) eval(3, 3)])); + fibredir = evec(:,ind(3)); + if(strncmp(model, 'Bingham', 7)) + beta_to_kappa = eigs(2)/eigs(3); + fanningdir = evec(:,ind(2)); + end + S0 = exp(D(1)); +end + +initTheta = acos(fibredir(3)); +initPhi = atan2(fibredir(2), fibredir(1)); + +if(strncmp(model, 'Bingham', 7)) + if abs(fibredir(3)) > 0.1 + mat = [-sin(initPhi) -cos(initTheta)*cos(initPhi); cos(initPhi) -cos(initTheta)*sin(initPhi)]; + tmp = mat\[fanningdir(1) fanningdir(2)]'; + initPsi = atan2(tmp(2), tmp(1)); + elseif abs(sin(initPhi)) > 0.1 + mat = [-sin(initPhi) -cos(initTheta)*cos(initPhi); 0 sin(initTheta)]; + tmp = mat\[fanningdir(1) fanningdir(3)]'; + initPsi = atan2(tmp(2), tmp(1)); + else + mat = [cos(initPhi) -cos(initTheta)*sin(initPhi); 0 sin(initTheta)]; + tmp = mat\[fanningdir(2) fanningdir(3)]'; + initPsi = atan2(tmp(2), tmp(1)); + end + if(strcmp(model, 'BinghamStickTortIsoV_B0')) + grid(4,:) = grid(3,:)*beta_to_kappa; + grid(5,:) = initPsi; + elseif(strcmp(model, 'BinghamCylSingleRadTortIsoV_GPD_B0')) + grid(5,:) = grid(4,:)*beta_to_kappa; + grid(6,:) = initPsi; + else + error('ERROR: Bingham initialization not implemented for this model'); + end +end + +% Add the b=0 measurement to the test combinations for models that need it. +if(strcmp(model, 'CylSingleRadIsoV_GPD_B0') ||... + strcmp(model, 'CylSingleRadTortIsoV_GPD_B0') ||... + strcmp(model, 'CylSingleRadIsoDotTortIsoV_GPD_B0') ||... + strcmp(model, 'WatsonSHCylSingleRadTortIsoV_GPD_B0') ||... + strcmp(model, 'WatsonSHStickIsoV_B0') ||... + strcmp(model, 'WatsonSHStickIsoVIsoDot_B0') ||... + strcmp(model, 'WatsonSHStickTortIsoV_B0') ||... + strcmp(model, 'WatsonSHStickTortIsoVIsoDot_B0') ||... + strcmp(model, 'BinghamStickTortIsoV_B0') ||... + strcmp(model, 'BinghamCylSingleRadTortIsoV_GPD_B0') ||... + strcmp(model, 'StickIsoV_B0') ||... + strcmp(model, 'StickTortIsoV_B0')) + grid = [grid' ones(size(grid,2), 1)*S0]'; +end + +% Add T1 and the b=0 measurement to the test combinations for models +% that need it. +if(strcmp(model, 'CylSingleRadIsoDotTortIsoV_GPD_B0T1')) + grid = [grid' ones(size(grid,2), 1)*S0 ones(size(grid,2), 1)*T1]'; +end + +% Test each combination +liks = zeros(numCombs, 1); +for j=1:numCombs + Eest = SynthMeas(model, grid(:,j), protocol, fibredir, constants); + liks(j) = RicianLogLik(Epn, Eest, initSig); +end +[a ind] = max(liks); +mlPars = grid(:,ind); + +% Rescale and construct the final result. +scale = GetScalingFactors(model); +psc = [mlPars' initSig].*scale; +x0 = [psc(1:(end-1)) initTheta initPhi initSig]; + diff --git a/NODDI_toolbox_v1.01/fitting/PlotFittedModel.m b/NODDI_toolbox_v1.01/fitting/PlotFittedModel.m new file mode 100644 index 0000000000000000000000000000000000000000..21e78d90114fd4ee070c76b4bcaa275f37a1f6da --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/PlotFittedModel.m @@ -0,0 +1,58 @@ +function PlotFittedModel(protocol, MODELNAME, fittedpars, constants, h, style) +% Plots the normalized measurements predicted by the model with +% the fitted parameters against the absolute dot product of the +% gradient and fibre directions. +% +% PlotFittedModel(protocol, MODELNAME, fittedpars, h) +% adds the plot to figure handle h. +% +% protocol is the imaging protocol. +% +% MODELNAME is the name identifying the model. +% +% fittedpars and the model parameter values. +% +% constants is a structure containing fixed values required for the model. +% +% h is a figure handle to add the plot to. If not specified, a new figure +% appears. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if(nargin<5) + h = figure; +end + +% Get estimated fibre direction and b=0 signal. +fibredir = GetFibreOrientation(MODELNAME, fittedpars); +b0est = GetB0(MODELNAME, fittedpars); + +if(nargin<6) + style = '-'; +end + +linedef{1} = ['r', style]; +linedef{2} = ['b', style]; +linedef{3} = ['g', style]; +linedef{4} = ['m', style]; +linedef{5} = ['c', style]; +linedef{6} = ['k', style]; +linedef{7} = ['y', style]; + +hold on; + +scale = GetScalingFactors(MODELNAME); +xsc = fittedpars(1:(length(scale)-1))./scale(1:(end-1)); +S_Meas = SynthMeas(MODELNAME, xsc, protocol, fibredir, constants); +Snormdw = S_Meas./b0est; +for j=1:length(protocol.uG) + inds = find(protocol.G == protocol.uG(j) & protocol.delta == protocol.udelta(j) & protocol.smalldel == protocol.usmalldel(j)); + dps = abs(protocol.grad_dirs(inds,:)*fibredir); + [t tinds] = sort(dps); + plot(dps(tinds), Snormdw(inds(tinds)), linedef{j}, 'LineWidth', 2); +end +xlabel('|n.G|/|G|_{max}'); +ylabel('S/S_0'); + diff --git a/NODDI_toolbox_v1.01/fitting/QualityOfFit.m b/NODDI_toolbox_v1.01/fitting/QualityOfFit.m new file mode 100644 index 0000000000000000000000000000000000000000..08a920f1b81089c162f72453a9c304e67e35a5d5 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/QualityOfFit.m @@ -0,0 +1,31 @@ +function [h] = QualityOfFit(signal, fittedpars, model, protocol) +% Assess the quality of fit +% [h] = QualityOfFit(signal, fittedpars, model, protocol); +% +% Typical usage as follows: +% +% 1) First fit the signal +% [gs fgs ml fml] = ThreeStageFittingVoxel(signal, protocol, model); +% +% 2) Now check the quality of fit +% QualityOfFit(signal, ml, model, protocol); +% +% Author: Gary Hui Zhang, PhD +% + +b0 = GetB0(model.name, fittedpars); +fibredir = GetFibreOrientation(model.name, fittedpars); + +h = figure; + +% the data plot +VoxelDataViewer(protocol, signal, fibredir, b0, h); + +% the predicted data plot +% constants is set to zero for NODDI but should be different for +% ActiveAx models +constants = 0; +PlotFittedModel(protocol, model.name, fittedpars, constants, h); + +end + diff --git a/NODDI_toolbox_v1.01/fitting/RemoveNegMeas.m b/NODDI_toolbox_v1.01/fitting/RemoveNegMeas.m new file mode 100644 index 0000000000000000000000000000000000000000..93da4b40cf47ca7275dc3531fa5574a4bf5ca5d1 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/RemoveNegMeas.m @@ -0,0 +1,78 @@ +function [E tempprot] = RemoveNegMeas(Epn, protocol) +% Removes negative or zero measurements from a set and returns a protocol +% with the corresponding elements removed to exclude the negative +% measurements from the fitting. +% +% Epn is the full set of measurements; E is that with the negative ones +% removed. +% +% protocol is the full protocol; tempprot is that with the entries +% corresponding to negative measurements removed. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +tempprot = protocol; +E = Epn; +if(min(Epn)<=0) + posonly = find(Epn>0); + E = Epn(posonly); + nonposonly = setdiff([1:size(Epn,1)], posonly); + tempprot.totalmeas = length(posonly); + + if (isfield(tempprot, 'b0_Indices')) + tempprot.b0_Indices = []; + end + if (isfield(tempprot, 'dti_subset')) + tempprot.dti_subset = []; + end + + for i=1:tempprot.totalmeas + if(isfield(tempprot, 'b0_Indices')) + if ismember(posonly(i), protocol.b0_Indices) + tempprot.b0_Indices = [tempprot.b0_Indices i]; + end + end + if(isfield(tempprot, 'dti_subset')) + if ismember(posonly(i), protocol.dti_subset) + tempprot.dti_subset = [tempprot.dti_subset i]; + end + end + end + if(isfield(tempprot, 'b0_Indices')) + tempprot.numZeros = length(tempprot.b0_Indices); + if length(tempprot.b0_Indices) == 0 + error('All b=0 measurements are negative'); + end + end + + if tempprot.totalmeas - length(tempprot.b0_Indices) < 6 + error('Not enough DWI measurements'); + end + + if(isfield(tempprot, 'dti_subset')) + if length(tempprot.dti_subset) - length(tempprot.b0_Indices) < 6 + error('Not enough DWI measurements'); + end + end + + if(strcmp(tempprot.pulseseq, 'PGSE') || strcmp(tempprot.pulseseq, 'STEAM')) + tempprot.G = tempprot.G(posonly); + tempprot.delta = tempprot.delta(posonly); + tempprot.smalldel = tempprot.smalldel(posonly); + tempprot.grad_dirs = tempprot.grad_dirs(posonly, :); + if(strcmp(tempprot.pulseseq, 'STEAM')) + tempprot.TM = tempprot.TM(posonly); + tempprot.TR = tempprot.TR(posonly); + tempprot.TE = tempprot.TE(posonly); + end + if(isfield(tempprot, 'TE')) + tempprot.TE = tempprot.TE(posonly); + end + else + error('Need to adapt for other pulse sequences.'); + end +end + + diff --git a/NODDI_toolbox_v1.01/fitting/SaveAsNIfTI.m b/NODDI_toolbox_v1.01/fitting/SaveAsNIfTI.m new file mode 100644 index 0000000000000000000000000000000000000000..7b272eb5a1a62080cafa2974637ae9ee6628bb2b --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/SaveAsNIfTI.m @@ -0,0 +1,35 @@ +function SaveAsNIfTI(data, target, output) + +% function SaveAsNIfTI(data, nifti) +% +% Input: +% +% data: the data array to be saved to disk +% +% target: the NIfTI object specifying the target volume specification +% +% output: the filename for the output NIfTI file +% + +% following the example in +% http://niftilib.sourceforge.net/mat_api_html/README.txt +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +dat = file_array; +dat.fname = output; +dat.dim = target.dim; +dat.dtype = 'FLOAT64-LE'; +dat.offset = ceil(348/8)*8; + +N = nifti; +N.dat = dat; +N.mat = target.mat; +N.mat_intent = target.mat_intent; +N.mat0 = target.mat0; +N.mat0_intent = target.mat0_intent; + +create(N); + +N.dat(:,:,:,:) = data; diff --git a/NODDI_toolbox_v1.01/fitting/SaveParamsAsNIfTI.m b/NODDI_toolbox_v1.01/fitting/SaveParamsAsNIfTI.m new file mode 100644 index 0000000000000000000000000000000000000000..afac5892bc3adf784396a1647186cc0416142aeb --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/SaveParamsAsNIfTI.m @@ -0,0 +1,153 @@ +function SaveParamsAsNIfTI(paramsfile, roifile, targetfile, outputpref) +% +% function SaveParamsAsNIfTI(paramsfile, roifile, targetfile, outputpref) +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +% load the fitting results +fprintf('loading the fitted parameters from : %s\n', paramsfile); +load(paramsfile); + +% load the roi file +fprintf('loading the roi from : %s\n', roifile); +load(roifile); + +% load the target volume +fprintf('loading the target volume : %s\n', targetfile); +target = nifti(targetfile); +xsize = target.dat.dim(1); +ysize = target.dat.dim(2); +if length(target.dat.dim) == 2 + zsize = 1; +else + zsize = target.dat.dim(3); +end +total = xsize*ysize*zsize; + +% determine the volumes to be saved +% the number of fitted parameters minus the two fibre orientation +% parameters. +idxOfFitted = find(model.GD.fixed(1:end-2)==0); +noOfVols = length(idxOfFitted); +vols = zeros(total,noOfVols); +% the volume for the objective function values +fobj_ml_vol = zeros(total,1); +% the volume for the error code +error_code_vol = zeros(total,1); +% some special cases +if (strfind(model.name, 'Watson')) + idxOfKappa = find(ismember(model.paramsStr, 'kappa')==1); + odi_vol = zeros(total,1); +end + +% the volumes for the fibre orientations +fibredirs_x_vol = zeros(total,1); +fibredirs_y_vol = zeros(total,1); +fibredirs_z_vol = zeros(total,1); +% compute the fibre orientations from the estimated theta and phi. +fibredirs = GetFibreOrientation(model.name, mlps); + +% determine the volumes with MCMC fitting to be saved +if (model.noOfStages==3) + idxOfFittedMCMC = find(model.MCMC.fixed(1:end-2)==0); + noOfVolsMCMC = length(idxOfFittedMCMC); + volsMCMC = zeros(total,noOfVolsMCMC); + + if (strfind(model.name, 'Watson')) + idxOfKappa = find(ismember(model.paramsStr, 'kappa')==1); + if (model.MCMC.fixed(idxOfKappa)==0) + odi_volMCMC = zeros(total,1); + end + end +end + +% convert to volumetric maps +fprintf('converting the fitted parameters into volumetric maps ...\n'); +for i=1:size(mlps,1) + % compute the index to 3D + volume_index = (idx(i,3)-1)*ysize*xsize + (idx(i,2)-1)*xsize + idx(i,1); + + % fitted parameters other than the fiber orientations + for j=1:length(idxOfFitted) + vols(volume_index,j) = mlps(i, idxOfFitted(j)); + end + + % objective function values + fobj_ml_vol(volume_index) = fobj_ml(i); + + % error codes + error_code_vol(volume_index) = error_code(i); + + % fiber orientations + fibredirs_x_vol(volume_index) = fibredirs(1,i); + fibredirs_y_vol(volume_index) = fibredirs(2,i); + fibredirs_z_vol(volume_index) = fibredirs(3,i); + + % special cases + if (strfind(model.name, 'Watson')) + odi_vol(volume_index) = atan2(1, mlps(i,idxOfKappa)*10)*2/pi; + end + + % MCMC fitted parameters + if (model.noOfStages==3) + for j=1:length(idxOfFittedMCMC) + volsMCMC(volume_index,j) = mean(squeeze(mcmcps(i,:,j))); + end + if (strfind(model.name, 'Watson')) + % Warning: Here we hard-coded the index to kappa!!! + odi_volMCMC(volume_index) = atan2(1, mean(squeeze(mcmcps(i,:,3)))*10)*2/pi; + end + end + +end + +% save as NIfTI +fprintf('Saving the volumetric maps of the fitted parameters ...\n'); + +niftiSpecs.dim = [xsize ysize zsize]; +niftiSpecs.mat = target.mat; +niftiSpecs.mat_intent = target.mat_intent; +niftiSpecs.mat0 = target.mat0; +niftiSpecs.mat0_intent = target.mat0_intent; + +% the fitted parameters other than the fiber orientations +for i=1:length(idxOfFitted) + output = [outputpref '_' cell2mat(model.paramsStr(idxOfFitted(i))) '.nii']; + SaveAsNIfTI(reshape(squeeze(vols(:,i)), [xsize ysize zsize]), niftiSpecs, output); +end + +% the special cases +if (strfind(model.name, 'Watson')) + output = [outputpref '_' 'odi.nii']; + SaveAsNIfTI(reshape(odi_vol, [xsize ysize zsize]), niftiSpecs, output); +end + +% the objective function values +output = [outputpref '_' 'fmin.nii']; +SaveAsNIfTI(reshape(fobj_ml_vol, [xsize ysize zsize]), niftiSpecs, output); + +% the error codes +output = [outputpref '_' 'error_code.nii']; +SaveAsNIfTI(reshape(error_code_vol, [xsize ysize zsize]), niftiSpecs, output); + +% the fibre orientations +output = [outputpref '_' 'fibredirs_xvec.nii']; +SaveAsNIfTI(reshape(fibredirs_x_vol, [xsize ysize zsize]), niftiSpecs, output); +output = [outputpref '_' 'fibredirs_yvec.nii']; +SaveAsNIfTI(reshape(fibredirs_y_vol, [xsize ysize zsize]), niftiSpecs, output); +output = [outputpref '_' 'fibredirs_zvec.nii']; +SaveAsNIfTI(reshape(fibredirs_z_vol, [xsize ysize zsize]), niftiSpecs, output); + +% the MCMC fitted parameters +if (model.noOfStages==3) + for i=1:length(idxOfFittedMCMC) + output = [outputpref '_' cell2mat(model.paramsStr(idxOfFittedMCMC(i))) '_MCMC.nii']; + SaveAsNIfTI(reshape(squeeze(volsMCMC(:,i)), [xsize ysize zsize]), niftiSpecs, output); + end + if (strfind(model.name, 'Watson')) + output = [outputpref '_' 'odi_MCMC.nii']; + SaveAsNIfTI(reshape(odi_volMCMC, [xsize ysize zsize]), niftiSpecs, output); + end +end + diff --git a/NODDI_toolbox_v1.01/fitting/SchemeToProtocol.m b/NODDI_toolbox_v1.01/fitting/SchemeToProtocol.m new file mode 100644 index 0000000000000000000000000000000000000000..45a1c361ab192b71512e730ec9cd6e8d89590017 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/SchemeToProtocol.m @@ -0,0 +1,34 @@ +function protocol = SchemeToProtocol(schemefile) +% +% Reads a Camino Version 1 schemefile into a protocol object +% +% function protocol = SchemeToProtocol(schemefile) +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +fid = fopen(schemefile, 'r', 'b'); + +% Read in the header (assumes one line) +%A = fscanf(fid, '%c', 10); +A = fgetl(fid); + +% Read in the data +A = fscanf(fid, '%f', [7, inf]); + +fclose(fid); + +% Create the protocol +protocol.pulseseq = 'PGSE'; +protocol.grad_dirs = A(1:3,:)'; +protocol.G = A(4,:); +protocol.delta = A(5,:); +protocol.smalldel = A(6,:); +protocol.TE = A(7,:); +protocol.totalmeas = length(A); + +% Find the B0's +bVals = GetB_Values(protocol); +protocol.b0_Indices = find(bVals==0); + diff --git a/NODDI_toolbox_v1.01/fitting/ThreeStageFittingVoxel.m b/NODDI_toolbox_v1.01/fitting/ThreeStageFittingVoxel.m new file mode 100644 index 0000000000000000000000000000000000000000..890594e955c00b011ad727222ac1656d1f7de550 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/ThreeStageFittingVoxel.m @@ -0,0 +1,219 @@ +function [gsps, fobj_gs, mlps, fobj_ml, error_code, ps] = ThreeStageFittingVoxel(Epn, protocol, model, verbose) +% Performs the three stage fitting routine used for the human data in +% Alexander et al NeuroImage 2000. The three stages are grid search, +% maximum likelihood gradient descent and MCMC with a Rician noise model. +% +% function [gsps, fobj_gs, mlps, fobj_ml, error_code, ps] = ThreeStageFittingVoxel(Epn, protocol, model, verbose) +% +% protocol is the measurement protocol. +% +% model is the model structure created with MakeModel +% +% verbose: optional, 1 for printing verbose messages, 0 for quiet (default) +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if nargin < 4 + verbose = 0; +end + +%% Initialization + +warning off all + +% Get the required variables +modelname = model.name; +noOfStages = model.noOfStages; +tissuetype = model.tissuetype; +GS = model.GS; +GD = model.GD; +MCMC = model.MCMC; + +% Initialize the output +error_code = 0; +gsps = zeros(1, model.numParams); +mlps = gsps; +fobj_gs = 0; +fobj_ml = 0; + +% Constants used during grid search and gradient descent +constantsGD.roots_cyl = BesselJ_RootsCyl(30); + +%% First remove non-positive measurements +try + [Epn, protocol] = RemoveNegMeas(Epn, protocol); +catch err + error_code = 1; + disp(err); + return; +end + +%% Determine the sigma +sig = EstimateSigma(Epn, protocol, model); + +%% Grid Search stage + +if verbose + fprintf('Grid Search fitting with %s\n', modelname); +end + +% Set up the search grid +grid = GetSearchGrid(modelname, tissuetype, GS.fixed, GS.fixedvals); + +% Run the grid search +[x0 liks] = GridSearchRician(Epn, modelname, grid, protocol, constantsGD, sig); +gsps = x0(1:(end-1)); +fobj_gs = max(liks); +if verbose + if (strcmp(modelname, 'StickIsoV_B0')) + fprintf('gsps: %5.4f %2.1f %2.1f %5.4f %2.1f %5.1f %5.4f %5.4f : %e\n', gsps, fobj_gs) + elseif (strcmp(modelname, 'StickTortIsoV_B0')) + fprintf('gsps: %5.4f %2.1f %5.4f %2.1f %5.1f %5.4f %5.4f : %e\n', gsps, fobj_gs) + elseif (strcmp(modelname, 'WatsonSHStickTortIsoV_B0')) + fprintf('gsps: %5.4f %2.1f %5.4f %5.4f %2.1f %5.1f %5.4f %5.4f : %e\n', gsps, fobj_gs) + elseif (strcmp(modelname, 'WatsonSHStickTortIsoVIsoDot_B0')) + fprintf('gsps: %5.4f %2.1f %5.4f %5.4f %2.1f %5.4f %5.1f %5.4f %5.4f : %e\n', gsps, fobj_gs) + elseif (strcmp(modelname, 'BinghamStickTortIsoV_B0')) + fprintf('gsps: %5.4f %2.1f %5.4f %5.4f %5.4f %5.4f %2.1f %5.1f %5.4f %5.4f : %e\n', gsps, fobj_gs) + else + disp(fobj_gs); + disp(gsps); + end +end + +if noOfStages == 1 + return; +end + +%% Gradient Descent stage + +if verbose + fprintf('Gradient Descent fitting with %s\n', modelname); +end + +h=optimset('Algorithm', 'active-set', 'Display', 'iter', 'MaxIter',100,... + 'MaxFunEvals',20000,'TolX',1e-6,... + 'TolFun',1e-6,'GradObj','off', 'Hessian', 'off', 'FunValCheck',... + 'on', 'Display', 'off');%,'DerivativeCheck','on'); + +% Convert from actual parameters to optimized quantities that enforce +% constraints. +startx = GradDescEncode(modelname, gsps); +fobj_ml = fobj_gs; +mlps = gsps; +if (strcmp(GD.type, 'multistart')) + noOfIterations = GD.multistart.noOfRuns; + perturbation = GD.multistart.perturbation; + if isempty(find(perturbation~=0, 1)) + error('multistart mode: at least one perturbation should be nonzero'); + else + perturbation(GD.fixed==1) = 0; + end + if verbose + fprintf('Multistart fitting with %i trials\n', noOfIterations); + fprintf('Parameter perturbation adjusted for fixed variables'); + end +else + noOfIterations = 1; +end + +% Get limits and constraints for gradient descent +[MinValGD MaxValGD] = GradDescLimits(modelname); + +% Get orientation dispersion index, if applicable +kappaIdx = GetParameterIndex(modelname, 'kappa'); + +for i=1:noOfIterations + if i==1 + parameter_input = startx; + else + parameter_input = startx.*(1 + perturbation.*randn(1,length(perturbation))); + end + + try + % optimize with orientation fixed + fixedGD = GD.fixed; + fixedGD(end-1:end) = 1; + % if kappa is a parameter, fix it first as well + if (kappaIdx ~= -1) + fixedGD(kappaIdx) = 1; + end + % Account for any fixed parameters + fittedMinValGD = MinValGD(fixedGD==0); + fittedMaxValGD = MaxValGD(fixedGD==0); + [parameter_hat,RESNORM,EXITFLAG,OUTPUT]=fmincon_fix(fixedGD, 'fobj_rician_fix',... + parameter_input,[],[],[],[],fittedMinValGD,fittedMaxValGD,[],h,Epn,protocol, modelname, sig, constantsGD); + parameter_input = parameter_hat; + + % now optimize all free variables + % Account for any fixed parameters + fittedMinValGD = MinValGD(GD.fixed==0); + fittedMaxValGD = MaxValGD(GD.fixed==0); + [parameter_hat,RESNORM,EXITFLAG,OUTPUT]=fmincon_fix(GD.fixed, 'fobj_rician_fix',... + parameter_input,[],[],[],[],fittedMinValGD,fittedMaxValGD,[],h,Epn,protocol, modelname, sig, constantsGD); + + if (-RESNORM > fobj_ml) + fobj_ml = -RESNORM; + mlps = GradDescDecode(modelname, parameter_hat); + end + if (verbose) + disp(fobj_ml); + end + catch err + error_code = 2; + disp(err); + return; + end + +end + +if verbose + if (strcmp(modelname, 'StickIsoV_B0')) + fprintf('mlps: %5.4f %2.1f %2.1f %5.4f %2.1f %5.1f %5.4f %5.4f : %e\n', mlps, fobj_ml) + elseif (strcmp(modelname, 'StickTortIsoV_B0')) + fprintf('mlps: %5.4f %2.1f %5.4f %2.1f %5.1f %5.4f %5.4f : %e\n', mlps, fobj_ml) + elseif (strcmp(modelname, 'WatsonSHStickTortIsoV_B0')) + fprintf('mlps: %5.4f %2.1f %5.4f %5.4f %2.1f %5.1f %5.4f %5.4f : %e\n', mlps, fobj_ml) + elseif (strcmp(modelname, 'WatsonSHStickTortIsoVIsoDot_B0')) + fprintf('mlps: %5.4f %2.1f %5.4f %5.4f %2.1f %5.4f %5.1f %5.4f %5.4f : %e\n', mlps, fobj_ml) + elseif (strcmp(modelname, 'BinghamStickTortIsoV_B0')) + fprintf('mlps: %5.4f %2.1f %5.4f %5.4f %5.4f %5.4f %2.1f %5.1f %5.4f %5.4f : %e\n', mlps, fobj_ml) + else + disp(fobj_ml); + disp(mlps); + end +end + +if noOfStages == 2 + return; +end + +%% MCMC stage + +if verbose + fprintf('MCMC fitting with %s\n', modelname); +end + +% Get limits and constraints for MCMC +[MinValMCMC MaxValMCMC] = MCMC_Limits(modelname); + +% MCMC parameters +steplengths = MCMC.steplengths; +burnin = MCMC.burnin; +interval = MCMC.interval; +samples = MCMC.samples; + +% Constants used during MCMC +constantsMCMC.roots_cyl = BesselJ_RootsCyl(20); + +% Run the MCMC procedure +x0t = [mlps sig]; + +ps(:,:) = RicianMCMC(Epn, x0t, modelname, protocol, MinValMCMC, MaxValMCMC, constantsMCMC, MCMC.fixed, steplengths, burnin, samples, interval); +mcmcps = squeeze(mean(ps,1)); + +if verbose + disp(mcmcps); +end diff --git a/NODDI_toolbox_v1.01/fitting/VoxelDataViewer.m b/NODDI_toolbox_v1.01/fitting/VoxelDataViewer.m new file mode 100644 index 0000000000000000000000000000000000000000..0cc24faaf308bd73e83c60e51d8a8093757812c0 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/VoxelDataViewer.m @@ -0,0 +1,70 @@ +function VoxelDataViewer(protocol, data, fibredir, b0, h, style) +% Plots the normalized measurements in one image voxel against the +% absolute dot product of the gradient and fibre directions. +% +% VoxelDataViewer(protocol, data, fibredir, b0, h) +% brings up a window containing the plot. +% +% protocol is the imaging protocol. +% +% data is the set of measurements in the voxel. +% +% fibredir is an estimate of the fibre direction in that voxel. By default +% this is set to the z-axis +% +% b0 is an estimate of the b=0 signal. By default, this is set to one. +% +% h is a figure handle to add the plot to. If not specified, a new figure +% appears. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if(nargin<3) + fibredir = [0 0 1]'; +end +if(nargin<4) + b0=1; +end +if(nargin<5) + h = figure; +end + +% Compute b-values +GAMMA = 2.675987E8; +modQ = GAMMA*protocol.usmalldel.*protocol.uG; +diffTime = (protocol.udelta - protocol.usmalldel/3); +bvals = diffTime.*modQ.^2; + +% Create normalized data set. +normdw = data/b0; + +if(nargin<6) + style = 'x'; +end + +linedef{1} = ['r', style]; +linedef{2} = ['b', style]; +linedef{3} = ['g', style]; +linedef{4} = ['m', style]; +linedef{5} = ['c', style]; +linedef{6} = ['k', style]; +linedef{7} = ['y', style]; + +hold on; +set(gca, 'FontName', 'Times'); +set(gca, 'FontSize', 17); +for j=1:length(protocol.uG) + inds = find(protocol.G == protocol.uG(j) & protocol.delta == protocol.udelta(j) & protocol.smalldel == protocol.usmalldel(j)); + scatter(abs(protocol.grad_dirs(inds,:)*fibredir), normdw(inds), linedef{j}); +end +xlabel('|n.G|/|G|_{max}'); +ylabel('S/S_0'); +%ylim([0,b0*1.1]); + +% Add b=0 measurements +b0_meas = data(protocol.b0_Indices); +for b=1:length(b0_meas) + h(1) = plot([0 1], [b0_meas(b)/b0 b0_meas(b)/b0], ':k'); +end diff --git a/NODDI_toolbox_v1.01/fitting/batch_fitting.m b/NODDI_toolbox_v1.01/fitting/batch_fitting.m new file mode 100644 index 0000000000000000000000000000000000000000..5806ea9ccaf12869de864e31e37551f1c59494dd --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/batch_fitting.m @@ -0,0 +1,130 @@ +function batch_fitting(roifile, protocol, model, outputfile, poolsize) + +% +% function batch_fitting(roifile, protocol, model, outputfile, poolsize) +% +% This function does batch fitting to the voxels in an entire ROI created with +% CreateROI function. +% +% Input: +% +% roifile: the ROI file created with CreateROI +% +% protocol: the protocol object created with FSL2Protocol +% +% model: the model object created with MakeModel +% +% outputfile: the name of the mat file to store the fitted parameters +% +% poolsize (optional): the number of parallel processes to run +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +% first check if there is a file there to resume +if exist(outputfile, 'file') + load(outputfile); + if exist('split_end', 'var') + % previously run and need to be restarted + current_split_start = split_end + 1; + fprintf('Resume an interrupted run from %i\n', current_split_start); + else + % completed + fprintf('An output file of the same name detected.\n'); + fprintf('Choose a different output file name.\n'); + return; + end +else + % if this is the first run + current_split_start = 1; +end + +% initiate the parallel environment if necessary +pool = gcp('nocreate'); +if isempty(pool) + if (nargin < 5) + pool = parpool('local'); + else + pool = parpool('local', poolsize); + end +end + +% load the roi file +load(roifile); +numOfVoxels = size(roi,1); + +% set up the fitting parameter variables if it is the first run +if current_split_start == 1 + gsps = zeros(numOfVoxels, model.numParams); + mlps = zeros(numOfVoxels, model.numParams); + fobj_gs = zeros(numOfVoxels, 1); + fobj_ml = zeros(numOfVoxels, 1); + error_code = zeros(numOfVoxels, 1); + if model.noOfStages == 3 + mcmcps = zeros(numOfVoxels, model.MCMC.samples, model.numParams + 1); + end +end + +% set up the PARFOR Progress Monitor +[mypath myname myext] = fileparts(mfilename('fullpath')); +mypath = [mypath '/../ParforProgMonv2/java']; +pctRunOnAll(['javaaddpath ' mypath]); +progressStepSize = 100; +ppm = ParforProgMon(['Fitting ' roifile, ' : '], numOfVoxels-current_split_start+1,... + progressStepSize, 400, 80); + +tic + +fprintf('%i of voxels to fit\n', numOfVoxels-current_split_start+1); + +% start the parallel fitting +for split_start=current_split_start:progressStepSize:numOfVoxels + % set up the split end + split_end = split_start + progressStepSize - 1; + if split_end > numOfVoxels + split_end = numOfVoxels; + end + + % fit the split + parfor i=split_start:split_end + + % get the MR signals for the voxel i + voxel = roi(i,:)'; + + % fit the voxel + if model.noOfStages == 2 + [gsps(i,:), fobj_gs(i), mlps(i,:), fobj_ml(i), error_code(i)] = ThreeStageFittingVoxel(voxel, protocol, model); + else + [gsps(i,:), fobj_gs(i), mlps(i,:), fobj_ml(i), error_code(i), mcmcps(i,:,:)] = ThreeStageFittingVoxel(voxel, protocol, model); + end + + % report to the progress monitor + if mod(i, progressStepSize)==0 + ppm.increment(); + end + + end + + % save the temporary results of the split + if model.noOfStages == 2 + save(outputfile, 'split_end', 'model', 'gsps', 'fobj_gs', 'mlps', 'fobj_ml', 'error_code'); + else + save(outputfile, 'split_end', 'model', 'gsps', 'fobj_gs', 'mlps', 'fobj_ml', 'mcmcps', 'error_code'); + end + +end + +toc + +ppm.delete(); + +% save the fitted parameters +if model.noOfStages == 2 + save(outputfile, 'model', 'gsps', 'fobj_gs', 'mlps', 'fobj_ml', 'error_code'); +else + save(outputfile, 'model', 'gsps', 'fobj_gs', 'mlps', 'fobj_ml', 'mcmcps', 'error_code'); +end + +% close the parallel pool +delete pool; + diff --git a/NODDI_toolbox_v1.01/fitting/batch_fitting_single.m b/NODDI_toolbox_v1.01/fitting/batch_fitting_single.m new file mode 100644 index 0000000000000000000000000000000000000000..9b7c92e7fada75ff8d081dd3deaeae7a15f80640 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/batch_fitting_single.m @@ -0,0 +1,95 @@ +function batch_fitting_single(roifile, protocol, model, outputfile) + +% +% function batch_fitting_single(roifile, protocol, model, outputfile) +% +% This function does batch fitting to the voxels in an entire ROI created with +% CreateROI function. +% +% Input: +% +% roifile: the ROI file created with CreateROI +% +% protocol: the protocol object created with FSL2Protocol +% +% model: the model object created with MakeModel +% +% outputfile: the name of the mat file to store the fitted parameters +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + + +% first check if there is a file there to resume +if exist(outputfile, 'file') + load(outputfile); + if exist('current_index', 'var') + % previously run and need to be restarted + current_index = current_index + 1; + fprintf('Resume an interrupted run from voxel %i\n', current_index); + else + % completed + fprintf('An output file of the same name detected.\n'); + fprintf('Choose a different output file name.\n'); + return; + end +else + % if this is the first run + current_index = 1; +end + +% load the roi file +load(roifile); +numOfVoxels = size(roi,1); + +% set up the fitting parameter variables if it is the first run +if current_index == 1 + gsps = zeros(numOfVoxels, model.numParams); + mlps = zeros(numOfVoxels, model.numParams); + fobj_gs = zeros(numOfVoxels, 1); + fobj_ml = zeros(numOfVoxels, 1); + error_code = zeros(numOfVoxels, 1); + if model.noOfStages == 3 + mcmcps = zeros(numOfVoxels, model.MCMC.samples, model.numParams + 1); + end +end + +tic + +fprintf('%i of voxels to fit\n', numOfVoxels-current_index+1); + +% start the parallel fitting +for i=current_index:numOfVoxels + + fprintf('Fitting voxel %i\n', i); + + % get the MR signals for the voxel i + voxel = roi(i,:)'; + + % fit the voxel + if model.noOfStages == 2 + [gsps(i,:), fobj_gs(i), mlps(i,:), fobj_ml(i), error_code(i)] = ThreeStageFittingVoxel(voxel, protocol, model); + else + [gsps(i,:), fobj_gs(i), mlps(i,:), fobj_ml(i), error_code(i), mcmcps(i,:,:)] = ThreeStageFittingVoxel(voxel, protocol, model); + end + + % save the temporary results + if mod(i, 100)==0 + current_index = i; + if model.noOfStages == 2 + save(outputfile, 'current_index', 'model', 'gsps', 'fobj_gs', 'mlps', 'fobj_ml', 'error_code'); + else + save(outputfile, 'current_index', 'model', 'gsps', 'fobj_gs', 'mlps', 'fobj_ml', 'mcmcps', 'error_code'); + end + end + +end + +toc + +% save the fitted parameters +if model.noOfStages == 2 + save(outputfile, 'model', 'gsps', 'fobj_gs', 'mlps', 'fobj_ml', 'error_code'); +else + save(outputfile, 'model', 'gsps', 'fobj_gs', 'mlps', 'fobj_ml', 'mcmcps', 'error_code'); +end diff --git a/NODDI_toolbox_v1.01/fitting/fmincon_fix.m b/NODDI_toolbox_v1.01/fitting/fmincon_fix.m new file mode 100644 index 0000000000000000000000000000000000000000..3ed93ba3478f39d3c52f6c401b095019cd676fe2 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/fmincon_fix.m @@ -0,0 +1,23 @@ +function [x,fval,exitflag,output,lambda,grad,hessian] = fmincon_fix(fix,fun,x0,A,b,Aeq,beq,lb,ub,nonlcon,options,varargin) +% Wrapper for fmincon that allows the user to specify a number of model +% parameters that remain fixed to the initial settings. +% +% fix is a binary array. Zero indicates that the parameter in the +% corresponding position in x0 varies during fitting; one indicates that +% the value remains fixed at the alue in x0. +% +% The other parameters are all as for fmincon. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +% Construct the parameter vector with fixed values removed. +x0f = x0(find(fix==0)); + +% Run the opt. +[x,fval,exitflag,output,lambda,grad,hessian] = fmincon(fun,x0f,A,b,Aeq,beq,lb,ub,nonlcon,options,varargin{:}, fix, x0); + +% Reconstruct the full fitted parameter list including the fixed values. +xf = fix.*x0; +xf(find(fix==0)) = x; +x = xf; diff --git a/NODDI_toolbox_v1.01/fitting/fobj_rician.m b/NODDI_toolbox_v1.01/fitting/fobj_rician.m new file mode 100644 index 0000000000000000000000000000000000000000..7acb8c74ddae85f3a7ef22a37ed99f9d2a50bf36 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/fobj_rician.m @@ -0,0 +1,43 @@ +function [sumRes, resJ, H]=fobj_rician(x, meas, protocol, model, sig, constants) +% Objective function for fitting models using a Rician noise model. +% +% x is the encoded model parameter values +% +% meas is the measurements +% +% protocol is the measurement protocol +% +% model is a string encoding the model +% +% sig is the standard deviation of the Gaussian distributions underlying +% the Rician noise +% +% constants contains values required to compute the model signals. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +% Need to transform to actual parameter values from optimized quantities. +xdec = GradDescDecode(model, x); + +scale = GetScalingFactors(model); +if (strcmp(model, 'ExCrossingCylSingleRadGPD') ||... + strcmp(model, 'ExCrossingCylSingleRadIsoDotTortIsoV_GPD_B0')) + xsc = xdec(1:(end-4))./scale(1:(end-1)); + theta = [xdec(end-3) xdec(end-1)]'; + phi = [xdec(end-2) xdec(end)]'; + fibredir = [cos(phi).*sin(theta) sin(phi).*sin(theta) cos(theta)]'; +else + xsc = xdec(1:(end-2))./scale(1:(end-1)); + theta = xdec(end-1); + phi = xdec(end); + fibredir = [cos(phi)*sin(theta) sin(phi)*sin(theta) cos(theta)]'; +end + +if(nargout == 1) + sumRes = fobj_rician_st(xsc, meas, protocol, model, sig, fibredir, constants); +elseif(nargout == 2) + [sumRes resJ] = fobj_rician_st(xsc, meas, protocol, model, sig, fibredir, constants); +else + [sumRes, resJ, H] = fobj_rician_st(xsc, meas, protocol, model, sig, fibredir, constants); +end diff --git a/NODDI_toolbox_v1.01/fitting/fobj_rician_fix.m b/NODDI_toolbox_v1.01/fitting/fobj_rician_fix.m new file mode 100644 index 0000000000000000000000000000000000000000..2d9231dbb02d6cddfa40a76072a5c1cb37a85ca5 --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/fobj_rician_fix.m @@ -0,0 +1,36 @@ +function [sumRes, resJ, H]=fobj_rician_fix(x, meas, protocol, model, sig, constants, fix, x0) +% Wrapper for fobj_rician for use with fmincon_fix. +% +% x is the encoded model parameter values +% +% meas is the measurements +% +% protocol is the measurement protocol +% +% model is a string encoding the model +% +% sig is the standard deviation of the Gaussian distributions underlying +% the Rician noise +% +% constants contains values required to compute the model signals. +% +% fix is a binary array specifying which parameters are fixed and which +% vary. +% +% x0 is the full starting point including the fixed parameters. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +% Construct the full parameter list including fixed values. +xf = fix.*x0; +xf(find(fix==0)) = x; + +% Now call the full objective function. +if(nargout == 1) + sumRes = fobj_rician(xf, meas, protocol, model, sig, constants); +elseif(nargout == 2) + [sumRes resJ] = fobj_rician(xf, meas, protocol, model, sig, constants); +else + [sumRes, resJ, H] = fobj_rician(xf, meas, protocol, model, sig, constants); +end diff --git a/NODDI_toolbox_v1.01/fitting/fobj_rician_st.m b/NODDI_toolbox_v1.01/fitting/fobj_rician_st.m new file mode 100644 index 0000000000000000000000000000000000000000..8206c3cb186212bf068c5c527f62826b2428d4ab --- /dev/null +++ b/NODDI_toolbox_v1.01/fitting/fobj_rician_st.m @@ -0,0 +1,69 @@ +function [sumRes, resJ, H] = fobj_rician_st(xsc, meas, protocol, model, sig, fibredir, constants) +% General function called by variants of fobj_rician once fibre direction +% has been extracted and other parameters scaled appropriately. +% +% xsc is the decoded model parameter values +% +% meas is the measurements +% +% protocol is the measurement protocol +% +% model is a string encoding the model +% +% sig is the standard deviation of the Gaussian distributions underlying +% the Rician noise +% +% fibredir is the fibre direction extracted from the full parameter list. +% +% constants contains values required to compute the model signals. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +E = SynthMeas(model, xsc, protocol, fibredir, constants); + +% Find the fitting error (log probabilities of the data given the parameter +% settings). +sumRes = -RicianLogLik(meas, E, sig); + +if(nargout>1) + % Construct the Jacobian of the probabilities from the Jacobian of the + % measurement estimates. + scp = meas.*signals./(sig.^2); + ysc = besseli1d0(scp); + sc = (E - meas.*ysc)./(sig.^2); + J = zeros(length(E), length(x)); + for i=1:(length(x)-1) + J(:,i) = sc.*Jnn(:,i); + end + + % Need to rescale the derivates to the scale of x + J = J./repmat(scale(1:(end-1)),[length(E),1]); + + % Now sum over the measurements + resJ = sum(J); +end + +% Finally create the Hessian matrix. Here in fact we use the Fisher +% information matrix instead to reduce computation and increase stability +% and convergence. Code is the same as FishMatRician.m. +% if(nargout>2) +% global RicCorX RicCorY; +% +% C = zeros(length(E),1); +% Esc = E/sig; +% out = find(Esc>=max(RicCorX)); +% in = find(Esc<max(RicCorX)); +% C(in) = interp1(RicCorX, RicCorY, Esc(in))*sig^2; +% C(out) = sig^2; +% JCor = Jnn.*repmat(C, [1,length(x)-1]); +% +% H = Jnn'*JCor/(sig^4); +% +% % Now compute the elements that depend on sigma. +% Jsig = Jnn.*repmat(sig^2*E + E.^3 + 2*E.*C, [1,length(x)-1]); +% H(length(x), 1:(length(x)-1)) = -2*sum(Jsig)/(sig^5); +% H(1:(length(x)-1), length(x)) = squeeze(H(length(x), 1:(length(x)-1))'); +% +% H(length(x), length(x)) = -4*sum(-sig^4 + sig^2*E.^2 - E.^2.*C)/(sig^6); +% end diff --git a/NODDI_toolbox_v1.01/models/BesselJ_RootsCyl.m b/NODDI_toolbox_v1.01/models/BesselJ_RootsCyl.m new file mode 100644 index 0000000000000000000000000000000000000000..4ca982b30542caf5ed9fc80e7e46db5365c0f308 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/BesselJ_RootsCyl.m @@ -0,0 +1,31 @@ +function root = BesselJ_RootsCyl(starts) +% BesselJ_RootsCyl(starts) finds the roots of the equation J'_1(x) = 0 +% where J_1 is the first order Bessel function of the first kind. +% +% starts is the number of starting points in the search for +% roots. The larger it is, the more roots are returned in the root array. +% The default is 20, which returns 6 roots. starts = 100 returns 32 roots. +% Generally the number of roots is just under 1/3 the number of starting +% points. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +if(nargin==0) + starts = 20; +end + +f = @(x)(0.5*(besselj(0,x) - besselj(2,x))); + +% Get a good list of starting points +y = 0:0.1:starts; +dj1 = f(y); +starts = (find(dj1(1:end-1).*dj1(2:end)<0)+1)*0.1; + +for s=1:length(starts) + root(s) = fzero(f,starts(s)); +end + + + + diff --git a/NODDI_toolbox_v1.01/models/CylNeumanLePar_PGSE.m b/NODDI_toolbox_v1.01/models/CylNeumanLePar_PGSE.m new file mode 100644 index 0000000000000000000000000000000000000000..2db0dd634836337d0ac1dcfa76910bc97eff8191 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/CylNeumanLePar_PGSE.m @@ -0,0 +1,42 @@ +function [LE,J]=CylNeumanLePar_PGSE(x, G, delta, smalldel) +% Substrate: Parallel, impermeable cylinders with one radius in an empty +% background. +% Pulse sequence: Pulsed gradient spin echo +% Signal approximation: Gaussian phase distribution. +% +% [LE,J]=CylNeumanLePar_PGSE(x, G, delta, smalldel) +% returns the log signal attenuation in parallel direction (LePar) according +% to the Neuman model and the Jacobian J of LePar with respect to the +% parameters. The Jacobian does not include derivates with respect to the +% fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the diffusivity of the material inside the cylinders. +% +% G, delta and smalldel are the gradient strength, pulse separation and +% pulse length of each measurement in the protocol. Each has +% size [N 1]. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +d=x(1); + +% Radial wavenumbers +GAMMA = 2.675987E8; +modQ = GAMMA*smalldel.*G; +modQ_Sq = modQ.^2; + +% diffusion time for PGSE, in a matrix for the computation below. +difftime = (delta-smalldel/3); + +% Parallel component +LE =-modQ_Sq.*difftime*d; + +% Compute the Jacobian matrix +if(nargout>1) + % dLE/d + J = -modQ_Sq.*difftime; +end + diff --git a/NODDI_toolbox_v1.01/models/CylNeumanLePerp_PGSE.m b/NODDI_toolbox_v1.01/models/CylNeumanLePerp_PGSE.m new file mode 100644 index 0000000000000000000000000000000000000000..466cdc7badf092505c3a83d223059368c458691c --- /dev/null +++ b/NODDI_toolbox_v1.01/models/CylNeumanLePerp_PGSE.m @@ -0,0 +1,137 @@ +function [LE,J]=CylNeumanLePerp_PGSE(d, R, G, delta, smalldel, roots) +% Substrate: Parallel, impermeable cylinders with one radius in an empty +% background. +% Pulse sequence: Pulsed gradient spin echo +% Signal approximation: Gaussian phase distribution. +% +% [LE,J] = CylNeumanLePerp_PGSE(d, R, G, delta, smalldel, roots) +% +% returns the log signal attenuation in perpendicular direction (LePerp) for +% EACH RADIUS specified in R according to the Neuman model and the Jacobian J +% of LePerp with respect to the parameters. +% +% The Jacobian DOES NOT include derivates with respect to the fibre direction. +% +% d is the diffusivity of the material inside the cylinders. +% +% R is the list of the radii of the cylinders. It has size [1 m] where m is the +% number of radii. +% +% G, delta and smalldel are the gradient strength, pulse separation and +% pulse length of each measurement in the protocol. Each has +% size [N 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +% When R=0, no need to do any calculation +if (R == 0.00) + LE = zeros(size(G,1), size(R,2)); + J = zeros([size(LE), 2]); + J(:,:,:) = 0; + return; +end + +% Check the roots array is correct +if(abs(roots(1) - 1.8412)>0.0001) + error('Looks like the roots array is wrong. First value should be 1.8412, but is %f', roots(1)); +end + +% Radial wavenumbers +GAMMA = 2.675987E8; + +% number of gradient directions, i.e. number of measurements +l_q=size(G,1); +l_a=numel(R); +k_max=numel(roots); + +R_mat=repmat(R,[l_q 1]); +R_mat=R_mat(:); +R_mat=repmat(R_mat,[1 1 k_max]); +R_matSq=R_mat.^2; + +root_m=reshape(roots,[1 1 k_max]); +alpha_mat=repmat(root_m,[l_q*l_a 1 1])./R_mat; +amSq=alpha_mat.^2; +amP6=amSq.^3; + +deltamx=repmat(delta,[1,l_a]); +deltamx_rep = deltamx(:); +deltamx_rep = repmat(deltamx_rep,[1 1 k_max]); + +smalldelmx=repmat(smalldel,[1,l_a]); +smalldelmx_rep = smalldelmx(:); +smalldelmx_rep = repmat(smalldelmx_rep,[1 1 k_max]); + +Gmx=repmat(G,[1,l_a]); +GmxSq = Gmx.^2; + +% Perpendicular component (Neuman model) +sda2 = smalldelmx_rep.*amSq; +bda2 = deltamx_rep.*amSq; +emdsda2 = exp(-d*sda2); +emdbda2 = exp(-d*bda2); +emdbdmsda2 = exp(-d*(bda2 - sda2)); +emdbdpsda2 = exp(-d*(bda2 + sda2)); + +sumnum1 = 2*d*sda2; +% the rest can be reused in dE/dR +sumnum2 = - 2 + 2*emdsda2 + 2*emdbda2; +sumnum2 = sumnum2 - emdbdmsda2 - emdbdpsda2; +sumnum = sumnum1 + sumnum2; + +sumdenom = d^2*amP6.*(R_matSq.*amSq - 1); + +% Check for zeros on top and bottom +%sumdenom(find(sumnum) == 0) = 1; +sumterms = sumnum./sumdenom; + +testinds = find(sumterms(:,:,end)>0); +test = sumterms(testinds,1)./sumterms(testinds,end); +if(min(test)<1E4) + warning('Ratio of largest to smallest terms in Neuman model sum is <1E4. May need more terms.'); +end + +s = sum(sumterms,3); +s = reshape(s,[l_q,l_a]); +if(min(s)<0) + warning('Negative sums found in Neuman sum. Setting to zero.'); + s(find(s<0))=0; +end + +LE = -2*GAMMA^2*GmxSq.*s; + +% Compute the Jacobian matrix +if(nargout>1) + + % dLE/dd + sumnumD = 2*sda2; + sumnumD = sumnumD - 2*sda2.*emdsda2; + sumnumD = sumnumD - 2*bda2.*emdbda2; + sumnumD = sumnumD + (bda2 - sda2).*emdbdmsda2; + sumnumD = sumnumD + (bda2 + sda2).*emdbdpsda2; + sumtermsD = sumnumD./sumdenom; + + sD = sum(sumtermsD,3); + sD = reshape(sD,[l_q,l_a]); + + dLEdd = -2*GAMMA^2*GmxSq.*(sD - 2*s/d); + + % dLE/dR + sumtermsR = (6*sumterms - 2*d*sumtermsD)./R_mat; + + sR = sum(sumtermsR,3); + sR = reshape(sR,[l_q,l_a]); + + dLEdr = -2*GAMMA^2*GmxSq.*sR; + + % Construct the jacobian matrix. + J = zeros([size(LE), 2]); + J(:,:,1) = dLEdd; + J(:,:,2) = dLEdr; +end + diff --git a/NODDI_toolbox_v1.01/models/GetB0.m b/NODDI_toolbox_v1.01/models/GetB0.m new file mode 100644 index 0000000000000000000000000000000000000000..65696598b76b42ad0fa09459136df95765858955 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/GetB0.m @@ -0,0 +1,16 @@ +function b0 = GetB0(modelname, fittedpars) +% +% function b0 = GetB0(modelname, fittedpars) +% +% Returns the b=0 signal estimate. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +b0Idx = GetParameterIndex(modelname, 'b0'); +if b0Idx > 0 + b0 = fittedpars(b0Idx); +else + b0 = 1; +end + diff --git a/NODDI_toolbox_v1.01/models/GetB_Values.m b/NODDI_toolbox_v1.01/models/GetB_Values.m new file mode 100644 index 0000000000000000000000000000000000000000..660aff310fba8395452422a93646d6e66ceec1e2 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/GetB_Values.m @@ -0,0 +1,25 @@ +function b = GetB_Values(protocol) +% Computes the b value for each measurement in the protocol +% +% b = GetB_Values(protocol) +% returns an array of b values, one for each measurement defined +% in the list of measurements in the protocol. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +GAMMA = 2.675987E8; +if(strcmp(protocol.pulseseq, 'PGSE') || strcmp(protocol.pulseseq, 'STEAM')) + modQ = GAMMA*protocol.smalldel.*protocol.G; + diffTime = protocol.delta - protocol.smalldel/3; + b = diffTime.*modQ.^2; + +elseif(strcmp(protocol.pulseseq, 'DSE')) + b = getB_ValuesDSE(protocol.G, protocol.delta1, protocol.delta2, protocol.delta3, protocol.t1, protocol.t2, protocol.t3); + +elseif(strcmp(protocol.pulseseq, 'OGSE')) + b = GetB_ValuesOGSE(protocol.G, protocol.delta, protocol.smalldel, protocol.omega); +end + + + diff --git a/NODDI_toolbox_v1.01/models/GetFibreOrientation.m b/NODDI_toolbox_v1.01/models/GetFibreOrientation.m new file mode 100644 index 0000000000000000000000000000000000000000..3053520dd81decc7f672ba3c2c1ea8328865b51c --- /dev/null +++ b/NODDI_toolbox_v1.01/models/GetFibreOrientation.m @@ -0,0 +1,14 @@ +function fibredir = GetFibreOrientation(modelname, fittedpars) +% +% function fibredir = GetFibreOrientation(modelname, fittedpars) +% +% Returns the fibre orientation as a unit vector from fitted parameters. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +theta = fittedpars(:, GetParameterIndex(modelname, 'theta')); +phi = fittedpars(:, GetParameterIndex(modelname, 'phi')); + +fibredir = [cos(phi).*sin(theta) sin(phi).*sin(theta) cos(theta)]'; + diff --git a/NODDI_toolbox_v1.01/models/GetParameterIndex.m b/NODDI_toolbox_v1.01/models/GetParameterIndex.m new file mode 100644 index 0000000000000000000000000000000000000000..2cac511c7d4610f75544df5b058a91a17318d4c0 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/GetParameterIndex.m @@ -0,0 +1,20 @@ +function idx = GetParameterIndex(modelname, parametername) +% +% function idx = GetParameterIndex(modelname, parametername) +% +% Given an input modelname and parametername, this function returns the index +% of the parameter within the model. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +strings = GetParameterStrings(modelname); + +for i=1:length(strings) + if (strcmp(strings(i), parametername)) + idx = i; + return; + end +end + +idx = -1; diff --git a/NODDI_toolbox_v1.01/models/GetParameterStrings.m b/NODDI_toolbox_v1.01/models/GetParameterStrings.m new file mode 100644 index 0000000000000000000000000000000000000000..ef3c4b29d8cad4e0552404e99c5173ab90159f9b --- /dev/null +++ b/NODDI_toolbox_v1.01/models/GetParameterStrings.m @@ -0,0 +1,34 @@ +function strings = GetParameterStrings(modelname) +% +% function strings = GetParameterStrings(modelname) +% +% Given an input modelname, this function returns the names of the model +% parameters +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if (strcmp(modelname, 'StickIsoV_B0')) + strings = {'ficvf', 'di', 'dh', 'fiso', 'diso', 'b0', 'theta', 'phi'}; +elseif (strcmp(modelname, 'StickTortIsoV_B0')) + strings = {'ficvf', 'di', 'fiso', 'diso', 'b0', 'theta', 'phi'}; +elseif (strcmp(modelname, 'WatsonSHStick')) + strings = {'ficvf', 'di', 'dh', 'kappa', 'theta', 'phi'}; +elseif (strcmp(modelname, 'WatsonSHStickIsoV_B0')) + strings = {'ficvf', 'di', 'dh', 'kappa', 'fiso', 'diso', 'b0', 'theta', 'phi'}; +elseif (strcmp(modelname, 'WatsonSHStickIsoVIsoDot_B0')) + strings = {'ficvf', 'di', 'dh', 'kappa', 'fiso', 'diso', 'irfrac', 'b0', 'theta', 'phi'}; +elseif (strcmp(modelname, 'WatsonSHStickTortIsoV_B0')) + strings = {'ficvf', 'di', 'kappa', 'fiso', 'diso', 'b0', 'theta', 'phi'}; +elseif (strcmp(modelname, 'WatsonSHStickTortIsoVIsoDot_B0')) + strings = {'ficvf', 'di', 'kappa', 'fiso', 'diso', 'irfrac', 'b0', 'theta', 'phi'}; +elseif (strcmp(modelname, 'BinghamStickTortIsoV_B0')) + strings = {'ficvf', 'di', 'kappa', 'beta', 'psi', 'fiso', 'diso', 'b0', 'theta', 'phi'}; +elseif (strcmp(modelname, 'WatsonSHCylSingleRadTortIsoV_GPD_B0')) + strings = {'ficvf', 'di', 'rad', 'kappa', 'fiso', 'diso', 'b0', 'theta', 'phi'}; +elseif (strcmp(modelname, 'CylSingleRadIsoDotTortIsoV_GPD_B0')) + strings = {'ficvf', 'di', 'rad', 'irfrac', 'fiso', 'diso', 'b0', 'theta', 'phi'}; +else + error(['Parameter strings yet to be defined for this model:', modelname]); +end + diff --git a/NODDI_toolbox_v1.01/models/GetScalingFactors.m b/NODDI_toolbox_v1.01/models/GetScalingFactors.m new file mode 100644 index 0000000000000000000000000000000000000000..d40f1dcaba94d84ab7c6c01687c80353aab0b923 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/GetScalingFactors.m @@ -0,0 +1,44 @@ +function scale = GetScalingFactors(modelname) +% +% function scale = GetScalingFactors(modelname) +% +% Returns an array of scaling factors for the parameters of the model +% intended to rescale so that they all have value close to 1. +% +% Note that including the scaling factor for sigma increases the number +% of model variables by 1. +% +% Note that the scaling factor not set for theta and phi +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +parameterStrings = GetParameterStrings(modelname); + +% here the scaling factors do not include the ones for theta and phi +% but include one for the sigma +scale = zeros(1, length(parameterStrings) - 1); + +% the scaling factor for sigma is set to 1 +scale(end) = 1; + +for i=1:length(parameterStrings) + if (strcmp(parameterStrings(i), 'di') ||... + strcmp(parameterStrings(i), 'dh') ||... + strcmp(parameterStrings(i), 'diso')) + scale(i) = 1E9; + elseif (strcmp(parameterStrings(i), 'rad')) + scale(i) = 1E6; + elseif (strcmp(parameterStrings(i), 'ficvf') ||... + strcmp(parameterStrings(i), 'fiso') ||... + strcmp(parameterStrings(i), 'irfrac') ||... + strcmp(parameterStrings(i), 'psi') ||... + strcmp(parameterStrings(i), 'b0') ||... + strcmp(parameterStrings(i), 't1')) + scale(i) = 1; + elseif (strcmp(parameterStrings(i), 'kappa') ||... + strcmp(parameterStrings(i), 'beta')) + scale(i) = 0.1; + end +end + diff --git a/NODDI_toolbox_v1.01/models/MakeDT_Matrix.m b/NODDI_toolbox_v1.01/models/MakeDT_Matrix.m new file mode 100644 index 0000000000000000000000000000000000000000..3d9633a6b1258c686fb68612adc26731067808c3 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/MakeDT_Matrix.m @@ -0,0 +1,14 @@ +function dt = MakeDT_Matrix(d11, d12, d13, d22, d23, d33) +% Makes a diffusion tensor matrix out of the six elements. +% +% dt = MakeDT_Matrix(d11, d12, d13, d22, d23, d33) +% returns the matrix +% [d11 d12 d13] +% [d12 d22 d23] +% [d13 d23 d33] +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +dt = [d11 d12 d13; d12 d22 d23; d13 d23 d33]; + diff --git a/NODDI_toolbox_v1.01/models/MakeModel.m b/NODDI_toolbox_v1.01/models/MakeModel.m new file mode 100644 index 0000000000000000000000000000000000000000..6bd48645d34649d22a065209d62dec9923c28817 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/MakeModel.m @@ -0,0 +1,89 @@ +function model = MakeModel(modelname) + +% function model = MakeModel(modelname) +% +% Set up the model specification for fitting +% +% model.name: model name +% +% model.numParams: number of parameters +% +% model.paramsStr: parameter strings +% +% model.tissuetype: type of tissue +% +% model.noOfStages: how many stages to run +% +% model.fixGD: fixed variables during gradient descent +% model.fixedvalsGD: values for the fixed variables during gradient descent +% +% model.fixMCMC: fixed variables during MCMC +% model.MCMC.steplengths: MCMC step lengths +% model.MCMC.burnin: MCMC burn-in +% model.MCMC.interval: MCMC interval +% model.MCMC.samples: MCMC samples +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +model.name = modelname; +model.numParams = NumFreeParams(modelname); +model.paramsStr = GetParameterStrings(modelname); +model.tissuetype = 'invivo'; +model.GS.fixed = zeros(1, model.numParams); +model.GS.fixedvals = zeros(1, model.numParams); +model.GD.fixed = zeros(1, model.numParams); +model.GD.fixedvals = zeros(1, model.numParams); +model.GD.type = 'single'; % 'multistart' +model.GD.multistart.perturbation = zeros(1, model.numParams); +model.GD.multistart.noOfRuns = 10; +model.MCMC.fixed = ones(1, model.numParams + 1); +model.MCMC.steplengths = 0.05*ones(1, model.numParams+1); +model.MCMC.burnin = 2000; +model.MCMC.interval = 200; +model.MCMC.samples = 40; +model.noOfStages = 2; +model.sigma.perVoxel = 1; +model.sigma.minSNR = 0.02; +model.sigma.scaling = 100; + +% use exvivo setting if isotropic restriction is included +irfracIdx = GetParameterIndex(modelname, 'irfrac'); +if irfracIdx > 0 + model.tissuetype = 'exvivo'; +end + +% fix intrinsic diffusivity +diIdx = GetParameterIndex(modelname, 'di'); +model.GS.fixed(diIdx) = 1; +model.GD.fixed(diIdx) = 1; +if strcmp(model.tissuetype, 'invivo') + model.GS.fixedvals(diIdx) = 1.7E-9; + model.GD.fixedvals(diIdx) = 1.7E-9; +else + model.GS.fixedvals(diIdx) = 0.6E-9; + model.GD.fixedvals(diIdx) = 0.6E-9; +end + +% fix isotropic diffusivity +disoIdx = GetParameterIndex(modelname, 'diso'); +if disoIdx > 0 + model.GS.fixed(disoIdx) = 1; + model.GD.fixed(disoIdx) = 1; + if strcmp(model.tissuetype, 'invivo') + model.GS.fixedvals(disoIdx) = 3.0E-9; + model.GD.fixedvals(disoIdx) = 3.0E-9; + else + model.GS.fixedvals(disoIdx) = 2.0E-9; + model.GD.fixedvals(disoIdx) = 2.0E-9; + end +end + +% fix B0 +% fixed value is estimated from the b0 images voxel-wise +b0Idx = GetParameterIndex(modelname, 'b0'); +if b0Idx > 0 + model.GS.fixed(b0Idx) = 1; + model.GD.fixed(b0Idx) = 1; +end + diff --git a/NODDI_toolbox_v1.01/models/NumFreeParams.m b/NODDI_toolbox_v1.01/models/NumFreeParams.m new file mode 100644 index 0000000000000000000000000000000000000000..6905509842a5824b193d89babac0c43c14d78af4 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/NumFreeParams.m @@ -0,0 +1,11 @@ +function numParams = NumFreeParams(modelname) +% +% function numParams = NumFreeParams(modelname) +% +% Given an input modelname, returns the number of free parameters of the model. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +numParams = length(GetParameterStrings(modelname)); + diff --git a/NODDI_toolbox_v1.01/models/RicianLogLik.m b/NODDI_toolbox_v1.01/models/RicianLogLik.m new file mode 100644 index 0000000000000000000000000000000000000000..2d504e71ddb9e6e6e88516c4b6cd359f59aaec2d --- /dev/null +++ b/NODDI_toolbox_v1.01/models/RicianLogLik.m @@ -0,0 +1,22 @@ +function loglik = RicianLogLik(meas, signals, sig) +% Computes the log likelihood of the measurements given the model signals +% for the Rician noise model. +% +% loglik = RicianLogLik(meas, signals, sig) returns the likelihood of +% measuring meas given the signals and the noise standard deviation sig. +% +% meas are the measurements +% +% signals are computed from a model +% +% sig is the standard deviation of the Gaussian distributions underlying +% the Rician distribution. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +sumsqsc = (signals.^2 + meas.^2)./(2*sig.^2); +scp = meas.*signals./(sig.^2); +lb0 = logbesseli0(scp); +logliks = - 2*log(sig) - sumsqsc + log(signals) + lb0; +loglik = sum(logliks); diff --git a/NODDI_toolbox_v1.01/models/SynthMeas.m b/NODDI_toolbox_v1.01/models/SynthMeas.m new file mode 100644 index 0000000000000000000000000000000000000000..3d91046de327728cbedc8d5bebd63a595aadf8dd --- /dev/null +++ b/NODDI_toolbox_v1.01/models/SynthMeas.m @@ -0,0 +1,212 @@ +function [E J] = SynthMeas(model, xsc, protocol, fibredir, constants) +% +% function [E J] = SynthMeas(model, xsc, protocol, fibredir, constants) +% +% General method for generating synthetic data from a model. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if(nargout == 1) + if(strcmp(model, 'IsoGPD')) + [E] = SynthMeasIsoGPD(xsc, protocol); + elseif(strcmp(model, 'CylSingleRadGPD')) + [E] = SynthMeasCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadGPD_B0')) + [E] = SynthMeasCylSingleRadGPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoV_GPD')) + [E] = SynthMeasCylSingleRadIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoV_GPD_B0')) + [E] = SynthMeasCylSingleRadIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadTortGPD')) + [E] = SynthMeasCylSingleRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadTortIsoGPD')) + [E] = SynthMeasCylSingleRadTortIsoGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadTortIsoV_GPD')) + [E] = SynthMeasCylSingleRadTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadTortIsoV_GPD_B0')) + [E] = SynthMeasCylSingleRadTortIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoCylTortIsoV_GPD')) + [E] = SynthMeasCylSingleRadIsoCylTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoStickTortIsoV_GPD')) + [E] = SynthMeasCylSingleRadIsoStickTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoSphereTortIsoV_GPD')) + [E] = SynthMeasCylSingleRadIsoSphereTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl, constants.roots_sph); + elseif(strcmp(model, 'CylSingleRadIsoDotGPD')) + [E] = SynthMeasCylSingleRadIsoDotGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoDotTortIsoV_GPD')) + [E] = SynthMeasCylSingleRadIsoDotTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoDotTortIsoV_GPD_B0')) + [E] = SynthMeasCylSingleRadIsoDotTortIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoDotTortIsoV_GPD_B0T1')) + [E] = SynthMeasCylSingleRadIsoDotTortIsoV_GPD_B0T1(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoSphereTortIsoV_GPD')) + [E] = SynthMeasCylSingleRadIsoSphereTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylGammaRadGPD')) + [E] = SynthMeasCylGammaRadGPD_PGSE(xsc, protocol.grad_dirs, protocol.G', protocol.delta', protocol.smalldel', fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadTortGPD')) + [E] = SynthMeasCylGammaRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadTortIsoGPD')) + [E] = SynthMeasCylGammaRadTortIsoGPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadTortIsoV_GPD')) + [E] = SynthMeasCylGammaRadTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadByVolGPD')) + [E] = SynthMeasCylGammaRadByVolGPD_PGSE(xsc, protocol.grad_dirs, protocol.G', protocol.delta', protocol.smalldel', fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadByVolTortGPD')) + [E] = SynthMeasCylGammaRadByVolTortGPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadByVolTortIsoGPD')) + [E] = SynthMeasCylGammaRadByVolTortIsoGPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadByVolTortIsoV_GPD')) + [E] = SynthMeasCylGammaRadByVolTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'SphereSingleRadGPD')) + [E] = SynthMeasSphereSingleRadGPD(xsc, protocol, constants.roots_sph); + elseif(strcmp(model, 'Stick')) + [E] = SynthMeasStick(xsc, protocol, fibredir); + elseif(strcmp(model, 'StickTort')) + [E] = SynthMeasStickTort(xsc, protocol, fibredir); + elseif(strcmp(model, 'StickIsoV_B0')) + [E] = SynthMeasStickIsoV_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'StickTortIsoV_B0')) + [E] = SynthMeasStickTortIsoV_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonCylSingleRadGPD')) + [E] = SynthMeasWatsonCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonCylSingleRadTortGPD')) + [E] = SynthMeasWatsonCylSingleRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonCylSingleRadTortIsoV_GPD')) + [E] = SynthMeasWatsonCylSingleRadTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonCylSingleRadTortIsoV_GPD_B0')) + [E] = SynthMeasWatsonCylSingleRadTortIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonStick')) + [E] = SynthMeasWatsonStick(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonStickTort')) + [E] = SynthMeasWatsonStickTort(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHCylSingleRadGPD')) + [E] = SynthMeasWatsonSHCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonSHCylSingleRadTortGPD')) + [E] = SynthMeasWatsonSHCylSingleRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonSHCylSingleRadTortIsoV_GPD')) + [E] = SynthMeasWatsonSHCylSingleRadTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonSHCylSingleRadTortIsoV_GPD_B0')) + [E] = SynthMeasWatsonSHCylSingleRadTortIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonSHStick')) + [E] = SynthMeasWatsonSHStick(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickIsoV_B0')) + [E] = SynthMeasWatsonSHStickIsoV_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickIsoVIsoDot_B0')) + [E] = SynthMeasWatsonSHStickIsoVIsoDot_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickTort')) + [E] = SynthMeasWatsonSHStickTort(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickTortIsoV_B0')) + [E] = SynthMeasWatsonSHStickTortIsoV_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickTortIsoVIsoDot_B0')) + [E] = SynthMeasWatsonSHStickTortIsoVIsoDot_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'BinghamCylSingleRadGPD')) + [E] = SynthMeasBinghamCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'BinghamCylSingleRadTortGPD')) + [E] = SynthMeasBinghamCylSingleRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'BinghamCylSingleRadTortIsoV_GPD')) + [E] = SynthMeasBinghamCylSingleRadTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'BinghamCylSingleRadTortIsoV_GPD_B0')) + [E] = SynthMeasBinghamCylSingleRadTortIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'BinghamStickTortIsoV_B0')) + [E] = SynthMeasBinghamStickTortIsoV_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'ExCrossingCylSingleRadGPD')) + [E] = SynthMeasExCrossingCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadGPD')) + [E] = SynthMeasExCrossingCylSingleRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotGPD')) + [E] = SynthMeasExCrossingCylSingleRadIsoDotGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotTortGPD')) + [E] = SynthMeasExCrossingCylSingleRadIsoDotTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotTortIsoV_GPD')) + [E] = SynthMeasExCrossingCylSingleRadIsoDotTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotTortIsoV_GPD_B0')) + [E] = SynthMeasExCrossingCylSingleRadIsoDotTortIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + else + error(['Undefined model: ', model]); + end +else + if(strcmp(model, 'IsoGPD')) + [E J] = SynthMeasIsoGPD(xsc, protocol); + elseif(strcmp(model, 'CylSingleRadGPD')) + [E J] = SynthMeasCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoV_GPD')) + [E J] = SynthMeasCylSingleRadIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadIsoV_GPD_B0')) + [E J] = SynthMeasCylSingleRadIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadTortGPD')) + [E J] = SynthMeasCylSingleRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadTortIsoGPD')) + [E J] = SynthMeasCylSingleRadTortIsoGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadTortIsoV_GPD')) + [E J] = SynthMeasCylSingleRadTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylSingleRadTortIsoV_GPD_B0')) + [E J] = SynthMeasCylSingleRadTortIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'CylGammaRadGPD')) + [E J] = SynthMeasCylGammaRadGPD_PGSE(xsc, protocol.grad_dirs, protocol.G', protocol.delta', protocol.smalldel', fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadTortGPD')) + [E J] = SynthMeasCylGammaRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadTortIsoGPD')) + [E J] = SynthMeasCylGammaRadTortIsoGPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadTortIsoV_GPD')) + [E J] = SynthMeasCylGammaRadTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadByVolGPD')) + [E J] = SynthMeasCylGammaRadByVolGPD_PGSE(xsc, protocol.grad_dirs, protocol.G', protocol.delta', protocol.smalldel', fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadByVolTortGPD')) + [E J] = SynthMeasCylGammaRadByVolTortGPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadByVolTortIsoGPD')) + [E J] = SynthMeasCylGammaRadByVolTortIsoGPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'CylGammaRadByVolTortIsoV_GPD')) + [E J] = SynthMeasCylGammaRadByVolTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl, 0); + elseif(strcmp(model, 'SphereSingleRadGPD')) + [E J] = SynthMeasSphereSingleRadGPD(xsc, protocol, constants.roots_sph); + elseif(strcmp(model, 'CylSingleRadGPD_B0')) + [E J] = SynthMeasCylSingleRadGPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'Stick')) + [E J] = SynthMeasStick(xsc, protocol, fibredir); + elseif(strcmp(model, 'StickTort')) + [E J] = SynthMeasStickTort(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonStick')) + [E J] = SynthMeasWatsonStick(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonStickTort')) + [E J] = SynthMeasWatsonStickTort(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStick')) + [E J] = SynthMeasWatsonSHStick(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickIsoV_B0')) + [E J] = SynthMeasWatsonSHStickIsoV_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickIsoVIsoDot_B0')) + [E J] = SynthMeasWatsonSHStickIsoVIsoDot_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickTort')) + [E J] = SynthMeasWatsonSHStickTort(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickTortIsoV_B0')) + [E J] = SynthMeasWatsonSHStickTortIsoV_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonSHStickTortIsoVIsoDot_B0')) + [E J] = SynthMeasWatsonSHStickTortIsoVIsoDot_B0(xsc, protocol, fibredir); + elseif(strcmp(model, 'WatsonCylSingleRadGPD')) + [E J] = SynthMeasWatsonCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonSHCylSingleRadGPD')) + [E J] = SynthMeasWatsonSHCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonSHCylSingleRadTortGPD')) + [E J] = SynthMeasWatsonSHCylSingleRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'WatsonSHCylSingleRadTortIsoV_GPD')) + [E J] = SynthMeasWatsonSHCylSingleRadTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'BinghamCylSingleRadGPD')) + [E J] = SynthMeasBinghamCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadGPD')) + [E J] = SynthMeasExCrossingCylSingleRadGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadTortGPD')) + [E J] = SynthMeasExCrossingCylSingleRadTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotGPD')) + [E J] = SynthMeasExCrossingCylSingleRadIsoDotGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotTortGPD')) + [E J] = SynthMeasExCrossingCylSingleRadIsoDotTortGPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotTortIsoV_GPD')) + [E J] = SynthMeasExCrossingCylSingleRadIsoDotTortIsoV_GPD(xsc, protocol, fibredir, constants.roots_cyl); + elseif(strcmp(model, 'ExCrossingCylSingleRadIsoDotTortIsoV_GPD_B0')) + [E J] = SynthMeasExCrossingCylSingleRadIsoDotTortIsoV_GPD_B0(xsc, protocol, fibredir, constants.roots_cyl); + else + error(['Undefined model: ', model]); + end +end + diff --git a/NODDI_toolbox_v1.01/models/SynthMeasHinderedDiffusion_PGSE.m b/NODDI_toolbox_v1.01/models/SynthMeasHinderedDiffusion_PGSE.m new file mode 100644 index 0000000000000000000000000000000000000000..f384052bd6736366804067e82ab057a2efdd912d --- /dev/null +++ b/NODDI_toolbox_v1.01/models/SynthMeasHinderedDiffusion_PGSE.m @@ -0,0 +1,61 @@ +function [E,J]=SynthMeasHinderedDiffusion_PGSE(x, grad_dirs, G, delta, smalldel, fibredir) +% Substrate: Anisotropic hindered diffusion compartment +% Pulse sequence: Pulsed gradient spin echo +% Signal approximation: N/A +% +% [E,J]=SynthMeasHinderedDiffusion_PGSE(x, grad_dirs, G, delta, smalldel, fibredir) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the free diffusivity of the material inside and outside the cylinders. +% x(2) is the hindered diffusivity outside the cylinders in perpendicular directions. +% +% grad_dirs is the gradient direction for each measurement. It has size [N +% 3] where N is the number of measurements. +% +% G, delta and smalldel are the gradient strength, pulse separation and +% pulse length of each measurement in the protocol. Each has +% size [N 1]. +% +% fibredir is a unit vector along the cylinder axis. It must be in +% Cartesian coordinates [x y z]' with size [3 1]. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +dPar=x(1); +dPerp=x(2); + +% Radial wavenumbers +GAMMA = 2.675987E8; +modQ = GAMMA*smalldel.*G; +modQ_Sq = modQ.^2; + +% Angles between gradient directions and fibre direction. +cosTheta = grad_dirs*fibredir; +cosThetaSq = cosTheta.^2; +sinThetaSq = 1-cosThetaSq; + +% b-value +bval = (delta-smalldel/3).*modQ_Sq; + +% Find hindered signals +E=exp(-bval.*((dPar - dPerp)*cosThetaSq + dPerp)); + +% Compute the Jacobian matrix +if(nargout>1) + bvalE = bval.*E; + % dE/ddPar + dEddPar = -bvalE.*cosThetaSq; + + % dE/ddPerp + dEddPerp = -bvalE.*sinThetaSq; + + % Construct the jacobian matrix. + J = zeros(size(E, 1), 2); + J(:,1) = dEddPar; + J(:,2) = dEddPerp; +end + diff --git a/NODDI_toolbox_v1.01/models/SynthMeasIsoGPD.m b/NODDI_toolbox_v1.01/models/SynthMeasIsoGPD.m new file mode 100644 index 0000000000000000000000000000000000000000..71f506ae50a2932bfde957959a6bc72adab92302 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/SynthMeasIsoGPD.m @@ -0,0 +1,73 @@ +function [E,J]=SynthMeasIsoGPD(d, protocol) +% Computes signals and their derivatives for isotropic free diffusion with +% diffusivity d for the protocol. +% +% [E,J]=SynthMeasIsoGPD(d, protocol) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameter d. +% +% d is the diffusivity. +% +% protocol is the object containing the acquisition protocol. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +if(strcmp(protocol.pulseseq, 'PGSE') || strcmp(protocol.pulseseq, 'STEAM')) + + GAMMA = 2.675987E8; + modQ = GAMMA*protocol.smalldel'.*protocol.G'; + modQ_Sq = modQ.^2; + difftime = (protocol.delta'-protocol.smalldel'/3); + + E = exp(-difftime.*modQ_Sq*d); + if(nargout>1) + J = -difftime.*modQ_Sq.*E; + end +elseif(strcmp(protocol.pulseseq, 'FullSTEAM')) + + GAMMA = 2.675987E8; + + FullG = protocol.grad_dirs.*repmat(protocol.G', [1 3]); + GdGd = sum(FullG.*FullG,2)'; + GcGc = sum(protocol.cG.*protocol.cG,2)'; + GrGr = sum(protocol.rG.*protocol.rG,2)'; + GdGc = sum(FullG.*protocol.cG,2)'; + GdGr = sum(FullG.*protocol.rG,2)'; + GcGr = sum(protocol.cG.*protocol.rG,2)'; + + tdd = protocol.gap1 + protocol.gap2 + protocol.TM + 2*protocol.sdelc + 2*protocol.smalldel/3 + 2*protocol.sdelr; + tcc = protocol.TM + 2*protocol.sdelc/3 + 2*protocol.sdelr; + trr = protocol.TM + 2*protocol.sdelr/3; + tdc = protocol.TM + protocol.sdelc + 2*protocol.sdelr; + tdr = protocol.TM + protocol.sdelr; + tcr = protocol.TM + protocol.sdelr; + + gqt = GAMMA^2*(GdGd.*protocol.smalldel.^2.*tdd + ... + GcGc.*protocol.sdelc.^2.*tcc + ... + GrGr.*protocol.sdelr.^2.*trr + ... + 2*GdGc.*protocol.smalldel.*protocol.sdelc.*tdc + ... + 2*GdGr.*protocol.smalldel.*protocol.sdelr.*tdr + ... + 2*GcGr.*protocol.sdelc.*protocol.sdelr.*tcr); + + E=exp(-gqt'*d); + + if(nargout>1) + J = -gqt.*E; + end +elseif(strcmp(protocol.pulseseq, 'DSE')) + bValue = GetB_ValuesDSE(protocol.G', protocol.delta1', protocol.delta2', protocol.delta3', protocol.t1', protocol.t2', protocol.t3'); + E = exp(-bValue*d); + if(nargout>1) + J = -bValue.*E; + end +elseif(strcmp(protocol.pulseseq, 'OGSE')) + bValue = GetB_Values(protocol)'; + E = exp(-bValue*d); + if(nargout>1) + J = -bValue.*E; + end +else + error('Not implemented for pulse sequence: %s', protocol.pulseseq); +end + diff --git a/NODDI_toolbox_v1.01/models/logbesseli0.m b/NODDI_toolbox_v1.01/models/logbesseli0.m new file mode 100644 index 0000000000000000000000000000000000000000..5134559969f378508c51808eb84f4b83e7900f01 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/logbesseli0.m @@ -0,0 +1,25 @@ +% Computes log(besseli(0,x)) robustly. Computing it directly causes +% numerical problems at high x, but the function has asymptotic linear +% behaviour, which we approximate here for high x. +% +% author: Daniel C Alexander (d.alexander@ucl.ac.uk) +% + +function lb0 = logbesseli0(x) + +% For very large arguments to besseli, we approximate log besseli using a +% linear model of the asymptotic behaviour. +% The linear parameters come from this command: +% app=regress(log(besseli(0,500:700))',[ones(201,1) (500:700)']); +app = [-3.61178295877576 0.99916157999904]; + +lb0 = zeros(length(x), 1); +exact = find(x<700); +approx = find(x>=700); +lb0(exact) = log(besseli(0, x(exact))); +%lb0(approx) = x(approx)*app(2) + app(1); + +% This is a more standard approximation. For large x, I_0(x) -> exp(x)/sqrt(2 pi x). +lb0(approx) = x(approx) - log(2*pi*x(approx))/2; + + diff --git a/NODDI_toolbox_v1.01/models/watson/LegendreGaussianIntegral.m b/NODDI_toolbox_v1.01/models/watson/LegendreGaussianIntegral.m new file mode 100644 index 0000000000000000000000000000000000000000..dd4a3421bdceb2eebe4ca72684ce316e5c4c51a0 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/LegendreGaussianIntegral.m @@ -0,0 +1,155 @@ +function [L, D] = legendreGaussianIntegral(x, n) +% function [L, D] = legendreGaussianIntegral(x, n) +% Computes legendre gaussian integrals up to the order specified and the +% derivatives if requested +% +% The integral takes the following form, in Mathematica syntax, +% +% L[x, n] = Integrate[Exp[-x \mu^2] Legendre[2*n, \mu], {\mu, -1, 1}] +% D[x, n] = Integrate[Exp[-x \mu^2] (-\mu^2) Legendre[2*n, \mu], {\mu, -1, 1}] +% +% INPUTS: +% +% x should be a column vector of positive numbers, specifying the +% parameters of the gaussian +% +% n should be a non-negative integer, such that 2n specifies the maximum order +% of legendre polynomial +% +% The maximum value for n is 6. +% +% OUTPUTS: +% +% L will be a two-dimensional array with each row containing the +% legendre gaussian integrals of the orders 0, 2, 4, ..., to 2n for the +% parameter value at the corresponding row in x +% +% Note that the legendre gaussian integrals of the odd orders are zero. +% +% D will be the 1st order derivative of L +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +% Make sure n is not larger than 6 +if n > 6 + error('The maximum value for n is 6, which correspondes to the 12th order Legendre polynomial'); +end + +% +% Computing the related exponent gaussian integrals +% I[x, n] = Integrate[Exp[-x \mu^2] \mu^(2*n), {\mu, -1, 1}] +% with the following recursion: +% 1) I[x, 0] = Sqrt[\pi]Erf[x]/Sqrt[x] +% 2) I[x, n+1] = -Exp[-x]/x + (2n+1)/(2x) I[x, n] +% +% This does not work well when x is small + +exact = find(x>0.05); +approx = find(x<=0.05); +% Necessary to make matlab happy when x is a single value +exact = exact(:); +approx = approx(:); + +if nargout > 1 + mn = n + 2; +else + mn = n + 1; +end +I = zeros(length(x),mn); +sqrtx = sqrt(x(exact)); +I(exact,1) = sqrt(pi)*erf(sqrtx)./sqrtx; +dx = 1.0./x(exact); +emx = -exp(-x(exact)); +for i = 2:mn + I(exact,i) = emx + (i-1.5)*I(exact,i-1); + I(exact,i) = I(exact,i).*dx; +end + +% Computing the legendre gaussian integrals for large enough x +L = zeros(length(x),n+1); +for i = 1:n+1 + if i == 1 + L(exact,1) = I(exact,1); + elseif i == 2 + L(exact,2) = -0.5*I(exact,1) + 1.5*I(exact,2); + elseif i == 3 + L(exact,3) = 0.375*I(exact,1) - 3.75*I(exact,2) + 4.375*I(exact,3); + elseif i == 4 + L(exact,4) = -0.3125*I(exact,1) + 6.5625*I(exact,2) - 19.6875*I(exact,3) + 14.4375*I(exact,4); + elseif i == 5 + L(exact,5) = 0.2734375*I(exact,1) - 9.84375*I(exact,2) + 54.140625*I(exact,3) - 93.84375*I(exact,4) + 50.2734375*I(exact,5); + elseif i == 6 + L(exact,6) = -(63/256)*I(exact,1) + (3465/256)*I(exact,2) - (30030/256)*I(exact,3) + (90090/256)*I(exact,4) - (109395/256)*I(exact,5) + (46189/256)*I(exact,6); + elseif i == 7 + L(exact,7) = (231/1024)*I(exact,1) - (18018/1024)*I(exact,2) + (225225/1024)*I(exact,3) - (1021020/1024)*I(exact,4) + (2078505/1024)*I(exact,5) - (1939938/1024)*I(exact,6) + (676039/1024)*I(exact,7); + end +end + +% Computing the legendre gaussian integrals for small x +x2=x(approx,1).^2; +x3=x2.*x(approx,1); +x4=x3.*x(approx,1); +x5=x4.*x(approx,1); +x6=x5.*x(approx,1); +for i = 1:n+1 + if i == 1 + L(approx,1) = 2 - 2*x(approx,1)/3 + x2/5 - x3/21 + x4/108; + elseif i == 2 + L(approx,2) = -4*x(approx,1)/15 + 4*x2/35 - 2*x3/63 + 2*x4/297; + elseif i == 3 + L(approx,3) = 8*x2/315 - 8*x3/693 + 4*x4/1287; + elseif i == 4 + L(approx,4) = -16*x3/9009 + 16*x4/19305; + elseif i == 5 + L(approx,5) = 32*x4/328185; + elseif i == 6 + L(approx,6) = -64*x5/14549535; + elseif i == 7 + L(approx,7) = 128*x6/760543875; + end +end + +if nargout == 1 + return; +end + +% Computing the derivatives for large enough x +D = zeros(length(x),n+1); +for i = 1:n+1 + if i == 1 + D(exact,1) = -I(exact,2); + elseif i == 2 + D(exact,2) = 0.5*I(exact,2) - 1.5*I(exact,3); + elseif i == 3 + D(exact,3) = -0.375*I(exact,2) + 3.75*I(exact,3) - 4.375*I(exact,4); + elseif i == 4 + D(exact,4) = 0.3125*I(exact,2) - 6.5625*I(exact,3) + 19.6875*I(exact,4) - 14.4375*I(exact,5); + elseif i == 5 + D(exact,5) = -0.2734375*I(exact,2) + 9.84375*I(exact,3) - 54.140625*I(exact,4) + 93.84375*I(exact,5) - 50.2734375*I(exact,6); + elseif i == 6 + D(exact,6) = (63/256)*I(exact,2) - (3465/256)*I(exact,3) + (30030/256)*I(exact,4) - (90090/256)*I(exact,5) + (109395/256)*I(exact,6) - (46189/256)*I(exact,7); + elseif i == 7 + D(exact,7) = -(231/1024)*I(exact,2) + (18018/1024)*I(exact,3) - (225225/1024)*I(exact,4) + (1021020/1024)*I(exact,5) - (2078505/1024)*I(exact,6) + (1939938/1024)*I(exact,7) - (676039/1024)*I(exact,8); + end +end + +% Computing the derivatives for small x +for i = 1:n+1 + if i == 1 + D(approx,1) = -2/3 + 2*x(approx,1)/5 - x2/7 + x3/27 - x4/132; + elseif i == 2 + D(approx,2) = -4/15 + 8*x(approx,1)/35 - 2*x2/21 + 8*x3/297 - 5*x4/858; + elseif i == 3 + D(approx,3) = 16*x(approx,1)/315 - 8*x2/231 + 16*x3/1287 - 4*x4/1287; + elseif i == 4 + D(approx,4) = -16*x2/3003 + 64*x3/19305 - 8*x4/7293; + elseif i == 5 + D(approx,5) = 128*x3/328185 - 32*x4/138567; + elseif i == 6 + D(approx,6) = -64*x4/2909907 + 128*x5/10140585; + elseif i == 7 + D(approx,7) = 256*x5/253514625; + end +end + diff --git a/NODDI_toolbox_v1.01/models/watson/NODDI_erfi.m b/NODDI_toolbox_v1.01/models/watson/NODDI_erfi.m new file mode 100644 index 0000000000000000000000000000000000000000..8db27db289462a450dfc21668835975926ee1ebd --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/NODDI_erfi.m @@ -0,0 +1,21 @@ +function ans=NODDI_erfi(x) +% %erfi(x). The Imaginary error function, as it is defined in Mathematica +% %erfi(z)==erf(iz)/i (z could be complex) using +% %the incomplete gamma function in matlab: gammainc +% %Using "@": erfi = @(x) real(-sqrt(-1).*sign(x).*gammainc(-x.^2,1/2)) +% %Note: limit(x->0) erfi(x)/x -> 2/sqrt(pi) +% +% %Example 1: +% x=linspace(0.001,6,100); +% y=exp(-x.^2).*erfi(x)./2./x; +% figure(1), clf;plot(x,y*sqrt(pi)) +% +% %Example 2: +% [x,y]=meshgrid(linspace(-3,3,180),linspace(-3,3,180)); +% z=x+i*y; +% figure(1), clf;contourf(x,y,log(erfi(z))) +% axis equal;axis off +xc=5.7;%cut for asymptotic approximation (when x is real) +ans=~isreal(x).*(-(sqrt(-x.^2)./(x+isreal(x))).*gammainc(-x.^2,1/2))+... + isreal(x).*real(-sqrt(-1).*sign(x).*((x<xc).*gammainc(-x.^2,1/2))+... + (x>=xc).*exp(x.^2)./x/sqrt(pi)); diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonHinderedDiffusion_PGSE.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonHinderedDiffusion_PGSE.m new file mode 100644 index 0000000000000000000000000000000000000000..38529358f53439a4f7bc1c655c53148c9d1fb161 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonHinderedDiffusion_PGSE.m @@ -0,0 +1,56 @@ +function [E,J]=SynthMeasWatsonHinderedDiffusion_PGSE(x, grad_dirs, G, delta, smalldel, fibredir) +% Substrate: Anisotropic hindered diffusion compartment +% Orientation distribution: Watson's distribution +% Pulse sequence: Pulsed gradient spin echo +% Signal approximation: N/A +% +% [E,J]=SynthMeasWatsonHinderedDiffusion_PGSE(x, grad_dirs, G, delta, smalldel, fibredir) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the free diffusivity of the material inside and outside the cylinders. +% x(2) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(3) is the concentration parameter of the Watson's distribution +% +% grad_dirs is the gradient direction for each measurement. It has size [N +% 3] where N is the number of measurements. +% +% G, delta and smalldel are the gradient strength, pulse separation and +% pulse length of each measurement in the protocol. Each has +% size [N 1]. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +dPar = x(1); +dPerp = x(2); +kappa = x(3); + +% get the equivalent diffusivities +if (nargout == 1) + dw = WatsonHinderedDiffusionCoeff(dPar, dPerp, kappa); +else + [dw, Jdw] = WatsonHinderedDiffusionCoeff(dPar, dPerp, kappa); +end + +xh = [dw(1) dw(2)]; +if (nargout == 1) + E = SynthMeasHinderedDiffusion_PGSE(xh, grad_dirs, G, delta, smalldel, fibredir); +else + [E, Jh] = SynthMeasHinderedDiffusion_PGSE(xh, grad_dirs, G, delta, smalldel, fibredir); +end + +% Compute the Jacobian matrix +if(nargout>1) + % Construct the jacobian matrix. + J = zeros(size(E, 1), 3); + J(:,1) = Jh(:,1)*Jdw(1,1) + Jh(:,2)*Jdw(2,1); + J(:,2) = Jh(:,1)*Jdw(1,2) + Jh(:,2)*Jdw(2,2); + J(:,3) = Jh(:,1)*Jdw(1,3) + Jh(:,2)*Jdw(2,3); +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylNeuman_PGSE.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylNeuman_PGSE.m new file mode 100644 index 0000000000000000000000000000000000000000..93838bbdff8d151e5f13bf53820f8d3d1326d2cb --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylNeuman_PGSE.m @@ -0,0 +1,138 @@ +function [E,J]=SynthMeasWatsonSHCylNeuman_PGSE(x, grad_dirs, G, delta, smalldel, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in an empty background. +% Orientation distribution: Watson's distribution with SH approximation +% Pulse sequence: Pulsed gradient spin echo +% Signal approximation: Gaussian phase distribution. +% +% [E,J]=SynthMeasWatsonSHCylNeuman_PGSE(x, grad_dirs, G, delta, smalldel, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the diffusivity of the material inside the cylinders. +% x(2) is the radius of the cylinders. +% x(3) is the concentration parameter of the Watson's distribution +% +% grad_dirs is the gradient direction for each measurement. It has size [N +% 3] where N is the number of measurements. +% +% G, delta and smalldel are the gradient strength, pulse separation and +% pulse length of each measurement in the protocol. Each has +% size [N 1]. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if length(x) ~= 3 + error('the first argument should have exactly three parameters'); +end + +d=x(1); +R=x(2); +kappa=x(3); + +l_q = size(grad_dirs,1); + +% Parallel component +if nargout > 1 + [LePar, J_LePar] = CylNeumanLePar_PGSE(d, G, delta, smalldel); +else + LePar = CylNeumanLePar_PGSE(d, G, delta, smalldel); +end + +% Perpendicular component +if nargout > 1 + [LePerp, J_LePerp] = CylNeumanLePerp_PGSE(d, R, G, delta, smalldel, roots); +else + LePerp = CylNeumanLePerp_PGSE(d, R, G, delta, smalldel, roots); +end +ePerp = exp(LePerp); + +% Compute the Legendre weighted signal +Lpmp = LePerp - LePar; +if nargout > 1 + [lgi, J_lgi] = LegendreGaussianIntegral(Lpmp, 6); +else + lgi = LegendreGaussianIntegral(Lpmp, 6); +end + +% Compute the spherical harmonic coefficients of the Watson's distribution +if nargout > 1 + [coeff, J_coeff] = WatsonSHCoeff(kappa); +else + coeff = WatsonSHCoeff(kappa); +end +coeffMatrix = repmat(coeff, [l_q, 1]); + +% Compute the dot product between the symmetry axis of the Watson's distribution +% and the gradient direction +% +% For numerical reasons, cosTheta might not always be between -1 and 1 +% Due to round off errors, individual gradient vectors in grad_dirs and the +% fibredir are never exactly normal. When a gradient vector and fibredir are +% essentially parallel, their dot product can fall outside of -1 and 1. +% +% BUT we need make sure it does, otherwise the legendre function call below +% will FAIL and abort the calculation!!! +% +cosTheta = grad_dirs*fibredir; +badCosTheta = find(abs(cosTheta)>1); +cosTheta(badCosTheta) = cosTheta(badCosTheta)./abs(cosTheta(badCosTheta)); + +% Compute the SH values at cosTheta +sh = zeros(size(coeff)); +shMatrix = repmat(sh, [l_q, 1]); +for i = 1:7 + shMatrix(:,i) = sqrt((i - .75)/pi); + % legendre function returns coefficients of all m from 0 to l + % we only need the coefficient corresponding to m = 0 + % WARNING: make sure to input ROW vector as variables!!! + % cosTheta is expected to be a COLUMN vector. + tmp = legendre(2*i - 2, cosTheta'); + tmp = tmp'; + shMatrix(:,i) = shMatrix(:,i) .* tmp(:,1); +end + +E = sum(lgi.*coeffMatrix.*shMatrix, 2); +% with the SH approximation, there will be no guarantee that E will be positive +% but we need to make sure it does!!! replace the negative values with 10% of +% the smallest positive values +E(find(E<=0)) = min(E(find(E>0)))*0.1; +E = 0.5*E.*ePerp; + +% Compute the Jacobian matrix +if(nargout>1) + % dePerp/dd + dePerpdd = E.*J_LePerp(1); + % dePar/dd + dElgi = sum(J_lgi.*coeffMatrix.*shMatrix, 2); + dePardd = 0.5*dElgi.*(J_LePerp(:,:,1) - J_LePar).*ePerp; + % dE/dd + dEdd = dePardd + dePerpdd; + + % dePerp/dR + dePerpdR = E.*J_LePerp(2); + % dePar/dR + dePardR = 0.5*dElgi.*J_LePerp(:,:,2).*ePerp; + % dE/dR + dEdR = dePardR + dePerpdR; + + % dE/dK + J_coeffMatrix = repmat(J_coeff, [l_q, 1]); + dEdk = sum(lgi.*J_coeffMatrix.*shMatrix,2); + dEdk = 0.5*dEdk.*ePerp; + + % Construct the jacobian matrix. + J = zeros(length(E), 3); + J(:,1) = dEdd; + J(:,2) = dEdR; + J(:,3) = dEdk; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadGPD.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadGPD.m new file mode 100644 index 0000000000000000000000000000000000000000..5dc387db240f9f5daffad709bcbbc58019768f9c --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadGPD.m @@ -0,0 +1,45 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadGPD(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Pulse sequence: Any +% Signal approximation: Gaussian phase distribution. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadGPD(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(4) is the radius of the cylinders. +% x(5) is the concentration parameter of the Watson's distribution +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +if(strcmp(protocol.pulseseq, 'PGSE') || strcmp(protocol.pulseseq, 'STEAM')) + if(nargout == 1) + [E] = SynthMeasWatsonSHCylSingleRadGPD_PGSE(x, protocol.grad_dirs, protocol.G', protocol.delta', protocol.smalldel', fibredir, roots); + else + [E J] = SynthMeasWatsonSHCylSingleRadGPD_PGSE(x, protocol.grad_dirs, protocol.G', protocol.delta', protocol.smalldel', fibredir, roots); + end +elseif(strcmp(protocol.pulseseq, 'DSE')) + if(nargout == 1) + [E] = SynthMeasWatsonSHCylSingleRadGPD_DSE(x, protocol.grad_dirs, protocol.G', protocol.TE, protocol.delta1', protocol.delta2', protocol.delta3', protocol.t1', protocol.t2', protocol.t3', fibredir, roots); + else + [E J] = SynthMeasWatsonSHCylSingleRadGPD_DSE(x, protocol.grad_dirs, protocol.G', protocol.TE, protocol.delta1', protocol.delta2', protocol.delta3', protocol.t1', protocol.t2', protocol.t3', fibredir, roots); + end +else + error(['Unknown pulse sequence: ' protocol.pulseseq]); +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadGPD_PGSE.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadGPD_PGSE.m new file mode 100644 index 0000000000000000000000000000000000000000..8d57d7352f3e6d3f182fa00f850e8a8cac8e7ff2 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadGPD_PGSE.m @@ -0,0 +1,90 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadGPD_PGSE(x, grad_dirs, G, delta, smalldel, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Pulse sequence: Pulsed gradient spin echo +% Signal approximation: Gaussian phase distribution. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadGPD_PGSE(x, grad_dirs, G, delta, smalldel, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(4) is the radius of the cylinders. +% x(5) is the concentration parameter of the Watson's distribution +% +% grad_dirs is the gradient direction for each measurement. It has size [N +% 3] where N is the number of measurements. +% +% G, delta and smalldel are the gradient strength, pulse separation and +% pulse length of each measurement in the protocol. Each has +% size [N 1]. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + + +% Duplication with SynthMeasDistributedRadVG remains, because of the +% derivative computation. + +f=x(1); +dPar=x(2); +dPerp=x(3); +R=x(4); +kappa=x(5); + +% build the input x vector for hindered compartment +x_h = [dPar dPerp kappa]; + +% build the input x vector for restricted diffusion in Neuman cylinder model +% set diffusion coeff in restricted compartment same as parallel one in +% hindered. +x_r = [dPar R kappa]; + +% Synthesize measurements from model +if (nargout>1) + [E_h, J_h] = SynthMeasWatsonHinderedDiffusion_PGSE(x_h, grad_dirs, G, delta, smalldel, fibredir); + [E_r, J_r] = SynthMeasWatsonSHCylNeuman_PGSE(x_r, grad_dirs, G, delta, smalldel, fibredir, roots); +else + E_h = SynthMeasWatsonHinderedDiffusion_PGSE(x_h, grad_dirs, G, delta, smalldel, fibredir); + E_r = SynthMeasWatsonSHCylNeuman_PGSE(x_r, grad_dirs, G, delta, smalldel, fibredir, roots); +end + +E=(1-f)*E_h+f*E_r; + +% Compute the Jacobian matrix +if(nargout>1) + + % dE_tot/df = E_r - E_h + dEtdf = E_r - E_h; + + % dE_tot/ddPar + dEtddPar = (1-f)*J_h(:,1) + f*J_r(:,1); + + % dE_tot/ddPerp + dEtddPerp = (1-f)*J_h(:,2); + + % dE_tot/dR + dEtdr = f*J_r(:,2); + + % dE_tot/dk + dEtdk = (1-f)*J_h(:,3) + f*J_r(:,3); + + % Construct the jacobian matrix. + J = zeros(length(E), 5); + J(:,1) = dEtdf; + J(:,2) = dEtddPar; + J(:,3) = dEtddPerp; + J(:,4) = dEtdr; + J(:,5) = dEtdk; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD.m new file mode 100644 index 0000000000000000000000000000000000000000..da5be9f3cb5f07ab45d0f6cc897a8cfdc331f9f5 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD.m @@ -0,0 +1,54 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Gaussian phase distribution. +% Notes: This version includes an isotropic diffusion compartment with its own +% diffusivity. +% This version includes a stationary water compartment. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(4) is the radius of the cylinders. +% x(5) is the concentration parameter of the Watson's distribution. +% x(6) is the volume fraction of the isotropic compartment. +% x(7) is the diffusivity of the isotropic compartment. +% x(8) is the volume fraction of the isotropic restriction. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +irFrac = x(8); + +% Call the model w/o the isotropic restriction +if(nargout == 1) + Ewo=SynthMeasWatsonSHCylSingleRadIsoV_GPD(x, protocol, fibredir, roots); +else + [Ewo,Jwo]=SynthMeasWatsonSHCylSingleRadIsoV_GPD(x, protocol, fibredir, roots); +end + +E = (1-irFrac)*Ewo + irFrac*1.0; + +if(nargout>1) + + % Update the component w/o isotropic restriction. + J = Jwo*(1-irFrac); + + % Add derivatives wrt isotropic restriction. + J(:,8) = 1.0 - Ewo; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD_B0.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD_B0.m new file mode 100644 index 0000000000000000000000000000000000000000..846e88374dda6b36a56e320da459d6574480e2dd --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD_B0.m @@ -0,0 +1,52 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD_B0(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Gaussian phase distribution. +% Notes: This version includes an isotropic diffusion compartment with its own +% diffusivity. +% This version includes a stationary water compartment. +% Includes a free parameter for the measurement at b=0. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD_B0(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(4) is the radius of the cylinders. +% x(5) is the concentration parameter of the Watson's distribution. +% x(6) is the volume fraction of the isotropic compartment. +% x(7) is the diffusivity of the isotropic compartment. +% x(8) is the volume fraction of the isotropic restriction. +% x(9) is the measurement at b=0. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +S0 = x(9); + +% Call the other function to get normalized measurements. +if(nargout == 1) + Enorm=SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD(x, protocol, fibredir, roots); +else + [Enorm,Jnorm]=SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD(x, protocol, fibredir, roots); +end + +E = Enorm*S0; + +if(nargout>1) + J = Jnorm*S0; + J(:,9) = Enorm; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoV_GPD.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoV_GPD.m new file mode 100644 index 0000000000000000000000000000000000000000..5799d60ba9db556962464ea78e9023cc854a8b8c --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoV_GPD.m @@ -0,0 +1,58 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadIsoV_GPD(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Gaussian phase distribution. +% Notes: This version includes an isotropic diffusion compartment with its own +% diffusivity. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadIsoV_GPD(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(4) is the radius of the cylinders. +% x(5) is the concentration parameter of the Watson's distribution. +% x(6) is the volume fraction of the isotropic compartment. +% x(7) is the diffusivity of the isotropic compartment. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +fiso = x(6); +dIso = x(7); + +% Call the model with no isotropic component to get the anisotropic component. +if(nargout == 1) + Eaniso=SynthMeasWatsonSHCylSingleRadGPD(x, protocol, fibredir, roots); + Eiso = SynthMeasIsoGPD(dIso, protocol); +else + [Eaniso,Janiso]=SynthMeasWatsonSHCylSingleRadGPD(x, protocol, fibredir, roots); + [Eiso, Jiso] = SynthMeasIsoGPD(dIso, protocol); +end + +E = (1-fiso)*Eaniso + fiso*Eiso; + +if(nargout>1) + + % Update with anisotropic component. + J = Janiso*(1-fiso); + + % Add derivatives wrt isotropic fraction. + J(:,6) = Eiso - Eaniso; + + % Add entry for dIso + J(:,7) = fiso*Jiso; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoV_GPD_B0.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoV_GPD_B0.m new file mode 100644 index 0000000000000000000000000000000000000000..c4d19ccc4627dac593ca59a35086b5c998a2d0f6 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadIsoV_GPD_B0.m @@ -0,0 +1,51 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadIsoV_GPD_B0(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Gaussian phase distribution. +% Notes: This version includes an isotropic diffusion compartment with its own +% diffusivity. +% Includes a free parameter for the measurement at b=0. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadIsoV_GPD_B0(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(4) is the radius of the cylinders. +% x(5) is the concentration parameter of the Watson's distribution. +% x(6) is the volume fraction of the isotropic compartment. +% x(7) is the diffusivity of the isotropic compartment. +% x(8) is the measurement at b=0. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +S0 = x(8); + +% Call the other function to get normalized measurements. +if(nargout == 1) + Enorm=SynthMeasWatsonSHCylSingleRadIsoV_GPD(x, protocol, fibredir, roots); +else + [Enorm,Jnorm]=SynthMeasWatsonSHCylSingleRadIsoV_GPD(x, protocol, fibredir, roots); +end + +E = Enorm*S0; + +if(nargout>1) + J = Jnorm*S0; + [meas, params] = size(J); + J(:,params+1) = Enorm; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortGPD.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortGPD.m new file mode 100644 index 0000000000000000000000000000000000000000..500288341b8ae955cdaffd8e5cca7ba4652d1d80 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortGPD.m @@ -0,0 +1,53 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadTortGPD(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Pulse sequence: Any +% Signal approximation: Gaussian phase distribution. +% Notes: This version estimates the hindered diffusivity from the free diffusivity +% and packing density using Szafer et al's tortuosity model for randomly +% packed cylinders. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadTortGPD(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the radius of the cylinders. +% x(4) is the concentration parameter of the Watson's distribution. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + + +f=x(1); +dPar=x(2); +% This version is for cylinders with regular packing. +%dPerp = dPar/((1 + f^(3/2))^2); +% This one is for randomly packed cylinders +dPerp = dPar*(1-f); +R=[x(3)]; +kappa=x(4); + +x_full = [f dPar dPerp R kappa]; + +% Call the model with no isotropic component to get the anisotropic component. +if(nargout == 1) + E=SynthMeasWatsonSHCylSingleRadGPD(x_full, protocol, fibredir, roots); +else + [E,J_full]=SynthMeasWatsonSHCylSingleRadGPD(x_full, protocol, fibredir, roots); + J(:,1) = J_full(:,1) - J_full(:,3)*dPar; + J(:,2) = J_full(:,2) + J_full(:,3)*(1-f); + J(:,3) = J_full(:,4); + J(:,4) = J_full(:,5); +end diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD.m new file mode 100644 index 0000000000000000000000000000000000000000..a42e1290981d6baac09308f051cb8581787102bb --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD.m @@ -0,0 +1,56 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Gaussian phase distribution. +% Notes: This version estimates the hindered diffusivity from the free diffusivity +% and packing density using Szafer et al's tortuosity model for randomly +% packed cylinders. +% This version includes an isotropic diffusion compartment with its own +% diffusivity. +% This version includes a stationary water compartment. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the radius of the cylinders. +% x(4) is the concentration parameter of the Watson's distribution. +% x(5) is the volume fraction of the isotropic compartment. +% x(6) is the diffusivity of the isotropic compartment. +% x(7) is the volume fraction of the isotropic restriction. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +irFrac = x(7); + +% Call the model w/o the isotropic restriction. +if(nargout == 1) + Ewo=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD(x, protocol, fibredir, roots); +else + [Ewo,Jwo]=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD(x, protocol, fibredir, roots); +end + +E = (1-irFrac)*Ewo + irFrac*1.0; + +if(nargout>1) + + % Update the component w/o isotropic restriction. + J = Jwo*(1-irFrac); + + % Add derivatives wrt isotropic restriction. + J(:,7) = 1.0 - Ewo; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD_B0.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD_B0.m new file mode 100644 index 0000000000000000000000000000000000000000..8f2c15cb04007980a5195aa8c07448ef31628a7e --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD_B0.m @@ -0,0 +1,54 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD_B0(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Gaussian phase distribution. +% Notes: This version estimates the hindered diffusivity from the free diffusivity +% and packing density using Szafer et al's tortuosity model for randomly +% packed cylinders. +% This version includes an isotropic diffusion compartment with its own +% diffusivity. +% This version includes a stationary water compartment. +% Includes a free parameter for the measurement at b=0. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD_B0(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the radius of the cylinders. +% x(4) is the concentration parameter of the Watson's distribution. +% x(5) is the volume fraction of the isotropic compartment. +% x(6) is the diffusivity of the isotropic compartment. +% x(7) is the volume fraction of the isotropic restriction. +% x(8) is the measurement at b=0. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +S0 = x(8); + +% Call the other function to get normalized measurements. +if(nargout == 1) + Enorm=SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD(x, protocol, fibredir, roots); +else + [Enorm,Jnorm]=SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD(x, protocol, fibredir, roots); +end + +E = Enorm*S0; + +if(nargout>1) + J = Jnorm*S0; + J(:,8) = Enorm; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoV_GPD.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoV_GPD.m new file mode 100644 index 0000000000000000000000000000000000000000..b935e4f7e8e3ffcff2c3db25178485da563b78b9 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoV_GPD.m @@ -0,0 +1,60 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Gaussian phase distribution. +% Notes: This version estimates the hindered diffusivity from the free diffusivity +% and packing density using Szafer et al's tortuosity model for randomly +% packed cylinders. +% This version includes an isotropic diffusion compartment with its own +% diffusivity. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the radius of the cylinders. +% x(4) is the concentration parameter of the Watson's distribution. +% x(5) is the volume fraction of the isotropic compartment. +% x(6) is the diffusivity of the isotropic compartment. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + + +fiso = x(5); +dIso = x(6); + +% Call the model with no isotropic component to get the anisotropic component. +if(nargout == 1) + Eaniso=SynthMeasWatsonSHCylSingleRadTortGPD(x, protocol, fibredir, roots); + Eiso = SynthMeasIsoGPD(dIso, protocol); +else + [Eaniso,Janiso]=SynthMeasWatsonSHCylSingleRadTortGPD(x, protocol, fibredir, roots); + [Eiso, Jiso] = SynthMeasIsoGPD(dIso, protocol); +end + +E = (1-fiso)*Eaniso + fiso*Eiso; + +if(nargout>1) + + % Update with anisotropic component. + J = Janiso*(1-fiso); + + % Add derivatives wrt isotropic fraction. + J(:,5) = Eiso - Eaniso; + + % Add entry for dIso + J(:,6) = fiso*Jiso; +end diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoV_GPD_B0.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoV_GPD_B0.m new file mode 100644 index 0000000000000000000000000000000000000000..2a287ef3bc9aa06b74c6dc7d034179e7ad5d6f46 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHCylSingleRadTortIsoV_GPD_B0.m @@ -0,0 +1,53 @@ +function [E,J]=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD_B0(x, protocol, fibredir, roots) +% Substrate: Impermeable cylinders with one radius in a homogeneous background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Gaussian phase distribution. +% Notes: This version estimates the hindered diffusivity from the free diffusivity +% and packing density using Szafer et al's tortuosity model for randomly +% packed cylinders. +% This version includes an isotropic diffusion compartment with its own +% diffusivity. +% Includes a free parameter for the measurement at b=0. +% +% [E,J]=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD_B0(x, protocol, fibredir, roots) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the radius of the cylinders. +% x(4) is the concentration parameter of the Watson's distribution. +% x(5) is the volume fraction of the isotropic compartment. +% x(6) is the diffusivity of the isotropic compartment. +% x(7) is the measurement at b=0. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% roots contains solutions to the Bessel function equation from function +% BesselJ_RootsCyl. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +S0 = x(7); + +% Call the other function to get normalized measurements. +if(nargout == 1) + Enorm=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD(x, protocol, fibredir, roots); +else + [Enorm,Jnorm]=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD(x, protocol, fibredir, roots); +end + +E = Enorm*S0; + +if(nargout>1) + J = Jnorm*S0; + [meas, params] = size(J); + J(:,params+1) = Enorm; +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickIsoVIsoDot_B0.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickIsoVIsoDot_B0.m new file mode 100644 index 0000000000000000000000000000000000000000..ce1b0d1837a4842d5d78259c3e9cfad5584506ca --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickIsoVIsoDot_B0.m @@ -0,0 +1,52 @@ +function [E,J]=SynthMeasWatsonSHStickIsoVIsoDot_B0(x, protocol, fibredir) +% Substrate: Impermeable sticks (cylinders with zero radius) in a homogeneous +% background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Not applicable +% This version includes an isotropic diffusion compartment with its own +% diffusivity. +% This version includes a stationary water compartment. +% Includes a free parameter for the measurement at b=0. +% +% [E,J]=SynthMeasWatsonSHStickTortIsoV_B0(x, protocol, fibredir) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(4) is the concentration parameter of the Watson's distribution. +% x(5) is the volume fraction of the isotropic compartment. +% x(6) is the diffusivity of the isotropic compartment. +% x(7) is the volume fraction of the isotropic restriction. +% x(8) is the measurement at b=0. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +xcyl=[x(1) x(2) x(3) 0 x(4) x(5) x(6) x(7) x(8)]; + +if(nargout == 1) + E=SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD_B0(xcyl, protocol, fibredir, 0); +else + [E,Jcyl]=SynthMeasWatsonSHCylSingleRadIsoVIsoDot_GPD_B0(xcyl, protocol, fibredir, 0); +end + +if(nargout>1) + J(:,1) = Jcyl(:,1); + J(:,2) = Jcyl(:,2); + J(:,3) = Jcyl(:,3); + J(:,4) = Jcyl(:,5); + J(:,5) = Jcyl(:,6); + J(:,6) = Jcyl(:,7); + J(:,7) = Jcyl(:,8); + J(:,8) = Jcyl(:,9); +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickIsoV_B0.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickIsoV_B0.m new file mode 100644 index 0000000000000000000000000000000000000000..7a62870a1623cde90662d40486497bfce705a128 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickIsoV_B0.m @@ -0,0 +1,49 @@ +function [E,J]=SynthMeasWatsonSHStickIsoV_B0(x, protocol, fibredir) +% Substrate: Impermeable sticks (cylinders with zero radius) in a homogeneous +% background. +% Orientation distribution: Watson's distribution with SH approximation +% Pulse sequence: Any +% Signal approximation: Not applicable +% Notes: This version includes an isotropic diffusion compartment with its own +% Includes a free parameter for the measurement at b=0. +% +% [E,J]=SynthMeasWatsonSHStickIsoV_B0(x, protocol, fibredir) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the hindered diffusivity outside the cylinders in perpendicular directions. +% x(4) is the concentration parameter of the Watson's distribution. +% x(5) is the volume fraction of the isotropic compartment. +% x(6) is the diffusivity of the isotropic compartment. +% x(7) is the measurement at b=0. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +xcyl=[x(1) x(2) x(3) 0 x(4) x(5) x(6) x(7)]; + +if(nargout == 1) + [E] = SynthMeasWatsonSHCylSingleRadIsoV_GPD_B0(xcyl, protocol, fibredir, 0); +else + [E Jcyl] = SynthMeasWatsonSHCylSingleRadIsoV_GPD_B0(xcyl, protocol, fibredir, 0); +end + +if (nargout == 2) + J(:,1) = Jcyl(:,1); + J(:,2) = Jcyl(:,2); + J(:,3) = Jcyl(:,3); + J(:,4) = Jcyl(:,5); + J(:,5) = Jcyl(:,6); + J(:,6) = Jcyl(:,7); + J(:,7) = Jcyl(:,8); +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickTortIsoVIsoDot_B0.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickTortIsoVIsoDot_B0.m new file mode 100644 index 0000000000000000000000000000000000000000..2d00f444b8fecb10ab7d058001a1db6c0c63c7c9 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickTortIsoVIsoDot_B0.m @@ -0,0 +1,53 @@ +function [E,J]=SynthMeasWatsonSHStickTortIsoVIsoDot_B0(x, protocol, fibredir) +% Substrate: Impermeable sticks (cylinders with zero radius) in a homogeneous +% background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Not applicable +% Notes: This version estimates the hindered diffusivity from the free diffusivity +% and packing density using Szafer et al's tortuosity model for randomly +% packed cylinders. +% This version includes an isotropic diffusion compartment with its own +% diffusivity. +% This version includes a stationary water compartment. +% Includes a free parameter for the measurement at b=0. +% +% [E,J]=SynthMeasWatsonSHStickTortIsoV_B0(x, protocol, fibredir) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the concentration parameter of the Watson's distribution. +% x(4) is the volume fraction of the isotropic compartment. +% x(5) is the diffusivity of the isotropic compartment. +% x(6) is the volume fraction of the isotropic restriction. +% x(7) is the measurement at b=0. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +xcyl=[x(1) x(2) 0 x(3) x(4) x(5) x(6) x(7)]; + +if(nargout == 1) + E=SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD_B0(xcyl, protocol, fibredir, 0); +else + [E,Jcyl]=SynthMeasWatsonSHCylSingleRadTortIsoVIsoDot_GPD_B0(xcyl, protocol, fibredir, 0); +end + +if(nargout>1) + J(:,1) = Jcyl(:,1); + J(:,2) = Jcyl(:,2); + J(:,3) = Jcyl(:,4); + J(:,4) = Jcyl(:,5); + J(:,5) = Jcyl(:,6); + J(:,6) = Jcyl(:,7); + J(:,7) = Jcyl(:,8); +end + diff --git a/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickTortIsoV_B0.m b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickTortIsoV_B0.m new file mode 100644 index 0000000000000000000000000000000000000000..15e2b092c8d2e624ac22fd7018d49d4c6ab862eb --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/SynthMeasWatsonSHStickTortIsoV_B0.m @@ -0,0 +1,49 @@ +function [E,J]=SynthMeasWatsonSHStickTortIsoV_B0(x, protocol, fibredir) +% Substrate: Impermeable sticks (cylinders with zero radius) in a homogeneous +% background. +% Orientation distribution: Watson's distribution with SH approximation +% Signal approximation: Not applicable +% Notes: This version estimates the hindered diffusivity from the free diffusivity +% and packing density using Szafer et al's tortuosity model for randomly +% packed cylinders. +% This version includes an isotropic diffusion compartment with its own +% diffusivity. +% Includes a free parameter for the measurement at b=0. +% +% [E,J]=SynthMeasWatsonSHStickTortIsoV_B0(x, protocol, fibredir) +% returns the measurements E according to the model and the Jacobian J of the +% measurements with respect to the parameters. The Jacobian does not +% include derivates with respect to the fibre direction. +% +% x is the list of model parameters in SI units: +% x(1) is the volume fraction of the intracellular space. +% x(2) is the free diffusivity of the material inside and outside the cylinders. +% x(3) is the concentration parameter of the Watson's distribution. +% x(4) is the volume fraction of the isotropic compartment. +% x(5) is the diffusivity of the isotropic compartment. +% x(6) is the measurement at b=0. +% +% protocol is the object containing the acquisition protocol. +% +% fibredir is a unit vector along the symmetry axis of the Watson's +% distribution. It must be in Cartesian coordinates [x y z]' with size [3 1]. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +xcyl=[x(1) x(2) 0 x(3) x(4) x(5) x(6)]; + +if(nargout == 1) + E=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD_B0(xcyl, protocol, fibredir, 0); +else + [E,Jcyl]=SynthMeasWatsonSHCylSingleRadTortIsoV_GPD_B0(xcyl, protocol, fibredir, 0); +end + +if(nargout>1) + J(:,1) = Jcyl(:,1); + J(:,2) = Jcyl(:,2); + J(:,3) = Jcyl(:,4); + J(:,4) = Jcyl(:,5); + J(:,5) = Jcyl(:,6); + J(:,6) = Jcyl(:,7); +end diff --git a/NODDI_toolbox_v1.01/models/watson/WatsonHinderedDiffusionCoeff.m b/NODDI_toolbox_v1.01/models/watson/WatsonHinderedDiffusionCoeff.m new file mode 100644 index 0000000000000000000000000000000000000000..aabecde3810ede74da0a56fd1330f4ecf327d4fb --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/WatsonHinderedDiffusionCoeff.m @@ -0,0 +1,51 @@ +function [dw, Jdw]=WatsonHinderedDiffusionCoeff(dPar, dPerp, kappa) +% Substrate: Anisotropic hindered diffusion compartment +% Orientation distribution: Watson's distribution +% +% [dw, Jdw]=WatsonHinderedDiffusionCoeff(dPar, dPerp, kappa) +% returns the equivalent parallel and perpendicular diffusion coefficients +% for hindered compartment with impermeable cylinder's oriented with a +% Watson's distribution with a cocentration parameter of kappa +% +% dPar is the free diffusivity of the material inside and outside the cylinders. +% dPerp is the hindered diffusivity outside the cylinders in perpendicular directions. +% kappa is the concentration parameter of the Watson's distribution +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +% compute the equivalent diffusion coefficient after integrating +% for all possible orientations +dw = zeros(2,1); +dParMdPerp = dPar - dPerp; + +if kappa < 1e-5 + dParP2dPerp = dPar + 2*dPerp; + k2 = kappa*kappa; + dw(1) = dParP2dPerp/3 + 4*dParMdPerp*kappa/45 + 8*dParMdPerp*k2/945; + dw(2) = dParP2dPerp/3 - 2*dParMdPerp*kappa/45 - 4*dParMdPerp*k2/945; + if (nargout==2) + Jdw(1,1) = 1/3 + 4/45*kappa + 8/945*k2; + Jdw(1,2) = 2/3 - 4/45*kappa - 8/945*k2; + Jdw(1,3) = 4/45*dParMdPerp + 16/945*dParMdPerp*kappa; + Jdw(2,1) = 1/3 - 2/45*kappa - 4/945*k2; + Jdw(2,2) = 2/3 + 2/45*kappa + 4/945*k2; + Jdw(2,3) = -2/45*dParMdPerp - 8/945*dParMdPerp*kappa; + end +else + sk = sqrt(kappa); + dawsonf = 0.5*exp(-kappa)*sqrt(pi)*NODDI_erfi(sk); + factor = sk/dawsonf; + dw(1) = (-dParMdPerp+2*dPerp*kappa+dParMdPerp*factor)/(2*kappa); + dw(2) = (dParMdPerp+2*(dPar+dPerp)*kappa-dParMdPerp*factor)/(4*kappa); + if (nargout==2) + % D[DawsonF(x),x] = 1 - 2xDawsonF(x) + dfactordk = ((1+2*kappa)*dawsonf - sk)/(2*sk*dawsonf*dawsonf); + Jdw(1,1) = (-1 + factor)/(2*kappa); + Jdw(1,2) = (1 + 2*kappa - factor)/(2*kappa); + Jdw(1,3) = (-2*dw(1) + 2*dPerp + dParMdPerp*dfactordk)/(2*kappa); + Jdw(2,1) = (1 + 2*kappa - factor)/(4*kappa); + Jdw(2,2) = (-1 + 2*kappa + factor)/(4*kappa); + Jdw(2,3) = (-4*dw(2) + 2*(dPar+dPerp) - dParMdPerp*dfactordk)/(4*kappa); + end +end diff --git a/NODDI_toolbox_v1.01/models/watson/WatsonSHCoeff.m b/NODDI_toolbox_v1.01/models/watson/WatsonSHCoeff.m new file mode 100644 index 0000000000000000000000000000000000000000..ee26b76ff5271a72fc1367cfa5e74e9d7ef370d2 --- /dev/null +++ b/NODDI_toolbox_v1.01/models/watson/WatsonSHCoeff.m @@ -0,0 +1,191 @@ +function [C, D] = WatsonSHCoeff(k) +% function [C, D] = WatsonSHCoeff(k) +% Computes the spherical harmonic (SH) coefficients of the Watson's +% distribution with the concentration parameter k (kappa) up to the 12th order +% and the derivatives if requested. +% +% Truncating at the 12th order gives good approximation for kappa up to 64. +% +% INPUTS: +% +% k should be an array of positive numbers, specifying a set of +% concentration parameters for the Watson's distribution. +% +% OUTPUTS: +% +% C will be a 2-D array and each row contains the SH coefficients of the +% orders 0, 2, 4, ..., to 2n for the parameter in the corresponding row in +% k. +% +% Note that the SH coefficients of the odd orders are always zero. +% +% D will be the 1st order derivative of C. +% +% author: Gary Hui Zhang (gary.zhang@ucl.ac.uk) +% + +large = find(k>30); +exact = find(k>0.1); +approx = find(k<=0.1); +% Necessary to make matlab happy when k is a single value +exact = exact(:); +approx = approx(:); +large = large(:); + +% The maximum order of SH coefficients (2n) +n = 6; + +% Computing the SH coefficients +C = zeros(length(k),n+1); + +% 0th order is a constant +C(:,1) = 2*sqrt(pi); + +% Precompute the special function values +sk = sqrt(k(exact)); +sk2 = sk.*k(exact); +sk3 = sk2.*k(exact); +sk4 = sk3.*k(exact); +sk5 = sk4.*k(exact); +sk6 = sk5.*k(exact); +sk7 = sk6.*k(exact); +k2 = k.^2; +k3 = k2.*k; +k4 = k3.*k; +k5 = k4.*k; +k6 = k5.*k; +k7 = k6.*k; + +erfik = NODDI_erfi(sk); +ierfik = 1./erfik; +ek = exp(k(exact)); +dawsonk = 0.5*sqrt(pi)*erfik./ek; + +% for large enough kappa +C(exact,2) = 3*sk - (3 + 2*k(exact)).*dawsonk; +C(exact,2) = sqrt(5)*C(exact,2).*ek; +C(exact,2) = C(exact,2).*ierfik./k(exact); + +C(exact,3) = (105 + 60*k(exact) + 12*k2(exact)).*dawsonk; +C(exact,3) = C(exact,3) -105*sk + 10*sk2; +C(exact,3) = .375*C(exact,3).*ek./k2(exact); +C(exact,3) = C(exact,3).*ierfik; + +C(exact,4) = -3465 - 1890*k(exact) - 420*k2(exact) - 40*k3(exact); +C(exact,4) = C(exact,4).*dawsonk; +C(exact,4) = C(exact,4) + 3465*sk - 420*sk2 + 84*sk3; +C(exact,4) = C(exact,4)*sqrt(13*pi)/64./k3(exact); +C(exact,4) = C(exact,4)./dawsonk; + +C(exact,5) = 675675 + 360360*k(exact) + 83160*k2(exact) + 10080*k3(exact) + 560*k4(exact); +C(exact,5) = C(exact,5).*dawsonk; +C(exact,5) = C(exact,5) - 675675*sk + 90090*sk2 - 23100*sk3 + 744*sk4; +C(exact,5) = sqrt(17)*C(exact,5).*ek; +C(exact,5) = C(exact,5)/512./k4(exact); +C(exact,5) = C(exact,5).*ierfik; + +C(exact,6) = -43648605 - 22972950*k(exact) - 5405400*k2(exact) - 720720*k3(exact) - 55440*k4(exact) - 2016*k5(exact); +C(exact,6) = C(exact,6).*dawsonk; +C(exact,6) = C(exact,6) + 43648605*sk - 6126120*sk2 + 1729728*sk3 - 82368*sk4 + 5104*sk5; +C(exact,6) = sqrt(21*pi)*C(exact,6)/4096./k5(exact); +C(exact,6) = C(exact,6)./dawsonk; + +C(exact,7) = 7027425405 + 3666482820*k(exact) + 872972100*k2(exact) + 122522400*k3(exact) + 10810800*k4(exact) + 576576*k5(exact) + 14784*k6(exact); +C(exact,7) = C(exact,7).*dawsonk; +C(exact,7) = C(exact,7) - 7027425405*sk + 1018467450*sk2 - 302630328*sk3 + 17153136*sk4 - 1553552*sk5 + 25376*sk6; +C(exact,7) = 5*C(exact,7).*ek; +C(exact,7) = C(exact,7)/16384./k6(exact); +C(exact,7) = C(exact,7).*ierfik; + +% for very large kappa +if size(large,1) > 0 + lnkd = log(k(large)) - log(30); + lnkd2 = lnkd.*lnkd; + lnkd3 = lnkd2.*lnkd; + lnkd4 = lnkd3.*lnkd; + lnkd5 = lnkd4.*lnkd; + lnkd6 = lnkd5.*lnkd; + C(large,2) = 7.52308 + 0.411538*lnkd - 0.214588*lnkd2 + 0.0784091*lnkd3 - 0.023981*lnkd4 + 0.00731537*lnkd5 - 0.0026467*lnkd6; + C(large,3) = 8.93718 + 1.62147*lnkd - 0.733421*lnkd2 + 0.191568*lnkd3 - 0.0202906*lnkd4 - 0.00779095*lnkd5 + 0.00574847*lnkd6; + C(large,4) = 8.87905 + 3.35689*lnkd - 1.15935*lnkd2 + 0.0673053*lnkd3 + 0.121857*lnkd4 - 0.066642*lnkd5 + 0.0180215*lnkd6; + C(large,5) = 7.84352 + 5.03178*lnkd - 1.0193*lnkd2 - 0.426362*lnkd3 + 0.328816*lnkd4 - 0.0688176*lnkd5 - 0.0229398*lnkd6; + C(large,6) = 6.30113 + 6.09914*lnkd - 0.16088*lnkd2 - 1.05578*lnkd3 + 0.338069*lnkd4 + 0.0937157*lnkd5 - 0.106935*lnkd6; + C(large,7) = 4.65678 + 6.30069*lnkd + 1.13754*lnkd2 - 1.38393*lnkd3 - 0.0134758*lnkd4 + 0.331686*lnkd5 - 0.105954*lnkd6; +end + +% for small kappa +C(approx,2) = 4/3*k(approx) + 8/63*k2(approx); +C(approx,2) = C(approx,2)*sqrt(pi/5); + +C(approx,3) = 8/21*k2(approx) + 32/693*k3(approx); +C(approx,3) = C(approx,3)*(sqrt(pi)*0.2); + +C(approx,4) = 16/693*k3(approx) + 32/10395*k4(approx); +C(approx,4) = C(approx,4)*sqrt(pi/13); + +C(approx,5) = 32/19305*k4(approx); +C(approx,5) = C(approx,5)*sqrt(pi/17); + +C(approx,6) = 64*sqrt(pi/21)*k5(approx)/692835; + +C(approx,7) = 128*sqrt(pi)*k6(approx)/152108775; + +if nargout == 1 + return; +end + +% Computing the derivatives +dawsonk2 = dawsonk.^2; +idawsonk2 = 1./dawsonk2; + +D = zeros(length(k),n+1); +D(:,1) = 0.0; + +% exact +D(exact,2) = -k(exact) + (2*sk2 -sk).*dawsonk + 2*dawsonk2; +D(exact,2) = (.75*sqrt(5*pi))*D(exact,2)./k2(exact).*idawsonk2; + +D(exact,3) = 21*k(exact) - 2*k2(exact); +D(exact,3) = D(exact,3) + (63*sk -44*sk2 + 4*sk3).*dawsonk; +D(exact,3) = D(exact,3) - (84 + 24*k(exact)).*dawsonk2; +D(exact,3) = D(exact,3)*(15*sqrt(pi)/32)./k3(exact).*idawsonk2; + +D(exact,4) = -165*k(exact) + 20*k2(exact) - 4*k3(exact); +D(exact,4) = D(exact,4) + (-825*sk + 390*sk2 - 44*sk3 + 8*sk4).*dawsonk; +D(exact,4) = D(exact,4) + (990 + 360*k(exact) + 40*k2(exact)).*dawsonk2; +D(exact,4) = D(exact,4)*(21*sqrt(13*pi)/128)./k4(exact).*idawsonk2; + +D(exact,5) = 225225*k(exact) - 30030*k2(exact) + 7700*k3(exact) - 248*k4(exact); +D(exact,5) = D(exact,5) + (1576575*sk - 600600*sk2 + 83160*sk3 - 15648*sk4 + 496*sk5).*dawsonk; +D(exact,5) = D(exact,5) - (1801800 + 720720*k(exact) + 110880*k2(exact) + 6720*k3(exact)).*dawsonk2; +D(exact,5) = D(exact,5)*(3*sqrt(17*pi)/2048)./k5(exact).*idawsonk2; + +D(exact,6) = -3968055*k(exact) + 556920*k2(exact) - 157248*k3(exact) + 7488*k4(exact) - 464*k5(exact); +D(exact,6) = D(exact,6) + (-35712495*sk + 11834550*sk2 - 1900090*sk3 + 336960*sk4 - 15440*sk5 + 928*sk6).*dawsonk; +D(exact,6) = D(exact,6) + (39680550 + 16707600*k(exact) + 2948400*k2(exact) + 262080*k3(exact) + 10080*k4(exact)).*dawsonk2; +D(exact,6) = D(exact,6)*(11*sqrt(21*pi)/8192)./k6(exact).*idawsonk2; + +D(exact,7) = 540571185*k(exact) - 78343650*k2(exact) + 23279256*k3(exact) - 1319472*k4(exact) + 119504*k5(exact) - 1952*k6(exact); +D(exact,7) = D(exact,7) + (5946283035*sk - 1786235220*sk2 + 319642092*sk3 - 53155872*sk4 + 2997456*sk5 - 240960*sk6 + 3904*sk7).*dawsonk; +D(exact,7) = D(exact,7) - (6486854220 + 2820371400*k(exact) + 537213600*k2(exact) + 56548800*k3(exact) + 3326400*k4(exact) + 88704*k5(exact)).*dawsonk2; +D(exact,7) = D(exact,7)*(65*sqrt(pi)/65536)./k7(exact).*idawsonk2; + +% approximation +D(approx,2) = 4/3 + 16/63*k(approx) - 16/315*k2(approx) - 128/6237*k3(approx); +D(approx,2) = D(approx,2)*sqrt(pi/5); + +D(approx,3) = 16/105*k(approx) + 32/1155*k2(approx) - 3712/675675*k3(approx) - 5888/2837835*k4(approx); +D(approx,3) = D(approx,3)*sqrt(pi); + +D(approx,4) = 16/231*k2(approx) + 128/10395*k3(approx) - 256/106029*k4(approx); +D(approx,4) = D(approx,4)*sqrt(pi/13); + +D(approx,5) = 128/19305*k3(approx) + 256/220077*k4(approx); +D(approx,5) = D(approx,5)*sqrt(pi/17); + +D(approx,6) = 64/138567*k4(approx); +D(approx,6) = D(approx,6)*sqrt(pi/21); + +D(approx,7) = 256/50702925*k5(approx); +D(approx,7) = D(approx,7)*sqrt(pi); + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/README.txt b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..1577d2291d230e04664584be637510d9af4e7a19 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/README.txt @@ -0,0 +1,237 @@ + +1. Overview + +The nifti1 matlab i/o code is written using matlab object oriented +data structures (in matlab, see help datatypes). The two +main structures are the nifti object, that primarily manages the +metadata (header information) and the file_array object, that manages +the data array and disk files. + +The nifti1 matlab code was provided by John Ashburner, Functional +Imaging Laboratory, Wellcome Department of Imaging Neuroscience, London. +This code is released under the GNU public license, see the license.txt +and gpl.txt files in the distribution. +This niftimatlib release was pulled in March 2012 from the spm8 +release: "Version 4667 (SPM8) 27-Feb-12" + + +2. Install/Build + +The nifti1 matlab i/o code was written to run under MATLAB version 6.5 or higher. +To install, just make sure that the niftimatlib/matlab directory is in your MATLAB +path. For example. in matlab you can run the addpath command: +addpath('/usr/local/pkg/niftimatlib/matlab') +Or, you can copy the contents of the niftimatlib/matlab directory to your <home>/matlab directory. + +There are two C program files included in the distribution: file2mat.c and mat2file.c +to handle file i/o. These need to be compiled into MATLAB mex files. +Precompiled mex files, taken from the spm8 distribution courtesy of the FIL, are included in +this distribution for the following platforms: +mexglx glnx86 Linux on x86 +mexa64 glnxa64 Linux on x86_64 +mexmaci maci Apple Mac OS X on x86 +mexmaci64 maci64 Apple Mac OS X on x86_64 +mexw32 win32 Microsoft Windows on x86 +mexw64 win64 Microsoft Windows on x64 +So, you may not need to do the mex compile. If you do compile, +a Makefile is in the matlab directory. Instructions are in the Makefile, a simple +"make all" should work. Note that you must have a MATLAB version 6.5 or higher mex compiler. +Alternately, a make.m file for calling mex from matlab was contributed by Alle Meije Wink. +Optional C code for a mex interface to Robert Cox's (NIH) nifti_stats.c code is provided +in the @nifti/private/src directory. + + +3. Tiny Example + +Short example for those who want to see something in a hurry (longer example below): +For access to the avg152T1_LR_nifti.nii image see +http://nifti.nimh.nih.gov/nifti-1/data + + +To open an existing nifti1 file: + +>> % be sure to rmpath any paths that point to any spm version +>> % after removing spm paths, clear all, then add niftimatlib path +>> % eg: +>> rmpath(genpath('/usr/local/pkg/spm8')) +>> clear all +>> addpath /usr/local/pkg/niftimatlib-1.2/matlab + + +>> f = nifti('avg152T1_LR_nifti.nii'); +>> disp(f) +NIFTI object: 1-by-1 + dat: [91x109x91 file_array] + mat: [4x4 double] + mat_intent: 'MNI152' + mat0: [4x4 double] + timing: [1x1 struct] + descrip: 'FSL3.2beta' + cal: [0 255] + aux_file: 'none' + + + +>> size(f.dat) + +ans = + + 91 109 91 + + +3. nifti1 i/o Class Structures + + + NIFTI Object + ------------ + + Constructor: + + a = nifti(filename); + a - nifti object + filename - filename for nifti1 dataset. Optional parameter, + if omitted and empty nifti object is returned. + + + Methods: + + create - Create a NIFTI-1 file + disp - Disp a NIFTI-1 object + display - Display a NIFTI-1 object + fieldnames - Fieldnames of a NIFTI-1 object + nifti - Create a NIFTI-1 object + subsasgn - Subscript assignment + subsref - Subscript referencing + + Fields: + + aux_file + cal + dat + descrip + diminfo + intent + mat + mat0 + mat0_intent + mat_intent + timing + + + + FILE_ARRAY Object + ----------------- + + Constructor: + + a = file_array(fname,dim,dtype,offset,scl_slope,scl_inter) + a - file_array object + fname - filename + dim - dimensions (default = [0 0] ) + dtype - datatype (default = 'uint8-le') + offset - offset into file (default = 0) + scl_slope - scalefactor (default = 1) + scl_inter - DC offset, such that dat = raw*scale + inter (default = 0) + + + Methods: + + cat - Concatenate file_array objects. + disp - Display a file_array object + display - Display a file_array object + double - Convert to double precision + end - Overloaded end function for file_array objects + fieldnames - Fieldnames of a file-array object + horzcat - Horizontal concatenation of file_array objects + length - Overloaded length function for file_array objects + ndims - Number of dimensions + numel - Number of simple file arrays involved + numeric - Convert to numeric form + reshape - Overloaded reshape function for file_array objects + size - Overloaded size function for file_array objects + subsasgn - Overloaded subsasgn function for file_array objects + subsref - Subscripted reference. + vertcat - Vertical concatenation of file_array objects + + Disallowed file_array methods: + ctranspose - Complex conjugate transposing is not allowed + permute - Permuting is not allowed + transpose - Transposing is not allowed + + Fields: + + fname + dim + dtype + offset + scl_inter + scl_slope + + + +4. Examples + + % Example of creating a simulated .nii file. + dat = file_array; + dat.fname = 'junk.nii'; + dat.dim = [64 64 32]; + dat.dtype = 'FLOAT64-LE'; + dat.offset = ceil(348/8)*8; + + % alternatively: + % dat = file_array( 'junk.nii',dim,dtype,off,scale,inter) + + disp(dat) + + % Create an empty NIFTI structure + N = nifti; + + fieldnames(N) % Dump fieldnames + + % Creating all the NIFTI header stuff + N.dat = dat; + N.mat = [2 0 0 -110 ; 0 2 0 -110; 0 0 -2 92; 0 0 0 1]; + N.mat_intent = 'xxx'; % dump possibilities + N.mat_intent = 'Scanner'; + N.mat0 = N.mat; + N.mat0_intent = 'Aligned'; + + N.diminfo.slice = 3; + N.diminfo.phase = 2; + N.diminfo.frequency = 2; + N.diminfo.slice_time.code='xxx'; % dump possibilities + N.diminfo.slice_time.code = 'sequential_increasing'; + N.diminfo.slice_time.start = 1; + N.diminfo.slice_time.end = 32; + N.diminfo.slice_time.duration = 3/32; + + N.intent.code='xxx' ; % dump possibilities + N.intent.code='FTEST'; % or N.intent.code=4; + N.intent.param = [4 8]; + + N.timing.toffset = 28800; + N.timing.tspace=3; + N.descrip = 'This is a NIFTI-1 file'; + N.aux_file='aux-file-name.txt'; + N.cal = [0 1]; + + create(N); % Writes hdr info + + %% Note that this call writes the data to the disk file + dat(:,:,:)=0; % Write out the data as all zeros + + [i,j,k] = ndgrid(1:64,1:64,1:32); + dat(find((i-32).^2+(j-32).^2+(k*2-32).^2 < 30^2))=1; % Write some ones in the file + dat(find((i-32).^2+(j-32).^2+(k*2-32).^2 < 15^2))=2; + + + % displaying a slice + imagesc(dat(:,:,12));colorbar + + % get a handle to 'junk.nii'; + M=nifti('junk.nii'); + + imagesc(M.dat(:,:,12)); + + + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/gpl.txt b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/gpl.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d45519c8c6cc926a7d6d96ebc45de7226f66099 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/gpl.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/license.txt b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/license.txt new file mode 100644 index 0000000000000000000000000000000000000000..c224bbbb14631845777fd7494d558f11a3751328 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/license.txt @@ -0,0 +1,96 @@ +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +=================================================================== +The GNU General Public License (gpl.txt) is available from: + http://www.gnu.org/copyleft/gpl.html + +Note: The niftilib matlab files are taken, with permission, from the + SPM8 software package (http://www.fil.ion.ucl.ac.uk/spm/). + Please note that this license pertains only to the files listed below, + dealing with nifti1 i/o methods, and has no bearing at all on the SPM + software package. +=================================================================== +matlab/Makefile +matlab/@file_array/numel.m +matlab/@file_array/permute.m +matlab/@file_array/reshape.m +matlab/@file_array/subsasgn.m +matlab/@file_array/subsref.m +matlab/@file_array/vertcat.m +matlab/@file_array/private/src/README +matlab/@file_array/private/src/file2mat.c +matlab/@file_array/private/src/mat2file.c +matlab/@file_array/private/datatypes.m +matlab/@file_array/private/dim.m +matlab/@file_array/private/dtype.m +matlab/@file_array/private/file2mat.m +matlab/@file_array/private/fname.m +matlab/@file_array/private/mat2file.m +matlab/@file_array/private/mystruct.m +matlab/@file_array/private/offset.m +matlab/@file_array/private/permission.m +matlab/@file_array/private/resize_scales.m +matlab/@file_array/private/scl_inter.m +matlab/@file_array/private/scl_slope.m +matlab/@file_array/cat.m +matlab/@file_array/Contents.m +matlab/@file_array/ctranspose.m +matlab/@file_array/display.m +matlab/@file_array/disp.m +matlab/@file_array/double.m +matlab/@file_array/end.m +matlab/@file_array/fieldnames.m +matlab/@file_array/file_array.m +matlab/@file_array/horzcat.m +matlab/@file_array/isnan.m +matlab/@file_array/length.m +matlab/@file_array/loadobj.m +matlab/@file_array/ndims.m +matlab/@file_array/numeric.m +matlab/@file_array/size.m +matlab/@file_array/transpose.m +matlab/@nifti/private/spm_fileparts.m +matlab/@nifti/private/decode_qform0.m +matlab/@nifti/private/empty_hdr.m +matlab/@nifti/private/encode_qform0.m +matlab/@nifti/private/findindict.m +matlab/@nifti/private/getdict.m +matlab/@nifti/private/M2Q.m +matlab/@nifti/private/mayo2nifti1.m +matlab/@nifti/private/mayostruc.m +matlab/@nifti/private/nifti_stats.m +matlab/@nifti/private/niftistruc.m +matlab/@nifti/private/Q2M.m +matlab/@nifti/private/read_extras.m +matlab/@nifti/private/read_hdr.m +matlab/@nifti/private/read_hdr_raw.m +matlab/@nifti/private/write_extras.m +matlab/@nifti/private/write_hdr_raw.m +matlab/@nifti/private/src/nifti_stats.c +matlab/@nifti/private/src/nifti_stats_mex.c +matlab/@nifti/private/src/nifti1.h +matlab/@nifti/private/src/README +matlab/@nifti/private/spm_existfile.m +matlab/@nifti/Contents.m +matlab/@nifti/create.m +matlab/@nifti/display.m +matlab/@nifti/disp.m +matlab/@nifti/fieldnames.m +matlab/@nifti/nifti.m +matlab/@nifti/structn.m +matlab/@nifti/subsasgn.m +matlab/@nifti/subsref.m +matlab/spm_flip_analyze_images.m + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/Contents.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/Contents.m new file mode 100644 index 0000000000000000000000000000000000000000..0180f20db129a45c67940203853acd2864b76c63 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/Contents.m @@ -0,0 +1,55 @@ +% File Array Object +% +% file_array - create a file_array +% horzcat - horizontal concatenation +% vertcat - vertical concatenation +% size - size of array +% length - length of longest dimension +% subsref - subscripted reference +% end - last index in an indexing expression +% resize - resize (but only of simple file_array structures) +% +% other operations are unlikely to work. +% +% Example usage. +% +% % Create a file array object by mapping test_le.img +% % to a 256x256x100 array, of datatype float32, stored +% % in a little-endian way starting at byte 0. +% fa0 = file_array('test_le.img',[256 256 100], 'FLOAT32-LE',0) +% +% % Creating an object from test_be.img, but skipping +% % the first plane of data. Data stored as big-endian +% fa1 = file_array('test_be.img',[256 256 99], 'FLOAT32-BE',4*256*256) +% +% % Reshape procedure +% fa2 = reshape(fa1,[128 2 256 99]) +% +% % Concatenation +% fa3 = [[fa0 fa0]; [fa0 fa0]] +% fa4 = cat(3,fa0,fa1) +% +% % Note that reshape will not work on the above +% % concatenated objects +% +% % Accessing values from the objects +% img = fa1(:,:,40); +% pixval = fa4(50,50,:); +% small = fa1(1:2:end,1:2:end,40); +% +% % Determining dimensions +% size(fa4) +% size(fa2) +% length(fa0) +% _________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: Contents.m 2696 2009-02-05 20:29:48Z guillaume + +% +% niftilib $Id: Contents.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/cat.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/cat.m new file mode 100644 index 0000000000000000000000000000000000000000..bc3c37e10243df562a7da6adce8fe02299ca3e53 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/cat.m @@ -0,0 +1,44 @@ +function o = cat(dr,varargin) +% Concatenate file_array objects. The result is a non-simple object +% that can no longer be reshaped. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: cat.m 4136 2010-12-09 22:22:28Z guillaume + +% +% niftilib $Id: cat.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +if dr>32 || dr<0, error('Unknown command option.'); end; +dr = max(round(dr),1); +d = ones(nargin-1,16); +tmp = {}; +dpos = 0; +for i=1:nargin-1, + vi = varargin{i}; + if strcmp(class(vi),'file_array') + sz = size(vi); + d(i,1:length(sz)) = sz; + svi = struct(vi); + svi = svi(:); + for j=1:length(svi(:)), + if length(svi(j).pos)<dr + svi(j).pos((length(svi(j).pos)+1):dr) = 1; + end + svi(j).pos(dr)= svi(j).pos(dr) + dpos; + end; + dpos = dpos + d(i,dr); + tmp{i} = svi; + else + error(['Conversion to file_array from ' class(vi) ' is not possible.']); + end; +end; +if any(diff(d(:,[1:(dr-1) (dr+1):end]),1,1)) + error('All matrices on a row in the bracketed expression must have the same number of rows.'); +else + o = vertcat(tmp{:}); + o = file_array(o); +end; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/ctranspose.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/ctranspose.m new file mode 100644 index 0000000000000000000000000000000000000000..6cc309036d450674815b983abc6daa639ccf0248 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/ctranspose.m @@ -0,0 +1,14 @@ +function varargout = ctranspose(varargin) +% Transposing not allowed +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: ctranspose.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: ctranspose.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +error('file_array objects can not be transposed.'); diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/disp.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/disp.m new file mode 100644 index 0000000000000000000000000000000000000000..f33b2fc6a64faa272f5fb584aefa954648704b0e --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/disp.m @@ -0,0 +1,39 @@ +function disp(obj) +% Display a file_array object +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: disp.m 4136 2010-12-09 22:22:28Z guillaume + +% +% niftilib $Id: disp.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +if numel(struct(obj))>1, + fprintf(' %s object: ', class(obj)); + sz = size(obj); + if length(sz)>4, + fprintf('%d-D\n',length(sz)); + else + for i=1:(length(sz)-1), + fprintf('%d-by-',sz(i)); + end; + fprintf('%d\n',sz(end)); + end; +else + disp(mystruct(obj)) +end; +return; +%======================================================================= + +%======================================================================= +function t = mystruct(obj) +fn = fieldnames(obj); +for i=1:length(fn) + t.(fn{i}) = subsref(obj,struct('type','.','subs',fn{i})); +end; +return; +%======================================================================= diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/display.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/display.m new file mode 100644 index 0000000000000000000000000000000000000000..f36a8fdf4e2c23735d25e76f4c8649928b849015 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/display.m @@ -0,0 +1,19 @@ +function display(obj) +% Display a file_array object +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: display.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: display.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +disp(' '); +disp([inputname(1),' = ']) +disp(' '); +disp(obj) +disp(' ') diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/double.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/double.m new file mode 100644 index 0000000000000000000000000000000000000000..dcee922442919845d641add493685c87c2d7a1c2 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/double.m @@ -0,0 +1,17 @@ +function out = double(fa) +% Convert to double precision +% FORMAT double(fa) +% fa - a file_array +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: double.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: double.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +out = double(numeric(fa)); + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/end.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/end.m new file mode 100644 index 0000000000000000000000000000000000000000..39f2bb82fd3370f3b5f0732fd1ab68d5553d29ad --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/end.m @@ -0,0 +1,22 @@ +function en = end(a,k,n) +% Overloaded end function for file_array objects. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: end.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: end.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +dim = size(a); +if k>length(dim) + en = 1; +else + if n<length(dim), + dim = [dim(1:(n-1)) prod(dim(n:end))]; + end; + en = dim(k); +end; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/fieldnames.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/fieldnames.m new file mode 100644 index 0000000000000000000000000000000000000000..7ef162bd5577745da70bbeac62cc3684fb838d10 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/fieldnames.m @@ -0,0 +1,21 @@ +function t = fieldnames(obj) +% Fieldnames of a file-array object +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: fieldnames.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: fieldnames.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +t = {... + 'fname' + 'dim' + 'dtype' + 'offset' + 'scl_slope' + 'scl_inter' +}; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/file_array.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/file_array.m new file mode 100644 index 0000000000000000000000000000000000000000..44fbe2fb36f0832e6ad81ef19cdb0d3a75395ba5 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/file_array.m @@ -0,0 +1,47 @@ +function a = file_array(varargin) +% Function for creating file_array objects. +% FORMAT a = file_array(fname,dim,dtype,offset,scl_slope,scl_inter,permission) +% a - file_array object +% fname - filename +% dim - dimensions (default = [0 0] ) +% dtype - datatype (default = 'uint8-le') +% offset - offset into file (default = 0) +% scl_slope - scalefactor (default = 1) +% scl_inter - DC offset, such that dat = raw*scale + inter (default = 0) +% permission - Write permission, either 'rw' or 'ro' (default = 'rw') +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: file_array.m 4136 2010-12-09 22:22:28Z guillaume + +% +% niftilib $Id: file_array.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +if nargin==1 + if isstruct(varargin{1}), + a = class(varargin{1},'file_array'); + return; + elseif isa(varargin{1},'file_array'), + a = varargin{1}; + return; + end; +end; +a = struct('fname','','dim',[0 0],'dtype',2,... + 'be',0,'offset',0,'pos',[],'scl_slope',[],'scl_inter',[], 'permission','rw'); +%a = class(a,'file_array'); + +if nargin>=1, a = fname(a,varargin{1}); end; +if nargin>=2, a = dim(a,varargin{2}); end; +if nargin>=3, a = dtype(a,varargin{3}); end; +if nargin>=4, a = offset(a,varargin{4}); end; +if nargin>=5, a = scl_slope(a,varargin{5}); end; +if nargin>=6, a = scl_inter(a,varargin{6}); end; +if nargin>=7, a = permission(a,varargin{7}); end; + +a.pos = ones(size(a.dim)); +a = file_array(a); + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/horzcat.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/horzcat.m new file mode 100644 index 0000000000000000000000000000000000000000..46b997c852cec8cc1982a924d15ed08a87e9028c --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/horzcat.m @@ -0,0 +1,16 @@ +function o = horzcat(varargin) +% Horizontal concatenation of file_array objects +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: horzcat.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: horzcat.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +o = cat(2,varargin{:}); +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/isnan.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/isnan.m new file mode 100644 index 0000000000000000000000000000000000000000..986846b5130189291f214a75a4c5a65911f77622 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/isnan.m @@ -0,0 +1,26 @@ +function out = isnan(fa) +% Convert to numeric form +% FORMAT isnan(fa) +% fa - a file_array +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: isnan.m 1301 2008-04-03 13:21:44Z john + +% +% niftilib $Id: isnan.m,v 1.1 2012/03/22 18:36:33 fissell Exp $ +% + + +bs = 10240; +m = size(fa); +fa = reshape(fa,prod(m),1); +n = prod(m); +out = false(m); +for i=1:ceil(n/bs), + ii = ((((i-1)*bs)+1):min((i*bs),n))'; + tmp = subsref(fa,struct('type','()','subs',{{ii}})); + out(ii) = isnan(tmp); +end + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/length.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/length.m new file mode 100644 index 0000000000000000000000000000000000000000..a375b3c0cf411743bd92ab7925590da46ab31704 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/length.m @@ -0,0 +1,16 @@ +function l = length(x) +% Overloaded length function for file_array objects +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: length.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: length.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +l = max(size(x)); + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/loadobj.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/loadobj.m new file mode 100644 index 0000000000000000000000000000000000000000..dafc535fe8de5e16ba9456e5191ae685acb384c8 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/loadobj.m @@ -0,0 +1,19 @@ +function b = loadobj(a) +% loadobj for file_array class +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: loadobj.m 1544 2008-05-06 10:34:36Z guillaume + +% +% niftilib $Id: loadobj.m,v 1.1 2012/03/22 18:36:33 fissell Exp $ +% + + +if isa(a,'file_array') + b = a; +else + a = permission(a, 'rw'); + b = file_array(a); +end diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/ndims.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/ndims.m new file mode 100644 index 0000000000000000000000000000000000000000..c76163b6d25da76c33ed6a2471669ade5e337cd6 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/ndims.m @@ -0,0 +1,17 @@ +function out = ndims(fa) +% Number of dimensions +%_______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: ndims.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: ndims.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +out = size(fa); +out = length(out); + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/numel.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/numel.m new file mode 100644 index 0000000000000000000000000000000000000000..d7931ab0dbbfa3dcb92d9c9fe251c22ff0936e4c --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/numel.m @@ -0,0 +1,19 @@ +function t = numel(obj) +% Number of simple file arrays involved. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: numel.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: numel.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +% Should be this, but it causes problems when accessing +% obj as a structure. +%t = prod(size(obj)); + +t = numel(struct(obj)); diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/numeric.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/numeric.m new file mode 100644 index 0000000000000000000000000000000000000000..3e6872083158ffdc34b0e07170195e93b89b719b --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/numeric.m @@ -0,0 +1,19 @@ +function out = numeric(fa) +% Convert to numeric form +% FORMAT numeric(fa) +% fa - a file_array +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: numeric.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: numeric.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +[vo{1:ndims(fa)}] = deal(':'); +out = subsref(fa,struct('type','()','subs',{vo})); + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/permute.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/permute.m new file mode 100644 index 0000000000000000000000000000000000000000..dd119d05dc9250a5bb6a2d4304b57559a953f6b0 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/permute.m @@ -0,0 +1,15 @@ +function varargout = permute(varargin) +% Can not be permuted. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: permute.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: permute.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +error('file_array objects can not be permuted.'); diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/datatypes.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/datatypes.m new file mode 100644 index 0000000000000000000000000000000000000000..d8ee22db8b0183ef227299cb7e9b5c80403599f7 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/datatypes.m @@ -0,0 +1,61 @@ +function dt = datatypes +% Datatype +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: datatypes.m 4136 2010-12-09 22:22:28Z guillaume + + +% +% niftilib $Id: datatypes.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +persistent dtype +if isempty(dtype), + t = true; + f = false; + table = {... + 0 ,'UNKNOWN' ,'uint8' ,@uint8 ,1,1 ,t,t,f + 1 ,'BINARY' ,'uint1' ,@logical,1,1/8,t,t,f + 256 ,'INT8' ,'int8' ,@int8 ,1,1 ,t,f,t + 2 ,'UINT8' ,'uint8' ,@uint8 ,1,1 ,t,t,t + 4 ,'INT16' ,'int16' ,@int16 ,1,2 ,t,f,t + 512 ,'UINT16' ,'uint16' ,@uint16 ,1,2 ,t,t,t + 8 ,'INT32' ,'int32' ,@int32 ,1,4 ,t,f,t + 768 ,'UINT32' ,'uint32' ,@uint32 ,1,4 ,t,t,t + 1024,'INT64' ,'int64' ,@int64 ,1,8 ,t,f,f + 1280,'UINT64' ,'uint64' ,@uint64 ,1,8 ,t,t,f + 16 ,'FLOAT32' ,'float32' ,@single ,1,4 ,f,f,t + 64 ,'FLOAT64' ,'double' ,@double ,1,8 ,f,f,t + 1536,'FLOAT128' ,'float128',@error ,1,16 ,f,f,f + 32 ,'COMPLEX64' ,'float32' ,@single ,2,4 ,f,f,f + 1792,'COMPLEX128','double' ,@double ,2,8 ,f,f,f + 2048,'COMPLEX256','float128',@error ,2,16 ,f,f,f + 128 ,'RGB24' ,'uint8' ,@uint8 ,3,1 ,t,t,f}; + dtype = struct(... + 'code' ,table(:,1),... + 'label' ,table(:,2),... + 'prec' ,table(:,3),... + 'conv' ,table(:,4),... + 'nelem' ,table(:,5),... + 'size' ,table(:,6),... + 'isint' ,table(:,7),... + 'unsigned' ,table(:,8),... + 'min',-Inf,'max',Inf',... + 'supported',table(:,9)); + for i=1:length(dtype), + if dtype(i).isint + if dtype(i).unsigned + dtype(i).min = 0; + dtype(i).max = 2^(8*dtype(i).size)-1; + else + dtype(i).min = -2^(8*dtype(i).size-1); + dtype(i).max = 2^(8*dtype(i).size-1)-1; + end; + end; + end; +end; + +dt = dtype; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/dim.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/dim.m new file mode 100644 index 0000000000000000000000000000000000000000..e4a1438cf637f26345549c40f834ecd5396d7307 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/dim.m @@ -0,0 +1,42 @@ +function varargout = dim(varargin) +% Format +% For getting the value +% dat = dim(obj) +% +% For setting the value +% obj = dim(obj,dat) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: dim.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: dim.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +if nargin==2, + varargout{1} = asgn(varargin{:}); +elseif nargin==1, + varargout{1} = ref(varargin{:}); +else + error('Wrong number of arguments.'); +end; +return; + +function dat = ref(obj) +dat = obj.dim; +return; + +function obj = asgn(obj,dat) +if isnumeric(dat) && all(dat>=0) && all(rem(dat,1)==0), + dat = [double(dat(:)') 1 1]; + lim = max([2 find(dat~=1)]); + dat = dat(1:lim); + obj.dim = dat; +else + error('"dim" must be a vector of positive integers.'); +end; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/dtype.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/dtype.m new file mode 100644 index 0000000000000000000000000000000000000000..dca0a23b99178aa1cbae66ba682917a55f2511b2 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/dtype.m @@ -0,0 +1,91 @@ +function varargout = dtype(varargin) +% Format +% For getting the value +% dat = dtype(obj) +% +% For setting the value +% obj = dtype(obj,dat) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: dtype.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: dtype.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + + +if nargin==2, + varargout{1} = asgn(varargin{:}); +elseif nargin==1, + varargout{1} = ref(varargin{:}); +else + error('Wring number of arguments.'); +end; +return; + +function t = ref(obj) +d = datatypes; +mch = find(cat(1,d.code)==obj.dtype); +if isempty(mch), t = 'UNKNOWN'; else t = d(mch).label; end; +if obj.be, t = [t '-BE']; else t = [t '-LE']; end; +return; + +function obj = asgn(obj,dat) +d = datatypes; +if isnumeric(dat) + if numel(dat)>=1, + mch = find(cat(1,d.code)==dat(1)); + if isempty(mch) || mch==0, + fprintf('Invalid datatype (%d).', dat(1)); + disp('First part of datatype should be of one of the following'); + disp(sortrows([num2str(cat(1,d.code)) ... + repmat(' ',numel(d),2) strvcat(d.label)])); + %error(['Invalid datatype (' num2str(dat(1)) ').']); + return; + end; + obj.dtype = double(dat(1)); + end; + if numel(dat)>=2, + obj.be = double(dat(2)~=0); + end; + if numel(dat)>2, + error('Too many elements in numeric datatype.'); + end; +elseif ischar(dat), + dat1 = lower(dat); + sep = find(dat1=='-' | dat1=='/'); + sep = sep(sep~=1); + if ~isempty(sep), + c1 = dat1(1:(sep(1)-1)); + c2 = dat1((sep(1)+1):end); + else + c1 = dat1; + c2 = ''; + end; + mch = find(strcmpi(c1,lower({d.label}))); + if isempty(mch), + disp('First part of datatype should be of one of the following'); + disp(sortrows([num2str(cat(1,d.code)) ... + repmat(' ',numel(d),2) strvcat(d.label)])); + %error(['Invalid datatype (' c1 ').']); + return; + else + obj.dtype = double(d(mch(1)).code); + end; + if any(c2=='b'), + if any(c2=='l'), + error('Cannot be both big and little endian.'); + end; + obj.be = 1; + elseif any(c2=='l'), + obj.be = 0; + end; +else + error('Invalid datatype.'); +end; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.m new file mode 100644 index 0000000000000000000000000000000000000000..819946828648509a09ac1471bcc8947de13fccaf --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.m @@ -0,0 +1,21 @@ +function val = file2mat(a,varargin) +% Function for reading from file_array objects. +% FORMAT val = file2mat(a,ind1,ind2,ind3,...) +% a - file_array object +% indx - indices for dimension x (int32) +% val - the read values +% +% This function is normally called by file_array/subsref +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% John Ashburner +% Id: file2mat.m 1530 2008-04-30 19:28:22Z guillaume + +% +% niftilib $Id: file2mat.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +%-This is merely the help file for the compiled routine +error('file2mat.c not compiled - see Makefile'); diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexa64 b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexa64 new file mode 100644 index 0000000000000000000000000000000000000000..e0f76658c7a7e87b895864d43b19ba06af2946ea Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexa64 differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexglx b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexglx new file mode 100644 index 0000000000000000000000000000000000000000..745b68660baaf9c0dccc97a116fa006c54497345 Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexglx differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexmaci b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexmaci new file mode 100644 index 0000000000000000000000000000000000000000..b932e4f334a808e12e28dd27a8bf1d24ab0e3e0c Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexmaci differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexmaci64 b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexmaci64 new file mode 100755 index 0000000000000000000000000000000000000000..d5a41f9db23b8d54e56afb6fe4ba26047766c8ca Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexmaci64 differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexw32 b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexw32 new file mode 100755 index 0000000000000000000000000000000000000000..1eb71ec9216aef2d33bc4b25fd14b7d3d294dd77 Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexw32 differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexw64 b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexw64 new file mode 100644 index 0000000000000000000000000000000000000000..9f06847197ed239024918faf2aa3b39ce735a1f5 Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/file2mat.mexw64 differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/fname.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/fname.m new file mode 100644 index 0000000000000000000000000000000000000000..42ea71267d0cd47f06049689b95bae750330936e --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/fname.m @@ -0,0 +1,40 @@ +function varargout = fname(varargin) +% Format +% For getting the value +% dat = fname(obj) +% +% For setting the value +% obj = fname(obj,dat) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: fname.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: fname.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + + +if nargin==2, + varargout{1} = asgn(varargin{:}); +elseif nargin==1, + varargout{1} = ref(varargin{:}); +else + error('Wrong number of arguments.'); +end; +return; + +function dat = ref(obj) +dat = obj.fname; +return; + +function obj = asgn(obj,dat) +if ischar(dat) + obj.fname = deblank(dat(:)'); +else + error('"fname" must be a character string.'); +end; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.m new file mode 100644 index 0000000000000000000000000000000000000000..12f140c848b431bc527677a3834da4595875c85a --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.m @@ -0,0 +1,21 @@ +function mat2file(a,val,varargin) +% Function for writing to file_array objects. +% FORMAT mat2file(a,val,ind1,ind2,ind3,...) +% a - file_array object +% val - values to write +% indx - indices for dimension x (int32) +% +% This function is normally called by file_array/subsasgn +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% John Ashburner +% Id: mat2file.m 1530 2008-04-30 19:28:22Z guillaume + +% +% niftilib $Id: mat2file.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +%-This is merely the help file for the compiled routine +error('mat2file.c not compiled - see Makefile'); diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexa64 b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexa64 new file mode 100644 index 0000000000000000000000000000000000000000..4b264678e6136c7085d9281e5c2e616b87238ac0 Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexa64 differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexglx b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexglx new file mode 100644 index 0000000000000000000000000000000000000000..3f277ed0ec84038e43efa73429ba9b77f58aef9a Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexglx differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexmaci b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexmaci new file mode 100644 index 0000000000000000000000000000000000000000..56a9a2f3f2dd1328171202d058c0e8762f77a6b1 Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexmaci differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexmaci64 b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexmaci64 new file mode 100755 index 0000000000000000000000000000000000000000..6c7da4370ea201514ca6a5527b38dd2f5d49c705 Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexmaci64 differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexw32 b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexw32 new file mode 100755 index 0000000000000000000000000000000000000000..783d6fb855cac0e53be08c0acb2c7291ba53e9e2 Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexw32 differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexw64 b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexw64 new file mode 100644 index 0000000000000000000000000000000000000000..2ba10482c90dae85d8b375aa47c5d5b85517c2ea Binary files /dev/null and b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mat2file.mexw64 differ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mystruct.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mystruct.m new file mode 100644 index 0000000000000000000000000000000000000000..124b802395c1d045856789427d735123598ccbcd --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/mystruct.m @@ -0,0 +1,21 @@ +function t = mystruct(obj) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: mystruct.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: mystruct.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +if numel(obj)~=1, + error('Too many elements to convert'); +end; +fn = fieldnames(obj); +for i=1:length(fn) + t.(fn{i}) = subsref(obj,struct('type','.','subs',fn{i})); +end; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/offset.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/offset.m new file mode 100644 index 0000000000000000000000000000000000000000..258487bfea1bc08ba0b58613e6c413bb67ed7feb --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/offset.m @@ -0,0 +1,40 @@ +function varargout = offset(varargin) +% Format +% For getting the value +% dat = offset(obj) +% +% For setting the value +% obj = offset(obj,dat) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: offset.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: offset.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + + +if nargin==2, + varargout{1} = asgn(varargin{:}); +elseif nargin==1, + varargout{1} = ref(varargin{:}); +else + error('Wrong number of arguments.'); +end; +return; + +function dat = ref(obj) +dat = obj.offset; +return; + +function obj = asgn(obj,dat) +if isnumeric(dat) && numel(dat)==1 && dat>=0 && rem(dat,1)==0, + obj.offset = double(dat); +else + error('"offset" must be a positive integer.'); +end; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/permission.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/permission.m new file mode 100644 index 0000000000000000000000000000000000000000..270187192d289436f35189e6f2ff70fd0b1170d9 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/permission.m @@ -0,0 +1,48 @@ +function varargout = permission(varargin) +% Format +% For getting the value +% dat = permission(obj) +% +% For setting the value +% obj = permission(obj,dat) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: permission.m 1340 2008-04-09 17:11:23Z john + +% +% niftilib $Id: permission.m,v 1.1 2012/03/22 18:36:33 fissell Exp $ +% + + + + +if nargin==2, + varargout{1} = asgn(varargin{:}); +elseif nargin==1, + varargout{1} = ref(varargin{:}); +else + error('Wrong number of arguments.'); +end; +return; + +function dat = ref(obj) +dat = obj.permission; +return; + +function obj = asgn(obj,dat) +if ischar(dat) + tmp = lower(deblank(dat(:)')); + switch tmp, + case 'ro', + case 'rw', + otherwise, + error('Permission must be either "ro" or "rw"'); + end + obj.permission = tmp; +else + error('"permission" must be a character string.'); +end; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/resize_scales.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/resize_scales.m new file mode 100644 index 0000000000000000000000000000000000000000..99f6fe8f3ca2f2406076949ea0f355ae06e13b8d --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/resize_scales.m @@ -0,0 +1,29 @@ +function s1 = resize_scales(s0,dim,args) +% Resize scalefactors +% _________________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: resize_scales.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: resize_scales.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +dim = [dim ones(1,max(numel(args)-numel(dim),0))]; +args1 = cell(1,numel(args)); +for i=1:numel(args), + if max(args{i})>dim(i) || min(args{i})<1, + error('Index exceeds matrix dimensions (1).'); + end; + + if size(s0,i)==1, + args1{i} = ones(size(args{i})); + else + args1{i} = args{i}; + end; +end; + +s1 = s0(args1{:}); + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/scl_inter.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/scl_inter.m new file mode 100644 index 0000000000000000000000000000000000000000..2fad537ec6b09eed8f8db69f8fe8e1d1c72ee64b --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/scl_inter.m @@ -0,0 +1,41 @@ +function varargout = scl_inter(varargin) +% Format +% For getting the value +% dat = scl_inter(obj) +% +% For setting the value +% obj = scl_inter(obj,dat) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: scl_inter.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: scl_inter.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + + +if nargin==2, + varargout{1} = asgn(varargin{:}); +elseif nargin==1, + varargout{1} = ref(varargin{:}); +else + error('Wrong number of arguments.'); +end; +return; + +function dat = ref(obj) +dat = obj.scl_inter; +return; + +function obj = asgn(obj,dat) +if isnumeric(dat), % && numel(dat)<=1, + obj.scl_inter = double(dat); +else + error('"scl_inter" must be numeric.'); +end; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/scl_slope.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/scl_slope.m new file mode 100644 index 0000000000000000000000000000000000000000..75d66179ea7721629732864b6db9d25867ea5d5a --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/scl_slope.m @@ -0,0 +1,40 @@ +function varargout = scl_slope(varargin) +% Format +% For getting the value +% dat = scl_slope(obj) +% +% For setting the value +% obj = scl_slope(obj,dat) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: scl_slope.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: scl_slope.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + + +if nargin==2, + varargout{1} = asgn(varargin{:}); +elseif nargin==1, + varargout{1} = ref(varargin{:}); +else + error('Wrong number of arguments.'); +end; +return; + +function dat = ref(obj) +dat = obj.scl_slope; +return; + +function obj = asgn(obj,dat) +if isnumeric(dat), % && numel(dat)<=1, + obj.scl_slope = double(dat); +else + error('"scl_slope" must be numeric.'); +end; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/README b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/README new file mode 100644 index 0000000000000000000000000000000000000000..6e5df6286e3de280dfcfe288fb001a092c4da792 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/README @@ -0,0 +1,12 @@ +To compile on a big-endian machine + mex -O -DBIGENDIAN file2mat.c + mex -O -DBIGENDIAN mat2file.c + +On a little-endian machine + mex -O file2mat.c + mex -O mat2file.c + +On a Windows machine + mex -O -DSPM_WIN32 file2mat.c + mex -O -DSPM_WIN32 mat2file.c + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/file2mat.c b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/file2mat.c new file mode 100644 index 0000000000000000000000000000000000000000..6e96cf20a170f3c42b97b2ccb5ab1f038b14cb52 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/file2mat.c @@ -0,0 +1,644 @@ +/* + * Id: file2mat.c 4136 2010-12-09 22:22:28Z guillaume + * John Ashburner + */ + +/* + * niftilib $Id: file2mat.c,v 1.3 2012/03/22 18:36:33 fissell Exp $ + */ + +/* +Memory mapping is used by this module. For more information on this, see: +http://www.mathworks.com/company/newsletters/digest/mar04/memory_map.html +*/ + +#define _FILE_OFFSET_BITS 64 + +#include <math.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <sys/types.h> +#include <string.h> +#include <stdio.h> +#include "mex.h" + +#ifdef SPM_WIN32 +#include <windows.h> +#include <memory.h> +#include <io.h> +HANDLE hFile, hMapping; +typedef char *caddr_t; +#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64 +#define stat _stati64 +#define fstat _fstati64 +#define open _open +#define close _close +#if defined _MSC_VER +#define size_t __int64 +#else +#define size_t unsigned long long +#endif +#endif +#else +#include <sys/mman.h> +#include <unistd.h> +#include <errno.h> +#define size_t unsigned long long +#endif + +/* +http://en.wikipedia.org/wiki/Page_(computing)#Determining_the_page_size_in_a_program +http://msdn.microsoft.com/en-us/library/aa366763(VS.85).aspx +*/ +int page_size() +{ +int size = 0; + +#if defined (_WIN32) || defined (_WIN64) + SYSTEM_INFO info; + GetSystemInfo (&info); + size = (int)info.dwAllocationGranularity; +#else + size = sysconf(_SC_PAGESIZE); +#endif + +return size; +} + + +#define MXDIMS 256 + +static long long icumprod[MXDIMS], ocumprod[MXDIMS]; + +static void get_1_sat(int ndim, int idim[], int *iptr[], unsigned char idat[], int odim[], unsigned char odat[], int indi, int indo) +{ + int i; + if (ndim == 0) + { + for(i=0; i<odim[0]; i++) + { + int tmp = indi+iptr[0][i]-1; + odat[indo++] = (idat[tmp>>3]>>(tmp&7))&1; + } + } + else + { + for(i=0; i<odim[ndim]; i++) + get_1_sat(ndim-1, idim, iptr, idat, odim, odat, + indi+icumprod[ndim]*(iptr[ndim][i]-1), indo+ocumprod[ndim]*i); + } +} + +void get_1(int ndim, int idim[], int *iptr[], unsigned char idat[], int odim[], unsigned char odat[]) +{ + get_1_sat(ndim, idim, iptr, idat, odim, odat, 0, 0); +} + +void get_8(int ndim, int idim[], int *iptr[], unsigned char idat[], int odim[], unsigned char odat[]) +{ + int i; + if (!ndim) + { + for(i=0; i<odim[0]; i++) + odat[i] = idat[iptr[0][i]-1]; + } + else + { + for(i=0; i<odim[ndim]; i++) + get_8(ndim-1, idim, iptr, idat+icumprod[ndim]*(iptr[ndim][i]-1), + odim, odat+ocumprod[ndim]*i); + } +} + +void get_16(int ndim, int idim[], int *iptr[], unsigned short idat[], int odim[], unsigned short odat[]) +{ + int i; + if (!ndim) + { + for(i=0; i<odim[0]; i++) + odat[i] = idat[iptr[0][i]-1]; + } + else + { + for(i=0; i<odim[ndim]; i++) + get_16(ndim-1, idim, iptr, idat+icumprod[ndim]*(iptr[ndim][i]-1), + odim, odat+ocumprod[ndim]*i); + } +} + +void get_32(int ndim, int idim[], int *iptr[], unsigned int idat[], int odim[], unsigned int odat[]) +{ + int i; + if (!ndim) + { + for(i=0; i<odim[0]; i++) + odat[i] = idat[iptr[0][i]-1]; + } + else + { + for(i=0; i<odim[ndim]; i++) + get_32(ndim-1, idim, iptr, idat+icumprod[ndim]*(iptr[ndim][i]-1), + odim, odat+ocumprod[ndim]*i); + } +} + +void get_64(int ndim, int idim[], int *iptr[], unsigned long long idat[], int odim[], unsigned long long odat[]) +{ + int i; + if (ndim == 0) + { + for(i=0; i<odim[0]; i++) + odat[i] = idat[iptr[0][i]-1]; + } + else + { + for(i=0; i<odim[ndim]; i++) + get_64(ndim-1, idim, iptr, idat+icumprod[ndim]*(iptr[ndim][i]-1), + odim, odat+ocumprod[ndim]*i); + } +} + +void get_w8(int ndim, int idim[], int *iptr[], unsigned char idat[], + int odim[], unsigned char odat_r[], unsigned char odat_i[]) +{ + int i; + if (ndim == 0) + { + int off; + for(i=0; i<odim[0]; i++) + { + off = 2*(iptr[0][i]-1); + odat_r[i] = idat[off ]; + odat_i[i] = idat[off+1]; + } + } + else + { + for(i=0; i<odim[ndim]; i++) + get_w8(ndim-1, idim, iptr, idat+icumprod[ndim]*(iptr[ndim][i]-1), + odim, odat_r+ocumprod[ndim]*i,odat_i+ocumprod[ndim]*i); + } +} + +void get_w16(int ndim, int idim[], int *iptr[], unsigned short idat[], + int odim[], unsigned short odat_r[], unsigned short odat_i[]) +{ + int i; + if (ndim == 0) + { + int off; + for(i=0; i<odim[0]; i++) + { + off = 2*(iptr[0][i]-1); + odat_r[i] = idat[off ]; + odat_i[i] = idat[off+1]; + } + } + else + { + for(i=0; i<odim[ndim]; i++) + get_w16(ndim-1, idim, iptr, idat+icumprod[ndim]*(iptr[ndim][i]-1), + odim, odat_r+ocumprod[ndim]*i,odat_i+ocumprod[ndim]*i); + } +} + +void get_w32(int ndim, int idim[], int *iptr[], unsigned int idat[], + int odim[], unsigned int odat_r[], unsigned int odat_i[]) +{ + int i; + if (ndim == 0) + { + int off; + for(i=0; i<odim[0]; i++) + { + off = 2*(iptr[0][i]-1); + odat_r[i] = idat[off ]; + odat_i[i] = idat[off+1]; + } + } + else + { + for(i=0; i<odim[ndim]; i++) + get_w32(ndim-1, idim, iptr, idat+icumprod[ndim]*(iptr[ndim][i]-1), + odim, odat_r+ocumprod[ndim]*i,odat_i+ocumprod[ndim]*i); + } +} + +void get_w64(int ndim, int idim[], int *iptr[], unsigned long long idat[], + int odim[], unsigned long long odat_r[], unsigned long long odat_i[]) +{ + int i; + if (ndim == 0) + { + int off; + for(i=0; i<odim[0]; i++) + { + off = 2*(iptr[0][i]-1); + odat_r[i] = idat[off ]; + odat_i[i] = idat[off+1]; + } + } + else + { + for(i=0; i<odim[ndim]; i++) + get_w64(ndim-1, idim, iptr, idat+icumprod[ndim]*(iptr[ndim][i]-1), + odim, odat_r+ocumprod[ndim]*i, odat_i+ocumprod[ndim]*i); + } +} + +void swap8(long long n, unsigned char d[]) +{ /* DO NOTHING */} + +void swap16(long long n, unsigned char d[]) +{ + unsigned char tmp, *de; + for(de=d+2*n; d<de; d+=2) + { + tmp = d[0]; d[0] = d[1]; d[1] = tmp; + } +} + +void swap32(long long n, unsigned char d[]) +{ + unsigned char tmp, *de; + for(de=d+4*n; d<de; d+=4) + { + tmp = d[0]; d[0] = d[3]; d[3] = tmp; + tmp = d[1]; d[1] = d[2]; d[2] = tmp; + } +} + +void swap64(long long n, unsigned char d[]) +{ + unsigned char tmp, *de; + for(de=d+8*n; d<de; d+=8) + { + tmp = d[0]; d[0] = d[7]; d[7] = tmp; + tmp = d[1]; d[1] = d[6]; d[6] = tmp; + tmp = d[2]; d[2] = d[5]; d[5] = tmp; + tmp = d[3]; d[3] = d[4]; d[4] = tmp; + } +} + +typedef struct dtype { + int code; + void (*func)(); + void (*swap)(); + int clss; + int bytes; + int channels; +} Dtype; + +Dtype table[] = { +{ 1,get_1 , swap8 , mxLOGICAL_CLASS, 1,1}, +{ 2,get_8 , swap8 , mxUINT8_CLASS , 8,1}, +{ 4,get_16 , swap16, mxINT16_CLASS ,16,1}, +{ 8,get_32 , swap32, mxINT32_CLASS ,32,1}, +{ 16,get_32 , swap32, mxSINGLE_CLASS ,32,1}, +{ 32,get_w32, swap32, mxSINGLE_CLASS ,32,2}, +{ 64,get_64 , swap64, mxDOUBLE_CLASS ,64,1}, +{ 256,get_8 , swap8 , mxINT8_CLASS , 8,1}, +{ 512,get_16 , swap16, mxUINT16_CLASS ,16,1}, +{ 768,get_32 , swap32, mxUINT32_CLASS ,32,1}, +{1792,get_w64, swap64, mxDOUBLE_CLASS ,64,2} +}; + +typedef struct mtype { + int ndim; + int dim[MXDIMS]; + Dtype *dtype; + int swap; + caddr_t addr; + size_t len; +#ifdef SPM_WIN32 + ULONGLONG off; +#else + off_t off; +#endif + void *data; +} MTYPE; + +#ifdef SPM_WIN32 +void werror(char *where, DWORD last_error) +{ + char buf[512]; + char s[1024]; + int i; + i = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + last_error, + 0, + buf, + 512/sizeof(TCHAR), + NULL ); + buf[i-2] = '\0'; /* remove \r\n */ + (void)sprintf(s,"%s: %s", where, buf); + mexErrMsgTxt(s); + return; +} +#else +void werror(char *where, int last_error) +{ + char s[1024]; + + (void)sprintf(s,"%s: %s", where, strerror(last_error)); + mexErrMsgTxt(s); + return; +} +#endif + +void do_unmap_file(MTYPE *map) +{ + int sts; + if (map->addr) + { +#ifdef SPM_WIN32 + sts = UnmapViewOfFile((LPVOID)(map->addr)); + if (sts == 0) + werror("Memory Map (UnmapViewOfFile)",GetLastError()); +#else + sts = munmap(map->addr, map->len); + if (sts == -1) + werror("Memory Map (munmap)",errno); +#endif + map->addr = NULL; + } +} + +const double *getpr(const mxArray *ptr, const char nam[], int len, int *n) +{ + char s[128]; + mxArray *arr; + + arr = mxGetField(ptr,0,nam); + if (arr == (mxArray *)0) + { + (void)sprintf(s,"'%s' field is missing.", nam); + mexErrMsgTxt(s); + } + if (!mxIsNumeric(arr) && !mxIsLogical(arr)) + { + (void)sprintf(s,"'%s' field is non-numeric.", nam); + mexErrMsgTxt(s); + } + if (!mxIsDouble(arr)) + { + (void)sprintf(s,"'%s' field is not double precision.", nam); + mexErrMsgTxt(s); + } + if (len>=0) + { + *n = mxGetM(arr)*mxGetN(arr); + if (*n != len) + { + (void)sprintf(s,"'%s' field should have %d elements (has %d).", nam, len, *n); + mexErrMsgTxt(s); + } + } + else + { + *n = mxGetM(arr)*mxGetN(arr); + if (*n > -len) + { + (void)sprintf(s,"'%s' field should have a maximum of %d elements (has %d).", nam, -len, *n); + mexErrMsgTxt(s); + } + } + return (double *)mxGetData(arr); +} + +void do_map_file(const mxArray *ptr, MTYPE *map) +{ + int n; + int i, dtype; +#ifdef SPM_WIN32 + ULONGLONG offset = 0; +#else + off_t offset = 0; +#endif + const double *pr; + mxArray *arr; + size_t siz; + if (!mxIsStruct(ptr)) mexErrMsgTxt("Not a structure."); + + dtype = (int)(getpr(ptr, "dtype", 1, &n)[0]); + for(i=0; i<sizeof(table)/sizeof(Dtype); i++) + { + if (table[i].code == dtype) + { + map->dtype = &table[i]; + break; + } + } + if (map->dtype == NULL) mexErrMsgTxt("Unrecognised 'dtype' value."); + pr = getpr(ptr, "dim", -MXDIMS, &n); + map->ndim = n; + siz = 1; + for(i=0; i<map->ndim; i++) + { + map->dim[i] = (int)fabs(pr[i]); + siz = siz*map->dim[i]; + } + + /* Avoid overflow if possible */ + if (map->dtype->bytes % 8) + siz = (map->dtype->bytes*siz+7)/8; + else + siz = siz*(map->dtype->bytes/8); + + /* On 32bit platforms, cannot map more than 2^31-1 bytes */ + if ((sizeof(map->data) == 4) && (siz > 2147483647ULL)) + mexErrMsgTxt("The total number of bytes mapped is too large."); + + pr = getpr(ptr, "be",1, &n); +#ifdef SPM_BIGENDIAN + map->swap = (int)pr[0]==0; +#else + map->swap = (int)pr[0]!=0; +#endif + pr = getpr(ptr, "offset",1, &n); +#ifdef SPM_WIN32 + map->off = (ULONGLONG)pr[0]; +#else + map->off = (off_t)pr[0]; +#endif + if (map->off < 0) map->off = 0; + + arr = mxGetField(ptr,0,"fname"); + if (arr == (mxArray *)0) mexErrMsgTxt("Cant find fname."); + if (mxIsChar(arr)) + { + int buflen; + char *buf; + int fd; + struct stat stbuf; + buflen = mxGetN(arr)*mxGetM(arr)+1; + buf = mxCalloc(buflen,sizeof(char)); + if (mxGetString(arr,buf,buflen)) + { + mxFree(buf); + mexErrMsgTxt("Cant get filename."); + } + if ((fd = open(buf, O_RDONLY)) == -1) + { + mxFree(buf); + mexErrMsgTxt("Cant open file."); + } + if (fstat(fd, &stbuf) == -1) + { + (void)close(fd); + mxFree(buf); + mexErrMsgTxt("Cant get file size."); + } + if (stbuf.st_size < siz + map->off) + { + (void)close(fd); + mxFree(buf); + mexErrMsgTxt("File is smaller than the dimensions say it should be."); + } + offset = map->off % page_size(); + map->len = siz + (size_t)offset; + map->off = map->off - offset; +#ifdef SPM_WIN32 + (void)close(fd); + + /* http://msdn.microsoft.com/library/default.asp? + url=/library/en-us/fileio/base/createfile.asp */ + hFile = CreateFile( + buf, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, + NULL); + mxFree(buf); + if (hFile == NULL) + werror("Memory Map (CreateFile)",GetLastError()); + + /* http://msdn.microsoft.com/library/default.asp? + url=/library/en-us/fileio/base/createfilemapping.asp */ + hMapping = CreateFileMapping( + hFile, + NULL, + PAGE_READONLY, + 0, + 0, + NULL); + (void)CloseHandle(hFile); + if (hMapping == NULL) + werror("Memory Map (CreateFileMapping)",GetLastError()); + + /* http://msdn.microsoft.com/library/default.asp? + url=/library/en-us/fileio/base/mapviewoffile.asp */ + map->addr = (caddr_t)MapViewOfFile( + hMapping, + FILE_MAP_READ, + (DWORD)(map->off >> 32), + (DWORD)(map->off), + map->len); + (void)CloseHandle(hMapping); + if (map->addr == NULL) + werror("Memory Map (MapViewOfFile)",GetLastError()); +#else + map->addr = mmap( + (caddr_t)0, + map->len, + PROT_READ, + MAP_SHARED, + fd, + map->off); + (void)close(fd); + mxFree(buf); + if (map->addr == (void *)-1) + werror("Memory Map (mmap)",errno); +#endif + } + map->data = (void *)((caddr_t)map->addr + offset); +} + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + MTYPE map; + void *idat; + int i; + int *iptr[MXDIMS], odim[MXDIMS], *idim, ndim; + int one[1]; + one[0] = 1; + + if (nrhs<2 || nlhs>1) mexErrMsgTxt("Incorrect usage."); + + do_map_file(prhs[0], &map); + + ndim = map.ndim; + idim = map.dim; + idat = map.data; + + if (ndim >= MXDIMS) mexErrMsgTxt("Too many dimensions."); + + /* if (nrhs > ndim+1) mexErrMsgTxt("Index exceeds matrix dimensions (1)."); */ + + for(i=0;i<nrhs-1; i++) + { + int j; + if (!mxIsNumeric(prhs[i+1]) || !mxIsInt32(prhs[i+1]) || mxIsComplex(prhs[i+1])) + { + do_unmap_file(&map); + mexErrMsgTxt("Indices must be int32."); + } + odim[i] = mxGetM(prhs[i+1])*mxGetN(prhs[i+1]); + iptr[i] = (int *)mxGetData(prhs[i+1]); + for(j=0; j<odim[i]; j++) + if (iptr[i][j]<1 || iptr[i][j]>((i<ndim)?idim[i]:1)) + { + do_unmap_file(&map); + mexErrMsgTxt("Index exceeds matrix dimensions (1)."); + } + } + + for(i=nrhs-1; i<ndim; i++) + { + odim[i] = 1; + iptr[i] = one; + } + if (ndim<nrhs-1) + { + for(i=ndim; i<nrhs-1; i++) + idim[i] = 1; + ndim = nrhs-1; + } + + icumprod[0] = map.dtype->channels; + ocumprod[0] = 1; + for(i=0; i<ndim; i++) + { + icumprod[i+1] = icumprod[i]*(long long)idim[i]; + ocumprod[i+1] = ocumprod[i]*(long long)odim[i]; + + /* Fix for each plane of 1 bit Analyze images being + padded out to a whole number of bytes */ + if (map.dtype->bytes==1 && i==1) + icumprod[i+1] = ((icumprod[i+1]+7)/8)*8; + } + + if (map.dtype->channels == 1) + { + plhs[0] = mxCreateNumericArray(ndim,odim,map.dtype->clss,mxREAL); + map.dtype->func(ndim-1, idim, iptr, idat, odim, mxGetData(plhs[0])); + if (map.swap) + map.dtype->swap(ocumprod[ndim],mxGetData(plhs[0])); + } + else if (map.dtype->channels == 2) + { + plhs[0] = mxCreateNumericArray(ndim,odim,map.dtype->clss,mxCOMPLEX); + (map.dtype->func)(ndim-1, idim, iptr, idat, odim, mxGetData(plhs[0]),mxGetImagData(plhs[0])); + if (map.swap) + { + map.dtype->swap(ocumprod[ndim],mxGetData(plhs[0])); + map.dtype->swap(ocumprod[ndim],mxGetImagData(plhs[0])); + } + } + + do_unmap_file(&map); +} diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/mat2file.c b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/mat2file.c new file mode 100644 index 0000000000000000000000000000000000000000..09ae79548205251d48fda31d232da228702f2f3d --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/private/src/mat2file.c @@ -0,0 +1,385 @@ +/* + * Id: mat2file.c 2896 2009-03-18 20:43:48Z guillaume + * John Ashburner + */ + +/* + * niftilib $Id: mat2file.c,v 1.3 2012/03/22 18:36:33 fissell Exp $ + */ + + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 + +#include <math.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <stdio.h> +#include "mex.h" +#ifdef SPM_WIN32 +#include <windows.h> +#include <memory.h> +#include <io.h> +#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64 +#if defined _MSC_VER +#define off_t __int64 +#define fseeko _fseeki64 +#else +#define off_t off64_t +#define fseeko fseeko64 +#endif +#endif +#endif + +#define MXDIMS 256 + +typedef struct dtype { + int code; + void (*swap)(); + mxClassID clss; + int bits; + int channels; +} Dtype; + +#define copy swap8 + +void swap8(int n, unsigned char id[], unsigned char od[]) +{ + unsigned char *de; + for(de=id+n; id<de; id++, od++) + { + *od = *id; + } +} + +void swap16(int n, unsigned char id[], unsigned char od[]) +{ + unsigned char tmp, *de; + for(de=id+n; id<de; id+=2, od+=2) + { + tmp = id[0]; od[0] = id[1]; od[1] = tmp; + } +} + +void swap32(int n, unsigned char id[], unsigned char od[]) +{ + unsigned char tmp, *de; + for(de=id+n; id<de; id+=4, od+=4) + { + tmp = id[0]; od[0] = id[3]; od[3] = tmp; + tmp = id[1]; od[1] = id[2]; od[2] = tmp; + } +} + +void swap64(int n, unsigned char id[], unsigned char od[]) +{ + unsigned char tmp, *de; + for(de=id+n; id<de; id+=8, od+=8) + { + tmp = id[0]; od[0] = id[7]; od[7] = tmp; + tmp = id[1]; od[1] = id[6]; od[6] = tmp; + tmp = id[2]; od[2] = id[5]; od[5] = tmp; + tmp = id[3]; od[3] = id[4]; od[4] = tmp; + } +} + + +Dtype table[] = { +{ 1, swap8 , mxLOGICAL_CLASS, 1,1}, +{ 2, swap8 , mxUINT8_CLASS , 8,1}, +{ 4, swap16, mxINT16_CLASS ,16,1}, +{ 8, swap32, mxINT32_CLASS ,32,1}, +{ 16, swap32, mxSINGLE_CLASS ,32,1}, +{ 32, swap32, mxSINGLE_CLASS ,32,2}, +{ 64, swap64, mxDOUBLE_CLASS ,64,1}, +{ 256, swap8 , mxINT8_CLASS , 8,1}, +{ 512, swap16, mxUINT16_CLASS ,16,1}, +{ 768, swap32, mxUINT32_CLASS ,32,1}, +{1792, swap64, mxDOUBLE_CLASS ,64,2} +}; + +typedef struct ftype { + int ndim; + int dim[MXDIMS]; + Dtype *dtype; + int swap; + FILE *fp; + off_t off; +} FTYPE; + +off_t icumprod[MXDIMS], ocumprod[MXDIMS]; +off_t poff; +long len; +#define BLEN 131072 +unsigned char wbuf[BLEN], *dptr; + +void put_bytes(int ndim, FILE *fp, int *ptr[], int idim[], unsigned char idat[], off_t indo, off_t indi, void (*swap)()) +{ + int i; + off_t nb = ocumprod[ndim]; + + if (ndim == 0) + { + off_t off; + for(i=0; i<idim[ndim]; i++) + { + off = indo+(ptr[ndim][i]-1)*nb; + if (((off-poff)!=nb) || (len == BLEN)) + { + swap(len,dptr,wbuf); + if (len && (fwrite(wbuf,1,len,fp) != len)) + { + /* Problem */ + (void)fclose(fp); + (void)mexErrMsgTxt("Problem writing data (1)."); + } + if (fseeko(fp, off, SEEK_SET) == -1) + { + /* Problem */ + (void)fclose(fp); + (void)mexErrMsgTxt("Problem writing data (2)."); + } + dptr = idat+indi+i*nb; + len = 0; + } + len += nb; + poff = off; + } + } + else + { + for(i=0; i<idim[ndim]; i++) + { + put_bytes(ndim-1, fp, ptr, idim, + idat, indo+nb*(ptr[ndim][i]-1), indi+icumprod[ndim]*i, swap); + } + } +} + +void put(FTYPE map, int *ptr[], int idim[], void *idat) +{ + int i, nbytes; + void (*swap)(); + + dptr = idat; + nbytes = map.dtype->bits/8; + len = 0; + poff = -999999; + ocumprod[0] = nbytes*map.dtype->channels; + icumprod[0] = nbytes*1; + for(i=0; i<map.ndim; i++) + { + icumprod[i+1] = icumprod[i]*idim[i]; + ocumprod[i+1] = ocumprod[i]*map.dim[i]; + } + + if (map.swap) + swap = map.dtype->swap; + else + swap = copy; + + put_bytes(map.ndim-1, map.fp, ptr, idim, (unsigned char *)idat, map.off, 0,swap); + + swap(len,dptr,wbuf); + if (fwrite(wbuf,1,len,map.fp) != len) + { + /* Problem */ + (void)fclose(map.fp); + (void)mexErrMsgTxt("Problem writing data (3)."); + } +} + +const double *getpr(const mxArray *ptr, const char nam[], int len, int *n) +{ + char s[256]; + mxArray *arr; + + arr = mxGetField(ptr,0,nam); + if (arr == (mxArray *)0) + { + (void)sprintf(s,"'%s' field is missing.", nam); + mexErrMsgTxt(s); + } + if (!mxIsNumeric(arr)) + { + (void)sprintf(s,"'%s' field is non-numeric.", nam); + mexErrMsgTxt(s); + } + if (!mxIsDouble(arr)) + { + (void)sprintf(s,"'%s' field is not double precision.", nam); + mexErrMsgTxt(s); + } + if (len>=0) + { + *n = mxGetM(arr)*mxGetN(arr); + if (*n != len) + { + (void)sprintf(s,"'%s' field should have %d elements (has %d).", nam, len, *n); + mexErrMsgTxt(s); + } + } + else + { + *n = mxGetNumberOfElements(arr); + if (*n > -len) + { + (void)sprintf(s,"'%s' field should have a maximum of %d elements (has %d).", nam, -len, *n); + mexErrMsgTxt(s); + } + } + return (double *)mxGetData(arr); +} + + +void open_file(const mxArray *ptr, FTYPE *map) +{ + int n; + int i, dtype; + const double *pr; + mxArray *arr; + + if (!mxIsStruct(ptr)) mexErrMsgTxt("Not a structure."); + + dtype = (int)(getpr(ptr, "dtype", 1, &n)[0]); + map->dtype = NULL; + for(i=0; i<sizeof(table)/sizeof(Dtype); i++) + { + if (table[i].code == dtype) + { + map->dtype = &table[i]; + break; + } + } + if (map->dtype == NULL) mexErrMsgTxt("Unrecognised 'dtype' value."); + if (map->dtype->bits % 8) mexErrMsgTxt("Can not yet write logical data."); + if (map->dtype->channels != 1) mexErrMsgTxt("Can not yet write complex data."); + pr = getpr(ptr, "dim", -MXDIMS, &n); + map->ndim = n; + for(i=0; i<map->ndim; i++) + { + map->dim[i] = (int)fabs(pr[i]); + } + pr = getpr(ptr, "be",1, &n); +#ifdef SPM_BIGENDIAN + map->swap = (int)pr[0]==0; +#else + map->swap = (int)pr[0]!=0; +#endif + pr = getpr(ptr, "offset",1, &n); + map->off = (off_t)pr[0]; + /* if (map->off < 0) map->off = 0; Unsigned, so not necessary */ + + arr = mxGetField(ptr,0,"fname"); + if (arr == (mxArray *)0) mexErrMsgTxt("Cant find 'fname' field."); + + if (mxIsChar(arr)) + { + int buflen; + char *buf; + buflen = mxGetNumberOfElements(arr)+1; + buf = mxCalloc(buflen+1,sizeof(char)); + if (mxGetString(arr,buf,buflen)) + { + mxFree(buf); + mexErrMsgTxt("Cant get 'fname'."); + } + map->fp = fopen(buf,"rb+"); + if (map->fp == (FILE *)0) + { + map->fp = fopen(buf,"wb"); + if (map->fp == (FILE *)0) + { + mxFree(buf); + mexErrMsgTxt("Cant open file."); + } + } + + mxFree(buf); + } + else + mexErrMsgTxt("Wrong type of 'fname' field."); +} + + +void close_file(FTYPE map) +{ + (void)fclose(map.fp); +} + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + FTYPE map; + void *idat; + int i; + int *ptr[MXDIMS], *odim, ndim, idim[MXDIMS]; + int one[1]; + const mxArray *curr; + one[0] = 1; + + if (nrhs<3 || nlhs>0) mexErrMsgTxt("Incorrect usage."); + + curr = prhs[0]; + open_file(curr, &map); + + ndim = map.ndim; + odim = map.dim; + + if (ndim >= MXDIMS) + { + close_file(map); + mexErrMsgTxt("Too many dimensions."); + } + curr = prhs[1]; + if (mxGetClassID(curr) != map.dtype->clss) + { + close_file(map); + mexErrMsgTxt("Incompatible class types."); + } + idat = mxGetData(curr); + + for(i=0;i<nrhs-2; i++) + { + int j; + curr = prhs[i+2]; + if (!mxIsInt32(curr)) + { + close_file(map); + mexErrMsgTxt("Indices must be int32."); + } + if (i< mxGetNumberOfDimensions(prhs[1])) + idim[i] = mxGetDimensions(prhs[1])[i]; + else + idim[i] = 1; + + if (mxGetNumberOfElements(curr) != idim[i]) + { + close_file(map); + mexErrMsgTxt("Subscripted assignment dimension mismatch (2)."); + } + + ptr[i] = (int *)mxGetData(curr); + for(j=0; j<idim[i]; j++) + if (ptr[i][j]<1 || ptr[i][j]> ((i<ndim)?odim[i]:1)) + { + close_file(map); + mexErrMsgTxt("Index exceeds matrix dimensions (2)."); + } + } + + for(i=nrhs-2; i<ndim; i++) + { + idim[i] = 1; + ptr[i] = one; + } + if (ndim<nrhs-2) + { + for(i=ndim; i<nrhs-2; i++) + map.dim[i] = 1; + map.ndim = nrhs-2; + } + put(map, ptr, idim, idat); + close_file(map); +} diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/reshape.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/reshape.m new file mode 100644 index 0000000000000000000000000000000000000000..c2d7a561122802937feb5041c87f047a3a3deb51 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/reshape.m @@ -0,0 +1,26 @@ +function a = reshape(b,varargin) +% Overloaded reshape function for file_array objects +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: reshape.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: reshape.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +if length(struct(b))~=1, error('Can only reshape simple file_array objects.'); end; + +args = []; +for i=1:length(varargin), + args = [args varargin{i}(:)']; +end; +if prod(args)~=prod(b.dim), + error('To RESHAPE the number of elements must not change.'); +end; +a = b; +a.dim = args; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/size.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/size.m new file mode 100644 index 0000000000000000000000000000000000000000..e1dfdebba6e033af1e10e1a35c095c7282f6492d --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/size.m @@ -0,0 +1,49 @@ +function d = size(a,varargin) +% overloaded size function for file_array objects. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: size.m 3730 2010-02-17 13:24:26Z john + +% +% niftilib $Id: size.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +sa = struct(a); +nd = 0; +for i=1:numel(sa), + nd = max(nd,numel(sa(i).dim)); + nd = max(nd,max(find(sa(i).pos==1))); +end +nd = nd+1; + +dim = ones(length(sa),nd); +pos = ones(length(sa),nd); + +for i=1:length(sa) + sz = sa(i).dim; + dim(i,1:length(sz)) = sz; + ps = sa(i).pos; + pos(i,1:length(ps)) = ps; +end + +tmp = pos==1; +d = zeros(1,nd); +for i=1:nd, + ind = all(tmp(:,[1:(i-1) (i+1):nd]),2); + d(i) = sum(dim(ind,i)); +end; +lim = max(max(find(d~=1)),2); +d = d(1:lim); + +if nargin>1, + if varargin{1}<=length(d), + d = d(varargin{1}); + else + d = 1; + end; +end; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/subsasgn.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/subsasgn.m new file mode 100644 index 0000000000000000000000000000000000000000..a8eb1f369810a1c7d4ab7d7db7343e48acdbf141 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/subsasgn.m @@ -0,0 +1,158 @@ +function obj = subsasgn(obj,subs,dat) +% Overloaded subsasgn function for file_array objects. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: subsasgn.m 4136 2010-12-09 22:22:28Z guillaume + +% +% niftilib $Id: subsasgn.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +if isempty(subs) + return; +end; +if ~strcmp(subs(1).type,'()'), + if strcmp(subs(1).type,'.'), + %error('Attempt to reference field of non-structure array.'); + if numel(struct(obj))~=1, + error('Can only change the fields of simple file_array objects.'); + end; + switch(subs(1).subs) + case 'fname', obj = asgn(obj,@fname, subs(2:end),dat); %fname(obj,dat); + case 'dtype', obj = asgn(obj,@dtype, subs(2:end),dat); %dtype(obj,dat); + case 'offset', obj = asgn(obj,@offset, subs(2:end),dat); %offset(obj,dat); + case 'dim', obj = asgn(obj,@dim, subs(2:end),dat); %obj = dim(obj,dat); + case 'scl_slope', obj = asgn(obj,@scl_slope, subs(2:end),dat); %scl_slope(obj,dat); + case 'scl_inter', obj = asgn(obj,@scl_inter, subs(2:end),dat); %scl_inter(obj,dat); + case 'permission', obj = asgn(obj,@permission,subs(2:end),dat); %permission(obj,dat); + otherwise, error(['Reference to non-existent field "' subs.subs '".']); + end; + return; + end; + if strcmp(subs(1).type,'{}'), error('Cell contents reference from a non-cell array object.'); end; +end; + +if numel(subs)~=1, error('Expression too complicated');end; +dm = size(obj); +sobj = struct(obj); + +if length(subs.subs) < length(dm), + l = length(subs.subs); + dm = [dm(1:(l-1)) prod(dm(l:end))]; + if numel(sobj) ~= 1, + error('Can only reshape simple file_array objects.'); + end; + if numel(sobj.scl_slope)>1 || numel(sobj.scl_inter)>1, + error('Can not reshape file_array objects with multiple slopes and intercepts.'); + end; +end; + +dm = [dm ones(1,16)]; +di = ones(1,16); +args = {}; +for i=1:length(subs.subs), + if ischar(subs.subs{i}), + if ~strcmp(subs.subs{i},':'), error('This shouldn''t happen....'); end; + args{i} = int32(1:dm(i)); + else + args{i} = int32(subs.subs{i}); + end; + di(i) = length(args{i}); +end; +for j=1:length(sobj), + if strcmp(sobj(j).permission,'ro'), + error('Array is read-only.'); + end +end + +if length(sobj)==1 + sobj.dim = dm; + if numel(dat)~=1, + subfun(sobj,double(dat),args{:}); + else + dat1 = double(dat) + zeros(di); + subfun(sobj,dat1,args{:}); + end; +else + for j=1:length(sobj), + ps = [sobj(j).pos ones(1,length(args))]; + dm = [sobj(j).dim ones(1,length(args))]; + siz = ones(1,16); + for i=1:length(args), + msk = args{i}>=ps(i) & args{i}<(ps(i)+dm(i)); + args2{i} = find(msk); + args3{i} = int32(double(args{i}(msk))-ps(i)+1); + siz(i) = numel(args2{i}); + end; + if numel(dat)~=1, + dat1 = double(subsref(dat,struct('type','()','subs',{args2}))); + else + dat1 = double(dat) + zeros(siz); + end; + subfun(sobj(j),dat1,args3{:}); + end +end +return + +function sobj = subfun(sobj,dat,varargin) +va = varargin; + +dt = datatypes; +ind = find(cat(1,dt.code)==sobj.dtype); +if isempty(ind), error('Unknown datatype'); end; +if dt(ind).isint, dat(~isfinite(dat)) = 0; end; + +if ~isempty(sobj.scl_inter), + inter = sobj.scl_inter; + if numel(inter)>1, + inter = resize_scales(inter,sobj.dim,varargin); + end; + dat = double(dat) - inter; +end; + +if ~isempty(sobj.scl_slope), + slope = sobj.scl_slope; + if numel(slope)>1, + slope = resize_scales(slope,sobj.dim,varargin); + dat = double(dat)./slope; + else + dat = double(dat)/slope; + end; +end; + +if dt(ind).isint, dat = round(dat); end; + +% Avoid warning messages in R14 SP3 +wrn = warning; +warning('off'); +dat = feval(dt(ind).conv,dat); +warning(wrn); + +nelem = dt(ind).nelem; +if nelem==1, + mat2file(sobj,dat,va{:}); +elseif nelem==2, + sobj1 = sobj; + sobj1.dim = [2 sobj.dim]; + sobj1.dtype = dt(find(strcmp(dt(ind).prec,{dt.prec}) & (cat(2,dt.nelem)==1))).code; + dat = reshape(dat,[1 size(dat)]); + dat = [real(dat) ; imag(dat)]; + mat2file(sobj1,dat,int32([1 2]),va{:}); +else + error('Inappropriate number of elements per voxel.'); +end; +return + +function obj = asgn(obj,fun,subs,dat) +if ~isempty(subs), + tmp = feval(fun,obj); + tmp = subsasgn(tmp,subs,dat); + obj = feval(fun,obj,tmp); +else + obj = feval(fun,obj,dat); +end; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/subsref.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/subsref.m new file mode 100644 index 0000000000000000000000000000000000000000..7e1df1356de3a6ff8813f042bd8bbb66776714b7 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/subsref.m @@ -0,0 +1,186 @@ +function varargout=subsref(obj,subs) +% SUBSREF Subscripted reference +% An overloaded function... +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: subsref.m 4136 2010-12-09 22:22:28Z guillaume + +% +% niftilib $Id: subsref.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +if isempty(subs), return; end + +switch subs(1).type + case '{}' + error('Cell contents reference from a non-cell array object.'); + case '.' + varargout = access_fields(obj,subs); + return; +end + +if numel(subs)~=1, error('Expression too complicated'); end; + +dim = [size(obj) ones(1,16)]; +nd = find(dim>1,1,'last')-1; +sobj = struct(obj); + +if ~numel(subs.subs) + [subs.subs{1:nd+1}] = deal(':'); +elseif length(subs.subs) < nd + l = length(subs.subs); + dim = [dim(1:(l-1)) prod(dim(l:end))]; + if numel(sobj) ~= 1 + error('Can only reshape simple file_array objects.'); + else + if numel(sobj.scl_slope)>1 || numel(sobj.scl_inter)>1 + error('Can not reshape file_array objects with multiple slopes and intercepts.'); + end + sobj.dim = dim; + end +end + +di = ones(16,1); +args = cell(1,length(subs.subs)); +for i=1:length(subs.subs) + if ischar(subs.subs{i}) + if ~strcmp(subs.subs{i},':'), error('This shouldn''t happen....'); end + if length(subs.subs) == 1 + args{i} = 1:prod(dim); % possible overflow when int32() + k = 0; + for j=1:length(sobj) + sobj(j).dim = [prod(sobj(j).dim) 1]; + sobj(j).pos = [k+1 1]; + k = k + sobj(j).dim(1); + end + else + args{i} = 1:dim(i); + end + else + args{i} = subs.subs{i}; + end + di(i) = length(args{i}); +end + +if length(sobj)==1 + t = subfun(sobj,args{:}); +else + dt = datatypes; + dt = dt([dt.code]==sobj(1).dtype); % assuming identical datatypes + t = zeros(di',func2str(dt.conv)); + for j=1:length(sobj) + ps = [sobj(j).pos ones(1,length(args))]; + dm = [sobj(j).dim ones(1,length(args))]; + for i=1:length(args) + msk = find(args{i}>=ps(i) & args{i}<(ps(i)+dm(i))); + args2{i} = msk; + args3{i} = double(args{i}(msk))-ps(i)+1; + end + + t = subsasgn(t,struct('type','()','subs',{args2}),subfun(sobj(j),args3{:})); + end +end +varargout = {t}; + + +%========================================================================== +% function t = subfun(sobj,varargin) +%========================================================================== +function t = subfun(sobj,varargin) + +%sobj.dim = [sobj.dim ones(1,16)]; +try + args = cell(size(varargin)); + for i=1:length(varargin) + args{i} = int32(varargin{i}); + end + t = file2mat(sobj,args{:}); +catch + t = multifile2mat(sobj,varargin{:}); +end +if ~isempty(sobj.scl_slope) || ~isempty(sobj.scl_inter) + slope = 1; + inter = 0; + if ~isempty(sobj.scl_slope), slope = sobj.scl_slope; end + if ~isempty(sobj.scl_inter), inter = sobj.scl_inter; end + if numel(slope)>1 + slope = resize_scales(slope,sobj.dim,varargin); + t = double(t).*slope; + else + t = double(t)*slope; + end + if numel(inter)>1 + inter = resize_scales(inter,sobj.dim,varargin); + end; + t = t + inter; +end + + +%========================================================================== +% function c = access_fields(obj,subs) +%========================================================================== +function c = access_fields(obj,subs) + +sobj = struct(obj); +c = cell(1,numel(sobj)); +for i=1:numel(sobj) + %obj = class(sobj(i),'file_array'); + obj = sobj(i); + switch(subs(1).subs) + case 'fname', t = fname(obj); + case 'dtype', t = dtype(obj); + case 'offset', t = offset(obj); + case 'dim', t = dim(obj); + case 'scl_slope', t = scl_slope(obj); + case 'scl_inter', t = scl_inter(obj); + case 'permission', t = permission(obj); + otherwise + error(['Reference to non-existent field "' subs(1).subs '".']); + end + if numel(subs)>1 + t = subsref(t,subs(2:end)); + end + c{i} = t; +end + + +%========================================================================== +% function val = multifile2mat(sobj,varargin) +%========================================================================== +function val = multifile2mat(sobj,varargin) + +% Convert subscripts into linear index +[indx2{1:length(varargin)}] = ndgrid(varargin{:},1); +ind = sub2ind(sobj.dim,indx2{:}); + +% Work out the partition +dt = datatypes; +dt = dt([dt.code]==sobj.dtype); +sz = dt.size; +try + mem = spm('Memory'); % in bytes, has to be a multiple of 16 (max([dt.size])) +catch + mem = 200 * 1024 * 1024; +end +s = ceil(prod(sobj.dim) * sz / mem); + +% Assign indices to partitions +[x,y] = ind2sub([mem/sz s],ind(:)); +c = histc(y,1:s); +cc = [0 reshape(cumsum(c),1,[])]; + +% Read data in relevant partitions +obj = sobj; +val = zeros(length(x),1,func2str(dt.conv)); +for i=reshape(find(c),1,[]) + obj.offset = sobj.offset + mem*(i-1); + obj.dim = [1 min(mem/sz, prod(sobj.dim)-(i-1)*mem/sz)]; + val(cc(i)+1:cc(i+1)) = file2mat(obj,int32(1),int32(x(y==i))); +end +r = cellfun('length',varargin); +if numel(r) == 1, r = [r 1]; end +val = reshape(val,r); diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/transpose.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/transpose.m new file mode 100644 index 0000000000000000000000000000000000000000..6451efef058c1c9f4be493bdfd4bbdd25fcf38b3 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/transpose.m @@ -0,0 +1,15 @@ +function varargout = transpose(varargin) +% Transposing is not allowed. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: transpose.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: transpose.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +error('file_array objects can not be transposed.'); diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/vertcat.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/vertcat.m new file mode 100644 index 0000000000000000000000000000000000000000..28b6ed1363315ba4fdb87eba16f9b8aad3512b47 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@file_array/vertcat.m @@ -0,0 +1,16 @@ +function o = vertcat(varargin) +% Vertical concatenation of file_array objects. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: vertcat.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: vertcat.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +o = cat(1,varargin{:}); +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/Contents.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/Contents.m new file mode 100644 index 0000000000000000000000000000000000000000..b1a0903b302ec4f72d8720ba4bf2948ac8aa0e39 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/Contents.m @@ -0,0 +1,84 @@ +% NIFTI Object +% +% create - Create a NIFTI-1 file +% disp - Disp a NIFTI-1 object +% display - Display a NIFTI-1 object +% fieldnames - Fieldnames of a NIFTI-1 object +% nifti - Create a NIFTI-1 object +% subsasgn - Subscript assignment +% subsref - Subscript referencing +% +% other operations are unlikely to work. +% +% Example usage. +% +% % Example of creating a simulated .nii file. +% dat = file_array; +% dat.fname = 'junk.nii'; +% dat.dim = [64 64 32]; +% dat.dtype = 'FLOAT64-BE'; +% dat.offset = ceil(348/8)*8; +% +% % alternatively: +% % dat = file_array( 'junk.nii',dim,dtype,off,scale,inter) +% +% disp(dat) +% +% % Create an empty NIFTI structure +% N = nifti; +% +% fieldnames(N) % Dump fieldnames +% +% % Creating all the NIFTI header stuff +% N.dat = dat; +% N.mat = [2 0 0 -110 ; 0 2 0 -110; 0 0 -2 92; 0 0 0 1]; +% N.mat_intent = 'xxx'; % dump possibilities +% N.mat_intent = 'Scanner'; +% N.mat0 = N.mat; +% N.mat0_intent = 'Aligned'; +% +% N.diminfo.slice = 3; +% N.diminfo.phase = 2; +% N.diminfo.frequency = 2; +% N.diminfo.slice_time.code='xxx'; % dump possibilities +% N.diminfo.slice_time.code = 'sequential_increasing'; +% N.diminfo.slice_time.start = 1; +% N.diminfo.slice_time.end = 32; +% N.diminfo.slice_time.duration = 3/32; +% +% N.intent.code='xxx' ; % dump possibilities +% N.intent.code='FTEST'; % or N.intent.code=4; +% N.intent.param = [4 8]; +% +% N.timing.toffset = 28800; +% N.timing.tspace=3; +% N.descrip = 'This is a NIFTI-1 file'; +% N.aux_file='aux-file-name.txt'; +% N.cal = [0 1]; +% +% create(N); % Writes hdr info +% +% dat(:,:,:)=0; % Write out the data as all zeros +% +% [i,j,k] = ndgrid(1:64,1:64,1:32); +% dat(find((i-32).^2+(j-32).^2+(k*2-32).^2 < 30^2))=1; % Write some ones in the file +% dat(find((i-32).^2+(j-32).^2+(k*2-32).^2 < 15^2))=2; +% +% +% % displaying a slice +% imagesc(dat(:,:,12));colorbar +% +% % get a handle to 'junk.nii'; +% M=nifti('junk.nii'); +% +% imagesc(M.dat(:,:,12)); +% +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: Contents.m 2696 2009-02-05 20:29:48Z guillaume + +% +% niftilib $Id: Contents.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/create.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/create.m new file mode 100644 index 0000000000000000000000000000000000000000..1d9099ff861dea45eae36802f4486aab95c15d8f --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/create.m @@ -0,0 +1,78 @@ +function create(obj,wrt) +% Create a NIFTI-1 file +% FORMAT create(obj) +% This writes out the header information for the nifti object +% +% create(obj,wrt) +% This also writes out an empty image volume if wrt==1 +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: create.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: create.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + +for i=1:numel(obj) + create_each(obj(i)); +end; + +function create_each(obj) +if ~isa(obj.dat,'file_array'), + error('Data must be a file-array'); +end; +fname = obj.dat.fname; +if isempty(fname), + error('No filename to write to.'); +end; +dt = obj.dat.dtype; +ok = write_hdr_raw(fname,obj.hdr,dt(end-1)=='B'); +if ~ok, + error(['Unable to write header for "' fname '".']); +end; + +write_extras(fname,obj.extras); + +if nargin>2 && any(wrt==1), + % Create an empty image file if necessary + d = findindict(obj.hdr.datatype, 'dtype'); + dim = double(obj.hdr.dim(2:end)); + dim((double(obj.hdr.dim(1))+1):end) = 1; + nbytes = ceil(d.size*d.nelem*prod(dim(1:2)))*prod(dim(3:end))+double(obj.hdr.vox_offset); + [pth,nam,ext] = fileparts(obj.dat.fname); + + if any(strcmp(deblank(obj.hdr.magic),{'n+1','nx1'})), + ext = '.nii'; + else + ext = '.img'; + end; + iname = fullfile(pth,[nam ext]); + fp = fopen(iname,'a+'); + if fp==-1, + error(['Unable to create image for "' fname '".']); + end; + + fseek(fp,0,'eof'); + pos = ftell(fp); + if pos<nbytes, + bs = 2048; % Buffer-size + nbytes = nbytes - pos; + buf = uint8(0); + buf(bs) = 0; + while(nbytes>0) + if nbytes<bs, buf = buf(1:nbytes); end; + nw = fwrite(fp,buf,'uint8'); + if nw<min(bs,nbytes), + fclose(fp); + error(['Problem while creating image for "' fname '".']); + end; + nbytes = nbytes - nw; + end; + end; + fclose(fp); +end; + +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/disp.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/disp.m new file mode 100644 index 0000000000000000000000000000000000000000..09563f2cb8a38525983b63f87a26af50e8a33f9b --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/disp.m @@ -0,0 +1,27 @@ +function disp(obj) +% Disp a NIFTI-1 object +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: disp.m 4136 2010-12-09 22:22:28Z guillaume + +% +% niftilib $Id: disp.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +sz = size(obj); +fprintf('NIFTI object: '); +if length(sz)>4, + fprintf('%d-D\n',length(sz)); +else + for i=1:(length(sz)-1), + fprintf('%d-by-',sz(i)); + end; + fprintf('%d\n',sz(end)); +end; +if prod(sz)==1, + disp(structn(obj)) +end; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/display.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/display.m new file mode 100644 index 0000000000000000000000000000000000000000..38383ab81c828f47841550b5553e179c0f728754 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/display.m @@ -0,0 +1,18 @@ +function display(obj) +% Display a NIFTI-1 object +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: display.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: display.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +disp(' '); +disp([inputname(1),' = ']) +disp(' '); +disp(obj) +disp(' ') diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/fieldnames.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/fieldnames.m new file mode 100644 index 0000000000000000000000000000000000000000..25739257debbe05b9b1b3835e2921f1ab06e56a0 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/fieldnames.m @@ -0,0 +1,30 @@ +function t = fieldnames(obj) +% Fieldnames of a NIFTI-1 object +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: fieldnames.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: fieldnames.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +if isfield(obj.hdr,'magic') + t = {... + 'dat' + 'mat' + 'mat_intent' + 'mat0' + 'mat0_intent' + 'intent' + 'diminfo' + 'timing' + 'descrip' + 'cal' + 'aux_file' + }; +else + error('This should not happen.'); +end; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/nifti.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/nifti.m new file mode 100644 index 0000000000000000000000000000000000000000..6bd71b1b911bc6965ddb226983c8c6f2e21ae8aa --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/nifti.m @@ -0,0 +1,95 @@ +function h = nifti(varargin) +% Create a NIFTI-1 object +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: nifti.m 4270 2011-03-29 16:26:26Z john + +% +% niftilib $Id: nifti.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +switch nargin +case 0, + org = niftistruc; + hdr = []; + for i=1:length(org), + hdr.(org(i).label) = feval(org(i).dtype.conv,org(i).def); + end; + h = struct('hdr',hdr,'dat',[],'extras',struct); + h = class(h,'nifti'); + +case 1 + if ischar(varargin{1}) + if size(varargin{1},1)>1, + h = nifti(cellstr(varargin{1})); + return; + end; + fname = deblank(varargin{1}); + vol = read_hdr(fname); + extras = read_extras(fname); + + if ~isfield(vol.hdr,'magic'), + vol.hdr = mayo2nifti1(vol.hdr); + + % For SPM99 compatibility + if isfield(extras,'M') && ~isfield(extras,'mat'), + extras.mat = extras.M; + if spm_flip_analyze_images, + extras.mat = diag([-1 1 1 1])*extras.mat; + end; + end; + + % Over-ride sform if a .mat file exists + if isfield(extras,'mat') && size(extras.mat,3)>=1, + mat = extras.mat(:,:,1); + mat1 = mat*[eye(4,3) [1 1 1 1]']; + vol.hdr.srow_x = mat1(1,:); + vol.hdr.srow_y = mat1(2,:); + vol.hdr.srow_z = mat1(3,:); + vol.hdr.sform_code = 2; + vol.hdr.qform_code = 2; + vol.hdr = encode_qform0(mat,vol.hdr); + end; + end; + + if isfield(extras,'M'), extras = rmfield(extras,'M'); end; + if isfield(extras,'mat') && size(extras.mat,3)<=1, + extras = rmfield(extras,'mat'); + end; + + dim = double(vol.hdr.dim); + dim = dim(2:(dim(1)+1)); + dt = double(vol.hdr.datatype); + offs = max(double(vol.hdr.vox_offset),0); + + if ~vol.hdr.scl_slope && ~vol.hdr.scl_inter, + vol.hdr.scl_slope = 1; + end; + slope = double(vol.hdr.scl_slope); + inter = double(vol.hdr.scl_inter); + + dat = file_array(vol.iname,dim,[dt,vol.be],offs,slope,inter); + h = struct('hdr',vol.hdr,'dat',dat,'extras',extras); + h = class(h,'nifti'); + + elseif isstruct(varargin{1}) + h = class(varargin{1},'nifti'); + + elseif iscell(varargin{1}) + fnames = varargin{1}; + h(numel(fnames)) = struct('hdr',[],'dat',[],'extras',struct); + h = class(h,'nifti'); + for i=1:numel(fnames), + h(i) = nifti(fnames{i}); + end; + + else + error('Dont know what to do yet.'); + end; +otherwise + error('Dont know what to do yet'); +end; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/M2Q.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/M2Q.m new file mode 100644 index 0000000000000000000000000000000000000000..1b453d6287c591292cf0cc1a39da389e8067b2f4 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/M2Q.m @@ -0,0 +1,38 @@ +function Q = M2Q(M) +% Convert from rotation matrix to quaternion form +% See: http://skal.planet-d.net/demo/matrixfaq.htm +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: M2Q.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: M2Q.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +d = diag(M(1:3,1:3)); +t = sum(d) + 1; +if t>0.5, + s = sqrt(t)*2; + Q = [(M(3,2)-M(2,3))/s (M(1,3)-M(3,1))/s (M(2,1)-M(1,2))/s 0.25*s]'; +else + t = find(d==max(d)); + t = t(1); + switch(t), + case 1, + s = 2*sqrt(1 + M(1,1) - M(2,2) - M(3,3)); + Q = [0.25*s (M(1,2)+M(2,1))/s (M(3,1)+M(1,3))/s (M(3,2)-M(2,3))/s]'; + case 2, + s = 2*sqrt(1 + M(2,2) - M(1,1) - M(3,3)); + Q = [(M(1,2)+M(2,1))/s 0.25*s (M(2,3)+M(3,2))/s (M(1,3)-M(3,1))/s ]'; + case 3, + s = 2*sqrt(1 + M(3,3) - M(1,1) - M(2,2)); + Q = [(M(3,1)+M(1,3))/s (M(2,3)+M(3,2))/s 0.25*s (M(2,1)-M(1,2))/s]'; + end; +end; +if Q(4)<0, Q = -Q; end; % w must be +ve +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/Q2M.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/Q2M.m new file mode 100644 index 0000000000000000000000000000000000000000..4d4caf1b08a681747fc512a904f2f440f0025f11 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/Q2M.m @@ -0,0 +1,36 @@ +function M = Q2M(Q) +% Generate a rotation matrix from a quaternion xi+yj+zk+w, +% where Q = [x y z], and w = 1-x^2-y^2-z^2. +% See: http://skal.planet-d.net/demo/matrixfaq.htm +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: Q2M.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: Q2M.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +Q = Q(1:3); % Assume rigid body +w = sqrt(1 - sum(Q.^2)); +x = Q(1); y = Q(2); z = Q(3); +if w<1e-7, + w = 1/sqrt(x*x+y*y+z*z); + x = x*w; + y = y*w; + z = z*w; + w = 0; +end; +xx = x*x; yy = y*y; zz = z*z; ww = w*w; +xy = x*y; xz = x*z; xw = x*w; +yz = y*z; yw = y*w; zw = z*w; +M = [... +(xx-yy-zz+ww) 2*(xy-zw) 2*(xz+yw) 0 + 2*(xy+zw) (-xx+yy-zz+ww) 2*(yz-xw) 0 + 2*(xz-yw) 2*(yz+xw) (-xx-yy+zz+ww) 0 + 0 0 0 1]; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/decode_qform0.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/decode_qform0.m new file mode 100644 index 0000000000000000000000000000000000000000..08ba04619f8d24f98bc65147910e3899311c2f96 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/decode_qform0.m @@ -0,0 +1,65 @@ +function M = decode_qform0(hdr) +% Decode qform info from NIFTI-1 headers. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: decode_qform0.m 3131 2009-05-18 15:54:10Z guillaume + +% +% niftilib $Id: decode_qform0.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +dim = double(hdr.dim); +pixdim = double(hdr.pixdim); +if ~isfield(hdr,'magic') || hdr.qform_code <= 0, + flp = spm_flip_analyze_images; + %disp('------------------------------------------------------'); + %disp('The images are in a form whereby it is not possible to'); + %disp('tell the left and right sides of the brain apart.'); + %if flp, + % disp('They are assumed to be stored left-handed.'); + %else + % disp('They are assumed to be stored right-handed.'); + %end; + %disp('------------------------------------------------------'); + + %R = eye(4); + n = min(dim(1),3); + vox = [pixdim(2:(n+1)) ones(1,3-n)]; + + if ~isfield(hdr,'origin') || ~any(hdr.origin(1:3)), + origin = (dim(2:4)+1)/2; + else + origin = double(hdr.origin(1:3)); + end; + off = -vox.*origin; + M = [vox(1) 0 0 off(1) ; 0 vox(2) 0 off(2) ; 0 0 vox(3) off(3) ; 0 0 0 1]; + + % Stuff for default orientations + if flp, M = diag([-1 1 1 1])*M; end; +else + + % Rotations from quaternions + R = Q2M(double([hdr.quatern_b hdr.quatern_c hdr.quatern_d])); + + % Translations + T = [eye(4,3) double([hdr.qoffset_x hdr.qoffset_y hdr.qoffset_z 1]')]; + + % Zooms. Note that flips are derived from the first + % element of pixdim, which is normally unused. + n = min(dim(1),3); + Z = [pixdim(2:(n+1)) ones(1,4-n)]; + Z(Z<0) = 1; + if pixdim(1)<0, Z(3) = -Z(3); end; + Z = diag(Z); + + M = T*R*Z; + + % Convert from first voxel at [1,1,1] + % to first voxel at [0,0,0] + M = M * [eye(4,3) [-1 -1 -1 1]']; +end; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/empty_hdr.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/empty_hdr.m new file mode 100644 index 0000000000000000000000000000000000000000..db269333b3c96626f9544f34b11412a476fc5987 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/empty_hdr.m @@ -0,0 +1,20 @@ +function hdr = empty_hdr +% Create an empty NIFTI-1 header +% FORMAT hdr = empty_hdr +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: empty_hdr.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: empty_hdr.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +org = niftistruc; +for i=1:length(org), + hdr.(org(i).label) = org(i).def; +end; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/encode_qform0.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/encode_qform0.m new file mode 100644 index 0000000000000000000000000000000000000000..7649ed60d2502d14cf4825410adeb09f286d5cc7 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/encode_qform0.m @@ -0,0 +1,50 @@ +function hdr = encode_qform0(M,hdr) +% Encode an affine transform into qform +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: encode_qform0.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: encode_qform0.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +% Convert from first voxel at [1,1,1] to first voxel at [0,0,0] +M = M * [eye(4,3) [1 1 1 1]']; + +% Translations +hdr.qoffset_x = M(1,4); +hdr.qoffset_y = M(2,4); +hdr.qoffset_z = M(3,4); + +% Rotations and zooms +R = M(1:3,1:3); +vx = sqrt(sum(M(1:3,1:3).^2)); +vx(vx==0) = 1; +R = R * diag(1./vx); + +% Ensure that R is O(3) +[U,S,V] = svd(R); +R = U*V'; +if any(abs(diag(S)-1)>1e-3), warning('QFORM0 representation has been rounded.'); end; + +% Ensure that R is SO(3) +if det(R)>0 + hdr.pixdim(1:4) = [ 1 vx]; +else + R = R*diag([1 1 -1]); + hdr.pixdim(1:4) = [-1 vx]; +end; + +% Convert to quaternions +Q = M2Q(R); +hdr.quatern_b = Q(1); +hdr.quatern_c = Q(2); +hdr.quatern_d = Q(3); + +if hdr.qform_code == 0, hdr.qform_code = 2; end; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/findindict.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/findindict.m new file mode 100644 index 0000000000000000000000000000000000000000..7fd41d9c187d75a936222faa6bd2d56f9df90766 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/findindict.m @@ -0,0 +1,42 @@ +function entry = findindict(c,dcode) +% Look up an entry in the dictionary +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: findindict.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: findindict.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +entry = []; +d = getdict; +d = d.(dcode); +if ischar(c) + for i=1:length(d), + if strcmpi(d(i).label,c), + entry = d(i); + break; + end; + end; +elseif isnumeric(c) && numel(c)==1 + for i=1:length(d), + if d(i).code==c, + entry = d(i); + break; + end; + end; +else + error(['Inappropriate code for ' dcode '.']); +end; +if isempty(entry) + fprintf('\nThis is not an option. Try one of these:\n'); + for i=1:length(d) + fprintf('%5d) %s\n', d(i).code, d(i).label); + end; + %fprintf('\nNO CHANGES MADE\n'); +end; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/getdict.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/getdict.m new file mode 100644 index 0000000000000000000000000000000000000000..acdfa4d481eb6428961e0cc5f045c9d495ecf928 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/getdict.m @@ -0,0 +1,158 @@ +function d = getdict +% Dictionary of NIFTI stuff +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: getdict.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: getdict.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +persistent dict; +if ~isempty(dict), + d = dict; + return; +end; + +% Datatype +t = true; +f = false; +table = {... + 0 ,'UNKNOWN' ,'uint8' ,@uint8 ,1,1 ,t,t,f + 1 ,'BINARY' ,'uint1' ,@logical,1,1/8,t,t,f + 256 ,'INT8' ,'int8' ,@int8 ,1,1 ,t,f,t + 2 ,'UINT8' ,'uint8' ,@uint8 ,1,1 ,t,t,t + 4 ,'INT16' ,'int16' ,@int16 ,1,2 ,t,f,t + 512 ,'UINT16' ,'uint16' ,@uint16 ,1,2 ,t,t,t + 8 ,'INT32' ,'int32' ,@int32 ,1,4 ,t,f,t + 768 ,'UINT32' ,'uint32' ,@uint32 ,1,4 ,t,t,t + 1024,'INT64' ,'int64' ,@int64 ,1,8 ,t,f,f + 1280,'UINT64' ,'uint64' ,@uint64 ,1,8 ,t,t,f + 16 ,'FLOAT32' ,'float32' ,@single ,1,4 ,f,f,t + 64 ,'FLOAT64' ,'double' ,@double ,1,8 ,f,f,t + 1536,'FLOAT128' ,'float128',@crash ,1,16 ,f,f,f + 32 ,'COMPLEX64' ,'float32' ,@single ,2,4 ,f,f,f + 1792,'COMPLEX128','double' ,@double ,2,8 ,f,f,f + 2048,'COMPLEX256','float128',@crash ,2,16 ,f,f,f + 128 ,'RGB24' ,'uint8' ,@uint8 ,3,1 ,t,t,f}; + +dtype = struct(... + 'code' ,table(:,1),... + 'label' ,table(:,2),... + 'prec' ,table(:,3),... + 'conv' ,table(:,4),... + 'nelem' ,table(:,5),... + 'size' ,table(:,6),... + 'isint' ,table(:,7),... + 'unsigned' ,table(:,8),... + 'min',-Inf,'max',Inf',... + 'supported',table(:,9)); +for i=1:length(dtype), + if dtype(i).isint + if dtype(i).unsigned + dtype(i).min = 0; + dtype(i).max = 2^(8*dtype(i).size)-1; + else + dtype(i).min = -2^(8*dtype(i).size-1); + dtype(i).max = 2^(8*dtype(i).size-1)-1; + end; + end; +end; +% Intent +table = {... + 0 ,'NONE' ,'None',{} + 2 ,'CORREL' ,'Correlation statistic',{'DOF'} + 3 ,'TTEST' ,'T-statistic',{'DOF'} + 4 ,'FTEST' ,'F-statistic',{'numerator DOF','denominator DOF'} + 5 ,'ZSCORE' ,'Z-score',{} + 6 ,'CHISQ' ,'Chi-squared distribution',{'DOF'} + 7 ,'BETA' ,'Beta distribution',{'a','b'} + 8 ,'BINOM' ,'Binomial distribution',... + {'number of trials','probability per trial'} + 9 ,'GAMMA' ,'Gamma distribution',{'shape','scale'} + 10 ,'POISSON' ,'Poisson distribution',{'mean'} + 11 ,'NORMAL' ,'Normal distribution',{'mean','standard deviation'} + 12 ,'FTEST_NONC' ,'F-statistic noncentral',... + {'numerator DOF','denominator DOF','numerator noncentrality parameter'} + 13 ,'CHISQ_NONC' ,'Chi-squared noncentral',{'DOF','noncentrality parameter'} + 14 ,'LOGISTIC' ,'Logistic distribution',{'location','scale'} + 15 ,'LAPLACE' ,'Laplace distribution',{'location','scale'} + 16 ,'UNIFORM' ,'Uniform distribition',{'lower end','upper end'} + 17 ,'TTEST_NONC' ,'T-statistic noncentral',{'DOF','noncentrality parameter'} + 18 ,'WEIBULL' ,'Weibull distribution',{'location','scale','power'} + 19 ,'CHI' ,'Chi distribution',{'DOF'} + 20 ,'INVGAUSS' ,'Inverse Gaussian distribution',{'mu','lambda'} + 21 ,'EXTVAL' ,'Extreme Value distribution',{'location','scale'} + 22 ,'PVAL' ,'P-value',{} + 23 ,'LOGPVAL' ,'Log P-value',{} + 24 ,'LOG10PVAL' ,'Log_10 P-value',{} + 1001,'ESTIMATE' ,'Estimate',{} + 1002,'LABEL' ,'Label index',{} + 1003,'NEURONAMES' ,'NeuroNames index',{} + 1004,'MATRIX' ,'General matrix',{'M','N'} + 1005,'MATRIX_SYM' ,'Symmetric matrix',{} + 1006,'DISPLACEMENT' ,'Displacement vector',{} + 1007,'VECTOR' ,'Vector',{} + 1008,'POINTS' ,'Pointset',{} + 1009,'TRIANGLE' ,'Triangle',{} + 1010,'QUATERNION' ,'Quaternion',{} + 1011,'DIMLESS' ,'Dimensionless',{} +}; +intent = struct('code',table(:,1),'label',table(:,2),... + 'fullname',table(:,3),'param',table(:,4)); + +% Units +table = {... + 0, 1,'UNKNOWN' + 1,1000,'m' + 2, 1,'mm' + 3,1e-3,'um' + 8, 1,'s' + 16,1e-3,'ms' + 24,1e-6,'us' + 32, 1,'Hz' + 40, 1,'ppm' + 48, 1,'rads'}; +units = struct('code',table(:,1),'label',table(:,3),'rescale',table(:,2)); + +% Reference space +% code = {0,1,2,3,4}; +table = {... + 0,'UNKNOWN' + 1,'Scanner Anat' + 2,'Aligned Anat' + 3,'Talairach' + 4,'MNI_152'}; +anat = struct('code',table(:,1),'label',table(:,2)); + +% Slice Ordering +table = {... + 0,'UNKNOWN' + 1,'sequential_increasing' + 2,'sequential_decreasing' + 3,'alternating_increasing' + 4,'alternating_decreasing'}; +sliceorder = struct('code',table(:,1),'label',table(:,2)); + +% Q/S Form Interpretation +table = {... + 0,'UNKNOWN' + 1,'Scanner' + 2,'Aligned' + 3,'Talairach' + 4,'MNI152'}; +xform = struct('code',table(:,1),'label',table(:,2)); + +dict = struct('dtype',dtype,'intent',intent,'units',units,... + 'space',anat,'sliceorder',sliceorder,'xform',xform); + +d = dict; +return; + +function varargout = crash(varargin) +error('There is a NIFTI-1 data format problem (an invalid datatype).'); + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/mayo2nifti1.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/mayo2nifti1.m new file mode 100644 index 0000000000000000000000000000000000000000..6c18e8ee781b7489d4acbe827e4c9f824a05b61e --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/mayo2nifti1.m @@ -0,0 +1,72 @@ +function hdr = mayo2nifti1(ohdr,mat) +% Convert from an ANALYZE to a NIFTI-1 header +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: mayo2nifti1.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: mayo2nifti1.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +if isfield(ohdr,'magic'), + hdr = ohdr; + return; +end; +hdr = empty_hdr; +hdr.dim = ohdr.dim; +hdr.datatype = ohdr.datatype; +hdr.bitpix = ohdr.bitpix; +hdr.pixdim = ohdr.pixdim; +hdr.vox_offset = ohdr.vox_offset; +hdr.scl_slope = ohdr.roi_scale; +hdr.scl_inter = ohdr.funused1; +hdr.descrip = ohdr.descrip; +hdr.aux_file = ohdr.aux_file; +hdr.glmax = ohdr.glmax; +hdr.glmin = ohdr.glmin; +hdr.cal_max = ohdr.cal_max; +hdr.cal_min = ohdr.cal_min; +hdr.magic = 'ni1'; + +switch hdr.datatype, +case 130, hdr.datatype = 256; % int8 +case 132, hdr.datatype = 512; % uint16 +case 136, hdr.datatype = 768; % uint32 +end; + +if nargin<2, + % No mat, so create the equivalent from the hdr... + if any(ohdr.origin(1:3)), origin = double(ohdr.origin(1:3)); + else origin = (double(ohdr.dim(2:4))+1)/2; end; + vox = double(ohdr.pixdim(2:4)); + if vox(1)<0, + % Assume FSL orientation + flp = 0; + else + % Assume SPM or proper Analyze + flp = spm_flip_analyze_images; + end; + if all(vox == 0), vox = [1 1 1]; end; + off = -vox.*origin; + mat = [vox(1) 0 0 off(1) ; 0 vox(2) 0 off(2) ; 0 0 vox(3) off(3) ; 0 0 0 1]; + if flp, + %disp(['Assuming that image is stored left-handed']); + mat = diag([-1 1 1 1])*mat; + else + %disp(['Assuming that image is stored right-handed']); + end; +end; + +hdr = encode_qform0(mat,hdr); +mat = mat*[eye(4,3) [1 1 1 1]']; +hdr.srow_x = mat(1,:); +hdr.srow_y = mat(2,:); +hdr.srow_z = mat(3,:); +hdr.qform_code = 2; +hdr.sform_code = 2; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/mayostruc.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/mayostruc.m new file mode 100644 index 0000000000000000000000000000000000000000..e18578d47eeee4abffca0e602816db02050b616c --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/mayostruc.m @@ -0,0 +1,85 @@ +function o = mayostruc +% Create a data structure describing Analyze headers +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: mayostruc.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: mayostruc.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +persistent org; +if ~isempty(org), + o = org; + return; +end; +t = struct('conv',{ @char, @int16, @int32, @single },... + 'prec',{'uint8','int16','int32','single'},... + 'size',{ 1, 2, 4, 4}); +c = t(1); +s = t(2); +i = t(3); +f = t(4); +table = {... + i, 1,'sizeof_hdr',348 + c,10,'data_type',[] + c,18,'db_name',[] + i, 1,'extents',[] + s, 1,'session_error',[] + c, 1,'regular','r' + c, 1,'hkey_un0',[] + s, 8,'dim',[3 1 1 1 1 1 1 1 1] + c, 4,'vox_units',[] + c, 8,'cal_units',[] + s, 1,'unused1',[] + s, 1,'datatype',[] + s, 1,'bitpix',[] + s, 1,'dim_un0',[] + f, 8,'pixdim',[] + f, 1,'vox_offset',0 + f, 1,'roi_scale',1 + f, 1,'funused1',0 + f, 1,'funused2',[] + f, 1,'cal_max',[] + f, 1,'cal_min',[] + i, 1,'compressed',[] + i, 1,'verified',[] + i, 1,'glmax',[] + i, 1,'glmin',[] + c,80,'descrip','Analyze Image' + c,24,'aux_file','' + c, 1,'orient',[] +% c,10,'originator',[] + s, 5,'origin',[] % SPM version + c,10,'generated',[] + c,10,'scannum',[] + c,10,'patient_id',[] + c,10,'exp_date',[] + c,10,'exp_time',[] + c, 3,'hist_un0',[] + i, 1,'views',[] + i, 1,'vols_added',[] + i, 1,'start_field',[] + i, 1,'field_skip',[] + i, 1,'omax',[] + i, 1,'omin',[] + i, 1,'smax',[] + i, 1,'smin',[]}; +org = struct('label',table(:,3),'dtype',table(:,1),'len',table(:,2),... + 'offset',0,'def',table(:,4)); +os = 0; +for j=1:length(org) + os = os + org(j).dtype.size*ceil(os/org(j).dtype.size); + fun = org(j).dtype.conv; + def = [org(j).def zeros(1,org(j).len-length(org(j).def))]; + org(j).def = feval(fun,def); + org(j).offset = os; + os = os + org(j).len*org(j).dtype.size; +end; +o = org; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/nifti_stats.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/nifti_stats.m new file mode 100644 index 0000000000000000000000000000000000000000..975f1af8836a44a687a31143aa3171dc5cc75f72 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/nifti_stats.m @@ -0,0 +1,46 @@ +function varargout = nifti_stats(varargin) +% Conversion among various statistics +% FORMAT P = nifti_stats(VAL,CODE,OPT,PARAM) +% CODE can be one of +% 'CORREL' 'TTEST' 'FTEST' 'ZSCORE' +% 'CHISQ' 'BETA' 'BINOM' 'GAMMA' +% 'POISSON' 'NORMAL' 'FTEST_NONC' 'CHISQ_NONC' +% 'LOGISTIC' 'LAPLACE' 'UNIFORM' 'TTEST_NONC' +% 'WEIBULL' 'CHI' 'INVGAUSS' 'EXTVAL' +% 'PVAL' +% With only one input argument, CODE defaults to 'ZSCORE' +% +% OPT can be one of +% '-p' ==> output P = Prob(statistic < VAL). +% '-q' ==> output is 1-p. +% '-d' ==> output is probability density. +% '-1' ==> output is X such that Prob(statistic < x) = VAL. +% '-z' ==> output is Z such that Normal cdf(Z) = p(VAL). +% '-h' ==> output is Z such that 1/2-Normal cdf(Z) = p(VAL). +% With less than three input arguments, OPT defaults to '-p'. +% +% PARAM are up to three distribution parameters. +% These default to zero if unspecified. +% +% P is an array with the same dimensions as VAL. +% +%_______________________________________________________________________ +% 99.99% of the work by RW Cox - SSCC/NIMH/NIH/DHHS/USA/EARTH - March 2004 +% 0.01% of the work (the mex wrapper) by John Ashburner - FIL/ION/UCL +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: nifti_stats.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: nifti_stats.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +fprintf('******************************************\n'); +fprintf('Compile the nifti_stats function with\n'); +fprintf(' mex nifti_stats.c nifti_stats_mex.c -O\n'); +fprintf('******************************************\n'); + +error('nifti_stats is not compiled.'); diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/niftistruc.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/niftistruc.m new file mode 100644 index 0000000000000000000000000000000000000000..38dd12733c39ae6612b911880693036997cbe415 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/niftistruc.m @@ -0,0 +1,86 @@ +function o = niftistruc +% Create a data structure describing NIFTI headers +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: niftistruc.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: niftistruc.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +persistent org; +if ~isempty(org), + o = org; + return; +end; +t = struct('conv',{ @char , @uint8 , @int16 , @int32 , @single },... + 'prec',{'uint8', 'uint8', 'int16', 'int32', 'single'},... + 'size',{ 1, 1, 2, 4, 4 }); +c = t(1); +b = t(2); +s = t(3); +i = t(4); +f = t(5); + +table = {... + i, 1,'sizeof_hdr',348 + c,10,'data_type',[] + c,18,'db_name',[] + i, 1,'extents',[] + s, 1,'session_error',[] + c, 1,'regular','r' + b, 1,'dim_info',[] + s, 8,'dim',[3 0 0 0 1 1 1 1 1] + f, 1,'intent_p1',0 + f, 1,'intent_p2',0 + f, 1,'intent_p3',0 + s, 1,'intent_code',0 + s, 1,'datatype',2 + s, 1,'bitpix',8 + s, 1,'slice_start',[] + f, 8,'pixdim',[0 1 1 1] + f, 1,'vox_offset',0 + f, 1,'scl_slope',1 + f, 1,'scl_inter',0 + s, 1,'slice_end',[] + b, 1,'slice_code',[] + b, 1,'xyzt_units',10 + f, 1,'cal_max',[] + f, 1,'cal_min',[] + f, 1,'slice_duration',[] + f, 1,'toffset',[] + i, 1,'glmax',[] + i, 1,'glmin',[] + c,80,'descrip','NIFTI-1 Image' + c,24,'aux_file','' + s, 1,'qform_code',0 + s, 1,'sform_code',0 + f, 1,'quatern_b',0 + f, 1,'quatern_c',0 + f, 1,'quatern_d',0 + f, 1,'qoffset_x',0 + f, 1,'qoffset_y',0 + f, 1,'qoffset_z',0 + f, 4,'srow_x',[1 0 0 0] + f, 4,'srow_y',[0 1 0 0] + f, 4,'srow_z',[0 0 1 0] + c,16,'intent_name','' + c, 4,'magic','ni1'}; +org = struct('label',table(:,3),'dtype',table(:,1),'len',table(:,2),... + 'offset',0,'def',table(:,4)); +os = 0; +for j=1:length(org) + os = os + org(j).dtype.size*ceil(os/org(j).dtype.size); + fun = org(j).dtype.conv; + def = [org(j).def zeros(1,org(j).len-length(org(j).def))]; + org(j).def = feval(fun,def); + org(j).offset = os; + os = os + org(j).len*org(j).dtype.size; +end; +o = org; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_extras.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_extras.m new file mode 100644 index 0000000000000000000000000000000000000000..5047979ef83c9ebc4ce231536f3a80f7e657bc99 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_extras.m @@ -0,0 +1,32 @@ +function extras = read_extras(fname) +% Read extra bits of information +%_______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: read_extras.m 2237 2008-09-29 17:39:53Z guillaume + +% +% niftilib $Id: read_extras.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +extras = struct; +[pth,nam,ext] = fileparts(fname); +switch ext +case {'.hdr','.img','.nii'} + mname = fullfile(pth,[nam '.mat']); +case {'.HDR','.IMG','.NII'} + mname = fullfile(pth,[nam '.MAT']); +otherwise + mname = fullfile(pth,[nam '.mat']); +end + +if spm_existfile(mname), + try, + extras = load(mname); + catch, + warning('Can not load "%s" as a binary MAT file.\n', mname); + end; +end; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_hdr.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_hdr.m new file mode 100644 index 0000000000000000000000000000000000000000..e25c9498c545df9535614273ca8f5b8a31bd6331 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_hdr.m @@ -0,0 +1,90 @@ +function vol = read_hdr(fname) +% Get a variety of information from a NIFTI-1 header. +% FORMAT vol = read_hdr(fname) +% fname - filename of image +% vol - various bits of information +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: read_hdr.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: read_hdr.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +persistent d +if isempty(d), d = getdict; end; + +[pth,nam,ext,num] = spm_fileparts(fname); +switch ext +case '.hdr' + hname = fullfile(pth,[nam '.hdr']); +case '.HDR' + hname = fullfile(pth,[nam '.HDR']); +case '.img' + hname = fullfile(pth,[nam '.hdr']); +case '.IMG' + hname = fullfile(pth,[nam '.HDR']); +case '.nii' + hname = fullfile(pth,[nam '.nii']); +case '.NII' + hname = fullfile(pth,[nam '.NII']); +otherwise + hname = fullfile(pth,[nam ext]); +end +[hdr,be] = read_hdr_raw(hname); +if isempty(hdr) + error(['Error reading header file "' hname '"']); +end; + +if ~isfield(hdr,'magic'), + % A patch for some possible SPM2 datatypes + switch hdr.datatype, + case 130, hdr.datatype = 256; % int8 + case 132, hdr.datatype = 512; % uint16 + case 136, hdr.datatype = 768; % uint32 + end; +end; + +dt = []; +for i=1:length(d.dtype) + if hdr.datatype == d.dtype(i).code + dt = d.dtype(i); + break; + end; +end; +if isempty(dt) + error(['Unrecognised datatype (' num2str(double(hdr.datatype)) ') for "' fname '.'] ); +end +if isfield(hdr,'magic') + switch deblank(hdr.magic) + case {'n+1'} + iname = hname; + if hdr.vox_offset < hdr.sizeof_hdr + error(['Bad vox_offset (' num2str(double(hdr.vox_offset)) ') for "' fname '.'] ); + end + case {'ni1'} + if strcmp(ext,lower(ext)), + iname = fullfile(pth,[nam '.img']); + else + iname = fullfile(pth,[nam '.IMG']); + end; + otherwise + error(['Bad magic (' hdr.magic ') for "' fname '.'] ); + end +else + if strcmp(ext,lower(ext)), + iname = fullfile(pth,[nam '.img']); + else + iname = fullfile(pth,[nam '.IMG']); + end; +end +if rem(double(hdr.vox_offset),dt.size) + error(['Bad alignment of voxels (' num2str(double(hdr.vox_offset)) '/' num2str(double(dt.size)) ') for "' fname '.'] ); +end; + +vol = struct('hdr',hdr,'be',be,'hname',hname,'iname',iname); +return diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_hdr_raw.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_hdr_raw.m new file mode 100644 index 0000000000000000000000000000000000000000..ff0d501f5ea24855e2fb9fedec08b851c47764d9 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/read_hdr_raw.m @@ -0,0 +1,98 @@ +function [hdr,be] = read_hdr_raw(fname) +% Read a NIFTI-1 hdr file +% FORMAT [hdr,be] = read_hdr_raw(fname) +% fname - filename of image +% hdr - a structure containing hdr info +% be - whether big-endian or not +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: read_hdr_raw.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: read_hdr_raw.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +hdr = []; +be = []; +ok = true; + +% Name of header file +[pth,nam,ext] = fileparts(fname); +switch ext +case {'.img','.hdr'} + hname = fullfile(pth,[nam '.hdr']); +case {'.nii'} + hname = fullfile(pth,[nam '.nii']); +otherwise + hname = fullfile(pth,[nam '.hdr']); +end; + +% Open it if possible +fp = fopen(hname,'r','native'); +if fp==-1 + hdr = []; + return; +end; + +% Sort out endian issues of header +[unused,unused,mach] = fopen(fp); +if strcmp(mach,'ieee-be') || strcmp(mach,'ieee-be.l64') + be = true; +else + be = false; +end; +fseek(fp,0,'bof'); +fseek(fp,40,'bof'); +nd = fread(fp,1,'int16')'; +if isempty(nd), + fclose(fp); + hdr = []; + return; +elseif nd<1 || nd>7 + be = ~be; + fclose(fp); + if be, mach = 'ieee-be'; + else mach = 'ieee-le'; + end; + fp = fopen(hname,'r',mach); + if fp==-1 + hdr = []; + return; + end; +end; + +% Is it NIFTI or not +fseek(fp,0,'bof'); +fseek(fp,344,'bof'); +mgc = deblank(char(fread(fp,4,'uint8')')); +switch mgc +case {'ni1','n+1'} + org = niftistruc; +otherwise + org = mayostruc; +end; +fseek(fp,0,'bof'); +% Read the fields +for i=1:length(org) + tmp = fread(fp,org(i).len,['*' org(i).dtype.prec])'; + if length(tmp) ~= org(i).len +disp([length(tmp) org(i).len]); + tmp = org(i).def; + ok = false; + end; + tmp = feval(org(i).dtype.conv,tmp); + hdr.(org(i).label) = tmp; +end; + +fclose(fp); +if ~ok, + fprintf('There was a problem reading the header of\n'); + fprintf('"%s".\n', fname); + fprintf('It may be corrupted in some way.'); +end; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/spm_existfile.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/spm_existfile.m new file mode 100644 index 0000000000000000000000000000000000000000..c3008e15fe1eddb264416fb241ae1f30ddc1260d --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/spm_existfile.m @@ -0,0 +1,33 @@ +function s = spm_existfile(filename) +% Check if a file exists on disk - a compiled routine +% FORMAT S = SPM_EXISTFILE(FILENAME) +% FILENAME - filename (can also be a relative or full pathname to a file) +% S - logical scalar, true if the file exists and false otherwise +%_______________________________________________________________________ +% +% This compiled routine is equivalent to: +% >> s = exist(filename,'file') == 2; +% and was written for speed purposes. The differences in behaviour are: +% * spm_existfile returns true for directory names +% * spm_existfile does not look in MATLAB's search path +% * spm_existfile returns false for an existing file that does not have +% read permission +%_______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% Guillaume Flandin +% $Id: spm_existfile.m,v 1.1 2012/03/22 18:36:33 fissell Exp $ + + +%-This is merely the help file for the compiled routine +%error('spm_existfile.c not compiled - see Makefile') +%persistent runonce +%if isempty(runonce) +% warning('spm_existfile is not compiled for your platform.'); +% runonce = 1; +%end + +%s = exist(filename,'file') > 0; + +% KF replace compiled version with almost equivalent matlab call +s = exist(filename,'file') == 2; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/spm_fileparts.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/spm_fileparts.m new file mode 100644 index 0000000000000000000000000000000000000000..26029f1a4ac0bd455ba774c51abb3b9a61853e32 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/spm_fileparts.m @@ -0,0 +1,26 @@ +function [pth,nam,ext,num] = spm_fileparts(fname) +% Like fileparts, but separates off a comma separated list at the end +% FORMAT [pth,nam,ext,num] = spm_fileparts(fname) +% fname - original filename +% pth - path +% nam - filename +% ext - extension +% num - comma separated list of values +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% John Ashburner +% Id: spm_fileparts.m 4205 2011-02-21 15:39:08Z guillaume + +% +% niftilib $Id: spm_fileparts.m,v 1.1 2012/03/22 18:36:33 fissell Exp $ +% + + +num = ''; +[pth,nam,ext] = fileparts(fname); +ind = find(ext==','); +if ~isempty(ind) + num = ext(ind(1):end); + ext = ext(1:(ind(1)-1)); +end diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/README b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/README new file mode 100644 index 0000000000000000000000000000000000000000..155b63d60fb5f09f8647b07adaa861292989db5d --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/README @@ -0,0 +1,17 @@ +/* + * This is a Matlab mex interface for Bob Cox's extensive nifti_stats.c + * functionality. See nifti_stats.m for documentation. + */ + + +To compile on a big-endian machine + mex -DBIGENDIAN nifti_stats.c nifti_stats_mex.c -O + +On a little-endian machine + mex nifti_stats.c nifti_stats_mex.c -O + +On a Windows machine + mex -O -DSPM_WIN32 nifti_stats.c nifti_stats_mex.c + + +mv the .mex* file up one level to the private dir diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti1.h b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti1.h new file mode 100644 index 0000000000000000000000000000000000000000..4e30c0ce6cb24f29b924f8f86950ad7ccf749eb5 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti1.h @@ -0,0 +1,1227 @@ +#ifndef _NIFTI_HEADER_ +#define _NIFTI_HEADER_ + +/***************************************************************************** + ** This file defines the "NIFTI-1" header format. ** + ** It is derived from 2 meetings at the NIH (31 Mar 2003 and ** + ** 02 Sep 2003) of the Data Format Working Group (DFWG), ** + ** chartered by the NIfTI (Neuroimaging Informatics Technology ** + ** Initiative) at the National Institutes of Health (NIH). ** + **--------------------------------------------------------------** + ** Neither the National Institutes of Health (NIH), the DFWG, ** + ** nor any of the members or employees of these institutions ** + ** imply any warranty of usefulness of this material for any ** + ** purpose, and do not assume any liability for damages, ** + ** incidental or otherwise, caused by any use of this document. ** + ** If these conditions are not acceptable, do not use this! ** + **--------------------------------------------------------------** + ** Author: Robert W Cox (NIMH, Bethesda) ** + ** Advisors: John Ashburner (FIL, London), ** + ** Stephen Smith (FMRIB, Oxford), ** + ** Mark Jenkinson (FMRIB, Oxford) ** +******************************************************************************/ + + +/* + * niftilib $Id: nifti1.h,v 1.1 2012/03/22 18:36:33 fissell Exp $ + */ + +/*---------------------------------------------------------------------------*/ +/* Note that the ANALYZE 7.5 file header (dbh.h) is + (c) Copyright 1986-1995 + Biomedical Imaging Resource + Mayo Foundation + Incorporation of components of dbh.h are by permission of the + Mayo Foundation. + + Changes from the ANALYZE 7.5 file header in this file are released to the + public domain, including the functional comments and any amusing asides. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*! INTRODUCTION TO NIFTI-1: + ------------------------ + The twin (and somewhat conflicting) goals of this modified ANALYZE 7.5 + format are: + (a) To add information to the header that will be useful for functional + neuroimaging data analysis and display. These additions include: + - More basic data types. + - Two affine transformations to specify voxel coordinates. + - "Intent" codes and parameters to describe the meaning of the data. + - Affine scaling of the stored data values to their "true" values. + - Optional storage of the header and image data in one file (.nii). + (b) To maintain compatibility with non-NIFTI-aware ANALYZE 7.5 compatible + software (i.e., such a program should be able to do something useful + with a NIFTI-1 dataset -- at least, with one stored in a traditional + .img/.hdr file pair). + + Most of the unused fields in the ANALYZE 7.5 header have been taken, + and some of the lesser-used fields have been co-opted for other purposes. + Notably, most of the data_history substructure has been co-opted for + other purposes, since the ANALYZE 7.5 format describes this substructure + as "not required". + + NIFTI-1 FLAG (MAGIC STRINGS): + ---------------------------- + To flag such a struct as being conformant to the NIFTI-1 spec, the last 4 + bytes of the header must be either the C String "ni1" or "n+1"; + in hexadecimal, the 4 bytes + 6E 69 31 00 or 6E 2B 31 00 + (in any future version of this format, the '1' will be upgraded to '2', + etc.). Normally, such a "magic number" or flag goes at the start of the + file, but trying to avoid clobbering widely-used ANALYZE 7.5 fields led to + putting this marker last. However, recall that "the last shall be first" + (Matthew 20:16). + + If a NIFTI-aware program reads a header file that is NOT marked with a + NIFTI magic string, then it should treat the header as an ANALYZE 7.5 + structure. + + NIFTI-1 FILE STORAGE: + -------------------- + "ni1" means that the image data is stored in the ".img" file corresponding + to the header file (starting at file offset 0). + + "n+1" means that the image data is stored in the same file as the header + information. We recommend that the combined header+data filename suffix + be ".nii". When the dataset is stored in one file, the first byte of image + data is stored at byte location (int)vox_offset in this combined file. + + GRACE UNDER FIRE: + ---------------- + Most NIFTI-aware programs will only be able to handle a subset of the full + range of datasets possible with this format. All NIFTI-aware programs + should take care to check if an input dataset conforms to the program's + needs and expectations (e.g., check datatype, intent_code, etc.). If the + input dataset can't be handled by the program, the program should fail + gracefully (e.g., print a useful warning; not crash). + + SAMPLE CODES: + ------------ + The associated files nifti1_io.h and nifti1_io.c provide a sample + implementation in C of a set of functions to read, write, and manipulate + NIFTI-1 files. The file nifti1_test.c is a sample program that uses + the nifti1_io.c functions. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* HEADER STRUCT DECLARATION: + ------------------------- + In the comments below for each field, only NIFTI-1 specific requirements + or changes from the ANALYZE 7.5 format are described. For convenience, + the 348 byte header is described as a single struct, rather than as the + ANALYZE 7.5 group of 3 substructs. + + Further comments about the interpretation of various elements of this + header are after the data type definition itself. Fields that are + marked as ++UNUSED++ have no particular interpretation in this standard. + (Also see the UNUSED FIELDS comment section, far below.) + + The presumption below is that the various C types have particular sizes: + sizeof(int) = sizeof(float) = 4 ; sizeof(short) = 2 +-----------------------------------------------------------------------------*/ + +/*=================*/ +#ifdef __cplusplus +extern "C" { +#endif +/*=================*/ + /*************************/ /************************/ +struct nifti_1_header { /* NIFTI-1 usage */ /* ANALYZE 7.5 field(s) */ + /*************************/ /************************/ + + /*--- was header_key substruct ---*/ + int sizeof_hdr; /*!< MUST be 348 */ /* int sizeof_hdr; */ + char data_type[10]; /*!< ++UNUSED++ */ /* char data_type[10]; */ + char db_name[18]; /*!< ++UNUSED++ */ /* char db_name[18]; */ + int extents; /*!< ++UNUSED++ */ /* int extents; */ + short session_error; /*!< ++UNUSED++ */ /* short session_error; */ + char regular; /*!< ++UNUSED++ */ /* char regular; */ + char dim_info; /*!< MRI slice ordering. */ /* char hkey_un0; */ + + /*--- was image_dimension substruct ---*/ + short dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ + float intent_p1 ; /*!< 1st intent parameter. */ /* short unused8; */ + /* short unused9; */ + float intent_p2 ; /*!< 2nd intent parameter. */ /* short unused10; */ + /* short unused11; */ + float intent_p3 ; /*!< 3rd intent parameter. */ /* short unused12; */ + /* short unused13; */ + short intent_code ; /*!< NIFTI_INTENT_* code. */ /* short unused14; */ + short datatype; /*!< Defines data type! */ /* short datatype; */ + short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ + short slice_start; /*!< First slice index. */ /* short dim_un0; */ + float pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ + float vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ + float scl_slope ; /*!< Data scaling: slope. */ /* float funused1; */ + float scl_inter ; /*!< Data scaling: offset. */ /* float funused2; */ + short slice_end; /*!< Last slice index. */ /* float funused3; */ + char slice_code ; /*!< Slice timing order. */ + char xyzt_units ; /*!< Units of pixdim[1..4] */ + float cal_max; /*!< Max display intensity */ /* float cal_max; */ + float cal_min; /*!< Min display intensity */ /* float cal_min; */ + float slice_duration;/*!< Time for 1 slice. */ /* float compressed; */ + float toffset; /*!< Time axis shift. */ /* float verified; */ + int glmax; /*!< ++UNUSED++ */ /* int glmax; */ + int glmin; /*!< ++UNUSED++ */ /* int glmin; */ + + /*--- was data_history substruct ---*/ + char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ + char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ + + short qform_code ; /*!< NIFTI_XFORM_* code. */ /*-- all ANALYZE 7.5 ---*/ + short sform_code ; /*!< NIFTI_XFORM_* code. */ /* fields below here */ + /* are replaced */ + float quatern_b ; /*!< Quaternion b param. */ + float quatern_c ; /*!< Quaternion c param. */ + float quatern_d ; /*!< Quaternion d param. */ + float qoffset_x ; /*!< Quaternion x shift. */ + float qoffset_y ; /*!< Quaternion y shift. */ + float qoffset_z ; /*!< Quaternion z shift. */ + + float srow_x[4] ; /*!< 1st row affine transform. */ + float srow_y[4] ; /*!< 2nd row affine transform. */ + float srow_z[4] ; /*!< 3rd row affine transform. */ + + char intent_name[16];/*!< 'name' or meaning of data. */ + + char magic[4] ; /*!< MUST be "ni1\0" or "n+1\0". */ + +} ; /**** 348 bytes total ****/ + +typedef struct nifti_1_header nifti_1_header ; + +/*---------------------------------------------------------------------------*/ +/* DATA DIMENSIONALITY (as in ANALYZE 7.5): + --------------------------------------- + dim[0] = number of dimensions; + - if dim[0] is outside range 1..7, then the header information + needs to be byte swapped appropriately + - ANALYZE supports dim[0] up to 7, but NIFTI-1 reserves + dimensions 1,2,3 for space (x,y,z), 4 for time (t), and + 5,6,7 for anything else needed. + + dim[i] = length of dimension #i, for i=1..dim[0] (must be positive) + - also see the discussion of intent_code, far below + + pixdim[i] = voxel width along dimension #i, i=1..dim[0] (positive) + - cf. ORIENTATION section below for use of pixdim[0] + - the units of pixdim can be specified with the xyzt_units + field (also described far below). + + Number of bits per voxel value is in bitpix, which MUST correspond with + the datatype field. The total number of bytes in the image data is + dim[1] * ... * dim[dim[0]] * bitpix / 8 + + In NIFTI-1 files, dimensions 1,2,3 are for space, dimension 4 is for time, + and dimension 5 is for storing multiple values at each spatiotemporal + voxel. Some examples: + - A typical whole-brain FMRI experiment's time series: + - dim[0] = 4 + - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM + - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC + - dim[3] = 20 pixdim[3] = 5.0 + - dim[4] = 120 pixdim[4] = 2.0 + - A typical T1-weighted anatomical volume: + - dim[0] = 3 + - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM + - dim[2] = 256 pixdim[2] = 1.0 + - dim[3] = 128 pixdim[3] = 1.1 + - A single slice EPI time series: + - dim[0] = 4 + - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM + - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC + - dim[3] = 1 pixdim[3] = 5.0 + - dim[4] = 1200 pixdim[4] = 0.2 + - A 3-vector stored at each point in a 3D volume: + - dim[0] = 5 + - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM + - dim[2] = 256 pixdim[2] = 1.0 + - dim[3] = 128 pixdim[3] = 1.1 + - dim[4] = 1 pixdim[4] = 0.0 + - dim[5] = 3 intent_code = NIFTI_INTENT_VECTOR + - A single time series with a 3x3 matrix at each point: + - dim[0] = 5 + - dim[1] = 1 xyzt_units = NIFTI_UNITS_SEC + - dim[2] = 1 + - dim[3] = 1 + - dim[4] = 1200 pixdim[4] = 0.2 + - dim[5] = 9 intent_code = NIFTI_INTENT_GENMATRIX + - intent_p1 = intent_p2 = 3.0 (indicates matrix dimensions) +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* DATA STORAGE: + ------------ + If the magic field is "n+1", then the voxel data is stored in the + same file as the header. In this case, the voxel data starts at offset + (int)vox_offset into the header file. Thus, vox_offset=348.0 means that + the data starts immediately after the NIFTI-1 header. If vox_offset is + greater than 348, the NIFTI-1 format does not say anything about the + contents of the dataset file between the end of the header and the + start of the data. + + FILES: + ----- + If the magic field is "ni1", then the voxel data is stored in the + associated ".img" file, starting at offset 0 (i.e., vox_offset is not + used in this case, and should be set to 0.0). + + When storing NIFTI-1 datasets in pairs of files, it is customary to name + the files in the pattern "name.hdr" and "name.img", as in ANALYZE 7.5. + When storing in a single file ("n+1"), the file name should be in + the form "name.nii" (the ".nft" and ".nif" suffixes are already taken; + cf. http://www.icdatamaster.com/n.html ). + + BYTE ORDERING: + ------------- + The byte order of the data arrays is presumed to be the same as the byte + order of the header (which is determined by examining dim[0]). + + Floating point types are presumed to be stored in IEEE-754 format. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* DATA SCALING: + ------------ + If the scl_slope field is nonzero, then each voxel value in the dataset + should be scaled as + y = scl_slope * x + scl_inter + where x = voxel value stored + y = "true" voxel value + Normally, we would expect this scaling to be used to store "true" floating + values in a smaller integer datatype, but that is not required. That is, + it is legal to use scaling even if the datatype is a float type (crazy, + perhaps, but legal). + - However, the scaling is to be ignored if datatype is DT_RGB24. + - If datatype is a complex type, then the scaling is to be + applied to both the real and imaginary parts. + + The cal_min and cal_max fields (if nonzero) are used for mapping (possibly + scaled) dataset values to display colors: + - Minimum display intensity (black) corresponds to dataset value cal_min. + - Maximum display intensity (white) corresponds to dataset value cal_max. + - Dataset values below cal_min should display as black also, and values + above cal_max as white. + - Colors "black" and "white", of course, may refer to any scalar display + scheme (e.g., a color lookup table specified via aux_file). + - cal_min and cal_max only make sense when applied to scalar-valued + datasets (i.e., dim[0] < 5 or dim[5] = 1). +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* TYPE OF DATA (acceptable values for datatype field): + --------------------------------------------------- + Values of datatype smaller than 256 are ANALYZE 7.5 compatible. + Larger values are NIFTI-1 additions. These are all multiples of 256, so + that no bits below position 8 are set in datatype. But there is no need + to use only powers-of-2, as the original ANALYZE 7.5 datatype codes do. + + The additional codes are intended to include a complete list of basic + scalar types, including signed and unsigned integers from 8 to 64 bits, + floats from 32 to 128 bits, and complex (float pairs) from 64 to 256 bits. + + Note that most programs will support only a few of these datatypes! + A NIFTI-1 program should fail gracefully (e.g., print a warning message) + when it encounters a dataset with a type it doesn't like. +-----------------------------------------------------------------------------*/ + +#undef DT_UNKNOWN /* defined in dirent.h on some Unix systems */ + + /*--- the original ANALYZE 7.5 type codes ---*/ +#define DT_NONE 0 +#define DT_UNKNOWN 0 /* what it says, dude */ +#define DT_BINARY 1 /* binary (1 bit/voxel) */ +#define DT_UNSIGNED_CHAR 2 /* unsigned char (8 bits/voxel) */ +#define DT_SIGNED_SHORT 4 /* signed short (16 bits/voxel) */ +#define DT_SIGNED_INT 8 /* signed int (32 bits/voxel) */ +#define DT_FLOAT 16 /* float (32 bits/voxel) */ +#define DT_COMPLEX 32 /* complex (64 bits/voxel) */ +#define DT_DOUBLE 64 /* double (64 bits/voxel) */ +#define DT_RGB 128 /* RGB triple (24 bits/voxel) */ +#define DT_ALL 255 /* not very useful (?) */ + + /*----- another set of names for the same ---*/ +#define DT_UINT8 2 +#define DT_INT16 4 +#define DT_INT32 8 +#define DT_FLOAT32 16 +#define DT_COMPLEX64 32 +#define DT_FLOAT64 64 +#define DT_RGB24 128 + + /*------------------- new codes for NIFTI ---*/ +#define DT_INT8 256 /* signed char (8 bits) */ +#define DT_UINT16 512 /* unsigned short (16 bits) */ +#define DT_UINT32 768 /* unsigned int (32 bits) */ +#define DT_INT64 1024 /* long long (64 bits) */ +#define DT_UINT64 1280 /* unsigned long long (64 bits) */ +#define DT_FLOAT128 1536 /* long double (128 bits) */ +#define DT_COMPLEX128 1792 /* double pair (128 bits) */ +#define DT_COMPLEX256 2048 /* long double pair (256 bits) */ + + /*------- aliases for all the above codes ---*/ + + /*! unsigned char. */ +#define NIFTI_TYPE_UINT8 2 + /*! signed short. */ +#define NIFTI_TYPE_INT16 4 + /*! signed int. */ +#define NIFTI_TYPE_INT32 8 + /*! 32 bit float. */ +#define NIFTI_TYPE_FLOAT32 16 + /*! 64 bit complex = 2 32 bit floats. */ +#define NIFTI_TYPE_COMPLEX64 32 + /*! 64 bit float = double. */ +#define NIFTI_TYPE_FLOAT64 64 + /*! 3 8 bit bytes. */ +#define NIFTI_TYPE_RGB24 128 + /*! signed char. */ +#define NIFTI_TYPE_INT8 256 + /*! unsigned short. */ +#define NIFTI_TYPE_UINT16 512 + /*! unsigned int. */ +#define NIFTI_TYPE_UINT32 768 + /*! signed long long. */ +#define NIFTI_TYPE_INT64 1024 + /*! unsigned long long. */ +#define NIFTI_TYPE_UINT64 1280 + /*! 128 bit float = long double. */ +#define NIFTI_TYPE_FLOAT128 1536 + /*! 128 bit complex = 2 64 bit floats. */ +#define NIFTI_TYPE_COMPLEX128 1792 + /*! 256 bit complex = 2 128 bit floats */ +#define NIFTI_TYPE_COMPLEX256 2048 + + /*-------- sample typedefs for complicated types ---*/ +#if 0 +typedef struct { float r,i; } complex_float ; +typedef struct { double r,i; } complex_double ; +typedef struct { long double r,i; } complex_longdouble ; +typedef struct { unsigned char r,g,b; } rgb_byte ; +#endif + +/*---------------------------------------------------------------------------*/ +/* INTERPRETATION OF VOXEL DATA: + ---------------------------- + The intent_code field can be used to indicate that the voxel data has + some particular meaning. In particular, a large number of codes is + given to indicate that the the voxel data should be interpreted as + being drawn from a given probability distribution. + + VECTOR-VALUED DATASETS: + ---------------------- + The 5th dimension of the dataset, if present (i.e., dim[0]=5 and + dim[5] > 1), contains multiple values (e.g., a vector) to be stored + at each spatiotemporal location. For example, the header values + - dim[0] = 5 + - dim[1] = 64 + - dim[2] = 64 + - dim[3] = 20 + - dim[4] = 1 (indicates no time axis) + - dim[5] = 3 + - datatype = DT_FLOAT + - intent_code = NIFTI_INTENT_VECTOR + mean that this dataset should be interpreted as a 3D volume (64x64x20), + with a 3-vector of floats defined at each point in the 3D grid. + + A program reading a dataset with a 5th dimension may want to reformat + the image data to store each voxels' set of values together in a struct + or array. This programming detail, however, is beyond the scope of the + NIFTI-1 file specification! Uses of dimensions 6 and 7 are also not + specified here. + + STATISTICAL PARAMETRIC DATASETS (i.e., SPMs): + -------------------------------------------- + Values of intent_code from NIFTI_FIRST_STATCODE to NIFTI_LAST_STATCODE + (inclusive) indicate that the numbers in the dataset should be interpreted + as being drawn from a given distribution. Most such distributions have + auxiliary parameters (e.g., NIFTI_INTENT_TTEST has 1 DOF parameter). + + If the dataset DOES NOT have a 5th dimension, then the auxiliary parameters + are the same for each voxel, and are given in header fields intent_p1, + intent_p2, and intent_p3. + + If the dataset DOES have a 5th dimension, then the auxiliary parameters + are different for each voxel. For example, the header values + - dim[0] = 5 + - dim[1] = 128 + - dim[2] = 128 + - dim[3] = 1 (indicates a single slice) + - dim[4] = 1 (indicates no time axis) + - dim[5] = 2 + - datatype = DT_FLOAT + - intent_code = NIFTI_INTENT_TTEST + mean that this is a 2D dataset (128x128) of t-statistics, with the + t-statistic being in the first "plane" of data and the degrees-of-freedom + parameter being in the second "plane" of data. + + If the dataset 5th dimension is used to store the voxel-wise statistical + parameters, then dim[5] must be 1 plus the number of parameters required + by that distribution (e.g., intent_code=NIFTI_INTENT_TTEST implies dim[5] + must be 2, as in the example just above). + + Note: intent_code values 2..10 are compatible with AFNI 1.5x (which is + why there is no code with value=1, which is obsolescent in AFNI). + + OTHER INTENTIONS: + ---------------- + The purpose of the intent_* fields is to help interpret the values + stored in the dataset. Some non-statistical values for intent_code + and conventions are provided for storing other complex data types. + + The intent_name field provides space for a 15 character (plus 0 byte) + 'name' string for the type of data stored. Examples: + - intent_code = NIFTI_INTENT_ESTIMATE; intent_name = "T1"; + could be used to signify that the voxel values are estimates of the + NMR parameter T1. + - intent_code = NIFTI_INTENT_TTEST; intent_name = "House"; + could be used to signify that the voxel values are t-statistics + for the significance of 'activation' response to a House stimulus. + - intent_code = NIFTI_INTENT_DISPVECT; intent_name = "ToMNI152"; + could be used to signify that the voxel values are a displacement + vector that transforms each voxel (x,y,z) location to the + corresponding location in the MNI152 standard brain. + - intent_code = NIFTI_INTENT_SYMMATRIX; intent_name = "DTI"; + could be used to signify that the voxel values comprise a diffusion + tensor image. + + If no data name is implied or needed, intent_name[0] should be set to 0. +-----------------------------------------------------------------------------*/ + + /*! default: no intention is indicated in the header. */ + +#define NIFTI_INTENT_NONE 0 + + /*-------- These codes are for probability distributions ---------------*/ + /* Most distributions have a number of parameters, + below denoted by p1, p2, and p3, and stored in + - intent_p1, intent_p2, intent_p3 if dataset doesn't have 5th dimension + - image data array if dataset does have 5th dimension + + Functions to compute with many of the distributions below can be found + in the CDF library from U Texas. + + Formulas for and discussions of these distributions can be found in the + following books: + + [U] Univariate Discrete Distributions, + NL Johnson, S Kotz, AW Kemp. + + [C1] Continuous Univariate Distributions, vol. 1, + NL Johnson, S Kotz, N Balakrishnan. + + [C2] Continuous Univariate Distributions, vol. 2, + NL Johnson, S Kotz, N Balakrishnan. */ + /*----------------------------------------------------------------------*/ + + /*! [C2, chap 32] Correlation coefficient R (1 param): + p1 = degrees of freedom + R/sqrt(1-R*R) is t-distributed with p1 DOF. */ + +#define NIFTI_INTENT_CORREL 2 + + /*! [C2, chap 28] Student t statistic (1 param): p1 = DOF. */ + +#define NIFTI_INTENT_TTEST 3 + + /*! [C2, chap 27] Fisher F statistic (2 params): + p1 = numerator DOF, p2 = denominator DOF. */ + +#define NIFTI_INTENT_FTEST 4 + + /*! [C1, chap 13] Standard normal (0 params): Density = N(0,1). */ + +#define NIFTI_INTENT_ZSCORE 5 + + /*! [C1, chap 18] Chi-squared (1 param): p1 = DOF. + Density(x) proportional to exp(-x/2) * x^(p1/2-1). */ + +#define NIFTI_INTENT_CHISQ 6 + + /*! [C2, chap 25] Beta distribution (2 params): p1=a, p2=b. + Density(x) proportional to x^(a-1) * (1-x)^(b-1). */ + +#define NIFTI_INTENT_BETA 7 + + /*! [U, chap 3] Binomial distribution (2 params): + p1 = number of trials, p2 = probability per trial. + Prob(x) = (p1 choose x) * p2^x * (1-p2)^(p1-x), for x=0,1,...,p1. */ + +#define NIFTI_INTENT_BINOM 8 + + /*! [C1, chap 17] Gamma distribution (2 params): + p1 = shape, p2 = scale. + Density(x) proportional to x^(p1-1) * exp(-p2*x). */ + +#define NIFTI_INTENT_GAMMA 9 + + /*! [U, chap 4] Poisson distribution (1 param): p1 = mean. + Prob(x) = exp(-p1) * p1^x / x! , for x=0,1,2,.... */ + +#define NIFTI_INTENT_POISSON 10 + + /*! [C1, chap 13] Normal distribution (2 params): + p1 = mean, p2 = standard deviation. */ + +#define NIFTI_INTENT_NORMAL 11 + + /*! [C2, chap 30] Noncentral F statistic (3 params): + p1 = numerator DOF, p2 = denominator DOF, + p3 = numerator noncentrality parameter. */ + +#define NIFTI_INTENT_FTEST_NONC 12 + + /*! [C2, chap 29] Noncentral chi-squared statistic (2 params): + p1 = DOF, p2 = noncentrality parameter. */ + +#define NIFTI_INTENT_CHISQ_NONC 13 + + /*! [C2, chap 23] Logistic distribution (2 params): + p1 = location, p2 = scale. + Density(x) proportional to sech^2((x-p1)/(2*p2)). */ + +#define NIFTI_INTENT_LOGISTIC 14 + + /*! [C2, chap 24] Laplace distribution (2 params): + p1 = location, p2 = scale. + Density(x) proportional to exp(-abs(x-p1)/p2). */ + +#define NIFTI_INTENT_LAPLACE 15 + + /*! [C2, chap 26] Uniform distribution: p1 = lower end, p2 = upper end. */ + +#define NIFTI_INTENT_UNIFORM 16 + + /*! [C2, chap 31] Noncentral t statistic (2 params): + p1 = DOF, p2 = noncentrality parameter. */ + +#define NIFTI_INTENT_TTEST_NONC 17 + + /*! [C1, chap 21] Weibull distribution (3 params): + p1 = location, p2 = scale, p3 = power. + Density(x) proportional to + ((x-p1)/p2)^(p3-1) * exp(-((x-p1)/p2)^p3) for x > p1. */ + +#define NIFTI_INTENT_WEIBULL 18 + + /*! [C1, chap 18] Chi distribution (1 param): p1 = DOF. + Density(x) proportional to x^(p1-1) * exp(-x^2/2) for x > 0. + p1 = 1 = 'half normal' distribution + p1 = 2 = Rayleigh distribution + p1 = 3 = Maxwell-Boltzmann distribution. */ + +#define NIFTI_INTENT_CHI 19 + + /*! [C1, chap 15] Inverse Gaussian (2 params): + p1 = mu, p2 = lambda + Density(x) proportional to + exp(-p2*(x-p1)^2/(2*p1^2*x)) / x^3 for x > 0. */ + +#define NIFTI_INTENT_INVGAUSS 20 + + /*! [C2, chap 22] Extreme value type I (2 params): + p1 = location, p2 = scale + cdf(x) = exp(-exp(-(x-p1)/p2)). */ + +#define NIFTI_INTENT_EXTVAL 21 + + /*! Data is a 'p-value' (no params). */ + +#define NIFTI_INTENT_PVAL 22 + + /*! Smallest intent_code that indicates a statistic. */ + +#define NIFTI_FIRST_STATCODE 2 + + /*! Largest intent_code that indicates a statistic. */ + +#define NIFTI_LAST_STATCODE 22 + + /*---------- these values for intent_code aren't for statistics ----------*/ + + /*! To signify that the value at each voxel is an estimate + of some parameter, set intent_code = NIFTI_INTENT_ESTIMATE. + The name of the parameter may be stored in intent_name. */ + +#define NIFTI_INTENT_ESTIMATE 1001 + + /*! To signify that the value at each voxel is an index into + some set of labels, set intent_code = NIFTI_INTENT_LABEL. + The filename with the labels may stored in aux_file. */ + +#define NIFTI_INTENT_LABEL 1002 + + /*! To signify that the value at each voxel is an index into the + NeuroNames labels set, set intent_code = NIFTI_INTENT_NEURONAME. */ + +#define NIFTI_INTENT_NEURONAME 1003 + + /*! To store an M x N matrix at each voxel: + - dataset must have a 5th dimension (dim[0]=5 and dim[5]>1) + - intent_code must be NIFTI_INTENT_GENMATRIX + - dim[5] must be M*N + - intent_p1 must be M (in float format) + - intent_p2 must be N (ditto) + - the matrix values A[i][[j] are stored in row-order: + - A[0][0] A[0][1] ... A[0][N-1] + - A[1][0] A[1][1] ... A[1][N-1] + - etc., until + - A[M-1][0] A[M-1][1] ... A[M-1][N-1] */ + +#define NIFTI_INTENT_GENMATRIX 1004 + + /*! To store an NxN symmetric matrix at each voxel: + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_SYMMATRIX + - dim[5] must be N*(N+1)/2 + - intent_p1 must be N (in float format) + - the matrix values A[i][[j] are stored in row-order: + - A[0][0] + - A[1][0] A[1][1] + - A[2][0] A[2][1] A[2][2] + - etc.: row-by-row */ + +#define NIFTI_INTENT_SYMMATRIX 1005 + + /*! To signify that the vector value at each voxel is to be taken + as a displacement field or vector: + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_DISPVECT + - dim[5] must be the dimensionality of the displacment + vector (e.g., 3 for spatial displacement, 2 for in-plane) */ + +#define NIFTI_INTENT_DISPVECT 1006 /* specifically for displacements */ +#define NIFTI_INTENT_VECTOR 1007 /* for any other type of vector */ + + /*! To signify that the vector value at each voxel is really a + spatial coordinate (e.g., the vertices or nodes of a surface mesh): + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_POINTSET + - dim[0] = 5 + - dim[1] = number of points + - dim[2] = dim[3] = dim[4] = 1 + - dim[5] must be the dimensionality of space (e.g., 3 => 3D space). + - intent_name may describe the object these points come from + (e.g., "pial", "gray/white" , "EEG", "MEG"). */ + +#define NIFTI_INTENT_POINTSET 1008 + + /*! To signify that the vector value at each voxel is really a triple + of indexes (e.g., forming a triangle) from a pointset dataset: + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_TRIANGLE + - dim[0] = 5 + - dim[1] = number of triangles + - dim[2] = dim[3] = dim[4] = 1 + - dim[5] = 3 + - datatype should be an integer type (preferably DT_INT32) + - the data values are indexes (0,1,...) into a pointset dataset. */ + +#define NIFTI_INTENT_TRIANGLE 1009 + + /*! To signify that the vector value at each voxel is a quaternion: + - dataset must have a 5th dimension + - intent_code must be NIFTI_INTENT_QUATERNION + - dim[0] = 5 + - dim[5] = 4 + - datatype should be a floating point type */ + +#define NIFTI_INTENT_QUATERNION 1010 + +/*---------------------------------------------------------------------------*/ +/* 3D IMAGE (VOLUME) ORIENTATION AND LOCATION IN SPACE: + --------------------------------------------------- + There are 3 different methods by which continuous coordinates can + attached to voxels. The discussion below emphasizes 3D volumes, and + the continuous coordinates are referred to as (x,y,z). The voxel + index coordinates (i.e., the array indexes) are referred to as (i,j,k), + with valid ranges: + i = 0 .. dim[1]-1 + j = 0 .. dim[2]-1 (if dim[0] >= 2) + k = 0 .. dim[3]-1 (if dim[0] >= 3) + The (x,y,z) coordinates refer to the CENTER of a voxel. In methods + 2 and 3, the (x,y,z) axes refer to a subject-based coordinate system, + with + +x = Right +y = Anterior +z = Superior. + This is a right-handed coordinate system. However, the exact direction + these axes point with respect to the subject depends on qform_code + (Method 2) and sform_code (Method 3). + + N.B.: The i index varies most rapidly, j index next, k index slowest. + Thus, voxel (i,j,k) is stored starting at location + (i + j*dim[1] + k*dim[1]*dim[2]) * (bitpix/8) + into the dataset array. + + N.B.: The ANALYZE 7.5 coordinate system is + +x = Left +y = Anterior +z = Superior + which is a left-handed coordinate system. This backwardness is + too difficult to tolerate, so this NIFTI-1 standard specifies the + coordinate order which is most common in functional neuroimaging. + + N.B.: The 3 methods below all give the locations of the voxel centers + in the (x,y,z) coordinate system. In many cases, programs will wish + to display image data on some other grid. In such a case, the program + will need to convert its desired (x,y,z) values into (i,j,k) values + in order to extract (or interpolate) the image data. This operation + would be done with the inverse transformation to those described below. + + N.B.: Method 2 uses a factor 'qfac' which is either -1 or 1; qfac is + stored in the otherwise unused pixdim[0]. If pixdim[0]=0.0 (which + should not occur), we take qfac=1. Of course, pixdim[0] is only used + when reading a NIFTI-1 header, not when reading an ANALYZE 7.5 header. + + N.B.: The units of (x,y,z) can be specified using the xyzt_units field. + + METHOD 1 (the "old" way, used only when qform_code = 0): + ------------------------------------------------------- + The coordinate mapping from (i,j,k) to (x,y,z) is the ANALYZE + 7.5 way. This is a simple scaling relationship: + + x = pixdim[1] * i + y = pixdim[2] * j + z = pixdim[3] * k + + No particular spatial orientation is attached to these (x,y,z) + coordinates. (NIFTI-1 does not have the ANALYZE 7.5 orient field, + which is not general and is often not set properly.) This method + is not recommended, and is present mainly for compatibility with + ANALYZE 7.5 files. + + METHOD 2 (used when qform_code > 0, which should be the "normal case): + --------------------------------------------------------------------- + The (x,y,z) coordinates are given by the pixdim[] scales, a rotation + matrix, and a shift. This method is intended to represent + "scanner-anatomical" coordinates, which are often embedded in the + image header (e.g., DICOM fields (0020,0032), (0020,0037), (0028,0030), + and (0018,0050)), and represent the nominal orientation and location of + the data. This method can also be used to represent "aligned" + coordinates, which would typically result from some post-acquisition + alignment of the volume to a standard orientation (e.g., the same + subject on another day, or a rigid rotation to true anatomical + orientation from the tilted position of the subject in the scanner). + The formula for (x,y,z) in terms of header parameters and (i,j,k) is: + + [ x ] [ R11 R12 R13 ] [ pixdim[1] * i ] [ qoffset_x ] + [ y ] = [ R21 R22 R23 ] [ pixdim[2] * j ] + [ qoffset_y ] + [ z ] [ R31 R32 R33 ] [ qfac * pixdim[3] * k ] [ qoffset_z ] + + The qoffset_* shifts are in the NIFTI-1 header. Note that the center + of the (i,j,k)=(0,0,0) voxel (first value in the dataset array) is + just (x,y,z)=(qoffset_x,qoffset_y,qoffset_z). + + The rotation matrix R is calculated from the quatern_* parameters. + This calculation is described below. + + The scaling factor qfac is either 1 or -1. The rotation matrix R + defined by the quaternion parameters is "proper" (has determinant 1). + This may not fit the needs of the data; for example, if the image + grid is + i increases from Left-to-Right + j increases from Anterior-to-Posterior + k increases from Inferior-to-Superior + Then (i,j,k) is a left-handed triple. In this example, if qfac=1, + the R matrix would have to be + + [ 1 0 0 ] + [ 0 -1 0 ] which is "improper" (determinant = -1). + [ 0 0 1 ] + + If we set qfac=-1, then the R matrix would be + + [ 1 0 0 ] + [ 0 -1 0 ] which is proper. + [ 0 0 -1 ] + + This R matrix is represented by quaternion [a,b,c,d] = [0,1,0,0] + (which encodes a 180 degree rotation about the x-axis). + + METHOD 3 (used when sform_code > 0): + ----------------------------------- + The (x,y,z) coordinates are given by a general affine transformation + of the (i,j,k) indexes: + + x = srow_x[0] * i + srow_x[1] * j + srow_x[2] * k + srow_x[3] + y = srow_y[0] * i + srow_y[1] * j + srow_y[2] * k + srow_y[3] + z = srow_z[0] * i + srow_z[1] * j + srow_z[2] * k + srow_z[3] + + The srow_* vectors are in the NIFTI_1 header. Note that no use is + made of pixdim[] in this method. + + WHY 3 METHODS? + -------------- + Method 1 is provided only for backwards compatibility. The intention + is that Method 2 (qform_code > 0) represents the nominal voxel locations + as reported by the scanner, or as rotated to some fiducial orientation and + location. Method 3, if present (sform_code > 0), is to be used to give + the location of the voxels in some standard space. The sform_code + indicates which standard space is present. Both methods 2 and 3 can be + present, and be useful in different contexts (method 2 for displaying the + data on its original grid; method 3 for displaying it on a standard grid). + + In this scheme, a dataset would originally be set up so that the + Method 2 coordinates represent what the scanner reported. Later, + a registration to some standard space can be computed and inserted + in the header. Image display software can use either transform, + depending on its purposes and needs. + + In Method 2, the origin of coordinates would generally be whatever + the scanner origin is; for example, in MRI, (0,0,0) is the center + of the gradient coil. + + In Method 3, the origin of coordinates would depend on the value + of sform_code; for example, for the Talairach coordinate system, + (0,0,0) corresponds to the Anterior Commissure. + + QUATERNION REPRESENTATION OF ROTATION MATRIX (METHOD 2) + ------------------------------------------------------- + The orientation of the (x,y,z) axes relative to the (i,j,k) axes + in 3D space is specified using a unit quaternion [a,b,c,d], where + a*a+b*b+c*c+d*d=1. The (b,c,d) values are all that is needed, since + we require that a = sqrt(1.0-b*b+c*c+d*d) be nonnegative. The (b,c,d) + values are stored in the (quatern_b,quatern_c,quatern_d) fields. + + The quaternion representation is chosen for its compactness in + representing rotations. The (proper) 3x3 rotation matrix that + corresponds to [a,b,c,d] is + + [ a*a+b*b-c*c-d*d 2*b*c-2*a*d 2*b*d+2*a*c ] + R = [ 2*b*c+2*a*d a*a+c*c-b*b-d*d 2*c*d-2*a*b ] + [ 2*b*d-2*a*c 2*c*d+2*a*b a*a+d*d-c*c-b*b ] + + [ R11 R12 R13 ] + = [ R21 R22 R23 ] + [ R31 R32 R33 ] + + If (p,q,r) is a unit 3-vector, then rotation of angle h about that + direction is represented by the quaternion + + [a,b,c,d] = [cos(h/2), p*sin(h/2), q*sin(h/2), r*sin(h/2)]. + + Requiring a >= 0 is equivalent to requiring -Pi <= h <= Pi. (Note that + [-a,-b,-c,-d] represents the same rotation as [a,b,c,d]; there are 2 + quaternions that can be used to represent a given rotation matrix R.) + To rotate a 3-vector (x,y,z) using quaternions, we compute the + quaternion product + + [0,x',y',z'] = [a,b,c,d] * [0,x,y,z] * [a,-b,-c,-d] + + which is equivalent to the matrix-vector multiply + + [ x' ] [ x ] + [ y' ] = R [ y ] (equivalence depends on a*a+b*b+c*c+d*d=1) + [ z' ] [ z ] + + Multiplication of 2 quaternions is defined by the following: + + [a,b,c,d] = a*1 + b*I + c*J + d*K + where + I*I = J*J = K*K = -1 (I,J,K are square roots of -1) + I*J = K J*K = I K*I = J + J*I = -K K*J = -I I*K = -J (not commutative!) + For example + [a,b,0,0] * [0,0,0,1] = [0,-b,0,a] + since this expands to + (a+b*I)*(K) = (a*K+b*I*K) = (a*K-b*J). + + The above formula shows how to go from quaternion (b,c,d) to + rotation matrix and direction cosines. Conversely, given R, + we can compute the fields for the NIFTI-1 header by + + a = 0.5 * sqrt(1+R11+R22+R33) (not stored) + b = 0.25 * (R32-R23) / a => quatern_b + c = 0.25 * (R13-R31) / a => quatern_c + d = 0.25 * (R21-R12) / a => quatern_d + + If a=0 (a 180 degree rotation), alternative formulas are needed. + See the nifti1_io.c function mat44_to_quatern() for an implementation + of the various cases in converting R to [a,b,c,d]. + + Note that R-transpose (= R-inverse) would lead to the quaternion + [a,-b,-c,-d]. + + The choice to specify the qoffset_x (etc.) values in the final + coordinate system is partly to make it easy to convert DICOM images to + this format. The DICOM attribute "Image Position (Patient)" (0020,0032) + stores the (Xd,Yd,Zd) coordinates of the center of the first voxel. + Here, (Xd,Yd,Zd) refer to DICOM coordinates, and Xd=-x, Yd=-y, Zd=z, + where (x,y,z) refers to the NIFTI coordinate system discussed above. + (i.e., DICOM +Xd is Left, +Yd is Posterior, +Zd is Superior, + whereas +x is Right, +y is Anterior , +z is Superior. ) + Thus, if the (0020,0032) DICOM attribute is extracted into (px,py,pz), then + qoffset_x = -px qoffset_y = -py qoffset_z = pz + is a reasonable setting when qform_code=NIFTI_XFORM_SCANNER_ANAT. + + That is, DICOM's coordinate system is 180 degrees rotated about the z-axis + from the neuroscience/NIFTI coordinate system. To transform between DICOM + and NIFTI, you just have to negate the x- and y-coordinates. + + The DICOM attribute (0020,0037) "Image Orientation (Patient)" gives the + orientation of the x- and y-axes of the image data in terms of 2 3-vectors. + The first vector is a unit vector along the x-axis, and the second is + along the y-axis. If the (0020,0037) attribute is extracted into the + value (xa,xb,xc,ya,yb,yc), then the first two columns of the R matrix + would be + [ -xa -ya ] + [ -xb -yb ] + [ xc yc ] + The negations are because DICOM's x- and y-axes are reversed relative + to NIFTI's. The third column of the R matrix gives the direction of + displacement (relative to the subject) along the slice-wise direction. + This orientation is not encoded in the DICOM standard in a simple way; + DICOM is mostly concerned with 2D images. The third column of R will be + either the cross-product of the first 2 columns or its negative. It is + possible to infer the sign of the 3rd column by examining the coordinates + in DICOM attribute (0020,0032) "Image Position (Patient)" for successive + slices. However, this method occasionally fails for reasons that I + (RW Cox) do not understand. +-----------------------------------------------------------------------------*/ + + /* [qs]form_code value: */ /* x,y,z coordinate system refers to: */ + /*-----------------------*/ /*---------------------------------------*/ + + /*! Arbitrary coordinates (Method 1). */ + +#define NIFTI_XFORM_UNKNOWN 0 + + /*! Scanner-based anatomical coordinates */ + +#define NIFTI_XFORM_SCANNER_ANAT 1 + + /*! Coordinates aligned to another file's, + or to anatomical "truth". */ + +#define NIFTI_XFORM_ALIGNED_ANAT 2 + + /*! Coordinates aligned to Talairach- + Tournoux Atlas; (0,0,0)=AC, etc. */ + +#define NIFTI_XFORM_TALAIRACH 3 + + /*! MNI 152 normalized coordinates. */ + +#define NIFTI_XFORM_MNI_152 4 + +/*---------------------------------------------------------------------------*/ +/* UNITS OF SPATIAL AND TEMPORAL DIMENSIONS: + ---------------------------------------- + The codes below can be used in xyzt_units to indicate the units of pixdim. + As noted earlier, dimensions 1,2,3 are for x,y,z; dimension 4 is for + time (t). + - If dim[4]=1 or dim[0] < 4, there is no time axis. + - A single time series (no space) would be specified with + - dim[0] = 4 (for scalar data) or dim[0] = 5 (for vector data) + - dim[1] = dim[2] = dim[3] = 1 + - dim[4] = number of time points + - pixdim[4] = time step + - xyzt_units indicates units of pixdim[4] + - dim[5] = number of values stored at each time point + + Bits 0..2 of xyzt_units specify the units of pixdim[1..3] + (e.g., spatial units are values 1..7). + Bits 3..5 of xyzt_units specify the units of pixdim[4] + (e.g., temporal units are multiples of 8). + + This compression of 2 distinct concepts into 1 byte is due to the + limited space available in the 348 byte ANALYZE 7.5 header. The + macros XYZT_TO_SPACE and XYZT_TO_TIME can be used to mask off the + undesired bits from the xyzt_units fields, leaving "pure" space + and time codes. Inversely, the macro SPACE_TIME_TO_XYZT can be + used to assemble a space code (0,1,2,...,7) with a time code + (0,8,16,32,...,56) into the combined value for xyzt_units. + + Note that codes are provided to indicate the "time" axis units are + actually frequency in Hertz (_HZ) or in part-per-million (_PPM). + + The toffset field can be used to indicate a nonzero start point for + the time axis. That is, time point #m is at t=toffset+m*pixdim[4] + for m=0..dim[4]-1. +-----------------------------------------------------------------------------*/ + + /*! NIFTI code for unspecified units. */ +#define NIFTI_UNITS_UNKNOWN 0 + + /** Space codes are multiples of 1. **/ + /*! NIFTI code for meters. */ +#define NIFTI_UNITS_METER 1 + /*! NIFTI code for millimeters. */ +#define NIFTI_UNITS_MM 2 + /*! NIFTI code for micrometers. */ +#define NIFTI_UNITS_MICRON 3 + + /** Time codes are multiples of 8. **/ + /*! NIFTI code for seconds. */ +#define NIFTI_UNITS_SEC 8 + /*! NIFTI code for milliseconds. */ +#define NIFTI_UNITS_MSEC 16 + /*! NIFTI code for microseconds. */ +#define NIFTI_UNITS_USEC 24 + + /*** These units are for spectral data: ***/ + /*! NIFTI code for Hertz. */ +#define NIFTI_UNITS_HZ 32 + /*! NIFTI code for ppm. */ +#define NIFTI_UNITS_PPM 40 + +#undef XYZT_TO_SPACE +#undef XYZT_TO_TIME +#define XYZT_TO_SPACE(xyzt) ( (xyzt) & 0x07 ) +#define XYZT_TO_TIME(xyzt) ( (xyzt) & 0x38 ) + +#undef SPACE_TIME_TO_XYZT +#define SPACE_TIME_TO_XYZT(ss,tt) ( (((char)(ss)) & 0x07) \ + | (((char)(tt)) & 0x38) ) + +/*---------------------------------------------------------------------------*/ +/* MRI-SPECIFIC SPATIAL AND TEMPORAL INFORMATION: + --------------------------------------------- + A few fields are provided to store some extra information + that is sometimes important when storing the image data + from an FMRI time series experiment. (After processing such + data into statistical images, these fields are not likely + to be useful.) + + { freq_dim } = These fields encode which spatial dimension (1,2, or 3) + { phase_dim } = corresponds to which acquisition dimension for MRI data. + { slice_dim } = + Examples: + Rectangular scan multi-slice EPI: + freq_dim = 1 phase_dim = 2 slice_dim = 3 (or some permutation) + Spiral scan multi-slice EPI: + freq_dim = phase_dim = 0 slice_dim = 3 + since the concepts of frequency- and phase-encoding directions + don't apply to spiral scan + + slice_duration = If this is positive, AND if slice_dim is nonzero, + indicates the amount of time used to acquire 1 slice. + slice_duration*dim[slice_dim] can be less than pixdim[4] + with a clustered acquisition method, for example. + + slice_code = If this is nonzero, AND if slice_dim is nonzero, AND + if slice_duration is positive, indicates the timing + pattern of the slice acquisition. The following codes + are defined: + NIFTI_SLICE_SEQ_INC + NIFTI_SLICE_SEQ_DEC + NIFTI_SLICE_ALT_INC + NIFTI_SLICE_ALT_DEC + { slice_start } = Indicates the start and end of the slice acquisition + { slice_end } = pattern, when slice_code is nonzero. These values + are present to allow for the possible addition of + "padded" slices at either end of the volume, which + don't fit into the slice timing pattern. If there + are no padding slices, then slice_start=0 and + slice_end=dim[slice_dim]-1 are the correct values. + For these values to be meaningful, slice_start must + be non-negative and slice_end must be greater than + slice_start. + + The following table indicates the slice timing pattern, relative to + time=0 for the first slice acquired, for some sample cases. Here, + dim[slice_dim]=7 (there are 7 slices, labeled 0..6), slice_duration=0.1, + and slice_start=1, slice_end=5 (1 padded slice on each end). + + slice + index SEQ_INC SEQ_DEC ALT_INC ALT_DEC + 6 -- n/a n/a n/a n/a n/a = not applicable + 5 -- 0.4 0.0 0.2 0.0 (slice time offset + 4 -- 0.3 0.1 0.4 0.3 doesn't apply to + 3 -- 0.2 0.2 0.1 0.1 slices outside range + 2 -- 0.1 0.3 0.3 0.4 slice_start..slice_end) + 1 -- 0.0 0.4 0.0 0.2 + 0 -- n/a n/a n/a n/a + + The fields freq_dim, phase_dim, slice_dim are all squished into the single + byte field dim_info (2 bits each, since the values for each field are + limited to the range 0..3). This unpleasantness is due to lack of space + in the 348 byte allowance. + + The macros DIM_INFO_TO_FREQ_DIM, DIM_INFO_TO_PHASE_DIM, and + DIM_INFO_TO_SLICE_DIM can be used to extract these values from the + dim_info byte. + + The macro FPS_INTO_DIM_INFO can be used to put these 3 values + into the dim_info byte. +-----------------------------------------------------------------------------*/ + +#undef DIM_INFO_TO_FREQ_DIM +#undef DIM_INFO_TO_PHASE_DIM +#undef DIM_INFO_TO_SLICE_DIM + +#define DIM_INFO_TO_FREQ_DIM(di) ( ((di) ) & 0x03 ) +#define DIM_INFO_TO_PHASE_DIM(di) ( ((di) >> 2) & 0x03 ) +#define DIM_INFO_TO_SLICE_DIM(di) ( ((di) >> 4) & 0x03 ) + +#undef FPS_INTO_DIM_INFO +#define FPS_INTO_DIM_INFO(fd,pd,sd) ( ( ( ((char)(fd)) & 0x03) ) | \ + ( ( ((char)(pd)) & 0x03) << 2 ) | \ + ( ( ((char)(sd)) & 0x03) << 4 ) ) + +#define NIFTI_SLICE_SEQ_INC 1 +#define NIFTI_SLICE_SEQ_DEC 2 +#define NIFTI_SLICE_ALT_INC 3 +#define NIFTI_SLICE_ALT_DEC 4 + +/*---------------------------------------------------------------------------*/ +/* UNUSED FIELDS: + ------------- + Some of the ANALYZE 7.5 fields marked as ++UNUSED++ may need to be set + to particular values for compatibility with other programs. The issue + of interoperability of ANALYZE 7.5 files is a murky one -- not all + programs require exactly the same set of fields. (Unobscuring this + murkiness is a principal motivation behind NIFTI-1.) + + Some of the fields that may need to be set for other (non-NIFTI aware) + software to be happy are: + + extents dbh.h says this should be 16384 + regular dbh.h says this should be the character 'r' + glmin, } dbh.h says these values should be the min and max voxel + glmax } values for the entire dataset + + It is best to initialize ALL fields in the NIFTI-1 header to 0 + (e.g., with calloc()), then fill in what is needed. +-----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* MISCELLANEOUS C MACROS +-----------------------------------------------------------------------------*/ + +/*.................*/ +/*! Given a nifti_1_header struct, check if it has a good magic number. + Returns NIFTI version number (1..9) if magic is good, 0 if it is not. */ + +#define NIFTI_VERSION(h) \ + ( ( (h).magic[0]=='n' && (h).magic[3]=='\0' && \ + ( (h).magic[1]=='i' || (h).magic[1]=='+' ) && \ + ( (h).magic[2]>='1' && (h).magic[2]<='9' ) ) \ + ? (h).magic[2]-'0' : 0 ) + +/*.................*/ +/*! Check if a nifti_1_header struct says if the data is stored in the + same file or in a separate file. Returns 1 if the data is in the same + file as the header, 0 if it is not. */ + +#define NIFTI_ONEFILE(h) ( (h).magic[1] == '+' ) + +/*.................*/ +/*! Check if a nifti_1_header struct needs to be byte swapped. + Returns 1 if it needs to be swapped, 0 if it does not. */ + +#define NIFTI_NEEDS_SWAP(h) ( (h).dim[0] < 0 || (h).dim[0] > 7 ) + +/*.................*/ +/*! Check if a nifti_1_header struct contains a 5th (vector) dimension. + Returns size of 5th dimension if > 1, returns 0 otherwise. */ + +#define NIFTI_5TH_DIM(h) ( ((h).dim[0]>4 && (h).dim[5]>1) ? (h).dim[5] : 0 ) + +/*****************************************************************************/ + +/*=================*/ +#ifdef __cplusplus +} +#endif +/*=================*/ + +#endif /* _NIFTI_HEADER_ */ diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti_stats.c b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..e1c276af529497d0ed1ed3baf5858c78ee6a1012 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti_stats.c @@ -0,0 +1,11282 @@ +#ifndef lint +static char sccsid[] = "%W% R.W. Cox %E%"; +#endif + /************************************************************************/ + /** Functions to compute cumulative distributions and their inverses **/ + /** for the NIfTI-1 statistical types. Much of this code is taken **/ + /** from other sources. In particular, the cdflib functions by **/ + /** Brown and Lovato make up the bulk of this file. That code **/ + /** was placed in the public domain. The code by K. Krishnamoorthy **/ + /** is also released for unrestricted use. Finally, the other parts **/ + /** of this file (by RW Cox) are released to the public domain. **/ + /** **/ + /** Most of this file comprises a set of "static" functions, to be **/ + /** called by the user-level functions at the very end of the file. **/ + /** At the end of the file is a simple main program to drive these **/ + /** functions. **/ + /** **/ + /** To find the user-level functions, search forward for the string **/ + /** "nifti_", which will be at about line 11000. **/ + /************************************************************************/ + /*****==============================================================*****/ + /***** Neither the National Institutes of Health (NIH), the DFWG, *****/ + /***** nor any of the members or employees of these institutions *****/ + /***** imply any warranty of usefulness of this material for any *****/ + /***** purpose, and do not assume any liability for damages, *****/ + /***** incidental or otherwise, caused by any use of this document. *****/ + /***** If these conditions are not acceptable, do not use this! *****/ + /*****==============================================================*****/ + /************************************************************************/ + + /*....................................................................... + To compile with gcc, for example: + + gcc -O3 -ffast-math -o nifti_stats nifti_stats.c -lm + ........................................................................*/ + + +/* + * niftilib $Id: nifti_stats.c,v 1.1 2012/03/22 18:36:33 fissell Exp $ + */ + +#include "nifti1.h" /* for the NIFTI_INTENT_* constants */ +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + + /************************************************************************/ + /************ Include all the cdflib functions here and now *************/ + /************ [about 9900 lines of code below here] *************/ + /************************************************************************/ + +/** Prototypes for cdflib functions **/ + +static double algdiv(double*,double*); +static double alngam(double*); +static double alnrel(double*); +static double apser(double*,double*,double*,double*); +static double basym(double*,double*,double*,double*); +static double bcorr(double*,double*); +static double betaln(double*,double*); +static double bfrac(double*,double*,double*,double*,double*,double*); +static void bgrat(double*,double*,double*,double*,double*,double*,int*i); +static double bpser(double*,double*,double*,double*); +static void bratio(double*,double*,double*,double*,double*,double*,int*); +static double brcmp1(int*,double*,double*,double*,double*); +static double brcomp(double*,double*,double*,double*); +static double bup(double*,double*,double*,double*,int*,double*); +static void cdfbet(int*,double*,double*,double*,double*,double*,double*, + int*,double*); +static void cdfbin(int*,double*,double*,double*,double*,double*,double*, + int*,double*); +static void cdfchi(int*,double*,double*,double*,double*,int*,double*); +static void cdfchn(int*,double*,double*,double*,double*,double*,int*,double*); +static void cdff(int*,double*,double*,double*,double*,double*,int*,double*); +static void cdffnc(int*,double*,double*,double*,double*,double*,double*, + int*s,double*); +static void cdfgam(int*,double*,double*,double*,double*,double*,int*,double*); +static void cdfnbn(int*,double*,double*,double*,double*,double*,double*, + int*,double*); +static void cdfnor(int*,double*,double*,double*,double*,double*,int*,double*); +static void cdfpoi(int*,double*,double*,double*,double*,int*,double*); +static void cdft(int*,double*,double*,double*,double*,int*,double*); +static void cumbet(double*,double*,double*,double*,double*,double*); +static void cumbin(double*,double*,double*,double*,double*,double*); +static void cumchi(double*,double*,double*,double*); +static void cumchn(double*,double*,double*,double*,double*); +static void cumf(double*,double*,double*,double*,double*); +static void cumfnc(double*,double*,double*,double*,double*,double*); +static void cumgam(double*,double*,double*,double*); +static void cumnbn(double*,double*,double*,double*,double*,double*); +static void cumnor(double*,double*,double*); +static void cumpoi(double*,double*,double*,double*); +static void cumt(double*,double*,double*,double*); +static double dbetrm(double*,double*); +static double devlpl(double [],int*,double*); +static double dexpm1(double*); +static double dinvnr(double *p,double *q); +static void E0000(int,int*,double*,double*,unsigned long*, + unsigned long*,double*,double*,double*, + double*,double*,double*,double*); +static void dinvr(int*,double*,double*,unsigned long*,unsigned long*); +static void dstinv(double*,double*,double*,double*,double*,double*, + double*); +static double dlanor(double*); +static double dln1mx(double*); +static double dln1px(double*); +static double dlnbet(double*,double*); +static double dlngam(double*); +static double dstrem(double*); +static double dt1(double*,double*,double*); +static void E0001(int,int*,double*,double*,double*,double*, + unsigned long*,unsigned long*,double*,double*, + double*,double*); +static void dzror(int*,double*,double*,double*,double *, + unsigned long*,unsigned long*); +static void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl); +static double erf1(double*); +static double erfc1(int*,double*); +static double esum(int*,double*); +static double exparg(int*); +static double fpser(double*,double*,double*,double*); +static double gam1(double*); +static void gaminv(double*,double*,double*,double*,double*,int*); +static double gamln(double*); +static double gamln1(double*); +static double Xgamm(double*); +static void grat1(double*,double*,double*,double*,double*,double*); +static void gratio(double*,double*,double*,double*,int*); +static double gsumln(double*,double*); +static double psi(double*); +static double rcomp(double*,double*); +static double rexp(double*); +static double rlog(double*); +static double rlog1(double*); +static double spmpar(int*); +static double stvaln(double*); +static double fifdint(double); +static double fifdmax1(double,double); +static double fifdmin1(double,double); +static double fifdsign(double,double); +static long fifidint(double); +static long fifmod(long,long); +static void ftnstop(char*); +static int ipmpar(int*); + +/***=====================================================================***/ +static double algdiv(double *a,double *b) +/* +----------------------------------------------------------------------- + + COMPUTATION OF LN(GAMMA(B)/GAMMA(A+B)) WHEN B .GE. 8 + + -------- + + IN THIS ALGORITHM, DEL(X) IS THE FUNCTION DEFINED BY + LN(GAMMA(X)) = (X - 0.5)*LN(X) - X + 0.5*LN(2*PI) + DEL(X). + +----------------------------------------------------------------------- +*/ +{ +static double c0 = .833333333333333e-01; +static double c1 = -.277777777760991e-02; +static double c2 = .793650666825390e-03; +static double c3 = -.595202931351870e-03; +static double c4 = .837308034031215e-03; +static double c5 = -.165322962780713e-02; +static double algdiv,c,d,h,s11,s3,s5,s7,s9,t,u,v,w,x,x2,T1; +/* + .. + .. Executable Statements .. +*/ + if(*a <= *b) goto S10; + h = *b/ *a; + c = 1.0e0/(1.0e0+h); + x = h/(1.0e0+h); + d = *a+(*b-0.5e0); + goto S20; +S10: + h = *a/ *b; + c = h/(1.0e0+h); + x = 1.0e0/(1.0e0+h); + d = *b+(*a-0.5e0); +S20: +/* + SET SN = (1 - X**N)/(1 - X) +*/ + x2 = x*x; + s3 = 1.0e0+(x+x2); + s5 = 1.0e0+(x+x2*s3); + s7 = 1.0e0+(x+x2*s5); + s9 = 1.0e0+(x+x2*s7); + s11 = 1.0e0+(x+x2*s9); +/* + SET W = DEL(B) - DEL(A + B) +*/ + t = pow(1.0e0/ *b,2.0); + w = ((((c5*s11*t+c4*s9)*t+c3*s7)*t+c2*s5)*t+c1*s3)*t+c0; + w *= (c/ *b); +/* + COMBINE THE RESULTS +*/ + T1 = *a/ *b; + u = d*alnrel(&T1); + v = *a*(log(*b)-1.0e0); + if(u <= v) goto S30; + algdiv = w-v-u; + return algdiv; +S30: + algdiv = w-u-v; + return algdiv; +} /* END */ + +/***=====================================================================***/ +static double alngam(double *x) +/* +********************************************************************** + + double alngam(double *x) + double precision LN of the GAMma function + + + Function + + + Returns the natural logarithm of GAMMA(X). + + + Arguments + + + X --> value at which scaled log gamma is to be returned + X is DOUBLE PRECISION + + + Method + + + If X .le. 6.0, then use recursion to get X below 3 + then apply rational approximation number 5236 of + Hart et al, Computer Approximations, John Wiley and + Sons, NY, 1968. + + If X .gt. 6.0, then use recursion to get X to at least 12 and + then use formula 5423 of the same source. + +********************************************************************** +*/ +{ +#define hln2pi 0.91893853320467274178e0 +static double coef[5] = { + 0.83333333333333023564e-1,-0.27777777768818808e-2,0.79365006754279e-3, + -0.594997310889e-3,0.8065880899e-3 +}; +static double scoefd[4] = { + 0.62003838007126989331e2,0.9822521104713994894e1,-0.8906016659497461257e1, + 0.1000000000000000000e1 +}; +static double scoefn[9] = { + 0.62003838007127258804e2,0.36036772530024836321e2,0.20782472531792126786e2, + 0.6338067999387272343e1,0.215994312846059073e1,0.3980671310203570498e0, + 0.1093115956710439502e0,0.92381945590275995e-2,0.29737866448101651e-2 +}; +static int K1 = 9; +static int K3 = 4; +static int K5 = 5; +static double alngam,offset,prod,xx; +static int i,n; +static double T2,T4,T6; +/* + .. + .. Executable Statements .. +*/ + if(!(*x <= 6.0e0)) goto S70; + prod = 1.0e0; + xx = *x; + if(!(*x > 3.0e0)) goto S30; +S10: + if(!(xx > 3.0e0)) goto S20; + xx -= 1.0e0; + prod *= xx; + goto S10; +S30: +S20: + if(!(*x < 2.0e0)) goto S60; +S40: + if(!(xx < 2.0e0)) goto S50; + prod /= xx; + xx += 1.0e0; + goto S40; +S60: +S50: + T2 = xx-2.0e0; + T4 = xx-2.0e0; + alngam = devlpl(scoefn,&K1,&T2)/devlpl(scoefd,&K3,&T4); +/* + COMPUTE RATIONAL APPROXIMATION TO GAMMA(X) +*/ + alngam *= prod; + alngam = log(alngam); + goto S110; +S70: + offset = hln2pi; +/* + IF NECESSARY MAKE X AT LEAST 12 AND CARRY CORRECTION IN OFFSET +*/ + n = fifidint(12.0e0-*x); + if(!(n > 0)) goto S90; + prod = 1.0e0; + for(i=1; i<=n; i++) prod *= (*x+(double)(i-1)); + offset -= log(prod); + xx = *x+(double)n; + goto S100; +S90: + xx = *x; +S100: +/* + COMPUTE POWER SERIES +*/ + T6 = 1.0e0/pow(xx,2.0); + alngam = devlpl(coef,&K5,&T6)/xx; + alngam += (offset+(xx-0.5e0)*log(xx)-xx); +S110: + return alngam; +#undef hln2pi +} /* END */ + +/***=====================================================================***/ +static double alnrel(double *a) +/* +----------------------------------------------------------------------- + EVALUATION OF THE FUNCTION LN(1 + A) +----------------------------------------------------------------------- +*/ +{ +static double p1 = -.129418923021993e+01; +static double p2 = .405303492862024e+00; +static double p3 = -.178874546012214e-01; +static double q1 = -.162752256355323e+01; +static double q2 = .747811014037616e+00; +static double q3 = -.845104217945565e-01; +static double alnrel,t,t2,w,x; +/* + .. + .. Executable Statements .. +*/ + if(fabs(*a) > 0.375e0) goto S10; + t = *a/(*a+2.0e0); + t2 = t*t; + w = (((p3*t2+p2)*t2+p1)*t2+1.0e0)/(((q3*t2+q2)*t2+q1)*t2+1.0e0); + alnrel = 2.0e0*t*w; + return alnrel; +S10: + x = 1.e0+*a; + alnrel = log(x); + return alnrel; +} /* END */ + +/***=====================================================================***/ +static double apser(double *a,double *b,double *x,double *eps) +/* +----------------------------------------------------------------------- + APSER YIELDS THE INCOMPLETE BETA RATIO I(SUB(1-X))(B,A) FOR + A .LE. MIN(EPS,EPS*B), B*X .LE. 1, AND X .LE. 0.5. USED WHEN + A IS VERY SMALL. USE ONLY IF ABOVE INEQUALITIES ARE SATISFIED. +----------------------------------------------------------------------- +*/ +{ +static double g = .577215664901533e0; +static double apser,aj,bx,c,j,s,t,tol; +/* + .. + .. Executable Statements .. +*/ + bx = *b**x; + t = *x-bx; + if(*b**eps > 2.e-2) goto S10; + c = log(*x)+psi(b)+g+t; + goto S20; +S10: + c = log(bx)+g+t; +S20: + tol = 5.0e0**eps*fabs(c); + j = 1.0e0; + s = 0.0e0; +S30: + j += 1.0e0; + t *= (*x-bx/j); + aj = t/j; + s += aj; + if(fabs(aj) > tol) goto S30; + apser = -(*a*(c+s)); + return apser; +} /* END */ + +/***=====================================================================***/ +static double basym(double *a,double *b,double *lambda,double *eps) +/* +----------------------------------------------------------------------- + ASYMPTOTIC EXPANSION FOR IX(A,B) FOR LARGE A AND B. + LAMBDA = (A + B)*Y - B AND EPS IS THE TOLERANCE USED. + IT IS ASSUMED THAT LAMBDA IS NONNEGATIVE AND THAT + A AND B ARE GREATER THAN OR EQUAL TO 15. +----------------------------------------------------------------------- +*/ +{ +static double e0 = 1.12837916709551e0; +static double e1 = .353553390593274e0; +static int num = 20; +/* +------------------------ + ****** NUM IS THE MAXIMUM VALUE THAT N CAN TAKE IN THE DO LOOP + ENDING AT STATEMENT 50. IT IS REQUIRED THAT NUM BE EVEN. + THE ARRAYS A0, B0, C, D HAVE DIMENSION NUM + 1. +------------------------ + E0 = 2/SQRT(PI) + E1 = 2**(-3/2) +------------------------ +*/ +static int K3 = 1; +static double basym,bsum,dsum,f,h,h2,hn,j0,j1,r,r0,r1,s,sum,t,t0,t1,u,w,w0,z,z0, + z2,zn,znm1; +static int i,im1,imj,j,m,mm1,mmj,n,np1; +static double a0[21],b0[21],c[21],d[21],T1,T2; +/* + .. + .. Executable Statements .. +*/ + basym = 0.0e0; + if(*a >= *b) goto S10; + h = *a/ *b; + r0 = 1.0e0/(1.0e0+h); + r1 = (*b-*a)/ *b; + w0 = 1.0e0/sqrt(*a*(1.0e0+h)); + goto S20; +S10: + h = *b/ *a; + r0 = 1.0e0/(1.0e0+h); + r1 = (*b-*a)/ *a; + w0 = 1.0e0/sqrt(*b*(1.0e0+h)); +S20: + T1 = -(*lambda/ *a); + T2 = *lambda/ *b; + f = *a*rlog1(&T1)+*b*rlog1(&T2); + t = exp(-f); + if(t == 0.0e0) return basym; + z0 = sqrt(f); + z = 0.5e0*(z0/e1); + z2 = f+f; + a0[0] = 2.0e0/3.0e0*r1; + c[0] = -(0.5e0*a0[0]); + d[0] = -c[0]; + j0 = 0.5e0/e0*erfc1(&K3,&z0); + j1 = e1; + sum = j0+d[0]*w0*j1; + s = 1.0e0; + h2 = h*h; + hn = 1.0e0; + w = w0; + znm1 = z; + zn = z2; + for(n=2; n<=num; n+=2) { + hn = h2*hn; + a0[n-1] = 2.0e0*r0*(1.0e0+h*hn)/((double)n+2.0e0); + np1 = n+1; + s += hn; + a0[np1-1] = 2.0e0*r1*s/((double)n+3.0e0); + for(i=n; i<=np1; i++) { + r = -(0.5e0*((double)i+1.0e0)); + b0[0] = r*a0[0]; + for(m=2; m<=i; m++) { + bsum = 0.0e0; + mm1 = m-1; + for(j=1; j<=mm1; j++) { + mmj = m-j; + bsum += (((double)j*r-(double)mmj)*a0[j-1]*b0[mmj-1]); + } + b0[m-1] = r*a0[m-1]+bsum/(double)m; + } + c[i-1] = b0[i-1]/((double)i+1.0e0); + dsum = 0.0e0; + im1 = i-1; + for(j=1; j<=im1; j++) { + imj = i-j; + dsum += (d[imj-1]*c[j-1]); + } + d[i-1] = -(dsum+c[i-1]); + } + j0 = e1*znm1+((double)n-1.0e0)*j0; + j1 = e1*zn+(double)n*j1; + znm1 = z2*znm1; + zn = z2*zn; + w = w0*w; + t0 = d[n-1]*w*j0; + w = w0*w; + t1 = d[np1-1]*w*j1; + sum += (t0+t1); + if(fabs(t0)+fabs(t1) <= *eps*sum) goto S80; + } +S80: + u = exp(-bcorr(a,b)); + basym = e0*t*u*sum; + return basym; +} /* END */ + +/***=====================================================================***/ +static double bcorr(double *a0,double *b0) +/* +----------------------------------------------------------------------- + + EVALUATION OF DEL(A0) + DEL(B0) - DEL(A0 + B0) WHERE + LN(GAMMA(A)) = (A - 0.5)*LN(A) - A + 0.5*LN(2*PI) + DEL(A). + IT IS ASSUMED THAT A0 .GE. 8 AND B0 .GE. 8. + +----------------------------------------------------------------------- +*/ +{ +static double c0 = .833333333333333e-01; +static double c1 = -.277777777760991e-02; +static double c2 = .793650666825390e-03; +static double c3 = -.595202931351870e-03; +static double c4 = .837308034031215e-03; +static double c5 = -.165322962780713e-02; +static double bcorr,a,b,c,h,s11,s3,s5,s7,s9,t,w,x,x2; +/* + .. + .. Executable Statements .. +*/ + a = fifdmin1(*a0,*b0); + b = fifdmax1(*a0,*b0); + h = a/b; + c = h/(1.0e0+h); + x = 1.0e0/(1.0e0+h); + x2 = x*x; +/* + SET SN = (1 - X**N)/(1 - X) +*/ + s3 = 1.0e0+(x+x2); + s5 = 1.0e0+(x+x2*s3); + s7 = 1.0e0+(x+x2*s5); + s9 = 1.0e0+(x+x2*s7); + s11 = 1.0e0+(x+x2*s9); +/* + SET W = DEL(B) - DEL(A + B) +*/ + t = pow(1.0e0/b,2.0); + w = ((((c5*s11*t+c4*s9)*t+c3*s7)*t+c2*s5)*t+c1*s3)*t+c0; + w *= (c/b); +/* + COMPUTE DEL(A) + W +*/ + t = pow(1.0e0/a,2.0); + bcorr = (((((c5*t+c4)*t+c3)*t+c2)*t+c1)*t+c0)/a+w; + return bcorr; +} /* END */ + +/***=====================================================================***/ +static double betaln(double *a0,double *b0) +/* +----------------------------------------------------------------------- + EVALUATION OF THE LOGARITHM OF THE BETA FUNCTION +----------------------------------------------------------------------- + E = 0.5*LN(2*PI) +-------------------------- +*/ +{ +static double e = .918938533204673e0; +static double betaln,a,b,c,h,u,v,w,z; +static int i,n; +static double T1; +/* + .. + .. Executable Statements .. +*/ + a = fifdmin1(*a0,*b0); + b = fifdmax1(*a0,*b0); + if(a >= 8.0e0) goto S100; + if(a >= 1.0e0) goto S20; +/* +----------------------------------------------------------------------- + PROCEDURE WHEN A .LT. 1 +----------------------------------------------------------------------- +*/ + if(b >= 8.0e0) goto S10; + T1 = a+b; + betaln = gamln(&a)+(gamln(&b)-gamln(&T1)); + return betaln; +S10: + betaln = gamln(&a)+algdiv(&a,&b); + return betaln; +S20: +/* +----------------------------------------------------------------------- + PROCEDURE WHEN 1 .LE. A .LT. 8 +----------------------------------------------------------------------- +*/ + if(a > 2.0e0) goto S40; + if(b > 2.0e0) goto S30; + betaln = gamln(&a)+gamln(&b)-gsumln(&a,&b); + return betaln; +S30: + w = 0.0e0; + if(b < 8.0e0) goto S60; + betaln = gamln(&a)+algdiv(&a,&b); + return betaln; +S40: +/* + REDUCTION OF A WHEN B .LE. 1000 +*/ + if(b > 1000.0e0) goto S80; + n = a-1.0e0; + w = 1.0e0; + for(i=1; i<=n; i++) { + a -= 1.0e0; + h = a/b; + w *= (h/(1.0e0+h)); + } + w = log(w); + if(b < 8.0e0) goto S60; + betaln = w+gamln(&a)+algdiv(&a,&b); + return betaln; +S60: +/* + REDUCTION OF B WHEN B .LT. 8 +*/ + n = b-1.0e0; + z = 1.0e0; + for(i=1; i<=n; i++) { + b -= 1.0e0; + z *= (b/(a+b)); + } + betaln = w+log(z)+(gamln(&a)+(gamln(&b)-gsumln(&a,&b))); + return betaln; +S80: +/* + REDUCTION OF A WHEN B .GT. 1000 +*/ + n = a-1.0e0; + w = 1.0e0; + for(i=1; i<=n; i++) { + a -= 1.0e0; + w *= (a/(1.0e0+a/b)); + } + betaln = log(w)-(double)n*log(b)+(gamln(&a)+algdiv(&a,&b)); + return betaln; +S100: +/* +----------------------------------------------------------------------- + PROCEDURE WHEN A .GE. 8 +----------------------------------------------------------------------- +*/ + w = bcorr(&a,&b); + h = a/b; + c = h/(1.0e0+h); + u = -((a-0.5e0)*log(c)); + v = b*alnrel(&h); + if(u <= v) goto S110; + betaln = -(0.5e0*log(b))+e+w-v-u; + return betaln; +S110: + betaln = -(0.5e0*log(b))+e+w-u-v; + return betaln; +} /* END */ + +/***=====================================================================***/ +static double bfrac(double *a,double *b,double *x,double *y,double *lambda, + double *eps) +/* +----------------------------------------------------------------------- + CONTINUED FRACTION EXPANSION FOR IX(A,B) WHEN A,B .GT. 1. + IT IS ASSUMED THAT LAMBDA = (A + B)*Y - B. +----------------------------------------------------------------------- +*/ +{ +static double bfrac,alpha,an,anp1,beta,bn,bnp1,c,c0,c1,e,n,p,r,r0,s,t,w,yp1; +/* + .. + .. Executable Statements .. +*/ + bfrac = brcomp(a,b,x,y); + if(bfrac == 0.0e0) return bfrac; + c = 1.0e0+*lambda; + c0 = *b/ *a; + c1 = 1.0e0+1.0e0/ *a; + yp1 = *y+1.0e0; + n = 0.0e0; + p = 1.0e0; + s = *a+1.0e0; + an = 0.0e0; + bn = anp1 = 1.0e0; + bnp1 = c/c1; + r = c1/c; +S10: +/* + CONTINUED FRACTION CALCULATION +*/ + n += 1.0e0; + t = n/ *a; + w = n*(*b-n)**x; + e = *a/s; + alpha = p*(p+c0)*e*e*(w**x); + e = (1.0e0+t)/(c1+t+t); + beta = n+w/s+e*(c+n*yp1); + p = 1.0e0+t; + s += 2.0e0; +/* + UPDATE AN, BN, ANP1, AND BNP1 +*/ + t = alpha*an+beta*anp1; + an = anp1; + anp1 = t; + t = alpha*bn+beta*bnp1; + bn = bnp1; + bnp1 = t; + r0 = r; + r = anp1/bnp1; + if(fabs(r-r0) <= *eps*r) goto S20; +/* + RESCALE AN, BN, ANP1, AND BNP1 +*/ + an /= bnp1; + bn /= bnp1; + anp1 = r; + bnp1 = 1.0e0; + goto S10; +S20: +/* + TERMINATION +*/ + bfrac *= r; + return bfrac; +} /* END */ + +/***=====================================================================***/ +static void bgrat(double *a,double *b,double *x,double *y,double *w, + double *eps,int *ierr) +/* +----------------------------------------------------------------------- + ASYMPTOTIC EXPANSION FOR IX(A,B) WHEN A IS LARGER THAN B. + THE RESULT OF THE EXPANSION IS ADDED TO W. IT IS ASSUMED + THAT A .GE. 15 AND B .LE. 1. EPS IS THE TOLERANCE USED. + IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. +----------------------------------------------------------------------- +*/ +{ +static double bm1,bp2n,cn,coef,dj,j,l,lnx,n2,nu,p,q,r,s,sum,t,t2,u,v,z; +static int i,n,nm1; +static double c[30],d[30],T1; +/* + .. + .. Executable Statements .. +*/ + bm1 = *b-0.5e0-0.5e0; + nu = *a+0.5e0*bm1; + if(*y > 0.375e0) goto S10; + T1 = -*y; + lnx = alnrel(&T1); + goto S20; +S10: + lnx = log(*x); +S20: + z = -(nu*lnx); + if(*b*z == 0.0e0) goto S70; +/* + COMPUTATION OF THE EXPANSION + SET R = EXP(-Z)*Z**B/GAMMA(B) +*/ + r = *b*(1.0e0+gam1(b))*exp(*b*log(z)); + r *= (exp(*a*lnx)*exp(0.5e0*bm1*lnx)); + u = algdiv(b,a)+*b*log(nu); + u = r*exp(-u); + if(u == 0.0e0) goto S70; + grat1(b,&z,&r,&p,&q,eps); + v = 0.25e0*pow(1.0e0/nu,2.0); + t2 = 0.25e0*lnx*lnx; + l = *w/u; + j = q/r; + sum = j; + t = cn = 1.0e0; + n2 = 0.0e0; + for(n=1; n<=30; n++) { + bp2n = *b+n2; + j = (bp2n*(bp2n+1.0e0)*j+(z+bp2n+1.0e0)*t)*v; + n2 += 2.0e0; + t *= t2; + cn /= (n2*(n2+1.0e0)); + c[n-1] = cn; + s = 0.0e0; + if(n == 1) goto S40; + nm1 = n-1; + coef = *b-(double)n; + for(i=1; i<=nm1; i++) { + s += (coef*c[i-1]*d[n-i-1]); + coef += *b; + } +S40: + d[n-1] = bm1*cn+s/(double)n; + dj = d[n-1]*j; + sum += dj; + if(sum <= 0.0e0) goto S70; + if(fabs(dj) <= *eps*(sum+l)) goto S60; + } +S60: +/* + ADD THE RESULTS TO W +*/ + *ierr = 0; + *w += (u*sum); + return; +S70: +/* + THE EXPANSION CANNOT BE COMPUTED +*/ + *ierr = 1; + return; +} /* END */ + +/***=====================================================================***/ +static double bpser(double *a,double *b,double *x,double *eps) +/* +----------------------------------------------------------------------- + POWER SERIES EXPANSION FOR EVALUATING IX(A,B) WHEN B .LE. 1 + OR B*X .LE. 0.7. EPS IS THE TOLERANCE USED. +----------------------------------------------------------------------- +*/ +{ +static double bpser,a0,apb,b0,c,n,sum,t,tol,u,w,z; +static int i,m; +/* + .. + .. Executable Statements .. +*/ + bpser = 0.0e0; + if(*x == 0.0e0) return bpser; +/* +----------------------------------------------------------------------- + COMPUTE THE FACTOR X**A/(A*BETA(A,B)) +----------------------------------------------------------------------- +*/ + a0 = fifdmin1(*a,*b); + if(a0 < 1.0e0) goto S10; + z = *a*log(*x)-betaln(a,b); + bpser = exp(z)/ *a; + goto S100; +S10: + b0 = fifdmax1(*a,*b); + if(b0 >= 8.0e0) goto S90; + if(b0 > 1.0e0) goto S40; +/* + PROCEDURE FOR A0 .LT. 1 AND B0 .LE. 1 +*/ + bpser = pow(*x,*a); + if(bpser == 0.0e0) return bpser; + apb = *a+*b; + if(apb > 1.0e0) goto S20; + z = 1.0e0+gam1(&apb); + goto S30; +S20: + u = *a+*b-1.e0; + z = (1.0e0+gam1(&u))/apb; +S30: + c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; + bpser *= (c*(*b/apb)); + goto S100; +S40: +/* + PROCEDURE FOR A0 .LT. 1 AND 1 .LT. B0 .LT. 8 +*/ + u = gamln1(&a0); + m = b0-1.0e0; + if(m < 1) goto S60; + c = 1.0e0; + for(i=1; i<=m; i++) { + b0 -= 1.0e0; + c *= (b0/(a0+b0)); + } + u = log(c)+u; +S60: + z = *a*log(*x)-u; + b0 -= 1.0e0; + apb = a0+b0; + if(apb > 1.0e0) goto S70; + t = 1.0e0+gam1(&apb); + goto S80; +S70: + u = a0+b0-1.e0; + t = (1.0e0+gam1(&u))/apb; +S80: + bpser = exp(z)*(a0/ *a)*(1.0e0+gam1(&b0))/t; + goto S100; +S90: +/* + PROCEDURE FOR A0 .LT. 1 AND B0 .GE. 8 +*/ + u = gamln1(&a0)+algdiv(&a0,&b0); + z = *a*log(*x)-u; + bpser = a0/ *a*exp(z); +S100: + if(bpser == 0.0e0 || *a <= 0.1e0**eps) return bpser; +/* +----------------------------------------------------------------------- + COMPUTE THE SERIES +----------------------------------------------------------------------- +*/ + sum = n = 0.0e0; + c = 1.0e0; + tol = *eps/ *a; +S110: + n += 1.0e0; + c *= ((0.5e0+(0.5e0-*b/n))**x); + w = c/(*a+n); + sum += w; + if(fabs(w) > tol) goto S110; + bpser *= (1.0e0+*a*sum); + return bpser; +} /* END */ + +/***=====================================================================***/ +static void bratio(double *a,double *b,double *x,double *y,double *w, + double *w1,int *ierr) +/* +----------------------------------------------------------------------- + + EVALUATION OF THE INCOMPLETE BETA FUNCTION IX(A,B) + + -------------------- + + IT IS ASSUMED THAT A AND B ARE NONNEGATIVE, AND THAT X .LE. 1 + AND Y = 1 - X. BRATIO ASSIGNS W AND W1 THE VALUES + + W = IX(A,B) + W1 = 1 - IX(A,B) + + IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. + IF NO INPUT ERRORS ARE DETECTED THEN IERR IS SET TO 0 AND + W AND W1 ARE COMPUTED. OTHERWISE, IF AN ERROR IS DETECTED, + THEN W AND W1 ARE ASSIGNED THE VALUE 0 AND IERR IS SET TO + ONE OF THE FOLLOWING VALUES ... + + IERR = 1 IF A OR B IS NEGATIVE + IERR = 2 IF A = B = 0 + IERR = 3 IF X .LT. 0 OR X .GT. 1 + IERR = 4 IF Y .LT. 0 OR Y .GT. 1 + IERR = 5 IF X + Y .NE. 1 + IERR = 6 IF X = A = 0 + IERR = 7 IF Y = B = 0 + +-------------------- + WRITTEN BY ALFRED H. MORRIS, JR. + NAVAL SURFACE WARFARE CENTER + DAHLGREN, VIRGINIA + REVISED ... NOV 1991 +----------------------------------------------------------------------- +*/ +{ +static int K1 = 1; +static double a0,b0,eps,lambda,t,x0,y0,z; +static int ierr1,ind,n; +static double T2,T3,T4,T5; +/* + .. + .. Executable Statements .. +*/ +/* + ****** EPS IS A MACHINE DEPENDENT CONSTANT. EPS IS THE SMALLEST + FLOATING POINT NUMBER FOR WHICH 1.0 + EPS .GT. 1.0 +*/ + eps = spmpar(&K1); + *w = *w1 = 0.0e0; + if(*a < 0.0e0 || *b < 0.0e0) goto S270; + if(*a == 0.0e0 && *b == 0.0e0) goto S280; + if(*x < 0.0e0 || *x > 1.0e0) goto S290; + if(*y < 0.0e0 || *y > 1.0e0) goto S300; + z = *x+*y-0.5e0-0.5e0; + if(fabs(z) > 3.0e0*eps) goto S310; + *ierr = 0; + if(*x == 0.0e0) goto S210; + if(*y == 0.0e0) goto S230; + if(*a == 0.0e0) goto S240; + if(*b == 0.0e0) goto S220; + eps = fifdmax1(eps,1.e-15); + if(fifdmax1(*a,*b) < 1.e-3*eps) goto S260; + ind = 0; + a0 = *a; + b0 = *b; + x0 = *x; + y0 = *y; + if(fifdmin1(a0,b0) > 1.0e0) goto S40; +/* + PROCEDURE FOR A0 .LE. 1 OR B0 .LE. 1 +*/ + if(*x <= 0.5e0) goto S10; + ind = 1; + a0 = *b; + b0 = *a; + x0 = *y; + y0 = *x; +S10: + if(b0 < fifdmin1(eps,eps*a0)) goto S90; + if(a0 < fifdmin1(eps,eps*b0) && b0*x0 <= 1.0e0) goto S100; + if(fifdmax1(a0,b0) > 1.0e0) goto S20; + if(a0 >= fifdmin1(0.2e0,b0)) goto S110; + if(pow(x0,a0) <= 0.9e0) goto S110; + if(x0 >= 0.3e0) goto S120; + n = 20; + goto S140; +S20: + if(b0 <= 1.0e0) goto S110; + if(x0 >= 0.3e0) goto S120; + if(x0 >= 0.1e0) goto S30; + if(pow(x0*b0,a0) <= 0.7e0) goto S110; +S30: + if(b0 > 15.0e0) goto S150; + n = 20; + goto S140; +S40: +/* + PROCEDURE FOR A0 .GT. 1 AND B0 .GT. 1 +*/ + if(*a > *b) goto S50; + lambda = *a-(*a+*b)**x; + goto S60; +S50: + lambda = (*a+*b)**y-*b; +S60: + if(lambda >= 0.0e0) goto S70; + ind = 1; + a0 = *b; + b0 = *a; + x0 = *y; + y0 = *x; + lambda = fabs(lambda); +S70: + if(b0 < 40.0e0 && b0*x0 <= 0.7e0) goto S110; + if(b0 < 40.0e0) goto S160; + if(a0 > b0) goto S80; + if(a0 <= 100.0e0) goto S130; + if(lambda > 0.03e0*a0) goto S130; + goto S200; +S80: + if(b0 <= 100.0e0) goto S130; + if(lambda > 0.03e0*b0) goto S130; + goto S200; +S90: +/* + EVALUATION OF THE APPROPRIATE ALGORITHM +*/ + *w = fpser(&a0,&b0,&x0,&eps); + *w1 = 0.5e0+(0.5e0-*w); + goto S250; +S100: + *w1 = apser(&a0,&b0,&x0,&eps); + *w = 0.5e0+(0.5e0-*w1); + goto S250; +S110: + *w = bpser(&a0,&b0,&x0,&eps); + *w1 = 0.5e0+(0.5e0-*w); + goto S250; +S120: + *w1 = bpser(&b0,&a0,&y0,&eps); + *w = 0.5e0+(0.5e0-*w1); + goto S250; +S130: + T2 = 15.0e0*eps; + *w = bfrac(&a0,&b0,&x0,&y0,&lambda,&T2); + *w1 = 0.5e0+(0.5e0-*w); + goto S250; +S140: + *w1 = bup(&b0,&a0,&y0,&x0,&n,&eps); + b0 += (double)n; +S150: + T3 = 15.0e0*eps; + bgrat(&b0,&a0,&y0,&x0,w1,&T3,&ierr1); + *w = 0.5e0+(0.5e0-*w1); + goto S250; +S160: + n = b0; + b0 -= (double)n; + if(b0 != 0.0e0) goto S170; + n -= 1; + b0 = 1.0e0; +S170: + *w = bup(&b0,&a0,&y0,&x0,&n,&eps); + if(x0 > 0.7e0) goto S180; + *w += bpser(&a0,&b0,&x0,&eps); + *w1 = 0.5e0+(0.5e0-*w); + goto S250; +S180: + if(a0 > 15.0e0) goto S190; + n = 20; + *w += bup(&a0,&b0,&x0,&y0,&n,&eps); + a0 += (double)n; +S190: + T4 = 15.0e0*eps; + bgrat(&a0,&b0,&x0,&y0,w,&T4,&ierr1); + *w1 = 0.5e0+(0.5e0-*w); + goto S250; +S200: + T5 = 100.0e0*eps; + *w = basym(&a0,&b0,&lambda,&T5); + *w1 = 0.5e0+(0.5e0-*w); + goto S250; +S210: +/* + TERMINATION OF THE PROCEDURE +*/ + if(*a == 0.0e0) goto S320; +S220: + *w = 0.0e0; + *w1 = 1.0e0; + return; +S230: + if(*b == 0.0e0) goto S330; +S240: + *w = 1.0e0; + *w1 = 0.0e0; + return; +S250: + if(ind == 0) return; + t = *w; + *w = *w1; + *w1 = t; + return; +S260: +/* + PROCEDURE FOR A AND B .LT. 1.E-3*EPS +*/ + *w = *b/(*a+*b); + *w1 = *a/(*a+*b); + return; +S270: +/* + ERROR RETURN +*/ + *ierr = 1; + return; +S280: + *ierr = 2; + return; +S290: + *ierr = 3; + return; +S300: + *ierr = 4; + return; +S310: + *ierr = 5; + return; +S320: + *ierr = 6; + return; +S330: + *ierr = 7; + return; +} /* END */ + +/***=====================================================================***/ +static double brcmp1(int *mu,double *a,double *b,double *x,double *y) +/* +----------------------------------------------------------------------- + EVALUATION OF EXP(MU) * (X**A*Y**B/BETA(A,B)) +----------------------------------------------------------------------- +*/ +{ +static double Const = .398942280401433e0; +static double brcmp1,a0,apb,b0,c,e,h,lambda,lnx,lny,t,u,v,x0,y0,z; +static int i,n; +/* +----------------- + CONST = 1/SQRT(2*PI) +----------------- +*/ +static double T1,T2,T3,T4; +/* + .. + .. Executable Statements .. +*/ + a0 = fifdmin1(*a,*b); + if(a0 >= 8.0e0) goto S130; + if(*x > 0.375e0) goto S10; + lnx = log(*x); + T1 = -*x; + lny = alnrel(&T1); + goto S30; +S10: + if(*y > 0.375e0) goto S20; + T2 = -*y; + lnx = alnrel(&T2); + lny = log(*y); + goto S30; +S20: + lnx = log(*x); + lny = log(*y); +S30: + z = *a*lnx+*b*lny; + if(a0 < 1.0e0) goto S40; + z -= betaln(a,b); + brcmp1 = esum(mu,&z); + return brcmp1; +S40: +/* +----------------------------------------------------------------------- + PROCEDURE FOR A .LT. 1 OR B .LT. 1 +----------------------------------------------------------------------- +*/ + b0 = fifdmax1(*a,*b); + if(b0 >= 8.0e0) goto S120; + if(b0 > 1.0e0) goto S70; +/* + ALGORITHM FOR B0 .LE. 1 +*/ + brcmp1 = esum(mu,&z); + if(brcmp1 == 0.0e0) return brcmp1; + apb = *a+*b; + if(apb > 1.0e0) goto S50; + z = 1.0e0+gam1(&apb); + goto S60; +S50: + u = *a+*b-1.e0; + z = (1.0e0+gam1(&u))/apb; +S60: + c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; + brcmp1 = brcmp1*(a0*c)/(1.0e0+a0/b0); + return brcmp1; +S70: +/* + ALGORITHM FOR 1 .LT. B0 .LT. 8 +*/ + u = gamln1(&a0); + n = b0-1.0e0; + if(n < 1) goto S90; + c = 1.0e0; + for(i=1; i<=n; i++) { + b0 -= 1.0e0; + c *= (b0/(a0+b0)); + } + u = log(c)+u; +S90: + z -= u; + b0 -= 1.0e0; + apb = a0+b0; + if(apb > 1.0e0) goto S100; + t = 1.0e0+gam1(&apb); + goto S110; +S100: + u = a0+b0-1.e0; + t = (1.0e0+gam1(&u))/apb; +S110: + brcmp1 = a0*esum(mu,&z)*(1.0e0+gam1(&b0))/t; + return brcmp1; +S120: +/* + ALGORITHM FOR B0 .GE. 8 +*/ + u = gamln1(&a0)+algdiv(&a0,&b0); + T3 = z-u; + brcmp1 = a0*esum(mu,&T3); + return brcmp1; +S130: +/* +----------------------------------------------------------------------- + PROCEDURE FOR A .GE. 8 AND B .GE. 8 +----------------------------------------------------------------------- +*/ + if(*a > *b) goto S140; + h = *a/ *b; + x0 = h/(1.0e0+h); + y0 = 1.0e0/(1.0e0+h); + lambda = *a-(*a+*b)**x; + goto S150; +S140: + h = *b/ *a; + x0 = 1.0e0/(1.0e0+h); + y0 = h/(1.0e0+h); + lambda = (*a+*b)**y-*b; +S150: + e = -(lambda/ *a); + if(fabs(e) > 0.6e0) goto S160; + u = rlog1(&e); + goto S170; +S160: + u = e-log(*x/x0); +S170: + e = lambda/ *b; + if(fabs(e) > 0.6e0) goto S180; + v = rlog1(&e); + goto S190; +S180: + v = e-log(*y/y0); +S190: + T4 = -(*a*u+*b*v); + z = esum(mu,&T4); + brcmp1 = Const*sqrt(*b*x0)*z*exp(-bcorr(a,b)); + return brcmp1; +} /* END */ + +/***=====================================================================***/ +static double brcomp(double *a,double *b,double *x,double *y) +/* +----------------------------------------------------------------------- + EVALUATION OF X**A*Y**B/BETA(A,B) +----------------------------------------------------------------------- +*/ +{ +static double Const = .398942280401433e0; +static double brcomp,a0,apb,b0,c,e,h,lambda,lnx,lny,t,u,v,x0,y0,z; +static int i,n; +/* +----------------- + CONST = 1/SQRT(2*PI) +----------------- +*/ +static double T1,T2; +/* + .. + .. Executable Statements .. +*/ + brcomp = 0.0e0; + if(*x == 0.0e0 || *y == 0.0e0) return brcomp; + a0 = fifdmin1(*a,*b); + if(a0 >= 8.0e0) goto S130; + if(*x > 0.375e0) goto S10; + lnx = log(*x); + T1 = -*x; + lny = alnrel(&T1); + goto S30; +S10: + if(*y > 0.375e0) goto S20; + T2 = -*y; + lnx = alnrel(&T2); + lny = log(*y); + goto S30; +S20: + lnx = log(*x); + lny = log(*y); +S30: + z = *a*lnx+*b*lny; + if(a0 < 1.0e0) goto S40; + z -= betaln(a,b); + brcomp = exp(z); + return brcomp; +S40: +/* +----------------------------------------------------------------------- + PROCEDURE FOR A .LT. 1 OR B .LT. 1 +----------------------------------------------------------------------- +*/ + b0 = fifdmax1(*a,*b); + if(b0 >= 8.0e0) goto S120; + if(b0 > 1.0e0) goto S70; +/* + ALGORITHM FOR B0 .LE. 1 +*/ + brcomp = exp(z); + if(brcomp == 0.0e0) return brcomp; + apb = *a+*b; + if(apb > 1.0e0) goto S50; + z = 1.0e0+gam1(&apb); + goto S60; +S50: + u = *a+*b-1.e0; + z = (1.0e0+gam1(&u))/apb; +S60: + c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; + brcomp = brcomp*(a0*c)/(1.0e0+a0/b0); + return brcomp; +S70: +/* + ALGORITHM FOR 1 .LT. B0 .LT. 8 +*/ + u = gamln1(&a0); + n = b0-1.0e0; + if(n < 1) goto S90; + c = 1.0e0; + for(i=1; i<=n; i++) { + b0 -= 1.0e0; + c *= (b0/(a0+b0)); + } + u = log(c)+u; +S90: + z -= u; + b0 -= 1.0e0; + apb = a0+b0; + if(apb > 1.0e0) goto S100; + t = 1.0e0+gam1(&apb); + goto S110; +S100: + u = a0+b0-1.e0; + t = (1.0e0+gam1(&u))/apb; +S110: + brcomp = a0*exp(z)*(1.0e0+gam1(&b0))/t; + return brcomp; +S120: +/* + ALGORITHM FOR B0 .GE. 8 +*/ + u = gamln1(&a0)+algdiv(&a0,&b0); + brcomp = a0*exp(z-u); + return brcomp; +S130: +/* +----------------------------------------------------------------------- + PROCEDURE FOR A .GE. 8 AND B .GE. 8 +----------------------------------------------------------------------- +*/ + if(*a > *b) goto S140; + h = *a/ *b; + x0 = h/(1.0e0+h); + y0 = 1.0e0/(1.0e0+h); + lambda = *a-(*a+*b)**x; + goto S150; +S140: + h = *b/ *a; + x0 = 1.0e0/(1.0e0+h); + y0 = h/(1.0e0+h); + lambda = (*a+*b)**y-*b; +S150: + e = -(lambda/ *a); + if(fabs(e) > 0.6e0) goto S160; + u = rlog1(&e); + goto S170; +S160: + u = e-log(*x/x0); +S170: + e = lambda/ *b; + if(fabs(e) > 0.6e0) goto S180; + v = rlog1(&e); + goto S190; +S180: + v = e-log(*y/y0); +S190: + z = exp(-(*a*u+*b*v)); + brcomp = Const*sqrt(*b*x0)*z*exp(-bcorr(a,b)); + return brcomp; +} /* END */ + +/***=====================================================================***/ +static double bup(double *a,double *b,double *x,double *y,int *n,double *eps) +/* +----------------------------------------------------------------------- + EVALUATION OF IX(A,B) - IX(A+N,B) WHERE N IS A POSITIVE INTEGER. + EPS IS THE TOLERANCE USED. +----------------------------------------------------------------------- +*/ +{ +static int K1 = 1; +static int K2 = 0; +static double bup,ap1,apb,d,l,r,t,w; +static int i,k,kp1,mu,nm1; +/* + .. + .. Executable Statements .. +*/ +/* + OBTAIN THE SCALING FACTOR EXP(-MU) AND + EXP(MU)*(X**A*Y**B/BETA(A,B))/A +*/ + apb = *a+*b; + ap1 = *a+1.0e0; + mu = 0; + d = 1.0e0; + if(*n == 1 || *a < 1.0e0) goto S10; + if(apb < 1.1e0*ap1) goto S10; + mu = fabs(exparg(&K1)); + k = exparg(&K2); + if(k < mu) mu = k; + t = mu; + d = exp(-t); +S10: + bup = brcmp1(&mu,a,b,x,y)/ *a; + if(*n == 1 || bup == 0.0e0) return bup; + nm1 = *n-1; + w = d; +/* + LET K BE THE INDEX OF THE MAXIMUM TERM +*/ + k = 0; + if(*b <= 1.0e0) goto S50; + if(*y > 1.e-4) goto S20; + k = nm1; + goto S30; +S20: + r = (*b-1.0e0)**x/ *y-*a; + if(r < 1.0e0) goto S50; + k = t = nm1; + if(r < t) k = r; +S30: +/* + ADD THE INCREASING TERMS OF THE SERIES +*/ + for(i=1; i<=k; i++) { + l = i-1; + d = (apb+l)/(ap1+l)**x*d; + w += d; + } + if(k == nm1) goto S70; +S50: +/* + ADD THE REMAINING TERMS OF THE SERIES +*/ + kp1 = k+1; + for(i=kp1; i<=nm1; i++) { + l = i-1; + d = (apb+l)/(ap1+l)**x*d; + w += d; + if(d <= *eps*w) goto S70; + } +S70: +/* + TERMINATE THE PROCEDURE +*/ + bup *= w; + return bup; +} /* END */ + +/***=====================================================================***/ +static void cdfbet(int *which,double *p,double *q,double *x,double *y, + double *a,double *b,int *status,double *bound) +/********************************************************************** + + void cdfbet(int *which,double *p,double *q,double *x,double *y, + double *a,double *b,int *status,double *bound) + + Cumulative Distribution Function + BETa Distribution + + + Function + + + Calculates any one parameter of the beta distribution given + values for the others. + + + Arguments + + + WHICH --> Integer indicating which of the next four argument + values is to be calculated from the others. + Legal range: 1..4 + iwhich = 1 : Calculate P and Q from X,Y,A and B + iwhich = 2 : Calculate X and Y from P,Q,A and B + iwhich = 3 : Calculate A from P,Q,X,Y and B + iwhich = 4 : Calculate B from P,Q,X,Y and A + + P <--> The integral from 0 to X of the chi-square + distribution. + Input range: [0, 1]. + + Q <--> 1-P. + Input range: [0, 1]. + P + Q = 1.0. + + X <--> Upper limit of integration of beta density. + Input range: [0,1]. + Search range: [0,1] + + Y <--> 1-X. + Input range: [0,1]. + Search range: [0,1] + X + Y = 1.0. + + A <--> The first parameter of the beta density. + Input range: (0, +infinity). + Search range: [1D-300,1D300] + + B <--> The second parameter of the beta density. + Input range: (0, +infinity). + Search range: [1D-300,1D300] + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + 4 if X + Y .ne. 1 + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Cumulative distribution function (P) is calculated directly by + code associated with the following reference. + + DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant + Digit Computation of the Incomplete Beta Function Ratios. ACM + Trans. Math. Softw. 18 (1993), 360-373. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + + + Note + + + The beta density is proportional to + t^(A-1) * (1-t)^(B-1) + +**********************************************************************/ +{ +#define tol (1.0e-8) +#define atol (1.0e-50) +#define zero (1.0e-300) +#define inf 1.0e300 +#define one 1.0e0 +static int K1 = 1; +static double K2 = 0.0e0; +static double K3 = 1.0e0; +static double K8 = 0.5e0; +static double K9 = 5.0e0; +static double fx,xhi,xlo,cum,ccum,xy,pq; +static unsigned long qhi,qleft,qporq; +static double T4,T5,T6,T7,T10,T11,T12,T13,T14,T15; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 4)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 4.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q < 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q < 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 2) goto S150; +/* + X +*/ + if(!(*x < 0.0e0 || *x > 1.0e0)) goto S140; + if(!(*x < 0.0e0)) goto S120; + *bound = 0.0e0; + goto S130; +S120: + *bound = 1.0e0; +S130: + *status = -4; + return; +S150: +S140: + if(*which == 2) goto S190; +/* + Y +*/ + if(!(*y < 0.0e0 || *y > 1.0e0)) goto S180; + if(!(*y < 0.0e0)) goto S160; + *bound = 0.0e0; + goto S170; +S160: + *bound = 1.0e0; +S170: + *status = -5; + return; +S190: +S180: + if(*which == 3) goto S210; +/* + A +*/ + if(!(*a <= 0.0e0)) goto S200; + *bound = 0.0e0; + *status = -6; + return; +S210: +S200: + if(*which == 4) goto S230; +/* + B +*/ + if(!(*b <= 0.0e0)) goto S220; + *bound = 0.0e0; + *status = -7; + return; +S230: +S220: + if(*which == 1) goto S270; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S260; + if(!(pq < 0.0e0)) goto S240; + *bound = 0.0e0; + goto S250; +S240: + *bound = 1.0e0; +S250: + *status = 3; + return; +S270: +S260: + if(*which == 2) goto S310; +/* + X + Y +*/ + xy = *x+*y; + if(!(fabs(xy-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S300; + if(!(xy < 0.0e0)) goto S280; + *bound = 0.0e0; + goto S290; +S280: + *bound = 1.0e0; +S290: + *status = 4; + return; +S310: +S300: + if(!(*which == 1)) qporq = *p <= *q; +/* + Select the minimum of P or Q + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P and Q +*/ + cumbet(x,y,a,b,p,q); + *status = 0; + } + else if(2 == *which) { +/* + Calculating X and Y +*/ + T4 = atol; + T5 = tol; + dstzr(&K2,&K3,&T4,&T5); + if(!qporq) goto S340; + *status = 0; + dzror(status,x,&fx,&xlo,&xhi,&qleft,&qhi); + *y = one-*x; +S320: + if(!(*status == 1)) goto S330; + cumbet(x,y,a,b,&cum,&ccum); + fx = cum-*p; + dzror(status,x,&fx,&xlo,&xhi,&qleft,&qhi); + *y = one-*x; + goto S320; +S330: + goto S370; +S340: + *status = 0; + dzror(status,y,&fx,&xlo,&xhi,&qleft,&qhi); + *x = one-*y; +S350: + if(!(*status == 1)) goto S360; + cumbet(x,y,a,b,&cum,&ccum); + fx = ccum-*q; + dzror(status,y,&fx,&xlo,&xhi,&qleft,&qhi); + *x = one-*y; + goto S350; +S370: +S360: + if(!(*status == -1)) goto S400; + if(!qleft) goto S380; + *status = 1; + *bound = 0.0e0; + goto S390; +S380: + *status = 2; + *bound = 1.0e0; +S400: +S390: + ; + } + else if(3 == *which) { +/* + Computing A +*/ + *a = 5.0e0; + T6 = zero; + T7 = inf; + T10 = atol; + T11 = tol; + dstinv(&T6,&T7,&K8,&K8,&K9,&T10,&T11); + *status = 0; + dinvr(status,a,&fx,&qleft,&qhi); +S410: + if(!(*status == 1)) goto S440; + cumbet(x,y,a,b,&cum,&ccum); + if(!qporq) goto S420; + fx = cum-*p; + goto S430; +S420: + fx = ccum-*q; +S430: + dinvr(status,a,&fx,&qleft,&qhi); + goto S410; +S440: + if(!(*status == -1)) goto S470; + if(!qleft) goto S450; + *status = 1; + *bound = zero; + goto S460; +S450: + *status = 2; + *bound = inf; +S470: +S460: + ; + } + else if(4 == *which) { +/* + Computing B +*/ + *b = 5.0e0; + T12 = zero; + T13 = inf; + T14 = atol; + T15 = tol; + dstinv(&T12,&T13,&K8,&K8,&K9,&T14,&T15); + *status = 0; + dinvr(status,b,&fx,&qleft,&qhi); +S480: + if(!(*status == 1)) goto S510; + cumbet(x,y,a,b,&cum,&ccum); + if(!qporq) goto S490; + fx = cum-*p; + goto S500; +S490: + fx = ccum-*q; +S500: + dinvr(status,b,&fx,&qleft,&qhi); + goto S480; +S510: + if(!(*status == -1)) goto S540; + if(!qleft) goto S520; + *status = 1; + *bound = zero; + goto S530; +S520: + *status = 2; + *bound = inf; +S530: + ; + } +S540: + return; +#undef tol +#undef atol +#undef zero +#undef inf +#undef one +} /* END */ + +/***=====================================================================***/ +static void cdfbin(int *which,double *p,double *q,double *s,double *xn, + double *pr,double *ompr,int *status,double *bound) +/********************************************************************** + + void cdfbin(int *which,double *p,double *q,double *s,double *xn, + double *pr,double *ompr,int *status,double *bound) + + Cumulative Distribution Function + BINomial distribution + + + Function + + + Calculates any one parameter of the binomial + distribution given values for the others. + + + Arguments + + + WHICH --> Integer indicating which of the next four argument + values is to be calculated from the others. + Legal range: 1..4 + iwhich = 1 : Calculate P and Q from S,XN,PR and OMPR + iwhich = 2 : Calculate S from P,Q,XN,PR and OMPR + iwhich = 3 : Calculate XN from P,Q,S,PR and OMPR + iwhich = 4 : Calculate PR and OMPR from P,Q,S and XN + + P <--> The cumulation from 0 to S of the binomial distribution. + (Probablility of S or fewer successes in XN trials each + with probability of success PR.) + Input range: [0,1]. + + Q <--> 1-P. + Input range: [0, 1]. + P + Q = 1.0. + + S <--> The number of successes observed. + Input range: [0, XN] + Search range: [0, XN] + + XN <--> The number of binomial trials. + Input range: (0, +infinity). + Search range: [1E-300, 1E300] + + PR <--> The probability of success in each binomial trial. + Input range: [0,1]. + Search range: [0,1] + + OMPR <--> 1-PR + Input range: [0,1]. + Search range: [0,1] + PR + OMPR = 1.0 + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + 4 if PR + OMPR .ne. 1 + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Formula 26.5.24 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to reduce the binomial + distribution to the cumulative incomplete beta distribution. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + + +**********************************************************************/ +{ +#define atol (1.0e-50) +#define tol (1.0e-8) +#define zero (1.0e-300) +#define inf 1.0e300 +#define one 1.0e0 +static int K1 = 1; +static double K2 = 0.0e0; +static double K3 = 0.5e0; +static double K4 = 5.0e0; +static double K11 = 1.0e0; +static double fx,xhi,xlo,cum,ccum,pq,prompr; +static unsigned long qhi,qleft,qporq; +static double T5,T6,T7,T8,T9,T10,T12,T13; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 && *which > 4)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 4.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q < 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q < 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 3) goto S130; +/* + XN +*/ + if(!(*xn <= 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -5; + return; +S130: +S120: + if(*which == 2) goto S170; +/* + S +*/ + if(!(*s < 0.0e0 || *which != 3 && *s > *xn)) goto S160; + if(!(*s < 0.0e0)) goto S140; + *bound = 0.0e0; + goto S150; +S140: + *bound = *xn; +S150: + *status = -4; + return; +S170: +S160: + if(*which == 4) goto S210; +/* + PR +*/ + if(!(*pr < 0.0e0 || *pr > 1.0e0)) goto S200; + if(!(*pr < 0.0e0)) goto S180; + *bound = 0.0e0; + goto S190; +S180: + *bound = 1.0e0; +S190: + *status = -6; + return; +S210: +S200: + if(*which == 4) goto S250; +/* + OMPR +*/ + if(!(*ompr < 0.0e0 || *ompr > 1.0e0)) goto S240; + if(!(*ompr < 0.0e0)) goto S220; + *bound = 0.0e0; + goto S230; +S220: + *bound = 1.0e0; +S230: + *status = -7; + return; +S250: +S240: + if(*which == 1) goto S290; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S280; + if(!(pq < 0.0e0)) goto S260; + *bound = 0.0e0; + goto S270; +S260: + *bound = 1.0e0; +S270: + *status = 3; + return; +S290: +S280: + if(*which == 4) goto S330; +/* + PR + OMPR +*/ + prompr = *pr+*ompr; + if(!(fabs(prompr-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S320; + if(!(prompr < 0.0e0)) goto S300; + *bound = 0.0e0; + goto S310; +S300: + *bound = 1.0e0; +S310: + *status = 4; + return; +S330: +S320: + if(!(*which == 1)) qporq = *p <= *q; +/* + Select the minimum of P or Q + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P +*/ + cumbin(s,xn,pr,ompr,p,q); + *status = 0; + } + else if(2 == *which) { +/* + Calculating S +*/ + *s = 5.0e0; + T5 = atol; + T6 = tol; + dstinv(&K2,xn,&K3,&K3,&K4,&T5,&T6); + *status = 0; + dinvr(status,s,&fx,&qleft,&qhi); +S340: + if(!(*status == 1)) goto S370; + cumbin(s,xn,pr,ompr,&cum,&ccum); + if(!qporq) goto S350; + fx = cum-*p; + goto S360; +S350: + fx = ccum-*q; +S360: + dinvr(status,s,&fx,&qleft,&qhi); + goto S340; +S370: + if(!(*status == -1)) goto S400; + if(!qleft) goto S380; + *status = 1; + *bound = 0.0e0; + goto S390; +S380: + *status = 2; + *bound = *xn; +S400: +S390: + ; + } + else if(3 == *which) { +/* + Calculating XN +*/ + *xn = 5.0e0; + T7 = zero; + T8 = inf; + T9 = atol; + T10 = tol; + dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); + *status = 0; + dinvr(status,xn,&fx,&qleft,&qhi); +S410: + if(!(*status == 1)) goto S440; + cumbin(s,xn,pr,ompr,&cum,&ccum); + if(!qporq) goto S420; + fx = cum-*p; + goto S430; +S420: + fx = ccum-*q; +S430: + dinvr(status,xn,&fx,&qleft,&qhi); + goto S410; +S440: + if(!(*status == -1)) goto S470; + if(!qleft) goto S450; + *status = 1; + *bound = zero; + goto S460; +S450: + *status = 2; + *bound = inf; +S470: +S460: + ; + } + else if(4 == *which) { +/* + Calculating PR and OMPR +*/ + T12 = atol; + T13 = tol; + dstzr(&K2,&K11,&T12,&T13); + if(!qporq) goto S500; + *status = 0; + dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); + *ompr = one-*pr; +S480: + if(!(*status == 1)) goto S490; + cumbin(s,xn,pr,ompr,&cum,&ccum); + fx = cum-*p; + dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); + *ompr = one-*pr; + goto S480; +S490: + goto S530; +S500: + *status = 0; + dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); + *pr = one-*ompr; +S510: + if(!(*status == 1)) goto S520; + cumbin(s,xn,pr,ompr,&cum,&ccum); + fx = ccum-*q; + dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); + *pr = one-*ompr; + goto S510; +S530: +S520: + if(!(*status == -1)) goto S560; + if(!qleft) goto S540; + *status = 1; + *bound = 0.0e0; + goto S550; +S540: + *status = 2; + *bound = 1.0e0; +S550: + ; + } +S560: + return; +#undef atol +#undef tol +#undef zero +#undef inf +#undef one +} /* END */ + +/***=====================================================================***/ +static void cdfchi(int *which,double *p,double *q,double *x,double *df, + int *status,double *bound) +/********************************************************************** + + void cdfchi(int *which,double *p,double *q,double *x,double *df, + int *status,double *bound) + + Cumulative Distribution Function + CHI-Square distribution + + + Function + + + Calculates any one parameter of the chi-square + distribution given values for the others. + + + Arguments + + + WHICH --> Integer indicating which of the next three argument + values is to be calculated from the others. + Legal range: 1..3 + iwhich = 1 : Calculate P and Q from X and DF + iwhich = 2 : Calculate X from P,Q and DF + iwhich = 3 : Calculate DF from P,Q and X + + P <--> The integral from 0 to X of the chi-square + distribution. + Input range: [0, 1]. + + Q <--> 1-P. + Input range: (0, 1]. + P + Q = 1.0. + + X <--> Upper limit of integration of the non-central + chi-square distribution. + Input range: [0, +infinity). + Search range: [0,1E300] + + DF <--> Degrees of freedom of the + chi-square distribution. + Input range: (0, +infinity). + Search range: [ 1E-300, 1E300] + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + 10 indicates error returned from cumgam. See + references in cdfgam + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Formula 26.4.19 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to reduce the chisqure + distribution to the incomplete distribution. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + +**********************************************************************/ +{ +#define tol (1.0e-8) +#define atol (1.0e-50) +#define zero (1.0e-300) +#define inf 1.0e300 +static int K1 = 1; +static double K2 = 0.0e0; +static double K4 = 0.5e0; +static double K5 = 5.0e0; +static double fx,cum,ccum,pq,porq; +static unsigned long qhi,qleft,qporq; +static double T3,T6,T7,T8,T9,T10,T11; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 3)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 3.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q <= 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 2) goto S130; +/* + X +*/ + if(!(*x < 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -4; + return; +S130: +S120: + if(*which == 3) goto S150; +/* + DF +*/ + if(!(*df <= 0.0e0)) goto S140; + *bound = 0.0e0; + *status = -5; + return; +S150: +S140: + if(*which == 1) goto S190; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S180; + if(!(pq < 0.0e0)) goto S160; + *bound = 0.0e0; + goto S170; +S160: + *bound = 1.0e0; +S170: + *status = 3; + return; +S190: +S180: + if(*which == 1) goto S220; +/* + Select the minimum of P or Q +*/ + qporq = *p <= *q; + if(!qporq) goto S200; + porq = *p; + goto S210; +S200: + porq = *q; +S220: +S210: +/* + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P and Q +*/ + *status = 0; + cumchi(x,df,p,q); + if(porq > 1.5e0) { + *status = 10; + return; + } + } + else if(2 == *which) { +/* + Calculating X +*/ + *x = 5.0e0; + T3 = inf; + T6 = atol; + T7 = tol; + dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); + *status = 0; + dinvr(status,x,&fx,&qleft,&qhi); +S230: + if(!(*status == 1)) goto S270; + cumchi(x,df,&cum,&ccum); + if(!qporq) goto S240; + fx = cum-*p; + goto S250; +S240: + fx = ccum-*q; +S250: + if(!(fx+porq > 1.5e0)) goto S260; + *status = 10; + return; +S260: + dinvr(status,x,&fx,&qleft,&qhi); + goto S230; +S270: + if(!(*status == -1)) goto S300; + if(!qleft) goto S280; + *status = 1; + *bound = 0.0e0; + goto S290; +S280: + *status = 2; + *bound = inf; +S300: +S290: + ; + } + else if(3 == *which) { +/* + Calculating DF +*/ + *df = 5.0e0; + T8 = zero; + T9 = inf; + T10 = atol; + T11 = tol; + dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); + *status = 0; + dinvr(status,df,&fx,&qleft,&qhi); +S310: + if(!(*status == 1)) goto S350; + cumchi(x,df,&cum,&ccum); + if(!qporq) goto S320; + fx = cum-*p; + goto S330; +S320: + fx = ccum-*q; +S330: + if(!(fx+porq > 1.5e0)) goto S340; + *status = 10; + return; +S340: + dinvr(status,df,&fx,&qleft,&qhi); + goto S310; +S350: + if(!(*status == -1)) goto S380; + if(!qleft) goto S360; + *status = 1; + *bound = zero; + goto S370; +S360: + *status = 2; + *bound = inf; +S370: + ; + } +S380: + return; +#undef tol +#undef atol +#undef zero +#undef inf +} /* END */ + +/***=====================================================================***/ +static void cdfchn(int *which,double *p,double *q,double *x,double *df, + double *pnonc,int *status,double *bound) +/********************************************************************** + + void cdfchn(int *which,double *p,double *q,double *x,double *df, + double *pnonc,int *status,double *bound) + + Cumulative Distribution Function + Non-central Chi-Square + + + Function + + + Calculates any one parameter of the non-central chi-square + distribution given values for the others. + + + Arguments + + + WHICH --> Integer indicating which of the next three argument + values is to be calculated from the others. + Input range: 1..4 + iwhich = 1 : Calculate P and Q from X and DF + iwhich = 2 : Calculate X from P,DF and PNONC + iwhich = 3 : Calculate DF from P,X and PNONC + iwhich = 3 : Calculate PNONC from P,X and DF + + P <--> The integral from 0 to X of the non-central chi-square + distribution. + Input range: [0, 1-1E-16). + + Q <--> 1-P. + Q is not used by this subroutine and is only included + for similarity with other cdf* routines. + + X <--> Upper limit of integration of the non-central + chi-square distribution. + Input range: [0, +infinity). + Search range: [0,1E300] + + DF <--> Degrees of freedom of the non-central + chi-square distribution. + Input range: (0, +infinity). + Search range: [ 1E-300, 1E300] + + PNONC <--> Non-centrality parameter of the non-central + chi-square distribution. + Input range: [0, +infinity). + Search range: [0,1E4] + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Formula 26.4.25 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to compute the cumulative + distribution function. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + + + WARNING + + The computation time required for this routine is proportional + to the noncentrality parameter (PNONC). Very large values of + this parameter can consume immense computer resources. This is + why the search range is bounded by 10,000. + +**********************************************************************/ +{ +#define tent4 1.0e4 +#define tol (1.0e-8) +#define atol (1.0e-50) +#define zero (1.0e-300) +#define one (1.0e0-1.0e-16) +#define inf 1.0e300 +static double K1 = 0.0e0; +static double K3 = 0.5e0; +static double K4 = 5.0e0; +static double fx,cum,ccum; +static unsigned long qhi,qleft; +static double T2,T5,T6,T7,T8,T9,T10,T11,T12,T13; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 4)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 4.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > one)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = one; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 2) goto S90; +/* + X +*/ + if(!(*x < 0.0e0)) goto S80; + *bound = 0.0e0; + *status = -4; + return; +S90: +S80: + if(*which == 3) goto S110; +/* + DF +*/ + if(!(*df <= 0.0e0)) goto S100; + *bound = 0.0e0; + *status = -5; + return; +S110: +S100: + if(*which == 4) goto S130; +/* + PNONC +*/ + if(!(*pnonc < 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -6; + return; +S130: +S120: +/* + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P and Q +*/ + cumchn(x,df,pnonc,p,q); + *status = 0; + } + else if(2 == *which) { +/* + Calculating X +*/ + *x = 5.0e0; + T2 = inf; + T5 = atol; + T6 = tol; + dstinv(&K1,&T2,&K3,&K3,&K4,&T5,&T6); + *status = 0; + dinvr(status,x,&fx,&qleft,&qhi); +S140: + if(!(*status == 1)) goto S150; + cumchn(x,df,pnonc,&cum,&ccum); + fx = cum-*p; + dinvr(status,x,&fx,&qleft,&qhi); + goto S140; +S150: + if(!(*status == -1)) goto S180; + if(!qleft) goto S160; + *status = 1; + *bound = 0.0e0; + goto S170; +S160: + *status = 2; + *bound = inf; +S180: +S170: + ; + } + else if(3 == *which) { +/* + Calculating DF +*/ + *df = 5.0e0; + T7 = zero; + T8 = inf; + T9 = atol; + T10 = tol; + dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); + *status = 0; + dinvr(status,df,&fx,&qleft,&qhi); +S190: + if(!(*status == 1)) goto S200; + cumchn(x,df,pnonc,&cum,&ccum); + fx = cum-*p; + dinvr(status,df,&fx,&qleft,&qhi); + goto S190; +S200: + if(!(*status == -1)) goto S230; + if(!qleft) goto S210; + *status = 1; + *bound = zero; + goto S220; +S210: + *status = 2; + *bound = inf; +S230: +S220: + ; + } + else if(4 == *which) { +/* + Calculating PNONC +*/ + *pnonc = 5.0e0; + T11 = tent4; + T12 = atol; + T13 = tol; + dstinv(&K1,&T11,&K3,&K3,&K4,&T12,&T13); + *status = 0; + dinvr(status,pnonc,&fx,&qleft,&qhi); +S240: + if(!(*status == 1)) goto S250; + cumchn(x,df,pnonc,&cum,&ccum); + fx = cum-*p; + dinvr(status,pnonc,&fx,&qleft,&qhi); + goto S240; +S250: + if(!(*status == -1)) goto S280; + if(!qleft) goto S260; + *status = 1; + *bound = zero; + goto S270; +S260: + *status = 2; + *bound = tent4; +S270: + ; + } +S280: + return; +#undef tent4 +#undef tol +#undef atol +#undef zero +#undef one +#undef inf +} /* END */ + +/***=====================================================================***/ +static void cdff(int *which,double *p,double *q,double *f,double *dfn, + double *dfd,int *status,double *bound) +/********************************************************************** + + void cdff(int *which,double *p,double *q,double *f,double *dfn, + double *dfd,int *status,double *bound) + + Cumulative Distribution Function + F distribution + + + Function + + + Calculates any one parameter of the F distribution + given values for the others. + + + Arguments + + + WHICH --> Integer indicating which of the next four argument + values is to be calculated from the others. + Legal range: 1..4 + iwhich = 1 : Calculate P and Q from F,DFN and DFD + iwhich = 2 : Calculate F from P,Q,DFN and DFD + iwhich = 3 : Calculate DFN from P,Q,F and DFD + iwhich = 4 : Calculate DFD from P,Q,F and DFN + + P <--> The integral from 0 to F of the f-density. + Input range: [0,1]. + + Q <--> 1-P. + Input range: (0, 1]. + P + Q = 1.0. + + F <--> Upper limit of integration of the f-density. + Input range: [0, +infinity). + Search range: [0,1E300] + + DFN < --> Degrees of freedom of the numerator sum of squares. + Input range: (0, +infinity). + Search range: [ 1E-300, 1E300] + + DFD < --> Degrees of freedom of the denominator sum of squares. + Input range: (0, +infinity). + Search range: [ 1E-300, 1E300] + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Formula 26.6.2 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to reduce the computation + of the cumulative distribution function for the F variate to + that of an incomplete beta. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + + WARNING + + The value of the cumulative F distribution is not necessarily + monotone in either degrees of freedom. There thus may be two + values that provide a given CDF value. This routine assumes + monotonicity and will find an arbitrary one of the two values. + +**********************************************************************/ +{ +#define tol (1.0e-8) +#define atol (1.0e-50) +#define zero (1.0e-300) +#define inf 1.0e300 +static int K1 = 1; +static double K2 = 0.0e0; +static double K4 = 0.5e0; +static double K5 = 5.0e0; +static double pq,fx,cum,ccum; +static unsigned long qhi,qleft,qporq; +static double T3,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 4)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 4.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q <= 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 2) goto S130; +/* + F +*/ + if(!(*f < 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -4; + return; +S130: +S120: + if(*which == 3) goto S150; +/* + DFN +*/ + if(!(*dfn <= 0.0e0)) goto S140; + *bound = 0.0e0; + *status = -5; + return; +S150: +S140: + if(*which == 4) goto S170; +/* + DFD +*/ + if(!(*dfd <= 0.0e0)) goto S160; + *bound = 0.0e0; + *status = -6; + return; +S170: +S160: + if(*which == 1) goto S210; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S200; + if(!(pq < 0.0e0)) goto S180; + *bound = 0.0e0; + goto S190; +S180: + *bound = 1.0e0; +S190: + *status = 3; + return; +S210: +S200: + if(!(*which == 1)) qporq = *p <= *q; +/* + Select the minimum of P or Q + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P +*/ + cumf(f,dfn,dfd,p,q); + *status = 0; + } + else if(2 == *which) { +/* + Calculating F +*/ + *f = 5.0e0; + T3 = inf; + T6 = atol; + T7 = tol; + dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); + *status = 0; + dinvr(status,f,&fx,&qleft,&qhi); +S220: + if(!(*status == 1)) goto S250; + cumf(f,dfn,dfd,&cum,&ccum); + if(!qporq) goto S230; + fx = cum-*p; + goto S240; +S230: + fx = ccum-*q; +S240: + dinvr(status,f,&fx,&qleft,&qhi); + goto S220; +S250: + if(!(*status == -1)) goto S280; + if(!qleft) goto S260; + *status = 1; + *bound = 0.0e0; + goto S270; +S260: + *status = 2; + *bound = inf; +S280: +S270: + ; + } + else if(3 == *which) { +/* + Calculating DFN +*/ + *dfn = 5.0e0; + T8 = zero; + T9 = inf; + T10 = atol; + T11 = tol; + dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); + *status = 0; + dinvr(status,dfn,&fx,&qleft,&qhi); +S290: + if(!(*status == 1)) goto S320; + cumf(f,dfn,dfd,&cum,&ccum); + if(!qporq) goto S300; + fx = cum-*p; + goto S310; +S300: + fx = ccum-*q; +S310: + dinvr(status,dfn,&fx,&qleft,&qhi); + goto S290; +S320: + if(!(*status == -1)) goto S350; + if(!qleft) goto S330; + *status = 1; + *bound = zero; + goto S340; +S330: + *status = 2; + *bound = inf; +S350: +S340: + ; + } + else if(4 == *which) { +/* + Calculating DFD +*/ + *dfd = 5.0e0; + T12 = zero; + T13 = inf; + T14 = atol; + T15 = tol; + dstinv(&T12,&T13,&K4,&K4,&K5,&T14,&T15); + *status = 0; + dinvr(status,dfd,&fx,&qleft,&qhi); +S360: + if(!(*status == 1)) goto S390; + cumf(f,dfn,dfd,&cum,&ccum); + if(!qporq) goto S370; + fx = cum-*p; + goto S380; +S370: + fx = ccum-*q; +S380: + dinvr(status,dfd,&fx,&qleft,&qhi); + goto S360; +S390: + if(!(*status == -1)) goto S420; + if(!qleft) goto S400; + *status = 1; + *bound = zero; + goto S410; +S400: + *status = 2; + *bound = inf; +S410: + ; + } +S420: + return; +#undef tol +#undef atol +#undef zero +#undef inf +} /* END */ + +/***=====================================================================***/ +static void cdffnc(int *which,double *p,double *q,double *f,double *dfn, + double *dfd,double *phonc,int *status,double *bound) +/********************************************************************** + + void cdffnc(int *which,double *p,double *q,double *f,double *dfn, + double *dfd,double *phonc,int *status,double *bound) + + Cumulative Distribution Function + Non-central F distribution + + + Function + + + Calculates any one parameter of the Non-central F + distribution given values for the others. + + + Arguments + + + WHICH --> Integer indicating which of the next five argument + values is to be calculated from the others. + Legal range: 1..5 + iwhich = 1 : Calculate P and Q from F,DFN,DFD and PNONC + iwhich = 2 : Calculate F from P,Q,DFN,DFD and PNONC + iwhich = 3 : Calculate DFN from P,Q,F,DFD and PNONC + iwhich = 4 : Calculate DFD from P,Q,F,DFN and PNONC + iwhich = 5 : Calculate PNONC from P,Q,F,DFN and DFD + + P <--> The integral from 0 to F of the non-central f-density. + Input range: [0,1-1E-16). + + Q <--> 1-P. + Q is not used by this subroutine and is only included + for similarity with other cdf* routines. + + F <--> Upper limit of integration of the non-central f-density. + Input range: [0, +infinity). + Search range: [0,1E300] + + DFN < --> Degrees of freedom of the numerator sum of squares. + Input range: (0, +infinity). + Search range: [ 1E-300, 1E300] + + DFD < --> Degrees of freedom of the denominator sum of squares. + Must be in range: (0, +infinity). + Input range: (0, +infinity). + Search range: [ 1E-300, 1E300] + + PNONC <-> The non-centrality parameter + Input range: [0,infinity) + Search range: [0,1E4] + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Formula 26.6.20 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to compute the cumulative + distribution function. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + + WARNING + + The computation time required for this routine is proportional + to the noncentrality parameter (PNONC). Very large values of + this parameter can consume immense computer resources. This is + why the search range is bounded by 10,000. + + WARNING + + The value of the cumulative noncentral F distribution is not + necessarily monotone in either degrees of freedom. There thus + may be two values that provide a given CDF value. This routine + assumes monotonicity and will find an arbitrary one of the two + values. + +**********************************************************************/ +{ +#define tent4 1.0e4 +#define tol (1.0e-8) +#define atol (1.0e-50) +#define zero (1.0e-300) +#define one (1.0e0-1.0e-16) +#define inf 1.0e300 +static double K1 = 0.0e0; +static double K3 = 0.5e0; +static double K4 = 5.0e0; +static double fx,cum,ccum; +static unsigned long qhi,qleft; +static double T2,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 5)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 5.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > one)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = one; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 2) goto S90; +/* + F +*/ + if(!(*f < 0.0e0)) goto S80; + *bound = 0.0e0; + *status = -4; + return; +S90: +S80: + if(*which == 3) goto S110; +/* + DFN +*/ + if(!(*dfn <= 0.0e0)) goto S100; + *bound = 0.0e0; + *status = -5; + return; +S110: +S100: + if(*which == 4) goto S130; +/* + DFD +*/ + if(!(*dfd <= 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -6; + return; +S130: +S120: + if(*which == 5) goto S150; +/* + PHONC +*/ + if(!(*phonc < 0.0e0)) goto S140; + *bound = 0.0e0; + *status = -7; + return; +S150: +S140: +/* + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P +*/ + cumfnc(f,dfn,dfd,phonc,p,q); + *status = 0; + } + else if(2 == *which) { +/* + Calculating F +*/ + *f = 5.0e0; + T2 = inf; + T5 = atol; + T6 = tol; + dstinv(&K1,&T2,&K3,&K3,&K4,&T5,&T6); + *status = 0; + dinvr(status,f,&fx,&qleft,&qhi); +S160: + if(!(*status == 1)) goto S170; + cumfnc(f,dfn,dfd,phonc,&cum,&ccum); + fx = cum-*p; + dinvr(status,f,&fx,&qleft,&qhi); + goto S160; +S170: + if(!(*status == -1)) goto S200; + if(!qleft) goto S180; + *status = 1; + *bound = 0.0e0; + goto S190; +S180: + *status = 2; + *bound = inf; +S200: +S190: + ; + } + else if(3 == *which) { +/* + Calculating DFN +*/ + *dfn = 5.0e0; + T7 = zero; + T8 = inf; + T9 = atol; + T10 = tol; + dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); + *status = 0; + dinvr(status,dfn,&fx,&qleft,&qhi); +S210: + if(!(*status == 1)) goto S220; + cumfnc(f,dfn,dfd,phonc,&cum,&ccum); + fx = cum-*p; + dinvr(status,dfn,&fx,&qleft,&qhi); + goto S210; +S220: + if(!(*status == -1)) goto S250; + if(!qleft) goto S230; + *status = 1; + *bound = zero; + goto S240; +S230: + *status = 2; + *bound = inf; +S250: +S240: + ; + } + else if(4 == *which) { +/* + Calculating DFD +*/ + *dfd = 5.0e0; + T11 = zero; + T12 = inf; + T13 = atol; + T14 = tol; + dstinv(&T11,&T12,&K3,&K3,&K4,&T13,&T14); + *status = 0; + dinvr(status,dfd,&fx,&qleft,&qhi); +S260: + if(!(*status == 1)) goto S270; + cumfnc(f,dfn,dfd,phonc,&cum,&ccum); + fx = cum-*p; + dinvr(status,dfd,&fx,&qleft,&qhi); + goto S260; +S270: + if(!(*status == -1)) goto S300; + if(!qleft) goto S280; + *status = 1; + *bound = zero; + goto S290; +S280: + *status = 2; + *bound = inf; +S300: +S290: + ; + } + else if(5 == *which) { +/* + Calculating PHONC +*/ + *phonc = 5.0e0; + T15 = tent4; + T16 = atol; + T17 = tol; + dstinv(&K1,&T15,&K3,&K3,&K4,&T16,&T17); + *status = 0; + dinvr(status,phonc,&fx,&qleft,&qhi); +S310: + if(!(*status == 1)) goto S320; + cumfnc(f,dfn,dfd,phonc,&cum,&ccum); + fx = cum-*p; + dinvr(status,phonc,&fx,&qleft,&qhi); + goto S310; +S320: + if(!(*status == -1)) goto S350; + if(!qleft) goto S330; + *status = 1; + *bound = 0.0e0; + goto S340; +S330: + *status = 2; + *bound = tent4; +S340: + ; + } +S350: + return; +#undef tent4 +#undef tol +#undef atol +#undef zero +#undef one +#undef inf +} /* END */ + +/***=====================================================================***/ +static void cdfgam(int *which,double *p,double *q,double *x,double *shape, + double *scale,int *status,double *bound) +/********************************************************************** + + void cdfgam(int *which,double *p,double *q,double *x,double *shape, + double *scale,int *status,double *bound) + + Cumulative Distribution Function + GAMma Distribution + + + Function + + + Calculates any one parameter of the gamma + distribution given values for the others. + + + Arguments + + + WHICH --> Integer indicating which of the next four argument + values is to be calculated from the others. + Legal range: 1..4 + iwhich = 1 : Calculate P and Q from X,SHAPE and SCALE + iwhich = 2 : Calculate X from P,Q,SHAPE and SCALE + iwhich = 3 : Calculate SHAPE from P,Q,X and SCALE + iwhich = 4 : Calculate SCALE from P,Q,X and SHAPE + + P <--> The integral from 0 to X of the gamma density. + Input range: [0,1]. + + Q <--> 1-P. + Input range: (0, 1]. + P + Q = 1.0. + + X <--> The upper limit of integration of the gamma density. + Input range: [0, +infinity). + Search range: [0,1E300] + + SHAPE <--> The shape parameter of the gamma density. + Input range: (0, +infinity). + Search range: [1E-300,1E300] + + SCALE <--> The scale parameter of the gamma density. + Input range: (0, +infinity). + Search range: (1E-300,1E300] + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + 10 if the gamma or inverse gamma routine cannot + compute the answer. Usually happens only for + X and SHAPE very large (gt 1E10 or more) + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Cumulative distribution function (P) is calculated directly by + the code associated with: + + DiDinato, A. R. and Morris, A. H. Computation of the incomplete + gamma function ratios and their inverse. ACM Trans. Math. + Softw. 12 (1986), 377-393. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + + + Note + + + + The gamma density is proportional to + T**(SHAPE - 1) * EXP(- SCALE * T) + +**********************************************************************/ +{ +#define tol (1.0e-8) +#define atol (1.0e-50) +#define zero (1.0e-300) +#define inf 1.0e300 +static int K1 = 1; +static double K5 = 0.5e0; +static double K6 = 5.0e0; +static double xx,fx,xscale,cum,ccum,pq,porq; +static int ierr; +static unsigned long qhi,qleft,qporq; +static double T2,T3,T4,T7,T8,T9; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 4)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 4.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q <= 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 2) goto S130; +/* + X +*/ + if(!(*x < 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -4; + return; +S130: +S120: + if(*which == 3) goto S150; +/* + SHAPE +*/ + if(!(*shape <= 0.0e0)) goto S140; + *bound = 0.0e0; + *status = -5; + return; +S150: +S140: + if(*which == 4) goto S170; +/* + SCALE +*/ + if(!(*scale <= 0.0e0)) goto S160; + *bound = 0.0e0; + *status = -6; + return; +S170: +S160: + if(*which == 1) goto S210; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S200; + if(!(pq < 0.0e0)) goto S180; + *bound = 0.0e0; + goto S190; +S180: + *bound = 1.0e0; +S190: + *status = 3; + return; +S210: +S200: + if(*which == 1) goto S240; +/* + Select the minimum of P or Q +*/ + qporq = *p <= *q; + if(!qporq) goto S220; + porq = *p; + goto S230; +S220: + porq = *q; +S240: +S230: +/* + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P +*/ + *status = 0; + xscale = *x**scale; + cumgam(&xscale,shape,p,q); + if(porq > 1.5e0) *status = 10; + } + else if(2 == *which) { +/* + Computing X +*/ + T2 = -1.0e0; + gaminv(shape,&xx,&T2,p,q,&ierr); + if(ierr < 0.0e0) { + *status = 10; + return; + } + else { + *x = xx/ *scale; + *status = 0; + } + } + else if(3 == *which) { +/* + Computing SHAPE +*/ + *shape = 5.0e0; + xscale = *x**scale; + T3 = zero; + T4 = inf; + T7 = atol; + T8 = tol; + dstinv(&T3,&T4,&K5,&K5,&K6,&T7,&T8); + *status = 0; + dinvr(status,shape,&fx,&qleft,&qhi); +S250: + if(!(*status == 1)) goto S290; + cumgam(&xscale,shape,&cum,&ccum); + if(!qporq) goto S260; + fx = cum-*p; + goto S270; +S260: + fx = ccum-*q; +S270: + if(!(qporq && cum > 1.5e0 || !qporq && ccum > 1.5e0)) goto S280; + *status = 10; + return; +S280: + dinvr(status,shape,&fx,&qleft,&qhi); + goto S250; +S290: + if(!(*status == -1)) goto S320; + if(!qleft) goto S300; + *status = 1; + *bound = zero; + goto S310; +S300: + *status = 2; + *bound = inf; +S320: +S310: + ; + } + else if(4 == *which) { +/* + Computing SCALE +*/ + T9 = -1.0e0; + gaminv(shape,&xx,&T9,p,q,&ierr); + if(ierr < 0.0e0) { + *status = 10; + return; + } + else { + *scale = xx/ *x; + *status = 0; + } + } + return; +#undef tol +#undef atol +#undef zero +#undef inf +} /* END */ + +/***=====================================================================***/ +static void cdfnbn(int *which,double *p,double *q,double *s,double *xn, + double *pr,double *ompr,int *status,double *bound) +/********************************************************************** + + void cdfnbn(int *which,double *p,double *q,double *s,double *xn, + double *pr,double *ompr,int *status,double *bound) + + Cumulative Distribution Function + Negative BiNomial distribution + + + Function + + + Calculates any one parameter of the negative binomial + distribution given values for the others. + + The cumulative negative binomial distribution returns the + probability that there will be F or fewer failures before the + XNth success in binomial trials each of which has probability of + success PR. + + The individual term of the negative binomial is the probability of + S failures before XN successes and is + Choose( S, XN+S-1 ) * PR^(XN) * (1-PR)^S + + + Arguments + + + WHICH --> Integer indicating which of the next four argument + values is to be calculated from the others. + Legal range: 1..4 + iwhich = 1 : Calculate P and Q from S,XN,PR and OMPR + iwhich = 2 : Calculate S from P,Q,XN,PR and OMPR + iwhich = 3 : Calculate XN from P,Q,S,PR and OMPR + iwhich = 4 : Calculate PR and OMPR from P,Q,S and XN + + P <--> The cumulation from 0 to S of the negative + binomial distribution. + Input range: [0,1]. + + Q <--> 1-P. + Input range: (0, 1]. + P + Q = 1.0. + + S <--> The upper limit of cumulation of the binomial distribution. + There are F or fewer failures before the XNth success. + Input range: [0, +infinity). + Search range: [0, 1E300] + + XN <--> The number of successes. + Input range: [0, +infinity). + Search range: [0, 1E300] + + PR <--> The probability of success in each binomial trial. + Input range: [0,1]. + Search range: [0,1]. + + OMPR <--> 1-PR + Input range: [0,1]. + Search range: [0,1] + PR + OMPR = 1.0 + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + 4 if PR + OMPR .ne. 1 + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Formula 26.5.26 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to reduce calculation of + the cumulative distribution function to that of an incomplete + beta. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + +**********************************************************************/ +{ +#define tol (1.0e-8) +#define atol (1.0e-50) +#define inf 1.0e300 +#define one 1.0e0 +static int K1 = 1; +static double K2 = 0.0e0; +static double K4 = 0.5e0; +static double K5 = 5.0e0; +static double K11 = 1.0e0; +static double fx,xhi,xlo,pq,prompr,cum,ccum; +static unsigned long qhi,qleft,qporq; +static double T3,T6,T7,T8,T9,T10,T12,T13; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 4)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 4.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q <= 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 2) goto S130; +/* + S +*/ + if(!(*s < 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -4; + return; +S130: +S120: + if(*which == 3) goto S150; +/* + XN +*/ + if(!(*xn < 0.0e0)) goto S140; + *bound = 0.0e0; + *status = -5; + return; +S150: +S140: + if(*which == 4) goto S190; +/* + PR +*/ + if(!(*pr < 0.0e0 || *pr > 1.0e0)) goto S180; + if(!(*pr < 0.0e0)) goto S160; + *bound = 0.0e0; + goto S170; +S160: + *bound = 1.0e0; +S170: + *status = -6; + return; +S190: +S180: + if(*which == 4) goto S230; +/* + OMPR +*/ + if(!(*ompr < 0.0e0 || *ompr > 1.0e0)) goto S220; + if(!(*ompr < 0.0e0)) goto S200; + *bound = 0.0e0; + goto S210; +S200: + *bound = 1.0e0; +S210: + *status = -7; + return; +S230: +S220: + if(*which == 1) goto S270; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S260; + if(!(pq < 0.0e0)) goto S240; + *bound = 0.0e0; + goto S250; +S240: + *bound = 1.0e0; +S250: + *status = 3; + return; +S270: +S260: + if(*which == 4) goto S310; +/* + PR + OMPR +*/ + prompr = *pr+*ompr; + if(!(fabs(prompr-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S300; + if(!(prompr < 0.0e0)) goto S280; + *bound = 0.0e0; + goto S290; +S280: + *bound = 1.0e0; +S290: + *status = 4; + return; +S310: +S300: + if(!(*which == 1)) qporq = *p <= *q; +/* + Select the minimum of P or Q + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P +*/ + cumnbn(s,xn,pr,ompr,p,q); + *status = 0; + } + else if(2 == *which) { +/* + Calculating S +*/ + *s = 5.0e0; + T3 = inf; + T6 = atol; + T7 = tol; + dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); + *status = 0; + dinvr(status,s,&fx,&qleft,&qhi); +S320: + if(!(*status == 1)) goto S350; + cumnbn(s,xn,pr,ompr,&cum,&ccum); + if(!qporq) goto S330; + fx = cum-*p; + goto S340; +S330: + fx = ccum-*q; +S340: + dinvr(status,s,&fx,&qleft,&qhi); + goto S320; +S350: + if(!(*status == -1)) goto S380; + if(!qleft) goto S360; + *status = 1; + *bound = 0.0e0; + goto S370; +S360: + *status = 2; + *bound = inf; +S380: +S370: + ; + } + else if(3 == *which) { +/* + Calculating XN +*/ + *xn = 5.0e0; + T8 = inf; + T9 = atol; + T10 = tol; + dstinv(&K2,&T8,&K4,&K4,&K5,&T9,&T10); + *status = 0; + dinvr(status,xn,&fx,&qleft,&qhi); +S390: + if(!(*status == 1)) goto S420; + cumnbn(s,xn,pr,ompr,&cum,&ccum); + if(!qporq) goto S400; + fx = cum-*p; + goto S410; +S400: + fx = ccum-*q; +S410: + dinvr(status,xn,&fx,&qleft,&qhi); + goto S390; +S420: + if(!(*status == -1)) goto S450; + if(!qleft) goto S430; + *status = 1; + *bound = 0.0e0; + goto S440; +S430: + *status = 2; + *bound = inf; +S450: +S440: + ; + } + else if(4 == *which) { +/* + Calculating PR and OMPR +*/ + T12 = atol; + T13 = tol; + dstzr(&K2,&K11,&T12,&T13); + if(!qporq) goto S480; + *status = 0; + dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); + *ompr = one-*pr; +S460: + if(!(*status == 1)) goto S470; + cumnbn(s,xn,pr,ompr,&cum,&ccum); + fx = cum-*p; + dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); + *ompr = one-*pr; + goto S460; +S470: + goto S510; +S480: + *status = 0; + dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); + *pr = one-*ompr; +S490: + if(!(*status == 1)) goto S500; + cumnbn(s,xn,pr,ompr,&cum,&ccum); + fx = ccum-*q; + dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); + *pr = one-*ompr; + goto S490; +S510: +S500: + if(!(*status == -1)) goto S540; + if(!qleft) goto S520; + *status = 1; + *bound = 0.0e0; + goto S530; +S520: + *status = 2; + *bound = 1.0e0; +S530: + ; + } +S540: + return; +#undef tol +#undef atol +#undef inf +#undef one +} /* END */ + +/***=====================================================================***/ +static void cdfnor(int *which,double *p,double *q,double *x,double *mean, + double *sd,int *status,double *bound) +/********************************************************************** + + void cdfnor(int *which,double *p,double *q,double *x,double *mean, + double *sd,int *status,double *bound) + + Cumulative Distribution Function + NORmal distribution + + + Function + + + Calculates any one parameter of the normal + distribution given values for the others. + + + Arguments + + + WHICH --> Integer indicating which of the next parameter + values is to be calculated using values of the others. + Legal range: 1..4 + iwhich = 1 : Calculate P and Q from X,MEAN and SD + iwhich = 2 : Calculate X from P,Q,MEAN and SD + iwhich = 3 : Calculate MEAN from P,Q,X and SD + iwhich = 4 : Calculate SD from P,Q,X and MEAN + + P <--> The integral from -infinity to X of the normal density. + Input range: (0,1]. + + Q <--> 1-P. + Input range: (0, 1]. + P + Q = 1.0. + + X < --> Upper limit of integration of the normal-density. + Input range: ( -infinity, +infinity) + + MEAN <--> The mean of the normal density. + Input range: (-infinity, +infinity) + + SD <--> Standard Deviation of the normal density. + Input range: (0, +infinity). + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + + + A slightly modified version of ANORM from + + Cody, W.D. (1993). "ALGORITHM 715: SPECFUN - A Portabel FORTRAN + Package of Special Function Routines and Test Drivers" + acm Transactions on Mathematical Software. 19, 22-32. + + is used to calulate the cumulative standard normal distribution. + + The rational functions from pages 90-95 of Kennedy and Gentle, + Statistical Computing, Marcel Dekker, NY, 1980 are used as + starting values to Newton's Iterations which compute the inverse + standard normal. Therefore no searches are necessary for any + parameter. + + For X < -15, the asymptotic expansion for the normal is used as + the starting value in finding the inverse standard normal. + This is formula 26.2.12 of Abramowitz and Stegun. + + + Note + + + The normal density is proportional to + exp( - 0.5 * (( X - MEAN)/SD)**2) + +**********************************************************************/ +{ +static int K1 = 1; +static double z,pq; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + *status = 0; + if(!(*which < 1 || *which > 4)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 4.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p <= 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p <= 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q <= 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 1) goto S150; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S140; + if(!(pq < 0.0e0)) goto S120; + *bound = 0.0e0; + goto S130; +S120: + *bound = 1.0e0; +S130: + *status = 3; + return; +S150: +S140: + if(*which == 4) goto S170; +/* + SD +*/ + if(!(*sd <= 0.0e0)) goto S160; + *bound = 0.0e0; + *status = -6; + return; +S170: +S160: +/* + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Computing P +*/ + z = (*x-*mean)/ *sd; + cumnor(&z,p,q); + } + else if(2 == *which) { +/* + Computing X +*/ + z = dinvnr(p,q); + *x = *sd*z+*mean; + } + else if(3 == *which) { +/* + Computing the MEAN +*/ + z = dinvnr(p,q); + *mean = *x-*sd*z; + } + else if(4 == *which) { +/* + Computing SD +*/ + z = dinvnr(p,q); + *sd = (*x-*mean)/z; + } + return; +} /* END */ + +/***=====================================================================***/ +static void cdfpoi(int *which,double *p,double *q,double *s,double *xlam, + int *status,double *bound) +/********************************************************************** + + void cdfpoi(int *which,double *p,double *q,double *s,double *xlam, + int *status,double *bound) + + Cumulative Distribution Function + POIsson distribution + + + Function + + + Calculates any one parameter of the Poisson + distribution given values for the others. + + + Arguments + + + WHICH --> Integer indicating which argument + value is to be calculated from the others. + Legal range: 1..3 + iwhich = 1 : Calculate P and Q from S and XLAM + iwhich = 2 : Calculate A from P,Q and XLAM + iwhich = 3 : Calculate XLAM from P,Q and S + + P <--> The cumulation from 0 to S of the poisson density. + Input range: [0,1]. + + Q <--> 1-P. + Input range: (0, 1]. + P + Q = 1.0. + + S <--> Upper limit of cumulation of the Poisson. + Input range: [0, +infinity). + Search range: [0,1E300] + + XLAM <--> Mean of the Poisson distribution. + Input range: [0, +infinity). + Search range: [0,1E300] + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Formula 26.4.21 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to reduce the computation + of the cumulative distribution function to that of computing a + chi-square, hence an incomplete gamma function. + + Cumulative distribution function (P) is calculated directly. + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + +**********************************************************************/ +{ +#define tol (1.0e-8) +#define atol (1.0e-50) +#define inf 1.0e300 +static int K1 = 1; +static double K2 = 0.0e0; +static double K4 = 0.5e0; +static double K5 = 5.0e0; +static double fx,cum,ccum,pq; +static unsigned long qhi,qleft,qporq; +static double T3,T6,T7,T8,T9,T10; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 3)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 3.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p < 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q <= 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 2) goto S130; +/* + S +*/ + if(!(*s < 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -4; + return; +S130: +S120: + if(*which == 3) goto S150; +/* + XLAM +*/ + if(!(*xlam < 0.0e0)) goto S140; + *bound = 0.0e0; + *status = -5; + return; +S150: +S140: + if(*which == 1) goto S190; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S180; + if(!(pq < 0.0e0)) goto S160; + *bound = 0.0e0; + goto S170; +S160: + *bound = 1.0e0; +S170: + *status = 3; + return; +S190: +S180: + if(!(*which == 1)) qporq = *p <= *q; +/* + Select the minimum of P or Q + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Calculating P +*/ + cumpoi(s,xlam,p,q); + *status = 0; + } + else if(2 == *which) { +/* + Calculating S +*/ + *s = 5.0e0; + T3 = inf; + T6 = atol; + T7 = tol; + dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); + *status = 0; + dinvr(status,s,&fx,&qleft,&qhi); +S200: + if(!(*status == 1)) goto S230; + cumpoi(s,xlam,&cum,&ccum); + if(!qporq) goto S210; + fx = cum-*p; + goto S220; +S210: + fx = ccum-*q; +S220: + dinvr(status,s,&fx,&qleft,&qhi); + goto S200; +S230: + if(!(*status == -1)) goto S260; + if(!qleft) goto S240; + *status = 1; + *bound = 0.0e0; + goto S250; +S240: + *status = 2; + *bound = inf; +S260: +S250: + ; + } + else if(3 == *which) { +/* + Calculating XLAM +*/ + *xlam = 5.0e0; + T8 = inf; + T9 = atol; + T10 = tol; + dstinv(&K2,&T8,&K4,&K4,&K5,&T9,&T10); + *status = 0; + dinvr(status,xlam,&fx,&qleft,&qhi); +S270: + if(!(*status == 1)) goto S300; + cumpoi(s,xlam,&cum,&ccum); + if(!qporq) goto S280; + fx = cum-*p; + goto S290; +S280: + fx = ccum-*q; +S290: + dinvr(status,xlam,&fx,&qleft,&qhi); + goto S270; +S300: + if(!(*status == -1)) goto S330; + if(!qleft) goto S310; + *status = 1; + *bound = 0.0e0; + goto S320; +S310: + *status = 2; + *bound = inf; +S320: + ; + } +S330: + return; +#undef tol +#undef atol +#undef inf +} /* END */ + +/***=====================================================================***/ +static void cdft(int *which,double *p,double *q,double *t,double *df, + int *status,double *bound) +/********************************************************************** + + void cdft(int *which,double *p,double *q,double *t,double *df, + int *status,double *bound) + + Cumulative Distribution Function + T distribution + + + Function + + + Calculates any one parameter of the t distribution given + values for the others. + + + Arguments + + + WHICH --> Integer indicating which argument + values is to be calculated from the others. + Legal range: 1..3 + iwhich = 1 : Calculate P and Q from T and DF + iwhich = 2 : Calculate T from P,Q and DF + iwhich = 3 : Calculate DF from P,Q and T + + P <--> The integral from -infinity to t of the t-density. + Input range: (0,1]. + + Q <--> 1-P. + Input range: (0, 1]. + P + Q = 1.0. + + T <--> Upper limit of integration of the t-density. + Input range: ( -infinity, +infinity). + Search range: [ -1E300, 1E300 ] + + DF <--> Degrees of freedom of the t-distribution. + Input range: (0 , +infinity). + Search range: [1e-300, 1E10] + + STATUS <-- 0 if calculation completed correctly + -I if input parameter number I is out of range + 1 if answer appears to be lower than lowest + search bound + 2 if answer appears to be higher than greatest + search bound + 3 if P + Q .ne. 1 + + BOUND <-- Undefined if STATUS is 0 + + Bound exceeded by parameter number I if STATUS + is negative. + + Lower search bound if STATUS is 1. + + Upper search bound if STATUS is 2. + + + Method + + + Formula 26.5.27 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to reduce the computation + of the cumulative distribution function to that of an incomplete + beta. + + Computation of other parameters involve a seach for a value that + produces the desired value of P. The search relies on the + monotinicity of P with the other parameter. + +**********************************************************************/ +{ +#define tol (1.0e-8) +#define atol (1.0e-50) +#define zero (1.0e-300) +#define inf 1.0e300 +#define maxdf 1.0e10 +static int K1 = 1; +static double K4 = 0.5e0; +static double K5 = 5.0e0; +static double fx,cum,ccum,pq; +static unsigned long qhi,qleft,qporq; +static double T2,T3,T6,T7,T8,T9,T10,T11; +/* + .. + .. Executable Statements .. +*/ +/* + Check arguments +*/ + if(!(*which < 1 || *which > 3)) goto S30; + if(!(*which < 1)) goto S10; + *bound = 1.0e0; + goto S20; +S10: + *bound = 3.0e0; +S20: + *status = -1; + return; +S30: + if(*which == 1) goto S70; +/* + P +*/ + if(!(*p <= 0.0e0 || *p > 1.0e0)) goto S60; + if(!(*p <= 0.0e0)) goto S40; + *bound = 0.0e0; + goto S50; +S40: + *bound = 1.0e0; +S50: + *status = -2; + return; +S70: +S60: + if(*which == 1) goto S110; +/* + Q +*/ + if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; + if(!(*q <= 0.0e0)) goto S80; + *bound = 0.0e0; + goto S90; +S80: + *bound = 1.0e0; +S90: + *status = -3; + return; +S110: +S100: + if(*which == 3) goto S130; +/* + DF +*/ + if(!(*df <= 0.0e0)) goto S120; + *bound = 0.0e0; + *status = -5; + return; +S130: +S120: + if(*which == 1) goto S170; +/* + P + Q +*/ + pq = *p+*q; + if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S160; + if(!(pq < 0.0e0)) goto S140; + *bound = 0.0e0; + goto S150; +S140: + *bound = 1.0e0; +S150: + *status = 3; + return; +S170: +S160: + if(!(*which == 1)) qporq = *p <= *q; +/* + Select the minimum of P or Q + Calculate ANSWERS +*/ + if(1 == *which) { +/* + Computing P and Q +*/ + cumt(t,df,p,q); + *status = 0; + } + else if(2 == *which) { +/* + Computing T + .. Get initial approximation for T +*/ + *t = dt1(p,q,df); + T2 = -inf; + T3 = inf; + T6 = atol; + T7 = tol; + dstinv(&T2,&T3,&K4,&K4,&K5,&T6,&T7); + *status = 0; + dinvr(status,t,&fx,&qleft,&qhi); +S180: + if(!(*status == 1)) goto S210; + cumt(t,df,&cum,&ccum); + if(!qporq) goto S190; + fx = cum-*p; + goto S200; +S190: + fx = ccum-*q; +S200: + dinvr(status,t,&fx,&qleft,&qhi); + goto S180; +S210: + if(!(*status == -1)) goto S240; + if(!qleft) goto S220; + *status = 1; + *bound = -inf; + goto S230; +S220: + *status = 2; + *bound = inf; +S240: +S230: + ; + } + else if(3 == *which) { +/* + Computing DF +*/ + *df = 5.0e0; + T8 = zero; + T9 = maxdf; + T10 = atol; + T11 = tol; + dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); + *status = 0; + dinvr(status,df,&fx,&qleft,&qhi); +S250: + if(!(*status == 1)) goto S280; + cumt(t,df,&cum,&ccum); + if(!qporq) goto S260; + fx = cum-*p; + goto S270; +S260: + fx = ccum-*q; +S270: + dinvr(status,df,&fx,&qleft,&qhi); + goto S250; +S280: + if(!(*status == -1)) goto S310; + if(!qleft) goto S290; + *status = 1; + *bound = zero; + goto S300; +S290: + *status = 2; + *bound = maxdf; +S300: + ; + } +S310: + return; +#undef tol +#undef atol +#undef zero +#undef inf +#undef maxdf +} /* END */ + +/***=====================================================================***/ +static void cumbet(double *x,double *y,double *a,double *b,double *cum, + double *ccum) +/* +********************************************************************** + + void cumbet(double *x,double *y,double *a,double *b,double *cum, + double *ccum) + + Double precision cUMulative incomplete BETa distribution + + + Function + + + Calculates the cdf to X of the incomplete beta distribution + with parameters a and b. This is the integral from 0 to x + of (1/B(a,b))*f(t)) where f(t) = t**(a-1) * (1-t)**(b-1) + + + Arguments + + + X --> Upper limit of integration. + X is DOUBLE PRECISION + + Y --> 1 - X. + Y is DOUBLE PRECISION + + A --> First parameter of the beta distribution. + A is DOUBLE PRECISION + + B --> Second parameter of the beta distribution. + B is DOUBLE PRECISION + + CUM <-- Cumulative incomplete beta distribution. + CUM is DOUBLE PRECISION + + CCUM <-- Compliment of Cumulative incomplete beta distribution. + CCUM is DOUBLE PRECISION + + + Method + + + Calls the routine BRATIO. + + References + + Didonato, Armido R. and Morris, Alfred H. Jr. (1992) Algorithim + 708 Significant Digit Computation of the Incomplete Beta Function + Ratios. ACM ToMS, Vol.18, No. 3, Sept. 1992, 360-373. + +********************************************************************** +*/ +{ +static int ierr; +/* + .. + .. Executable Statements .. +*/ + if(!(*x <= 0.0e0)) goto S10; + *cum = 0.0e0; + *ccum = 1.0e0; + return; +S10: + if(!(*y <= 0.0e0)) goto S20; + *cum = 1.0e0; + *ccum = 0.0e0; + return; +S20: + bratio(a,b,x,y,cum,ccum,&ierr); +/* + Call bratio routine +*/ + return; +} /* END */ + +/***=====================================================================***/ +static void cumbin(double *s,double *xn,double *pr,double *ompr, + double *cum,double *ccum) +/* +********************************************************************** + + void cumbin(double *s,double *xn,double *pr,double *ompr, + double *cum,double *ccum) + + CUmulative BINomial distribution + + + Function + + + Returns the probability of 0 to S successes in XN binomial + trials, each of which has a probability of success, PBIN. + + + Arguments + + + S --> The upper limit of cumulation of the binomial distribution. + S is DOUBLE PRECISION + + XN --> The number of binomial trials. + XN is DOUBLE PRECISIO + + PBIN --> The probability of success in each binomial trial. + PBIN is DOUBLE PRECIS + + OMPR --> 1 - PBIN + OMPR is DOUBLE PRECIS + + CUM <-- Cumulative binomial distribution. + CUM is DOUBLE PRECISI + + CCUM <-- Compliment of Cumulative binomial distribution. + CCUM is DOUBLE PRECIS + + + Method + + + Formula 26.5.24 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to reduce the binomial + distribution to the cumulative beta distribution. + +********************************************************************** +*/ +{ +static double T1,T2; +/* + .. + .. Executable Statements .. +*/ + if(!(*s < *xn)) goto S10; + T1 = *s+1.0e0; + T2 = *xn-*s; + cumbet(pr,ompr,&T1,&T2,ccum,cum); + goto S20; +S10: + *cum = 1.0e0; + *ccum = 0.0e0; +S20: + return; +} /* END */ + +/***=====================================================================***/ +static void cumchi(double *x,double *df,double *cum,double *ccum) +/* +********************************************************************** + + void cumchi(double *x,double *df,double *cum,double *ccum) + CUMulative of the CHi-square distribution + + + Function + + + Calculates the cumulative chi-square distribution. + + + Arguments + + + X --> Upper limit of integration of the + chi-square distribution. + X is DOUBLE PRECISION + + DF --> Degrees of freedom of the + chi-square distribution. + DF is DOUBLE PRECISION + + CUM <-- Cumulative chi-square distribution. + CUM is DOUBLE PRECISIO + + CCUM <-- Compliment of Cumulative chi-square distribution. + CCUM is DOUBLE PRECISI + + + Method + + + Calls incomplete gamma function (CUMGAM) + +********************************************************************** +*/ +{ +static double a,xx; +/* + .. + .. Executable Statements .. +*/ + a = *df*0.5e0; + xx = *x*0.5e0; + cumgam(&xx,&a,cum,ccum); + return; +} /* END */ + +/***=====================================================================***/ +static void cumchn(double *x,double *df,double *pnonc,double *cum, + double *ccum) +/* +********************************************************************** + + void cumchn(double *x,double *df,double *pnonc,double *cum, + double *ccum) + + CUMulative of the Non-central CHi-square distribution + + + Function + + + Calculates the cumulative non-central chi-square + distribution, i.e., the probability that a random variable + which follows the non-central chi-square distribution, with + non-centrality parameter PNONC and continuous degrees of + freedom DF, is less than or equal to X. + + + Arguments + + + X --> Upper limit of integration of the non-central + chi-square distribution. + X is DOUBLE PRECISION + + DF --> Degrees of freedom of the non-central + chi-square distribution. + DF is DOUBLE PRECISION + + PNONC --> Non-centrality parameter of the non-central + chi-square distribution. + PNONC is DOUBLE PRECIS + + CUM <-- Cumulative non-central chi-square distribution. + CUM is DOUBLE PRECISIO + + CCUM <-- Compliment of Cumulative non-central chi-square distribut + CCUM is DOUBLE PRECISI + + + Method + + + Uses formula 26.4.25 of Abramowitz and Stegun, Handbook of + Mathematical Functions, US NBS (1966) to calculate the + non-central chi-square. + + + Variables + + + EPS --- Convergence criterion. The sum stops when a + term is less than EPS*SUM. + EPS is DOUBLE PRECISIO + + NTIRED --- Maximum number of terms to be evaluated + in each sum. + NTIRED is INTEGER + + QCONV --- .TRUE. if convergence achieved - + i.e., program did not stop on NTIRED criterion. + QCONV is LOGICAL + + CCUM <-- Compliment of Cumulative non-central + chi-square distribution. + CCUM is DOUBLE PRECISI + +********************************************************************** +*/ +{ +#define dg(i) (*df+2.0e0*(double)(i)) +#define qsmall(xx) (int)(sum < 1.0e-20 || (xx) < eps*sum) +#define qtired(i) (int)((i) > ntired) +static double eps = 1.0e-5; +static int ntired = 1000; +static double adj,centaj,centwt,chid2,dfd2,lcntaj,lcntwt,lfact,pcent,pterm,sum, + sumadj,term,wt,xnonc; +static int i,icent,iterb,iterf; +static double T1,T2,T3; +/* + .. + .. Executable Statements .. +*/ + if(!(*x <= 0.0e0)) goto S10; + *cum = 0.0e0; + *ccum = 1.0e0; + return; +S10: + if(!(*pnonc <= 1.0e-10)) goto S20; +/* + When non-centrality parameter is (essentially) zero, + use cumulative chi-square distribution +*/ + cumchi(x,df,cum,ccum); + return; +S20: + xnonc = *pnonc/2.0e0; +/* +********************************************************************** + The following code calcualtes the weight, chi-square, and + adjustment term for the central term in the infinite series. + The central term is the one in which the poisson weight is + greatest. The adjustment term is the amount that must + be subtracted from the chi-square to move up two degrees + of freedom. +********************************************************************** +*/ + icent = fifidint(xnonc); + if(icent == 0) icent = 1; + chid2 = *x/2.0e0; +/* + Calculate central weight term +*/ + T1 = (double)(icent+1); + lfact = alngam(&T1); + lcntwt = -xnonc+(double)icent*log(xnonc)-lfact; + centwt = exp(lcntwt); +/* + Calculate central chi-square +*/ + T2 = dg(icent); + cumchi(x,&T2,&pcent,ccum); +/* + Calculate central adjustment term +*/ + dfd2 = dg(icent)/2.0e0; + T3 = 1.0e0+dfd2; + lfact = alngam(&T3); + lcntaj = dfd2*log(chid2)-chid2-lfact; + centaj = exp(lcntaj); + sum = centwt*pcent; +/* +********************************************************************** + Sum backwards from the central term towards zero. + Quit whenever either + (1) the zero term is reached, or + (2) the term gets small relative to the sum, or + (3) More than NTIRED terms are totaled. +********************************************************************** +*/ + iterb = 0; + sumadj = 0.0e0; + adj = centaj; + wt = centwt; + i = icent; + goto S40; +S30: + if(qtired(iterb) || qsmall(term) || i == 0) goto S50; +S40: + dfd2 = dg(i)/2.0e0; +/* + Adjust chi-square for two fewer degrees of freedom. + The adjusted value ends up in PTERM. +*/ + adj = adj*dfd2/chid2; + sumadj += adj; + pterm = pcent+sumadj; +/* + Adjust poisson weight for J decreased by one +*/ + wt *= ((double)i/xnonc); + term = wt*pterm; + sum += term; + i -= 1; + iterb += 1; + goto S30; +S50: + iterf = 0; +/* +********************************************************************** + Now sum forward from the central term towards infinity. + Quit when either + (1) the term gets small relative to the sum, or + (2) More than NTIRED terms are totaled. +********************************************************************** +*/ + sumadj = adj = centaj; + wt = centwt; + i = icent; + goto S70; +S60: + if(qtired(iterf) || qsmall(term)) goto S80; +S70: +/* + Update weights for next higher J +*/ + wt *= (xnonc/(double)(i+1)); +/* + Calculate PTERM and add term to sum +*/ + pterm = pcent-sumadj; + term = wt*pterm; + sum += term; +/* + Update adjustment term for DF for next iteration +*/ + i += 1; + dfd2 = dg(i)/2.0e0; + adj = adj*chid2/dfd2; + sumadj += adj; + iterf += 1; + goto S60; +S80: + *cum = sum; + *ccum = 0.5e0+(0.5e0-*cum); + return; +#undef dg +#undef qsmall +#undef qtired +} /* END */ + +/***=====================================================================***/ +static void cumf(double *f,double *dfn,double *dfd,double *cum,double *ccum) +/* +********************************************************************** + + void cumf(double *f,double *dfn,double *dfd,double *cum,double *ccum) + CUMulative F distribution + + + Function + + + Computes the integral from 0 to F of the f-density with DFN + and DFD degrees of freedom. + + + Arguments + + + F --> Upper limit of integration of the f-density. + F is DOUBLE PRECISION + + DFN --> Degrees of freedom of the numerator sum of squares. + DFN is DOUBLE PRECISI + + DFD --> Degrees of freedom of the denominator sum of squares. + DFD is DOUBLE PRECISI + + CUM <-- Cumulative f distribution. + CUM is DOUBLE PRECISI + + CCUM <-- Compliment of Cumulative f distribution. + CCUM is DOUBLE PRECIS + + + Method + + + Formula 26.5.28 of Abramowitz and Stegun is used to reduce + the cumulative F to a cumulative beta distribution. + + + Note + + + If F is less than or equal to 0, 0 is returned. + +********************************************************************** +*/ +{ +#define half 0.5e0 +#define done 1.0e0 +static double dsum,prod,xx,yy; +static int ierr; +static double T1,T2; +/* + .. + .. Executable Statements .. +*/ + if(!(*f <= 0.0e0)) goto S10; + *cum = 0.0e0; + *ccum = 1.0e0; + return; +S10: + prod = *dfn**f; +/* + XX is such that the incomplete beta with parameters + DFD/2 and DFN/2 evaluated at XX is 1 - CUM or CCUM + YY is 1 - XX + Calculate the smaller of XX and YY accurately +*/ + dsum = *dfd+prod; + xx = *dfd/dsum; + if(xx > half) { + yy = prod/dsum; + xx = done-yy; + } + else yy = done-xx; + T1 = *dfd*half; + T2 = *dfn*half; + bratio(&T1,&T2,&xx,&yy,ccum,cum,&ierr); + return; +#undef half +#undef done +} /* END */ + +/***=====================================================================***/ +static void cumfnc(double *f,double *dfn,double *dfd,double *pnonc, + double *cum,double *ccum) +/* +********************************************************************** + + F -NON- -C-ENTRAL F DISTRIBUTION + + + + Function + + + COMPUTES NONCENTRAL F DISTRIBUTION WITH DFN AND DFD + DEGREES OF FREEDOM AND NONCENTRALITY PARAMETER PNONC + + + Arguments + + + X --> UPPER LIMIT OF INTEGRATION OF NONCENTRAL F IN EQUATION + + DFN --> DEGREES OF FREEDOM OF NUMERATOR + + DFD --> DEGREES OF FREEDOM OF DENOMINATOR + + PNONC --> NONCENTRALITY PARAMETER. + + CUM <-- CUMULATIVE NONCENTRAL F DISTRIBUTION + + CCUM <-- COMPLIMENT OF CUMMULATIVE + + + Method + + + USES FORMULA 26.6.20 OF REFERENCE FOR INFINITE SERIES. + SERIES IS CALCULATED BACKWARD AND FORWARD FROM J = LAMBDA/2 + (THIS IS THE TERM WITH THE LARGEST POISSON WEIGHT) UNTIL + THE CONVERGENCE CRITERION IS MET. + + FOR SPEED, THE INCOMPLETE BETA FUNCTIONS ARE EVALUATED + BY FORMULA 26.5.16. + + + REFERENCE + + + HANDBOOD OF MATHEMATICAL FUNCTIONS + EDITED BY MILTON ABRAMOWITZ AND IRENE A. STEGUN + NATIONAL BUREAU OF STANDARDS APPLIED MATEMATICS SERIES - 55 + MARCH 1965 + P 947, EQUATIONS 26.6.17, 26.6.18 + + + Note + + + THE SUM CONTINUES UNTIL A SUCCEEDING TERM IS LESS THAN EPS + TIMES THE SUM (OR THE SUM IS LESS THAN 1.0E-20). EPS IS + SET TO 1.0E-4 IN A DATA STATEMENT WHICH CAN BE CHANGED. + +********************************************************************** +*/ +{ +#define qsmall(x) (int)(sum < 1.0e-20 || (x) < eps*sum) +#define half 0.5e0 +#define done 1.0e0 +static double eps = 1.0e-4; +static double dsum,dummy,prod,xx,yy,adn,aup,b,betdn,betup,centwt,dnterm,sum, + upterm,xmult,xnonc; +static int i,icent,ierr; +static double T1,T2,T3,T4,T5,T6; +/* + .. + .. Executable Statements .. +*/ + if(!(*f <= 0.0e0)) goto S10; + *cum = 0.0e0; + *ccum = 1.0e0; + return; +S10: + if(!(*pnonc < 1.0e-10)) goto S20; +/* + Handle case in which the non-centrality parameter is + (essentially) zero. +*/ + cumf(f,dfn,dfd,cum,ccum); + return; +S20: + xnonc = *pnonc/2.0e0; +/* + Calculate the central term of the poisson weighting factor. +*/ + icent = xnonc; + if(icent == 0) icent = 1; +/* + Compute central weight term +*/ + T1 = (double)(icent+1); + centwt = exp(-xnonc+(double)icent*log(xnonc)-alngam(&T1)); +/* + Compute central incomplete beta term + Assure that minimum of arg to beta and 1 - arg is computed + accurately. +*/ + prod = *dfn**f; + dsum = *dfd+prod; + yy = *dfd/dsum; + if(yy > half) { + xx = prod/dsum; + yy = done-xx; + } + else xx = done-yy; + T2 = *dfn*half+(double)icent; + T3 = *dfd*half; + bratio(&T2,&T3,&xx,&yy,&betdn,&dummy,&ierr); + adn = *dfn/2.0e0+(double)icent; + aup = adn; + b = *dfd/2.0e0; + betup = betdn; + sum = centwt*betdn; +/* + Now sum terms backward from icent until convergence or all done +*/ + xmult = centwt; + i = icent; + T4 = adn+b; + T5 = adn+1.0e0; + dnterm = exp(alngam(&T4)-alngam(&T5)-alngam(&b)+adn*log(xx)+b*log(yy)); +S30: + if(qsmall(xmult*betdn) || i <= 0) goto S40; + xmult *= ((double)i/xnonc); + i -= 1; + adn -= 1.0; + dnterm = (adn+1.0)/((adn+b)*xx)*dnterm; + betdn += dnterm; + sum += (xmult*betdn); + goto S30; +S40: + i = icent+1; +/* + Now sum forwards until convergence +*/ + xmult = centwt; + if(aup-1.0+b == 0) upterm = exp(-alngam(&aup)-alngam(&b)+(aup-1.0)*log(xx)+ + b*log(yy)); + else { + T6 = aup-1.0+b; + upterm = exp(alngam(&T6)-alngam(&aup)-alngam(&b)+(aup-1.0)*log(xx)+b* + log(yy)); + } + goto S60; +S50: + if(qsmall(xmult*betup)) goto S70; +S60: + xmult *= (xnonc/(double)i); + i += 1; + aup += 1.0; + upterm = (aup+b-2.0e0)*xx/(aup-1.0)*upterm; + betup -= upterm; + sum += (xmult*betup); + goto S50; +S70: + *cum = sum; + *ccum = 0.5e0+(0.5e0-*cum); + return; +#undef qsmall +#undef half +#undef done +} /* END */ + +/***=====================================================================***/ +static void cumgam(double *x,double *a,double *cum,double *ccum) +/* +********************************************************************** + + void cumgam(double *x,double *a,double *cum,double *ccum) + Double precision cUMulative incomplete GAMma distribution + + + Function + + + Computes the cumulative of the incomplete gamma + distribution, i.e., the integral from 0 to X of + (1/GAM(A))*EXP(-T)*T**(A-1) DT + where GAM(A) is the complete gamma function of A, i.e., + GAM(A) = integral from 0 to infinity of + EXP(-T)*T**(A-1) DT + + + Arguments + + + X --> The upper limit of integration of the incomplete gamma. + X is DOUBLE PRECISION + + A --> The shape parameter of the incomplete gamma. + A is DOUBLE PRECISION + + CUM <-- Cumulative incomplete gamma distribution. + CUM is DOUBLE PRECISION + + CCUM <-- Compliment of Cumulative incomplete gamma distribution. + CCUM is DOUBLE PRECISIO + + + Method + + + Calls the routine GRATIO. + +********************************************************************** +*/ +{ +static int K1 = 0; +/* + .. + .. Executable Statements .. +*/ + if(!(*x <= 0.0e0)) goto S10; + *cum = 0.0e0; + *ccum = 1.0e0; + return; +S10: + gratio(a,x,cum,ccum,&K1); +/* + Call gratio routine +*/ + return; +} /* END */ + +/***=====================================================================***/ +static void cumnbn(double *s,double *xn,double *pr,double *ompr, + double *cum,double *ccum) +/* +********************************************************************** + + void cumnbn(double *s,double *xn,double *pr,double *ompr, + double *cum,double *ccum) + + CUmulative Negative BINomial distribution + + + Function + + + Returns the probability that it there will be S or fewer failures + before there are XN successes, with each binomial trial having + a probability of success PR. + + Prob(# failures = S | XN successes, PR) = + ( XN + S - 1 ) + ( ) * PR^XN * (1-PR)^S + ( S ) + + + Arguments + + + S --> The number of failures + S is DOUBLE PRECISION + + XN --> The number of successes + XN is DOUBLE PRECISIO + + PR --> The probability of success in each binomial trial. + PR is DOUBLE PRECISIO + + OMPR --> 1 - PR + OMPR is DOUBLE PRECIS + + CUM <-- Cumulative negative binomial distribution. + CUM is DOUBLE PRECISI + + CCUM <-- Compliment of Cumulative negative binomial distribution. + CCUM is DOUBLE PRECIS + + + Method + + + Formula 26.5.26 of Abramowitz and Stegun, Handbook of + Mathematical Functions (1966) is used to reduce the negative + binomial distribution to the cumulative beta distribution. + +********************************************************************** +*/ +{ +static double T1; +/* + .. + .. Executable Statements .. +*/ + T1 = *s+1.e0; + cumbet(pr,ompr,xn,&T1,cum,ccum); + return; +} /* END */ + +/***=====================================================================***/ +static void cumnor(double *arg,double *result,double *ccum) +/* +********************************************************************** + + void cumnor(double *arg,double *result,double *ccum) + + + Function + + + Computes the cumulative of the normal distribution, i.e., + the integral from -infinity to x of + (1/sqrt(2*pi)) exp(-u*u/2) du + + X --> Upper limit of integration. + X is DOUBLE PRECISION + + RESULT <-- Cumulative normal distribution. + RESULT is DOUBLE PRECISION + + CCUM <-- Compliment of Cumulative normal distribution. + CCUM is DOUBLE PRECISION + + Renaming of function ANORM from: + + Cody, W.D. (1993). "ALGORITHM 715: SPECFUN - A Portabel FORTRAN + Package of Special Function Routines and Test Drivers" + acm Transactions on Mathematical Software. 19, 22-32. + + with slight modifications to return ccum and to deal with + machine constants. + +********************************************************************** + Original Comments: +------------------------------------------------------------------ + + This function evaluates the normal distribution function: + + / x + 1 | -t*t/2 + P(x) = ----------- | e dt + sqrt(2 pi) | + /-oo + + The main computation evaluates near-minimax approximations + derived from those in "Rational Chebyshev approximations for + the error function" by W. J. Cody, Math. Comp., 1969, 631-637. + This transportable program uses rational functions that + theoretically approximate the normal distribution function to + at least 18 significant decimal digits. The accuracy achieved + depends on the arithmetic system, the compiler, the intrinsic + functions, and proper selection of the machine-dependent + constants. + +******************************************************************* +******************************************************************* + + Explanation of machine-dependent constants. + + MIN = smallest machine representable number. + + EPS = argument below which anorm(x) may be represented by + 0.5 and above which x*x will not underflow. + A conservative value is the largest machine number X + such that 1.0 + X = 1.0 to machine precision. +******************************************************************* +******************************************************************* + + Error returns + + The program returns ANORM = 0 for ARG .LE. XLOW. + + + Intrinsic functions required are: + + ABS, AINT, EXP + + + Author: W. J. Cody + Mathematics and Computer Science Division + Argonne National Laboratory + Argonne, IL 60439 + + Latest modification: March 15, 1992 + +------------------------------------------------------------------ +*/ +{ +static double a[5] = { + 2.2352520354606839287e00,1.6102823106855587881e02,1.0676894854603709582e03, + 1.8154981253343561249e04,6.5682337918207449113e-2 +}; +static double b[4] = { + 4.7202581904688241870e01,9.7609855173777669322e02,1.0260932208618978205e04, + 4.5507789335026729956e04 +}; +static double c[9] = { + 3.9894151208813466764e-1,8.8831497943883759412e00,9.3506656132177855979e01, + 5.9727027639480026226e02,2.4945375852903726711e03,6.8481904505362823326e03, + 1.1602651437647350124e04,9.8427148383839780218e03,1.0765576773720192317e-8 +}; +static double d[8] = { + 2.2266688044328115691e01,2.3538790178262499861e02,1.5193775994075548050e03, + 6.4855582982667607550e03,1.8615571640885098091e04,3.4900952721145977266e04, + 3.8912003286093271411e04,1.9685429676859990727e04 +}; +static double half = 0.5e0; +static double p[6] = { + 2.1589853405795699e-1,1.274011611602473639e-1,2.2235277870649807e-2, + 1.421619193227893466e-3,2.9112874951168792e-5,2.307344176494017303e-2 +}; +static double one = 1.0e0; +static double q[5] = { + 1.28426009614491121e00,4.68238212480865118e-1,6.59881378689285515e-2, + 3.78239633202758244e-3,7.29751555083966205e-5 +}; +static double sixten = 1.60e0; +static double sqrpi = 3.9894228040143267794e-1; +static double thrsh = 0.66291e0; +static double root32 = 5.656854248e0; +static double zero = 0.0e0; +static int K1 = 1; +static int K2 = 2; +static int i; +static double del,eps,temp,x,xden,xnum,y,xsq,min; +/* +------------------------------------------------------------------ + Machine dependent constants +------------------------------------------------------------------ +*/ + eps = spmpar(&K1)*0.5e0; + min = spmpar(&K2); + x = *arg; + y = fabs(x); + if(y <= thrsh) { +/* +------------------------------------------------------------------ + Evaluate anorm for |X| <= 0.66291 +------------------------------------------------------------------ +*/ + xsq = zero; + if(y > eps) xsq = x*x; + xnum = a[4]*xsq; + xden = xsq; + for(i=0; i<3; i++) { + xnum = (xnum+a[i])*xsq; + xden = (xden+b[i])*xsq; + } + *result = x*(xnum+a[3])/(xden+b[3]); + temp = *result; + *result = half+temp; + *ccum = half-temp; + } +/* +------------------------------------------------------------------ + Evaluate anorm for 0.66291 <= |X| <= sqrt(32) +------------------------------------------------------------------ +*/ + else if(y <= root32) { + xnum = c[8]*y; + xden = y; + for(i=0; i<7; i++) { + xnum = (xnum+c[i])*y; + xden = (xden+d[i])*y; + } + *result = (xnum+c[7])/(xden+d[7]); + xsq = fifdint(y*sixten)/sixten; + del = (y-xsq)*(y+xsq); + *result = exp(-(xsq*xsq*half))*exp(-(del*half))**result; + *ccum = one-*result; + if(x > zero) { + temp = *result; + *result = *ccum; + *ccum = temp; + } + } +/* +------------------------------------------------------------------ + Evaluate anorm for |X| > sqrt(32) +------------------------------------------------------------------ +*/ + else { + *result = zero; + xsq = one/(x*x); + xnum = p[5]*xsq; + xden = xsq; + for(i=0; i<4; i++) { + xnum = (xnum+p[i])*xsq; + xden = (xden+q[i])*xsq; + } + *result = xsq*(xnum+p[4])/(xden+q[4]); + *result = (sqrpi-*result)/y; + xsq = fifdint(x*sixten)/sixten; + del = (x-xsq)*(x+xsq); + *result = exp(-(xsq*xsq*half))*exp(-(del*half))**result; + *ccum = one-*result; + if(x > zero) { + temp = *result; + *result = *ccum; + *ccum = temp; + } + } + if(*result < min) *result = 0.0e0; +/* +------------------------------------------------------------------ + Fix up for negative argument, erf, etc. +------------------------------------------------------------------ +----------Last card of ANORM ---------- +*/ + if(*ccum < min) *ccum = 0.0e0; +} /* END */ + +/***=====================================================================***/ +static void cumpoi(double *s,double *xlam,double *cum,double *ccum) +/* +********************************************************************** + + void cumpoi(double *s,double *xlam,double *cum,double *ccum) + CUMulative POIsson distribution + + + Function + + + Returns the probability of S or fewer events in a Poisson + distribution with mean XLAM. + + + Arguments + + + S --> Upper limit of cumulation of the Poisson. + S is DOUBLE PRECISION + + XLAM --> Mean of the Poisson distribution. + XLAM is DOUBLE PRECIS + + CUM <-- Cumulative poisson distribution. + CUM is DOUBLE PRECISION + + CCUM <-- Compliment of Cumulative poisson distribution. + CCUM is DOUBLE PRECIS + + + Method + + + Uses formula 26.4.21 of Abramowitz and Stegun, Handbook of + Mathematical Functions to reduce the cumulative Poisson to + the cumulative chi-square distribution. + +********************************************************************** +*/ +{ +static double chi,df; +/* + .. + .. Executable Statements .. +*/ + df = 2.0e0*(*s+1.0e0); + chi = 2.0e0**xlam; + cumchi(&chi,&df,ccum,cum); + return; +} /* END */ + +/***=====================================================================***/ +static void cumt(double *t,double *df,double *cum,double *ccum) +/* +********************************************************************** + + void cumt(double *t,double *df,double *cum,double *ccum) + CUMulative T-distribution + + + Function + + + Computes the integral from -infinity to T of the t-density. + + + Arguments + + + T --> Upper limit of integration of the t-density. + T is DOUBLE PRECISION + + DF --> Degrees of freedom of the t-distribution. + DF is DOUBLE PRECISIO + + CUM <-- Cumulative t-distribution. + CCUM is DOUBLE PRECIS + + CCUM <-- Compliment of Cumulative t-distribution. + CCUM is DOUBLE PRECIS + + + Method + + + Formula 26.5.27 of Abramowitz and Stegun, Handbook of + Mathematical Functions is used to reduce the t-distribution + to an incomplete beta. + +********************************************************************** +*/ +{ +static double K2 = 0.5e0; +static double xx,a,oma,tt,yy,dfptt,T1; +/* + .. + .. Executable Statements .. +*/ + tt = *t**t; + dfptt = *df+tt; + xx = *df/dfptt; + yy = tt/dfptt; + T1 = 0.5e0**df; + cumbet(&xx,&yy,&T1,&K2,&a,&oma); + if(!(*t <= 0.0e0)) goto S10; + *cum = 0.5e0*a; + *ccum = oma+*cum; + goto S20; +S10: + *ccum = 0.5e0*a; + *cum = oma+*ccum; +S20: + return; +} /* END */ + +/***=====================================================================***/ +static double dbetrm(double *a,double *b) +/* +********************************************************************** + + double dbetrm(double *a,double *b) + Double Precision Sterling Remainder for Complete + Beta Function + + + Function + + + Log(Beta(A,B)) = Lgamma(A) + Lgamma(B) - Lgamma(A+B) + where Lgamma is the log of the (complete) gamma function + + Let ZZ be approximation obtained if each log gamma is approximated + by Sterling's formula, i.e., + Sterling(Z) = LOG( SQRT( 2*PI ) ) + ( Z-0.5 ) * LOG( Z ) - Z + + Returns Log(Beta(A,B)) - ZZ + + + Arguments + + + A --> One argument of the Beta + DOUBLE PRECISION A + + B --> The other argument of the Beta + DOUBLE PRECISION B + +********************************************************************** +*/ +{ +static double dbetrm,T1,T2,T3; +/* + .. + .. Executable Statements .. +*/ +/* + Try to sum from smallest to largest +*/ + T1 = *a+*b; + dbetrm = -dstrem(&T1); + T2 = fifdmax1(*a,*b); + dbetrm += dstrem(&T2); + T3 = fifdmin1(*a,*b); + dbetrm += dstrem(&T3); + return dbetrm; +} /* END */ + +/***=====================================================================***/ +static double devlpl(double a[],int *n,double *x) +/* +********************************************************************** + + double devlpl(double a[],int *n,double *x) + Double precision EVALuate a PoLynomial at X + + + Function + + + returns + A(1) + A(2)*X + ... + A(N)*X**(N-1) + + + Arguments + + + A --> Array of coefficients of the polynomial. + A is DOUBLE PRECISION(N) + + N --> Length of A, also degree of polynomial - 1. + N is INTEGER + + X --> Point at which the polynomial is to be evaluated. + X is DOUBLE PRECISION + +********************************************************************** +*/ +{ +static double devlpl,term; +static int i; +/* + .. + .. Executable Statements .. +*/ + term = a[*n-1]; + for(i= *n-1-1; i>=0; i--) term = a[i]+term**x; + devlpl = term; + return devlpl; +} /* END */ + +/***=====================================================================***/ +static double dexpm1(double *x) +/* +********************************************************************** + + double dexpm1(double *x) + Evaluation of the function EXP(X) - 1 + + + Arguments + + + X --> Argument at which exp(x)-1 desired + DOUBLE PRECISION X + + + Method + + + Renaming of function rexp from code of: + + DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant + Digit Computation of the Incomplete Beta Function Ratios. ACM + Trans. Math. Softw. 18 (1993), 360-373. + +********************************************************************** +*/ +{ +static double p1 = .914041914819518e-09; +static double p2 = .238082361044469e-01; +static double q1 = -.499999999085958e+00; +static double q2 = .107141568980644e+00; +static double q3 = -.119041179760821e-01; +static double q4 = .595130811860248e-03; +static double dexpm1,w; +/* + .. + .. Executable Statements .. +*/ + if(fabs(*x) > 0.15e0) goto S10; + dexpm1 = *x*(((p2**x+p1)**x+1.0e0)/((((q4**x+q3)**x+q2)**x+q1)**x+1.0e0)); + return dexpm1; +S10: + w = exp(*x); + if(*x > 0.0e0) goto S20; + dexpm1 = w-0.5e0-0.5e0; + return dexpm1; +S20: + dexpm1 = w*(0.5e0+(0.5e0-1.0e0/w)); + return dexpm1; +} /* END */ + +/***=====================================================================***/ +static double dinvnr(double *p,double *q) +/* +********************************************************************** + + double dinvnr(double *p,double *q) + Double precision NoRmal distribution INVerse + + + Function + + + Returns X such that CUMNOR(X) = P, i.e., the integral from - + infinity to X of (1/SQRT(2*PI)) EXP(-U*U/2) dU is P + + + Arguments + + + P --> The probability whose normal deviate is sought. + P is DOUBLE PRECISION + + Q --> 1-P + P is DOUBLE PRECISION + + + Method + + + The rational function on page 95 of Kennedy and Gentle, + Statistical Computing, Marcel Dekker, NY , 1980 is used as a start + value for the Newton method of finding roots. + + + Note + + + If P or Q .lt. machine EPS returns +/- DINVNR(EPS) + +********************************************************************** +*/ +{ +#define maxit 100 +#define eps (1.0e-13) +#define r2pi 0.3989422804014326e0 +#define nhalf (-0.5e0) +#define dennor(x) (r2pi*exp(nhalf*(x)*(x))) +static double dinvnr,strtx,xcur,cum,ccum,pp,dx; +static int i; +static unsigned long qporq; +/* + .. + .. Executable Statements .. +*/ +/* + FIND MINIMUM OF P AND Q +*/ + qporq = *p <= *q; + if(!qporq) goto S10; + pp = *p; + goto S20; +S10: + pp = *q; +S20: +/* + INITIALIZATION STEP +*/ + strtx = stvaln(&pp); + xcur = strtx; +/* + NEWTON INTERATIONS +*/ + for(i=1; i<=maxit; i++) { + cumnor(&xcur,&cum,&ccum); + dx = (cum-pp)/dennor(xcur); + xcur -= dx; + if(fabs(dx/xcur) < eps) goto S40; + } + dinvnr = strtx; +/* + IF WE GET HERE, NEWTON HAS FAILED +*/ + if(!qporq) dinvnr = -dinvnr; + return dinvnr; +S40: +/* + IF WE GET HERE, NEWTON HAS SUCCEDED +*/ + dinvnr = xcur; + if(!qporq) dinvnr = -dinvnr; + return dinvnr; +#undef maxit +#undef eps +#undef r2pi +#undef nhalf +#undef dennor +} /* END */ + +/***=====================================================================***/ +static void E0000(int IENTRY,int *status,double *x,double *fx, + unsigned long *qleft,unsigned long *qhi,double *zabsst, + double *zabsto,double *zbig,double *zrelst, + double *zrelto,double *zsmall,double *zstpmu) +{ +#define qxmon(zx,zy,zz) (int)((zx) <= (zy) && (zy) <= (zz)) +static double absstp,abstol,big,fbig,fsmall,relstp,reltol,small,step,stpmul,xhi, + xlb,xlo,xsave,xub,yy; +static int i99999; +static unsigned long qbdd,qcond,qdum1,qdum2,qincr,qlim,qok,qup; + switch(IENTRY){case 0: goto DINVR; case 1: goto DSTINV;} +DINVR: + if(*status > 0) goto S310; + qcond = !qxmon(small,*x,big); + if(qcond){ ftnstop("SMALL,X,BIG nonmonotone in E0000"); *status=-1; return;} + xsave = *x; +/* + See that SMALL and BIG bound the zero and set QINCR +*/ + *x = small; +/* + GET-FUNCTION-VALUE +*/ + i99999 = 1; + goto S300; +S10: + fsmall = *fx; + *x = big; +/* + GET-FUNCTION-VALUE +*/ + i99999 = 2; + goto S300; +S20: + fbig = *fx; + qincr = fbig > fsmall; + if(!qincr) goto S50; + if(fsmall <= 0.0e0) goto S30; + *status = -1; + *qleft = *qhi = 1; + return; +S30: + if(fbig >= 0.0e0) goto S40; + *status = -1; + *qleft = *qhi = 0; + return; +S40: + goto S80; +S50: + if(fsmall >= 0.0e0) goto S60; + *status = -1; + *qleft = 1; + *qhi = 0; + return; +S60: + if(fbig <= 0.0e0) goto S70; + *status = -1; + *qleft = 0; + *qhi = 1; + return; +S80: +S70: + *x = xsave; + step = fifdmax1(absstp,relstp*fabs(*x)); +/* + YY = F(X) - Y + GET-FUNCTION-VALUE +*/ + i99999 = 3; + goto S300; +S90: + yy = *fx; + if(!(yy == 0.0e0)) goto S100; + *status = 0; + qok = 1; + return; +S100: + qup = qincr && yy < 0.0e0 || !qincr && yy > 0.0e0; +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + HANDLE CASE IN WHICH WE MUST STEP HIGHER +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +*/ + if(!qup) goto S170; + xlb = xsave; + xub = fifdmin1(xlb+step,big); + goto S120; +S110: + if(qcond) goto S150; +S120: +/* + YY = F(XUB) - Y +*/ + *x = xub; +/* + GET-FUNCTION-VALUE +*/ + i99999 = 4; + goto S300; +S130: + yy = *fx; + qbdd = qincr && yy >= 0.0e0 || !qincr && yy <= 0.0e0; + qlim = xub >= big; + qcond = qbdd || qlim; + if(qcond) goto S140; + step = stpmul*step; + xlb = xub; + xub = fifdmin1(xlb+step,big); +S140: + goto S110; +S150: + if(!(qlim && !qbdd)) goto S160; + *status = -1; + *qleft = 0; + *qhi = !qincr; + *x = big; + return; +S160: + goto S240; +S170: +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + HANDLE CASE IN WHICH WE MUST STEP LOWER +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +*/ + xub = xsave; + xlb = fifdmax1(xub-step,small); + goto S190; +S180: + if(qcond) goto S220; +S190: +/* + YY = F(XLB) - Y +*/ + *x = xlb; +/* + GET-FUNCTION-VALUE +*/ + i99999 = 5; + goto S300; +S200: + yy = *fx; + qbdd = qincr && yy <= 0.0e0 || !qincr && yy >= 0.0e0; + qlim = xlb <= small; + qcond = qbdd || qlim; + if(qcond) goto S210; + step = stpmul*step; + xub = xlb; + xlb = fifdmax1(xub-step,small); +S210: + goto S180; +S220: + if(!(qlim && !qbdd)) goto S230; + *status = -1; + *qleft = 1; + *qhi = qincr; + *x = small; + return; +S240: +S230: + dstzr(&xlb,&xub,&abstol,&reltol); +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + IF WE REACH HERE, XLB AND XUB BOUND THE ZERO OF F. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +*/ + *status = 0; + goto S260; +S250: + if(!(*status == 1)) goto S290; +S260: + dzror(status,x,fx,&xlo,&xhi,&qdum1,&qdum2); + if(!(*status == 1)) goto S280; +/* + GET-FUNCTION-VALUE +*/ + i99999 = 6; + goto S300; +S280: +S270: + goto S250; +S290: + *x = xlo; + *status = 0; + return; +DSTINV: + small = *zsmall; + big = *zbig; + absstp = *zabsst; + relstp = *zrelst; + stpmul = *zstpmu; + abstol = *zabsto; + reltol = *zrelto; + return; +S300: +/* + TO GET-FUNCTION-VALUE +*/ + *status = 1; + return; +S310: + switch((int)i99999){case 1: goto S10;case 2: goto S20;case 3: goto S90;case + 4: goto S130;case 5: goto S200;case 6: goto S270;default: break;} +#undef qxmon +} /* END */ + +/***=====================================================================***/ +static void dinvr(int *status,double *x,double *fx, + unsigned long *qleft,unsigned long *qhi) +/* +********************************************************************** + + void dinvr(int *status,double *x,double *fx, + unsigned long *qleft,unsigned long *qhi) + + Double precision + bounds the zero of the function and invokes zror + Reverse Communication + + + Function + + + Bounds the function and invokes ZROR to perform the zero + finding. STINVR must have been called before this routine + in order to set its parameters. + + + Arguments + + + STATUS <--> At the beginning of a zero finding problem, STATUS + should be set to 0 and INVR invoked. (The value + of parameters other than X will be ignored on this cal + + When INVR needs the function evaluated, it will set + STATUS to 1 and return. The value of the function + should be set in FX and INVR again called without + changing any of its other parameters. + + When INVR has finished without error, it will return + with STATUS 0. In that case X is approximately a root + of F(X). + + If INVR cannot bound the function, it returns status + -1 and sets QLEFT and QHI. + INTEGER STATUS + + X <-- The value of X at which F(X) is to be evaluated. + DOUBLE PRECISION X + + FX --> The value of F(X) calculated when INVR returns with + STATUS = 1. + DOUBLE PRECISION FX + + QLEFT <-- Defined only if QMFINV returns .FALSE. In that + case it is .TRUE. If the stepping search terminated + unsucessfully at SMALL. If it is .FALSE. the search + terminated unsucessfully at BIG. + QLEFT is LOGICAL + + QHI <-- Defined only if QMFINV returns .FALSE. In that + case it is .TRUE. if F(X) .GT. Y at the termination + of the search and .FALSE. if F(X) .LT. Y at the + termination of the search. + QHI is LOGICAL + +********************************************************************** +*/ +{ + E0000(0,status,x,fx,qleft,qhi,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +} /* END */ + +/***=====================================================================***/ +static void dstinv(double *zsmall,double *zbig,double *zabsst, + double *zrelst,double *zstpmu,double *zabsto, + double *zrelto) +/* +********************************************************************** + void dstinv(double *zsmall,double *zbig,double *zabsst, + double *zrelst,double *zstpmu,double *zabsto, + double *zrelto) + + Double Precision - SeT INverse finder - Reverse Communication + Function + Concise Description - Given a monotone function F finds X + such that F(X) = Y. Uses Reverse communication -- see invr. + This routine sets quantities needed by INVR. + More Precise Description of INVR - + F must be a monotone function, the results of QMFINV are + otherwise undefined. QINCR must be .TRUE. if F is non- + decreasing and .FALSE. if F is non-increasing. + QMFINV will return .TRUE. if and only if F(SMALL) and + F(BIG) bracket Y, i. e., + QINCR is .TRUE. and F(SMALL).LE.Y.LE.F(BIG) or + QINCR is .FALSE. and F(BIG).LE.Y.LE.F(SMALL) + if QMFINV returns .TRUE., then the X returned satisfies + the following condition. let + TOL(X) = MAX(ABSTOL,RELTOL*ABS(X)) + then if QINCR is .TRUE., + F(X-TOL(X)) .LE. Y .LE. F(X+TOL(X)) + and if QINCR is .FALSE. + F(X-TOL(X)) .GE. Y .GE. F(X+TOL(X)) + Arguments + SMALL --> The left endpoint of the interval to be + searched for a solution. + SMALL is DOUBLE PRECISION + BIG --> The right endpoint of the interval to be + searched for a solution. + BIG is DOUBLE PRECISION + ABSSTP, RELSTP --> The initial step size in the search + is MAX(ABSSTP,RELSTP*ABS(X)). See algorithm. + ABSSTP is DOUBLE PRECISION + RELSTP is DOUBLE PRECISION + STPMUL --> When a step doesn't bound the zero, the step + size is multiplied by STPMUL and another step + taken. A popular value is 2.0 + DOUBLE PRECISION STPMUL + ABSTOL, RELTOL --> Two numbers that determine the accuracy + of the solution. See function for a precise definition. + ABSTOL is DOUBLE PRECISION + RELTOL is DOUBLE PRECISION + Method + Compares F(X) with Y for the input value of X then uses QINCR + to determine whether to step left or right to bound the + desired x. the initial step size is + MAX(ABSSTP,RELSTP*ABS(S)) for the input value of X. + Iteratively steps right or left until it bounds X. + At each step which doesn't bound X, the step size is doubled. + The routine is careful never to step beyond SMALL or BIG. If + it hasn't bounded X at SMALL or BIG, QMFINV returns .FALSE. + after setting QLEFT and QHI. + If X is successfully bounded then Algorithm R of the paper + 'Two Efficient Algorithms with Guaranteed Convergence for + Finding a Zero of a Function' by J. C. P. Bus and + T. J. Dekker in ACM Transactions on Mathematical + Software, Volume 1, No. 4 page 330 (DEC. '75) is employed + to find the zero of the function F(X)-Y. This is routine + QRZERO. +********************************************************************** +*/ +{ + E0000(1,NULL,NULL,NULL,NULL,NULL,zabsst,zabsto,zbig,zrelst,zrelto,zsmall, + zstpmu); +} /* END */ + +/***=====================================================================***/ +static double dlanor(double *x) +/* +********************************************************************** + + double dlanor(double *x) + Double precision Logarith of the Asymptotic Normal + + + Function + + + Computes the logarithm of the cumulative normal distribution + from abs( x ) to infinity for abs( x ) >= 5. + + + Arguments + + + X --> Value at which cumulative normal to be evaluated + DOUBLE PRECISION X + + + Method + + + 23 term expansion of formula 26.2.12 of Abramowitz and Stegun. + The relative error at X = 5 is about 0.5E-5. + + + Note + + + ABS(X) must be >= 5 else there is an error stop. + +********************************************************************** +*/ +{ +#define dlsqpi 0.91893853320467274177e0 +static double coef[12] = { + -1.0e0,3.0e0,-15.0e0,105.0e0,-945.0e0,10395.0e0,-135135.0e0,2027025.0e0, + -34459425.0e0,654729075.0e0,-13749310575.e0,316234143225.0e0 +}; +static int K1 = 12; +static double dlanor,approx,correc,xx,xx2,T2; +/* + .. + .. Executable Statements .. +*/ + xx = fabs(*x); + if(xx < 5.0e0){ ftnstop("Argument too small in DLANOR"); return 66.6; } + approx = -dlsqpi-0.5e0*xx*xx-log(xx); + xx2 = xx*xx; + T2 = 1.0e0/xx2; + correc = devlpl(coef,&K1,&T2)/xx2; + correc = dln1px(&correc); + dlanor = approx+correc; + return dlanor; +#undef dlsqpi +} /* END */ + +/***=====================================================================***/ +static double dln1mx(double *x) +/* +********************************************************************** + + double dln1mx(double *x) + Double precision LN(1-X) + + + Function + + + Returns ln(1-x) for small x (good accuracy if x .le. 0.1). + Note that the obvious code of + LOG(1.0-X) + won't work for small X because 1.0-X loses accuracy + + + Arguments + + + X --> Value for which ln(1-x) is desired. + X is DOUBLE PRECISION + + + Method + + + If X > 0.1, the obvious code above is used ELSE + The Taylor series for 1-x is expanded to 20 terms. + +********************************************************************** +*/ +{ +static double dln1mx,T1; +/* + .. + .. Executable Statements .. +*/ + T1 = -*x; + dln1mx = dln1px(&T1); + return dln1mx; +} /* END */ + +/***=====================================================================***/ +static double dln1px(double *a) +/* +********************************************************************** + + double dln1px(double *a) + Double precision LN(1+X) + + + Function + + + Returns ln(1+x) + Note that the obvious code of + LOG(1.0+X) + won't work for small X because 1.0+X loses accuracy + + + Arguments + + + X --> Value for which ln(1-x) is desired. + X is DOUBLE PRECISION + + + Method + + + Renames ALNREL from: + DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant + Digit Computation of the Incomplete Beta Function Ratios. ACM + Trans. Math. Softw. 18 (1993), 360-373. + +********************************************************************** +----------------------------------------------------------------------- + EVALUATION OF THE FUNCTION LN(1 + A) +----------------------------------------------------------------------- +*/ +{ +static double p1 = -.129418923021993e+01; +static double p2 = .405303492862024e+00; +static double p3 = -.178874546012214e-01; +static double q1 = -.162752256355323e+01; +static double q2 = .747811014037616e+00; +static double q3 = -.845104217945565e-01; +static double dln1px,t,t2,w,x; +/* + .. + .. Executable Statements .. +*/ + if(fabs(*a) > 0.375e0) goto S10; + t = *a/(*a+2.0e0); + t2 = t*t; + w = (((p3*t2+p2)*t2+p1)*t2+1.0e0)/(((q3*t2+q2)*t2+q1)*t2+1.0e0); + dln1px = 2.0e0*t*w; + return dln1px; +S10: + x = 1.e0+*a; + dln1px = log(x); + return dln1px; +} /* END */ + +/***=====================================================================***/ +static double dlnbet(double *a0,double *b0) +/* +********************************************************************** + + double dlnbet(a0,b0) + Double precision LN of the complete BETa + + + Function + + + Returns the natural log of the complete beta function, + i.e., + + ln( Gamma(a)*Gamma(b) / Gamma(a+b) + + + Arguments + + + A,B --> The (symmetric) arguments to the complete beta + DOUBLE PRECISION A, B + + + Method + + + Renames BETALN from: + DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant + Digit Computation of the Incomplete Beta Function Ratios. ACM + Trans. Math. Softw. 18 (1993), 360-373. + +********************************************************************** +----------------------------------------------------------------------- + EVALUATION OF THE LOGARITHM OF THE BETA FUNCTION +----------------------------------------------------------------------- + E = 0.5*LN(2*PI) +-------------------------- +*/ +{ +static double e = .918938533204673e0; +static double dlnbet,a,b,c,h,u,v,w,z; +static int i,n; +static double T1; +/* + .. + .. Executable Statements .. +*/ + a = fifdmin1(*a0,*b0); + b = fifdmax1(*a0,*b0); + if(a >= 8.0e0) goto S100; + if(a >= 1.0e0) goto S20; +/* +----------------------------------------------------------------------- + PROCEDURE WHEN A .LT. 1 +----------------------------------------------------------------------- +*/ + if(b >= 8.0e0) goto S10; + T1 = a+b; + dlnbet = gamln(&a)+(gamln(&b)-gamln(&T1)); + return dlnbet; +S10: + dlnbet = gamln(&a)+algdiv(&a,&b); + return dlnbet; +S20: +/* +----------------------------------------------------------------------- + PROCEDURE WHEN 1 .LE. A .LT. 8 +----------------------------------------------------------------------- +*/ + if(a > 2.0e0) goto S40; + if(b > 2.0e0) goto S30; + dlnbet = gamln(&a)+gamln(&b)-gsumln(&a,&b); + return dlnbet; +S30: + w = 0.0e0; + if(b < 8.0e0) goto S60; + dlnbet = gamln(&a)+algdiv(&a,&b); + return dlnbet; +S40: +/* + REDUCTION OF A WHEN B .LE. 1000 +*/ + if(b > 1000.0e0) goto S80; + n = a-1.0e0; + w = 1.0e0; + for(i=1; i<=n; i++) { + a -= 1.0e0; + h = a/b; + w *= (h/(1.0e0+h)); + } + w = log(w); + if(b < 8.0e0) goto S60; + dlnbet = w+gamln(&a)+algdiv(&a,&b); + return dlnbet; +S60: +/* + REDUCTION OF B WHEN B .LT. 8 +*/ + n = b-1.0e0; + z = 1.0e0; + for(i=1; i<=n; i++) { + b -= 1.0e0; + z *= (b/(a+b)); + } + dlnbet = w+log(z)+(gamln(&a)+(gamln(&b)-gsumln(&a,&b))); + return dlnbet; +S80: +/* + REDUCTION OF A WHEN B .GT. 1000 +*/ + n = a-1.0e0; + w = 1.0e0; + for(i=1; i<=n; i++) { + a -= 1.0e0; + w *= (a/(1.0e0+a/b)); + } + dlnbet = log(w)-(double)n*log(b)+(gamln(&a)+algdiv(&a,&b)); + return dlnbet; +S100: +/* +----------------------------------------------------------------------- + PROCEDURE WHEN A .GE. 8 +----------------------------------------------------------------------- +*/ + w = bcorr(&a,&b); + h = a/b; + c = h/(1.0e0+h); + u = -((a-0.5e0)*log(c)); + v = b*alnrel(&h); + if(u <= v) goto S110; + dlnbet = -(0.5e0*log(b))+e+w-v-u; + return dlnbet; +S110: + dlnbet = -(0.5e0*log(b))+e+w-u-v; + return dlnbet; +} /* END */ + +/***=====================================================================***/ +static double dlngam(double *a) +/* +********************************************************************** + + double dlngam(double *a) + Double precision LN of the GAMma function + + + Function + + + Returns the natural logarithm of GAMMA(X). + + + Arguments + + + X --> value at which scaled log gamma is to be returned + X is DOUBLE PRECISION + + + Method + + + Renames GAMLN from: + DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant + Digit Computation of the Incomplete Beta Function Ratios. ACM + Trans. Math. Softw. 18 (1993), 360-373. + +********************************************************************** +----------------------------------------------------------------------- + EVALUATION OF LN(GAMMA(A)) FOR POSITIVE A +----------------------------------------------------------------------- + WRITTEN BY ALFRED H. MORRIS + NAVAL SURFACE WARFARE CENTER + DAHLGREN, VIRGINIA +-------------------------- + D = 0.5*(LN(2*PI) - 1) +-------------------------- +*/ +{ +static double c0 = .833333333333333e-01; +static double c1 = -.277777777760991e-02; +static double c2 = .793650666825390e-03; +static double c3 = -.595202931351870e-03; +static double c4 = .837308034031215e-03; +static double c5 = -.165322962780713e-02; +static double d = .418938533204673e0; +static double dlngam,t,w; +static int i,n; +static double T1; +/* + .. + .. Executable Statements .. +*/ + if(*a > 0.8e0) goto S10; + dlngam = gamln1(a)-log(*a); + return dlngam; +S10: + if(*a > 2.25e0) goto S20; + t = *a-0.5e0-0.5e0; + dlngam = gamln1(&t); + return dlngam; +S20: + if(*a >= 10.0e0) goto S40; + n = *a-1.25e0; + t = *a; + w = 1.0e0; + for(i=1; i<=n; i++) { + t -= 1.0e0; + w = t*w; + } + T1 = t-1.0e0; + dlngam = gamln1(&T1)+log(w); + return dlngam; +S40: + t = pow(1.0e0/ *a,2.0); + w = (((((c5*t+c4)*t+c3)*t+c2)*t+c1)*t+c0)/ *a; + dlngam = d+w+(*a-0.5e0)*(log(*a)-1.0e0); + return dlngam; +} /* END */ + +/***=====================================================================***/ +static double dstrem(double *z) +{ +/* +********************************************************************** + double dstrem(double *z) + Double precision Sterling Remainder + Function + Returns Log(Gamma(Z)) - Sterling(Z) where Sterling(Z) is + Sterling's Approximation to Log(Gamma(Z)) + Sterling(Z) = LOG( SQRT( 2*PI ) ) + ( Z-0.5 ) * LOG( Z ) - Z + Arguments + Z --> Value at which Sterling remainder calculated + Must be positive. + DOUBLE PRECISION Z + Method + If Z >= 6 uses 9 terms of series in Bernoulli numbers + (Values calculated using Maple) + Otherwise computes difference explicitly +********************************************************************** +*/ +#define hln2pi 0.91893853320467274178e0 +#define ncoef 10 +static double coef[ncoef] = { + 0.0e0,0.0833333333333333333333333333333e0, + -0.00277777777777777777777777777778e0,0.000793650793650793650793650793651e0, + -0.000595238095238095238095238095238e0, + 0.000841750841750841750841750841751e0,-0.00191752691752691752691752691753e0, + 0.00641025641025641025641025641026e0,-0.0295506535947712418300653594771e0, + 0.179644372368830573164938490016e0 +}; +static int K1 = 10; +static double dstrem,sterl,T2; +/* + .. + .. Executable Statements .. +*/ +/* + For information, here are the next 11 coefficients of the + remainder term in Sterling's formula + -1.39243221690590111642743221691 + 13.4028640441683919944789510007 + -156.848284626002017306365132452 + 2193.10333333333333333333333333 + -36108.7712537249893571732652192 + 691472.268851313067108395250776 + -0.152382215394074161922833649589D8 + 0.382900751391414141414141414141D9 + -0.108822660357843910890151491655D11 + 0.347320283765002252252252252252D12 + -0.123696021422692744542517103493D14 +*/ + if(*z <= 0.0e0){ ftnstop("nonpositive argument in DSTREM"); return 66.6; } + if(!(*z > 6.0e0)) goto S10; + T2 = 1.0e0/pow(*z,2.0); + dstrem = devlpl(coef,&K1,&T2)**z; + goto S20; +S10: + sterl = hln2pi+(*z-0.5e0)*log(*z)-*z; + dstrem = dlngam(z)-sterl; +S20: + return dstrem; +#undef hln2pi +#undef ncoef +} /* END */ + +/***=====================================================================***/ +static double dt1(double *p,double *q,double *df) +/* +********************************************************************** + + double dt1(double *p,double *q,double *df) + Double precision Initalize Approximation to + INVerse of the cumulative T distribution + + + Function + + + Returns the inverse of the T distribution function, i.e., + the integral from 0 to INVT of the T density is P. This is an + initial approximation + + + Arguments + + + P --> The p-value whose inverse from the T distribution is + desired. + P is DOUBLE PRECISION + + Q --> 1-P. + Q is DOUBLE PRECISION + + DF --> Degrees of freedom of the T distribution. + DF is DOUBLE PRECISION + +********************************************************************** +*/ +{ +static double coef[4][5] = { + 1.0e0,1.0e0,0.0e0,0.0e0,0.0e0,3.0e0,16.0e0,5.0e0,0.0e0,0.0e0,-15.0e0,17.0e0, + 19.0e0,3.0e0,0.0e0,-945.0e0,-1920.0e0,1482.0e0,776.0e0,79.0e0 +}; +static double denom[4] = { + 4.0e0,96.0e0,384.0e0,92160.0e0 +}; +static int ideg[4] = { + 2,3,4,5 +}; +static double dt1,denpow,sum,term,x,xp,xx; +static int i; +/* + .. + .. Executable Statements .. +*/ + x = fabs(dinvnr(p,q)); + xx = x*x; + sum = x; + denpow = 1.0e0; + for(i=0; i<4; i++) { + term = devlpl(&coef[i][0],&ideg[i],&xx)*x; + denpow *= *df; + sum += (term/(denpow*denom[i])); + } + if(!(*p >= 0.5e0)) goto S20; + xp = sum; + goto S30; +S20: + xp = -sum; +S30: + dt1 = xp; + return dt1; +} /* END */ + +/***=====================================================================***/ +static void E0001(int IENTRY,int *status,double *x,double *fx, + double *xlo,double *xhi,unsigned long *qleft, + unsigned long *qhi,double *zabstl,double *zreltl, + double *zxhi,double *zxlo) +{ +#define ftol(zx) (0.5e0*fifdmax1(abstol,reltol*fabs((zx)))) +static double a,abstol,b,c,d,fa,fb,fc,fd,fda,fdb,m,mb,p,q,reltol,tol,w,xxhi,xxlo; +static int ext,i99999; +static unsigned long first,qrzero; + switch(IENTRY){case 0: goto DZROR; case 1: goto DSTZR;} +DZROR: + if(*status > 0) goto S280; + *xlo = xxlo; + *xhi = xxhi; + b = *x = *xlo; +/* + GET-FUNCTION-VALUE +*/ + i99999 = 1; + goto S270; +S10: + fb = *fx; + *xlo = *xhi; + a = *x = *xlo; +/* + GET-FUNCTION-VALUE +*/ + i99999 = 2; + goto S270; +S20: +/* + Check that F(ZXLO) < 0 < F(ZXHI) or + F(ZXLO) > 0 > F(ZXHI) +*/ + if(!(fb < 0.0e0)) goto S40; + if(!(*fx < 0.0e0)) goto S30; + *status = -1; + *qleft = *fx < fb; + *qhi = 0; + return; +S40: +S30: + if(!(fb > 0.0e0)) goto S60; + if(!(*fx > 0.0e0)) goto S50; + *status = -1; + *qleft = *fx > fb; + *qhi = 1; + return; +S60: +S50: + fa = *fx; + first = 1; +S70: + c = a; + fc = fa; + ext = 0; +S80: + if(!(fabs(fc) < fabs(fb))) goto S100; + if(!(c != a)) goto S90; + d = a; + fd = fa; +S90: + a = b; + fa = fb; + *xlo = c; + b = *xlo; + fb = fc; + c = a; + fc = fa; +S100: + tol = ftol(*xlo); + m = (c+b)*.5e0; + mb = m-b; + if(!(fabs(mb) > tol)) goto S240; + if(!(ext > 3)) goto S110; + w = mb; + goto S190; +S110: + tol = fifdsign(tol,mb); + p = (b-a)*fb; + if(!first) goto S120; + q = fa-fb; + first = 0; + goto S130; +S120: + fdb = (fd-fb)/(d-b); + fda = (fd-fa)/(d-a); + p = fda*p; + q = fdb*fa-fda*fb; +S130: + if(!(p < 0.0e0)) goto S140; + p = -p; + q = -q; +S140: + if(ext == 3) p *= 2.0e0; + if(!(p*1.0e0 == 0.0e0 || p <= q*tol)) goto S150; + w = tol; + goto S180; +S150: + if(!(p < mb*q)) goto S160; + w = p/q; + goto S170; +S160: + w = mb; +S190: +S180: +S170: + d = a; + fd = fa; + a = b; + fa = fb; + b += w; + *xlo = b; + *x = *xlo; +/* + GET-FUNCTION-VALUE +*/ + i99999 = 3; + goto S270; +S200: + fb = *fx; + if(!(fc*fb >= 0.0e0)) goto S210; + goto S70; +S210: + if(!(w == mb)) goto S220; + ext = 0; + goto S230; +S220: + ext += 1; +S230: + goto S80; +S240: + *xhi = c; + qrzero = fc >= 0.0e0 && fb <= 0.0e0 || fc < 0.0e0 && fb >= 0.0e0; + if(!qrzero) goto S250; + *status = 0; + goto S260; +S250: + *status = -1; +S260: + return; +DSTZR: + xxlo = *zxlo; + xxhi = *zxhi; + abstol = *zabstl; + reltol = *zreltl; + return; +S270: +/* + TO GET-FUNCTION-VALUE +*/ + *status = 1; + return; +S280: + switch((int)i99999){case 1: goto S10;case 2: goto S20;case 3: goto S200; + default: break;} +#undef ftol +} /* END */ + +/***=====================================================================***/ +static void dzror(int *status,double *x,double *fx,double *xlo, + double *xhi,unsigned long *qleft,unsigned long *qhi) +/* +********************************************************************** + + void dzror(int *status,double *x,double *fx,double *xlo, + double *xhi,unsigned long *qleft,unsigned long *qhi) + + Double precision ZeRo of a function -- Reverse Communication + + + Function + + + Performs the zero finding. STZROR must have been called before + this routine in order to set its parameters. + + + Arguments + + + STATUS <--> At the beginning of a zero finding problem, STATUS + should be set to 0 and ZROR invoked. (The value + of other parameters will be ignored on this call.) + + When ZROR needs the function evaluated, it will set + STATUS to 1 and return. The value of the function + should be set in FX and ZROR again called without + changing any of its other parameters. + + When ZROR has finished without error, it will return + with STATUS 0. In that case (XLO,XHI) bound the answe + + If ZROR finds an error (which implies that F(XLO)-Y an + F(XHI)-Y have the same sign, it returns STATUS -1. In + this case, XLO and XHI are undefined. + INTEGER STATUS + + X <-- The value of X at which F(X) is to be evaluated. + DOUBLE PRECISION X + + FX --> The value of F(X) calculated when ZROR returns with + STATUS = 1. + DOUBLE PRECISION FX + + XLO <-- When ZROR returns with STATUS = 0, XLO bounds the + inverval in X containing the solution below. + DOUBLE PRECISION XLO + + XHI <-- When ZROR returns with STATUS = 0, XHI bounds the + inverval in X containing the solution above. + DOUBLE PRECISION XHI + + QLEFT <-- .TRUE. if the stepping search terminated unsucessfully + at XLO. If it is .FALSE. the search terminated + unsucessfully at XHI. + QLEFT is LOGICAL + + QHI <-- .TRUE. if F(X) .GT. Y at the termination of the + search and .FALSE. if F(X) .LT. Y at the + termination of the search. + QHI is LOGICAL + +********************************************************************** +*/ +{ + E0001(0,status,x,fx,xlo,xhi,qleft,qhi,NULL,NULL,NULL,NULL); +} /* END */ + +/***=====================================================================***/ +static void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl) +/* +********************************************************************** + void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl) + Double precision SeT ZeRo finder - Reverse communication version + Function + Sets quantities needed by ZROR. The function of ZROR + and the quantities set is given here. + Concise Description - Given a function F + find XLO such that F(XLO) = 0. + More Precise Description - + Input condition. F is a double precision function of a single + double precision argument and XLO and XHI are such that + F(XLO)*F(XHI) .LE. 0.0 + If the input condition is met, QRZERO returns .TRUE. + and output values of XLO and XHI satisfy the following + F(XLO)*F(XHI) .LE. 0. + ABS(F(XLO) .LE. ABS(F(XHI) + ABS(XLO-XHI) .LE. TOL(X) + where + TOL(X) = MAX(ABSTOL,RELTOL*ABS(X)) + If this algorithm does not find XLO and XHI satisfying + these conditions then QRZERO returns .FALSE. This + implies that the input condition was not met. + Arguments + XLO --> The left endpoint of the interval to be + searched for a solution. + XLO is DOUBLE PRECISION + XHI --> The right endpoint of the interval to be + for a solution. + XHI is DOUBLE PRECISION + ABSTOL, RELTOL --> Two numbers that determine the accuracy + of the solution. See function for a + precise definition. + ABSTOL is DOUBLE PRECISION + RELTOL is DOUBLE PRECISION + Method + Algorithm R of the paper 'Two Efficient Algorithms with + Guaranteed Convergence for Finding a Zero of a Function' + by J. C. P. Bus and T. J. Dekker in ACM Transactions on + Mathematical Software, Volume 1, no. 4 page 330 + (Dec. '75) is employed to find the zero of F(X)-Y. +********************************************************************** +*/ +{ + E0001(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,zabstl,zreltl,zxhi,zxlo); +} /* END */ + +/***=====================================================================***/ +static double erf1(double *x) +/* +----------------------------------------------------------------------- + EVALUATION OF THE REAL ERROR FUNCTION +----------------------------------------------------------------------- +*/ +{ +static double c = .564189583547756e0; +static double a[5] = { + .771058495001320e-04,-.133733772997339e-02,.323076579225834e-01, + .479137145607681e-01,.128379167095513e+00 +}; +static double b[3] = { + .301048631703895e-02,.538971687740286e-01,.375795757275549e+00 +}; +static double p[8] = { + -1.36864857382717e-07,5.64195517478974e-01,7.21175825088309e+00, + 4.31622272220567e+01,1.52989285046940e+02,3.39320816734344e+02, + 4.51918953711873e+02,3.00459261020162e+02 +}; +static double q[8] = { + 1.00000000000000e+00,1.27827273196294e+01,7.70001529352295e+01, + 2.77585444743988e+02,6.38980264465631e+02,9.31354094850610e+02, + 7.90950925327898e+02,3.00459260956983e+02 +}; +static double r[5] = { + 2.10144126479064e+00,2.62370141675169e+01,2.13688200555087e+01, + 4.65807828718470e+00,2.82094791773523e-01 +}; +static double s[4] = { + 9.41537750555460e+01,1.87114811799590e+02,9.90191814623914e+01, + 1.80124575948747e+01 +}; +static double erf1,ax,bot,t,top,x2; +/* + .. + .. Executable Statements .. +*/ + ax = fabs(*x); + if(ax > 0.5e0) goto S10; + t = *x**x; + top = (((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4]+1.0e0; + bot = ((b[0]*t+b[1])*t+b[2])*t+1.0e0; + erf1 = *x*(top/bot); + return erf1; +S10: + if(ax > 4.0e0) goto S20; + top = ((((((p[0]*ax+p[1])*ax+p[2])*ax+p[3])*ax+p[4])*ax+p[5])*ax+p[6])*ax+p[ + 7]; + bot = ((((((q[0]*ax+q[1])*ax+q[2])*ax+q[3])*ax+q[4])*ax+q[5])*ax+q[6])*ax+q[ + 7]; + erf1 = 0.5e0+(0.5e0-exp(-(*x**x))*top/bot); + if(*x < 0.0e0) erf1 = -erf1; + return erf1; +S20: + if(ax >= 5.8e0) goto S30; + x2 = *x**x; + t = 1.0e0/x2; + top = (((r[0]*t+r[1])*t+r[2])*t+r[3])*t+r[4]; + bot = (((s[0]*t+s[1])*t+s[2])*t+s[3])*t+1.0e0; + erf1 = (c-top/(x2*bot))/ax; + erf1 = 0.5e0+(0.5e0-exp(-x2)*erf1); + if(*x < 0.0e0) erf1 = -erf1; + return erf1; +S30: + erf1 = fifdsign(1.0e0,*x); + return erf1; +} /* END */ + +/***=====================================================================***/ +static double erfc1(int *ind,double *x) +/* +----------------------------------------------------------------------- + EVALUATION OF THE COMPLEMENTARY ERROR FUNCTION + + ERFC1(IND,X) = ERFC(X) IF IND = 0 + ERFC1(IND,X) = EXP(X*X)*ERFC(X) OTHERWISE +----------------------------------------------------------------------- +*/ +{ +static double c = .564189583547756e0; +static double a[5] = { + .771058495001320e-04,-.133733772997339e-02,.323076579225834e-01, + .479137145607681e-01,.128379167095513e+00 +}; +static double b[3] = { + .301048631703895e-02,.538971687740286e-01,.375795757275549e+00 +}; +static double p[8] = { + -1.36864857382717e-07,5.64195517478974e-01,7.21175825088309e+00, + 4.31622272220567e+01,1.52989285046940e+02,3.39320816734344e+02, + 4.51918953711873e+02,3.00459261020162e+02 +}; +static double q[8] = { + 1.00000000000000e+00,1.27827273196294e+01,7.70001529352295e+01, + 2.77585444743988e+02,6.38980264465631e+02,9.31354094850610e+02, + 7.90950925327898e+02,3.00459260956983e+02 +}; +static double r[5] = { + 2.10144126479064e+00,2.62370141675169e+01,2.13688200555087e+01, + 4.65807828718470e+00,2.82094791773523e-01 +}; +static double s[4] = { + 9.41537750555460e+01,1.87114811799590e+02,9.90191814623914e+01, + 1.80124575948747e+01 +}; +static int K1 = 1; +static double erfc1,ax,bot,e,t,top,w; +/* + .. + .. Executable Statements .. +*/ +/* + ABS(X) .LE. 0.5 +*/ + ax = fabs(*x); + if(ax > 0.5e0) goto S10; + t = *x**x; + top = (((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4]+1.0e0; + bot = ((b[0]*t+b[1])*t+b[2])*t+1.0e0; + erfc1 = 0.5e0+(0.5e0-*x*(top/bot)); + if(*ind != 0) erfc1 = exp(t)*erfc1; + return erfc1; +S10: +/* + 0.5 .LT. ABS(X) .LE. 4 +*/ + if(ax > 4.0e0) goto S20; + top = ((((((p[0]*ax+p[1])*ax+p[2])*ax+p[3])*ax+p[4])*ax+p[5])*ax+p[6])*ax+p[ + 7]; + bot = ((((((q[0]*ax+q[1])*ax+q[2])*ax+q[3])*ax+q[4])*ax+q[5])*ax+q[6])*ax+q[ + 7]; + erfc1 = top/bot; + goto S40; +S20: +/* + ABS(X) .GT. 4 +*/ + if(*x <= -5.6e0) goto S60; + if(*ind != 0) goto S30; + if(*x > 100.0e0) goto S70; + if(*x**x > -exparg(&K1)) goto S70; +S30: + t = pow(1.0e0/ *x,2.0); + top = (((r[0]*t+r[1])*t+r[2])*t+r[3])*t+r[4]; + bot = (((s[0]*t+s[1])*t+s[2])*t+s[3])*t+1.0e0; + erfc1 = (c-t*top/bot)/ax; +S40: +/* + FINAL ASSEMBLY +*/ + if(*ind == 0) goto S50; + if(*x < 0.0e0) erfc1 = 2.0e0*exp(*x**x)-erfc1; + return erfc1; +S50: + w = *x**x; + t = w; + e = w-t; + erfc1 = (0.5e0+(0.5e0-e))*exp(-t)*erfc1; + if(*x < 0.0e0) erfc1 = 2.0e0-erfc1; + return erfc1; +S60: +/* + LIMIT VALUE FOR LARGE NEGATIVE X +*/ + erfc1 = 2.0e0; + if(*ind != 0) erfc1 = 2.0e0*exp(*x**x); + return erfc1; +S70: +/* + LIMIT VALUE FOR LARGE POSITIVE X + WHEN IND = 0 +*/ + erfc1 = 0.0e0; + return erfc1; +} /* END */ + +/***=====================================================================***/ +static double esum(int *mu,double *x) +/* +----------------------------------------------------------------------- + EVALUATION OF EXP(MU + X) +----------------------------------------------------------------------- +*/ +{ +static double esum,w; +/* + .. + .. Executable Statements .. +*/ + if(*x > 0.0e0) goto S10; + if(*mu < 0) goto S20; + w = (double)*mu+*x; + if(w > 0.0e0) goto S20; + esum = exp(w); + return esum; +S10: + if(*mu > 0) goto S20; + w = (double)*mu+*x; + if(w < 0.0e0) goto S20; + esum = exp(w); + return esum; +S20: + w = *mu; + esum = exp(w)*exp(*x); + return esum; +} /* END */ + +/***=====================================================================***/ +static double exparg(int *l) +/* +-------------------------------------------------------------------- + IF L = 0 THEN EXPARG(L) = THE LARGEST POSITIVE W FOR WHICH + EXP(W) CAN BE COMPUTED. + + IF L IS NONZERO THEN EXPARG(L) = THE LARGEST NEGATIVE W FOR + WHICH THE COMPUTED VALUE OF EXP(W) IS NONZERO. + + NOTE... ONLY AN APPROXIMATE VALUE FOR EXPARG(L) IS NEEDED. +-------------------------------------------------------------------- +*/ +{ +static int K1 = 4; +static int K2 = 9; +static int K3 = 10; +static double exparg,lnb; +static int b,m; +/* + .. + .. Executable Statements .. +*/ + b = ipmpar(&K1); + if(b != 2) goto S10; + lnb = .69314718055995e0; + goto S40; +S10: + if(b != 8) goto S20; + lnb = 2.0794415416798e0; + goto S40; +S20: + if(b != 16) goto S30; + lnb = 2.7725887222398e0; + goto S40; +S30: + lnb = log((double)b); +S40: + if(*l == 0) goto S50; + m = ipmpar(&K2)-1; + exparg = 0.99999e0*((double)m*lnb); + return exparg; +S50: + m = ipmpar(&K3); + exparg = 0.99999e0*((double)m*lnb); + return exparg; +} /* END */ + +/***=====================================================================***/ +static double fpser(double *a,double *b,double *x,double *eps) +/* +----------------------------------------------------------------------- + + EVALUATION OF I (A,B) + X + + FOR B .LT. MIN(EPS,EPS*A) AND X .LE. 0.5. + +----------------------------------------------------------------------- + + SET FPSER = X**A +*/ +{ +static int K1 = 1; +static double fpser,an,c,s,t,tol; +/* + .. + .. Executable Statements .. +*/ + fpser = 1.0e0; + if(*a <= 1.e-3**eps) goto S10; + fpser = 0.0e0; + t = *a*log(*x); + if(t < exparg(&K1)) return fpser; + fpser = exp(t); +S10: +/* + NOTE THAT 1/B(A,B) = B +*/ + fpser = *b/ *a*fpser; + tol = *eps/ *a; + an = *a+1.0e0; + t = *x; + s = t/an; +S20: + an += 1.0e0; + t = *x*t; + c = t/an; + s += c; + if(fabs(c) > tol) goto S20; + fpser *= (1.0e0+*a*s); + return fpser; +} /* END */ + +/***=====================================================================***/ +static double gam1(double *a) +/* + ------------------------------------------------------------------ + COMPUTATION OF 1/GAMMA(A+1) - 1 FOR -0.5 .LE. A .LE. 1.5 + ------------------------------------------------------------------ +*/ +{ +static double s1 = .273076135303957e+00; +static double s2 = .559398236957378e-01; +static double p[7] = { + .577215664901533e+00,-.409078193005776e+00,-.230975380857675e+00, + .597275330452234e-01,.766968181649490e-02,-.514889771323592e-02, + .589597428611429e-03 +}; +static double q[5] = { + .100000000000000e+01,.427569613095214e+00,.158451672430138e+00, + .261132021441447e-01,.423244297896961e-02 +}; +static double r[9] = { + -.422784335098468e+00,-.771330383816272e+00,-.244757765222226e+00, + .118378989872749e+00,.930357293360349e-03,-.118290993445146e-01, + .223047661158249e-02,.266505979058923e-03,-.132674909766242e-03 +}; +static double gam1,bot,d,t,top,w,T1; +/* + .. + .. Executable Statements .. +*/ + t = *a; + d = *a-0.5e0; + if(d > 0.0e0) t = d-0.5e0; + T1 = t; + if(T1 < 0) goto S40; + else if(T1 == 0) goto S10; + else goto S20; +S10: + gam1 = 0.0e0; + return gam1; +S20: + top = (((((p[6]*t+p[5])*t+p[4])*t+p[3])*t+p[2])*t+p[1])*t+p[0]; + bot = (((q[4]*t+q[3])*t+q[2])*t+q[1])*t+1.0e0; + w = top/bot; + if(d > 0.0e0) goto S30; + gam1 = *a*w; + return gam1; +S30: + gam1 = t/ *a*(w-0.5e0-0.5e0); + return gam1; +S40: + top = (((((((r[8]*t+r[7])*t+r[6])*t+r[5])*t+r[4])*t+r[3])*t+r[2])*t+r[1])*t+ + r[0]; + bot = (s2*t+s1)*t+1.0e0; + w = top/bot; + if(d > 0.0e0) goto S50; + gam1 = *a*(w+0.5e0+0.5e0); + return gam1; +S50: + gam1 = t*w/ *a; + return gam1; +} /* END */ + +/***=====================================================================***/ +static void gaminv(double *a,double *x,double *x0,double *p,double *q, + int *ierr) +/* + ---------------------------------------------------------------------- + INVERSE INCOMPLETE GAMMA RATIO FUNCTION + + GIVEN POSITIVE A, AND NONEGATIVE P AND Q WHERE P + Q = 1. + THEN X IS COMPUTED WHERE P(A,X) = P AND Q(A,X) = Q. SCHRODER + ITERATION IS EMPLOYED. THE ROUTINE ATTEMPTS TO COMPUTE X + TO 10 SIGNIFICANT DIGITS IF THIS IS POSSIBLE FOR THE + PARTICULAR COMPUTER ARITHMETIC BEING USED. + + ------------ + + X IS A VARIABLE. IF P = 0 THEN X IS ASSIGNED THE VALUE 0, + AND IF Q = 0 THEN X IS SET TO THE LARGEST FLOATING POINT + NUMBER AVAILABLE. OTHERWISE, GAMINV ATTEMPTS TO OBTAIN + A SOLUTION FOR P(A,X) = P AND Q(A,X) = Q. IF THE ROUTINE + IS SUCCESSFUL THEN THE SOLUTION IS STORED IN X. + + X0 IS AN OPTIONAL INITIAL APPROXIMATION FOR X. IF THE USER + DOES NOT WISH TO SUPPLY AN INITIAL APPROXIMATION, THEN SET + X0 .LE. 0. + + IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. + WHEN THE ROUTINE TERMINATES, IERR HAS ONE OF THE FOLLOWING + VALUES ... + + IERR = 0 THE SOLUTION WAS OBTAINED. ITERATION WAS + NOT USED. + IERR.GT.0 THE SOLUTION WAS OBTAINED. IERR ITERATIONS + WERE PERFORMED. + IERR = -2 (INPUT ERROR) A .LE. 0 + IERR = -3 NO SOLUTION WAS OBTAINED. THE RATIO Q/A + IS TOO LARGE. + IERR = -4 (INPUT ERROR) P + Q .NE. 1 + IERR = -6 20 ITERATIONS WERE PERFORMED. THE MOST + RECENT VALUE OBTAINED FOR X IS GIVEN. + THIS CANNOT OCCUR IF X0 .LE. 0. + IERR = -7 ITERATION FAILED. NO VALUE IS GIVEN FOR X. + THIS MAY OCCUR WHEN X IS APPROXIMATELY 0. + IERR = -8 A VALUE FOR X HAS BEEN OBTAINED, BUT THE + ROUTINE IS NOT CERTAIN OF ITS ACCURACY. + ITERATION CANNOT BE PERFORMED IN THIS + CASE. IF X0 .LE. 0, THIS CAN OCCUR ONLY + WHEN P OR Q IS APPROXIMATELY 0. IF X0 IS + POSITIVE THEN THIS CAN OCCUR WHEN A IS + EXCEEDINGLY CLOSE TO X AND A IS EXTREMELY + LARGE (SAY A .GE. 1.E20). + ---------------------------------------------------------------------- + WRITTEN BY ALFRED H. MORRIS, JR. + NAVAL SURFACE WEAPONS CENTER + DAHLGREN, VIRGINIA + ------------------- +*/ +{ +static double a0 = 3.31125922108741e0; +static double a1 = 11.6616720288968e0; +static double a2 = 4.28342155967104e0; +static double a3 = .213623493715853e0; +static double b1 = 6.61053765625462e0; +static double b2 = 6.40691597760039e0; +static double b3 = 1.27364489782223e0; +static double b4 = .036117081018842e0; +static double c = .577215664901533e0; +static double ln10 = 2.302585e0; +static double tol = 1.e-5; +static double amin[2] = { + 500.0e0,100.0e0 +}; +static double bmin[2] = { + 1.e-28,1.e-13 +}; +static double dmin[2] = { + 1.e-06,1.e-04 +}; +static double emin[2] = { + 2.e-03,6.e-03 +}; +static double eps0[2] = { + 1.e-10,1.e-08 +}; +static int K1 = 1; +static int K2 = 2; +static int K3 = 3; +static int K8 = 0; +static double am1,amax,ap1,ap2,ap3,apn,b,c1,c2,c3,c4,c5,d,e,e2,eps,g,h,pn,qg,qn, + r,rta,s,s2,sum,t,u,w,xmax,xmin,xn,y,z; +static int iop; +static double T4,T5,T6,T7,T9; +/* + .. + .. Executable Statements .. +*/ +/* + ****** E, XMIN, AND XMAX ARE MACHINE DEPENDENT CONSTANTS. + E IS THE SMALLEST NUMBER FOR WHICH 1.0 + E .GT. 1.0. + XMIN IS THE SMALLEST POSITIVE NUMBER AND XMAX IS THE + LARGEST POSITIVE NUMBER. +*/ + e = spmpar(&K1); + xmin = spmpar(&K2); + xmax = spmpar(&K3); + *x = 0.0e0; + if(*a <= 0.0e0) goto S300; + t = *p+*q-1.e0; + if(fabs(t) > e) goto S320; + *ierr = 0; + if(*p == 0.0e0) return; + if(*q == 0.0e0) goto S270; + if(*a == 1.0e0) goto S280; + e2 = 2.0e0*e; + amax = 0.4e-10/(e*e); + iop = 1; + if(e > 1.e-10) iop = 2; + eps = eps0[iop-1]; + xn = *x0; + if(*x0 > 0.0e0) goto S160; +/* + SELECTION OF THE INITIAL APPROXIMATION XN OF X + WHEN A .LT. 1 +*/ + if(*a > 1.0e0) goto S80; + T4 = *a+1.0e0; + g = Xgamm(&T4); + qg = *q*g; + if(qg == 0.0e0) goto S360; + b = qg/ *a; + if(qg > 0.6e0**a) goto S40; + if(*a >= 0.30e0 || b < 0.35e0) goto S10; + t = exp(-(b+c)); + u = t*exp(t); + xn = t*exp(u); + goto S160; +S10: + if(b >= 0.45e0) goto S40; + if(b == 0.0e0) goto S360; + y = -log(b); + s = 0.5e0+(0.5e0-*a); + z = log(y); + t = y-s*z; + if(b < 0.15e0) goto S20; + xn = y-s*log(t)-log(1.0e0+s/(t+1.0e0)); + goto S220; +S20: + if(b <= 0.01e0) goto S30; + u = ((t+2.0e0*(3.0e0-*a))*t+(2.0e0-*a)*(3.0e0-*a))/((t+(5.0e0-*a))*t+2.0e0); + xn = y-s*log(t)-log(u); + goto S220; +S30: + c1 = -(s*z); + c2 = -(s*(1.0e0+c1)); + c3 = s*((0.5e0*c1+(2.0e0-*a))*c1+(2.5e0-1.5e0**a)); + c4 = -(s*(((c1/3.0e0+(2.5e0-1.5e0**a))*c1+((*a-6.0e0)**a+7.0e0))*c1+( + (11.0e0**a-46.0)**a+47.0e0)/6.0e0)); + c5 = -(s*((((-(c1/4.0e0)+(11.0e0**a-17.0e0)/6.0e0)*c1+((-(3.0e0**a)+13.0e0)* + *a-13.0e0))*c1+0.5e0*(((2.0e0**a-25.0e0)**a+72.0e0)**a-61.0e0))*c1+(( + (25.0e0**a-195.0e0)**a+477.0e0)**a-379.0e0)/12.0e0)); + xn = (((c5/y+c4)/y+c3)/y+c2)/y+c1+y; + if(*a > 1.0e0) goto S220; + if(b > bmin[iop-1]) goto S220; + *x = xn; + return; +S40: + if(b**q > 1.e-8) goto S50; + xn = exp(-(*q/ *a+c)); + goto S70; +S50: + if(*p <= 0.9e0) goto S60; + T5 = -*q; + xn = exp((alnrel(&T5)+gamln1(a))/ *a); + goto S70; +S60: + xn = exp(log(*p*g)/ *a); +S70: + if(xn == 0.0e0) goto S310; + t = 0.5e0+(0.5e0-xn/(*a+1.0e0)); + xn /= t; + goto S160; +S80: +/* + SELECTION OF THE INITIAL APPROXIMATION XN OF X + WHEN A .GT. 1 +*/ + if(*q <= 0.5e0) goto S90; + w = log(*p); + goto S100; +S90: + w = log(*q); +S100: + t = sqrt(-(2.0e0*w)); + s = t-(((a3*t+a2)*t+a1)*t+a0)/((((b4*t+b3)*t+b2)*t+b1)*t+1.0e0); + if(*q > 0.5e0) s = -s; + rta = sqrt(*a); + s2 = s*s; + xn = *a+s*rta+(s2-1.0e0)/3.0e0+s*(s2-7.0e0)/(36.0e0*rta)-((3.0e0*s2+7.0e0)* + s2-16.0e0)/(810.0e0**a)+s*((9.0e0*s2+256.0e0)*s2-433.0e0)/(38880.0e0**a* + rta); + xn = fifdmax1(xn,0.0e0); + if(*a < amin[iop-1]) goto S110; + *x = xn; + d = 0.5e0+(0.5e0-*x/ *a); + if(fabs(d) <= dmin[iop-1]) return; +S110: + if(*p <= 0.5e0) goto S130; + if(xn < 3.0e0**a) goto S220; + y = -(w+gamln(a)); + d = fifdmax1(2.0e0,*a*(*a-1.0e0)); + if(y < ln10*d) goto S120; + s = 1.0e0-*a; + z = log(y); + goto S30; +S120: + t = *a-1.0e0; + T6 = -(t/(xn+1.0e0)); + xn = y+t*log(xn)-alnrel(&T6); + T7 = -(t/(xn+1.0e0)); + xn = y+t*log(xn)-alnrel(&T7); + goto S220; +S130: + ap1 = *a+1.0e0; + if(xn > 0.70e0*ap1) goto S170; + w += gamln(&ap1); + if(xn > 0.15e0*ap1) goto S140; + ap2 = *a+2.0e0; + ap3 = *a+3.0e0; + *x = exp((w+*x)/ *a); + *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2)))/ *a); + *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2)))/ *a); + *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2*(1.0e0+*x/ap3))))/ *a); + xn = *x; + if(xn > 1.e-2*ap1) goto S140; + if(xn <= emin[iop-1]*ap1) return; + goto S170; +S140: + apn = ap1; + t = xn/apn; + sum = 1.0e0+t; +S150: + apn += 1.0e0; + t *= (xn/apn); + sum += t; + if(t > 1.e-4) goto S150; + t = w-log(sum); + xn = exp((xn+t)/ *a); + xn *= (1.0e0-(*a*log(xn)-xn-t)/(*a-xn)); + goto S170; +S160: +/* + SCHRODER ITERATION USING P +*/ + if(*p > 0.5e0) goto S220; +S170: + if(*p <= 1.e10*xmin) goto S350; + am1 = *a-0.5e0-0.5e0; +S180: + if(*a <= amax) goto S190; + d = 0.5e0+(0.5e0-xn/ *a); + if(fabs(d) <= e2) goto S350; +S190: + if(*ierr >= 20) goto S330; + *ierr += 1; + gratio(a,&xn,&pn,&qn,&K8); + if(pn == 0.0e0 || qn == 0.0e0) goto S350; + r = rcomp(a,&xn); + if(r == 0.0e0) goto S350; + t = (pn-*p)/r; + w = 0.5e0*(am1-xn); + if(fabs(t) <= 0.1e0 && fabs(w*t) <= 0.1e0) goto S200; + *x = xn*(1.0e0-t); + if(*x <= 0.0e0) goto S340; + d = fabs(t); + goto S210; +S200: + h = t*(1.0e0+w*t); + *x = xn*(1.0e0-h); + if(*x <= 0.0e0) goto S340; + if(fabs(w) >= 1.0e0 && fabs(w)*t*t <= eps) return; + d = fabs(h); +S210: + xn = *x; + if(d > tol) goto S180; + if(d <= eps) return; + if(fabs(*p-pn) <= tol**p) return; + goto S180; +S220: +/* + SCHRODER ITERATION USING Q +*/ + if(*q <= 1.e10*xmin) goto S350; + am1 = *a-0.5e0-0.5e0; +S230: + if(*a <= amax) goto S240; + d = 0.5e0+(0.5e0-xn/ *a); + if(fabs(d) <= e2) goto S350; +S240: + if(*ierr >= 20) goto S330; + *ierr += 1; + gratio(a,&xn,&pn,&qn,&K8); + if(pn == 0.0e0 || qn == 0.0e0) goto S350; + r = rcomp(a,&xn); + if(r == 0.0e0) goto S350; + t = (*q-qn)/r; + w = 0.5e0*(am1-xn); + if(fabs(t) <= 0.1e0 && fabs(w*t) <= 0.1e0) goto S250; + *x = xn*(1.0e0-t); + if(*x <= 0.0e0) goto S340; + d = fabs(t); + goto S260; +S250: + h = t*(1.0e0+w*t); + *x = xn*(1.0e0-h); + if(*x <= 0.0e0) goto S340; + if(fabs(w) >= 1.0e0 && fabs(w)*t*t <= eps) return; + d = fabs(h); +S260: + xn = *x; + if(d > tol) goto S230; + if(d <= eps) return; + if(fabs(*q-qn) <= tol**q) return; + goto S230; +S270: +/* + SPECIAL CASES +*/ + *x = xmax; + return; +S280: + if(*q < 0.9e0) goto S290; + T9 = -*p; + *x = -alnrel(&T9); + return; +S290: + *x = -log(*q); + return; +S300: +/* + ERROR RETURN +*/ + *ierr = -2; + return; +S310: + *ierr = -3; + return; +S320: + *ierr = -4; + return; +S330: + *ierr = -6; + return; +S340: + *ierr = -7; + return; +S350: + *x = xn; + *ierr = -8; + return; +S360: + *x = xmax; + *ierr = -8; + return; +} /* END */ + +/***=====================================================================***/ +static double gamln(double *a) +/* +----------------------------------------------------------------------- + EVALUATION OF LN(GAMMA(A)) FOR POSITIVE A +----------------------------------------------------------------------- + WRITTEN BY ALFRED H. MORRIS + NAVAL SURFACE WARFARE CENTER + DAHLGREN, VIRGINIA +-------------------------- + D = 0.5*(LN(2*PI) - 1) +-------------------------- +*/ +{ +static double c0 = .833333333333333e-01; +static double c1 = -.277777777760991e-02; +static double c2 = .793650666825390e-03; +static double c3 = -.595202931351870e-03; +static double c4 = .837308034031215e-03; +static double c5 = -.165322962780713e-02; +static double d = .418938533204673e0; +static double gamln,t,w; +static int i,n; +static double T1; +/* + .. + .. Executable Statements .. +*/ + if(*a > 0.8e0) goto S10; + gamln = gamln1(a)-log(*a); + return gamln; +S10: + if(*a > 2.25e0) goto S20; + t = *a-0.5e0-0.5e0; + gamln = gamln1(&t); + return gamln; +S20: + if(*a >= 10.0e0) goto S40; + n = *a-1.25e0; + t = *a; + w = 1.0e0; + for(i=1; i<=n; i++) { + t -= 1.0e0; + w = t*w; + } + T1 = t-1.0e0; + gamln = gamln1(&T1)+log(w); + return gamln; +S40: + t = pow(1.0e0/ *a,2.0); + w = (((((c5*t+c4)*t+c3)*t+c2)*t+c1)*t+c0)/ *a; + gamln = d+w+(*a-0.5e0)*(log(*a)-1.0e0); + return gamln; +} /* END */ + +/***=====================================================================***/ +static double gamln1(double *a) +/* +----------------------------------------------------------------------- + EVALUATION OF LN(GAMMA(1 + A)) FOR -0.2 .LE. A .LE. 1.25 +----------------------------------------------------------------------- +*/ +{ +static double p0 = .577215664901533e+00; +static double p1 = .844203922187225e+00; +static double p2 = -.168860593646662e+00; +static double p3 = -.780427615533591e+00; +static double p4 = -.402055799310489e+00; +static double p5 = -.673562214325671e-01; +static double p6 = -.271935708322958e-02; +static double q1 = .288743195473681e+01; +static double q2 = .312755088914843e+01; +static double q3 = .156875193295039e+01; +static double q4 = .361951990101499e+00; +static double q5 = .325038868253937e-01; +static double q6 = .667465618796164e-03; +static double r0 = .422784335098467e+00; +static double r1 = .848044614534529e+00; +static double r2 = .565221050691933e+00; +static double r3 = .156513060486551e+00; +static double r4 = .170502484022650e-01; +static double r5 = .497958207639485e-03; +static double s1 = .124313399877507e+01; +static double s2 = .548042109832463e+00; +static double s3 = .101552187439830e+00; +static double s4 = .713309612391000e-02; +static double s5 = .116165475989616e-03; +static double gamln1,w,x; +/* + .. + .. Executable Statements .. +*/ + if(*a >= 0.6e0) goto S10; + w = ((((((p6**a+p5)**a+p4)**a+p3)**a+p2)**a+p1)**a+p0)/((((((q6**a+q5)**a+ + q4)**a+q3)**a+q2)**a+q1)**a+1.0e0); + gamln1 = -(*a*w); + return gamln1; +S10: + x = *a-0.5e0-0.5e0; + w = (((((r5*x+r4)*x+r3)*x+r2)*x+r1)*x+r0)/(((((s5*x+s4)*x+s3)*x+s2)*x+s1)*x + +1.0e0); + gamln1 = x*w; + return gamln1; +} /* END */ + +/***=====================================================================***/ +static double Xgamm(double *a) +/* +----------------------------------------------------------------------- + + EVALUATION OF THE GAMMA FUNCTION FOR REAL ARGUMENTS + + ----------- + + GAMMA(A) IS ASSIGNED THE VALUE 0 WHEN THE GAMMA FUNCTION CANNOT + BE COMPUTED. + +----------------------------------------------------------------------- + WRITTEN BY ALFRED H. MORRIS, JR. + NAVAL SURFACE WEAPONS CENTER + DAHLGREN, VIRGINIA +----------------------------------------------------------------------- +*/ +{ +static double d = .41893853320467274178e0; +static double pi = 3.1415926535898e0; +static double r1 = .820756370353826e-03; +static double r2 = -.595156336428591e-03; +static double r3 = .793650663183693e-03; +static double r4 = -.277777777770481e-02; +static double r5 = .833333333333333e-01; +static double p[7] = { + .539637273585445e-03,.261939260042690e-02,.204493667594920e-01, + .730981088720487e-01,.279648642639792e+00,.553413866010467e+00,1.0e0 +}; +static double q[7] = { + -.832979206704073e-03,.470059485860584e-02,.225211131035340e-01, + -.170458969313360e+00,-.567902761974940e-01,.113062953091122e+01,1.0e0 +}; +static int K2 = 3; +static int K3 = 0; +static double Xgamm,bot,g,lnx,s,t,top,w,x,z; +static int i,j,m,n,T1; +/* + .. + .. Executable Statements .. +*/ + Xgamm = 0.0e0; + x = *a; + if(fabs(*a) >= 15.0e0) goto S110; +/* +----------------------------------------------------------------------- + EVALUATION OF GAMMA(A) FOR ABS(A) .LT. 15 +----------------------------------------------------------------------- +*/ + t = 1.0e0; + m = fifidint(*a)-1; +/* + LET T BE THE PRODUCT OF A-J WHEN A .GE. 2 +*/ + T1 = m; + if(T1 < 0) goto S40; + else if(T1 == 0) goto S30; + else goto S10; +S10: + for(j=1; j<=m; j++) { + x -= 1.0e0; + t = x*t; + } +S30: + x -= 1.0e0; + goto S80; +S40: +/* + LET T BE THE PRODUCT OF A+J WHEN A .LT. 1 +*/ + t = *a; + if(*a > 0.0e0) goto S70; + m = -m-1; + if(m == 0) goto S60; + for(j=1; j<=m; j++) { + x += 1.0e0; + t = x*t; + } +S60: + x += (0.5e0+0.5e0); + t = x*t; + if(t == 0.0e0) return Xgamm; +S70: +/* + THE FOLLOWING CODE CHECKS IF 1/T CAN OVERFLOW. THIS + CODE MAY BE OMITTED IF DESIRED. +*/ + if(fabs(t) >= 1.e-30) goto S80; + if(fabs(t)*spmpar(&K2) <= 1.0001e0) return Xgamm; + Xgamm = 1.0e0/t; + return Xgamm; +S80: +/* + COMPUTE GAMMA(1 + X) FOR 0 .LE. X .LT. 1 +*/ + top = p[0]; + bot = q[0]; + for(i=1; i<7; i++) { + top = p[i]+x*top; + bot = q[i]+x*bot; + } + Xgamm = top/bot; +/* + TERMINATION +*/ + if(*a < 1.0e0) goto S100; + Xgamm *= t; + return Xgamm; +S100: + Xgamm /= t; + return Xgamm; +S110: +/* +----------------------------------------------------------------------- + EVALUATION OF GAMMA(A) FOR ABS(A) .GE. 15 +----------------------------------------------------------------------- +*/ + if(fabs(*a) >= 1.e3) return Xgamm; + if(*a > 0.0e0) goto S120; + x = -*a; + n = x; + t = x-(double)n; + if(t > 0.9e0) t = 1.0e0-t; + s = sin(pi*t)/pi; + if(fifmod(n,2) == 0) s = -s; + if(s == 0.0e0) return Xgamm; +S120: +/* + COMPUTE THE MODIFIED ASYMPTOTIC SUM +*/ + t = 1.0e0/(x*x); + g = ((((r1*t+r2)*t+r3)*t+r4)*t+r5)/x; +/* + ONE MAY REPLACE THE NEXT STATEMENT WITH LNX = ALOG(X) + BUT LESS ACCURACY WILL NORMALLY BE OBTAINED. +*/ + lnx = log(x); +/* + FINAL ASSEMBLY +*/ + z = x; + g = d+g+(z-0.5e0)*(lnx-1.e0); + w = g; + t = g-w; + if(w > 0.99999e0*exparg(&K3)) return Xgamm; + Xgamm = exp(w)*(1.0e0+t); + if(*a < 0.0e0) Xgamm = 1.0e0/(Xgamm*s)/x; + return Xgamm; +} /* END */ + +/***=====================================================================***/ +static void grat1(double *a,double *x,double *r,double *p,double *q, + double *eps) +{ +static int K2 = 0; +static double a2n,a2nm1,am0,an,an0,b2n,b2nm1,c,cma,g,h,j,l,sum,t,tol,w,z,T1,T3; +/* + .. + .. Executable Statements .. +*/ +/* +----------------------------------------------------------------------- + EVALUATION OF THE INCOMPLETE GAMMA RATIO FUNCTIONS + P(A,X) AND Q(A,X) + IT IS ASSUMED THAT A .LE. 1. EPS IS THE TOLERANCE TO BE USED. + THE INPUT ARGUMENT R HAS THE VALUE E**(-X)*X**A/GAMMA(A). +----------------------------------------------------------------------- +*/ + if(*a**x == 0.0e0) goto S120; + if(*a == 0.5e0) goto S100; + if(*x < 1.1e0) goto S10; + goto S60; +S10: +/* + TAYLOR SERIES FOR P(A,X)/X**A +*/ + an = 3.0e0; + c = *x; + sum = *x/(*a+3.0e0); + tol = 0.1e0**eps/(*a+1.0e0); +S20: + an += 1.0e0; + c = -(c*(*x/an)); + t = c/(*a+an); + sum += t; + if(fabs(t) > tol) goto S20; + j = *a**x*((sum/6.0e0-0.5e0/(*a+2.0e0))**x+1.0e0/(*a+1.0e0)); + z = *a*log(*x); + h = gam1(a); + g = 1.0e0+h; + if(*x < 0.25e0) goto S30; + if(*a < *x/2.59e0) goto S50; + goto S40; +S30: + if(z > -.13394e0) goto S50; +S40: + w = exp(z); + *p = w*g*(0.5e0+(0.5e0-j)); + *q = 0.5e0+(0.5e0-*p); + return; +S50: + l = rexp(&z); + w = 0.5e0+(0.5e0+l); + *q = (w*j-l)*g-h; + if(*q < 0.0e0) goto S90; + *p = 0.5e0+(0.5e0-*q); + return; +S60: +/* + CONTINUED FRACTION EXPANSION +*/ + a2nm1 = a2n = 1.0e0; + b2nm1 = *x; + b2n = *x+(1.0e0-*a); + c = 1.0e0; +S70: + a2nm1 = *x*a2n+c*a2nm1; + b2nm1 = *x*b2n+c*b2nm1; + am0 = a2nm1/b2nm1; + c += 1.0e0; + cma = c-*a; + a2n = a2nm1+cma*a2n; + b2n = b2nm1+cma*b2n; + an0 = a2n/b2n; + if(fabs(an0-am0) >= *eps*an0) goto S70; + *q = *r*an0; + *p = 0.5e0+(0.5e0-*q); + return; +S80: +/* + SPECIAL CASES +*/ + *p = 0.0e0; + *q = 1.0e0; + return; +S90: + *p = 1.0e0; + *q = 0.0e0; + return; +S100: + if(*x >= 0.25e0) goto S110; + T1 = sqrt(*x); + *p = erf1(&T1); + *q = 0.5e0+(0.5e0-*p); + return; +S110: + T3 = sqrt(*x); + *q = erfc1(&K2,&T3); + *p = 0.5e0+(0.5e0-*q); + return; +S120: + if(*x <= *a) goto S80; + goto S90; +} /* END */ + +/***=====================================================================***/ +static void gratio(double *a,double *x,double *ans,double *qans,int *ind) +/* + ---------------------------------------------------------------------- + EVALUATION OF THE INCOMPLETE GAMMA RATIO FUNCTIONS + P(A,X) AND Q(A,X) + + ---------- + + IT IS ASSUMED THAT A AND X ARE NONNEGATIVE, WHERE A AND X + ARE NOT BOTH 0. + + ANS AND QANS ARE VARIABLES. GRATIO ASSIGNS ANS THE VALUE + P(A,X) AND QANS THE VALUE Q(A,X). IND MAY BE ANY INTEGER. + IF IND = 0 THEN THE USER IS REQUESTING AS MUCH ACCURACY AS + POSSIBLE (UP TO 14 SIGNIFICANT DIGITS). OTHERWISE, IF + IND = 1 THEN ACCURACY IS REQUESTED TO WITHIN 1 UNIT OF THE + 6-TH SIGNIFICANT DIGIT, AND IF IND .NE. 0,1 THEN ACCURACY + IS REQUESTED TO WITHIN 1 UNIT OF THE 3RD SIGNIFICANT DIGIT. + + ERROR RETURN ... + ANS IS ASSIGNED THE VALUE 2 WHEN A OR X IS NEGATIVE, + WHEN A*X = 0, OR WHEN P(A,X) AND Q(A,X) ARE INDETERMINANT. + P(A,X) AND Q(A,X) ARE COMPUTATIONALLY INDETERMINANT WHEN + X IS EXCEEDINGLY CLOSE TO A AND A IS EXTREMELY LARGE. + ---------------------------------------------------------------------- + WRITTEN BY ALFRED H. MORRIS, JR. + NAVAL SURFACE WEAPONS CENTER + DAHLGREN, VIRGINIA + -------------------- +*/ +{ +static double alog10 = 2.30258509299405e0; +static double d10 = -.185185185185185e-02; +static double d20 = .413359788359788e-02; +static double d30 = .649434156378601e-03; +static double d40 = -.861888290916712e-03; +static double d50 = -.336798553366358e-03; +static double d60 = .531307936463992e-03; +static double d70 = .344367606892378e-03; +static double rt2pin = .398942280401433e0; +static double rtpi = 1.77245385090552e0; +static double third = .333333333333333e0; +static double acc0[3] = { + 5.e-15,5.e-7,5.e-4 +}; +static double big[3] = { + 20.0e0,14.0e0,10.0e0 +}; +static double d0[13] = { + .833333333333333e-01,-.148148148148148e-01,.115740740740741e-02, + .352733686067019e-03,-.178755144032922e-03,.391926317852244e-04, + -.218544851067999e-05,-.185406221071516e-05,.829671134095309e-06, + -.176659527368261e-06,.670785354340150e-08,.102618097842403e-07, + -.438203601845335e-08 +}; +static double d1[12] = { + -.347222222222222e-02,.264550264550265e-02,-.990226337448560e-03, + .205761316872428e-03,-.401877572016461e-06,-.180985503344900e-04, + .764916091608111e-05,-.161209008945634e-05,.464712780280743e-08, + .137863344691572e-06,-.575254560351770e-07,.119516285997781e-07 +}; +static double d2[10] = { + -.268132716049383e-02,.771604938271605e-03,.200938786008230e-05, + -.107366532263652e-03,.529234488291201e-04,-.127606351886187e-04, + .342357873409614e-07,.137219573090629e-05,-.629899213838006e-06, + .142806142060642e-06 +}; +static double d3[8] = { + .229472093621399e-03,-.469189494395256e-03,.267720632062839e-03, + -.756180167188398e-04,-.239650511386730e-06,.110826541153473e-04, + -.567495282699160e-05,.142309007324359e-05 +}; +static double d4[6] = { + .784039221720067e-03,-.299072480303190e-03,-.146384525788434e-05, + .664149821546512e-04,-.396836504717943e-04,.113757269706784e-04 +}; +static double d5[4] = { + -.697281375836586e-04,.277275324495939e-03,-.199325705161888e-03, + .679778047793721e-04 +}; +static double d6[2] = { + -.592166437353694e-03,.270878209671804e-03 +}; +static double e00[3] = { + .25e-3,.25e-1,.14e0 +}; +static double x00[3] = { + 31.0e0,17.0e0,9.7e0 +}; +static int K1 = 1; +static int K2 = 0; +static double a2n,a2nm1,acc,am0,amn,an,an0,apn,b2n,b2nm1,c,c0,c1,c2,c3,c4,c5,c6, + cma,e,e0,g,h,j,l,r,rta,rtx,s,sum,t,t1,tol,twoa,u,w,x0,y,z; +static int i,iop,m,max,n; +static double wk[20],T3; +static int T4,T5; +static double T6,T7; +/* + .. + .. Executable Statements .. +*/ +/* + -------------------- + ****** E IS A MACHINE DEPENDENT CONSTANT. E IS THE SMALLEST + FLOATING POINT NUMBER FOR WHICH 1.0 + E .GT. 1.0 . +*/ + e = spmpar(&K1); + if(*a < 0.0e0 || *x < 0.0e0) goto S430; + if(*a == 0.0e0 && *x == 0.0e0) goto S430; + if(*a**x == 0.0e0) goto S420; + iop = *ind+1; + if(iop != 1 && iop != 2) iop = 3; + acc = fifdmax1(acc0[iop-1],e); + e0 = e00[iop-1]; + x0 = x00[iop-1]; +/* + SELECT THE APPROPRIATE ALGORITHM +*/ + if(*a >= 1.0e0) goto S10; + if(*a == 0.5e0) goto S390; + if(*x < 1.1e0) goto S160; + t1 = *a*log(*x)-*x; + u = *a*exp(t1); + if(u == 0.0e0) goto S380; + r = u*(1.0e0+gam1(a)); + goto S250; +S10: + if(*a >= big[iop-1]) goto S30; + if(*a > *x || *x >= x0) goto S20; + twoa = *a+*a; + m = fifidint(twoa); + if(twoa != (double)m) goto S20; + i = m/2; + if(*a == (double)i) goto S210; + goto S220; +S20: + t1 = *a*log(*x)-*x; + r = exp(t1)/Xgamm(a); + goto S40; +S30: + l = *x/ *a; + if(l == 0.0e0) goto S370; + s = 0.5e0+(0.5e0-l); + z = rlog(&l); + if(z >= 700.0e0/ *a) goto S410; + y = *a*z; + rta = sqrt(*a); + if(fabs(s) <= e0/rta) goto S330; + if(fabs(s) <= 0.4e0) goto S270; + t = pow(1.0e0/ *a,2.0); + t1 = (((0.75e0*t-1.0e0)*t+3.5e0)*t-105.0e0)/(*a*1260.0e0); + t1 -= y; + r = rt2pin*rta*exp(t1); +S40: + if(r == 0.0e0) goto S420; + if(*x <= fifdmax1(*a,alog10)) goto S50; + if(*x < x0) goto S250; + goto S100; +S50: +/* + TAYLOR SERIES FOR P/R +*/ + apn = *a+1.0e0; + t = *x/apn; + wk[0] = t; + for(n=2; n<=20; n++) { + apn += 1.0e0; + t *= (*x/apn); + if(t <= 1.e-3) goto S70; + wk[n-1] = t; + } + n = 20; +S70: + sum = t; + tol = 0.5e0*acc; +S80: + apn += 1.0e0; + t *= (*x/apn); + sum += t; + if(t > tol) goto S80; + max = n-1; + for(m=1; m<=max; m++) { + n -= 1; + sum += wk[n-1]; + } + *ans = r/ *a*(1.0e0+sum); + *qans = 0.5e0+(0.5e0-*ans); + return; +S100: +/* + ASYMPTOTIC EXPANSION +*/ + amn = *a-1.0e0; + t = amn/ *x; + wk[0] = t; + for(n=2; n<=20; n++) { + amn -= 1.0e0; + t *= (amn/ *x); + if(fabs(t) <= 1.e-3) goto S120; + wk[n-1] = t; + } + n = 20; +S120: + sum = t; +S130: + if(fabs(t) <= acc) goto S140; + amn -= 1.0e0; + t *= (amn/ *x); + sum += t; + goto S130; +S140: + max = n-1; + for(m=1; m<=max; m++) { + n -= 1; + sum += wk[n-1]; + } + *qans = r/ *x*(1.0e0+sum); + *ans = 0.5e0+(0.5e0-*qans); + return; +S160: +/* + TAYLOR SERIES FOR P(A,X)/X**A +*/ + an = 3.0e0; + c = *x; + sum = *x/(*a+3.0e0); + tol = 3.0e0*acc/(*a+1.0e0); +S170: + an += 1.0e0; + c = -(c*(*x/an)); + t = c/(*a+an); + sum += t; + if(fabs(t) > tol) goto S170; + j = *a**x*((sum/6.0e0-0.5e0/(*a+2.0e0))**x+1.0e0/(*a+1.0e0)); + z = *a*log(*x); + h = gam1(a); + g = 1.0e0+h; + if(*x < 0.25e0) goto S180; + if(*a < *x/2.59e0) goto S200; + goto S190; +S180: + if(z > -.13394e0) goto S200; +S190: + w = exp(z); + *ans = w*g*(0.5e0+(0.5e0-j)); + *qans = 0.5e0+(0.5e0-*ans); + return; +S200: + l = rexp(&z); + w = 0.5e0+(0.5e0+l); + *qans = (w*j-l)*g-h; + if(*qans < 0.0e0) goto S380; + *ans = 0.5e0+(0.5e0-*qans); + return; +S210: +/* + FINITE SUMS FOR Q WHEN A .GE. 1 + AND 2*A IS AN INTEGER +*/ + sum = exp(-*x); + t = sum; + n = 1; + c = 0.0e0; + goto S230; +S220: + rtx = sqrt(*x); + sum = erfc1(&K2,&rtx); + t = exp(-*x)/(rtpi*rtx); + n = 0; + c = -0.5e0; +S230: + if(n == i) goto S240; + n += 1; + c += 1.0e0; + t = *x*t/c; + sum += t; + goto S230; +S240: + *qans = sum; + *ans = 0.5e0+(0.5e0-*qans); + return; +S250: +/* + CONTINUED FRACTION EXPANSION +*/ + tol = fifdmax1(5.0e0*e,acc); + a2nm1 = a2n = 1.0e0; + b2nm1 = *x; + b2n = *x+(1.0e0-*a); + c = 1.0e0; +S260: + a2nm1 = *x*a2n+c*a2nm1; + b2nm1 = *x*b2n+c*b2nm1; + am0 = a2nm1/b2nm1; + c += 1.0e0; + cma = c-*a; + a2n = a2nm1+cma*a2n; + b2n = b2nm1+cma*b2n; + an0 = a2n/b2n; + if(fabs(an0-am0) >= tol*an0) goto S260; + *qans = r*an0; + *ans = 0.5e0+(0.5e0-*qans); + return; +S270: +/* + GENERAL TEMME EXPANSION +*/ + if(fabs(s) <= 2.0e0*e && *a*e*e > 3.28e-3) goto S430; + c = exp(-y); + T3 = sqrt(y); + w = 0.5e0*erfc1(&K1,&T3); + u = 1.0e0/ *a; + z = sqrt(z+z); + if(l < 1.0e0) z = -z; + T4 = iop-2; + if(T4 < 0) goto S280; + else if(T4 == 0) goto S290; + else goto S300; +S280: + if(fabs(s) <= 1.e-3) goto S340; + c0 = ((((((((((((d0[12]*z+d0[11])*z+d0[10])*z+d0[9])*z+d0[8])*z+d0[7])*z+d0[ + 6])*z+d0[5])*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z-third; + c1 = (((((((((((d1[11]*z+d1[10])*z+d1[9])*z+d1[8])*z+d1[7])*z+d1[6])*z+d1[5] + )*z+d1[4])*z+d1[3])*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; + c2 = (((((((((d2[9]*z+d2[8])*z+d2[7])*z+d2[6])*z+d2[5])*z+d2[4])*z+d2[3])*z+ + d2[2])*z+d2[1])*z+d2[0])*z+d20; + c3 = (((((((d3[7]*z+d3[6])*z+d3[5])*z+d3[4])*z+d3[3])*z+d3[2])*z+d3[1])*z+ + d3[0])*z+d30; + c4 = (((((d4[5]*z+d4[4])*z+d4[3])*z+d4[2])*z+d4[1])*z+d4[0])*z+d40; + c5 = (((d5[3]*z+d5[2])*z+d5[1])*z+d5[0])*z+d50; + c6 = (d6[1]*z+d6[0])*z+d60; + t = ((((((d70*u+c6)*u+c5)*u+c4)*u+c3)*u+c2)*u+c1)*u+c0; + goto S310; +S290: + c0 = (((((d0[5]*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z-third; + c1 = (((d1[3]*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; + c2 = d2[0]*z+d20; + t = (c2*u+c1)*u+c0; + goto S310; +S300: + t = ((d0[2]*z+d0[1])*z+d0[0])*z-third; +S310: + if(l < 1.0e0) goto S320; + *qans = c*(w+rt2pin*t/rta); + *ans = 0.5e0+(0.5e0-*qans); + return; +S320: + *ans = c*(w-rt2pin*t/rta); + *qans = 0.5e0+(0.5e0-*ans); + return; +S330: +/* + TEMME EXPANSION FOR L = 1 +*/ + if(*a*e*e > 3.28e-3) goto S430; + c = 0.5e0+(0.5e0-y); + w = (0.5e0-sqrt(y)*(0.5e0+(0.5e0-y/3.0e0))/rtpi)/c; + u = 1.0e0/ *a; + z = sqrt(z+z); + if(l < 1.0e0) z = -z; + T5 = iop-2; + if(T5 < 0) goto S340; + else if(T5 == 0) goto S350; + else goto S360; +S340: + c0 = ((((((d0[6]*z+d0[5])*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z- + third; + c1 = (((((d1[5]*z+d1[4])*z+d1[3])*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; + c2 = ((((d2[4]*z+d2[3])*z+d2[2])*z+d2[1])*z+d2[0])*z+d20; + c3 = (((d3[3]*z+d3[2])*z+d3[1])*z+d3[0])*z+d30; + c4 = (d4[1]*z+d4[0])*z+d40; + c5 = (d5[1]*z+d5[0])*z+d50; + c6 = d6[0]*z+d60; + t = ((((((d70*u+c6)*u+c5)*u+c4)*u+c3)*u+c2)*u+c1)*u+c0; + goto S310; +S350: + c0 = (d0[1]*z+d0[0])*z-third; + c1 = d1[0]*z+d10; + t = (d20*u+c1)*u+c0; + goto S310; +S360: + t = d0[0]*z-third; + goto S310; +S370: +/* + SPECIAL CASES +*/ + *ans = 0.0e0; + *qans = 1.0e0; + return; +S380: + *ans = 1.0e0; + *qans = 0.0e0; + return; +S390: + if(*x >= 0.25e0) goto S400; + T6 = sqrt(*x); + *ans = erf1(&T6); + *qans = 0.5e0+(0.5e0-*ans); + return; +S400: + T7 = sqrt(*x); + *qans = erfc1(&K2,&T7); + *ans = 0.5e0+(0.5e0-*qans); + return; +S410: + if(fabs(s) <= 2.0e0*e) goto S430; +S420: + if(*x <= *a) goto S370; + goto S380; +S430: +/* + ERROR RETURN +*/ + *ans = 2.0e0; + return; +} /* END */ + +/***=====================================================================***/ +static double gsumln(double *a,double *b) +/* +----------------------------------------------------------------------- + EVALUATION OF THE FUNCTION LN(GAMMA(A + B)) + FOR 1 .LE. A .LE. 2 AND 1 .LE. B .LE. 2 +----------------------------------------------------------------------- +*/ +{ +static double gsumln,x,T1,T2; +/* + .. + .. Executable Statements .. +*/ + x = *a+*b-2.e0; + if(x > 0.25e0) goto S10; + T1 = 1.0e0+x; + gsumln = gamln1(&T1); + return gsumln; +S10: + if(x > 1.25e0) goto S20; + gsumln = gamln1(&x)+alnrel(&x); + return gsumln; +S20: + T2 = x-1.0e0; + gsumln = gamln1(&T2)+log(x*(1.0e0+x)); + return gsumln; +} /* END */ + +/***=====================================================================***/ +static double psi(double *xx) +/* +--------------------------------------------------------------------- + + EVALUATION OF THE DIGAMMA FUNCTION + + ----------- + + PSI(XX) IS ASSIGNED THE VALUE 0 WHEN THE DIGAMMA FUNCTION CANNOT + BE COMPUTED. + + THE MAIN COMPUTATION INVOLVES EVALUATION OF RATIONAL CHEBYSHEV + APPROXIMATIONS PUBLISHED IN MATH. COMP. 27, 123-127(1973) BY + CODY, STRECOK AND THACHER. + +--------------------------------------------------------------------- + PSI WAS WRITTEN AT ARGONNE NATIONAL LABORATORY FOR THE FUNPACK + PACKAGE OF SPECIAL FUNCTION SUBROUTINES. PSI WAS MODIFIED BY + A.H. MORRIS (NSWC). +--------------------------------------------------------------------- +*/ +{ +static double dx0 = 1.461632144968362341262659542325721325e0; +static double piov4 = .785398163397448e0; +static double p1[7] = { + .895385022981970e-02,.477762828042627e+01,.142441585084029e+03, + .118645200713425e+04,.363351846806499e+04,.413810161269013e+04, + .130560269827897e+04 +}; +static double p2[4] = { + -.212940445131011e+01,-.701677227766759e+01,-.448616543918019e+01, + -.648157123766197e+00 +}; +static double q1[6] = { + .448452573429826e+02,.520752771467162e+03,.221000799247830e+04, + .364127349079381e+04,.190831076596300e+04,.691091682714533e-05 +}; +static double q2[4] = { + .322703493791143e+02,.892920700481861e+02,.546117738103215e+02, + .777788548522962e+01 +}; +static int K1 = 3; +static int K2 = 1; +static double psi,aug,den,sgn,upper,w,x,xmax1,xmx0,xsmall,z; +static int i,m,n,nq; +/* + .. + .. Executable Statements .. +*/ +/* +--------------------------------------------------------------------- + MACHINE DEPENDENT CONSTANTS ... + XMAX1 = THE SMALLEST POSITIVE FLOATING POINT CONSTANT + WITH ENTIRELY INTEGER REPRESENTATION. ALSO USED + AS NEGATIVE OF LOWER BOUND ON ACCEPTABLE NEGATIVE + ARGUMENTS AND AS THE POSITIVE ARGUMENT BEYOND WHICH + PSI MAY BE REPRESENTED AS ALOG(X). + XSMALL = ABSOLUTE ARGUMENT BELOW WHICH PI*COTAN(PI*X) + MAY BE REPRESENTED BY 1/X. +--------------------------------------------------------------------- +*/ + xmax1 = ipmpar(&K1); + xmax1 = fifdmin1(xmax1,1.0e0/spmpar(&K2)); + xsmall = 1.e-9; + x = *xx; + aug = 0.0e0; + if(x >= 0.5e0) goto S50; +/* +--------------------------------------------------------------------- + X .LT. 0.5, USE REFLECTION FORMULA + PSI(1-X) = PSI(X) + PI * COTAN(PI*X) +--------------------------------------------------------------------- +*/ + if(fabs(x) > xsmall) goto S10; + if(x == 0.0e0) goto S100; +/* +--------------------------------------------------------------------- + 0 .LT. ABS(X) .LE. XSMALL. USE 1/X AS A SUBSTITUTE + FOR PI*COTAN(PI*X) +--------------------------------------------------------------------- +*/ + aug = -(1.0e0/x); + goto S40; +S10: +/* +--------------------------------------------------------------------- + REDUCTION OF ARGUMENT FOR COTAN +--------------------------------------------------------------------- +*/ + w = -x; + sgn = piov4; + if(w > 0.0e0) goto S20; + w = -w; + sgn = -sgn; +S20: +/* +--------------------------------------------------------------------- + MAKE AN ERROR EXIT IF X .LE. -XMAX1 +--------------------------------------------------------------------- +*/ + if(w >= xmax1) goto S100; + nq = fifidint(w); + w -= (double)nq; + nq = fifidint(w*4.0e0); + w = 4.0e0*(w-(double)nq*.25e0); +/* +--------------------------------------------------------------------- + W IS NOW RELATED TO THE FRACTIONAL PART OF 4.0 * X. + ADJUST ARGUMENT TO CORRESPOND TO VALUES IN FIRST + QUADRANT AND DETERMINE SIGN +--------------------------------------------------------------------- +*/ + n = nq/2; + if(n+n != nq) w = 1.0e0-w; + z = piov4*w; + m = n/2; + if(m+m != n) sgn = -sgn; +/* +--------------------------------------------------------------------- + DETERMINE FINAL VALUE FOR -PI*COTAN(PI*X) +--------------------------------------------------------------------- +*/ + n = (nq+1)/2; + m = n/2; + m += m; + if(m != n) goto S30; +/* +--------------------------------------------------------------------- + CHECK FOR SINGULARITY +--------------------------------------------------------------------- +*/ + if(z == 0.0e0) goto S100; +/* +--------------------------------------------------------------------- + USE COS/SIN AS A SUBSTITUTE FOR COTAN, AND + SIN/COS AS A SUBSTITUTE FOR TAN +--------------------------------------------------------------------- +*/ + aug = sgn*(cos(z)/sin(z)*4.0e0); + goto S40; +S30: + aug = sgn*(sin(z)/cos(z)*4.0e0); +S40: + x = 1.0e0-x; +S50: + if(x > 3.0e0) goto S70; +/* +--------------------------------------------------------------------- + 0.5 .LE. X .LE. 3.0 +--------------------------------------------------------------------- +*/ + den = x; + upper = p1[0]*x; + for(i=1; i<=5; i++) { + den = (den+q1[i-1])*x; + upper = (upper+p1[i+1-1])*x; + } + den = (upper+p1[6])/(den+q1[5]); + xmx0 = x-dx0; + psi = den*xmx0+aug; + return psi; +S70: +/* +--------------------------------------------------------------------- + IF X .GE. XMAX1, PSI = LN(X) +--------------------------------------------------------------------- +*/ + if(x >= xmax1) goto S90; +/* +--------------------------------------------------------------------- + 3.0 .LT. X .LT. XMAX1 +--------------------------------------------------------------------- +*/ + w = 1.0e0/(x*x); + den = w; + upper = p2[0]*w; + for(i=1; i<=3; i++) { + den = (den+q2[i-1])*w; + upper = (upper+p2[i+1-1])*w; + } + aug = upper/(den+q2[3])-0.5e0/x+aug; +S90: + psi = aug+log(x); + return psi; +S100: +/* +--------------------------------------------------------------------- + ERROR RETURN +--------------------------------------------------------------------- +*/ + psi = 0.0e0; + return psi; +} /* END */ + +/***=====================================================================***/ +static double rcomp(double *a,double *x) +/* + ------------------- + EVALUATION OF EXP(-X)*X**A/GAMMA(A) + ------------------- + RT2PIN = 1/SQRT(2*PI) + ------------------- +*/ +{ +static double rt2pin = .398942280401433e0; +static double rcomp,t,t1,u; +/* + .. + .. Executable Statements .. +*/ + rcomp = 0.0e0; + if(*a >= 20.0e0) goto S20; + t = *a*log(*x)-*x; + if(*a >= 1.0e0) goto S10; + rcomp = *a*exp(t)*(1.0e0+gam1(a)); + return rcomp; +S10: + rcomp = exp(t)/Xgamm(a); + return rcomp; +S20: + u = *x/ *a; + if(u == 0.0e0) return rcomp; + t = pow(1.0e0/ *a,2.0); + t1 = (((0.75e0*t-1.0e0)*t+3.5e0)*t-105.0e0)/(*a*1260.0e0); + t1 -= (*a*rlog(&u)); + rcomp = rt2pin*sqrt(*a)*exp(t1); + return rcomp; +} /* END */ + +/***=====================================================================***/ +static double rexp(double *x) +/* +----------------------------------------------------------------------- + EVALUATION OF THE FUNCTION EXP(X) - 1 +----------------------------------------------------------------------- +*/ +{ +static double p1 = .914041914819518e-09; +static double p2 = .238082361044469e-01; +static double q1 = -.499999999085958e+00; +static double q2 = .107141568980644e+00; +static double q3 = -.119041179760821e-01; +static double q4 = .595130811860248e-03; +static double rexp,w; +/* + .. + .. Executable Statements .. +*/ + if(fabs(*x) > 0.15e0) goto S10; + rexp = *x*(((p2**x+p1)**x+1.0e0)/((((q4**x+q3)**x+q2)**x+q1)**x+1.0e0)); + return rexp; +S10: + w = exp(*x); + if(*x > 0.0e0) goto S20; + rexp = w-0.5e0-0.5e0; + return rexp; +S20: + rexp = w*(0.5e0+(0.5e0-1.0e0/w)); + return rexp; +} /* END */ + +/***=====================================================================***/ +static double rlog(double *x) +/* + ------------------- + COMPUTATION OF X - 1 - LN(X) + ------------------- +*/ +{ +static double a = .566749439387324e-01; +static double b = .456512608815524e-01; +static double p0 = .333333333333333e+00; +static double p1 = -.224696413112536e+00; +static double p2 = .620886815375787e-02; +static double q1 = -.127408923933623e+01; +static double q2 = .354508718369557e+00; +static double rlog,r,t,u,w,w1; +/* + .. + .. Executable Statements .. +*/ + if(*x < 0.61e0 || *x > 1.57e0) goto S40; + if(*x < 0.82e0) goto S10; + if(*x > 1.18e0) goto S20; +/* + ARGUMENT REDUCTION +*/ + u = *x-0.5e0-0.5e0; + w1 = 0.0e0; + goto S30; +S10: + u = *x-0.7e0; + u /= 0.7e0; + w1 = a-u*0.3e0; + goto S30; +S20: + u = 0.75e0**x-1.e0; + w1 = b+u/3.0e0; +S30: +/* + SERIES EXPANSION +*/ + r = u/(u+2.0e0); + t = r*r; + w = ((p2*t+p1)*t+p0)/((q2*t+q1)*t+1.0e0); + rlog = 2.0e0*t*(1.0e0/(1.0e0-r)-r*w)+w1; + return rlog; +S40: + r = *x-0.5e0-0.5e0; + rlog = r-log(*x); + return rlog; +} /* END */ + +/***=====================================================================***/ +static double rlog1(double *x) +/* +----------------------------------------------------------------------- + EVALUATION OF THE FUNCTION X - LN(1 + X) +----------------------------------------------------------------------- +*/ +{ +static double a = .566749439387324e-01; +static double b = .456512608815524e-01; +static double p0 = .333333333333333e+00; +static double p1 = -.224696413112536e+00; +static double p2 = .620886815375787e-02; +static double q1 = -.127408923933623e+01; +static double q2 = .354508718369557e+00; +static double rlog1,h,r,t,w,w1; +/* + .. + .. Executable Statements .. +*/ + if(*x < -0.39e0 || *x > 0.57e0) goto S40; + if(*x < -0.18e0) goto S10; + if(*x > 0.18e0) goto S20; +/* + ARGUMENT REDUCTION +*/ + h = *x; + w1 = 0.0e0; + goto S30; +S10: + h = *x+0.3e0; + h /= 0.7e0; + w1 = a-h*0.3e0; + goto S30; +S20: + h = 0.75e0**x-0.25e0; + w1 = b+h/3.0e0; +S30: +/* + SERIES EXPANSION +*/ + r = h/(h+2.0e0); + t = r*r; + w = ((p2*t+p1)*t+p0)/((q2*t+q1)*t+1.0e0); + rlog1 = 2.0e0*t*(1.0e0/(1.0e0-r)-r*w)+w1; + return rlog1; +S40: + w = *x+0.5e0+0.5e0; + rlog1 = *x-log(w); + return rlog1; +} /* END */ + +/***=====================================================================***/ +static double spmpar(int *i) +/* +----------------------------------------------------------------------- + + SPMPAR PROVIDES THE SINGLE PRECISION MACHINE CONSTANTS FOR + THE COMPUTER BEING USED. IT IS ASSUMED THAT THE ARGUMENT + I IS AN INTEGER HAVING ONE OF THE VALUES 1, 2, OR 3. IF THE + SINGLE PRECISION ARITHMETIC BEING USED HAS M BASE B DIGITS AND + ITS SMALLEST AND LARGEST EXPONENTS ARE EMIN AND EMAX, THEN + + SPMPAR(1) = B**(1 - M), THE MACHINE PRECISION, + + SPMPAR(2) = B**(EMIN - 1), THE SMALLEST MAGNITUDE, + + SPMPAR(3) = B**EMAX*(1 - B**(-M)), THE LARGEST MAGNITUDE. + +----------------------------------------------------------------------- + WRITTEN BY + ALFRED H. MORRIS, JR. + NAVAL SURFACE WARFARE CENTER + DAHLGREN VIRGINIA +----------------------------------------------------------------------- +----------------------------------------------------------------------- + MODIFIED BY BARRY W. BROWN TO RETURN DOUBLE PRECISION MACHINE + CONSTANTS FOR THE COMPUTER BEING USED. THIS MODIFICATION WAS + MADE AS PART OF CONVERTING BRATIO TO DOUBLE PRECISION +----------------------------------------------------------------------- +*/ +{ +static int K1 = 4; +static int K2 = 8; +static int K3 = 9; +static int K4 = 10; +static double spmpar,b,binv,bm1,one,w,z; +static int emax,emin,ibeta,m; +/* + .. + .. Executable Statements .. +*/ + if(*i > 1) goto S10; + b = ipmpar(&K1); + m = ipmpar(&K2); + spmpar = pow(b,(double)(1-m)); + return spmpar; +S10: + if(*i > 2) goto S20; + b = ipmpar(&K1); + emin = ipmpar(&K3); + one = 1.0; + binv = one/b; + w = pow(b,(double)(emin+2)); + spmpar = w*binv*binv*binv; + return spmpar; +S20: + ibeta = ipmpar(&K1); + m = ipmpar(&K2); + emax = ipmpar(&K4); + b = ibeta; + bm1 = ibeta-1; + one = 1.0; + z = pow(b,(double)(m-1)); + w = ((z-one)*b+bm1)/(b*z); + z = pow(b,(double)(emax-2)); + spmpar = w*z*b*b; + return spmpar; +} /* END */ + +/***=====================================================================***/ +static double stvaln(double *p) +/* +********************************************************************** + + double stvaln(double *p) + STarting VALue for Neton-Raphon + calculation of Normal distribution Inverse + + + Function + + + Returns X such that CUMNOR(X) = P, i.e., the integral from - + infinity to X of (1/SQRT(2*PI)) EXP(-U*U/2) dU is P + + + Arguments + + + P --> The probability whose normal deviate is sought. + P is DOUBLE PRECISION + + + Method + + + The rational function on page 95 of Kennedy and Gentle, + Statistical Computing, Marcel Dekker, NY , 1980. + +********************************************************************** +*/ +{ +static double xden[5] = { + 0.993484626060e-1,0.588581570495e0,0.531103462366e0,0.103537752850e0, + 0.38560700634e-2 +}; +static double xnum[5] = { + -0.322232431088e0,-1.000000000000e0,-0.342242088547e0,-0.204231210245e-1, + -0.453642210148e-4 +}; +static int K1 = 5; +static double stvaln,sign,y,z; +/* + .. + .. Executable Statements .. +*/ + if(!(*p <= 0.5e0)) goto S10; + sign = -1.0e0; + z = *p; + goto S20; +S10: + sign = 1.0e0; + z = 1.0e0-*p; +S20: + y = sqrt(-(2.0e0*log(z))); + stvaln = y+devlpl(xnum,&K1,&y)/devlpl(xden,&K1,&y); + stvaln = sign*stvaln; + return stvaln; +} /* END */ + +/***=====================================================================***/ +static double fifdint(double a) +/************************************************************************ +FIFDINT: +Truncates a double precision number to an integer and returns the +value in a double. +************************************************************************/ +/* a - number to be truncated */ +{ + return (double) ((int) a); +} /* END */ + +/***=====================================================================***/ +static double fifdmax1(double a,double b) +/************************************************************************ +FIFDMAX1: +returns the maximum of two numbers a and b +************************************************************************/ +/* a - first number */ +/* b - second number */ +{ + if (a < b) return b; + else return a; +} /* END */ + +/***=====================================================================***/ +static double fifdmin1(double a,double b) +/************************************************************************ +FIFDMIN1: +returns the minimum of two numbers a and b +************************************************************************/ +/* a - first number */ +/* b - second number */ +{ + if (a < b) return a; + else return b; +} /* END */ + +/***=====================================================================***/ +static double fifdsign(double mag,double sign) +/************************************************************************ +FIFDSIGN: +transfers the sign of the variable "sign" to the variable "mag" +************************************************************************/ +/* mag - magnitude */ +/* sign - sign to be transfered */ +{ + if (mag < 0) mag = -mag; + if (sign < 0) mag = -mag; + return mag; + +} /* END */ + +/***=====================================================================***/ +static long fifidint(double a) +/************************************************************************ +FIFIDINT: +Truncates a double precision number to a long integer +************************************************************************/ +/* a - number to be truncated */ +{ + if (a < 1.0) return (long) 0; + else return (long) a; +} /* END */ + +/***=====================================================================***/ +static long fifmod(long a,long b) +/************************************************************************ +FIFMOD: +returns the modulo of a and b +************************************************************************/ +/* a - numerator */ +/* b - denominator */ +{ + return a % b; +} /* END */ + +/***=====================================================================***/ +static void ftnstop(char* msg) +/************************************************************************ +FTNSTOP: +Prints msg to standard error and then exits +************************************************************************/ +/* msg - error message */ +{ + if (msg != NULL) fprintf(stderr,"*** CDFLIB ERROR: %s\n",msg); + /** exit(1); **/ /** RWCox - DON'T EXIT */ +} /* END */ + +/***=====================================================================***/ +static int ipmpar(int *i) +/* +----------------------------------------------------------------------- + + IPMPAR PROVIDES THE INTEGER MACHINE CONSTANTS FOR THE COMPUTER + THAT IS USED. IT IS ASSUMED THAT THE ARGUMENT I IS AN INTEGER + HAVING ONE OF THE VALUES 1-10. IPMPAR(I) HAS THE VALUE ... + + INTEGERS. + + ASSUME INTEGERS ARE REPRESENTED IN THE N-DIGIT, BASE-A FORM + + SIGN ( X(N-1)*A**(N-1) + ... + X(1)*A + X(0) ) + + WHERE 0 .LE. X(I) .LT. A FOR I=0,...,N-1. + + IPMPAR(1) = A, THE BASE. + + IPMPAR(2) = N, THE NUMBER OF BASE-A DIGITS. + + IPMPAR(3) = A**N - 1, THE LARGEST MAGNITUDE. + + FLOATING-POINT NUMBERS. + + IT IS ASSUMED THAT THE SINGLE AND DOUBLE PRECISION FLOATING + POINT ARITHMETICS HAVE THE SAME BASE, SAY B, AND THAT THE + NONZERO NUMBERS ARE REPRESENTED IN THE FORM + + SIGN (B**E) * (X(1)/B + ... + X(M)/B**M) + + WHERE X(I) = 0,1,...,B-1 FOR I=1,...,M, + X(1) .GE. 1, AND EMIN .LE. E .LE. EMAX. + + IPMPAR(4) = B, THE BASE. + + SINGLE-PRECISION + + IPMPAR(5) = M, THE NUMBER OF BASE-B DIGITS. + + IPMPAR(6) = EMIN, THE SMALLEST EXPONENT E. + + IPMPAR(7) = EMAX, THE LARGEST EXPONENT E. + + DOUBLE-PRECISION + + IPMPAR(8) = M, THE NUMBER OF BASE-B DIGITS. + + IPMPAR(9) = EMIN, THE SMALLEST EXPONENT E. + + IPMPAR(10) = EMAX, THE LARGEST EXPONENT E. + +----------------------------------------------------------------------- + + TO DEFINE THIS FUNCTION FOR THE COMPUTER BEING USED REMOVE + THE COMMENT DELIMITORS FROM THE DEFINITIONS DIRECTLY BELOW THE NAME + OF THE MACHINE + +*** RWCox: at this time, the IEEE parameters are enabled. + +----------------------------------------------------------------------- + + IPMPAR IS AN ADAPTATION OF THE FUNCTION I1MACH, WRITTEN BY + P.A. FOX, A.D. HALL, AND N.L. SCHRYER (BELL LABORATORIES). + IPMPAR WAS FORMED BY A.H. MORRIS (NSWC). THE CONSTANTS ARE + FROM BELL LABORATORIES, NSWC, AND OTHER SOURCES. + +----------------------------------------------------------------------- + .. Scalar Arguments .. +*/ +{ +static int imach[11]; +static int outval ; +/* MACHINE CONSTANTS FOR AMDAHL MACHINES. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 16; + imach[5] = 6; + imach[6] = -64; + imach[7] = 63; + imach[8] = 14; + imach[9] = -64; + imach[10] = 63; +*/ +/* MACHINE CONSTANTS FOR THE AT&T 3B SERIES, AT&T + PC 7300, AND AT&T 6300. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -125; + imach[7] = 128; + imach[8] = 53; + imach[9] = -1021; + imach[10] = 1024; +*/ +/* MACHINE CONSTANTS FOR THE BURROUGHS 1700 SYSTEM. */ +/* + imach[1] = 2; + imach[2] = 33; + imach[3] = 8589934591; + imach[4] = 2; + imach[5] = 24; + imach[6] = -256; + imach[7] = 255; + imach[8] = 60; + imach[9] = -256; + imach[10] = 255; +*/ +/* MACHINE CONSTANTS FOR THE BURROUGHS 5700 SYSTEM. */ +/* + imach[1] = 2; + imach[2] = 39; + imach[3] = 549755813887; + imach[4] = 8; + imach[5] = 13; + imach[6] = -50; + imach[7] = 76; + imach[8] = 26; + imach[9] = -50; + imach[10] = 76; +*/ +/* MACHINE CONSTANTS FOR THE BURROUGHS 6700/7700 SYSTEMS. */ +/* + imach[1] = 2; + imach[2] = 39; + imach[3] = 549755813887; + imach[4] = 8; + imach[5] = 13; + imach[6] = -50; + imach[7] = 76; + imach[8] = 26; + imach[9] = -32754; + imach[10] = 32780; +*/ +/* MACHINE CONSTANTS FOR THE CDC 6000/7000 SERIES + 60 BIT ARITHMETIC, AND THE CDC CYBER 995 64 BIT + ARITHMETIC (NOS OPERATING SYSTEM). */ +/* + imach[1] = 2; + imach[2] = 48; + imach[3] = 281474976710655; + imach[4] = 2; + imach[5] = 48; + imach[6] = -974; + imach[7] = 1070; + imach[8] = 95; + imach[9] = -926; + imach[10] = 1070; +*/ +/* MACHINE CONSTANTS FOR THE CDC CYBER 995 64 BIT + ARITHMETIC (NOS/VE OPERATING SYSTEM). */ +/* + imach[1] = 2; + imach[2] = 63; + imach[3] = 9223372036854775807; + imach[4] = 2; + imach[5] = 48; + imach[6] = -4096; + imach[7] = 4095; + imach[8] = 96; + imach[9] = -4096; + imach[10] = 4095; +*/ +/* MACHINE CONSTANTS FOR THE CRAY 1, XMP, 2, AND 3. */ +/* + imach[1] = 2; + imach[2] = 63; + imach[3] = 9223372036854775807; + imach[4] = 2; + imach[5] = 47; + imach[6] = -8189; + imach[7] = 8190; + imach[8] = 94; + imach[9] = -8099; + imach[10] = 8190; +*/ +/* MACHINE CONSTANTS FOR THE DATA GENERAL ECLIPSE S/200. */ +/* + imach[1] = 2; + imach[2] = 15; + imach[3] = 32767; + imach[4] = 16; + imach[5] = 6; + imach[6] = -64; + imach[7] = 63; + imach[8] = 14; + imach[9] = -64; + imach[10] = 63; +*/ +/* MACHINE CONSTANTS FOR THE HARRIS 220. */ +/* + imach[1] = 2; + imach[2] = 23; + imach[3] = 8388607; + imach[4] = 2; + imach[5] = 23; + imach[6] = -127; + imach[7] = 127; + imach[8] = 38; + imach[9] = -127; + imach[10] = 127; +*/ +/* MACHINE CONSTANTS FOR THE HONEYWELL 600/6000 + AND DPS 8/70 SERIES. */ +/* + imach[1] = 2; + imach[2] = 35; + imach[3] = 34359738367; + imach[4] = 2; + imach[5] = 27; + imach[6] = -127; + imach[7] = 127; + imach[8] = 63; + imach[9] = -127; + imach[10] = 127; +*/ +/* MACHINE CONSTANTS FOR THE HP 2100 + 3 WORD DOUBLE PRECISION OPTION WITH FTN4 */ +/* + imach[1] = 2; + imach[2] = 15; + imach[3] = 32767; + imach[4] = 2; + imach[5] = 23; + imach[6] = -128; + imach[7] = 127; + imach[8] = 39; + imach[9] = -128; + imach[10] = 127; +*/ +/* MACHINE CONSTANTS FOR THE HP 2100 + 4 WORD DOUBLE PRECISION OPTION WITH FTN4 */ +/* + imach[1] = 2; + imach[2] = 15; + imach[3] = 32767; + imach[4] = 2; + imach[5] = 23; + imach[6] = -128; + imach[7] = 127; + imach[8] = 55; + imach[9] = -128; + imach[10] = 127; +*/ +/* MACHINE CONSTANTS FOR THE HP 9000. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -126; + imach[7] = 128; + imach[8] = 53; + imach[9] = -1021; + imach[10] = 1024; +*/ +/* MACHINE CONSTANTS FOR THE IBM 360/370 SERIES, + THE ICL 2900, THE ITEL AS/6, THE XEROX SIGMA + 5/7/9 AND THE SEL SYSTEMS 85/86. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 16; + imach[5] = 6; + imach[6] = -64; + imach[7] = 63; + imach[8] = 14; + imach[9] = -64; + imach[10] = 63; +*/ +/* MACHINE CONSTANTS FOR THE IBM PC. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -125; + imach[7] = 128; + imach[8] = 53; + imach[9] = -1021; + imach[10] = 1024; +*/ +/* MACHINE CONSTANTS FOR THE MACINTOSH II - ABSOFT + MACFORTRAN II. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -125; + imach[7] = 128; + imach[8] = 53; + imach[9] = -1021; + imach[10] = 1024; +*/ +/* MACHINE CONSTANTS FOR THE MICROVAX - VMS FORTRAN. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -127; + imach[7] = 127; + imach[8] = 56; + imach[9] = -127; + imach[10] = 127; +*/ +/* MACHINE CONSTANTS FOR THE PDP-10 (KA PROCESSOR). */ +/* + imach[1] = 2; + imach[2] = 35; + imach[3] = 34359738367; + imach[4] = 2; + imach[5] = 27; + imach[6] = -128; + imach[7] = 127; + imach[8] = 54; + imach[9] = -101; + imach[10] = 127; +*/ +/* MACHINE CONSTANTS FOR THE PDP-10 (KI PROCESSOR). */ +/* + imach[1] = 2; + imach[2] = 35; + imach[3] = 34359738367; + imach[4] = 2; + imach[5] = 27; + imach[6] = -128; + imach[7] = 127; + imach[8] = 62; + imach[9] = -128; + imach[10] = 127; +*/ +/* MACHINE CONSTANTS FOR THE PDP-11 FORTRAN SUPPORTING + 32-BIT INTEGER ARITHMETIC. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -127; + imach[7] = 127; + imach[8] = 56; + imach[9] = -127; + imach[10] = 127; +*/ +/* MACHINE CONSTANTS FOR THE SEQUENT BALANCE 8000. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -125; + imach[7] = 128; + imach[8] = 53; + imach[9] = -1021; + imach[10] = 1024; +*/ +/* MACHINE CONSTANTS FOR THE SILICON GRAPHICS IRIS-4D + SERIES (MIPS R3000 PROCESSOR). */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -125; + imach[7] = 128; + imach[8] = 53; + imach[9] = -1021; + imach[10] = 1024; +*/ +/* MACHINE CONSTANTS FOR IEEE ARITHMETIC MACHINES, SUCH AS THE AT&T + 3B SERIES, MOTOROLA 68000 BASED MACHINES (E.G. SUN 3 AND AT&T + PC 7300), AND 8087 BASED MICROS (E.G. IBM PC AND AT&T 6300). */ + + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -125; + imach[7] = 128; + imach[8] = 53; + imach[9] = -1021; + imach[10] = 1024; + +/* MACHINE CONSTANTS FOR THE UNIVAC 1100 SERIES. */ +/* + imach[1] = 2; + imach[2] = 35; + imach[3] = 34359738367; + imach[4] = 2; + imach[5] = 27; + imach[6] = -128; + imach[7] = 127; + imach[8] = 60; + imach[9] = -1024; + imach[10] = 1023; +*/ +/* MACHINE CONSTANTS FOR THE VAX 11/780. */ +/* + imach[1] = 2; + imach[2] = 31; + imach[3] = 2147483647; + imach[4] = 2; + imach[5] = 24; + imach[6] = -127; + imach[7] = 127; + imach[8] = 56; + imach[9] = -127; + imach[10] = 127; +*/ + outval = imach[*i]; + return outval ; +} + +/*************************************************************************/ +/*************************************************************************/ +/************************ End of cdflib inclusion ************************/ +/*************************************************************************/ +/*************************************************************************/ + +/*-----------------------------------------------------------------------*/ +typedef struct { double p,q ; } pqpair ; /* for returning p=cdf q=1-cdf */ +/*-----------------------------------------------------------------------*/ +#undef BIGG +#define BIGG 9.99e+37 /* a really big number (duh) */ +/*-----------------------------------------------------------------------*/ + +/*************************************************************************/ +/******** Internal functions for various statistical computations ********/ +/*************************************************************************/ + +/*--------------------------------------------------------------- + F statistic +-----------------------------------------------------------------*/ + +static double fstat_pq2s( pqpair pq , double dofnum , double dofden ) +{ + int which , status ; + double p , q , f , dfn , dfd , bound ; + + which = 2 ; + p = pq.p ; if( p <= 0.0 ) return 0.0 ; + q = pq.q ; if( q <= 0.0 ) return BIGG ; + f = 0.0 ; + dfn = dofnum ; + dfd = dofden ; + + cdff( &which , &p , &q , &f , &dfn , &dfd , &status , &bound ) ; + return f ; +} + +/*------------------------------*/ + +static pqpair fstat_s2pq( double ff , double dofnum , double dofden ) +{ + int which , status ; + double p , q , f , dfn , dfd , bound ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + f = ff ; if( f <= 0.0 ) return pq; + dfn = dofnum ; if( dfn <= 0.0 ) return pq ; + dfd = dofden ; if( dfd <= 0.0 ) return pq ; + + cdff( &which , &p , &q , &f , &dfn , &dfd , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*--------------------------------------------------------------- + noncentral F statistic +-----------------------------------------------------------------*/ + +static double fnonc_pq2s( pqpair pq , double dofnum , double dofden , double nonc ) +{ + int which , status ; + double p , q , f , dfn , dfd , bound , pnonc ; + + which = 2 ; + p = pq.p ; if( p <= 0.0 ) return 0.0 ; + q = pq.q ; if( q <= 0.0 ) return BIGG ; + f = 0.0 ; + dfn = dofnum ; + dfd = dofden ; + pnonc = nonc ; + + cdffnc( &which , &p , &q , &f , &dfn , &dfd , &pnonc , &status , &bound ) ; + return f ; +} + +/*------------------------------*/ + +static pqpair fnonc_s2pq( double ff , double dofnum , double dofden , double nonc ) +{ + int which , status ; + double p , q , f , dfn , dfd , bound , pnonc ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + f = ff ; if( f <= 0.0 ) return pq ; + dfn = dofnum ; if( dfn <= 0.0 ) return pq ; + dfd = dofden ; if( dfd <= 0.0 ) return pq ; + pnonc = nonc ; if( pnonc < 0.0 ) return pq ; + + cdffnc( &which , &p , &q , &f , &dfn , &dfd , &pnonc , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*--------------------------------------------------------------- + Standard Normal distribution +-----------------------------------------------------------------*/ + +static pqpair normal_s2pq( double zz ) +{ + double p , q , x=zz ; + pqpair pq ; + + cumnor( &x, &p, &q ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +static double normal_pq2s( pqpair pq ) +{ + double p=pq.p , q=pq.q ; + + if( p <= 0.0 ) return -BIGG ; + if( q <= 0.0 ) return BIGG ; + return dinvnr( &p,&q ) ; +} + +/*---------------------------------------------------------------- + Chi-square +------------------------------------------------------------------*/ + +static pqpair chisq_s2pq( double xx , double dof ) +{ + int which , status ; + double p,q,x,df,bound ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + x = xx ; if( x <= 0.0 ) return pq ; + df = dof ; if( dof <= 0.0 ) return pq ; + + cdfchi( &which , &p , &q , &x , &df , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +static double chisq_pq2s( pqpair pq , double dof ) +{ + int which , status ; + double p,q,x,df,bound ; + + which = 2 ; + p = pq.p ; if( p <= 0.0 ) return 0.0 ; + q = pq.q ; if( q <= 0.0 ) return BIGG ; + x = 0.0 ; + df = dof ; + + cdfchi( &which , &p , &q , &x , &df , &status , &bound ) ; + return x ; +} + +/*---------------------------------------------------------------- + noncentral Chi-square +------------------------------------------------------------------*/ + +static pqpair chsqnonc_s2pq( double xx , double dof , double nonc ) +{ + int which , status ; + double p,q,x,df,bound , pnonc ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + x = xx ; if( x <= 0.0 ) return pq ; + df = dof ; if( df <= 0.0 ) return pq ; + pnonc = nonc ; if( pnonc < 0.0 ) return pq ; + + cdfchn( &which , &p , &q , &x , &df , &pnonc , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +static double chsqnonc_pq2s( pqpair pq , double dof , double nonc ) +{ + int which , status ; + double p,q,x,df,bound , pnonc ; + + which = 2 ; + p = pq.p ; if( p <= 0.0 ) return 0.0 ; + q = pq.q ; if( q <= 0.0 ) return BIGG ; + x = 0.0 ; + df = dof ; + pnonc = nonc ; + + cdfchn( &which , &p , &q , &x , &df , &pnonc , &status , &bound ) ; + return x ; +} + +/*---------------------------------------------------------------- + Beta distribution +------------------------------------------------------------------*/ + +static pqpair beta_s2pq( double xx , double aa , double bb ) +{ + int which , status ; + double p,q,x,y,a,b,bound ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + x = xx ; if( x <= 0.0 ) return pq ; + y = 1.0 - xx ; if( y <= 0.0 ){ pq.p=1.0; pq.q=0.0; return pq; } + a = aa ; if( a < 0.0 ) return pq ; + b = bb ; if( b < 0.0 ) return pq ; + + cdfbet( &which , &p , &q , &x , &y , &a , &b , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +static double beta_pq2s( pqpair pq , double aa , double bb ) +{ + int which , status ; + double p,q,x,y,a,b,bound ; + + which = 2 ; + p = pq.p ; if( p <= 0.0 ) return 0.0 ; + q = pq.q ; if( q <= 0.0 ) return 1.0 ; + x = 0.0 ; + y = 1.0 ; + a = aa ; + b = bb ; + + cdfbet( &which , &p , &q , &x , &y , &a , &b , &status , &bound ) ; + return x ; +} + +/*---------------------------------------------------------------- + Binomial distribution + (that is, the probability that more than ss out of ntrial + trials were successful). +------------------------------------------------------------------*/ + +static pqpair binomial_s2pq( double ss , double ntrial , double ptrial ) +{ + int which , status ; + double p,q, s,xn,pr,ompr,bound ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + s = ss ; if( s < 0.0 ) return pq ; + xn = ntrial ; if( xn <= 0.0 ) return pq ; + pr = ptrial ; if( pr < 0.0 ) return pq ; + ompr = 1.0 - ptrial ; + + cdfbin( &which , &p , &q , &s , &xn , &pr , &ompr , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +static double binomial_pq2s( pqpair pq , double ntrial , double ptrial ) +{ + int which , status ; + double p,q, s,xn,pr,ompr,bound ; + + which = 2 ; + p = pq.p ; + q = pq.q ; + s = 0.0 ; + xn = ntrial ; + pr = ptrial ; + ompr = 1.0 - ptrial ; + + cdfbin( &which , &p , &q , &s , &xn , &pr , &ompr , &status , &bound ) ; + return s ; +} + +/*---------------------------------------------------------------- + Gamma distribution. +------------------------------------------------------------------*/ + +static pqpair gamma_s2pq( double xx , double sh , double sc ) +{ + int which , status ; + double p,q, x,shape,scale,bound ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + x = xx ; if( x <= 0.0 ) return pq ; + shape = sh ; if( shape <= 0.0 ) return pq ; + scale = sc ; if( scale <= 0.0 ) return pq ; + + cdfgam( &which , &p , &q , &x , &shape , &scale , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +static double gamma_pq2s( pqpair pq , double sh , double sc ) +{ + int which , status ; + double p,q, x,shape,scale,bound ; + + which = 2 ; + p = pq.p ; if( p <= 0.0 ) return 0.0 ; + q = pq.q ; if( q <= 0.0 ) return BIGG ; + x = 0.0 ; + shape = sh ; + scale = sc ; + + cdfgam( &which , &p , &q , &x , &shape , &scale , &status , &bound ) ; + return x ; +} + +/*---------------------------------------------------------------- + Poisson distribution +------------------------------------------------------------------*/ + +static pqpair poisson_s2pq( double xx , double lambda ) +{ + int which , status ; + double p,q, s,xlam,bound ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + s = xx ; if( s < 0.0 ) return pq ; + xlam = lambda ; if( xlam < 0.0 ) return pq ; + + cdfpoi( &which , &p , &q , &s , &xlam , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +static double poisson_pq2s( pqpair pq , double lambda ) +{ + int which , status ; + double p,q, s,xlam,bound ; + + which = 2 ; + p = pq.p ; + q = pq.q ; + s = 0.0 ; + xlam = lambda ; + + cdfpoi( &which , &p , &q , &s , &xlam , &status , &bound ) ; + return s ; +} + +/*---------------------------------------------------------------- + T distribution. +------------------------------------------------------------------*/ + +static pqpair student_s2pq( double xx , double dof ) +{ + int which , status ; + double p,q, s,xlam,bound ; + pqpair pq={0.0,1.0} ; + + which = 1 ; + p = 0.0 ; + q = 1.0 ; + s = xx ; + xlam = dof ; if( xlam <= 0.0 ) return pq ; + + cdft( &which , &p , &q , &s , &xlam , &status , &bound ) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +double student_pq2s( pqpair pq , double dof ) +{ + int which , status ; + double p,q, s,xlam,bound ; + + which = 2 ; + p = pq.p ; + q = pq.q ; + s = 0.0 ; + xlam = dof ; + + cdft( &which , &p , &q , &s , &xlam , &status , &bound ) ; + return s ; +} + +/****************************************************************************/ +/* For the distributions below here, cdflib can't do what we want directly. */ +/****************************************************************************/ + +/*---------------------------------------------------------------- + Null correlation distribution. + Let x = (rr+1)/2; then x is Beta(dof/2,dof/2). +------------------------------------------------------------------*/ + +static pqpair correl_s2pq( double rr , double dof ) /* fake it with cdflib */ +{ + return beta_s2pq( 0.5*(rr+1.0) , 0.5*dof , 0.5*dof ) ; +} + +/*------------------------------*/ + +static double correl_pq2s( pqpair pq , double dof ) +{ + double xx = beta_pq2s( pq , 0.5*dof , 0.5*dof ) ; + return (2.0*xx-1.0) ; +} + +/*---------------------------------------------------------------- + Uniform U(0,1) distribution. +------------------------------------------------------------------*/ + +static pqpair uniform_s2pq( double xx ) /* this isn't too hard */ +{ + pqpair pq ; + if( xx <= 0.0 ) pq.p = 0.0 ; + else if( xx >= 1.0 ) pq.p = 1.0 ; + else pq.p = xx ; + pq.q = 1.0-xx ; return pq ; +} + +/*------------------------------*/ + +static double uniform_pq2s( pqpair pq ) +{ + return pq.p ; /* that was easy */ +} + +/*---------------------------------------------------------------- + standard Logistic distribution. +------------------------------------------------------------------*/ + +static pqpair logistic_s2pq( double xx ) /* this isn't hard, either */ +{ + pqpair pq ; + if( xx >= 0.0 ){ pq.q = 1.0/(1.0+exp( xx)); pq.p = 1.0-pq.q; } + else { pq.p = 1.0/(1.0+exp(-xx)); pq.q = 1.0-pq.p; } + return pq ; +} + +/*------------------------------*/ + +static double logistic_pq2s( pqpair pq ) +{ + if( pq.p <= 0.0 ) return -BIGG ; + else if( pq.q <= 0.0 ) return BIGG ; + + if( pq.p < pq.q ) return -log(1.0/pq.p-1.0) ; + else return log(1.0/pq.q-1.0) ; +} + +/*---------------------------------------------------------------- + standard Laplace distribution. +------------------------------------------------------------------*/ + +static pqpair laplace_s2pq( double xx ) /* easy */ +{ + pqpair pq ; + + if( xx >= 0.0 ){ pq.q = 0.5*exp(-xx) ; pq.p = 1.0-pq.q ; } + else { pq.p = 0.5*exp( xx) ; pq.q = 1.0-pq.p ; } + return pq ; +} + +/*------------------------------*/ + +static double laplace_pq2s( pqpair pq ) +{ + if( pq.p <= 0.0 ) return -BIGG ; + else if( pq.q <= 0.0 ) return BIGG ; + + if( pq.p < pq.q ) return log(2.0*pq.p) ; + else return -log(2.0*pq.q) ; +} + +/*---------------------------------------------------------------- + noncentral T distribution = hard calculation +------------------------------------------------------------------*/ + +/**************************************************************************** + Noncentral t distribution function by + Professor K. Krishnamoorthy + Department of Mathematics + University of Louisiana at Lafayette + Manually translated from Fortran by RWC. +*****************************************************************************/ + +#if 0 +static double alng( double x ) /* log(Gamma(x)) from K */ +{ + int indx ; + double xx,fterm,sum,valg ; + double b[9] = { 0.0 , + 8.33333333333333e-2, 3.33333333333333e-2, + 2.52380952380952e-1, 5.25606469002695e-1, + 1.01152306812684e0, 1.51747364915329e0, + 2.26948897420496e0, 3.00991738325940e0 } ; + + if( x < 8.0 ){ xx = x + 8.0 ; indx = 1 ; } + else { xx = x ; indx = 0 ; } + + fterm = (xx-0.5)*log(xx) - xx + 9.1893853320467e-1 ; + sum = b[1]/(xx+b[2]/(xx+b[3]/(xx+b[4]/(xx+b[5]/(xx+b[6]/ + (xx+b[7]/(xx+b[8]))))))) ; + valg = sum + fterm ; + if(indx) + valg = valg-log(x+7.0)-log(x+6.0)-log(x+5.0) + -log(x+4.0)-log(x+3.0)-log(x+2.0)-log(x+1.0)-log(x) ; + return valg ; +} +#else +static double alng( double x ) /*-- replace with cdflib function --*/ +{ + double xx=x ; return alngam( &xx ) ; +} +#endif + +/*---------------------------------------------------------------------------*/ + +#if 0 +static double gaudf( double x ) /* N(0,1) cdf from K */ +{ + static double p0=913.16744211475570 , p1=1024.60809538333800, + p2=580.109897562908800, p3=202.102090717023000, + p4=46.0649519338751400, p5=6.81311678753268400, + p6=6.047379926867041e-1,p7=2.493381293151434e-2 ; + static double q0=1826.33488422951125, q1=3506.420597749092, + q2=3044.77121163622200, q3=1566.104625828454, + q4=523.596091947383490, q5=116.9795245776655, + q6=17.1406995062577800, q7=1.515843318555982, + q8=6.25e-2 ; + static double sqr2pi=2.506628274631001 ; + int check ; + double reslt,z , first,phi ; + + if(x > 0.0){ z = x ; check = 1 ; } + else { z =-x ; check = 0 ; } + + if( z > 32.0 ) return (x > 0.0) ? 1.0 : 0.0 ; + + first = exp(-0.5*z*z) ; + phi = first/sqr2pi ; + + if (z < 7.0) + reslt = first* (((((((p7*z+p6)*z+p5)*z+p4)*z+p3)*z+p2)*z+p1)*z+p0) + /((((((((q8*z+q7)*z+q6)*z+q5)*z+q4)*z+q3)*z+q2)*z+q1)*z+q0); + else + reslt = phi/(z+1.0/(z+2.0/(z+3.0/(z+4.0/(z+6.0/(z+7.0)))))) ; + + if(check) reslt = 1.0 - reslt ; + return reslt ; +} +#else +static double gaudf( double x ) /*-- replace with cdflib func --*/ +{ + double xx=x , p,q ; + cumnor( &xx, &p, &q ); return p; +} +#endif + +/*---------------------------------------------------------------------------*/ + +#if 0 +static double betadf( double x , double p , double q ) /* Beta cdf from K */ +{ + int check , ns ; + double result,betf,psq,xx,cx,pp,qq ; + double term,ai,rx,temp ; + + if( x >= 1.0 ) return 1.0 ; + if( x <= 0.0 ) return 0.0 ; + + betf = alng(p)+alng(q)-alng(p+q) ; + result=x ; + psq=p+q ; + cx=1.0-x ; + if(p < psq*x){ xx=cx ; cx=x ; pp=q ; qq=p ; check=1 ; } + else { xx=x ; pp=p ; qq=q ; check=0 ; } + + term=1.0 ; + ai=1.0 ; + result=1.0 ; + ns=(int)(qq+cx*psq) ; + rx=xx/cx ; +L3: + temp=qq-ai ; + if(ns == 0) rx=xx ; +L4: + term=term*temp*rx/(pp+ai) ; + result=result+term ; + temp=fabs(term) ; + if(temp <= 1.e-14 && temp <= 1.e-14*result) goto L5 ; + ai=ai+1.0 ; + ns=ns-1 ; + if(ns >= 0) goto L3 ; + temp=psq ; + psq=psq+1.0 ; + goto L4 ; + +L5: + result=result*exp(pp*log(xx)+(qq-1.0)*log(cx)-betf)/pp ; + if(check) result=1.0-result ; + return result ; +} +#else +static double betadf( double x , double p , double q ) /*-- cdflib func --*/ +{ + double xx=x,yy=1.0-x , aa=p,bb=q , pp,qq ; + cumbet( &xx,&yy , &aa,&bb , &pp,&qq ) ; return pp ; +} +#endif + +/*---------------------------------------------------------------------------*/ +/* Krishnamoorthy's function for cdf of noncentral t, for df > 0, + translated into C by RW Cox [Mar 2004]. + Note the original fails for delta=0, so we call the cdflib func for this. + A couple of other minor fixes are also included. +-----------------------------------------------------------------------------*/ + +static pqpair tnonc_s2pq( double t , double df , double delta ) +{ + int indx , k , i ; + double x,del,tnd,ans,y,dels,a,b,c ; + double pkf,pkb,qkf,qkb , pgamf,pgamb,qgamf,qgamb ; + double pbetaf,pbetab,qbetaf,qbetab ; + double ptermf,qtermf,ptermb,qtermb,term ; + double rempois,delosq2,sum,cons,error ; + + pqpair pq={0.0,1.0} ; /* will be return value */ + double ab1 ; + + /*-- stupid user? --*/ + + if( df <= 0.0 ) return pq ; + + /*-- non-centrality = 0? --*/ + + if( fabs(delta) < 1.e-8 ) return student_s2pq(t,df) ; + + /*-- start K's code here --*/ + + if( t < 0.0 ){ x = -t ; del = -delta ; indx = 1 ; } /* x will be */ + else { x = t ; del = delta ; indx = 0 ; } /* positive */ + + ans = gaudf(-del) ; /* prob that x <= 0 = Normal cdf */ + + /*-- the nearly trivial case of x=0 --*/ + + if( x == 0.0 ){ pq.p = ans; pq.q = 1.0-ans; return pq; } + + if( df == 1.0 ) df = 1.0000001 ; /** df=1 is BAD **/ + + y = x*x/(df+x*x) ; /* between 0 and 1 */ + dels = 0.5*del*del ; /* will be positive */ + k = (int)dels ; /* 0, 1, 2, ... */ + a = k+0.5 ; /* might be as small as 0.5 */ + c = k+1.0 ; + b = 0.5*df ; /* might be as small as 0.0 */ + + pkf = exp(-dels+k*log(dels)-alng(k+1.0)) ; + pkb = pkf ; + qkf = exp(-dels+k*log(dels)-alng(k+1.0+0.5)) ; + qkb = qkf ; + + pbetaf = betadf(y, a, b) ; + pbetab = pbetaf ; + qbetaf = betadf(y, c, b) ; + qbetab = qbetaf ; + + ab1 = a+b-1.0 ; /* might be as small as -0.5 */ + + /*-- RWCox: if a+b-1 < 0, log(Gamma(a+b-1)) won't work; + instead, use Gamma(a+b-1)=Gamma(a+b)/(a+b-1) --*/ + + if( ab1 > 0.0 ) + pgamf = exp(alng(ab1)-alng(a)-alng(b)+(a-1.0)*log(y)+b*log(1.0-y)) ; + else + pgamf = exp(alng(a+b)-alng(a)-alng(b)+(a-1.0)*log(y)+b*log(1.0-y))/ab1 ; + + pgamb = pgamf*y*(ab1)/a ; + + /*-- we can't have c+b-1 < 0, so the above patchup isn't needed --*/ + + qgamf = exp(alng(c+b-1.0)-alng(c)-alng(b)+(c-1.0)*log(y) + b*log(1.0-y)) ; + qgamb = qgamf*y*(c+b-1.0)/c ; + + rempois = 1.0 - pkf ; + delosq2 = del/1.4142135623731 ; + sum = pkf*pbetaf+delosq2*qkf*qbetaf ; + cons = 0.5*(1.0 + 0.5*fabs(delta)) ; + i = 0 ; +L1: + i = i + 1 ; + pgamf = pgamf*y*(a+b+i-2.0)/(a+i-1.0) ; + pbetaf = pbetaf - pgamf ; + pkf = pkf*dels/(k+i) ; + ptermf = pkf*pbetaf ; + qgamf = qgamf*y*(c+b+i-2.0)/(c+i-1.0) ; + qbetaf = qbetaf - qgamf ; + qkf = qkf*dels/(k+i-1.0+1.5) ; + qtermf = qkf*qbetaf ; + term = ptermf + delosq2*qtermf ; + sum = sum + term ; + error = rempois*cons*pbetaf ; + rempois = rempois - pkf ; + + if( i > k ){ + if( error <= 1.e-12 || i >= 9999 ) goto L2 ; + goto L1 ; + } else { + pgamb = pgamb*(a-i+1.0)/(y*(a+b-i)) ; + pbetab = pbetab + pgamb ; + pkb = (k-i+1.0)*pkb/dels ; + ptermb = pkb*pbetab ; + qgamb = qgamb*(c-i+1.0)/(y*(c+b-i)) ; + qbetab = qbetab + qgamb ; + qkb = (k-i+1.0+0.5)*qkb/dels ; + qtermb = qkb*qbetab ; + term = ptermb + delosq2*qtermb ; + sum = sum + term ; + rempois = rempois - pkb ; + if (rempois <= 1.e-12 || i >= 9999) goto L2 ; + goto L1 ; + } +L2: + tnd = 0.5*sum + ans ; + + /*-- return a pqpair, not just the cdf --*/ + + if( indx ){ pq.p = 1.0-tnd; pq.q = tnd ; } + else { pq.p = tnd ; pq.q = 1.0-tnd; } + return pq ; +} + +/*------------------------------*/ +/* Inverse to above function; + uses cdflib dstinv()/dinvr() + to solve the equation. +--------------------------------*/ + +static double tnonc_pq2s( pqpair pq , double dof , double nonc ) +{ + double t ; /* will be result */ + double tbot,ttop , dt ; + double T6=1.e-50,T7=1.e-8 ; + double K4=0.5,K5=5.0 ; + double fx ; + unsigned long qhi,qleft ; + int status , qporq , ite ; + pqpair tpq ; + + if( dof <= 0.0 ) return BIGG ; /* bad user */ + if( pq.p <= 0.0 ) return -BIGG ; + if( pq.q <= 0.0 ) return BIGG ; + + t = student_pq2s(pq,dof) ; /* initial guess */ + + if( fabs(nonc) < 1.e-8 ) return t ; + + t += 0.5*nonc ; /* adjust up or down */ + + dt = 0.1 * fabs(t) ; if( dt < 1.0 ) dt = 1.0 ; /* stepsize */ + + /* scan down for lower bound, below which cdf is < p */ + + tbot = t ; + for( ite=0 ; ite < 1000 ; ite++ ){ + tpq = tnonc_s2pq( tbot , dof , nonc ) ; + if( tpq.p <= pq.p ) break ; + tbot -= dt ; + } + if( ite >= 1000 ) return -BIGG ; + + /* scan up for upper bound, above which cdf is > p */ + + ttop = tbot+0.5*dt ; + for( ite=0 ; ite < 1000 ; ite++ ){ + tpq = tnonc_s2pq( ttop , dof , nonc ) ; + if( tpq.p >= pq.p ) break ; + ttop += dt ; + } + if( ite >= 1000 ) return BIGG ; + + t = 0.5*(tbot+ttop) ; /* initial guess in middle */ + + /* initialize searching parameters */ + + dstinv(&tbot,&ttop,&K4,&K4,&K5,&T6,&T7); + + status = 0 ; qporq = (pq.p <= pq.q) ; + + while(1){ + + dinvr(&status,&t,&fx,&qleft,&qhi) ; + + if( status != 1 ) return t ; /* done! */ + + tpq = tnonc_s2pq( t , dof , nonc ) ; /* get cdf */ + + /* goal of dinvr is to drive fx to zero */ + + fx = (qporq) ? pq.p-tpq.p : pq.q-tpq.q ; + } + + return BIGG ; /* unreachable */ +} + +/*---------------------------------------------------------------- + Chi distribution (sqrt of chi-squared, duh). +------------------------------------------------------------------*/ + +static pqpair chi_s2pq( double xx , double dof ) +{ + pqpair pq={0.0,1.0} ; + + if( xx <= 0.0 || dof <= 0.0 ) return pq ; + return chisq_s2pq( xx*xx , dof ) ; +} + +/*------------------------------*/ + +static double chi_pq2s( pqpair pq , double dof ) +{ + if( pq.p <= 0.0 ) return 0.0 ; + if( pq.q <= 0.0 ) return BIGG ; + return sqrt(chisq_pq2s(pq,dof)) ; +} + +/*---------------------------------------------------------------- + Extreme value type I: cdf(x) = exp(-exp(-x)). +------------------------------------------------------------------*/ + +static pqpair extval1_s2pq( double x ) +{ + double p,q,y ; pqpair pq ; + + if( x > -5.0 ){ y = exp(-x) ; p = exp(-y) ; } + else { y = 1.0 ; p = 0.0 ; } + + if( y >= 1.e-4 ) q = 1.0-p ; + else q = y*(1.0+y*(-0.5+y*(1.0/6.0-y/24.0))) ; + pq.p = p ; pq.q = q ; return pq ; +} + +/*------------------------------*/ + +static double extval1_pq2s( pqpair pq ) +{ + if( pq.p <= 0.0 ) return -BIGG ; + else if( pq.p >= 1.0 ) return BIGG ; + return -log(-log(pq.p)) ; +} + +/*---------------------------------------------------------------- + Weibull distribution: cdf(x) = 1 - exp( -x^c ) for x>0 and c>0. +------------------------------------------------------------------*/ + +static pqpair weibull_s2pq( double x , double c ) +{ + double y ; + pqpair pq={0.0,1.0} ; + + if( x <= 0.0 || c <= 0.0 ) return pq ; + + y = pow(x,c) ; pq.q = exp(-y) ; + if( y >= 1.e-4 ) pq.p = 1.0-pq.q ; + else pq.p = y*(1.0+y*(-0.5+y*(1.0/6.0-y/24.0))) ; + return pq ; +} + +/*------------------------------*/ + +static double weibull_pq2s( pqpair pq , double c ) +{ + if( pq.p <= 0.0 || c <= 0.0 ) return 0.0 ; + else if( pq.q <= 0.0 ) return BIGG ; + return pow( -log(pq.q) , 1.0/c ) ; +} + +/*---------------------------------------------------------------- + Inverse Gaussian: + density proportional to exp(-0.5*c(x+1/x))/x^1.5 (x,c >0). +------------------------------------------------------------------*/ + +static pqpair invgauss_s2pq( double x, double c ) +{ + double y , p1,q1 , p2,q2 , v ; + pqpair pq={0.0,1.0} ; + + if( x <= 0.0 || c <= 0.0 ) return pq ; + + y = sqrt(c/x) ; + v = y*(x-1.0) ; cumnor( &v , &p1,&q1 ) ; + v = -y*(x+1.0) ; cumnor( &v , &p2,&q2 ) ; + pq.p = p1 ; + if( p2 > 0.0 ) pq.p += exp(2.0*c+log(p2)) ; + pq.q = 1.0-pq.p ; return pq ; +} + +/*------------------------------*/ +/* Inverse to above function; + uses cdflib dstinv()/dinvr() + to solve the equation. +--------------------------------*/ + +static double invgauss_pq2s( pqpair pq , double c ) +{ + double t ; /* will be result */ + double tbot,ttop , dt ; + double T6=1.e-50,T7=1.e-8 ; + double K4=0.5,K5=5.0 ; + double fx ; + unsigned long qhi,qleft ; + int status , qporq , ite ; + pqpair tpq ; + + if( c <= 0.0 ) return BIGG ; /* bad user */ + if( pq.p <= 0.0 ) return 0.0 ; + if( pq.q <= 0.0 ) return BIGG ; + + /* initial guess is t=1; scan down for lower bound */ + + tbot = 1.01 ; dt = 0.9 ; + for( ite=0 ; ite < 1000 ; ite++ ){ + tpq = invgauss_s2pq( tbot , c ) ; + if( tpq.p <= pq.p ) break ; + tbot *= dt ; + } + if( ite >= 1000 ) return 0.0 ; + + /* scan up for upper bound */ + + dt = 1.1 ; ttop = tbot*dt ; + for( ite=0 ; ite < 1000 ; ite++ ){ + tpq = invgauss_s2pq( ttop , c ) ; + if( tpq.p >= pq.p ) break ; + ttop *= dt ; + } + if( ite >= 1000 ) return BIGG ; + + t = sqrt(tbot*ttop) ; /* start at geometric mean */ + + /* initialize searching parameters */ + + dstinv(&tbot,&ttop,&K4,&K4,&K5,&T6,&T7); + + status = 0 ; qporq = (pq.p <= pq.q) ; + + while(1){ + + dinvr(&status,&t,&fx,&qleft,&qhi) ; + + if( status != 1 ) return t ; /* done! */ + + tpq = invgauss_s2pq( t , c ) ; + + /* goal is to drive fx to zero */ + + fx = (qporq) ? pq.p-tpq.p : pq.q-tpq.q ; + } + + return BIGG ; /* unreachable */ +} + +/*--------------------------------------------------------------------------*/ +/*! Given a value, calculate both its cdf and reversed cdf (1.0-cdf). + If an error occurs, you'll probably get back {0.0,1.0}. + All the actual work is done in utility functions for each distribution. +----------------------------------------------------------------------------*/ + +static pqpair stat2pq( double val, int code, double p1,double p2,double p3 ) +{ + pqpair pq={0.0,1.0} ; + + switch( code ){ + + case NIFTI_INTENT_CORREL: pq = correl_s2pq ( val, p1 ) ; break; + case NIFTI_INTENT_TTEST: pq = student_s2pq ( val, p1 ) ; break; + case NIFTI_INTENT_FTEST: pq = fstat_s2pq ( val, p1,p2 ) ; break; + case NIFTI_INTENT_ZSCORE: pq = normal_s2pq ( val ) ; break; + case NIFTI_INTENT_CHISQ: pq = chisq_s2pq ( val, p1 ) ; break; + case NIFTI_INTENT_BETA: pq = beta_s2pq ( val, p1,p2 ) ; break; + case NIFTI_INTENT_BINOM: pq = binomial_s2pq( val, p1,p2 ) ; break; + case NIFTI_INTENT_GAMMA: pq = gamma_s2pq ( val, p1,p2 ) ; break; + case NIFTI_INTENT_POISSON: pq = poisson_s2pq ( val, p1 ) ; break; + case NIFTI_INTENT_FTEST_NONC: pq = fnonc_s2pq ( val, p1,p2,p3 ); break; + case NIFTI_INTENT_CHISQ_NONC: pq = chsqnonc_s2pq( val, p1,p2 ); break; + case NIFTI_INTENT_TTEST_NONC: pq = tnonc_s2pq ( val, p1,p2 ) ; break; + case NIFTI_INTENT_CHI: pq = chi_s2pq ( val, p1 ) ; break; + + /* these distributions are shifted and scaled copies of a standard case */ + + case NIFTI_INTENT_INVGAUSS: + if( p1 > 0.0 && p2 > 0.0 ) pq = invgauss_s2pq( val/p1,p2/p1 ) ; break; + + case NIFTI_INTENT_WEIBULL: + if( p2 > 0.0 && p3 > 0.0 ) pq = weibull_s2pq ((val-p1)/p2,p3) ; break; + + case NIFTI_INTENT_EXTVAL: + if( p2 > 0.0 ) pq = extval1_s2pq ( (val-p1)/p2 ) ; break; + + case NIFTI_INTENT_NORMAL: + if( p2 > 0.0 ) pq = normal_s2pq ( (val-p1)/p2 ) ; break; + + case NIFTI_INTENT_LOGISTIC: + if( p2 > 0.0 ) pq = logistic_s2pq( (val-p1)/p2 ) ; break; + + case NIFTI_INTENT_LAPLACE: + if( p2 > 0.0 ) pq = laplace_s2pq ( (val-p1)/p2 ) ; break; + + case NIFTI_INTENT_UNIFORM: + if( p2 > p1 ) pq = uniform_s2pq((val-p1)/(p2-p1)); break; + + /* this case is trivial */ + + case NIFTI_INTENT_PVAL: pq.p = 1.0-val ; pq.q = val ; break; + } + + return pq ; +} + +/*--------------------------------------------------------------------------*/ +/*! Given a pq value (cdf and 1-cdf), compute the value that gives this. + If an error occurs, you'll probably get back a BIGG number. + All the actual work is done in utility functions for each distribution. +----------------------------------------------------------------------------*/ + +static double pq2stat( pqpair pq, int code, double p1,double p2,double p3 ) +{ + double val=BIGG ; + + if( pq.p < 0.0 || pq.q < 0.0 || pq.p > 1.0 || pq.q > 1.0 ) return val ; + + switch( code ){ + + case NIFTI_INTENT_CORREL: val = correl_pq2s ( pq , p1 ) ; break; + case NIFTI_INTENT_TTEST: val = student_pq2s ( pq , p1 ) ; break; + case NIFTI_INTENT_FTEST: val = fstat_pq2s ( pq , p1,p2 ) ; break; + case NIFTI_INTENT_ZSCORE: val = normal_pq2s ( pq ) ; break; + case NIFTI_INTENT_CHISQ: val = chisq_pq2s ( pq , p1 ) ; break; + case NIFTI_INTENT_BETA: val = beta_pq2s ( pq , p1,p2 ) ; break; + case NIFTI_INTENT_BINOM: val = binomial_pq2s( pq , p1,p2 ) ; break; + case NIFTI_INTENT_GAMMA: val = gamma_pq2s ( pq , p1,p2 ) ; break; + case NIFTI_INTENT_POISSON: val = poisson_pq2s ( pq , p1 ) ; break; + case NIFTI_INTENT_FTEST_NONC: val = fnonc_pq2s ( pq , p1,p2,p3 ); break; + case NIFTI_INTENT_CHISQ_NONC: val = chsqnonc_pq2s( pq , p1,p2 ); break; + case NIFTI_INTENT_TTEST_NONC: val = tnonc_pq2s ( pq , p1,p2 ) ; break; + case NIFTI_INTENT_CHI: val = chi_pq2s ( pq , p1 ) ; break; + + /* these distributions are shifted and scaled copies of a standard case */ + + case NIFTI_INTENT_INVGAUSS: + if( p1 > 0.0 && p2 > 0.0 ) val = p1*invgauss_pq2s ( pq,p2/p1); break; + + case NIFTI_INTENT_WEIBULL: + if( p2 > 0.0 && p3 > 0.0 ) val = p1+p2*weibull_pq2s ( pq, p3 ) ; break; + + case NIFTI_INTENT_EXTVAL: + if( p2 > 0.0 ) val = p1+p2*extval1_pq2s ( pq ) ; break; + + case NIFTI_INTENT_NORMAL: + if( p2 > 0.0 ) val = p1+p2*normal_pq2s ( pq ) ; break; + + case NIFTI_INTENT_LOGISTIC: + if( p2 > 0.0 ) val = p1+p2*logistic_pq2s( pq ) ; break; + + case NIFTI_INTENT_LAPLACE: + if( p2 > 0.0 ) val = p1+p2*laplace_pq2s ( pq ) ; break; + + case NIFTI_INTENT_UNIFORM: + if( p2 > p1 ) val = p1+(p2-p1)*uniform_pq2s(pq) ; break; + + /* this case is trivial */ + + case NIFTI_INTENT_PVAL: val = pq.q ; break; + } + + return val ; +} + +/****************************************************************************/ +/*[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]*/ +/*..........................................................................*/ +/*............. AT LAST! Functions to be called by the user! ..............*/ +/*..........................................................................*/ +/*[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]*/ +/****************************************************************************/ + +/**************************************************************************** + Statistical codes implemented here: + + NIFTI_INTENT_CORREL = correlation statistic + NIFTI_INTENT_TTEST = t statistic (central) + NIFTI_INTENT_FTEST = F statistic (central) + NIFTI_INTENT_ZSCORE = N(0,1) statistic + NIFTI_INTENT_CHISQ = Chi-squared (central) + NIFTI_INTENT_BETA = Beta variable (central) + NIFTI_INTENT_BINOM = Binomial variable + NIFTI_INTENT_GAMMA = Gamma distribution + NIFTI_INTENT_POISSON = Poisson distribution + NIFTI_INTENT_FTEST_NONC = noncentral F statistic + NIFTI_INTENT_CHISQ_NONC = noncentral chi-squared + NIFTI_INTENT_TTEST_NONC = noncentral t statistic + NIFTI_INTENT_CHI = Chi statistic (central) + NIFTI_INTENT_INVGAUSS = inverse Gaussian variable + NIFTI_INTENT_WEIBULL = Weibull distribution + NIFTI_INTENT_EXTVAL = Extreme value type I + NIFTI_INTENT_NORMAL = N(mu,variance) normal + NIFTI_INTENT_LOGISTIC = Logistic distribution + NIFTI_INTENT_LAPLACE = Laplace distribution + NIFTI_INTENT_UNIFORM = Uniform distribution + NIFTI_INTENT_PVAL = "p-value" +*****************************************************************************/ + +static char *inam[]={ NULL , NULL , + "CORREL" , "TTEST" , "FTEST" , "ZSCORE" , + "CHISQ" , "BETA" , "BINOM" , "GAMMA" , + "POISSON" , "NORMAL" , "FTEST_NONC" , "CHISQ_NONC" , + "LOGISTIC" , "LAPLACE" , "UNIFORM" , "TTEST_NONC" , + "WEIBULL" , "CHI" , "INVGAUSS" , "EXTVAL" , + "PVAL" , + NULL } ; + +#include <ctype.h> +#include <string.h> + +/*--------------------------------------------------------------------------*/ +/*! Given a string name for a statistic, return its integer code. + Returns -1 if not found. +----------------------------------------------------------------------------*/ + +int nifti_intent_code( char *name ) +{ + char *unam , *upt ; + int ii ; + + if( name == NULL || *name == '\0' ) return -1 ; + + unam = strdup(name) ; + for( upt=unam ; *upt != '\0' ; upt++ ) *upt = (char)toupper(*upt) ; + + for( ii=NIFTI_FIRST_STATCODE ; ii <= NIFTI_LAST_STATCODE ; ii++ ) + if( strcmp(inam[ii],unam) == 0 ) break ; + + free(unam) ; + return (ii <= NIFTI_LAST_STATCODE) ? ii : -1 ; +} + +/*--------------------------------------------------------------------------*/ +/*! Given a value, return its cumulative distribution function (cdf): + - val = statistic + - code = NIFTI_INTENT_* statistical code + - p1,p2,p3 = parameters of the distribution + + If an error occurs, you'll probably get back 0.0. +----------------------------------------------------------------------------*/ + +double nifti_stat2cdf( double val, int code, double p1,double p2,double p3 ) +{ + pqpair pq ; + pq = stat2pq( val, code, p1,p2,p3 ) ; + return pq.p ; +} + +/*--------------------------------------------------------------------------*/ +/*! Given a value, return its reversed cumulative distribution function + (1-cdf): + - val = statistic + - code = NIFTI_INTENT_* statistical code + - p1,p2,p3 = parameters of the distribution + + If an error transpires, you'll probably get back 1.0. +----------------------------------------------------------------------------*/ + +double nifti_stat2rcdf( double val, int code, double p1,double p2,double p3 ) +{ + pqpair pq ; + pq = stat2pq( val, code, p1,p2,p3 ) ; + return pq.q ; +} + +/*--------------------------------------------------------------------------*/ +/*! Given a cdf probability, find the value that gave rise to it. + - p = cdf; 0 < p < 1 + - code = NIFTI_INTENT_* statistical code + - p1,p2,p3 = parameters of the distribution + + If an error transpires, you'll probably get back a BIGG number. +----------------------------------------------------------------------------*/ + +double nifti_cdf2stat( double p , int code, double p1,double p2,double p3 ) +{ + pqpair pq ; + pq.p = p ; pq.q = 1.0-p ; + return pq2stat(pq,code,p1,p2,p3) ; +} + +/*--------------------------------------------------------------------------*/ +/*! Given a reversed cdf probability, find the value that gave rise to it. + - q = 1-cdf; 0 < q < 1 + - code = NIFTI_INTENT_* statistical code + - p1,p2,p3 = parameters of the distribution + + If an error transpires, you'll probably get back a BIGG number. +----------------------------------------------------------------------------*/ + +double nifti_rcdf2stat( double q , int code, double p1,double p2,double p3 ) +{ + pqpair pq ; + pq.p = 1.0-q ; pq.q = q ; + return pq2stat(pq,code,p1,p2,p3) ; +} + +/*--------------------------------------------------------------------------*/ +/*! Given a statistic, compute a z-score from it. That is, the output + is z such that cdf(z) of a N(0,1) variable is the same as the cdf + of the given distribution at val. +----------------------------------------------------------------------------*/ + +double nifti_stat2zscore( double val , int code, double p1,double p2,double p3 ) +{ + pqpair pq ; + + if( code == NIFTI_INTENT_ZSCORE ) return val ; /* trivial */ + if( code == NIFTI_INTENT_NORMAL ) return (val-p1)/p2 ; /* almost so */ + + pq = stat2pq( val, code, p1,p2,p3 ) ; /* find cdf */ + return normal_pq2s( pq ) ; /* find z */ +} + +/*--------------------------------------------------------------------------*/ +/*! Given a statistic, compute a half-z-score from it. That is, the output + is z such that cdf(z) of a half-N(0,1) variable is the same as the cdf + of the given distribution at val. A half-N(0,1) variable has density + zero for z < 0 and twice the usual N(0,1) density for z > 0. +----------------------------------------------------------------------------*/ + +double nifti_stat2hzscore( double val, int code, double p1,double p2,double p3 ) +{ + pqpair pq ; + + pq = stat2pq( val, code, p1,p2,p3 ) ; /* find cdf */ + pq.q = 0.5*(1.0-pq.p) ; pq.p = 0.5*(1.0+pq.p) ; /* mangle it */ + return normal_pq2s( pq ) ; /* find z */ +} + +/****************************************************************************/ +/*[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]*/ +/****************************************************************************/ + +/*--------------------------------------------------------------------------*/ +/* Sample program to test the above functions. Otherwise unimportant. +----------------------------------------------------------------------------*/ + +int main( int argc , char *argv[] ) +{ + double val , p , q , p1=0.0,p2=0.0,p3=0.0 ; + double vbot,vtop,vdel ; + int code , iarg=1 , doq=0 , dod=0 , doi=0 , doz=0 , doh=0 ; + + /*-- print some help for the pitiful user --*/ + + if( argc < 3 || strstr(argv[1],"help") != NULL ){ + int ii ; + printf("\n") ; + printf("Demo program for computing NIfTI statistical functions.\n") ; + printf("Usage: nifti_stats [-q|-d|-1|-z] val CODE [p1 p2 p3]\n") ; + printf(" val can be a single number or in the form bot:top:step.\n") ; + printf(" default ==> output p = Prob(statistic < val).\n") ; + printf(" -q ==> output is 1-p.\n") ; + printf(" -d ==> output is density.\n") ; + printf(" -1 ==> output is x such that Prob(statistic < x) = val.\n") ; + printf(" -z ==> output is z such that Normal cdf(z) = p(val).\n") ; + printf(" -h ==> output is z such that 1/2-Normal cdf(z) = p(val).\n"); + printf(" Allowable CODEs:\n") ; + for( ii=NIFTI_FIRST_STATCODE ; ii <= NIFTI_LAST_STATCODE ; ii++ ){ + printf(" %-10s",inam[ii]); if((ii-NIFTI_FIRST_STATCODE)%6==5)printf("\n"); + } + printf("\n") ; + printf(" Following CODE are distributional parameters, as needed.\n"); + printf("\n") ; + printf("Results are written to stdout, 1 number per output line.\n") ; + printf("Example (piping output into AFNI program 1dplot):\n") ; + printf(" nifti_stats -d 0:4:.001 INVGAUSS 1 3 | 1dplot -dx 0.001 -stdin\n"); + printf("\n") ; + printf("Author - RW Cox - SSCC/NIMH/NIH/DHHS/USA/EARTH - March 2004\n") ; + printf("\n") ; + exit(0) ; + } + + /*-- check first arg to see if it is an output option; + if so, set the appropriate output flag to determine what to compute --*/ + + if( strcmp(argv[iarg],"-q") == 0 ){ doq = 1 ; iarg++ ; } + else if( strcmp(argv[iarg],"-d") == 0 ){ dod = 1 ; iarg++ ; } + else if( strcmp(argv[iarg],"-1") == 0 ){ doi = 1 ; iarg++ ; } + else if( strcmp(argv[iarg],"-z") == 0 ){ doz = 1 ; iarg++ ; } + else if( strcmp(argv[iarg],"-h") == 0 ){ doh = 1 ; iarg++ ; } + + /*-- get the value(s) to process --*/ + + vbot=vtop=vdel = 0.0 ; + sscanf( argv[iarg++] , "%lf:%lf:%lf" , &vbot,&vtop,&vdel ) ; + if( vbot >= vtop ) vdel = 0.0 ; + if( vdel <= 0.0 ) vtop = vbot ; + + /*-- decode the CODE into the integer signifying the distribution --*/ + + code = nifti_intent_code(argv[iarg++]) ; + if( code < 0 ){ fprintf(stderr,"illegal code=%s\n",argv[iarg-1]); exit(1); } + + /*-- get the parameters, if present (defaults are 0) --*/ + + if( argc > iarg ) p1 = strtod(argv[iarg++],NULL) ; + if( argc > iarg ) p2 = strtod(argv[iarg++],NULL) ; + if( argc > iarg ) p3 = strtod(argv[iarg++],NULL) ; + + /*-- loop over input value(s), compute output, write to stdout --*/ + + for( val=vbot ; val <= vtop ; val += vdel ){ + if( doq ) /* output = 1-cdf */ + p = nifti_stat2rcdf( val , code,p1,p2,p3 ) ; + else if( dod ) /* output = density */ + p = 1000.0*( nifti_stat2cdf(val+.001,code,p1,p2,p3) + -nifti_stat2cdf(val ,code,p1,p2,p3)) ; + else if( doi ) /* output = inverse */ + p = nifti_cdf2stat( val , code,p1,p2,p3 ) ; + else if( doz ) /* output = z score */ + p = nifti_stat2zscore( val , code,p1,p2,p3 ) ; + else if( doh ) /* output = halfz score */ + p = nifti_stat2hzscore( val , code,p1,p2,p3 ) ; + else /* output = cdf */ + p = nifti_stat2cdf( val , code,p1,p2,p3 ) ; + + printf("%.9g\n",p) ; + if( vdel <= 0.0 ) break ; /* the case of just 1 value */ + } + + /*-- terminus est --*/ + + exit(0) ; +} + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti_stats_mex.c b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti_stats_mex.c new file mode 100644 index 0000000000000000000000000000000000000000..6c617243f9b7f444ffc76f8ab03a4aa649bacef7 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/src/nifti_stats_mex.c @@ -0,0 +1,129 @@ +#ifndef lint +static char svnid[] = "Id: nifti_stats_mex.c 253 2005-10-13 15:31:34Z guillaume "; +#endif +/* + * This is a Matlab mex interface for Bob Cox's extensive nifti_stats.c + * functionality. See nifti_stats.m for documentation. + */ + + +/* + * niftilib $Id: nifti_stats_mex.c,v 1.1 2012/03/22 18:36:33 fissell Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "mex.h" + +#include "nifti1.h" +extern int nifti_intent_code( char *name ); +extern double nifti_stat2cdf( double val, int code, double p1,double p2,double p3 ); +extern double nifti_stat2rcdf( double val, int code, double p1,double p2,double p3 ); +extern double nifti_stat2cdf( double val, int code, double p1,double p2,double p3 ); +extern double nifti_cdf2stat( double val, int code, double p1,double p2,double p3 ); +extern double nifti_stat2zscore( double val, int code, double p1,double p2,double p3 ); +extern double nifti_stat2hzscore( double val, int code, double p1,double p2,double p3 ); + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + double *val, *p, p1=0.0,p2=0.0,p3=0.0 ; + int code=5, dop=1, doq=0, dod=0, doi=0, doz=0, doh=0 ; + int ndim, i, n; + const int *dim; + + if (nlhs>1) mexErrMsgTxt("Too many output arguments."); + if (nrhs<1) mexErrMsgTxt("Not enough input arguments."); + if (nrhs>4) mexErrMsgTxt("Too many input arguments."); + + /* VAL */ + if (!mxIsNumeric(prhs[0]) || !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0])) + mexErrMsgTxt("Wrong datatype for 1st argument."); + ndim = mxGetNumberOfDimensions(prhs[0]); + dim = mxGetDimensions(prhs[0]); + n = 1; + for(i=0,n=1; i<ndim; i++) + n = n*dim[i]; + val = mxGetPr(prhs[0]); + + /* CODE */ + if (nrhs>=2) + { + if (mxIsChar(prhs[1])) + { + int buflen; + char *buf; + buflen = mxGetN(prhs[1])*mxGetM(prhs[1])+1; + buf = (char *)mxCalloc(buflen,sizeof(char)); + mxGetString(prhs[1],buf,buflen); + code = nifti_intent_code(buf); + mxFree(buf); + } + else if (mxIsNumeric(prhs[1]) && mxIsDouble(prhs[1]) && !mxIsComplex(prhs[1])) + { + if (mxGetM(prhs[1])*mxGetN(prhs[1]) != 1) + mexErrMsgTxt("Wrong sized 2nd argument."); + code = (int)mxGetPr(prhs[1])[0]; + } + else mexErrMsgTxt("Wrong datatype for 2nd argument."); + if (code<NIFTI_FIRST_STATCODE || code>NIFTI_LAST_STATCODE) + mexErrMsgTxt("Illegal Stat-Code."); + } + + /* OPT */ + if (nrhs>=3) + { + int buflen; + char *buf; + dop = 0; + if (!mxIsChar(prhs[2])) + mexErrMsgTxt("Wrong datatype for3rd argument."); + buflen = mxGetN(prhs[2])*mxGetM(prhs[2])+1; + buf = (char *)mxCalloc(buflen,sizeof(char)); + mxGetString(prhs[2],buf,buflen); + if ( strcmp(buf,"-p") == 0 ) dop = 1; + else if ( strcmp(buf,"-q") == 0 ) doq = 1; + else if ( strcmp(buf,"-d") == 0 ) dod = 1; + else if ( strcmp(buf,"-1") == 0 ) doi = 1; + else if ( strcmp(buf,"-z") == 0 ) doz = 1; + else if ( strcmp(buf,"-h") == 0 ) doh = 1; + else { mxFree(buf); mexErrMsgTxt("Unrecognised option."); } + mxFree(buf); + } + + /* PARAM */ + if (nrhs>=4) + { + int np; + if (!mxIsNumeric(prhs[3]) || !mxIsDouble(prhs[3]) || mxIsComplex(prhs[3])) + mexErrMsgTxt("Wrong datatype for 4th argument."); + np = mxGetM(prhs[3])*mxGetN(prhs[3]); + if (np>3) mexErrMsgTxt("Wrong sized 4th argument."); + if (np>=1) p1 = mxGetPr(prhs[3])[0]; + if (np>=2) p2 = mxGetPr(prhs[3])[1]; + if (np>=3) p3 = mxGetPr(prhs[3])[2]; + } + + /* P */ + plhs[0] = mxCreateNumericArray(ndim,dim,mxDOUBLE_CLASS,mxREAL); + p = mxGetData(plhs[0]); + + /* Call Bob's code */ + for(i=0; i<n; i++) + { + if ( dop ) + p[i] = nifti_stat2cdf(val[i], code,p1,p2,p3 ) ; + else if ( doq ) + p[i] = nifti_stat2rcdf(val[i], code,p1,p2,p3 ) ; + else if ( dod ) + p[i] = 1000.0*( nifti_stat2cdf(val[i]+.001,code,p1,p2,p3) + -nifti_stat2cdf(val[i] ,code,p1,p2,p3)) ; + else if ( doi ) + p[i] = nifti_cdf2stat(val[i], code,p1,p2,p3 ) ; + else if ( doz ) + p[i] = nifti_stat2zscore(val[i], code,p1,p2,p3 ) ; + else if ( doh ) + p[i] = nifti_stat2hzscore(val[i], code,p1,p2,p3 ) ; + } +} + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/write_extras.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/write_extras.m new file mode 100644 index 0000000000000000000000000000000000000000..49c4cc54591d5f622a6daf54fc0e20381287ccf7 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/write_extras.m @@ -0,0 +1,41 @@ +function extras = write_extras(fname,extras) +% Write extra bits of information +%_______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: write_extras.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: write_extras.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +[pth,nam,ext] = fileparts(fname); +switch ext +case {'.hdr','.img','.nii'} + mname = fullfile(pth,[nam '.mat']); +case {'.HDR','.IMG','.NII'} + mname = fullfile(pth,[nam '.MAT']); +otherwise + mname = fullfile(pth,[nam '.mat']); +end +if isstruct(extras) && ~isempty(fieldnames(extras)), + savefields(mname,extras); +end; + +function savefields(fnam,p) +if length(p)>1, error('Can''t save fields.'); end; +fn = fieldnames(p); +for i_=1:length(fn), + eval([fn{i_} '= p.' fn{i_} ';']); +end; +if str2num(version('-release'))>=14, + fn = {'-V6',fn{:}}; +end; +if numel(fn)>0, + save(fnam,fn{:}); +end; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/write_hdr_raw.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/write_hdr_raw.m new file mode 100644 index 0000000000000000000000000000000000000000..01b65e57f1c75fbffa28bb05af390179d0cc3851 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/private/write_hdr_raw.m @@ -0,0 +1,82 @@ +function ok = write_hdr_raw(fname,hdr,be) +% Write a NIFTI-1 .hdr file. +% FORMAT ok = write_hdr_raw(fname,hdr,be) +% fname - filename of image +% hdr - a structure containing hdr info +% be - whether big-endian or not +% ok - status (1=good, 0=bad) +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: write_hdr_raw.m 2237 2008-09-29 17:39:53Z guillaume + +% +% niftilib $Id: write_hdr_raw.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + + +[pth,nam,ext] = fileparts(fname); +if isempty(pth), pth = pwd; end + +if isfield(hdr,'magic') + org = niftistruc; + switch deblank(hdr.magic) + case {'ni1'} + hname = fullfile(pth,[nam '.hdr']); + case {'n+1'} + hname = fullfile(pth,[nam '.nii']); + otherwise + error('Bad header.'); + end; +else + org = mayostruc; + hname = fullfile(pth,[nam '.hdr']); +end; + +if nargin >=3 + if be, mach = 'ieee-be'; + else mach = 'ieee-le'; + end; +else mach = 'native'; +end; + +ok = true; +if spm_existfile(hname), + fp = fopen(hname,'r+',mach); +else + fp = fopen(hname,'w+',mach); +end +if fp == -1, + ok = false; + return; +end + +for i=1:length(org) + if isfield(hdr,org(i).label), + dat = hdr.(org(i).label); + if length(dat) ~= org(i).len, + if length(dat)< org(i).len, + dat = [dat(:) ; zeros(org(i).len-length(dat),1)]; + else + dat = dat(1:org(i).len); + end; + end; + else + dat = org(i).def; + end; + % fprintf('%s=\n',org(i).label) + % disp(dat) + len = fwrite(fp,dat,org(i).dtype.prec); + if len ~= org(i).len, + ok = false; + end; +end; +fclose(fp); +if ~ok, + fprintf('There was a problem writing to the header of\n'); + fprintf('"%s"\n', fname); +end; +return; + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/structn.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/structn.m new file mode 100644 index 0000000000000000000000000000000000000000..074ab049638eb314e1d66218aac044bde82335fd --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/structn.m @@ -0,0 +1,24 @@ +function t = structn(obj) +% Convert a NIFTI-1 object into a form of struct +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: structn.m 1143 2008-02-07 19:33:33Z spm + +% +% niftilib $Id: structn.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +if numel(obj)~=1, + error('Too many elements to convert'); +end; +fn = fieldnames(obj); +for i=1:length(fn) + tmp = subsref(obj,struct('type','.','subs',fn{i})); + if ~isempty(tmp) + t.(fn{i}) = tmp; + end; +end; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/subsasgn.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/subsasgn.m new file mode 100644 index 0000000000000000000000000000000000000000..5335be170879ac1f762cd66a424934b0f250e46a --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/subsasgn.m @@ -0,0 +1,404 @@ +function obj = subsasgn(obj,subs,varargin) +% Subscript assignment +% See subsref for meaning of fields. +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: subsasgn.m 4136 2010-12-09 22:22:28Z guillaume + +% +% niftilib $Id: subsasgn.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +switch subs(1).type, +case {'.'}, + if numel(obj)~=nargin-2, + error('The number of outputs should match the number of inputs.'); + end; + objs = struct(obj); + for i=1:length(varargin), + val = varargin{i}; + obji = nifti(objs(i)); + obji = fun(obji,subs,val); + objs(i) = struct(obji); + end; + obj = nifti(objs); + +case {'()'}, + objs = struct(obj); + if length(subs)>1, + t = subsref(objs,subs(1)); + % A lot of this stuff is a little flakey, and may cause Matlab to bomb. + % + %if numel(t) ~= nargin-2, + % error('The number of outputs should match the number of inputs.'); + %end; + for i=1:numel(t), + val = varargin{1}; + obji = nifti(t(i)); + obji = subsasgn(obji,subs(2:end),val); + t(i) = struct(obji); + end; + objs = subsasgn(objs,subs(1),t); + else + if numel(varargin)>1, + error('Illegal right hand side in assignment. Too many elements.'); + end; + val = varargin{1}; + if isa(val,'nifti'), + objs = subsasgn(objs,subs,struct(val)); + elseif isempty(val), + objs = subsasgn(objs,subs,[]); + else + error('Assignment between unlike types is not allowed.'); + end; + end; + obj = nifti(objs); + +otherwise + error('Cell contents reference from a non-cell array object.'); +end; +return; +%======================================================================= + +%======================================================================= +function obj = fun(obj,subs,val) +% Subscript referencing + +switch subs(1).type, +case {'.'}, + objs = struct(obj); + for ii=1:numel(objs) + obj = objs(ii); + + if any(strcmpi(subs(1).subs,{'dat'})), + if length(subs)>1, + val = subsasgn(obj.dat,subs(2:end),val); + end; + obj = assigndat(obj,val); + objs(ii) = obj; + continue; + end; + + if isempty(obj.hdr), obj.hdr = empty_hdr; end; + if ~isfield(obj.hdr,'magic'), error('Not a NIFTI-1 header'); end; + + if length(subs)>1, % && ~strcmpi(subs(1).subs,{'raw','dat'}), + val0 = subsref(nifti(obj),subs(1)); + val1 = subsasgn(val0,subs(2:end),val); + else + val1 = val; + end; + + switch(subs(1).subs) + case {'extras'} + if length(subs)>1, + obj.extras = subsasgn(obj.extras,subs(2:end),val); + else + obj.extras = val; + end; + + case {'mat0'} + if ~isnumeric(val1) || ndims(val1)~=2 || any(size(val1)~=[4 4]) || sum((val1(4,:)-[0 0 0 1]).^2)>1e-8, + error('"mat0" should be a 4x4 matrix, with a last row of 0,0,0,1.'); + end; + if obj.hdr.qform_code==0, obj.hdr.qform_code=2; end; + s = double(bitand(obj.hdr.xyzt_units,7)); + if s + d = findindict(s,'units'); + val1 = diag([[1 1 1]/d.rescale 1])*val1; + end; + obj.hdr = encode_qform0(double(val1), obj.hdr); + + case {'mat0_intent'} + if isempty(val1), + obj.hdr.qform_code = 0; + else + if ~ischar(val1) && ~(isnumeric(val1) && numel(val1)==1), + error('"mat0_intent" should be a string or a scalar.'); + end; + d = findindict(val1,'xform'); + if ~isempty(d) + obj.hdr.qform_code = d.code; + end; + end; + + case {'mat'} + if ~isnumeric(val1) || ndims(val1)~=2 || any(size(val1)~=[4 4]) || sum((val1(4,:)-[0 0 0 1]).^2)>1e-8 + error('"mat" should be a 4x4 matrix, with a last row of 0,0,0,1.'); + end; + if obj.hdr.sform_code==0, obj.hdr.sform_code=2; end; + s = double(bitand(obj.hdr.xyzt_units,7)); + if s + d = findindict(s,'units'); + val1 = diag([[1 1 1]/d.rescale 1])*val1; + end; + val1 = val1 * [eye(4,3) [1 1 1 1]']; + obj.hdr.srow_x = val1(1,:); + obj.hdr.srow_y = val1(2,:); + obj.hdr.srow_z = val1(3,:); + + case {'mat_intent'} + if isempty(val1), + obj.hdr.sform_code = 0; + else + if ~ischar(val1) && ~(isnumeric(val1) && numel(val1)==1), + error('"mat_intent" should be a string or a scalar.'); + end; + d = findindict(val1,'xform'); + if ~isempty(d), + obj.hdr.sform_code = d.code; + end; + end; + + case {'intent'} + if ~valid_fields(val1,{'code','param','name'}) + obj.hdr.intent_code = 0; + obj.hdr.intent_p1 = 0; + obj.hdr.intent_p2 = 0; + obj.hdr.intent_p3 = 0; + obj.hdr.intent_name = ''; + else + if ~isfield(val1,'code'), + val1.code = obj.hdr.intent_code; + end; + d = findindict(val1.code,'intent'); + if ~isempty(d), + obj.hdr.intent_code = d.code; + if isfield(val1,'param'), + prm = [double(val1.param(:)) ; 0 ; 0; 0]; + prm = [prm(1:length(d.param)) ; 0 ; 0; 0]; + obj.hdr.intent_p1 = prm(1); + obj.hdr.intent_p2 = prm(2); + obj.hdr.intent_p3 = prm(3); + end; + if isfield(val1,'name'), + obj.hdr.intent_name = val1.name; + end; + end; + end; + + case {'diminfo'} + if ~valid_fields(val1,{'frequency','phase','slice','slice_time'}) + tmp = obj.hdr.dim_info; + for bit=1:6, + tmp = bitset(tmp,bit,0); + end; + obj.hdr.dim_info = tmp; + obj.hdr.slice_start = 0; + obj.hdr.slice_end = 0; + obj.hdr.slice_duration = 0; + obj.hdr.slice_code = 0; + else + if isfield(val1,'frequency'), + tmp = val1.frequency; + if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3, + error('Invalid frequency direction'); + end; + obj.hdr.dim_info = bitset(obj.hdr.dim_info,1,bitget(tmp,1)); + obj.hdr.dim_info = bitset(obj.hdr.dim_info,2,bitget(tmp,2)); + end; + + if isfield(val1,'phase'), + tmp = val1.phase; + if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3, + error('Invalid phase direction'); + end; + obj.hdr.dim_info = bitset(obj.hdr.dim_info,3,bitget(tmp,1)); + obj.hdr.dim_info = bitset(obj.hdr.dim_info,4,bitget(tmp,2)); + end; + + if isfield(val1,'slice'), + tmp = val1.slice; + if ~isnumeric(tmp) || numel(tmp)~=1 || tmp<0 || tmp>3, + error('Invalid slice direction'); + end; + obj.hdr.dim_info = bitset(obj.hdr.dim_info,5,bitget(tmp,1)); + obj.hdr.dim_info = bitset(obj.hdr.dim_info,6,bitget(tmp,2)); + end; + + if isfield(val1,'slice_time') + tim = val1.slice_time; + if ~valid_fields(tim,{'start','end','duration','code'}), + obj.hdr.slice_code = 0; + obj.hdr.slice_start = 0; + obj.hdr.end_slice = 0; + obj.hdr.slice_duration = 0; + else + % sld = double(bitget(obj.hdr.dim_info,5)) + 2*double(bitget(obj.hdr.dim_info,6)); + + if isfield(tim,'start'), + ss = double(tim.start); + if isnumeric(ss) && numel(ss)==1 && ~rem(ss,1), % && ss>=1 && ss<=obj.hdr.dim(sld+1) + obj.hdr.slice_start = ss-1; + else + error('Inappropriate "slice_time.start".'); + end; + end; + + if isfield(tim,'end'), + ss = double(tim.end); + if isnumeric(ss) && numel(ss)==1 && ~rem(ss,1), % && ss>=1 && ss<=obj.hdr.dim(sld+1) + obj.hdr.slice_end = ss-1; + else + error('Inappropriate "slice_time.end".'); + end; + end; + + if isfield(tim,'duration') + sd = double(tim.duration); + if isnumeric(sd) && numel(sd)==1, + s = double(bitand(obj.hdr.xyzt_units,24)); + d = findindict(s,'units'); + if ~isempty(d) && d.rescale, sd = sd/d.rescale; end; + obj.hdr.slice_duration = sd; + else + error('Inappropriate "slice_time.duration".'); + end; + end; + + if isfield(tim,'code'), + d = findindict(tim.code,'sliceorder'); + if ~isempty(d), + obj.hdr.slice_code = d.code; + end; + end; + end; + end; + end; + + case {'timing'} + if ~valid_fields(val1,{'toffset','tspace'}), + obj.hdr.pixdim(5) = 0; + obj.hdr.toffset = 0; + else + s = double(bitand(obj.hdr.xyzt_units,24)); + d = findindict(s,'units'); + if isfield(val1,'toffset'), + if isnumeric(val1.toffset) && numel(val1.toffset)==1, + if d.rescale, + val1.toffset = val1.toffset/d.rescale; + end; + obj.hdr.toffset = val1.toffset; + else + error('"timing.toffset" needs to be numeric with 1 element'); + end; + end; + if isfield(val1,'tspace'), + if isnumeric(val1.tspace) && numel(val1.tspace)==1, + if d.rescale, + val1.tspace = val1.tspace/d.rescale; + end; + obj.hdr.pixdim(5) = val1.tspace; + else + error('"timing.tspace" needs to be numeric with 1 element'); + end; + end; + end; + + case {'descrip'} + if isempty(val1), val1 = char(val1); end; + if ischar(val1), + obj.hdr.descrip = val1; + else + error('"descrip" must be a string.'); + end; + + case {'cal'} + if isempty(val1), + obj.hdr.cal_min = 0; + obj.hdr.cal_max = 0; + else + if isnumeric(val1) && numel(val1)==2, + obj.hdr.cal_min = val1(1); + obj.hdr.cal_max = val1(2); + else + error('"cal" should contain two elements.'); + end; + end; + + case {'aux_file'} + if isempty(val1), val1 = char(val1); end; + if ischar(val1), + obj.hdr.aux_file = val1; + else + error('"aux_file" must be a string.'); + end; + + case {'hdr'} + error('hdr is a read-only field.'); + obj.hdr = val1; + + otherwise + error(['Reference to non-existent field ''' subs(1).subs '''.']); + end; + + objs(ii) = obj; + end + obj = nifti(objs); + +otherwise + error('This should not happen.'); +end; +return; +%======================================================================= + +%======================================================================= +function obj = assigndat(obj,val) +if isa(val,'file_array'), + sz = size(val); + if numel(sz)>7, + error('Too many dimensions in data.'); + end; + sz = [sz 1 1 1 1 1 1 1]; + sz = sz(1:7); + sval = struct(val); + d = findindict(sval.dtype,'dtype'); + if isempty(d) + error(['Unknown datatype (' num2str(double(sval.datatype)) ').']); + end; + + [pth,nam,suf] = fileparts(sval.fname); + if any(strcmp(suf,{'.img','.IMG'})) + val.offset = max(sval.offset,0); + obj.hdr.magic = ['ni1' char(0)]; + elseif any(strcmp(suf,{'.nii','.NII'})) + val.offset = max(sval.offset,352); + obj.hdr.magic = ['n+1' char(0)]; + else + error(['Unknown filename extension (' suf ').']); + end; + val.offset = (ceil(val.offset/16))*16; + obj.hdr.vox_offset = val.offset; + + obj.hdr.dim(2:(numel(sz)+1)) = sz; + nd = max(find(obj.hdr.dim(2:end)>1)); + if isempty(nd), nd = 3; end; + obj.hdr.dim(1) = nd; + obj.hdr.datatype = sval.dtype; + obj.hdr.bitpix = d.size*8; + if ~isempty(sval.scl_slope), obj.hdr.scl_slope = sval.scl_slope; end; + if ~isempty(sval.scl_inter), obj.hdr.scl_inter = sval.scl_inter; end; + obj.dat = val; +else + error('"raw" must be of class "file_array"'); +end; +return; + +function ok = valid_fields(val,allowed) +if isempty(val), ok = false; return; end; +if ~isstruct(val), + error(['Expecting a structure, not a ' class(val) '.']); +end; +fn = fieldnames(val); +for ii=1:length(fn), + if ~any(strcmpi(fn{ii},allowed)), + fprintf('Allowed fieldnames are:\n'); + for i=1:length(allowed), fprintf(' %s\n', allowed{i}); end; + error(['"' fn{ii} '" is not a valid fieldname.']); + end +end +ok = true; +return; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/subsref.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/subsref.m new file mode 100644 index 0000000000000000000000000000000000000000..dcedc971af54b9f1fb05813de10d49a90d0f46e6 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/@nifti/subsref.m @@ -0,0 +1,245 @@ +function varargout = subsref(opt,subs) +% Subscript referencing +% +% Fields are: +% dat - a file-array representing the image data +% mat0 - a 9-parameter affine transform (from qform0) +% Note that the mapping is from voxels (where the first +% is considered to be at [1,1,1], to millimetres. See +% mat0_interp for the meaning of the transform. +% mat - a 12-parameter affine transform (from sform0) +% Note that the mapping is from voxels (where the first +% is considered to be at [1,1,1], to millimetres. See +% mat1_interp for the meaning of the transform. +% mat_intent - intention of mat. This field may be missing/empty. +% mat0_intent - intention of mat0. This field may be missing/empty. +% intent - interpretation of image. When present, this structure +% contains the fields +% code - name of interpretation +% params - parameters needed to interpret the image +% diminfo - MR encoding of different dimensions. This structure may +% contain some or all of the following fields +% frequency - a value of 1-3 indicating frequency direction +% phase - a value of 1-3 indicating phase direction +% slice - a value of 1-3 indicating slice direction +% slice_time - only present when "slice" field is present. +% Contains the following fields +% code - ascending/descending etc +% start - starting slice number +% end - ending slice number +% duration - duration of each slice acquisition +% Setting frequency, phase or slice to 0 will remove it. +% timing - timing information. When present, contains the fields +% toffset - acquisition time of first volume (seconds) +% tspace - time between sucessive volumes (seconds) +% descrip - a brief description of the image +% cal - a two-element vector containing cal_min and cal_max +% aux_file - name of an auxiliary file +% _______________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% +% Id: subsref.m 4136 2010-12-09 22:22:28Z guillaume + +% +% niftilib $Id: subsref.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + + +varargout = rec(opt,subs); +return; + +function c = rec(opt,subs) +switch subs(1).type, +case {'.'}, + c = {}; + opts = struct(opt); + for ii=1:numel(opts) + opt = nifti(opts(ii)); + %if ~isstruct(opt) + % error('Attempt to reference field of non-structure array.'); + %end; + + h = opt.hdr; + if isempty(h), + %error('No header.'); + h = empty_hdr; + end; + + % NIFTI-1 FORMAT + switch(subs(1).subs) + case 'extras', + t = opt.extras; + + case 'raw', % A hidden field + if isa(opt.dat,'file_array'), + tmp = struct(opt.dat); + tmp.scl_slope = []; + tmp.scl_inter = []; + t = file_array(tmp); + else + t = opt.dat; + end; + + case 'dat', + t = opt.dat; + + case 'mat0', + t = decode_qform0(h); + s = double(bitand(h.xyzt_units,7)); + if s + d = findindict(s,'units'); + if ~isempty(d) + t = diag([d.rescale*[1 1 1] 1])*t; + end; + end; + + case 'mat0_intent', + d = findindict(h.qform_code,'xform'); + if isempty(d) || d.code==0, + t = ''; + else + t = d.label; + end; + + case 'mat', + if h.sform_code > 0 + t = double([h.srow_x ; h.srow_y ; h.srow_z ; 0 0 0 1]); + t = t * [eye(4,3) [-1 -1 -1 1]']; + else + t = decode_qform0(h); + end + s = double(bitand(h.xyzt_units,7)); + if s + d = findindict(s,'units'); + t = diag([d.rescale*[1 1 1] 1])*t; + end; + + case 'mat_intent', + if h.sform_code>0, + t = h.sform_code; + else + t = h.qform_code; + end; + d = findindict(t,'xform'); + if isempty(d) || d.code==0, + t = ''; + else + t = d.label; + end; + + case 'intent', + d = findindict(h.intent_code,'intent'); + if isempty(d) || d.code == 0, + %t = struct('code','UNKNOWN','param',[]); + t = []; + else + t = struct('code',d.label,'param',... + double([h.intent_p1 h.intent_p2 h.intent_p3]), 'name',deblank(h.intent_name)); + t.param = t.param(1:length(d.param)); + end + + case 'diminfo', + t = []; + tmp = bitand( h.dim_info ,3); if tmp, t.frequency = double(tmp); end; + tmp = bitand(bitshift(h.dim_info,-2),3); if tmp, t.phase = double(tmp); end; + tmp = bitand(bitshift(h.dim_info,-4),3); if tmp, t.slice = double(tmp); end; + % t = struct('frequency',bitand( h.dim_info ,3),... + % 'phase',bitand(bitshift(h.dim_info,-2),3),... + % 'slice',bitand(bitshift(h.dim_info,-4),3)) + if isfield(t,'slice') + sc = double(h.slice_code); + ss = double(h.slice_start)+1; + se = double(h.slice_end)+1; + ss = max(ss,1); + se = min(se,double(h.dim(t.slice+1))); + + sd = double(h.slice_duration); + s = double(bitand(h.xyzt_units,24)); + d = findindict(s,'units'); + if d.rescale, sd = sd*d.rescale; end; + + ns = (se-ss+1); + d = findindict(sc,'sliceorder'); + if isempty(d) + label = 'UNKNOWN'; + else + label = d.label; + end; + t.slice_time = struct('code',label,'start',ss,'end',se,'duration',sd); + if 0, % Never + t.times = zeros(1,double(h.dim(t.slice+1)))+NaN; + switch sc, + case 0, % Unknown + t.times(ss:se) = zeros(1,ns); + case 1, % sequential increasing + t.times(ss:se) = (0:(ns-1))*sd; + case 2, % sequential decreasing + t.times(ss:se) = ((ns-1):-1:0)*sd; + case 3, % alternating increasing + t.times(ss:2:se) = (0:floor((ns+1)/2-1))*sd; + t.times((ss+1):2:se) = (floor((ns+1)/2):(ns-1))*sd; + case 4, % alternating decreasing + t.times(se:-2:ss) = (0:floor((ns+1)/2-1))*sd; + t.times(se:-2:(ss+1)) = (floor((ns+1)/2):(ns-1))*sd; + end; + end; + end; + + case 'timing', + to = double(h.toffset); + dt = double(h.pixdim(5)); + if to==0 && dt==0, + t = []; + else + s = double(bitand(h.xyzt_units,24)); + d = findindict(s,'units'); + if d.rescale, + to = to*d.rescale; + dt = dt*d.rescale; + end; + t = struct('toffset',to,'tspace',dt); + end; + + case 'descrip', + t = deblank(h.descrip); + msk = find(t==0); + if any(msk), t=t(1:(msk(1)-1)); end; + + case 'cal', + t = [double(h.cal_min) double(h.cal_max)]; + if all(t==0), t = []; end; + + case 'aux_file', + t = deblank(h.aux_file); + + case 'hdr', % Hidden field + t = h; + + otherwise + error(['Reference to non-existent field ''' subs(1).subs '''.']); + end; + if numel(subs)>1, + t = subsref(t,subs(2:end)); + end; + c{ii} = t; + end; +case {'{}'}, + error('Cell contents reference from a non-cell array object.'); +case {'()'}, + opt = struct(opt); + t = subsref(opt,subs(1)); + if length(subs)>1 + c = {}; + for i=1:numel(t), + ti = nifti(t(i)); + ti = rec(ti,subs(2:end)); + c = {c{:}, ti{:}}; + end; + else + c = {nifti(t)}; + end; + +otherwise + error('This should not happen.'); +end; diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/Makefile b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..03e71fcaf915fec9f73da24af95f70b769015784 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/Makefile @@ -0,0 +1,85 @@ +#!make -f +# +# The tardist file for the nifti1 matlab code contains precompiled +# mex files for the PCWIN, MAC, SOL2, LNX86, GLNXA64 platforms, so +# you do not need to do this build if you have one of those platforms. +# Run "uname" at your shell prompt to see your platform code. +# +# +# Two files need to be compiled with the MATLAB mex compiler: +# file2mat.c +# mat2file.c +# These files are in the @file_array/private/src directory. +# A successful compile will leave two "mex" files in the @file_array/private directory: +# file2mat.mex<platform suffix> +# mat2file.mex<platform suffix> +# +# To make the mex files, in this matlab directory type: +# make all +# +# +# Problems ? +# If you need to make platform specific tweaks to the mex call, you +# may want to look at the SPM8 (http://www.fil.ion.ucl.ac.uk/spm/) +# distribution src/Makefile and src/Makefile.var that has more detailed flag settings. +# +# For Windows you need the CygWin environment (http://sourceware.org/cygwin/). +# Install the Default configuration, along with the gcc C compiler, and make +# from the "Devel" options. +# You may want to refer to Matthew Brett's web page on mex files for Windows: +# (http://gnumex.sourceforge.net/) +# + + +## Defines +MEX = mex -O +CC = cc +DIR = @file_array/private/src + + + +## Default targets +unknown: + @ make `uname` + +all: + @ make `uname` + +help: + @echo "make all to compile the file2mat and mat2file mex libraries" + @echo "" + + +## Platforms +SunOS: big_endian +IRIX: big_endian +IRIX64: big_endian +HP-UX: big_endian +AIX: big_endian +OSF1: big_endian + +# for MAC power pc reset to big_endian +Darwin: little_endian + +Linux: little_endian +Linux.A64: little_endian + +CYGWIN_NT-4.0: windows +CYGWIN_NT-5.0: windows +CYGWIN_NT-5.1: windows + + + +## Compiles +big_endian: + (cd $(DIR); $(MEX) -DBIGENDIAN file2mat.c; mv *mex* ..) + (cd $(DIR); $(MEX) -DBIGENDIAN mat2file.c; mv *mex* ..) + +little_endian: + (cd $(DIR); $(MEX) file2mat.c; mv *mex* ..) + (cd $(DIR); $(MEX) mat2file.c; mv *mex* ..) + +windows: + (cd $(DIR); $(MEX) -DSPM_WIN32 file2mat.c; mv *.dll ..) + (cd $(DIR); $(MEX) -DSPM_WIN32 mat2file.c; mv *.dll ..) + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/make.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/make.m new file mode 100644 index 0000000000000000000000000000000000000000..8ffdd4c19ea8f8bcc29efca10db7fdc867385e74 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/make.m @@ -0,0 +1,41 @@ +% +% Makefile equivalent for use in MatLab +% requires availability of MEX +% +% calling 'make' from the matlab prompt: +% 1. compiles the c-sources in @file_array/private/src +% 2. moves the compiled files to @file_array/private +% +% Alle Meije Wink 27/03/2012 +% a.wink@vumc.nl +% + +% +% niftilib $Id: make.m,v 1.1 2012/03/30 15:25:41 fissell Exp $ +% + +% check for existence of MEX compiler +if (exist('mex') ~=2) + error('MEX not installed on your system. Exiting.'); +end + +% go to the directory where the c sources are +cd(['@file_array' filesep 'private' filesep 'src']) + +% compile the 2 sources +if(mex('file2mat.c') | mex('mat2file.c')) + error('something went wrong during compilation'); +else + % move them to the parent directory + if(~movefile('*.mex*','..')) + error('compiled files could not be moved') + end +end + +% go bake to the directory of make.m +cd(['..' filesep '..' filesep '..']); + +% report the good news +disp ('files successfully compiled and moved') + + diff --git a/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/spm_flip_analyze_images.m b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/spm_flip_analyze_images.m new file mode 100644 index 0000000000000000000000000000000000000000..1f56afae12c744dff696773b455c1f347c0c7eb6 --- /dev/null +++ b/NODDI_toolbox_v1.01/niftimatlib-1.2/niftimatlib-1.2/matlab/spm_flip_analyze_images.m @@ -0,0 +1,19 @@ +function flip = spm_flip_analyze_images +% Do Analyze format images need to be left-right flipped? The default +% behaviour is to have the indices of the voxels stored as left-handed and +% interpret the mm coordinates within a right-handed coordinate system. +% +% Note: the behaviour used to be set in spm_defaults.m, but this has now +% been changed. +%__________________________________________________________________________ +% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging + +% John Ashburner +% Id: spm_flip_analyze_images.m 1418 2008-04-15 19:15:16Z john + +% +% niftilib $Id: spm_flip_analyze_images.m,v 1.3 2012/03/22 18:36:33 fissell Exp $ +% + +flip = 1; + diff --git a/PPMI_NODDI.m b/PPMI_NODDI.m new file mode 100644 index 0000000000000000000000000000000000000000..4b62d03e54c9b23c4f775a70c2afa3769f4fb349 --- /dev/null +++ b/PPMI_NODDI.m @@ -0,0 +1,51 @@ +function PPMI_NODDI(i) +addpath(genpath('NODDI_toolbox_v1.0.1')); +importPPMIlist +PatientNumber=VarName1; +%for i=1:floor(length(PatientNumber)/3) +% +% [bVal, bGradX, bGradY, bGradZ] = textread(strcat('/data/project/dti/For_William/rotateDWIv2/BMTXT/',int2str(PatientNumber(i)),'.rotatetwo.BVEC.txt'),'%f %f %f %f'); +% lengthB = length(bGradX); +% +% fileID = fopen(strcat('/data/project/dti/For_William/rotateDWIv2/BMTXT/',int2str(PatientNumber(i)),'.rotatetwo.bval'),'w'); +% +% formatSpec = '%f '; +% +% for j=1:lengthB +% fprintf(fileID,formatSpec,bVal(j)); +% end +% fclose(fileID); +% +% clear fileID +% +% fileID = fopen(strcat('/data/project/dti/For_William/rotateDWIv2/BMTXT/',int2str(PatientNumber(i)),'.rotatetwo.bvec'),'w'); +% +% formatSpec = '%f '; +% +% for j=1:lengthB +% fprintf(fileID,formatSpec,bGradX(j)); +% end +% +% fprintf(fileID,'\n'); +% +% for j=1:lengthB +% fprintf(fileID,formatSpec,bGradY(j)); +% end +% +% fprintf(fileID,'\n'); +% +% for j=1:lengthB +% fprintf(fileID,formatSpec,bGradZ(j)); +% end +% fclose(fileID); +% +% clear fileID + +CreateROI(strcat('/data/project/dti/For_William/rotateDWIv2/finalrotatedDWIv2/',int2str(PatientNumber(i)),'.DWI.rotat.med.nii'),strcat('/data/project/dti/For_William/rotateDWIv2/brainMasks/',int2str(PatientNumber(i)),'.brainmask.nii'),strcat('/data/project/dti/For_William/rotateDWIv2/FreeWaterResults_WB/',int2str(PatientNumber(i)),'.NODDIroi.mat')); +%CreateROI('/data/project/dti/For_William/rotateDWIv2/finalrotatedDWIv2/3111.DWI.rotat.med.nii','/data/project/dti/For_William/rotateDWIv2/brainMasks/3111.brainmask.nii','NODDIroi1.mat') +protocol = FSL2Protocol(strcat('/data/project/dti/For_William/rotateDWIv2/BMTXT/',int2str(PatientNumber(i)),'.rotatetwo.bval'),strcat('/data/project/dti/For_William/rotateDWIv2/BMTXT/',int2str(PatientNumber(i)),'.rotatetwo.bvec')) +noddi = MakeModel('WatsonSHStickTortIsoV_B0'); +batch_fitting(strcat('/data/project/dti/For_William/rotateDWIv2/FreeWaterResults_WB/',int2str(PatientNumber(i)),'.NODDIroi.mat'),protocol,noddi,strcat('/data/project/dti/For_William/rotateDWIv2/FreeWaterResults_WB/',int2str(PatientNumber(i)),'.FittedParams.mat'),8); +SaveParamsAsNIfTI(strcat('/data/project/dti/For_William/rotateDWIv2/FreeWaterResults_WB/',int2str(PatientNumber(i)),'.FittedParams.mat'),strcat('/data/project/dti/For_William/rotateDWIv2/FreeWaterResults_WB/',int2str(PatientNumber(i)),'.NODDIroi.mat'),strcat('/data/project/dti/For_William/rotateDWIv2/brainMasks/',int2str(PatientNumber(i)),'.brainmask.nii'),strcat('/data/project/dti/For_William/rotateDWIv2/FreeWaterResults_WB/',int2str(PatientNumber(i)),'.noddi')) + +end diff --git a/importPPMIlist.m b/importPPMIlist.m new file mode 100644 index 0000000000000000000000000000000000000000..0a381a84f46ce3ef08d987cc482b06249608e593 --- /dev/null +++ b/importPPMIlist.m @@ -0,0 +1,45 @@ +%% Import data from text file. +% Script for importing data from the following text file: +% +% /data/project/dti/For_William/matlab/NODDI_toolbox_v1.0/rotateone.txt +% +% To extend the code to different selected data or a different text file, +% generate a function instead of a script. + +% Auto-generated by MATLAB on 2018/05/01 11:40:45 + +%% Initialize variables. +filename = 'rotateone.txt'; +delimiter = ','; + +%% Format for each line of text: +% column1: double (%f) +% column2: text (%s) +% For more information, see the TEXTSCAN documentation. +formatSpec = '%f%s%[^\n\r]'; + +%% Open the text file. +fileID = fopen(filename,'r'); + +%% Read columns of data according to the format. +% This call is based on the structure of the file used to generate this +% code. If an error occurs for a different file, try regenerating the code +% from the Import Tool. +dataArray = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'TextType', 'string', 'ReturnOnError', false); + +%% Close the text file. +fclose(fileID); + +%% Post processing for unimportable data. +% No unimportable data rules were applied during the import, so no post +% processing code is included. To generate code which works for +% unimportable data, select unimportable cells in a file and regenerate the +% script. + +%% Allocate imported array to column variable names +VarName1 = dataArray{:, 1}; +rotate000I000R000Aashift4100S500L700P = cellstr(dataArray{:, 2}); + + +%% Clear temporary variables +clearvars filename delimiter formatSpec fileID dataArray ans; diff --git a/rotateone.txt b/rotateone.txt new file mode 100644 index 0000000000000000000000000000000000000000..91bd27baf674ec35324aa5fae10fb87c8dc94d10 --- /dev/null +++ b/rotateone.txt @@ -0,0 +1,151 @@ +3775, -rotate 0.00I 0.00R 0.00A -ashift 41.00S 5.00L -7.00P +3325, -rotate 2.00I -0.14R -4.00A -ashift 31.19S 8.35L -14.80P +3866, -rotate 3.00I 0.00R 0.00A -ashift 42.00S 11.98L -11.63P +3584, -rotate 10.00I 0.00R 0.00A -ashift 33.00S 8.24L -7.72P +3816, -rotate -3.00I 8.00R 0.00A -ashift 49.27S 3.99L -19.43P +3814, -rotate -4.00I 0.00R 0.00A -ashift 42.00S 6.40L -7.57P +3181, -rotate 0.00I 12.00R -2.00A -ashift 8.10S -2.72L 9.00P +3151, -rotate 0.00I 16.00R 0.00A -ashift 4.78S -2.00L 4.67P +3852, -rotate 0.00I 16.00R 0.00A -ashift 6.00S 2.50L 14.00P +3355, -rotate 0.00I 27.00R 0.00A -ashift 5.00S 0.00L 13.00P +3157, -rotate 0.00I 28.00R 0.00A -ashift 5.43S 0.00L 14.36P +3390, -rotate 0.00I 8.00R 0.00A -ashift 6.00S -2.50L 20.00P +3788, -rotate 0.00I 8.00R 0.00A -ashift 11.00S 2.00L 7.00P +3830, -rotate 0.17I 12.04R 3.88A -ashift 9.78S -0.05L -2.92P +3350, -rotate -0.22I 26.07R 4.59A -ashift 7.14S -2.61L 11.32P +3358, -rotate 0.25I 26.04R 2.25A -ashift 11.59S -0.76L 12.57P +3368, -rotate -0.31I 22.26R 6.69A -ashift 7.86S -1.99L 8.14P +3178, -rotate 0.35I 9.99R -2.03A -ashift 4S -2L 13P +3321, -rotate 0.35I 9.99R -2.03A -ashift 1.97S 1.00L 12.99P +3191, -rotate -0.42I 7.99R 4.03A -ashift 4.01S 0.43L 14.00P +3800, -rotate -0.46I 20.07R -1.03A -ashift 7S -1.74L -5.10P +3377, -rotate 0.47I 16.02R 1.79A -ashift 5.90S -3.24L 15.02P +3327, -rotate 0.47I 18.10R 4.68A -ashift 9.50S 1.00L 13.97P +3172, -rotate -0.55I 30.36R 5.45A -ashift 4.90S -2.98L 8.31P +3316, -rotate -0.68I 18.00R -0.05A -ashift 7.58S -2.13L 11.25P +4082, -rotate -0.77I 27.04R 1.23A -ashift 5.06S 3.45L 12.92P +4067, -rotate -0.81I 14.12R -4.65A -ashift 8.00S 0.00L 2.00P +3789, -rotate 0.81I 25.06R 2.38A -ashift 4.00S 2.42L 11.92P +3770, -rotate 0.82I 5.03R 2.01A -ashift 7.04S -3.00L 16.44P +3352, -rotate -0.94I 22.07R -4.43A -ashift 6.10S -1.27L 13.96P +3824, -rotate -0.95I 18.00R -0.32A -ashift 9.00S -1.96L 2.03P +3166, -rotate 0.96I 15.10R 3.87A -ashift 8S 1.19L 11.98P +3307, -rotate 0I 10R 0A -ashift 9S 0L 20P +3161, -rotate 0I 12R 0A -ashift 12.24S -4L 14.30P +3311, -rotate 0I 14R 0A -ashift 6.65S -4L 10.13P +3762, -rotate 0I 16R 0A -ashift 12S -5L 22P +3376, -rotate 0I 18R 0A -ashift 8.14S -1L 9.53P +3107, -rotate 0I 20R 0A -ashift 5S -4L 10P +3373, -rotate 0I 22R 0A -ashift 6S 0L 9P +3807, -rotate 0I 22R 0A -ashift 5S -2L 0P +3105, -rotate 0I 26R 0A -ashift 1.03S 2L 7.58P +3563, -rotate 0I 26R 0A -ashift -3S -3L 2P +3570, -rotate 0I 26R 0A -ashift -3S -3L 2P +3855, -rotate 0I 26R 1A -ashift 0S -0.50L 0P +3556, -rotate 0I 27R 0A -ashift 9.67S -0.56L 6.46P +3369, -rotate 0I 28R 0A -ashift 0S -2L 7P +3802, -rotate 0I 28R 0A -ashift -1S -2L -4P +3767, -rotate 0I 9R 0A -ashift 12.21S -0.5L 11.77P +3309, -rotate 1.00I 14.00R 1.00A -ashift 6.06S 2.50L 19.95P +3108, -rotate 1.03I 14R -0.25A -ashift 7.58S -1.79L 12.30P +3853, -rotate -1.04I 15.93R 3.29A -ashift -4.96S -2.59L -0.03P +3826, -rotate 1.08I 22R -0.4A -ashift 10S -2.48L 1.03P +3554, -rotate 1.10I 26R -0.34A -ashift 11.75S -1.50L 12.36P +3808, -rotate 1.11I 23.98R 0.19A -ashift 9.08S -3.18L 5P +3753, -rotate 1.25I 14.09R 3.09A -ashift 8.04S -1L 16.53P +3765, -rotate -1.25I 17.94R -1.75A -ashift 4.00S -1.58L 14.01P +3758, -rotate 1.27I 19.99R 2.13A -ashift 12.67S -2L 16.81P +3571, -rotate 1.29I 21.17R 4.20A -ashift 11S -1.5L 11.08P +3838, -rotate -1.76I 23.02R 1.75A -ashift 7.00S 0.98L -1.02P +3190, -rotate -1.90I 17.99R 1.35A -ashift 7.92S -3.79L 13.83P +3778, -rotate 1.92I 16.13R -3.43A -ashift 9.07S -1L 1.97P +3756, -rotate 10.06I 15.21R 3.06A -ashift 10S -0.5L 15.03P +3332, -rotate -10.12I 33.87R -2.13A -ashift 0.06S -2.99L 3.83P +3173, -rotate 13.42I 9.38R 8.65A -ashift 6.93S 2.78L 12.83P +3760, -rotate 1I 25R 0A -ashift 10.98S -3L 8.05P +3112, -rotate 2.00I 16.00R 0.00A -ashift 8.03S 0.00L -0.72P +3828, -rotate -2.00I 5.00R 0.00A -ashift 9.27S -3.00L 13.30P +3850, -rotate -2.03I 9.99R -1.65A -ashift 2.05S -1.93L 2.95P +3768, -rotate 2.04I 11.99R -0.43A -ashift 11S -0.58L 11.99P +3837, -rotate -2.07I 24.98R -2.21A -ashift 8.95S 2.00L 3.94P +3759, -rotate 2.08I 15.99R 1.43A -ashift 9.38S -2.83L 14.33P +3832, -rotate 2.14I 21.13R 4.23A -ashift 9.00S 0.00L 0.00P +3806, -rotate -2.31I 18R 1.05A -ashift 10S -3L 5P +3763, -rotate 2.44I 14.06R -1.63A -ashift 10.44S -2L 16.23P +3831, -rotate 2.45I 27.17R 2.45A -ashift 10.25S 3.99L 3.85P +3310, -rotate -2.47I 35.97R 1.45A -ashift 7.36S -3.90L -3.07P +3169, -rotate -2.49I 16.05R 2.51A -ashift -0.05S -2.58L 12.03P +3823, -rotate -2.50I 14.94R -0.80A -ashift 4.76S -4.71L 7.16P +3805, -rotate 2.53I 14.03R 1.81A -ashift 10.00S 0.00L 4.00P +3184, -rotate -2.60I 12.03R -2.83A -ashift 1.22S -3.27L 16.84P +4080, -rotate 2.74I 22.16R 4.39A -ashift 7.32S 1.00L 9.54P +3833, -rotate 2.91I 11.10R -2.56A -ashift 4.03S -1.00L -0.02P +3375, -rotate 2.93I 26.10R 4.79A -ashift 4.08S -4.50L 13P +4004, -rotate -2.98I 11R -1.19A -ashift -2.17S 6.06L 5.65P +4083, -rotate 2.98I 23.04R 2.09A -ashift 5.66S 1.37L 9.12P +3320, -rotate 2I 16R 0A -ashift 8.54S -1.00L 12.64P +3308, -rotate 2I 24R 0A -ashift 13.53S -3.5L 12.59P +3354, -rotate 2I 26R 2A -ashift 9.84S -3.34L 14.09P +3392, -rotate 3.00I 16.00R 1.00A -ashift 6.02S 1.00L 10.00P +3769, -rotate -3.00I 17.00R 0.00A -ashift 2.70S -1.00L 18.07P +3118, -rotate 3.02I 25.98R 4.22A -ashift 4.22S -2.15L 11.30P +3835, -rotate -3.09I 19.87R 3.19A -ashift 7.97S 2.00L 0.34P +3389, -rotate 3.15I 29.86R -4.04A -ashift 11.00S -0.69L 12.99P +3365, -rotate 3.22I 28.07R 3.52A -ashift 2.45S -1L 14.13P +3558, -rotate -3.25I 16.01R 1.75A -ashift -1.03S -0.88L 6.01P +3555, -rotate -3.28I 23.97R -1.33A -ashift 7S 0L 18.95P +3559, -rotate -3.36I 20R 1.06A -ashift 0.72S -4L 8.03P +3551, -rotate 3.37I 26.69R 0.47A -ashift -2.01S -0.14L -3.99P +3366, -rotate 3.46I 29.85R 1.74A -ashift 2.14S 1.99L 10.83P +3779, -rotate 3.56I 10.98R -0.62A -ashift 9.60S -0.6L 23.10P +3776, -rotate 3.73I 15.00R 1.04A -ashift 10.95S -2.50L 5.99P +3587, -rotate 3.79I 23.88R -1.74A -ashift 0.00S 2.00L 12.03P +3168, -rotate -3.84I 3R -3A -ashift 5.47S -2L 12.20P +3165, -rotate 3I 14.10R 4.12A -ashift 1S 0L 12P +3125, -rotate 3I 18R 0A -ashift 7.44S 2L 16.27P +3361, -rotate 3I 19R 0A -ashift 5.42S 0L 13.82P +3593, -rotate 4.00I 22.00R 1.00A -ashift 5.82S -1.60L 8.14P +3174, -rotate 4.15I 13.16R 3.41A -ashift 7.05S -0.54L 18.32P +3305, -rotate 4.19I 12.01R -0.81A -ashift 6.58S 0.80L 11.32P +3757, -rotate 4.19I 24.05R 1.11A -ashift 6.39S -1.36L 8.36P +3834, -rotate 4.24I 27.07R 5.42A -ashift 8.09S -0.07L 4.87P +3817, -rotate 4.36I 11.98R 3.07A -ashift 11.03S 0.50L 4.01P +3811, -rotate -4.41I 24.93R -2.14A -ashift 4.14S -1.99L 3.86P +3592, -rotate 4.43I 22.07R 1.98A -ashift 4.71S -0.78L 17.08P +3119, -rotate -4.45I 24R 1.09A -ashift 13S -0.5L 4P +3818, -rotate -4.57I 15.99R 2.08A -ashift 1.93S -3L 1.98P +3104, -rotate 4.66I 27.17R 1.47A -ashift -0.33S 0.22L 8.45P +3764, -rotate 4.72I 22R 1.75A -ashift 11S -1.33L 10.02P +4010, -rotate 4.74I 8.06R 1.74A -ashift 2.29S 6.61L 3.43P +3825, -rotate 4.86I 16.19R -3.12A -ashift 10.93S -2L 3.21P +3809, -rotate -4I 10R 0A -ashift 3.75S -2L 7.14P +3120, -rotate -4I 14R 0A -ashift 5.16S 1L 24.09P +3829, -rotate 4I 18R 0A -ashift 12.85S 0L 4.42P +3812, -rotate 4I 22R 0A -ashift 4S -1.5L 0.14P +3815, -rotate 5.00I 24.00R 0.00A -ashift 2.99S -2.50L 4.03P +3557, -rotate 5.02I 14.38R 3.86A -ashift 5S 0.71L 11.99P +3175, -rotate 5.26I 6.96R 6.04A -ashift 3.16S 0L 8.93P +3777, -rotate 5.41I 23.07R 3.90A -ashift 6.00S 0.00L 18.00P +4024, -rotate -5.43I 15.99R -2.08A -ashift -1.38S -9.94L 13.09P +3771, -rotate 5.53I 22.05R 1.35A -ashift 6.50S 0.52L 15.99P +3102, -rotate 5.64I 31.98R 3.25A -ashift 2.96S 3.45L 11.72P +3575, -rotate 5I 34R 0A -ashift -2.88S -5L 2.03P +3591, -rotate 6.08I 15.99R -0.57A -ashift 3.00S -1.27L 21.02P +3380, -rotate 6.33I 23.18R 6.27A -ashift 4.86S -2.17L 9P +3154, -rotate 6.41I 16.73R 5.20A -ashift 2.47S -3.99L 15.30P +3116, -rotate 6.55I 18.05R -1.45A -ashift 2.93S 2.58L 12.04P +3367, -rotate 6.59I 24.18R 6.59A -ashift 8.56S -4.60L 12.28P +3171, -rotate 6.5I 19R 0A -ashift 7.79S -3.5L 12.14P +3353, -rotate -6.62I 17.93R 5.26A -ashift 5.29S -4.00L 11.41P +3819, -rotate -6.65I 17.99R 2.10A -ashift 7.29S -2L 6.28P +3318, -rotate -6.67I 20.08R -3.53A -ashift 11.70S -3.38L 11.1P +3574, -rotate 6I 12R 0A -ashift 2S 4L 7P +4029, -rotate -6I 19R 0A -ashift 2.69S -7L 18.05P +3787, -rotate 7.03I 14.00R -0.25A -ashift 4.00S -0.95L 3.00P +3123, -rotate -7.19I 27.40R -9.36A -ashift 0.64S -3.58L 8.34P +3780, -rotate 7.25I 16.01R -0.75A -ashift 13.97S 1.70L 17.02P +3372, -rotate 7.27I 25.04R 1.27A -ashift 4S 0.28L 8P +3111, -rotate 8.06I 20.28R 5.07A -ashift 13.89S -3.98L 20.58P +3552, -rotate 8.15I 18.11R 5.66A -ashift 7.00S 0.52L 15.99P +3359, -rotate 9.44I 25.09R 5.01A -ashift 8.89S -3.10L 17.15P +3585, -rotate 9.78I 17.99R 0.40A -ashift 5.86S 6.02L 15.94P