diff --git a/1_preprocessing/andy_temp.m b/1_preprocessing/andy_temp.m
new file mode 100755
index 0000000000000000000000000000000000000000..0cb9ccc6da5e68932641c5b8afb0c83c8992ed43
--- /dev/null
+++ b/1_preprocessing/andy_temp.m
@@ -0,0 +1,95 @@
+function andy_temp(scanname)
+
+% does flatfield correction, normalisation and 2D medianfiltering to the
+% absorption part
+
+%function m=create_abs(scanname)
+% function m=create_abs(scanname)
+tmp=load('parameters.mat');
+acq=tmp.parameters.acq;
+prep=tmp.parameters.prep;
+
+datadir=sprintf('%s/0_rawdata/%s',acq.dir,scanname);
+
+% read the summed dark image and divide it by the number of frames
+% we read in the boundingbox prep.bb, which is slightly bigger than acq.bb
+% the extra margin will be used for intensity normalisation of the images
+% the saved absorption images will be of size acq.bb
+
+d=edf_read(sprintf('%s/darkend0000.edf',datadir),prep.bb)/acq.ndark;
+
+
+%% two little helper functions to put and get subimages defined by a
+%% gt_boundingbox from a bigger image
+
+function a=getbb(im,gtbb)
+   a=im(gtbb(2):gtbb(2)+gtbb(4)-1,gtbb(1):gtbb(1)+gtbb(3)-1);
+end   
+
+function b=putbb(im,gtbb,roi)
+    b=im;
+    b(gtbb(2):gtbb(2)+gtbb(4)-1,gtbb(1):gtbb(1)+gtbb(3)-1)=roi;
+end  
+
+
+
+refname2old=[];
+refname1old=[];
+
+% now loop through all the images:  we do the following processing steps:
+% - flatfield correction
+% - normalization of the beam intensity outside the sample to be equal to
+%   one:  allows to remove horizontal intensity variations in the images
+% - we keep a record of the mean intensity in the image in the vector m(i+1)
+
+for i=0:(acq.nproj-1)
+	
+  %% check if we need ot update the reference images
+  refname1=sprintf('%s/refHST%04d.edf',datadir,floor(i/acq.refon)*acq.refon);
+  refname2=sprintf('%s/refHST%04d.edf',datadir,ceil(i/acq.refon)*acq.refon);
+  if (~strcmp(refname1,refname1old) | ~strcmp(refname2,refname2old))
+    ref1=edf_read(refname1,prep.bb)-d;
+    ref2=edf_read(refname2,prep.bb)-d;
+    refname1old=refname1;
+    refname2old=refname2;
+    %disp([refname1;refname2]);
+  end
+  w=mod(i,acq.refon)/acq.refon;
+  ref=(1-w).*ref1+w.*ref2;
+  
+  name=sprintf('%s/%s%04d.edf',datadir,scanname,i);
+  im=edf_read(name,prep.bb)-d;
+  
+  % keep a record of the mean intensity
+  m(i+1)=mean2(im(:,[1:prep.margin,end-prep.margin+1:end]));
+ 
+  %% flatfield correction
+  %%im=im./ref;
+  
+%   % calculate the vertical mean intensity profile, and normalize images
+%   mim=mean(im(:,[1:prep.margin,end-prep.margin+1:end]),2);
+%   mim=repmat(mim,1,size(im,2));
+%   im=im./mim;
+%   
+%   % apply a 2D median filter to reduce noise
+%   im=medfilt2(im,prep.filtsize);
+%   % correct for vertical drift during scan
+%   im=interpolatef(im,prep.zdrift(i+1),0);
+%   % now put the image back into the full image and cut out the absorption image of size acq.bb
+%   dummy=zeros(acq.ydet,acq.xdet);
+%   im=putbb(dummy,prep.bb,im);
+%   im=getbb(im,acq.bb);
+%   
+%   name=sprintf('%s/1_preprocessing/abs/abs%04d.edf',acq.dir,i)
+%   edf_write(im,name,'float32');
+%  
+i
+end % for
+
+fname=sprintf('%s/1_preprocessing/mean.mat',acq.dir);
+save(fname,'m');
+
+disp('now creating the median filtered images abs/med%04d.edf');
+moving_median_function(0,acq.nproj,acq.nproj,prep.absint,prep.absrange,'1_preprocessing/abs','1_preprocessing/abs','abs',zeros(size(im)),ones(6001,1));
+
+end
diff --git a/1_preprocessing/copyKodak.m b/1_preprocessing/copyKodak.m
new file mode 100755
index 0000000000000000000000000000000000000000..101b16d5dfc4b186ab21366871a9a5084c7b2d73
--- /dev/null
+++ b/1_preprocessing/copyKodak.m
@@ -0,0 +1,47 @@
+function copyKodak(first,last,dirname)
+  disp('copyKodak.m')
+  
+  sourcedir=['/data/id19/inhouse1/graintracking/' dirname];
+  if ~exist(sourcedir,'dir')
+    error('Cannot find directory!')
+  end
+  destinationdir=['/data/id19/graintracking/data/june2007/' dirname '/0_rawdata/' dirname];
+  if ~exist(destinationdir,'dir')
+    mkdir(destinationdir)
+  end
+  copiedfiles=[];
+  while true
+    d=dir([sourcedir '/*']);
+    cfiles=dir([destinationdir '/*']);
+    for n=1:length(cfiles)
+      copiedfiles{n}=cfiles(n).name;
+    end
+    for n=1:length(d)
+      fname=d(n).name;
+      if ~any(strcmp(fname,copiedfiles))
+        fnamein=[sourcedir '/' fname];
+        fnameout=[destinationdir '/' fname];
+        fprintf('Copying %s to %s\n',fnamein,fnameout);
+
+        if strcmp(fname(end-2:end),'edf')
+          im=pfWaitToRead(fnamein);
+          info=edf_info(fnamein);
+          info=rmfield(info,{'dim_1','dim_2'});
+
+
+          info.ccdmodel='Kodak4Mv1';
+          info.israw='true';
+          edf_write(im,fnameout,info)
+        else
+          cmd=sprintf('cp %s %s',fnamein,fnameout);
+          system(cmd);
+        end
+      else
+       1;% fprintf('Not copying %s\n',fname);
+      end
+
+    end
+    disp('Sleeping')
+    pause(5)
+
+  end
diff --git a/1_preprocessing/copygrid_tmp.m b/1_preprocessing/copygrid_tmp.m
new file mode 100755
index 0000000000000000000000000000000000000000..220e049a1d78dda48e43cccbce1753dd1e724e1f
--- /dev/null
+++ b/1_preprocessing/copygrid_tmp.m
@@ -0,0 +1,47 @@
+function copyKodak(first,last,dirname)
+  disp('copyKodak.m')
+  
+  sourcedir=['/data/id19/inhouse/graintracking/june2007/' dirname];
+  if ~exist(sourcedir,'dir')
+    error('Cannot find directory!')
+  end
+  destinationdir=['/data/id19/graintracking/data/june2007/' dirname];
+  if ~exist(destinationdir,'dir')
+    mkdir(destinationdir)
+  end
+  copiedfiles=[];
+  while true
+    d=dir([sourcedir '/*']);
+    cfiles=dir([destinationdir '/*']);
+    for n=1:length(cfiles)
+      copiedfiles{n}=cfiles(n).name;
+    end
+    for n=1:length(d)
+      fname=d(n).name;
+      if ~any(strcmp(fname,copiedfiles))
+        fnamein=[sourcedir '/' fname];
+        fnameout=[destinationdir '/' fname];
+        fprintf('Copying %s to %s\n',fnamein,fnameout);
+
+        if strcmp(fname(end-2:end),'edf')
+          im=pfWaitToRead(fnamein);
+          info=edf_info(fnamein);
+          info=rmfield(info,{'dim_1','dim_2'});
+
+
+          info.ccdmodel='Kodak4Mv1';
+          info.israw='true';
+          edf_write(im,fnameout,info)
+        else
+          cmd=sprintf('cp %s %s',fnamein,fnameout);
+          system(cmd);
+        end
+      else
+       1;% fprintf('Not copying %s\n',fname);
+      end
+
+    end
+    disp('Sleeping')
+    pause(5)
+
+  end
diff --git a/1_preprocessing/create_abs_live.m b/1_preprocessing/create_abs_live.m
new file mode 100755
index 0000000000000000000000000000000000000000..6f99cb076820c59bd230b4aae08573e2fca3c82b
--- /dev/null
+++ b/1_preprocessing/create_abs_live.m
@@ -0,0 +1,182 @@
+% does flatfield correction, normalisation and 2D medianfiltering to the
+% absorption part
+%if the scan has been done as many, broken acquistions, it is easier to the
+%flat-fielding for each partial sequence using sequence_flatfield.  In this
+%case, add a field to parameters:  prep.prior_flatfield.
+%add the possibility to apply a horizontal shift to the images: prep.ydrift
+
+%live! will wait for files to appear during the acquistion as a single
+%condor job
+
+function m=create_abs_live(first, last, workingdirectory)
+% function m=create_abs(scanname)
+disp('CREATE_ABS_LIVE.M')
+ if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end % special case for running interactively in current directory
+
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+cd(workingdirectory);
+
+parameters=[];
+load('parameters.mat');
+acq=parameters.acq;
+prep=parameters.prep;
+
+
+
+datadir=sprintf('%s/0_rawdata/%s',acq.dir,acq.name);
+
+%check if flatfielding is required
+if (isfield(prep,'prior_flatfield') & prep.prior_flatfield==true)
+  do_flatfield=0;
+else
+  do_flatfield=1;
+end
+
+%do drift corrections elsewhere
+%%%check if horizontal drift correction is specified
+%if ~isfield(prep,'ydrift')
+%prep.ydrift = zeros(size(prep.zdrift));
+%end
+
+% read the summed dark image and divide it by the number of frames
+% we read in the boundingbox prep.bb, which is slightly bigger than acq.bb
+% the extra margin will be used for intensity normalisation of the images
+% the saved absorption images will be of size acq.bb
+if do_flatfield 
+    if ~exist(sprintf('%s/darkend0000.edf',datadir))
+        d=pfWaitToRead(sprintf('%s/dark.edf',datadir),prep.bb);
+    else
+        d=pfWaitToRead(sprintf('%s/darkend0000.edf',datadir),prep.bb)/acq.ndark;
+    end
+end
+
+
+%% two little helper functions to put and get subimages defined by a
+%% gt_boundingbox from a bigger image
+
+function a=getbb(im,gtbb)
+   a=im(gtbb(2):gtbb(2)+gtbb(4)-1,gtbb(1):gtbb(1)+gtbb(3)-1);
+end   
+
+function b=putbb(im,gtbb,roi)
+    b=im;
+    b(gtbb(2):gtbb(2)+gtbb(4)-1,gtbb(1):gtbb(1)+gtbb(3)-1)=roi;
+end  
+
+
+
+refname2old=[];
+refname1old=[];
+int0=[];
+% now loop through all the images:  we do the following processing steps:
+% - flatfield correction
+% - normalization of the beam intensity outside the sample to be equal to
+%   one:  allows to remove horizontal intensity variations in the images
+% - we keep a record of the mean intensity in the image in the vector m(i+1)
+
+gtDBConnect
+for i=first:last
+%  gtDBProgressUpdate(mfilename,acq.name,first,last,i);
+%for i= 575:725
+ 
+  if do_flatfield % if doing the flatfield in this step
+  %read image
+ name=sprintf('%s/%s%04d.edf',datadir,acq.name,i)
+
+  im=pfWaitToRead(name,prep.bb)-d;
+    
+%  %ak - this is repeated later....
+%  % keep a record of the mean intensity
+%  m(i+1)=mean2(im(:,[1:prep.margin,end-prep.margin+1:end]));
+  
+  %% check if we need ot update the reference images
+  refname1=sprintf('%s/refHST%04d.edf',datadir,floor(i/acq.refon)*acq.refon);
+  
+  % take mono_tune into account wl 01/2008
+  if isfield(acq,'mono_tune') && acq.mono_tune~=0 % sabine if mono_tune
+      if mod(ceil(i/acq.refon)*acq.refon,acq.mono_tune)==0
+          refname2=sprintf('%s/refHST%04d.edf',datadir,max(0,ceil(i/acq.refon)*acq.refon-1));
+      else
+          refname2=sprintf('%s/refHST%04d.edf',datadir,ceil(i/acq.refon)*acq.refon);
+      end
+  else
+      refname2=sprintf('%s/refHST%04d.edf',datadir,ceil(i/acq.refon)*acq.refon);
+  end
+  
+  if (~strcmp(refname1,refname1old) | ~strcmp(refname2,refname2old))
+   
+    ref1=pfWaitToRead(refname1,prep.bb)-d;
+    ref2=pfWaitToRead(refname2,prep.bb)-d;
+
+    refname1old=refname1;
+    refname2old=refname2;
+  end
+  w=mod(i,acq.refon)/acq.refon;
+  ref=(1-w).*ref1+w.*ref2;
+ 
+  % flatfield correction
+  im=im./ref;
+  
+  else
+  %read flat fielded image
+  name=sprintf('%s/%sflat_%04d.edf',datadir,acq.name,i);  
+  im=pfWaitToRead(name,prep.bb);
+  
+  end%end of if do flat field 
+  %ak - this end statement was missing before)
+  
+%Now do further, special normalisation    
+  % keep a record of the mean intensity, nomralise image intensity
+  switch prep.normalisation
+    case 'margin'   % should be the standard way to do it - leave min 10 pixels left and right from the sample
+      m(i+1)=mean2(im(:,[1:prep.margin,end-prep.margin+1:end]));
+      % calculate the vertical mean intensity profile outside the sample
+      % and renormalize this area to one
+      mim=mean(im(:,[1:prep.margin,end-prep.margin+1:end]),2);
+      mim=repmat(mim,1,size(im,2));
+      im=im./mim;
+    case 'fullbeam'  %ak - mod to use central part of the image (within the sample) to normalise
+      % warning('have a look at this normalisation to check that it makes sense! ak')
+      if i==0
+        int0=mean2(im);
+      else
+         
+        inti=mean2(im);
+        im=(int0/inti)*im;
+      end
+      m(i+1)=mean2(im);  % do nothing - m is obsolete and will not be used any more
+    case 'none'
+      m(i)=1;
+  end  
+ 
+
+  
+  
+  % apply a 2D median filter to reduce noise
+  im=medfilt2(im,prep.filtsize);
+%   %do drift corrections later
+%   % correct for vertical drift during scan
+%   im=interpolatef(im,prep.zdrift(i+1),prep.ydrift(i+1));
+  % now put the image back into the full image and cut out the absorption image of size acq.bb
+  dummy=zeros(acq.ydet,acq.xdet);
+  im=putbb(dummy,prep.bb,im);
+  im=getbb(im,acq.bb);
+  
+  name=sprintf('%s/1_preprocessing/abs/abs%04d.edf',acq.dir,i);
+  edf_write(im,name,'float32');
+ 
+end % for
+
+fname=sprintf('%s/1_preprocessing/mean.mat',acq.dir);
+save(fname,'m');
+
+
+
+
+end
diff --git a/1_preprocessing/create_full.m b/1_preprocessing/create_full.m
new file mode 100755
index 0000000000000000000000000000000000000000..22871d28f3b5b24892f4bac3d63d7e1d8e48803e
--- /dev/null
+++ b/1_preprocessing/create_full.m
@@ -0,0 +1,123 @@
+function create_full(first,last,workingdirectory)
+%add linearity correction if using 4M camera
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+
+cd(workingdirectory);
+
+parameters=[];
+load('parameters.mat');
+
+
+acq=parameters.acq;
+prep=parameters.prep;
+
+name=sprintf('%s/0_rawdata/%s/darkend0000.edf',acq.dir,acq.name);
+
+%4M camera needs an adjustment to linearity
+if isfield(acq, 'camera') && strcmp(acq.camera,'4M')
+  %apply this correction to the dark just once
+  d=(edf_read(name)/acq.ndark).^0.96;
+else
+    d=edf_read(name)/acq.ndark;
+end
+  
+fullmedianold='';
+
+%check if horizontal drift correction is specified, else use zeros
+if ~isfield(prep,'ydrift')
+  prep.ydrift = zeros(size(prep.zdrift));
+end
+
+first=floor(first/prep.absint)*prep.absint;
+last=ceil(last/prep.absint)*prep.absint;
+
+
+for i=first:prep.absint:last-prep.absint
+
+  % check if we need to update the median file of the full images
+  fullmediannew=sprintf('%s/1_preprocessing/full/med%04d.edf',acq.dir,floor(i/prep.fullint)*prep.fullint);
+ 
+  % fullmediannew=sprintf('%s/1_preprocessing/full/med0000.edf',acq.dir);
+  %warning('USING ONLY ONE MEDIAN')
+  %note - these commented lines are for running a partial scan, in which a
+  %single median replaces the moving median
+  
+  if ~strcmp(fullmediannew,fullmedianold)
+    medfull=edf_read(fullmediannew);
+    fullmedianold=fullmediannew;
+  end
+
+  %warning('using only one abs median!')
+  name=sprintf('%s/1_preprocessing/abs/med%04d.edf',acq.dir,i);
+  %name=sprintf('%s/1_preprocessing/abs/med%04d.edf',acq.dir,0);
+  medabs=edf_read(name);
+
+  for j=0:prep.absint-1
+
+    name=sprintf('%s/0_rawdata/%s/%s%04d.edf',acq.dir,acq.name,acq.name,i+j);
+    %4M camera needs an adjustment to linearity
+    if isfield(acq, 'camera') && strcmp(acq.camera,'4M')
+      %dark already corrected
+      full=(edf_read(name).^0.96-d;
+    else
+      full=edf_read(name)-d;
+    end
+    
+    center=gtCrop(full,prep.bb);
+
+    % calculate mean intensity in two vertical stripes of parp.margin width
+    % around the (truncated) direct beam
+    switch prep.normalisation
+      case 'margin'
+        m(i+j+1)=mean2(center(:,[1:prep.margin,end-prep.margin+1:end]));
+        full=prep.intensity/m(i+j+1)*full;
+      case 'fullbeam'
+        m(i+j+1)=mean2(center);
+        full=prep.meanintensity/m(i+j+1)*full;
+      otherwise
+        m(i+j+1)=prep.intensity;
+    end
+
+
+
+    full=full-medfull;
+    full=gtShift(full,round(prep.ydrift(i+j+1)),round(prep.zdrift(i+j+1)));
+    name=sprintf('%s/1_preprocessing/abs/abs%04d.edf',acq.dir,i+j);
+    abs=edf_read(name);
+    direct=prep.intensity*(abs-medabs);
+    full=putbb(full,acq.bb,direct);
+    full=medfilt2(full,prep.filtsize);
+    name=sprintf('%s/1_preprocessing/full/full%04d.edf',acq.dir,i+j);
+    edf_write(full,name,'float32');
+
+    ext=-log(abs)+log(medabs);
+    ext=medfilt2(ext,prep.filtsize);
+    name=sprintf('%s/1_preprocessing/ext/ext%04d.edf',acq.dir,i+j);
+    edf_write(ext,name,'float32');
+
+    disp(sprintf('done image %d',i+j))
+
+
+  end % for j
+end %for i
+
+
+  function b=putbb(im,gtbb,roi)
+    b=im;
+    b(gtbb(2):gtbb(2)+gtbb(4)-1,gtbb(1):gtbb(1)+gtbb(3)-1)=roi;
+  end
+
+
+end
+
+
+
+
diff --git a/1_preprocessing/create_full_live.m b/1_preprocessing/create_full_live.m
new file mode 100755
index 0000000000000000000000000000000000000000..3d870ef94e1778c5205c4335bcb186765a56a549
--- /dev/null
+++ b/1_preprocessing/create_full_live.m
@@ -0,0 +1,118 @@
+function create_full_live(first,last,workingdirectory)
+%live! will wait for files to appear during acquistion
+disp('create_full_live.m')
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+
+cd(workingdirectory);
+parameters=[];
+load('parameters.mat');
+%load parameters
+
+acq=parameters.acq;
+prep=parameters.prep;
+
+name=sprintf('%s/0_rawdata/%s/darkend0000.edf',acq.dir,acq.name);
+d=pfWaitToRead(name)/acq.ndark;
+
+  
+fullmedianold='';
+
+%do drifts later, after preprocessing
+%check if horizontal drift correction is specified, else use zeros
+%if ~isfield(prep,'ydrift')
+%  prep.ydrift = zeros(size(prep.zdrift));
+%end
+
+first=floor(first/prep.absint)*prep.absint;
+last=ceil(last/prep.absint)*prep.absint;
+
+if prep.absint==1
+    last=last+1;
+end
+
+gtDBConnect
+for i=first:prep.absint:last-prep.absint
+    i
+  %gtDBProgressUpdate(mfilename,acq.name,first,last-prep.absint,i);
+  % check if we need to update the median file of the full images
+  fullmediannew=sprintf('%s/1_preprocessing/full/med%04d.edf',acq.dir,floor(i/prep.fullint)*prep.fullint);
+ 
+  % fullmediannew=sprintf('%s/1_preprocessing/full/med0000.edf',acq.dir);
+  %warning('USING ONLY ONE MEDIAN')
+  %note - these commented lines are for running a partial scan, in which a
+  %single median replaces the moving median
+  
+  if ~strcmp(fullmediannew,fullmedianold)
+    medfull=pfWaitToRead(fullmediannew);
+    fullmedianold=fullmediannew;
+  end
+
+  %warning('using only one abs median!')
+  name=sprintf('%s/1_preprocessing/abs/med%04d.edf',acq.dir,i);
+  %name=sprintf('%s/1_preprocessing/abs/med%04d.edf',acq.dir,0);
+  medabs=pfWaitToRead(name);
+
+  for j=0:prep.absint-1
+    j
+    name=sprintf('%s/0_rawdata/%s/%s%04d.edf',acq.dir,acq.name,acq.name,i+j);
+    full=pfWaitToRead(name)-d;
+
+    center=gtCrop(full,prep.bb);
+
+    % calculate mean intensity in two vertical stripes of parp.margin width
+    % around the (truncated) direct beam
+    switch prep.normalisation
+      case 'margin'
+        m(i+j+1)=mean2(center(:,[1:prep.margin,end-prep.margin+1:end]));
+        full=prep.intensity/m(i+j+1)*full;
+      case 'fullbeam'
+        m(i+j+1)=mean2(center);
+        full=prep.intensity/m(i+j+1)*full;
+      otherwise
+        m(i+j+1)=prep.intensity;
+    end
+
+
+    full=full-medfull;
+    %correct drifts after preprocessing
+    %full=gtShift(full,round(prep.ydrift(i+j+1)),round(prep.zdrift(i+j+1)));
+    name=sprintf('%s/1_preprocessing/abs/abs%04d.edf',acq.dir,i+j);
+    abs=pfWaitToRead(name);
+    direct=prep.intensity*(abs-medabs);
+    full=putbb(full,acq.bb,direct);
+    full=medfilt2(full,prep.filtsize);
+    name=sprintf('%s/1_preprocessing/full/full%04d.edf',acq.dir,i+j);
+    edf_write(full,name,'float32');
+
+    ext=-log(abs)+log(medabs);
+
+    ext=medfilt2(ext,prep.filtsize); 
+    
+    name=sprintf('%s/1_preprocessing/ext/ext%04d.edf',acq.dir,i+j);
+    edf_write(ext,name,'float32');
+
+    disp(sprintf('done image %d',i+j))
+
+
+  end % for j
+end %for i
+
+
+  function b=putbb(im,gtbb,roi)
+    b=im;
+    b(gtbb(2):gtbb(2)+gtbb(4)-1,gtbb(1):gtbb(1)+gtbb(3)-1)=roi;
+  end
+
+
+end
+
+
+
+
diff --git a/1_preprocessing/create_full_taper.m b/1_preprocessing/create_full_taper.m
new file mode 100755
index 0000000000000000000000000000000000000000..69eb6391f2793a06b18fc3c91fced40cc08b1301
--- /dev/null
+++ b/1_preprocessing/create_full_taper.m
@@ -0,0 +1,59 @@
+
+function create_full_taper(first, last, workingdirectory)
+
+%%% create fulls for taper images
+
+% /full/med%04d.edf are dark corrected.
+% need to do im - dark - med
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+cd(workingdirectory)
+
+load parameters;
+acq=parameters.acq;
+prep=parameters.prep;
+
+medname2old=[];
+medname1old=[];
+
+%get the dark image
+dark = pfWaitToRead(sprintf('%s/0_rawdata/%s/dark.edf', acq.dir, acq.name));
+
+for i=first:last
+
+  disp(sprintf('doing image %d', i))
+
+  %read the image, subtract dark
+  name=sprintf('%s/0_rawdata/%s/%s%04d.edf', acq.dir, acq.name, acq.name,i);
+  im=pfWaitToRead(name)-dark;
+
+  %% check if we need ot update the median images
+  medname1=sprintf('%s/1_preprocessing/full/med%04d.edf', acq.dir, floor(i/prep.fullint)*prep.fullint);
+  medname2=sprintf('%s/1_preprocessing/full/med%04d.edf', acq.dir, ceil(i/prep.fullint)*prep.fullint);
+
+  if (~strcmp(medname1,medname1old) | ~strcmp(medname2,medname2old))
+    med1=pfWaitToRead(medname1);
+    med2=pfWaitToRead(medname2);
+    medname1old=medname1;
+    medname2old=medname2;
+  end
+
+  %calculate weighted average median image
+  w=mod(i,prep.fullint)/prep.fullint;
+  med=(1-w).*med1 + w.*med2;
+
+  %subtract background
+  im=im-med;
+
+  %write file
+  file_out=sprintf('%s/1_preprocessing/full/full%04d.edf', acq.dir, i);
+  edf_write(im, file_out, 'float32');
+
+end
+
+
+
diff --git a/1_preprocessing/gtAbsMedian_live.m b/1_preprocessing/gtAbsMedian_live.m
new file mode 100755
index 0000000000000000000000000000000000000000..0de07d6e37a43d3b2b9848493a944a71d39a6202
--- /dev/null
+++ b/1_preprocessing/gtAbsMedian_live.m
@@ -0,0 +1,127 @@
+
+function gtAbsMedian_live(first, last, workingdirectory)
+%live function to create the medians of the abs images as they appear.
+%adapt from moving_median_function.m to do the specific case of the abs
+%images (ie already flatfielded so no dark or refs needed, no intensity
+%correction needed)
+
+disp('gtAbsMedian_live.m')
+ if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end % special case for running interactively in current directory
+
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+
+cd(workingdirectory);
+parameters=[];
+load('parameters.mat');
+acq=parameters.acq;
+prep=parameters.prep;
+
+
+nproj=acq.nproj;
+%for a 360 degree run of data need to consider more images
+if strcmp(parameters.acq.type, '180degree') ||  strcmp(parameters.acq.type, '180')
+  nimages=parameters.acq.nproj;
+elseif strcmp(parameters.acq.type, '360degree') || strcmp(parameters.acq.type, '360')
+  nimages=parameters.acq.nproj*2;
+else
+  error('unrecognised data type')
+end
+
+interval=prep.absint;
+range=prep.absrange;
+indir='1_preprocessing/abs';
+outdir='1_preprocessing/abs';
+name='abs';
+
+
+% Problem: some special processing in the beginning and at the end required - no symmetric
+% median available
+
+if first-range/2<0
+  start=0;
+else
+  start=first-range/2;
+end
+
+
+% read the full stack only for the first image - in the following only one image is replaced in the stack
+
+% in case we start from image 0, we use the median calculated from [0:interval:range]
+% and write the same file for the first  0:interval:range/2 images
+
+
+k=0;
+gtDBConnect
+for i=start:interval:start+range
+ % gtDBProgressUpdate(mfilename,acq.name,start,start+range,i);
+  k=k+1;
+  fname=sprintf('%s/%s%04d.edf',indir,name,i);
+  medstack(k,:,:)=pfWaitToRead(fname);
+end
+
+med=squeeze(median(medstack,1));
+
+
+% if we are in the special case of starting before range/2, we write out
+% the same median image range/2/interval times
+if start==0
+  for i=start:interval:range/2
+    fname=sprintf('%s/med%04d.edf',outdir,i);
+    edf_write(med,fname,'float32');
+    start=range/2 + interval;
+  end
+else
+  fname=sprintf('%s/med%04d.edf',outdir,first);
+  edf_write(med,fname,'float32');
+  start=first + interval;
+end
+
+
+% check if we are not running out of images
+
+if last<=nimages-range/2
+  stop=last;
+else
+  stop=nimages-range/2;
+end
+
+%% now process images form start:interval:stop
+
+for i=start:interval:stop
+  k=k+1;
+  if mod(k,range/interval+1)
+    k=mod(k,range/interval+1)
+  else
+    k=range/interval+1
+  end
+
+  fname=sprintf('%s/%s%04d.edf',indir,name,i+range/2);
+  medstack(k,:,:)=pfWaitToRead(fname);
+
+
+  med=squeeze(median(medstack,1));
+  fname=sprintf('%s/med%04d.edf',outdir,i)
+  edf_write(med,fname,'float32');
+
+end
+
+
+% some special processing for the last range/2 images: median is no longer
+% updated since no images > last available
+
+for i=stop+interval:interval:last
+  fname=sprintf('%s/med%04d.edf',outdir,i)
+  edf_write(med,fname,'float32');
+end
+
+end
+
+
+
+
diff --git a/1_preprocessing/gtApplyDrifts.m b/1_preprocessing/gtApplyDrifts.m
new file mode 100755
index 0000000000000000000000000000000000000000..f72d0d6ecf8ca294980df6ee3b3ca3dc52f51db0
--- /dev/null
+++ b/1_preprocessing/gtApplyDrifts.m
@@ -0,0 +1,192 @@
+function gtApplyDrifts(first, last, workingdir, copymode)
+
+%function gtApplyDrifts(first, last, copymode, dirpath, scanname, parameterfile)
+%
+% FUNCTION gtApplyDrifts(first, last, copymode, dirpath, scanname, parameterfile)
+%
+% Shifts edf images in the 'dirpath' with a value given in the parameterfile corresponding to the edf number.  folder OverwritesCopies, corrects and undistorts full images online.
+%
+% INPUT
+%   copymode       = 'online' or 'parallel' 
+%   dirpath        = full path of the folder containing edf-s
+%   scanname       = name of scan
+%   parameterfile  = full path and name of the parameterfile (drifts has to be stored as
+%                     parameters.prep.ydrifts, parameters.prep.zdrifts)
+%
+
+
+%% Extract parameters
+
+cd(workingdir)
+
+if exist('parameters.mat','file')
+  load('parameters.mat')
+else
+  error('Cannot find parameter file!')
+end
+
+disp('Searching files in: ') 
+dirpath=parameters.acq.dir
+disp(' ')
+
+if ~exist(dirpath,'dir')
+  error('Cannot find acquisition directory!')
+end
+
+%scanname=parameters.acq.dir(find(parameters.acq.dir=='/',1,'last')+1:end);
+
+shiftthese=[];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%All the image numbers are extracted from set shiftthese{1}. The other sets
+%are searched for corresponding numbers.
+shiftthese{1}=[dirpath '/1_preprocessing/full/full*.edf'];
+pad{1}=0;
+shiftthese{2}=[dirpath '/1_preprocessing/abs/abs*.edf'];
+pad{2}='av'; % !! the very last abs image won't be treated 
+shiftthese{3}=[dirpath '/1_preprocessing/ext/ext*.edf'];
+pad{3}=0;
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if isdeployed
+  first=str2num(first);
+  last=str2num(last);
+end
+
+disp(' ')
+disp('Shifting and overwriting the following images:')
+disp(' ')
+for i=1:length(shiftthese)
+  disp(shiftthese{i})
+end
+disp(' ')
+disp('"istranslated=true" field is going to be added to the edf headers')
+disp(' ')
+
+%% Copymode online
+if strcmpi(copymode,'online')
+
+  disp('Online version is not yet implemented...')
+  return
+
+%   % read drifts from parameterfile first (or get in from a function), 
+%   % by that time those files must exist, so just overwrite them
+%   check if pfWaitToRead(fname) is ever needed
+
+%   filesdone=[];
+%   counter=0;
+%   
+%   while counter<250
+%     sfiles=dir([dirname '/*']);
+%     n=1;
+%     while n<=length(sfiles)
+%       sfname=sfiles(n).name;
+%       if strcmp('.',sfname(1)) || ~strcmp('.edf',sfname(end-3:end))
+%         sfiles(n)=[];
+%       else
+%         n=n+1;
+%       end
+%     end
+% 
+%
+%     if found==1
+%       counter=0;
+%     else
+%       counter=counter+1;
+%       disp('Sleeping')
+%       pause(5)
+%     end
+
+  
+%% Copymode parallel - do all from first to last
+elseif strcmpi(copymode,'parallel')
+  
+  
+  yshift=parameters.prep.ydrift; % !! im0000 -> yshift(0001) , etc.
+  zshift=parameters.prep.zdrift; % !! im0000 -> zshift(0001) , etc.
+
+  if isempty(yshift)
+    error('parameters.prep.ydrift is empty, check parameter file!')
+  end
+  
+  if isempty(zshift)
+    error('parameters.prep.zdrift is empty, check parameter file!')
+  end
+  
+  fname=[];
+  flist=[];
+  fnamel=[];
+  for i=1:length(shiftthese)
+    flist=dir(shiftthese{i});
+    fnamel(i)=length(flist);
+    for j=1:length(flist)
+%      fname_unsorted{j}=flist(j).name;
+      fname{i,j}=flist(j).name;
+
+    end
+%    fname(i,:)=sort(fname_unsorted);
+  end
+  
+  if fnamel(1)==0
+    error(sprintf('No source files are found as %s',shiftthese{1}))
+  end
+    
+  % Images
+  for i=first:last
+    fnum=fname{1,i};
+    fnum=str2num(fnum(end-7:end-4));
+    if length(yshift)>=fnum+1
+      disp(sprintf('Shifting %s',fname{1,i}))
+      fwr=shiftthese{1};
+      fwr=sprintf('%s%0.4d%s',fwr(1:find(fwr=='*',1,'last')-1),fnum,fwr(end-3:end));
+      sfOverwrite(fwr,yshift(fnum+1),zshift(fnum+1),pad{1}); % !! im0000 -> yshift(0001) , etc.
+    else
+      error('No drift(s) are specified for this image.')
+    end
+    
+  %Corresponding numbered images in shiftthese{:}
+    for j=2:length(shiftthese)
+      flook=shiftthese{j};
+      flook=sprintf('%s%0.4d%s',flook(find(flook=='/',1,'last')+1:find(flook=='*',1,'last')-1),fnum,flook(end-3:end));
+      for k=1:fnamel(j)
+        if strcmp(flook,fname{j,k})  
+          disp(sprintf('  Shifting %s',flook))
+          flook=shiftthese{j};
+          flook=sprintf('%s%0.4d%s',flook(1:find(flook=='*',1,'last')-1),fnum,flook(end-3:end));
+          sfOverwrite(flook,yshift(fnum+1),zshift(fnum+1),pad{2}); % !! im0000 -> yshift(0001) , etc.
+          break
+        end
+      end
+    end
+  end
+else
+  disp('Copymode must be either "online" or "parallel".')
+  error('Copymode is not recognized!')
+end % copymode
+
+end % of function
+
+
+%% Sub-functions
+
+function sfOverwrite(fname, yshift, zshift, pad)
+  im=edf_read(fname); % pfWaitToRead(fname);
+  info=edf_info(fname);
+  
+  %if isfield(info,'istranslated')
+    %yshift=yshift-info.yshift;    % to store absolute shift relative to raw image
+    %zshift=zshift-info.zshift;
+  %end
+  %info.yshift=info.yshift+yshift;
+  %info.zshift=info.zshift+zshift;
+
+  if isfield(info,'istranslated')
+    if strcmp(info.istranslated,'true')
+      warning('Image has been shifted earlier!')
+    end
+  end
+  
+  info.istranslated='true';
+  im=gtShift(im,yshift,zshift,pad);  % gtShift(im,x(horizontal_right),y(vertical_downwards))
+  edf_write(im,fname,info);
+end
diff --git a/1_preprocessing/gtApplyDrifts_raw.m b/1_preprocessing/gtApplyDrifts_raw.m
new file mode 100755
index 0000000000000000000000000000000000000000..bbf3184bce9259d03fd78ca4d172248fa05acb90
--- /dev/null
+++ b/1_preprocessing/gtApplyDrifts_raw.m
@@ -0,0 +1,81 @@
+function gtApplyDrifts_raw(first, last, workingdir, yshift)
+%
+% new version _raw to act on images before Preprocessing.  To put the
+% centre of rotation to pixel 1024.5 *before* making full/abs/ext images
+% this can be integrated into gtCopyCorrectUndistortCondor...
+% Apply a single yshift to align axis
+% yshift = (-1/2)*findshifts2(im0, fliplr(im180)) horizontal part
+
+
+%% Extract parameters
+
+cd(workingdir)
+if exist('parameters.mat','file')
+  load('parameters.mat')
+  acq=parameters.acq;
+else
+  error('Cannot find parameter file!')
+end
+
+% treat raw images only, but need to treat all images - refs/refHSTs as
+% well
+directory = sprintf('%s/0_rawdata/%s/', acq.dir, acq.name);
+pad='av';
+
+if isdeployed
+  first=str2num(first)
+  last=str2num(last)
+  yshift=str2num(yshift)
+end
+
+
+%% Copymode parallel - do all from first to last
+
+if isempty(yshift)
+  error('No yshift specified!')
+end
+
+filelist=dir([directory '*.edf']); %list all edf files
+if length(filelist)==0
+  error(sprintf('no files found in %s', directory))
+end
+  
+  
+  %get the list of files in the directory
+  fname=[];
+  for i=1:length(filelist)
+    fname{i}=filelist(i).name;
+  end
+
+    
+  % Shift images - need to ensure that condor make is run with the right
+  % number of files (or too many?)
+  for i=first:last
+    file_in = sprintf('%s%s', directory, fname{i});
+    sfOverwrite(file_in,yshift,pad);
+  end
+
+
+end % of function
+
+
+%% Sub-functions
+
+  function sfOverwrite(fname, yshift, pad)
+
+    im=edf_read(fname); % pfWaitToRead(fname);
+    info=edf_info(fname);
+
+    if isfield(info,'istranslated')
+      if strcmp(info.istranslated,'true')
+        warning('Image has been shifted earlier!, not touching this file')
+        return
+      end
+    end
+
+    %update istranslated in header
+    info.istranslated='true';
+    im=gtShift(im,yshift,0,pad);  % gtShift(im,x(horizontal_right),y(vertical_downwards))
+    edf_write(im,fname,info);
+
+  end
diff --git a/1_preprocessing/gtApplyDrifts_xxx.m b/1_preprocessing/gtApplyDrifts_xxx.m
new file mode 100755
index 0000000000000000000000000000000000000000..27e787f7b9b3ed0b1ac38b9348f505211211fcd2
--- /dev/null
+++ b/1_preprocessing/gtApplyDrifts_xxx.m
@@ -0,0 +1,142 @@
+function gtApplyDrifts(first, last, copymode, dirpath, scanname, parameterfile)
+
+% FUNCTION gtApplyDrifts(first, last, copymode, dirpath, scanname, parameterfile)
+%
+% Shifts edf images in the 'dirpath' with a value given in the parameterfile corresponding to the edf number.  folder OverwritesCopies, corrects and undistorts full images online.
+%
+% INPUT
+%   copymode       = 'online' or 'parallel' 
+%   dirpath        = full path of the folder containing edf-s
+%   scanname       = name of scan
+%   parameterfile  = full path and name of the parameterfile (drifts has to be stored as
+%                     parameters.prep.ydrifts, parameters.prep.zdrifts)
+%
+
+
+%% Extract parameters
+
+if ~exist(dirpath,'dir')
+  error('Cannot find directory!')
+end
+
+if ~exist(parameterfile,'file')
+  error('Cannot find parameterfile!')
+end
+
+if isdeployed
+  first=str2num(first);
+  last=str2num(last);
+end
+  
+disp(' ')
+disp('Shifting and overwriting images with the following filenames...')
+disp('    - ref*.edf')
+disp(sprintf('    - %s*.edf',scanname))
+disp(' shifted = true/false field is added to edf header')
+disp(' /dark images are not modified/')
+disp(' ')
+
+%% Copymode online
+if strcmpi(copymode,'online')
+
+  disp('Online version is not yet implemented...')
+  return
+
+%   % read drifts from parameterfile first (or get in from a function), 
+%   % by that time those files must exist, so just overwrite them
+%   check if pfWaitToRead(fname) is ever needed
+
+%   filesdone=[];
+%   counter=0;
+%   
+%   while counter<250
+%     sfiles=dir([dirname '/*']);
+%     n=1;
+%     while n<=length(sfiles)
+%       sfname=sfiles(n).name;
+%       if strcmp('.',sfname(1)) || ~strcmp('.edf',sfname(end-3:end))
+%         sfiles(n)=[];
+%       else
+%         n=n+1;
+%       end
+%     end
+% 
+%
+%     if found==1
+%       counter=0;
+%     else
+%       counter=counter+1;
+%       disp('Sleeping')
+%       pause(5)
+%     end
+
+  
+%% Copymode parallel - do all from first to last
+elseif strcmpi(copymode,'parallel')
+  load(parameterfile)
+  yshift=parameters.prep.ydrift; % !! im0000 -> yshift(0001) , etc.
+  zshift=parameters.prep.zdrift; % !! im0000 -> zshift(0001) , etc.
+
+  if isempty(yshift)
+    error('parameters.prep.ydrift is empty, check parameter file!')
+  end
+  
+  if isempty(zshift)
+    error('parameters.prep.zdrift is empty, check parameter file!')
+  end
+  
+  % Images
+  ims=dir([dirpath '/' scanname '*.edf']);
+  for i=first:last
+    fname=[dirpath '/' ims(i).name];
+    disp(sprintf('Shifting %s',fname))
+    fnum=ims(i).name;
+    fnum=str2num(fnum(end-7:end-4));
+    if length(yshift)>=fnum+1
+      sfOverwrite(fname,yshift(fnum+1),zshift(fnum+1)); % !! im0000 -> yshift(0001) , etc.
+    else
+      %disp(sprintf('File: %s',fname))
+      error('No drift(s) are specified for this image.')
+    end
+
+    % Refs with the same number if exists
+    refs=dir(sprintf('%s/ref*%0.4d.edf',dirpath,fnum));
+    if ~isempty(refs)
+      for j=1:length(refs)
+        fname=[dirpath '/' refs(j).name];
+        disp(sprintf('Shifting %s',fname))
+        sfOverwrite(fname,yshift(fnum+1),zshift(fnum+1)); % !! im0000 -> yshift(0001) , etc.
+      end
+    end
+    
+  end
+  
+else
+  disp('Copymode must be either "online" or "parallel".')
+  error('Copymode is not recognized!')
+end % copymode
+
+end % of function
+
+
+%% Sub-functions
+
+function sfOverwrite(fname, yshift, zshift)
+
+  im=edf_read(fname); % pfWaitToRead(fname);
+  info=edf_info(fname);
+  
+  %if isfield(info,'istranslated')
+    %yshift=yshift-info.yshift;
+    %zshift=zshift-info.zshift;
+  %end
+  %info.yshift=info.yshift+yshift;
+  %info.zshift=info.zshift+zshift;
+
+  info.istranslated=true;
+  
+  im=gtShift(im,yshift,zshift);  % gtShift(im,x(horizontal_right),y(vertical_downwards))
+  
+  edf_write(im,fname,info);
+
+end
diff --git a/1_preprocessing/gtBondMethod.m b/1_preprocessing/gtBondMethod.m
new file mode 100755
index 0000000000000000000000000000000000000000..3fda2edfd8888ec3d358208f473ba35931ec7cd6
--- /dev/null
+++ b/1_preprocessing/gtBondMethod.m
@@ -0,0 +1,13 @@
+function angle=gtBondMethod(energy)
+%given an energy in keV, calculate the rotation required to find the Si
+%{111} reflection
+%simple helper function
+
+
+lambda=12.398/energy;
+a=5.431;
+d=a./sqrt([3 27 75 243]);
+theta=asind(lambda./(2*d));
+
+angle=theta;
+
diff --git a/1_preprocessing/gtCart2Hex.m b/1_preprocessing/gtCart2Hex.m
new file mode 100755
index 0000000000000000000000000000000000000000..e42ad37b7ba524b7b984d299658051f0f6168dbe
--- /dev/null
+++ b/1_preprocessing/gtCart2Hex.m
@@ -0,0 +1,45 @@
+
+function hkil=gtCart2Hex(hkl)
+%convert a plane normal in cartesian coordinates (hkl) to four index
+%hexagonal coordinates.
+%reverse of the formulae implemented by Sabine in gtForwardSimulate_360
+%%the output {hkil} is not normalised in any way.
+% A King, 6/2008
+
+load parameters
+
+%cart to hex
+
+
+
+hkil=zeros(size(hkl,1), 4);
+
+%change to hexagonal axes
+hkil(:,1) = hkl(:,1) - (hkl(:,2)/sqrt(3));
+hkil(:,2) = hkl(:,2)*2/sqrt(3);
+hkil(:,3) = -(hkil(:,1)+hkil(:,2));
+hkil(:,4) = hkl(:,3);
+
+%allow for unit cell parameters
+hkil(:,1:3)=hkil(:,1:3)*(parameters.acq.latticepar(1)*sqrt(3))/2;
+hkil(:,4)= hkil(:,4)*parameters.acq.latticepar(3);
+
+
+% %hex to orthogonal    
+% 
+% i=1
+% hkil=[1 1 -2 1]
+% 
+% for i=1:8
+% hkl(i,1)= hkil(i,1) + 0.5 * hkil(i,2);
+% hkl(i,2)= 3^0.5/2 *hkil(i,2);
+% hkl(i,3)= hkil(i,4);
+% 
+% hkl(i,1)=hkl(i,1)*2/(sqrt(3)*parameters.acq.latticepar(1));
+% hkl(i,2)=hkl(i,2)*2/(sqrt(3)*parameters.acq.latticepar(1));
+% hkl(i,3)=hkl(i,3)/parameters .acq.latticepar(3);
+% 
+% %normalise
+% tmp = sqrt(sum((hkl.*hkl),2));
+% hkl = hkl./(repmat(tmp,1,3))
+% end
diff --git a/1_preprocessing/gtCheckParameters.m b/1_preprocessing/gtCheckParameters.m
new file mode 100755
index 0000000000000000000000000000000000000000..03d16fdf0f70d44df6242f22e66f7f70cba3294e
--- /dev/null
+++ b/1_preprocessing/gtCheckParameters.m
@@ -0,0 +1,16 @@
+function prep=gtCheckParameters(acq)
+
+    prep.margin=5;
+    prep.bb    =[acq.bb(1)-prep.margin,acq.bb(2),acq.bb(3)+2*prep.margin,acq.bb(4)];
+    prep.absrange=100;
+    prep.absint=10;
+    prep.filtsize=[3 3];
+    prep.fullint=50;
+    prep.fullrange=500;
+    %prep.zdrift=acq.zdrift;
+    prep.intensity=1800;
+    prep.normalisation='margin';% as default
+end
+
+
+    
\ No newline at end of file
diff --git a/1_preprocessing/gtCopyCorrectUndistortCondor.m b/1_preprocessing/gtCopyCorrectUndistortCondor.m
new file mode 100755
index 0000000000000000000000000000000000000000..d236662ceea53324bcb9d552fc386c1b94b3be15
--- /dev/null
+++ b/1_preprocessing/gtCopyCorrectUndistortCondor.m
@@ -0,0 +1,286 @@
+%function gtCopyCorrectUndistortCondor(first, last, otherparameters)
+function gtCopyCorrectUndistortCondor(first, last, sourcedir, destinationdir, sensortype, distmapfile)
+
+% FUNCTION gtCopyCorrectUndistortFulls(first, last, otherparameters)
+%
+%  to use with gtCopyCorrectUndistortWrapper, which handles condoring.
+%  otherparameters is a string containing :
+% 'copymode sourcedirectory destdirectory sensortype distmap'
+
+% Copies, corrects and undistorts full images online.
+% Destination directory should be .../0_rawdata/scanname .
+% Sensor types recognized:
+%    - Frelon      - no correction applied
+%    - Kodak4Mv1   - missing center line interpolated, 0.96 gamma applied
+%
+% INPUT
+%   sourcedir      = full path of source directory
+%   destinationdir = full path of destination directory
+%
+%   varargin{1}    = full path and name of distortion map file
+%
+
+
+%% Extract parameters
+
+if ~exist(sourcedir,'dir')
+    error('Cannot find source directory!')
+end
+
+if ~exist(destinationdir,'dir')
+    mkdir(destinationdir)
+end
+
+if ~strcmp(distmapfile, 'none')
+    distortion=distortion_read(distmapfile); % distortion map
+    disp('Distortion map loaded.')
+else
+    distortion=[];
+end
+
+if isdeployed
+    first=str2num(first);
+    last=str2num(last);
+end
+
+gtDBConnect
+parameters=[];
+load parameters;
+filetable=[parameters.acq.name '_filetable'];
+
+%determine if we need to move the data from the collection directory to the analysis location.
+%If sourcedir is "xxx/0_rawdata/Orig", and destinationdir is "xxx/0_rawdata/scanname"
+%then data has already been moved.
+path1=sourcedir(1:find(sourcedir=='/',1,'last'));
+path2=destinationdir(1:find(destinationdir=='/',1,'last'));
+source_dirname=sourcedir(find(sourcedir=='/',1,'last')+1:end);
+if strcmp(path1,path2) | strcmp(source_dirname, 'Orig')
+    move_data_flag=0
+else
+    move_data_flag=1
+end
+
+disp('Copying raw images...')
+
+
+counter=0;
+
+while counter<100
+    %get file lists from source and dest dirs
+    sfiles=dir([sourcedir '/*']);
+    if move_data_flag==1
+        cfiles=dir([destinationdir '/../Orig/']); %need to compare to Orig dir if renaming
+    else
+        cfiles=dir(destinationdir); % just accept some unneccessary overwriting for this case
+    end
+    for n=1:length(cfiles)
+        cfnames{n}=cfiles(n).name;
+    end
+    n=1;
+    %go through the source list, remove directories, parameters.mat,
+    %and anything else already copied
+    while n<=length(sfiles)
+        sfname=sfiles(n).name;
+        sfdir=sfiles(n).isdir;
+        if sfdir || strcmp('parameters.mat',sfname) %|| any(strcmp(cfnames, sfname))
+            sfiles(n)=[];
+        else
+            n=n+1;
+        end
+    end
+
+    sfdates=[];
+    for n=1:length(sfiles)
+        sfdates(n)=sfiles(n).datenum;
+    end
+    [sfdates,i]=sort(sfdates);
+
+    %go through source list, do copying if no other instance
+    %of gtCopyCorrect... has already taken the file.
+    found=0;
+
+    for n=1:length(sfiles)
+        %    while length(sfiles)>0
+        %n=ceil(rand*length(sfiles));
+        sfname=sfiles(i(n)).name;
+        %check if sfnamein has already been taken by anther condor job
+        test=0;
+        try
+            test=mym(sprintf('insert into %s (filename) values ("%s")', filetable, sfname));
+        end
+
+        if test==1 %no other job is copying this file, do copy
+
+            disp(sprintf('working on %s',sfname))
+
+            if isfield(parameters.acq, 'interlaced_turns') && parameters.acq.interlaced_turns>0
+                %if using interlaced turns, may need some renaming
+                fnamein=[sourcedir '/' sfiles(i(n)).name];
+                newfname=sfRename(sfiles(i(n)).name); %determine how file should be renamed
+                fnameout=[destinationdir '/' newfname];
+                fnameout_orig=[destinationdir '/../Orig/' sfiles(i(n)).name];%keep original data as collected
+
+            else %standard routine
+                fnamein=[sourcedir '/' sfiles(i(n)).name];
+                newfname=1; %flag to do copy in this case
+                fnameout=[destinationdir '/' sfiles(i(n)).name];
+                fnameout_orig=[destinationdir '/../Orig/' sfiles(i(n)).name];
+            end
+
+            if ~isempty(newfname)
+                fprintf('Copying %s to %s\n',fnamein,fnameout)
+                sfCopy(fnamein,fnameout,fnameout_orig,sensortype,distortion, move_data_flag);
+                found=1;
+            else
+                fprintf('not happy about the filename, skipping...')
+            end
+        end
+        %   sfiles(i(n))=[];%remove this files from the source list
+        %   n=n+1;
+
+        % end %while there are files in the source list
+    end %now a for loop over the file list, working in date order
+
+    if found==0
+        counter=counter+1;
+        pause(10) %have a rest, wait before looking again
+        disp('sleeping 10, then look again')
+    else
+        counter=0;
+    end
+
+end
+disp('Timed out while waited for files to appear... quitting')
+
+
+%% Sub-functions
+
+    function sfCopy(fnamein, fnameout, fnameout_orig, sensortype, distortion, move_data_flag)
+
+        if strcmp(fnamein(end-2:end),'edf')
+            im=pfWaitToRead(fnamein);
+
+            switch lower(sensortype)
+
+                case 'kodak4mv1'
+
+                    info=edf_info(fnamein);
+                    info.ccdmodel='Kodak4Mv1';
+                    info.israw='false';
+                    %%% info=rmfield(info,{'dim_1','dim_2'});
+                    %put these lines into a CorrectKodak function, which is called both from
+                    %here and from inside edf_read
+                    %change israw to a clearer name - isCCDcorrected?
+
+                    midline=1024;
+                    im=[im(1:midline,:); ...
+                        mean([im(midline,:);im(midline+1,:)]);...
+                        im(midline+1:end-1,:)];
+                    im=im.^0.96;
+
+                case 'frelon'
+                    info=edf_info(fnamein);
+
+                otherwise
+                    disp(sprintf('Sensor type: %s',sensortype))
+                    error('Sensor type is not recognized.')
+            end
+
+            if ~isempty(distortion)
+                im_corr=distortion_correct(im,distortion);
+            else
+                im_corr=im;
+            end
+
+            edf_write(im_corr,fnameout,info)
+            %move original file to the Orig directory
+            if move_data_flag
+                try
+                    cmd=sprintf('mv %s %s', fnamein, fnameout_orig);
+                    system(cmd);
+                catch %if no permission to mv, copy instead
+                    cmd=sprintf('cp %s %s', fnamein, fnameout_orig);
+                    system(cmd);
+                end
+            end
+        else %for files that are not .edfs 
+            cmd=sprintf('cp %s %s',fnamein,fnameout);
+            system(cmd);
+            if move_data_flag
+                try
+                    cmd=sprintf('mv %s %s', fnamein, fnameout_orig);
+                    system(cmd);
+                catch %if no permission to mv, copy instead
+                    cmd=sprintf('cp %s %s', fnamein, fnameout_orig);
+                    system(cmd);
+                end
+
+            end
+        end
+    end %end of sfCopy
+
+    function newname=sfRename(oldname)
+        %determine how files should be renamed
+        if 1 %old convention
+            %description of scheme:
+            %for 80 images collected over two turns
+            %note this would be nproj=40 in ftomosetup, so be careful!
+            %keep parameters.acq.nproj as images/180degrees in final data
+            %first turn:
+            %ref0000_0000.edf..., name_0_0000.edf, name_0_0001.edf... name_0_0039.edf, ref0000_0040.edf
+            %second turn:
+            %name_1_0000.edf, name_1_0001.edf... name_1_0039.edf, ref0000_1_0040.edf
+            %we want sequentially number filenames and references groups, without the
+            %turn indication.
+            images_per_turn=(2*parameters.acq.nproj)/(parameters.acq.interlaced_turns+1);
+
+            if strcmp(oldname((end-2):end), 'edf') %edf renaming
+
+                if strcmp(oldname(1:4), 'dark') %for darks don't need to change
+                    newname=oldname;
+
+                elseif strcmp(oldname(1:3), 'ref') %bad idea to name scans ref*!
+                    old_number=str2num(oldname((end-7):(end-4)));
+                    if length(oldname)==16 %no added number in the ref name
+                        chief_turn=0;
+                    elseif length(oldname)==18 %no added number in the ref name
+                        chief_turn=str2num(oldname(9));
+                    else
+                        warning('dont recognise the name of this edf! doing nothing...') %don't rename / renumber / overwrite if not sure!
+                        newname=[];
+                    end
+                    new_number=old_number+(chief_turn*images_per_turn);
+                    newname=sprintf('%s%04d.edf', oldname(1:8), new_number); %keep the ref000x_ part of the name
+
+                    %do this part last because name is *usually* longer than ref name, and
+                    %thus falls over for the case of a ref or a dark
+                elseif strcmp(oldname(1:length(parameters.acq.name)), parameters.acq.name) %if this is an image
+                    chief_turn=str2num(oldname(length(parameters.acq.name)+1));
+                    old_number=str2num(oldname((end-7):(end-4)));
+                    new_number=old_number+(chief_turn*images_per_turn);
+                    newname=sprintf('%s%04d.edf', parameters.acq.name, new_number); %note that in some datasets we exceed 9999 images.
+
+                else
+                    warning('dont recognise the name of this edf! doing nothing...') %don't rename / renumber / overwrite if not sure!
+                    newname=[];
+                end
+
+
+            else %not an edf file
+                newname=oldname;
+
+            end
+
+
+        elseif 0 %new convention if available
+
+
+        end
+
+    end %end of sfRename
+
+
+
+
+
+end %end of function
\ No newline at end of file
diff --git a/1_preprocessing/gtCopyCorrectUndistortFulls.m b/1_preprocessing/gtCopyCorrectUndistortFulls.m
new file mode 100755
index 0000000000000000000000000000000000000000..1b42c9aa4db880431f41ceff792466339a80bedd
--- /dev/null
+++ b/1_preprocessing/gtCopyCorrectUndistortFulls.m
@@ -0,0 +1,98 @@
+
+function gtCopyCorrectUndistortFulls(sourcedir,destinationdir,sensortype,varargin)
+
+%
+% FUNCTION gtCopyCorrectUndistortFulls(sourcedir,destinationdir,sensortype,varargin)
+%
+% Copies, corrects and undistorts full images online.
+% Destination directory should be .../0_rawdata/scanname .
+% Sensor types recognized: 
+%    - Frelon      - no correction applied
+%    - Kodak4Mv1   - missing center line interpolated, 0.96 gamma applied 
+%
+% INPUT 
+%   sourcedir      = full path of source directory
+%   destinationdir = full path of destination directory
+%
+%   varargin{1}    = full path and name of distortion map file
+%
+
+
+if ~exist(sourcedir,'dir')
+  error('Cannot find source directory!')
+end
+
+if ~exist(destinationdir,'dir')
+  mkdir(destinationdir)
+end
+
+if exist('varargin','var')
+  filename_distmapF2D=varargin{1};
+  distortion=distortion_read(filename_distmapF2D); % distortion map
+  disp('Distortion map loaded.')
+else
+  disp('No undistortion applied')
+end
+
+disp('Copying full images...')
+
+copiedfiles=[];
+while true
+  d=dir([sourcedir '/*']);
+  cfiles=dir([destinationdir '/*']);
+  for n=1:length(cfiles)
+    copiedfiles{n}=cfiles(n).name;
+  end
+  for n=1:length(d)
+    fname=d(n).name;
+    if ~any(strcmp(fname,copiedfiles))
+      fnamein=[sourcedir '/' fname];
+      fnameout=[destinationdir '/' fname];
+      fprintf('Copying %s to %s\n',fnamein,fnameout);
+
+      if strcmp(fname(end-2:end),'edf')
+        im=pfWaitToRead(fnamein);
+        
+        switch lower(cameratype)
+
+          case 'kodak4mv1'
+          
+            info=edf_info(fnamein);
+            info.ccdmodel='Kodak4Mv1';
+            info.israw='false';
+            %%%info=rmfield(info,{'dim_1','dim_2'}); why???
+                    
+            im=[im(1:midline,:); ...
+                mean([im(midline,:);im(midline+1,:)]);...
+                im(midline+1:end-1,:)];
+            im=im.^0.96;
+          
+          case 'frelon'
+            info=edf_info(fnamein);
+          
+          otherwise
+            disp(sprintf('Sensor type: %s',sensortype))
+            error('Sensor type is not recognized.')
+        end
+        
+        im_corr=distortion_correct(im,distortion);
+        
+        edf_write(im_corr,fnameout,info)
+      else
+        cmd=sprintf('cp %s %s',fnamein,fnameout);
+        system(cmd);
+      end
+    else
+      1;% fprintf('Not copying %s\n',fname);
+      %%% why???
+    end
+
+  end
+  disp('Sleeping')
+  pause(5)
+
+end
+
+
+
+end % of function
diff --git a/1_preprocessing/gtCopyCorrectUndistortWrapper.m b/1_preprocessing/gtCopyCorrectUndistortWrapper.m
new file mode 100755
index 0000000000000000000000000000000000000000..bd3184f199266901d6f290ed308ccab191fdd84c
--- /dev/null
+++ b/1_preprocessing/gtCopyCorrectUndistortWrapper.m
@@ -0,0 +1,54 @@
+function gtCopyCorrectUndistortWrapper(parameters, sourcedir, destdir)
+%this wrapper calculates the number of jobs to launch.  The function is the
+%same regardless, only the number of parallel instances changes
+
+
+if ~exist('distmapfile','var')
+  distmapfile=[];
+end
+
+%create the database table to manage file transfers for this dataset
+mym('close')
+gtDBConnect('admin')
+filetable=[parameters.acq.name '_filetable'];
+mym(sprintf('drop table if exists %s',filetable));
+mym(sprintf('create table if not exists %s (filename text, unique key (filename(40)))', filetable))
+
+  %kick start the process by copying the .xml file first
+  disp('copying .xml file first to get everything started')
+  cmd=sprintf('cp %s/*.xml %s', sourcedir, destdir);
+  system(cmd);
+  
+  %count files in source dir, nfiles
+  
+  sfiles=dir([sourcedir '/*']);
+  cfiles=dir([destdir '/*']);
+  for n=1:length(cfiles)
+    cfnames{n}=cfiles(n).name;
+  end
+  n=1;
+  %go through the source list, remove directories, parameters.mat,
+  %and anything else already copied
+  while n<=length(sfiles)
+    sfname=sfiles(n).name;
+    sfdir=sfiles(n).isdir;
+    if sfdir || strcmp('parameters.mat',sfname) || any(strcmp(cfnames, sfname))
+      sfiles(n)=[];
+    else
+      n=n+1;
+    end
+  end
+  nfiles=length(sfiles)+1;
+  
+  njobs=ceil(nfiles/500);
+  
+  
+njobs=njobs+4;
+disp('increasing number of jobs for id22')
+
+  
+  condor_make('gtCopyCorrectUndistortCondor', 0 ,njobs*100, njobs, [sourcedir ' ' destdir ' ' parameters.acq.sensortype ' ' parameters.acq.distortion], 1);
+
+
+
+end % of function
diff --git a/1_preprocessing/gtDriftsEndOfScan.m b/1_preprocessing/gtDriftsEndOfScan.m
new file mode 100755
index 0000000000000000000000000000000000000000..42e1d76e8b59af2d044d33a1327ac2197a029d0f
--- /dev/null
+++ b/1_preprocessing/gtDriftsEndOfScan.m
@@ -0,0 +1,261 @@
+function [ydrift,zdrift,varargout]=gtDriftsEndOfScan(acq,bbdir)
+% 
+% Treats images taken as references at end of scan (cropped in bbdir), 
+% determines rotation axis location at sub-pixel and interpolates sample 
+% drifts (thus provides a rough reference).
+%
+% Uses ref0000_xxxx-s for flat field correction.
+%
+% INPUT  
+%   acq = acquisition parameters  
+%   bbdir = direct beam bb according to GT conventions [originx, originy, width, height]
+%            bbdir doesn't need to be centered in full image       
+%            if acq.correlationdim=1 bbdir(4) needs to be even number (for correlate1)
+%            if acq.correlationdim=2 bbdir(3) needs to be even number (for correlate1)
+%
+% OUTPUT  
+%   ydrift, zdrift = direct values with which the images need to be translated
+%                     (e.g direct input for interpolatef)
+%   varargout{1} = rotaxisloc_abs;  rot axis horizontal location in full image 
+%                   (non-integer in pixels)
+%   varargout{2} = rotoff_abs;  rot axis offset in full image; vector pointing
+%                   from center of image to rotation axis location;
+%                   positive to the right
+%   varargout{3} = rotoff;  rot axis offset in bbdir; vector pointing from center
+%                   of bbdir to rotation axis location in bbdir, positive to the right
+%
+% 07/2007 Wolfgang, Peter
+%
+
+
+frame=20; % for bb extension when translating images
+
+if strcmpi(acq.type,'180degree')
+  totproj=acq.nproj;
+elseif strcmpi(acq.type,'360degree');
+  totproj=acq.nproj*2;
+else
+  error('Unknown type of scan. Check acq.type!');
+end
+
+dim=acq.correlationdim;
+
+d=edf_read(sprintf('0_rawdata/%s/dark.edf',acq.name),[],'nodisp');
+
+refend=edf_read(sprintf('0_rawdata/%s/ref%04d_%04d.edf',acq.name,acq.nref-1,totproj),[],'nodisp')-d;
+
+name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj);
+im0=(edf_read(name,[],'nodisp')-d)./refend;
+
+name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+2); 
+im2=(edf_read(name,[],'nodisp')-d)./refend;
+
+a0=gtCrop(im0,bbdir);
+a2=fliplr(gtCrop(im2,bbdir));
+
+% Calculate the double of rotation axis offset from center of bbdir
+rotoff1=median(correlate1(a0',a2'));
+
+% double check this result and modify if necessary by  user intervention...
+a2c=interpolatef(a2,0,rotoff1);
+
+shift=[];
+assignin('base','shift',shift);
+disp(' ')
+disp('Images at end: check result of image correlation with findshifts...')
+disp(' ')
+
+findshifts2(a0,a2c);
+set(gcf,'name','Images at end: check correlation...')
+while isempty(shift)
+  drawnow;
+  shift=evalin('base','shift');
+end
+
+shift=evalin('base','shift');
+rotoff1=shift(2)/2+rotoff1/2
+rotoff2=rotoff1;
+
+close(gcf)
+
+if strcmpi(acq.type,'360degree')
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+1);
+  im1=(edf_read(name,[],'nodisp')-d)./refend;
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+3);
+  im3=(edf_read(name,[],'nodisp')-d)./refend;
+
+  a1=gtCrop(im1,bbdir);
+  a3=fliplr(gtCrop(im3,bbdir));
+
+  rotoff2=median(correlate1(a1',a3'));
+  a3c=interpolatef(a3,0,rotoff2);
+
+  shift=[];
+  assignin('base','shift',shift);
+  disp(' ')
+  disp('Images at end: check result of image correlation with findshifts...')
+  disp(' ')
+  
+  findshifts2(a1,a3c);
+  set(gcf,'name','Images at end: check correlation...')
+  while isempty(shift)
+    drawnow;
+    shift=evalin('base','shift');
+  end
+  shift=evalin('base','shift');
+  rotoff2=shift(2)/2+rotoff2/2
+  close(gcf)
+end
+
+rotoff=(rotoff1+rotoff2)/2
+
+detcenter_abs=acq.xdet/2+0.5;
+bbdircenter_abs=(2*bbdir(1)+bbdir(3)-1)/2;
+
+rotoff_abs=bbdircenter_abs-detcenter_abs+rotoff
+rotaxisloc_abs=bbdircenter_abs+rotoff
+
+% acq.rotx=bbdir(1)+bbdir(3)/2+offset; % check if we should add + 0.5 here
+% or not:  (does the pixel 1 start at 0 or at 0.5 ?)
+
+
+%% Now check if there was a sample drift during the scan and correct for it
+% for the moment we suppose a 360 degree scan with 4 images at the end...
+
+
+bbread=[bbdir(1)-frame,bbdir(2)-frame,bbdir(3)+2*frame,bbdir(4)+2*frame];
+bbor=[frame+1,frame+1,bbdir(3),bbdir(4)];
+
+if strcmpi(acq.type,'360degree');
+
+  name=sprintf('0_rawdata/%s/dark.edf',acq.name);
+  d=edf_read(name,bbread,'nodisp');
+
+  name=sprintf('0_rawdata/%s/ref%04d_%04d.edf',acq.name,acq.nref-1,totproj); % last ref at end of scan
+  refend=edf_read(name,bbread,'nodisp')-d;
+
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj);
+  im_end_360=(edf_read(name,bbread,'nodisp')-d)./refend;
+  im_end_360=interpolatef(im_end_360,0,-rotoff);
+  im_end_360=gtCrop(im_end_360,bbor);
+
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+1);
+  im_end_270=(edf_read(name,bbread,'nodisp')-d)./refend;
+  im_end_270=interpolatef(im_end_270,0,-rotoff);
+  im_end_270=gtCrop(im_end_270,bbor);
+
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+2);
+  im_end_180=(edf_read(name,bbread,'nodisp')-d)./refend;
+  im_end_180=interpolatef(im_end_180,0,-rotoff);
+  im_end_180=gtCrop(im_end_180,bbor);
+
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+3);
+  im_end_90=(edf_read(name,bbread,'nodisp')-d)./refend;
+  im_end_90=interpolatef(im_end_90,0,-rotoff);
+  im_end_90=gtCrop(im_end_90,bbor);
+  
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+4);
+  im_end_0=(edf_read(name,bbread,'nodisp')-d)./refend;
+  im_end_0=interpolatef(im_end_0,0,-rotoff);
+  im_end_0=gtCrop(im_end_0,bbor);
+
+  
+  name=sprintf('0_rawdata/%s/dark.edf',acq.name);
+  d=edf_read(name,bbdir,'nodisp');
+  
+  name=sprintf('0_rawdata/%s/ref%04d_%04d.edf',acq.name,acq.nref-1,totproj);
+  ref360=edf_read(name,bbdir,'nodisp')-d;
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj);
+  im_360=(edf_read(name,bbdir,'nodisp')-d)./ref360;
+
+  name=sprintf('0_rawdata/%s/ref%04d_%04d.edf',acq.name,acq.nref-1,totproj*0.75);
+  ref270=edf_read(name,bbdir,'nodisp')-d;
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.75);
+  im_270=(edf_read(name,bbdir,'nodisp')-d)./ref270;
+
+  name=sprintf('0_rawdata/%s/ref%04d_%04d.edf',acq.name,acq.nref-1,totproj*0.5);
+  ref180=edf_read(name,bbdir,'nodisp')-d;
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.5);
+  im_180=(edf_read(name,bbdir,'nodisp')-d)./ref180;
+
+  name=sprintf('0_rawdata/%s/ref%04d_%04d.edf',acq.name,acq.nref-1,totproj*0.25);
+  ref90=edf_read(name,bbdir,'nodisp')-d;
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.25);
+  im_90=(edf_read(name,bbdir,'nodisp')-d)./ref90;
+
+  name=sprintf('0_rawdata/%s/ref%04d_%04d.edf',acq.name,acq.nref-1,0);
+  ref0=edf_read(name,bbdir,'nodisp')-d;
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,0);
+  im_0=(edf_read(name,bbdir,'nodisp')-d)./ref0;
+
+
+  if dim==0 || isempty(dim)
+    corr_0=correlate(im_end_0,im_0);
+    corr_90=correlate(im_end_90,im_90);
+    corr_180=correlate(im_end_180,im_180);
+    corr_270=correlate(im_end_270,im_270);
+    corr_360=correlate(im_end_360,im_360);
+  elseif dim==1
+    corr_0=[median(correlate1(im_end_0,im_0)), 0];
+    corr_90=[median(correlate1(im_end_90,im_90)), 0];
+    corr_180=[median(correlate1(im_end_180,im_180)), 0];
+    corr_270=[median(correlate1(im_end_270,im_270)), 0];
+    corr_360=[median(correlate1(im_end_360,im_360)), 0];
+  elseif dim==2
+    corr_0=[0, median(correlate1(im_end_0',im_0'))];
+    corr_90=[0, median(correlate1(im_end_90',im_90'))];
+    corr_180=[0, median(correlate1(im_end_180',im_180'))];
+    corr_270=[0, median(correlate1(im_end_270',im_270'))];
+    corr_360=[0, median(correlate1(im_end_360',im_360'))];
+  else
+    error('Dimension (second input argument) should be [], 0, 1 or 2!')
+  end
+
+
+  check_drift=1;
+
+  while check_drift
+
+    % simple linear interpolation for the moment - not the most
+    % accurate - for higher accuracy one should acquire a small
+    % calibration scan !
+
+    zdrift=interp1([0,totproj*0.25,totproj*0.5,totproj*0.75,totproj],[corr_0(1),corr_90(1),corr_180(1),corr_270(1),corr_360(1)],0:totproj);
+    ydrift=interp1([0,totproj*0.25,totproj*0.5,totproj*0.75,totproj],[corr_0(2),corr_90(2),corr_180(2),corr_270(2),corr_360(2)],0:totproj);
+
+    ydrift=ydrift+(detcenter_abs-bbdircenter_abs);
+    
+    figure('name','Drifts according to images at end')
+    subplot(2,1,1);plot(ydrift,'r.');title('horizontal drift');
+    subplot(2,1,2);plot(zdrift,'b.');title('vertical drift');
+    accept=inputwdefault('Do you accept those values ?','y');
+
+    if strcmpi(accept,'y') || strcmpi(accept,'yes')
+      check_drift=0;
+    else
+      disp('Run findshifts2 on pairs: corr_0=findshifts2(im_end_0, im_0), corr_90=findshifts(im_end_90, im_90), ...');
+      %disp('when done set check_drift=0');  % no - we need to go once more through the calculation above... 
+      disp('when done type return to continue');
+	  keyboard;
+    end
+  end
+
+else
+  % to be done...
+  disp('Correction is not yet implemented for 180degree scans.');
+  zdrift=zeros(totproj+1,1);
+  ydrift=zeros(totproj+1,1);
+end
+
+
+output{1}=rotaxisloc_abs;
+output{2}=rotoff_abs; 
+output{3}=rotoff; 
+
+nout=max(nargout,2)-2;
+for i=1:nout
+  varargout{i}=output{i};
+end
+
+
+end % of function
diff --git a/1_preprocessing/gtEvaluateCalibrationQuali.m b/1_preprocessing/gtEvaluateCalibrationQuali.m
new file mode 100755
index 0000000000000000000000000000000000000000..a6681c1c654f6918676945570931af1d66598573
--- /dev/null
+++ b/1_preprocessing/gtEvaluateCalibrationQuali.m
@@ -0,0 +1,822 @@
+function [ydrift_pol,zdrift_pol,varargout]=gtEvaluateCalibrationQuali(acq,calib,bbox,showcorr)
+%
+% FUNCTION [ydrift_pol,zdrift_pol,varargout]=gtEvaluateCalibrationScan2(acq,bbox)
+% 
+% In bbox, treats the calibration scan, determines rotation axis location
+% at sub-pixel (in full image and in bbox), creates master images as references
+% to sample drifts, determines accurate sample bounding box for the total scan
+% inside bbox.
+%
+% Sample drifts are relative to constant reference positions, where 
+% reference positions have been determined the following way:
+% Assuming that during calibration scan the sample doesn't move relative to
+% the rotation table, the rotation axis is determined from image pairs 180
+% degrees offset. Master images are created from the calibration in a way
+% that they are translated to have the rotation axis in the very center of
+% the full image (even if working in an asymmetric bbox).
+% Images of the scan are correlated (horizontally and/or vertically) with
+% those masters, yielding 'ydrift' and 'zdrift'.
+%
+% Uses linear flat correction between ref0000_xxxx-s.
+%
+% INPUT  
+%   acq = acquisition parameters of scan 
+%   bbox = according to GT conventions [originx, originy, width, height]
+%            bbox doesn't need to be centered in full image       
+%            if acq.correlationdim=1 bbox(4) needs to be even number (for correlate1)
+%            if acq.correlationdim=2 bbox(3) needs to be even number (for correlate1)
+%
+% OUTPUT  
+%   ydrift_pol, zdrift_pol = polynomial values with which the images need to be directly
+%                             translated (e.g direct input for interpolatef)
+%   varargout{1} = ydrift_int;  interpolated values of ydrifts
+%   varargout{2} = zdrift_int;  interpolated values of zdrifts  
+%   varargout{3} = rotaxisloc_abs;  rot axis x (horizontal) location in full image 
+%                   (non-integer in pixels)
+%   varargout{4} = rotdev_abs;  rot axis offset in full image; vector pointing
+%                   from center of image to rotation axis location;
+%                   positive to the right
+%   varargout{5} = rotdev;  rot axis offset in bbox; vector pointing from center
+%                   of bbox to rotation axis location in bbox, positive to the right
+%   varargout{6} = bbs_ext;  bounding box of maximum fill by sample  during 
+%                   rotation extended horizontally by ext_pix, in full image
+%   varargout{7} = edges;  bounding box of maximum fill by sample in bbox according to 'lim_samatten'
+%   varargout{8} = edges_ext;  'edges' extended by 'ext_pix' (at most up to the edges of bbox)
+%
+% 07/2007 Wolfgang, Peter
+%
+
+%% Parameters
+tol_pol=1; % tolerance factor for polynomial outliers (in unit std)
+%polyorder_outliers=18; % order of polynomial for rejecting outliers of drift curves
+polyorder_driftcurve=18; % order of polynomial of drift curves
+tol_rotdev=0.5; % tolerance for deviation in rotation axis location found by different pairs (used for warning)
+lim_samatten=0.7; % limit to describe sample attenuation
+ext_pix=5; % sample bounding box extension in pixels
+frame=20; % frame extension for reading master files to be able to translate them
+
+clims_substract=[-0.05 0.05]; % color limits for substracted sample image display
+clims_sample=[0 1]; % color limits for sample display
+
+qualiname='quali_';
+qualirefname='quali_ref_';
+
+%% Prepare variables
+    
+disp(' ')
+disp('Evaluating calibration scan...')
+disp(' ')
+
+% Check if acquisition types and calibration offset make sense
+if strcmpi(acq.type,'360degree')
+  totproj=acq.nproj*2;
+  if calib.offset<0 || calib.offset>=totproj 
+    disp(sprintf('Calibration offset has to be >=0 and <%d',totproj))
+    error('Invalid calibration offset value!')
+  end  
+elseif strcmpi(acq.type,'180degree')
+  totproj=acq.nproj;
+  if calib.offset<0 || calib.offset>=totproj
+    disp(sprintf('Calibration offset has to be >=0 and <%d',2*totproj))
+    error('Invalid calibration offset value!')
+  end
+else
+  error('Unknown type of scan. Check acq.type!');
+end
+
+if ~strcmpi(calib.type,'180degree') && ~strcmpi(calib.type,'360degree')
+  error('Unknown type of calibration scan (see calib.type)!')
+end
+
+close all
+
+if ~exist('showcorr','var')
+  showcorr=true;
+end
+
+tomo_N=calib.totproj; % =xml.acquisition.tomo_N
+ref_N=calib.nref;    % =xml.acquisition.ref_N
+dim=calib.correlationdim;
+scanname=acq.name;
+scanfolder=sprintf('%s/0_rawdata/%s',acq.dir,scanname);
+
+% decrease frame value if bbread would extend over the detector size
+frame=min([acq.xdet-(bbox(1)+bbox(3)-1),acq.ydet-(bbox(2)+bbox(4)-1),frame]);
+% BB for read-out (wider so that no need for padding after translation)
+bbread=[bbox(1)-frame,bbox(2)-frame,bbox(3)+2*frame,bbox(4)+2*frame];
+%bbread(1:2)=max([1 1],bbread(1:2));
+%bbread(3:4)=min([acq.xdet-bbread(1)+1 acq.ydet-bbread(2)+1],bbread(3:4));
+
+%% Determine rotation axis offset
+
+detcenter_abs=acq.xdet/2+0.5;
+bboxcenter_abs=(2*bbox(1)+bbox(3)-1)/2;
+
+% Darks and ref-s
+cdark=edf_read(sprintf('%s/dark.edf',calib.dir),bbread,'nodisp');
+cdarkbb=cdark(1+frame:end-frame,1+frame:end-frame);
+
+% refstart=edf_read(sprintf('%s/ref0000_0000.edf',calib.dir),bbread,'nodisp');
+% for i=1:ref_N-1
+%   refstart=refstart+edf_read(sprintf('%s/ref%0.4d_0000.edf',calib.dir,i),bbread,'nodisp');
+% end
+% refstart=refstart/ref_N-cdark;
+
+%  refstart=[];
+%  refstart(:,:,1)=edf_read(sprintf('%s/ref0000_0000.edf',calib.dir),bbread,'nodisp');
+%  for i=1:ref_N-1
+%    refstart(:,:,i+1)=edf_read(sprintf('%s/ref%0.4d_0000.edf',calib.dir,i),bbread,'nodisp');
+%  end
+%  refstartmed=median(refstart,3)-cdark;
+
+% refend=edf_read(sprintf('%s/ref0000_%0.4d.edf',calib.dir,tomo_N),bbread,'nodisp');
+% for i=1:ref_N-1
+%   refend=refend+edf_read(sprintf('%s/ref%0.4d_%0.4d.edf',calib.dir,i,tomo_N),bbread,'nodisp');
+% end
+% refend=refend/ref_N-cdark;
+
+refstart=edf_read(sprintf('%s/refHST0000.edf',calib.dir),bbread,'nodisp')-cdark;
+refstartbb=refstart(1+frame:end-frame,1+frame:end-frame);
+
+refend=edf_read(sprintf('%s/refHST%0.4d.edf',calib.dir,tomo_N),bbread,'nodisp')-cdark;
+refendbb=refend(1+frame:end-frame,1+frame:end-frame);
+
+imend180=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N+2),bbox,'nodisp')-cdarkbb)./refendbb;
+imend0=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N),bbox,'nodisp')-cdarkbb)./refendbb;
+imend0=fliplr(imend0);
+
+% Determine rotdev: that is a vector of [bbox center to rotation axis 
+%  location in the bbox], positive to the right.
+rotdev1=median(correlate1(imend180',imend0'))/2;
+
+% Confirm with Findshifts and add auto and manual results
+imforfs=interpolatef(imend0,0,rotdev1*2);
+shifts=sfConfirmWithFindshifts(imend180,imforfs);
+rotdev1=shifts(2)/2+rotdev1;
+
+if strcmpi(calib.type,'360degree')
+  % Deal with other end pair
+  imend270=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N+3),bbox,'nodisp')-cdarkbb)./refendbb;
+  imend90=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N+1),bbox,'nodisp')-cdarkbb)./refendbb;
+  imend90=fliplr(imend90);
+
+  rotdev2=median(correlate1(imend270',imend90'))/2;
+  
+  disp('Rotation axis location in bounding box found by first pair:')
+  disp(rotdev1)
+  disp('Rotation axis location in bounding box found by second pair:')
+  disp(rotdev2)
+  
+  % Confirm with Findshifts and add auto and manual results
+  imforfs=interpolatef(imend90,0,rotdev2*2);
+  shifts=sfConfirmWithFindshifts(imend270,imforfs);
+  rotdev2=shifts(2)/2+rotdev2;
+  
+  if abs(rotdev1-rotdev2)>tol_rotdev
+    disp('WARNING! Incosistent values have been found for rotation axis location in calibration scan.')
+    disp('Check images at end in calibration scan!')
+    pause(3)
+  end
+  
+  % Compute rotdev from all the calib pairs
+  rotdev=nfLocateRotAxis;
+end
+
+% vector of rotation axis location in full image; [from image center
+% to rotation axis location], positive to the right;
+rotdev_abs=bboxcenter_abs-detcenter_abs+rotdev
+rotaxisloc_abs=bboxcenter_abs+rotdev
+
+
+%% Compute drifts
+
+% Create masters
+[sf,masterblob]=nfCreateMasterblob;
+
+% Depending on scan type and calibration type (3 cases): matching the corresponding
+% pairs, flipping master images if needed, and creation of master and image blobs.
+[imblob,cmimi,corr]=nfCorrelateMastersAndScan;
+
+% Polynomial and interpolated values of drifts
+[ydrift_pol,zdrift_pol,ydrift_int,zdrift_int]=nfComputePolynomials;
+
+% Check bounding box fill
+imno_probl=nfScanBBfill;
+[mno_probl,minrow,mincol,masterblob_min3]=nfMasterBBfill;
+
+
+%% Display
+
+if showcorr
+  sfDisplayImages(cmimi,masterblob,imblob,corr,clims_sample,clims_substract,mno_probl,imno_probl,0)
+end
+
+showims=inputwdefault('Would you like to loop through the scan images?',showims);
+
+if strcmpi(showims,'y') || strcmpi(showims,'yes')
+  disp('Check master and scan images...')
+  disp('Press enter to loop through images')
+  sfDisplayImages(cmimi,masterblob,imblob,corr,clims_sample,clims_substract,mno_probl,imno_probl,1)
+end
+
+[bbs_ext,edges,edges_ext]=nfCreateSampleBoundingBox;
+
+output{1}=ydrift_int;
+output{2}=zdrift_int;
+output{3}=rotaxisloc_abs; 
+output{4}=rotdev_abs; 
+output{5}=rotdev; 
+output{6}=bbs_ext; 
+output{7}=edges; 
+output{8}=edges_ext;
+
+nout=max(nargout,2)-2;
+for i=1:nout
+  varargout{i}=output{i};
+end
+
+%disp('End of gtEvaluateCalibratonQuali.')
+%keyboard
+
+
+
+%% Sub- and nested functions
+
+
+%% Confirm with findshifts
+
+function shifts=sfConfirmWithFindshifts(baseim,imforfs)
+
+  shift=[];
+  assignin('base','shift',shift);
+  disp(' ')
+  disp('Calibration scan: check result of image correlation with findshifts...')
+  disp(' ')
+
+  wdefault=warning;
+  warning('off','all');
+  
+  findshifts2(baseim,imforfs);
+
+  warning(wdefault);
+  
+  set(gcf,'name','Calibration scan: check correlation...')
+  while isempty(shift)
+    drawnow;
+    shift=evalin('base','shift');
+  end
+
+  shifts=evalin('base','shift');
+
+end % of sfConfirmWithFindshifts
+
+
+%% Check rotation axis defined by all the pairs
+
+  function [rotdev_mean,rotaxisloc_abs_mean]=nfLocateRotAxis
+
+    nofimpairs=tomo_N/2;
+    rotdev_vec=[];
+
+    if nofimpairs==round(nofimpairs)
+      disp(' ')
+      disp('Analysing location of rotation axis during calibration...')
+      disp(' ')
+      for i=0:nofimpairs
+        refA=(tomo_N-i)/tomo_N*refstartbb+i/tomo_N*refendbb;
+        refB=(tomo_N/2-i)/tomo_N*refstartbb+(i+tomo_N/2)/tomo_N*refendbb;
+
+        imA=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,i),bbox,'nodisp')-cdarkbb)./refA;
+        imB=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,i+nofimpairs),bbox,'nodisp')-cdarkbb)./refB;
+        imB=fliplr(imB);
+
+        rotdev_vec(i+1)=median(correlate1(imA',imB'))/2;
+      end
+    else
+      disp(' ')
+      disp('Odd number of radiographs in calibration.')
+      disp('Can''t analyse rotation axis location by image pairs through all the scan.')
+      disp(' ')
+    end
+
+    % values of rotation axis location in full image;
+    % [from image center to rotation axis location], positive to the right;
+    rotdev_mean=mean(rotdev_vec);
+    %rotdev_abs_vec=bboxcenter_abs-detcenter_abs+rotdev_vec;
+    rotaxisloc_abs_vec=bboxcenter_abs+rotdev_vec; % locations of rotation axis in full image
+    rotaxisloc_abs_mean=mean(rotaxisloc_abs_vec); % mean value for location of rotation axis in full image
+
+    figure('name','Location of the rotation axis during calibration')
+    hold on
+    plot(0:tomo_N/2,rotaxisloc_abs_vec,'b.')
+    plot(0:tomo_N/2,rotaxisloc_abs_vec,'b-')
+    plot([0 tomo_N/2],[rotaxisloc_abs_mean rotaxisloc_abs_mean],'g-')
+    drawnow
+
+  end % of nfLocateRotAxis
+
+
+%% Create masters
+
+  function [sf,masterblob]=nfCreateMasterblob
+
+    if strcmpi(acq.type,'360degree')
+      if strcmpi(calib.type,'360degree')
+        sf=totproj/tomo_N;
+      elseif strcmpi(calib.type,'180degree')
+        sf=totproj/tomo_N/2;
+      else
+        error('Unknown type of calibration scan (see parameter file)!')
+      end
+    elseif strcmpi(acq.type,'180degree')
+      if strcmpi(calib.type,'360degree')
+        sf=totproj/tomo_N*2;
+      elseif strcmpi(calib.type,'180degree')
+        sf=totproj/tomo_N;
+      else
+        error('Unknown type of calibration scan (see parameter file)!')
+      end
+    else
+      error('Unknown type of scan (see parameter file acq.type)!')
+    end
+
+    if mod(sf,1)~=0
+      error('No. of images in scan and calibration do not correspond!')
+    end
+
+    disp(' ')
+    disp('Creating master images...')
+    disp(' ')
+
+    masterblob=zeros(bbox(4),bbox(3),tomo_N+1,'single');
+
+    for i=0:tomo_N
+      cref=(tomo_N-i)/tomo_N*refstart+i/tomo_N*refend;
+      master=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,i),bbread,'nodisp')-cdark)./cref;
+      master=interpolatef(master,0,-rotdev);
+      masterblob(:,:,i+1)=master(1+frame:end-frame,1+frame:end-frame);
+      %edf_write(masterbb,sprintf('%s/master_%0.4d.edf',calib.dir,i),'float32');
+    end
+
+  end % of nfCreateMasterblob
+
+
+%% Correlation of masters and scan; creation of scan image blob
+% cmimi=[imi mi isflipped];
+%   imi = image index
+%   mi = corresponding master index
+
+  function [imblob,cmimi,corr]=nfCorrelateMastersAndScan
+
+    imblob=zeros(bbox(4),bbox(3),tomo_N+1,'single');
+    corr=NaN(totproj+1,2);
+    cmimi=[];
+
+    imdark=edf_read(sprintf('%s/dark.edf',scanfolder),bbox,'nodisp');
+
+    if strcmpi(calib.type,'180degree') && strcmpi(acq.type,'180degree')
+      for imi=0:sf:totproj
+
+        if abs((imi-calib.offset)/sf)==tomo_N
+          mi=tomo_N;
+        else
+          mi=mod((imi-calib.offset)/sf,tomo_N);
+        end
+
+        masterbb=masterblob(:,:,mi+1);
+
+        if (imi>=calib.offset) || (imi<=calib.offset-totproj) || (imi==totproj && mi==0)
+          fl=[];
+          cmimi=[cmimi; imi mi 0];
+        else
+          fl='flipped';
+          cmimi=[cmimi; imi mi 1];
+          masterbb=fliplr(masterbb);
+        end
+
+        disp(sprintf(' Correlating: image %d with master %d %s',imi,mi,fl))
+        [corr,imbb]=sfCorrMaster(corr,scanfolder,qualiname,qualirefname,imi,acq,bbox,imdark,masterbb,dim);
+        imblob(:,:,imi/sf+1)=imbb;
+      end
+    end
+
+
+    if strcmpi(calib.type,'180degree') && strcmpi(acq.type,'360degree')
+      for imi=0:sf:totproj
+
+        if abs((imi-calib.offset)/sf)==tomo_N
+          mi=tomo_N;
+        else
+          mi=mod((imi-calib.offset)/sf,tomo_N);
+        end
+
+        masterbb=masterblob(:,:,mi+1);
+
+        if (imi>=calib.offset && imi<=calib.offset+totproj/2) || (imi<=calib.offset-totproj/2) || (imi==totproj && mi==0)
+          fl=[];
+          cmimi=[cmimi; imi mi 0];
+        else
+          fl='flipped';
+          masterbb=fliplr(masterbb);
+          cmimi=[cmimi; imi mi 1];
+        end
+
+        disp(sprintf(' Correlating: image %d with master %d %s',imi,mi,fl))
+        [corr,imbb]=sfCorrMaster(corr,scanfolder,qualiname,qualirefname,imi,acq,bbox,imdark,masterbb,dim);
+        imblob(:,:,imi/sf+1)=imbb;
+      end
+    end
+
+    if strcmpi(calib.type,'360degree')
+      for imi=0:sf:totproj
+        mi=mod((imi-calib.offset)/sf,tomo_N);
+
+        if mi==0 && imi==totproj
+          mi=tomo_N;
+        end
+
+        masterbb=masterblob(:,:,mi+1);
+
+        cmimi=[cmimi; imi mi 0];
+
+        disp(sprintf(' Correlating: image %d with master %d',imi,mi))
+
+        [corr,imbb]=sfCorrMaster(corr,scanfolder,qualiname,qualirefname,imi,acq,bbox,imdark,masterbb,dim);
+        imblob(:,:,imi/sf+1)=imbb;
+      end
+    end
+
+  end % of nfCorrelateMastersAndScan
+
+
+%% Correlate a given master-scanimage pair
+
+function [corr,im]=sfCorrMaster(corr,scanfolder,scanname,refname,imi,acq,bbox,imdark,masterbb,dim)
+  %imrefa=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,floor(imi/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+  %imrefb=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,ceil((imi-eps)/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+  %imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+
+  imrefa=edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,refname,floor(imi/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+  imrefb=edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,refname,ceil((imi-eps)/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+  imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+
+  im=(edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,scanname,imi),bbox,'nodisp')-imdark)./imref;
+
+  if dim==0 || isempty(dim)
+    %corrvec=correlaterealspace(masterbb,im,20,20);
+    %corr(imi+1,1:2)=(corrvec+correlate(masterbb,im))/2;
+    corr(imi+1,1:2)=correlate(masterbb,im);
+  elseif dim==1
+    corrvec=correlate1(masterbb,im);
+    corr(imi+1,1:2)=[median(corrvec), 0];
+  elseif dim==2
+    corrvec=correlate1(masterbb',im');
+    corr(imi+1,1:2)=[0, median(corrvec)];
+  else
+    error('Dimension (first input argument) should be [], 0, 1 or 2!')
+  end
+end
+
+%% Display correlated images in loop
+
+function sfDisplayImages(cmimi,masterblob,imblob,corr,clims_sample,clims_substract,mno_probl,imno_probl,dopause)
+
+  figure('name','Evaluation of calibration')
+  set(gcf,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);
+
+  subplot(2,2,1)
+  set(gca,'Units','normalized','OuterPosition',[0 0.5 0.5 0.5]);
+
+  subplot(2,2,2)
+  set(gca,'Units','normalized','OuterPosition',[0.5 0.5 0.5 0.5]);
+
+  subplot(2,2,3)
+  set(gca,'Units','normalized','OuterPosition',[0 0 0.5 0.5]);
+
+  subplot(2,2,4)
+  set(gca,'Units','normalized','OuterPosition',[0.5 0 0.5 0.5]);
+
+  for i=1:length(cmimi)
+    subplot(2,2,1)
+    if cmimi(i,3)==1
+      imshow(fliplr(masterblob(:,:,cmimi(i,2)+1)),clims_sample)
+      title(sprintf('Master # %d flipped',cmimi(i,2)));
+    else
+      imshow(masterblob(:,:,cmimi(i,2)+1),clims_sample)
+      title(sprintf('Master # %d',cmimi(i,2)));
+    end
+    if any(cmimi(i,2)==mno_probl)
+      hold on
+      plot([-20 size(masterblob,2)+20 size(masterblob,2)+20 -20 -20],[-20 -20 size(masterblob,1)+20 size(masterblob,1)+20 -20],'r-','linewidth',2);
+      hold off
+    end
+    axis([-25 size(masterblob,2)+25 -25 size(masterblob,1)+25])
+    set(gca,'position',[0.05 0.55 0.4 0.4])
+
+    subplot(2,2,2)
+    imshow(imblob(:,:,i),clims_sample)
+    if any(cmimi(i,1)==imno_probl)
+      hold on
+      plot([-20 size(masterblob,2)+20 size(masterblob,2)+20 -20 -20],[-20 -20 size(masterblob,1)+20 size(masterblob,1)+20 -20],'r-','linewidth',2);
+      hold off
+    end
+    title(sprintf('Image # %d',cmimi(i,1)));
+    axis([-25 size(masterblob,2)+25 -25 size(masterblob,1)+25])
+    set(gca,'position',[0.55 0.55 0.4 0.4])
+
+    subplot(2,2,3)
+    plot(0:size(corr,1)-1,corr(:,2),'c.')
+    hold on
+    plot(0:size(corr,1)-1,corr(:,1),'b.')
+    plot(cmimi(i,1),corr(cmimi(i,1)+1,2),'ms')
+    plot(cmimi(i,1),corr(cmimi(i,1)+1,1),'ms')
+    hold off
+    title('Horizontal (cyan) and vertical (blue) drifts');
+    xlim([0 size(corr,1)])
+    set(gca,'position',[0.05 0.05 0.4 0.4])
+
+    subplot(2,2,4)
+    if cmimi(i,3)==1
+      mbb=fliplr(masterblob(:,:,cmimi(i,2)+1));
+    else
+      mbb=masterblob(:,:,cmimi(i,2)+1);
+    end
+    imbb=imblob(:,:,i);
+    imbb=interpolatef(imbb,corr(cmimi(i,1)+1,1),corr(cmimi(i,1)+1,2));
+    imshow(mbb-imbb,clims_substract)
+    title('Substraction of correlated images')
+    set(gca,'position',[0.55 0.05 0.4 0.4])
+
+    drawnow
+    if dopause==1
+      pause
+    end
+  end
+
+end % of sfDisplayImages
+
+
+%% Polynomials of vertical and horizontal drifts
+
+  function [ydrift_pol,zdrift_pol,ydrift_int,zdrift_int]=nfComputePolynomials
+    %corr(isnan(corr))=interp1(find(~isnan(corr)),corr(~isnan(corr)),find(isnan(corr)));
+
+    % Polynomial of vertical drift
+    corr_ver=corr(:,1);
+    
+    figure('name','Vertical drift of scan from calibration')
+    hold on
+    plot(corr_ver,'r.')
+
+    %[pol_ver,s_ver,mu_ver]=polyfit(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),polyorder_outliers);
+    %corrp_ver=polyval(pol_ver,((1:totproj+1)-mu_ver(1))/mu_ver(2))';
+    %err_ver=corrp_ver-corr_ver;
+    err_ver=0; % no outliers considered
+    
+    corr_ver(abs(err_ver)>tol_pol*std(err_ver(~isnan(err_ver))))=NaN;
+    plot(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),'g.')
+    [pol_ver,s_ver,mu_ver]=polyfit(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),polyorder_driftcurve);
+    corrp_ver=polyval(pol_ver,((1:totproj+1)-mu_ver(1))/mu_ver(2))'; % vector of drifts
+    plot(corrp_ver,'r.','markersize',3)
+
+
+    % Polynomial of horizontal drift
+    % add a constant drift to all, if bounding bbox is not centered in the
+    %  original image
+    corr_hor=corr(:,2)+(detcenter_abs-bboxcenter_abs);
+
+    figure('name','Horizontal drift of scan from calibration')
+    hold on
+    plot(corr_hor,'r.')
+
+    %[pol_hor,s_hor,mu_hor]=polyfit(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),polyorder_outliers);
+    %corrp_hor=polyval(pol_hor,((1:totproj+1)-mu_hor(1))/mu_hor(2))';
+    %err_hor=corrp_hor-corr_hor;
+    err_hor=0; % no outliers considered
+
+    corr_hor(abs(err_hor)>tol_pol*std(err_hor(~isnan(err_hor))))=NaN;
+    plot(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),'g.')
+    [pol_hor,s_hor,mu_hor]=polyfit(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),polyorder_driftcurve);
+    corrp_hor=polyval(pol_hor,((1:totproj+1)-mu_hor(1))/mu_hor(2))'; % vector of drifts
+    plot(corrp_hor,'r.','markersize',3)
+
+    % the resulting drift polynomials
+    ydrift_pol=corrp_hor;
+    zdrift_pol=corrp_ver;
+
+
+    % Interpolated drifts
+    zdrift_int=corr(:,1);
+    zdrift_int(isnan(zdrift_int))=interp1(find(~isnan(zdrift_int)),zdrift_int(~isnan(zdrift_int)),find(isnan(zdrift_int)));
+
+    ydrift_int=corr(:,2)+(detcenter_abs-bboxcenter_abs);
+    ydrift_int(isnan(ydrift_int))=interp1(find(~isnan(ydrift_int)),ydrift_int(~isnan(ydrift_int)),find(isnan(ydrift_int)));
+
+  end % of nfComputePolynomials
+
+
+%% BBox filled by sample during scan
+
+  function [imno_probl]=nfScanBBfill
+ 
+    [imblob_min3,imno_imblobmin]=min(imblob,[],3);
+    [minrow,imno_minrow]=min(imblob_min3,[],1);
+    [mincol,imno_mincol]=min(imblob_min3,[],2);
+
+    % image id-s which give the extreme values
+    imno_minrow=imno_imblobmin(imno_minrow+(0:size(imno_imblobmin,2)-1)*size(imno_imblobmin,1))-1;
+    imno_mincol=imno_imblobmin((1:size(imno_imblobmin,1))'+(imno_mincol-1)*size(imno_imblobmin,1))-1;
+
+    if strcmpi(calib.type,'180degree') && strcmpi(acq.type,'360degree')
+      tmp=imno_minrow;
+      imno_minrow=mod(tmp,tomo_N);
+      imno_minrow(tmp>0 & imno_minrow==0)=tomo_N;
+
+      tmp=imno_mincol;
+      imno_mincol=mod(tmp,tomo_N);
+      imno_mincol(tmp>0 & imno_mincol==0)=tomo_N;
+    end
+
+    % problematic images (images from which the sample may have moved out)
+    imno_probl=[];
+
+    if max(mincol)>lim_samatten
+      disp('WARNING! Sample during scan may not entirely fill the given bounding box!')
+      imno_probl=unique(imno_mincol(mincol>lim_samatten));
+      disp(' See scan images no. : ');
+      disp(imno_probl)
+      showims='yes';
+    end
+
+    if max(minrow)<lim_samatten
+      disp('WARNING! Sample during scan may have moved out of the given bounding box!')
+      imno_probl=unique(imno_minrow(minrow<lim_samatten));
+      disp(' See scan images no. : ');
+      disp(imno_probl')
+      showims='yes';
+    end
+
+  end % of nfSampleBB
+
+
+%% Determine and check bbox filled by sample during calibration
+
+  function [mno_probl,minrow,mincol,masterblob_min3]=nfMasterBBfill
+    [masterblob_min3,mno_masterblobmin]=min(masterblob,[],3);
+    [minrow,mno_minrow]=min(masterblob_min3,[],1);
+    [mincol,mno_mincol]=min(masterblob_min3,[],2);
+
+    % image id-s which give the extreme values
+    mno_minrow=mno_masterblobmin(mno_minrow+(0:size(mno_masterblobmin,2)-1)*size(mno_masterblobmin,1))-1;
+    mno_mincol=mno_masterblobmin((1:size(mno_masterblobmin,1))'+(mno_mincol-1)*size(mno_masterblobmin,1))-1;
+
+    if strcmpi(calib.type,'180degree') && strcmpi(acq.type,'360degree')
+      tmp=mno_minrow;
+      mno_minrow=mod(tmp,tomo_N);
+      mno_minrow(tmp>0 & mno_minrow==0)=tomo_N;
+
+      tmp=mno_mincol;
+      mno_mincol=mod(tmp,tomo_N);
+      mno_mincol(tmp>0 & mno_mincol==0)=tomo_N;
+    end
+
+    showims='no';
+
+    % problematic images (images from which the sample may have moved out)
+    mno_probl=[];
+
+    if max(mincol)>lim_samatten
+      disp('WARNING! Sample during calibration may not entirely fill the given bounding box!')
+      mno_probl=unique(mno_mincol(mincol>lim_samatten));
+      disp(' See master image no. : ');
+      disp(mno_probl)
+      showims='yes';
+    end
+
+    if max(minrow)<lim_samatten
+      disp('WARNING! Sample during calibration may have moved out of the given bounding box!')
+      mno_probl=unique(mno_minrow(minrow<lim_samatten));
+      disp(' See master image no. : ');
+      disp(mno_probl')
+      showims='yes';
+    end
+
+  end %of nfMasterBBfill
+
+
+%% Create sample bounding box
+
+  function [bbs_ext,edges,edges_ext]=nfCreateSampleBoundingBox
+
+    minrow=minrow<lim_samatten;
+    marker=false(size(minrow));
+    marker(round(length(marker)/2))=true;
+    minrowr=imreconstruct(marker,minrow);
+    edgel=find(minrowr,1,'first');
+    edger=find(minrowr,1,'last');
+    edgextl=max(edgel-ext_pix,1);
+    edgextr=min(edger+ext_pix,bbox(3));
+    bbs_ext(1)=bbox(1)+edgextl-1;
+    bbs_ext(3)=edgextr-edgextl+1;
+
+    mincol=mincol<lim_samatten;
+    marker=false(size(mincol));
+    marker(round(length(marker)/2))=true;
+    mincolr=imreconstruct(marker,mincol);
+    edget=find(mincolr,1,'first');
+    edgeb=find(mincolr,1,'last');
+    edgextt=max(edget-ext_pix,1);
+    edgextb=min(edgeb+ext_pix,bbox(4));
+    bbs_ext(2)=bbox(2)+edgextt-1;
+    bbs_ext(4)=edgextb-edgextt+1;
+
+    edges=[edgel edget edger edgeb];
+    edges_ext=[edgextl edgextt edgextr edgextb];
+
+    figure('name','Bounding box filled by sample during calibration')
+
+    wdefault=warning;
+    warning('off','all');
+    
+    imshow(masterblob_min3,[0 1])
+
+    warning(wdefault);
+    
+    hold on
+    plot([edgel edger edger edgel edgel],[edget edget edgeb edgeb edget],'r-')
+    plot([edgextl edgextr edgextr edgextl edgextl],[edgextt edgextt edgextb edgextb edgextt],'g-')
+
+  end % of nfCreateSampleBoundingBox
+
+
+%%
+
+end % of primary function
+
+
+
+
+
+
+
+
+
+
+% Helpful crap
+
+%plot([bbs_ext(1),bbs_ext(1)+bbs_ext(3)-1,bbs_ext(1)+bbs_ext(3)-1,bbs_ext(1),bbs_ext(1)],[bbs_ext(2),bbs_ext(2),bbs_ext(2)+bbs_ext(4)-1,bbs_ext(2)+bbs_ext(4)-1,bbs_ext(2)],'g-') 
+%[edgel edger edget edgeb]
+%bbs_ext
+
+% For displaying a given image pair
+
+% i=1
+%   cref=(tomo_N-i)/tomo_N*refstart+i/tomo_N*refend;
+%   master=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,i),bbread)-cdark)./cref;
+%   master=interpolatef(master,0,-rotdev);
+%   masterbb=master(1+frame:end-frame,1+frame:end-frame);
+%   figure(1)
+%   imshow(masterbb,[0 1])
+%   shg
+% 
+%   imi=mod(i*sf+calib.offset,totproj);
+%   if imi~=i*sf+calib.offset && strcmpi(acq.type,'180degree')
+%     masterbb=fliplr(masterbb);
+%   end
+% 
+%   imi=mod((i+tomo_N)*sf+calib.offset,totproj)
+% 
+%   imrefa=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,floor(imi/acq.refon)*acq.refon),bbox)-imdark;
+%   imrefb=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,ceil((imi-eps)/acq.refon)*acq.refon),bbox)-imdark;
+%   imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+%   im=(edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,scanname,imi),bbox)-imdark)./imref;
+%   figure(2)
+%   imshow(im,[0 1]),shg
+
+
+% For displaying the masters:
+% 
+% figure
+% for ii=0:36
+%   imshow(edf_read(sprintf('master_%0.4d.edf',ii)),[]);shg
+%   pause
+% end
+
+% For displaying the masters:
+% 
+% figure
+% for ii=0:36
+%   imshow(masterblob(:,:,ii+1),[0 1]);shg
+% end
+
+
+% figure
+% for ii=1:73
+%   imshow(imblob{ii},[0 1]);shg
+%   disp(ii)
+%   pause
+% end
+
+
+
+
diff --git a/1_preprocessing/gtEvaluateCalibrationScan.m b/1_preprocessing/gtEvaluateCalibrationScan.m
new file mode 100755
index 0000000000000000000000000000000000000000..f0438b74bd742b1a8a33560cc8c8354aae9302e8
--- /dev/null
+++ b/1_preprocessing/gtEvaluateCalibrationScan.m
@@ -0,0 +1,665 @@
+function [ydrift_pol,zdrift_pol,varargout]=gtEvaluateCalibrationScan(acq,bbox)
+%
+% FUNCTION [ydrift_pol,zdrift_pol,varargout]=gtEvaluateCalibrationScan2(acq,bbox)
+% 
+% In bbox, treats the calibration scan, determines rotation axis location
+% at sub-pixel (in full image and in bbox), creates master images as references
+% to sample drifts, determines accurate sample bounding box for the total scan
+% inside bbox.
+%
+% Sample drifts are relative to constant reference positions, where 
+% reference positions have been determined the following way:
+% Assuming that during calibration scan the sample doesn't move relative to
+% the rotation table, the rotation axis is determined from image pairs 180
+% degrees offset. Master images are created from the calibration in a way
+% that they are translated to have the rotation axis in the very center of
+% the full image (even if working in an asymmetric bbox).
+% Images of the scan are correlated (horizontally and/or vertically) with
+% those masters, yielding 'ydrift' and 'zdrift'.
+%
+% Uses linear flat correction between ref0000_xxxx-s.
+%
+% INPUT  
+%   acq = acquisition parameters of scan 
+%   bbox = according to GT conventions [originx, originy, width, height]
+%            bbox doesn't need to be centered in full image       
+%            if acq.correlationdim=1 bbox(4) needs to be even number (for correlate1)
+%            if acq.correlationdim=2 bbox(3) needs to be even number (for correlate1)
+%
+% OUTPUT  
+%   ydrift_pol, zdrift_pol = polynomial values with which the images need to be directly
+%                             translated (e.g direct input for interpolatef)
+%   varargout{1} = ydrift_int;  interpolated values of ydrifts
+%   varargout{2} = zdrift_int;  interpolated values of zdrifts  
+%   varargout{3} = rotaxisloc_abs;  rot axis x (horizontal) location in full image 
+%                   (non-integer in pixels)
+%   varargout{4} = rotdev_abs;  rot axis offset in full image; vector pointing
+%                   from center of image to rotation axis location;
+%                   positive to the right
+%   varargout{5} = rotdev;  rot axis offset in bbox; vector pointing from center
+%                   of bbox to rotation axis location in bbox, positive to the right
+%   varargout{6} = bbs_ext;  bounding box of maximum fill by sample  during 
+%                   rotation extended horizontally by ext_pix, in full image
+%   varargout{7} = edges;  bounding box of maximum fill by sample in bbox according to 'lim_samatten'
+%   varargout{8} = edges_ext;  'edges' extended by 'ext_pix' (at most up to the edges of bbox)
+%
+% 07/2007 Wolfgang, Peter
+%
+
+%% Parameters
+tol_pol=1; % tolerance factor for polynomial outliers (in unit std)
+tol_rotdev=0.5; % tolerance for deviation in rotation axis location found by different pairs (used for warning)
+lim_samatten=0.92; % limit to describe sample attenuation
+ext_pix=2; % sample bounding box extension in pixels
+frame=20; % frame extension for reading master files to be able to translate them
+
+clims_substract=[-0.1 0.1]; % color limits for substracted sample image display
+clims_sample=[0 1]; % color limits for sample display
+
+%%
+
+disp(' ')
+disp('Evaluating calibration scan...')
+disp(' ')
+
+dim=acq.correlationdim;
+
+calibname=acq.calibration_path(find(acq.calibration_path=='/',1,'last')+1:end);
+
+scanname=acq.dir(find(acq.dir=='/',1,'last')+1:end);
+scanfolder=sprintf('%s/0_rawdata/%s',acq.dir,scanname);
+
+if strcmpi(acq.type,'360degree')
+  totproj=acq.nproj*2;
+  if acq.caliboffset<0 || acq.caliboffset>=totproj 
+    disp(sprintf('Calibration offset have to be >=0 and <%d',totproj))
+    error('Invalid calibration offset value!')
+  end  
+elseif strcmpi(acq.type,'180degree')
+  totproj=acq.nproj;
+  if acq.caliboffset<0 || acq.caliboffset>=totproj
+    disp(sprintf('Calibration offset have to be >=0 and <%d',2*totproj))
+    error('Invalid calibration offset value!')
+  end
+else
+  error('Unknown type of scan. Check acq.type!');
+end
+
+bbread=[bbox(1)-frame,bbox(2)-frame,bbox(3)+2*frame,bbox(4)+2*frame];
+
+if ~strcmpi(acq.calibtype,'180degree') && ~strcmpi(acq.calibtype,'360degree')
+  error('Unknown type of calibration scan (see acq.calibtype)!')
+end
+
+xml=xml_load(sprintf('%s/%s.xml',acq.calibration_path,calibname));
+
+tomo_N=str2num(xml.acquisition.tomo_N);
+ref_N=str2num(xml.acquisition.ref_N);
+%ref_On=str2num(xml.acquisition.ref_On);
+%dark_N=str2num(xml.acquisition.dark_N);
+
+close all
+
+%% Determine rotation axis offset
+
+detcenter_abs=acq.xdet/2+0.5;
+bboxcenter_abs=(2*bbox(1)+bbox(3)-1)/2;
+
+% Darks and ref-s
+cdark=edf_read(sprintf('%s/dark.edf',acq.calibration_path),bbread,'nodisp');
+cdarkbb=cdark(1+frame:end-frame,1+frame:end-frame);
+
+refstart=edf_read(sprintf('%s/ref0000_0000.edf',acq.calibration_path),bbread,'nodisp');
+for i=1:ref_N-1
+  refstart=refstart+edf_read(sprintf('%s/ref%0.4d_0000.edf',acq.calibration_path,i),bbread,'nodisp');
+end
+refstart=refstart/ref_N-cdark;
+% refstartbb=refstart(1+frame:end-frame,1+frame:end-frame);
+
+refend=edf_read(sprintf('%s/ref0000_%0.4d.edf',acq.calibration_path,tomo_N),bbread,'nodisp');
+for i=1:ref_N-1
+  refend=refend+edf_read(sprintf('%s/ref%0.4d_%0.4d.edf',acq.calibration_path,i,tomo_N),bbread,'nodisp');
+end
+refend=refend/ref_N-cdark;
+refendbb=refend(1+frame:end-frame,1+frame:end-frame);
+
+imend180=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,tomo_N+2),bbox,'nodisp')-cdarkbb)./refendbb;
+imend0=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,tomo_N),bbox,'nodisp')-cdarkbb)./refendbb;
+imend0=fliplr(imend0);
+
+% Determine rotdev: that is a vector of [bbox center to rotation axis 
+%  location in the bbox], positive to the right.
+rotdev=median(correlate1(imend180',imend0'))/2;
+
+% Confirmation with findshifts %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+imforfs=interpolatef(imend0,0,rotdev*2);
+
+shift=[];
+assignin('base','shift',shift);
+disp(' ')
+disp('Calibration scan: check result of image correlation with findshifts...')
+disp(' ')
+
+findshifts2(imend180,imforfs);
+set(gcf,'name','Calibration scan: check correlation...')
+while isempty(shift)
+  drawnow;
+  shift=evalin('base','shift');
+end
+
+shift=evalin('base','shift');
+rotdev=shift(2)/2+rotdev; %%% check this!!!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if strcmpi(acq.calibtype,'360degree')
+  imend270=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,tomo_N+3),bbox,'nodisp')-cdarkbb)./refendbb;
+  imend90=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,tomo_N+1),bbox,'nodisp')-cdarkbb)./refendbb;
+  imend90=fliplr(imend90);
+
+  rotdev2=median(correlate1(imend270',imend90'))/2;
+  
+  disp('Rotation axis location in bounding box found by first pair:')
+  disp(rotdev)
+  disp('Rotation axis location in bounding box found by second pair:')
+  disp(rotdev2)
+  
+  % Confirmation with findshifts %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  imforfs=interpolatef(imend90,0,rotdev2*2);
+
+  shift=[];
+  assignin('base','shift',shift);
+  disp(' ')
+  disp('Calibration scan: check result of image correlation with findshifts...')
+  disp(' ')
+
+  findshifts2(imend270,imforfs);
+  set(gcf,'name','Calibration scan: check correlation...')
+  while isempty(shift)
+    drawnow;
+    shift=evalin('base','shift');
+  end
+
+  shift=evalin('base','shift');
+  rotdev2=shift(2)/2+rotdev2; %%% check this!!!
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  
+  if abs(rotdev-rotdev2)>tol_rotdev
+    disp('WARNING! Incosistent values have been found for rotation axes location in calibration scan.')
+    disp('Check images at end in calibration scan!')
+    pause(3)
+  end
+  rotdev=(rotdev+rotdev2)/2;
+end
+
+% vector of rotation axis location in full image; [from image center
+% to rotation axis location], positive to the right;
+rotdev_abs=bboxcenter_abs-detcenter_abs+rotdev;
+rotaxisloc_abs=bboxcenter_abs+rotdev;
+
+%% Create masters and correlate scan images
+
+if strcmpi(acq.type,'360degree')
+  if strcmpi(acq.calibtype,'360degree')
+    sf=totproj/tomo_N;
+  elseif strcmpi(acq.calibtype,'180degree')
+    sf=totproj/tomo_N/2;
+  else
+    error('Unknown type of calibration scan (see parameter file)!')
+  end
+elseif strcmpi(acq.type,'180degree')
+  if strcmpi(acq.calibtype,'360degree')
+    sf=totproj/tomo_N*2;
+  elseif strcmpi(acq.calibtype,'180degree')
+    sf=totproj/tomo_N;
+  else
+    error('Unknown type of calibration scan (see parameter file)!')
+  end
+else   
+  error('Unknown type of scan (see parameter file acq.type)!')
+end
+
+if mod(sf,1)~=0
+  error('No. of images in scan and calibration do not correspond!')
+end
+
+
+imdark=edf_read(sprintf('%s/dark.edf',scanfolder),bbox,'nodisp');
+corr=NaN(totproj+1,2);
+masterblob=[];
+imblob=[];
+
+for i=0:tomo_N 
+  cref=(tomo_N-i)/tomo_N*refstart+i/tomo_N*refend;
+  master=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,i),bbread,'nodisp')-cdark)./cref;
+  master=interpolatef(master,0,-rotdev);
+  masterblob(:,:,i+1)=master(1+frame:end-frame,1+frame:end-frame);
+  %edf_write(masterbb,sprintf('%s/master_%0.4d.edf',acq.calibration_path,i),'float32');
+end
+
+
+%% Determine correlation
+
+cmimi=[];
+
+if strcmpi(acq.calibtype,'180degree') && strcmpi(acq.type,'180degree')
+  for imi=0:sf:totproj
+
+    if abs((imi-acq.caliboffset)/sf)==tomo_N
+      mi=tomo_N;
+    else
+      mi=mod((imi-acq.caliboffset)/sf,tomo_N);
+    end
+
+    masterbb=masterblob(:,:,mi+1);
+    
+    if (imi>=acq.caliboffset) || (imi<=acq.caliboffset-totproj) || (imi==totproj && mi==0)
+      fl=[];
+    else
+      fl='flipped';
+      masterbb=fliplr(masterbb);
+    end
+    
+    cmimi=[cmimi; imi mi];
+    disp(sprintf(' Correlating: image %d with master %d %s',imi,mi,fl))
+    [corr,imbb]=sfCorrMaster(corr,scanfolder,scanname,imi,acq,bbox,imdark,masterbb,dim);
+    imblob(:,:,end+1)=imbb;
+  end
+end
+
+
+if strcmpi(acq.calibtype,'180degree') && strcmpi(acq.type,'360degree')
+  for imi=0:sf:totproj
+
+    if abs((imi-acq.caliboffset)/sf)==tomo_N
+      mi=tomo_N;
+    else
+      mi=mod((imi-acq.caliboffset)/sf,tomo_N);
+    end
+
+    masterbb=masterblob(:,:,mi+1);
+       
+    if (imi>=acq.caliboffset && imi<=acq.caliboffset+totproj/2) || (imi<=acq.caliboffset-totproj/2) || (imi==totproj && mi==0)
+      fl=[];
+      cmimi=[cmimi; imi mi 0];
+    else
+      fl='flipped';
+      masterbb=fliplr(masterbb);
+      cmimi=[cmimi; imi mi 1];
+    end
+    
+    disp(sprintf(' Correlating: image %d with master %d %s',imi,mi,fl))
+    [corr,imbb]=sfCorrMaster(corr,scanfolder,scanname,imi,acq,bbox,imdark,masterbb,dim);
+    imblob(:,:,end+1)=imbb;
+  end
+end
+
+if strcmpi(acq.calibtype,'360degree')
+  for imi=0:sf:totproj
+    mi=mod((imi-acq.caliboffset)/sf,tomo_N);
+
+    if mi==0 && imi==totproj
+      mi=tomo_N;
+    end
+    
+    masterbb=masterblob(:,:,mi+1);
+    
+    cmimi=[cmimi; imi mi 0];
+    disp(sprintf(' Correlating: image %d with master %d',imi,mi))
+    [corr,imbb]=sfCorrMaster(corr,scanfolder,scanname,imi,acq,bbox,imdark,masterbb,dim);
+    imblob(:,:,end+1)=imbb;
+  end
+end
+
+imblob(:,:,1)=[];
+
+
+%disp('Master images are saved in calibration folder.') 
+
+%corr(isnan(corr))=interp1(find(~isnan(corr)),corr(~isnan(corr)),find(isnan(corr)));
+
+%% Polynomial of vertical drift
+corr_ver=corr(:,1);
+figure('name','Vertical drift of scan from calibration') 
+hold on
+plot(corr_ver,'r.')
+
+[pol_ver,s_ver,mu_ver]=polyfit(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),5);
+corrp_ver=polyval(pol_ver,((1:totproj+1)-mu_ver(1))/mu_ver(2))';
+err_ver=corrp_ver-corr_ver;
+
+corr_ver(abs(err_ver)>tol_pol*std(err_ver(~isnan(err_ver))))=NaN;
+plot(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),'g.')
+[pol_ver,s_ver,mu_ver]=polyfit(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),8);
+corrp_ver=polyval(pol_ver,((1:totproj+1)-mu_ver(1))/mu_ver(2))'; % vector of drifts
+plot(corrp_ver,'r.','markersize',3)
+
+
+% Polynomial of horizontal drift
+% add a constant drift to all, if bounding bbox is not centered in the
+%  original image
+corr_hor=corr(:,2)+(detcenter_abs-bboxcenter_abs);
+figure('name','Horizontal drift of scan from calibration') 
+hold on
+plot(corr_hor,'r.')
+
+[pol_hor,s_hor,mu_hor]=polyfit(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),5);
+corrp_hor=polyval(pol_hor,((1:totproj+1)-mu_hor(1))/mu_hor(2))';
+err_hor=corrp_hor-corr_hor;
+
+corr_hor(abs(err_hor)>tol_pol*std(err_hor(~isnan(err_hor))))=NaN;
+plot(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),'g.')
+[pol_hor,s_hor,mu_hor]=polyfit(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),8);
+corrp_hor=polyval(pol_hor,((1:totproj+1)-mu_hor(1))/mu_hor(2))'; % vector of drifts
+plot(corrp_hor,'r.','markersize',3)
+
+ydrift_pol=corrp_hor;
+zdrift_pol=corrp_ver;
+
+
+% Interpolated drifts 
+zdrift_int=corr(:,1);
+zdrift_int(isnan(zdrift_int))=interp1(find(~isnan(zdrift_int)),zdrift_int(~isnan(zdrift_int)),find(isnan(zdrift_int)));
+
+ydrift_int=corr(:,2)+(detcenter_abs-bboxcenter_abs);
+ydrift_int(isnan(ydrift_int))=interp1(find(~isnan(ydrift_int)),ydrift_int(~isnan(ydrift_int)),find(isnan(ydrift_int)));
+
+
+%% BBox filled by sample during scan
+[imblob_min3,imno_imblobmin]=min(imblob,[],3);
+[minrow,imno_minrow]=min(imblob_min3,[],1);
+[mincol,imno_mincol]=min(imblob_min3,[],2);
+
+imno_minrow=imno_imblobmin(imno_minrow+(0:size(imno_imblobmin,2)-1)*size(imno_imblobmin,1))-1;
+imno_mincol=imno_imblobmin((1:size(imno_imblobmin,1))'+(imno_mincol-1)*size(imno_imblobmin,1))-1;
+
+if strcmpi(acq.calibtype,'180degree') && strcmpi(acq.type,'360degree')
+  tmp=imno_minrow;
+  imno_minrow=mod(tmp,tomo_N);
+  imno_minrow(tmp>0 & imno_minrow==0)=tomo_N;
+
+  tmp=imno_mincol;
+  imno_mincol=mod(tmp,tomo_N);
+  imno_mincol(tmp>0 & imno_mincol==0)=tomo_N;
+end
+
+imno_probl=[];
+
+if max(mincol)>lim_samatten
+  disp('WARNING! Sample during scan may not entirely fill the given bounding box!')
+  imno_probl=unique(imno_mincol(mincol>lim_samatten));
+  disp(' See scan images no. : ');
+  disp(imno_probl)
+  showims='yes';
+end
+
+if max(minrow)<lim_samatten
+  disp('WARNING! Sample during scan may have moved out of the given bounding box!')
+  imno_probl=unique(imno_minrow(minrow<lim_samatten));
+  disp(' See scan images no. : ');
+  disp(imno_probl')
+  showims='yes';
+end
+
+
+%% Determine and check bbox filled by sample during calibration
+[masterblob_min3,mno_masterblobmin]=min(masterblob,[],3);
+[minrow,mno_minrow]=min(masterblob_min3,[],1);
+[mincol,mno_mincol]=min(masterblob_min3,[],2);
+
+mno_minrow=mno_masterblobmin(mno_minrow+(0:size(mno_masterblobmin,2)-1)*size(mno_masterblobmin,1))-1;
+mno_mincol=mno_masterblobmin((1:size(mno_masterblobmin,1))'+(mno_mincol-1)*size(mno_masterblobmin,1))-1;
+
+if strcmpi(acq.calibtype,'180degree') && strcmpi(acq.type,'360degree')
+  tmp=mno_minrow;
+  mno_minrow=mod(tmp,tomo_N);
+  mno_minrow(tmp>0 & mno_minrow==0)=tomo_N;
+
+  tmp=mno_mincol;
+  mno_mincol=mod(tmp,tomo_N);
+  mno_mincol(tmp>0 & mno_mincol==0)=tomo_N;
+end
+
+showims='no';
+
+mno_probl=[];
+
+if max(mincol)>lim_samatten
+  disp('WARNING! Sample during calibration may not entirely fill the given bounding box!')
+  mno_probl=unique(mno_mincol(mincol>lim_samatten));
+  disp(' See master image no. : ');
+  disp(mno_probl)
+  showims='yes';
+end
+
+if max(minrow)<lim_samatten
+  disp('WARNING! Sample during calibration may have moved out of the given bounding box!')
+  mno_probl=unique(mno_minrow(minrow<lim_samatten));
+  disp(' See master image no. : ');
+  disp(mno_probl')
+  showims='yes';
+end
+
+
+%% Display
+
+sfDisplayImages(cmimi,masterblob,imblob,corr,clims_sample,clims_substract,mno_probl,imno_probl,0)
+
+showims=inputwdefault('Would you like to loop through the scan images?',showims);
+
+if strcmpi(showims,'y') || strcmpi(showims,'yes')
+  disp('Check master and scan images...')
+  disp('Press enter to loop through images')
+  sfDisplayImages(cmimi,masterblob,imblob,corr,clims_sample,clims_substract,mno_probl,imno_probl,1)
+end
+
+%% Create sample bounding box
+
+minrow=minrow<lim_samatten;
+marker=false(size(minrow));
+marker(round(length(marker)/2))=true;
+minrowr=imreconstruct(marker,minrow);
+edgel=find(minrowr,1,'first');
+edger=find(minrowr,1,'last');
+edgextl=max(edgel-ext_pix,1);
+edgextr=min(edger+ext_pix,bbox(3));
+bbs_ext(1)=bbox(1)+edgextl-1;
+bbs_ext(3)=edgextr-edgextl+1;
+
+mincol=mincol<lim_samatten;
+marker=false(size(mincol));
+marker(round(length(marker)/2))=true;
+mincolr=imreconstruct(marker,mincol);
+edget=find(mincolr,1,'first');
+edgeb=find(mincolr,1,'last');
+edgextt=max(edget-ext_pix,1);
+edgextb=min(edgeb+ext_pix,bbox(4));
+bbs_ext(2)=bbox(2)+edgextt-1;
+bbs_ext(4)=edgextb-edgextt+1;
+
+edges=[edgel edget edger edgeb];
+edges_ext=[edgextl edgextt edgextr edgextb];
+
+figure('name','Bounding box filled by sample during calibration')
+imshow(masterblob_min3,[0 1])
+hold on
+plot([edgel edger edger edgel edgel],[edget edget edgeb edgeb edget],'r-')
+plot([edgextl edgextr edgextr edgextl edgextl],[edgextt edgextt edgextb edgextb edgextt],'g-')
+
+output{1}=ydrift_int;
+output{2}=zdrift_int;
+output{3}=rotaxisloc_abs; 
+output{4}=rotdev_abs; 
+output{5}=rotdev; 
+output{6}=bbs_ext; 
+output{7}=edges; 
+output{8}=edges_ext;
+
+nout=max(nargout,2)-2;
+for i=1:nout
+  varargout{i}=output{i};
+end
+
+keyboard
+
+end % of function
+
+
+%% Sub-functions
+
+function [corr,im]=sfCorrMaster(corr,scanfolder,scanname,imi,acq,bbox,imdark,masterbb,dim)
+  imrefa=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,floor(imi/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+  imrefb=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,ceil((imi-eps)/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+  imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+  im=(edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,scanname,imi),bbox,'nodisp')-imdark)./imref;
+
+  if dim==0 || isempty(dim)
+    %corrvec=correlaterealspace(masterbb,im,20,20);
+    %corr(imi+1,1:2)=(corrvec+correlate(masterbb,im))/2;
+    corr(imi+1,1:2)=correlate(masterbb,im);
+  elseif dim==1
+    corrvec=correlate1(masterbb,im);
+    corr(imi+1,1:2)=[median(corrvec), 0];
+  elseif dim==2
+    corrvec=correlate1(masterbb',im');
+    corr(imi+1,1:2)=[0, median(corrvec)];
+  else
+    error('Dimension (first input argument) should be [], 0, 1 or 2!')
+  end
+end
+
+
+function sfDisplayImages(cmimi,masterblob,imblob,corr,clims_sample,clims_substract,mno_probl,imno_probl,dopause)
+
+figure('name','Evaluation of calibration')
+ set(gcf,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);
+
+ subplot(2,2,1)
+  set(gca,'Units','normalized','OuterPosition',[0 0.5 0.5 0.5]);
+
+ subplot(2,2,2)
+  set(gca,'Units','normalized','OuterPosition',[0.5 0.5 0.5 0.5]);
+ 
+ subplot(2,2,3)
+  set(gca,'Units','normalized','OuterPosition',[0 0 0.5 0.5]);
+
+ subplot(2,2,4)
+  set(gca,'Units','normalized','OuterPosition',[0.5 0 0.5 0.5]);
+  
+for i=1:length(cmimi)
+  subplot(2,2,1)
+   if cmimi(i,3)==1
+     imshow(fliplr(masterblob(:,:,cmimi(i,2)+1)),clims_sample)
+     title(sprintf('Master # %d flipped',cmimi(i,2)));
+   else
+     imshow(masterblob(:,:,cmimi(i,2)+1),clims_sample)
+     title(sprintf('Master # %d',cmimi(i,2)));
+   end
+   if any(cmimi(i,2)==mno_probl)
+     hold on
+     plot([-20 size(masterblob,2)+20 size(masterblob,2)+20 -20 -20],[-20 -20 size(masterblob,1)+20 size(masterblob,1)+20 -20],'r-','linewidth',2);
+     hold off
+   end
+   axis([-25 size(masterblob,2)+25 -25 size(masterblob,1)+25])
+   set(gca,'position',[0.05 0.55 0.4 0.4])
+
+  subplot(2,2,2)
+   imshow(imblob(:,:,i),clims_sample)
+   if any(cmimi(i,1)==imno_probl)
+     hold on
+     plot([-20 size(masterblob,2)+20 size(masterblob,2)+20 -20 -20],[-20 -20 size(masterblob,1)+20 size(masterblob,1)+20 -20],'r-','linewidth',2);
+     hold off
+   end
+   title(sprintf('Image # %d',cmimi(i,1)));
+   axis([-25 size(masterblob,2)+25 -25 size(masterblob,1)+25])
+   set(gca,'position',[0.55 0.55 0.4 0.4])
+
+  subplot(2,2,3)
+   plot(0:size(corr,1)-1,corr(:,2),'c.')
+   hold on
+   plot(0:size(corr,1)-1,corr(:,1),'b.')
+   plot(cmimi(i,1),corr(cmimi(i,1)+1,2),'ms')
+   plot(cmimi(i,1),corr(cmimi(i,1)+1,1),'ms')
+   hold off
+   title('Horizontal (cyan) and vertical (blue) drifts');
+   xlim([0 size(corr,1)])
+   set(gca,'position',[0.05 0.05 0.4 0.4])
+
+  subplot(2,2,4) 
+   if cmimi(i,3)==1
+     mbb=fliplr(masterblob(:,:,cmimi(i,2)+1));
+   else
+     mbb=masterblob(:,:,cmimi(i,2)+1);
+   end
+   imbb=imblob(:,:,i);
+   imbb=interpolatef(imbb,corr(cmimi(i,1)+1,1),corr(cmimi(i,1)+1,2));
+   imshow(mbb-imbb,clims_substract)
+   title('Substraction of correlated images')
+   set(gca,'position',[0.55 0.05 0.4 0.4])
+   
+  drawnow
+  if dopause==1
+    pause
+  end
+end
+
+end % of sfDisplayImages
+
+
+
+
+%plot([bbs_ext(1),bbs_ext(1)+bbs_ext(3)-1,bbs_ext(1)+bbs_ext(3)-1,bbs_ext(1),bbs_ext(1)],[bbs_ext(2),bbs_ext(2),bbs_ext(2)+bbs_ext(4)-1,bbs_ext(2)+bbs_ext(4)-1,bbs_ext(2)],'g-') 
+%[edgel edger edget edgeb]
+%bbs_ext
+
+% For displaying a given image pair
+
+% i=1
+%   cref=(tomo_N-i)/tomo_N*refstart+i/tomo_N*refend;
+%   master=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,i),bbread)-cdark)./cref;
+%   master=interpolatef(master,0,-rotdev);
+%   masterbb=master(1+frame:end-frame,1+frame:end-frame);
+%   figure(1)
+%   imshow(masterbb,[0 1])
+%   shg
+% 
+%   imi=mod(i*sf+acq.caliboffset,totproj);
+%   if imi~=i*sf+acq.caliboffset && strcmpi(acq.type,'180degree')
+%     masterbb=fliplr(masterbb);
+%   end
+% 
+%   imi=mod((i+tomo_N)*sf+acq.caliboffset,totproj)
+% 
+%   imrefa=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,floor(imi/acq.refon)*acq.refon),bbox)-imdark;
+%   imrefb=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,ceil((imi-eps)/acq.refon)*acq.refon),bbox)-imdark;
+%   imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+%   im=(edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,scanname,imi),bbox)-imdark)./imref;
+%   figure(2)
+%   imshow(im,[0 1]),shg
+
+
+% For displaying the masters:
+% 
+% figure
+% for ii=0:36
+%   imshow(edf_read(sprintf('master_%0.4d.edf',ii)),[]);shg
+%   pause
+% end
+
+% For displaying the masters:
+% 
+% figure
+% for ii=0:36
+%   imshow(masterblob(:,:,ii+1),[0 1]);shg
+% end
+
+
+% figure
+% for ii=1:73
+%   imshow(imblob{ii},[0 1]);shg
+%   disp(ii)
+%   pause
+% end
+
+
+
+
diff --git a/1_preprocessing/gtEvaluateCalibrationScan_xxx.m b/1_preprocessing/gtEvaluateCalibrationScan_xxx.m
new file mode 100755
index 0000000000000000000000000000000000000000..39d42453c39e08ae5301b0c4cc0b275a6e4e5288
--- /dev/null
+++ b/1_preprocessing/gtEvaluateCalibrationScan_xxx.m
@@ -0,0 +1,508 @@
+function [ydrift_pol,zdrift_pol,varargout]=gtEvaluateCalibrationScan(acq,bbox)
+% 
+% In bbox, treats the calibration scan, determines rotation axis location
+% at sub-pixel (in full image and in bbox), creates master images as references
+% to sample drifts, determines accurate sample bounding box for the total scan
+% inside bbox.
+%
+% Sample drifts are relative to constant reference positions, where 
+% reference positions have been determined the following way:
+% Assuming that during calibration scan the sample doesn't move relative to
+% the rotation table, the rotation axis is determined from image pairs 180
+% degrees offset. Master images are created from the calibration in a way
+% that they are translated to have the rotation axis in the very center of
+% the full image (even if working in an asymmetric bbox).
+% Images of the scan are correlated (horizontally and/or vertically) with
+% those masters, yielding 'ydrift' and 'zdrift'.
+%
+% Uses linear flat correction between ref0000_xxxx-s.
+%
+% INPUT  
+%   acq = acquisition parameters  
+%   bbox = according to GT conventions [originx, originy, width, height]
+%            bbox doesn't need to be centered in full image       
+%            if acq.correlationdim=1 bbox(4) needs to be even number (for correlate1)
+%            if acq.correlationdim=2 bbox(3) needs to be even number (for correlate1)
+%
+% OUTPUT  
+%   ydrift_pol, zdrift_pol = polynomial values with which the images need to be directly
+%                             translated (e.g direct input for interpolatef)
+%   varargout{1} = ydrift_int;  interpolated values of ydrifts
+%   varargout{2} = zdrift_int;  interpolated values of zdrifts  
+%   varargout{3} = rotaxisloc_abs;  rot axis x (horizontal) location in full image 
+%                   (non-integer in pixels)
+%   varargout{4} = rotdev_abs;  rot axis offset in full image; vector pointing
+%                   from center of image to rotation axis location;
+%                   positive to the right
+%   varargout{5} = rotdev;  rot axis offset in bbox; vector pointing from center
+%                   of bbox to rotation axis location in bbox, positive to the right
+%   varargout{6} = bbs_ext;  bounding box of maximum fill by sample  during 
+%                   rotation extended horizontally by ext_pix, in full image
+%   varargout{7} = edges;  bounding box of maximum fill by sample in bbox according to 'lim_samatten'
+%   varargout{8} = edges_ext;  'edges' extended by 'ext_pix' (at most up to the edges of bbox)
+%
+% 07/2007 Wolfgang, Peter
+%
+
+%% Parameters
+tol_pol=1; % tolerance factor for polynomial outliers (in unit std)
+tol_rotdev=0.5; % tolerance for deviation in rotation axis location found by different pairs (used for warning)
+lim_samatten=0.92; % limit to describe sample attenuation
+ext_pix=2; % sample bounding box extension in pixels
+frame=20; % frame extension for reading master files to be able to translate them
+
+%%
+
+disp(' ')
+disp('Evaluating calibration scan...')
+disp(' ')
+
+dim=acq.correlationdim;
+
+calibname=acq.calibration_path(find(acq.calibration_path=='/',1,'last')+1:end);
+
+scanname=acq.dir(find(acq.dir=='/',1,'last')+1:end);
+scanfolder=sprintf('%s/0_rawdata/%s',acq.dir,scanname);
+
+if strcmpi(acq.type,'360degree')
+  totproj=acq.nproj*2;
+elseif strcmpi(acq.type,'180degree')
+  totproj=acq.nproj;
+else
+  error('Unknown type of scan. Check acq.type!');
+end
+
+bbread=[bbox(1)-frame,bbox(2)-frame,bbox(3)+2*frame,bbox(4)+2*frame];
+
+if ~strcmpi(acq.calibtype,'180degree') && ~strcmpi(acq.calibtype,'360degree')
+  error('Unknown type of calibration scan (see acq.calibtype)!')
+end
+
+xml=xml_load(sprintf('%s/%s.xml',acq.calibration_path,calibname));
+
+tomo_N=str2num(xml.acquisition.tomo_N);
+ref_N=str2num(xml.acquisition.ref_N);
+%ref_On=str2num(xml.acquisition.ref_On);
+%dark_N=str2num(xml.acquisition.dark_N);
+
+
+%% Determine rotation axis offset
+
+detcenter_abs=acq.xdet/2+0.5;
+bboxcenter_abs=(2*bbox(1)+bbox(3)-1)/2;
+
+% Darks and ref-s
+cdark=edf_read(sprintf('%s/dark.edf',acq.calibration_path),bbread,'nodisp');
+cdarkbb=cdark(1+frame:end-frame,1+frame:end-frame);
+
+refstart=edf_read(sprintf('%s/ref0000_0000.edf',acq.calibration_path),bbread,'nodisp');
+for i=1:ref_N-1
+  refstart=refstart+edf_read(sprintf('%s/ref%0.4d_0000.edf',acq.calibration_path,i),bbread,'nodisp');
+end
+refstart=refstart/ref_N-cdark;
+% refstartbb=refstart(1+frame:end-frame,1+frame:end-frame);
+
+refend=edf_read(sprintf('%s/ref0000_%0.4d.edf',acq.calibration_path,tomo_N),bbread,'nodisp');
+for i=1:ref_N-1
+  refend=refend+edf_read(sprintf('%s/ref%0.4d_%0.4d.edf',acq.calibration_path,i,tomo_N),bbread,'nodisp');
+end
+refend=refend/ref_N-cdark;
+refendbb=refend(1+frame:end-frame,1+frame:end-frame);
+
+imend180=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,tomo_N+2),bbox,'nodisp')-cdarkbb)./refendbb;
+imend0=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,tomo_N),bbox,'nodisp')-cdarkbb)./refendbb;
+imend0=fliplr(imend0);
+
+% Determine rotdev: that is a vector of [bbox center to rotation axis 
+%  location in the bbox], positive to the right.
+rotdev=median(correlate1(imend180',imend0'))/2;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% confirmation with findshifts
+imforfs=interpolatef(imend0,0,rotdev*2);
+
+shift=[];
+assignin('base','shift',shift);
+disp(' ')
+disp('Calibration scan: check result of image correlation with findshifts...')
+disp(' ')
+
+findshifts2(imend180,imforfs);
+set(gcf,'name','Calibration scan: check correlation...')
+while isempty(shift)
+  drawnow;
+  shift=evalin('base','shift');
+end
+
+shift=evalin('base','shift');
+rotdev=shift(2)/2+rotdev; %%% check this!!!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if strcmpi(acq.calibtype,'360degree')
+  imend270=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,tomo_N+3),bbox,'nodisp')-cdarkbb)./refendbb;
+  imend90=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,tomo_N+1),bbox,'nodisp')-cdarkbb)./refendbb;
+  imend90=fliplr(imend90);
+
+  rotdev2=median(correlate1(imend270',imend90'))/2;
+  
+  disp('Rotation axis location in bounding box found by first pair:')
+  disp(rotdev)
+  disp('Rotation axis location in bounding box found by second pair:')
+  disp(rotdev2)
+
+  
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % confirmation with findshifts
+  imforfs=interpolatef(imend90,0,rotdev2*2);
+
+  shift=[];
+  assignin('base','shift',shift);
+  disp(' ')
+  disp('Calibration scan: check result of image correlation with findshifts...')
+  disp(' ')
+
+  findshifts2(imend270,imforfs);
+  set(gcf,'name','Calibration scan: check correlation...')
+  while isempty(shift)
+    drawnow;
+    shift=evalin('base','shift');
+  end
+
+  shift=evalin('base','shift');
+  rotdev2=shift(2)/2+rotdev2; %%% check this!!!
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+    
+  
+  if abs(rotdev-rotdev2)>tol_rotdev
+    disp('WARNING! Incosistent values have been found for rotation axes location in calibration scan.')
+    disp('Check images at end in calibration scan!')
+    pause(3)
+  end
+  rotdev=(rotdev+rotdev2)/2;
+end
+
+% vector of rotation axis location in full image; [from image center
+% to rotation axis location], positive to the right;
+
+rotdev_abs=bboxcenter_abs-detcenter_abs+rotdev;
+rotaxisloc_abs=bboxcenter_abs+rotdev;
+
+%% Create masters and correlate scan images
+
+if strcmpi(acq.type,'360degree')
+  if strcmpi(acq.calibtype,'360degree')
+    sf=totproj/tomo_N;
+  elseif strcmpi(acq.calibtype,'180degree')
+    sf=totproj/tomo_N/2;
+  else
+    error('Unknown type of calibration scan (see parameter file)!')
+  end
+elseif strcmpi(acq.type,'180degree')
+  if strcmpi(acq.calibtype,'360degree')
+    sf=totproj/tomo_N*2;
+  elseif strcmpi(acq.calibtype,'180degree')
+    sf=totproj/tomo_N;
+  else
+    error('Unknown type of calibration scan (see parameter file)!')
+  end
+else   
+  error('Unknown type of scan (see parameter file acq.type)!')
+end
+
+if mod(sf,1)~=0
+  error('No. of images in scan and calibration do not correspond!')
+end
+
+
+imdark=edf_read(sprintf('%s/dark.edf',scanfolder),bbox,'nodisp');
+corr=NaN(totproj+1,2);
+masterblob=[];
+
+for i=0:tomo_N 
+  cref=(tomo_N-i)/tomo_N*refstart+i/tomo_N*refend;
+  master=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,i),bbread,'nodisp')-cdark)./cref;
+  master=interpolatef(master,0,-rotdev);
+  masterbb=master(1+frame:end-frame,1+frame:end-frame);
+
+  imi=mod(i*sf+acq.caliboffset,totproj);
+  if imi~=i*sf+acq.caliboffset && strcmpi(acq.type,'180degree')
+    masterbb=fliplr(masterbb);
+  end
+  masterblob(:,:,i+1)=masterbb;  
+
+  edf_write(masterbb,sprintf('%s/master_%0.4d.edf',acq.calibration_path,i),'float32'); 
+
+  doit=true;
+  while doit==true
+    imrefa=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,floor(imi/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+    imrefb=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,ceil((imi-eps)/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+    imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+    im=(edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,scanname,imi),bbox,'nodisp')-imdark)./imref;
+    
+    if dim==0 || isempty(dim)
+      %corrvec=correlaterealspace(masterbb,im,20,20);
+      %corr(imi+1,1:2)=(corrvec+correlate(masterbb,im))/2;
+      corr(imi+1,1:2)=correlate(masterbb,im);
+    elseif dim==1
+      corrvec=correlate1(masterbb,im);
+      corr(imi+1,1:2)=[median(corrvec), 0];
+    elseif dim==2
+      corrvec=correlate1(masterbb',im');
+      corr(imi+1,1:2)=[0, median(corrvec)];
+    else
+      error('Dimension (first input argument) should be [], 0, 1 or 2!')
+    end
+  
+    if imi==0 && totproj~=0
+      if strcmpi(acq.type,'180degree')
+        masterbb=fliplr(masterbb);
+        imi=totproj; 
+      elseif strcmpi(acq.calibtype,'360degree')
+        imi=totproj;
+      end
+    else
+      doit=false;
+    end
+  end
+  
+  if strcmpi(acq.calibtype,'180degree') && strcmpi(acq.type,'360degree')
+    masterbb=fliplr(masterbb);
+    masterblob(:,:,i+1+tomo_N)=masterbb;
+    edf_write(masterbb,sprintf('%s/master_%0.4d.edf',acq.calibration_path,i+tomo_N),'float32');
+    
+    imi=mod((i+tomo_N)*sf+acq.caliboffset,totproj);
+
+    doit=true;
+    while doit==true
+      imrefa=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,floor(imi/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+      imrefb=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,ceil((imi-eps)/acq.refon)*acq.refon),bbox,'nodisp')-imdark;
+      imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+      im=(edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,scanname,imi),bbox,'nodisp')-imdark)./imref;
+
+      if i==tomo_N
+        break
+      end
+
+      if dim==0 || isempty(dim)
+        %corrvec=correlaterealspace(masterbb,im,20,20);
+        %corr(imi+1,1:2)=(corrvec+correlate(masterbb,im))/2;
+        corr(imi+1,1:2)=correlate(masterbb,im);
+      elseif dim==1
+        corrvec=correlate1(masterbb,im);
+        corr(imi+1,1:2)=[median(corrvec), 0];
+      elseif dim==2
+        corrvec=correlate1(masterbb',im');
+        corr(imi+1,1:2)=[0, median(corrvec)];
+      else
+        error('Dimension (first input argument) should be [], 0, 1 or 2!')
+      end
+
+      if imi==0 && totproj~=0
+        imi=totproj;
+      else
+        doit=false;
+      end
+      
+    end
+    
+  end
+end
+
+disp('Master images are saved in calibration folder.') 
+
+%corr(isnan(corr))=interp1(find(~isnan(corr)),corr(~isnan(corr)),find(isnan(corr)));
+
+% Polynomial of vertical drift
+corr_ver=corr(:,1);
+figure('name','Vertical drift of scan from calibration') 
+hold on
+plot(corr_ver,'r.')
+
+[pol_ver,s_ver,mu_ver]=polyfit(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),5);
+corrp_ver=polyval(pol_ver,((1:totproj+1)-mu_ver(1))/mu_ver(2))';
+err_ver=corrp_ver-corr_ver;
+
+corr_ver(abs(err_ver)>tol_pol*std(err_ver(~isnan(err_ver))))=NaN;
+plot(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),'g.')
+[pol_ver,s_ver,mu_ver]=polyfit(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),8);
+corrp_ver=polyval(pol_ver,((1:totproj+1)-mu_ver(1))/mu_ver(2))'; % vector of drifts
+plot(corrp_ver,'r.','markersize',3)
+
+
+% Polynomial of horizontal drift
+% add a constant drift to all, if bounding bbox is not centered in the
+%  original image
+corr_hor=corr(:,2)+(detcenter_abs-bboxcenter_abs);
+figure('name','Horizontal drift of scan from calibration') 
+hold on
+plot(corr_hor,'r.')
+
+[pol_hor,s_hor,mu_hor]=polyfit(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),5);
+corrp_hor=polyval(pol_hor,((1:totproj+1)-mu_hor(1))/mu_hor(2))';
+err_hor=corrp_hor-corr_hor;
+
+corr_hor(abs(err_hor)>tol_pol*std(err_hor(~isnan(err_hor))))=NaN;
+plot(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),'g.')
+[pol_hor,s_hor,mu_hor]=polyfit(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),8);
+corrp_hor=polyval(pol_hor,((1:totproj+1)-mu_hor(1))/mu_hor(2))'; % vector of drifts
+plot(corrp_hor,'r.','markersize',3)
+
+ydrift_pol=corrp_hor;
+zdrift_pol=corrp_ver;
+
+
+% Drifts interpolated
+zdrift_int=corr(:,1);
+zdrift_int(isnan(zdrift_int))=interp1(find(~isnan(zdrift_int)),zdrift_int(~isnan(zdrift_int)),find(isnan(zdrift_int)));
+
+ydrift_int=corr(:,2)+(detcenter_abs-bboxcenter_abs);
+ydrift_int(isnan(ydrift_int))=interp1(find(~isnan(ydrift_int)),ydrift_int(~isnan(ydrift_int)),find(isnan(ydrift_int)));
+
+
+%% Determine and check bbox filled by sample
+[masterblob_min3,imno_masterblobmin]=min(masterblob,[],3);
+[minrow,imno_minrow]=min(masterblob_min3,[],1);
+[mincol,imno_mincol]=min(masterblob_min3,[],2);
+
+imno_minrow=imno_masterblobmin(imno_minrow+(0:size(imno_masterblobmin,2)-1)*size(imno_masterblobmin,1))-1;
+imno_mincol=imno_masterblobmin((1:size(imno_masterblobmin,1))'+(imno_mincol-1)*size(imno_masterblobmin,1))-1;
+
+if strcmpi(acq.calibtype,'180degree') && strcmpi(acq.type,'360degree')
+  tmp=imno_minrow;
+  imno_minrow=mod(tmp,tomo_N);
+  imno_minrow(tmp>0 & imno_minrow==0)=tomo_N;
+
+  tmp=imno_mincol;
+  imno_mincol=mod(tmp,tomo_N);
+  imno_mincol(tmp>0 & imno_mincol==0)=tomo_N;
+end
+
+showmasters='no';
+
+if max(mincol)>lim_samatten
+  disp('WARNING! Sample may not entirely fill the preliminary bounding box!')
+  imno_probl=unique(imno_mincol(mincol>lim_samatten));
+  disp('See master image no. : ');
+  disp(imno_probl)
+  showmasters=inputwdefault('Would you like to loop through the master images?','y');
+end
+
+if max(minrow)<lim_samatten
+  disp('WARNING! Sample may have moved out of preliminary bounding box!')
+  imno_probl=unique(imno_minrow(minrow<lim_samatten));
+  disp('See master image no. : ');
+  disp(imno_probl')
+  showmasters=inputwdefault('Would you like to loop through the master images?','y');
+end
+
+if strcmpi(showmasters,'y') || strcmpi(showmasters,'yes')
+  disp('Check master images...')
+  disp('Press enter to loop through images')
+  figure('name','Masters')
+  for i=1:size(masterblob,3)
+    imshow(masterblob(:,:,i),[0 1])
+    set(gcf,'name',sprintf('Master no. %d',i-1))
+    disp(i-1)
+    pause
+  end
+end
+
+%% Create sample bounding box
+
+minrow=minrow<lim_samatten;
+marker=false(size(minrow));
+marker(round(length(marker)/2))=true;
+minrowr=imreconstruct(marker,minrow);
+edgel=find(minrowr,1,'first');
+edger=find(minrowr,1,'last');
+edgextl=max(edgel-ext_pix,1);
+edgextr=min(edger+ext_pix,bbox(3));
+bbs_ext(1)=bbox(1)+edgextl-1;
+bbs_ext(3)=edgextr-edgextl+1;
+
+mincol=mincol<lim_samatten;
+marker=false(size(mincol));
+marker(round(length(marker)/2))=true;
+mincolr=imreconstruct(marker,mincol);
+edget=find(mincolr,1,'first');
+edgeb=find(mincolr,1,'last');
+edgextt=max(edget-ext_pix,1);
+edgextb=min(edgeb+ext_pix,bbox(4));
+bbs_ext(2)=bbox(2)+edgextt-1;
+bbs_ext(4)=edgextb-edgextt+1;
+
+edges=[edgel edget edger edgeb];
+edges_ext=[edgextl edgextt edgextr edgextb];
+
+figure('name','Bounding box filled by sample during calibration')
+imshow(masterblob_min3,[0 1])
+hold on
+plot([edgel edger edger edgel edgel],[edget edget edgeb edgeb edget],'r-')
+plot([edgextl edgextr edgextr edgextl edgextl],[edgextt edgextt edgextb edgextb edgextt],'g-')
+
+output{1}=ydrift_int;
+output{2}=zdrift_int;
+output{3}=rotaxisloc_abs; 
+output{4}=rotdev_abs; 
+output{5}=rotdev; 
+output{6}=bbs_ext; 
+output{7}=edges; 
+output{8}=edges_ext;
+
+nout=max(nargout,2)-2;
+for i=1:nout
+  varargout{i}=output{i};
+end
+
+%keyboard
+
+end % of function
+
+
+
+
+
+%plot([bbs_ext(1),bbs_ext(1)+bbs_ext(3)-1,bbs_ext(1)+bbs_ext(3)-1,bbs_ext(1),bbs_ext(1)],[bbs_ext(2),bbs_ext(2),bbs_ext(2)+bbs_ext(4)-1,bbs_ext(2)+bbs_ext(4)-1,bbs_ext(2)],'g-') 
+%[edgel edger edget edgeb]
+%bbs_ext
+
+% For displaying a given image pair
+
+% i=1
+%   cref=(tomo_N-i)/tomo_N*refstart+i/tomo_N*refend;
+%   master=(edf_read(sprintf('%s/%s%0.4d.edf',acq.calibration_path,calibname,i),bbread)-cdark)./cref;
+%   master=interpolatef(master,0,-rotdev);
+%   masterbb=master(1+frame:end-frame,1+frame:end-frame);
+%   figure(1)
+%   imshow(masterbb,[0 1])
+%   shg
+% 
+%   imi=mod(i*sf+acq.caliboffset,totproj);
+%   if imi~=i*sf+acq.caliboffset && strcmpi(acq.type,'180degree')
+%     masterbb=fliplr(masterbb);
+%   end
+% 
+%   imi=mod((i+tomo_N)*sf+acq.caliboffset,totproj)
+% 
+%   imrefa=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,floor(imi/acq.refon)*acq.refon),bbox)-imdark;
+%   imrefb=edf_read(sprintf('%s/ref0000_%0.4d.edf',scanfolder,ceil((imi-eps)/acq.refon)*acq.refon),bbox)-imdark;
+%   imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+%   im=(edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,scanname,imi),bbox)-imdark)./imref;
+%   figure(2)
+%   imshow(im,[0 1]),shg
+
+
+% For displaying the masters:
+% figure
+% for ii=0:36
+%   imshow(edf_read(sprintf('master_%0.4d.edf',ii)),[]);shg
+%   pause
+% end
+
+
+
+
+
+
diff --git a/1_preprocessing/gtFindDirectBeamBB.m b/1_preprocessing/gtFindDirectBeamBB.m
new file mode 100755
index 0000000000000000000000000000000000000000..2c2862f5e32e6ea2da439a3145a71ddf88e33019
--- /dev/null
+++ b/1_preprocessing/gtFindDirectBeamBB.m
@@ -0,0 +1,169 @@
+function bb=gtFindDirectBeamBB(acq)
+%
+% Gives approximate bounding box of direct beam to be used for
+% calibration and to be refined as sample bounding box.
+%
+% 07/2007 Wolfgang, Peter
+%
+
+refarea=127; 
+lim_directbeam=0.8; 
+
+disp(' ')
+disp('Determining direct beam bounding box...')
+disp(' ')
+
+
+
+
+%name=sprintf('0_rawdata/%s/ref0000_0000.edf',acq.name);
+% modif sabine
+d=edf_read('dark.edf');
+
+name='ref0000_0000.edf';
+if ~exist(name,'file')                                     %%%%%%%%%%modif sabine
+    name='refHST0000.edf';
+end
+ref0=[];
+ref0=edf_read(name,[],'nodisp')-d; % reference at beginning of scan
+
+%name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj);
+% modif sabine
+totproj=2*acq.nproj;
+if acq.interlaced_turns==0
+     name=sprintf('ref0000_%04d.edf',totproj); 
+     if ~exist(name,'file')                                     %%%%%%%%%%modif sabine
+        name=sprintf('refHST%04d.edf',totproj);       
+    end    
+else
+   name=sprintf('ref0000_%04d.edf',floor(totproj/(acq.interlaced_turns+1)));     
+end
+% end modif sabine
+ref1=[];
+ref1=edf_read(name,[],'nodisp')-d; % reference at end of scan
+
+%ref=(ref0+ref1)/2;
+ref=[];
+ref=min(ref0,ref1); % min of ref-s at beginning and end of scan
+
+% calculate mean value m in central part of the image
+m=mean2(ref(round(acq.ydet/2-refarea:acq.ydet/2+refarea+1),round(acq.xdet/2-refarea:acq.xdet/2+refarea+1)));
+cen=double(ref>(lim_directbeam*m));  % should correspond to direct beam footprint
+
+% find the direct beam region bb automatically (supposes fairly homogeneous
+% beam profile - attention with ID11 data here... !
+
+marker=zeros(acq.ydet,acq.xdet);
+marker(round(acq.ydet/2),round(acq.xdet/2))=1;
+cen=imreconstruct(marker,cen);
+tmp=regionprops(cen,'BoundingBox');
+bb=tmp.BoundingBox;
+
+% Tighten bb until it's fully filled
+bb=[ceil(bb(1:2)),bb(3:4)-1];
+goon=true;
+while goon
+  cenbb=gtCrop(cen,bb);
+  goon=false;
+  
+  if any(~cenbb(:,1)) % tighten bb on the left
+    bb(1)=bb(1)+1;
+    bb(3)=bb(3)-1;
+    goon=true;
+  end
+
+  if any(~cenbb(:,end)) % tighten bb on the right
+    bb(3)=bb(3)-1;
+    goon=true;
+  end
+
+  cenbb=gtCrop(cen,bb);
+  
+  if any(~cenbb(1,:)) % tighten bb at the top
+    bb(2)=bb(2)+1;
+    bb(4)=bb(4)-1;
+    goon=true;
+  end
+
+  if any(~cenbb(end,:)) % tighten bb at the bottom
+    bb(4)=bb(4)-1;
+    goon=true;
+  end
+end
+
+% Loosen bb if it can be on any side
+goon=true;
+while goon
+  goon=false;
+  
+  tmpbb=bb+[-1 0 1 0]; % loose bb on the left
+  tmpim=gtCrop(cen,tmpbb);
+  if all(tmpim(:)) 
+    bb=tmpbb;
+    goon=true;
+  end
+
+  tmpbb=bb+[0 0 1 0]; % loose bb on the right
+  tmpim=gtCrop(cen,tmpbb);
+  if all(tmpim(:)) 
+    bb=tmpbb;
+    goon=true;
+  end
+
+  tmpbb=bb+[0 -1 0 1]; % loose bb at the top
+  tmpim=gtCrop(cen,tmpbb);
+  if all(tmpim(:)) 
+    bb=tmpbb;
+    goon=true;
+  end
+
+  tmpbb=bb+[0 0 0 1]; % loose bb at the bottom
+  tmpim=gtCrop(cen,tmpbb);
+  if all(tmpim(:)) 
+    bb=tmpbb;
+    goon=true;
+  end
+end
+
+
+% make sure the bbox width and height are even numbers (needed for correlation)
+bb(3:4)=ceil(bb(3:4)/2)*2;
+
+bbcenter_abs=(2*bb(1)+bb(3)-1)/2;
+
+% plot bbox found, its center-line and center-line of image
+figure('name','Direct beam bounding box')
+imshow(ref,[])
+drawnow
+hold on
+plot([bb(1),bb(1)+bb(3)-1,bb(1)+bb(3)-1,bb(1),bb(1)],[bb(2),bb(2),bb(2)+bb(4)-1,bb(2)+bb(4)-1,bb(2)],'r-')
+plot([acq.xdet/2+0.5 acq.xdet/2+0.5],[1 acq.ydet],'b-.') % centre of the ccd
+plot([bbcenter_abs bbcenter_abs],[bb(2) bb(2)+bb(4)-1],'c-.') % centre of the direct beam
+bb
+disp('press any key to continue');
+pause
+%bboxmin=min(abs(acq.xdet/2-bbox(1)),abs(acq.xdet/2-(bbox(1)+bbox(3)-1)));
+%bboxmin(2)=bbox(2);
+% ajout sabine
+bbout=bb;
+rep=input('Are you satisfied with this bounding box for the direct beam?','s')
+while (strcmpi(rep, 'no')| strcmpi(rep, 'n'))
+    bbbis(1)=input('Indicate top left corner x coordinate')
+    bbbis(2)=input('Indicate top left corner y coordinate')
+    bbbis(3)=input('Indicate size in x')
+    bbbis(4)=input('Indicate size in y')
+    figure, imshow(ref,[]), drawnow,     hold on
+    plot([bbbis(1),bbbis(1)+bbbis(3)-1,bbbis(1)+bbbis(3)-1,bbbis(1),bbbis(1)],[bbbis(2),bbbis(2),bbbis(2)+bbbis(4)-1,bbbis(2)+bbbis(4)-1,bbbis(2)],'r-')
+    bbcenter_abs=(2*bbbis(1)+bbbis(3)-1)/2
+    plot([acq.xdet/2+0.5 acq.xdet/2+0.5],[1 acq.ydet],'b-.');
+    plot([bbcenter_abs bbcenter_abs],[bbbis(2) bbbis(2)+bbbis(4)-1],'c-.') % centre of the direct beam
+    disp('press any key to continue');
+    pause
+    rep=input('Are you satisfied with this bounding box for the direct beam?','s');
+    bbout(1:4)=bbbis(1:4);
+end
+bb=bbout;
+% fin sabine
+
+
+end % of function
diff --git a/1_preprocessing/gtFindDirectBeamBBQuali.m b/1_preprocessing/gtFindDirectBeamBBQuali.m
new file mode 100755
index 0000000000000000000000000000000000000000..e8e9eee463902cdf7328073032d6c4e6c38920cd
--- /dev/null
+++ b/1_preprocessing/gtFindDirectBeamBBQuali.m
@@ -0,0 +1,137 @@
+function bb=gtFindDirectBeamBBQuali(acq,calib)
+%
+% Gives approximate bounding box of direct beam to be used for
+% calibration and to be refined as sample bounding box.
+%
+% 09/2007 Peter
+%
+
+refarea=127;
+lim_directbeam=0.6;
+
+disp(' ')
+disp('Determining direct beam bounding box of qualis...')
+disp(' ')
+
+if strcmpi(acq.type,'180degree')
+  totproj=acq.nproj;
+elseif strcmpi(acq.type,'360degree');
+  totproj=acq.nproj*2;
+else
+  disp('unknown scantype in gtFindDirectBeamBBQuali');
+  return;
+end
+
+d=edf_read(sprintf('%s/dark.edf',calib.dir),[],'nodisp');
+
+ref0=edf_read([calib.dir '/refHST0000.edf'],[],'nodisp')-d; % reference at beginning of scan
+ref1=edf_read(sprintf('%s/refHST%04d.edf',calib.dir,calib.totproj),[],'nodisp')-d; % reference at end of scan
+
+ref=min(ref0,ref1); % min of ref-s at beginning and end of scan
+
+% calculate mean value m in central part of the image
+m=mean2(ref(round(acq.ydet/2-refarea:acq.ydet/2+refarea+1),round(acq.xdet/2-refarea:acq.xdet/2+refarea+1)));
+cen=double(ref>(lim_directbeam*m));  % should correspond to direct beam footprint
+
+% find the direct beam region bb automatically (supposes fairly homogeneous
+% beam profile - attention with ID11 data here... !
+
+marker=zeros(acq.ydet,acq.xdet);
+marker(round(acq.ydet/2),round(acq.xdet/2))=1;
+cen=imreconstruct(marker,cen);
+tmp=regionprops(cen,'BoundingBox');
+bb=tmp.BoundingBox;
+
+% Tighten bb until it's fully filled
+bb=[ceil(bb(1:2)),bb(3:4)-1];
+goon=true;
+while goon
+  cenbb=gtCrop(cen,bb);
+  goon=false;
+  
+  if any(~cenbb(:,1)) % tighten bb on the left
+    bb(1)=bb(1)+1;
+    bb(3)=bb(3)-1;
+    goon=true;
+  end
+
+  if any(~cenbb(:,end)) % tighten bb on the right
+    bb(3)=bb(3)-1;
+    goon=true;
+  end
+
+  cenbb=gtCrop(cen,bb);
+  
+  if any(~cenbb(1,:)) % tighten bb at the top
+    bb(2)=bb(2)+1;
+    bb(4)=bb(4)-1;
+    goon=true;
+  end
+
+  if any(~cenbb(end,:)) % tighten bb at the bottom
+    bb(4)=bb(4)-1;
+    goon=true;
+  end
+end
+
+% Loosen bb if it can be on any side
+goon=true;
+while goon
+  goon=false;
+  
+  tmpbb=bb+[-1 0 1 0]; % loose bb on the left
+  tmpim=gtCrop(cen,tmpbb);
+  if all(tmpim(:)) 
+    bb=tmpbb;
+    goon=true;
+  end
+
+  tmpbb=bb+[0 0 1 0]; % loose bb on the right
+  tmpim=gtCrop(cen,tmpbb);
+  if all(tmpim(:)) 
+    bb=tmpbb;
+    goon=true;
+  end
+
+  tmpbb=bb+[0 -1 0 1]; % loose bb at the top
+  tmpim=gtCrop(cen,tmpbb);
+  if all(tmpim(:)) 
+    bb=tmpbb;
+    goon=true;
+  end
+
+  tmpbb=bb+[0 0 0 1]; % loose bb at the bottom
+  tmpim=gtCrop(cen,tmpbb);
+  if all(tmpim(:)) 
+    bb=tmpbb;
+    goon=true;
+  end
+end
+
+
+% make sure the bbox width and height are even numbers (needed for correlate1, so probably not for qualis)
+bb(3:4)=ceil(bb(3:4)/2)*2;
+
+bbcenter_abs=(2*bb(1)+bb(3)-1)/2;
+
+% plot bbox found, its center-line and center-line of image
+figure('name','Direct beam bounding box')
+
+wdefault=warning;
+warning('off','all');
+
+imshow(ref,[])
+
+warning(wdefault);
+
+hold on
+plot([bb(1),bb(1)+bb(3)-1,bb(1)+bb(3)-1,bb(1),bb(1)],[bb(2),bb(2),bb(2)+bb(4)-1,bb(2)+bb(4)-1,bb(2)],'r-')
+plot([acq.xdet/2+0.5 acq.xdet/2+0.5],[1 acq.ydet],'b-.')
+plot([bbcenter_abs bbcenter_abs],[bb(2) bb(2)+bb(4)-1],'c-.')
+
+%bboxmin=min(abs(acq.xdet/2-bbox(1)),abs(acq.xdet/2-(bbox(1)+bbox(3)-1)));
+%bboxmin(2)=bbox(2);
+
+
+
+end % of function
diff --git a/1_preprocessing/gtFindRotationAxis.m b/1_preprocessing/gtFindRotationAxis.m
new file mode 100755
index 0000000000000000000000000000000000000000..81d846574b630e77f929064e0c71cee6ddb987b3
--- /dev/null
+++ b/1_preprocessing/gtFindRotationAxis.m
@@ -0,0 +1,24 @@
+function rot = gtFindRotationAxis(acq,bbdir)
+
+disp(' finding rotation axis...') 
+d=edf_read('dark.edf',bbdir,'nodisp');
+if acq.interlaced_turns==0
+  im0=edf_read(sprintf('%s0000.edf',acq.name),bbdir,'nodisp');
+  im1=edf_read(sprintf('%s%04d.edf',acq.name,acq.nproj),bbdir,'nodisp'); %note nproj is number per 180 degrees
+  ref0=edf_read('ref0000_0000.edf',bbdir,'nodisp');
+  ref1=edf_read(sprintf('ref0000_%04d.edf',acq.nproj),bbdir,'nodisp');
+  im0=(im0-d)./(ref0-d);
+  im1=(im1-d)./(ref1-d);
+else
+  im0=edf_read(sprintf('%s0_0000.edf',acq.name),bbdir,'nodisp');
+  im1=edf_read(sprintf('%s0_%04d.edf',acq.name,acq.nproj/(2*acq.interlaced_turns)),bbdir,'nodisp');
+  ref0=edf_read('ref0000_0000.edf',bbdir,'nodisp');
+  ref1=edf_read(sprintf('ref0000_%04d.edf',acq.nproj/(2*acq.interlaced_turns)),bbdir,'nodisp');
+  im0=(im0-d)./(ref0-d);
+  im1=(im1-d)./(ref1-d);
+end
+
+shift = gt_findshifts2(im0,fliplr(im1), 'block', 'on'); %version that returns shift!
+
+rot=acq.xdet/2+0.5 - (shift(2)/2);% signe a valider avec wolfgang - should be correct AK
+
diff --git a/1_preprocessing/gtFindSampleEdges.m b/1_preprocessing/gtFindSampleEdges.m
new file mode 100755
index 0000000000000000000000000000000000000000..55c3ea77998fe6e08bb572fb5018dee45f52b599
--- /dev/null
+++ b/1_preprocessing/gtFindSampleEdges.m
@@ -0,0 +1,155 @@
+function [first,last,ims]=gtFindSampleEdges(acq,bb)
+
+
+intervals=6;
+margin=5;
+
+%ak - edit to run in local directory
+%d=edf_read(sprintf('0_rawdata/%s/dark.edf',acq.name),[],'nodisp');
+
+%use bb when reading the files in.
+
+d=edf_read('dark.edf',bb,'nodisp');
+%test sabine
+%ims=zeros(bb(4),bb(3)); original
+%test=bb(3);bb(3)=bb(4); bb(4)=test;
+
+
+ims=zeros(bb(4),bb(3));
+j=1;
+if acq.interlaced_turns==0
+    for i=0:round(acq.nproj/intervals):acq.nproj
+        %im=edf_read(sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,i),[],'nodisp')-d;
+        im=edf_read(sprintf('%s%04d.edf',acq.name,i),bb,'nodisp')-d;
+        %ref=edf_read(sprintf('0_rawdata/%s/ref0001_%04d.edf',acq.name,floor(i/acq.refon)*acq.refon),[],'nodisp')-d;
+        %%%%%%%%%%modif sab
+        %ref=edf_read(sprintf('ref0001_%04d.edf',floor(i/acq.refon)*acq.refon),[],'nodisp')-d;
+        name=sprintf('ref0001_%04d.edf',floor(i/acq.refon)*acq.refon);
+        if ~exist(name)
+            name=sprintf('refHST%04d.edf',floor(i/acq.refon)*acq.refon);
+        end
+        %%%%%%%%%%%end modif sab
+        ref=edf_read(name,bb,'nodisp')-d;
+        im=im./ref;
+        ims=ims+im;
+        j=j+1;
+    end
+else
+    for i=0:round(acq.nproj/intervals):acq.nproj % search on the first interalced scan
+        %im=edf_read(sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,i),[],'nodisp')-d;
+        if i==acq.nproj
+            im=edf_read(sprintf('%s0_%04d.edf',acq.name,3599),bb,'nodisp')-d;
+        else
+            im=edf_read(sprintf('%s0_%04d.edf',acq.name,i),bb,'nodisp')-d;
+        end
+        %ref=edf_read(sprintf('0_rawdata/%s/ref0001_%04d.edf',acq.name,floor(i/acq.refon)*acq.refon),[],'nodisp')-d;
+        %%%%%%%%%%modif sab
+        %ref=edf_read(sprintf('ref0001_%04d.edf',floor(i/acq.refon)*acq.refon),[],'nodisp')-d;
+        name=sprintf('ref0001_%04d.edf',floor(i/acq.refon)*acq.refon);
+        if ~exist(name)
+            name=sprintf('refHST%04d.edf',floor(i/acq.refon)*acq.refon);
+        end
+        %%%%%%%%%%%end modif sab
+        ref=edf_read(name,bb,'nodisp')-d;
+        im=im./ref;
+        ims=ims+im;
+        j=j+1;
+    end
+end
+
+
+
+%  m(bb(1):bb(1)+bb(3)-2)=abs(diff(mean(gtCrop(ims,bb))));
+%  m_signed(bb(1):bb(1)+bb(3)-2)=diff(mean(gtCrop(ims,bb)));
+m(bb(1):bb(1)+bb(3)-2)=abs(diff(mean(ims))); % sorte de calcul de gradient
+m_signed(bb(1):bb(1)+bb(3)-2)=diff(mean(ims));
+
+% tried min, but wasn't any better - Peter
+%m(bb(1):bb(1)+bb(3)-2)=abs(diff(min(gtCrop(ims,bb))));
+%m_signed(bb(1):bb(1)+bb(3)-2)=diff(min(gtCrop(ims,bb)));
+
+%plot(m);drawnow;
+
+
+first=find(m>0.5*max(m),1,'first');
+last =find(m>0.5*max(m),1,'last');
+
+%try another way of getting the bounding box
+%marginally better
+%look for local maxima in m, other than the very start and very end
+%(which are the edges of the slits rather than the sample
+m2=[]; %store local maxima
+m3=[]; %store zero crossings
+range=10;
+m(end+1:end+range)=zeros(1,range);
+m_signed(end+1:end+range)=zeros(1,range);
+
+for i=bb(1):bb(1)+bb(3)-2
+    tmp=m(i-range:i+range);
+    if m(i)==max(tmp) %local maxima
+        m2=[m2 i];
+    end
+    if (m_signed(i)<0 & m_signed(i+1)>0) | (m_signed(i)>0 & m_signed(i+1)<0) % recherche du bord
+        m3=[m3 i];
+    end
+
+end
+%local maxima, hopefully excluding the slits
+first=m2(2);
+last=m2(end-1);
+first1=first; last1=last; %
+%zero crossing points outside these local maxima
+first=max(m3(find(m3<first)));
+last=min(m3(find(m3>last)));
+
+%modif sabine if there is no other local maximalfound by zero crossing
+
+if (isempty(first));  first=first1; end
+if (isempty(last)); last=last1; end
+
+
+width=round(max(acq.rotx-first,last-acq.rotx));
+if mod(2*acq.rotx,2)
+    first=ceil(acq.rotx)-width;
+    last=ceil(acq.rotx)+width-1;
+else
+    first=ceil(acq.rotx)-width;
+    last=ceil(acq.rotx)+width;
+end
+
+h=figure(1);
+% modif sabine
+% tmp=ims;
+% tmp(:,[first,last])=0;
+% imshow(gtCrop(tmp,bb),[]);drawnow
+tmp=ims;
+bb2=[first-bb(1) 1 last-first size(ims,1)];
+imshow(gtCrop(tmp,bb2),[]);drawnow
+title('use arrow keys to modify the BoundingBox - press enter to accept')
+
+c=1;
+while c~=13
+    waitforbuttonpress
+    c=get(h,'CurrentCharacter');
+    tmp=ims;
+
+    switch c
+        case 29 %right arrow
+            disp('increasing width');
+            first=first-1;
+            last=last+1;
+        case 28 % left arrow
+            disp('decreasing width');
+            first=first+1;
+            last=last-1;
+    end
+    %tmp(:,[first,last])=0;
+    %imshow(gtCrop(tmp,bb),[]);drawnow
+
+    bb2=[first-bb(1) 1 last-first size(ims,1)];
+    imshow(gtCrop(tmp,bb2),[]);
+    drawnow;
+end
+
+disp('end of sample edges selection ....');
+end
diff --git a/1_preprocessing/gtFlipExtImages.m b/1_preprocessing/gtFlipExtImages.m
new file mode 100755
index 0000000000000000000000000000000000000000..1b400ec1dc7efef05329a5c73f8d17e6e9af3f1b
--- /dev/null
+++ b/1_preprocessing/gtFlipExtImages.m
@@ -0,0 +1,26 @@
+
+function gtFlipExtImages(first, last, workingdirectory)
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+
+cd(workingdirectory)
+
+for i=first:last
+  
+  disp(sprintf('flipping image:  ext%04d',i))
+  
+  
+  im=edf_read(sprintf('1_preprocessing/ext/ext%04d.edf',i));
+%  im=flipud(im);
+  im=fliplr(im);
+  edf_write(im, sprintf('1_preprocessing/ext/ext%04d.edf',i), 'float32')
+  
+
+end
diff --git a/1_preprocessing/gtFlipFullImages.m b/1_preprocessing/gtFlipFullImages.m
new file mode 100755
index 0000000000000000000000000000000000000000..1e247e91140032e642fc9dba66ea872d7647f6d7
--- /dev/null
+++ b/1_preprocessing/gtFlipFullImages.m
@@ -0,0 +1,49 @@
+
+function gtFlipFullImages(first, last, workingdirectory, updown, leftright)
+%flip full images.  
+%set updown or leftright to true to flip on that axis
+
+workingdirectory
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+  updown=str2double(updown);
+  leftright=str2double(leftright);
+end
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+
+cd(workingdirectory)
+
+disp(sprintf('doing images from %d to %d', first, last))
+if updown
+  disp('flipping up-down')
+end
+if leftright
+  disp('flipping left-right')
+end
+
+
+
+
+for i=first:last
+  
+  disp(sprintf('processing image:  full%04d',i))
+  
+  %read image
+  im=edf_read(sprintf('1_preprocessing/full/full%04d.edf',i));
+  %apply flips
+  if updown
+    im=flipud(im);
+  end
+  if leftright
+    im=fliplr(im);
+  end
+  %write image
+  edf_write(im, sprintf('1_preprocessing/full/full%04d.edf',i), 'float32')
+  
+
+end
diff --git a/1_preprocessing/gtFullStatAssembleOutputFiles.m b/1_preprocessing/gtFullStatAssembleOutputFiles.m
new file mode 100755
index 0000000000000000000000000000000000000000..6b9a65705f375576b4dd020c8f685bdb78c66160
--- /dev/null
+++ b/1_preprocessing/gtFullStatAssembleOutputFiles.m
@@ -0,0 +1,53 @@
+%
+% FUNCTION gtFullStatAssembleOutputFiles
+%
+% Looks for the output files of gtFullStatCondor and copies the data in one
+% single file named 'fullstat_dataname.mat'.
+% The seperate result files can be deleted afterwards.
+
+function gtFullStatAssembleOutputFiles
+
+load parameters.mat
+
+rfile=dir('fullstatpart_*_*.mat');
+
+disp(['Number of result files: ' num2str(length(rfile))])
+
+for i=1:length(rfile)
+  fname=rfile(i).name;
+  data=load(fname);
+  startno=str2num(fname(12:15));
+  endno=str2num(fname(17:20));
+  mean_full_all(startno+1:endno+1)=data.mean_full;
+  mean_full_1_all(startno+1:endno+1)=data.mean_full_1;
+  med_full_all(startno+1:endno+1)=data.med_full;
+  peak_full_all(startno+1:endno+1)=data.peak_full;
+  std_full_all(startno+1:endno+1)=data.std_full;
+  std_full_1_all(startno+1:endno+1)=data.std_full_1;
+end
+
+figure('name','Median of fullimages')
+plot(med_full_all,'b+')
+
+figure('name','Peak of fullimages')
+plot(peak_full_all,'b+')
+
+figure('name','Mean of fullimages')
+plot(mean_full_all,'b+')
+
+figure('name','Mean of fullimages; 1% cut off')
+plot(mean_full_1_all,'b+')
+
+figure('name','STD of fullimages')
+plot(std_full_all,'b+')
+
+figure('name','STD of fullimages; 1% cut off')
+plot(std_full_1_all,'b+')
+
+allfilename=['fullstat_' parameters.acq.name '.mat'];
+allfilename=allfilename(1:end-1);
+
+save(allfilename,'mean_full_all','mean_full_1_all',...
+     'med_full_all','peak_full_all','std_full_all','std_full_1_all')
+
+end
diff --git a/1_preprocessing/gtMakeMontage.m b/1_preprocessing/gtMakeMontage.m
new file mode 100755
index 0000000000000000000000000000000000000000..71b8c111d2eeeb400c595226cf357ef199f55b6a
--- /dev/null
+++ b/1_preprocessing/gtMakeMontage.m
@@ -0,0 +1,51 @@
+
+
+function gtMakeMontage
+
+name='ss10j_'
+lims=[0.1 1];
+bbox=[800 850 450 350];
+
+dark=edf_read('dark.edf',bbox);
+
+
+im=edf_read(sprintf('%s0000.edf',name),bbox);
+ref=edf_read('refHST0000.edf',bbox);
+im=(im-dark)./(ref-dark);
+subplot(2,4,1);imshow(im,lims);
+
+im=edf_read(sprintf('%s0900.edf',name),bbox);
+ref=edf_read('refHST0900.edf',bbox);
+im=(im-dark)./(ref-dark);
+subplot(2,4,2);imshow(im,lims);
+
+im=edf_read(sprintf('%s1800.edf',name),bbox);
+ref=edf_read('refHST1800.edf',bbox);
+im=(im-dark)./(ref-dark);
+subplot(2,4,3);imshow(im,lims);
+
+im=edf_read(sprintf('%s2700.edf',name),bbox);
+ref=edf_read('refHST2700.edf',bbox);
+im=(im-dark)./(ref-dark);
+subplot(2,4,4);imshow(im,lims);
+
+im=edf_read(sprintf('%s3599.edf',name),bbox);
+ref=edf_read('refHST3600.edf',bbox);
+im=(im-dark)./(ref-dark);
+subplot(2,4,5);imshow(im,lims);
+
+
+im=edf_read(sprintf('%s3600.edf',name),bbox);
+ref=edf_read('refHST3600.edf',bbox);
+im=(im-dark)./(ref-dark);
+subplot(2,4,6);imshow(im,lims);
+
+im=edf_read(sprintf('%s3601.edf',name),bbox);
+ref=edf_read('refHST3600.edf',bbox);
+im=(im-dark)./(ref-dark);
+subplot(2,4,7);imshow(im,lims);
+
+im=edf_read(sprintf('%s3602.edf',name),bbox);
+ref=edf_read('refHST3600.edf',bbox);
+im=(im-dark)./(ref-dark);
+subplot(2,4,8);imshow(im,lims);
\ No newline at end of file
diff --git a/1_preprocessing/gtMovingMedian.m b/1_preprocessing/gtMovingMedian.m
new file mode 100755
index 0000000000000000000000000000000000000000..3051e9705b96bfd4ca7ff515d5b908401e5953ca
--- /dev/null
+++ b/1_preprocessing/gtMovingMedian.m
@@ -0,0 +1,164 @@
+% function gtMovingMedian(first,last)
+% calculates the moving median of a series of raw images (first : last) 
+
+% median is calculated from a stack containing prep.fullrange/interval images
+%
+% ATTENTION
+% prep.fullrange must be multiple of prep.INTERVAL and a MULTIPLE OF 2   !!!!!!!!
+% NPROJ should be a multiple of prep.fullrange
+%
+% median is calculated/updated only each interval images
+% the original files are supposed to be in indir/name%04.edf
+% the output is written to directory outdir/med%04d.edf
+% in order to normalize raw images to the same intensity, dark subtraction and a multiplicative corection factor are applied 
+
+%add the 4M camera linearity correction
+
+function gtMovingMedian(first,last)
+
+if isdeployed
+  first=str2num(first);
+  last=str2num(last);
+end
+  % Problem: some special processing in the beginning and at the end required - no symmetric
+  % median available
+  parameters=[];
+  load parameters
+  acq=parameters.acq;
+  prep=parameters.prep;
+  
+  
+  indir=sprintf('0_rawdata/%s',acq.name);
+  outdir=sprintf('%s/1_preprocessing/full',acq.dir);
+  
+  
+  %read in the dark image
+  fname=sprintf('0_rawdata/%s/darkend0000.edf',acq.name);
+  %4M camera needs an adjustment to linearity
+  if isfield(acq, 'camera') && strcmp(acq.camera,'4M')
+    %apply this correction to the dark just once
+    dark=(edf_read(fname)/acq.ndark).^0.96;
+  else
+    dark=edf_read(fname)/acq.ndark;
+  end
+  
+  
+  if first-prep.fullrange/2<0  
+    start=0;
+  else
+    start=first-prep.fullrange/2;
+  end
+
+  
+  % read the full stack only for the first image - in the following only one image is replaced in the stack
+ 
+  % in case we start from image 0, we use the median calculated from [0:interval:prep.fullrange] 
+  % and write the same file for the first  0:interval:prep.fullrange/2 images
+  
+  
+  k=0;
+   for i=start:prep.fullint:start+prep.fullrange
+     k=k+1;
+     fname=sprintf('%s/%s%04d.edf',indir,acq.name,i);
+     
+     %4M camera needs an adjustment to linearity
+     if isfield(acq, 'camera') && strcmp(acq.camera,'4M')
+       %dark already corrected
+       im=edf_read(fname).^0.96-dark;
+     else
+       im=edf_read(fname)-dark;
+     end
+     
+     switch prep.normalisation
+       case 'margin'
+         int=mean2(im(acq.bb(2):acq.bb(2)+acq.bb(4)-1,[prep.bb(1):prep.bb(1)+prep.margin-1,prep.bb(1)+prep.bb(3)-prep.margin+1:prep.bb(1)+prep.bb(3)-1]));
+         medstack(k,:,:)=prep.intensity/int.*im;
+       case 'fullbeam'
+         int=mean2(gtCrop(im,prep.bb));
+         medstack(k,:,:)=prep.meanintensity/int.*im;
+       case 'none'
+         int=prep.intensity;
+     end
+  
+        
+   end
+   
+   med=squeeze(median(medstack,1));
+  
+   
+   % if we are in the special case of starting before prep.fullrange/2, we write out
+   % the same median image prep.fullrange/2/interval times
+   if start==0
+     for i=start:prep.fullint:prep.fullrange/2
+       fname=sprintf('%s/med%04d.edf',outdir,i)
+       edf_write(med,fname,'float32');
+       start=prep.fullrange/2 + prep.fullint;  
+     end  
+   else
+       fname=sprintf('%s/med%04d.edf',outdir,first)
+       edf_write(med,fname,'float32');
+       start=first + prep.fullint;
+   end    
+   
+   
+   % check if we are not running out of images
+   
+   if last<=acq.nproj-prep.fullrange/2
+     stop=last;
+   else
+     stop=acq.nproj-prep.fullrange/2;
+   end  
+   
+%% now process images form start:interval:stop
+
+for i=start:prep.fullint:stop
+  k=k+1;
+  if mod(k,prep.fullrange/prep.fullint+1)
+   		k=mod(k,prep.fullrange/prep.fullint+1)
+ 	else
+   		k=prep.fullrange/prep.fullint+1
+  end   
+  
+  fname=sprintf('%s/%s%04d.edf',indir,acq.name,i+prep.fullrange/2);
+   
+  %4M camera needs an adjustment to linearity
+  if isfield(acq, 'camera') && strcmp(acq.camera,'4M')
+    %dark already corrected
+    im=edf_read(fname).^0.96-dark;
+  else
+    im=edf_read(fname)-dark;
+  end
+  
+  switch prep.normalisation
+    case 'margin'
+      int=mean2(im(acq.bb(2):acq.bb(2)+acq.bb(4)-1,[prep.bb(1):prep.bb(1)+prep.margin-1,prep.bb(1)+prep.bb(3)-prep.margin+1:prep.bb(1)+prep.bb(3)-1]));
+      medstack(k,:,:)=prep.intensity/int.*im; 
+    case 'fullbeam'
+      int=mean2(gtCrop(im,prep.bb));
+      medstack(k,:,:)=prep.meanintensity/int.*im; 
+    case 'none'
+      int=prep.intensity;
+  end
+  
+ 
+  med=squeeze(median(medstack,1));
+  fname=sprintf('%s/med%04d.edf',outdir,i)
+  edf_write(med,fname,'float32'); 
+ 
+end
+
+
+% some special processing for the last prep.fullrange/2 images: median is no longer
+% updated since no images > last available
+
+for i=stop+prep.fullint:prep.fullint:last
+  fname=sprintf('%s/med%04d.edf',outdir,i)
+  edf_write(med,fname,'float32');
+end
+
+end
+
+   
+  
+  
+  
\ No newline at end of file
diff --git a/1_preprocessing/gtMovingMedian_live.m b/1_preprocessing/gtMovingMedian_live.m
new file mode 100755
index 0000000000000000000000000000000000000000..cfbdbe86d51aa13354995a62d5eacbeb8fb030eb
--- /dev/null
+++ b/1_preprocessing/gtMovingMedian_live.m
@@ -0,0 +1,169 @@
+% function gtMovingMedian(first,last)
+% calculates the moving median of a series of raw images (first : last) 
+
+% median is calculated from a stack containing prep.fullrange/interval images
+%
+% ATTENTION
+% prep.fullrange must be multiple of prep.INTERVAL and a MULTIPLE OF 2   !!!!!!!!
+% NPROJ should be a multiple of prep.fullrange
+%
+% median is calculated/updated only each interval images
+% the original files are supposed to be in indir/name%04.edf
+% the output is written to directory outdir/med%04d.edf
+% in order to normalize raw images to the same intensity, dark subtraction and a multiplicative corection factor are applied 
+
+%live! will wait for files to appear
+
+function gtMovingMedian_live(first,last, workingdirectory)
+  disp('gtMovingMedian_live.m')
+  
+if isdeployed
+  first=str2num(first);
+  last=str2num(last);
+end
+  % Problem: some special processing in the beginning and at the end required - no symmetric
+  % median available
+  
+  if ~exist('workingdirectory','var')
+    workingdirectory=pwd;
+  end
+  cd(workingdirectory);
+
+  parameters=[];
+  load parameters
+  acq=parameters.acq;
+  prep=parameters.prep;
+  
+  
+  indir=sprintf('0_rawdata/%s',acq.name);
+  outdir=sprintf('%s/1_preprocessing/full',acq.dir);
+  
+  
+  %read in the dark image
+  fname=sprintf('0_rawdata/%s/darkend0000.edf',acq.name);  
+  dark=pfWaitToRead(fname)/acq.ndark;
+
+  
+  if first-prep.fullrange/2<0  
+    start=0;
+  else
+    start=first-prep.fullrange/2;
+  end
+
+  
+  % read the full stack only for the first image - in the following only one image is replaced in the stack
+ 
+  % in case we start from image 0, we use the median calculated from [0:interval:prep.fullrange] 
+  % and write the same file for the first  0:interval:prep.fullrange/2 images
+  
+  
+  k=0;
+  gtDBConnect
+   for i=start:prep.fullint:start+prep.fullrange
+   %  gtDBProgressUpdate(mfilename,acq.name,start,start+prep.fullrange,i*prep.fullint);
+     k=k+1;
+     fname=sprintf('%s/%s%04d.edf',indir,acq.name,i)
+     
+ 
+     im=pfWaitToRead(fname)-dark;
+     center=gtCrop(im,prep.bb);%copy from create full
+     
+     switch prep.normalisation
+       case 'margin'
+         %int=mean2(im(acq.bb(2):acq.bb(2)+acq.bb(4)-1,[prep.bb(1):prep.bb(1)+prep.margin-1,prep.bb(1)+prep.bb(3)-prep.margin+1:prep.bb(1)+prep.bb(3)-1]));
+         int=mean2(center(:,[1:prep.margin,end-prep.margin+1:end])); % copy from create_full
+         medstack(k,:,:)=prep.intensity/int.*im;
+       case 'fullbeam'
+         int=mean2(gtCrop(im,prep.bb));
+         medstack(k,:,:)=prep.intensity/int.*im;
+       case 'none'
+         int=prep.intensity;
+         medstack(k,:,:)=im;
+     end
+  
+        
+   end
+   
+   med=squeeze(median(medstack,1));
+  
+   
+   % if we are in the special case of starting before prep.fullrange/2, we write out
+   % the same median image prep.fullrange/2/interval times
+   if start==0
+     for i=start:prep.fullint:prep.fullrange/2
+       fname=sprintf('%s/med%04d.edf',outdir,i);
+       edf_write(med,fname,'float32');
+       start=prep.fullrange/2 + prep.fullint;  
+     end  
+   else
+       fname=sprintf('%s/med%04d.edf',outdir,first);
+       edf_write(med,fname,'float32');
+       start=first + prep.fullint;
+   end    
+   
+   
+   % check if we are not running out of images
+   if strcmp(parameters.acq.type, '180degree') || strcmp(parameters.acq.type, '180')
+     nimages=parameters.acq.nproj;
+   elseif strcmp(parameters.acq.type, '360degree') || strcmp(parameters.acq.type, '360')
+     nimages=parameters.acq.nproj*2;
+   else
+     error('unrecognised data type')
+   end
+   
+   if last<=nimages-prep.fullrange/2
+     stop=last;
+   else
+     stop=nimages-prep.fullrange/2;
+   end  
+% keyboard
+%% now process images form start:interval:stop
+
+for i=start:prep.fullint:stop
+  k=k+1;
+  if mod(k,prep.fullrange/prep.fullint+1)
+   		k=mod(k,prep.fullrange/prep.fullint+1)
+ 	else
+   		k=prep.fullrange/prep.fullint+1
+  end   
+  
+  fname=sprintf('%s/%s%04d.edf',indir,acq.name,i+prep.fullrange/2);
+   
+
+      im=pfWaitToRead(fname)-dark;
+     center=gtCrop(im,prep.bb);%copy from create full
+     
+     switch prep.normalisation
+       case 'margin'
+         %int=mean2(im(acq.bb(2):acq.bb(2)+acq.bb(4)-1,[prep.bb(1):prep.bb(1)+prep.margin-1,prep.bb(1)+prep.bb(3)-prep.margin+1:prep.bb(1)+prep.bb(3)-1]));
+         int=mean2(center(:,[1:prep.margin,end-prep.margin+1:end])); % copy from create_full
+         medstack(k,:,:)=prep.intensity/int.*im;
+    case 'fullbeam'
+      int=mean2(gtCrop(im,prep.bb));
+      medstack(k,:,:)=prep.intensity/int.*im; 
+    case 'none'
+      medstack(k,:,:)=im;
+  end
+  
+ 
+  med=squeeze(median(medstack,1));
+  fname=sprintf('%s/med%04d.edf',outdir,i)
+  edf_write(med,fname,'float32'); 
+  
+end
+
+
+% some special processing for the last prep.fullrange/2 images: median is no longer
+% updated since no images > last available
+
+for i=stop+prep.fullint:prep.fullint:last
+  fname=sprintf('%s/med%04d.edf',outdir,i)
+  edf_write(med,fname,'float32');
+end
+
+end
+
+   
+  
+  
+  
diff --git a/1_preprocessing/gtOneBigMedian.m b/1_preprocessing/gtOneBigMedian.m
new file mode 100755
index 0000000000000000000000000000000000000000..af1602f68ed91f4c9712c16fc05a4061d0779ecc
--- /dev/null
+++ b/1_preprocessing/gtOneBigMedian.m
@@ -0,0 +1,59 @@
+function gtOneBigMedian
+load parameters
+prep=parameters.prep;
+scanname=parameters.acq.name;
+
+d=edf_read(sprintf('0_rawdata/%s/dark.edf',scanname));
+
+k=1;
+step=25;
+first=6950; last=7200;
+medstack=zeros(length(first:step:last),2048,2048);
+for n=first:step:last
+  k
+  fname=sprintf('0_rawdata/%s/%s%04d.edf',scanname,scanname,n);
+  im=edf_read(fname)-d;
+  
+  if 1 %do normalisation?
+    
+    center=gtCrop(im,prep.bb);%copy from create full
+    switch prep.normalisation
+      case 'margin'
+        int=mean2(center(:,[1:prep.margin,end-prep.margin+1:end])); % copy from create_full
+        medstack(k,:,:)=prep.intensity/int.*im;
+      case 'fullbeam'
+        int=mean2(gtCrop(im,prep.bb));
+        medstack(k,:,:)=prep.intensity/int.*im;
+      case 'none'
+        medstack(k,:,:)=im;
+    end
+  
+  else %  bypass normalisation
+  medstack(k,:,:)=im;
+  end
+  k=k+1;
+end
+
+med=squeeze(median(medstack,1));
+  
+
+
+edf_write(med,'1_preprocessing/full/big_med0000.edf');
+
+q=1;
+step=1;
+first=0;last=50;
+vol=zeros(length(first:step:last),200,168);
+for n=first:step:last
+  n
+  fname=sprintf('1_preprocessing/abs/abs%04d.edf',n);
+  im=edf_read(fname);%-d;
+  vol(q,:,:)=im;
+  q=q+1;
+end
+
+med=squeeze(median(vol,1));
+  
+
+
+edf_write(med,'1_preprocessing/abs/big_med0000.edf');
\ No newline at end of file
diff --git a/1_preprocessing/gtPreprocessing.m b/1_preprocessing/gtPreprocessing.m
new file mode 100755
index 0000000000000000000000000000000000000000..9de83d581e9612f37bac0ca683f37ac43d54f62b
--- /dev/null
+++ b/1_preprocessing/gtPreprocessing.m
@@ -0,0 +1,55 @@
+%gtPreprocessing - "do all" script to handle all preprocessing
+%start in relevent top level directory
+%need to run both halves of scan for 360 case
+
+function gtPreprocessing
+
+finished=0;pair=1;
+
+while finished==0
+
+if exist('parameters.mat', 'file')
+  load parameters;
+else
+disp('first run gtSetup to create parameters file for the experiment!')
+return
+end
+
+%sequence median refs
+cd(sprintf('0_rawdata/%s',parameters.acq.name));
+sequence_median_refs('wait',false, 'offset',[-1 1]); %cover back by trying all offsets
+cd('../..');
+disp('sequence_median_refs finished')
+
+%create_abs
+%make abs images and small meds in abs directory
+create_abs;
+disp('create_abs_finished')
+
+%gtMovingMedian
+gtMovingMedian(0, parameters.acq.nproj)
+%make large meds in full directory, quick enough for a single machine
+disp('gtMovingMedian finished')
+
+%create_full
+disp('sending create_full to condor')
+njobs = ceil(parameters.acq.nproj/200);
+condor_make('create_full', 0, parameters.acq.nproj, njobs, parameters.acq.dir, 1);
+%make full images and ext images
+
+disp('now wait for condor to finish... check the full directory')
+
+if pair==1 & strcmp(parameters.acq.type,'360degree')
+    %repeat for pair data
+    pair=2;
+    cd(sprintf('../%s', parameters.acq.pair_name))
+    clear parameters %clear current parameters
+else
+  finished=1;
+end
+
+end %while finished==0
+
+
+  
+  
\ No newline at end of file
diff --git a/1_preprocessing/gtPreprocessing_live.m b/1_preprocessing/gtPreprocessing_live.m
new file mode 100755
index 0000000000000000000000000000000000000000..ccd459add092c8a6f993aeaf13087ec1df90eecc
--- /dev/null
+++ b/1_preprocessing/gtPreprocessing_live.m
@@ -0,0 +1,87 @@
+%gtPreprocessing - "do all" script to handle all preprocessing
+%parameters file, created by gtSetup, should have all required directorry
+%info.  Run this script in the top level analysis directory (containig the
+%parameters file)
+%live! launch a series of condor jobs which will sit and wait
+%gtCopyCorrectUndistortWrapper launches a number of instances of
+%condor_... according to how many files are present in the directory
+%when the function is started.
+
+function gtPreprocessing_live
+
+
+gtDBConnect
+
+if exist('parameters.mat', 'file')
+  load parameters;
+else
+disp('first run gtSetup to create parameters file for the experiment, or go to the directory containing this file!')
+return
+end
+
+freshcompile=false;  % recompile binaries - not often needed.  But more often than it should be...
+use_cronii=false;  % submit jobs to cronus.  Shhhh...
+% some basic checks
+% dark file exists?
+
+% xml file exists?
+
+% source and target directory exist?
+if freshcompile
+  disp('recompiling all functions')
+  id19_mcc('sequence_median_refs')
+  gt_mcc('create_abs_live');
+  gt_mcc('gtAbsMedian_live');
+  gt_mcc('gtMovingMedian_live');
+  gt_mcc('create_full_live');
+%  gt_mcc('copyKodak');  %replaced by gtCopyCorrectUndistortWrapper
+end
+
+
+
+%copy data from acquistion directory to analysis location
+sourcedir=parameters.acq.collection_dir;
+rawdir=sprintf('%s/0_rawdata/%s', parameters.acq.dir, parameters.acq.name);
+sensortype=parameters.acq.sensortype;
+distmapfile=parameters.acq.distortion;
+if strcmp(parameters.acq.type, '180degree') || strcmp(parameters.acq.type, '180')
+  nimages=parameters.acq.nproj;
+elseif strcmp(parameters.acq.type, '360degree') || strcmp(parameters.acq.type, '360')
+  nimages=parameters.acq.nproj*2;
+else
+  error('unrecognised data type')
+end
+  
+%keyboard %modif sabine 28/06/08
+
+%gtCopyCorrectUndistortWrapper handles condoring of copying
+gtCopyCorrectUndistortWrapper(parameters, sourcedir, rawdir)
+
+%sequence median refs RHST in raw data
+condor_make('gt_sequence_median_refs', 0, 0, 1, [rawdir ' ' nimages ' overwrite'], true,use_cronii) 
+disp('gt_sequence_median_refs launched') %note - gt_sequ... can work from the parameters.mat rather than from the xml
+
+
+%create_abs
+%make abs images and small meds in abs directory
+condor_make('create_abs_live', 0, nimages, 1, parameters.acq.dir, true,use_cronii); 
+disp('create_abs_live launched')
+
+%also need to launch moving_median_function - which does the median on the
+%abs - as a live (waiting) job, in parallel with creating the abs
+condor_make('gtAbsMedian_live', 0, nimages, 1, parameters.acq.dir, true,use_cronii); 
+disp('gtAbsMedian_live launched')
+
+%gtMovingMedian
+condor_make('gtMovingMedian_live', 0, nimages, 1, parameters.acq.dir, true,use_cronii); 
+%make large meds in full directory, quick enough for a single machine
+disp('gtMovingMedian_live launched')
+
+%create_full
+condor_make('create_full_live', 0, nimages, 30, parameters.acq.dir, true,use_cronii); 
+%make full images and ext images
+disp('create_full_live launched')
+
+
+  
+  
diff --git a/1_preprocessing/gtPreprocessing_live_taper.m b/1_preprocessing/gtPreprocessing_live_taper.m
new file mode 100755
index 0000000000000000000000000000000000000000..b71c2c8f3455ce74b03289f352f5e72d12ca957e
--- /dev/null
+++ b/1_preprocessing/gtPreprocessing_live_taper.m
@@ -0,0 +1,77 @@
+%gtPreprocessing - "do all" script to handle all preprocessing
+%parameters file, created by gtSetup, should have all required directorry
+%info.  Run this script in the top level analysis directory (containig the
+%parameters file)
+%live! launch a series of condor jobs which will sit and wait
+%gtCopyCorrectUndistortWrapper launches a number of instances of
+%condor_... according to how many files are present in the directory
+%when the function is started.
+
+%version _taper
+%doesn't deal with abs/ext images, and calls create_full_taper
+
+
+function gtPreprocessing_live_taper
+
+  
+if exist('parameters.mat', 'file')
+  load parameters;
+else
+disp('first run gtSetup to create parameters file for the experiment, or go to the directory containing this file!')
+return
+end
+
+freshcompile=false;  % recompile binaries - not often needed.  But more often than it should be...
+use_cronii=false;  % submit jobs to cronus.  Shhhh...
+% some basic checks
+% dark file exists?
+
+% xml file exists?
+
+% source and target directory exist?
+if freshcompile
+  disp('recompiling all functions')
+  id19_mcc('sequence_median_refs')
+  gt_mcc('create_abs_live');
+  gt_mcc('gtAbsMedian_live');
+  gt_mcc('gtMovingMedian_live');
+  gt_mcc('create_full_live');
+%  gt_mcc('copyKodak');  %replaced by gtCopyCorrectUndistortWrapper
+end
+
+
+
+%copy data from acquistion directory to analysis location
+sourcedir=parameters.acq.collection_dir;
+rawdir=sprintf('%s/0_rawdata/%s', parameters.acq.dir, parameters.acq.name);
+sensortype=parameters.acq.sensortype;
+distmapfile=parameters.acq.distortion;
+if strcmp(parameters.acq.type, '180degree')
+  nimages=parameters.acq.nproj;
+elseif strcmp(parameters.acq.type, '360degree')
+  nimages=parameters.acq.nproj*2;
+else
+  error('unrecognised data type')
+end
+  
+%keyboard
+%gtCopyCorrectUndistortWrapper handles condoring of copying
+gtCopyCorrectUndistortWrapper(parameters, sourcedir, rawdir)
+
+%sequence median refs RHST in raw data
+condor_make('gt_sequence_median_refs', 0, 0, 1, [rawdir ' ' nimages ' overwrite'], true,use_cronii) 
+disp('gt_sequence_median_refs launched') %note - gt_sequ... can work from the parameters.mat rather than from the xml
+
+%gtMovingMedian
+condor_make('gtMovingMedian_live', 0, nimages, 1, parameters.acq.dir, true,use_cronii); 
+%make large meds in full directory, quick enough for a single machine
+disp('gtMovingMedian_live launched')
+
+%create_full
+condor_make('create_full_taper', 0, nimages, 30, parameters.acq.dir, true,use_cronii); 
+%make full images and ext images
+disp('create_full_taper launched')
+
+
+  
+  
diff --git a/1_preprocessing/gtPreprocessing_trial.m b/1_preprocessing/gtPreprocessing_trial.m
new file mode 100755
index 0000000000000000000000000000000000000000..bd5058f2433402b24c9de91a2030d81e478e98fc
--- /dev/null
+++ b/1_preprocessing/gtPreprocessing_trial.m
@@ -0,0 +1,73 @@
+%gtPreprocessing - "do all" script to handle all preprocessing
+%parameters file, created by gtSetup, should have all required directorry
+%info.  Run this script in the top level analysis directory (containig the
+%parameters file)
+%live! launch a series of condor jobs which will sit and wait
+%trial version - runs only a subset of the images, so different parameters
+%can be tested.  Remove other preprocessed files before starting this
+%script.
+
+function gtPreprocessing_trial(first, last)
+
+if exist('parameters.mat', 'file')
+  load parameters;
+else
+disp('first run gtSetup to create parameters file for the experiment, or go to the directory containing this file!')
+return
+end
+
+freshcompile=false;  % recompile binaries - not often needed.  But more often than it should be...
+use_cronii=false;  % submit jobs to cronus.  Shhhh...
+% some basic checks
+% dark file exists?
+
+% xml file exists?
+
+% source and target directory exist?
+if freshcompile
+  disp('recompiling all functions')
+  id19_mcc('sequence_median_refs')
+  gt_mcc('create_abs_live');
+  gt_mcc('gtAbsMedian_live');
+  gt_mcc('gtMovingMedian_live');
+  gt_mcc('create_full_live');
+%  gt_mcc('copyKodak');  %replaced by gtCopyCorrectUndistortWrapper
+end
+
+%run the same functions as gtPreprocessing_live, but only do those images
+%required by the range first - last
+
+%first make sure first and last are multiples of the absint
+first=first-mod(first, parameters.prep.absint);
+last=last+absint-mod(last, parameters.prep.absint);
+%process enough abs imiages to supply the median filter
+abs_first = floor(first - (parameters.prep.absrange/2));
+abs_last = ceil(last + (parameters.prep.absrange/2));
+%make sure full_first and full_last are multiple of the fullint
+full_first=first-mod(first, parameters.prep.fullint);
+full_last=last+fullint-mod(last, parameters.prep.fullint);
+
+%create_abs
+%make abs images and small meds in abs directory
+condor_make('create_abs_live', abs_first, abs_last, 1, parameters.acq.dir, true,use_cronii); 
+disp('create_abs_live launched')
+
+%also need to launch moving_median_function - which does the median on the
+%abs - as a live (waiting) job, in parallel with creating the abs
+condor_make('gtAbsMedian_live', first, last, 1, parameters.acq.dir, true,use_cronii); 
+disp('gtAbsMedian_live launched')
+
+%gtMovingMedian
+condor_make('gtMovingMedian_live', full_first, full_last, 1, parameters.acq.dir, true,use_cronii); 
+%make large meds in full directory, quick enough for a single machine
+disp('gtMovingMedian_live launched')
+
+%create_full
+njobs=ceil((last-first)/500);
+condor_make('create_full_live', first, last, njobs, parameters.acq.dir, true,use_cronii); 
+%make full images and ext images
+disp('create_full_live launched')
+
+
+  
+  
diff --git a/1_preprocessing/gtRenumberInterlaced.m b/1_preprocessing/gtRenumberInterlaced.m
new file mode 100755
index 0000000000000000000000000000000000000000..873db17f40465315291bcf0b58550ebf5552f885
--- /dev/null
+++ b/1_preprocessing/gtRenumberInterlaced.m
@@ -0,0 +1,97 @@
+function gtRenumberInterlaced()
+
+
+parameters=[];
+load parameters;
+
+interlacedscan=parameters.acq.interlaced_turns+1;
+imageperturn=(2*parameters.acq.nproj)/(interlacedscan);
+
+if isfield(parameters.prep,'renumber') && parameters.prep.renumber==1
+    disp('The interlaced renumbering has already been done! ');
+    return
+else
+    parameters.prep.renumber=1;
+    disp('The interlaced renumbering will be processed now! ');
+    save parameters parameters
+end
+
+wd=pwd;
+
+%keyboard
+
+cd 1_preprocessing/full
+
+disp(' copying original full ...');
+% intermediate renumbering
+for i=0:2*parameters.acq.nproj-1
+    orig=sprintf('full%04d.edf',i);
+    dest=sprintf('full_%04d.edf',i);
+    cmd = ['mv ' orig ' '  dest];
+    unix(cmd);
+end
+
+%keyboard
+% final renumbering
+disp(' renamining full ...');
+for i=0:2*parameters.acq.nproj-1
+    orig=sprintf('full_%04d.edf',i);
+    j=interlacedscan*mod(i,imageperturn)+floor(i/imageperturn);
+    dest=sprintf('full%04d.edf',j);
+    cmd = ['mv ' orig ' ' dest];
+    unix(cmd);
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cd(wd)
+if exist('1_preprocessing/ext/ext0000.edf')
+disp('copying original ext ...');
+cd 1_preprocessing/ext
+
+for i=0:2*parameters.acq.nproj-1
+    orig=sprintf('ext%04d.edf',i);
+    dest=sprintf('ext_%04d.edf',i);
+    cmd = ['mv ' orig ' '  dest];
+    unix(cmd);
+end
+%keyboard
+% final renumbering
+disp('renaming ext ...');
+for i=0:2*parameters.acq.nproj-1
+    orig=sprintf('ext_%04d.edf',i);
+    j=interlacedscan*mod(i,imageperturn)+floor(i/imageperturn);
+    dest=sprintf('ext%04d.edf',j);
+    cmd = ['mv ' orig ' ' dest];
+    unix(cmd);
+end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(wd)
+if exist('1_preprocessing/abs/abs0000.edf')
+cd 1_preprocessing/abs
+disp('copying original abs ...');
+for i=0:2*parameters.acq.nproj-1
+    orig=sprintf('abs%04d.edf',i);
+    dest=sprintf('abs_%04d.edf',i);
+    cmd = ['mv ' orig ' '  dest];
+    unix(cmd);
+end
+disp('renaming abs ...');
+
+% final renumbering
+for i=0:2*parameters.acq.nproj-1
+    orig=sprintf('abs_%04d.edf',i);
+    j=interlacedscan*mod(i,imageperturn)+floor(i/imageperturn);
+    dest=sprintf('abs%04d.edf',j);
+    cmd = ['mv ' orig ' ' dest];
+    unix(cmd);
+end
+end
+
+
+
+cd(wd)
+
+
+end %end of function
\ No newline at end of file
diff --git a/1_preprocessing/gtRenumberInterlacedRiso.m b/1_preprocessing/gtRenumberInterlacedRiso.m
new file mode 100755
index 0000000000000000000000000000000000000000..1d9c670c449e77e575d7a10978b0d83941372241
--- /dev/null
+++ b/1_preprocessing/gtRenumberInterlacedRiso.m
@@ -0,0 +1,51 @@
+function gtRenumberInterlacedRiso(nimages, nturns)
+
+%  Function to run live during acquistion of an interlaced scan.
+%  As the files are collected, copy them to a new directory, renaming 
+%  and reordering.  
+%  What is two steps in DCT processing (renaming and then later
+%  renumbering) can be done in a single step in this case.
+%  References do not need to be treated.
+%
+%
+%  so.. for 80 images collected over two turns
+%  nproj=40 in ftomosetup - 
+%  nimages=40 in this macro.
+%  nturns=2 in this macro.
+%  first turn:
+%  name_0_0000.edf, name_0_0001.edf... name_0_0039.edf
+%  second turn:
+%  name_1_0000.edf, name_1_0001.edf... name_1_0039.edf,
+%  should become, in the new directory:
+%  name_0000.edf, name_0002.edf... name_0078.edf
+%  and:
+%  name_0001.edf, name_0003.edf... name_0079.edf
+
+%  get the scan name and input directory name
+inputdir=pwd;
+scanname=inputdir(find(inputdir==filesep,1,'last')+1:end);
+%  ouput directory name - suffix "renamed"
+outputdir=sprintf('%srenamed', inputdir);
+mkdir(outputdir);
+
+for i=1:nturns
+    for j=1:nimages
+
+        %names for the copy operation
+        oldname=sprintf('%s%d_%04d.edf', scanname, i-1, j-1);
+        newname=sprintf('%s%04d.edf', scanname, ((j-1)*nturns)+(i-1));
+
+        done=0;
+        while done==0
+            if exist(sprintf('%s/%s',inputdir, oldname), 'file')
+                cmd=sprintf('cp %s/%s %s/%s', inputdir, oldname, outputdir, newname);
+                system(cmd);
+                done=1;
+                disp(sprintf('done image %d of %d', j+(nimages*(i-1)), nimages*nturns))
+            else
+                disp('file not found, waiting 10 seconds (crtl-C to quit)')
+                pause(10)
+            end
+        end
+    end
+end
diff --git a/1_preprocessing/gtSetup.m b/1_preprocessing/gtSetup.m
new file mode 100755
index 0000000000000000000000000000000000000000..629055e2abf0d781f1e0ac433cab67639be24b87
--- /dev/null
+++ b/1_preprocessing/gtSetup.m
@@ -0,0 +1,322 @@
+function acq=gtSetup
+
+% Sets up acquisition parameters including drifts. 
+
+
+% warning limit of inconsistency of the calibration method in pixels:
+% (difference between total horizontal sample drift during scan and
+% rotation axis drift from calibration to the end of scan) 
+
+%allow user to input working directory, if data is being collected in one
+%place but will be copied to another.
+
+lim_incon=0.05;
+
+
+close all
+
+tmppwd=pwd;
+scanname=tmppwd(find(tmppwd=='/',1,'last')+1:end);
+
+disp('setting up directory structure');
+[s,msg]=mkdir('0_rawdata'); disp(msg)
+[s,msg]=mkdir(['0_rawdata/',scanname]); disp(msg)
+[s,msg]=mkdir('1_preprocessing'); disp(msg)
+[s,msg]=mkdir('1_preprocessing/full'); disp(msg)
+[s,msg]=mkdir('1_preprocessing/abs'); disp(msg)
+[s,msg]=mkdir('1_preprocessing/ext'); disp(msg)
+[s,msg]=mkdir('2_difspot'); disp(msg)
+
+disp('Moving rawdata into subdirectory 0_rawdata');
+unix(sprintf('mv *.edf *.info *.xml 0_rawdata/%s',scanname)); % ???
+
+xmlfname=sprintf('0_rawdata/%s/%s.xml',scanname,scanname);
+if ~exist(xmlfname,'file')
+  error('Cannot proceed - missing xml file')
+end
+disp('reading parameters from xml file');
+tmp=xml_load(xmlfname);
+tmp=tmp.acquisition;
+
+acq.dir=pwd;
+
+
+acq.name=tmp.scanName;
+acq.date=tmp.date;
+acq.pixelsize=str2num(tmp.pixelSize)/1000;
+acq.xdet=str2num(tmp.projectionSize.DIM_2);
+acq.ydet=str2num(tmp.projectionSize.DIM_1);
+acq.nproj=str2num(tmp.tomo_N);
+acq.refon=str2num(tmp.ref_On);
+acq.nref=str2num(tmp.ref_N);
+acq.ndark=str2num(tmp.dark_N);
+
+% Energy and Distance should be determined precisely from Si 111 crystal
+% for the moment we will ask direct input in order to make sure we do not
+% adopt potentially non-sense values from the xml file
+
+disp(' ')
+acq.nproj=inputwdefault('Please, confirm that total number of images per 180 degrees in scan is:',num2str(acq.nproj)) ;
+acq.nproj=str2num(acq.nproj);
+
+%acq.energy=inputwdefaultnumeric('Energy',tmp.energy);
+
+acq.energy=input(sprintf('energy (%s)\t:',tmp.energy));
+if isempty(acq.energy)
+  acq.energy=str2num(tmp.energy);
+end
+
+acq.dist=[];
+if acq.pixelsize==0.0014  %this is currently the only optics where xc and distance are the same...
+  n=length(tmp.listMotors);
+  for i=1:n
+	if strcmp(tmp.listMotors(i).motor.motorName,'xc')
+	  acq.dist=tmp.listMotors(i).motor.motorPosition;
+	  break;
+	end
+  end
+end
+acq.dist=inputwdefault('... distance (in ... units)',acq.dist);
+acq.dist=str2num(acq.dist);
+
+% We need to know spacegroup and laticeparameters...
+disp('Please enter sample parameters:')
+acq.material=inputwdefault('material','Al');
+
+%info should be in header
+%what camera is it?  Can this be read from xml?
+disp('could enter camera type here!')
+%disp('Enter camera type ("4M" / "2K14"):')
+%acq.camera=inputwdefault('camera','2K14');
+
+acq.spacegroup=inputwdefault('spacegroup','225');
+acq.spacegroup=str2num(acq.spacegroup);
+
+acq.latticepar=inputwdefault('latticeparameters','4.05,4.05,4.05,90,90,90');
+acq.latticepar=str2num(acq.latticepar);
+
+%data type, pair dataset etc
+finished=0;
+while finished==0 %chance to try several times!
+    
+  disp('Please enter acquistion type (360degree, 180degree, etc.)')
+  acq.type=inputwdefault('type','360degree');
+  
+  disp('Please enter filename for undistorion correction (filename / none)');
+  acq.distortion=inputwdefault('filename','none');
+  
+  %disp('Correction of sample drift based on ''images at end'' or ') 
+  %disp('''calibration scan 180 degree'' or ''calibration scan 360 degree''');
+  %acq.calibration=inputwdefault('type of calibration','calibration scan 360degree');
+
+  % Calibration scan parameters
+  
+  disp('Type of calibration scan?');
+  acq.calibtype=inputwdefault('''180degree'', ''360degree'' or ''none''','360degree');
+ 
+  if strcmpi(acq.calibtype,'180degree') || strcmpi(acq.calibtype,'360degree')
+    acq.caliboffset=inputwdefault('Image number in scan where corresponding calibration image is #0000 (positive or negative offset)','0');
+    acq.caliboffset=str2num(acq.caliboffset);
+    acq.calibration_path=input('Enter absolute path of calibration scan: ','s');
+    
+    % Create dark.edf file of the calibration (no refHST-s for calib)
+    disp(' ')
+    disp('Creating dark.edf image of calibration scan')
+
+    calibname=acq.calibration_path(find(acq.calibration_path=='/',1,'last')+1:end);
+    xmlfname_calib=sprintf('%s/%s.xml',acq.calibration_path,calibname);
+    if ~exist(xmlfname_calib,'file')
+      error('Cannot proceed - missing xml file of calibration scan.')
+    end
+    xml_calib=xml_load(xmlfname_calib);
+    xml_calib=xml_calib.acquisition;
+    ndark_calib=str2num(xml_calib.dark_N);
+    dark=edf_read(sprintf('%s/darkend0000.edf',acq.calibration_path))/ndark_calib; 
+    edf_write(dark,sprintf('%s/dark.edf',acq.calibration_path),'float32');
+    disp(' ')
+    
+  end
+  
+  disp('In which dimension would you like to compute sample drifts?')
+  disp('( vertical=1, horizontal=2, both=0 ) ')
+  acq.correlationdim=inputwdefault('dimension of correlation:','0');
+  acq.correlationdim=str2num(acq.correlationdim);
+  
+  tmp=inputwdefault('Do you want to set up pair tables? eg for a 360 degree scan (y/n)','y');
+  if strcmpi(tmp, 'y') || strcmpi(tmp, 'yes') 
+    %get the pair/A/B details
+    
+    disp('Enter the name of the dataset that is the pair of this one')
+    acq.pair_name=input('pair_name: ', 's');
+    disp('Enter the name of the database table for the difspot pair information')
+    acq.pair_tablename=input('pair_tablename:', 's');
+    
+    disp(sprintf('Will dataset \"%s\" be difA or difB?', acq.name))
+    tmp=inputwdefault(sprintf('%s is A or B',acq.name),'A');
+    if strcmpi(tmp, 'a')
+      acq.difA_name=acq.name;
+      acq.difB_name=acq.pair_name;
+      finished=1;
+    elseif strcmpi(tmp, 'b')
+      acq.difA_name=acq.pair_name;
+      acq.difB_name=acq.name;
+      finished=1;
+    else
+      disp('Enter either A or B!')
+      disp('Try again...')
+    end
+  else
+    disp('Not collecting pair table information...')
+    finished=1;
+  end % of 360 dataset stuff
+    
+end % of while
+
+% create dark.edf file of scan
+disp(' ')
+disp('Creating dark.edf image of scan.')
+dark=edf_read(sprintf('0_rawdata/%s/darkend0000.edf',acq.name))/acq.ndark;
+edf_write(dark,sprintf('0_rawdata/%s/dark.edf',acq.name),'float32');
+
+% direct beam bb
+bbdir=gtFindDirectBeamBB(acq);
+
+[ydrift_end,zdrift_end,rotaxisloc_abs_end,rotoff_abs_end,rotoff_rel_end]=gtDriftsEndOfScan(acq,bbdir);
+
+if strcmpi(acq.calibtype,'180degree') || strcmpi(acq.calibtype,'360degree')
+  
+  %[ydrift_pol_calib,zdrift_calib,rotaxisloc_abs_calib,rotoff_abs_calib,rotoff_rel_calib,bbs_calib]=gtEvaluateCalibrationScan(acq,bbdir);
+  [ydrift_pol_calib,zdrift_pol_calib,ydrift_int_calib,zdrift_int_calib,rotaxisloc_abs_calib,rotoff_abs_calib,rotoff_rel_calib,bbs_calib]=gtEvaluateCalibrationScan(acq,bbdir);
+  
+  if strcmpi(acq.type,'180degree')
+    totproj=acq.nproj;
+  elseif strcmpi(acq.type,'360degree');
+    totproj=acq.nproj*2;
+  else
+    error('Unknown type of scan. Check acq.type!');
+  end
+  
+  % Inconsistency of calibration: when there is a sample drift during the scan,
+  % the rotation axis location is determined from ... ??? ....
+  % drifted images at the end of scan, 'rotoff_abs_end' and rotoff_  
+  incon=abs((ydrift_end(totproj+1)-ydrift_end(1))+(rotoff_abs_end-rotoff_abs_calib));
+  
+  if incon>lim_incon
+    disp('WARNING! Inconsistency of calibration method is above the preset limit.')
+  end
+  
+  format short g
+  
+  disp(' ')
+  disp('-----------------------------------------------------------')
+  disp(' ')
+  disp('IMAGES AT END  and  CALIBRATION  comparison:')
+  disp('Maximum absolute value of horizontal sample drift: ')
+  disp([max(abs(ydrift_end)) max(abs(ydrift_int_calib))])
+  disp('Mean value of horizontal sample drift: ')
+  disp([mean(ydrift_end) mean(ydrift_int_calib)])
+  disp('Maximum value of vertical sample drift: ')
+  disp([max(zdrift_end) max(zdrift_int_calib)])
+  disp('Mean value of vertical sample drift: ')
+  disp([mean(zdrift_end) mean(zdrift_int_calib)])
+  disp('Rotation axis offset relative to center of direct beam bb:')
+  disp([rotoff_rel_end rotoff_rel_calib])
+  disp('Rotation axis offset relative to center of full images:')
+  disp([rotoff_abs_end rotoff_abs_calib])
+  disp('Rotation axis location in full images:')
+  disp([rotaxisloc_abs_end rotaxisloc_abs_calib])
+  disp('Inconsistency of calibration:')
+  disp(incon)
+  disp(' ')
+  disp('-----------------------------------------------------------')
+  disp(' ')
+  
+  figure('name','Sample drifts according to images at end and calibration')
+   subplot(2,1,1)
+   title('horizontal drift');
+   hold on
+   plot(ydrift_end,'b.')
+   plot(ydrift_pol_calib,'g.') 
+   plot(ydrift_int_calib,'k-')
+   
+   subplot(2,1,2)
+   title('vertical drift');
+   hold on
+   plot(zdrift_end,'b.')
+   plot(zdrift_pol_calib,'g.')
+   plot(zdrift_int_calib,'k-')
+
+   
+  disp('On what would you like to base sample drifts computation?')
+  disp('    1. polynomial fit from calibration scan')
+  disp('    2. interpolated values from calibration scan')
+  disp('    3. interpolated values from images at end of scan')
+  disp('    4. average 1. and 3. ?')
+  acq.driftsbase=inputwdefault(' Drifts based on','1');
+  acq.driftsbase=str2num(acq.driftsbase);
+  
+else
+  disp(' ')
+  disp('Sample drifts are computed on the basis of images at end of scan.')
+  disp(' ')
+  acq.driftsbase=3;
+end
+
+switch acq.driftsbase
+  case 1
+    acq.driftsbase='calib_pol';
+    ydrift=ydrift_pol_calib;
+    zdrift=zdrift_pol_calib;
+  case 2
+    acq.driftsbase='calib_int';
+    ydrift=ydrift_int_calib;
+    zdrift=zdrift_int_calib;
+  case 3
+    acq.driftsbase='images_at_end';
+    ydrift=ydrift_end;
+    zdrift=zdrift_end;
+  case 4
+    acq.driftsbase='average';
+    ydrift=(ydrift_pol_calib+ydrift_end)/2;
+    zdrift=(zdrift_pol_calib+zdrift_end)/2;
+end
+
+acq.bb=bbdir; %%% ???
+acq.rotx=acq.xdet/2+0.5;
+
+
+disp('debugged up to here...')
+keyboard
+
+%%%%% debugged up to here
+
+assignin('base','bbdir',bbdir);
+assignin('base','acq',acq);
+
+% bbdir is not centered in full image so far!
+
+%determine the limits of sample horizontally
+disp('Trying to determine a tight BoundingBox around the sample and a region for intensity normalization');
+[first,last,ims]=gtFindSampleEdges(acq,bbdir);
+
+keyboard
+
+%test0=gtcrop(im0,acq.bb);
+%test1=gtCrop(im1,acq.bb);
+%findshifts2(test0,fliplr(test1));
+
+prep=gtCheckParameters(acq);%error here because no field zdrift
+keyboard
+prep.ydrift=ydrift;
+prep.zdrift=zdrift;
+
+parameters.acq=acq;
+parameters.prep=prep;
+save('parameters_test','parameters');
+
+end
+
+
+
+
+
diff --git a/1_preprocessing/gtSetupCalibration.m b/1_preprocessing/gtSetupCalibration.m
new file mode 100755
index 0000000000000000000000000000000000000000..fdfaafbc08483f9aae71d185c91b3027b10cc0c7
--- /dev/null
+++ b/1_preprocessing/gtSetupCalibration.m
@@ -0,0 +1,171 @@
+function gtSetupCalibration(bbdir)
+
+% Sets up calibration data and drifts. 
+
+
+% warning limit of inconsistency of the calibration method in pixels:
+% (difference between total horizontal sample drift during scan and
+% rotation axis drift from calibration to the end of scan) 
+
+%allow user to input working directory, if data is being collected in one
+%place but will be copied to another.
+
+lim_incon=0.05;
+
+%load(parameterfile)
+load parameters.mat
+
+close all
+
+
+% Calibration scan parameters
+
+disp('Type of calibration scan?');
+parameters.acq.calibtype=inputwdefault('''180degree'', ''360degree'' or ''none''','360degree');
+
+if strcmpi(parameters.acq.calibtype,'180degree') || strcmpi(parameters.acq.calibtype,'360degree')
+  parameters.acq.caliboffset=inputwdefault('Image number in scan where corresponding calibration image is #0000 (positive or negative offset)','0');
+  parameters.acq.caliboffset=str2num(parameters.acq.caliboffset);
+  parameters.acq.calibration_path=input('Enter absolute path of calibration scan: ','s');
+
+  % Create dark.edf file of the calibration (no refHST-s for calib)
+  disp(' ')
+  disp('Creating dark.edf image of calibration scan')
+
+  calibname=parameters.acq.calibration_path(find(parameters.acq.calibration_path=='/',1,'last')+1:end);
+  xmlfname_calib=sprintf('%s/%s.xml',parameters.acq.calibration_path,calibname);
+  if ~exist(xmlfname_calib,'file')
+    error('Cannot proceed - missing xml file of calibration scan.')
+  end
+  xml_calib=xml_load(xmlfname_calib);
+  xml_calib=xml_calib.acquisition;
+  ndark_calib=str2num(xml_calib.dark_N);
+  dark=edf_read(sprintf('%s/darkend0000.edf',parameters.acq.calibration_path))/ndark_calib;
+  edf_write(dark,sprintf('%s/dark.edf',parameters.acq.calibration_path),'float32');
+  disp(' ')
+
+end
+
+disp('In which dimension would you like to compute sample drifts?')
+disp('( vertical=1, horizontal=2, both=0 ) ')
+parameters.acq.correlationdim=inputwdefault('dimension of correlation:','0');
+parameters.acq.correlationdim=str2num(parameters.acq.correlationdim);
+  
+
+
+% direct beam bb
+%bbdir=gtFindDirectBeamBB(parameters.acq);
+%bbdir=parameters.acq.bb;
+
+[ydrift_end,zdrift_end,rotaxisloc_abs_end,rotoff_abs_end,rotoff_rel_end]=gtDriftsEndOfScan(parameters.acq,bbdir);
+
+if strcmpi(parameters.acq.calibtype,'180degree') || strcmpi(parameters.acq.calibtype,'360degree')
+  
+  [ydrift_pol_calib,zdrift_pol_calib,ydrift_int_calib,zdrift_int_calib,rotaxisloc_abs_calib,rotoff_abs_calib,rotoff_rel_calib,bbs_calib]=gtEvaluateCalibrationScan(parameters.acq,bbdir);
+  
+  if strcmpi(parameters.acq.type,'180degree')
+    totproj=parameters.acq.nproj;
+  elseif strcmpi(parameters.acq.type,'360degree');
+    totproj=parameters.acq.nproj*2;
+  else
+    error('Unknown type of scan. Check parameters.acq.type!');
+  end
+  
+  % Inconsistency of calibration: when there is a sample drift during the scan,
+  % the rotation axis location is determined from ... ??? ....
+  % drifted images at the end of scan, 'rotoff_abs_end' and rotoff_  
+  incon=abs((ydrift_end(totproj+1)-ydrift_end(1))+(rotoff_abs_end-rotoff_abs_calib));
+  
+  if incon>lim_incon
+    disp('WARNING! Inconsistency of calibration method is above the preset limit.')
+  end
+  
+  format short g
+  
+  disp(' ')
+  disp('-----------------------------------------------------------')
+  disp(' ')
+  disp('IMAGES AT END  and  CALIBRATION  comparison:')
+  disp('Maximum absolute value of horizontal sample drift: ')
+  disp([max(abs(ydrift_end)) max(abs(ydrift_int_calib))])
+  disp('Mean value of horizontal sample drift: ')
+  disp([mean(ydrift_end) mean(ydrift_int_calib)])
+  disp('Maximum value of vertical sample drift: ')
+  disp([max(zdrift_end) max(zdrift_int_calib)])
+  disp('Mean value of vertical sample drift: ')
+  disp([mean(zdrift_end) mean(zdrift_int_calib)])
+  disp('Rotation axis offset relative to center of direct beam bb:')
+  disp([rotoff_rel_end rotoff_rel_calib])
+  disp('Rotation axis offset relative to center of full images:')
+  disp([rotoff_abs_end rotoff_abs_calib])
+  disp('Rotation axis location in full images:')
+  disp([rotaxisloc_abs_end rotaxisloc_abs_calib])
+  disp('Inconsistency of calibration:')
+  disp(incon)
+  disp(' ')
+  disp('-----------------------------------------------------------')
+  disp(' ')
+  
+  figure('name','Sample drifts according to images at end and calibration')
+   subplot(2,1,1)
+   title('horizontal drift');
+   hold on
+   plot(ydrift_end,'b.')
+   plot(ydrift_pol_calib,'g.') 
+   plot(ydrift_int_calib,'k-')
+   
+   subplot(2,1,2)
+   title('vertical drift');
+   hold on
+   plot(zdrift_end,'b.')
+   plot(zdrift_pol_calib,'g.')
+   plot(zdrift_int_calib,'k-')
+
+   
+  disp('On what would you like to base sample drifts computation?')
+  disp('    1. polynomial fit from calibration scan')
+  disp('    2. interpolated values from calibration scan')
+  disp('    3. interpolated values from images at end of scan')
+  disp('    4. average 1. and 3. ?')
+  parameters.acq.driftsbase=inputwdefault(' Drifts based on','1');
+  parameters.acq.driftsbase=str2num(parameters.acq.driftsbase);
+  
+else
+  disp(' ')
+  disp('Sample drifts are computed on the basis of images at end of scan.')
+  disp(' ')
+  parameters.acq.driftsbase=3;
+end
+
+switch parameters.acq.driftsbase
+  case 1
+    parameters.acq.driftsbase='calib_pol';
+    ydrift=ydrift_pol_calib;
+    zdrift=zdrift_pol_calib;
+  case 2
+    parameters.acq.driftsbase='calib_int';
+    ydrift=ydrift_int_calib;
+    zdrift=zdrift_int_calib;
+  case 3
+    parameters.acq.driftsbase='images_at_end';
+    ydrift=ydrift_end;
+    zdrift=zdrift_end;
+  case 4
+    parameters.acq.driftsbase='average';
+    ydrift=(ydrift_pol_calib+ydrift_end)/2;
+    zdrift=(zdrift_pol_calib+zdrift_end)/2;
+end
+
+parameters.prep.ydrift=ydrift;
+parameters.prep.zdrift=zdrift;
+
+save('parameters.mat','parameters')
+
+disp('Calibration data and drifts saved in parameters file.')
+
+end
+
+
+
+
+
diff --git a/1_preprocessing/gtSetupCalibrationQuali.m b/1_preprocessing/gtSetupCalibrationQuali.m
new file mode 100755
index 0000000000000000000000000000000000000000..c09057c2592b05e56c4d4877af043644d200b3db
--- /dev/null
+++ b/1_preprocessing/gtSetupCalibrationQuali.m
@@ -0,0 +1,207 @@
+function gtSetupCalibrationQuali(bbdir,showcorr)
+
+% Sets up calibration data and drifts with quali images. 
+
+% warning limit of inconsistency of the calibration method in pixels:
+% (difference between total horizontal sample drift during scan and
+% rotation axis drift from calibration to the end of scan) 
+
+%allow user to input working directory, if data is being collected in one
+%place but will be copied to another.
+
+%lim_incon=0.05;
+
+disp(' ')
+disp('CALIBRATION WITH QUALI IMAGES')
+
+
+if ~exist('bbdir','var')
+  bbdir=[];
+end
+
+if ~exist('showcorr','var')
+  showcorr=true;
+end
+
+%load(parameterfile)
+load parameters.mat
+
+close all
+
+% Calibration scan parameters
+disp(' ')
+calibdir_default=parameters.acq.dir(1:find(parameters.acq.dir=='/',1,'last')-1);
+calibdir_default=sprintf('%s/%scalib_/0_rawdata/%scalib_',calibdir_default,...
+  parameters.acq.name,parameters.acq.name);
+
+disp('Type of calibration scan?');
+parameters.calib.type=inputwdefault('''180degree'', ''360degree'' or ''none''','360degree');
+
+if strcmpi(parameters.calib.type,'180degree') || strcmpi(parameters.calib.type,'360degree')
+  parameters.calib.offset=inputwdefault('Image number in scan where corresponding calibration image is #0000 (positive or negative offset)','0');
+  parameters.calib.offset=str2num(parameters.calib.offset);
+  parameters.calib.dir=inputwdefault('Enter absolute path of calibration scan: ',calibdir_default);
+  parameters.calib.images='quali';
+  
+  % Create dark.edf file of the calibration
+  disp(' ')
+  disp('Creating dark.edf image of calibration scan')
+  parameters.calib.name=parameters.calib.dir(find(parameters.calib.dir=='/',1,'last')+1:end);
+  xmlfname_calib=sprintf('%s/%s.xml',parameters.calib.dir,parameters.calib.name);
+  if ~exist(xmlfname_calib,'file')
+    error('Cannot proceed - missing xml file of calibration scan.')
+  end
+  xml_calib=xml_load(xmlfname_calib);
+  xml_calib=xml_calib.acquisition;
+  ndark_calib=str2num(xml_calib.dark_N);
+  parameters.calib.totproj=str2num(xml_calib.tomo_N);
+  parameters.calib.refon=str2num(xml_calib.ref_On);
+  parameters.calib.nref=str2num(xml_calib.ref_N);
+  dark=edf_read(sprintf('%s/darkend0000.edf',parameters.calib.dir))/ndark_calib;
+  edf_write(dark,sprintf('%s/dark.edf',parameters.calib.dir),'float32');
+  disp(' ')
+
+  %refs=dir([parameters.calib.dir '/refHST*']);
+    
+  % Direct beam bb of qualis
+  if isempty(bbdir)
+    bbdir=gtFindDirectBeamBBQuali(parameters.acq,parameters.calib);
+    pause
+  end
+  
+end
+
+disp('In which dimension would you like to compute sample drifts?')
+disp('( vertical=1, horizontal=2, both=0 ) ')
+parameters.calib.correlationdim=inputwdefault('dimension of correlation:','0');
+parameters.calib.correlationdim=str2num(parameters.calib.correlationdim);
+ 
+parameters.calib.bb=bbdir;
+
+%keyboard
+
+% Drfist according to images at end of scan
+%[ydrift_end,zdrift_end,rotaxisloc_abs_end,rotoff_abs_end,rotoff_rel_end]=gtDriftsEndOfScanQuali(parameters.acq,bbdir);
+[ydrift_end]=[];
+[zdrift_end]=[];
+[rotaxisloc_abs_end]=[];
+[rotoff_abs_end]=[];
+[rotoff_rel_end]=[];
+
+if strcmpi(parameters.calib.type,'180degree') || strcmpi(parameters.calib.type,'360degree')
+  
+  % Evaluate calibration
+  [ydrift_pol_calib,zdrift_pol_calib,ydrift_int_calib,zdrift_int_calib,rotaxisloc_abs_calib,...
+    rotoff_abs_calib,rotoff_rel_calib,bbs_calib]=gtEvaluateCalibrationQuali(parameters.acq,parameters.calib,bbdir,showcorr);
+
+  % Inconsistency of calibration: when there is a sample drift during the scan,
+  % the rotation axis location is determined from ... ??? ....
+  % drifted images at the end of scan, 'rotoff_abs_end' and rotoff_  
+
+  if strcmpi(parameters.acq.type,'180degree')
+    totproj=parameters.acq.nproj;
+  elseif strcmpi(parameters.acq.type,'360degree');
+    totproj=parameters.acq.nproj*2;
+  else
+    error('Unknown type of scan. Check parameters.acq.type!');
+  end
+  
+%   incon=abs((ydrift_end(totproj+1)-ydrift_end(1))+(rotoff_abs_end-rotoff_abs_calib));
+%   if incon>lim_incon
+%     disp('WARNING! Inconsistency of calibration method is above the preset limit.')
+%   end
+%   
+%   % Display results
+%   format short g
+%   
+%   disp(' ')
+%   disp('-----------------------------------------------------------')
+%   disp(' ')
+%   disp('IMAGES AT END  and  CALIBRATION  comparison:')
+%   disp('Maximum absolute value of horizontal sample drift: ')
+%   disp([max(abs(ydrift_end)) max(abs(ydrift_int_calib))])
+%   disp('Mean value of horizontal sample drift: ')
+%   disp([mean(ydrift_end) mean(ydrift_int_calib)])
+%   disp('Maximum value of vertical sample drift: ')
+%   disp([max(zdrift_end) max(zdrift_int_calib)])
+%   disp('Mean value of vertical sample drift: ')
+%   disp([mean(zdrift_end) mean(zdrift_int_calib)])
+%   disp('Rotation axis offset relative to center of direct beam bb:')
+%   disp([rotoff_rel_end rotoff_rel_calib])
+%   disp('Rotation axis offset relative to center of full images:')
+%   disp([rotoff_abs_end rotoff_abs_calib])
+%   disp('Rotation axis location in full images:')
+%   disp([rotaxisloc_abs_end rotaxisloc_abs_calib])
+%   disp('Inconsistency of calibration:')
+%   disp(incon)
+%   disp(' ')
+%   disp('-----------------------------------------------------------')
+%   disp(' ')
+%   
+  figure('name','Sample drifts according to images at end and calibration')
+   subplot(2,1,1)
+   title('horizontal drift');
+   hold on
+   %plot(ydrift_end,'b.')
+   plot(ydrift_pol_calib,'g.') 
+   plot(ydrift_int_calib,'k-')
+   
+   subplot(2,1,2)
+   title('vertical drift');
+   hold on
+   %plot(zdrift_end,'b.')
+   plot(zdrift_pol_calib,'g.')
+   plot(zdrift_int_calib,'k-')
+ 
+  disp('On what would you like to base sample drifts computation?')
+  disp('    1. polynomial fit from calibration scan')
+  disp('    2. interpolated values from calibration scan')
+  %disp('    3. interpolated values from images at end of scan')
+  %disp('    4. average 1. and 3. ?')
+  parameters.calib.driftsbase=inputwdefault(' Drifts based on','1');
+  parameters.calib.driftsbase=str2num(parameters.calib.driftsbase);
+  
+else
+  disp(' ')
+  disp('Sample drifts are computed on the basis of images at end of scan.')
+  disp(' ')
+  parameters.calib.driftsbase=3;
+end
+
+% Use one of the methods
+switch parameters.calib.driftsbase
+  case 1
+    parameters.calib.driftsbase='calib_pol';
+    ydrift=ydrift_pol_calib;
+    zdrift=zdrift_pol_calib;
+  case 2
+    parameters.calib.driftsbase='calib_int';
+    ydrift=ydrift_int_calib;
+    zdrift=zdrift_int_calib;
+  case 3
+    parameters.calib.driftsbase='images_at_end';
+    ydrift=ydrift_end;
+    zdrift=zdrift_end;
+  case 4
+    parameters.calib.driftsbase='average';
+    ydrift=(ydrift_pol_calib+ydrift_end)/2;
+    zdrift=(zdrift_pol_calib+zdrift_end)/2;
+end
+
+%parameters.prep.ydrift=ydrift;
+%parameters.prep.zdrift=zdrift;
+parameters.calib.ydrift=ydrift;
+parameters.calib.zdrift=zdrift;
+
+parameters.calib.rotx=rotaxisloc_abs_calib;
+
+save('parameters.mat','parameters')
+
+disp('Calibration data and drifts saved in parameters file.')
+
+end
+
+
+
+
+
diff --git a/1_preprocessing/gtSetup_ak.m b/1_preprocessing/gtSetup_ak.m
new file mode 100755
index 0000000000000000000000000000000000000000..59fb1ef176a374f8b546cde04b35ed6787d69c8d
--- /dev/null
+++ b/1_preprocessing/gtSetup_ak.m
@@ -0,0 +1,343 @@
+function acq=gtSetup_ak
+
+% Sets up acquisition parameters including drifts. 
+%run this script in the acquistion directory
+
+% warning limit of inconsistency of the calibration method in pixels:
+% (difference between total horizontal sample drift during scan and
+% rotation axis drift from calibration to the end of scan) 
+
+%allow user to input working directory, if data is being collected in one
+%place (ie here, pwd) but will be copied to another place for analysis (/graintracking/...).
+
+
+
+close all
+
+% should be in the acquisition directory.  
+tmppwd=pwd;
+% save the collection directory, to be used by gtCopyCorrect
+acq.collection_dir=tmppwd;
+% Use this to get the name of the scan
+scanname=tmppwd(find(tmppwd=='/',1,'last')+1:end);
+% allow user to change name
+scanname=inputwdefault('is this the correct scan name? if not, enter the correct name', scanname);
+
+
+%select analysis directory (use top level of graintracking as default)
+%copying and undistorting of data will then happen in preprocessing
+acq.dir=inputwdefault('enter the directory in which this data will be analysed',...
+  ['/data/id19/graintracking/' scanname]);
+
+
+%set up directory structure in this location
+disp(sprintf('setting up directory structure in %s', acq.dir));
+[s,msg]=mkdir(acq.dir); disp(msg)
+[s,msg]=mkdir([acq.dir '/0_rawdata']); disp(msg)
+[s,msg]=mkdir([acq.dir '/0_rawdata/',scanname]); disp(msg)
+[s,msg]=mkdir([acq.dir '/0_rawdata/Orig']); disp(msg) %for un-undistorted images
+[s,msg]=mkdir([acq.dir '/1_preprocessing']); disp(msg)
+[s,msg]=mkdir([acq.dir '/1_preprocessing/full']); disp(msg)
+[s,msg]=mkdir([acq.dir '/1_preprocessing/abs']); disp(msg)
+[s,msg]=mkdir([acq.dir '/1_preprocessing/ext']); disp(msg)
+[s,msg]=mkdir([acq.dir '/2_difspot']); disp(msg)
+[s,msg]=mkdir([acq.dir '/4_grains']); disp(msg)
+[s,msg]=mkdir([acq.dir '/5_reconstruction']); disp(msg)
+
+
+% try to read the .xml file that may be present
+xmlfname=sprintf('%s.xml',scanname);
+if exist(xmlfname,'file')
+    disp('reading parameters from xml file');
+    
+    tmp=xml_load(xmlfname);
+    tmp=tmp.acquisition;
+
+    acq.name=tmp.scanName;
+    acq.date=tmp.date;
+    acq.pixelsize=str2num(tmp.pixelSize)/1000;
+    acq.xdet=str2num(tmp.projectionSize.DIM_2);
+    acq.ydet=str2num(tmp.projectionSize.DIM_1);
+    acq.nproj=str2num(tmp.tomo_N);
+    acq.refon=str2num(tmp.ref_On);
+    acq.nref=str2num(tmp.ref_N);
+    acq.ndark=str2num(tmp.dark_N);
+
+    %added this check due to revolver situation
+    acq.pixelsize=inputwdefault('Please confirm that the pixel size really is:',acq.pixelsize) ;
+    acq.pixelsize=str2num(acq.pixelsize);
+
+else %if .xml not found
+    disp('No .xml file found!  Are you sure you are correcly in the acquistion direcory?')
+    check=inputwdefault('Do you want to proceed without the xml file? y/n', 'n');
+    if check=='n'
+        disp('quitting...')
+        return
+    end
+    %get information manually
+    acq.name=inputwdefault('scanname?', scanname);
+    acq.date=input('date? ', 's');
+    acq.pixelsize=input('pixelsize/mm? ');
+    acq.xdet=inputwdefault('xdet number of pixels', '2048');
+    acq.ydet=inputwdefault('ydet number of pixels', '2048');
+    acq.xdet=str2num(acq.xdet);
+    acq.ydet=str2num(acq.ydet);
+    acq.nproj=input('number of projections in 180 degrees? ');
+    acq.refon=input('reference interval? ');
+    acq.nref=input('number of references? ');
+    acq.ndark=input('number of dark images? ');
+end
+
+
+% Energy and Distance should be determined precisely from Si 111 crystal
+% for the moment we will ask direct input in order to make sure we do not
+% adopt potentially non-sense values from the xml file
+
+disp(' ')
+acq.nproj=inputwdefault('Please confirm that total number of images per 180 degrees in scan is:',num2str(acq.nproj)) ;
+acq.nproj=str2num(acq.nproj);
+disp('how many interlaced turns? 0 is a singles rotation, 1 is one additional rotation, etc')
+acq.interlaced_turns=input('number of extra turns? ');
+
+
+acq.energy=input(sprintf('energy (%s)\t:',tmp.energy));
+if isempty(acq.energy)
+  acq.energy=str2num(tmp.energy);
+end
+
+acq.dist=[];
+if acq.pixelsize==0.0014  %this is currently the only optics where xc and distance are the same...
+  n=length(tmp.listMotors);
+  for i=1:n
+	if strcmp(tmp.listMotors(i).motor.motorName,'xc')
+	  acq.dist=tmp.listMotors(i).motor.motorPosition;
+	  break;
+	end
+  end
+end
+acq.dist=inputwdefault('sample-centre of rotation distance / mm',acq.dist);
+acq.dist=str2num(acq.dist);
+
+% We need to know spacegroup and laticeparameters...
+disp('Please enter sample parameters:')
+acq.material=inputwdefault('material','Al');
+
+%info should be in header
+%what camera is it?  Can this be read from xml?
+acq.sensortype=inputwdefault('camera type (kodak4mv1 / frelon)', 'frelon');
+
+acq.spacegroup=inputwdefault('spacegroup','225');
+acq.spacegroup=str2num(acq.spacegroup);
+
+acq.latticepar=inputwdefault('latticeparameters','4.05,4.05,4.05,90,90,90');
+acq.latticepar=str2num(acq.latticepar);
+
+%data type, pair dataset etc
+%finished=0;
+
+%simplified here for 360degree single scan idea
+
+disp('Was the monochromator tuned during the scan? After how many reference groups? Or no=0')
+acq.mono_tune=inputwdefault('tune after N reference groups','0');
+acq.mono_tune=str2num(acq.mono_tune)*acq.refon
+
+  disp('Please enter acquistion type (360degree, 180degree, etc.)')
+  acq.type=inputwdefault('type','360degree');
+  
+  disp('Please enter filename for undistortion correction (filename / none)');
+  acq.distortion=inputwdefault('filename','none');
+  
+  tmp=inputwdefault('Do you want to set up spot pair table name? eg for a 360 degree scan (y/n)','y');
+  if strcmpi(tmp, 'y') || strcmpi(tmp, 'yes') 
+    %get the pair/A/B details
+    
+    %disp('Enter the name of the dataset that is the pair of this one')
+    %acq.pair_name=input('pair_name: ', 's');
+    
+    disp('Enter the name of the database table for the difspot pair information')
+    acq.pair_tablename=input('pair_tablename:', 's');
+    
+    %disp(sprintf('Will dataset \"%s\" be difA or difB?', acq.name))
+    %tmp=inputwdefault(sprintf('%s is A or B',acq.name),'A');
+    %if strcmpi(tmp, 'a')
+    %  acq.difA_name=acq.name;
+    %  acq.difB_name=acq.pair_name;
+    % finished=1;
+    %elseif strcmpi(tmp, 'b')
+    %  acq.difA_name=acq.pair_name;
+    %  acq.difB_name=acq.name;
+    %  finished=1;
+    %else
+     % disp('Enter either A or B!')
+     % disp('Try again...')
+    %end
+  else
+    disp('Not collecting pair table information...')
+    finished=1;
+  end % of 360 dataset stuff
+    
+%end % of while
+
+% create dark.edf file of scan
+disp(' ')
+disp('Creating dark.edf image of scan.')
+dark=edf_read('darkend0000.edf')/acq.ndark;
+
+edf_write(dark,'dark.edf','float32');
+disp('also creating dark in the analysis directories')
+sfCopy(dark, 'darkend0000.edf', sprintf('%s/0_rawdata/%s/dark.edf', acq.dir, acq.name), sprintf('%s/0_rawdata/Orig/dark.edf',acq.dir), acq.sensortype, acq.distortion)
+
+
+% direct beam bb - ak change to work in current directory, before copying
+% operation
+
+
+acq.rotx=acq.xdet/2+0.5;
+
+try %images may not yet have been acquired
+    bbdir=gtFindDirectBeamBB(acq)
+    acq.bb=bbdir;
+    %disp('add input for accurate pixel size')
+    assignin('base','bbdir',bbdir);
+    assignin('base','acq',acq);
+
+    %ask about this!
+    disp('bbdir is not centered in full image so far!')
+
+    %determine the limits of sample horizontally
+    close all
+
+    disp('Trying to determine a tight BoundingBox around the sample and a region for intensity normalization');
+    [first,last,ims]=gtFindSampleEdges(acq,bbdir);
+
+    bbs=[first acq.bb(2) last-first+1 acq.bb(4)] % sample bbox
+    acq.bb=bbs;
+    
+    acq.rotx=gtFindRotationAxis(acq,bbdir);
+catch
+    disp('cant find all the images required yet! DIY / bricolage time...')
+    acq.bb=input('manual input of the sample bounding box: [xorig yorig xsize ysize] ')
+end
+%test0=gtcrop(im0,acq.bb);
+%test1=gtCrop(im1,acq.bb);
+%findshifts2(test0,fliplr(test1));
+
+prep=gtCheckParameters(acq);%error here because no field zdrift
+%prep.ydrift=ydrift;
+%prep.zdrift=zdrift;
+% modif sabine
+prep.margin=5;
+prep.absrange=100;
+prep.filtsize=[3 3];
+prep.fullint=50;
+prep.fullrange=500;
+prep.intensity=1800;
+
+seg.th2=3;
+seg.th1=5;
+seg.bb=acq.bb;
+seg.minsize=50;
+seg.minint=100;
+seg.icut=0.1;
+seg.dbfields='difspotID, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, Integral, StartImage,EndImage, MaxImage, ExtStartImage, ExtEndImage, CentroidImage';
+
+match.thr_ang=0.2;
+match.thr_max_offset=2;
+match.thr_ext_offset=10;
+match.thr_genim_offset=1;
+match.corr_rot_to_det=0;
+
+match.thr_intint=3;
+match.thr_area=1.2;
+match.thr_bbsize=1.2;
+
+match.tiltY=0;
+match.tiltZ=0;
+match.centmode=0;
+match.addconstr=[];
+
+parameters.match=match;
+parameters.seg=seg;
+% end modif
+
+
+parameters.acq=acq;
+parameters.acq.difA_name=parameters.acq.name; %should be streamlined!
+parameters.prep=prep;
+
+parameters.sortgrains.buildgs.ang=1.2;
+parameters.sortgrains.buildgs.int=40;
+parameters.sortgrains.buildgs.bbxs=5;
+parameters.sortgrains.buildgs.bbys=1.4;
+parameters.sortgrains.buildgs.geo=10;
+parameters.sortgrains.buildgs.dist=20;
+
+parameters.sortgrains.rodr.inc=0.05;
+parameters.sortgrains.rodr.cons=0.2;
+parameters.sortgrains.rodr.dotspacing=0.001;
+
+
+%save the parameters file into the newly created working directory
+
+
+
+save([parameters.acq.dir '/parameters.mat'],'parameters');
+
+close all
+
+end
+
+
+%simplified sfCopy taken from gtCopyCorrectUndistortCondor to do the undistortion
+%correction for the dark files
+%modified so that can pass in the treated image to be saved in the
+%destination directory
+function sfCopy(im, fnamein, fnameout, fnameout_orig, sensortype, distortion)
+
+
+  switch lower(sensortype)
+
+    case 'kodak4mv1'
+
+      info=edf_info(fnamein);
+      info_orig=info;
+      info.ccdmodel='Kodak4Mv1';
+      info.israw='false';
+      %%% info=rmfield(info,{'dim_1','dim_2'});
+ %put these lines into a CorrectKodak function, which is called both from
+ %here and from inside edf_read
+ %change israw to a clearer name - isCCDcorrected?
+ 
+      midline=1024;
+      im=[im(1:midline,:); ...
+        mean([im(midline,:);im(midline+1,:)]);...
+        im(midline+1:end-1,:)];
+      im=im.^0.96;
+
+    case 'frelon'
+      info=edf_info(fnamein);
+      info_orig=info;
+      
+    otherwise
+      disp(sprintf('Sensor type: %s',sensortype))
+      error('Sensor type is not recognized.')
+  end
+
+  if ~isempty(distortion) && ~strcmp(distortion, 'none')
+      % modif sabine
+      dist_map=distortion_read(distortion);
+      im_corr=distortion_correct(im,dist_map);
+      % fin modif sabine
+    %im_corr=distortion_correct(im,distortion);
+  else
+    im_corr=im;
+  end
+  
+  %write undistorted dark into the analysis directory
+  edf_write(im_corr,fnameout,info)
+  %write uncorrected file to the Orig directory
+  edf_write(im,fnameout_orig,info_orig)
+
+end %end of sfCopy
+
+
diff --git a/1_preprocessing/gt_findshifts2.m b/1_preprocessing/gt_findshifts2.m
new file mode 100755
index 0000000000000000000000000000000000000000..5b9ef03d21e8c5bf769edb379c108f546adc11bb
--- /dev/null
+++ b/1_preprocessing/gt_findshifts2.m
@@ -0,0 +1,267 @@
+function shift_output = gt_findshifts2(varargin)
+% function shift=findshifts(im1,im2)
+% allows to to determine visually the relative shift between two images
+% KEYS:
+% arrows (cursor keys) - one pixel shift
+% shift-arrows - ten pixel shift
+% 1 (2)  - increase (decrease) image contrast
+% 3 (4)  - increase (decrease) image brightness
+%
+% press    t       to toggle between images
+% press    s       to return to to image subtraction mode
+% press    z       to select graphically a region of interest (4 times oversampling)
+% press    r       to return to full image')
+% press  enter     to accept current value')
+% 
+% OTHER STARTUP OPTIONS
+% findshifts2(im1,im1,parameter,value)
+% where parameter and value pairs can be:
+%   'roix',[minimum maximum]  - set the horizontal region of interest
+%   'roiy',[minimum maximum]  - vertical ROI
+%   'clims',[minimum maximum] - preset the colour limits
+%   'precorrelate','yes'      - attempt to correlate the images before
+%                               interaction
+
+% origin: Wolfgang  12/05
+
+  %% startup
+  app=[];
+  app.view.h=figure; % create a new figure
+  app.mode='subtract';
+  app.togglestate=true;
+  app.vshift=0;
+  app.hshift=0;
+  app.voffset=0;
+  app.hoffset=0;
+  app.zoom=1;
+  app.view.h=gcf;
+  app.clims=[-0.1 0.1];
+  app.climt=[0 1];
+  app.clima=[0 2];
+  app.im0=varargin{1};
+  app.im1=varargin{2};
+  app.roix=[1 size(app.im0,2)];
+  app.roiy=[1 size(app.im0,1)];
+  app.precorrelate='off';
+  app.block='off';
+  app.quit=0;
+  if nargin>2
+    if iscell(varargin{3})
+      app=parse_pv_pairs(app,varargin{3});
+    else
+      app=parse_pv_pairs(app,{varargin{3:end}});
+    end
+  end
+  % precrop the image 
+  app.im0=app.im0(app.roiy(1):app.roiy(2),app.roix(1):app.roix(2));
+  app.im1=app.im1(app.roiy(1):app.roiy(2),app.roix(1):app.roix(2));
+  
+  % then pre-correlate if requested
+  if strcmpi(app.precorrelate,'yes') || strcmpi(app.precorrelate,'on')
+    fprintf('Pre-correlating images\n')
+
+    tmp=correlate(app.im0,app.im1);
+    app.voffset = tmp(1);app.hoffset=tmp(2);
+  end
+  
+  set(app.view.h,'KeyPressFcn',@sfKeyPress)
+  %  help(mfilename)
+  iptsetpref('imtoolinitialmagnification','fit')
+  sfUpdateFigure;
+  if strcmp(app.block,'on')
+    % if user wants nothing to return until findshift is finished
+    while 1
+      drawnow
+      if app.quit==1
+        break
+      end
+    end
+  end
+
+function sfKeyPress(varargin)
+  c=varargin{2};
+  switch c.Key
+    case 'uparrow'    
+      if strcmp(c.Modifier,'shift')
+        app.vshift=app.vshift+10/app.zoom;
+      else
+        app.vshift=app.vshift+1/app.zoom;
+      end
+      sfUpdateFigure;
+
+    case 'downarrow'
+      if strcmp(c.Modifier,'shift')
+        app.vshift=app.vshift-10/app.zoom;
+      else
+        app.vshift=app.vshift-1/app.zoom;
+      end
+      sfUpdateFigure;
+    
+    case 'rightarrow'
+      if strcmp(c.Modifier,'shift')
+        app.hshift=app.hshift+10/app.zoom;
+      else
+        app.hshift=app.hshift+1/app.zoom;
+      end
+      sfUpdateFigure;
+
+    case 'leftarrow'
+      if strcmp(c.Modifier,'shift')
+        app.hshift=app.hshift-10/app.zoom;
+      else
+        app.hshift=app.hshift-1/app.zoom;
+      end
+      sfUpdateFigure;
+    
+    case 'return'
+      %exit interactive mode and return current shift
+      set(app.view.h,'KeyPressFcn','');
+      assignin('base','shift',[app.vshift+app.voffset app.hshift+app.hoffset]);
+      fprintf('Shift is: [%.2fv %.2fh]\n',app.vshift+app.voffset,app.hshift+app.hoffset);
+      shift_output=[app.vshift+app.voffset app.hshift+app.hoffset];
+      app.quit=1;
+      return;
+
+    case 'a'
+      disp('changing to adding mode');
+      app.mode='add';
+      sfUpdateFigure;
+
+    case '1'
+      disp('Increasing contrast')
+      switch app.mode
+        case 'subtract'
+          app.clims=app.clims*0.9;
+          disp(sprintf('clim is %f %f',app.clims(1),app.clims(2)));
+        case 'toggle'
+          app.climt=app.climt*0.95;
+          disp(sprintf('clim is %f %f',app.climt(1),app.climt(2)));
+        case 'add'
+          app.clima=app.clima*0.9;
+          disp(sprintf('clim is %f %f',app.clima(1),app.clima(2)));
+      end
+      sfUpdateFigure;
+      
+    case '2'
+      disp('Decreasing contrast')
+      switch app.mode
+        case 'subtract'
+          app.clims=app.clims*1.1;
+          disp(sprintf('clim is %f %f',app.clims(1),app.clims(2)));
+        case 'toggle'
+          app.climt=app.climt*1.05;
+          disp(sprintf('clim is %f %f',app.climt(1),app.climt(2)));
+        case 'add'
+          app.clima=app.clima*1.1;
+          disp(sprintf('clim is %f %f',app.clima(1),app.clima(2)));
+      end
+      sfUpdateFigure;
+    case '3'
+      disp('Colormap brighter')
+      switch app.mode
+        case 'subtract'
+          app.clims=app.clims-max(app.clims)*0.1;
+          disp(sprintf('clim is %f %f',app.clims(1),app.clims(2)));
+        case 'toggle'
+          app.climt=app.climt-mean(app.climt)*0.05;
+          disp(sprintf('clim is %f %f',app.climt(1),app.climt(2)));
+        case 'add'
+          app.clima=app.clima-mean(app.clima)*0.1;
+          disp(sprintf('clim is %f %f',app.clima(1),app.clima(2)));
+      end
+      sfUpdateFigure;
+    case '4'
+      disp('Colormap darker')
+      switch app.mode
+        case 'subtract'
+          app.clims=app.clims+max(app.clims)*0.1;
+          disp(sprintf('clim is %f %f',app.clims(1),app.clims(2)));
+        case 'toggle'
+          app.climt=app.climt+mean(app.climt)*0.05;
+          disp(sprintf('clim is %f %f',app.climt(1),app.climt(2)));
+        case 'add'
+          app.clima=app.clima+mean(app.clima)*0.1;
+          disp(sprintf('clim is %f %f',app.clima(1),app.clima(2)));
+      end
+      sfUpdateFigure;
+    case 's'
+      disp('changing to subtraction mode');
+      app.mode='subtract';
+      app.clim=app.clims;
+      sfUpdateFigure;
+    case 'z'
+      disp('Select region of interest');
+      title('Select region of interest');
+      [toto,r]=imcrop;
+      disp('Zooming...')
+      title('Zooming...')
+      r=round(r);
+      sfZoom(r)
+      sfUpdateFigure;
+    case 'r'
+      disp('reset full image');
+      app.zoom=1;
+      app.im0=app.orig0;
+      app.im1=app.orig1;
+      app.vshift=round(app.vshift+app.voffset);
+      app.hshift=round(app.hshift+app.hoffset);
+      app.voffset=0;
+      app.hoffset=0;
+      sfUpdateFigure;
+    case 't'
+      app.mode='toggle';
+      app.togglestate= not(app.togglestate);
+      app.clim=app.climt;
+      sfUpdateFigure;
+    case 'h'
+      help(mfilename)
+  end
+
+end
+
+
+
+function sfZoom(roi)
+  
+  app.orig0=app.im0;
+  app.orig1=app.im1;
+  app.zoom=10;
+  app.im0=imresize(imcrop(app.im0,roi),app.zoom,'bicubic');
+  app.im1=imresize(imcrop(app.im1,[roi(1)-app.hshift,roi(2)-app.vshift,roi(3),roi(4)]),app.zoom,'bicubic');
+  app.voffset=app.vshift;
+  app.hoffset=app.hshift;
+  app.vshift=0;
+  app.hshift=0;
+end
+
+function sfUpdateFigure
+  colormap gray;
+  im_tmp=roll(app.im1,app.vshift*app.zoom,app.hshift*app.zoom);
+  switch app.mode
+    case 'add'
+      imshow(app.im0+im_tmp,app.clima);
+      title(sprintf('vertical shift: %.2f\t horizontal shift: %.2f',app.vshift+app.voffset,app.hshift+app.hoffset));
+    case 'subtract'
+      %imagesc(app.im0-im_tmp,app.clims);
+     imshow(app.im0-im_tmp,app.clims);
+%      keyboard
+%      axis image
+      title(sprintf('vertical shift: %.2f\t horizontal shift: %.2f',app.vshift+app.voffset,app.hshift+app.hoffset));
+    case 'toggle'
+      if app.togglestate == true
+        imagesc(app.im0,app.climt);
+        axis image
+        title('first image (fixed position)');
+      else
+        imagesc(im_tmp,app.climt);
+        axis image
+        title(sprintf('second image: vertical shift: %.2f\t horizontal shift: %.2f',app.vshift+app.voffset,app.hshift+app.hoffset));
+      end
+  end
+  drawnow
+end
+
+
+
+end
+
diff --git a/1_preprocessing/makeparameterfile_s5_dct8_.m b/1_preprocessing/makeparameterfile_s5_dct8_.m
new file mode 100755
index 0000000000000000000000000000000000000000..e8ddfbabba1b05351e645bfc2a69c765d04c0d0d
--- /dev/null
+++ b/1_preprocessing/makeparameterfile_s5_dct8_.m
@@ -0,0 +1,70 @@
+%% Create Directory structure
+
+
+
+
+
+%% Stage_0  Aquisition and Sample Parameters
+
+
+acq.dir       = '/data/id19/graintracking/graingrowth/s5_dct89_';
+acq.name      = 's5_dct8_';
+acq.type      = '360degree';
+acq.date      = 'sept2006';
+acq.energy    = 22.2;
+acq.dist      = 2.865;               % we think that we have to subtract 0.135 mm from the spec xc value
+acq.pixelsize = 0.0014;
+acq.xdet      = 2048;
+acq.ydet      = 2048;
+acq.rotx      = 1026;
+acq.bb        = [838 829 377 376];  % GTBoundingBox, chose it tight with respect the sample in order to help masking spots !
+acq.nproj     = 6000;               % images over 180 degrees
+acq.refon     = 50;
+acq.nref      = 5;
+acq.ndark     = 20;
+acq.material  = 'Al1050';
+acq.spacegroup= 225;
+acq.latticepar= [4.05,4.05,4.05,90,90,90];
+
+
+
+%% Stage_1  Preprocessing Parameters
+
+prep.bb         = acq.bb+[-10 -2 20 4];  % a boundong box slightly bigger than acq.bb - extra area will be used for normalization
+prep.range      = 100;         % range of images for which the moving median filter is calculated
+prep.int        = 10;          % filenumber interval for the moving median filter of the absorption images
+prep.filtsize   = [5 5];       % size of 2D median filter applied for noise reduction
+prep.intensity  =  5000;       % normalize images to same intensity
+prep.fullint    = 50;          % interval for the moving median filter of the full images 
+prep.fullrange  = 500;         % range over which we calculate the median of the full images
+
+
+%% Stage_2  Segmentation Parameters for DiffractionSpots
+
+seg.boxsize   = 100;                 % during segmentation an initial area of +/- 100 pixels around the COM position will be considered
+seg.bb        = [753 765 531 490];   % mask out this area close to the direct beam - segmentation will go crazy in here
+seg.th1       = 40;                  % spots need to have at least seg.scut pixels above threshold seg.th1 in order to be taken into account
+seg.th2       = 10;                  % low intensity threshold for double threshold segmentation
+seg.icut      = 0.1;                 % difspots may extend over 10th of images - we will sum up extspots only in the intensity percentile range [seg.icut : 1-seg.icut] 
+seg.scut      = 20;                  % minimum size of connected pixels above threshold seg.th1 for a difspot in order to be taken into account
+
+%% Stage_3  Match Extinction Spots
+
+match.dummy    =0;
+
+
+
+
+parameters = struct('acq', acq, 'prep', prep, 'seg', seg, 'match', match); 
+
+fname = sprintf('%s/parameters.mat',acq.dir);
+save(fname, 'parameters');
+disp(sprintf('parameters written to file %s',fname));
+
+
+
+
+
+
+
+
diff --git a/1_preprocessing/makeparameterfile_template.m b/1_preprocessing/makeparameterfile_template.m
new file mode 100755
index 0000000000000000000000000000000000000000..ec364019598ea5fb41e957998b1a966b98f080e1
--- /dev/null
+++ b/1_preprocessing/makeparameterfile_template.m
@@ -0,0 +1,83 @@
+%% Create Directory structure
+
+
+
+
+
+%% Stage_0  Aquisition and Sample Parameters
+
+
+acq.dir       = '/data/id19/graintracking/graingrowth/s5_dct1_';
+acq.name      = 's5_dct1_';
+acq.type      = '180degree';
+acq.date      = '2005';
+acq.energy    = 19.98;   % not known precisely
+acq.dist      = 2.865;               % we think that we have to subtract 0.135 mm from the spec xc value
+acq.pixelsize = 0.0014;
+acq.xdet      = 2048;
+acq.ydet      = 2048;
+acq.rotx      = 1022;
+acq.bb        = [835 800 374 420];  % GTBoundingBox, chose it tight with respect the sample in order to help masking spots !
+acq.nproj     = 6000;               % images over 180 degrees
+acq.refon     = 50;
+acq.nref      = 5;
+acq.ndark     = 20;
+acq.material  = 'Al1050';
+acq.spacegroup= 225;
+acq.latticepar= [4.05,4.05,4.05,90,90,90];
+
+
+
+%% Stage_1  Preprocessing Parameters
+
+prep.margin     = 10;           % horizontal margin around direct beam, used for intensity normalization
+prep.bb         = acq.bb+[-prep.margin 0 2*prep.margin 0];  % a boundong box slightly bigger than acq.bb - extra area will be used for normalization
+prep.absrange   = 100;         % range of abs images for which the moving median filter is calculated
+prep.absint     = 10;          % filenumber interval for the moving median filter of the absorption images
+prep.filtsize   = [3 3];       % size of 2D median filter applied for noise reduction
+prep.intensity  = 5000;       % normalize images to same intensity
+prep.fullint    = 50;          % interval for the moving median filter of the full images 
+prep.fullrange  = 500;         % range over which we calculate the median of the full images
+
+
+%% Stage_2  Segmentation Parameters for DiffractionSpots
+
+
+seg.boxsize   = 50;                 % during segmentation an initial area of +/- 100 pixels around the COM position will be considered
+seg.bb        = [753 765 531 490];   % mask out this area close to the direct beam - segmentation will go crazy in here
+seg.th1       = 40;                  % spots need to have at least seg.minsize pixels above threshold seg.th1 in order to be taken into account
+seg.th2       = 10;                  % low intensity threshold for double threshold segmentation
+seg.icut      = 0.1;                 % difspots may extend over 10th of images - we will sum up extspots only in the intensity percentile range [seg.icut : 1-seg.icut] 
+seg.minsize   = 20;                  % minimum size of connected pixels above threshold seg.th1 for a difspot in order to be taken into account
+seg.range     = 100;                  % stop summation if range>seg.range
+seg.minint    = 100;                 % minimum integrated intensity in a single frame contributing to a spot
+seg.spotstruct = struct('Area',{0},'Centroid',{0},'BoundingBox',{0},'Intensity',{0},'Integral',{0},'StartImage',{0},...
+               'EndImage',{0},'MaxImage',{0},'ExtStartImage',{0},'ExtEndImage',{0},'SummedImage',{0});
+             
+seg.dbfields  = 'Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, Integral, StartImage,EndImage, MaxImage, ExtStartImage, ExtEndImage';            
+
+
+
+
+
+
+%% Stage_3  Match Extinction Spots
+
+match.dummy    =0;
+
+
+
+
+parameters = struct('acq', acq, 'prep', prep, 'seg', seg, 'match', match); 
+
+fname = sprintf('%s/parameters.mat',acq.dir);
+save(fname, 'parameters');
+disp(sprintf('parameters written to file %s',fname));
+
+
+
+
+
+
+
+
diff --git a/1_preprocessing/moving_median.m b/1_preprocessing/moving_median.m
new file mode 100755
index 0000000000000000000000000000000000000000..66727aaa083c9985f4f7dfa2f6aa59431323f13e
--- /dev/null
+++ b/1_preprocessing/moving_median.m
@@ -0,0 +1,78 @@
+% function moving_median(acq,prep,m,scanname)
+
+function moving_median(acq,prep,m,scanname)
+
+
+datadir=sprintf('%s/0_rawdata/%s',acq.dir,scanname);
+
+
+   fname=sprintf('%s/darkend0000.edf',datadir);
+   d=edf_read(fname)/acq.ndark;
+ 
+% some special processing for the first prep.range/2 images, since no
+% symmetric median (-range/2 : int: range/2) available
+     
+   k=0;
+   for i=0:prep.int:prep.range
+     k=k+1;
+     fname=sprintf('%s/1_preprocessing/abs_%s/abs%04d.edf',acq.dir,scanname,i);
+     meddirect(k,:,:)=edf_read(fname);
+      
+     fname=sprintf('%s/%s%04d.edf',datadir,scanname,i);
+     medfull(k,:,:)=  prep.intensity/m(i+1) * (edf_read(fname)-d);       % rescale the intensity to the average one
+     
+   end
+   
+   medd=squeeze(median(meddirect,1));
+   medf=squeeze(median(medfull,1));
+  
+   for i=0:prep.int:prep.range/2
+     fname=sprintf('%s/1_preprocessing/abs_%s/med%04d.edf',acq.dir,scanname,i);
+     edf_write(medd,fname,'float32');
+     
+     fname=sprintf('%s/1_preprocessing/full_%s/med%04d.edf',acq.dir,scanname,i)
+     edf_write(medf,fname,'float32');
+   end
+   
+%% now process until acq.nproj-prep.range/2
+
+for i=prep.range/2+prep.int:prep.int:acq.nproj-prep.range/2
+  k=k+1;
+  if mod(k,prep.range/prep.int+1)
+   		k=mod(k,prep.range/prep.int+1)
+ 	else
+   		k=prep.range/prep.int+1
+  end   
+  
+  fname=sprintf('%s/1_preprocessing/abs_%s/abs%04d.edf',acq.dir,scanname,i+prep.range/2);
+  meddirect(k,:,:)=edf_read(fname);
+  disp(sprintf('%s read into stack(%d,:,:)',fname,k));
+      
+  fname=sprintf('%s/%s%04d.edf',datadir,scanname,i+prep.range/2);
+  medfull(k,:,:)=  prep.intensity/m(i+prep.range/2+1) * (edf_read(fname)-d);       % rescale the intensity to the average one
+     
+  medd=squeeze(median(meddirect,1));
+  medf=squeeze(median(medfull,1));
+  
+  fname=sprintf('%s/1_preprocessing/abs_%s/med%04d.edf',acq.dir,scanname,i);
+  edf_write(medd,fname,'float32');
+     
+  fname=sprintf('%s/1_preprocessing/full_%s/med%04d.edf',acq.dir,scanname,i);
+  edf_write(medf,fname,'float32');
+end
+
+
+for i=acq.nproj-prep.range/2+prep.int:prep.int:acq.nproj
+  fname=sprintf('%s/1_preprocessing/abs_%s/med%04d.edf',acq.dir,scanname,i);
+  edf_write(medd,fname,'float32');
+     
+  fname=sprintf('%s/1_preprocessing/full_%s/med%04d.edf',acq.dir,scanname,i)
+  edf_write(medf,fname,'float32');
+end
+
+end
+
+   
+  
+  
+  
\ No newline at end of file
diff --git a/1_preprocessing/moving_median_function.m b/1_preprocessing/moving_median_function.m
new file mode 100755
index 0000000000000000000000000000000000000000..e3c8e657f6d6a5a979d3fefa61248d6b13598294
--- /dev/null
+++ b/1_preprocessing/moving_median_function.m
@@ -0,0 +1,102 @@
+% function moving_median(first,last,nproj,interval,range,indir,outdir,name,dark,correction)
+% calculates the moving median of a series of images (first : last) 
+% the directory indir contains nproj imagesnamed name%04d.edf
+% median is calculated from a stack containing range/interval images
+%
+% ATTENTION
+% RANGE must be multiple of INTERVAL and a MULTIPLE OF 2   !!!!!!!!
+% NPROJ should be a multiple of RANGE
+%
+% median is calculated/updated only each interval images
+% the original files are supposed to be in indir/name%04.edf
+% the output is written to directory outdir/med%04d.edf
+% in order to normalize raw images to the same intensity, dark subtraction and a multiplicative corection factor are applied 
+% in case the images are already flatfielded, provide a (dummy)  zero darkimage and
+% a vector of ones(last-first+1,1) for correction
+
+function moving_median_function(first,last,nproj,interval,range,indir,outdir,name,dark,correction)
+
+  % Problem: some special processing in the beginning and at the end required - no symmetric
+  % median available
+  
+  if first-range/2<0  
+    start=0;
+  else
+    start=first-range/2;
+  end
+
+  
+  % read the full stack only for the first image - in the following only one image is replaced in the stack
+ 
+  % in case we start from image 0, we use the median calculated from [0:interval:range] 
+  % and write the same file for the first  0:interval:range/2 images
+  
+  
+  k=0;
+   for i=start:interval:start+range
+     k=k+1;
+     fname=sprintf('%s/%s%04d.edf',indir,name,i);
+     medstack(k,:,:)=correction(i+1)*(edf_read(fname)-dark);    
+   end
+   
+   med=squeeze(median(medstack,1));
+  
+   
+   % if we are in the special case of starting before range/2, we write out
+   % the same median image range/2/interval times
+   if start==0
+     for i=start:interval:range/2
+       fname=sprintf('%s/med%04d.edf',outdir,i)
+       edf_write(med,fname,'float32');
+       start=range/2 + interval;  
+     end  
+   else
+       fname=sprintf('%s/med%04d.edf',outdir,first)
+       edf_write(med,fname,'float32');
+       start=first + interval;
+   end    
+   
+   
+   % check if we are not running out of images
+   
+   if last<=nproj-range/2
+     stop=last;
+   else
+     stop=nproj-range/2;
+   end  
+   
+%% now process images form start:interval:stop
+
+for i=start:interval:stop
+  k=k+1;
+  if mod(k,range/interval+1)
+   		k=mod(k,range/interval+1)
+ 	else
+   		k=range/interval+1
+  end   
+  
+  fname=sprintf('%s/%s%04d.edf',indir,name,i+range/2);
+  medstack(k,:,:)=correction(i+range/2+1)*(edf_read(fname)-dark);  
+  
+ 
+  med=squeeze(median(medstack,1));
+  fname=sprintf('%s/med%04d.edf',outdir,i)
+  edf_write(med,fname,'float32'); 
+ 
+end
+
+
+% some special processing for the last range/2 images: median is no longer
+% updated since no images > last available
+
+for i=stop+interval:interval:last
+  fname=sprintf('%s/med%04d.edf',outdir,i)
+  edf_write(med,fname,'float32');
+end
+
+end
+
+   
+  
+  
+  
\ No newline at end of file
diff --git a/1_preprocessing/moving_median_parallel.m b/1_preprocessing/moving_median_parallel.m
new file mode 100755
index 0000000000000000000000000000000000000000..66727aaa083c9985f4f7dfa2f6aa59431323f13e
--- /dev/null
+++ b/1_preprocessing/moving_median_parallel.m
@@ -0,0 +1,78 @@
+% function moving_median(acq,prep,m,scanname)
+
+function moving_median(acq,prep,m,scanname)
+
+
+datadir=sprintf('%s/0_rawdata/%s',acq.dir,scanname);
+
+
+   fname=sprintf('%s/darkend0000.edf',datadir);
+   d=edf_read(fname)/acq.ndark;
+ 
+% some special processing for the first prep.range/2 images, since no
+% symmetric median (-range/2 : int: range/2) available
+     
+   k=0;
+   for i=0:prep.int:prep.range
+     k=k+1;
+     fname=sprintf('%s/1_preprocessing/abs_%s/abs%04d.edf',acq.dir,scanname,i);
+     meddirect(k,:,:)=edf_read(fname);
+      
+     fname=sprintf('%s/%s%04d.edf',datadir,scanname,i);
+     medfull(k,:,:)=  prep.intensity/m(i+1) * (edf_read(fname)-d);       % rescale the intensity to the average one
+     
+   end
+   
+   medd=squeeze(median(meddirect,1));
+   medf=squeeze(median(medfull,1));
+  
+   for i=0:prep.int:prep.range/2
+     fname=sprintf('%s/1_preprocessing/abs_%s/med%04d.edf',acq.dir,scanname,i);
+     edf_write(medd,fname,'float32');
+     
+     fname=sprintf('%s/1_preprocessing/full_%s/med%04d.edf',acq.dir,scanname,i)
+     edf_write(medf,fname,'float32');
+   end
+   
+%% now process until acq.nproj-prep.range/2
+
+for i=prep.range/2+prep.int:prep.int:acq.nproj-prep.range/2
+  k=k+1;
+  if mod(k,prep.range/prep.int+1)
+   		k=mod(k,prep.range/prep.int+1)
+ 	else
+   		k=prep.range/prep.int+1
+  end   
+  
+  fname=sprintf('%s/1_preprocessing/abs_%s/abs%04d.edf',acq.dir,scanname,i+prep.range/2);
+  meddirect(k,:,:)=edf_read(fname);
+  disp(sprintf('%s read into stack(%d,:,:)',fname,k));
+      
+  fname=sprintf('%s/%s%04d.edf',datadir,scanname,i+prep.range/2);
+  medfull(k,:,:)=  prep.intensity/m(i+prep.range/2+1) * (edf_read(fname)-d);       % rescale the intensity to the average one
+     
+  medd=squeeze(median(meddirect,1));
+  medf=squeeze(median(medfull,1));
+  
+  fname=sprintf('%s/1_preprocessing/abs_%s/med%04d.edf',acq.dir,scanname,i);
+  edf_write(medd,fname,'float32');
+     
+  fname=sprintf('%s/1_preprocessing/full_%s/med%04d.edf',acq.dir,scanname,i);
+  edf_write(medf,fname,'float32');
+end
+
+
+for i=acq.nproj-prep.range/2+prep.int:prep.int:acq.nproj
+  fname=sprintf('%s/1_preprocessing/abs_%s/med%04d.edf',acq.dir,scanname,i);
+  edf_write(medd,fname,'float32');
+     
+  fname=sprintf('%s/1_preprocessing/full_%s/med%04d.edf',acq.dir,scanname,i)
+  edf_write(medf,fname,'float32');
+end
+
+end
+
+   
+  
+  
+  
\ No newline at end of file
diff --git a/1_preprocessing/prepare_data.m b/1_preprocessing/prepare_data.m
new file mode 100755
index 0000000000000000000000000000000000000000..cd31f693119e1b8592008cdd4a0dd63fe1a40415
--- /dev/null
+++ b/1_preprocessing/prepare_data.m
@@ -0,0 +1,207 @@
+function prepare_data(scanname,first,last)
+
+tmp = load('parameters.mat');
+acq=tmp.acq;
+prep=tmp.prep;
+
+
+
+datadir=sprintf('%s/0_rawdata/%s',acq.dir,scanname);
+
+create_full_and_abs=1;
+create_abs_projections=0;
+create_calc_projections=0;
+
+function a=getbb(im,gtbb);
+   a=im(gtbb(2):gtbb(2)+gtbb(4)-1,gtbb(1):gtbb(1)+gtbb(3)-1);
+end   
+
+function b=putbb(im,gtbb,roi)
+    b=im;
+    b(gtbb(2):gtbb(2)+gtbb(4)-1,gtbb(1):gtbb(1)+gtbb(3)-1)=roi;
+end  
+
+if create_full_and_abs
+
+[s,msg]=mkdir('1_preprocessing');  
+[s,msg]=mkdir('1_preprocessing/full');	
+[s,msg]=mkdir('1_preprocessing/abs'); 
+[s,msg]=mkdir('1_preprocessing/ext');
+
+d=roi_read(sprintf('%s/darkend0000.edf',datadir),acq.bb)/acq.ndark;
+D=edf_read(sprintf('%s/darkend0000.edf',datadir))/acq.ndark;
+
+refname2old=[];
+refname1old=[];
+
+
+
+
+%%% create the median stack (typically each prep.int (10) image
+%%% over a range of +/- prep.range/2 images) symetrically to the first image 
+%%% if we start with 0 , we fill half the stack with the first (0000) image
+
+
+k=0;
+for i=first-prep.range/2:prep.int:first+prep.range/2
+	k=k+1;
+	
+  refname1=sprintf('%s/refHST%04d.edf',datadir,max(0,floor(i/acq.refon)*acq.refon));
+  refname2=sprintf('%s/refHST%04d.edf',datadir,max(0,ceil(i/acq.refon)*acq.refon));
+  if (~strcmp(refname1,refname1old) | ~strcmp(refname2,refname2old))
+    ref1=roi_read(refname1,acq.bb)-d;
+    ref2=roi_read(refname2,acq.bb)-d;
+    refname1old=refname1;
+    refname2old=refname2;
+    disp([refname1,refname2]);
+  end
+  w=mod(i,acq.refon)/acq.refon;
+  ref=(1-w).*ref1+w.*ref2;
+  
+  name=sprintf('%s/%s%04d.edf',datadir,scanname,max(0,i));
+  p(:,:,k)=(roi_read(name,acq.bb)-d)./ref;   % direct beam projection image
+  m(:,:,k)=edf_read(name)-D;          % full size images
+	
+end
+
+if first==0
+  start=prep.range/prep.int/2+1;
+else start=1;
+end
+
+  med=median(m(:,:,start:end),3);
+  pmed=median(p(:,:,start:end),3);
+
+%%% now create the background corrected image ('full/fullxxxx.edf') and the absorption
+%%% image ('abs/absxxxx.edf' - only each 10th image for   ) and a first variant of the extinction image
+%%% ('ext/medxxxx.edf');
+%%% basic idea behond all these images:  background estimated by the (moving) median of neighboring images)
+%%% 
+%%% median will be updated each sint (typically each 10th) image - and
+%%% calculated over a range of srange (typically 100 images)
+%%% in order to avoid reading the whole median stack we update only one image (index k) in the stack m(:,:,k)  
+
+k=prep.range/prep.int;  % will be used as (cycling over) index into the median stack
+
+for i=first:prep.int:last-prep.int
+	
+  %calculate reference for new image (i+prep.range/2) in the median stack
+  refname1=sprintf('%s/refHST%04d.edf',datadir,min(acq.nproj,floor((i+prep.range/2)/acq.refon)*acq.refon));
+  refname2=sprintf('%s/refHST%04d.edf',datadir,min(acq.nproj,ceil((i+prep.range/2)/acq.refon)*acq.refon));
+  if (~strcmp(refname1,refname1old) | ~strcmp(refname2,refname2old))
+    ref1=roi_read(refname1,acq.bb)-d;
+    ref2=roi_read(refname2,acq.bb)-d;
+    refname1old=refname1;
+    refname2old=refname2;
+    disp([refname1,refname2]);
+  end
+  w=mod(i,acq.refon)/acq.refon;
+  ref=(1-w).*ref1+w.*ref2;
+  
+  % replace the oldest image in the floating median stack by the new one
+  k=k+1;
+ 	if mod(k,prep.range/prep.int+1)  
+   		k=mod(k,prep.range/prep.int+1)
+ 	else
+   		k=prep.range/prep.int+1
+  end   
+  name=sprintf('%s/%s%04d.edf',datadir,scanname,min(acq.nproj,i+prep.range/2))
+	m(:,:,k)=edf_read(name)-D;
+  p(:,:,k)=(roi_read(name,acq.bb)-d)./ref;
+  med=median(m,3);
+  pmed=median(p,3);
+  pmed=medfilt2(pmed,prep.filtsize);
+  
+  % now process the next sint images
+	for j=0:prep.int-1
+    sim=0
+    %calculate current reference
+    refname1=sprintf('%s/refHST%04d.edf',datadir,floor((i+j)/acq.refon)*acq.refon);
+    refname2=sprintf('%s/refHST%04d.edf',datadir,ceil((i+j)/acq.refon)*acq.refon);
+    if (~strcmp(refname1,refname1old) | ~strcmp(refname2,refname2old))
+      ref1=roi_read(refname1,acq.bb)-d;
+      ref2=roi_read(refname2,acq.bb)-d;
+      refname1old=refname1;
+      refname2old=refname2;
+      disp([refname1,refname2]);
+    end
+    w=mod(i+j,acq.refon)/acq.refon;
+    ref=(1-w).*ref1+w.*ref2;
+ 
+    name=sprintf('%s/%s%04d.edf',datadir,scanname,i+j)
+		im=edf_read(name)-D;
+    proj=getbb(im,acq.bb)./ref;
+    sim=sim+proj;
+    full=im-med;
+    direct=(proj-pmed)*mean2(ref);
+    full=putbb(full,acq.bb,direct);
+    name=sprintf('1_preprocessing/full/full%04d.edf',i+j);
+		edf_write(full,name,'float32');
+    name=sprintf('ext/med%04d.edf',i+j);
+    ext=-log(proj)+log(pmed);
+    
+    edf_write(ext,name,'float32');
+    if j==(prep.int-1)
+      sim=sim/prep.int;
+      name=sprintf('1_preprocessing/abs/abs%04d.edf',i/prep.int);
+      diffr=find(sim<pmed);
+      sim(diffr)=pmed(diffr);
+      edf_write(-log(sim),name,'float32');
+    end  
+  end % for k
+end %for i
+
+
+
+end %if create_full_and_abs 
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% CREATE_CALCULATED_PROJECTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+if create_calc_projections
+
+int=10;
+xsize=acq.bb(4)+1;
+ysize=acq.bb(4)+1;
+zbeg=1;  
+zend=acq.bb(3)+1;	
+volname=sprintf('abs/med.vol',n1);
+calc=calculate_projection(volname,xsize,ysize,zbeg,zend,0);
+cc=round(size(calc,1)/2);
+sa=floor((acq.bb(4)+1)/2);
+r2=[0 384 50 84];
+for i=0:int:acq.nproj
+        angle=i/acq.nproj*180;
+        calc=calculate_projection(volname,xsize,ysize,zbeg,zend,angle);
+	calc=calc(cc-sa:cc+sa,:);
+	name=sprintf('abs/med%04d.edf',i/int);
+	med=edf_read(name);
+	mmed=mean(med,2);
+	mcalc=mean(calc,2);
+        p=polyfit(mcalc,mmed,1);
+        calc=polyval(p,calc);
+	cor(i/int+1)=myfindshift(gtcrop(med,r2),gtcrop(calc,r2),[-2:0.1:2]);
+	cor(i/int+1)
+	calcc=interpolatef(calc,cor(i/int+1),0);
+	name=sprintf('calc/calc%04d.edf',i/int)
+	edf_write(name,calcc,'float32');
+	imshow(med-calcc,[-0.1 0.1]);
+	drawnow;
+        for j=0:int-1
+            name=sprintf('abs/abs%04d.edf',i+j);
+	    im=edf_read(name);
+	    ext=im-calcc;
+	    name=sprintf('ext/ext%04d.edf',i+j)
+            edf_write(name,ext,'float32');
+	end
+end
+
+end % create_calc_projections
+
+end
+
diff --git a/1_preprocessing/sequence_median_refs2.m b/1_preprocessing/sequence_median_refs2.m
new file mode 100755
index 0000000000000000000000000000000000000000..63f81236bff61ccf98f9c6ac3353e7ab32a9ec27
--- /dev/null
+++ b/1_preprocessing/sequence_median_refs2.m
@@ -0,0 +1,60 @@
+function sequence_median_refs2(varargin)
+% MEDIAN_REFS
+% Simple function to generate median image for each set of reference images
+% in a scan.  Works on reference files found in current directory, and only
+% overwrites if explicitly told to.
+
+%if arg = 'no_waiting'
+%will do all possible refs, but won't wait if any are missing
+skip=0;
+if (~isempty(varargin) & varargin{1}=='no_waiting')
+  skip=1;
+end
+%will look for "99" refs as well
+  
+
+% find scan name (same as directory name)
+%[tmp,dname,tmp,tmp]=fileparts(pwd);
+tmp=pwd;
+dname=tmp(find(tmp==filesep,1,'last')+1:end);
+
+fname_xml=[dname '.xml']; 
+if ~exist(fname_xml,'file')
+  disp(sprintf('Directory with images must also contain the xml file (%s)!!',fname_xml))
+  return
+end
+
+acq=query_xml(fname_xml,'acquisition');
+for n=0:acq.RefSpacing:acq.nRadio
+  for offset = -1:-1
+  fname_refC=sprintf('refHST%04d.edf',n+offset);
+  if exist(fname_refC,'file')
+    fprintf('%s already exists - skipping\n',fname_refC);
+    continue
+  end
+      fname_test=sprintf('ref%04d_%04d.edf',0,n+offset);
+  if (~exist(fname_test,'file') & skip==1)
+    continue
+  end
+  fprintf('Reading references at %d\n',n+offset);
+  ref=zeros(acq.nRefs,acq.size2,acq.size1);
+
+ 
+  for m=0:acq.nRefs-1
+    fprintf('Reading image %d of %d\r',m+1,acq.nRefs)
+    fname_ref=sprintf('ref%04d_%04d.edf',m,n+offset);
+    if ~exist(fname_ref,'file') 
+      fprintf('Waiting for %s...',fname_ref)
+      while ~exist(fname_ref,'file')
+        pause(2)
+      end
+      fprintf('Found it!\n')
+    end
+    ref(m+1,:,:)=edf_read(fname_ref); 
+  end
+  fprintf('Now performing median...\n')
+  refC=squeeze(median(ref));
+  edf_write(refC,fname_refC,'uint16');
+  
+  end
+end
diff --git a/1_preprocessing/work.m b/1_preprocessing/work.m
new file mode 100755
index 0000000000000000000000000000000000000000..357b7decf3e224ca7b65a12fa8fbe11e36b75965
--- /dev/null
+++ b/1_preprocessing/work.m
@@ -0,0 +1,12 @@
+rawdir='/data/id19/inhouse/graintracking/s5_dct8_';
+D=edf_read(sprintf('%s/darkend0000.edf',rawdir))/20;
+j=0;
+test=-zeros(11,2048,2048);
+for i=0:50:500
+  j=j+1;
+  name=sprintf('%s/s5_dct8_%04d.edf',rawdir,i);
+  test(j,:,:)=5000/m(i+1)*(edf_read(name)-D);
+end 
+  toto=squeeze(median(test,1));
+  
+  
diff --git a/2_segment_difspot/SegmentDiffractionSpotsnew.m b/2_segment_difspot/SegmentDiffractionSpotsnew.m
new file mode 100755
index 0000000000000000000000000000000000000000..1996eae1ae301cefe1f6a284bec66cebbb3977a3
--- /dev/null
+++ b/2_segment_difspot/SegmentDiffractionSpotsnew.m
@@ -0,0 +1,254 @@
+function SegmentDiffractionSpotsnew(first,last,scanname)
+
+parameters=[];
+load parameters
+
+
+
+acq=parameters.acq;
+prep=parameters.prep;
+seg=parameters.seg;
+seg.zeroim=zeros([acq.ydet acq.xdet]+2*seg.boxsize);   %
+
+
+seg.spot=struct('Area',{0},'Centroid',{0},'BoundingBox',{0},'Intensity',{0},'Integral',{0},'BB',{0},'StartImage',{0},...
+    'EndImage',{0},'MaxImage',{0},'PixelIdxList',{0},'ExtStartImage',{0},'ExtEndImage',{0},'SummedImage',{0},'Image',{0}); 
+difspot=struct('Area',{0},'Centroid',{0},'BoundingBox',{0},'Integral',{0},'StartImage',{0},...
+    'EndImage',{0},'MaxImage',{0},'ExtStartImage',{0},'ExtEndImage',{0}); 
+seg.toto=difspot;
+seg.difspotfields=fieldnames(difspot);
+
+
+
+cd(acq.dir);
+
+%load 2_difspot/difspot
+%seg.currentspot=length(difspot)+1;
+seg.currentspot=1;
+
+
+for k=first:last
+
+  seg.imnum=k;
+    fname=sprintf('1_preprocessing/full_%s/full%04d.edf',scanname,seg.imnum)
+    tmp=edf_read(fname);
+    seg.fullim=gtPlaceSubImage(tmp,seg.zeroim,seg.boxsize+1,seg.boxsize+1);
+
+	  % remove previously found spots from current image
+    seg.fullim=sfMaskSegmentedSpots(seg,difspot);
+    % segment new difspot in currentimage
+    [seg,difspot]=sfSegmentNewspots(seg,difspot);
+    % save results 
+    fname=sprintf('2_difspot/difspot');
+    save(fname,'difspot');
+end
+
+%% sfMaskSegmentedSpots
+function masked_image=sfMaskSegmentedSpots(seg,difspot)
+
+   bb=[seg.bb(1:2)+seg.boxsize,seg.bb(3:4)];
+   masked_image=gtPlaceSubImage(-10*ones(bb(4),bb(3)),seg.fullim,bb(1),bb(2));
+   
+   imshow(masked_image,[]);
+   index1=find([difspot.StartImage]<seg.imnum);
+   index2=find([difspot(index1).EndImage]>=seg.imnum);
+   index=index1(index2);
+   
+   for i=index
+	   fname=sprintf('2_difspot/difspot%05d.edf',i);
+     tmp=-edf_read(fname);
+     bb=[difspot(i).BoundingBox(1:2)+seg.boxsize,difspot(i).BoundingBox(3:4)];
+	   masked_image=gtPlaceSubImage(tmp,masked_image,bb(1),bb(2));
+	   
+   end
+   figure(1);imshow(masked_image,[-200 200]);
+   drawnow;
+
+end
+
+
+%% sfSegmentNewspots
+function [seg,difspot]=sfSegmentNewspots(seg,difspot)
+	
+  % perform image reconstruction (double threshold) on current image
+	marker=seg.fullim>seg.th1;
+	mask=seg.fullim>seg.th2;
+	seg.imrec=imreconstruct(marker,mask);
+	seg.imrec=bwlabel(seg.imrec);
+	props=regionprops(seg.imrec,'Area','Centroid','BoundingBox','Image');
+ 
+  if isempty(props)
+		disp(sprintf('No new spot in image %d',seg.imnum));
+  else
+    num=0;
+		for i=1:length(props)
+			seg.spot=sfCopyStruct(props(i),seg.spot);
+      %keyboard
+			seg.spot.BoundingBox=ceil(seg.spot.BoundingBox);
+			if seg.spot.Area>seg.minsize
+				num=num+1;
+				seg.spot.SumBox=sfIncreaseBB(seg);    % increase the bounding box by +/-  seg.boxsize in all directions
+        
+        % crop with new SumBox 
+				seg.tmp.SpotOutline=gtCrop(ismember(seg.imrec,i),seg.spot.SumBox);   %   black & white mask of current spot
+				seg.tmp.SumSpot=seg.tmp.SpotOutline.*gtCrop(seg.fullim,seg.spot.SumBox);   
+				
+        check_boundingbox=1;
+        while check_boundingbox
+          % now try to sum up the images in forward and backward direction
+          seg=sfSumSpot(seg,acq);
+          
+          % check if the spot does not grow out of the current SumBox region
+          [seg,check_boundingbox]=sfCheckBoundingBox(seg,i);  
+        end
+        
+        % calculate the [seg.icut : 1-seg.icut] integration range
+        seg=sfFindIntegrationRange(seg);
+        
+        % calculate the regionprops of summed spot
+        seg=sfCalculateSummedSpotProps(seg);
+        
+        % now save the results
+        dummy=sfCopyStruct(seg.spot,seg.toto,fieldnames(difspot));
+				difspot(seg.currentspot)=dummy;
+				fname=sprintf('2_difspot/difspot%05d.edf',seg.currentspot)
+				edf_write(seg.spot.SummedImage,fname,'uint16');
+				seg.currentspot=seg.currentspot+1;
+			end
+		end
+        disp(sprintf('%d diffraction spots written',num)); 
+	end
+end 
+
+%% sfCheckBoundingBox
+	function [seg,check_boundingbox]=sfCheckBoundingBox(seg,i)
+		check_boundingbox=0;
+		if seg.spot.BoundingBox(1)<seg.spot.SumBox(1)
+			seg.spot.SumBox(1)=seg.spot.SumBox(1)-seg.boxsize;
+		  seg.spot.SumBox(3)=seg.spot.SumBox(3)+seg.boxsize;
+      check_boundingbox=1;
+		elseif seg.spot.BoundingBox(2)<seg.spot.SumBox(2)
+			seg.spot.SumBox(2)=seg.spot.SumBox(2)-seg.boxsize;
+			seg.spot.BB(4)=seg.spot.SumBox(4)+seg.boxsize;
+	    check_boundingbox=1;
+		elseif (seg.spot.BoundingBox(1)+seg.spot.BoundingBox(3))>(seg.spot.SumBox(1)+seg.spot.SumBox(3))
+			seg.spot.SumBox(3)=seg.spot.SumBoxBB(3)+seg.boxsize;
+      check_boundingbox=1;
+    elseif (seg.spot.BoundingBox(2)+seg.spot.BoundingBox(4))>(seg.spot.SumBox(2)+seg.spot.SumBox(4))
+      seg.spot.SumBox(4)=seg.spot.SumBoxBB(4)+seg.boxsize;
+			check_boundingbox=1;
+    end
+
+    if check_boundingbox==1
+			disp('update BoundingBox');
+			seg.tmp.SpotOutline=gtCrop(ismember(seg.imrec,i),seg.spot.SumBox);
+      seg.tmp.SumSpot=seg.tmp.SpotOutline.*gtCrop(seg.fullim,seg.spot.SumBox);
+		end	
+			
+			
+	end
+
+%% sfCopyStruct
+    function to=sfCopyStruct(from,to,varargin)
+        switch nargin
+			case 2
+				names=fieldnames(from);
+			case 3
+				names=varargin{:};
+		end		
+        for i=1:length(names)
+            to=setfield(to,names{i},getfield(from,names{i}));
+        end
+    end    
+
+
+%% sfIncreaseBB
+% use a Bounding Box of +/- seg.boxsize
+function bb=sfIncreaseBB(seg)
+  bb(1:2)= seg.spot.BoundingBox(1:2)-seg.boxsize;      
+  bb(3:4)=seg.spot.BoundingBox(3:4)+2*seg.boxsize;
+end  
+
+%% sfSumSpot
+ function seg=sfSumSpot(seg,acq)     % 3D double threshold image reconstruction with a moving subvolume (2 slices)
+		
+    i=1;
+    direction=1;  % +1 in forward search; -1 during backward search
+    seg.spot.Intensity=[];  % clear array
+    seg.tmp.ConstrainedSum=seg.tmp.SumSpot;  %initialise the Summed Outline image with the value of the current image
+    seg.spot.SummedImage=gtCrop(seg.fullim,seg.spot.SumBox);
+    seg.tmp.SpotOutlineini=seg.tmp.SpotOutline;        %keep a copy of the spot in the initial image where it was detected (will be reused for backward search)
+    seg.spot.Intensity(seg.imnum)=sum(seg.tmp.ConstrainedSum(:));  % initialise the spot intensity array
+    
+    
+    checknext=1;
+    incrememnt=1;
+    while checknext
+      n=seg.imnum+i*direction
+      if (n>acq.nproj || n<1)
+        break
+      elseif (abs(n-seg.imnum)>seg.range)
+         disp('summation abandonned: maximum range eceeded');
+        break;
+      end
+      fname=sprintf('1_preprocessing/full_%s/full%04d.edf',scanname,n);
+      seg.tmp.image=edf_read(fname);
+      seg.tmp.image=gtPlaceSubImage(seg.tmp.image,seg.zeroim,seg.boxsize+1,seg.boxsize+1);
+      seg.tmp.image=gtCrop(seg.tmp.image,seg.spot.SumBox);
+      
+      
+      % read next subimage
+      marker(:,:,1)=seg.tmp.SpotOutline;                   % use the spot outline in the current slice as marker
+      marker(:,:,2)=0;                                     % add an empty slice
+	    mask(:,:,1)=seg.tmp.SpotOutline;                      
+      mask(:,:,2)=seg.tmp.image>seg.th2;
+      seg.tmp.SpotOutline=imreconstruct(marker,mask);
+      seg.tmp.SpotOutline=seg.tmp.SpotOutline(:,:,2);                       % the spot outline in the new image  
+      seg.spot.Intensity(n)=sum(sum(seg.tmp.SpotOutline.*seg.tmp.image));   % the spot intensity in the new image 
+     
+      if seg.spot.Intensity(n)<200 
+        if direction==1   % reverse direction
+          direction=-1;   % and restart the procedure in the other direction
+          i=1;
+          seg.tmp.SpotOutline=seg.tmp.SpotOutlineini;    
+        else
+          checknext=0;
+        end  
+      else
+        seg.tmp.ConstrainedSum=seg.tmp.ConstrainedSum+seg.tmp.SpotOutline.*seg.tmp.image;
+        seg.spot.SummedImage=seg.spot.SummedImage+seg.tmp.image;
+        i=i+1;
+      end
+    end %while
+ end
+
+%% sfFindIntegrationRange
+  function seg=sfFindIntegrationRange(seg)
+    seg.spot.Integral=cumsum(seg.spot.Intensity);
+    seg.spot.StartImage=find(seg.spot.Intensity,1,'first');
+    seg.spot.EndImage=find(seg.spot.Intensity,1,'last');
+    seg.spot.ExtStartImage=find(seg.spot.Integral>0.1*seg.spot.Integral(end),1,'first');
+    seg.spot.ExtEndImage=find(seg.spot.Integral>0.9*seg.spot.Integral(end),1,'first');
+    seg.spot.MaxImage=find(seg.spot.Intensity==max(seg.spot.Intensity));
+    seg.spot.Integral=seg.spot.Integral(end);
+  end
+
+
+%% sfcalculateSummedSpotProps
+function seg=sfCalculateSummedSpotProps(seg)   %
+   
+    mask=seg.tmp.ConstrainedSum>0.1*max(seg.spot.SummedImage(:));
+    mask=(mask+seg.tmp.SpotOutlineini)>0;   % shrink Outlini to one point one day in order to avoid this extra step...
+    seg.FinalOutline=imreconstruct(seg.tmp.SpotOutlineini,mask);
+    seg.spot.SummedImage=seg.FinalOutline.*seg.spot.SummedImage;
+    
+    tmp=gtPlaceSubImage(seg.spot.SummedImage,seg.zeroim,seg.spot.SumBox(1),seg.spot.SumBox(2));
+    seg.prop=regionprops(double(tmp>0),'Area','PixelIdxList','BoundingBox','Centroid');
+    seg.spot.SummedImage=gtCrop(tmp,ceil(seg.prop.BoundingBox));
+    seg.prop.BoundingBox=[ceil(seg.prop.BoundingBox(1:2)-seg.boxsize),seg.prop.BoundingBox(3:4)];
+    seg.spot=sfCopyStruct(seg.prop,seg.spot);
+end   
+
+
+end
+      
\ No newline at end of file
diff --git a/2_segment_difspot/difspot_test.m b/2_segment_difspot/difspot_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..1e7d4334d51bf44e6f46e0603725f05e561dadb2
--- /dev/null
+++ b/2_segment_difspot/difspot_test.m
@@ -0,0 +1,100 @@
+clear
+clear all
+close all
+
+use_full=true;
+
+if 1
+  c=zeros(5,5);
+  c(1,:,1)=1;
+  c(:,1,2)=1;
+  c(3,3,1)=1;
+  c(5,5,1)=1;
+  c(4:5,5,2)=1;
+
+
+  c(4:5,4:5,3)=1;
+  c(3:5,3:5,4)=1;
+  [rdim,cdim,slicedim]=size(c);
+end
+if 0
+  c=zeros(10,10,3);
+  c(1,:,1)=1;
+  c(:,1,2)=1;
+  c(end,:,3)=1;
+end
+allspotsndx=1;
+
+for slicendx=1:size(c,3)-1
+  % first find all spots in b that have overlap in a
+
+  a=c(:,:,slicendx);
+  b=c(:,:,slicendx+1);
+
+  [i,j]=find(a);
+
+  q=bwselect(b,j,i,4);  % four-connected for demo (NB r,c -> c,r!!
+
+  % now label the new spots
+
+  labels=bwlabeln(q,4);
+
+  for spotndx=1:max(labels(:))  % iterate over all the valid spots in b
+    keyboard
+    [i2,j2]=find(labels==spotndx);
+    r=bwselect(a,j2,i2,4);
+
+    tmp1=find(r);
+    tmp2=find(labels==spotndx);
+
+      allspots{allspotsndx}=[repmat(slicendx,size(tmp1)) tmp1];
+      allspots{allspotsndx}=[allspots{allspotsndx};[repmat(slicendx+1,size(tmp2)) tmp2]];
+
+
+      allsparse{allspotsndx}=sparse(repmat(slicendx,size(tmp1)),tmp1,tmp1,slicendx+1,rdim*cdim);
+      allsparse{allspotsndx}(slicendx+1,[tmp2])=tmp2';
+
+
+
+    % have a look at previous spots and agglomerate...
+    for q=1:allspotsndx-1  % all previous spots
+
+      if use_full
+        if ~any(allspots{q}(:,1)==slicendx+1) && any(allspots{q}(:,1)==slicendx)
+          % only those not in current slice but in previous slice
+          if intersect(allspots{q},allspots{allspotsndx},'rows')
+            % merge the two spots - they are one
+            allspots{q}=union(allspots{q},allspots{allspotsndx},'rows');
+            allspots={allspots{1:allspotsndx-1}};  % drop that cell
+            allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+          end
+        end
+      
+      else % try the sparse solution - tricky...
+
+        if ~any(full(allsparse{q}(2,:))) && any(full(allsparse{q}(1,:)))
+          disp('here we go')
+          % only those not in current slice but in previous slice
+
+          if intersect(allsparse{q},allsparse{allspotsndx},'rows')
+
+            disp('found something')
+            % merge the two spots - they are one
+            allsparse{q}=union(allsparse{q},allsparse{allspotsndx},'rows');
+            allsparse={allsparse{1:allspotsndx-1}};  % drop that cell
+            allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+          end
+        end
+    end
+  end
+
+
+
+
+  allspotsndx=allspotsndx+1;
+end
+end
+
+
+
+
diff --git a/2_segment_difspot/gtAnnullDuplicateDifspots.m b/2_segment_difspot/gtAnnullDuplicateDifspots.m
new file mode 100755
index 0000000000000000000000000000000000000000..5b306e739dfd8fee93ff16c61dcdaaee5d197c68
--- /dev/null
+++ b/2_segment_difspot/gtAnnullDuplicateDifspots.m
@@ -0,0 +1,51 @@
+function gtAnnullDuplicateDifspots
+
+load parameters
+
+
+% remove duplicates from difspots (~10% apparently...)
+
+maxdifID=mym(sprintf('select max(difspotID) from %sdifspot',parameters.acq.name))
+AnnulledCount=0;
+
+for i=1:maxdifID
+  
+  %id duplicates
+  
+  
+  [maxim,bb1,bb2,bb3,bb4]=mym(sprintf(['select MaxImage,BoundingBoxXorigin,'...
+  'BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where difspotID=%d'],...
+  parameters.acq.name,i));
+
+if ~isnan(maxim)
+
+  difs=mym(sprintf(['select difspotID from %sdifspot where '...
+    'MaxImage=%d and abs(BoundingBoxXorigin-%d)<5 and abs(BoundingBoxYorigin-%d)<5 and'...
+    ' abs(BoundingBoxXsize-%d)<10 and abs(BoundingBoxYsize-%d)<10 and difspotID!=%d'],...
+  parameters.acq.name,maxim,bb1,bb2,bb3,bb4,i));
+  
+if ~isempty(difs) %if there are some to anull...
+  for j=1:length(difs)
+    
+    mym(sprintf('update %sextspot set bbID=null, searchbbID=null where extspotID=%d',parameters.acq.name,difs(j)));
+
+    mym(sprintf(['update %sdifspot set StartImage=null,ExtStartImage=null,'...
+      'MaxImage=null,ExtEndImage=null,EndImage=null,BoundingBoxXorigin=null,'...
+      'BoundingBoxYorigin=null,BoundingBoxXsize=null,BoundingBoxYsize=null where difspotID=%d'],...
+      parameters.acq.name,difs(j)));
+  
+    AnnulledCount=AnnulledCount+1;
+    
+  end
+end
+
+end
+
+if mod(i,1000)==0
+sprintf('Done %d difspots, removed %f percent duplicated spots',i,100*(AnnulledCount/i))
+end
+
+end
+
+    
+    
\ No newline at end of file
diff --git a/2_segment_difspot/gtBrowseDiffractionVolume.m b/2_segment_difspot/gtBrowseDiffractionVolume.m
new file mode 100755
index 0000000000000000000000000000000000000000..814e172a1f9f68c117ee70c49cd75eef6a5c77d3
--- /dev/null
+++ b/2_segment_difspot/gtBrowseDiffractionVolume.m
@@ -0,0 +1,14 @@
+function gtBrowseDiffractionVolume(allspots,ndx,siz)
+z=allspots{ndx}(:,1);
+[y,x]=ind2sub(siz,allspots{ndx}(:,2));
+vals=allspots{ndx}(:,3);
+
+fprintf('Volume extent:\n\t%4d %4d X\n\t%4d %4d Y\n\t%4d %4d Z\n',min(x),max(x),min(y),max(y),min(z),max(z));
+x=x-min(x)+1;
+y=y-min(y)+1;
+z=z-min(z)+1;
+vol=zeros(max(y),max(x),max(z));
+for n=1:length(x)
+  vol(y(n),x(n),z(n))=vals(n);
+end
+vol_view(vol)
\ No newline at end of file
diff --git a/2_segment_difspot/gtBrowseEntireDiffractionVolume.m b/2_segment_difspot/gtBrowseEntireDiffractionVolume.m
new file mode 100755
index 0000000000000000000000000000000000000000..a52aaab4538dc381a2aea182ededa3da85085c87
--- /dev/null
+++ b/2_segment_difspot/gtBrowseEntireDiffractionVolume.m
@@ -0,0 +1,16 @@
+function vol=gtBrowseEntireDiffractionVolume(allspots,siz)
+
+vol=zeros(siz);
+
+for ndx=1:length(allspots)
+ndx
+  z=allspots{ndx}(:,1);
+  [y,x]=ind2sub(siz,allspots{ndx}(:,2));
+  vals=allspots{ndx}(:,3);
+  for n=1:length(x)
+    vol(y(n),x(n),z(n))=  vals(n);
+  end
+
+end
+
+vol_view(vol)
\ No newline at end of file
diff --git a/2_segment_difspot/gtDBBlob2SpotTable.m b/2_segment_difspot/gtDBBlob2SpotTable.m
new file mode 100755
index 0000000000000000000000000000000000000000..987661c85cb8b1f1ec8c817699e46078ba3b9774
--- /dev/null
+++ b/2_segment_difspot/gtDBBlob2SpotTable.m
@@ -0,0 +1,135 @@
+%difblobdetails ----> difspot table
+%read difblobs, calculate meta data, and fill in difspot table
+
+
+function gtDBBlob2SpotTable(first, last, workingdirectory)
+
+% special case for running interactively in current directory
+ if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end 
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+cd(workingdirectory);
+
+parameters=[];
+parameters=load('parameters.mat');
+%load parameters
+acq=parameters.parameters.acq;
+seg=parameters.parameters.seg;
+
+gtDBConnect
+
+difspot_table=sprintf('%sdifspot', acq.name);
+colnames=seg.dbfields;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for difspotID=first:last
+  
+  spot.difspotID=difspotID;
+  %get the blob
+  [vol,bb]=gtDBBrowseDiffractionVolume(acq.name, difspotID);
+  
+  if isempty(vol)
+  sprintf('difspotID %d has been exterminated',difspotID)
+    continue
+  end
+  
+  
+  
+  
+  %do Intensity integral properties
+  spot=sfFindIntegrationRange(spot, vol, bb);
+  %do centroid and bb
+  spot=sfFindCentroid(spot,vol, bb);
+  
+  
+  
+  %conditions?  reject too small blobs here
+%  bad=0;
+if 0
+%  disp('bad blob')
+% continue 
+else
+  sfDoInsert(spot, difspot_table,colnames)
+end
+  
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  
+
+
+  
+  
+  
+  %% sub functions to keep things tidy
+  
+  
+  %% sfFindIntegrationRange
+  function spot=sfFindIntegrationRange(spot, vol, bb)
+%note - bb(3) can be zero, but the first value in integral has index 1.
+%Thus need to -1 to get correct CentroidImage
+  spot.StartImage=bb(3);
+  spot.EndImage=bb(3)+bb(6)-1;
+  
+  Intensity=squeeze(sum(sum(vol,1),2))';
+  spot.Integral=cumsum(Intensity);
+  spot.ExtStartImage=bb(3)+(find(spot.Integral>seg.icut*spot.Integral(end),1,'first'))-1;   % -1
+  spot.ExtEndImage=bb(3)+(find(spot.Integral>(1-seg.icut)*spot.Integral(end),1,'first'))-1;   % -1
+  % modif erik mickael sabine in case of multiple indices with equal
+  % max-value
+  %spot.MaxImage=bb(3)+(find(Intensity==max(Intensity)))-1;   % -1
+  spot.MaxImage=bb(3)+max((find(Intensity==max(Intensity))))-1; 
+  % end modif
+  spot.Integral=spot.Integral(end);
+  
+  image_cen=(Intensity*(1:size(Intensity,2))')/sum(Intensity);
+  spot.CentroidImage=bb(3)+image_cen-1;
+  end
+  
+
+  %%sfFindCentroid (greyscale centroid)
+  function spot=sfFindCentroid(spot,vol, bb);
+  
+  spot.BoundingBoxXorigin=bb(1);
+  spot.BoundingBoxYorigin=bb(2);
+  spot.BoundingBoxXsize=bb(4);
+  spot.BoundingBoxYsize=bb(5);
+  
+  im=sum(vol,3);
+  xprofile=sum(im, 1);
+  yprofile=sum(im,2);
+  xcen=(xprofile*(1:size(xprofile,2))')/sum(xprofile);
+  ycen=(yprofile'*(1:size(yprofile,1))')/sum(yprofile);
+  spot.CentroidX=spot.BoundingBoxXorigin+xcen-1;
+  spot.CentroidY=spot.BoundingBoxYorigin+ycen-1;
+  
+  spot.Area=length(find(im~=0));
+  end
+
+%%sfDoInsert
+  function sfDoInsert(spot, difspot_table,colnames)
+%write info to difspot table
+%collect the data in values - not autoincrement difspotID in this case
+%same order as in parameters.seg.dbfields
+values=[spot.difspotID, ...
+  spot.Area,...
+  spot.CentroidX, spot.CentroidY,...
+  spot.BoundingBoxXorigin, spot.BoundingBoxYorigin, ...
+  spot.BoundingBoxXsize, spot.BoundingBoxYsize, ...
+  spot.Integral, ... 
+  spot.StartImage, spot.EndImage, spot.MaxImage, ...
+  spot.ExtStartImage, spot.ExtEndImage, ...
+  spot.CentroidImage]';
+
+cmd=dbInsert(difspot_table,colnames,values);
+mym(cmd);
+  end
+
+
+
+end%end function
diff --git a/2_segment_difspot/gtDBBlob2SpotTable_WriteDifspots.m b/2_segment_difspot/gtDBBlob2SpotTable_WriteDifspots.m
new file mode 100755
index 0000000000000000000000000000000000000000..22c22685a7314c0947385c4739c9f9d283443b58
--- /dev/null
+++ b/2_segment_difspot/gtDBBlob2SpotTable_WriteDifspots.m
@@ -0,0 +1,174 @@
+%
+% modification of gtDBBlob2SpotTable
+% thr_area: if specified, only spots with an area greater than thr_area
+% will be considered
+%
+% Creates difspot edf-s in the difspot folder. They are summed full images
+% in the maximum volume determined by the dfiblobs. Centroid is calculated
+% from this image.
+%
+%difblobdetails ----> difspot table
+%read difblobs, calculate meta data, and fill in difspot table
+%
+
+function gtDBBlob2SpotTable_WriteDifspots(first,last,workingdirectory,writeflag,thr_area)
+
+% special case for running interactively in current directory
+ if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end 
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+cd(workingdirectory);
+
+if ~exist('writeflag','var')
+  writeflag=false;
+end
+
+if ~exist('thr_area','var')
+  thr_area=[];
+end
+
+parameters=[];
+load('parameters.mat');
+acq=parameters.acq;
+seg=parameters.seg;
+
+gtDBConnect
+
+blob_table=sprintf('%sdifblobdetails', acq.name);
+difspot_table=sprintf('%sdifspot', acq.name);
+colnames=seg.dbfields;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for difspotID=first:last
+  
+  spot.difspotID=difspotID;
+  %get the blob
+  [vol,bb]=gtDBBrowseDiffractionVolume(blob_table, difspotID);
+  
+  if isempty(vol)
+  sprintf('difspotID %d has been exterminated',difspotID)
+    continue
+  end
+  
+  
+  %%% write edf-s of the spots %%%
+  
+  mask=sum(vol,3)>0;
+
+  if ~isempty(thr_area)
+    if length(find(mask))<thr_area
+      continue
+    end
+  end
+  
+  full=zeros(bb(5),bb(4));
+  for fullID=bb(3):bb(3)+bb(6)-1
+    full=full+edf_read(sprintf('1_preprocessing/full/full%04d.edf', fullID), bb([1 2 4 5]));
+  end
+  
+  full=full.*mask;
+  
+  if writeflag
+  
+    fnameout=sprintf('2_difspot/difspot/difspot%05d.edf',difspotID);
+    disp(['Writing difspot into ',fnameout,' ...'])
+    edf_write(full,fnameout,'float32');
+  
+  end
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  
+  
+  
+  %do Intensity integral properties
+  spot=sfFindIntegrationRange(spot, vol, bb);
+  
+  %do centroid and bb
+  spot=sfFindCentroid(spot,full, bb);
+  
+  %conditions?  reject too small blobs here
+%  bad=0;
+if 0
+%  disp('bad blob')
+% continue 
+else
+  sfDoInsert(spot, difspot_table,colnames)
+end
+  
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  
+
+
+  
+  
+  
+  %% sub functions to keep things tidy
+  
+  
+  %% sfFindIntegrationRange
+  function spot=sfFindIntegrationRange(spot, vol, bb)
+%note - bb(3) can be zero, but the first value in integral has index 1.
+%Thus need to -1 to get correct CentroidImage
+  spot.StartImage=bb(3);
+  spot.EndImage=bb(3)+bb(6)-1;
+  
+  Intensity=squeeze(sum(sum(vol,1),2))';
+  spot.Integral=cumsum(Intensity);
+  spot.ExtStartImage=bb(3)+(find(spot.Integral>seg.icut*spot.Integral(end),1,'first'))-1;   % -1
+  spot.ExtEndImage=bb(3)+(find(spot.Integral>(1-seg.icut)*spot.Integral(end),1,'first'))-1;   % -1
+  spot.MaxImage=bb(3)+(find(Intensity==max(Intensity)))-1;   % -1
+  spot.Integral=spot.Integral(end);
+  
+  image_cen=(Intensity*(1:size(Intensity,2))')/sum(Intensity);
+  spot.CentroidImage=bb(3)+image_cen-1;
+  end
+  
+
+  %%sfFindCentroid (greyscale centroid)
+  function spot=sfFindCentroid(spot,im,bb);
+  
+  spot.BoundingBoxXorigin=bb(1);
+  spot.BoundingBoxYorigin=bb(2);
+  spot.BoundingBoxXsize=bb(4);
+  spot.BoundingBoxYsize=bb(5);
+  
+  %im=sum(vol,3);
+ 
+  xprofile=sum(im,1);
+  yprofile=sum(im,2);
+  xcen=(xprofile*(1:size(xprofile,2))')/sum(xprofile);
+  ycen=(yprofile'*(1:size(yprofile,1))')/sum(yprofile);
+  spot.CentroidX=spot.BoundingBoxXorigin+xcen-1;
+  spot.CentroidY=spot.BoundingBoxYorigin+ycen-1;
+  
+  spot.Area=length(find(im~=0));
+  end
+
+%%sfDoInsert
+  function sfDoInsert(spot, difspot_table,colnames)
+%write info to difspot table
+%collect the data in values - not autoincrement difspotID in this case
+%same order as in parameters.seg.dbfields
+values=[spot.difspotID, ...
+  spot.Area,...
+  spot.CentroidX, spot.CentroidY,...
+  spot.BoundingBoxXorigin, spot.BoundingBoxYorigin, ...
+  spot.BoundingBoxXsize, spot.BoundingBoxYsize, ...
+  spot.Integral, ... 
+  spot.StartImage, spot.EndImage, spot.MaxImage, ...
+  spot.ExtStartImage, spot.ExtEndImage, ...
+  spot.CentroidImage]';
+
+cmd=dbInsert(difspot_table,colnames,values);
+mym(cmd);
+  end
+
+
+
+end%end function
diff --git a/2_segment_difspot/gtDBBlobCracker.m b/2_segment_difspot/gtDBBlobCracker.m
new file mode 100755
index 0000000000000000000000000000000000000000..1fab049c2253bfb4b588e9d3424c829b73431817
--- /dev/null
+++ b/2_segment_difspot/gtDBBlobCracker.m
@@ -0,0 +1,124 @@
+%% gtDBBlobCracker
+% check that we have only one spot in the volume.
+% If neccessary, split it up!
+% 3D watershed doesn't seem great, 2D might be better, but for the moment
+% using a nearest local maxima approach to seperate voxels
+%output, cracked_spot, is the mask that divides up the volume
+
+% function gtDBBlobCracker(inTable,outTable,ndx,parameters)
+function gtDBBlobCracker(first,last,workingdirectory)
+
+%read from a table, write to new table...
+%outTable can be a copy of the inTable, and then just change indexes
+%where appropriate
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+cd(workingdirectory);
+
+load parameters
+gtDBConnect
+
+
+seg=parameters.seg;
+acq=parameters.acq;
+
+inTable_difblobdetails = sprintf('%sdifblobdetails',acq.name);
+outTable_difblob=sprintf('%scracked_difblob',acq.name);
+outTable_difblobdetails=sprintf('%scracked_difblobdetails',acq.name);
+
+
+for ndx=first:last
+  ndx
+  %get the volume contining the spot
+  [GreyVol,bb]=gtDBBrowseDiffractionVolume(acq.name,ndx);
+  siz=size(GreyVol);
+  if any(siz(1:2)<10)
+    disp('Rejecting small blob (or nonexistent blob')
+    continue
+  end
+
+
+  %threshold between the two thresholds?  Does it still look like one spot?
+  local_maxima=GreyVol>(seg.th1);%+seg.th2)/2;
+  [local_maxima, num]=bwlabeln(local_maxima);
+%keyboard
+  if num>1     %perhaps need to crack the spot...
+    %remove nuclei smaller than the min size
+
+    for i=1:num
+      tmp=find(local_maxima==i);
+      if length(tmp)<seg.minsize;
+        local_maxima(tmp)=0;
+      end
+    end
+
+    local_maxima=local_maxima~=0;%relabel
+    [local_maxima, num]=bwlabeln(local_maxima);
+
+  end
+  if num>1
+    %more than one large nucleus, so crack the spot
+    %try associating each voxel >th2 with the closest nucleus (local maxima)
+    %simpler than 3D watershedding which doesn't seem to work super well
+    if 1 %nearest local maxima approach
+
+      vol=GreyVol>seg.th2;
+      [dist, index]=bwdist(local_maxima>0); %dist=distance to nearest maxima, index=index of that maxima
+      crackedSpot=local_maxima(index).*double(vol);  %vol (voxels>th2), coloured according to closest local maxima
+
+
+
+    else %try scaling and watershedding
+
+      [y,x,z]=size(GreyVol);
+      [xi,yi,zi]=meshgrid(1:x, 1:y, 1:0.25:z);
+      vol2=interp3(GreyVol, xi, yi, zi);
+      vol=vol2>seg.th2;
+      dist=-bwdist(~vol2);
+      dist(~vol2)=-Inf;
+      L=watershed(dist);
+      keyboard
+
+    end
+
+
+  else %only one spot
+    crackedSpot=double(GreyVol>seg.th2);
+  end %if the spot needs cracking
+
+%keyboard
+
+  %Save the output in the outTable
+  %    num=max(crackedSpot(:))
+  %    if num>1
+  %      keyboard
+  %    end
+  fprintf('Writing %d spots to new table...',max(crackedSpot(:)));
+
+  for i=1:max(crackedSpot(:))
+
+    [y,x,z]=ind2sub(size(crackedSpot), find(crackedSpot==i));
+    [vals]=GreyVol(find(crackedSpot==i));
+
+    % get a new difblobID
+    mym(dbInsert(outTable_difblob,'difblobID',0))
+    difblobID=mym('select last_insert_id()');
+
+    dbInsertMultiple(outTable_difblobdetails,...
+      'difblobID',repmat(difblobID,1,length(x)),...
+      'xIndex',x,...
+      'yIndex',y,...
+      'zIndex',z,...
+      'graylevel',vals);
+
+  end
+  fprintf('done!\n');
+end
+end
\ No newline at end of file
diff --git a/2_segment_difspot/gtDBBrowseDiffractionVolume.m b/2_segment_difspot/gtDBBrowseDiffractionVolume.m
new file mode 100755
index 0000000000000000000000000000000000000000..86ec3bf5107f2d8db643bc58014f6cec27207666
--- /dev/null
+++ b/2_segment_difspot/gtDBBrowseDiffractionVolume.m
@@ -0,0 +1,19 @@
+function [vol,bb]=gtDBBrowseDiffractionVolume(table,ndx)
+%function [vol,bb]=gtDBBrowseDiffractionVolume(table,ndx)
+
+table=[table 'difblobdetails'];
+
+[x,y,z,vals]=mym(sprintf('select xIndex,yIndex,zIndex,graylevel from %s where difblobID = %d',table,ndx));
+
+fprintf('Volume extent:\n\t%4d %4d X\n\t%4d %4d Y\n\t%4d %4d Z\n',...
+         min(x),max(x),min(y),max(y),min(z),max(z));
+         
+         
+bb=[min(x) min(y) min(z) max(x)-min(x)+1 max(y)-min(y)+1 max(z)-min(z)+1];
+x=x-min(x)+1;
+y=y-min(y)+1;
+z=z-min(z)+1;
+vol=zeros(max(y),max(x),max(z));
+for n=1:length(x)
+  vol(y(n),x(n),z(n))=vals(n);
+end
diff --git a/2_segment_difspot/gtDBBrowseDiffractionVolumeBB.m b/2_segment_difspot/gtDBBrowseDiffractionVolumeBB.m
new file mode 100755
index 0000000000000000000000000000000000000000..31c1df471d8ed88ed9b255240744cff8ef4fc14a
--- /dev/null
+++ b/2_segment_difspot/gtDBBrowseDiffractionVolumeBB.m
@@ -0,0 +1,13 @@
+function bb=gtDBBrowseDiffractionVolumeBB(table,ndx)
+%function [vol,bb]=gtDBBrowseDiffractionVolume(table,ndx)
+
+%table=[table 'difblobdetails'];
+
+[minx,maxx,miny,maxy,minz,maxz]=mym(sprintf('select min(xIndex),max(xIndex),min(yIndex),max(yIndex),min(zIndex),max(zIndex) from %s where difblobID = %d',table,ndx));
+
+fprintf('Volume extent:\n\t%4d %4d X\n\t%4d %4d Y\n\t%4d %4d Z\n',...
+         minx,maxx,miny,maxy,minz,maxz);
+         
+         
+bb=[minx miny minz maxx-minx+1 maxy-miny+1 maxz-minz+1];
+
diff --git a/2_segment_difspot/gtDBBrowseDiffractionVolume_sab.m b/2_segment_difspot/gtDBBrowseDiffractionVolume_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..e381969f1f3dfff72c9cd05e388db3141fd235f7
--- /dev/null
+++ b/2_segment_difspot/gtDBBrowseDiffractionVolume_sab.m
@@ -0,0 +1,19 @@
+function [vol,bb]=gtDBBrowseDiffractionVolume_sab(table,ndx)
+%function [vol,bb]=gtDBBrowseDiffractionVolume(table,ndx)
+
+table=[table 'difblobdetails_old'];
+
+[x,y,z,vals]=mym(sprintf('select xIndex,yIndex,zIndex,graylevel from %s where difblobID = %d',table,ndx));
+
+fprintf('Volume extent:\n\t%4d %4d X\n\t%4d %4d Y\n\t%4d %4d Z\n',...
+         min(x),max(x),min(y),max(y),min(z),max(z));
+         
+         
+bb=[min(x) min(y) min(z) max(x)-min(x)+1 max(y)-min(y)+1 max(z)-min(z)+1];
+x=x-min(x)+1;
+y=y-min(y)+1;
+z=z-min(z)+1;
+vol=zeros(max(y),max(x),max(z));
+for n=1:length(x)
+  vol(y(n),x(n),z(n))=vals(n);
+end
diff --git a/2_segment_difspot/gtDBBrowseEntireDiffractionVolume.m b/2_segment_difspot/gtDBBrowseEntireDiffractionVolume.m
new file mode 100755
index 0000000000000000000000000000000000000000..2de216f4899dd98839b4068c565346ac0ccef8b1
--- /dev/null
+++ b/2_segment_difspot/gtDBBrowseEntireDiffractionVolume.m
@@ -0,0 +1,40 @@
+function [vol,labels]=gtDBBrowseEntireDiffractionVolume(table,varargin)
+
+
+
+table=[table 'difblobdetails'];
+
+params.xrange=[1 2048];
+params.yrange=[1 2048];
+maxz=mym(sprintf('select max(zIndex) from %s',table));
+params.zrange=[1 maxz];
+
+params=parse_pv_pairs(params,varargin)
+xrange=params.xrange;
+yrange=params.yrange;
+zrange=params.zrange;
+
+[id,x,y,z,vals]=mym(sprintf('select difblobID,xIndex,yIndex,zIndex,graylevel from %s where xIndex between %d and %d and yIndex between %d and %d and zIndex between %d and %d',table,xrange(1),xrange(2),yrange(1),yrange(2),zrange(1),zrange(2)));
+fprintf('Inserting %d voxels\n',length(id));
+
+%%% ak - I think this is wrong, because it will crop the returned volume if
+%%% there are empty rows/columes
+%z=z-min(z)+1;
+%x=x-min(x)+1;
+%y=y-min(y)+1;
+%vol=zeros(max(y),max(x),max(z));
+%labels=vol;
+%for n=1:length(id)
+%  vol(y(n),x(n),z(n))=  vals(n);
+%  labels(y(n),x(n),z(n))=id(n);
+%end
+
+z=z-zrange(1)+1;
+x=x-xrange(1)+1;
+y=y-yrange(1)+1;
+vol=zeros(yrange(2)-yrange(1)+1, xrange(2)-xrange(1)+1, zrange(2)-zrange(1)+1);
+labels=vol;
+for n=1:length(id)
+  vol(y(n),x(n),z(n))=  vals(n);
+  labels(y(n),x(n),z(n))=id(n);
+end
diff --git a/2_segment_difspot/gtDBStretchDifblobs.m b/2_segment_difspot/gtDBStretchDifblobs.m
new file mode 100755
index 0000000000000000000000000000000000000000..0957384170e5db725bef931c496742f11632e297
--- /dev/null
+++ b/2_segment_difspot/gtDBStretchDifblobs.m
@@ -0,0 +1,46 @@
+function gtDBStretchDifblobs(table,zfactor)
+%function [vol,bb]=gtDBBrowseDiffractionVolume(table,ndx)
+
+tabledetails=[table 'difblobdetails'];
+tmptable=[table 'difblobdetails2'];
+tmptabledetails=[tmptable 'difblobdetails'];
+
+
+
+mym(sprintf('create table %s as select * from %s',tmptabledetails,tabledetails))
+mym(sprintf('update %s set zIndex=zIndex*%d',tmptabledetails,zfactor))
+
+numblobs=mym(sprintf('select count(distinct difblobID) from %s',tmptabledetails));
+
+for n=1:numblobs
+  fprintf('Progress %3.1f%\n',n/numblobs*100);
+  [vol,bb]=gtDBBrowseDiffractionVolume(tmptable,n);
+
+  vol=vol(:,:,1:2:end);
+  if size(vol,3)>1
+    [x,y,z]=meshgrid(bb(1):bb(1)+bb(4)-1,bb(2):bb(2)+bb(5)-1,bb(3):2:bb(3)+bb(6)-1);  % original mesh for volume
+    [xi,yi,zi]=meshgrid(bb(1):bb(1)+bb(4)-1,bb(2):bb(2)+bb(5)-1,bb(3):bb(3)+bb(6)-1);
+
+    vol2=interp3(x,y,z,vol,xi,yi,zi);
+    
+    % now just insert the new rows:
+    vol3=vol2(:,:,2:2:end);
+    [xi2,yi2,zi2]=meshgrid(...
+      bb(1):bb(1)+bb(4)-1,...
+      bb(2):bb(2)+bb(5)-1,...
+      bb(3)+1:2:bb(3)+bb(6)-1);
+    
+    id=repmat(n,size(xi2));
+
+    % THIS CALL DOESN'T SEEM TO WORK!
+    mysqlcmd=dbInsertMultiple(tmptabledetails,...
+      'difblobID',id(:),...
+      'xIndex',xi2(:),...
+      'yIndex',yi2(:),...
+      'zIndex',zi2(:),'graylevel',vol3(:));
+    mym(mysqlcmd)
+    
+  end    
+end
+  
+
diff --git a/2_segment_difspot/gtDiffractionSpotExtents.m b/2_segment_difspot/gtDiffractionSpotExtents.m
new file mode 100755
index 0000000000000000000000000000000000000000..6fe18ad12e0c77165448d9248d073ac8f780744e
--- /dev/null
+++ b/2_segment_difspot/gtDiffractionSpotExtents.m
@@ -0,0 +1,6 @@
+function gtDiffractionSpotExtents(allspots,ndx,siz)
+z=allspots{ndx}(:,1);
+[y,x]=ind2sub(siz,allspots{ndx}(:,2));
+vals=allspots{ndx}(:,3);
+
+fprintf('Volume extent:\n\t%4d %4d X\n\t%4d %4d Y\n\t%4d %4d Z\n',min(x),max(x),min(y),max(y),min(z),max(z));
diff --git a/2_segment_difspot/gtFullStatCondor.m b/2_segment_difspot/gtFullStatCondor.m
new file mode 100755
index 0000000000000000000000000000000000000000..e4483e3a930a345c3c9257c8472261dc7b0b48e5
--- /dev/null
+++ b/2_segment_difspot/gtFullStatCondor.m
@@ -0,0 +1,143 @@
+% FUNCTION gtFullStatCondor(first,last,workingdir,flag_overwrite)
+%
+% Gives mean, median, peak and std values of the given full images
+% discarding the segmentation bounding box seg.bb area.
+% Mean and std are also given after 1-1% cut off the extremes values in a given
+% image.
+% Use gtFullStatAssembleOutputFiles to assemble the output files. They can
+% be deleted afterwards.
+%
+% If flag_overwrite==true, it overwrites the full edf-s with the median
+% value offset.
+%
+
+function gtFullStatCondor(first,last,workingdir,flag_overwrite)
+
+
+if ~exist('flag_overwrite','var')
+  flag_overwrite=false; 
+end
+
+if isdeployed
+  first=str2num(first);
+  last=str2num(last);
+end
+
+cd(workingdir)
+
+load parameters
+
+ims=first:last;
+
+bb=parameters.seg.bb; 
+nullbb=NaN(bb(4),bb(3));
+
+nofims=length(ims);
+
+framey=0;
+framez=0;
+if isfield(parameters,'calib')
+  if isfield(parameters.calib,'ydrift')
+    framey=ceil(max(abs(parameters.calib.ydrift)));
+  end 
+  if isfield(parameters.calib,'zdrift')
+    framez=ceil(max(abs(parameters.calib.zdrift)));
+  end
+end
+
+med_full=NaN(nofims,1);
+std_full=NaN(nofims,1);
+mean_full=NaN(nofims,1);
+peak_full=NaN(nofims,1);
+
+std_full_1=NaN(nofims,1);
+mean_full_1=NaN(nofims,1);
+
+for i=1:length(ims)
+ 
+  fname=sprintf('1_preprocessing/full/full%04d.edf',ims(i));
+   
+  disp(sprintf('Reading %s',fname)) 
+  info=edf_info(fname);
+  im=edf_read(fname);
+  
+  im_cent=gtCrop(im,bb);
+  imn=gtPlaceSubImage(nullbb,im,bb(1),bb(2));
+  
+
+  imn(1:framez,:)=[];
+  imn(end-framez+1:end,:)=[];
+  imn(:,1:framey)=[];
+  imn(:,end-framey+1:end)=[];
+  
+  imn=imn(~isnan(imn(:)));
+
+
+  %[n,xout]=hist(imn(:),-20:0.01:20);
+  %xout(1)=[];
+  %xout(end)=[];
+  %n(1)=[];
+  %n(end)=[];
+  %bar(xout,n)
+
+  n=hist(imn(:),-20:0.01:20);
+  n(1)=[];
+  n(end)=[];
+  [tmp,peakloc]=max(n);
+  peakloc=(peakloc-2000)*0.01;
+
+  med_full(i)=median(imn);
+  std_full(i)=std(imn);
+  mean_full(i)=mean(imn);
+  peak_full(i)=peakloc;
+  
+  
+  % 1% top and bottom values cut off
+  imn_1=sort(imn);
+  cutimn_1=round(length(imn_1)*0.01);
+  imn_1(1:cutimn_1)=[];
+  imn_1(end-cutimn_1+1:end)=[];
+  
+  std_full_1(i)=std(imn_1);
+  mean_full_1(i)=mean(imn_1);
+
+  % offset grayscale values in fulls, outside the bb
+  if flag_overwrite
+    im=im-med_full(i);
+    im=gtPlaceSubImage(im_cent,im,bb(1),bb(2));
+    im=single(im);
+    edf_write(im,fname,info);
+  end
+  
+end
+
+fnameout=sprintf('fullstatpart_%04d_%04d.mat',first,last);
+
+disp(['Results written into ' fnameout])
+
+save(fnameout,'med_full','std_full','mean_full','peak_full',...
+  'std_full_1','mean_full_1')
+
+
+figure('name','Median of fullimages')
+plot(med_full,'b+')
+
+figure('name','Peak of fullimages')
+plot(peak_full,'b+')
+
+figure('name','Mean of fullimages')
+plot(mean_full,'b+')
+
+figure('name','Mean of fullimages; 1% cut off')
+plot(mean_full_1,'b+')
+
+figure('name','STD of fullimages')
+plot(std_full,'b+')
+
+figure('name','STD of fullimages; 1% cut off')
+plot(std_full_1,'b+')
+
+
+end
+
+ 
diff --git a/2_segment_difspot/gtGetFullImage.m b/2_segment_difspot/gtGetFullImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..c13e9bea0fbf838073b17870c0a91647ceaaa2c6
--- /dev/null
+++ b/2_segment_difspot/gtGetFullImage.m
@@ -0,0 +1,15 @@
+function im=gtGetFullImage(n,varargin)
+% returns the full image n
+
+load parameters;
+
+im =  edf_read(sprintf('1_preprocessing/full/full%04d.edf',n));
+
+if nargin==2
+    figure;imshow(im,varargin{1})    
+else
+    figure;imshow(im,[]);    
+end
+
+
+
diff --git a/2_segment_difspot/gtMergeBlobs.m b/2_segment_difspot/gtMergeBlobs.m
new file mode 100755
index 0000000000000000000000000000000000000000..b8d2a759ac076cbf27a39b533dc45ab08eeda3b9
--- /dev/null
+++ b/2_segment_difspot/gtMergeBlobs.m
@@ -0,0 +1,93 @@
+function gtMergeBlobs(first,last,workingdirectory)
+%first, last dummy variables, going to be a single job only
+%merge blobs which are split betweeen jobs of gtSegmentDiffractionBlobs
+
+
+
+warning('off','Images:initSize:adjustingMag');
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist(workingdirectory,'var')
+  workingdirectory=pwd;
+end
+cd(workingdirectory);
+%%
+parameters=[];
+load parameters
+acq=parameters.acq;
+seg=parameters.seg;
+
+
+
+gtDBConnect
+%%
+table_difblobdetails=[acq.name 'difblobdetails']; %  index, x, y, z, greylevel for all blobs
+table_difblob=[acq.name 'difblob'];   %  simply a list of blob indexes
+table_difblobinfo=[acq.name 'difblobinfo'];  %  records start/end for each 'chunk' during segmentation
+% 
+% %while 1
+% mysqlcmd=sprintf('select endIndex from %s where startIndex=0',table_difblobinfo);
+% chunk1end=mym(mysqlcmd);
+% chunk2start=chunk1end+1;
+% 
+% mysqlcmd=sprintf('select distinct difblobID from %s where zIndex=%d',table_difblobdetails,chunk1end);
+% topblobID=mym(mysqlcmd);
+% 
+% mysqlcmd=sprintf('select distinct difblobID from %s where zIndex=%d',table_difblobdetails,chunk2start);
+% bottomblobID=mym(mysqlcmd);
+
+%get info from difblobinfo table
+[chunk,start_ndx, end_ndx]=mym(sprintf('select * from %s', table_difblobinfo));
+%not in order, so sort
+
+%get the data from the chunk1end and chunk2start slices
+for c=1:max(chunk)
+  
+  chunk1end=end_ndx(c);
+  %start of the 2nd chunk can wrap over to first slice for 360 degrees
+  if c==max(chunk) && strcmp(acq.type, '360degree')
+    chunk2start=start_ndx(1);
+  elseif c==max(chunk)
+    return
+  else
+    chunk2start=start_ndx(c+1);
+  end
+  %get chunk1end data
+  [id,x,y]=mym(sprintf('select difblobID,xIndex,yIndex from %s where zIndex=%d',table_difblobdetails, chunk1end));
+  %put in slimmed down allspots format (allspots{i}.[xyindex] )
+  %will handle the rest of the data later, after deciding which need to be
+  %merged
+  
+
+
+
+q=1;
+while (true)
+  if any(allspots{q}(:,1)==currentfilendx-1)
+    if intersect(allspots{q}(:,2),allspots{allspotsndx}(:,2))
+      disp('Merging spots');
+      allspots{q}=union(allspots{q},allspots{allspotsndx},'rows');
+      allspots={allspots{1:allspotsndx-1}};  % drop that last one
+      allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+    end
+  end
+  q=q+1;
+  if q>allspotsndx-1  % list has been shortened - if we're at the end, get out
+    break
+  end
+end
+end
+
+for n=1:length(topblobID)
+  mysqlcmd=sprintf('select xIndex,yIndex from %s where difblobID=%d',table_difblobdetails,topblobID(n));
+  [xtop,ytop]=mym(mysqlcmd);
+
+
+  %end
+  %%
+end
+
diff --git a/2_segment_difspot/gtPlasticViewer.m b/2_segment_difspot/gtPlasticViewer.m
new file mode 100755
index 0000000000000000000000000000000000000000..4fab00b21cea02289d0a3928cc858a90067592e6
--- /dev/null
+++ b/2_segment_difspot/gtPlasticViewer.m
@@ -0,0 +1,276 @@
+
+%tool to find a sequence of spots/blobs from plastic0-4 and display the
+%results
+
+function varargout=gtPlasticViewer(id, table_index)
+  
+  
+  pixsize=2.8; % pixelsize in microns
+  angspacing=5/100;  % angular spacing of omega in degrees
+  
+  %input id is blob id in plastic0...
+  %remove scaling, assume all datasets are equivelent omega spacings
+  %table index = which table to look for first spot in.
+
+
+  %table names
+  tables(1).name='magnesium_taper_0_difblobdetails';
+  tables(2).name='magnesium_taper_50N_difblobdetails';
+%  tables(1).name='plastic0_difblobdetails';
+%  tables(2).name='plastic1_difblobdetails';
+%  tables(3).name='plastic2_difblobdetails';
+%  tables(4).name='plastic3_difblobdetails';
+  %tables(5).name='plastic4_';
+
+  if mym('status') % if not connected
+    gtDBConnect
+  end
+
+  [tables(table_index).vol, tables(table_index).bb]=gtDBBrowseDiffractionVolume(tables(table_index).name, id);
+  bb0=tables(table_index).bb;
+ 
+  if 0 %not relevent for full data sets
+  if bb0(3)+bb0(6)-1>100
+    disp('TEMP: spot is outside the range of plastic2-4....  not very useful  to pursue...')
+    return
+  end
+  end
+
+  %get data to search for other spots
+  test_data=[id bb0(1:3)+(bb0(4:6)/2) bb0(4:5) ];
+
+  %search subsequent tables for related spots
+  %looop through these tables
+  for i=1:length(tables)
+
+    if i==table_index
+      continue %this is alrady done
+    else
+
+      pos_ids = mym(sprintf(['select difblobid from %s where xIndex between %d and %d and '...
+        'yIndex between %d and %d and zIndex between %d and %d'], ...
+        tables(i).name, bb0(1), bb0(1)+bb0(4), bb0(2), bb0(2)+bb0(5),  bb0(3)-20, bb0(3)+bb0(6)+20 ));
+%allow an extra 20 images +- in omega
+      
+      pos_ids_unique=unique(pos_ids);
+
+      if isempty(pos_ids)
+        disp(sprintf('no blobs found in table %s...  try something else?', tables(i).name))
+        continue
+
+      elseif length(pos_ids_unique)>1
+        disp('found more than one possible difblob...  need to choose')
+        %crude choice!  mode of pos_ids. Can improve later...
+        tmp=[];
+
+        %collect info to make a better choice
+        for j=1:length(pos_ids_unique)
+          [tmpbb]=gtDBBrowseDiffractionVolumeBB(tables(i).name, pos_ids_unique(j));
+
+          %tmp = [id center(x,y,z) size(x,y) {ranking}]
+          tmp(j,:)=[pos_ids_unique(j) tmpbb(1:3)+(tmpbb(4:6)/2) tmpbb(4:5) ];
+        end
+
+        orig_size=(test_data(5)*test_data(6))^0.5;
+        %"distance" (using x-y only, to use omega too change 3s to 4s...)
+        tmp(:,2:4)=tmp(:,2:4)-repmat(test_data(2:4), size(tmp,1), 1);
+        tmp(:,7)=(sum((tmp(:,2:4).*tmp(:,2:4)),2)).^(0.5);
+        tmp(:,7)=tmp(:,7)/orig_size;
+        %size (x-y)
+        tmp(:,8) = (abs(((tmp(:,5).*tmp(:,6)).^0.5)-orig_size)) /orig_size; %zero if good, large if bad
+        %combined criteria
+        tmp(:,9)=tmp(:,7)+tmp(:,8);
+
+        pos_ids=pos_ids_unique(find(tmp(:,9)==min(tmp(:,9))));
+
+        if 0 %to iterfere with auto choice
+          keyboard
+        end
+
+
+      else
+        disp('found one possible only...')
+        pos_ids=pos_ids_unique;
+      end
+
+      [tables(i).vol,tables(i).bb]=gtDBBrowseDiffractionVolume(tables(i).name, pos_ids);
+
+    end
+  end
+
+
+
+  %Having read in a sequence, analyse and display them...
+  figure(1); clf;hold on %for the summed images
+  figure(2); clf;hold on %for the intensity profiles
+
+  %paste all volumes into the same size bb for easier comparison
+  minx=[]; miny=[]; minz=[]; maxx=[]; maxy=[]; maxz=[];
+  for i=1:length(tables)
+    if ~isempty(tables(i).bb)
+      minx(end+1)=tables(i).bb(1);
+      miny(end+1)=tables(i).bb(2);
+      minz(end+1)=tables(i).bb(3);
+      maxx(end+1)=tables(i).bb(1)+tables(i).bb(4);
+      maxy(end+1)=tables(i).bb(2)+tables(i).bb(5);
+      maxz(end+1)=tables(i).bb(3)+tables(i).bb(6);
+    end
+  end
+  minx=min(minx);
+  miny=min(miny);
+  minz=min(minz);
+  maxx=max(maxx);
+  maxy=max(maxy);
+  maxz=max(maxz);
+  new_bb=[minx miny minz maxx-minx+1 maxy-miny+1 maxz-minz+1];
+  for i=1:length(tables)
+
+    tmp=zeros( maxy-miny+1,maxx-minx+1, maxz-minz+1);
+    if ~isempty(tables(i).vol)
+      bb=tables(i).bb-[new_bb(1:3)-1 0 0 0];
+
+      tmp( bb(2):bb(2)+bb(5)-1,bb(1):bb(1)+bb(4)-1 , bb(3):bb(3)+bb(6)-1)=tables(i).vol;
+    end
+    tables(i).vol=tmp;
+
+    tables(i).orig_bb=tables(i).bb;
+    tables(i).bb=new_bb;
+  end
+
+
+
+  xdata=[];
+  ydata=[];
+  for i=1:length(tables)
+
+    if ~isempty(tables(i).vol)
+
+      tables(i).im=sum(tables(i).vol,3);
+      tables(i).im_xz=squeeze(sum(tables(i).vol,2));
+      tables(i).im_yz=squeeze(sum(tables(i).vol,1));
+      tables(i).int=squeeze(sum(sum(tables(i).vol,1),2));
+
+
+      tables(i).xdata=tables(i).bb(3):tables(i).bb(3)+tables(i).bb(6)-1;
+      xdata(i,:)=tables(i).xdata;
+      ydata(i,:)=tables(i).int;
+
+      figure(2)
+      subplot(3,4,i)
+      imagesc(tables(i).im)
+
+      switch i
+        case 1
+          ylabel('Summed through angle\newline(\mum)')
+          xlabel('X (um)')
+          title('Plastic0')
+        case 2
+          title('Plastic1')
+        case 3
+          title('Plastic2')
+        case 4
+          title('Plastic3')
+      end
+
+      axis image
+      subplot(3,4,i+4)
+      imagesc(xdata(i,:)*angspacing,pixsize*(1:tables(i).bb(5)),tables(i).im_xz)
+      if i==1
+        ylabel('Summed through X\newline(\mum)')
+        xlabel('omega (\circ)')
+      end
+      %  axis image
+      subplot(3,4,i+8)
+      imagesc(xdata(i,:)*angspacing,pixsize*(1:tables(i).bb(5)),tables(i).im_yz)
+      if i==1
+        ylabel('Summed through Y\newline(\mum)')
+        xlabel('omega (\circ)')
+      end
+      
+
+      % axis image
+
+    end
+  end
+
+
+
+  figure(1)
+
+  clf
+  scalefactor=3e4;
+  colours='rgbk';
+  for q=1:length(tables)
+    xgj=xdata(q,:);
+    ygj=ydata(q,:)/scalefactor;  % to avoid singularities from scaling
+    [pk,ndx]=max(ygj);
+    mu=xgj(ndx);
+    coefguess=[pk/2*pi;1;mu;0];
+    %    coefguess=[0.85;3;56; 0];
+
+    try
+      coef=lsqcurvefit(@(coef,xgj) gauss1D(coef,xgj),coefguess,xgj,ygj);
+
+      [coefguess coef]
+
+    catch
+      disp('Fitting failed');
+      coef=[NaN;NaN;NaN;NaN];
+    end
+
+    if true % centre all plots
+    %  subplot(1,4,q)
+      plot(xgj-coef(3),ygj*scalefactor,[colours(q) '.'])
+      hold on
+      xfit=linspace(xgj(1),xgj(end),100);
+      yfit=gauss1D(coef,xfit);
+      plot(xfit-coef(3),yfit*scalefactor,[colours(q) '-'])
+      axis([-15 15 -inf inf])
+    else % leave untouched
+      plot(xgj,ygj*scalefactor,[colours(q) '.'])
+      hold on
+      xfit=linspace(xgj(1),xgj(end),100);
+      yfit=gauss1D(coef,xfit);
+      plot(xfit,yfit*scalefactor,[colours(q) '-'])
+
+    end
+    title(sprintf('Blob %d (plastic %d)',id,table_index-1));
+    %    fprintf('Sigma %f\t Mu %f \tFWHM
+    %    %f\n',coef(2),coef(3),2*sqrt(2*log(2))*coef(2));
+    tables(q).fwhm=2*sqrt(2*log(2))*coef(2);
+    fprintf('FWHM %3.4f\n',tables(q).fwhm);
+
+    %title(sprintf('FWHM: %3.3f',tables(q).fwhm))
+
+  end
+  try
+[a,b,c,d]=  legend(...
+    '',sprintf('FWHM: %3.2f',tables(1).fwhm),...
+    '',sprintf('FWHM: %3.2f',tables(2).fwhm),...
+    '',sprintf('FWHM: %3.2f',tables(3).fwhm),...
+    '',sprintf('FWHM: %3.2f',tables(4).fwhm));
+  delete(b(10:2:end))
+  end
+  tilefig
+  figure(1)
+  print('-dpng',sprintf('fwhm_%04d',id))
+  figure(2)
+  maxfig
+  print('-dpng',sprintf('sums_%04d',id));
+maxfig
+  if nargout
+    varargout{1}=tables;
+  end
+
+  function F = gauss1D(coef,xdata)
+    peakheight=coef(1);
+    sigma=coef(2);
+    mu=coef(3);
+    background=coef(4);
+
+    F= peakheight/(sigma * 2*pi) * exp(- ((xdata-mu).^2)/(2*sigma^2)) + background;
+
+  end
+
+end
+
diff --git a/2_segment_difspot/gtRemoveOverlappingDifblobs.m b/2_segment_difspot/gtRemoveOverlappingDifblobs.m
new file mode 100755
index 0000000000000000000000000000000000000000..abd707e09d4a46b44a61c294bf88cf99961f753e
--- /dev/null
+++ b/2_segment_difspot/gtRemoveOverlappingDifblobs.m
@@ -0,0 +1,90 @@
+function gtRemoveOverlappingDifblobs(tname)
+  gtDBConnect
+
+%   tdetails=sprintf('%sdifblobdetails',tname);
+%   tinfo=sprintf('%sdifblobinfo',tname);
+%   tblob=sprintf('%sdifblob',tname);
+
+tdetails=sprintf('%sdifblobdetails',tname);
+tinfo=sprintf('%sdifblobinfo',tname);
+tblob=sprintf('%sdifblob',tname);
+
+
+  [first,last]=mym(sprintf('select startIndex,endIndex from %s order by startIndex',tinfo));
+  length(first);
+  first=first';
+
+  for chunk=first(2:end)
+    chunk
+    blobIDs=mym(sprintf('select distinct difblobID from %s where zIndex=%d order by difblobID',tdetails,chunk));
+    % keyboard
+    %  blobIDs=[359];
+    n=1;
+    double=0;
+    single=0;
+    while n<=length(blobIDs)
+      % grab a single voxel from a blob
+      [x,y]=mym(sprintf('select xIndex,yIndex from %s where difblobID=%d and zIndex=%d limit 1',tdetails,blobIDs(n),chunk));
+      % find the two blobx
+      twoblobs=mym(sprintf('select distinct difblobID from %s where xIndex=%d and yIndex=%d and zIndex=%d',tdetails,x,y,chunk));
+      % sometimes there are two entries with the same difblobID - where does
+      % this come from???  the 'distinct' fixes it, but still...
+
+      if length(twoblobs)==2
+        fprintf('Double blob: %d of %d\n',n,length(blobIDs));
+        double=double+1;
+        % first get rid of the overlapping voxels in the second blob:
+        mysqlcmd=sprintf('delete from %s where difblobID=%d and zIndex=%d',tdetails,max(twoblobs),chunk);
+        mym(mysqlcmd)
+        % then merge them
+        mysqlcmd=sprintf('update %s set difblobID = %d where difblobID=%d',tdetails,min(twoblobs),max(twoblobs));
+        mym(mysqlcmd)
+        % now clean up the listing for blobIDs
+        mysqlcmd=sprintf('delete from %s where difblobID=%d',tblob,max(twoblobs));
+        mym(mysqlcmd)
+        %keyboard
+        blobIDs(find(blobIDs==max(twoblobs)))=[];
+      elseif length(twoblobs)==1
+        % keyboard
+        disp('Single')
+        single=single+1;
+      else
+        disp('MORE THAN TWO BLOBS!')
+      end
+      n=n+1;
+
+    end
+    disp(sprintf('Single/Double %d %d',single,double))
+    % that chunk boundary is finished, so remove it from the chunks table
+    %  disp('About to remove chunk details')
+    %  end_tokeep=mym(sprintf('select endIndex from %s where startIndex=%d',tinfo,chunk));
+    %  mym(sprintf('delete from %s where startIndex=%d',tinfo,chunk));
+    %  mym(sprintf('update %s set endIndex=%d where endIndex=%d',tinfo,end_tokeep,chunk));
+
+  end
+
+  
+  if 0  % special cleanup code - shouldn't be needed anymore.
+    mym('close')
+    gtDBConnect('admin')
+    a=0:93:3600
+    for n=a(2:end)
+      n
+      mym(sprintf('create temporary table t123 as select distinct * from ss2007_A_difblobdetails where zIndex=%d',n));
+      mym(sprintf('delete from ss2007_A_difblobdetails where zIndex=%d',n))
+      mym(sprintf('insert into ss2007_A_difblobdetails select * from t123'))
+      mym('drop table t123');
+    end
+
+    %%
+    if 0  % shouldn't be needed at all (works, but VERY slow for large tables)
+      disp('Now removing duplicate spots')
+      mym('close')
+      gtDBConnect('admin')
+      mym(sprintf('create temporary table tmp345 as select distinct * from %s',tdetails))
+      mym(sprintf('drop table %s',tdetails));
+      mym(sprintf('create table %s as select * from tmp345',tdetails))
+      mym(sprintf('drop table %s',tinfo));  % _difblobinfo table no longer useful
+      mym('close')  % close the connection to ensure the temporary table is dropped
+    end
+  end
diff --git a/2_segment_difspot/gtRemoveOverlappingDifblobs_sab.m b/2_segment_difspot/gtRemoveOverlappingDifblobs_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..658af59553bbe081dce38fa44283ba5986eeb636
--- /dev/null
+++ b/2_segment_difspot/gtRemoveOverlappingDifblobs_sab.m
@@ -0,0 +1,111 @@
+function gtRemoveOverlappingDifblobs_sab(tname)
+  gtDBConnect
+
+%   tdetails=sprintf('%sdifblobdetails',tname);
+%   tinfo=sprintf('%sdifblobinfo',tname);
+%   tblob=sprintf('%sdifblob',tname);
+
+tdetails=sprintf('%sdifblobdetails',tname);
+tinfo=sprintf('%sdifblobinfo',tname);
+tblob=sprintf('%sdifblob',tname);
+
+
+  [first,last]=mym(sprintf('select startIndex,endIndex from %s order by startIndex',tinfo));
+  length(first);
+  first=first';
+
+  for chunk=first(2:end)
+    chunk
+    blobIDs=mym(sprintf('select distinct difblobID from %s where zIndex=%d order by difblobID',tdetails,chunk));
+    % keyboard
+    %  blobIDs=[359];
+    n=1;
+    double=0;
+    single=0;
+    while n<=length(blobIDs)
+      % grab a single voxel from a blob
+      [x,y]=mym(sprintf('select xIndex,yIndex from %s where difblobID=%d and zIndex=%d limit 1',tdetails,blobIDs(n),chunk));
+      % find the two blobx
+      twoblobs=mym(sprintf('select distinct difblobID from %s where xIndex=%d and yIndex=%d and zIndex=%d',tdetails,x,y,chunk));
+      % sometimes there are two entries with the same difblobID - where does
+      % this come from???  the 'distinct' fixes it, but still...
+
+      if length(twoblobs)==2
+        fprintf('Double blob: %d of %d\n',n,length(blobIDs));
+        double=double+1;
+        % first get rid of the overlapping voxels in the second blob:
+        mysqlcmd=sprintf('delete from %s where difblobID=%d and zIndex=%d',tdetails,max(twoblobs),chunk);
+        mym(mysqlcmd)
+        % then merge them
+        mysqlcmd=sprintf('update %s set difblobID = %d where difblobID=%d',tdetails,min(twoblobs),max(twoblobs));
+        mym(mysqlcmd)
+        % now clean up the listing for blobIDs
+        mysqlcmd=sprintf('delete from %s where difblobID=%d',tblob,max(twoblobs));
+        mym(mysqlcmd)
+        %keyboard
+        blobIDs(find(blobIDs==max(twoblobs)))=[];
+      elseif length(twoblobs)==1
+        % keyboard
+        disp('Single')
+        single=single+1;
+      else
+        disp('%%%%%%%%%%%%%%%%%%');
+        disp('MORE THAN TWO BLOBS!')
+        fprintf('Double blob: %d of %d\n',n,length(blobIDs));
+        keyboard
+  
+        for i=1:length(twoblobs)
+            [a,b,c]=mym(sprintf('select xIndex,yIndex,zIndex from %s where difblobID = %d',tdetails,twoblobs(i)));
+            maxix(i)=max(a); minix(i)=min(a);
+            maxiy(i)=max(b); miniy(i)=min(b);
+            maxiz(i)=max(c); miniz(i)=min(c);
+        end
+        
+        if maxix(1)==maxix(2) && minix(1)==minix(2) && maxiy(1)==maxiy(2) && miniy(1)==miniy(2)
+            
+        elseif maxix(1)==maxix(3) && minix(1)==minix(3) && maxiy(1)==maxiy(3) && miniy(1)==miniy(3)
+                
+        end
+        
+        
+        disp('%%%%%%%%%%%%%%%%%%');
+        
+        %
+      end
+      n=n+1;
+
+    end
+    disp(sprintf('Single/Double %d %d',single,double))
+    % that chunk boundary is finished, so remove it from the chunks table
+    %  disp('About to remove chunk details')
+    %  end_tokeep=mym(sprintf('select endIndex from %s where startIndex=%d',tinfo,chunk));
+    %  mym(sprintf('delete from %s where startIndex=%d',tinfo,chunk));
+    %  mym(sprintf('update %s set endIndex=%d where endIndex=%d',tinfo,end_tokeep,chunk));
+
+  end
+
+  
+  if 0  % special cleanup code - shouldn't be needed anymore.
+    mym('close')
+    gtDBConnect('admin')
+    a=0:93:3600
+    for n=a(2:end)
+      n
+      mym(sprintf('create temporary table t123 as select distinct * from ss2007_A_difblobdetails where zIndex=%d',n));
+      mym(sprintf('delete from ss2007_A_difblobdetails where zIndex=%d',n))
+      mym(sprintf('insert into ss2007_A_difblobdetails select * from t123'))
+      mym('drop table t123');
+    end
+
+    %%
+    if 0  % shouldn't be needed at all (works, but VERY slow for large tables)
+      disp('Now removing duplicate spots')
+      mym('close')
+      gtDBConnect('admin')
+      mym(sprintf('create temporary table tmp345 as select distinct * from %s',tdetails))
+      mym(sprintf('drop table %s',tdetails));
+      mym(sprintf('create table %s as select * from tmp345',tdetails))
+      mym(sprintf('drop table %s',tinfo));  % _difblobinfo table no longer useful
+      mym('close')  % close the connection to ensure the temporary table is dropped
+    end
+  end
diff --git a/2_segment_difspot/gtSegmentDiffractionBlobs.m b/2_segment_difspot/gtSegmentDiffractionBlobs.m
new file mode 100755
index 0000000000000000000000000000000000000000..acbd46b4d9b2e19c1bd06f00b938f7a5b12e2a50
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionBlobs.m
@@ -0,0 +1,161 @@
+function gtSegmentDiffractionBlobs(first,last,workingdirectory)
+  %latest version, writes blobs to database as it finds them to ease
+  %database traffic.
+
+
+
+  warning('off','Images:initSize:adjustingMag');
+
+  if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end % special case for running interactively in current directory
+
+  if ~exist('workingdirectory','var')
+    workingdirectory=pwd;
+  end
+
+  fprintf('Changing directory to %s\n',workingdirectory)
+  cd(workingdirectory)
+
+
+
+  parameters=[];
+  load parameters parameters
+  acq=parameters.acq;
+  seg=parameters.seg;
+
+  %disp('duplicating one slice with the next chunk')
+  last=last+1;
+  disp('Date: 22/5/2007')
+  disp(sprintf(' ~~~  This Job: Image %d to %d, for %s  ~~~   ',first,last,workingdirectory))
+  disp('THIS DOES NOT WRAP OVER THE END OF THE DATASET PROPERLY!')
+
+  % read the size of one image to make an estimate for the number we can read
+  % at once:
+  test=pfReadAndThreshold(first,seg);
+  details=whos('test');
+  maxmemoryusage=100;  % in MB
+  step=floor(maxmemoryusage*1024*1024/details.bytes);
+
+  % open database
+  gtDBConnect
+
+  siz=[2048 2048];
+ 
+  table_difblobdetails=[acq.name 'difblobdetails'];
+  table_difblob=[acq.name 'difblob'];
+  table_difblobinfo=[acq.name 'difblobinfo'];
+  
+  
+
+  allspotsndx=0;
+  for currentfilendx=first:step:last
+    disp(['current file ndx: ' num2str(currentfilendx)])
+    step=min(step,last-currentfilendx+1);
+
+    fprintf('Reading %d images (~%dMB) in this chunk\n',step,round(step*details.bytes/1024/1024));
+    shortvol=zeros(2048,2048,step);
+    %add a median filter to de-noise the thresholded images
+    for n=1:step
+      im=pfReadAndThreshold(currentfilendx+n-1,seg);
+      shortvol(:,:,n)=medfilt2(im);
+    end
+
+    labels=bwlabeln(shortvol);
+    numlabels=max(labels(:));
+    for ndx=1:numlabels  % iterate over all the blobs
+      %tic
+      ind=find(labels==ndx);
+      if length(ind)<10  % discard small blobs
+        %disp('skipping small blob')
+        % toc
+        continue
+      end
+      allspotsndx=allspotsndx+1;
+      %fprintf('Blob: %d/%d Agglomerated blob: %d\n',ndx,numlabels,allspotsndx);
+      grayvals=shortvol(ind);
+      [i,j,k]=ind2sub(size(shortvol),ind);
+      k=k+currentfilendx-1;  % offset shortvol
+      ind2D=sub2ind(size(shortvol(:,:,1)),i,j);
+
+      % now record the blob
+      allspots{allspotsndx}=[];
+      for z=min(k):max(k) % iterate over all slices for this blob
+        howmanyinz=length(find(k==z));
+        allspots{allspotsndx}=[allspots{allspotsndx};
+          [repmat(z,[howmanyinz 1]) ind2D(k==z) grayvals(k==z)]];
+      end
+      if currentfilendx>first
+        if any(k==currentfilendx)  % blob is at top of sub volume
+          % look through all spots to find ones touching bottom of previous
+          % subvolume
+          q=1;
+          while (true)
+            if (~isempty(allspots{q}) && any(allspots{q}(:,1)==currentfilendx-1))
+              if intersect(allspots{q}(:,2),allspots{allspotsndx}(:,2))
+                % disp('Merging spots');
+                allspots{q}=union(allspots{q},allspots{allspotsndx},'rows');
+                allspots={allspots{1:allspotsndx-1}};  % drop that last one
+                allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+              end
+            end
+            q=q+1;
+            if q>allspotsndx-1  % list has been shortened - if we're at the end, get out
+              break
+            end
+          end
+        end
+      end
+    end
+    if currentfilendx+step <last
+      % write all completed blobs to database and erase from cell array
+      for qwe=1:length(allspots)
+        if (~isempty(allspots{qwe}) && max(allspots{qwe}(:,1)) < currentfilendx-1)
+          % this blob is finished - write it out
+          sfDBWriteBlob(allspots{qwe})
+          disp(['clearing out blob ' num2str(qwe)])
+          allspots{qwe}=[];
+        end
+      end
+    else
+      disp('Writing at the end of the loop')
+      % write all of them
+      for qwe=1:length(allspots)
+        if ~isempty(allspots{qwe})
+          sfDBWriteBlob(allspots{qwe})
+          allspots{qwe}=[];
+        end
+      end
+    end
+  end
+
+  % finished processing - update the chunk table
+  mym(dbInsert(table_difblobinfo,'StartIndex',first,'EndIndex',last))
+
+
+  function sfDBWriteBlob(blob)
+
+    zz=blob(:,1);
+    if length(zz)>seg.minsize
+%should only proceed if the blob is bigger than the minimum size defined in
+%the parameters file
+    [yy,xx]=ind2sub(siz,blob(:,2));
+    vals=blob(:,3);
+
+    % get a new difblobID
+    mym(dbInsert(table_difblob,'difblobID',0))
+    difblobID=mym('select last_insert_id()');
+    disp(sprintf('***DB WRITE *** Blob %d:inserting %d rows\n\r',difblobID,length(xx)))
+
+    dbInsertMultiple(table_difblobdetails,...
+      'difblobID',repmat(difblobID,1,length(xx)),...
+      'xIndex',xx,...
+      'yIndex',yy,...
+      'zIndex',zz,...
+      'graylevel',vals);
+    end
+
+  end
+end
+
diff --git a/2_segment_difspot/gtSegmentDiffractionBlobs2_sab.m b/2_segment_difspot/gtSegmentDiffractionBlobs2_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..f0c3e1839ddf68a0757d8e3690a89ebac0738462
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionBlobs2_sab.m
@@ -0,0 +1,163 @@
+function gtSegmentDiffractionBlobs2_sab(first,last,workingdirectory)
+  %latest version, writes blobs to database as it finds them to ease
+  %database traffic.
+
+
+
+  warning('off','Images:initSize:adjustingMag');
+
+  if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end % special case for running interactively in current directory
+
+  if ~exist('workingdirectory','var')
+    workingdirectory=pwd;
+  end
+
+  fprintf('Changing directory to %s\n',workingdirectory)
+  cd(workingdirectory)
+
+
+
+  parameters=[];
+  load parameters parameters
+  acq=parameters.acq;
+  seg=parameters.seg;
+
+  %disp('duplicating one slice with the next chunk')
+  last=last+1;
+  disp('Date: 22/5/2007')
+  disp(sprintf(' ~~~  This Job: Image %d to %d, for %s  ~~~   ',first,last,workingdirectory))
+  disp('THIS DOES NOT WRAP OVER THE END OF THE DATASET PROPERLY!')
+
+  % read the size of one image to make an estimate for the number we can read
+  % at once:
+  test=pfReadAndThreshold(first,seg);
+  details=whos('test');
+  maxmemoryusage=100;  % in MB
+  step=floor(maxmemoryusage*1024*1024/details.bytes);
+
+  % open database
+  gtDBConnect
+
+  siz=[2048 2048];
+  % modif sabine
+%   table_difblobdetails=[acq.name 'difblobdetails'];
+%   table_difblob=[acq.name 'difblob'];
+%   table_difblobinfo=[acq.name 'difblobinfo'];
+  
+  table_difblobdetails=[acq.name 'difblobdetails_test1'];
+  table_difblob=[acq.name 'difblob_test1'];
+  table_difblobinfo=[acq.name 'difblobinfo_test1'];
+
+  allspotsndx=0;
+  for currentfilendx=first:step:last
+    disp(['current file ndx: ' num2str(currentfilendx)])
+    step=min(step,last-currentfilendx+1);
+
+    fprintf('Reading %d images (~%dMB) in this chunk\n',step,round(step*details.bytes/1024/1024));
+    shortvol=zeros(2048,2048,step);
+    %add a median filter to de-noise the thresholded images
+    for n=1:step
+      im=pfReadAndThreshold(currentfilendx+n-1,seg);
+      shortvol(:,:,n)=medfilt2(im);
+    end
+
+    labels=bwlabeln(shortvol);
+    numlabels=max(labels(:));
+    for ndx=1:numlabels  % iterate over all the blobs
+      %tic
+      ind=find(labels==ndx);
+      if length(ind)<10  % discard small blobs
+        %disp('skipping small blob')
+        % toc
+        continue
+      end
+      allspotsndx=allspotsndx+1;
+      %fprintf('Blob: %d/%d Agglomerated blob: %d\n',ndx,numlabels,allspotsndx);
+      grayvals=shortvol(ind);
+      [i,j,k]=ind2sub(size(shortvol),ind);
+      k=k+currentfilendx-1;  % offset shortvol
+      ind2D=sub2ind(size(shortvol(:,:,1)),i,j);
+
+      % now record the blob
+      allspots{allspotsndx}=[];
+      for z=min(k):max(k) % iterate over all slices for this blob
+        howmanyinz=length(find(k==z));
+        allspots{allspotsndx}=[allspots{allspotsndx};
+          [repmat(z,[howmanyinz 1]) ind2D(k==z) grayvals(k==z)]];
+      end
+      if currentfilendx>first
+        if any(k==currentfilendx)  % blob is at top of sub volume
+          % look through all spots to find ones touching bottom of previous
+          % subvolume
+          q=1;
+          while (true)
+            if (~isempty(allspots{q}) && any(allspots{q}(:,1)==currentfilendx-1))
+              if intersect(allspots{q}(:,2),allspots{allspotsndx}(:,2))
+                % disp('Merging spots');
+                allspots{q}=union(allspots{q},allspots{allspotsndx},'rows');
+                allspots={allspots{1:allspotsndx-1}};  % drop that last one
+                allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+              end
+            end
+            q=q+1;
+            if q>allspotsndx-1  % list has been shortened - if we're at the end, get out
+              break
+            end
+          end
+        end
+      end
+    end
+    if currentfilendx+step <last
+      % write all completed blobs to database and erase from cell array
+      for qwe=1:length(allspots)
+        if (~isempty(allspots{qwe}) && max(allspots{qwe}(:,1)) < currentfilendx-1)
+          % this blob is finished - write it out
+          sfDBWriteBlob(allspots{qwe})
+          disp(['clearing out blob ' num2str(qwe)])
+          allspots{qwe}=[];
+        end
+      end
+    else
+      disp('Writing at the end of the loop')
+      % write all of them
+      for qwe=1:length(allspots)
+        if ~isempty(allspots{qwe})
+          sfDBWriteBlob(allspots{qwe})
+          allspots{qwe}=[];
+        end
+      end
+    end
+  end
+
+  % finished processing - update the chunk table
+  mym(dbInsert(table_difblobinfo,'StartIndex',first,'EndIndex',last))
+
+
+  function sfDBWriteBlob(blob)
+
+    zz=blob(:,1);
+    if length(zz)>seg.minsize
+%should only proceed if the blob is bigger than the minimum size defined in
+%the parameters file
+    [yy,xx]=ind2sub(siz,blob(:,2));
+    vals=blob(:,3);
+
+    % get a new difblobID
+    mym(dbInsert(table_difblob,'difblobID',0))
+    difblobID=mym('select last_insert_id()');
+    disp(sprintf('***DB WRITE *** Blob %d:inserting %d rows\n\r',difblobID,length(xx)))
+
+    dbInsertMultiple(table_difblobdetails,...
+      'difblobID',repmat(difblobID,1,length(xx)),...
+      'xIndex',xx,...
+      'yIndex',yy,...
+      'zIndex',zz,...
+      'graylevel',vals);
+    end
+
+  end
+end
+
diff --git a/2_segment_difspot/gtSegmentDiffractionBlobsPlasticTest.m b/2_segment_difspot/gtSegmentDiffractionBlobsPlasticTest.m
new file mode 100755
index 0000000000000000000000000000000000000000..c6430d78ef5b13e39f7d19a0524fc08eb254e41c
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionBlobsPlasticTest.m
@@ -0,0 +1,154 @@
+function gtSegmentDiffractionVolumes(first,last,workingdirectory)
+
+warning('off','Images:initSize:adjustingMag');
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist(workingdirectory,'var')
+  workingdirectory=pwd;
+end
+cd(workingdirectory);
+
+parameters=[];
+load parameters
+acq=parameters.acq;
+seg=parameters.seg;
+
+disp('duplicate one slice with the next chunk')
+last=last+1;
+disp('Date: 22/5/2007')
+disp(sprintf(' ~~~  This Job: Image %d to %d, for %s  ~~~   ',first,last,workingdirectory))
+disp('THIS DOES NOT WRAP OVER THE END OF THE DATASET PROPERLY!')
+tic
+% read the size of one image to make an estimate for the number we can read
+% at once:
+%pfReadAndThreshold masks the direct beam area and thresholds at seg.th2
+test=pfReadAndThreshold(first,seg);
+details=whos('test');
+maxmemoryusage=600;  % in MB
+step=floor(maxmemoryusage*1024*1024/details.bytes);
+
+
+allspotsndx=0;
+for currentfilendx=first:step:last
+  step=min(step,last-currentfilendx+1);
+
+  fprintf('Reading %d images (~%dMB) in this chunk\n',step,round(step*details.bytes/1024/1024));
+  shortvol=zeros(2048,2048,step);
+  for n=1:step
+    shortvol(:,:,n)=pfReadAndThreshold(currentfilendx+n-1,seg);
+  end
+
+  labels=bwlabeln(shortvol);
+  numlabels=max(labels(:));
+  for ndx=1:numlabels  % iterate over all the blobs
+
+    ind=find(labels==ndx);
+       if length(ind)<10  % discard small blobs 
+         disp('skipping small blob')
+         continue
+       end
+    allspotsndx=allspotsndx+1;
+    fprintf('Blob: %d/%d Agglomerated blob: %d\r',ndx,numlabels,allspotsndx);
+    grayvals=shortvol(ind);
+    [i,j,k]=ind2sub(size(shortvol),ind);
+    k=k+currentfilendx-1;  % offset shortvol
+    ind2D=sub2ind(size(shortvol(:,:,1)),i,j);
+
+    % now record the blob
+    allspots{allspotsndx}=[];
+    for z=min(k):max(k) % iterate over all slices for this blob
+      howmanyinz=length(find(k==z));
+      allspots{allspotsndx}=[allspots{allspotsndx};
+        [repmat(z,[howmanyinz 1]) ind2D(k==z) grayvals(k==z)]];
+    end
+    if currentfilendx>first
+      if any(k==currentfilendx)  % blob is at top of sub volume
+        % look through all spots to find ones touching bottom of previous
+        % subvolume
+        q=1;
+        while (true)
+          if any(allspots{q}(:,1)==currentfilendx-1)
+            if intersect(allspots{q}(:,2),allspots{allspotsndx}(:,2))
+              disp('Merging spots');
+              allspots{q}=union(allspots{q},allspots{allspotsndx},'rows');
+              allspots={allspots{1:allspotsndx-1}};  % drop that last one
+              allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+            end
+          end
+          q=q+1;
+          if q>allspotsndx-1  % list has been shortened - if we're at the end, get out
+            break
+          end
+        end
+      end
+    end
+  end
+  fprintf('Slice %d took %fs\n',currentfilendx-1,toc);
+end
+disp('Putting all blobs into the database')
+
+%disp('(Re)create database tables')
+%gtDBCreateDifblobTable(acq.name)
+gtDBConnect
+
+siz=[2048 2048];
+table_difblobdetails=[acq.name 'difblobdetails'];
+table_difblob=[acq.name 'difblob'];
+table_difblobinfo=[acq.name 'difblobinfo'];
+
+mym(dbInsert(table_difblobinfo,'StartIndex',first,'EndIndex',last))
+
+
+tic
+
+for ndx=1:length(allspots)
+  z=allspots{ndx}(:,1);
+%  keyboard
+  if length(z)==1
+    if z~=first && z~=last
+      disp('ignoring single voxel blob')
+      % skip this blob if it is in the middle of the chunk and only a single
+      % voxel
+      continue
+    end
+  end
+
+  [y,x]=ind2sub(siz,allspots{ndx}(:,2));
+  vals=allspots{ndx}(:,3);
+
+  disp(sprintf('Blob: %d/%d - inserting %d rows\n\r',ndx,length(allspots),length(x)))
+  % get a new difblobID
+  mym(dbInsert(table_difblob,'difblobID',0))
+  difblobID=mym('select last_insert_id()');
+  if 1 % FAST method
+    mym(dbInsertMultiple(table_difblobdetails,...
+      'difblobID',repmat(difblobID,1,length(x)),...
+      'xIndex',x,...
+      'yIndex',y,...
+      'zIndex',z,...
+      'graylevel',vals));
+  else  % SLOW method
+    chunk=100;
+    for first=1:chunk:length(x)
+      last=first+chunk-1;
+      if last>length(x)
+        last=length(x);
+      end
+      mym(dbInsertMultiple(table_difblobdetails,...
+        'difblobID',repmat(difblobID,1,last-first+1),...
+        'xIndex',x(first:last),...
+        'yIndex',y(first:last),...
+        'zIndex',z(first:last),...
+        'graylevel',vals(first:last)));
+    end
+  end
+end
+toc
+
+%%
+end
+
diff --git a/2_segment_difspot/gtSegmentDiffractionBlobs_ak.m b/2_segment_difspot/gtSegmentDiffractionBlobs_ak.m
new file mode 100755
index 0000000000000000000000000000000000000000..9ba90a12c87d099341b340c2802eeac10e665bc3
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionBlobs_ak.m
@@ -0,0 +1,170 @@
+function gtSegmentDiffractionBlobs(first,last,workingdirectory)
+  %latest version, writes blobs to database as it finds them to ease
+  %database traffic.
+
+
+
+  warning('off','Images:initSize:adjustingMag');
+
+  if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end % special case for running interactively in current directory
+
+  if ~exist('workingdirectory','var')
+    workingdirectory=pwd;
+  end
+
+  fprintf('Changing directory to %s\n',workingdirectory)
+  cd(workingdirectory)
+
+
+
+  parameters=[];
+  load parameters parameters
+  acq=parameters.acq;
+  seg=parameters.seg;
+
+  % duplicating one slice with the next chunk - unless this is the last job
+  if strcmp(acq.type, '180degree') || strcmp(acq.type, '180')
+      nimages=acq.nproj;
+  elseif strcmp(acq.type, '360degree') || strcmp(acq.type, '360')
+      nimages=acq.nproj*2;
+  else
+      nimages=Inf;
+  end
+  %note images numbered 0 - 7199 for example
+  last=min(last+1, nimages-1);
+  
+  
+  disp(sprintf(' ~~~  This Job: Image %d to %d, for %s  ~~~   ',first,last,workingdirectory))
+  disp('THIS DOES NOT WRAP OVER THE END OF THE DATASET PROPERLY!')
+
+  % read the size of one image to make an estimate for the number we can read
+  % at once:
+  test=pfReadAndThreshold_SubtractMedian(first,seg);
+  details=whos('test');
+  maxmemoryusage=100;  % in MB
+  step=floor(maxmemoryusage*1024*1024/details.bytes);
+
+  % open database
+  gtDBConnect
+
+  siz=[2048 2048];
+ 
+  table_difblobdetails=[acq.name 'difblobdetails'];
+  table_difblob=[acq.name 'difblob'];
+  table_difblobinfo=[acq.name 'difblobinfo'];
+  
+  
+
+  allspotsndx=0;
+  for currentfilendx=first:step:last
+    disp(['current file ndx: ' num2str(currentfilendx)])
+    step=min(step,last-currentfilendx+1);
+
+    fprintf('Reading %d images (~%dMB) in this chunk\n',step,round(step*details.bytes/1024/1024));
+    shortvol=zeros(2048,2048,step);
+    %add a median filter to de-noise the thresholded images
+    for n=1:step
+      im=pfReadAndThreshold_SubtractMedian(currentfilendx+n-1,seg);
+      shortvol(:,:,n)=medfilt2(im);
+    end
+
+    labels=bwlabeln(shortvol);
+    numlabels=max(labels(:));
+    for ndx=1:numlabels  % iterate over all the blobs
+      %tic
+      ind=find(labels==ndx);
+      if length(ind)<10  % discard small blobs
+        %disp('skipping small blob')
+        % toc
+        continue
+      end
+      allspotsndx=allspotsndx+1;
+      %fprintf('Blob: %d/%d Agglomerated blob: %d\n',ndx,numlabels,allspotsndx);
+      grayvals=shortvol(ind);
+      [i,j,k]=ind2sub(size(shortvol),ind);
+      k=k+currentfilendx-1;  % offset shortvol
+      ind2D=sub2ind(size(shortvol(:,:,1)),i,j);
+
+      % now record the blob
+      allspots{allspotsndx}=[];
+      for z=min(k):max(k) % iterate over all slices for this blob
+        howmanyinz=length(find(k==z));
+        allspots{allspotsndx}=[allspots{allspotsndx};
+          [repmat(z,[howmanyinz 1]) ind2D(k==z) grayvals(k==z)]];
+      end
+      if currentfilendx>first
+        if any(k==currentfilendx)  % blob is at top of sub volume
+          % look through all spots to find ones touching bottom of previous
+          % subvolume
+          q=1;
+          while (true)
+            if (~isempty(allspots{q}) && any(allspots{q}(:,1)==currentfilendx-1))
+              if intersect(allspots{q}(:,2),allspots{allspotsndx}(:,2))
+                % disp('Merging spots');
+                allspots{q}=union(allspots{q},allspots{allspotsndx},'rows');
+                allspots={allspots{1:allspotsndx-1}};  % drop that last one
+                allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+              end
+            end
+            q=q+1;
+            if q>allspotsndx-1  % list has been shortened - if we're at the end, get out
+              break
+            end
+          end
+        end
+      end
+    end
+    if currentfilendx+step <last
+      % write all completed blobs to database and erase from cell array
+      for qwe=1:length(allspots)
+        if (~isempty(allspots{qwe}) && max(allspots{qwe}(:,1)) < currentfilendx-1)
+          % this blob is finished - write it out
+          sfDBWriteBlob(allspots{qwe})
+          disp(['clearing out blob ' num2str(qwe)])
+          allspots{qwe}=[];
+        end
+      end
+    else
+      disp('Writing at the end of the loop')
+      % write all of them
+      for qwe=1:length(allspots)
+        if ~isempty(allspots{qwe})
+          sfDBWriteBlob(allspots{qwe})
+          allspots{qwe}=[];
+        end
+      end
+    end
+  end
+
+  % finished processing - update the chunk table
+  mym(dbInsert(table_difblobinfo,'StartIndex',first,'EndIndex',last))
+
+
+  function sfDBWriteBlob(blob)
+
+    zz=blob(:,1);
+    if length(zz)>seg.minsize
+%should only proceed if the blob is bigger than the minimum size defined in
+%the parameters file
+    [yy,xx]=ind2sub(siz,blob(:,2));
+    vals=blob(:,3);
+
+    % get a new difblobID
+    mym(dbInsert(table_difblob,'difblobID',0))
+    difblobID=mym('select last_insert_id()');
+    disp(sprintf('***DB WRITE *** Blob %d:inserting %d rows\n\r',difblobID,length(xx)))
+
+    dbInsertMultiple(table_difblobdetails,...
+      'difblobID',repmat(difblobID,1,length(xx)),...
+      'xIndex',xx,...
+      'yIndex',yy,...
+      'zIndex',zz,...
+      'graylevel',vals);
+    end
+
+  end
+end
+
diff --git a/2_segment_difspot/gtSegmentDiffractionBlobs_sab.m b/2_segment_difspot/gtSegmentDiffractionBlobs_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..14dcf406fcf9a98e471de69e31df0e728ea082a3
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionBlobs_sab.m
@@ -0,0 +1,163 @@
+function gtSegmentDiffractionBlobs_sab(first,last,workingdirectory)
+  %latest version, writes blobs to database as it finds them to ease
+  %database traffic.
+
+
+
+  warning('off','Images:initSize:adjustingMag');
+
+  if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end % special case for running interactively in current directory
+
+  if ~exist('workingdirectory','var')
+    workingdirectory=pwd;
+  end
+
+  fprintf('Changing directory to %s\n',workingdirectory)
+  cd(workingdirectory)
+
+
+
+  parameters=[];
+  load parameters parameters
+  acq=parameters.acq;
+  seg=parameters.seg;
+
+  %disp('duplicating one slice with the next chunk')
+  last=last+1;
+  disp('Date: 22/5/2007')
+  disp(sprintf(' ~~~  This Job: Image %d to %d, for %s  ~~~   ',first,last,workingdirectory))
+  disp('THIS DOES NOT WRAP OVER THE END OF THE DATASET PROPERLY!')
+
+  % read the size of one image to make an estimate for the number we can read
+  % at once:
+  test=pfReadAndThreshold(first,seg);
+  details=whos('test');
+  maxmemoryusage=100;  % in MB
+  step=floor(maxmemoryusage*1024*1024/details.bytes);
+
+  % open database
+  gtDBConnect
+
+  siz=[2048 2048];
+  % modif sabine
+%   table_difblobdetails=[acq.name 'difblobdetails'];
+%   table_difblob=[acq.name 'difblob'];
+%   table_difblobinfo=[acq.name 'difblobinfo'];
+  
+  table_difblobdetails=[acq.name 'difblobdetails_test1'];
+  table_difblob=[acq.name 'difblob_test1'];
+  table_difblobinfo=[acq.name 'difblobinfo_test1'];
+
+  allspotsndx=0;
+  for currentfilendx=first:step:last
+    disp(['current file ndx: ' num2str(currentfilendx)])
+    step=min(step,last-currentfilendx+1);
+
+    fprintf('Reading %d images (~%dMB) in this chunk\n',step,round(step*details.bytes/1024/1024));
+    shortvol=zeros(2048,2048,step);
+    %add a median filter to de-noise the thresholded images
+    for n=1:step
+      im=pfReadAndThreshold(currentfilendx+n-1,seg);
+      shortvol(:,:,n)=medfilt2(im);
+    end
+
+    labels=bwlabeln(shortvol);
+    numlabels=max(labels(:));
+    for ndx=1:numlabels  % iterate over all the blobs
+      %tic
+      ind=find(labels==ndx);
+      if length(ind)<10  % discard small blobs
+        %disp('skipping small blob')
+        % toc
+        continue
+      end
+      allspotsndx=allspotsndx+1;
+      %fprintf('Blob: %d/%d Agglomerated blob: %d\n',ndx,numlabels,allspotsndx);
+      grayvals=shortvol(ind);
+      [i,j,k]=ind2sub(size(shortvol),ind);
+      k=k+currentfilendx-1;  % offset shortvol
+      ind2D=sub2ind(size(shortvol(:,:,1)),i,j);
+
+      % now record the blob
+      allspots{allspotsndx}=[];
+      for z=min(k):max(k) % iterate over all slices for this blob
+        howmanyinz=length(find(k==z));
+        allspots{allspotsndx}=[allspots{allspotsndx};
+          [repmat(z,[howmanyinz 1]) ind2D(k==z) grayvals(k==z)]];
+      end
+      if currentfilendx>first
+        if any(k==currentfilendx)  % blob is at top of sub volume
+          % look through all spots to find ones touching bottom of previous
+          % subvolume
+          q=1;
+          while (true)
+            if (~isempty(allspots{q}) && any(allspots{q}(:,1)==currentfilendx-1))
+              if intersect(allspots{q}(:,2),allspots{allspotsndx}(:,2))
+                % disp('Merging spots');
+                allspots{q}=union(allspots{q},allspots{allspotsndx},'rows');
+                allspots={allspots{1:allspotsndx-1}};  % drop that last one
+                allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+              end
+            end
+            q=q+1;
+            if q>allspotsndx-1  % list has been shortened - if we're at the end, get out
+              break
+            end
+          end
+        end
+      end
+    end
+    if currentfilendx+step <last
+      % write all completed blobs to database and erase from cell array
+      for qwe=1:length(allspots)
+        if (~isempty(allspots{qwe}) && max(allspots{qwe}(:,1)) < currentfilendx-1)
+          % this blob is finished - write it out
+          sfDBWriteBlob(allspots{qwe})
+          disp(['clearing out blob ' num2str(qwe)])
+          allspots{qwe}=[];
+        end
+      end
+    else
+      disp('Writing at the end of the loop')
+      % write all of them
+      for qwe=1:length(allspots)
+        if ~isempty(allspots{qwe})
+          sfDBWriteBlob(allspots{qwe})
+          allspots{qwe}=[];
+        end
+      end
+    end
+  end
+
+  % finished processing - update the chunk table
+  mym(dbInsert(table_difblobinfo,'StartIndex',first,'EndIndex',last))
+
+
+  function sfDBWriteBlob(blob)
+
+    zz=blob(:,1);
+    if length(zz)>seg.minsize
+%should only proceed if the blob is bigger than the minimum size defined in
+%the parameters file
+    [yy,xx]=ind2sub(siz,blob(:,2));
+    vals=blob(:,3);
+
+    % get a new difblobID
+    mym(dbInsert(table_difblob,'difblobID',0))
+    difblobID=mym('select last_insert_id()');
+    disp(sprintf('***DB WRITE *** Blob %d:inserting %d rows\n\r',difblobID,length(xx)))
+
+    dbInsertMultiple(table_difblobdetails,...
+      'difblobID',repmat(difblobID,1,length(xx)),...
+      'xIndex',xx,...
+      'yIndex',yy,...
+      'zIndex',zz,...
+      'graylevel',vals);
+    end
+
+  end
+end
+
diff --git a/2_segment_difspot/gtSegmentDiffractionSpots.m b/2_segment_difspot/gtSegmentDiffractionSpots.m
new file mode 100755
index 0000000000000000000000000000000000000000..2a49cbd780b4e310f1b7436313258b84c53b9a2e
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionSpots.m
@@ -0,0 +1,347 @@
+function gtSegmentDiffractionSpots(first,last,workingdirectory)
+% now using the database...
+% I changed the location of the full images, that seeems to be the new one,
+% only full instead of full_s5_dctX_ - - - - - Marcelo 04/12/06
+%modify so that image 0000.edf can be treated with errors - ak
+%Add display statements to keep track of things went submitted to condor
+%ak 4/2007 made some minor mods (search "ak" to see)
+
+warning('off','Images:initSize:adjustingMag');
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist(workingdirectory,'var')
+  workingdirectory=pwd;
+end
+fprintf('Changing directory to %s',workingdirectory)
+cd(workingdirectory);
+
+%create difspot directory if needed!
+  if~exist('2_difspot','dir')
+mkdir 2_difspot;
+  end
+  if~exist('2_difspot/difspot','dir')
+mkdir 2_difspot/difspot;
+  end
+  
+parameters=[];
+load parameters
+acq=parameters.acq;
+seg=parameters.seg;
+
+% define a full image with an extra margin of size seg.boxsize
+seg.zeroim=zeros([acq.ydet acq.xdet]+2*seg.boxsize);   
+
+
+%  seg.currentspot=1;  % still needed ?
+gtDBConnect
+
+%mym('open' ,'mysql.esrf.fr', 'gtuser','gtuser');
+%mym('use graintracking');
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Main Loop
+disp(sprintf(' ~~~~~~~~~~~~  This Job: Image %d to %d, for %s  ~~~~~~~~~~~~~~~   ',first,last,workingdirectory))
+for k=first:last   
+    seg.imnum=k;
+    % read and zeropad a new full image
+    fname=sprintf('1_preprocessing/full/full%04d.edf',seg.imnum);
+    disp(sprintf('now processing image %s',fname));
+    tmp=edf_read(fname);
+    seg.fullim=gtPlaceSubImage(tmp,seg.zeroim,seg.boxsize+1,seg.boxsize+1);
+	  % remove previously found spots from current image
+    seg.fullim=sfMaskSegmentedSpots(seg);   
+    % segment new difspot in currentimage
+    sfSegmentNewSpots(acq,seg);
+   disp(sprintf('End of main loop for image %d',k));
+    
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+
+%% sfMaskSegmentedSpots
+function masked_image=sfMaskSegmentedSpots(seg)
+   
+  % mask out the direct beam region
+   bb1=[seg.bb(1:2)+seg.boxsize,seg.bb(3:4)];
+   masked_image=gtPlaceSubImage(-10*ones(bb1(4),bb1(3)),seg.fullim,bb1(1),bb1(2));
+   
+   mysqlcmd=sprintf('select difspotID,BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where %d between StartImage and EndImage',acq.name,seg.imnum);
+   [index,bb(:,1),bb(:,2),bb(:,3),bb(:,4)]=mym(mysqlcmd);
+   
+  
+   for i=1:length(index)
+	   fname=sprintf('2_difspot/difspot/difspot%05d.edf',index(i));
+		 tmp=-edf_read(fname);
+     bb2=[bb(i,1:2)+seg.boxsize,bb(i,3:4)];
+	   masked_image=masked_image+gtPlaceSubImage(tmp,seg.zeroim,bb2(1),bb2(2));
+   end
+   
+   figure(1);imshow(masked_image,[-500 500]);
+   %drawnow;
+end
+
+
+%% sfSegmentNewSpots
+function sfSegmentNewSpots(acq,seg)
+	
+  % perform image reconstruction (double threshold) on current image
+	marker=seg.fullim>seg.th1;
+	mask=seg.fullim>seg.th2;
+	seg.imrec=imreconstruct(marker,mask);
+	seg.imrec=bwlabel(seg.imrec);
+	props=regionprops(seg.imrec,'Area','Centroid','BoundingBox');
+ 
+  if isempty(props)
+		disp(sprintf('No new spot in image %d',seg.imnum));
+    num=0;
+  else
+    num=0;
+		for i=1:length(props)
+    
+      if props(i).Area>seg.minsize
+%        spot.id=i; %redundant because then overwritten
+        spot=seg.spotstruct;  %reinitialize spot structure
+        spot=sfCopyStruct(props(i),spot);
+        spot.BoundingBox=ceil(spot.BoundingBox); %ak - I think this is okay for GTbb convention
+        spot.SumBox=sfIncreaseBB(seg,spot);    % increase the bounding box of current spot by +/-  seg.boxsize in all directions
+        
+        % initialize spot.marker and sum images
+        spot.maskOrig=gtCrop(ismember(seg.imrec,i),spot.SumBox);  
+        spot.SummedSpot=spot.maskOrig.*gtCrop(seg.fullim,spot.SumBox);
+        
+        spot=sfSumSpot(acq,seg,spot);
+        spot=sfCalculateSummedSpotProps(spot);
+        if ~isempty(spot)
+          sfSaveSpot(acq,seg,spot);
+          num=num+1;
+        end
+      end 
+    end % for
+  end %if
+
+  disp(sprintf('%d diffraction spots written',num));
+
+end 
+
+
+%% sfSumSpot
+ function spot=sfSumSpot(acq,seg,spot)     % 3D double threshold image reconstruction with a moving subvolume (2 slices)
+		
+   i=1;
+   direction=1;  % +1 in forward search; -1 during backward search
+   spot.Intensity=zeros(acq.nproj,1);  % allocate Intensity array
+   
+   spot.mask=spot.maskOrig;       
+   spot.Intensity(seg.imnum+1)=sum(spot.SummedSpot(:));  % initialise the spot intensity array, +1 to avoid zero image problem
+       
+   checknext=1;
+   
+   while checknext
+      n=seg.imnum+i*direction;  %look at image number n
+      if (n>(acq.nproj-1) || n< 0)
+        break;
+      elseif (abs(n-seg.imnum)>seg.range)
+         disp('summation abandonned: maximum range exceeded');
+         break;
+      end
+      fname=sprintf('1_preprocessing/full/full%04d.edf',n);
+     
+      
+      %spot.fullim=edf_read(fname);
+      %spot.fullim=gtPlaceSubImage(spot.fullim,seg.zeroim,seg.boxsize+1,seg.boxsize+1);
+      % mask out the direct beam region
+      %bb=[seg.bb(1:2)+seg.boxsize,seg.bb(3:4)];
+      %spot.fullim=gtPlaceSubImage(-10*ones(bb(4),bb(3)),seg.fullim,bb(1),bb(2));
+      %spot.cropim=gtCrop(seg.fullim,spot.SumBox);
+      
+      check_bb=1;
+      while check_bb
+        bb=[spot.SumBox(1:2)-seg.boxsize,spot.SumBox(3:4)]; %new image is not zero padded hence -boxsize
+        spot.cropim=gt_edf_read(fname,bb);
+      %ak - would it be better to use only the part >th1 as the marker? -
+      %might reduce overlaps
+        spot.marker(:,:,1)=spot.mask;                   % use the spot outline in the current slice as spot.marker
+        spot.marker(:,:,2)=0;                                     % add an empty slice
+        spot.mask(:,:,1)=spot.mask;
+        spot.mask(:,:,2)=spot.cropim>seg.th2;
+        spot.mask=imreconstruct(spot.marker,spot.mask);
+        props=regionprops(double(spot.mask(:,:,2)),'BoundingBox');
+        if ~isempty(props)
+          spot.BoundingBox=ceil(props.BoundingBox);
+          [spot,check_bb]=sfCheckBoundingBox(seg,spot);
+        else
+          check_bb=0;
+          spot.mask=spot.mask(:,:,2);
+        end  
+      end
+      
+      
+      spot.Intensity(n+1)=sum(sum(spot.mask.*spot.cropim));   % the spot intensity in the new image
+      
+      if spot.Intensity(n+1)<seg.minint
+        if direction==1   % reverse direction
+          direction=-1;   % and restart the procedure in the other direction
+          i=1;
+          spot.mask=spot.maskOrig;    
+        else
+          checknext=0;
+        end  
+      else
+        spot.SummedSpot=spot.SummedSpot+(spot.mask.*spot.cropim); %ak -- i reckon this should be .*spot.mask
+        i=i+1;
+      end
+    end %while
+ end
+
+
+
+%% sfCheckBoundingBox
+	function [spot,check_bb]=sfCheckBoundingBox(seg,spot)
+		check_bb=0;
+		if spot.BoundingBox(1)==1
+			spot.SumBox(1)=spot.SumBox(1)-seg.boxsize;
+		  spot.SumBox(3)=spot.SumBox(3)+seg.boxsize;
+      spot.extramargin=[seg.boxsize,0,0,0];
+      check_bb=1; 
+		elseif spot.BoundingBox(2)==1
+			spot.SumBox(2)=spot.SumBox(2)-seg.boxsize;
+			spot.SumBox(4)=spot.SumBox(4)+seg.boxsize;
+      spot.extramargin=[0,seg.boxsize,0,0];
+	    check_bb=1;
+		elseif (spot.BoundingBox(1)+spot.BoundingBox(3)-1)==spot.SumBox(3)
+			spot.SumBox(3)=spot.SumBox(3)+seg.boxsize;
+      spot.extramargin=[0,0,seg.boxsize,0];
+      check_bb=1;
+    elseif (spot.BoundingBox(2)+spot.BoundingBox(4)-1)==spot.SumBox(4)
+      spot.SumBox(4)=spot.SumBox(4)+seg.boxsize;
+			spot.extramargin=[0,0,0,seg.boxsize];
+      check_bb=1;
+    end
+
+    if check_bb==1
+			disp('update BoundingBox');
+      spot.mask=logical(sfZeroPad(spot.mask(:,:,1),spot.extramargin));
+      spot.marker=logical(zeros(size(spot.mask)));
+      spot.SummedSpot=sfZeroPad(spot.SummedSpot,spot.extramargin);
+      spot.maskOrig=logical(sfZeroPad(spot.maskOrig,spot.extramargin));
+    else
+      spot.mask=spot.mask(:,:,2);
+    end	
+					
+  end
+   
+%% sfZeroPad
+  function impad=sfZeroPad(im,margin)
+    [m,n]=size(im);
+    width=n+margin(1)+margin(3);
+    height=m+margin(2)+margin(4);
+    impad=zeros(height,width);
+    impad=gtPlaceSubImage(im,impad,margin(1)+1,margin(2)+1);
+  end  
+
+
+%% sfFindIntegrationRange
+  function spot=sfFindIntegrationRange(spot)
+    spot.Integral=cumsum(spot.Intensity);
+    spot.StartImage=(find(spot.Intensity,1,'first'))-1;  %-1 to adjust for +1 at line 129, avoiding zero image index problem
+    spot.EndImage=(find(spot.Intensity,1,'last'))-1;   % -1
+    spot.ExtStartImage=(find(spot.Integral>seg.icut*spot.Integral(end),1,'first'))-1;   % -1, ak- change hard code to seg.icut
+    spot.ExtEndImage=(find(spot.Integral>(1-seg.icut)*spot.Integral(end),1,'first'))-1;   % -1
+    spot.MaxImage=(find(spot.Intensity==max(spot.Intensity)))-1;   % -1
+    spot.Integral=spot.Integral(end);
+  end
+
+
+%% sfcalculateSummedSpotProps
+function spot=sfCalculateSummedSpotProps(spot)   %
+  
+    spot=sfFindIntegrationRange(spot);
+  
+    th=(spot.EndImage-spot.StartImage)*seg.th2;  %ak what is this - surely we want to continue to use th2 here?
+    spot.mask=spot.SummedSpot>th; %0.05*max(spot.SummedSpot(:));
+%    spot.mask=spot.SummedSpot>seg.th2; %ak - try it...
+%spot.mask=(spot.mask+spot.maskOrig)>0;   % replace image reconstruction by edge detection and Watershed Segemntation here ?
+    
+spot.Outline=imreconstruct(spot.maskOrig&spot.mask,spot.mask);
+    spot.Outline=bwmorph(spot.Outline,'dilate',1);
+    spot.SummedSpot=spot.Outline.*spot.SummedSpot;
+    
+    tmp=gtPlaceSubImage(spot.SummedSpot,seg.zeroim,spot.SumBox(1),spot.SumBox(2));
+    props=regionprops(double(tmp>0),'Area','BoundingBox','Centroid');
+      
+    if ~isempty(props)
+      spot.SummedSpot=gtCrop(tmp,ceil(props.BoundingBox));
+      props.BoundingBox=[ceil(props.BoundingBox(1:2)-seg.boxsize),props.BoundingBox(3:4)];
+      props.Centroid=props.Centroid-seg.boxsize;
+      spot=sfCopyStruct(props,spot);
+    else
+      spot=[];
+    end  
+end   
+
+
+
+%% sfCopyStruct
+    function to=sfCopyStruct(from,to,varargin)
+        switch nargin
+          case 2
+            names=fieldnames(from);
+          case 3
+            names=varargin{:};
+        end
+        for i=1:length(names)
+            to=setfield(to,names{i},getfield(from,names{i}));
+        end
+    end    
+
+
+%% sfIncreaseBB
+% use a Bounding Box of +/- seg.boxsize
+function bb=sfIncreaseBB(seg,spot)
+  bb(1:2)= spot.BoundingBox(1:2)-seg.boxsize;      
+  bb(3:4)= spot.BoundingBox(3:4)+2*seg.boxsize;
+end  
+
+%% sfSaveSpot
+  function spotID=sfSaveSpot(acq,seg,spot)
+    
+    tblname=sprintf('%sdifspot',acq.name);
+   
+      % ak - before doing insert... check for duplication
+%   mysqlcmd=sprintf(['select difspotID from %s where MaxImage=%d and '...
+%      'abs(BoundingBoxXorigin-%d)<5 and abs(BoundingBoxYorigin-%d)<5 and '...
+%    'abs(BoundingBoxXsize-%d)<5 and abs(BoundingBoxYsize-%d)<5'],...
+%    tblname,spot.MaxImage,spot.BoundingBox(1),...
+%    spot.BoundingBox(2),spot.BoundingBox(3),spot.BoundingBox(4));
+%  duplicates=mym(mysqlcmd);
+%  if ~isempty(duplicates)
+%    keyboard
+%  end
+    
+    colnames=seg.dbfields;
+    values=[[spot.Area]', [spot.Centroid(1)]',[spot.Centroid(2)]',[spot.BoundingBox(1)]',[spot.BoundingBox(2)]',...
+      [spot.BoundingBox(3)]',[spot.BoundingBox(4)]',[spot.Integral]',[spot.StartImage]',[spot.EndImage]',[spot.MaxImage]',...
+      [spot.ExtStartImage]',[spot.ExtEndImage]'];
+     
+    cmd=dbInsert(tblname,colnames,values);
+    mym(cmd);
+    % get back the ID's written - currently only one
+    mysqlcmd=sprintf('select last_insert_id()');
+    spotID=mym(mysqlcmd);
+    %keyboard
+    fname=sprintf('2_difspot/difspot/difspot%05d.edf',spotID);
+    disp(sprintf('writing %s',fname)); 
+    edf_write(spot.SummedSpot,fname,'uint16');
+  end
+
+end
+      
\ No newline at end of file
diff --git a/2_segment_difspot/gtSegmentDiffractionSpots_3D.m b/2_segment_difspot/gtSegmentDiffractionSpots_3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..54af75b511514f7ed6ac2807ba1933683a512bfd
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionSpots_3D.m
@@ -0,0 +1,151 @@
+%segment difspot 3D...  treat series of radiographs as a volume (sinogram
+%style).  Then segment difspots as connected objects in this volume.  
+%Will need a script to treat spots at the edges of volumes.
+
+function gtSegmentDifspots3D(first, last, workingdir)
+
+cd(workingdir)
+load parameters
+acq=parameters.acq;
+seg=parameters.seg;
+
+%prepare vol
+vol=zeros(acq.ydet, acq.xdet, (last-first+1));
+%read slices
+for i=first:last
+  vol(:,:,i-first+1)=edf_read(sprintf('1_preprocessing/full/full%04d.edf',i));
+end
+
+%set central area around direct beam to -10
+vol(seg.bb(2):seg.bb(2)+seg.bb(4), seg.bb(1):seg.bb(1)+seg.bb(3), :)=-10;
+
+%label spot nuclei
+vol_nuclei = bwlabeln(vol>seg.th1);
+
+%go through nuclei, finding those greater than a minimum volume
+seg.minvol=100;
+
+for i=1:max(vol_nuclei(:))
+  progress=100*i/max(vol_nuclei(:))
+  if length(find(vol_nuclei))>seg.minvol
+  
+    %select this nucleus
+    vol_marker_big=double(vol_nuclei==i);
+    %imreconstruct is slow... so work on a subvolume
+    props=regionprops(vol_marker_big,'Centroid');
+    Centroid=props.Centroid;
+    Centroid=ceil(Centroid);
+    %first guess at crop limits
+    rstart=Centroid(2)-seg.boxsize;
+    cstart=Centroid(1)-seg.boxsize;
+    rend=Centroid(2)+seg.boxsize;
+    cend=Centroid(1)+seg.boxsize;
+    omstart=Centroid(3)-10;
+    omend=Centroid(3)+10;
+    
+    checkbb=1;
+    while checkbb==1
+      checkbb=0;
+      %check crop limits don't exceed volume
+      rstart=max(rstart,1);
+      cstart=max(cstart,1);
+      rend=min(rend,acq.xdet);
+      cend=min(cend,acq.ydet);
+      omstart=max(omstart,first+1);
+      omend=min(omend,last+1);
+      
+    vol_marker=vol_marker_big(rstart:rend, cstart:cend, omstart:omend);
+    vol_crop=vol(rstart:rend, cstart:cend, omstart:omend);
+    vol_mask=double(vol_crop>seg.th2);
+    vol_recon=imreconstruct(vol_marker, vol_mask);
+
+    %test - is bounding box big enough (in x-y) ? 
+    props=regionprops(vol_recon, 'BoundingBox', 'Centroid');
+    bb=ceil(props.BoundingBox);
+    if bb(1)==1 & cstart~=1 
+    cstart=cstart-seg.boxsize;
+    checkbb=1;
+    end
+    if bb(2)==1 & rstart~=1 
+    rstart=rstart-seg.boxsize;
+    checkbb=1;
+    end
+    if bb(1)+bb(4)==cend-cstart+1 & cend~=acq.ydet 
+    cend=cend+seg.boxsize;
+    checkbb=1;
+    end
+    if bb(2)+bb(5)==rend-rstart+1 & rend~=acq.xdet 
+    rend=rend+seg.boxsize;
+    checkbb=1;
+    end
+    if bb(3)+bb(6)==omend-omstart+1 & omend~=last+1
+      checkbb=1;
+      omend=omend+10;
+    end
+    if bb(3)==1 & omstart~=first+1
+      checkbb=1;
+      omstart=omstart-10;
+    end
+    
+    %does spot touch the ends of the subvolume (in omega, 3rd dimension)
+    if bb(3)+bb(6)==last-first+1
+      disp('touches at high omega!')
+      %write a single image as a marker to pass run on the next volume
+    end
+    if bb(3)==1
+      disp('touches at low omega!')
+      %write a single image as a marker to pass to the next volume
+    end
+    
+    end %of the while loop
+      
+    %Sum image for difspot,
+    vol_crop=vol_crop.*vol_recon;
+    spot.image=sum(vol_crop,3);
+    
+    tmp=spot.image>0;
+    spot.Area=sum(tmp(:)>0)
+    
+    %get intensity profile for start/end/extstart/etc data
+    spot.Intensity=sum(vol_crop,1);
+    spot.Intensity=sum(spot.Intensity,2);
+    spot.Intensity=squeeze(spot.Intensity);
+    spot.Integral=cumsum(spot.Intensity);
+
+    spot.StartImage=(find(spot.Integral,1,'first'))-1+omstart;  %-1 to adjust for +1 at line 129, avoiding zero image index problem
+    spot.EndImage=(find(spot.Integral,1,'last'))-1+omstart;   % -1
+    spot.ExtStartImage=(find(spot.Integral>seg.icut*spot.Integral(end),1,'first'))-1+omstart;   % -1, ak- change hard code to seg.icut
+    spot.ExtEndImage=(find(spot.Integral>(1-seg.icut)*spot.Integral(end),1,'first'))-1+omstart;   % -1
+    spot.MaxImage=(find(spot.Intensity==max(spot.Intensity)))-1+omstart;   % -1
+    spot.Integral=spot.Integral(end);
+
+    %get spot Centroid, BoundingBox, Start etc in correct coordinates
+    spot.Centroid=props.Centroid(1,2)+[rstart-1, cstart-1];
+    spot.BoundingBox=props.BoundingBox([1,2,4,5])+[rstart-1 cstart-1 0 00];
+    %save the spot    
+    tblname=sprintf('%stest_difspot',acq.name);
+
+    colnames=seg.dbfields;
+    values=[[spot.Area]', [spot.Centroid(1)]',[spot.Centroid(2)]',[spot.BoundingBox(1)]',[spot.BoundingBox(2)]',...
+      [spot.BoundingBox(3)]',[spot.BoundingBox(4)]',[spot.Integral]',[spot.StartImage]',[spot.EndImage]',[spot.MaxImage]',...
+      [spot.ExtStartImage]',[spot.ExtEndImage]'];
+     
+    cmd=dbInsert(tblname,colnames,values);
+    mym(cmd);
+    % get back the ID's written - currently only one
+    mysqlcmd=sprintf('select last_insert_id()');
+    spotID=mym(mysqlcmd);
+    %keyboard
+    fname=sprintf('2_difspot/difspot/difspot_A_%05d.edf',spotID);
+    disp(sprintf('writing %s',fname)); 
+    edf_write(spot.image,fname,'uint16');
+    
+    
+  end
+    
+  end
+  
+
+
+
+
diff --git a/2_segment_difspot/gtSegmentDiffractionSpots_3D_2.m b/2_segment_difspot/gtSegmentDiffractionSpots_3D_2.m
new file mode 100755
index 0000000000000000000000000000000000000000..22ddfbce014f2763217217b1fd885e7b8cdf4372
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionSpots_3D_2.m
@@ -0,0 +1,473 @@
+function vol=gtSegmentDiffractionSpots(first,last,workingdirectory)
+% now using the database...
+% I changed the location of the full images, that seeems to be the new one,
+% only full instead of full_s5_dctX_ - - - - - Marcelo 04/12/06
+%modify so that image 0000.edf can be treated with errors - 
+%Add display statements to keep track of things went submitted to condor
+%ak 4/2007 made some minor mods (search "ak" to see)
+
+%try adding a feature to separate overlapping spots by a watershed...
+%save the 3D x-y-omega volume as the spot is summed.  If the final volume
+%looks dodgy (threshold -> more than one object) can go to a 3D treatment
+%for a second attempt.  
+%All summed properties/images can be taken directly off the greyscale
+%volume in a final step.
+
+warning('off','Images:initSize:adjustingMag');
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist(workingdirectory,'var')
+  workingdirectory=pwd;
+end
+cd(workingdirectory);
+
+%create difspot directory if needed!
+  if~exist('2_difspot','dir')
+mkdir 2_difspot;
+  end
+  if~exist('2_difspot/difspot','dir')
+mkdir 2_difspot/difspot;
+  end
+  
+parameters=[];
+load parameters
+acq=parameters.acq;
+seg=parameters.seg;
+
+% define a full image with an extra margin of size seg.boxsize
+seg.zeroim=zeros([acq.ydet acq.xdet]+2*seg.boxsize);   
+
+
+%  seg.currentspot=1;  % still needed ?
+gtDBConnect
+
+%mym('open' ,'mysql.esrf.fr', 'gtuser','gtuser');
+%mym('use graintracking');
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Main Loop
+disp(sprintf(' ~~~~~~~~~~~~  This Job: Image %d to %d, for %s  ~~~~~~~~~~~~~~~   ',first,last,workingdirectory))
+for k=first:last   
+    seg.imnum=k;
+    % read and zeropad a new full image
+    fname=sprintf('1_preprocessing/full/full%04d.edf',seg.imnum);
+    disp(sprintf('now processing image %s',fname));
+    tmp=edf_read(fname);
+    seg.fullim=gtPlaceSubImage(tmp,seg.zeroim,seg.boxsize+1,seg.boxsize+1);
+	  % remove previously found spots from current image
+    seg.fullim=sfMaskSegmentedSpots(seg);   
+    % segment new difspot in currentimage
+    sfSegmentNewSpots(acq,seg);
+   disp(sprintf('End of main loop for image %d',k));
+    
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+
+%% sfMaskSegmentedSpots
+function masked_image=sfMaskSegmentedSpots(seg)
+   
+  % mask out the direct beam region
+   bb1=[seg.bb(1:2)+seg.boxsize,seg.bb(3:4)];
+   masked_image=gtPlaceSubImage(-10*ones(bb1(4),bb1(3)),seg.fullim,bb1(1),bb1(2));
+   
+   mysqlcmd=sprintf('select difspotID,BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where %d between StartImage and EndImage',acq.name,seg.imnum);
+   [index,bb(:,1),bb(:,2),bb(:,3),bb(:,4)]=mym(mysqlcmd);
+   
+  
+ %  for i=1:length(index)
+%	   fname=sprintf('2_difspot/difspot/difspot%05d.edf',index(i));
+%		 tmp=-edf_read(fname);
+ %    bb2=[bb(i,1:2)+seg.boxsize,bb(i,3:4)];
+%	   masked_image=masked_image+gtPlaceSubImage(tmp,seg.zeroim,bb2(1),bb2(2));
+%   end
+   
+   figure(1);imshow(masked_image,[-500 500]);
+   %drawnow;
+end
+
+
+%% sfSegmentNewSpots
+function sfSegmentNewSpots(acq,seg)
+	
+  % perform image reconstruction (double threshold) on current image
+	marker=seg.fullim>seg.th1;
+	mask=seg.fullim>seg.th2;
+	seg.imrec=imreconstruct(marker,mask);
+  
+  keyboard
+  
+	seg.imrec=bwlabel(seg.imrec);
+	props=regionprops(seg.imrec,'Area','Centroid','BoundingBox');
+ 
+  if isempty(props)
+		disp(sprintf('No new spot in image %d',seg.imnum));
+    num=0;
+  else
+    num=0;
+		for i=1:length(props)
+    
+      if props(i).Area>seg.minsize
+%        spot.id=i; %redundant because then overwritten
+        spot=seg.spotstruct;  %reinitialize spot structure
+        spot=sfCopyStruct(props(i),spot);
+        spot.BoundingBox=ceil(spot.BoundingBox); 
+        spot.SumBox=sfIncreaseBB(seg,spot);    % increase the bounding box of current spot by +/-  seg.boxsize in all directions
+        
+        % initialize spot.marker and sum images
+        spot.maskOrig=gtCrop(ismember(seg.imrec,i),spot.SumBox);  
+        spot.SummedSpot=spot.maskOrig.*gtCrop(seg.fullim,spot.SumBox);
+       
+        %save the gregscale image.  This will become a greyscale volume
+        spot.GreyVol= spot.SummedSpot;
+        spot.GreyVolBox=[spot.SumBox(1:2) seg.imnum spot.SumBox(3:4) 1];
+        
+        %sum the spot across adjacent images...
+        spot=sfSumSpot(acq,seg,spot);
+        
+        %crop the accumulated greyscale volume here
+        [spot.GreyVol, spot.GreyVolBox]=sfCropVol(spot.GreyVol, spot.GreyVolBox);
+        
+        %check for overlapping spots here, and if neccessary break the spot
+        %up into components using a watershed/other system
+        spot=sfSpotCracker(spot,seg)
+       
+        %calculate summed properties, save the spot
+        if ~isempty(spot)
+          numAdded=sfSaveSpot(acq,seg,spot);
+          num=num+numAdded;
+        end
+      end 
+    end % for
+  end %if
+
+  disp(sprintf('%d diffraction spots written',num));
+
+end 
+
+
+%% sfSumSpot
+ function spot=sfSumSpot(acq,seg,spot)     % 3D double threshold image reconstruction with a moving subvolume (2 slices)
+		
+   i=1;
+   direction=1;  % +1 in forward search; -1 during backward search
+   
+   spot.mask=spot.maskOrig;       
+       
+   checknext=1;
+   
+   while checknext
+      n=seg.imnum+i*direction;  %look at image number n
+      if (n>(acq.nproj-1) || n< 0)
+        break;
+      elseif (abs(n-seg.imnum)>seg.range)
+         disp('summation abandonned: maximum range exceeded');
+         break;
+      end
+      fname=sprintf('1_preprocessing/full/full%04d.edf',n);
+      
+      check_bb=1;
+      while check_bb
+        bb=[spot.SumBox(1:2)-seg.boxsize,spot.SumBox(3:4)]; %new image is not zero padded hence -boxsize
+        spot.cropim=gt_edf_read(fname,bb);
+  
+        %change this to a set operation / bwlabel...
+        
+        
+        spot.marker(:,:,1)=spot.mask;                   % use the spot outline in the current slice as spot.marker
+        spot.marker(:,:,2)=0;                                     % add an empty slice
+        spot.mask(:,:,1)=spot.mask;
+        spot.mask(:,:,2)=spot.cropim>seg.th2;
+        spot.mask=imreconstruct(spot.marker,spot.mask);
+        props=regionprops(double(spot.mask(:,:,2)),'BoundingBox');
+        if ~isempty(props)
+          spot.BoundingBox=ceil(props.BoundingBox);
+          [spot,check_bb]=sfCheckBoundingBox(seg,spot);
+        else
+          check_bb=0;
+          spot.mask=spot.mask(:,:,2);
+        end  
+      end
+      
+      
+      spot.Intensity=sum(sum(spot.mask.*spot.cropim));   % the spot intensity in the new image
+      
+      if spot.Intensity<seg.minint
+        if direction==1   % reverse direction
+          direction=-1;   % and restart the procedure in the other direction
+          i=1;
+          spot.mask=spot.maskOrig;    
+        else
+          checknext=0;
+        end  
+      else
+        %add the new greyscale slice to the volume (also use the mask.*cropim)
+        spot=sfAddSlice(spot,direction); %just store the volume, not the image
+        i=i+1;
+      end
+    end %while
+ end
+
+
+
+%% sfCheckBoundingBox
+	function [spot,check_bb]=sfCheckBoundingBox(seg,spot)
+		check_bb=0;
+		if spot.BoundingBox(1)==1
+			spot.SumBox(1)=spot.SumBox(1)-seg.boxsize;
+		  spot.SumBox(3)=spot.SumBox(3)+seg.boxsize;
+      spot.extramargin=[seg.boxsize,0,0,0];
+      check_bb=1; 
+		elseif spot.BoundingBox(2)==1
+			spot.SumBox(2)=spot.SumBox(2)-seg.boxsize;
+			spot.SumBox(4)=spot.SumBox(4)+seg.boxsize;
+      spot.extramargin=[0,seg.boxsize,0,0];
+	    check_bb=1;
+		elseif (spot.BoundingBox(1)+spot.BoundingBox(3)-1)==spot.SumBox(3)
+			spot.SumBox(3)=spot.SumBox(3)+seg.boxsize;
+      spot.extramargin=[0,0,seg.boxsize,0];
+      check_bb=1;
+    elseif (spot.BoundingBox(2)+spot.BoundingBox(4)-1)==spot.SumBox(4)
+      spot.SumBox(4)=spot.SumBox(4)+seg.boxsize;
+			spot.extramargin=[0,0,0,seg.boxsize];
+      check_bb=1;
+    end
+
+    if check_bb==1
+			disp('update BoundingBox');
+      spot.mask=logical(sfZeroPad(spot.mask(:,:,1),spot.extramargin));
+      spot.marker=logical(zeros(size(spot.mask)));
+      %spot.SummedSpot=sfZeroPad(spot.SummedSpot,spot.extramargin);
+      spot.maskOrig=logical(sfZeroPad(spot.maskOrig,spot.extramargin));
+     
+      %zero pad the volume in the same way
+      spot.GreyVol=sfZeroPadVol(spot.GreyVol,spot.extramargin);
+    else
+      spot.mask=spot.mask(:,:,2);
+    end	
+					
+  end
+   
+%% sfZeroPad
+  function impad=sfZeroPad(im,margin)
+    [m,n]=size(im);
+    width=n+margin(1)+margin(3);
+    height=m+margin(2)+margin(4);
+    impad=zeros(height,width);
+    impad=gtPlaceSubImage(im,impad,margin(1)+1,margin(2)+1);
+  end  
+
+%% sfZeroPadVol
+  function volpad = sfZeroPadVol(vol,margin)
+    [m,n,o]=size(vol);
+    width=n+margin(1)+margin(3);
+    height=m+margin(2)+margin(4);
+    volpad=zeros(height,width,o);
+    volpad(margin(2)+1:margin(2)+m, margin(1)+1:margin(1)+n, 1:end)=vol;
+  end
+
+    
+
+
+
+%% sfCopyStruct
+    function to=sfCopyStruct(from,to,varargin)
+        switch nargin
+          case 2
+            names=fieldnames(from);
+          case 3
+            names=varargin{:};
+        end
+        for i=1:length(names)
+            to=setfield(to,names{i},getfield(from,names{i}));
+        end
+    end    
+
+
+%% sfIncreaseBB
+% use a Bounding Box of +/- seg.boxsize
+function bb=sfIncreaseBB(seg,spot)
+  bb(1:2)= spot.BoundingBox(1:2)-seg.boxsize;      
+  bb(3:4)= spot.BoundingBox(3:4)+2*seg.boxsize;
+end  
+
+%% sfAddSlice
+%add a slice to the greyscale volume, update the GreyVolBox
+  function spot=sfAddSlice(spot, direction)
+    vol=spot.GreyVol;
+    slice=spot.mask.*spot.cropim;
+    if direction == 1
+      vol=cat(3,vol,slice);
+      spot.GreyVolBox(6)=spot.GreyVolBox(6)+1;
+    else
+      vol=cat(3,slice,vol);
+      spot.GreyVolBox(3)=spot.GreyVolBox(3)-1;
+    end
+    spot.GreyVol=vol;
+  end
+
+%% sfCropVol
+%crop a greyscale volume to aid 3D calculations
+%simply remove zeros
+  function [GreyVol, GreyVolBox]=sfCropVol(GreyVol, GreyVolBox)
+    props=regionprops(double(GreyVol>0),'BoundingBox');
+    bb=props.BoundingBox;
+    bb=ceil(bb);
+    %if 2D, add the 3rd dimenson values
+    if length(bb)==4
+      bb=[bb(1) bb(2) 1 bb(3) bb(4) 1];
+    end
+   %old BB is GreyVolBox
+   %crop volume to new bb
+   GreyVol=GreyVol(bb(2):(bb(2)+bb(5)-1), bb(1):(bb(1)+bb(4)-1), bb(3):(bb(3)+bb(6)-1));
+   %adjust the GreyVolBox
+   GreyVolBox(1:3)=GreyVolBox(1:3)+bb([2 1 3])-1;
+   GreyVolBox(4:6)=bb([5 4 6]);
+  end
+
+   
+   
+%% sfSpotCracker
+% check that we have only one spot in the volume.  
+% If neccessary, split it up!
+% 3D watershed doesn't seem great, 2D might be better, but for the moment
+% using a nearest local maxima approach to seperate voxels
+%output, cracked_spot, is the mask that divides up the volume
+  function spot=sfSpotCracker(spot,seg)
+     
+   %threshold between the two thresholds?  Does it still look like one spot?
+   local_maxima=spot.GreyVol>(seg.th1+seg.th2)/2;
+   [local_maxima, num]=bwlabeln(local_maxima);
+    
+   if num>1     %perhaps need to crack the spot...
+     %remove nuclei smaller than the min size
+     for i=1:num
+       tmp=find(local_maxima==i);
+       if length(tmp)<seg.minsize;
+         local_maxima(tmp)=0;
+       end
+     end
+       local_maxima=local_maxima~=0;%relabel
+       [local_maxima, num]=bwlabeln(local_maxima);
+   end
+       
+   if num>1     %more than one large nucleus, so crack the spot
+     %try associating each voxel >th2 with the closest nucleus (local maxima)
+     %simpler than 3D watershedding which doesn't seem to work super well
+     vol=spot.GreyVol>seg.th2;
+     [dist, index]=bwdist(local_maxima>0); %dist=distance to nearest maxima, index=index of that maxima
+     spot.crackedSpot=local_maxima(index).*double(vol);  %vol (voxels>th2), coloured according to closest local maxima
+   
+   else %only one spot
+     spot.crackedSpot=[];
+   end %if the spot needs cracking
+   
+  end
+
+
+
+  %% sfFindIntegrationRange
+  function spot=sfFindIntegrationRange(spot)
+    spot.Integral=cumsum(spot.Intensity);
+    spot.StartImage=(find(spot.Intensity,1,'first'))-1;  %-1 to adjust for +1 at line 129, avoiding zero image index problem
+    spot.EndImage=(find(spot.Intensity,1,'last'))-1;   % -1
+    spot.ExtStartImage=(find(spot.Integral>seg.icut*spot.Integral(end),1,'first'))-1;   % -1, ak- change hard code to seg.icut
+    spot.ExtEndImage=(find(spot.Integral>(1-seg.icut)*spot.Integral(end),1,'first'))-1;   % -1
+    spot.MaxImage=(find(spot.Intensity==max(spot.Intensity)))-1;   % -1
+    spot.Integral=spot.Integral(end);
+  end
+
+
+%% sfcalculateSummedSpotProps
+function [spot,values]=sfCalculateSpotProperties(spot, i, seg)   %
+  
+  if isempty(spot.crackedSpot)
+    vol=spot.GreyVol;
+    volBox=spot.GreyVolBox;
+  else %apply the cracked spot mask
+    vol=spot.GreyVol.*double(spot.crackedSpot==i);
+    %crop spot
+    [vol, volBox]=sfCropVol(vol,spot.GreyVolBox);
+  end
+  %read all properties from this greyscale volume
+  
+  %get intensity profile for start/end/extstart/etc data
+  Intensity=squeeze(sum(sum(vol,1),2));
+  Integral=cumsum(Intensity);
+
+  StartImage=(find(Integral,1,'first'))-1+volBox(3);  %-1 to adjust for +1 at line 129, avoiding zero image index problem
+  EndImage=(find(Integral,1,'last'))-1+volBox(3);   % -1
+  ExtStartImage=(find(Integral>seg.icut*Integral(end),1,'first'))-1+volBox(3);   % -1, ak- change hard code to seg.icut
+  ExtEndImage=(find(Integral>(1-seg.icut)*Integral(end),1,'first'))-1+volBox(3);   % -1
+  MaxImage=(find(Intensity==max(Intensity)))-1+volBox(3);   % -1
+  Integral=Integral(end);
+  %GreyScale center
+  CenterImage=(Intensity'*(1:length(Intensity))'/Integral)-1+volBox(3);
+  
+  
+  %make the summed spot image
+  spot.SummedSpot = sum(vol,3);
+  [x,y]=meshgrid(1:size(spot.SummedSpot,2), 1:size(spot.SummedSpot,1));
+  x=x.*spot.SummedSpot;
+  x=sum(x(:))/Integral+volBox(1)-1-seg.boxsize;
+  y=y.*spot.SummedSpot;
+  y=sum(y(:))/Integral+volBox(2)-1-seg.boxsize;
+  
+  %get the bounding box, region props...
+  tmp=gtPlaceSubImage(spot.SummedSpot,seg.zeroim,volBox(1),volBox(2));
+  props=regionprops(double(tmp>0),'Area','BoundingBox','Centroid');
+  BoundingBox=[ceil(props.BoundingBox(1:2)-seg.boxsize),props.BoundingBox(3:4)];
+  Centroid=props.Centroid-seg.boxsize;
+  Area=props.Area;
+  
+  
+  %collect the data in values
+  values=[Area, Centroid(1), Centroid(2), BoundingBox(1), BoundingBox(2), ...
+    BoundingBox(3), BoundingBox(4), Integral, StartImage, EndImage, MaxImage, ...
+    ExtStartImage, ExtEndImage]'
+  
+end   
+
+
+%% sfSaveSpot
+%calculate spot data and save, for multiple spots if neccessary
+  function numSpots=sfSaveSpot(acq,seg,spot)
+    
+    %how many to save?
+    numSpots=max(spot.crackedSpot(:));
+      if isempty(numSpots)
+        numSpots=1;
+      end
+      
+      for i=1:numSpots
+        [spot,values]=sfCalculateSpotProperties(spot, i, seg)
+    
+        tblname=sprintf('%sdifspot',acq.name);
+        colnames=seg.dbfields;
+
+     %   cmd=dbInsert(tblname,colnames,values);
+     %   mym(cmd);
+     %   % get back the ID's written - currently only one
+     %   mysqlcmd=sprintf('select last_insert_id()');
+     %   spotID=mym(mysqlcmd);
+        
+        
+        
+      %  fname=sprintf('2_difspot/difspot/difspot%05d.edf',spotID);
+      %  disp(sprintf('writing %s',fname));
+      %  edf_write(spot.SummedSpot,fname,'uint16');
+    
+      end%loop through overlapping spots
+  end
+
+end
+      
\ No newline at end of file
diff --git a/2_segment_difspot/gtSegmentDiffractionSpots_test.m b/2_segment_difspot/gtSegmentDiffractionSpots_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..39076dfc60a02f0a24a9a7ba02bffdd4f5eaa279
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionSpots_test.m
@@ -0,0 +1,319 @@
+function gtSegmentDiffractionSpots(first,last)
+% now using the database...
+% I changed the location of the full images, that seeems to be the new one,
+% only full instead of full_s5_dctX_ - - - - - Marcelo 04/12/06
+
+warning('off','Images:initSize:adjustingMag');
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+parameters=[];
+load parameters
+acq=parameters.acq;
+seg=parameters.seg;
+
+% define a full image with an extra margin of size seg.boxsize
+seg.zeroim=zeros([acq.ydet acq.xdet]+2*seg.boxsize);   
+
+
+%  seg.currentspot=1;  % still needed ?
+gtDBConnect
+
+%mym('open' ,'mysql.esrf.fr', 'gtuser','gtuser');
+%mym('use graintracking');
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Main Loop
+
+for k=first:last   
+    seg.imnum=k;
+    % read and zeropad a new full image
+    fname=sprintf('1_preprocessing/full/full%04d.edf',seg.imnum);
+    disp(sprintf('now processing image %s',fname));
+    tmp=edf_read(fname);
+    seg.fullim=gtPlaceSubImage(tmp,seg.zeroim,seg.boxsize+1,seg.boxsize+1);
+
+	  % remove previously found spots from current image
+    seg.fullim=sfMaskSegmentedSpots(seg);
+   
+    % segment new difspot in currentimage
+    sfSegmentNewSpots(acq,seg);
+   
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+
+%% sfMaskSegmentedSpots
+function masked_image=sfMaskSegmentedSpots(seg)
+   
+  % mask out the direct beam region
+   bb1=[seg.bb(1:2)+seg.boxsize,seg.bb(3:4)];
+   masked_image=gtPlaceSubImage(-10*ones(bb1(4),bb1(3)),seg.fullim,bb1(1),bb1(2));
+   
+   mysqlcmd=sprintf('select difspotID,BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where %d between StartImage and EndImage',acq.name,seg.imnum);
+   [index,bb(:,1),bb(:,2),bb(:,3),bb(:,4)]=mym(mysqlcmd);
+   
+  
+   for i=1:length(index)
+	   fname=sprintf('2_difspot/difspot/difspot%05d.edf',index(i));
+		 tmp=-edf_read(fname);
+     bb2=[bb(i,1:2)+seg.boxsize,bb(i,3:4)];
+	   masked_image=masked_image+gtPlaceSubImage(tmp,seg.zeroim,bb2(1),bb2(2));
+   end
+   
+   figure(1);imshow(masked_image,[-500 500]);
+   drawnow;
+
+end
+
+
+%% sfSegmentNewSpots
+function sfSegmentNewSpots(acq,seg)
+	
+  % perform image reconstruction (double threshold) on current image
+	marker=seg.fullim>seg.th1;
+	mask=seg.fullim>seg.th2;
+	seg.imrec=imreconstruct(marker,mask);
+	seg.imrec=bwlabel(seg.imrec);
+	props=regionprops(seg.imrec,'Area','Centroid','BoundingBox');
+ 
+  if isempty(props)
+		disp(sprintf('No new spot in image %d',seg.imnum));
+  else
+    num=0;
+		for i=1:length(props)
+    
+      if props(i).Area>seg.minsize
+        spot.id=i; 
+        spot=seg.spotstruct;  %reinitialize spot structure
+        spot=sfCopyStruct(props(i),spot);
+        spot.BoundingBox=ceil(spot.BoundingBox);
+		    
+        spot.SumBox=sfIncreaseBB(seg,spot);    % increase the bounding box of current spot by +/-  seg.boxsize in all directions
+        
+        % initialize spot.marker and sum images
+        spot.maskOrig=gtCrop(ismember(seg.imrec,i),spot.SumBox);  
+        spot.SummedSpot=spot.maskOrig.*gtCrop(seg.fullim,spot.SumBox);
+        
+        spot=sfSumSpot(acq,seg,spot);
+        spot=sfCalculateSummedSpotProps(spot);
+        if ~isempty(spot)
+          sfSaveSpot(acq,seg,spot);
+          num=num+1;
+        end
+      end 
+    end % for
+  end %if
+
+  disp(sprintf('%d diffraction spots written',num));
+
+end 
+
+
+%% sfSumSpot
+ function spot=sfSumSpot(acq,seg,spot)     % 3D double threshold image reconstruction with a moving subvolume (2 slices)
+		
+   i=1;
+   direction=1;  % +1 in forward search; -1 during backward search
+   spot.Intensity=zeros(acq.nproj,1);  % allocate Intensity array
+   
+   spot.mask=spot.maskOrig;       
+   spot.Intensity(seg.imnum+1)=sum(spot.SummedSpot(:));  % initialise the spot intensity array, +1 to avoid zero image problem
+       
+   checknext=1;
+   
+   while checknext
+      n=seg.imnum+i*direction;  %look at image number n
+      if (n>acq.nproj || n<1)
+        break;
+      elseif (abs(n-seg.imnum)>seg.range)
+         disp('summation abandonned: maximum range exceeded');
+         break;
+      end
+      fname=sprintf('1_preprocessing/full/full%04d.edf',n);
+     
+      
+      %spot.fullim=edf_read(fname);
+      %spot.fullim=gtPlaceSubImage(spot.fullim,seg.zeroim,seg.boxsize+1,seg.boxsize+1);
+      % mask out the direct beam region
+      %bb=[seg.bb(1:2)+seg.boxsize,seg.bb(3:4)];
+      %spot.fullim=gtPlaceSubImage(-10*ones(bb(4),bb(3)),seg.fullim,bb(1),bb(2));
+      %spot.cropim=gtCrop(seg.fullim,spot.SumBox);
+      
+      check_bb=1;
+      while check_bb
+        bb=[spot.SumBox(1:2)-seg.boxsize,spot.SumBox(3:4)];
+        spot.cropim=gt_edf_read(fname,bb);
+      
+        spot.marker(:,:,1)=spot.mask;                   % use the spot outline in the current slice as spot.marker
+        spot.marker(:,:,2)=0;                                     % add an empty slice
+        spot.mask(:,:,1)=spot.mask;
+        spot.mask(:,:,2)=spot.cropim>seg.th2;
+        spot.mask=imreconstruct(spot.marker,spot.mask);
+        
+        props=regionprops(double(spot.mask(:,:,2)),'BoundingBox');
+        if ~isempty(props)
+          spot.BoundingBox=ceil(props.BoundingBox);
+          [spot,check_bb]=sfCheckBoundingBox(seg,spot);
+        else
+          check_bb=0;
+          spot.mask=spot.mask(:,:,2);
+        end  
+      end
+      
+      
+      spot.Intensity(n+1)=sum(sum(spot.mask.*spot.cropim));   % the spot intensity in the new image
+      
+      if spot.Intensity(n+1)<seg.minint
+        if direction==1   % reverse direction
+          direction=-1;   % and restart the procedure in the other direction
+          i=1;
+          spot.mask=spot.maskOrig;    
+        else
+          checknext=0;
+        end  
+      else
+        spot.SummedSpot=spot.SummedSpot+spot.cropim;
+        i=i+1;
+      end
+    end %while
+ end
+
+
+
+%% sfCheckBoundingBox
+	function [spot,check_bb]=sfCheckBoundingBox(seg,spot)
+		check_bb=0;
+		if spot.BoundingBox(1)==1
+			spot.SumBox(1)=spot.SumBox(1)-seg.boxsize;
+		  spot.SumBox(3)=spot.SumBox(3)+seg.boxsize;
+      spot.extramargin=[seg.boxsize,0,0,0];
+      check_bb=1;
+		elseif spot.BoundingBox(2)==1
+			spot.SumBox(2)=spot.SumBox(2)-seg.boxsize;
+			spot.SumBox(4)=spot.SumBox(4)+seg.boxsize;
+      spot.extramargin=[0,seg.boxsize,0,0];
+	    check_bb=1;
+		elseif (spot.BoundingBox(1)+spot.BoundingBox(3)-1)==spot.SumBox(3)
+			spot.SumBox(3)=spot.SumBox(3)+seg.boxsize;
+      spot.extramargin=[0,0,seg.boxsize,0];
+      check_bb=1;
+    elseif (spot.BoundingBox(2)+spot.BoundingBox(4)-1)==spot.SumBox(4)
+      spot.SumBox(4)=spot.SumBox(4)+seg.boxsize;
+			spot.extramargin=[0,0,0,seg.boxsize];
+      check_bb=1;
+    end
+
+    if check_bb==1
+			disp('update BoundingBox');
+      spot.mask=logical(sfZeroPad(spot.mask(:,:,1),spot.extramargin));
+      spot.marker=logical(zeros(size(spot.mask)));
+      spot.SummedSpot=sfZeroPad(spot.SummedSpot,spot.extramargin);
+      spot.maskOrig=logical(sfZeroPad(spot.maskOrig,spot.extramargin));
+    else
+      spot.mask=spot.mask(:,:,2);
+    end	
+					
+  end
+   
+%% sfZeroPad
+  function impad=sfZeroPad(im,margin)
+    [m,n]=size(im);
+    width=n+margin(1)+margin(3);
+    height=m+margin(2)+margin(4);
+    impad=zeros(height,width);
+    impad=gtPlaceSubImage(im,impad,margin(1)+1,margin(2)+1);
+  end  
+
+
+%% sfFindIntegrationRange
+  function spot=sfFindIntegrationRange(spot)
+    spot.Integral=cumsum(spot.Intensity);
+    spot.StartImage=(find(spot.Intensity,1,'first'))-1;  %-1 to adjust for +1 at line 129, avoiding zero image index problem
+    spot.EndImage=(find(spot.Intensity,1,'last'))-1;   % -1
+    spot.ExtStartImage=(find(spot.Integral>0.1*spot.Integral(end),1,'first'))-1;   % -1
+    spot.ExtEndImage=(find(spot.Integral>0.9*spot.Integral(end),1,'first'))-1;   % -1
+    spot.MaxImage=(find(spot.Intensity==max(spot.Intensity)))-1;   % -1
+    spot.Integral=spot.Integral(end);
+  end
+
+
+%% sfcalculateSummedSpotProps
+function spot=sfCalculateSummedSpotProps(spot)   %
+   
+   
+    spot=sfFindIntegrationRange(spot);
+    th=(spot.EndImage-spot.StartImage)*seg.th2;
+    spot.mask=spot.SummedSpot>th; %0.05*max(spot.SummedSpot(:));
+    %spot.mask=(spot.mask+spot.maskOrig)>0;   % replace image reconstruction by edge detection and Watershed Segemntation here ?
+    spot.Outline=imreconstruct(spot.maskOrig&spot.mask,spot.mask);
+    spot.Outline=bwmorph(spot.Outline,'dilate',1);
+    spot.SummedSpot=spot.Outline.*spot.SummedSpot;
+    
+    tmp=gtPlaceSubImage(spot.SummedSpot,seg.zeroim,spot.SumBox(1),spot.SumBox(2));
+    props=regionprops(double(tmp>0),'Area','BoundingBox','Centroid');
+    if ~isempty(props)
+      spot.SummedSpot=gtCrop(tmp,ceil(props.BoundingBox));
+      props.BoundingBox=[ceil(props.BoundingBox(1:2)-seg.boxsize),props.BoundingBox(3:4)];
+      props.Centroid=props.Centroid-seg.boxsize;
+      spot=sfCopyStruct(props,spot);
+    else
+      spot=[];
+    end  
+end   
+
+
+
+%% sfCopyStruct
+    function to=sfCopyStruct(from,to,varargin)
+        switch nargin
+          case 2
+            names=fieldnames(from);
+          case 3
+            names=varargin{:};
+        end
+        for i=1:length(names)
+            to=setfield(to,names{i},getfield(from,names{i}));
+        end
+    end    
+
+
+%% sfIncreaseBB
+% use a Bounding Box of +/- seg.boxsize
+function bb=sfIncreaseBB(seg,spot)
+  bb(1:2)= spot.BoundingBox(1:2)-seg.boxsize;      
+  bb(3:4)= spot.BoundingBox(3:4)+2*seg.boxsize;
+end  
+
+%% sfSaveSpot
+  function spotID=sfSaveSpot(acq,seg,spot)
+    
+    tblname=sprintf('%sdifspot',acq.name);
+    colnames=seg.dbfields;
+    values=[[spot.Area]', [spot.Centroid(1)]',[spot.Centroid(2)]',[spot.BoundingBox(1)]',[spot.BoundingBox(2)]',...
+      [spot.BoundingBox(3)]',[spot.BoundingBox(4)]',[spot.Integral]',[spot.StartImage]',[spot.EndImage]',[spot.MaxImage]',...
+      [spot.ExtStartImage]',[spot.ExtEndImage]'];
+    
+    cmd=dbInsert(tblname,colnames,values);
+    mym(cmd);
+    % get back the ID's written - currently only one
+    mysqlcmd=sprintf('select last_insert_id()');
+    spotID=mym(mysqlcmd);
+    %keyboard
+    fname=sprintf('2_difspot/difspot/difspot%05d.edf',spotID);
+    disp(sprintf('writing %s',fname)); 
+    edf_write(spot.SummedSpot,fname,'uint16');
+    
+  end
+
+
+end
+      
\ No newline at end of file
diff --git a/2_segment_difspot/gtSegmentDiffractionVolumes.m b/2_segment_difspot/gtSegmentDiffractionVolumes.m
new file mode 100755
index 0000000000000000000000000000000000000000..6b6b6ddb3026da6a7f284cd1860fe6e53ef5b8ab
--- /dev/null
+++ b/2_segment_difspot/gtSegmentDiffractionVolumes.m
@@ -0,0 +1,141 @@
+function gtSegmentDiffractionVolumes(first,last,workingdirectory)
+
+warning('off','Images:initSize:adjustingMag');
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+
+if ~exist(workingdirectory,'var')
+  workingdirectory=pwd;
+end
+cd(workingdirectory);
+
+parameters=[];
+load parameters
+acq=parameters.acq;
+seg=parameters.seg;
+
+
+
+disp(sprintf(' ~~~  This Job: Image %d to %d, for %s  ~~~   ',first,last,workingdirectory))
+tic
+% read the size of one image to make an estimate for the number we can read
+% at once:
+test=pfReadAndThreshold(first,seg);
+details=whos('test');
+maxmemoryusage=600;  % in MB
+step=floor(maxmemoryusage*1024*1024/details.bytes);
+
+currentfilendx=first;
+
+allspotsndx=0;
+for currentfilendx=first:step:last
+  step=min(step,last-currentfilendx+1);
+
+  fprintf('Reading %d images (~%dMB) in this chunk\n',step,round(step*details.bytes/1024/1024));
+  shortvol=zeros(2048,2048,step);
+  for n=1:step
+    shortvol(:,:,n)=pfReadAndThreshold(currentfilendx+n-1,seg);
+  end
+
+  labels=bwlabeln(shortvol);
+  numlabels=max(labels(:));
+  for ndx=1:numlabels  % iterate over all the blobs
+
+    ind=find(labels==ndx);
+    %   if length(ind)<2  % discard blobs with less than 5 voxels
+    %     disp('skipping small blob')
+    %     continue
+    %   end
+    allspotsndx=allspotsndx+1;
+    fprintf('Blob: %d/%d Agglomerated blob: %d\r',ndx,numlabels,allspotsndx);
+    grayvals=shortvol(ind);
+    [i,j,k]=ind2sub(size(shortvol),ind);
+    k=k+currentfilendx-1;  % offset shortvol
+    ind2D=sub2ind(size(shortvol(:,:,1)),i,j);
+
+    % now record the blob
+    allspots{allspotsndx}=[];
+    for z=min(k):max(k) % iterate over all slices for this blob
+      howmanyinz=length(find(k==z));
+      allspots{allspotsndx}=[allspots{allspotsndx};
+        [repmat(z,[howmanyinz 1]) ind2D(k==z) grayvals(k==z)]];
+    end
+    if currentfilendx>first
+      if any(k==currentfilendx)  % blob is at top of sub volume
+        % look through all spots to find ones touching bottom of previous
+        % subvolume
+        q=1;
+        while (true)
+          if any(allspots{q}(:,1)==currentfilendx-1)
+            if intersect(allspots{q}(:,2),allspots{allspotsndx}(:,2))
+              disp('Merging spots');
+              allspots{q}=union(allspots{q},allspots{allspotsndx},'rows');
+              allspots={allspots{1:allspotsndx-1}};  % drop that last one
+              allspotsndx=allspotsndx-1;  % decrement - this spotndx will be redone
+            end
+          end
+          q=q+1;
+          if q>allspotsndx-1  % list has been shortened - if we're at the end, get out
+            break
+          end
+        end
+      end
+    end
+  end
+  fprintf('Slice %d took %fs\n',currentfilendx-1,toc);
+end
+disp('Putting all blobs into the database')
+
+%disp('(Re)create database tables')
+%gtDBCreateDifblobTable(acq.name)
+gtDBConnect
+
+siz=[2048 2048];
+table_difblobdetails=[acq.name 'difblobdetails'];
+table_difblob=[acq.name 'difblob'];
+table_difblobinfo=[acq.name 'difblobinfo'];
+
+mym(dbInsert(table_difblobinfo,'StartIndex',first,'EndIndex',last))
+
+
+tic
+
+for ndx=1:length(allspots)
+  z=allspots{ndx}(:,1);
+  [y,x]=ind2sub(siz,allspots{ndx}(:,2));
+  vals=allspots{ndx}(:,3);
+
+  disp(sprintf('Blob: %d/%d - inserting %d rows\n\r',ndx,length(allspots),length(x)))
+  % get a new difblobID
+  mym(dbInsert(table_difblob,'difblobID',0))
+  difblobID=mym('select last_insert_id()');
+  if 1 % FAST method
+    chunk=100;
+    for first=1:chunk:length(x)
+      last=first+chunk-1;
+      if last>length(x)
+        last=length(x);
+      end
+      mym(dbInsertMultiple(table_difblobdetails,...
+        'difblobID',repmat(difblobID,1,last-first+1),...
+        'xIndex',x(first:last),...
+        'yIndex',y(first:last),...
+        'zIndex',z(first:last),...
+        'graylevel',vals(first:last)));
+    end
+  else  % SLOW method
+    for n=1:length(x)
+      mym(dbInsert(table_difblob,'xIndex',x(n),'yIndex',y(n),'zIndex',z(n),'graylevel',vals(n)))
+    end
+  end
+end
+toc
+
+disp('Updating _difblobinfo with work done')
+disp('COMPLETE THIS')
+%%
+end
+
diff --git a/2_segment_difspot/gtSetupSeg.m b/2_segment_difspot/gtSetupSeg.m
new file mode 100755
index 0000000000000000000000000000000000000000..684113c69b6e1fe1549ad234f3f307bb249d4c26
--- /dev/null
+++ b/2_segment_difspot/gtSetupSeg.m
@@ -0,0 +1,23 @@
+function gtSetupSeg
+
+%after preprocessing, do the necessary setup to run
+%gtSegmentDiffractionBlobs.  Create seg field in parameters.mat, and setup
+%a difblob table in the database.
+%Run in the analysis database (with parameters.mat)
+
+if exist('parameters.mat', 'file')
+  load parameters;
+else
+  disp('Need to go to the directory containing parameters.mat for your dataset!')
+return
+end
+
+%set up tables
+gtDBCreateDifblobTable(parameters.acq.name, 0) %don't overwrite for the mo'
+
+
+%fields for parameters.seg
+seg.bb=[]  
+seg.th1=[] %threshold to crack overlapping blobs 
+seg.th2=[] %threshold for full images
+seg.icut=0.1;%for finding extstart, extend
diff --git a/2_segment_difspot/gtShowDifblobs.m b/2_segment_difspot/gtShowDifblobs.m
new file mode 100755
index 0000000000000000000000000000000000000000..30edfda766d40d98f41b457b249c85aa76a9af44
--- /dev/null
+++ b/2_segment_difspot/gtShowDifblobs.m
@@ -0,0 +1,91 @@
+%
+% Shows given difblobs: the summed blob, the full image, the full images
+% summed in the blob volume, the difference between that and the blob, and 
+% the blob with the volume viewer.
+%
+
+function gtShowDifblobs(ids)
+
+clims=[-50 50];
+figpos=[0.2 0.2 0.6 0.6];
+
+load parameters.mat
+table=[parameters.acq.name 'difblobdetails'];
+
+maxID=mym(sprintf('SELECT MAX(difblobID) FROM %s',table));
+
+close all
+
+  fig_full=figure('name','Full image #');
+  set(gcf,'units','normalized','position',[0 0.2 0.3 0.3])
+
+  fig_fullreg=figure('name','Summed full region');
+  set(gcf,'units','normalized','position',[0 0.6 0.3 0.3])
+
+  fig_blob=figure('name','Difblob ');
+  set(gcf,'units','normalized','position',[0.3 0.6 0.3 0.3])
+
+  fig_diff=figure('name','Difference between the two');
+  set(gcf,'units','normalized','position',[0.3 0.2 0.3 0.3])
+ 
+
+for iw=1:length(ids)
+
+  if ids(iw)>maxID
+    break
+  end
+  
+  [vol,bb]=gtDBBrowseDiffractionVolume(table,ids(iw));
+  difspot=sum(vol,3);
+
+  im=zeros(bb(5),bb(4));
+  for i=bb(3):bb(3)+bb(6)-1
+    im=im+edf_read(sprintf('1_preprocessing/full/full%04d.edf',i),bb([1 2 4 5]));
+  end
+
+  fullimID=round((bb(3)+bb(3)+bb(6)-1)/2);
+  fullim=edf_read(sprintf('1_preprocessing/full/full%04d.edf',fullimID));
+
+  
+  figure(fig_full)
+  clf
+  set(gcf,'name',sprintf('Full image #%d',fullimID))
+  imshow(fullim,clims)
+  set(gcf,'units','normalized','position',[0 0.2 0.3 0.3])
+  hold on
+  rectangle('position',bb([1 2 4 5])+[-1 -1 2 2],'edgecolor','g')
+
+  figure(fig_fullreg)
+  clf
+  set(gcf,'name',sprintf('Summed full #%d-#%d',bb(3),bb(3)+bb(6)-1))
+  imshow(im,[])
+  set(gcf,'units','normalized','position',[0 0.6 0.3 0.3])
+  set(gca,'position',figpos)
+
+  figure(fig_blob)
+  clf
+  set(gcf,'name',sprintf('Difblob #%d',ids(iw)));
+  imshow(difspot,[])
+  set(gcf,'units','normalized','position',[0.3 0.6 0.3 0.3])
+  set(gca,'position',figpos)
+
+  figure(fig_diff)
+  clf
+  imshow(im-difspot,[])
+  set(gcf,'units','normalized','position',[0.3 0.2 0.3 0.3])
+  colorbar
+  set(gca,'position',figpos)
+
+  if bb(6)>1
+    vol_view(vol)
+    fig_vol=gcf;
+    set(gcf,'units','normalized','position',[0.6 0.6 0.4 0.4])
+  else
+    fig_vol=[];
+  end
+  
+  pause
+
+  close(fig_vol)
+    
+end
diff --git a/2_segment_difspot/gtnewGetSummedFullImage.m b/2_segment_difspot/gtnewGetSummedFullImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..57354d2aa40de346462b3f77f7211dc31b2299b7
--- /dev/null
+++ b/2_segment_difspot/gtnewGetSummedFullImage.m
@@ -0,0 +1,21 @@
+function im=gtnewGetSummedFullImage(ndx)
+% returns the summed full image corresponding to a given difspot
+
+global parameters;
+gtDBConnect;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+
+im=zeros(parameters.acq.ydet, parameters.acq.xdet);
+[EndIm,StartIm]=mym(sprintf('select EndImage,StartImage from %sdifspot where difspotID=%d',parameters.acq.name,ndx));
+
+disp( [num2str(EndIm-StartIm+1), ' images in sum'])
+for i=StartIm:EndIm
+  im = im + edf_read(sprintf('1_preprocessing/full/full%04d.edf',i));
+end
+
+end
diff --git a/2_segment_difspot/pfReadAndThreshold.m b/2_segment_difspot/pfReadAndThreshold.m
new file mode 100755
index 0000000000000000000000000000000000000000..6e2ce967a31c3ee40700146d1b14073c99497278
--- /dev/null
+++ b/2_segment_difspot/pfReadAndThreshold.m
@@ -0,0 +1,21 @@
+%% pfReadAndThreshold -
+  function im=pfReadAndThreshold(ndx,seg)
+    fname=sprintf('1_preprocessing/full/full%04d.edf',ndx);
+    disp(sprintf('now processing image %s',fname));
+    im_full=pfWaitToRead(fname);
+    % now blank out the extinction image in the centre
+    bb1=[seg.bb(1:2),seg.bb(3:4)];
+    im_justdiffraction=gtPlaceSubImage(zeros(bb1(4),bb1(3)),im_full,bb1(1),bb1(2));
+
+    % immediately take the th2 threshold
+    im = im_justdiffraction;
+    
+ %   m=mean(im(:));
+ %   s=std(im(:));
+%    im(im<m+3*s)=0;
+    im(im<seg.th2)=0;
+
+%    disp('manual threshold in pfReadAndThreshold')
+%    im(im<9)=0;
+%   im=im(1:2:end,1:2:end);
+  end
diff --git a/2_segment_difspot/pfReadAndThreshold_SubtractMedian.m b/2_segment_difspot/pfReadAndThreshold_SubtractMedian.m
new file mode 100755
index 0000000000000000000000000000000000000000..9020928addd1702a135c1eea4dacd544e429f87a
--- /dev/null
+++ b/2_segment_difspot/pfReadAndThreshold_SubtractMedian.m
@@ -0,0 +1,30 @@
+%% pfReadAndThreshold -
+  function im=pfReadAndThreshold_SubtractMedian(ndx,seg)
+    fname=sprintf('1_preprocessing/full/full%04d.edf',ndx);
+    disp(sprintf('now processing image %s',fname));
+    im_full=pfWaitToRead(fname);
+    
+    %subtract the median of the background 
+    %taken from gtFullStatCondor - thanks Peter!
+    nullbb=NaN(seg.bb(4),seg.bb(3));
+    imn=gtPlaceSubImage(nullbb,im_full,seg.bb(1),seg.bb(2));
+    imn=imn(~isnan(imn(:)));
+    med_value=median(imn);
+    im_full=im_full-med_value;
+    
+    % now blank out the extinction image in the centre
+    bb1=[seg.bb(1:2),seg.bb(3:4)];
+    im_justdiffraction=gtPlaceSubImage(zeros(bb1(4),bb1(3)),im_full,bb1(1),bb1(2));
+
+    % immediately take the th2 threshold
+    im = im_justdiffraction;
+    
+ %   m=mean(im(:));
+ %   s=std(im(:));
+%    im(im<m+3*s)=0;
+    im(im<seg.th2)=0;
+
+%    disp('manual threshold in pfReadAndThreshold')
+%    im(im<9)=0;
+%   im=im(1:2:end,1:2:end);
+  end
diff --git a/2_segment_difspot/sfMaskSegmentedSpots.m b/2_segment_difspot/sfMaskSegmentedSpots.m
new file mode 100755
index 0000000000000000000000000000000000000000..d818d3f03a35b4cf425ad807bb2dae9bb4457926
--- /dev/null
+++ b/2_segment_difspot/sfMaskSegmentedSpots.m
@@ -0,0 +1,20 @@
+%% sfMaskSegmentedSpots
+function masked_image=sfMaskSegmentedSpots(app,prep,difspot)
+
+   bb=[segD.bb(1:2)+segD.boxsize,segD.bb(3:4)];
+   masked_image=app.data.image;
+   masked_image(bb(2):bb(2)+bb(4)-1,bb(1):bb(1)+bb(3)-1)=-10;
+   imshow(masked_image,[]);
+   index1=find([difspot.StartImage]<app.currentimage);
+   index2=find([difspot(index1).EndImage]>=app.currentimage);
+   index=index1(index2);
+   
+   for i=index
+	   fname=sprintf('difspot/difspot%05d.edf',i);
+       tmp=-edfread(fname);
+	    masked_image=sfReplaceRoi(masked_image,ceil(difspot(i).BoundingBox),tmp);
+	   
+   end
+   figure(1);imshow(masked_image,[-200 200]);
+   drawnow;
+end
\ No newline at end of file
diff --git a/2_segment_difspot/submit_marcelo.m b/2_segment_difspot/submit_marcelo.m
new file mode 100755
index 0000000000000000000000000000000000000000..26a40413236f8ee33cbeed1e1a237edbc8a81393
--- /dev/null
+++ b/2_segment_difspot/submit_marcelo.m
@@ -0,0 +1,3 @@
+function submit_marcelo
+pause(10800)
+condor_make('gtSegmentDiffractionSpots',4201,5999,20,'/data/id19/graintracking/graingrowth/s5_dct4_',1)
\ No newline at end of file
diff --git a/3_match_extspot/@mhashtable/delete.m b/3_match_extspot/@mhashtable/delete.m
new file mode 100755
index 0000000000000000000000000000000000000000..573945daa6b1e009a1eb25e551ab63688ca783da
--- /dev/null
+++ b/3_match_extspot/@mhashtable/delete.m
@@ -0,0 +1,19 @@
+% deletes the hashtable object form memory, manual garbage collection
+% *************************************************************************
+% function varargout = delete(obj)
+%
+% Purpose: frees the memory for the object which is not used any more
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function success = delete(obj)
+
+% always return one argument
+success = HashtableStore('delete', obj.ind);
diff --git a/3_match_extspot/@mhashtable/display.m b/3_match_extspot/@mhashtable/display.m
new file mode 100755
index 0000000000000000000000000000000000000000..586b129b907fa2e4b8f15e27dc77ea0b77d7c6e8
--- /dev/null
+++ b/3_match_extspot/@mhashtable/display.m
@@ -0,0 +1,34 @@
+% displays mHashTable object contents
+% *************************************************************************
+% function display(mhash)
+%
+% Purpose: this is a mHashTable method which displays mHashTable object
+%          contents
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function display(mhash)
+
+isLoose = strcmp(get(0, 'FormatSpacing'), 'loose');
+
+if(length(inputname(1)) ~= 0)
+    if isLoose, disp(' '), end
+    disp(sprintf('%s =', inputname(1)));
+end
+
+if isLoose, disp(' '), end
+
+if isempty(mhash)
+    fprintf('\tEmpty\n\n' );
+else
+    display(HashtableStore('toString', mhash.ind));
+    disp(' ')
+end
+
diff --git a/3_match_extspot/@mhashtable/isMHashTable.m b/3_match_extspot/@mhashtable/isMHashTable.m
new file mode 100755
index 0000000000000000000000000000000000000000..0075eba3e7ba9ec5993a47eb880ff528e93f39ac
--- /dev/null
+++ b/3_match_extspot/@mhashtable/isMHashTable.m
@@ -0,0 +1,18 @@
+% is this object a valid isMHashTable
+% *************************************************************************
+% function flag = isMHashTable(obj)
+%
+% Purpose: 
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function flag = isMHashTable(obj)
+
+flag = HashtableStore('isMHashTable', obj.ind);
diff --git a/3_match_extspot/@mhashtable/isempty.m b/3_match_extspot/@mhashtable/isempty.m
new file mode 100755
index 0000000000000000000000000000000000000000..c123bf042785a6b6d35176342f9d617f6863af1a
--- /dev/null
+++ b/3_match_extspot/@mhashtable/isempty.m
@@ -0,0 +1,18 @@
+% object isempty overloading
+% *************************************************************************
+% function flag = isempty(obj)
+%
+% Purpose: 
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function flag = isempty(obj)
+
+flag = HashtableStore('isempty', obj.ind);
diff --git a/3_match_extspot/@mhashtable/length.m b/3_match_extspot/@mhashtable/length.m
new file mode 100755
index 0000000000000000000000000000000000000000..c36db84175030751723d0291d4b06ee728c567d4
--- /dev/null
+++ b/3_match_extspot/@mhashtable/length.m
@@ -0,0 +1,18 @@
+% object isempty overloading
+% *************************************************************************
+% function flag = length(obj)
+%
+% Purpose: 
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function flag = length(obj)
+
+flag = HashtableStore('size', obj.ind);
diff --git a/3_match_extspot/@mhashtable/mhashtable.m b/3_match_extspot/@mhashtable/mhashtable.m
new file mode 100755
index 0000000000000000000000000000000000000000..d5d3fd98e66f06b8e4b28ad7a4ca0992b96e90af
--- /dev/null
+++ b/3_match_extspot/@mhashtable/mhashtable.m
@@ -0,0 +1,46 @@
+% constructor for the mhashtable class
+% *************************************************************************
+% function mhash = mhashtable(varargin)
+%
+% Purpose: returns an object of the mhashtable class. The object is a
+%          REFERENCE!!!
+%
+%          When called with no arguments the reference to a new hashtable is
+%          returned. When called with the mhashtable object as argument, the
+%          copy of this obejct is made and its reference is returned.
+%
+%          For the hashtable methods description see:
+%          http://java.sun.com/j2se/1.4.2/docs/api/java/util/Hashtable.html
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function mhash = mhashtable(varargin)
+
+try
+h = [];
+
+if nargin == 0
+    h.ind = HashtableStore('new');
+else
+    obj = varargin{1};
+    if isa(obj, 'mhashtable')
+        h.ind = HashtableStore('createCopy', obj.ind);
+        
+    % private call, tried to minimize the probability of an accidental call from outside
+    elseif HashtableStore('isInternID', varargin{2})
+        h.ind = obj;
+    end
+end
+    
+if ~isempty(h), mhash = class(h, 'mhashtable'); end
+
+catch
+error('HashTable:mhashtable', 'Invalid number of arguments.');
+end
\ No newline at end of file
diff --git a/3_match_extspot/@mhashtable/private/HashtableStore.m b/3_match_extspot/@mhashtable/private/HashtableStore.m
new file mode 100755
index 0000000000000000000000000000000000000000..ae5951ee50b738e1a31d46d00149bea6cf5b6ac7
--- /dev/null
+++ b/3_match_extspot/@mhashtable/private/HashtableStore.m
@@ -0,0 +1,586 @@
+% stores mhash object as a persistent variable and manages all its methods
+% *************************************************************************
+% function ArgOut = HashtableStore(action, ind, varargin)
+%
+% Purpose: this function stores mhash object as a persistent variable and
+%          manages all its methods - maps keys to values, store and 
+%          retrieve objects from a hashtable, ecc. The methods are
+%          equivalent to the Java methods.
+%
+%          For the hashtable methods description see:
+%          http://java.sun.com/j2se/1.4.2/docs/api/java/util/Hashtable.html
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     25.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function ArgOut = HashtableStore(action, ind, varargin)
+
+ArgOut = [];
+
+persistent HTable
+if isempty(HTable), HTable = local_newElement; end
+
+switch lower(action)
+    
+% Java methods
+    case 'clear'
+        HTable = local_Clear(HTable, ind);
+    case 'clone'
+        [HTable, ArgOut] = local_Clone(HTable, ind);
+    case 'contains'
+        ArgOut = local_ContainsValue(HTable, ind, varargin{:});
+    case 'containskey'
+        ArgOut = local_ContainsKey(HTable, ind, varargin{:});
+    case 'containsvalue'
+        ArgOut = local_ContainsValue(HTable, ind, varargin{:});
+    case 'elements'
+        ArgOut = local_Elements(HTable, ind);
+    case 'entryset'
+        % do nothing
+    case 'equals'
+        ArgOut = local_Equals(HTable, ind, varargin{:});
+    case 'get'
+        [HTable, ArgOut] = local_Get(HTable, ind, varargin{:});
+    case 'hashcode'
+        ArgOut = ind;
+    case 'isempty'
+        ArgOut = local_IsEmpty(HTable, ind);
+    case 'keys'
+        ArgOut = local_Keys(HTable, ind);
+    case 'keyset'
+        ArgOut = local_Keys(HTable, ind);
+    case 'put'
+        [HTable, ArgOut] = local_Put(HTable, ind, varargin{:});
+    case 'putall'
+        HTable = local_PutAll(HTable, ind, varargin{:});
+    case 'rehash'
+        % do nothing
+    case 'remove'
+        HTable = local_Remove(HTable, ind, varargin{:});
+    case 'size'
+        ArgOut = local_Size(HTable, ind);
+    case 'tostring'
+        ArgOut = local_ToString(HTable, ind);
+    case 'values'
+        ArgOut = local_Elements(HTable, ind);
+                
+% Non-Java methods
+    case 'new'
+        [HTable, ArgOut] = local_New(HTable);
+    case 'delete'
+        [HTable, ArgOut] = local_removeElement(HTable, ind);
+    case 'createcopy'
+        [HTable, ArgOut] = local_CreateCopy(HTable, ind);
+    case 'display'
+        ArgOut = local_Display(HTable);
+    case 'isinternid'
+        ArgOut = local_IsInternID(ind);
+    case 'ismhashtable'
+        ArgOut = local_isKey(HTable, ind);
+    case 'getelement'
+        ArgOut = local_getElement(HTable, ind);
+        
+    otherwise
+        % do nothing
+end
+
+
+% *************************************************************************
+% function HTable = local_Clear(HTable, ind)
+%
+% Purpose: Clears this hashtable so that it contains no keys.
+%
+% *************************************************************************
+function HTable = local_Clear(HTable, ind)
+
+element = local_newElement;
+HTable  = local_putElement(HTable, ind, element);
+
+
+% *************************************************************************
+% function [HTable, HClone] = local_Clone(HTable, ind)
+%
+% Purpose: Creates a shallow copy of this hashtable. Uses intern ID to make
+%           sure that no outside call could make the same thing
+%
+% Status: DIRTY
+%
+% *************************************************************************
+function [HTable, HClone] = local_Clone(HTable, ind)
+
+[HTable, ind]   = local_CreateCopy(HTable, ind);
+HClone          = mhashtable(ind, 849784.87374/exp(pi));
+
+
+% *************************************************************************
+% function isContained = local_ContainsValue(HTable, ind, value)
+%
+% Purpose: Tests if some key maps into the specified value in this hashtable.
+%
+% *************************************************************************
+function isContained = local_ContainsValue(HTable, ind, value)
+
+isContained = 0;
+element     = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+data        = {element.num_data{:}, element.char_data{:}};
+
+if ischar(value)
+    for i = 1:length(data)
+        val = data{i};
+        if ischar(val)
+            if strcmp(val, value)
+                isContained = 1;
+                return
+            end
+        end
+    end
+elseif isnumber(value)
+    for i = 1:length(data)
+        val = data{i};
+        if isnumber(val)
+            if val == value
+                isContained = 1;
+                return
+            end
+        end
+    end
+else
+    % not yet supported match for non char/num values
+    isContained = [];
+    return;
+end
+
+
+% *************************************************************************
+% function isKey = local_ContainsKey(HTable, ind, value)
+%
+% Purpose: Tests if the specified object is a key in this hashtable.
+%
+% *************************************************************************
+function isKey = local_ContainsKey(HTable, ind, key)
+
+isKey       = 0;
+element     = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+isKey       = local_isKey(element, key);
+
+
+% *************************************************************************
+% function isKey = local_isKey(element, key)
+%
+% Purpose: Tests if the specified key exists in this hashtable.
+%
+% *************************************************************************
+function isKey = local_isKey(element, key)
+
+isKey       = 0;
+index       = [];
+
+if ischar(key)
+    index = find(strcmp(element.char_keys, key));
+elseif isnumeric(key)
+    index = find(element.num_keys == key(1));
+else
+    return
+end
+
+if ~isempty(index), isKey = 1; end
+
+
+% *************************************************************************
+% function data = local_Elements(HTable, ind)
+%
+% Purpose: Returns an enumeration of the values in this hashtable.
+%
+% *************************************************************************
+function data = local_Elements(HTable, ind)
+
+data    = [];
+element	= local_getElement(HTable, ind);
+if isempty(element), return; end
+
+data  	= {element.num_data{:}, element.char_data{:}};
+
+
+% *************************************************************************
+% function isEqual = local_Equals(HTable, ind, obj)
+%
+% Purpose: Compares the specified Object with this hashtable for equality
+%
+% *************************************************************************
+function isEqual = local_Equals(HTable, ind, obj)
+
+isEqual = 0;
+if ~isa(obj, 'mhashtable'), return; end
+obj = struct(obj);
+if ind == obj.ind, isEqual = 1; end
+
+
+% *************************************************************************
+% function [HTable, val] = local_Get(HTable, ind, key)
+%
+% Purpose: Returns the value to which the specified key is mapped in this 
+%          hashtable. If no such key is existent the return an empty array
+%
+% *************************************************************************
+function [HTable, val] = local_Get(HTable, ind, key)
+
+val     = [];
+element = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+val     = local_getElement(element, key);
+
+
+% *************************************************************************
+% function isHEmpty = local_IsEmpty(HTable, ind)
+%
+% Purpose: Tests if this hashtable maps no keys to values.
+%
+% *************************************************************************
+function isHEmpty = local_IsEmpty(HTable, ind)
+
+isHEmpty = 1;
+element  = local_getElement(HTable, ind);
+if isempty(element), return; end
+if ~(isempty(element.num_data) && isempty(element.char_data)), isHEmpty = 0; end
+
+
+% *************************************************************************
+% function keys = local_Keys(HTable, ind)
+%
+% Purpose: Returns an enumeration of the keys in this hashtable.
+%
+% *************************************************************************
+function keys = local_Keys(HTable, ind)
+
+keys        = [];
+element     = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+num_keys    = num2cell(element.num_keys);
+keys        = {num_keys{:}, element.char_keys{:}};
+
+
+% *************************************************************************
+% function [HTable, success] = local_Put(HTable, ind, key, val)
+%
+% Purpose: Maps the specified key to the specified value in this hashtable.
+%
+% *************************************************************************
+function [HTable, success] = local_Put(HTable, ind, key, val)
+
+success             = 0;
+element             = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+[element, success]  = local_putElement(element, key, val);
+HTable              = local_putElement(HTable, ind, element);
+
+
+% *************************************************************************
+% function HTable = local_PutAll(HTable, ind, obj)
+%
+% Purpose: Copies all of the mappings from the specified obj to this
+%           Hashtable These mappings will replace any mappings that this 
+%           Hashtable had for any of the currently specified keys
+%
+% *************************************************************************
+function HTable = local_PutAll(HTable, ind, obj)
+
+if ~isa(obj, 'hashtable'), return; end
+
+element     = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+obj_data  	= obj.getElement;
+if isempty(obj_data), return; end
+
+num_data    = obj_data.num_data;
+char_data   = obj_data.char_data;
+
+num_keys    = obj_data.num_keys;
+char_keys   = obj_data.char_keys;
+
+% loop for all numeric keys
+for i = 1:length(num_keys)
+    element = local_putElement(element, num_keys(i), num_data{i});
+end
+
+% loop for all char keys
+for i = 1:length(char_keys)
+    element = local_putElement(element, char_keys{i}, num_data{i});
+end
+
+HTable  = local_putElement(HTable, ind, element);
+
+
+% *************************************************************************
+% function HTable = local_Remove(HTable, ind, key)
+%
+% Purpose: Removes the key (and its corresponding value) from this hashtable.
+%
+% *************************************************************************
+function HTable = local_Remove(HTable, ind, key)
+
+element = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+element = local_removeElement(element, key);
+HTable  = local_putElement(HTable, ind, element);
+
+
+% *************************************************************************
+% function HSize = local_Size(HTable, ind)
+%
+% Purpose: Returns the number of keys in this hashtable.
+%
+% *************************************************************************
+function HSize = local_Size(HTable, ind)
+
+HSize   = [];
+element = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+HSize   = length(element.char_keys) + length(element.num_keys);
+
+
+% *************************************************************************
+% function data = local_ToString(HTable, ind)
+%
+% Purpose: Returns a string representation of this Hashtable object in the
+%           form of a set of entries
+%
+% *************************************************************************
+function dataString = local_ToString(HTable, ind)
+
+try
+dataString  = '[]';
+element     = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+num_keys    = num2cell(element.num_keys);
+char_keys   = element.char_keys;
+
+char_data   = element.char_data;
+num_data    = element.num_data;
+
+data        = {num_data{:}, char_data{:}};
+keys        = {num_keys{:}, char_keys{:}};
+
+data_length = length(data);
+
+if data_length > 0
+    
+    char_ones   = ones(data_length, 1);
+    dpoints     = char(58*char_ones);
+    empty       = char(32*char_ones);
+    
+    data_cell   = cell(1, data_length);
+    key_cell    = data_cell;
+    
+    % loop for all data and key elements
+    for i = 1:data_length
+        data_cell{i}    = local_DisplayCell(data(i));
+        cell_str        = local_DisplayCell(keys(i));
+        key_cell{i}     = cell_str(end:-1:1);
+    end
+    
+    data_str    = char(data_cell);
+    key_str     = char(key_cell);
+        
+    dataString  = [key_str(:,end:-1:1), dpoints, empty, data_str];
+end
+catch
+dataString = 'an error has occured while producing string rapresentation of hashtable contents';    
+end
+
+
+% *************************************************************************
+% function cell_cell = local_DisplayCell(cell_cell, cell_data, ind, isInverse)
+%
+% Purpose: returns string view of the cell contents
+%
+% *************************************************************************
+function cell_str = local_DisplayCell(cell_cell)
+
+iCell       = cell_cell;
+iElement    = cell_cell{1};
+
+if ischar(iElement)
+    if length(iElement) > 25
+        cell_str = sprintf('[%0.0fx%0.0f char]', size(iElement));
+    else
+        cell_str = sprintf('''%s''', iElement);
+    end
+elseif isnumeric(iElement)
+    if length(iElement) == 1
+        cell_str = sprintf('%g', iElement);
+    elseif length(iElement) > 5
+        cell_str = sprintf('[%0.0fx%0.0f %s]', size(iElement), class(iElement(1)));
+    else
+        cell_str = hsprintf(iElement);
+    end
+else
+    cell_str = evalc('disp(iCell)');
+    cell_str([1, 2, 3, 4, end - 1, end]) = [];
+end
+
+
+% *************************************************************************
+% function [HTable, ind] = local_New(HTable)
+%
+% Purpose: creates a new hashtable object
+%
+% *************************************************************************
+function [HTable, ind] = local_New(HTable)
+
+element = local_newElement;
+ind     = max(HTable.num_keys) + 1;
+if isempty(ind), ind = 1; end
+HTable  = local_putElement(HTable, ind, element);
+
+
+% *************************************************************************
+% function [element, success] = local_removeElement(element, key)
+%
+% Purpose: removes hashtable element
+%
+% *************************************************************************
+function [element, success] = local_removeElement(element, key)
+
+success = 0;
+
+if ischar(key)
+    index = find(strcmp(element.char_keys, key));
+    if ~isempty(index)
+        element.char_data(index)    = []; 
+        element.char_keys(index)    = []; 
+        success                     = 1;
+    end
+elseif isnumeric(key)
+    index = find(element.num_keys == key(1));
+    if ~isempty(index)
+        element.num_data(index)     = [];
+        element.num_keys(index)     = []; 
+        success                     = 1;
+    end
+else
+    return
+end
+
+
+% *************************************************************************
+% function [HTable, ind] = local_CreateCopy(HTable, ind)
+%
+% Purpose: creates a copy of the element and returns it index
+%
+% *************************************************************************
+function [HTable, ind] = local_CreateCopy(HTable, ind)
+
+ind     = [];
+element = local_getElement(HTable, ind);
+if isempty(element), return; end
+
+ind     = max(HTable.num_keys) + 1;
+if isempty(ind), ind = 1; end
+HTable  = local_putElement(HTable, ind, element);
+
+
+% *************************************************************************
+% function isIntern = local_IsInternID(internID)
+%
+% Purpose: verifies whether the argument matches the intern ID constant
+%
+% Status: DIRTY
+%
+% *************************************************************************
+function isIntern = local_IsInternID(internID)
+
+isIntern = 0;
+if ~isnumeric(internID) || length(internID) > 1, return; end
+if internID == 849784.87374/exp(pi), isIntern = 1; end
+
+
+% *************************************************************************
+% function element = local_newElement
+%
+% Purpose: returns a struct corresponding to an empty element
+%
+% *************************************************************************
+function element = local_newElement
+
+element.num_data    = {};
+element.char_data   = {};
+element.num_keys    = [];
+element.char_keys   = [];
+
+
+% *************************************************************************
+% function [val, success] = local_getElement(element, key)
+%
+% Purpose: returns the value corresponding to the given key
+%
+% *************************************************************************
+function [val, success] = local_getElement(element, key)
+
+success = 0;
+val     = [];
+index   = [];
+
+if isempty(element) || isempty(key), return; end
+
+if ischar(key)
+    index = find(strcmp(element.char_keys, key));
+    if ~isempty(index), val = element.char_data{index}; end
+elseif isnumeric(key)
+    index = find(element.num_keys == key(1));
+    if ~isempty(index), val = element.num_data{index}; end
+else
+    return
+end
+
+if ~isempty(index), success = 1; end
+
+
+% *************************************************************************
+% function [element, success] = local_putElement(element, key, val)
+%
+% Purpose: assigns value to the given key
+%
+% *************************************************************************
+function [element, success] = local_putElement(element, key, val)
+
+success	= 0;
+if isempty(element) || isempty(key), return; end
+
+if ischar(key)
+    index = find(strcmp(element.char_keys, key));
+    if isempty(index)
+        index = length(element.char_keys) + 1;
+        element.char_keys{index} = key;
+        element.char_data{index} = val;
+    else
+        element.char_data{index} = val;
+    end
+    success	= 1;
+elseif isnumeric(key)
+    index = find(element.num_keys == key(1));
+    if isempty(index)
+        index = length(element.num_keys) + 1;
+        element.num_keys(index) = key(1);
+        element.num_data{index} = val;
+    else
+        element.num_data{index} = val;         
+    end
+    success	= 1;
+end
\ No newline at end of file
diff --git a/3_match_extspot/@mhashtable/private/hsprintf.m b/3_match_extspot/@mhashtable/private/hsprintf.m
new file mode 100755
index 0000000000000000000000000000000000000000..cbb1cfeb48fc05ad8b0ac252512700ecd2eb0548
--- /dev/null
+++ b/3_match_extspot/@mhashtable/private/hsprintf.m
@@ -0,0 +1,268 @@
+% gets the string from a number the way you would like to see it
+% *************************************************************************
+% function val_string = hsprintf(varargin)
+%
+% Purpose: gets the string from a number for the best human viewing, there
+%					 is no unnecessary information (digits), but also not more information
+%					 can be lost lost then specified by the SignificantDigitsNo attribute.
+%					 It extends sprintf to the functionality that any very large or very
+%				   small number could be displayed the way you expect and would like.
+%
+% Arguments:
+%       varargin : see example below. Attribute-value pairs in arbitrary order.
+%									 All attributes have a default value and can be not explicitly
+%									 specified
+%
+% Return values
+%     val_string : string
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Examples:
+%
+%   1. With default settings:
+%           str = hsprintf(859)
+%
+%   2. Array input with default settings
+%           str = hsprintf([859, 798])
+%           >> str = 859, 798
+%
+%   3. MATLAB - sprintf behaviour
+%           str = hsprintf('%5.6f', 798)
+%
+%   4. Set all parameters
+%           str = hsprintf('Value', [798, pi], 'CharsNo', 8, 'SignificantDigitsNo', 4, 'Separator', '; ')
+%           >> str = 798; 3.142
+%
+% *************************************************************************
+function val_string = hsprintf(varargin)
+
+val_string  = [];
+ArgIn       = {};
+
+% resolve different cases: with one input, or C conversion mode
+if length(varargin) == 1
+    ArgIn = {'Value', varargin{1}};
+else
+    ind_format = strfind(varargin{1}, '%');
+
+    % special case, sprintf syntax with empty format
+    if isempty(varargin{1})
+        ArgIn = {'Value', varargin{2}};
+
+    % sprintf syntax
+    elseif ~isempty(ind_format)
+        val_string = sprintf(varargin{:});
+        return;
+
+    % dafault hsprintf syntax
+    else
+        ArgIn = varargin;
+    end
+end
+
+% set properties
+Value               = [];
+CharsNo             = 8;
+SignificantDigitsNo	= 4;
+Separator           = ', ';
+
+for i = 1:2:length(ArgIn)
+    switch lower(ArgIn{i})
+        case 'value'
+            Value = ArgIn{i+1};
+        case 'CharsNo'
+            CharsNo = ArgIn{i+1};
+        case 'SignificantDigitsNo'
+            SignificantDigitsNo = ArgIn{i+1};
+        case 'Separator'
+            Separator = ArgIn{i+1};
+    end
+end
+
+if (isempty(Value) || ~isnumeric(Value)), return; end
+
+CharsNo                 = max(4, round(CharsNo));
+SignificantDigitsNo     = min(CharsNo - 1, round(SignificantDigitsNo));
+
+% skalar
+if length(Value) == 1
+    val_string = local_getValString(Value, CharsNo, SignificantDigitsNo);
+
+% vector
+else
+    val_cell = cell(1, length(Value));
+    for iValue = 1:length(Value)
+        val = Value(iValue);
+        val_cell{iValue} = local_getValString(val, CharsNo, SignificantDigitsNo);
+    end
+    val_string = local_cell2string(val_cell, Separator);
+end
+
+
+% *************************************************************************
+% function val_string = local_getValString(Value, CharsNo, SignificantDigitsNo)
+%
+% Purpose:
+%     function to
+%
+% Arguments:
+%     Value:
+%   CharsNo:
+%   SignificantDigitsNo:
+%
+% Return values
+%     val_string
+%
+% *************************************************************************
+function val_string = local_getValString(Value, CharsNo, SignificantDigitsNo)
+
+val_string  = [];
+realVal     = real(Value);
+imagVal     = imag(Value);
+
+if realVal ~= 0
+    val_string  = local_resolve(realVal, CharsNo, SignificantDigitsNo);
+end
+
+if imagVal ~= 0
+    imag_string = local_resolve(imagVal, CharsNo, SignificantDigitsNo);
+    if imagVal < 0
+        val_string  = [val_string, imag_string, 'i'];
+    else
+        val_string  = [val_string, '+', imag_string, 'i'];
+    end
+end
+
+if isempty(val_string), val_string = '[]'; end
+
+
+% *************************************************************************
+% function String = local_cell2string(Cell, Delimiter)
+%
+% Purpose:
+%     function to
+%
+% Arguments:
+%       Cell:
+%  Delimiter:
+%
+% Return values
+%     String:
+%
+% *************************************************************************
+function String = local_cell2string(Cell, Delimiter)
+
+String = Cell{1};
+
+for iCell = 2:length(Cell)
+    String = [String, Delimiter, Cell{iCell}];
+end
+
+
+% *************************************************************************
+% function val_string = local_resolve(Value, CharsNo, SignificantDigitsNo)
+%
+% Purpose:
+%     function to
+%
+% Arguments:
+%     Value:
+%   CharsNo:
+%   SignificantDigitsNo:
+%
+% Return values
+%     val_string
+%
+% *************************************************************************
+function val_string = local_resolve(Value, CharsNo, SignificantDigitsNo)
+
+Value = double(Value);
+
+if Value < 0
+    isSign	= 1;
+    Value 	= -Value;
+elseif Value > 0
+    isSign	= 0;
+else
+    val_string = '0';
+    return
+end
+
+isSmall     = Value < 1;
+
+val_log10  	= log10(Value);
+decNo       = floor(val_log10);
+val         = Value;
+val_norm    = val/10^(decNo);
+
+
+isExp       = (isSmall && (abs(decNo) >= (CharsNo - SignificantDigitsNo))) || (~isSmall && decNo > CharsNo - 3);
+
+
+% cut all values beyond the accuracy given by CharsNo
+if ~isExp
+    if isSmall
+        digNo = SignificantDigitsNo - 1;
+    else
+        if SignificantDigitsNo > decNo
+            digNo = SignificantDigitsNo - 1;
+        else
+            digNo = decNo;
+        end
+    end
+else
+    digNo = SignificantDigitsNo;
+end
+
+val_norm = round(val_norm*10^(digNo))/(10^(digNo));
+
+% pre-allocate array
+val_array   = zeros(1, CharsNo);
+
+% loop for all digits
+for iPlace = 1:CharsNo
+    val_floor           = floor(val_norm);
+    val_rem             = val_norm - val_floor;
+    val_norm            = val_rem*10;
+
+    isNeg               =  (1 - val_rem) < 1e-5;
+    isPos               =  val_rem < 1e-5;
+
+    if isNeg
+        val_array(iPlace) = val_floor + 1;
+    else
+        val_array(iPlace) 	= val_floor;
+    end
+
+    if isNeg || isPos
+        val_array(iPlace+1:end) = [];
+        break
+    end
+end
+
+val_string    = sprintf('%d', val_array);
+
+if ~isExp
+    if decNo >= 0
+        if length(val_string) > (decNo + 1)
+            val_string  = [val_string(1:decNo + 1), '.', val_string(decNo + 2:end)];
+        else
+            val_string  = [val_string, sprintf('%d', zeros((decNo + 1 - length(val_string)), 1))];
+        end
+    else
+        val_string  = ['0.', sprintf('%d', zeros(-decNo-1, 1)), val_string];
+    end
+else
+    if length(val_string) > 1
+        val_string = [val_string(1), '.', val_string(2:end), 'e', sprintf('%+d', decNo)];
+    else
+        val_string = [val_string(1), 'e', sprintf('%+d', decNo)];
+    end
+end
+
+if isSign, val_string = ['-', val_string]; end
diff --git a/3_match_extspot/@mhashtable/size.m b/3_match_extspot/@mhashtable/size.m
new file mode 100755
index 0000000000000000000000000000000000000000..18e6b8e0bf79f94e37c11484709e36f0b42dbeed
--- /dev/null
+++ b/3_match_extspot/@mhashtable/size.m
@@ -0,0 +1,19 @@
+% object isempty overloading
+% *************************************************************************
+% function [m, n] = size(obj)
+%
+% Purpose: 
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function [m, n] = size(obj)
+
+m = HashtableStore('size', obj.ind);
+if m == 0, n = 0; else n = 1; end 
diff --git a/3_match_extspot/@mhashtable/subsref.m b/3_match_extspot/@mhashtable/subsref.m
new file mode 100755
index 0000000000000000000000000000000000000000..33f3fb13a8f46aac6389fc94eb7927acbc1d966b
--- /dev/null
+++ b/3_match_extspot/@mhashtable/subsref.m
@@ -0,0 +1,28 @@
+% manages Java-like methods syntax
+% *************************************************************************
+% function varargout = subsref(obj, index)
+%
+% Purpose: the methods syntax for mHashTable class is not Matlab-like but
+%          Java-like. This is achieved using subsref
+%
+% Author:
+%     Mikhail Poda-Razumtsev
+%
+% Initial Version:
+%     26.11.2005
+%
+% Change History:
+%
+% *************************************************************************
+function ArgOut = subsref(obj, index)
+
+% check calling mode
+if index(1).type ~= '.', return; end
+
+% get action and arguments
+arg     = {};
+action  = index(1).subs;
+if length(index) > 1, arg = index(2).subs; end
+
+% always return one argument
+ArgOut = HashtableStore(action, obj.ind, arg{:});
diff --git a/3_match_extspot/AutoFind_360.m b/3_match_extspot/AutoFind_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..e82094921af78d75950ce7b1301db98141401086
--- /dev/null
+++ b/3_match_extspot/AutoFind_360.m
@@ -0,0 +1,603 @@
+function [output_point]=AutoFind_360(inputID,parameters,varargin)
+
+%adapt AutoFind_test to work on single 360 scan, rather than two halves
+
+%use a pair table which contains all difspots:
+%  | pairID | difAID | difBID |
+%where either of the difIDs can be null - unpaired spots
+
+%all possible difspots are contained in the single 360 degree difspot
+%table.  If there is pair information it is in the pairtable
+
+
+warning on backtrace
+close all
+
+% data base connect
+%varargin of 1 means already connected
+connected=0;
+if ~isempty(varargin) 
+  connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SETUP VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+struct_id = inputID;
+name=parameters.acq.name;
+  
+% DB table names
+table_difspot=sprintf('%sdifspot',parameters.acq.name);
+table_extspot=sprintf('%sextspot',parameters.acq.name);
+table_snakes=sprintf('%ssnakes',parameters.acq.name);
+table_bboxes=sprintf('%sbboxes',parameters.acq.name);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%  AUTOFIND 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% options for graphical display
+% graphics.show_dif=1;
+% graphics.show_initialmatch=1;
+% graphics.show_gvf=false;
+% graphics.show_snakeprogress=false;
+% graphics.show_snakefinal=0;
+% graphics.show_convergence=false;
+
+graphics.show_dif=false;
+graphics.show_initialmatch=false;
+graphics.show_gvf=false;
+graphics.show_snakeprogress=false;
+graphics.show_snakefinal=false;
+graphics.show_convergence=false;
+
+% first check what parameters exist
+if ~exist('struct_id','var')
+  error('Please supply a structure ID')
+end
+
+fprintf('AUTO_FIND\n');
+fprintf('Name: %s\n',name);
+fprintf('Parameters: \n');
+fprintf('\tStructID: %d\n',struct_id);
+
+%is database empty?
+if (mym(sprintf('select count(*) from %s',table_extspot)))
+  disp('DB has extspot data already')
+else
+  disp('DB has no extspot data yet')
+end
+
+if 1%check for overwriting extspot
+if ~isempty(mym(sprintf('select extspotID from %s where extspotID=%d',table_extspot,struct_id)))
+  error('extspotID already exists - aborting')
+end
+else
+disp('OVERWRITING EXTSPOT!')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOAD DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+mysqlcmd=sprintf('select difspotID from %s where difspotID=%d',table_difspot,struct_id);
+if isempty(mym(mysqlcmd))
+  error('That difspot structure does not exist!');
+end
+
+%get 3 images (around the max image) to be correlated
+[ndx_im1,ndx_im2]=sfWhichExtImages_new_format(struct_id);
+%prepare variable for correlation map
+cc_sum=zeros(parameters.acq.bb(4), parameters.acq.bb(3)); 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Read images
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% read the summed images
+extmean=gtGetMeanFullImage(struct_id, parameters, 1); 
+summeddif=gtGetSummedDifSpot(struct_id, parameters, 1);
+
+%calc centre of mass, area of difspot
+com_x = sum(summeddif) * ((1:length(sum(summeddif)))') / sum(sum(summeddif));
+com_y = (sum(summeddif')*(1:length(sum(summeddif')))')/sum(sum(summeddif'));
+area = length(find(summeddif~=0));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate search area mask
+% use mask_extinction_function_pair
+%uses pair info if available
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+extmask=gtMaskExtinctionFunction_360(struct_id,parameters,1);%already DB connected
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% MAIN LOOP OF THREE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for ndx_im=ndx_im1:ndx_im2
+  fprintf('Examining image: %d\n',ndx_im);
+
+  ext=gtGetExtImage(ndx_im, parameters); 
+  dif=gtGetDifImage(ndx_im,struct_id, parameters, 1); % 1 - already DB connected
+
+%variables for the gradient images
+  im_x=zeros(gtBboxSizeMat(parameters.acq.bb));
+  im_y=zeros(gtBboxSizeMat(parameters.acq.bb));
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% Gradient calculations
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  %make dif spot gradient, threshold
+  dif_med = medfilt2(dif, [3 3]); % ak 10/2007 - try changing to lower values for snow (small spots) - was [5 5]
+  [dif_gradx,dif_grady]=gradient(dif_med);
+
+  %dif_grad = sqrt((dif_gradx).^2+(dif_grady).^2);
+  %grad_thresh = (mean(dif_grad(:))+0.75*std(dif_grad(:)));
+  %grad_thresh2 = max(dif_grad(:));
+%ak 10/2007 - this seems to over estimate compared to the x or y only
+%gradients
+  grad_threshx = (mean(dif_gradx(:))+0.75*std(dif_gradx(:)));
+  grad_thresh2x = max(dif_gradx(:));  
+  grad_threshy = (mean(dif_grady(:))+0.75*std(dif_grady(:)));
+  grad_thresh2y = max(dif_grady(:));  
+  
+  grad_thresh=(grad_threshx+grad_threshy)/2;
+  
+  
+  dif_gradx_sign = sign(dif_gradx);
+ % dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+  dif_gradx_t1=abs(dif_gradx) > grad_threshx;
+  dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+  dif_grady_sign = sign(dif_grady);
+%  dif_grady_t1=abs(dif_grady) > grad_thresh;
+  dif_grady_t1=abs(dif_grady) > grad_threshy;
+  dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+  %make dif spot perimeter for display - snake input?
+  dif_spot = dif_med > 0.1*max(dif_med(:));
+  dif_spot_perimeter=double(bwperim(dif_spot));
+
+  %median filter, find edges
+  ext_med = medfilt2(ext, [3 3]); % ak 10/2007 - try changing to lower values for snow (small spots) - was [10 10]
+  ext_edges=edge(ext_med,0.001);
+
+  [ext_gradx,ext_grady]=gradient(ext_med);
+
+  ext_gradx_sign = -sign(ext_gradx);
+  ext_gradx = abs(ext_gradx);
+ % ext_gradx_t1=and(ext_gradx>grad_thresh, ext_gradx<grad_thresh2);
+ ext_gradx_t1=and(ext_gradx>grad_threshx, ext_gradx<grad_thresh2x);
+  ext_gradx_t1 = ext_gradx_sign.*ext_gradx_t1;
+
+  ext_grady_sign = -sign(ext_grady);
+  ext_grady = abs(ext_grady);
+  %ext_grady_t1=and(ext_grady>grad_thresh, ext_grady<grad_thresh2);
+  ext_grady_t1=and(ext_grady>grad_threshy, ext_grady<grad_thresh2y);
+  ext_grady_t1 = ext_grady_sign.*ext_grady_t1;
+
+  ext_gradx_t1(logical(im_x)) = 0;
+  ext_grady_t1(logical(im_y)) = 0;
+  %%%%%%%%%%%%%%%%%%%%%%%%
+  %pad dif_grad to size of ext to use correlate
+  dif_maskx = gtPlaceSubImage(dif_gradx_t1, zeros(size(ext)), 1, 1);
+  dif_masky = gtPlaceSubImage(dif_grady_t1, zeros(size(ext)), 1, 1);
+  %  dif_perim_mask = gtPlaceSubImage(dif_spot_perimeter, zeros(size(ext)), 1, 1);
+
+  summeddif_bw=summeddif>0.25*max(summeddif(:));
+  summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+  summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+  summeddif_bw=bwmorph(summeddif_bw,'dilate',1);
+
+  summeddif_mask=gtPlaceSubImage(summeddif_bw,zeros(size(ext)),1,1);
+  dif_spot_mask=gtPlaceSubImage(dif_spot,zeros(size(ext)),1,1);
+
+  %%%%%%%%%%%%%%%%%%%%%%%%
+  % Look at previous diffraction spots
+  %%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  mysqlcmd=sprintf(['select extspotID from %s where (extspotID!=%d) and '...
+    '(extspotID=any(select difspotID from %s where %d between StartImage and EndImage))'],...
+    table_extspot,struct_id,table_difspot,ndx_im);
+
+  extspotIDs=mym(mysqlcmd)
+
+  %subtract prior extspots
+  fprintf('Removing %d spots from correlation image\n',length(extspotIDs));
+
+  for i=1:length(extspotIDs)
+    [tmpx,tmpy]=gtMaskPriorExtspot(extspotIDs(i), ndx_im, grad_thresh, parameters);
+		%note - only uses a single threshold when preparing gradient image
+    im_x(logical(tmpx))=0;
+    im_y(logical(tmpy))=0;
+  end
+
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Apply search area mask
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  ext_gradx_t1(~extmask)=0;
+  ext_grady_t1(~extmask)=0;
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% do correlation
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  cc_x=real(ifft2(fft2(ext_gradx_t1).*conj(fft2(dif_maskx))));% from correlate.m
+  cc_y=real(ifft2(fft2(ext_grady_t1).*conj(fft2(dif_masky))));% from correlate.m
+  cc_sum=cc_sum+ (cc_x+cc_y);
+
+  
+  
+end
+
+
+shift=gtFindMaxSubscripts(cc_sum);
+
+%apply shifts
+
+%dif_perim_mask=roll(dif_perim_mask,shift(1),shift(2));
+dif_spot_mask=roll(dif_spot_mask,shift(1),shift(2));
+[com_x,com_y]=gtShiftContour(...
+  com_x,com_y,...
+  shift(2),shift(1),...
+  size(dif_spot_mask,2),size(dif_spot_mask,1));
+
+output_point = round([com_x com_y]); %where user would click in find_spots...
+summeddif_mask=roll(summeddif_mask,shift(1),shift(2));
+
+% try to remove bad portion of wrapped mask
+marker=zeros(size(summeddif_mask));
+marker(round(com_y),round(com_x))=1;
+summeddif_mask=imreconstruct(marker,summeddif_mask);
+summeddif_perim_mask=bwperim(summeddif_mask);
+
+% show some results
+if graphics.show_dif
+%  h_dif=figure;
+%  imshow(dif,[])
+andy_fig=figure;
+subplot(1,2,1)
+imshow(gtPlaceSubImage(summeddif, zeros(size(ext)), 50,50), [])
+
+end
+if graphics.show_initialmatch
+  %something has change in how alpha is handled, so this doesn't work well
+  %now!
+%   h_initialmatch=figure;
+%   h1=imshow(extmean,[]);
+%   hold on
+%   h3=imagesc(cat(3,summeddif_perim_mask, zeros(size(summeddif_perim_mask)), zeros(size(summeddif_perim_mask))));
+%   set(h3,'alphadata',summeddif_perim_mask);
+%   plot(com_x, com_y, 'xr', 'markersize', 10)
+%   h4=imagesc(cat(3,zeros(size(extmask)),~extmask,zeros(size(extmask))));
+%   set(h4,'alphadata',0.2)
+%   hold off
+
+subplot(1,2,2)
+tmp=extmean;
+tmp(~extmask)=0.1;
+imshow(tmp, [])
+hold on
+plot(com_x, com_y, 'rx')
+pause(1)
+
+figure
+
+[x,cx,cy]=mym(sprintf('select maximage, centroidx,centroidy from %sdifspot where difspotid=%d',parameters.acq.name,struct_id));
+full=edf_read(sprintf('1_preprocessing/full/full%04d.edf', x));
+imshow(full, [])
+hold on
+plot(cx,cy,'rx')
+plot(com_x+parameters.acq.bb(1), com_y+parameters.acq.bb(2),'x')
+
+   drawnow
+   title(num2str(struct_id))
+   
+
+   
+end
+
+
+if 1 
+  tmp = imfill(summeddif_perim_mask,'holes');
+  tmp2=regionprops(double(tmp),'BoundingBox');
+  tmp2=tmp2.BoundingBox;
+
+% add SearchBoundingBox to bboxes table
+
+mysqlcmd=dbInsert(table_bboxes,...
+  'extspotID',struct_id,... % I changed here to the new names 
+	'Xorigin',tmp2(1),...     % I changed here to the new names
+  'Yorigin',tmp2(2),...     % I changed here to the new names
+  'Xsize',tmp2(3),...       % I changed here to the new names
+  'Ysize',tmp2(4),...       % I changed here to the new names ------Marcelo 08/12/06 - I stoped here...
+	'Xcentroid',com_x,...     % use new format of putting centroid and bb into a single table
+	'Ycentroid',com_y);        % use new format of putting centroid and bb into a single table
+mym(mysqlcmd);
+% get bboxID
+bboxID=mym('select last_insert_id()');
+
+% insert bboxID into extspot table
+mysqlcmd=dbInsert(table_extspot,...
+  'extspotID',struct_id,...
+  'searchbbID',bboxID);
+mym(mysqlcmd);
+end
+
+im=gaussianBlur(extmean,1);
+
+% polarity of image not important because only magnitude of gradient is used
+[fx,fy]=gradient(im);
+fmag=sqrt(fx.^2+fy.^2);
+
+% use a small part of the image to find the starting snake
+[roffset,coffset]=find(summeddif_perim_mask);
+
+[x_orig,y_orig]=gtMask2Poly(...
+  summeddif_perim_mask(...
+  min(roffset):max(roffset),...
+  min(coffset):max(coffset)));
+
+% adjust back to original coordinates
+x_orig=x_orig+min(coffset)-1;
+y_orig=y_orig+min(roffset)-1;
+
+x=x_orig;y=y_orig;
+
+
+%%%%%%%%%%%%%%
+% make some measures of the spot we are considering:
+defaultmaskarea=29000;
+maskarea=numel(summeddif_bw);
+arearatio=maskarea/defaultmaskarea;
+fprintf('Area ratio: %3.2f\n',arearatio);
+
+defaultmaskperim=575;
+tmp=regionprops(double(summeddif_bw),'perimeter');
+maskperim=round(tmp.Perimeter);
+perimratio=maskperim/defaultmaskperim;
+fprintf('Perimeter ratio: %3.2f\n',perimratio);
+
+% intensity variation
+% need bw mask of spot:
+if 1
+  bwtmp=poly2mask(x_orig,y_orig,size(extmean,2),size(extmean,1));
+  tmp_inside=extmean(bwtmp);
+  tmp_outside=extmean(~bwtmp);
+  mean_inside=mean(tmp_inside(:))*1e3;
+  mean_outside=mean(tmp_outside(:))*1e3;
+  defaultmeanratio=2.88/0.6; % stndxruct_id 700
+  meanratio=mean_inside/mean_outside;
+  % when intensity ratio is lower, snake is harder to bind to perimeter
+  intensityratio=meanratio/defaultmeanratio;
+  fprintf('Intensity ratio: %3.2f\n',intensityratio);
+end
+
+snakeoptions.elasticity=3;
+snakeoptions.rigidity=15;  % keep this high to prevent spurs from local features
+snakeoptions.viscosity=3;
+snakeoptions.forcefactor=5;
+snakeoptions.iterations=10; 
+
+snakeoptions.elasticity=snakeoptions.elasticity*arearatio.^2;
+%  snakeoptions.rigidity=10;  % keep this high to prevent spurs from local features
+%  snakeoptions.viscosity=5;
+%    snakeoptions.forcefactor=snakeoptions.forcefactor*perimratio;
+%  snakeoptions.iterations=5;
+snakeoptions;
+
+%%%%%%%%%%%%%%%
+
+pad=25;
+tmp_bbox=round([min(x(:))-pad min(y(:))-pad gtRange(x)+(2*pad) gtRange(y)+(2*pad)]);
+
+[u,v] = GVF(gtExtract(fmag,tmp_bbox), 0.05, 15);  % 0.2,80 % 0.3 15
+% Normalizing the GVF external force
+mag = sqrt(u.^2+v.^2);
+pxnorm = u./(mag+1e-10);pynorm = v./(mag+1e-10);
+
+forcefield.x=pxnorm;
+forcefield.y=pynorm;
+
+x=x-(tmp_bbox(1)+1);
+y=y-(tmp_bbox(2)+1);
+% should now remove points that are outside bbox
+if 0
+  x(y>size(mag,1))=[];
+  y(y>size(mag,1))=[];
+
+  y(x>size(mag,2))=[];
+  x(x>size(mag,2))=[];
+end
+if graphics.show_gvf
+  h_gvf=figure;
+  imagesc(mag,autolim(mag))
+  colorbar
+  hold on
+  quiver(pxnorm,pynorm,'r');
+  axis ij
+  axis equal
+  h_ax(1)=gca;
+end
+
+if graphics.show_snakeprogress && graphics.show_initialmatch
+  figure(h_initialmatch)
+  imagesc(gtExtract(extmean,tmp_bbox)),axis image,colormap(gray)
+  hold on
+  snakedisp(x,y,'r-')
+  h_ax(2)=gca;
+  if h_ax(1)~=0
+    linkaxes(h_ax,'xy')
+  end
+  axis image
+  drawnow
+end
+
+[x,y]=snakeinterp(x,y,20,1);
+origlength=length(x);
+clear hp
+converged=false;
+sfConverged([]); % reset sfConverged
+i=0;
+while not(converged)
+  i=i+1;
+  if i>100
+    break % get out of loop - we've taken too long
+  end
+  if length(x)<origlength/2
+    %      disp('Snake is too short!')
+    % break
+  end
+  [x2,y2]=snakedeform(x,y,forcefield,snakeoptions);
+  tmp=poly2mask(x,y,round(max(x)+5),round(max(y)+5));
+  area=sum(tmp(:));
+  converged=sfConverged(area);
+
+  [x,y]=snakeinterp(x2,y2,20,1);
+  if graphics.show_snakeprogress && graphics.show_initialmatch
+    figure(h_initialmatch)
+    if exist('hp','var')
+      delete(hp)
+    end
+    hp=snakedisp(x,y,'g.-');
+    axis image
+    title(['Deformation in progress,  iter = ' num2str(i*snakeoptions.iterations)])
+    drawnow
+    print('-dtiff',sprintf('perrin_%03d.tif',i));
+  end
+end
+if converged
+  disp('Converged')
+else
+  disp('Did NOT converge')
+end
+
+if graphics.show_snakefinal && graphics.show_initialmatch
+  if graphics.show_gvf
+    figure(h_gvf);
+    snakedisp(x,y,'g-')
+    title(['Structure ' num2str(struct_id)])
+  end
+%  figure(h_initialmatch)
+figure(andy_fig) 
+if graphics.show_snakeprogress
+    snakedisp(x,y,'g-');
+  else
+    snakedisp(x+(tmp_bbox(1)+1),y+(tmp_bbox(2)+1),'g-')
+  end
+  title(['Structure ' num2str(struct_id)])
+  
+  drawnow
+  
+end
+% restore snake coordinates to that of extinction image
+x=x+tmp_bbox(1);  % mussing +??
+y=y+tmp_bbox(2);
+
+% write snake to sql table
+tmp=repmat(struct_id,1,length(x));  % produce vector of repeated struct_id
+values=sprintf('("%f","%f","%f"),',[tmp; x(:)'; y(:)']);
+values(end)=[];  % remove final comma
+mysqlcmd=sprintf('insert into %s (snakeID,x,y) values %s',table_snakes,values);
+mym(mysqlcmd)
+
+tmp = poly2mask(x,y, parameters.acq.bb(4), parameters.acq.bb(3));
+props=regionprops(double(tmp),'Area','BoundingBox','Centroid');
+
+if 1 
+	% add (snake) BoundingBox to bboxes table
+mysqlcmd=dbInsert(table_bboxes,...
+  'extspotID',struct_id,... % I changed here to the new names 
+	'Xorigin',props.BoundingBox(1),...     % I changed here to the new names
+  'Yorigin',props.BoundingBox(2),...     % I changed here to the new names
+  'Xsize',props.BoundingBox(3),...       % I changed here to the new names
+  'Ysize',props.BoundingBox(4),...       % I changed here to the new names ------Marcelo 08/12/06 - I stoped here...
+	'Xcentroid',props.Centroid(1),...     % use new format of putting centroid and bb into a single table
+	'Ycentroid',props.Centroid(2));        % use new format of putting centroid and bb into a single table
+
+mym(mysqlcmd);
+
+% get bboxID
+bboxID=mym('select last_insert_id()');
+
+% update (snake) bboxID into extspot table
+mysqlcmd=dbUpdate(table_extspot,'extspotID',struct_id,...
+  'Area',props.Area,...
+	'snakeID',struct_id,...
+	'bbID',bboxID);
+mym(mysqlcmd);
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function flag=sfConverged(data1)
+    persistent diffdata data h_history
+    if isempty(data1)
+      clear data diffdata h_history
+      return
+    end
+    if numel(data)==0
+      data=[data1];
+      flag=false;
+      disp('*******************************************STARTING')
+      if graphics.show_convergence
+        h_history=figure;
+      end
+
+    else
+      data=[data;data1];
+      diffdata=diff(data);
+      if graphics.show_convergence
+        h_convergence=figure(h_history);
+        plot(abs(diffdata),'.-');
+      end
+      if abs(diffdata(end))<1
+        flag=true;
+      else
+        flag=false;
+      end
+
+    end
+  end
+
+  function [ndx1,ndx2]=sfWhichExtImages_new_format(struct_id)
+
+    [maxim,startim,endim]=mym(sprintf(...
+      'select MaxImage,ExtStartImage,ExtEndImage from %s where difspotID=%d',...
+      table_difspot,struct_id));
+
+    if (endim - startim + 1) <= 3
+      %if less than or equal to 3 images, do all of them
+      ndx1=startim;
+      ndx2=endim;
+      %      disp('one')
+      %else do three, centred around maxim
+    elseif maxim == endim;
+      %      disp('two')
+      ndx1 = maxim-2;
+      ndx2 = maxim;
+    elseif maxim == startim;
+      %      disp('three')
+      ndx1 = maxim;
+      ndx2 = maxim+2;
+    else
+      %      disp('four')
+      ndx1 = maxim-1;
+      ndx2 = maxim+1;
+    end
+
+    %ensure doesn't go outside limits - should never be able to anyway...
+    if ndx1 <0
+      ndx1=0;
+    end
+    %360 degree data range - 2*nproj
+    if ndx2 > ((2*parameters.acq.nproj) - 1)
+      ndx2=parameters.acq.nproj -1;
+    end
+    
+  end
+
+end
+
diff --git a/3_match_extspot/AutoFind_360wl.m b/3_match_extspot/AutoFind_360wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..7cdd153cf10a5abb2b246d2ebc5b27a77af7e0ff
--- /dev/null
+++ b/3_match_extspot/AutoFind_360wl.m
@@ -0,0 +1,611 @@
+function [output_point]=AutoFind_360(inputID,parameters,varargin)
+
+%adapt AutoFind_test to work on single 360 scan, rather than two halves
+
+%use a pair table which contains all difspots:
+%  | pairID | difAID | difBID |
+%where either of the difIDs can be null - unpaired spots
+
+%all possible difspots are contained in the single 360 degree difspot
+%table.  If there is pair information it is in the pairtable
+
+option.writeprotected = 0;    % if true: extspot table is writeprotected 
+
+
+warning on backtrace
+close all
+
+% data base connect
+%varargin of 1 means already connected
+connected=0;
+if ~isempty(varargin) 
+  connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SETUP VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+struct_id = inputID;
+name=parameters.acq.name;
+  
+% DB table names
+table_difspot=sprintf('%sdifspot',parameters.acq.name);
+table_extspot=sprintf('%sextspot',parameters.acq.name);
+table_snakes=sprintf('%ssnakes',parameters.acq.name);
+table_bboxes=sprintf('%sbboxes',parameters.acq.name);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%  AUTOFIND 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% options for graphical display
+ graphics.show_dif=1;
+ graphics.show_initialmatch=1;
+% graphics.show_gvf=false;
+% graphics.show_snakeprogress=false;
+% graphics.show_snakefinal=0;
+% graphics.show_convergence=false;
+
+graphics.show_dif=false;
+graphics.show_initialmatch=false;
+graphics.show_gvf=false;
+graphics.show_snakeprogress=false;
+graphics.show_snakefinal=false;
+graphics.show_convergence=false;
+
+% first check what parameters exist
+if ~exist('struct_id','var')
+  error('Please supply a structure ID')
+end
+
+fprintf('AUTO_FIND\n');
+fprintf('Name: %s\n',name);
+fprintf('Parameters: \n');
+fprintf('\tStructID: %d\n',struct_id);
+
+%is database empty?
+if (mym(sprintf('select count(*) from %s',table_extspot)))
+  disp('DB has extspot data already')
+else
+  disp('DB has no extspot data yet')
+end
+
+if option.writeprotected  
+if ~isempty(mym(sprintf('select extspotID from %s where extspotID=%d',table_extspot,struct_id)))
+  error('extspotID already exists - aborting')
+end
+else
+disp('OVERWRITING EXTSPOT!')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOAD DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+mysqlcmd=sprintf('select difspotID from %s where difspotID=%d',table_difspot,struct_id);
+if isempty(mym(mysqlcmd))
+  error('That difspot structure does not exist!');
+end
+
+%get 3 images (around the max image) to be correlated
+[ndx_im1,ndx_im2]=sfWhichExtImages_new_format(struct_id);
+%prepare variable for correlation map
+cc_sum=zeros(parameters.acq.bb(4), parameters.acq.bb(3)); 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Read images
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% read the summed images
+extmean=gtGetMeanFullImage(struct_id, parameters, 1); 
+summeddif=gtGetSummedDifSpot(struct_id, parameters, 1);
+
+%calc centre of mass, area of difspot
+com_x = sum(summeddif) * ((1:length(sum(summeddif)))') / sum(sum(summeddif));
+com_y = (sum(summeddif')*(1:length(sum(summeddif')))')/sum(sum(summeddif'));
+area = length(find(summeddif~=0));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate search area mask
+% use mask_extinction_function_pair
+%uses pair info if available
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+extmask=gtMaskExtinctionFunction_360(struct_id,parameters,1);%already DB connected
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% MAIN LOOP OF THREE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for ndx_im=ndx_im1:ndx_im2
+  fprintf('Examining image: %d\n',ndx_im);
+
+  ext=gtGetExtImage(ndx_im, parameters);              % read direct beam part of Full image
+  dif=gtGetDifImage(ndx_im,struct_id, parameters, 1); % 1 - already DB connected
+
+%variables for the gradient images
+  im_x=zeros(gtBboxSizeMat(parameters.acq.bb));
+  im_y=zeros(gtBboxSizeMat(parameters.acq.bb));
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% Gradient calculations
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  %make dif spot gradient, threshold
+  dif_med = medfilt2(dif, [3 3]); % ak 10/2007 - try changing to lower values for snow (small spots) - was [5 5]
+  [dif_gradx,dif_grady]=gradient(dif_med);
+
+  %dif_grad = sqrt((dif_gradx).^2+(dif_grady).^2);
+  %grad_thresh = (mean(dif_grad(:))+0.75*std(dif_grad(:)));
+  %grad_thresh2 = max(dif_grad(:));
+%ak 10/2007 - this seems to over estimate compared to the x or y only
+%gradients
+  grad_threshx = (mean(dif_gradx(:))+0.75*std(dif_gradx(:)));
+  grad_thresh2x = max(dif_gradx(:));  
+  grad_threshy = (mean(dif_grady(:))+0.75*std(dif_grady(:)));
+  grad_thresh2y = max(dif_grady(:));  
+  
+  grad_thresh=(grad_threshx+grad_threshy)/2;
+  
+  
+  dif_gradx_sign = sign(dif_gradx);
+ % dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+  dif_gradx_t1=abs(dif_gradx) > grad_threshx;
+  dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+  dif_grady_sign = sign(dif_grady);
+%  dif_grady_t1=abs(dif_grady) > grad_thresh;
+  dif_grady_t1=abs(dif_grady) > grad_threshy;
+  dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+  %make dif spot perimeter for display - snake input?
+  dif_spot = dif_med > 0.1*max(dif_med(:));               
+  dif_spot_perimeter=double(bwperim(dif_spot));
+
+  %median filter, find edges
+  ext_med = medfilt2(ext, [3 3]); % ak 10/2007 - try changing to lower values for snow (small spots) - was [10 10]
+  ext_edges=edge(ext_med,0.001);
+
+  [ext_gradx,ext_grady]=gradient(ext_med);
+
+  ext_gradx_sign = -sign(ext_gradx);
+  ext_gradx = abs(ext_gradx);
+ % ext_gradx_t1=and(ext_gradx>grad_thresh, ext_gradx<grad_thresh2);
+ ext_gradx_t1=and(ext_gradx>grad_threshx, ext_gradx<grad_thresh2x);
+  ext_gradx_t1 = ext_gradx_sign.*ext_gradx_t1;
+
+  ext_grady_sign = -sign(ext_grady);
+  ext_grady = abs(ext_grady);
+  %ext_grady_t1=and(ext_grady>grad_thresh, ext_grady<grad_thresh2);
+  ext_grady_t1=and(ext_grady>grad_threshy, ext_grady<grad_thresh2y);
+  ext_grady_t1 = ext_grady_sign.*ext_grady_t1;
+
+  ext_gradx_t1(logical(im_x)) = 0;    % what is this good for here ?
+  ext_grady_t1(logical(im_y)) = 0;    % idem....  wl 12/2007
+  %%%%%%%%%%%%%%%%%%%%%%%%
+  %pad dif_grad to size of ext to use correlate
+  dif_maskx = gtPlaceSubImage(dif_gradx_t1, zeros(size(ext)), 1, 1);
+  dif_masky = gtPlaceSubImage(dif_grady_t1, zeros(size(ext)), 1, 1);
+  %  dif_perim_mask = gtPlaceSubImage(dif_spot_perimeter, zeros(size(ext)), 1, 1);
+
+  summeddif_bw=summeddif>0.25*max(summeddif(:));  % summed difspot has already had a treshold applied to it - is this second threshold necessary ? 
+  summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+  summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+  summeddif_bw=bwmorph(summeddif_bw,'dilate',1);
+
+  summeddif_mask=gtPlaceSubImage(summeddif_bw,zeros(size(ext)),1,1);
+  dif_spot_mask=gtPlaceSubImage(dif_spot,zeros(size(ext)),1,1);
+
+  %%%%%%%%%%%%%%%%%%%%%%%%
+  % Look at previous diffraction spots
+  %%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  mysqlcmd=sprintf(['select extspotID from %s where (extspotID!=%d) and '...
+    '(extspotID=any(select difspotID from %s where %d between StartImage and EndImage))'],...
+    table_extspot,struct_id,table_difspot,ndx_im);
+
+  extspotIDs=mym(mysqlcmd)
+
+  %subtract prior extspots
+  fprintf('Removing %d spots from correlation image\n',length(extspotIDs));
+
+  for i=1:length(extspotIDs)
+    [tmpx,tmpy]=gtMaskPriorExtspot(extspotIDs(i), ndx_im, grad_thresh, parameters);
+		%note - only uses a single threshold when preparing gradient image
+    im_x(logical(tmpx))=0;
+    im_y(logical(tmpy))=0;
+  end
+
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Apply search area mask
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  ext_gradx_t1(~extmask)=0;
+  ext_grady_t1(~extmask)=0;
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% do correlation
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  cc_x=real(ifft2(fft2(ext_gradx_t1).*conj(fft2(dif_maskx))));% from correlate.m
+  cc_y=real(ifft2(fft2(ext_grady_t1).*conj(fft2(dif_masky))));% from correlate.m
+  cc_sum=cc_sum+ (cc_x+cc_y);
+
+  
+  
+end
+
+
+shift=gtFindMaxSubscripts(cc_sum);
+
+%apply shifts
+
+%dif_perim_mask=roll(dif_perim_mask,shift(1),shift(2));
+dif_spot_mask=roll(dif_spot_mask,shift(1),shift(2));
+[com_x,com_y]=gtShiftContour(...
+  com_x,com_y,...
+  shift(2),shift(1),...
+  size(dif_spot_mask,2),size(dif_spot_mask,1));
+
+output_point = round([com_x com_y]); %where user would click in find_spots...
+summeddif_mask=roll(summeddif_mask,shift(1),shift(2));
+
+% try to remove bad portion of wrapped mask
+marker=zeros(size(summeddif_mask));
+marker(round(com_y),round(com_x))=1;
+summeddif_mask=imreconstruct(marker,summeddif_mask);
+summeddif_perim_mask=bwperim(summeddif_mask);
+
+% show some results
+if graphics.show_dif
+%  h_dif=figure;
+%  imshow(dif,[])
+andy_fig=figure;
+subplot(1,2,1)
+imshow(gtPlaceSubImage(summeddif, zeros(size(ext)), 50,50), [])
+
+end
+if graphics.show_initialmatch
+  %something has change in how alpha is handled, so this doesn't work well
+  %now!
+%   h_initialmatch=figure;
+%   h1=imshow(extmean,[]);
+%   hold on
+%   h3=imagesc(cat(3,summeddif_perim_mask, zeros(size(summeddif_perim_mask)), zeros(size(summeddif_perim_mask))));
+%   set(h3,'alphadata',summeddif_perim_mask);
+%   plot(com_x, com_y, 'xr', 'markersize', 10)
+%   h4=imagesc(cat(3,zeros(size(extmask)),~extmask,zeros(size(extmask))));
+%   set(h4,'alphadata',0.2)
+%   hold off
+
+subplot(1,2,2)
+tmp=extmean;
+tmp(~extmask)=0.1;
+imshow(tmp, [])
+hold on
+plot(com_x, com_y, 'rx')
+pause(1)
+
+figure
+
+[x,cx,cy]=mym(sprintf('select maximage, centroidx,centroidy from %sdifspot where difspotid=%d',parameters.acq.name,struct_id));
+full=edf_read(sprintf('1_preprocessing/full/full%04d.edf', x));
+imshow(full, [])
+hold on
+plot(cx,cy,'rx')
+plot(com_x+parameters.acq.bb(1), com_y+parameters.acq.bb(2),'x')
+
+   drawnow
+   title(num2str(struct_id))
+   
+
+   
+end
+
+
+keyboard
+
+if 1 
+  tmp = imfill(summeddif_perim_mask,'holes');
+  tmp2=regionprops(double(tmp),'BoundingBox');
+  tmp2=tmp2.BoundingBox;
+
+% add SearchBoundingBox to bboxes table
+
+mysqlcmd=dbInsert(table_bboxes,...
+  'extspotID',struct_id,... % I changed here to the new names 
+	'Xorigin',tmp2(1),...     % I changed here to the new names
+  'Yorigin',tmp2(2),...     % I changed here to the new names
+  'Xsize',tmp2(3),...       % I changed here to the new names
+  'Ysize',tmp2(4),...       % I changed here to the new names ------Marcelo 08/12/06 - I stoped here...
+	'Xcentroid',com_x,...     % use new format of putting centroid and bb into a single table
+	'Ycentroid',com_y);        % use new format of putting centroid and bb into a single table
+mym(mysqlcmd);
+% get bboxID
+bboxID=mym('select last_insert_id()');
+
+
+% insert bboxID into extspot table
+mysqlcmd=dbInsert(table_extspot,...
+  'extspotID',struct_id,...
+  'searchbbID',bboxID);
+mym(mysqlcmd);
+end
+
+
+
+
+im=gaussianBlur(extmean,1);
+
+% polarity of image not important because only magnitude of gradient is used
+[fx,fy]=gradient(im);
+fmag=sqrt(fx.^2+fy.^2);
+
+% use a small part of the image to find the starting snake
+[roffset,coffset]=find(summeddif_perim_mask);
+
+[x_orig,y_orig]=gtMask2Poly(...
+  summeddif_perim_mask(...
+  min(roffset):max(roffset),...
+  min(coffset):max(coffset)));
+
+% adjust back to original coordinates
+x_orig=x_orig+min(coffset)-1;
+y_orig=y_orig+min(roffset)-1;
+
+x=x_orig;y=y_orig;
+
+
+%%%%%%%%%%%%%%
+% make some measures of the spot we are considering:
+defaultmaskarea=29000;
+maskarea=numel(summeddif_bw);
+arearatio=maskarea/defaultmaskarea;
+fprintf('Area ratio: %3.2f\n',arearatio);
+
+defaultmaskperim=575;
+tmp=regionprops(double(summeddif_bw),'perimeter');
+maskperim=round(tmp.Perimeter);
+perimratio=maskperim/defaultmaskperim;
+fprintf('Perimeter ratio: %3.2f\n',perimratio);
+
+% intensity variation
+% need bw mask of spot:
+if 1
+  bwtmp=poly2mask(x_orig,y_orig,size(extmean,2),size(extmean,1));
+  tmp_inside=extmean(bwtmp);
+  tmp_outside=extmean(~bwtmp);
+  mean_inside=mean(tmp_inside(:))*1e3;
+  mean_outside=mean(tmp_outside(:))*1e3;
+  defaultmeanratio=2.88/0.6; % stndxruct_id 700
+  meanratio=mean_inside/mean_outside;
+  % when intensity ratio is lower, snake is harder to bind to perimeter
+  intensityratio=meanratio/defaultmeanratio;
+  fprintf('Intensity ratio: %3.2f\n',intensityratio);
+end
+
+snakeoptions.elasticity=3;
+snakeoptions.rigidity=15;  % keep this high to prevent spurs from local features
+snakeoptions.viscosity=3;
+snakeoptions.forcefactor=5;
+snakeoptions.iterations=10; 
+
+snakeoptions.elasticity=snakeoptions.elasticity*arearatio.^2;
+%  snakeoptions.rigidity=10;  % keep this high to prevent spurs from local features
+%  snakeoptions.viscosity=5;
+%    snakeoptions.forcefactor=snakeoptions.forcefactor*perimratio;
+%  snakeoptions.iterations=5;
+snakeoptions;
+
+%%%%%%%%%%%%%%%
+
+pad=25;
+tmp_bbox=round([min(x(:))-pad min(y(:))-pad gtRange(x)+(2*pad) gtRange(y)+(2*pad)]);
+
+[u,v] = GVF(gtExtract(fmag,tmp_bbox), 0.05, 15);  % 0.2,80 % 0.3 15
+% Normalizing the GVF external force
+mag = sqrt(u.^2+v.^2);
+pxnorm = u./(mag+1e-10);pynorm = v./(mag+1e-10);
+
+forcefield.x=pxnorm;
+forcefield.y=pynorm;
+
+x=x-(tmp_bbox(1)+1);
+y=y-(tmp_bbox(2)+1);
+% should now remove points that are outside bbox
+if 0
+  x(y>size(mag,1))=[];
+  y(y>size(mag,1))=[];
+
+  y(x>size(mag,2))=[];
+  x(x>size(mag,2))=[];
+end
+if graphics.show_gvf
+  h_gvf=figure;
+  imagesc(mag,autolim(mag))
+  colorbar
+  hold on
+  quiver(pxnorm,pynorm,'r');
+  axis ij
+  axis equal
+  h_ax(1)=gca;
+end
+
+if graphics.show_snakeprogress && graphics.show_initialmatch
+  figure(h_initialmatch)
+  imagesc(gtExtract(extmean,tmp_bbox)),axis image,colormap(gray)
+  hold on
+  snakedisp(x,y,'r-')
+  h_ax(2)=gca;
+  if h_ax(1)~=0
+    linkaxes(h_ax,'xy')
+  end
+  axis image
+  drawnow
+end
+
+[x,y]=snakeinterp(x,y,20,1);
+origlength=length(x);
+clear hp
+converged=false;
+sfConverged([]); % reset sfConverged
+i=0;
+while not(converged)
+  i=i+1;
+  if i>100
+    break % get out of loop - we've taken too long
+  end
+  if length(x)<origlength/2
+    %      disp('Snake is too short!')
+    % break
+  end
+  [x2,y2]=snakedeform(x,y,forcefield,snakeoptions);
+  tmp=poly2mask(x,y,round(max(x)+5),round(max(y)+5));
+  area=sum(tmp(:));
+  converged=sfConverged(area);
+
+  [x,y]=snakeinterp(x2,y2,20,1);
+  if graphics.show_snakeprogress && graphics.show_initialmatch
+    figure(h_initialmatch)
+    if exist('hp','var')
+      delete(hp)
+    end
+    hp=snakedisp(x,y,'g.-');
+    axis image
+    title(['Deformation in progress,  iter = ' num2str(i*snakeoptions.iterations)])
+    drawnow
+    print('-dtiff',sprintf('perrin_%03d.tif',i));
+  end
+end
+if converged
+  disp('Converged')
+else
+  disp('Did NOT converge')
+end
+
+if graphics.show_snakefinal && graphics.show_initialmatch
+  if graphics.show_gvf
+    figure(h_gvf);
+    snakedisp(x,y,'g-')
+    title(['Structure ' num2str(struct_id)])
+  end
+%  figure(h_initialmatch)
+figure(andy_fig) 
+if graphics.show_snakeprogress
+    snakedisp(x,y,'g-');
+  else
+    snakedisp(x+(tmp_bbox(1)+1),y+(tmp_bbox(2)+1),'g-')
+  end
+  title(['Structure ' num2str(struct_id)])
+  
+  drawnow
+  
+end
+% restore snake coordinates to that of extinction image
+x=x+tmp_bbox(1);  % mussing +??
+y=y+tmp_bbox(2);
+
+% write snake to sql table
+tmp=repmat(struct_id,1,length(x));  % produce vector of repeated struct_id
+values=sprintf('("%f","%f","%f"),',[tmp; x(:)'; y(:)']);
+values(end)=[];  % remove final comma
+mysqlcmd=sprintf('insert into %s (snakeID,x,y) values %s',table_snakes,values);
+mym(mysqlcmd)
+
+tmp = poly2mask(x,y, parameters.acq.bb(4), parameters.acq.bb(3));
+props=regionprops(double(tmp),'Area','BoundingBox','Centroid');
+
+if 1 
+	% add (snake) BoundingBox to bboxes table
+mysqlcmd=dbInsert(table_bboxes,...
+  'extspotID',struct_id,... % I changed here to the new names 
+	'Xorigin',props.BoundingBox(1),...     % I changed here to the new names
+  'Yorigin',props.BoundingBox(2),...     % I changed here to the new names
+  'Xsize',props.BoundingBox(3),...       % I changed here to the new names
+  'Ysize',props.BoundingBox(4),...       % I changed here to the new names ------Marcelo 08/12/06 - I stoped here...
+	'Xcentroid',props.Centroid(1),...     % use new format of putting centroid and bb into a single table
+	'Ycentroid',props.Centroid(2));        % use new format of putting centroid and bb into a single table
+
+mym(mysqlcmd);
+
+% get bboxID
+bboxID=mym('select last_insert_id()');
+
+% update (snake) bboxID into extspot table
+mysqlcmd=dbUpdate(table_extspot,'extspotID',struct_id,...
+  'Area',props.Area,...
+	'snakeID',struct_id,...
+	'bbID',bboxID);
+mym(mysqlcmd);
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function flag=sfConverged(data1)
+    persistent diffdata data h_history
+    if isempty(data1)
+      clear data diffdata h_history
+      return
+    end
+    if numel(data)==0
+      data=[data1];
+      flag=false;
+      disp('*******************************************STARTING')
+      if graphics.show_convergence
+        h_history=figure;
+      end
+
+    else
+      data=[data;data1];
+      diffdata=diff(data);
+      if graphics.show_convergence
+        h_convergence=figure(h_history);
+        plot(abs(diffdata),'.-');
+      end
+      if abs(diffdata(end))<1
+        flag=true;
+      else
+        flag=false;
+      end
+
+    end
+  end
+
+  function [ndx1,ndx2]=sfWhichExtImages_new_format(struct_id)
+
+    [maxim,startim,endim]=mym(sprintf(...
+      'select MaxImage,ExtStartImage,ExtEndImage from %s where difspotID=%d',...
+      table_difspot,struct_id));
+
+    if (endim - startim + 1) <= 3
+      %if less than or equal to 3 images, do all of them
+      ndx1=startim;
+      ndx2=endim;
+      %      disp('one')
+      %else do three, centred around maxim
+    elseif maxim == endim;
+      %      disp('two')
+      ndx1 = maxim-2;
+      ndx2 = maxim;
+    elseif maxim == startim;
+      %      disp('three')
+      ndx1 = maxim;
+      ndx2 = maxim+2;
+    else
+      %      disp('four')
+      ndx1 = maxim-1;
+      ndx2 = maxim+1;
+    end
+
+    %ensure doesn't go outside limits - should never be able to anyway...
+    if ndx1 <0
+      ndx1=0;
+    end
+    %360 degree data range - 2*nproj
+    if ndx2 > ((2*parameters.acq.nproj) - 1)
+      ndx2=parameters.acq.nproj -1;
+    end
+    
+  end
+
+end
+
diff --git a/3_match_extspot/auto_find.m b/3_match_extspot/auto_find.m
new file mode 100755
index 0000000000000000000000000000000000000000..f655155ef34b7550af9d7dcaaf834b531f062e44
--- /dev/null
+++ b/3_match_extspot/auto_find.m
@@ -0,0 +1,254 @@
+function [output_point]=auto_find(struct_id,saveflag)
+global app;
+
+%get ext image
+%  %create the summed ext image
+ext=zeros(app.data.ext.ysize, app.data.ext.xsize);
+disp([num2str(app.extspot(struct_id).ExtEndImage-app.extspot(struct_id).ExtStartImage+1) ' images in sum'])
+for i=app.extspot(struct_id).ExtStartImage:app.extspot(struct_id).ExtEndImage
+  ext = ext + edf_read(sprintf('ext/ext%04d.edf',i));
+end
+extsummed=ext/(app.extspot(struct_id).EndImage-app.extspot(struct_id).StartImage+1);
+
+%read maximum intensity ext image from full
+ext = edf_read(sprintf('full/full%04d.edf',app.extspot(struct_id).MaxImage),app.bb.directbeam);
+
+% make a mask for the extinction image
+% use mask_extinction_function, which determines 180 degree (single difspot)
+% or 360 degree (pair of difspots) treatment
+
+%ext_mask = mask_extinction_function(struct_id);
+
+
+%  %get the difspot image, transpose
+%  dif = edf_read(sprintf('difspot/difspot%05d.edf',app.extspot(struct_id).ID))';
+
+%read max intensity difspot from full
+dif = edf_read(sprintf('full/full%04d.edf',app.extspot(struct_id).MaxImage),app.extspot(struct_id).BoundingBox);
+
+
+%calc centre of mass, area of difspot
+com_x = sum(dif) * ([1:length(sum(dif))]') / sum(sum(dif));
+com_y = (sum(dif')*[1:length(sum(dif'))]')/sum(sum(dif'));
+area = length(find(dif~=0));
+
+
+%ext - direct beam image of sample, containing extinction spots
+%dif - diffraction spot image
+
+%   %attempt to reduce fringing at top and bottom in s5_dct1_
+%   ext=roifill(ext,[1 471 471 1],[1 1 7 7]);
+%   ext=roifill(ext,[1 471 471 1],[390 390 400 400]);
+%   figure(1); imshow(ext,[]);
+%   figure(2); imshow(dif,[]);
+%   iptwindowalign(figure(1),'right',figure(2),'left')
+%   iptwindowalign(figure(1),'top',figure(2),'top')
+
+
+%%%%%%%%%%%%%%%%%%%
+% Gradient stuff
+%%%%%%%%%%%%%%%%%%%
+
+%make dif spot gradient, threshold
+dif_med = medfilt2(dif, [5 5]);
+[dif_gradx,dif_grady]=gradient(dif_med);
+
+dif_grad = sqrt((dif_gradx).^2+(dif_grady).^2);
+grad_thresh = (mean(dif_grad(:))+1*std(dif_grad(:)));
+grad_thresh2 = max(dif_grad(:));
+
+dif_gradx_sign = sign(dif_gradx);
+dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+dif_grady_sign = sign(dif_grady);
+dif_grady_t1=abs(dif_grady) > grad_thresh;
+dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+%make dif spot perimeter for display - snake input?
+dif_spot = dif_med > 0.1*max(dif_med(:));
+dif_spot_perimeter=double(bwperim(dif_spot));
+
+%median filter, find edges
+ext_med = medfilt2(ext, [10 10]);
+ext_edges=edge(ext_med,0.001);
+
+[ext_gradx,ext_grady]=gradient(ext_med);
+
+ext_gradx_sign = -sign(ext_gradx);
+ext_gradx = abs(ext_gradx);
+ext_gradx_t1=and(ext_gradx>grad_thresh, ext_gradx<grad_thresh2);
+ext_gradx_t1 = ext_gradx_sign.*ext_gradx_t1;
+
+ext_grady_sign = -sign(ext_grady);
+ext_grady = abs(ext_grady);
+ext_grady_t1=and(ext_grady>grad_thresh, ext_grady<grad_thresh2);
+ext_grady_t1 = ext_grady_sign.*ext_grady_t1;
+
+%pad dif_grad to size of ext to use correlate
+dif_maskx=zeros(size(ext));
+dif_maskx(1:size(dif_gradx_t1,1),1:size(dif_gradx_t1,2))=dif_gradx_t1;
+dif_masky=zeros(size(ext));
+dif_masky(1:size(dif_grady_t1,1),1:size(dif_grady_t1,2))=dif_grady_t1;
+
+dif_perim_mask=zeros(size(ext));
+dif_perim_mask(1:size(dif_gradx_t1,1),1:size(dif_gradx_t1,2))=dif_spot_perimeter;
+dif_spot_mask=zeros(size(ext));
+dif_spot_mask(1:size(dif_gradx_t1,1),1:size(dif_gradx_t1,2))=dif_spot;
+
+
+if 1
+  disp('Using mask to reduce search area')
+  extmask=mask_extinction_function(struct_id);
+  extmask=extmask(1:end-1,1:end-1);
+
+  ext_gradx_t1(~extmask)=0;
+  ext_grady_t1(~extmask)=0;
+else
+  extmask=ones(2048);
+end
+% do correlation
+cc_x=abs(ifft2(fft2(ext_gradx_t1).*conj(fft2(dif_maskx))));% from correlate.m
+cc_y=abs(ifft2(fft2(ext_grady_t1).*conj(fft2(dif_masky))));% from correlate.m
+
+cc= sqrt(cc_x.^2 + cc_y.^2);
+
+[tmp,tmp2] = max(cc(:));
+[tmp3,tmp4] = ind2sub(size(cc),tmp2);
+shift = [tmp3 tmp4];
+
+%apply shifts
+dif_perim_mask=roll(dif_perim_mask,shift(1),shift(2));
+dif_spot_mask=roll(dif_spot_mask,shift(1),shift(2));
+com_x = com_x + shift(2);
+com_y = com_y + shift(1);
+output_point = round([com_x com_y]); %where user would click in find_spots...
+
+if 1
+  % produce display
+if 0
+  figure(1)
+  imshow(dif,[]);
+end
+  figure(2)
+  % set(2,'visible','off')
+  clf
+  h1=imshow(ext,[]);
+  hold on
+  h3=imagesc(cat(3,dif_perim_mask, zeros(size(dif_perim_mask)), zeros(size(dif_perim_mask))));
+  set(h3,'alphadata',dif_perim_mask);
+  plot(com_x, com_y, 'xr', 'markersize', 10)
+  h4=imagesc(cat(3,zeros(size(extmask)),~extmask,zeros(size(extmask))));
+  set(h4,'alphadata',0.2)
+  hold off
+  drawnow
+  title(num2str(struct_id))
+end
+global point
+point(struct_id).x=com_x;
+point(struct_id).y=com_y;
+
+% save if so requested
+if exist('saveflag','var') && saveflag==true
+  disp('Saving...')
+  fname=sprintf('/data/id19/graintracking/tmp/anotherovernight%04d.jpg',struct_id);
+  save('/data/id19/graintracking/tmp/anotherovernight.mat','point')
+  print(gcf,'-djpeg',fname)
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%ength(h_ax)==2
+disp('Snake code')
+im=extsummed;
+
+if 1
+  disp('Blurring for snake')
+  im=gaussianBlur(im,1);
+end
+perim=dif_perim_mask;
+[fx,fy]=gradient(im);
+fmag=sqrt(fx.^2+fy.^2);
+ext_snake=-im;  % make the spot white
+[y,x]=find(perim);
+
+% gtOPP hangs if there are two contours in 'perimeter'.. FIX!
+
+
+[x,y]=gtOrderPerimeterPoints(x,y);
+
+
+[u,v] = GVF(fmag, 0.2, 15);  % 0.2,80
+disp(' Normalizing the GVF external force ...');
+mag = sqrt(u.^2+v.^2);
+pxnorm = u./(mag+1e-10);pynorm = v./(mag+1e-10);
+px=u;py=v;
+
+% good for 700
+tension=.1;
+rigidity=.5;
+viscosity=1;  % must be greater than 0.1 or so!
+force=1;  % positive if the spot is bright, negative if the spot is dark
+iter=5;
+% good for ...
+%snakeoptions.tension=0.5;
+%snakeoptions.rigidity=1;
+%snakeoptions.viscosity=1;
+%snakeoptions.forcemultiplier=1;
+%snakeoptions.iterations=5;
+
+if 0
+  figure(3);
+  clf
+  imagesc(mag,[0 0.08])
+  hold on
+  quiver(px*100,py*100,'r');
+  axis ij
+  axis equal
+  pad=25;
+  axis([min(x(:))-pad max(x(:))+pad min(y(:))-pad max(y(:))+pad])
+  h_ax(1)=gca;
+end
+
+figure(2)
+clf
+imagesc(extsummed),axis image,colormap(gray)
+axis equal
+pad=25;
+axis([min(x(:))-pad max(x(:))+pad min(y(:))-pad max(y(:))+pad])
+hold on
+snakedisp(x,y,'r-')
+h_ax(2)=gca;
+if h_ax(1)~=0
+  linkaxes(h_ax,'xy')
+end
+
+[x,y]=snakeinterp(x,y,2,1);
+drawnow
+clear hp
+%forcefield.x=pxnorm;
+%forcefield.y=pynorm;
+for i=1:10,
+%  [x,y]=gtSnakeDeform(x,y,forcefield,snakeoptions);
+  [x,y] = snakedeform(x,y,tension,rigidity,viscosity,force,pxnorm,pynorm,iter);
+  %  [x,y] = snakeinterp(x,y,5,0.5);
+  [x,y]=snakeinterp(x,y,2,1);
+  if exist('hp','var')
+    delete(hp)
+  end
+%  hp=snakedisp(x,y,'g.-');
+%  title(['Deformation in progress,  iter = ' num2str(i*iter)])
+%  drawnow
+end
+snakedisp(x,y,'g-')
+
+% save if so requested
+if exist('saveflag','var') && saveflag==true
+  disp('Saving snake...')
+  fname=sprintf('/data/id19/graintracking/tmp/snake%04d.jpg',struct_id);
+  print(gcf,'-djpeg',fname)
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+end
+
+
diff --git a/3_match_extspot/auto_find_snake.m b/3_match_extspot/auto_find_snake.m
new file mode 100755
index 0000000000000000000000000000000000000000..cc5e4e126f826bf69a16c05d9b375ea506755848
--- /dev/null
+++ b/3_match_extspot/auto_find_snake.m
@@ -0,0 +1,364 @@
+%try some ideas to match diff and ext spots automatically.
+%this script has to start from the app.dir directory, otherwise it crashes
+
+%Andy, 8/2006
+
+function [output_point]=auto_find(struct_id,option,saveflag)
+
+
+global app;
+
+
+
+%get ext image
+
+%  %create the summed ext image
+%  ext=zeros(app.data.ext.ysize, app.data.ext.xsize);
+%  for i=app.extspot(struct_id).ExtStartImage:app.extspot(struct_id).ExtEndImage
+%    ext = ext + edf_read(sprintf('ext/ext%04d.edf',i));
+%  end
+%  ext=ext/(app.extspot(struct_id).EndImage-app.extspot(struct_id).StartImage+1);
+
+%read maximum intensity ext image from full
+ext = edf_read(sprintf('full/full%04d.edf',app.extspot(struct_id).MaxImage),app.bb.directbeam);
+
+%  %get the difspot image, transpose
+%  dif = edf_read(sprintf('difspot/difspot%05d.edf',app.extspot(struct_id).ID))';
+
+%read max intensity difspot from full
+dif = edf_read(sprintf('full/full%04d.edf',app.extspot(struct_id).MaxImage),app.extspot(struct_id).BoundingBox);
+
+
+%calc centre of mass, area of difspot
+com_x = sum(dif) * ([1:length(sum(dif))]') / sum(sum(dif));
+com_y = (sum(dif')*[1:length(sum(dif'))]')/sum(sum(dif'));
+area = length(find(dif~=0));
+
+%ext - direct beam image of sample, containing extinction spots
+%dif - diffraction spot image
+
+close all
+
+%   %attempt to reduce fringing at top and bottom in s5_dct1_
+%   ext=roifill(ext,[1 471 471 1],[1 1 7 7]);
+%   ext=roifill(ext,[1 471 471 1],[390 390 400 400]);
+%   figure(1); imshow(ext,[]);
+%   figure(2); imshow(dif,[]);
+%   iptwindowalign(figure(1),'right',figure(2),'left')
+%   iptwindowalign(figure(1),'top',figure(2),'top')
+
+
+
+switch option
+  case 'gradient'
+    sfGradient
+    %correlation of edge detection image
+
+  case 'gradient2'%correlation of edge detection image
+    sfGradient2
+  case 'subtraction'
+    sfSubtraction
+
+end
+
+  function sfGradient2
+    %make dif spot gradient, threshold
+    dif_med = medfilt2(dif, [5 5]);
+    [dif_gradx,dif_grady]=gradient(dif_med);
+
+    dif_grad = sqrt((dif_gradx).^2+(dif_grady).^2);
+    grad_thresh = (mean(dif_grad(:))+1*std(dif_grad(:)));
+    grad_thresh2 = max(dif_grad(:));
+
+    dif_gradx_sign = sign(dif_gradx);
+    dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+    dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+    dif_grady_sign = sign(dif_grady);
+    dif_grady_t1=abs(dif_grady) > grad_thresh;
+    dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+    %make dif spot perimeter for display - snake input?
+    dif_spot = dif_med > 0.1*max(dif_med(:));
+    dif_spot_perimeter=double(bwperim(dif_spot));
+
+    %median filter, find edges
+    ext_med = medfilt2(ext, [10 10]);
+    ext_edges=edge(ext_med,0.001);
+
+    [ext_gradx,ext_grady]=gradient(ext_med);
+
+    ext_gradx_sign = -sign(ext_gradx);
+    ext_gradx = abs(ext_gradx);
+    ext_gradx_t1=and(ext_gradx>grad_thresh, ext_gradx<grad_thresh2);
+    ext_gradx_t1 = ext_gradx_sign.*ext_gradx_t1;
+
+    ext_grady_sign = -sign(ext_grady);
+    ext_grady = abs(ext_grady);
+    ext_grady_t1=and(ext_grady>grad_thresh, ext_grady<grad_thresh2);
+    ext_grady_t1 = ext_grady_sign.*ext_grady_t1;
+
+    %pad dif_grad to size of ext to use correlate
+    dif_maskx=zeros(size(ext));
+    dif_maskx(1:size(dif_gradx_t1,1),1:size(dif_gradx_t1,2))=dif_gradx_t1;
+    dif_masky=zeros(size(ext));
+    dif_masky(1:size(dif_grady_t1,1),1:size(dif_grady_t1,2))=dif_grady_t1;
+
+    dif_perim_mask=zeros(size(ext));
+    dif_perim_mask(1:size(dif_gradx_t1,1),1:size(dif_gradx_t1,2))=dif_spot_perimeter;
+    dif_spot_mask=zeros(size(ext));
+    dif_spot_mask(1:size(dif_gradx_t1,1),1:size(dif_gradx_t1,2))=dif_spot;
+
+    % do correlation
+    cc_x=abs(ifft2(fft2(ext_gradx_t1).*conj(fft2(dif_maskx))));% from correlate.m
+    cc_y=abs(ifft2(fft2(ext_grady_t1).*conj(fft2(dif_masky))));% from correlate.m
+
+    cc= sqrt(cc_x.^2 + cc_y.^2);
+
+    [tmp,tmp2] = max(cc(:));
+    [tmp3,tmp4] = ind2sub(size(cc),tmp2);
+    shift = [tmp3 tmp4];
+
+    %apply shifts
+    dif_perim_mask=roll(dif_perim_mask,shift(1),shift(2));
+    dif_spot_mask=roll(dif_spot_mask,shift(1),shift(2));
+    com_x = com_x + shift(2);
+    com_y = com_y + shift(1);
+    output_point = round([com_x com_y]); %where user would click in find_spots...
+
+    % produce display
+    figure(1)
+    %set(1,'visible','off')
+    imshow(dif,[]);
+
+    figure(2)
+    % set(2,'visible','off')
+    clf
+    h1=imshow(ext,[]);
+    hold on
+    h3=imagesc(cat(3,dif_perim_mask, zeros(size(dif_perim_mask)), zeros(size(dif_perim_mask))));
+    set(h3,'alphadata',dif_perim_mask);
+    plot(com_x, com_y, 'xr', 'markersize', 10)
+    hold off
+    drawnow
+    global point
+    title(num2str(struct_id))
+    point(struct_id).x=com_x;
+    point(struct_id).y=com_y;
+    h_ax(1)=gca;
+
+    % save if so requested
+    if exist('saveflag','var') && saveflag==true
+      fname=sprintf('/data/id19/graintracking/tmp/overnight%04d.jpg',struct_id);
+      save('/data/id19/graintracking/tmp/overnight.mat','point')
+      print(gcf,'-djpeg',fname)
+    end
+
+    if 1 % start snake stuff
+      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+      % snake moves towards the light
+      ext_snake=gtNormaliseImage(ext);
+      keyboard
+      disp(' Compute GVF ...');
+      disp('Low rez gvf!');
+      [u,v] = GVF(ext_snake, 0.2, 20);  % 0.2,80
+
+      disp(' Nomalizing the GVF external force ...');
+      mag = sqrt(u.^2+v.^2);
+      px = u./(mag+1e-10); py = v./(mag+1e-10);
+
+      % display the gradient of the edge map
+      [fx,fy] = gradient(ext_snake);
+      %     subplot(223); quiver(fx,fy);
+      %     axis off; axis equal; axis 'ij';     % fix the axis
+      %     title('edge map gradient');
+
+      % display the GVF
+      figure(3); quiver(px,py);
+      hold on
+      h4=imagesc(cat(3,dif_perim_mask, zeros(size(dif_perim_mask)), zeros(size(dif_perim_mask))));
+      set(h4,'alphadata',dif_perim_mask);
+      plot(com_x, com_y, 'xr', 'markersize', 10)
+      hold off
+      %     axis off; axis equal; axis 'ij';     % fix the axis
+      %    title('normalized GVF field');
+      h_ax(2)=gca;
+      linkaxes(h_ax,'xy')
+pause
+      % snake deformation
+      close all
+      figure(1); clf
+      colormap(gray);
+      b=imagesc(ext_snake);
+      set(b,'alphadata',0.5);
+      hold on
+
+      % find polygon that is equivalent to perim mask of difpot
+      [y,x]=find(dif_perim_mask);
+      [x,y]=gtOrderPerimeterPoints(x,y);  % sort them out properly
+
+      snakedisp(x,y,'r.-')
+
+      [x,y] = snakeinterp(x,y,20,0.5);
+
+
+      elastic=0.15;
+      rigid=0.5;
+      viscous=0.3;
+      force=-.05;  % positive if the spot is bright, negative if the spot is dark
+      iter=5;
+      for i=1:25,
+        [x,y] = snakedeform(x,y,elastic,rigid,viscous,force,px,py,iter);
+        [x,y] = snakeinterp(x,y,5,0.5);
+        snakedisp(x,y,'r.-')
+        title(['Deformation in progress,  iter = ' num2str(i*iter)])
+        drawnow
+      end
+
+      %
+      % NOTE:
+      %
+      % traditional snake and distance snake differed from GVF snake only
+      %   by using different external force field. In order to produce the
+      %   corresponding external force field, use the following (all
+      %   assuming edge map f is in memory).
+      %
+      % traditional snake:
+      %   f0 = gaussianBlur(f,1);
+      %   [px,py] = gradient(f0);
+      %
+      % distance snake:
+      %   D = dt(f>0.5);  % distance transform (dt) require binary edge map
+      %   [px,py] = gradient(-D);
+      %
+      % [px,py] is the external force field in both cases
+      %
+      % balloon model using a different matlab function "snakedeform2"
+      % instead of "snakedeform". The external force could be any force
+      % field generated above.
+      %
+      % an example of using it is as follows
+      %       [x,y] = snakedeform2(x,y, alpha, beta, gamma, kappa, kappap, px,py,2);
+      % do a "help snakedeform2" for more details
+      %
+
+
+
+      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    end
+  end
+
+  function sfGradient
+    %dif_norm=gtNormaliseImage(dif);
+    %find perimeter of difspot
+    %   dif_spot=dif_norm>0.1;
+    dif_spot = medfilt2(dif, [5 5]);
+    dif_spot = dif_spot > 0.1*max(dif_spot(:));
+    dif_spot_perimeter=double(bwperim(dif_spot));
+
+    %[gx,gy]=gradient(ext);
+    %ext_grad=sqrt(gx.^2+gy.^2);
+
+    %median filter, find edges
+    ext_med = medfilt2(ext, [10 10]);
+    ext_edges=edge(ext_med,0.001);
+
+    [gradx,grady]=gradient(ext_med);
+    ext_grad = sqrt((gradx).^2+(grady).^2);
+
+    ext_grad_t1=ext_grad>(mean(ext_grad(:))+1*std(ext_grad(:)));
+
+    %pad dif_grad to size of ext to use correlate
+    dif_perim_mask=zeros(size(ext));
+    dif_perim_mask(1:size(dif_spot_perimeter,1),1:size(dif_spot_perimeter,2))=dif_spot_perimeter;
+
+
+    dif_fullsize=zeros(size(ext));
+    dif_fullsize(1:size(dif,1),1:size(dif,2))=dif;
+
+
+
+    %do correlation
+    shift = round(correlate(ext_edges,dif_perim_mask));
+    dif_perim_mask2=roll(dif_perim_mask,shift(1),shift(2));
+    dif_fullsize=roll(dif_fullsize,shift(1),shift(2));
+
+    shift2=round(correlate(ext_grad_t1,dif_perim_mask));
+    tmp2=roll(dif_perim_mask,shift2(1),shift2(2));
+
+    %%%%%%%%%%
+    if 0
+      % cross-correlate BW and T_offset to recover offset
+      cc = normxcorr2(dif_spot_perimeter,ext_edges);
+      [max_cc, imax] = max(abs(cc(:)));
+      [ypeak, xpeak] = ind2sub(size(cc),imax(1));
+      xpeak=xpeak-size(dif_spot_perimeter,2);
+      ypeak=ypeak-size(dif_spot_perimeter,1);
+      dif_perim_mask3=gtShift(dif_perim_mask,xpeak,-ypeak);
+    end
+    %%%%%%%%%
+
+    com_x = com_x + shift(2);
+    com_y = com_y + shift(1);
+    output_point = round([com_x com_y]); %where user would click in find_spots...
+
+
+    figure(1)
+    clf
+    h1=imshow(gtNormaliseImage(ext),[]);
+    hold on
+    h3=imagesc(tmp2);
+    set(h3,'alphadata',0.3);
+    hold off
+    drawnow
+
+  end
+  function sfSubtraction
+
+    dif=gtNormaliseImage(dif);
+    ext=gtNormaliseImage(ext);
+
+    ext = medfilt2(ext,[5 5]);
+
+    %estimate centre of dif
+    c_dif=(size(dif)./2);
+    imshow(dif,[]);
+    hold on
+    plot(c_dif(2),c_dif(1),'xg');
+
+
+
+    result = nlfilter(ext,size(dif),@calc_dif);
+
+    dummy=find(result == min(result(:)));
+
+
+    figure;
+    imshow(ext,[]);
+    hold on
+
+    for i=1:length(dummy);
+
+      col = ceil(dummy(i)/size(ext,1));
+      row = dummy(i)-((col-1)*size(ext,1));
+
+      col = col;%+c_dif(2);
+      row = row;%+c_dif(1);
+
+      plot(col,row,'xr');
+
+    end
+    function output = calc_dif(nhood)
+
+      temp = (-nhood) + dif;
+      temp = abs(temp);
+      temp = sum(temp(:));
+      output = temp;
+
+    end
+
+  end
+end
+
+
diff --git a/3_match_extspot/backpro.m b/3_match_extspot/backpro.m
new file mode 100755
index 0000000000000000000000000000000000000000..c13b2f1aed14aa419f61eeb99f3489be384151b6
--- /dev/null
+++ b/3_match_extspot/backpro.m
@@ -0,0 +1,56 @@
+function img=backpro(sino,theta)
+
+    
+    %theta=theta+pi;  probably wrong !
+	%interp='linear';
+    interp='nearest neighbor';
+    
+	N=size(sino,1);
+
+
+    img = zeros(N);        % Allocate memory for the image.
+
+	% Define the x & y axes for the reconstructed image so that the origin
+	% (center) is in the spot which RADON would choose.
+	xax = (1:N)-ceil(N/2);
+	x = repmat(xax, N, 1);    % x coordinates, the y coordinates are rot90(x)
+	y = rot90(x);
+
+	costheta = cos(theta);
+	sintheta = sin(theta);
+	ctrIdx = ceil(N/2);     % index of the center of the projections
+
+	% Zero pad the projections to size 1+2*ceil(N/sqrt(2)) if this
+	% quantity is greater than the length of the projections
+	imgDiag = 2*ceil(N/sqrt(2))+1;  % largest distance through image.
+	if size(sino,1) < imgDiag
+		rz = imgDiag - size(sino,1);  % how many rows of zeros
+		sino = [zeros(ceil(rz/2),size(sino,2)); sino; zeros(floor(rz/2),size(sino,2))];
+		ctrIdx = ctrIdx+ceil(rz/2);
+	end
+
+	% Backprojection - vectorized in (x,y), looping over theta
+	if strcmp(interp, 'nearest neighbor')
+		for i=1:length(theta)
+			proj = sino(:,i);
+			t = round(x*costheta(i) + y*sintheta(i));
+			img = img + proj(t+ctrIdx);
+		end
+	elseif strcmp(interp, 'linear')
+		for i=1:length(theta)
+			proj = sino(:,i);
+			t = x.*costheta(i) + y.*sintheta(i);
+			a = floor(t);
+			img = img + (t-a).*proj(a+1+ctrIdx) + (a+1-t).*proj(a+ctrIdx);
+		end
+	elseif strcmp(interp, 'spline')
+		for i=1:length(theta)
+			proj = sino(:,i);
+			taxis = (1:size(sino,1)) - ctrIdx;
+			t = x.*costheta(i) + y.*sintheta(i);
+			projContrib = interp1(taxis,proj,t(:),'*spline');
+			img = img + reshape(projContrib,N,N);
+		end
+	end
+
+
diff --git a/3_match_extspot/backpro_new.m b/3_match_extspot/backpro_new.m
new file mode 100755
index 0000000000000000000000000000000000000000..6d968da001e9480c64241157116ddd107a953ad3
--- /dev/null
+++ b/3_match_extspot/backpro_new.m
@@ -0,0 +1,234 @@
+function[ir, sinogram ,angles, centres] = backpro_new(family,common)
+
+load parameters
+
+%loop through the spots in the family
+for i=1:length(family)
+
+spotid = common(family(i)).ID;
+angles(i) = 180*common(family(i)).MaxImage/app.nvue;
+
+%determine which line of image is used for sinogram 
+if i==1 
+  sino_ypos = common(family(i)).ExtBoundingBox(2) + ceil(common(family(i)).ExtBoundingBox(4)/2);
+end
+
+%read line of extspot into sinogram
+sinogram(i,:) = zeros(1,app.data.ext.xsize);
+sino_xpos = common(family(i)).ExtBoundingBox(1);
+
+
+% %work around bug in replaced spots
+% if isempty(common(family(i)).Replaced)==1
+   sino_xwidth = common(family(i)).ExtBoundingBox(3);
+% else
+%   sino_xwidth = common(family(i)).BoundingBox(3);
+% end
+% 
+% 
+
+
+extspot_ypos = sino_ypos - common(family(i)).ExtBoundingBox(2);
+
+extspot = edfread(sprintf('extspot/extspot%05d.edf',spotid));
+extspot_width = size(extspot);
+extspot_width = extspot_width(2)-1;
+
+if sino_xwidth ~= (extspot_width)
+sprintf('warning: bounding box and spot edf size mismatch at common(%d), theta=%d',family(i),angles(i))
+end
+
+%read extspot width regardless of reported bounding box width
+%prints warning on screen.
+if extspot_ypos <= length(extspot)
+  sinogram(i,sino_xpos:sino_xpos+extspot_width) = extspot(extspot_ypos,:);
+  %do normalisation
+  sinogram(i,:) = sinogram(i,:)./sum(sinogram(i,:));
+else
+  sprintf('warning: serious bounding box mismatch at common(%d), IGNORING!',family(i))
+end
+  
+%else
+%prob = family(i)
+%keyboard
+%end
+  
+end
+
+%sort sinogram and angles by angle
+temp = [angles' sinogram];
+temp = sortrows(temp,1);
+angles=temp(:,1);
+temp(:,1)=[];
+sinogram=temp;
+
+
+%do backprojection with iradon
+
+ir =1000000*iradon(sinogram', angles','Hamming');
+
+
+%calculate centre of mass positions in sinogram for sine fit
+pos=1:1:length(sinogram);
+
+centres=pos*sinogram';
+figure(2);
+plot(angles,centres,'or')
+hold on
+
+figure(3);
+imshow(ir,[])
+app.handles.fig=figure(3);
+set(app.handles.fig,'numbertitle','off','menubar','none');
+set(app.handles.fig,'WindowButtonDownFcn',@sfMouseClick);
+
+
+%pick a spot...
+%xpos = input('(approx) x position of spot');
+%ypos = input('(approx) y position of spot');
+
+%calc phase and amplitude
+centre = 331/2;
+amp = sqrt((xpos-centre)^2+(ypos-centre)^2);
+phase = atan((xpos-centre)/(ypos-centre))+pi()/2;%why the pi/2???
+params0 = [amp phase];
+dummy = 0:5:180;
+dummy2 = sino_function(params0, dummy);
+figure(2);
+plot(dummy,dummy2,'-y')
+
+
+
+
+%imtool(ir, [])
+
+% 
+% 
+% 
+% 
+%       %for i=1:length(theta)
+% 
+%           %name=sprintf('rawsino%d.tif',n);
+%           %p=imread(name)';
+%           p=double(sinogram);
+% 
+%           len=size(p,1);
+% 
+%           keyboard
+% 
+%           %name=sprintf('C:/Program Files/ADCIS-AAI/Aphelion/extinction/angle%d.dat',grain);
+%           %[theta,comx]=textread(name,'%s %s %*[^\n]','delimiter',',');
+%           %theta=str2double(theta)/180*pi;
+% 
+%           %interp='linear';
+%           interp='nearest neighbor';
+%           N=len;
+% 
+% 
+%           img = zeros(N);        % Allocate memory for the image.
+% 
+%       % Define the x & y axes for the reconstructed image so that the origin
+%       % (center) is in the spot which RADON would choose.
+%       xax = (1:N)-ceil(N/2);
+%       x = repmat(xax, N, 1);    % x coordinates, the y coordinates are rot90(x)
+%       y = rot90(x);
+% 
+%       costheta = cos(theta);
+%       sintheta = sin(theta);
+%       ctrIdx = ceil(len/2);     % index of the center of the projections
+% 
+%       % Zero pad the projections to size 1+2*ceil(N/sqrt(2)) if this
+%       % quantity is greater than the length of the projections
+%       imgDiag = 2*ceil(N/sqrt(2))+1;  % largest distance through image.
+%       if size(p,1) < imgDiag
+%          rz = imgDiag - size(p,1);  % how many rows of zeros
+%          p = [zeros(ceil(rz/2),size(p,2)); p; zeros(floor(rz/2),size(p,2))];
+%          ctrIdx = ctrIdx+ceil(rz/2);
+%       end
+% 
+%       % Backprojection - vectorized in (x,y), looping over theta
+%       if strcmp(interp, 'nearest neighbor')
+%          for i=1:length(theta)
+%             proj = p(:,i);
+%             t = round(x*costheta(i) + y*sintheta(i));
+%             img = img + proj(t+ctrIdx);
+%          end
+%       elseif strcmp(interp, 'linear')
+%          for i=1:length(theta)
+%             proj = p(:,i);
+%             t = x.*costheta(i) + y.*sintheta(i);
+%             a = floor(t);
+%             img = img + (t-a).*proj(a+1+ctrIdx) + (a+1-t).*proj(a+ctrIdx);
+%          end
+%       elseif strcmp(interp, 'spline')
+%          for i=1:length(theta)
+%             proj = p(:,i);
+%             taxis = (1:size(p,1)) - ctrIdx;
+%             t = x.*costheta(i) + y.*sintheta(i);
+%             projContrib = interp1(taxis,proj,t(:),'*spline');
+%             img = img + reshape(projContrib,N,N);
+%          end
+%       end
+% 
+% 
+%       name='back_projection_test.tif';
+%       mat2gray(img,[0 255]);
+%       imwrite(mat2gray(img,[0 255]),name)
+%       %end
+% 
+%       imshow(img,[])
+% 
+% 
+%       %%%
+%       %%%  Sub-Function:  designFilter
+%       %%%
+% 
+%       function filt = designFilter(filter, len, d)
+%       % Returns the Fourier Transform of the filter which will be
+%       % used to filter the projections
+%       %
+%       % INPUT ARGS:   filter - either the string specifying the filter
+%       %               len    - the length of the projections
+%       %               d      - the fraction of frequencies below the nyquist
+%       %                        which we want to pass
+%       %
+%       % OUTPUT ARGS:  filt   - the filter to use on the projections
+% 
+% 
+%       order = max(64,2^nextpow2(2*len));
+% 
+%       % First create a ramp filter - go up to the next highest
+%       % power of 2.
+% 
+%       filt = 2*( 0:(order/2) )./order;
+%       w = 2*pi*(0:size(filt,2)-1)/order;   % frequency axis up to Nyquist
+% 
+%       switch filter
+%       case 'ram-lak'
+%          % Do nothing
+%       case 'shepp-logan'
+%          % be careful not to divide by 0:
+%          filt(2:end) = filt(2:end) .* (sin(w(2:end)/(2*d))./(w(2:end)/(2*d)));
+%       case 'cosine'
+%          filt(2:end) = filt(2:end) .* cos(w(2:end)/(2*d));
+%       case 'hamming'
+%          filt(2:end) = filt(2:end) .* (.54 + .46 * cos(w(2:end)/d));
+%       case 'hann'
+%          filt(2:end) = filt(2:end) .*(1+cos(w(2:end)./d)) / 2;
+%       otherwise
+%          error('Invalid filter selected.');
+%       end
+% 
+%       filt(w>pi*d) = 0;                      % Crop the frequency response
+%       filt = [filt' ; filt(end-1:-1:2)'];    % Symmetry of the filter
+% 
+% 
+% 
+
+end
+
+function sfMouseClick(varargin)
+pt = get(gca, 'currentpoint');
+xpos = pt(1);
+ypos = pt(2);
+end
diff --git a/3_match_extspot/backproject.m b/3_match_extspot/backproject.m
new file mode 100755
index 0000000000000000000000000000000000000000..4d158cb22645942742f25f1d1eff7770fcaf2ff8
--- /dev/null
+++ b/3_match_extspot/backproject.m
@@ -0,0 +1,113 @@
+chdir('C:/wolfgang/data/extinction/Risoe_fine');
+n=load('spots.log');
+
+for i=1:n
+
+    name=sprintf('rawsino%d.tif',n);
+    p=imread(name)';
+    p=double(p);
+    len=size(p,1);
+    name=sprintf('C:/Program Files/ADCIS-AAI/Aphelion/extinction/angle%d.dat',grain);
+    [theta,comx]=textread(name,'%s %s %*[^\n]','delimiter',',');
+    theta=str2double(theta)/180*pi;
+
+    %interp='linear';
+    interp='nearest neighbor';
+    N=len;
+
+
+    img = zeros(N);        % Allocate memory for the image.
+
+% Define the x & y axes for the reconstructed image so that the origin
+% (center) is in the spot which RADON would choose.
+xax = (1:N)-ceil(N/2);
+x = repmat(xax, N, 1);    % x coordinates, the y coordinates are rot90(x)
+y = rot90(x);
+
+costheta = cos(theta);
+sintheta = sin(theta);
+ctrIdx = ceil(len/2);     % index of the center of the projections
+
+% Zero pad the projections to size 1+2*ceil(N/sqrt(2)) if this
+% quantity is greater than the length of the projections
+imgDiag = 2*ceil(N/sqrt(2))+1;  % largest distance through image.
+if size(p,1) < imgDiag
+   rz = imgDiag - size(p,1);  % how many rows of zeros
+   p = [zeros(ceil(rz/2),size(p,2)); p; zeros(floor(rz/2),size(p,2))];
+   ctrIdx = ctrIdx+ceil(rz/2);
+end
+
+% Backprojection - vectorized in (x,y), looping over theta
+if strcmp(interp, 'nearest neighbor')
+   for i=1:length(theta)
+      proj = p(:,i);
+      t = round(x*costheta(i) + y*sintheta(i));
+      img = img + proj(t+ctrIdx);
+   end
+elseif strcmp(interp, 'linear')
+   for i=1:length(theta)
+      proj = p(:,i);
+      t = x.*costheta(i) + y.*sintheta(i);
+      a = floor(t);
+      img = img + (t-a).*proj(a+1+ctrIdx) + (a+1-t).*proj(a+ctrIdx);
+   end
+elseif strcmp(interp, 'spline')
+   for i=1:length(theta)
+      proj = p(:,i);
+      taxis = (1:size(p,1)) - ctrIdx;
+      t = x.*costheta(i) + y.*sintheta(i);
+      projContrib = interp1(taxis,proj,t(:),'*spline');
+      img = img + reshape(projContrib,N,N);
+   end
+end
+
+
+name=sprintf('recon%d.tif',n);
+mat2gray(img,[0 255]);
+imwrite(mat2gray(img,[0 255]),name)
+end
+%%%
+%%%  Sub-Function:  designFilter
+%%%
+
+function filt = designFilter(filter, len, d)
+% Returns the Fourier Transform of the filter which will be
+% used to filter the projections
+%
+% INPUT ARGS:   filter - either the string specifying the filter
+%               len    - the length of the projections
+%               d      - the fraction of frequencies below the nyquist
+%                        which we want to pass
+%
+% OUTPUT ARGS:  filt   - the filter to use on the projections
+
+
+order = max(64,2^nextpow2(2*len));
+
+% First create a ramp filter - go up to the next highest
+% power of 2.
+
+filt = 2*( 0:(order/2) )./order;
+w = 2*pi*(0:size(filt,2)-1)/order;   % frequency axis up to Nyquist
+
+switch filter
+case 'ram-lak'
+   % Do nothing
+case 'shepp-logan'
+   % be careful not to divide by 0:
+   filt(2:end) = filt(2:end) .* (sin(w(2:end)/(2*d))./(w(2:end)/(2*d)));
+case 'cosine'
+   filt(2:end) = filt(2:end) .* cos(w(2:end)/(2*d));
+case 'hamming'
+   filt(2:end) = filt(2:end) .* (.54 + .46 * cos(w(2:end)/d));
+case 'hann'
+   filt(2:end) = filt(2:end) .*(1+cos(w(2:end)./d)) / 2;
+otherwise
+   error('Invalid filter selected.');
+end
+
+filt(w>pi*d) = 0;                      % Crop the frequency response
+filt = [filt' ; filt(end-1:-1:2)'];    % Symmetry of the filter
+
+
+
diff --git a/3_match_extspot/calculate_twotheta.m b/3_match_extspot/calculate_twotheta.m
new file mode 100755
index 0000000000000000000000000000000000000000..4b085fce9ed44af7fbbd14c65c8eafc9f05d7872
--- /dev/null
+++ b/3_match_extspot/calculate_twotheta.m
@@ -0,0 +1,73 @@
+function twotheta=calculate_twotheta(d0,spacegroup,energy,strain)
+% CALCULATE_TWOTHETA.M
+% Given the d0 spacing, spacegroup, and energy, returns the diffraction
+% angles for different reflections.
+%
+% Usage:
+% theta=calculate_theta(d0,spacegroup,energy[,strain])
+%
+% Input:
+% d0 is lattice spacing in angstroms (eg 4.04)
+% spacegroup is 'FCC' (only option supported at present
+% energy is in keV
+% strain, if present, is between 0 and 1.
+%
+% Output:
+% twotheta is a mhashtable object - an array which has a NAME for each
+% element, not an index.  You can get look at your results like this:
+% if twotheta.containsKey('111')
+%   twotheta.get('111')
+% end
+% the min and max values only appear if the strain is non-zero
+% More help on mhashtable in demo_hashtable
+
+
+% Check parameters
+if ~ischar(spacegroup)
+  error('Spacegroup must be a string - ''FCC'',''BCC'',''HCP''');
+end
+
+if ~exist('strain','var')
+  % only calculate perfect values
+  strain=0;
+elseif strain<0|strain>1
+  error('Strain must be between 0 and 1')
+end
+
+
+switch spacegroup
+  case 'FCC'
+    % verify the theoretically allowed reflections !
+    reflections=[...
+      1 1 1;...
+      2 0 0;...
+      2 2 0;...
+      3 1 1;...
+      4 0 0;...
+      3 3 1;...
+      ];
+
+    lambda=12.398/energy;   % verify constant !
+    twotheta=mhashtable;
+    for i=1:size(reflections,1)
+      
+      tmp=2*180/pi*asin(lambda/2./(d0*[1-strain 1 1+strain])*norm(reflections(i,:)));
+      if strain~=0
+        vals.max=tmp(1);
+        vals.min=tmp(3);
+      end
+      vals.centre=tmp(2);
+      stmp=num2str(reflections(i,:));
+      stmp(isspace(stmp))=[];
+      twotheta.put(stmp,vals);
+    end
+  otherwise
+    error('Sorry, only FCC possible at present');
+end
+
+
+end
+
+
+
+
diff --git a/3_match_extspot/generate_extinctionmask.m b/3_match_extspot/generate_extinctionmask.m
new file mode 100755
index 0000000000000000000000000000000000000000..ed90e07dcbde0d9f898bfd18909a0f5c0a9c7426
--- /dev/null
+++ b/3_match_extspot/generate_extinctionmask.m
@@ -0,0 +1,73 @@
+function mask=generate_extinctionmask(im,point)
+% im=edf_read('full0000.edf');
+% point.x=1591; point.y=1312;
+global app
+if ~exist('app','var')
+  error('Please load the common/parameter file before using this function')
+end
+
+bb=app.bb.directbeam;
+ext_axis=[bb(2) bb(2)+bb(4) bb(1) bb(1)+bb(3)];
+im_ext=im(bb(2):bb(2)+bb(4),bb(1):bb(1)+bb(3));
+
+%calculate the cones that emmanate from the selected point
+
+% distance from diffraction spot to near and far edge of sample
+
+sample_hbb=[850-20 1200+20];  % this should NOT be hardcoded like this!
+sample_vbb=[780 1260];  % nor this!
+sample_width=diff(sample_hbb);
+
+% 111 8.6
+% 002 9.9
+% 220 14.1
+% 311 16.5
+% stainless steel a=3.61A 40keV
+
+theta=[8.6 9.9 14.1 16.5];
+tmp=calculate_twotheta(3.61,'FCC',40);
+% this uses hashtables - very powerful, but perhaps a little too weird???
+tmp=tmp.elements;
+for n=1:length(tmp)
+  theta(n)=tmp{n}.centre;
+end
+
+dist_rear=app.dist+(sample_width*app.pixelsize); % assume sample is cuboid
+dist_front=app.dist-(sample_width*app.pixelsize);
+
+rad_front=dist_front*tan(deg2rad(theta))/app.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(theta))/app.pixelsize;
+
+
+tmask=zeros(size(im));
+for n=1:length(rad_front)
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+mask=zeros(size(im));
+mask(tmask)=1;
+
+
+return
+
+
+% calc theta and eta
+point2=ginput(1);% grain in image2
+
+offset=point_mirror-point2;
+Theta=atan((sqrt(offset*offset'))/(10/0.0014));
+Theta=(Theta*180/pi)/2;%divide by 2 for 2theta -> theta
+
+Eta=atan2(offset(1,1),offset(1,2))*180/pi;
+if Eta<0
+  Eta=360+Eta;
+end
+
+
+Theta
+Eta
+
diff --git a/3_match_extspot/gtBatchAutoFind_360.m b/3_match_extspot/gtBatchAutoFind_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..fc6d4774caf8b5439c8ea15a63815b590ffe4df6
--- /dev/null
+++ b/3_match_extspot/gtBatchAutoFind_360.m
@@ -0,0 +1,56 @@
+function gtBatchAutoFind_360(first,last,wdir)
+  %first=first IMAGE, last= last IMAGE
+
+  %mod from gt_batchAutoFind_pairs to use database tables extending over 360
+  %degrees, rather than a scan split into two 180 degree halves, A and B.
+
+  %try changing this to do all of the spots in an image, rather than a number
+  %of difspot ids, as it seems important to do the brightest spots in an
+  %image first
+
+  if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end
+
+  cd(wdir)
+
+
+  load parameters.mat
+
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %   SIZE ORDERING
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  gtDBConnect;
+
+  %[remaining]=mym(sprintf(...
+  %  'select difspotID from %sdifspot where difspotID>=%d and difspotID<=%d and BoundingBoxXsize>10 and BoundingBoxYsize>10 order by (integral/Area) desc',...
+  %  parameters.acq.name,first,last));
+
+  [remaining]=mym(sprintf(...
+    'select difspotID from %sdifspot where maximage>=%d and maximage<=%d and BoundingBoxXsize>%d and BoundingBoxYsize>%d order by (integral/Area) desc',...
+    parameters.acq.name,first,last, parameters.match.minsize, parameters.match.minsize));
+
+
+  fprintf('First %d Last %d Number %d\n',first,last,length(remaining))
+
+
+  for i=1:length(remaining)
+    try
+      struct_id=remaining(i);
+      fprintf('~~~~~~ Doing difspot %d of %d (struct_id = %d) ~~~~~~~~~\n', i,length(remaining),struct_id)
+      AutoFind_360(struct_id,parameters,1);
+      fprintf('~~~~~~~~ DONE OK ~~~~~~~~\n\n\n');
+    catch
+      fprintf('~~~~~~~~~ SPOT UNFINISHED ~~~~~~~~~~\n')
+      tmp=lasterror;
+      fprintf('Error: %s \n%s at line %d\n',tmp.message,tmp.stack(1).file,tmp.stack(1).line);
+      fprintf('\n\n\n');
+    end
+  end
+
+  mym('close')
+
+
diff --git a/3_match_extspot/gtDoAll.m b/3_match_extspot/gtDoAll.m
new file mode 100755
index 0000000000000000000000000000000000000000..cc02e47d4152e364c9f8867b95d0b8168e1b5591
--- /dev/null
+++ b/3_match_extspot/gtDoAll.m
@@ -0,0 +1,81 @@
+function gtDoAll;
+% remove seg2vie.sh
+% truncate grainid
+% set GrainID in extspot to null
+% remove -r 4_grain/*
+
+%load data
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+cd(parameters.acq.dir);
+
+cand=gtSelectCandidates(220,450);
+
+fprintf('Candidate list length: %d\n',length(cand));
+
+
+%cand(cand==4)=[];%kill dodgy entry number 4!
+
+for i=1:length(cand)
+  
+  close all
+  if mym(sprintf('select !isnull(GrainID) from %sextspot where (extspotID=%d)',parameters.acq.name,cand(i)));
+    % GrainID has already been allocated to this candidate
+    continue % bomb out of loop
+  end
+  
+
+  % request a GrainID to use
+  mym(sprintf('insert into %sgrainid set grainID=default',parameters.acq.name));
+  grainID=mym(sprintf('select last_insert_id()'));
+  fprintf('now looking at candidate %d of %d (family belonging to extspot(%d)) using grainID %d\n',i,length(cand),cand(i),grainID);
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  [accept, stack] = gtHandleSpot(cand(i),grainID);
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  if accept
+
+    %consistancy check writes data into the grain%d_.mat file
+    %returns a list of rejected struct_ids, the extspot.GrainID entries
+    %for which must be reset
+    %use overwite flag=1 to remove bad data from the grain%d_.mat file
+    %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    [struct_ids,a,a,a,a,bad_struct_ids]=gtConsistancyCheck(grainID,1);
+    %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    %do the database reset here
+    if ~isempty(bad_struct_ids);
+      disp('Resetting bad grainIDs')
+      fprintf('removing bads: ')
+      fprintf('%d ',bad_struct_ids)
+      fprintf('\n')
+      gtResetGrainID(bad_struct_ids);
+    end
+    
+    if length(struct_ids)>=4
+    %write stack and information about scan
+    disp(sprintf('writing %d projections for grain %d',length(struct_ids),grainID));
+    %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    gtWriteStack(grainID);
+    %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    %do ART after consistancy check, not before!
+    %[lamba, use_grain] = gtnew_choose_art_params_wolf(grainid);
+    %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    gtDoART(grainID);
+    %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    else
+      disp('removing this grain, not enough projections');
+      %reset and remove grain...
+      gtResetGrainID(struct_ids);
+      cmd = sprintf('rm -rf 4_grains/grain%d_',grainID);
+      unix(cmd)
+    end
+
+    
+    cd(parameters.acq.dir);
+  end
+end
+
+disp('Done!')
diff --git a/3_match_extspot/gtDoAll2.m b/3_match_extspot/gtDoAll2.m
new file mode 100755
index 0000000000000000000000000000000000000000..c1776fe728f9fecd3474d43ae124d49e0af0f7c9
--- /dev/null
+++ b/3_match_extspot/gtDoAll2.m
@@ -0,0 +1,71 @@
+function gtDoAll2;
+% remove seg2vie.sh
+% truncate grainid
+% set GrainID in extspot to null
+% remove -r 4_grain/*
+
+%gtDoAll2 - simplify to use streamlined HandleSpot2...
+
+
+
+%load data
+global parameters
+
+if isempty(parameters)
+  load parameters.mat
+end
+
+cd(parameters.acq.dir);
+cand=gtSelectCandidates(180,185);
+
+grainID = 1;
+
+if exist(sprintf('4_grains/grain%d_',grainID),'dir')
+  disp(sprintf('4_grains/grain%d_/ already exists! Either delete it, or change grainID in DoAll2! Aborting...',grainID))
+  return
+end
+
+
+
+fprintf('Candidate list length: %d\n',length(cand));
+
+for i=1:length(cand)
+  
+  close all
+  
+  if mym(sprintf('select !isnull(GrainID) from %sextspot where (extspotID=%d)',parameters.acq.name,cand(i)));
+    % GrainID has already been allocated to this candidate
+    continue % bomb out of loop
+  end
+  
+% % request a GrainID to use - use simpler system for test
+ % mym(sprintf('insert into %sgrainid set grainID=default',parameters.acq.name));
+  %grainID=mym(sprintf('select last_insert_id()'));
+ 
+  
+  fprintf('now looking at candidate %d of %d (family belonging to extspot(%d)) using grainID %d\n',i,length(cand),cand(i),grainID);
+  
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  accept = gtHandleSpot2_180(cand(i),grainID);
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  if accept
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  gtWriteStack(grainID);
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  gtDoART(grainID);
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  
+  %increment grainID
+  grainID=grainID+1;
+  
+  end
+  
+  cd(parameters.acq.dir);
+  close all
+
+end
+
+disp('Done!')
diff --git a/3_match_extspot/gtDoAll2_pairs.m b/3_match_extspot/gtDoAll2_pairs.m
new file mode 100755
index 0000000000000000000000000000000000000000..f50e151f05b7039a0de407a473d47fe66bd1b6fb
--- /dev/null
+++ b/3_match_extspot/gtDoAll2_pairs.m
@@ -0,0 +1,68 @@
+function gtDoAll2_pairs(parameters);
+% remove seg2vie.sh
+% truncate grainid
+% set GrainID in extspot to null
+% remove -r 4_grain/*
+
+%gtDoAll2 - simplify to use streamlined HandleSpot2...
+
+%load data
+%global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%cd(parameters.acq.dir);
+cand=gtSelectCandidates(0, 619, 10);%zstart, zend, min Ysize
+
+grainID = 1;
+
+fprintf('Candidate list length: %d\n',length(cand));
+
+%dummy=find(cand==19715)
+
+
+
+
+%for i=(dummy+1):length(cand)
+  for i=1:length(cand)
+  
+  close all
+  
+  if mym(sprintf('select !isnull(GrainID) from %sextspot where (extspotID=%d)',parameters.acq.name,cand(i)));
+    % GrainID has already been allocated to this candidate
+    continue % bomb out of loop
+  end
+  
+% % request a GrainID to use - use simpler system for test
+ % mym(sprintf('insert into %sgrainid set grainID=default',parameters.acq.name));
+  %grainID=mym(sprintf('select last_insert_id()'));
+ 
+  
+  fprintf('now looking at candidate %d of %d (family belonging to extspot(%d)) using grainID %d\n',i,length(cand),cand(i),grainID);
+  
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  accept = gtHandleSpot2_360(cand(i),grainID, parameters);
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  if accept
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  gtWriteStack_replaced(grainID);
+  gt_select_projections_auto(grainID);
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  gtDoART(grainID);
+  %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  
+  %increment grainID
+  grainID=grainID+1;
+  
+  end
+  
+  cd(parameters.acq.dir);
+  close all
+
+end
+
+disp('Done!')
diff --git a/3_match_extspot/gtDoAll_360.m b/3_match_extspot/gtDoAll_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..89422de16831e9764fa8c3ef38631b03015466b4
--- /dev/null
+++ b/3_match_extspot/gtDoAll_360.m
@@ -0,0 +1,76 @@
+function gtDoAll_360
+  % remove seg2vie.sh
+  % truncate grainid
+  % set GrainID in extspot to null
+  % remove -r 4_grain/*
+
+  %gtDoAll2 - simplify to use streamlined HandleSpot2...
+
+  %360degree scan convention - ak 10/2007
+
+  %load data
+  load parameters.mat
+
+
+  %cd(parameters.acq.dir);
+  cand=gtSelectCandidates(0, parameters.acq.bb(4), parameters.match.minsize);%zstart, zend, min Ysize
+
+
+  %avoid overwriting grains - continue from the max current grain id +1
+  a=mym(sprintf('select max(grainid) from %sextspot', parameters.acq.name));
+  if isnan(a)
+    grainID = 1;
+  else
+    grainID=a+1;
+  end
+
+  fprintf('Candidate list length: %d\n',length(cand));
+
+  dummy=find(cand==42974)
+warning('messing with the list of candidates for restart')
+
+
+
+  for i=dummy:length(cand)
+%  for i=1:length(cand)
+
+    close all
+
+    if mym(sprintf('select !isnull(GrainID) from %sextspot where (extspotID=%d)',parameters.acq.name,cand(i)));
+      % GrainID has already been allocated to this candidate
+      continue % bomb out of loop
+    end
+
+    % % request a GrainID to use - use simpler system for test
+    % mym(sprintf('insert into %sgrainid set grainID=default',parameters.acq.name));
+    %grainID=mym(sprintf('select last_insert_id()'));
+
+
+    fprintf('now looking at candidate %d of %d (family belonging to extspot(%d)) using grainID %d\n',i,length(cand),cand(i),grainID);
+
+    %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    accept = gtHandleSpot_360(cand(i),grainID, parameters);
+    %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    if accept
+      %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+      plot_flag=0;
+      gtWriteStack_360(grainID, 'sheared_difspots'); %flag can be "sheared_difspots", "replaced", or nothing (default) 
+      gt_select_projections_auto(grainID, plot_flag);
+      %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+      %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+      gtDoART(grainID);
+      %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+      %increment grainID
+      grainID=grainID+1;
+
+    end
+
+    cd(parameters.acq.dir);
+    close all
+
+  end
+
+  disp('Done!')
diff --git a/3_match_extspot/gtFindMaxSubscripts.m b/3_match_extspot/gtFindMaxSubscripts.m
new file mode 100755
index 0000000000000000000000000000000000000000..99936c0464049f793f571ae5cbcd1887674f9a8c
--- /dev/null
+++ b/3_match_extspot/gtFindMaxSubscripts.m
@@ -0,0 +1,6 @@
+function subscripts=gtFindMaxSubscripts(im)
+
+[tmp,tmp2] = max(im(:));
+[tmp3,tmp4] = ind2sub(size(im),tmp2);
+subscripts = [tmp3 tmp4];
+end
diff --git a/3_match_extspot/gtGetDifImage.m b/3_match_extspot/gtGetDifImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..eed4200fb04a8442e19ea44be0fcad1083962078
--- /dev/null
+++ b/3_match_extspot/gtGetDifImage.m
@@ -0,0 +1,26 @@
+function im=gtGetDifImage(ndx,struct_id,parameters, varargin)
+%returns the full image requested, cropped to the specified difspot
+%bounding box
+
+if ~exist('parameters','var')
+  load('parameters.mat');
+end 
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+name=parameters.acq.name;
+
+mysqlcmd=sprintf(['select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize '...
+  'from %sdifspot where difspotID=%d'],...
+  name, struct_id);
+
+[BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize]=mym(mysqlcmd);
+
+im=edf_read(sprintf('1_preprocessing/full/full%04d.edf',ndx),[BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize]);
diff --git a/3_match_extspot/gtGetDifImage_old.m b/3_match_extspot/gtGetDifImage_old.m
new file mode 100755
index 0000000000000000000000000000000000000000..a2eac3c8cc06be321e129252d25ad32302ca7560
--- /dev/null
+++ b/3_match_extspot/gtGetDifImage_old.m
@@ -0,0 +1,11 @@
+function im=gtGetDifImage(ndx,struct_id)
+%returns the full image requested, cropped to the specified difspot bounding box
+
+global difspot
+
+if isempty(difspot)
+  disp('Loading difspot file')
+  load('2_difspot/difspot.mat');
+end
+
+im = edf_read(sprintf('1_preprocessed/full/full%04d.edf',ndx),difspot(struct_id).BoundingBox);
diff --git a/3_match_extspot/gtGetDifImage_test.m b/3_match_extspot/gtGetDifImage_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..a5a2b493e0828a8d7453d8ba11fe2361c8e4e071
--- /dev/null
+++ b/3_match_extspot/gtGetDifImage_test.m
@@ -0,0 +1,13 @@
+function im=gtGetDifImage(ndx,struct_id)
+%returns the full image requested, cropped to the specified difspot bounding box
+
+%global difspot
+gtDBconnect
+
+% if isempty(difspot)
+ % disp('Loading difspot file')
+ % load('2_difspot/difspot.mat');
+% end
+
+% im = edf_read(sprintf('1_preprocessed/full/full%04d.edf',ndx),difspot(struct_id).BoundingBox);
+im=mysqlcmd(sprintf('1_preprocessed/full/full%04d.edf',ndx),'select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize from %sdifspot where difspotID=%d',parameters.acq.name, struct_id)
\ No newline at end of file
diff --git a/3_match_extspot/gtGetExtImage.m b/3_match_extspot/gtGetExtImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..fdd340c40d374b8eda729792aa9a580cc0188179
--- /dev/null
+++ b/3_match_extspot/gtGetExtImage.m
@@ -0,0 +1,18 @@
+function im=gtGetExtImage(ndx, parameters)%, varargin)
+%returns the direct beam part of the requested full image
+%varargin - ABflag for 360 data - struct_id refers to which half of the scan?
+%will take from the working directory (whichever parameter.mat is loaded!)
+%by default, so can be used as before
+
+
+if ~exist('parameters','var')
+  load('parameters.mat');
+end 
+
+name=parameters.acq.name;
+
+path=sprintf('../%s/',name);
+
+im = edf_read(sprintf('%s1_preprocessing/full/full%04d.edf',path,ndx),parameters.acq.bb);
+
+
diff --git a/3_match_extspot/gtGetMaxDifSpot.m b/3_match_extspot/gtGetMaxDifSpot.m
new file mode 100755
index 0000000000000000000000000000000000000000..2a792ed25aaf44219482e4105eaf9a5af9390a61
--- /dev/null
+++ b/3_match_extspot/gtGetMaxDifSpot.m
@@ -0,0 +1,10 @@
+function spot=gtGetSummedDifSpot(ndx)
+global app
+if isempty(app)
+  disp('Loading parameter file')
+  load('common.mat');
+end
+
+spot = edf_read(sprintf('full/full%04d.edf',app.extspot(ndx).MaxImage),app.extspot(ndx).BoundingBox);
+
+end
diff --git a/3_match_extspot/gtGetMaxExtImage.m b/3_match_extspot/gtGetMaxExtImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..f235df2cdf2f760b2f0a8a0d113f38ce81568d98
--- /dev/null
+++ b/3_match_extspot/gtGetMaxExtImage.m
@@ -0,0 +1,11 @@
+function im=gtGetMaxExtImage(ndx)
+
+global app
+if isempty(app)
+  disp('Loading parameter file')
+  load('common.mat');
+end
+
+%read maximum intensity ext image from full
+im = edf_read(sprintf('full/full%04d.edf',app.extspot(ndx).MaxImage),app.bb.directbeam);
+end
diff --git a/3_match_extspot/gtGetMeanExtImage.m b/3_match_extspot/gtGetMeanExtImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..2180cf248ca2dd0589ccda09a500483b1f09ab43
--- /dev/null
+++ b/3_match_extspot/gtGetMeanExtImage.m
@@ -0,0 +1,21 @@
+function [ims,im]=gtGetSummedExtImage(extspotID,parameters)
+
+if ~exist('parameters','var')
+  load('parameters.mat');
+end  
+acq=parameters.acq;
+
+[start,endim]=mym(sprintf('select ExtStartImage, ExtEndImage from %sdifspot where difspotID=%d',acq.name,extspotID));
+
+im=zeros(acq.bb(4), acq.bb(3),endim-start+1);
+ims=zeros(acq.bb(4), acq.bb(3));
+disp([num2str(endim-start+1) ' images in sum'])
+j=1;
+for i=start:endim
+  im(:,:,j) = edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',acq.dir,i));
+  ims=ims+im(:,:,j);
+  j=j+1;
+end
+
+
+end
diff --git a/3_match_extspot/gtGetMeanFullImage.m b/3_match_extspot/gtGetMeanFullImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..505e49e2a8e909e12b0bced870aec4be086d7aca
--- /dev/null
+++ b/3_match_extspot/gtGetMeanFullImage.m
@@ -0,0 +1,36 @@
+function im=gtGetMeanFullImage(struct_id, parameters, varargin)
+% returns the mean full direct beam corresponding to a given difspot
+
+
+% modified December 2006 to support database
+
+%if isempty(parameters)
+    if ~exist('parameters', 'var')
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+name=parameters.acq.name;
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+im=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',name,struct_id);
+
+[ExtStartImage,ExtEndImage]=mym(mysqlcmd);
+
+fprintf('%d images in sum\n',ExtEndImage-ExtStartImage+1);
+
+%path ensures that correct half of a 360 scan is read
+for i=ExtStartImage:ExtEndImage
+  im = im + edf_read(sprintf('1_preprocessing/full/full%04d.edf',i), parameters.acq.bb);
+end
+im=im/(ExtEndImage-ExtStartImage+1);
+end
diff --git a/3_match_extspot/gtGetSummedDifSpot.m b/3_match_extspot/gtGetSummedDifSpot.m
new file mode 100755
index 0000000000000000000000000000000000000000..80637ed4f31f0f1cdf5a386f5a7949881569b3cd
--- /dev/null
+++ b/3_match_extspot/gtGetSummedDifSpot.m
@@ -0,0 +1,38 @@
+function spot=gtGetSummedDifSpot(difID, parameters, varargin)
+%returns the summed difspot image (saved as difspot%05d.edf) or in difblob
+%table
+
+%360degree scan convention - ak 10/2007
+
+if ~exist('parameters','var')
+  load('parameters.mat');
+end  
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+name=parameters.acq.name;
+
+
+filename=sprintf('%s/2_difspot/difspot/difspot%05d.edf',parameters.acq.dir,difID);
+
+if exist(filename, 'file') %read the edf file
+spot=edf_read(filename);
+else%see if there is a blob...
+  try
+    %tablename=sprintf('%sdifblobdetails',name);
+    tablename=name;
+    vol=gtDBBrowseDiffractionVolume(tablename, difID);
+    spot=sum(vol,3);
+  catch
+    disp('cannot find difspot as edf or as difblob!')
+  end
+end
+
+end
diff --git a/3_match_extspot/gtGetSummedDifSpot_pair.m b/3_match_extspot/gtGetSummedDifSpot_pair.m
new file mode 100755
index 0000000000000000000000000000000000000000..adcfad97b568d59cf743018bf2a014a80a503fc4
--- /dev/null
+++ b/3_match_extspot/gtGetSummedDifSpot_pair.m
@@ -0,0 +1,53 @@
+function spot=gtGetSummedDifSpot_pair(difID, pair, varargin)
+%returns the summed difspot image (saved as difspot%05d.edf)
+%pair=1 - this dataset, pair=2 - pair dataset
+%difblob compatible, varargin{1}=1 if already connected to mysql
+% if varargin{2}=parameters is defined, it won't load the parameters file
+
+disp('DO NOT USE THIS!!'
+RETURN
+% connect to database
+connected=0;
+parameters=[];
+if ~isempty(varargin)
+	connected=varargin{1};
+  parameters=varargin{2};
+end
+if ~connected
+  gtDBConnect
+end
+if isempty(parameters)
+  %disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+
+if pair == 2
+  name=parameters.acq.pair_name;
+elseif pair ==1
+  name=parameters.acq.name;
+end
+%path=sprintf('../%s',name);
+%path=parameters.acq.dir;
+path=[parameters.acq.dir '/../' name];
+
+
+filename=sprintf('%s/2_difspot/difspot/difspot%05d.edf',path,difID);
+%filename=sprintf('%s/2_difspot/difspot%05d.edf',path,difID);
+
+if exist(filename, 'file') %read the edf file
+  spot=edf_read(filename);
+else%seee if there is a blob...
+  try
+    tablename=sprintf('%sdifblobdetails',name);
+    vol=gtDBBrowseDiffractionVolume(tablename, difID);
+    spot=sum(vol,3);
+  catch
+    disp('cannot find difspot as edf or as difblob!')
+    lasterr
+  end
+end
+
+
+
+end
diff --git a/3_match_extspot/gtMaskExtinctionFunction_360.m b/3_match_extspot/gtMaskExtinctionFunction_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..099b605e4d666a0fa3c760bad0a32acc741a8b60
--- /dev/null
+++ b/3_match_extspot/gtMaskExtinctionFunction_360.m
@@ -0,0 +1,201 @@
+% MASK_EXTINCTION.M
+% Given a full Frelon image, with the user selection of a diffraction spot,
+% attempts to mask the possible area in the extinction image within which
+% the spot could have diffracted from.  See below for assumptions about
+% diffraction criteria.
+%
+% Based on plot_rings.m by Andy King
+%
+% Greg Johnson September 2006
+
+%modified to at as a function, returning mask based on input of difspot
+%struct_id
+%Andy, 11/9/2006
+%taking the difspot parameters from the database -------Marcelo 08/12/2006,
+%read from the spotpairs database, and the relevent difspot tables
+
+%use idea of having two extspot tables.  Therefore inputID is the difspotID
+%of the dataset in which function is called.  Pair info is looked up in the
+%pair table and the relevent other difspot table
+
+%360 difspot table concept
+
+function mask_ext = gtMaskExtinctionFunction_360(struct_id, parameters, varargin);
+
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+im=zeros(parameters.acq.ydet, parameters.acq.xdet);
+bb=parameters.acq.bb;
+
+%varargin of 1 means already connected
+if ~isempty(varargin) 
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%get the information about this difspot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mysqlcmd=sprintf([...
+  'select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, '...
+  'CentroidX, CentroidY from %sdifspot where difspotID=%d'],...
+  parameters.acq.name, struct_id);
+[BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, CentroidX, CentroidY]=mym(mysqlcmd);
+dif_bb = [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize];
+dif_cent = [CentroidX, CentroidY];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%get info from pair table
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if parameters.acq.type=='360degree'
+  spotpairs_table = parameters.acq.pair_tablename;
+
+  %get the pair_struct_id, if possible
+  mysqlcmd=sprintf('select difAID, difBID, Theta from %s where difAID=%d or difBID=%d',...
+    spotpairs_table,struct_id, struct_id);
+  
+  [a, b, Theta] = mym(mysqlcmd);
+  %this can return the two ids, or two NaNs
+  pair_struct_id=[a b];
+  if all(isnan(pair_struct_id))
+    %no pair id found
+    pair_struct_id=[];
+  else
+    %drop the duplicated struct_id
+    pair_struct_id(find(pair_struct_id==struct_id))=[];
+  end
+  
+  %should be only one value!
+  if length(pair_struct_id)>1
+    error('somethings gone tits up')
+  end
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %get the pair difspot information
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  if ~isempty(pair_struct_id)
+    mysqlcmd=sprintf([...
+      'select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, '...
+      'CentroidX, CentroidY from %sdifspot where difspotID=%d'],...
+      parameters.acq.name, pair_struct_id);
+    [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, CentroidX, CentroidY]=mym(mysqlcmd);
+    dif_bb = [dif_bb; BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize];
+    dif_cent = [dif_cent; CentroidX, CentroidY];
+  end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%Construct mask from pair of difspots 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+pair_flag=0;
+if size(dif_bb,1)==2 %360 degree data, and have two difspots   
+pair_flag=1;
+  
+%apply mirror transform to pair position
+dif_cent(2,1) = 2*parameters.acq.rotx - dif_cent(2,1);
+dif_bb(2,1) = 2*parameters.acq.rotx - dif_bb(2,1) - dif_bb(2,3);
+
+grad = (dif_cent(2,2)-dif_cent(1,2))/(dif_cent(2,1)-dif_cent(1,1));
+
+%in line equation, find all possible c in y=mx+c
+%max and min c values gives edges of mask area
+c(1) = dif_bb(1,2) - grad*dif_bb(1,1);
+c(2) = dif_bb(1,2) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(3) = (dif_bb(1,2)+dif_bb(1,4)) - grad*dif_bb(1,1);
+c(4) = (dif_bb(1,2)+dif_bb(1,4)) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(5) = dif_bb(2,2) - grad*dif_bb(2,1);
+c(6) = dif_bb(2,2) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c(7) = (dif_bb(2,2)+dif_bb(2,4)) - grad*dif_bb(2,1);
+c(8) = (dif_bb(2,2)+dif_bb(2,4)) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c_min = min(c);
+c_max = max(c);
+
+mask_line=zeros(size(im));
+y(1) = (grad*1)+c_min;
+y(2) = (grad*size(im,1))+c_min;
+y(3) = (grad*size(im,1))+c_max;
+y(4) = (grad*1)+c_max;
+
+y(find(y<1))=1;
+y(find(y>size(im,2)))=size(im,2);
+x(1:2) = (y(1:2) - c_min)./grad;
+x(3:4) = (y(3:4) - c_max)./grad;
+
+fullmask = poly2mask(x,y,size(im,2),size(im,1));
+mask(3,:,:) = gtCrop(fullmask,parameters.acq.bb);
+
+end %line mask for two difspots
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%Construct mask from single difspot, using
+%allowed theta angles condition
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for i=1:size(dif_bb,1);%for - to run this for both spots if available
+  
+  %note - this is probably not very efficient! ak
+  
+%centre of difspot - use centre of bb
+point.x = ceil(dif_bb(i,1)+dif_bb(i,3)/2);
+point.y = ceil(dif_bb(i,2)+dif_bb(i,4)/2);
+
+%note - sample width overestimates
+xc=parameters.acq.dist;  
+sample_width=parameters.acq.bb(3);
+
+if (pair_flag == 1 && ~isempty(Theta))
+%if we have a pair of difspots, we should know Theta, so
+%single value read from database
+%warning('spotpairs theta value actually two theta!!')---no longer the case
+twotheta=2*Theta;
+else%180 degree case, get all possible allowed Theta angles
+  tmp=gtnew_calculate_twotheta;
+  tmp=tmp.elements;
+  for n=1:length(tmp)
+    twotheta(n)=tmp{n}.centre;
+  end
+end
+
+dist_rear=xc+(sample_width*parameters.acq.pixelsize/2); % assume sample is cuboid
+dist_front=xc-(sample_width*parameters.acq.pixelsize/2);
+
+rad_front=dist_front*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+
+%add a constant to radii based on the size of the difspot
+dif_rad = (sqrt(dif_bb(i,3:4)*dif_bb(i,3:4)'))/2;
+rad_front = rad_front-dif_rad;
+rad_rear = rad_rear+dif_rad;
+
+tmask=zeros(size(im));
+for n=1:length(rad_front)
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+
+mask(i,:,:)=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+tmask = gtCrop(tmask, parameters.acq.bb);
+mask(i,tmask)=1;
+  
+end%180 case for one or two difspots
+
+
+if pair_flag == 1
+%final mask is the AND of all three masks
+mask(1,:,:) = (mask(1,:,:) & mask(2,:,:) & mask(3,:,:));
+end
+
+%flatten mask to 2d
+mask_ext = reshape(mask(1,:,:), size(mask,2), size(mask,3)); 
+
+
diff --git a/3_match_extspot/gtMaskPriorExtspot.m b/3_match_extspot/gtMaskPriorExtspot.m
new file mode 100755
index 0000000000000000000000000000000000000000..9a31262ff5cf0c8d164c5d0a76c058bcb3e336c4
--- /dev/null
+++ b/3_match_extspot/gtMaskPriorExtspot.m
@@ -0,0 +1,40 @@
+function [dif_maskx, dif_masky] = gtMaskPriorExtspot(struct_id, ndx_im, grad_thresh, parameters)
+
+%prepare image to be subtracted from subsequent correlation inputs
+%ie - edge detected image of difspot, placed at extspot location, in the
+%relevent ext image, but calculated with threshold values of the new difspot
+%because being used for a mask only, sign information can be discarded
+
+if ~exist('parameters','var')
+  load('parameters.mat');
+end 
+
+
+%read relevent difspot image from full
+dif = gtGetDifImage(ndx_im, struct_id, parameters, 1);% 1 - already mysql connected
+
+%calc centre of mass, area of difspot
+%this needs to be the whole, summed difspot)
+difsummed=gtGetSummedDifSpot(struct_id, parameters, 1);
+com_x = sum(difsummed) * ((1:length(sum(difsummed)))') / sum(sum(difsummed));
+com_y = (sum(difsummed')*(1:length(sum(difsummed')))')/sum(sum(difsummed'));
+
+%make dif spot gradient, threshold
+dif_med = medfilt2(dif, [5 5]);
+[dif_gradx,dif_grady]=gradient(dif_med);
+dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+dif_grady_t1=abs(dif_grady) > grad_thresh;
+
+%search com of difspot in extinction image
+%to place difspot image in correct place in extinction image
+[ext_bb, ext_centroid] = gtGetBBProps(struct_id,parameters,'search');
+shift_x = ceil(ext_centroid(1) - com_x);
+shift_y = ceil(ext_centroid(2) - com_y);
+
+%make ext sized image, paste in dif spot...
+dif_maskx=gtPlaceSubImage(dif_gradx_t1,zeros(parameters.acq.bb(4), parameters.acq.bb(3)),1,1);
+dif_masky=gtPlaceSubImage(dif_grady_t1,zeros(parameters.acq.bb(4), parameters.acq.bb(3)),1,1);
+
+%gtShift mask to correct position
+dif_maskx=gtShift(dif_maskx,shift_x,shift_y);
+dif_masky=gtShift(dif_masky,shift_x,shift_y);
diff --git a/3_match_extspot/gt_batchAutoFind.m b/3_match_extspot/gt_batchAutoFind.m
new file mode 100755
index 0000000000000000000000000000000000000000..ca116acc6a8bc2c15a9982e812fb1a1dbdd46f6d
--- /dev/null
+++ b/3_match_extspot/gt_batchAutoFind.m
@@ -0,0 +1,40 @@
+function gt_batchAutoFind(first,last,wdir)
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+cd(wdir)
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   SIZE ORDERING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Opening database')
+mym('open','mysql.esrf.fr','gtuser','gtuser');
+mym('use graintracking');
+[remaining]=mym(sprintf(...
+  'select difspotID from %sdifspot where difspotID>=%d and difspotID<=%d order by Area desc',...
+  parameters.acq.name,first,last));
+fprintf('First %d Last %d Number %d\n',first,last,length(remaining))
+
+
+for i=1:length(remaining)
+  try 
+    struct_id=remaining(i);
+    fprintf('~~~~~~ Doing difspot %d, with %d remaining (struct_id = %d) ~~~~~~~~~\n', i,length(remaining),struct_id)
+    AutoFind(struct_id,parameters,1);% 1 because already connected to mysql
+    fprintf('~~~~~~~~ DONE OK ~~~~~~~~\n\n\n');
+  catch
+    fprintf('~~~~~~~~~ SPOT UNFINISHED ~~~~~~~~~~\n')
+    tmp=lasterror;
+    fprintf('Error: %s \n%s at line %d\n',tmp.message,tmp.stack(1).file,tmp.stack(1).line);
+    fprintf('\n\n\n');
+  end
+end
+
+mym('close')
+
+
diff --git a/3_match_extspot/gt_batchAutoFind2.m b/3_match_extspot/gt_batchAutoFind2.m
new file mode 100755
index 0000000000000000000000000000000000000000..ffae8841b6e9a8608be9bd40e5e55c26eac7abd5
--- /dev/null
+++ b/3_match_extspot/gt_batchAutoFind2.m
@@ -0,0 +1,40 @@
+function gt_batchAutoFind2(first,last,wdir)
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+cd(wdir)
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   SIZE ORDERING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Opening database')
+mym('open','mysql.esrf.fr','gtuser','gtuser');
+mym('use graintracking');
+[remaining]=mym(sprintf(...
+  'select difspotID from %sdifspot where difspotID>=%d and difspotID<=%d order by Area desc',...
+  parameters.acq.name,first,last));
+fprintf('First %d Last %d Number %d\n',first,last,length(remaining))
+
+
+for i=1:length(remaining)
+  try 
+    struct_id=remaining(i);
+    fprintf('~~~~~~ Doing difspot %d, with %d remaining (struct_id = %d) ~~~~~~~~~\n', i,length(remaining),struct_id)
+    AutoFind(struct_id,parameters);
+    fprintf('~~~~~~~~ DONE OK ~~~~~~~~\n\n\n');
+  catch
+    fprintf('~~~~~~~~~ SPOT UNFINISHED ~~~~~~~~~~\n')
+    tmp=lasterror;
+    fprintf('Error: %s \n%s at line %d\n',tmp.message,tmp.stack(1).file,tmp.stack(1).line);
+    fprintf('\n\n\n');
+  end
+end
+
+mym('close')
+
+
diff --git a/3_match_extspot/gt_batchAutoFind_pairs.m b/3_match_extspot/gt_batchAutoFind_pairs.m
new file mode 100755
index 0000000000000000000000000000000000000000..ca2bccf94b2a26e75240f4235540caa544d56b45
--- /dev/null
+++ b/3_match_extspot/gt_batchAutoFind_pairs.m
@@ -0,0 +1,39 @@
+function gt_batchAutoFind_pairs(first,last,wdir)
+%mod to use pair table
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+cd(wdir)
+
+  load parameters.mat
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   SIZE ORDERING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Opening database')
+gtDBConnect
+[remaining]=mym(sprintf(...
+  'select difspotID from %sdifspot where difspotID>=%d and difspotID<=%d and BoundingBoxXsize>10 and BoundingBoxYsize>10 order by Area desc',...
+  parameters.acq.name,first,last));
+
+fprintf('First %d Last %d Number %d\n',first,last,length(remaining))
+
+
+for i=1:length(remaining)
+  try 
+    struct_id=remaining(i);
+    fprintf('~~~~~~ Doing difspot %d of %d (struct_id = %d) ~~~~~~~~~\n', i,length(remaining),struct_id)
+    AutoFind_test(struct_id,parameters,1);
+    fprintf('~~~~~~~~ DONE OK ~~~~~~~~\n\n\n');
+  catch
+    fprintf('~~~~~~~~~ SPOT UNFINISHED ~~~~~~~~~~\n')
+    tmp=lasterror;
+    fprintf('Error: %s \n%s at line %d\n',tmp.message,tmp.stack(1).file,tmp.stack(1).line);
+    fprintf('\n\n\n');
+ end
+end
+
+mym('close')
+
+
diff --git a/3_match_extspot/gtnewGetDifImage.m b/3_match_extspot/gtnewGetDifImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..a2eac3c8cc06be321e129252d25ad32302ca7560
--- /dev/null
+++ b/3_match_extspot/gtnewGetDifImage.m
@@ -0,0 +1,11 @@
+function im=gtGetDifImage(ndx,struct_id)
+%returns the full image requested, cropped to the specified difspot bounding box
+
+global difspot
+
+if isempty(difspot)
+  disp('Loading difspot file')
+  load('2_difspot/difspot.mat');
+end
+
+im = edf_read(sprintf('1_preprocessed/full/full%04d.edf',ndx),difspot(struct_id).BoundingBox);
diff --git a/3_match_extspot/gtnewGetExtImage.m b/3_match_extspot/gtnewGetExtImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..634042fc957c4ccca772e1761778e17bfe8f0a55
--- /dev/null
+++ b/3_match_extspot/gtnewGetExtImage.m
@@ -0,0 +1,12 @@
+function im=gtnewGetExtImage(ndx)
+%returns the direct beam part of the requested full image
+
+global parameters;
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+im = edf_read(sprintf('1_preprocessed/full/full%04d.edf',ndx),parameters.acq.bb);
+
+
diff --git a/3_match_extspot/gtnewGetMeanExtImage.m b/3_match_extspot/gtnewGetMeanExtImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..1100994324963b335597b2f1861a3073a35b31d6
--- /dev/null
+++ b/3_match_extspot/gtnewGetMeanExtImage.m
@@ -0,0 +1,21 @@
+function im=gtnewGetMeanExtImage(ndx)
+% returns the mean extinction image corresponding to a given difspot
+
+global parameters; global difspot;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+if isempty(difspot)
+  disp('Loading difspot file')
+  load('2_difspot/difspot.mat');
+end
+
+im=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+disp([num2str(difspot(ndx).ExtEndImage-difspot(ndx).ExtStartImage+1) ' images in sum'])
+for i=difspot(ndx).ExtStartImage:difspot(ndx).ExtEndImage
+  im = im + edf_read(sprintf('1_preprocessed/ext/ext%04d.edf',i));
+end
+im=im/(difspot(ndx).ExtEndImage-difspot(ndx).ExtStartImage+1);
+end
diff --git a/3_match_extspot/gtnewGetMeanFullImage.m b/3_match_extspot/gtnewGetMeanFullImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..96cfa35d670555beda179eec2639e8b55088168b
--- /dev/null
+++ b/3_match_extspot/gtnewGetMeanFullImage.m
@@ -0,0 +1,31 @@
+function im=gtnewGetMeanFullImage(ndx)
+% returns the mean full direct beam corresponding to a given difspot
+
+% modified December 2006 to support database
+global parameters
+% global difspot
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+%if isempty(difspot)
+%  disp('Loading difspot file')
+%  load('2_difspot/difspot.mat');
+%end
+
+% connect to database
+gtDBConnect
+
+im=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',parameters.acq.name,ndx);
+
+[ExtStartImage,ExtEndImage]=mym(mysqlcmd);
+
+fprintf('%d images in sum\n',ExtEndImage-ExtStartImage+1);
+
+for i=ExtStartImage:ExtEndImage
+  im = im + edf_read(sprintf('1_preprocessed/full/full%04d.edf',i), parameters.acq.bb);
+end
+im=im/(ExtEndImage-ExtStartImage+1);
+end
diff --git a/3_match_extspot/gtnew_calculate_twotheta.m b/3_match_extspot/gtnew_calculate_twotheta.m
new file mode 100755
index 0000000000000000000000000000000000000000..85624cf656a266f600fdf10e8e78f797a466f576
--- /dev/null
+++ b/3_match_extspot/gtnew_calculate_twotheta.m
@@ -0,0 +1,228 @@
+%function [twotheta,results]=gtnew_calculate_twotheta_sab(d0,spacegroup,energy,strain)
+function [twotheta,results]=gtnew_calculate_twotheta()
+
+% CALCULATE_TWOTHETA.M
+% Given the d0 spacing(==lattice paramter), spacegroup, and energy, returns the diffraction
+% angles for different reflections.
+%
+% Usage:
+% theta=calculate_theta(d0,spacegroup,energy[,strain])
+%
+%%
+% DESCRIPTIVE TEXT
+% Input:
+% d0 is lattice spacing in angstroms (eg 4.04 for Al)
+% spacegroup, e.g.:  225 (only option supported at present
+% energy is in keV
+% strain, if present, is between 0 and 1.
+%
+% Output:
+% twotheta is a mhashtable object - an array which has a NAME for each
+% element, not an index.  You can get look at your results like this:
+% if twotheta.containsKey('111')
+%   twotheta.get('111')
+% end
+% the min and max values only appear if the strain is non-zero
+% More help on mhashtable in demo_hashtable
+
+
+% Check parameters
+%%%%%%%%%%%%modif sabine%%%%%%%%%%%%%%%%%%%%
+load('parameters.mat');
+acq=parameters.acq;
+spacegroup=acq.spacegroup;
+energy= acq.energy;
+lambda=12.398/energy;
+latticepar=acq.latticepar;
+%%%%%%%%%%%%%%%%%fin modif sabine%%%%%%%%%%%%%%%%%
+
+if ~exist('strain','var')
+    % only calculate perfect values
+    strain=0;
+elseif strain<0||strain>1
+    error('Strain must be between 0 and 1')
+end
+
+
+switch spacegroup
+    case 225
+        % verify the theoretically allowed reflections !
+        reflections=[...
+            1 1 1;...
+            2 0 0;...
+            2 2 0;...
+            3 1 1;...
+            4 0 0;...
+            3 3 1;...
+            ];
+
+        
+        twotheta=mhashtable;
+        %modif sabine
+        d0=latticepar(1);
+        %fin modif sabine
+        for i=1:size(reflections,1)
+            tmp=2*180/pi*asin(lambda/2./(d0*[1-strain 1 1+strain])*norm(reflections(i,:)));
+            if strain~=0
+                vals.max=tmp(1);
+                vals.min=tmp(3);
+                maxvalue(i)=tmp(1);
+                minvalue(i)=tmp(3);
+            end
+            vals.centre=tmp(2);
+            centrevalues(i)=tmp(2);
+            stmp=num2str(reflections(i,:));
+
+            stmp(isspace(stmp))=[];
+            twotheta.put(stmp,vals);
+        end
+    case 229
+        % verify the theoretically allowed reflections !
+        reflections=[...
+            1 1 0;...
+            2 0 0;...
+            2 1 1;...
+            2 2 0;...
+            3 1 0;...
+            ];
+
+        %lambda=12.398/energy;   % verify constant !
+        twotheta=mhashtable;
+        %modif sabine
+        d0=latticepar(1);
+        %fin modif sabine
+
+        for i=1:size(reflections,1)
+            tmp=2*180/pi*asin(lambda/2./(d0*[1-strain 1 1+strain])*norm(reflections(i,:)));
+            if strain~=0
+                vals.max=tmp(1);
+                vals.min=tmp(3);
+                maxvalue(i)=tmp(1);
+                minvalue(i)=tmp(3);
+            end
+            vals.centre=tmp(2);
+            centrevalues(i)=tmp(2);
+            stmp=num2str(reflections(i,:));
+
+            stmp(isspace(stmp))=[];
+            twotheta.put(stmp,vals);
+        end
+
+    case 663 %cas de la neige
+        reflections=[...
+            0 0 0 2; ...
+            1 1 -2 0; ...
+            1 -1 0 0; ...
+            1 -1 0 1; ...
+            1 1 -2 2; ...
+            -2 0 2 1; ...
+            ];
+
+
+        twotheta=mhashtable;
+
+
+        for i=1:size(reflections,1)
+            h=reflections(i,1);k=reflections(i,2) ;l=reflections(i,4);
+            dspacing = latticepar(1)/(4/3*(h^2+k^2+h*k)+(l*latticepar(1)/latticepar(3))^2)^0.5;
+            tmp=2*180/pi*asin(lambda/2./(dspacing*[1-strain 1 1+strain]));
+            if strain~=0
+                vals.max=tmp(1);
+                vals.min=tmp(3);
+                maxvalue(i)=tmp(1);
+                minvalue(i)=tmp(3);
+            end
+            vals.centre=tmp(2);
+            centrevalues(i)=tmp(2);
+            stmp=num2str(reflections(i,:));
+
+            stmp(isspace(stmp))=[];
+            twotheta.put(stmp,vals);
+
+		end
+
+		
+    case 194 % hexagonal close packed - Mg
+	  
+	  reflections=[...
+            1 0 -1 0; ...
+			0 0 0 2; ...
+			1 0 -1 1; ...
+			1 0 -1 2; ...
+			1 1 -2 0; ...
+			1 0 -1 3; ...
+            ];
+%first 6, followed by 1 1 -2 2 ; 2 0 -2 1 ; 1 0 -1 4
+
+        twotheta=mhashtable;
+
+        for i=1:size(reflections,1)
+            h=reflections(i,1);k=reflections(i,2) ;l=reflections(i,4);
+            dspacing = latticepar(1)/(4/3*(h^2+k^2+h*k)+(l*latticepar(1)/latticepar(3))^2)^0.5;
+            tmp=2*180/pi*asin(lambda/2./(dspacing*[1-strain 1 1+strain]));
+            if strain~=0
+                vals.max=tmp(1);
+                vals.min=tmp(3);
+                maxvalue(i)=tmp(1);
+                minvalue(i)=tmp(3);
+            end
+            vals.centre=tmp(2);
+            centrevalues(i)=tmp(2);
+            stmp=num2str(reflections(i,:));
+
+            stmp(isspace(stmp))=[];
+            twotheta.put(stmp,vals);
+
+		end
+
+		   case 167 % Trigonal hexagonal scalenohedral r(-)3c - Alumina
+                    % removed 20-22 - v low intensity)
+	  reflections=[...
+           0 1 -1 2; ...
+           1 0 -1 4; ...
+           1 1 -2 0; ...
+           1 1 -2 3; ...
+           0 2 -2 4; ...
+           1 1 -2 6; ...
+            ];
+
+        twotheta=mhashtable;
+
+        for i=1:size(reflections,1)
+            h=reflections(i,1);k=reflections(i,2) ;l=reflections(i,4);
+            dspacing = latticepar(1)/(4/3*(h^2+k^2+h*k)+(l*latticepar(1)/latticepar(3))^2)^0.5;
+            tmp=2*180/pi*asin(lambda/2./(dspacing*[1-strain 1 1+strain]));
+            if strain~=0
+                vals.max=tmp(1);
+                vals.min=tmp(3);
+                maxvalue(i)=tmp(1);
+                minvalue(i)=tmp(3);
+            end
+            vals.centre=tmp(2);
+            centrevalues(i)=tmp(2);
+            stmp=num2str(reflections(i,:));
+
+            stmp(isspace(stmp))=[];
+            twotheta.put(stmp,vals);
+
+		end
+
+
+    otherwise
+        error('Sorry, only primitive FCC (225) or bcc (229) or hexagonal (663, 194) trigonal (167) are possible at present');
+end
+
+if nargout==2
+    % simpler output (should ditch the hashtable)
+    results.reflections=reflections;
+    if exist('minvalues','var')
+        results.min=minvalues';
+        results.max=maxvalues';
+    end
+    results.centre=centrevalues';
+end
+end
+
+
+
+
diff --git a/3_match_extspot/gtnew_calculate_twotheta_old.m b/3_match_extspot/gtnew_calculate_twotheta_old.m
new file mode 100755
index 0000000000000000000000000000000000000000..94563d4cbbe5a906476cd79457bbb4aeb6cdbac3
--- /dev/null
+++ b/3_match_extspot/gtnew_calculate_twotheta_old.m
@@ -0,0 +1,135 @@
+function [twotheta,results]=gtnew_calculate_twotheta(d0,spacegroup,energy,strain)
+% CALCULATE_TWOTHETA.M
+% Given the d0 spacing(==lattice paramter), spacegroup, and energy, returns the diffraction
+% angles for different reflections.
+%
+% Usage:
+% theta=calculate_theta(d0,spacegroup,energy[,strain])
+%
+% Input:
+% d0 is lattice spacing in angstroms (eg 4.04 for Al)
+% spacegroup, e.g.:  225 (only option supported at present
+% energy is in keV
+% strain, if present, is between 0 and 1.
+%
+% Output:
+% twotheta is a mhashtable object - an array which has a NAME for each
+% element, not an index.  You can get look at your results like this:
+% if twotheta.containsKey('111')
+%   twotheta.get('111')
+% end
+% the min and max values only appear if the strain is non-zero
+% More help on mhashtable in demo_hashtable
+
+
+% Check parameters
+
+if ~exist('strain','var')
+  % only calculate perfect values
+  strain=0;
+elseif strain<0||strain>1
+  error('Strain must be between 0 and 1')
+end
+
+
+switch spacegroup
+  case 225
+    % verify the theoretically allowed reflections !
+    reflections=[...
+      1 1 1;...
+      2 0 0;...
+      2 2 0;...
+      3 1 1;...
+      4 0 0;...
+      3 3 1;...
+      ];
+
+    lambda=12.398/energy;   % verify constant !
+    twotheta=mhashtable;
+    for i=1:size(reflections,1)
+      
+      tmp=2*180/pi*asin(lambda/2./(d0*[1-strain 1 1+strain])*norm(reflections(i,:)));
+      if strain~=0
+        vals.max=tmp(1);
+        vals.min=tmp(3);
+        maxvalue(i)=tmp(1);
+        minvalue(i)=tmp(3);
+      end
+      vals.centre=tmp(2);
+      centrevalues(i)=tmp(2);
+      stmp=num2str(reflections(i,:));
+      
+      stmp(isspace(stmp))=[];
+      twotheta.put(stmp,vals);
+    end
+  case 229
+    % verify the theoretically allowed reflections !
+    reflections=[...
+      1 1 0;...
+      2 0 0;...
+      1 1 2;...
+      ];
+
+    lambda=12.398/energy;   % verify constant !
+    twotheta=mhashtable;
+    for i=1:size(reflections,1)
+      
+      tmp=2*180/pi*asin(lambda/2./(d0*[1-strain 1 1+strain])*norm(reflections(i,:)));
+      if strain~=0
+        vals.max=tmp(1);
+        vals.min=tmp(3);
+        maxvalue(i)=tmp(1);
+        minvalue(i)=tmp(3);
+      end
+      vals.centre=tmp(2);
+      centrevalues(i)=tmp(2);
+      stmp=num2str(reflections(i,:));
+      
+      stmp(isspace(stmp))=[];
+      twotheta.put(stmp,vals);
+    end
+    
+  case hexagonal
+    %check the allowed reflections
+    reflections=[...
+      %put allowed hkls here...
+      ];
+    lambda=12.398/energy;   % verify constant !
+    twotheta=mhashtable;
+        for i=1:size(reflections,1)
+          dspacing=%some function of a,c,h,k,l
+          tmp=2*180/pi*asin(lambda/2./(dspacing*[1-strain 1 1+strain])));
+          
+           if strain~=0
+        vals.max=tmp(1);
+        vals.min=tmp(3);
+        maxvalue(i)=tmp(1);
+        minvalue(i)=tmp(3);
+      end
+      vals.centre=tmp(2);
+      centrevalues(i)=tmp(2);
+      stmp=num2str(reflections(i,:));
+      
+      stmp(isspace(stmp))=[];
+      twotheta.put(stmp,vals);
+          
+        end
+        
+  otherwise
+    error('Sorry, only primitive FCC (225) or bcc (229) possible at present');
+end
+
+if nargout==2
+    % simpler output (should ditch the hashtable)
+    results.reflections=reflections;
+    if exist('minvalues','var')
+        results.min=minvalues';  
+        results.max=maxvalues';
+    end
+    results.centre=centrevalues';
+end
+end
+
+
+
+
diff --git a/3_match_extspot/gtnew_mask_extinction_function.m b/3_match_extspot/gtnew_mask_extinction_function.m
new file mode 100755
index 0000000000000000000000000000000000000000..6d3a412ef7b92e56c6efbf0b2e79725ed0a190f3
--- /dev/null
+++ b/3_match_extspot/gtnew_mask_extinction_function.m
@@ -0,0 +1,169 @@
+% MASK_EXTINCTION.M
+% Given a full Frelon image, with the user selection of a diffraction spot,
+% attempts to mask the possible area in the extinction image within which
+% the spot could have diffracted from.  See below for assumptions about
+% diffraction criteria.
+%
+% Based on plot_rings.m by Andy King
+%
+% Greg Johnson September 2006
+
+%modified to at as a function, returning mask based on input of difspot
+%struct_id
+%Andy, 11/9/2006
+%taking the difspot parameters from the database -------Marcelo 08/12/2006,
+%should work for 360 is available
+
+function mask_ext = gtnew_mask_extinction_function(struct_id, varargin);
+
+global parameters; 
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+im=zeros(parameters.acq.ydet, parameters.acq.xdet);
+bb=parameters.acq.bb;
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%get the difspot information of the spot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mysqlcmd=sprintf([...
+  'select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, '...
+  'CentroidX, CentroidY from %sdifspot where difspotID=%d'],... %PairID was deleted from the list
+  parameters.acq.name, struct_id);
+[BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, CentroidX, CentroidY]=mym(mysqlcmd);%, PairID]=mym(mysqlcmd);
+dif_bb(1,:) = [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize];
+dif_cent(1,:) = [CentroidX, CentroidY];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%get the difspot pair information if possible
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+pair_flag = 0; %180, one difspot, default case
+%if ~isnan(PairID) 
+%   pair_flag = 1;% 360, two difspots, special case
+%   mysqlcmd=sprintf([...
+%     'select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, '...
+%     'CentroidX, CentroidY, Theta from %sdifspot where difspotID=%d'],...
+%     parameters.acq.pair_name, PairID);
+%   [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, CentroidX, CentroidY, Theta]=mym(mysqlcmd);
+%   dif_bb(2,:) = [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize];
+%   dif_cent(2,:) = [CentroidX, CentroidY];
+   %so dif_bb has two entries if available, plus read known Theta angle
+%end
+%warning('force pair flag to zero')
+%pair_flag=0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%Construct mask from pair of difspots 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%if pair_flag == 1%360 degree, two difspots   
+%apply mirror transform to pair position
+%dif_cent(2,1) = 2*parameters.acq.rotx - dif_cent(2,1);
+%dif_bb(2,1) = 2*parameters.acq.rotx - dif_bb(2,1) - dif_bb(2,3);
+
+%grad = (dif_cent(2,2)-dif_cent(1,2))/(dif_cent(2,1)-dif_cent(1,1));
+
+%in line equation, find all possible c in y=mx+c
+%max and min c values gives edges of mask area
+%c(1) = dif_bb(1,2) - grad*dif_bb(1,1);
+%c(2) = dif_bb(1,2) - grad*(dif_bb(1,1)+dif_bb(1,3));
+%c(3) = (dif_bb(1,2)+dif_bb(1,4)) - grad*dif_bb(1,1);
+%c(4) = (dif_bb(1,2)+dif_bb(1,4)) - grad*(dif_bb(1,1)+dif_bb(1,3));
+%c(5) = dif_bb(2,2) - grad*dif_bb(2,1);
+%c(6) = dif_bb(2,2) - grad*(dif_bb(2,1)+dif_bb(2,3));
+%c(7) = (dif_bb(2,2)+dif_bb(2,4)) - grad*dif_bb(2,1);
+%c(8) = (dif_bb(2,2)+dif_bb(2,4)) - grad*(dif_bb(2,1)+dif_bb(2,3));
+%c_min = min(c);
+%c_max = max(c);
+
+%mask_line=zeros(size(im));
+%y(1) = (grad*1)+c_min;
+%y(2) = (grad*size(im,1))+c_min;
+%y(3) = (grad*size(im,1))+c_max;
+%y(4) = (grad*1)+c_max;
+
+%y(find(y<1))=1;
+%y(find(y>size(im,2)))=size(im,2);
+%x(1:2) = (y(1:2) - c_min)./grad;
+%x(3:4) = (y(3:4) - c_max)./grad;
+
+%mask = poly2mask(x,y,size(im,2),size(im,1));
+%mask(3,:,:) = gtCrop(mask,parameters.acq.bb);
+
+%end %line mask for two difspots
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%Construct mask from single difspot, using
+%allowed theta angles condition
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for i=1:size(dif_bb,1);%for - to run this for both spots if available
+  
+  %note - this is probably not very efficient! ak
+  
+%centre of difspot - use centre of bb
+point.x = ceil(dif_bb(i,1)+dif_bb(i,3)/2);
+point.y = ceil(dif_bb(i,2)+dif_bb(i,4)/2);
+
+%note - sample width overestimates
+xc=parameters.acq.dist;  
+sample_width=parameters.acq.bb(3);
+
+if (pair_flag == 1 && ~isempty(Theta))
+%if we have a pair of difspots, we should know Theta, so
+%single value read from database
+twotheta=2*Theta;
+else%180 degree case, get all possible allowed Theta angles
+  tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+  tmp=tmp.elements;
+  for n=1:length(tmp)
+    twotheta(n)=tmp{n}.centre;
+  end
+end
+
+dist_rear=xc+(sample_width*parameters.acq.pixelsize/2); % assume sample is cuboid
+dist_front=xc-(sample_width*parameters.acq.pixelsize/2);
+
+rad_front=dist_front*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+
+%add a constant to radii based on the size of the difspot
+dif_rad = (sqrt(dif_bb(i,3:4)*dif_bb(i,3:4)'))/2;
+rad_front = rad_front-dif_rad;
+rad_rear = rad_rear+dif_rad;
+
+tmask=zeros(size(im));
+for n=1:length(rad_front)
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+
+mask(i,:,:)=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+tmask = gtCrop(tmask, parameters.acq.bb);
+mask(i,tmask)=1;
+  
+end%180 case for one or two difspots
+
+
+if pair_flag == 1
+%final mask is the AND of all three masks
+mask(1,:,:) = (mask(1,:,:) & mask(2,:,:) & mask(3,:,:));
+end
+
+%flatten mask to 2d
+mask_ext = reshape(mask(1,:,:), size(mask,2), size(mask,3)); 
+
+
diff --git a/3_match_extspot/gtnew_mask_extinction_function_mod.m b/3_match_extspot/gtnew_mask_extinction_function_mod.m
new file mode 100755
index 0000000000000000000000000000000000000000..5fc4b0aeb16f0d469a6ae7deaf1b7b6a4c4751d7
--- /dev/null
+++ b/3_match_extspot/gtnew_mask_extinction_function_mod.m
@@ -0,0 +1,156 @@
+% MASK_EXTINCTION.M
+% Given a full Frelon image, with the user selection of a diffraction spot,
+% attempts to mask the possible area in the extinction image within which
+% the spot could have diffracted from.  See below for assumptions about
+% diffraction criteria.
+%
+% Based on plot_rings.m by Andy King
+%
+% Greg Johnson September 2006
+
+%modified to at as a function, returning mask based on input of difspot
+%struct_id
+%Andy, 11/9/2006
+
+
+function mask_ext = gtnew_mask_extinction_function_mod(struct_id);
+
+global parameters; % global difspot;
+database='graintracking' ;
+
+
+
+
+% ONLY FOR TEST. MODIFICATION NEEDED IN DATABASE NAMES !!
+disp('ONLY FOR TEST. MODIFICATION NEEDED IN DATABASE NAMES !!')
+%difspottable1=[parameters.acq.name 'difspot'] ;  ??????
+%difspottable2= ... ??????
+difspottable1 = 's5_dct8_difspot' % FOR TEST
+difspottable2 = 's5_dct9_difspot' % FOR TEST
+
+
+
+
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+disp('Loading difspot data from database')
+mym('open','mysql.esrf.fr','gtuser','gtuser') ;
+mym(['use ',database]) ;
+
+im=zeros(parameters.acq.ydet, parameters.acq.xdet);
+
+bb=parameters.acq.bb;
+
+[dif_bb(1,1),dif_bb(1,2),dif_bb(1,3),dif_bb(1,4),dif_cent(1,1),dif_cent(1,2)] = mym(sprintf(['select ', ...
+    'BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize,CentroidX,CentroidY ', ...
+    'from %s where difspotID=%d'],difspottable1,struct_id)) ;
+
+flag = 0; %180, one difspot, default case
+if isequal(parameters.acq.type,'360degree')
+  pair_id = mym(sprintf('select PairID from %s where difspotID=%d',difspottable1,struct_id)) ;
+  if ~isempty(pair_id) 
+    flag = 1;% 360, two difspots, special case
+    
+    [dif_bb(2,1),dif_bb(2,2),dif_bb(2,3),dif_bb(2,4),dif_cent(2,1),dif_cent(2,2)] = mym(sprintf(['select ', ...
+    'BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize,CentroidX,CentroidY ', ...
+    'from %s where difspotID=%d'],difspottable2,pair_id)) ;
+  end
+end
+
+if flag == 1  %360 degree, two difspot sets/tables
+
+%apply mirror transform to pair position
+dif_cent(2,1) = 2*parameters.acq.rotx - dif_cent(2,1);
+dif_bb(2,1) = 2*parameters.acq.rotx - dif_bb(2,1) - dif_bb(2,3);
+
+grad = (dif_cent(2,2)-dif_cent(1,2))/(dif_cent(2,1)-dif_cent(1,1));
+
+%in line equation, find all possible c in y=mx+c
+%max and min c values gives edges of mask area
+
+c(1) = dif_bb(1,2) - grad*dif_bb(1,1);
+c(2) = dif_bb(1,2) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(3) = (dif_bb(1,2)+dif_bb(1,4)) - grad*dif_bb(1,1);
+c(4) = (dif_bb(1,2)+dif_bb(1,4)) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(5) = dif_bb(2,2) - grad*dif_bb(2,1);
+c(6) = dif_bb(2,2) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c(7) = (dif_bb(2,2)+dif_bb(2,4)) - grad*dif_bb(2,1);
+c(8) = (dif_bb(2,2)+dif_bb(2,4)) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c_min = min(c);
+c_max = max(c);
+
+mask_line=zeros(size(im));
+y(1) = (grad*1)+c_min;
+y(2) = (grad*size(im,1))+c_min;
+y(3) = (grad*size(im,1))+c_max;
+y(4) = (grad*1)+c_max;
+
+y(find(y<1))=1;
+y(find(y>size(im,2)))=size(im,2);
+x(1:2) = (y(1:2) - c_min)./grad;
+x(3:4) = (y(3:4) - c_max)./grad;
+
+mask = poly2mask(x,y,size(im,2),size(im,1));
+mask(3,:,:) = gtCrop(mask,parameters.acq.bb);
+
+end %line mask for two difspots
+
+
+for i=1:size(dif_bb,1); %for - to run this for both spots if available%180 degree, single difspot case
+  
+%centre of difspot - use centre of bb
+point.x = ceil(dif_bb(i,1)+dif_bb(i,3)/2);
+point.y = ceil(dif_bb(i,2)+dif_bb(i,4)/2);
+
+%note - sample width overestimates
+xc=parameters.acq.dist;  
+sample_width=parameters.acq.bb(3);
+
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+
+dist_rear=xc+(sample_width*parameters.acq.pixelsize/2); % assume sample is cuboid
+dist_front=xc-(sample_width*parameters.acq.pixelsize/2);
+
+rad_front=dist_front*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+
+%add a constant to radii based on the size of the difspot
+dif_rad = (sqrt(dif_bb(i,3:4)*dif_bb(i,3:4)'))/2;
+rad_front = rad_front-dif_rad;
+rad_rear = rad_rear+dif_rad;
+
+
+tmask=zeros(size(im));
+for n=1:length(rad_front) % as many as twotheta angles; valid theta to be set here
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+
+mask(i,:,:)=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+tmask = gtCrop(tmask, parameters.acq.bb);
+mask(i,tmask)=1;
+  
+end%180 case for one or two difspots
+
+
+if flag == 1
+%final mask is the AND of all three masks
+mask(1,:,:) = (mask(1,:,:) & mask(2,:,:) & mask(3,:,:));
+end
+
+%flatten mask to 2d
+mask_ext = reshape(mask(1,:,:), size(mask,2), size(mask,3)); 
+
+
diff --git a/3_match_extspot/gtnew_mask_extinction_function_old.m b/3_match_extspot/gtnew_mask_extinction_function_old.m
new file mode 100755
index 0000000000000000000000000000000000000000..625a46702f1001e8c9809399198ac1766b17e568
--- /dev/null
+++ b/3_match_extspot/gtnew_mask_extinction_function_old.m
@@ -0,0 +1,145 @@
+% MASK_EXTINCTION.M
+% Given a full Frelon image, with the user selection of a diffraction spot,
+% attempts to mask the possible area in the extinction image within which
+% the spot could have diffracted from.  See below for assumptions about
+% diffraction criteria.
+%
+% Based on plot_rings.m by Andy King
+%
+% Greg Johnson September 2006
+
+%modified to at as a function, returning mask based on input of difspot
+%struct_id
+%Andy, 11/9/2006
+
+
+function mask_ext = gtnew_mask_extinction_function(struct_id);
+
+global parameters; global difspot;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+if isempty(difspot)
+  disp('Loading difspot file')
+  load('2_difspot/difspot/difspot.mat');
+end
+
+im=zeros(parameters.acq.ydet, parameters.acq.xdet);
+
+bb=parameters.acq.bb;
+
+dif_bb(1,:) = difspot(struct_id).BoundingBox;
+dif_cent(1,:) = difspot(struct_id).Centroid;
+
+
+
+
+
+flag = 0; %180, one difspot, default case
+if isfield(difspot(struct_id),'pair_id')
+  if ~isempty(difspot(struct_id).pair_id) 
+    flag = 1;% 360, two difspots, special case
+    pair_id = difspot(struct_id).pair_id;
+    dif_bb(2,:) = difspot(pair_id).BoundingBox;%or however...
+    dif_cent(2,:) = difspot(pair_id).Centroid;
+%so dif_bb has two entries if available
+  end
+end
+
+if flag == 1%360 degree, two difspots
+    
+
+%apply mirror transform to pair position
+dif_cent(2,1) = 2*parameters.acq.rotx - dif_cent(2,1);
+dif_bb(2,1) = 2*parameters.acq.rotx - dif_bb(2,1) - dif_bb(2,3);
+
+grad = (dif_cent(2,2)-dif_cent(1,2))/(dif_cent(2,1)-dif_cent(1,1));
+
+%in line equation, find all possible c in y=mx+c
+%max and min c values gives edges of mask area
+
+c(1) = dif_bb(1,2) - grad*dif_bb(1,1);
+c(2) = dif_bb(1,2) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(3) = (dif_bb(1,2)+dif_bb(1,4)) - grad*dif_bb(1,1);
+c(4) = (dif_bb(1,2)+dif_bb(1,4)) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(5) = dif_bb(2,2) - grad*dif_bb(2,1);
+c(6) = dif_bb(2,2) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c(7) = (dif_bb(2,2)+dif_bb(2,4)) - grad*dif_bb(2,1);
+c(8) = (dif_bb(2,2)+dif_bb(2,4)) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c_min = min(c);
+c_max = max(c);
+
+mask_line=zeros(size(im));
+y(1) = (grad*1)+c_min;
+y(2) = (grad*size(im,1))+c_min;
+y(3) = (grad*size(im,1))+c_max;
+y(4) = (grad*1)+c_max;
+
+y(find(y<1))=1;
+y(find(y>size(im,2)))=size(im,2);
+x(1:2) = (y(1:2) - c_min)./grad;
+x(3:4) = (y(3:4) - c_max)./grad;
+
+mask = poly2mask(x,y,size(im,2),size(im,1));
+mask(3,:,:) = gtCrop(mask,parameters.acq.bb);
+
+end %line mask for two difspots
+
+
+for i=1:size(dif_bb,1);%for - to run this for both spots if available%180 degree, single difspot case
+  
+%centre of difspot - use centre of bb
+point.x = ceil(dif_bb(i,1)+dif_bb(i,3)/2);
+point.y = ceil(dif_bb(i,2)+dif_bb(i,4)/2);
+
+
+%note - sample width overestimates
+xc=parameters.acq.dist;  
+sample_width=parameters.acq.bb(3);
+
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+
+dist_rear=xc+(sample_width*parameters.acq.pixelsize/2); % assume sample is cuboid
+dist_front=xc-(sample_width*parameters.acq.pixelsize/2);
+
+rad_front=dist_front*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+
+%add a constant to radii based on the size of the difspot
+dif_rad = (sqrt(dif_bb(i,3:4)*dif_bb(i,3:4)'))/2;
+rad_front = rad_front-dif_rad;
+rad_rear = rad_rear+dif_rad;
+
+
+tmask=zeros(size(im));
+for n=1:length(rad_front)
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+
+mask(i,:,:)=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+tmask = gtCrop(tmask, parameters.acq.bb);
+mask(i,tmask)=1;
+  
+end%180 case for one or two difspots
+
+
+if flag == 1
+%final mask is the AND of all three masks
+mask(1,:,:) = (mask(1,:,:) & mask(2,:,:) & mask(3,:,:));
+end
+
+%flatten mask to 2d
+mask_ext = reshape(mask(1,:,:), size(mask,2), size(mask,3)); 
+
+
diff --git a/3_match_extspot/gtnew_mask_extinction_function_pair.m b/3_match_extspot/gtnew_mask_extinction_function_pair.m
new file mode 100755
index 0000000000000000000000000000000000000000..13d351303b5974a301ed3d3a2c22f8304ae0c9ca
--- /dev/null
+++ b/3_match_extspot/gtnew_mask_extinction_function_pair.m
@@ -0,0 +1,196 @@
+% MASK_EXTINCTION.M
+% Given a full Frelon image, with the user selection of a diffraction spot,
+% attempts to mask the possible area in the extinction image within which
+% the spot could have diffracted from.  See below for assumptions about
+% diffraction criteria.
+%
+% Based on plot_rings.m by Andy King
+%
+% Greg Johnson September 2006
+
+%modified to at as a function, returning mask based on input of difspot
+%struct_id
+%Andy, 11/9/2006
+%taking the difspot parameters from the database -------Marcelo 08/12/2006,
+%read from the spotpairs database, and the relevent difspot tables
+
+%use idea of having two extspot tables.  Therefore inputID is the difspotID
+%of the dataset in which function is called.  Pair info is looked up in the
+%pair table and the relevent other difspot table
+
+function mask_ext = gtnew_mask_extinction_function_pair(struct_id, varargin);
+
+
+
+  load('parameters.mat');
+
+
+im=zeros(parameters.acq.ydet, parameters.acq.xdet);
+bb=parameters.acq.bb;
+
+%varargin of 1 means already connected
+if ~isempty(varargin) 
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%get the information about this difspot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mysqlcmd=sprintf([...
+  'select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, '...
+  'CentroidX, CentroidY from %sdifspot where difspotID=%d'],...
+  parameters.acq.name, struct_id);
+[BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, CentroidX, CentroidY]=mym(mysqlcmd);
+dif_bb = [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize];
+dif_cent = [CentroidX, CentroidY];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%get info from pair table
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if parameters.acq.type=='360degree'
+  spotpairs_table = parameters.acq.pair_tablename;
+  pair_name = parameters.acq.pair_name;
+
+  %is the current dataset A or B?
+  if strcmp(parameters.acq.name,parameters.acq.difA_name)
+    difID='difAID';
+    pair_difID='difBID';
+  elseif strcmp(parameters.acq.name, parameters.acq.difB_name)
+    difID='difBID';
+    pair_difID='difAID';
+  else
+    error('cannot determine if this dataset is A or B in 360 case')
+  end
+
+  %get the pair_struct_id
+  mysqlcmd=sprintf('select %s, Theta from %s where %s=%d ',...
+    pair_difID,spotpairs_table,difID,struct_id);
+  [pair_struct_id, Theta] = mym(mysqlcmd);
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %get the pair difspot information
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  if ~isnan(pair_struct_id)
+    mysqlcmd=sprintf([...
+      'select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, '...
+      'CentroidX, CentroidY from %sdifspot where difspotID=%d'],...
+      pair_name, pair_struct_id);
+    [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, CentroidX, CentroidY]=mym(mysqlcmd);
+    dif_bb = [dif_bb; BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize];
+    dif_cent = [dif_cent; CentroidX, CentroidY];
+  end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%Construct mask from pair of difspots 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+pair_flag=0;
+if size(dif_bb,1)==2 %360 degree data, and have two difspots   
+pair_flag=1;
+  
+%apply mirror transform to pair position
+dif_cent(2,1) = 2*parameters.acq.rotx - dif_cent(2,1);
+dif_bb(2,1) = 2*parameters.acq.rotx - dif_bb(2,1) - dif_bb(2,3);
+
+grad = (dif_cent(2,2)-dif_cent(1,2))/(dif_cent(2,1)-dif_cent(1,1));
+
+%in line equation, find all possible c in y=mx+c
+%max and min c values gives edges of mask area
+c(1) = dif_bb(1,2) - grad*dif_bb(1,1);
+c(2) = dif_bb(1,2) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(3) = (dif_bb(1,2)+dif_bb(1,4)) - grad*dif_bb(1,1);
+c(4) = (dif_bb(1,2)+dif_bb(1,4)) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(5) = dif_bb(2,2) - grad*dif_bb(2,1);
+c(6) = dif_bb(2,2) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c(7) = (dif_bb(2,2)+dif_bb(2,4)) - grad*dif_bb(2,1);
+c(8) = (dif_bb(2,2)+dif_bb(2,4)) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c_min = min(c);
+c_max = max(c);
+
+mask_line=zeros(size(im));
+y(1) = (grad*1)+c_min;
+y(2) = (grad*size(im,1))+c_min;
+y(3) = (grad*size(im,1))+c_max;
+y(4) = (grad*1)+c_max;
+
+y(find(y<1))=1;
+y(find(y>size(im,2)))=size(im,2);
+x(1:2) = (y(1:2) - c_min)./grad;
+x(3:4) = (y(3:4) - c_max)./grad;
+
+fullmask = poly2mask(x,y,size(im,2),size(im,1));
+mask(3,:,:) = gtCrop(fullmask,parameters.acq.bb);
+
+end %line mask for two difspots
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%Construct mask from single difspot, using
+%allowed theta angles condition
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for i=1:size(dif_bb,1);%for - to run this for both spots if available
+  
+  %note - this is probably not very efficient! ak
+  
+%centre of difspot - use centre of bb
+point.x = ceil(dif_bb(i,1)+dif_bb(i,3)/2);
+point.y = ceil(dif_bb(i,2)+dif_bb(i,4)/2);
+
+%note - sample width overestimates
+xc=parameters.acq.dist;  
+sample_width=parameters.acq.bb(3);
+
+if (pair_flag == 1 && ~isempty(Theta))
+%if we have a pair of difspots, we should know Theta, so
+%single value read from database
+%warning('spotpairs theta value actually two theta!!')---no longer the case
+twotheta=2*Theta;
+else%180 degree case, get all possible allowed Theta angles
+%  tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=gtnew_calculate_twotheta; 
+tmp=tmp.elements;
+  for n=1:length(tmp)
+    twotheta(n)=tmp{n}.centre;
+  end
+end
+
+dist_rear=xc+(sample_width*parameters.acq.pixelsize/2); % assume sample is cuboid
+dist_front=xc-(sample_width*parameters.acq.pixelsize/2);
+
+rad_front=dist_front*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+
+%add a constant to radii based on the size of the difspot
+dif_rad = (sqrt(dif_bb(i,3:4)*dif_bb(i,3:4)'))/2;
+rad_front = rad_front-dif_rad;
+rad_rear = rad_rear+dif_rad;
+
+tmask=zeros(size(im));
+for n=1:length(rad_front)
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+
+mask(i,:,:)=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+tmask = gtCrop(tmask, parameters.acq.bb);
+mask(i,tmask)=1;
+  
+end%180 case for one or two difspots
+
+
+if pair_flag == 1
+%final mask is the AND of all three masks
+mask(1,:,:) = (mask(1,:,:) & mask(2,:,:) & mask(3,:,:));
+end
+
+%flatten mask to 2d
+mask_ext = reshape(mask(1,:,:), size(mask,2), size(mask,3)); 
+
+
diff --git a/3_match_extspot/gtnew_mask_extinction_function_test.m b/3_match_extspot/gtnew_mask_extinction_function_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..6d1098e512077c087d816e745e1ecd29693839b1
--- /dev/null
+++ b/3_match_extspot/gtnew_mask_extinction_function_test.m
@@ -0,0 +1,146 @@
+% MASK_EXTINCTION.M
+% Given a full Frelon image, with the user selection of a diffraction spot,
+% attempts to mask the possible area in the extinction image within which
+% the spot could have diffracted from.  See below for assumptions about
+% diffraction criteria.
+%
+% Based on plot_rings.m by Andy King
+%
+% Greg Johnson September 2006
+
+%modified to at as a function, returning mask based on input of difspot
+%struct_id
+%Andy, 11/9/2006
+%taking the difspot parameters from the database -------Marcelo 08/12/2006
+
+function mask_ext = gtnew_mask_extinction_function(struct_id);
+
+global parameters; %global difspot;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+%if isempty(difspot)
+ % disp('Loading difspot file')
+ % load('2_difspot/difspot.mat');
+% end
+
+im=zeros(parameters.acq.ydet, parameters.acq.xdet);
+
+bb=parameters.acq.bb;
+
+gtDBconnect
+mysqlcmd=sprintf('select BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, CentroidX, CentroidY, PairID from %sdifspot where difspotID=%d',parameters.acq.name, struct_id);
+[BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, CentroidX, CentroidY, PairID]=mym(mysqlcmd);
+
+dif_bb(1,:) = [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize];%difspot(struct_id).BoundingBox;
+dif_cent(1,:) = [CentroidX, CentroidY];%difspot(struct_id).Centroid;
+
+
+flag = 0; %180, one difspot, default case
+ %if isfield(difspot(struct_id),'pair_id')
+  if ~isempty(PairID) %(difspot(struct_id).pair_id) 
+    flag = 1;% 360, two difspots, special case
+    %pair_id = difspot(struct_id).pair_id;
+    dif_bb(2,:) = [BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize];%difspot(pair_id).BoundingBox;%or however...
+    dif_cent(2,:) = [CentroidX, CentroidY];%difspot(pair_id).Centroid;
+%so dif_bb has two entries if available
+  end
+%end
+
+if flag == 1%360 degree, two difspots
+    
+
+%apply mirror transform to pair position
+dif_cent(2,1) = 2*parameters.acq.rotx - dif_cent(2,1);
+dif_bb(2,1) = 2*parameters.acq.rotx - dif_bb(2,1) - dif_bb(2,3);
+
+grad = (dif_cent(2,2)-dif_cent(1,2))/(dif_cent(2,1)-dif_cent(1,1));
+
+%in line equation, find all possible c in y=mx+c
+%max and min c values gives edges of mask area
+
+c(1) = dif_bb(1,2) - grad*dif_bb(1,1);
+c(2) = dif_bb(1,2) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(3) = (dif_bb(1,2)+dif_bb(1,4)) - grad*dif_bb(1,1);
+c(4) = (dif_bb(1,2)+dif_bb(1,4)) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(5) = dif_bb(2,2) - grad*dif_bb(2,1);
+c(6) = dif_bb(2,2) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c(7) = (dif_bb(2,2)+dif_bb(2,4)) - grad*dif_bb(2,1);
+c(8) = (dif_bb(2,2)+dif_bb(2,4)) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c_min = min(c);
+c_max = max(c);
+
+mask_line=zeros(size(im));
+y(1) = (grad*1)+c_min;
+y(2) = (grad*size(im,1))+c_min;
+y(3) = (grad*size(im,1))+c_max;
+y(4) = (grad*1)+c_max;
+
+y(find(y<1))=1;
+y(find(y>size(im,2)))=size(im,2);
+x(1:2) = (y(1:2) - c_min)./grad;
+x(3:4) = (y(3:4) - c_max)./grad;
+
+mask = poly2mask(x,y,size(im,2),size(im,1));
+mask(3,:,:) = gtCrop(mask,parameters.acq.bb);
+
+end %line mask for two difspots
+
+
+for i=1:size(dif_bb,1);%for - to run this for both spots if available%180 degree, single difspot case
+  
+%centre of difspot - use centre of bb
+point.x = ceil(dif_bb(i,1)+dif_bb(i,3)/2);
+point.y = ceil(dif_bb(i,2)+dif_bb(i,4)/2);
+
+
+%note - sample width overestimates
+xc=parameters.acq.dist;  
+sample_width=parameters.acq.bb(3);
+
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+
+dist_rear=xc+(sample_width*parameters.acq.pixelsize/2); % assume sample is cuboid
+dist_front=xc-(sample_width*parameters.acq.pixelsize/2);
+
+rad_front=dist_front*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(twotheta))/parameters.acq.pixelsize;
+
+%add a constant to radii based on the size of the difspot
+dif_rad = (sqrt(dif_bb(i,3:4)*dif_bb(i,3:4)'))/2;
+rad_front = rad_front-dif_rad;
+rad_rear = rad_rear+dif_rad;
+
+
+tmask=zeros(size(im));
+for n=1:length(rad_front)
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+
+mask(i,:,:)=zeros(parameters.acq.bb(4), parameters.acq.bb(3));
+tmask = gtCrop(tmask, parameters.acq.bb);
+mask(i,tmask)=1;
+  
+end%180 case for one or two difspots
+
+
+if flag == 1
+%final mask is the AND of all three masks
+mask(1,:,:) = (mask(1,:,:) & mask(2,:,:) & mask(3,:,:));
+end
+
+%flatten mask to 2d
+mask_ext = reshape(mask(1,:,:), size(mask,2), size(mask,3)); 
+
+
diff --git a/3_match_extspot/gtnew_prepare_correlation_image.m b/3_match_extspot/gtnew_prepare_correlation_image.m
new file mode 100755
index 0000000000000000000000000000000000000000..27edccc764d1a7ec9632f9e8ea6a7da99ab4465a
--- /dev/null
+++ b/3_match_extspot/gtnew_prepare_correlation_image.m
@@ -0,0 +1,47 @@
+function [dif_maskx, dif_masky] = gtnew_prepare_correlation_image(struct_id, ndx_im, grad_thresh, grad_thresh2)
+
+%prepare image to be subtracted from subsequent correlation inputs
+%ie - edge detected image of difspot, placed at extspot location, in the
+%relevent ext image, but calculated with threshold values of the new difspot
+
+global parameters; 
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+%read relevent difspot image from full
+dif = gtGetDifImage(ndx_im, struct_id);
+
+%calc centre of mass, area of difspot
+%this needs to be the whole, summed difspot)
+difsummed=gtGetSummedDifSpot(struct_id);
+com_x = sum(difsummed) * ((1:length(sum(difsummed)))') / sum(sum(difsummed));
+com_y = (sum(difsummed')*(1:length(sum(difsummed')))')/sum(sum(difsummed'));
+
+%make dif spot gradient, threshold
+dif_med = medfilt2(dif, [5 5]);
+[dif_gradx,dif_grady]=gradient(dif_med);
+
+dif_gradx_sign = sign(dif_gradx);
+dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+dif_grady_sign = sign(dif_grady);
+dif_grady_t1=abs(dif_grady) > grad_thresh;
+dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+%search com of difspot in extinction image
+%[ext_com_x,ext_com_y] = mym(sprintf('select CentroidX,CentroidY from %sextspot where extspotID=%d',parameters.acq.name,struct_id));
+[ext_bb, ext_centroid] = gtGetBBProps(struct_id,'search')
+shift_x = ceil(ext_centroid(1) - com_x);
+shift_y = ceil(ext_centroid(2) - com_y);
+
+%make ext sized image, paste in dif spot...
+dif_maskx=gtPlaceSubImage(dif_gradx_t1,zeros(parameters.acq.bb(4), parameters.acq.bb(3)),1,1);
+dif_masky=gtPlaceSubImage(dif_grady_t1,zeros(parameters.acq.bb(4), parameters.acq.bb(3)),1,1);
+
+%roll mask to correct position
+dif_maskx=roll(dif_maskx,shift_y,shift_x);
+dif_masky=roll(dif_masky,shift_y,shift_x);
+
diff --git a/3_match_extspot/gtnew_run_auto_find.m b/3_match_extspot/gtnew_run_auto_find.m
new file mode 100755
index 0000000000000000000000000000000000000000..e01d06929529880712cd1d8d79a371dbfe96c47e
--- /dev/null
+++ b/3_match_extspot/gtnew_run_auto_find.m
@@ -0,0 +1,39 @@
+function gtnew_run_auto_find(first,last,wdir)
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end
+cd(wdir)
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   SIZE ORDERING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mym('open','mysql.esrf.fr','gtuser','gtuser');
+mym('use graintracking');
+[remaining]=mym(sprintf('select difspotID from %sdifspot where difspotID>=first and difspotID<=last order by Area desc',parameters.acq.name))
+
+
+
+savesuffix=[num2str(first) '_' num2str(last)];
+savesuffix='greg';
+
+
+for i=1:length(remaining)
+  try 
+    fprintf('~~~~~~DOING %d %d~~~~~~~~~', i,remaining(i))
+    auto_find_db_enabled(remaining(i)+first-1,savesuffix,parameters);
+    fprintf('~~~~~~~~DONE OK~~~~~~~~\n\n\n');
+  catch
+    fprintf('~~~~~~~~~SPOT UNFINISHED~~~~~~~~~~\n')
+    lasterr
+    fprintf('\n\n\n');
+  end
+end
+
+
+
+
diff --git a/3_match_extspot/html/gtBatchAutoFind_360.html b/3_match_extspot/html/gtBatchAutoFind_360.html
new file mode 100755
index 0000000000000000000000000000000000000000..410822c604ae23e964912c3ea8f4ca9e18bd043b
--- /dev/null
+++ b/3_match_extspot/html/gtBatchAutoFind_360.html
@@ -0,0 +1,159 @@
+
+<!DOCTYPE html
+  PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>gtBatchAutoFind_360</title>
+      <meta name="generator" content="MATLAB 7.4">
+      <meta name="date" content="2007-10-24">
+      <meta name="m-file" content="gtBatchAutoFind_360"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows. */ 
+p,h1,h2,div.content div {
+  max-width: 600px;
+  /* Hack for IE6 */
+  width: auto !important; width: 600px;
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">gttest</a></li>
+               <li><a href="#2">gtBatchAutoFind_360</a></li>
+               <li><a href="#3">Startup checks</a></li>
+            </ul>
+         </div>
+         <h2>gttest<a name="1"></a></h2>
+         <h2>gtBatchAutoFind_360<a name="2"></a></h2>
+         <p>This is the overall text driver</p>
+         <h2>Startup checks<a name="3"></a></h2>
+         <p>check to see if we are running a compiled version</p>
+         <p class="footer"><br>
+            Published with MATLAB&reg; 7.4<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% gttest
+function gtBatchAutoFind_360(first,last,wdir)
+
+%% gtBatchAutoFind_360
+% This is the overall text driver
+
+
+  %first=first IMAGE, last= last IMAGE
+
+  %mod from gt_batchAutoFind_pairs to use database tables extending over 360
+  %degrees, rather than a scan split into two 180 degree halves, A and B.
+
+  %try changing this to do all of the spots in an image, rather than a number
+  %of difspot ids, as it seems important to do the brightest spots in an
+  %image first
+%% Startup checks
+% check to see if we are running a compiled version
+  if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end
+
+  cd(wdir)
+
+
+  load parameters.mat
+
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %   SIZE ORDERING
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  gtDBConnect;
+
+  %[remaining]=mym(sprintf(...
+  %  'select difspotID from %sdifspot where difspotID>=%d and difspotID<=%d and BoundingBoxXsize>10 and BoundingBoxYsize>10 order by (integral/Area) desc',...
+  %  parameters.acq.name,first,last));
+
+  [remaining]=mym(sprintf(...
+    'select difspotID from %sdifspot where maximage>=%d and maximage<=%d and BoundingBoxXsize>%d and BoundingBoxYsize>%d order by (integral/Area) desc',...
+    parameters.acq.name,first,last, parameters.match.minsize, parameters.match.minsize));
+
+
+  fprintf('First %d Last %d Number %d\n',first,last,length(remaining))
+
+
+  for i=1:length(remaining)
+    try
+      struct_id=remaining(i);
+      fprintf('~~~~~~ Doing difspot %d of %d (struct_id = %d) ~~~~~~~~~\n', i,length(remaining),struct_id)
+      AutoFind_360(struct_id,parameters,1);
+      fprintf('~~~~~~~~ DONE OK ~~~~~~~~\n\n\n');
+    catch
+      fprintf('~~~~~~~~~ SPOT UNFINISHED ~~~~~~~~~~\n')
+      tmp=lasterror;
+      fprintf('Error: %s \n%s at line %d\n',tmp.message,tmp.stack(1).file,tmp.stack(1).line);
+      fprintf('\n\n\n');
+    end
+  end
+
+  mym('close')
+
+
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
\ No newline at end of file
diff --git a/3_match_extspot/mask_extinction_function.m b/3_match_extspot/mask_extinction_function.m
new file mode 100755
index 0000000000000000000000000000000000000000..b9e7560613c7bed267acd6315a9bad80874cbd37
--- /dev/null
+++ b/3_match_extspot/mask_extinction_function.m
@@ -0,0 +1,144 @@
+% MASK_EXTINCTION.M
+% Given a full Frelon image, with the user selection of a diffraction spot,
+% attempts to mask the possible area in the extinction image within which
+% the spot could have diffracted from.  See below for assumptions about
+% diffraction criteria.
+%
+% Based on plot_rings.m by Andy King
+%
+% Greg Johnson September 2006
+
+%modified to at as a function, returning mask based on input of difspot
+%struct_id
+%Andy, 11/9/2006
+
+
+function mask_ext = mask_extinction_function(struct_id);
+
+global app;
+
+disp('HARD CODED variables here')
+% produces oversize image
+% image size 2048*2048!');
+im=zeros(2048);
+
+bb=app.bb.directbeam;
+
+dif_bb(1,:) = app.extspot(struct_id).BoundingBox;
+dif_cent(1,:) = app.extspot(struct_id).Centroid;
+
+
+
+
+
+flag = 0; %180, one difspot, default case
+if isfield(app.extspot(struct_id),'pair_id')
+  if ~isempty(app.extspot(struct_id).pair_id) 
+    flag = 1;% 360, two difspots, special case
+    pair_id = app.extspot(struct_id).pair_id;
+    dif_bb(2,:) = app.extspot(pair_id).BoundingBox;%or however...
+    dif_cent(2,:) = app.extspot(pair_id).Centroid;
+%so dif_bb has two enteries if available
+  end
+end
+
+if flag == 1%360 degree, two difspots
+    
+
+%apply mirror transform to pair position
+%disp('HARD CODED center of rotation!');
+dif_cent(2,1) = 2048 - dif_cent(2,1);
+dif_bb(2,1) = 2048 - dif_bb(2,1) - dif_bb(2,3);
+
+grad = (dif_cent(2,2)-dif_cent(1,2))/(dif_cent(2,1)-dif_cent(1,1));
+
+%in line equation, find all possible c in y=mx+c
+%max and min c values gives edges of mask area
+
+c(1) = dif_bb(1,2) - grad*dif_bb(1,1);
+c(2) = dif_bb(1,2) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(3) = (dif_bb(1,2)+dif_bb(1,4)) - grad*dif_bb(1,1);
+c(4) = (dif_bb(1,2)+dif_bb(1,4)) - grad*(dif_bb(1,1)+dif_bb(1,3));
+c(5) = dif_bb(2,2) - grad*dif_bb(2,1);
+c(6) = dif_bb(2,2) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c(7) = (dif_bb(2,2)+dif_bb(2,4)) - grad*dif_bb(2,1);
+c(8) = (dif_bb(2,2)+dif_bb(2,4)) - grad*(dif_bb(2,1)+dif_bb(2,3));
+c_min = min(c);
+c_max = max(c);
+
+mask_line=zeros(size(im));
+y(1) = (grad*1)+c_min;
+y(2) = (grad*size(im,1))+c_min;
+y(3) = (grad*size(im,1))+c_max;
+y(4) = (grad*1)+c_max;
+
+y(find(y<1))=1;
+y(find(y>size(im,2)))=size(im,2);
+x(1:2) = (y(1:2) - c_min)./grad;
+x(3:4) = (y(3:4) - c_max)./grad;
+
+mask(3,:,:) = poly2mask(x,y,size(im,2),size(im,1));
+
+end %line mask for two difspots
+
+
+for i=1:size(dif_bb,1);%for - to run this for both spots if available%180 degree, single difspot case
+  
+%centre of difspot - use centre of bb
+%dif_bb = app.extspot(struct_id).BoundingBox;
+point.x = ceil(dif_bb(i,1)+dif_bb(i,3)/2);
+point.y = ceil(dif_bb(i,2)+dif_bb(i,4)/2);
+
+
+%note - sample width overestimates
+%disp('HARD CODED sample width 830-1200 not app.bb!');
+xc=app.dist;  
+%sample_width=app.bb.directbeam(3);
+sample_width=1200-830;
+
+%disp('HARD CODED Al data - a=4.05, FCC!');
+tmp=calculate_twotheta(4.05,'FCC',app.energy);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+
+dist_rear=xc+(sample_width*app.pixelsize/2); % assume sample is cuboid
+dist_front=xc-(sample_width*app.pixelsize/2);
+
+rad_front=dist_front*tan(deg2rad(twotheta))/app.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(twotheta))/app.pixelsize;
+
+%add a constant to radii based on the size of the difspot
+dif_rad = (sqrt(dif_bb(i,3:4)*dif_bb(i,3:4)'))/2;
+rad_front = rad_front-dif_rad;
+rad_rear = rad_rear+dif_rad;
+
+
+tmask=zeros(size(im));
+for n=1:length(rad_front)
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+mask(i,:,:)=zeros(size(im));
+mask(i,tmask)=1;
+  
+end%180 case for one or two difspots
+
+
+%crop mask(s) to size of extinction image
+mask_ext=mask(:,bb(2):bb(2)+bb(4),bb(1):bb(1)+bb(3));
+
+if flag == 1
+%final mask is the AND of all three masks
+mask_ext(1,:,:) = (mask_ext(1,:,:) & mask_ext(2,:,:) & mask_ext(3,:,:));
+end
+
+%flatten mask to 2d
+mask_ext = reshape(mask_ext(1,:,:), size(mask_ext,2), size(mask_ext,3)); 
+
+
diff --git a/3_match_extspot/old_gtGetSummedDifSpot_360.m b/3_match_extspot/old_gtGetSummedDifSpot_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..765d7a17fe4d87c9870e8f7426a1f2c9c77c064c
--- /dev/null
+++ b/3_match_extspot/old_gtGetSummedDifSpot_360.m
@@ -0,0 +1,36 @@
+function spot=gtGetSummedDifSpot_360(pair_id)
+%returns the summed difspot image (saved as difspot%05d.edf)
+%for 360 datasets, given a pair ID it returns the A difspot, if one exists,
+%else the B difspot
+
+global parameters
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+acq=parameters.acq;
+
+%get the root of the pair name
+pair_name=parameters.acq.pair_tablename;
+pair_name(end-8:end)=[];
+
+%is there an A difspot in the pair table?
+  mysqlcmd = sprintf(['select !isnull(difAID), ifnull(difAID,difBID) from %s where pairID=%d'],...
+    acq.pair_tablename,pair_id);
+[A,difID]=mym(mysqlcmd);
+
+if A %if the first half of the scan
+  name=parameters.acq.difA_name;
+  disp('reading difspot from A')
+else
+  name=parameters.acq.difB_name;
+  disp('reading difspot from B')
+end
+path=sprintf('../%s/',name);
+
+
+spot=edf_read(sprintf('%s2_difspot/difspot/difspot%05d.edf',path,difID));
+
+
+
+end
diff --git a/3_match_extspot/prepare_correlation_image.m b/3_match_extspot/prepare_correlation_image.m
new file mode 100755
index 0000000000000000000000000000000000000000..9c983f252dadb20a61d5362f336c8a0c2410d3e5
--- /dev/null
+++ b/3_match_extspot/prepare_correlation_image.m
@@ -0,0 +1,46 @@
+function [dif_maskx, dif_masky] = prepare_correlation_image(struct_id, grad_thresh, grad_thresh2,fname)
+
+%prepare image to be subtracted from subsequent correlation inputs
+%ie - edge detected image of difspot, placed at extspot location,
+%calculated with threshold values of the new difspot
+
+
+global app;
+
+trial = load(fname);
+
+
+%read max intensity difspot from full
+dif = edf_read(sprintf('full/full%04d.edf',app.extspot(struct_id).MaxImage),app.extspot(struct_id).BoundingBox);
+
+%calc centre of mass, area of difspot
+com_x = sum(dif) * ([1:length(sum(dif))]') / sum(sum(dif));
+com_y = (sum(dif')*[1:length(sum(dif'))]')/sum(sum(dif'));
+
+%make dif spot gradient, threshold
+dif_med = medfilt2(dif, [5 5]);
+[dif_gradx,dif_grady]=gradient(dif_med);
+
+dif_gradx_sign = sign(dif_gradx);
+dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+dif_grady_sign = sign(dif_grady);
+dif_grady_t1=abs(dif_grady) > grad_thresh;
+dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+%com in extinction image can be read from anotherovernight structure
+
+ext_com_x = trial.point(struct_id).x;
+ext_com_y = trial.point(struct_id).y;
+shift_x = ceil(ext_com_x - com_x);
+shift_y = ceil(ext_com_y - com_y);
+
+%make ext sized image, paste in dif spot...
+dif_maskx=gtPlaceSubImage(dif_gradx_t1,zeros(app.data.ext.ysize,app.data.ext.xsize),1,1);
+dif_masky=gtPlaceSubImage(dif_grady_t1,zeros(app.data.ext.ysize,app.data.ext.xsize),1,1);
+
+%roll mask to correct position
+dif_maskx=roll(dif_maskx,shift_y,shift_x);
+dif_masky=roll(dif_masky,shift_y,shift_x);
+
diff --git a/3_match_extspot/prepare_correlation_image_andytest.m b/3_match_extspot/prepare_correlation_image_andytest.m
new file mode 100755
index 0000000000000000000000000000000000000000..9eebadbfdf2cc6a95ef0be87d32fb019128e2875
--- /dev/null
+++ b/3_match_extspot/prepare_correlation_image_andytest.m
@@ -0,0 +1,49 @@
+function [dif_maskx, dif_masky] = prepare_correlation_image_andytest(struct_id, grad_thresh, grad_thresh2)
+
+%prepare image to be subtracted from subsequent correlation inputs
+%ie - edge detected image of difspot, placed at extspot location,
+%calculated with threshold values of the new difspot
+
+
+global app;
+
+trial = load('../../tmp/correlate150906.mat');
+disp('HARD CODED ../../tmp/autofind_extspot')
+
+%read max intensity difspot from full
+dif = edf_read(sprintf('full/full%04d.edf',app.extspot(struct_id).MaxImage),app.extspot(struct_id).BoundingBox);
+
+%calc centre of mass, area of difspot
+com_x = sum(dif) * ([1:length(sum(dif))]') / sum(sum(dif));
+com_y = (sum(dif')*[1:length(sum(dif'))]')/sum(sum(dif'));
+
+%make dif spot gradient, threshold
+dif_med = medfilt2(dif, [5 5]);
+[dif_gradx,dif_grady]=gradient(dif_med);
+
+dif_gradx_sign = sign(dif_gradx);
+dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+dif_grady_sign = sign(dif_grady);
+dif_grady_t1=abs(dif_grady) > grad_thresh;
+dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+%com in extinction image can be read from anotherovernight structure
+
+ext_com_x = trial.point(struct_id).x;
+ext_com_y = trial.point(struct_id).y;
+shift_x = ceil(ext_com_x - com_x);
+shift_y = ceil(ext_com_y - com_y);
+
+%make ext sized image, paste in dif spot...
+dif_maskx = zeros(app.bb.directbeam(4), app.bb.directbeam(3));
+dif_maskx(1:size(dif_gradx_t1,1),1:size(dif_gradx_t1,2))=dif_gradx_t1;
+
+dif_masky = zeros(app.bb.directbeam(4), app.bb.directbeam(3));
+dif_masky(1:size(dif_grady_t1,1),1:size(dif_grady_t1,2))=dif_grady_t1;
+
+%roll mask to correct position
+dif_maskx=roll(dif_maskx,shift_y,shift_x);
+dif_masky=roll(dif_masky,shift_y,shift_x);
+
diff --git a/4_spot_sorting/.gtGetCubicSymOp.m.swp b/4_spot_sorting/.gtGetCubicSymOp.m.swp
new file mode 100755
index 0000000000000000000000000000000000000000..000631f13f77273c700c101104d95fa822b10dff
Binary files /dev/null and b/4_spot_sorting/.gtGetCubicSymOp.m.swp differ
diff --git a/4_spot_sorting/.gtShearDifspots.m.swp b/4_spot_sorting/.gtShearDifspots.m.swp
new file mode 100755
index 0000000000000000000000000000000000000000..fa9fa531ec78c1173ffbf507ea89a47e52f118af
Binary files /dev/null and b/4_spot_sorting/.gtShearDifspots.m.swp differ
diff --git a/4_spot_sorting/AutoFind.m b/4_spot_sorting/AutoFind.m
new file mode 100755
index 0000000000000000000000000000000000000000..6bfd98d5306fcb6924be36f822c60d88831e7824
--- /dev/null
+++ b/4_spot_sorting/AutoFind.m
@@ -0,0 +1,537 @@
+function [output_point]=AutoFind(struct_id,parameters,varargin)
+
+warning on backtrace
+
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+
+% setup mysql access
+if ~connected %if already connected, don't check
+if (mym('status'))
+  disp('Opening database again')
+  mym('open','mysql.esrf.fr','gtuser','gtuser')
+  mym('use graintracking')
+end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SETUP VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% DB table names
+table_difspot=sprintf('%sdifspot',parameters.acq.name);
+table_extspot=sprintf('%sextspot',parameters.acq.name);
+table_snakes=sprintf('%ssnakes',parameters.acq.name);
+table_bboxes=sprintf('%sbboxes',parameters.acq.name);% we put this setup here, that was not...., Marcelo 08/12/06
+close all
+% options for graphical display
+graphics.show_dif=false;
+graphics.show_initialmatch=1;
+graphics.show_gvf=false;
+graphics.show_snakeprogress=false;
+graphics.show_snakefinal=1;
+graphics.show_convergence=false;
+
+% first check what parameters exist
+if ~exist('struct_id','var')
+  error('Please supply a structure ID')
+end
+
+fprintf('AUTO_FIND\n');
+fprintf('Name: %s\n',parameters.acq.name);
+fprintf('Parameters: \n');
+fprintf('\tStructID: %d\n',struct_id);
+
+cd(parameters.acq.dir)
+disp('OVERWRITING EXTSPOT!')
+if 0
+if ~isempty(mym(sprintf('select extspotID from %s where extspotID=%d',table_extspot,struct_id)))
+  error('extspotID already exists - aborting')
+end
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOAD DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%
+%subtract prior extspots
+im_x=zeros(gtBboxSizeMat(parameters.acq.bb));
+im_y=zeros(gtBboxSizeMat(parameters.acq.bb));
+
+mysqlcmd=sprintf('select difspotID from %s where difspotID=%d',table_difspot,struct_id);
+if isempty(mym(mysqlcmd))
+  error('That structure does not exist!');
+end
+
+%max_im = difspot(struct_id).MaxImage
+max_im=mym(sprintf('select MaxImage from %s where difspotID=%d',table_difspot,struct_id));
+
+%reload updated extspot.mat
+if (mym(sprintf('select count(*) from %s',table_extspot)))
+  disp('DB has extspot data already')
+else
+  disp('DB has no extspot data yet')
+end
+
+
+%get 3 images (around the max image) to be correlated
+[ndx_im1,ndx_im2]=sfWhichExtImages_new_format(struct_id);
+
+cc_sum=zeros(parameters.acq.bb(4), parameters.acq.bb(3)); %new format, will have to make all consistant
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Read images
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% read the summed images
+extmean=gtGetMeanFullImage(struct_id,1); % 1 - already mysql connected
+summeddif=gtGetSummedDifSpot(struct_id); % 1 - already mysql connected
+
+%ext=gtGetMaxExtImage(struct_id);
+%dif=gtGetMaxDifSpot(struct_id);
+
+
+%calc centre of mass, area of difspot
+com_x = sum(summeddif) * ((1:length(sum(summeddif)))') / sum(sum(summeddif));
+com_y = (sum(summeddif')*(1:length(sum(summeddif')))')/sum(sum(summeddif'));
+area = length(find(summeddif~=0));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate search area mask
+% use mask_extinction_function, which determines 180 degree (single difspot)
+% or 360 degree (pair of difspots) treatment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+extmask=gtnew_mask_extinction_function(struct_id,1); % 1 - already mysql connected 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% MAIN LOOP OF THREE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for ndx_im=ndx_im1:ndx_im2
+  fprintf('Examining image: %d\n',ndx_im);
+  %note - GetExtImage actually returns the middle part of the Full image -
+  %better for the correlation
+  ext=gtGetExtImage(ndx_im); % I changed gtnewGetExtImage by gtGetExtImage - Marcelo 08/12/06
+  dif=gtGetDifImage(ndx_im,struct_id,1); % 1 - already mysql connected
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% Gradient calculations
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  %make dif spot gradient, threshold
+  dif_med = medfilt2(dif, [5 5]);
+  [dif_gradx,dif_grady]=gradient(dif_med);
+
+  dif_grad = sqrt((dif_gradx).^2+(dif_grady).^2);
+  grad_thresh = (mean(dif_grad(:))+0.75*std(dif_grad(:)));
+  grad_thresh2 = max(dif_grad(:));
+
+  dif_gradx_sign = sign(dif_gradx);
+  dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+  dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+  dif_grady_sign = sign(dif_grady);
+  dif_grady_t1=abs(dif_grady) > grad_thresh;
+  dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+  %make dif spot perimeter for display - snake input?
+  dif_spot = dif_med > 0.1*max(dif_med(:));
+  dif_spot_perimeter=double(bwperim(dif_spot));
+
+  %median filter, find edges
+  ext_med = medfilt2(ext, [10 10]);
+  ext_edges=edge(ext_med,0.001);
+
+  [ext_gradx,ext_grady]=gradient(ext_med);
+
+  ext_gradx_sign = -sign(ext_gradx);
+  ext_gradx = abs(ext_gradx);
+  ext_gradx_t1=and(ext_gradx>grad_thresh, ext_gradx<grad_thresh2);
+  ext_gradx_t1 = ext_gradx_sign.*ext_gradx_t1;
+
+  ext_grady_sign = -sign(ext_grady);
+  ext_grady = abs(ext_grady);
+  ext_grady_t1=and(ext_grady>grad_thresh, ext_grady<grad_thresh2);
+  ext_grady_t1 = ext_grady_sign.*ext_grady_t1;
+
+  ext_gradx_t1(logical(im_x)) = 0;
+  ext_grady_t1(logical(im_y)) = 0;
+  %%%%%%%%%%%%%%%%%%%%%%%%
+  %pad dif_grad to size of ext to use correlate
+  dif_maskx = gtPlaceSubImage(dif_gradx_t1, zeros(size(ext)), 1, 1);
+  dif_masky = gtPlaceSubImage(dif_grady_t1, zeros(size(ext)), 1, 1);
+  %  dif_perim_mask = gtPlaceSubImage(dif_spot_perimeter, zeros(size(ext)), 1, 1);
+
+  summeddif_bw=summeddif>0.25*max(summeddif(:));
+  summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+  summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+  summeddif_bw=bwmorph(summeddif_bw,'dilate',1);
+
+  summeddif_mask=gtPlaceSubImage(summeddif_bw,zeros(size(ext)),1,1);
+  dif_spot_mask=gtPlaceSubImage(dif_spot,zeros(size(ext)),1,1);
+
+  %%%%%%%%%%%%%%%%%%%%%%%%
+  % Look at previous diffraction spots
+  %%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  % check all diffraction spots
+  %    disp('NOT CHECKING OTHER DIFSPOTS')
+  mysqlcmd=sprintf('select extspotID from %s where (extspotID!=%d) and (extspotID=any(select difspotID from %s where %d between StartImage and EndImage))',table_extspot,struct_id,table_difspot,ndx_im);
+  extspotIDs=mym(mysqlcmd)
+  
+  fprintf('Removing %d spots from correlation image\n',length(extspotIDs))
+  for i=1:length(extspotIDs)
+    [tmpx,tmpy]=gtMaskPriorExtspot(extspotIDs(i), ndx_im, grad_thresh);
+		%note - only uses a single threshold when preparing gradient image
+    im_x(logical(tmpx))=0;
+    im_y(logical(tmpy))=0;
+	end
+
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Apply search area mask
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  ext_gradx_t1(~extmask)=0;
+  ext_grady_t1(~extmask)=0;
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% do correlation
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  cc_x=real(ifft2(fft2(ext_gradx_t1).*conj(fft2(dif_maskx))));% from correlate.m
+  cc_y=real(ifft2(fft2(ext_grady_t1).*conj(fft2(dif_masky))));% from correlate.m
+  cc_sum=cc_sum+ (cc_x+cc_y);
+
+end
+
+shift=gtFindMaxSubscripts(cc_sum);
+
+%apply shifts
+
+%dif_perim_mask=roll(dif_perim_mask,shift(1),shift(2));
+dif_spot_mask=roll(dif_spot_mask,shift(1),shift(2));
+[com_x,com_y]=gtShiftContour(...
+  com_x,com_y,...
+  shift(2),shift(1),...
+  size(dif_spot_mask,2),size(dif_spot_mask,1));
+
+output_point = round([com_x com_y]); %where user would click in find_spots...
+summeddif_mask=roll(summeddif_mask,shift(1),shift(2));
+
+% try to remove bad portion of wrapped mask
+marker=zeros(size(summeddif_mask));
+marker(round(com_y),round(com_x))=1;
+summeddif_mask=imreconstruct(marker,summeddif_mask);
+summeddif_perim_mask=bwperim(summeddif_mask);
+
+% show some results
+if graphics.show_dif
+  h_dif=figure;
+  imshow(dif,[])
+end
+if graphics.show_initialmatch
+  h_initialmatch=figure;
+  h1=imshow(extmean,[]);
+  hold on
+  h3=imagesc(cat(3,summeddif_perim_mask, zeros(size(summeddif_perim_mask)), zeros(size(summeddif_perim_mask))));
+  set(h3,'alphadata',summeddif_perim_mask);
+  plot(com_x, com_y, 'xr', 'markersize', 10)
+  h4=imagesc(cat(3,zeros(size(extmask)),~extmask,zeros(size(extmask))));
+  set(h4,'alphadata',0.2)
+  hold off
+  drawnow
+  title(num2str(struct_id))
+end
+
+
+if 1 
+  tmp = imfill(summeddif_perim_mask,'holes');
+  tmp2=regionprops(double(tmp),'BoundingBox');
+  tmp2=tmp2.BoundingBox;
+
+% add SearchBoundingBox to bboxes table
+mysqlcmd=dbInsert(table_bboxes,...
+  'extspotID',struct_id,... % I changed here to the new names 
+	'Xorigin',tmp2(1),...     % I changed here to the new names
+  'Yorigin',tmp2(2),...     % I changed here to the new names
+  'Xsize',tmp2(3),...       % I changed here to the new names
+  'Ysize',tmp2(4),...       % I changed here to the new names ------Marcelo 08/12/06 - I stoped here...
+	'Xcentroid',com_x,...     % use new format of putting centroid and bb into a single table
+	'Ycentroid',com_y);        % use new format of putting centroid and bb into a single table
+mym(mysqlcmd);
+% get bboxID
+bboxID=mym('select last_insert_id()');
+
+% insert bboxID into extspot table
+mysqlcmd=dbInsert(table_extspot,...
+  'extspotID',struct_id,...
+  'searchbbID',bboxID);
+mym(mysqlcmd);
+end
+
+im=gaussianBlur(extmean,1);
+
+% polarity of image not important because only magnitude of gradient is used
+[fx,fy]=gradient(im);
+fmag=sqrt(fx.^2+fy.^2);
+
+% use a small part of the image to find the starting snake
+[roffset,coffset]=find(summeddif_perim_mask);
+
+[x_orig,y_orig]=gtMask2Poly(...
+  summeddif_perim_mask(...
+  min(roffset):max(roffset),...
+  min(coffset):max(coffset)));
+
+% adjust back to original coordinates
+x_orig=x_orig+min(coffset)-1;
+y_orig=y_orig+min(roffset)-1;
+
+x=x_orig;y=y_orig;
+
+
+%%%%%%%%%%%%%%
+% make some measures of the spot we are considering:
+defaultmaskarea=29000;
+maskarea=numel(summeddif_bw);
+arearatio=maskarea/defaultmaskarea;
+fprintf('Area ratio: %3.2f\n',arearatio);
+
+defaultmaskperim=575;
+tmp=regionprops(double(summeddif_bw),'perimeter');
+maskperim=round(tmp.Perimeter);
+perimratio=maskperim/defaultmaskperim;
+fprintf('Perimeter ratio: %3.2f\n',perimratio);
+
+% intensity variation
+% need bw mask of spot:
+if 1
+  bwtmp=poly2mask(x_orig,y_orig,size(extmean,2),size(extmean,1));
+  tmp_inside=extmean(bwtmp);
+  tmp_outside=extmean(~bwtmp);
+  mean_inside=mean(tmp_inside(:))*1e3;
+  mean_outside=mean(tmp_outside(:))*1e3;
+  defaultmeanratio=2.88/0.6; % stndxruct_id 700
+  meanratio=mean_inside/mean_outside;
+  % when intensity ratio is lower, snake is harder to bind to perimeter
+  intensityratio=meanratio/defaultmeanratio;
+  fprintf('Intensity ratio: %3.2f\n',intensityratio);
+end
+
+snakeoptions.elasticity=3;
+snakeoptions.rigidity=15;  % keep this high to prevent spurs from local features
+snakeoptions.viscosity=3;
+snakeoptions.forcefactor=5;
+snakeoptions.iterations=10; 
+
+snakeoptions.elasticity=snakeoptions.elasticity*arearatio.^2;
+%  snakeoptions.rigidity=10;  % keep this high to prevent spurs from local features
+%  snakeoptions.viscosity=5;
+%    snakeoptions.forcefactor=snakeoptions.forcefactor*perimratio;
+%  snakeoptions.iterations=5;
+snakeoptions;
+
+%%%%%%%%%%%%%%%
+
+pad=25;
+tmp_bbox=round([min(x(:))-pad min(y(:))-pad gtRange(x)+(2*pad) gtRange(y)+(2*pad)]);
+
+[u,v] = GVF(gtExtract(fmag,tmp_bbox), 0.05, 15);  % 0.2,80 % 0.3 15
+% Normalizing the GVF external force
+mag = sqrt(u.^2+v.^2);
+pxnorm = u./(mag+1e-10);pynorm = v./(mag+1e-10);
+
+forcefield.x=pxnorm;
+forcefield.y=pynorm;
+
+x=x-(tmp_bbox(1)+1);
+y=y-(tmp_bbox(2)+1);
+% should now remove points that are outside bbox
+if 0
+  x(y>size(mag,1))=[];
+  y(y>size(mag,1))=[];
+
+  y(x>size(mag,2))=[];
+  x(x>size(mag,2))=[];
+end
+if graphics.show_gvf
+  h_gvf=figure;
+  imagesc(mag,autolim(mag))
+  colorbar
+  hold on
+  quiver(pxnorm,pynorm,'r');
+  axis ij
+  axis equal
+  h_ax(1)=gca;
+end
+
+if graphics.show_snakeprogress && graphics.show_initialmatch
+  figure(h_initialmatch)
+  imagesc(gtExtract(extmean,tmp_bbox)),axis image,colormap(gray)
+  hold on
+  snakedisp(x,y,'r-')
+  h_ax(2)=gca;
+  if h_ax(1)~=0
+    linkaxes(h_ax,'xy')
+  end
+  axis image
+  drawnow
+end
+
+[x,y]=snakeinterp(x,y,20,1);
+origlength=length(x);
+clear hp
+converged=false;
+sfConverged([]); % reset sfConverged
+i=0;
+while not(converged)
+  i=i+1;
+  if i>100
+    break % get out of loop - we've taken too long
+  end
+  if length(x)<origlength/2
+    %      disp('Snake is too short!')
+    % break
+  end
+  [x2,y2]=snakedeform(x,y,forcefield,snakeoptions);
+  tmp=poly2mask(x,y,round(max(x)+5),round(max(y)+5));
+  area=sum(tmp(:));
+  converged=sfConverged(area);
+
+  [x,y]=snakeinterp(x2,y2,20,1);
+  if graphics.show_snakeprogress && graphics.show_initialmatch
+    figure(h_initialmatch)
+    if exist('hp','var')
+      delete(hp)
+    end
+    hp=snakedisp(x,y,'g.-');
+    axis image
+    title(['Deformation in progress,  iter = ' num2str(i*snakeoptions.iterations)])
+    drawnow
+    print('-dtiff',sprintf('perrin_%03d.tif',i));
+  end
+end
+if converged
+  disp('Converged')
+else
+  disp('Did NOT converge')
+end
+
+if graphics.show_snakefinal && graphics.show_initialmatch
+  if graphics.show_gvf
+    figure(h_gvf);
+    snakedisp(x,y,'g-')
+    title(['Structure ' num2str(struct_id)])
+  end
+  figure(h_initialmatch)
+  if graphics.show_snakeprogress
+    snakedisp(x,y,'g-');
+  else
+    snakedisp(x+(tmp_bbox(1)+1),y+(tmp_bbox(2)+1),'g-')
+  end
+  title(['Structure ' num2str(struct_id)])
+end
+% restore snake coordinates to that of extinction image
+x=x+tmp_bbox(1);  % mussing +??
+y=y+tmp_bbox(2);
+
+% write snake to sql table
+tmp=repmat(struct_id,1,length(x));  % produce vector of repeated struct_id
+values=sprintf('("%f","%f","%f"),',[tmp; x(:)'; y(:)']);
+values(end)=[];  % remove final comma
+mysqlcmd=sprintf('insert into %s (snakeID,x,y) values %s',table_snakes,values);
+mym(mysqlcmd)
+
+tmp = poly2mask(x,y, parameters.acq.bb(4), parameters.acq.bb(3));
+props=regionprops(double(tmp),'Area','BoundingBox','Centroid');
+
+if 1 
+	% add (snake) BoundingBox to bboxes table
+mysqlcmd=dbInsert(table_bboxes,...
+  'extspotID',struct_id,... % I changed here to the new names 
+	'Xorigin',props.BoundingBox(1),...     % I changed here to the new names
+  'Yorigin',props.BoundingBox(2),...     % I changed here to the new names
+  'Xsize',props.BoundingBox(3),...       % I changed here to the new names
+  'Ysize',props.BoundingBox(4),...       % I changed here to the new names ------Marcelo 08/12/06 - I stoped here...
+	'Xcentroid',props.Centroid(1),...     % use new format of putting centroid and bb into a single table
+	'Ycentroid',props.Centroid(2));        % use new format of putting centroid and bb into a single table
+mym(mysqlcmd);
+% get bboxID
+bboxID=mym('select last_insert_id()');
+
+% update (snake) bboxID into extspot table
+mysqlcmd=dbUpdate(table_extspot,'extspotID',struct_id,...
+  'Area',props.Area,...
+	'snakeID',struct_id,...
+	'bbID',bboxID);
+mym(mysqlcmd);
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function flag=sfConverged(data1)
+    persistent diffdata data h_history
+    if isempty(data1)
+      clear data diffdata h_history
+      return
+    end
+    if numel(data)==0
+      data=[data1];
+      flag=false;
+      disp('*******************************************STARTING')
+      if graphics.show_convergence
+        h_history=figure;
+      end
+
+    else
+      data=[data;data1];
+      diffdata=diff(data);
+      if graphics.show_convergence
+        h_convergence=figure(h_history);
+        plot(abs(diffdata),'.-');
+      end
+      if abs(diffdata(end))<1
+        flag=true;
+      else
+        flag=false;
+      end
+
+    end
+  end
+
+  function [ndx1,ndx2]=sfWhichExtImages_new_format(struct_id)
+
+    %    maxim = difspot(struct_id).MaxImage;
+    %    startim = difspot(struct_id).ExtStartImage;
+    %    endim = difspot(struct_id).ExtEndImage;
+    [maxim,startim,endim]=mym(sprintf(...
+      'select MaxImage,ExtStartImage,ExtEndImage from %s where difspotID=%d',...
+      table_difspot,struct_id));
+
+
+    if (endim - startim + 1) <= 3
+      %if less than or equal to 3 images, do all of them
+      ndx1=startim;
+      ndx2=endim;
+      %      disp('one')
+      %else do three, centred around maxim
+    elseif maxim == endim;
+      %      disp('two')
+      ndx1 = maxim-2;
+      ndx2 = maxim;
+    elseif maxim == startim;
+      %      disp('three')
+      ndx1 = maxim;
+      ndx2 = maxim+2;
+    else
+      %      disp('four')
+      ndx1 = maxim-1;
+      ndx2 = maxim+1;
+    end
+
+  end
+
+end
+
diff --git a/4_spot_sorting/AutoFind_test.m b/4_spot_sorting/AutoFind_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..3fe35f9ea211eae8146a6ffb8771295b88b4f54b
--- /dev/null
+++ b/4_spot_sorting/AutoFind_test.m
@@ -0,0 +1,552 @@
+function [output_point]=AutoFind_test(inputID,parameters,varargin)
+
+%test version - sorry! - to try adapting to use the pair table concept
+%AK 18/12/2006
+
+%use a pair table which contains all difspots:
+%  | pairID | difAID | difBID |
+%where either of the difIDs can be null - unpaired spots
+
+%AutoFind runs on *only* the difspots belonging to the directory in which
+%it is launched (A *or* B), and refers to the pair table to retrive apot
+%pair info from the other half of the scan.
+
+
+warning on backtrace
+close all
+
+% data base connect
+%varargin of 1 means already connected
+connected=0;
+if ~isempty(varargin) 
+  connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SETUP VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+struct_id = inputID;
+name=parameters.acq.name;
+  
+% DB table names
+table_difspot=sprintf('%sdifspot',parameters.acq.name);
+table_extspot=sprintf('%sextspot',parameters.acq.name);
+table_snakes=sprintf('%ssnakes',parameters.acq.name);
+table_bboxes=sprintf('%sbboxes',parameters.acq.name);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%  AUTOFIND 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% options for graphical display
+graphics.show_dif=0;
+graphics.show_initialmatch=0;
+graphics.show_gvf=false;
+graphics.show_snakeprogress=false;
+graphics.show_snakefinal=0;
+graphics.show_convergence=false;
+
+% first check what parameters exist
+if ~exist('struct_id','var')
+  error('Please supply a structure ID')
+end
+
+fprintf('AUTO_FIND\n');
+fprintf('Name: %s\n',name);
+fprintf('Parameters: \n');
+fprintf('\tStructID: %d\n',struct_id);
+
+%is database empty?
+if ~isdeployed % only check if running interactively. If not, save one query...
+if (mym(sprintf('select count(*) from %s',table_extspot)))
+  disp('DB has extspot data already')
+else
+  disp('DB has no extspot data yet')
+end
+end
+
+if 1%check for overwriting extspot
+if ~isempty(mym(sprintf('select extspotID from %s where extspotID=%d',table_extspot,struct_id)))
+  error('extspotID already exists - aborting')
+end
+else
+disp('OVERWRITING EXTSPOT!')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOAD DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+mysqlcmd=sprintf('select difspotID from %s where difspotID=%d',table_difspot,struct_id);
+if isempty(mym(mysqlcmd))
+  error('That difspot structure does not exist!');
+end
+
+%get 3 images (around the max image) to be correlated
+[ndx_im1,ndx_im2]=sfWhichExtImages_new_format(struct_id);
+%prepare variable for correlation map
+cc_sum=zeros(parameters.acq.bb(4), parameters.acq.bb(3)); 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Read images
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% read the summed images
+extmean=gtGetMeanFullImage(struct_id); 
+summeddif=gtGetSummedDifSpot(struct_id, parameters, 1);
+
+%calc centre of mass, area of difspot
+com_x = sum(summeddif) * ((1:length(sum(summeddif)))') / sum(sum(summeddif));
+com_y = (sum(summeddif')*(1:length(sum(summeddif')))')/sum(sum(summeddif'));
+area = length(find(summeddif~=0));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate search area mask
+% use mask_extinction_function_pair
+%uses pair info if available
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+extmask=gtnew_mask_extinction_function_pair(struct_id,1);%already DB connected
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% MAIN LOOP OF THREE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for ndx_im=ndx_im1:ndx_im2
+  fprintf('Examining image: %d\n',ndx_im);
+
+  ext=gtGetExtImage(ndx_im); 
+  dif=gtGetDifImage(ndx_im,struct_id,parameters, 1); % 1 - already DB connected
+
+%variables for the gradient images
+  im_x=zeros(gtBboxSizeMat(parameters.acq.bb));
+  im_y=zeros(gtBboxSizeMat(parameters.acq.bb));
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% Gradient calculations
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  %make dif spot gradient, threshold
+  dif_med = medfilt2(dif, [5 5]);
+  [dif_gradx,dif_grady]=gradient(dif_med);
+
+  dif_grad = sqrt((dif_gradx).^2+(dif_grady).^2);
+  grad_thresh = (mean(dif_grad(:))+0.75*std(dif_grad(:)));
+  grad_thresh2 = max(dif_grad(:));
+
+  dif_gradx_sign = sign(dif_gradx);
+  dif_gradx_t1=abs(dif_gradx) > grad_thresh;
+  dif_gradx_t1 = dif_gradx_sign.*dif_gradx_t1;
+
+  dif_grady_sign = sign(dif_grady);
+  dif_grady_t1=abs(dif_grady) > grad_thresh;
+  dif_grady_t1 = dif_grady_sign.*dif_grady_t1;
+
+  %make dif spot perimeter for display - snake input?
+  dif_spot = dif_med > 0.1*max(dif_med(:));
+  dif_spot_perimeter=double(bwperim(dif_spot));
+
+  %median filter, find edges
+  ext_med = medfilt2(ext, [10 10]);
+  ext_edges=edge(ext_med,0.001);
+
+  [ext_gradx,ext_grady]=gradient(ext_med);
+
+  ext_gradx_sign = -sign(ext_gradx);
+  ext_gradx = abs(ext_gradx);
+  ext_gradx_t1=and(ext_gradx>grad_thresh, ext_gradx<grad_thresh2);
+  ext_gradx_t1 = ext_gradx_sign.*ext_gradx_t1;
+
+  ext_grady_sign = -sign(ext_grady);
+  ext_grady = abs(ext_grady);
+  ext_grady_t1=and(ext_grady>grad_thresh, ext_grady<grad_thresh2);
+  ext_grady_t1 = ext_grady_sign.*ext_grady_t1;
+
+  ext_gradx_t1(logical(im_x)) = 0;
+  ext_grady_t1(logical(im_y)) = 0;
+  %%%%%%%%%%%%%%%%%%%%%%%%
+  %pad dif_grad to size of ext to use correlate
+  dif_maskx = gtPlaceSubImage(dif_gradx_t1, zeros(size(ext)), 1, 1);
+  dif_masky = gtPlaceSubImage(dif_grady_t1, zeros(size(ext)), 1, 1);
+  %  dif_perim_mask = gtPlaceSubImage(dif_spot_perimeter, zeros(size(ext)), 1, 1);
+
+  summeddif_bw=summeddif>0.25*max(summeddif(:));
+  summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+  summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+  summeddif_bw=bwmorph(summeddif_bw,'dilate',1);
+
+  summeddif_mask=gtPlaceSubImage(summeddif_bw,zeros(size(ext)),1,1);
+  dif_spot_mask=gtPlaceSubImage(dif_spot,zeros(size(ext)),1,1);
+
+  %%%%%%%%%%%%%%%%%%%%%%%%
+  % Look at previous diffraction spots
+  %%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  mysqlcmd=sprintf(['select extspotID from %s where (extspotID!=%d) and '...
+    '(extspotID=any(select difspotID from %s where %d between StartImage and EndImage))'],...
+    table_extspot,struct_id,table_difspot,ndx_im);
+
+  extspotIDs=mym(mysqlcmd)
+
+  %subtract prior extspots
+  fprintf('Removing %d spots from correlation image\n',length(extspotIDs));
+
+  for i=1:length(extspotIDs)
+    [tmpx,tmpy]=gtMaskPriorExtspot(extspotIDs(i), ndx_im, grad_thresh);
+		%note - only uses a single threshold when preparing gradient image
+    im_x(logical(tmpx))=0;
+    im_y(logical(tmpy))=0;
+  end
+
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Apply search area mask
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  ext_gradx_t1(~extmask)=0;
+  ext_grady_t1(~extmask)=0;
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% do correlation
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  cc_x=real(ifft2(fft2(ext_gradx_t1).*conj(fft2(dif_maskx))));% from correlate.m
+  cc_y=real(ifft2(fft2(ext_grady_t1).*conj(fft2(dif_masky))));% from correlate.m
+  cc_sum=cc_sum+ (cc_x+cc_y);
+
+end
+
+
+
+shift=gtFindMaxSubscripts(cc_sum);
+
+%apply shifts
+
+%dif_perim_mask=roll(dif_perim_mask,shift(1),shift(2));
+dif_spot_mask=roll(dif_spot_mask,shift(1),shift(2));
+[com_x,com_y]=gtShiftContour(...
+  com_x,com_y,...
+  shift(2),shift(1),...
+  size(dif_spot_mask,2),size(dif_spot_mask,1));
+
+output_point = round([com_x com_y]); %where user would click in find_spots...
+summeddif_mask=roll(summeddif_mask,shift(1),shift(2));
+
+% try to remove bad portion of wrapped mask
+marker=zeros(size(summeddif_mask));
+marker(round(com_y),round(com_x))=1;
+summeddif_mask=imreconstruct(marker,summeddif_mask);
+summeddif_perim_mask=bwperim(summeddif_mask);
+
+% show some results
+if graphics.show_dif
+  h_dif=figure;
+  imshow(dif,[])
+end
+if graphics.show_initialmatch
+  h_initialmatch=figure;
+  h1=imshow(extmean,[]);
+  hold on
+  h3=imagesc(cat(3,summeddif_perim_mask, zeros(size(summeddif_perim_mask)), zeros(size(summeddif_perim_mask))));
+  set(h3,'alphadata',summeddif_perim_mask);
+  plot(com_x, com_y, 'xr', 'markersize', 10)
+  h4=imagesc(cat(3,zeros(size(extmask)),~extmask,zeros(size(extmask))));
+  set(h4,'alphadata',0.2)
+  hold off
+  drawnow
+  title(num2str(struct_id))
+end
+
+
+if 1 
+  tmp = imfill(summeddif_perim_mask,'holes');
+  tmp2=regionprops(double(tmp),'BoundingBox');
+  tmp2=tmp2.BoundingBox;
+
+% add SearchBoundingBox to bboxes table
+
+mysqlcmd=dbInsert(table_bboxes,...
+  'extspotID',struct_id,... % I changed here to the new names 
+	'Xorigin',tmp2(1),...     % I changed here to the new names
+  'Yorigin',tmp2(2),...     % I changed here to the new names
+  'Xsize',tmp2(3),...       % I changed here to the new names
+  'Ysize',tmp2(4),...       % I changed here to the new names ------Marcelo 08/12/06 - I stoped here...
+	'Xcentroid',com_x,...     % use new format of putting centroid and bb into a single table
+	'Ycentroid',com_y);        % use new format of putting centroid and bb into a single table
+mym(mysqlcmd);
+% get bboxID
+bboxID=mym('select last_insert_id()');
+
+% insert bboxID into extspot table
+mysqlcmd=dbInsert(table_extspot,...
+  'extspotID',struct_id,...
+  'searchbbID',bboxID);
+mym(mysqlcmd);
+end
+
+im=gaussianBlur(extmean,1);
+
+% polarity of image not important because only magnitude of gradient is used
+[fx,fy]=gradient(im);
+fmag=sqrt(fx.^2+fy.^2);
+
+% use a small part of the image to find the starting snake
+[roffset,coffset]=find(summeddif_perim_mask);
+
+[x_orig,y_orig]=gtMask2Poly(...
+  summeddif_perim_mask(...
+  min(roffset):max(roffset),...
+  min(coffset):max(coffset)));
+
+% adjust back to original coordinates
+x_orig=x_orig+min(coffset)-1;
+y_orig=y_orig+min(roffset)-1;
+
+x=x_orig;y=y_orig;
+
+
+%%%%%%%%%%%%%%
+% make some measures of the spot we are considering:
+defaultmaskarea=29000;
+maskarea=numel(summeddif_bw);
+arearatio=maskarea/defaultmaskarea;
+fprintf('Area ratio: %3.2f\n',arearatio);
+
+defaultmaskperim=575;
+tmp=regionprops(double(summeddif_bw),'perimeter');
+maskperim=round(tmp.Perimeter);
+perimratio=maskperim/defaultmaskperim;
+fprintf('Perimeter ratio: %3.2f\n',perimratio);
+
+% intensity variation
+% need bw mask of spot:
+if 1
+  bwtmp=poly2mask(x_orig,y_orig,size(extmean,2),size(extmean,1));
+  tmp_inside=extmean(bwtmp);
+  tmp_outside=extmean(~bwtmp);
+  mean_inside=mean(tmp_inside(:))*1e3;
+  mean_outside=mean(tmp_outside(:))*1e3;
+  defaultmeanratio=2.88/0.6; % stndxruct_id 700
+  meanratio=mean_inside/mean_outside;
+  % when intensity ratio is lower, snake is harder to bind to perimeter
+  intensityratio=meanratio/defaultmeanratio;
+  fprintf('Intensity ratio: %3.2f\n',intensityratio);
+end
+
+snakeoptions.elasticity=3;
+snakeoptions.rigidity=15;  % keep this high to prevent spurs from local features
+snakeoptions.viscosity=3;
+snakeoptions.forcefactor=5;
+snakeoptions.iterations=10; 
+
+snakeoptions.elasticity=snakeoptions.elasticity*arearatio.^2;
+%  snakeoptions.rigidity=10;  % keep this high to prevent spurs from local features
+%  snakeoptions.viscosity=5;
+%    snakeoptions.forcefactor=snakeoptions.forcefactor*perimratio;
+%  snakeoptions.iterations=5;
+snakeoptions;
+
+%%%%%%%%%%%%%%%
+
+pad=25;
+tmp_bbox=round([min(x(:))-pad min(y(:))-pad gtRange(x)+(2*pad) gtRange(y)+(2*pad)]);
+
+[u,v] = GVF(gtExtract(fmag,tmp_bbox), 0.05, 15);  % 0.2,80 % 0.3 15
+% Normalizing the GVF external force
+mag = sqrt(u.^2+v.^2);
+pxnorm = u./(mag+1e-10);pynorm = v./(mag+1e-10);
+
+forcefield.x=pxnorm;
+forcefield.y=pynorm;
+
+x=x-(tmp_bbox(1)+1);
+y=y-(tmp_bbox(2)+1);
+% should now remove points that are outside bbox
+if 0
+  x(y>size(mag,1))=[];
+  y(y>size(mag,1))=[];
+
+  y(x>size(mag,2))=[];
+  x(x>size(mag,2))=[];
+end
+if graphics.show_gvf
+  h_gvf=figure;
+  imagesc(mag,autolim(mag))
+  colorbar
+  hold on
+  quiver(pxnorm,pynorm,'r');
+  axis ij
+  axis equal
+  h_ax(1)=gca;
+end
+
+if graphics.show_snakeprogress && graphics.show_initialmatch
+  figure(h_initialmatch)
+  imagesc(gtExtract(extmean,tmp_bbox)),axis image,colormap(gray)
+  hold on
+  snakedisp(x,y,'r-')
+  h_ax(2)=gca;
+  if h_ax(1)~=0
+    linkaxes(h_ax,'xy')
+  end
+  axis image
+  drawnow
+end
+
+[x,y]=snakeinterp(x,y,20,1);
+origlength=length(x);
+clear hp
+converged=false;
+sfConverged([]); % reset sfConverged
+i=0;
+while not(converged)
+  i=i+1;
+  if i>100
+    break % get out of loop - we've taken too long
+  end
+  if length(x)<origlength/2
+    %      disp('Snake is too short!')
+    % break
+  end
+  [x2,y2]=snakedeform(x,y,forcefield,snakeoptions);
+  tmp=poly2mask(x,y,round(max(x)+5),round(max(y)+5));
+  area=sum(tmp(:));
+  converged=sfConverged(area);
+
+  [x,y]=snakeinterp(x2,y2,20,1);
+  if graphics.show_snakeprogress && graphics.show_initialmatch
+    figure(h_initialmatch)
+    if exist('hp','var')
+      delete(hp)
+    end
+    hp=snakedisp(x,y,'g.-');
+    axis image
+    title(['Deformation in progress,  iter = ' num2str(i*snakeoptions.iterations)])
+    drawnow
+    print('-dtiff',sprintf('perrin_%03d.tif',i));
+  end
+end
+if converged
+  disp('Converged')
+else
+  disp('Did NOT converge')
+end
+
+if graphics.show_snakefinal && graphics.show_initialmatch
+  if graphics.show_gvf
+    figure(h_gvf);
+    snakedisp(x,y,'g-')
+    title(['Structure ' num2str(struct_id)])
+  end
+  figure(h_initialmatch)
+  if graphics.show_snakeprogress
+    snakedisp(x,y,'g-');
+  else
+    snakedisp(x+(tmp_bbox(1)+1),y+(tmp_bbox(2)+1),'g-')
+  end
+  title(['Structure ' num2str(struct_id)])
+end
+% restore snake coordinates to that of extinction image
+x=x+tmp_bbox(1);  % mussing +??
+y=y+tmp_bbox(2);
+
+% write snake to sql table
+tmp=repmat(struct_id,1,length(x));  % produce vector of repeated struct_id
+values=sprintf('("%f","%f","%f"),',[tmp; x(:)'; y(:)']);
+values(end)=[];  % remove final comma
+mysqlcmd=sprintf('insert into %s (snakeID,x,y) values %s',table_snakes,values);
+mym(mysqlcmd)
+
+tmp = poly2mask(x,y, parameters.acq.bb(4), parameters.acq.bb(3));
+props=regionprops(double(tmp),'Area','BoundingBox','Centroid');
+
+if 1 
+	% add (snake) BoundingBox to bboxes table
+mysqlcmd=dbInsert(table_bboxes,...
+  'extspotID',struct_id,... % I changed here to the new names 
+	'Xorigin',props.BoundingBox(1),...     % I changed here to the new names
+  'Yorigin',props.BoundingBox(2),...     % I changed here to the new names
+  'Xsize',props.BoundingBox(3),...       % I changed here to the new names
+  'Ysize',props.BoundingBox(4),...       % I changed here to the new names ------Marcelo 08/12/06 - I stoped here...
+	'Xcentroid',props.Centroid(1),...     % use new format of putting centroid and bb into a single table
+	'Ycentroid',props.Centroid(2));        % use new format of putting centroid and bb into a single table
+mym(mysqlcmd);
+% get bboxID
+bboxID=mym('select last_insert_id()');
+
+% update (snake) bboxID into extspot table
+mysqlcmd=dbUpdate(table_extspot,'extspotID',struct_id,...
+  'Area',props.Area,...
+	'snakeID',struct_id,...
+	'bbID',bboxID);
+mym(mysqlcmd);
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function flag=sfConverged(data1)
+    persistent diffdata data h_history
+    if isempty(data1)
+      clear data diffdata h_history
+      return
+    end
+    if numel(data)==0
+      data=[data1];
+      flag=false;
+      disp('*******************************************STARTING')
+      if graphics.show_convergence
+        h_history=figure;
+      end
+
+    else
+      data=[data;data1];
+      diffdata=diff(data);
+      if graphics.show_convergence
+        h_convergence=figure(h_history);
+        plot(abs(diffdata),'.-');
+      end
+      if abs(diffdata(end))<1
+        flag=true;
+      else
+        flag=false;
+      end
+
+    end
+  end
+
+  function [ndx1,ndx2]=sfWhichExtImages_new_format(struct_id)
+
+    [maxim,startim,endim]=mym(sprintf(...
+      'select MaxImage,ExtStartImage,ExtEndImage from %s where difspotID=%d',...
+      table_difspot,struct_id));
+
+    if (endim - startim + 1) <= 3
+      %if less than or equal to 3 images, do all of them
+      ndx1=startim;
+      ndx2=endim;
+      %      disp('one')
+      %else do three, centred around maxim
+    elseif maxim == endim;
+      %      disp('two')
+      ndx1 = maxim-2;
+      ndx2 = maxim;
+    elseif maxim == startim;
+      %      disp('three')
+      ndx1 = maxim;
+      ndx2 = maxim+2;
+    else
+      %      disp('four')
+      ndx1 = maxim-1;
+      ndx2 = maxim+1;
+    end
+
+    %ensure doesn't go outside limits - should never be able to anyway...
+    if ndx1 <0
+      ndx1=0;
+    end
+    if ndx2 > (parameters.acq.nproj - 1)
+      ndx2=parameters.acq.nproj -1;
+    end
+    
+  end
+
+end
+
diff --git a/4_spot_sorting/Rod2g.m b/4_spot_sorting/Rod2g.m
new file mode 100755
index 0000000000000000000000000000000000000000..ab96f68ca24a848dffd0217c651f7ca3b0f4a5c0
--- /dev/null
+++ b/4_spot_sorting/Rod2g.m
@@ -0,0 +1,77 @@
+function g = Rod2g(r)
+% function g = Rod2g(r)
+% This function calculates the orientation matrix g given a Rodrigues
+% vector r. 
+% See e.g. equation 3.13 in Three-Dimensional X-Ray Diffraction Microscopy
+% by H.F. Poulsen
+%
+% Written by EML Sept. 04
+%
+% Note - there is a sign difference in the permutation tensor compared to
+% other published versions.  (Thanks P. Kenesei for spotting this)
+% Therefore what is produced is inv(g) rather than g, which explains the
+% issues in gtFowardSimulate where there appears to be a conflict with
+% formula 3.6 in Poulsen's book.  For the moment we are leaving it as it
+% is!
+
+% AK - 13/11/2008 rewritten with the permutation and identity matrices hard
+% coded rather than derived each time (2x faster!)
+
+
+g=zeros(3,3);   % Initialise the orientation matrix
+%initialise the permutation tensor
+%e=calc_perm_tensor;
+
+e(:,:,1) = [...
+     0     0     0; ...
+     0     0     1; ...
+     0    -1     0];
+e(:,:,2) = [...
+     0     0    -1; ...
+     0     0     0; ...
+     1     0     0];
+e(:,:,3) = [...
+     0     1     0; ...
+    -1     0     0; ...
+     0     0     0];
+ 
+delta=[1 0 0; 0 1 0; 0 0 1];
+
+
+% Loop over the elements of the orientation matrix
+for i=1:3
+    for j=1:3
+        g(i,j)= (1-dot(r,r))*delta(i,j) + 2*r(i)*r(j);
+        % Summing over the remaining component
+        for k=1:3
+             g(i,j) = g(i,j) - 2*e(i,j,k)*r(k);
+        end
+        g(i,j) = g(i,j)/(1+dot(r,r));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%function  e=calc_perm_tensor
+% Calculates the permutation tensor
+%e_ijk(i,j,k)=(x_i dot (x_j cross x_k))
+% 
+% I=eye(3);   % Identity matrix
+% for i=1:3
+%     for j=1:3
+%         for k=1:3
+%             e(i,j,k) = dot(I(:,i),cross(I(:,j),I(:,k)));
+%         end
+%     end
+% end
+
+
+
+% function res=delta(i,j)
+% % Calculates the Kronecker delta
+% if i==j
+%     res = 1;
+% else
+%     res= 0;
+% end
+
+    
\ No newline at end of file
diff --git a/4_spot_sorting/RotVecArAxed.m b/4_spot_sorting/RotVecArAxed.m
new file mode 100755
index 0000000000000000000000000000000000000000..b4139502aeec081784bb543c4def217009af71ab
--- /dev/null
+++ b/4_spot_sorting/RotVecArAxed.m
@@ -0,0 +1,43 @@
+function B = RotVecArAxed(A,L,Phi)
+% Function B = RotVecArAxe(L,Phi,A) rotate 
+% the vector A(3,1) around the axe L(3,1) 
+% into angle Phi radian counterclockwise.
+% Author: Sergiy Iglin
+% e-mail: iglin@kpi.kharkov.ua
+% or: siglin@yandex.ru
+% personal page: http://iglin.exponenta.ru
+
+%========== Checking of datas ==================
+strerr='Is needed 3 input parameters: vector A(3,1), axe L(3,1) and angle Phi!';
+if nargin<3,
+  error(strerr);
+end
+if ~isnumeric(A)
+  error(strerr);
+else
+  A=A(:);
+  if length(A)<3,
+    error(strerr);
+  end
+  A=A(1:3);
+end
+if ~isnumeric(L)
+  error(strerr);
+else
+  L=L(:);
+  if length(L)<3,
+    error(strerr);
+  end
+  L=L(1:3);
+  L0=L/norm(L); % orth
+end
+if ~isnumeric(Phi)
+  error(strerr);
+else
+  Phi=Phi(1);
+end
+
+%============= Solution ================
+cphi=cosd(Phi);
+B=A*cphi+(A'*L0)*(1-cphi)*L0+cross(L0,A)*sind(Phi);
+return
\ No newline at end of file
diff --git a/4_spot_sorting/check_normals.m b/4_spot_sorting/check_normals.m
new file mode 100755
index 0000000000000000000000000000000000000000..3d30daf20995b66665053ad575dfabe15875c088
--- /dev/null
+++ b/4_spot_sorting/check_normals.m
@@ -0,0 +1,16 @@
+
+
+
+function output = check_normals(predicted_normals, real_normals)
+
+output = []
+for i=1:length(real_normals)
+  tmp = predicted_normals - repmat(real_normals(i,:),length(predicted_normals),1);
+  tmp = tmp.*tmp;
+  tmp = sum(tmp,2);
+  sqrt(tmp);
+  dummy=find(tmp == min(tmp))
+  output(i,:)=predicted_normals(dummy,:);
+
+
+end
\ No newline at end of file
diff --git a/4_spot_sorting/combine_grains.m b/4_spot_sorting/combine_grains.m
new file mode 100755
index 0000000000000000000000000000000000000000..ea7d281ccf3a8aa57ce7d3dc9070ad9dd90048e6
--- /dev/null
+++ b/4_spot_sorting/combine_grains.m
@@ -0,0 +1,84 @@
+function output = combine_grains(r_vectors,positions)
+
+%r_vectors = [grainid rx ry rz]
+%positions = [grainid grainx grainy grainz grainsize]
+%produced by gtReadGrains
+
+  %avoid using this old version by mistake!
+  check=inputwdefault('should use version 2!!!  continue with this old version? (y/n)', 'n');
+    if check=='n'
+    return
+    end
+ 
+
+
+
+
+output=zeros(size(r_vectors,1),50);%assume no more than 50 grains to be combined...
+
+for i=1:size(r_vectors,1)
+  
+  dif = r_vectors(:,2:4)-repmat(r_vectors(i,2:4),size(r_vectors,1),1);
+  dif = dif.^2;
+  r_distance = sqrt(sum(dif,2));
+  
+  dif = positions(:,2:4)-repmat(positions(i,2:4),size(r_vectors,1),1);
+  dif = dif.^2;
+  p_distance = sqrt(sum(dif,2));
+  %consider the average size of the two grains
+  p_distance = p_distance./(0.5*(positions(:,5)+repmat(positions(i,5),size(r_vectors,1),1)));
+
+  %close in orientation and distance
+  dummy =[];
+  %dummy = [dummy; find(r_distance < 0.03 & p_distance < 0.2)];
+  %if super close in orientation, can relax distance requirement to allow
+  %for irregular shapes
+dummy = [dummy; find(r_distance < 0.03 & p_distance < 0.4)];
+  dummy = [dummy; find(p_distance < 0.2)];
+  
+  dummy = unique(dummy);
+  
+  output(i,1:(length(dummy))) = r_vectors(dummy,1)';
+  
+end
+  
+%crop output to only the required number of columns
+tmp = sum(output,1);
+dummy=find(tmp==0);
+output(:,dummy)=[];
+
+%get the unique rows - grains to be combined
+output = unique(output,'rows');
+%can still have multiple rows that refer to a single grain, eg ...;15 21
+%0;15 21 35;... in s5_dct5.  Remove these...
+tmp = unique(output(:,1));
+output2=[];
+
+for i=1:length(tmp)
+  dummy=find(output(:,1)==tmp(i));
+  output2(i,:)=output(max(dummy),:);%take only the row with the most entries
+end
+output=output2;
+
+%also need to ensure that a grain only occurs once in the matrix
+maxid = max(output(:));%max grainid
+del_rows=[];
+for i=1:maxid;
+  dummy=find(output==i);
+ 
+  if length(dummy)>1
+    [r,c]=ind2sub(size(output),dummy);%need to remove the entry in the first column
+   dummy2=find(c==1);
+   del_rows=[del_rows r(dummy2)];
+  end
+
+end
+
+del_rows=unique(del_rows);
+output(del_rows,:)=[];
+
+
+
+
+%output is now a table of grains that should be grouped together...
+
diff --git a/4_spot_sorting/combine_grains2.m b/4_spot_sorting/combine_grains2.m
new file mode 100755
index 0000000000000000000000000000000000000000..f36687c8ab6e0fe92d3aef50cbd5dc97c36ace5b
--- /dev/null
+++ b/4_spot_sorting/combine_grains2.m
@@ -0,0 +1,218 @@
+function combines = combine_grains2(r_vectors,positions, bads)
+
+%r_vectors = [grainid rx ry rz]
+%positions = [grainid grainx grainy grainz grainsize]
+%produced by gtReadGrains
+%combine_grains2 - need to improve the handling of what combines with
+%what...
+%apparently need to use positions calculated from the reconstructed,
+%post-processed grains - the x/y/zcenters are rubbish for this, need
+%x/y/zcenter2s
+%check consistancy because of the danger of combining twins, or other close
+%grains
+
+%get rid of bads grains before starting, also those already merged
+
+if 1
+dummy=find(bads==1 | bads==2); %consider possibly bad grains
+
+r_vectors(dummy,:)=[];
+positions(dummy,:)=[];
+else
+	disp('not dealing with bad grains!')
+end
+
+output=zeros(size(r_vectors,1),50);%assume no more than 50 grains to be combined...
+
+for i=1:size(r_vectors,1)
+  
+  dif = r_vectors(:,2:4)-repmat(r_vectors(i,2:4),size(r_vectors,1),1);
+  dif = dif.^2;
+  r_distance = sqrt(sum(dif,2));
+  
+  dif = positions(:,2:4)-repmat(positions(i,2:4),size(r_vectors,1),1);
+  dif = dif.^2;
+  p_distance = sqrt(sum(dif,2));
+  %consider the average size of the two grains
+  p_distance = p_distance./(0.5*(positions(:,5)+repmat(positions(i,5),size(r_vectors,1),1)));
+
+  %close in orientation and distance
+  dummy =[];
+  %dummy = [dummy; find(r_distance < 0.03 & p_distance < 0.2)];
+  %if super close in orientation, can relax distance requirement to allow
+  %for irregular shapes
+  dummy = [dummy; find(r_distance < 0.03 & p_distance < 0.4)];
+  %can have found the wrong r space solution - will test consistancy later
+  dummy = [dummy; find(p_distance < 0.2)];
+  
+  dummy = unique(dummy);
+  
+  output(i,1:(length(dummy))) = r_vectors(dummy,1)';
+ 
+end
+  
+
+
+%crop output to only the required number of columns
+tmp = sum(output,1);
+dummy=find(tmp==0);
+output(:,dummy)=[];
+tmp = sum(output,2);
+dummy=find(tmp==0);
+output(dummy,:)=[];
+
+%get the unique rows - grains to be combined
+output = unique(output,'rows');
+
+
+%can still have multiple rows that refer to a single grain, eg ...;15 21
+%0;15 21 35;... in s5_dct5.  Remove these...
+%want to keep the largest possible grain sets
+
+output2=zeros(length(output),50); %assume no more than 50 grains to be combined...
+count=1;
+test=0;
+test_length_old=size(output,1)
+
+while test==0
+  
+for i=1:max(output(:)) % go though all grainids
+
+
+  dummy=find(output==i);
+  [a,b]=ind2sub(size(output),dummy); % a are the rows to combine
+  tmp=output(a,:); % get those rows
+  tmp=tmp(:); 
+  tmp=unique(tmp);
+  tmp(find(tmp==0))=[];%remove zeros
+  output2(count,1:length(tmp))=tmp; %and combined set of grains to output2
+  count=count+1;
+  
+end
+
+%remove empty rows and columns from output2
+tmp = sum(output2,1);
+dummy=find(tmp==0);
+output2(:,dummy)=[];
+tmp = sum(output2,2);
+dummy=find(tmp==0);
+output2(dummy,:)=[];
+
+test_length=size(output2,1);
+if test_length==test_length_old %no change in the sets
+  test=1
+else
+  test=0
+  test_length_old=test_length;
+  output=output2;
+  output2=zeros(length(output),50);
+  %and do it all again
+end
+
+end % end of while loop
+
+output2=unique(output2,'rows');
+%output2 is now a table of grains that should be grouped together...
+
+
+
+
+
+%Next step - where output2 suggests combining grains, test the consistancy
+%of the result.  If putting the grain together results in a mess, should
+%not do it - either because it's a twin, or because two large grains with
+%com close together.
+
+combines=output2(find(output2(:,2)~=0),:);%rows containing more than a single grain
+
+results=[];
+for i=1:size(combines,1)
+  
+  plane_normal=[];
+  hkl=[];
+  list=0; %dummy entry, delete after
+  
+  for j=1:size(combines,2)
+    if combines(i,j)~=0
+    tmp=load(sprintf('4_grains/grain%d_/grain%d_.mat',combines(i,j),combines(i,j)));
+  % tmp=load(sprintf('grain%d_/grain%d_.mat',combines(i,j),combines(i,j)));
+  plane_normal=[plane_normal; tmp.plane_normal(find(tmp.index),:)]; %collect data for rodrigues
+  hkl=[hkl; tmp.hkl(find(tmp.index),:)]; %note - consider only those being used for reconstruction
+  list((end+1):(end+length(find(tmp.index))))=j;
+    end
+  end
+  
+  list(1)=[];%remove the dummy 0 entry
+  
+  [a,good_list]=plot_rodrigues_consistancy_test(plane_normal,hkl,0);
+  out=list(find(good_list==1));% the spots which are consistant
+	
+  for j=1:size(combines,2) %calc the fraction of each grain that remains good after the combination
+    results(i,j)=length(find(out==j))/length(find(list==j));
+  end
+  
+end
+%results contains the fractions of spots which stay good in each grain when
+%grains are combined as suggested.  Only do the combinations which do not
+%mess up consistancy
+consistancy_test=0.85;  %if consistancy drops below 90% of what it was
+results(find(isnan(results)))=1; %set NaN to 1 to ignore
+results=results<consistancy_test;  %keep those above threshold
+
+combines(find(results))=0;  %remove the grains that should not be combined
+%combines is now the list of grains to combines, but with some rows with
+%only one, or no grainids.
+kill_list=[];
+for i=1:size(combines,1)
+  dummy=find(combines(i,:)~=0);%how many non zero entries?
+  if length(dummy)<=1
+    kill_list=[kill_list i];
+  end
+end
+combines(kill_list,:)=[];%remove the rows with less than two grainids
+
+
+%tidy up the combines table - remove zeros, sort
+for i=1:size(combines,1)
+  combines(i,:)=sort(combines(i,:),'descend');
+end
+combines=unique(combines,'rows');%get unique rows
+tmp = sum(combines,1);%remove entirely zero columns
+dummy=find(tmp==0);
+combines(:,dummy)=[];
+%final sort to ascending order but with zeros to the end!
+for i=1:size(combines,1)
+  tmp=length(find(combines(i,:)~=0)); %number of non-zeros in row
+  combines(i,1:tmp)=sort(combines(i,1:tmp));
+end
+
+combines=sortrows(combines);%final sort by rows
+%can have lines like this:
+%     5     8    17    23    24    25    64     0     0
+%     5     8    17    24    25    64     0     0     0
+%     5     8    17    25    64     0     0     0     0
+%     5     8    23    24    25    64     0     0     0
+%get the longest list, kill the rest
+
+kill_a=[];
+for i=1:max(combines(:))
+  a=find(combines(:,1)==i);
+  if length(a)>1 %more than one row
+    count=zeros(size(a));%count the number of entries
+    for j=1:length(a)
+      count(j)=length(find(combines(a(j),:)~=0));
+    end
+%    keep_a = a(find(count==max(count)));
+    kill_a = [kill_a ; a(find(count~=max(count)))];
+  end
+end
+combines(kill_a, :)=[];
+
+    
+    
+    
+
+
+
+
+
diff --git a/4_spot_sorting/combine_grains2_twins.m b/4_spot_sorting/combine_grains2_twins.m
new file mode 100755
index 0000000000000000000000000000000000000000..afb6232b4393eb3c16b75b1ecbc59ab4b8d33eb5
--- /dev/null
+++ b/4_spot_sorting/combine_grains2_twins.m
@@ -0,0 +1,216 @@
+function combines = combine_grains2(r_vectors,positions, bads)
+
+%r_vectors = [grainid rx ry rz]
+%positions = [grainid grainx grainy grainz grainsize]
+%produced by gtReadGrains
+%combine_grains2 - need to improve the handling of what combines with
+%what...
+%apparently need to use positions calculated from the reconstructed,
+%post-processed grains - the x/y/zcenters are rubbish for this, need
+%x/y/zcenter2s
+%check consistancy because of the danger of combining twins, or other close
+%grains
+
+%get rid of bads grains before starting, also those already merged
+
+if 1
+dummy=find(bads==1 | bads==2); %consider possibly bad grains
+
+r_vectors(dummy,:)=[];
+positions(dummy,:)=[];
+else
+	disp('not dealing with bad grains!')
+end
+
+output=zeros(size(r_vectors,1),50);%assume no more than 50 grains to be combined...
+
+for i=1:size(r_vectors,1)
+  
+  dif = r_vectors(:,2:4)-repmat(r_vectors(i,2:4),size(r_vectors,1),1);
+  dif = dif.^2;
+  r_distance = sqrt(sum(dif,2));
+  
+  dif = positions(:,2:4)-repmat(positions(i,2:4),size(r_vectors,1),1);
+  dif = dif.^2;
+  p_distance = sqrt(sum(dif,2));
+  %consider the average size of the two grains
+  p_distance = p_distance./(0.5*(positions(:,5)+repmat(positions(i,5),size(r_vectors,1),1)));
+
+  %close in orientation and distance
+  dummy =[];
+  %dummy = [dummy; find(r_distance < 0.03 & p_distance < 0.2)];
+  %if super close in orientation, can relax distance requirement to allow
+  %for irregular shapes
+  dummy = [dummy; find(r_distance < 0.03 & p_distance < 0.4)];
+  %can have found the wrong r space solution - will test consistancy later
+  dummy = [dummy; find(p_distance < 0.2)];
+  
+  dummy = unique(dummy);
+  
+  output(i,1:(length(dummy))) = r_vectors(dummy,1)';
+ 
+end
+  
+%crop output to only the required number of columns
+tmp = sum(output,1);
+dummy=find(tmp==0);
+output(:,dummy)=[];
+tmp = sum(output,2);
+dummy=find(tmp==0);
+output(dummy,:)=[];
+
+%get the unique rows - grains to be combined
+output = unique(output,'rows');
+
+
+%can still have multiple rows that refer to a single grain, eg ...;15 21
+%0;15 21 35;... in s5_dct5.  Remove these...
+%want to keep the largest possible grain sets
+
+output2=zeros(length(output),50); %assume no more than 50 grains to be combined...
+count=1;
+test=0;
+test_length_old=size(output,1)
+
+while test==0
+  
+for i=1:max(output(:)) % go though all grainids
+
+
+  dummy=find(output==i);
+  [a,b]=ind2sub(size(output),dummy); % a are the rows to combine
+  tmp=output(a,:); % get those rows
+  tmp=tmp(:); 
+  tmp=unique(tmp);
+  tmp(find(tmp==0))=[];%remove zeros
+  output2(count,1:length(tmp))=tmp; %and combined set of grains to output2
+  count=count+1;
+  
+end
+
+%remove empty rows and columns from output2
+tmp = sum(output2,1);
+dummy=find(tmp==0);
+output2(:,dummy)=[];
+tmp = sum(output2,2);
+dummy=find(tmp==0);
+output2(dummy,:)=[];
+
+test_length=size(output2,1);
+if test_length==test_length_old %no change in the sets
+  test=1
+else
+  test=0
+  test_length_old=test_length;
+  output=output2;
+  output2=zeros(length(output),50);
+  %and do it all again
+end
+
+end % end of while loop
+
+output2=unique(output2,'rows');
+%output2 is now a table of grains that should be grouped together...
+
+
+
+
+
+%Next step - where output2 suggests combining grains, test the consistancy
+%of the result.  If putting the grain together results in a mess, should
+%not do it - either because it's a twin, or because two large grains with
+%com close together.
+
+combines=output2(find(output2(:,2)~=0),:);%rows containing more than a single grain
+
+results=[];
+for i=1:size(combines,1)
+  
+  plane_normal=[];
+  hkl=[];
+  list=0; %dummy entry, delete after
+  
+  for j=1:size(combines,2)
+    if combines(i,j)~=0
+    tmp=load(sprintf('4_grains/grain%d_/grain%d_.mat',combines(i,j),combines(i,j)));
+  % tmp=load(sprintf('grain%d_/grain%d_.mat',combines(i,j),combines(i,j)));
+  plane_normal=[plane_normal; tmp.plane_normal(find(tmp.index),:)]; %collect data for rodrigues
+  hkl=[hkl; tmp.hkl(find(tmp.index),:)]; %note - consider only those being used for reconstruction
+  list((end+1):(end+length(find(tmp.index))))=j;
+    end
+  end
+  
+  list(1)=[];%remove the dummy 0 entry
+  
+  [a,good_list]=plot_rodrigues_consistancy_test(plane_normal,hkl,0);
+  out=list(find(good_list==1));% the spots which are consistant
+	
+  for j=1:size(combines,2) %calc the fraction of each grain that remains good after the combination
+    results(i,j)=length(find(out==j))/length(find(list==j));
+  end
+  
+end
+%results contains the fractions of spots which stay good in each grain when
+%grains are combined as suggested.  Only do the combinations which do not
+%mess up consistancy
+consistancy_test=0.85;  %if consistancy drops below 90% of what it was
+results(find(isnan(results)))=1; %set NaN to 1 to ignore
+results=results<consistancy_test;  %keep those above threshold
+
+combines(find(results))=0;  %remove the grains that should not be combined
+%combines is now the list of grains to combines, but with some rows with
+%only one, or no grainids.
+kill_list=[];
+for i=1:size(combines,1)
+  dummy=find(combines(i,:)~=0);%how many non zero entries?
+  if length(dummy)<=1
+    kill_list=[kill_list i];
+  end
+end
+combines(kill_list,:)=[];%remove the rows with less than two grainids
+
+
+%tidy up the combines table - remove zeros, sort
+for i=1:size(combines,1)
+  combines(i,:)=sort(combines(i,:),'descend');
+end
+combines=unique(combines,'rows');%get unique rows
+tmp = sum(combines,1);%remove entirely zero columns
+dummy=find(tmp==0);
+combines(:,dummy)=[];
+%final sort to ascending order but with zeros to the end!
+for i=1:size(combines,1)
+  tmp=length(find(combines(i,:)~=0)); %number of non-zeros in row
+  combines(i,1:tmp)=sort(combines(i,1:tmp));
+end
+
+combines=sortrows(combines);%final sort by rows
+%can have lines like this:
+%     5     8    17    23    24    25    64     0     0
+%     5     8    17    24    25    64     0     0     0
+%     5     8    17    25    64     0     0     0     0
+%     5     8    23    24    25    64     0     0     0
+%get the longest list, kill the rest
+
+kill_a=[];
+for i=1:max(combines(:))
+  a=find(combines(:,1)==i);
+  if length(a)>1 %more than one row
+    count=zeros(size(a));%count the number of entries
+    for j=1:length(a)
+      count(j)=length(find(combines(a(j),:)~=0));
+    end
+%    keep_a = a(find(count==max(count)));
+    kill_a = [kill_a ; a(find(count~=max(count)))];
+  end
+end
+combines(kill_a, :)=[];
+
+    
+    
+    
+
+
+
+
+
diff --git a/4_spot_sorting/gt2LinesAngle.m b/4_spot_sorting/gt2LinesAngle.m
new file mode 100755
index 0000000000000000000000000000000000000000..95a814d5b3d2d6184bf209727dadcba749b1f7ca
--- /dev/null
+++ b/4_spot_sorting/gt2LinesAngle.m
@@ -0,0 +1,13 @@
+%
+% Calculates the angle (in degrees) of two straight lines (l1 and l2) in 3D.
+%
+% INPUT:    Two straight lines l1 and l2 = [ point_X point_Y point_Z dir_X dir_Y dir_Z ]
+% 
+% OUTPUT:   Angle (in degrees) between l1 and l2 = out   
+%           
+
+function out = gt2LinesAngle(l1,l2)
+
+out = acosd(dot(l2(4:6),l1(4:6))/norm(l2(4:6))/norm(l1(4:6))) ;
+
+end
diff --git a/4_spot_sorting/gt2LinesDist.m b/4_spot_sorting/gt2LinesDist.m
new file mode 100755
index 0000000000000000000000000000000000000000..e46a75e233008a5c3862f0584631774549159bbb
--- /dev/null
+++ b/4_spot_sorting/gt2LinesDist.m
@@ -0,0 +1,27 @@
+% Gives the spatial distance between a given base line and other 3D lines pair-wise 
+% 
+% INPUT:    bl=   base line [ point_X point_Y point_Z dir_X dir_Y dir_Z ]
+%           ol=   other lines [ point_X point_Y point_Z dir_X dir_Y dir_Z ]
+%
+% OUTPUT:   Spatial distance between bl and ol-s
+%        
+
+function out = gt2LinesDist(bl,ol)
+
+nol=size(ol,1);
+blr=repmat(bl,nol,1);
+a=cross(blr(:,4:6),ol(:,4:6),2);
+
+out = abs(dot(ol(:,1:3)-blr(:,1:3),a,2)./sqrt(sum(a.*a,2))) ;
+
+end
+
+
+
+% function out = gt2LinesDist(l1,l2)
+% 
+% a=cross(l1(4:6),l2(4:6)) ;
+% 
+% out = abs(dot(l2(1:3)-l1(1:3),a)/norm(a)) ;
+% 
+% end
diff --git a/4_spot_sorting/gt2LinesIntersection.m b/4_spot_sorting/gt2LinesIntersection.m
new file mode 100755
index 0000000000000000000000000000000000000000..d21fc8f2c6e45aa4a94b9e8041e8949b5ade7960
--- /dev/null
+++ b/4_spot_sorting/gt2LinesIntersection.m
@@ -0,0 +1,50 @@
+%
+% Gives the closest point between a given base line and other 3D lines pair-wise 
+%       (their 'point of intersection').
+%
+% INPUT:  bl[point_X point_Y point_Z norm_dir_X norm_dir_Y norm_dir_Z] =
+%           equation of the base line, direction vector normalized
+%         ol[point_X point_Y point_Z norm_dir_X norm_dir_Y norm_dir_Z] =
+%           equation of the ohter 3D lines, direction vector normalized
+%
+% OUTPUT: out[ X;Y;Z ] = closest point to pairs (`intersection point`)
+%
+
+function out = gt2LinesIntersection(bl,ol)
+
+nol=size(ol,1);
+
+A11=bl(4:6)*bl(4:6)';
+A12=-ol(:,4:6)*bl(4:6)';
+A21=A12;
+A22=sum(ol(:,4:6).*ol(:,4:6),2);
+
+c0=ol(:,1:3)-repmat(bl(1:3),nol,1);
+
+c11=c0*bl(4:6)';
+c21=sum(-c0.*ol(:,4:6),2);
+
+out=zeros(nol,3);
+
+for i=1:nol
+  
+  if bl==ol(i,:)
+    out(i,1:3)=bl(1:3);
+    continue
+  end
+  
+  A=[A11 A12(i); A21(i) A22(i)];
+  
+  c(1,1)=c11(i);
+  c(2,1)=c21(i);
+
+  par=A\c;
+  
+  out1=(bl(1:3)+par(1)*bl(4:6))' ;
+  out2=(ol(i,1:3)+par(2)*ol(i,4:6))' ;
+
+  out(i,1:3) = (out1+out2)/2 ;
+end
+
+
+end
diff --git a/4_spot_sorting/gt2PlanesAngle.m b/4_spot_sorting/gt2PlanesAngle.m
new file mode 100755
index 0000000000000000000000000000000000000000..1523a636a27ce3e924e2f122fb7d0227deb37720
--- /dev/null
+++ b/4_spot_sorting/gt2PlanesAngle.m
@@ -0,0 +1,19 @@
+% angle between two plane normals (any vectors)
+% Output is between 0 and 90.
+% If input is not normalized, use norm_flag=1 !
+
+
+function ang=gt2PlanesAngle(bpl,opl,norm_flag)
+
+if exist('norm_flag','var')
+  if norm_flag
+    ang=acosd((opl*bpl')./sqrt(sum(opl.*opl,2))/norm(bpl));
+    ang=min(ang,180-ang);
+    return
+  end
+end
+    
+ang=acosd(opl*bpl');
+ang=min(ang,180-ang);
+
+end
diff --git a/4_spot_sorting/gtAngConsCosMat.m b/4_spot_sorting/gtAngConsCosMat.m
new file mode 100755
index 0000000000000000000000000000000000000000..29e0b221920e920dee9a54f8d258aee107c6cdf8
--- /dev/null
+++ b/4_spot_sorting/gtAngConsCosMat.m
@@ -0,0 +1,12 @@
+function ACM=gtAngConsCosMat(spacegroup)
+
+no_ref=size(gtGetSpaceGroupReflections(spacegroup),1);
+
+for i=1:no_ref
+  for j=i:no_ref
+    ACM{i,j}=gtAngularConsCos(spacegroup,i,j);
+    ACM{j,i}=ACM{i,j} ;
+  end
+end
+
+end
diff --git a/4_spot_sorting/gtAngConsCosVec.m b/4_spot_sorting/gtAngConsCosVec.m
new file mode 100755
index 0000000000000000000000000000000000000000..e9d7e72584363a49fa72895c671aee0361c47161
--- /dev/null
+++ b/4_spot_sorting/gtAngConsCosVec.m
@@ -0,0 +1,14 @@
+
+function ACM_vec=gtAngConsCosVec(spacegroup)
+
+ACM=gtAngConsMat(spacegroup);
+
+ACM_vec=[];
+
+for i=1:size(ACM,1)
+  for j=i:size(ACM,2)
+    ACM_vec=[ACM_vec; ACM{i,j}] ;
+  end
+end
+
+end
diff --git a/4_spot_sorting/gtAngConsMat.m b/4_spot_sorting/gtAngConsMat.m
new file mode 100755
index 0000000000000000000000000000000000000000..1e5ffaca7e58f4c9c4cf96c15be8bd178c3c128d
--- /dev/null
+++ b/4_spot_sorting/gtAngConsMat.m
@@ -0,0 +1,18 @@
+
+function [ACM,ACMU]=gtAngConsMat(spacegroup)
+
+no_ref=size(gtGetSpaceGroupReflections(spacegroup),1);
+
+%ACM=zeros(no_ref,no_ref) ;
+
+for i=1:no_ref
+  for j=i:no_ref
+    [uniangle,angle_mult]=gtAngularCons(spacegroup,i,j);
+    ACM{i,j}=uniangle;
+    ACM{j,i}=uniangle;
+    ACMU{i,j}=angle_mult; % multiplicity
+    ACMU{j,i}=angle_mult;
+  end
+end
+
+end
diff --git a/4_spot_sorting/gtAngularCons.m b/4_spot_sorting/gtAngularCons.m
new file mode 100755
index 0000000000000000000000000000000000000000..a1a0c4300f774ffe530ddf0757b0692141950110
--- /dev/null
+++ b/4_spot_sorting/gtAngularCons.m
@@ -0,0 +1,43 @@
+
+function [uniangle,angle_mult]=gtAngularCons(spacegroup,f1,f2)
+
+ref=gtGetSpaceGroupReflections(spacegroup);
+
+angle=[];
+
+%%%  if cubic (225, 229)  %%%
+if spacegroup==225 || spacegroup==229 
+  v1=gtGetReflections(ref(f1,:)) ;
+  v2=gtGetReflections(ref(f2,:)) ;
+%%%  if hexagonal (194, 663)  %%%
+elseif spacegroup==194 || spacegroup==663 || spacegroup==167
+  v1=gtGetReflections_sab(ref(f1,:)) ;
+  v2=gtGetReflections_sab(ref(f2,:)) ;
+  v1=gtHKL2Cart(v1);
+  v2=gtHKL2Cart(v2);
+%%%  otherwise error  %%%
+else
+  error('Currently only spacegroups 225, 229, 194, 663 (167?) supported')
+end
+
+
+for i=1:size(v1,1)
+  for j=1:size(v2,1)
+    if v1(i,:)==v2(j,:)
+      angle=[angle; 0];
+    elseif v1(i,:)==-v2(j,:)
+      angle=[angle; 0];
+    else
+      angle=[angle; acosd(abs((v1(i,:)*v2(j,:)')/norm(v1(i,:))/norm(v2(j,:))))] ;
+    end
+  end
+end
+
+
+
+uniangle=unique(angle);
+for i=1:length(uniangle)
+  angle_mult(i)=length(find(uniangle(i)==angle));
+end
+
+end
diff --git a/4_spot_sorting/gtAngularConsCos.m b/4_spot_sorting/gtAngularConsCos.m
new file mode 100755
index 0000000000000000000000000000000000000000..2376b97a945eb547a6b6a1d61213707d90334714
--- /dev/null
+++ b/4_spot_sorting/gtAngularConsCos.m
@@ -0,0 +1,17 @@
+function cos=gtAngularConsCos(spacegroup,f1,f2)
+
+ref=gtGetSpaceGroupReflections(spacegroup);
+
+cos=[];
+
+v1=gtGetReflections(ref(f1,:)) ;
+v2=gtGetReflections(ref(f2,:)) ;
+for i=1:size(v1,1)
+  for j=1:size(v2,1)
+    cos=[cos; abs(v1(i,:)*v2(j,:)')/norm(v1)/norm(v2)] ;
+  end
+end
+cos=unique(cos);
+cos=[1; cos];
+
+end
diff --git a/4_spot_sorting/gtApplyForwardSimulate.m b/4_spot_sorting/gtApplyForwardSimulate.m
new file mode 100755
index 0000000000000000000000000000000000000000..20b0e8127395132136ec8f15f91f76f57f8d139c
--- /dev/null
+++ b/4_spot_sorting/gtApplyForwardSimulate.m
@@ -0,0 +1,183 @@
+function gtApplyForwardSimulate(new_struct_ids,grainid)
+
+%function to add new extspots to the grain
+%for situation where difspot and extspot are correct, but gtHandleSpot has
+%missed out the extspot.  ie ext_possibles from gtForwardSimulate_ak
+
+%reorder struct_ids in mat file, and adjust other parameters where
+%neccessary
+
+%ak 23/11 - remove extspots stolen from other grains at the same time.
+
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%set up new directory
+new_dir =sprintf('4_grains/new_grains/grain%d_',grainid);
+mkdir(new_dir);
+
+%if no spots to add, just copy the mat file to the new_grains location
+if isempty(new_struct_ids)
+cmd=sprintf('cp 4_grains/grain%d_/grain%d_.mat 4_grains/new_grains/grain%d_/grain%d_.mat',grainid,grainid,grainid,grainid);
+unix(cmd)
+
+
+else%add the new spots
+
+%collect new data
+new_struct_ids;%to be added
+new_replaced = zeros(1, length(new_struct_ids));
+new_index = ones(1, length(new_struct_ids));
+new_Omega = gtGetOmega(new_struct_ids);
+%note - this assumes that no replacement or selection of preojections has
+%been done yet, so replaced=0, index=1 for all
+new_zstart=[];
+new_zend=[];
+
+for i=1:length(new_struct_ids)
+  %collect 
+  [former_grainid, new_zstart(i), new_zend(i)] = mym(sprintf('select GrainID, Yorigin, Yorigin+Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d',...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    new_struct_ids(i)));
+
+  %update extspot database with grainid
+  mym(sprintf('update %sextspot set GrainID=%d where extspotID=%d',...
+  parameters.acq.name, grainid, new_struct_ids(i)));
+  %update bb database with grainid
+  mym(sprintf('update %sbb set GrainID=%d where extspotID=%d',...
+  parameters.acq.name, grainid, new_struct_ids(i)));
+
+%remove those extspots with a former_grainid from old grains
+if ~isnan(former_grainid)
+  try
+load(sprintf('4_grains/grain%d_/grain%d_.mat',former_grainid,former_grainid));
+kill_index = find(struct_ids == new_struct_ids(i));
+struct_ids(kill_index)=[];
+plane_normal(kill_index,:)=[];
+hkl(kill_index,:)=[];
+stack(:,:,kill_index)=[];
+Omega(kill_index)=[];
+Theta(kill_index)=[];
+Eta(kill_index)=[];
+index(kill_index)=[];
+replaced(kill_index)=[];
+save(sprintf('4_grains/grain%d_/grain%d_.mat',former_grainid,former_grainid),'struct_ids','plane_normal','hkl','stack','Omega','Theta','Eta','index','replaced','-append');
+  end
+end
+
+end
+
+
+
+%load the current grain data, add the new data
+name=sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid);
+load(name);
+
+new_Omega = 180*(new_Omega./parameters.acq.proj);%working in degrees
+[new_Theta, new_Eta]=gtFindAngles(new_struct_ids, x1+(nx/2), y1+(ny/2), zcenter, new_Omega);%works in degrees
+
+new_stack = gtReadSpots(struct_ids(1), new_struct_ids);
+%note - for s5_dct5_, gtReadSpots applies the 15 pixel z-shift
+
+%calculate plane normals in sample coordinates
+new_Theta=new_Theta*pi/180;%convert to radians
+new_Eta=new_Eta*pi/180;
+new_Omega=new_Omega*pi/180;
+for i=1:length(new_struct_ids);
+  new_plane_normal(i,1) = -sin(new_Theta(i))*cos(new_Omega(i)) - cos(new_Theta(i))*sin(new_Eta(i))*sin(new_Omega(i));
+  new_plane_normal(i,2) = cos(new_Theta(i))*sin(new_Eta(i))*cos(new_Omega(i)) - sin(new_Theta(i))*sin(new_Omega(i));%30/10 - signs change in this line
+  new_plane_normal(i,3) = cos(new_Theta(i))*cos(new_Eta(i));
+end
+new_Theta=new_Theta*180/pi;%convert back to degrees
+new_Eta=new_Eta*180/pi;
+new_Omega=new_Omega*180/pi;
+
+%determine new hkls from new_Theta
+new_hkl=zeros(length(new_Theta),3);
+hkl_list=zeros(length(new_Theta),1);%tmp = 1 means hkl = {111}, 2 means {002} etc
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+allowed_Theta = (twotheta/2);%work in degrees
+allowed_Theta = [0.95*allowed_Theta; 1.05*allowed_Theta];% %5 tolerance
+for i=1:length(allowed_Theta)% run through the allow thetas calculated above
+  dummy = find(new_Theta>allowed_Theta(1,i) & new_Theta<allowed_Theta(2,i));
+  hkl_list(dummy)=i;
+end
+%hkl lookup table...
+warning('hard coded FCC in hkl look up table')
+hkl_table = [1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1 ; 0 0 4 ; 3 3 1];
+%fill in hkl matrix
+for i=1:size(hkl_table,1)
+  dummy = find(hkl_list == i);
+  for d=1:length(dummy)
+    new_hkl(dummy(d),:) = hkl_table(i,:);
+  end
+end
+
+%combine old and new data for .mat file
+struct_ids = [struct_ids new_struct_ids];
+plane_normal = [plane_normal; new_plane_normal];
+hkl = [hkl; new_hkl];
+stack = cat(3,stack,new_stack);
+Omega = [Omega new_Omega];
+Theta = [Theta new_Theta];
+Eta = [Eta new_Eta];
+replaced = [replaced new_replaced];
+index = [index new_index];
+zstart = min([zstart new_zstart]);
+zend = max([zend new_zend]);
+
+%sort where needed
+[Omega,tmp]=sort(Omega);
+Theta = Theta(tmp);
+Eta = Eta(tmp);
+struct_ids = struct_ids(tmp);
+plane_normal = plane_normal(tmp,:);
+hkl = hkl(tmp,:);
+stack = stack(:,:,tmp);
+index = index(tmp);
+replaced = replaced(tmp);
+
+%may need also to remove duplicates....
+[struct_ids,tmp]=unique(struct_ids);
+Omega=Omega(tmp);
+Theta=Theta(tmp);
+Eta=Eta(tmp);
+index=index(tmp);
+replaced=replaced(tmp);
+plane_normal=plane_normal(tmp,:);
+hkl=hkl(tmp,:);
+stack=stack(:,:,tmp);
+
+%get new average zcenter of all spots in the grain
+zcenter = mym(sprintf('select CentroidY from %sextspot where GrainID=%d',parameters.acq.name,grainid));
+zcenter = ceil(mean(zcenter));
+
+%save new data into grain .mat
+new_name=sprintf('4_grains/new_grains/grain%d_/grain%d_.mat',grainid,grainid);
+%currentll save a new mat file in /new_grains/ rather than appending to old
+save(new_name, 'struct_ids','stack','Theta','Eta','Omega','plane_normal','hkl','index','replaced','zstart','zend','x1','nx','y1','ny')%,'-append');
+
+
+%ensure that all grainIDs are up to date - should be unnecessary normally
+for i=1:length(struct_ids)
+  %update extspot database with grainid
+  mym(sprintf('update %sextspot set GrainID=%d where extspotID=%d',...
+  parameters.acq.name, grainid, struct_ids(i)));
+  %update bb database with grainid
+  mym(sprintf('update %sbb set GrainID=%d where extspotID=%d',...
+  parameters.acq.name, grainid, struct_ids(i)));
+end
+
+
+end
diff --git a/4_spot_sorting/gtCalcOmega.m b/4_spot_sorting/gtCalcOmega.m
new file mode 100755
index 0000000000000000000000000000000000000000..fc8ccdc7f6f3c91425759eb1d111fcd314b70846
--- /dev/null
+++ b/4_spot_sorting/gtCalcOmega.m
@@ -0,0 +1,53 @@
+function [Theta,Eta,Omega]=gtCalcOmega(normal, hkl)
+
+%calculates the Omega position at which diffraction will occur from a plane
+%defined by its plane normal and hkl type [h k l]
+
+%load data
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%put plane normal in cylindrical polar coords
+length = sqrt(normal(1)^2 + normal(2)^2);
+alpha = atan2(normal(2), normal(1));
+vert = normal(3);
+
+%calc Theta for diffraction
+lambda = 12.398/parameters.acq.energy;
+if parameters.acq.spacegroup == 225
+d=parameters.acq.latticepar(1)/sqrt(hkl*hkl');
+else
+  disp('only works for FCC at the mo...')
+end
+Theta = asin(lambda/(2*d));
+
+try
+  %produce Omega angles
+  temp(1) = acos((cos((pi/2)-Theta))/length);
+  temp(2) = pi-temp(1);
+  Omega = temp - alpha;
+  Omega(3:4) = Omega(1:2)+pi;
+
+  %put all in 0-2pi interval
+  dummy = find(Omega<0);
+  Omega(dummy) = Omega(dummy) + (2*pi);
+  dummy = find(Omega>(2*pi));
+  Omega(dummy) = Omega(dummy) - (2*pi);
+
+  %calc Eta
+for i=1:size(Omega,2)
+  alpha2 = alpha + Omega(i);
+  y = length*sin(alpha2);
+  Eta(i) = sin(y/vert);
+  Theta(i) = Theta(1);
+end
+
+catch%if no solutions
+  disp('no diffraction from this plane normal!')
+end
+
+
+
+
diff --git a/4_spot_sorting/gtCentroidOfRegion.m b/4_spot_sorting/gtCentroidOfRegion.m
new file mode 100755
index 0000000000000000000000000000000000000000..8f44ac82ebf9b3c8bdd6103abd32eda458e30dd5
--- /dev/null
+++ b/4_spot_sorting/gtCentroidOfRegion.m
@@ -0,0 +1,10 @@
+function c=gtCentroidOfRegion(m)
+% Gives the centroid x and y - first moment - of a matrix.
+% Minimum value: [1 1]
+% Maximum value: [size(m,1) size(m,2)]
+
+all=sum(sum(m));
+c(1)=sum(sum(m,2).*[1:size(m,1)]')/all;
+c(2)=sum(sum(m,1).*[1:size(m,2)])/all;
+
+end
diff --git a/4_spot_sorting/gtCheckGroupCons.m b/4_spot_sorting/gtCheckGroupCons.m
new file mode 100755
index 0000000000000000000000000000000000000000..254e54166abcd14be077e71750aec7954dc624ff
--- /dev/null
+++ b/4_spot_sorting/gtCheckGroupCons.m
@@ -0,0 +1,16 @@
+
+function groupcons=gtCheckGroupCons(tryline,goodl,goodpofinters,tol,sample,ACM)
+
+nof_goods=length(goodl.id);
+
+paircons=gtCheckPairCons(tryline,goodl,tol,sample,ACM);
+
+groupcons=false;
+
+if length(paircons)==nof_goods
+  if pointtolinedist(goodpofinters,[tryline.ca tryline.dir])<2*tol.dist;
+    groupcons=true;
+  end
+end
+
+end
diff --git a/4_spot_sorting/gtCheckPairCons.m b/4_spot_sorting/gtCheckPairCons.m
new file mode 100755
index 0000000000000000000000000000000000000000..82f3e008664d4ffdf4751d7fb09e9a4cdec4d706
--- /dev/null
+++ b/4_spot_sorting/gtCheckPairCons.m
@@ -0,0 +1,67 @@
+%
+% Checks pair consistency in a set of lines. 
+%
+% act:  the actual line (structure)
+% cand: candidates (structure) to be pair consistent with it
+% tol:  tolerances (structure)
+% sample: sample geometry parameters (structure)
+% ACM:  angular consistency matrix
+
+function [paircons,progress,cand,pofinters,angle]=gtCheckPairCons(act,cand,tol,sample,ACM)
+
+paircons=(1:length(cand.id))';  % initial indices of consistent lines 
+progress=length(cand.id);
+
+% integrated intensities close enough?
+cons=(act.int/tol.int<cand.int) & (act.int*tol.int>cand.int);
+cand=gtKeepLine(cons,cand);
+paircons(~cons)=[];
+progress=[progress; length(cand.id)];
+
+% bbox x size close enough?
+cons=(act.bbxs/tol.bbxs<cand.bbxs) & (act.bbxs*tol.bbxs>cand.bbxs);
+cand=gtKeepLine(cons,cand);
+paircons(~cons)=[]; 
+progress=[progress; length(cand.id)];
+
+% bbox y size close enough?
+cons=(act.bbys/tol.bbys<cand.bbys) & (act.bbys*tol.bbys>cand.bbys);
+cand=gtKeepLine(cons,cand);
+paircons(~cons)=[]; 
+progress=[progress; length(cand.id)];
+
+% spatial distance small enough?
+cons=gt2LinesDist([act.ca act.dir],[cand.ca cand.dir])<tol.dist;
+cand=gtKeepLine(cons,cand);
+paircons(~cons)=[]; 
+progress=[progress; length(cand.id)];
+
+% is intersection in the sample volume?%
+% NOTE: intersection of 2 lines might actually be far from the grain center
+% if they are near being parallel. This could be taken into account here...
+% On the other hand, there should be no parallel lines in a grain set.
+pofinters=gt2LinesIntersection([act.ca act.dir],[cand.ca cand.dir]);
+cons=gtIsPointInSample(pofinters,sample,tol);
+cand=gtKeepLine(cons,cand);
+pofinters(~cons,:)=[];
+paircons(~cons)=[]; 
+progress=[progress; length(cand.id)];
+
+% plane angles consistent?
+cons=false(length(cand.id),1);
+angle=zeros(length(cand.id),1);
+for i=1:length(cand.id)
+  ACV=ACM{act.thetatype,cand.thetatype(i)};
+  ang=gt2PlanesAngle(act.pl,cand.pl(i,:));
+  angle(i)=ang;
+  cons(i)=min(abs(ACV-ang))<tol.ang;
+end
+cand=gtKeepLine(cons,cand);
+pofinters(~cons,:)=[];
+angle(~cons)=[];
+paircons(~cons)=[]; 
+progress=[progress; length(cand.id)];
+
+
+end
+
diff --git a/4_spot_sorting/gtCheckThetas.m b/4_spot_sorting/gtCheckThetas.m
new file mode 100755
index 0000000000000000000000000000000000000000..dd5d8affb70515f3faa9597b7586882038c8eb68
--- /dev/null
+++ b/4_spot_sorting/gtCheckThetas.m
@@ -0,0 +1,42 @@
+%
+% function [theta_OK,differs,thetatype]=gtCheckThetas(scXA,scYA,scXB,scYB,
+%   rottodet,tiltY,tiltZ,rotx,sorZ,valid_2thetas,thr_ang)
+%
+% Checks whether the positions of two diffraction spots in a pair of images
+% 180 degrees offset fulfills the crystallographic criterion (i.e. the line
+% connecting them corresponds to a 2theta diffraction angle within the given
+% threshold).
+%
+% INPUT  scXA,scYA,scXB,scYB = spot positions in the Scintillator system
+%        rottodet = rotation axis to detector (scintillator) distance at rotx,sorZ (pixels or mm-s)
+%        /scX,scY,rottodet have to be in the same units; e.g. pixels or mm-s/
+%        tiltY = tilt around axis Y in Lab system (in degrees)
+%        tiltZ = tilt around axis Z in Lab system (in degrees)
+%        rotx = location of rotation axis in the images (X coord. in pixels)
+%        sorZ = Z=0 location in the images (Y coord. in pixels at the rotation axis) 
+%        valid_2thetas = vector of all valid crystallographic 2theta angles (in degrees)
+%        thr_ang = angular threshold for 2theta angles (in degrees)
+%
+%        e.g. ([234;334;434],[1444;1644;1944],[134;234;534],[555;545;535],
+%              3600,0.123,0.421,1026,1024,[6.981 7.562 9.365 13.457],0.5)
+%           
+% OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+%           differs = difference relative to the theoretical twotheta angles
+%           thetatype = index of the closest valid twotheta angle
+%
+
+function [theta_OK,differs,thetatype]=gtCheckThetas(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ,valid_2thetas,thr_ang)
+  
+  angle=gtThetaOfPairs(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ) ;
+
+  differs=valid_2thetas-angle;
+    
+  if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+    theta_OK=false ;
+    thetatype=[] ;
+  else
+    theta_OK=true ;
+    [mini,thetatype]=min(abs(valid_2thetas-angle));
+  end
+      
+end
diff --git a/4_spot_sorting/gtConsistancyCheck.m b/4_spot_sorting/gtConsistancyCheck.m
new file mode 100755
index 0000000000000000000000000000000000000000..297e89dc628015310e52abda58d122b7970fbf4a
--- /dev/null
+++ b/4_spot_sorting/gtConsistancyCheck.m
@@ -0,0 +1,237 @@
+
+function [struct_id,plane_normal,hkl,output,angles,bad_struct_id, discrepancy] = gtConsistancyCheck(grainid, overwrite_flag)
+%read from grain%d_.mat, calculate plane normals, hkls, the consistancy matrix, and the interplanar angles
+%function [plane_normal,hkl,output,angles] = gtnew_consistancy_check(grainid)
+%if overwrite_flag==1, then inconsistant data will be removed from grain%d_.mat
+%can add a second grain if two appear to be same
+
+%30/10/2006 change calculation on plane normal to reflect true sense of
+%camera image ("looking into beam")...  AK
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%read in data
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+
+struct_id = grain_data.struct_ids;
+stack = grain_data.stack;
+Omega = grain_data.Omega*pi/180;
+Theta = grain_data.Theta*pi/180;
+Eta = grain_data.Eta*pi/180;
+if isfield(grain_data, 'index')
+  index = grain_data.index; %index of projections to use for art
+end
+
+if 0 %if combining two grains
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid2,grainid2));
+struct_id = [struct_id grain_data.struct_ids];
+stack = cat(3,stack,grain_data.stack);
+Omega = [Omega grain_data.Omega*pi/180];
+Theta = [Theta grain_data.Theta*pi/180];
+Eta = [Eta grain_data.Eta*pi/180];
+end
+%calculate plane normals in sample coordinates
+for i=1:length(struct_id);
+  plane_normal(i,1) = -sin(Theta(i))*cos(Omega(i)) - cos(Theta(i))*sin(Eta(i))*sin(Omega(i));
+  plane_normal(i,2) = cos(Theta(i))*sin(Eta(i))*cos(Omega(i)) - sin(Theta(i))*sin(Omega(i));%30/10 - signs change in this line
+  plane_normal(i,3) = cos(Theta(i))*cos(Eta(i));
+end
+
+%plane_normal contains all plane normals....calc angles between plane
+%normals
+for i=1:length(struct_id);
+  for j=1:length(struct_id);
+    angles(i,j) = real(acos(dot(plane_normal(i,:),plane_normal(j,:))))*180/pi;
+    if(i==j)%set diagonal values to zero because of imaginaries
+      angles(i,j)=0;
+    end
+  end
+end
+
+%determine which Theta is which hkl
+hkl=zeros(length(Theta),3);
+hkl_list=zeros(length(Theta),1);%tmp = 1 means hkl = {111}, 2 means {002} etc
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+allowed_Theta = (twotheta/2)*pi/180;
+allowed_Theta = [0.95*allowed_Theta; 1.05*allowed_Theta];% %5 tolerance
+
+for i=1:length(allowed_Theta)% run through the allow thetas calculated above
+  dummy = find(Theta>allowed_Theta(1,i) & Theta<allowed_Theta(2,i));
+  hkl_list(dummy)=i;
+end
+%for searching
+tmp1 = repmat(hkl_list', length(hkl_list), 1);
+tmp2 = repmat(hkl_list, 1, length(hkl_list));
+
+%hkl lookup table...
+warning('hard coded FCC in hkl look up table')
+hkl_table = [1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1 ; 0 0 4 ; 3 3 1];
+%fill in hkl matrix
+for i=1:size(hkl_table,1)
+  dummy = find(hkl_list == i);
+  for d=1:length(dummy)
+    hkl(dummy(d),:) = hkl_table(i,:);
+  end
+end
+
+
+%write the output (consistancy) matrix
+output = zeros(size(angles));
+discrepancy = zeros(size(angles));
+%for each pair of spots, check if angle is good - loop though each possible
+%combination, doing all spot pairs of that type
+for i=1:size(hkl_table,1); %first family of reflection
+  for j=1:size(hkl_table,1); %second family of reflection
+
+    dummy = find(tmp1 == i & tmp2 ==j);
+    allowed = sfGetAllowedInterplaneAngles(hkl_table(i,:), hkl_table(j,:));
+    range=2;%tolerance (IN DEGREES) for two planes to be consistant
+
+    for k=1:length(dummy);
+      if min(abs(allowed - angles(dummy(k)))) < range
+        output(dummy(k)) = 1;
+      end
+      discrepancy(dummy(k)) = min(abs(allowed - angles(dummy(k))));
+    end
+
+
+  end
+end
+
+%output is a square, diagonally symmetric matrix of which spots are
+%consistant with which others.  Can use this to reject poorly agreeing
+%spots, until a fully consistant set remains
+%preserve output, work on temp
+temp = output;
+%select the good rows/columns from the output matrix
+good_index = 1:length(struct_id);
+bad_index = [];
+%calculate initial "goodness" of output matrix
+test = sum(temp)./size(temp,1);
+
+counter = 1;
+while any(test < 1);
+  dummy = find(test == min(test));%find worst rows/columns
+  for k=1:length(dummy)
+    bad_index(counter) = good_index(dummy(k));%write bad indices
+    counter = counter+1;
+  end
+  temp(dummy,:)=[];%remove rows
+  temp(:,dummy)=[];%remove columns
+  good_index(dummy) = [];%remove bad indexs from good
+  test = sum(temp)./size(temp,1);%calc "goodness" again
+end
+
+%this may remove too many!  so need a subsequent possibility to
+% %replace erroneous rejections.
+%an example of the problem is grain 10, if the range=6 when checking consistancy
+for i=1:length(bad_index);%for each "bad" spot
+  if all(output(bad_index(i), good_index)==1)%if "bad" actually agrees with all, replace it
+    good_index(end+1) = bad_index(i)%relace index in good list
+  end
+end
+
+%make a list of bad struct ids to be returned to the original data pool
+good_index = sort(good_index,2,'descend');%put in reverse order for this removal step
+bad_struct_id=struct_id;
+for i=1:length(good_index)
+  bad_struct_id(good_index(i)) = [];%remove good ids from this list
+end
+
+%produce final results - output matrix, lists of good struct_ids
+good_index = sort(good_index,2,'ascend');%put in normal order for this list
+
+struct_id=struct_id(good_index);
+plane_normal=plane_normal(good_index,:);
+hkl = hkl(good_index,:);
+Theta=Theta(good_index)*180/pi;
+Eta=Eta(good_index)*180/pi;
+Omega=Omega(good_index)*180/pi;
+stack = stack(:,:,good_index);
+if isfield(grain_data, 'index')
+  index = index(good_index);
+end
+
+%to plot the good plane normals as a 3D vector plot
+if 1
+
+  hkl_list = hkl_list(good_index);
+
+  %plot the plane normal vectors {111}, {002}, {220} and {311}
+  orig=zeros(size(plane_normal));
+  dummy=find(hkl_list==2);%(200) plane normals - blue
+  figure;
+  quiver3(orig(dummy,1),orig(dummy,2),orig(dummy,3),plane_normal(dummy,1),plane_normal(dummy,2),plane_normal(dummy,3));
+  hold on
+
+  dummy=find(hkl_list==1);%(111) plane normals - red
+  quiver3(orig(dummy,1),orig(dummy,2),orig(dummy,3),plane_normal(dummy,1),plane_normal(dummy,2),plane_normal(dummy,3),'r');
+
+  dummy=find(hkl_list==3);%(220) plane normals - green
+  quiver3(orig(dummy,1),orig(dummy,2),orig(dummy,3),plane_normal(dummy,1),plane_normal(dummy,2),plane_normal(dummy,3),'g');
+
+  dummy=find(hkl_list==4);%(311) plane normals - black
+  if ~isempty(dummy)
+    quiver3(orig(dummy,1),orig(dummy,2),orig(dummy,3),plane_normal(dummy,1),plane_normal(dummy,2),plane_normal(dummy,3),'k');
+  end
+
+  axis equal
+  hold off
+
+
+end
+
+goodness = sum(output(:))/(size(output,1)*size(output,2));
+if 1%simple to switch off modification to .mat file
+%save the plane normals into the grain structure
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('/%s/4_grains/grain%d_',parameters.acq.dir,grainid);
+name=sprintf('%s/%s.mat',graindir,grainname);
+save(name,'plane_normal','hkl','-append');
+
+if (overwrite_flag) == 1
+  struct_ids=struct_id;%!bodge... AK
+  save(name, 'stack', 'struct_ids', 'Theta', 'Eta', 'Omega', '-append')
+end
+
+end
+end
+
+
+
+
+
+function allowed_angles = sfGetAllowedInterplaneAngles(hkl_1, hkl_2)
+hkl_m1 = gtGetReflections(hkl_1);
+hkl_m2 = gtGetReflections(hkl_2);
+allowed_angles = [];counter = 1;
+for i=1:size(hkl_m1,1)
+  for j=1:size(hkl_m2,1)
+    tmp = acos ( dot(hkl_m1(i,:), hkl_m2(j,:)) / (sqrt( (hkl_m1(i,:)*hkl_m1(i,:)')*(hkl_m2(j,:)*hkl_m2(j,:)') )) );
+    tmp = tmp*180/pi;
+    allowed_angles(counter) = tmp;
+    counter = counter+1;
+  end
+end
+%remove duplicates
+dummy=[];counter=1;
+for i=1:length(allowed_angles)
+  for j=(i+1):length(allowed_angles)
+    if allowed_angles(i) == allowed_angles(j)
+      dummy(counter)=i;
+      counter=counter+1;
+    end
+  end
+end
+allowed_angles(dummy)=[];
+end
+
+
+
diff --git a/4_spot_sorting/gtConvEnergyToWavelength.m b/4_spot_sorting/gtConvEnergyToWavelength.m
new file mode 100755
index 0000000000000000000000000000000000000000..5f2ae5fca4ee5ad5704e746b876612c951c50974
--- /dev/null
+++ b/4_spot_sorting/gtConvEnergyToWavelength.m
@@ -0,0 +1,16 @@
+%
+% Converts beam energy to wavelength. 
+%
+% gtConvEnergyToWavelength(50)= 0.2479
+%
+% INPUT:    energy in keV
+% 
+% OUTPUT:   wavelength in angstroms
+%
+
+
+function lambda=gtConvEnergyToWavelength(energy)
+
+lambda=12.3984428/energy ;
+
+end
diff --git a/4_spot_sorting/gtCorrectGeo.m b/4_spot_sorting/gtCorrectGeo.m
new file mode 100755
index 0000000000000000000000000000000000000000..7906fcee72e8ac408727ccbd3d9062ce5e62db1f
--- /dev/null
+++ b/4_spot_sorting/gtCorrectGeo.m
@@ -0,0 +1,474 @@
+% 
+% Gives geometrical correction for the rotation axis to detector distance,
+% and detector tilts according to data in a Spotpair or Calibration table.
+% Based on that, it also gives optimized values of the d-spacing, and the
+% theta angles. Plane-families to be used can be set, a minimum of two is 
+% necessary.
+% 
+%
+% e.g. gtCorrectGeo(1,'s5_dct89_calibration',0)
+%      gtCorrectGeo(0,'s5_dct89_spotpairs',[1 3 4]) 
+%   
+%
+% INPUT:    gtCorrectGeo(showresults,pairtable,which_ref)
+%
+%           showresults = if not 0, figures are displayed for feedback
+%           pairtable = name of table to be used
+%           which_ref = number of plane-family type to be used for optimization, e.g [1 2 4]
+%                       if 0, all types are used
+%
+%
+% OUTPUT:   [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas] 
+%
+%             tiltY = tilt around axis Y in Lab system (in degrees)
+%             tiltZ = tilt around axis Z in Lab system (in degrees)
+%             corr_rottodet_mm = correction for the rotation axis to
+%               detector distance in millimeters
+%             corr_rottodet_pix = correction for the rotation axis to
+%               detector distance in pixels    
+%               (precise value = measured + correction)
+%             opt_d = optimized d-spacing of the first reflecting
+%               plane-family
+%             [opt_thetas] = optimized theta angles
+%             
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+function [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas]=gtCorrectGeo(showresults,pairtable,which_ref)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% read PARAMETERS from .mat file
+tic
+
+%global parameters
+%if isempty(parameters)
+  load parameters.mat
+%end
+
+%parameters.acq.pixelsize=0.00137
+%parameters.acq.dist=2.865
+
+measured_rottodet_mm= parameters.acq.dist
+measured_rottodet_pix= parameters.acq.dist/parameters.acq.pixelsize
+
+rotx= parameters.acq.rotx
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = floor(parameters.acq.ydet/2) % at the geometrical center of the image
+
+table1=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+table2=[parameters.acq.difB_name 'difspot'] ; % difspot table B set
+%pairtable=parameters.acq.pair_tablename ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% SET inputs for calculation
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+
+reflections=gtGetSpaceGroupReflections(parameters.acq.spacegroup) 
+
+gtDBConnect ;
+
+nof_pairs= mym(sprintf('select count(*) from %s',pairtable)) 
+
+disp('Reading data from database...')
+
+%[th,eta,diftyp]=mym(sprintf('SELECT theta, eta, thetatype FROM %s',pairtable)) ;
+
+%[difAID,difBID,th,eta,diftyp]=mym(sprintf('SELECT difAID, difBID, theta, eta, thetatype FROM %s',pairtable)) ; 
+%
+%centXimA=zeros(nof_pairs,1) ;
+%centYimA=zeros(nof_pairs,1) ;
+%centXimB=zeros(nof_pairs,1) ;
+%centYimB=zeros(nof_pairs,1) ;
+%
+%for i=1:nof_pairs
+%  [centXimA(i),centYimA(i)]=mym(sprintf('SELECT CentroidX, CentroidY FROM %s WHERE difspotID=%d',table1,difAID(i))) ;
+%  [centXimB(i),centYimB(i)]=mym(sprintf('SELECT CentroidX, CentroidY FROM %s WHERE difspotID=%d',table2,difBID(i))) ;
+%end
+
+%[centXimA,centYimA]=mym(sprintf('SELECT %s. %s.CentroidX, %s.CentroidY FROM (%s INNER JOIN %s) INNER JOIN %s ON %s.difspotID=%s.difAID',...
+%  table1,table1,table1,pairtable,table1,pairtable)) ;
+%[centXimB,centYimB]=mym(sprintf('SELECT %s.CentroidX, %s.CentroidY FROM %s INNER JOIN %s ON %s.difspotID=%s.difBID',...
+%  table2,table2,table2,pairtable,table2,pairtable)) ;
+
+if which_ref == 0
+  %  [centXimA,centYimA,centXimB,centYimB,th,eta,om,diftyp]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, %s.CentroidX, %s.CentroidY, ' ...
+  %    '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID) INNER JOIN %s ON %s.difspotID=%s.difBID ' ...
+  %    ' WHERE %s.thetatype=4 ORDER BY %s.eta'], ...
+  %    table1,table1,table2,table2,pairtable,pairtable,pairtable,pairtable,table1,pairtable,table1,pairtable,table2,table2,pairtable,pairtable,pairtable)) ;
+  
+  [centXimA,centYimA,centXimB,centYimB,th,eta,om,diftyp]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, %s.CentroidX, %s.CentroidY, ' ...
+    '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID) INNER JOIN %s ON %s.difspotID=%s.difBID ' ...
+    ' ORDER BY %s.eta'], ...
+    table1,table1,table2,table2,pairtable,pairtable,pairtable,pairtable,table1,pairtable,table1,pairtable,table2,table2,pairtable,pairtable)) ;
+
+  % cent values read from the database are in Scintillator system;
+  % th,eta,om values are computed according to that (thus not optimized)
+  
+  %jj=1;
+  %while jj<=length(diftyp)
+  %  if isempty(find(keep==diftyp(jj)))
+  %    centXimA(jj)=[];
+  %    centYimA(jj)=[];
+  %    centXimB(jj)=[];
+  %    centYimB(jj)=[];
+  %    th(jj)=[];
+  %    eta(jj)=[];
+  %    om(jj)=[];
+  %    diftyp(jj)=[];
+  %  else
+  %    jj=jj+1;
+  %  end
+  %end
+      
+  
+else
+  centXimA= [] ;
+  centYimA= [] ;
+  centXimB= [] ;
+  centYimB= [] ;
+  th=       [] ;
+  eta=      [] ;
+  om=       [] ;
+  diftyp=   [] ;
+  for ii=1:length(which_ref)
+    [centXimA_r,centYimA_r,centXimB_r,centYimB_r,th_r,eta_r,om_r,diftyp_r]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, %s.CentroidX, %s.CentroidY, ' ...
+      '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID) INNER JOIN %s ON %s.difspotID=%s.difBID ' ...
+      'WHERE %s.thetatype=%d ORDER BY %s.eta'], ...
+      table1,table1,table2,table2,pairtable,pairtable,pairtable,pairtable,table1,pairtable,table1,pairtable,table2,table2,pairtable,pairtable,which_ref(ii),pairtable)) ;
+    centXimA= [centXimA; centXimA_r] ;
+    centYimA= [centYimA; centYimA_r] ;
+    centXimB= [centXimB; centXimB_r] ;
+    centYimB= [centYimB; centYimB_r] ;
+    th=       [th; th_r] ;
+    eta=      [eta; eta_r] ;
+    om=       [om; om_r] ;
+    diftyp=   [diftyp; diftyp_r] ;
+  end
+end
+
+[centXimA,centYimA]=gtTrImToSc(centXimA,centYimA);
+[centXimB,centYimB]=gtTrImToSc(centXimB,centYimB);
+
+disp('Processing data...')
+
+v=zeros(length(diftyp),1) ;
+
+for i=1:length(diftyp)
+  v(i)=1./norm(reflections(diftyp(i),:)) ;   % in angstroms
+end
+
+inp1=(centXimA+centXimB-2*rotx)*parameters.acq.pixelsize ; % in mm
+inp2=(centYimA+centYimB-2*sorZ)*parameters.acq.pixelsize ; % in mm
+inp3=(centYimA-centYimB)*parameters.acq.pixelsize ;        % in mm
+
+[opt,fval,exitflag]=fminsearch(@(var) sfPsiError(var,v,inp1,inp2,inp3),[0,0,measured_rottodet_mm],optimset('Display','iter'));
+
+if exitflag~=1
+  disp(' ')
+  disp('No optimized values for correction were found.')
+  disp(' ')
+  return
+end
+
+tiltY=opt(1) ; % alpha in degrees
+tiltZ=opt(2) ; % beta in degrees
+rottodet_mm=opt(3) ;
+
+rottodet_pix=rottodet_mm/parameters.acq.pixelsize ;
+corr_rottodet_pix=rottodet_pix-measured_rottodet_pix ;
+corr_rottodet_mm=corr_rottodet_pix*parameters.acq.pixelsize ;
+
+%% Calculation of optimized values
+
+th_op=gtThetaOfPairs(centXimA,centYimA,centXimB,centYimB,rottodet_pix,tiltY,tiltZ,rotx,sorZ);
+
+eta_op=gtEtaOfPairs(centXimA,centYimA,centXimB,centYimB,tiltY,tiltZ,rotx,sorZ);
+
+% Diffraction vector coordinates in Lab system
+%Dop1=2*rottodet_mm-sind(tiltZ)*inp1-sind(tiltY)*cosd(tiltZ)*inp2 ; 
+%Dop2=cosd(tiltZ)*inp1-sind(tiltY)*sind(tiltZ)*inp2 ;
+%Dop3=-cosd(tiltY)*(inp3) ;
+%th_op=0.5*acosd(Dop1./sqrt(Dop1.^2+Dop2.^2+Dop3.^2)); % vector of all measured thetas
+
+psi_op=v.*sind(th_op) ;
+std_psi_op=std(psi_op) ;
+
+d_op=lambda./(2.*psi_op) ;  % d-spacing
+std_d_op=std(d_op) ;
+opt_d=lambda/2/mean(psi_op) ;
+
+for i=1:size(reflections,1)
+  w(i)=1./norm(reflections(i,:)) ;   % plane geometry (in angstroms)
+end
+
+opt_thetas=asind(mean(psi_op)./w) ; % optimized diffraction angle for each plane family
+
+% optimized eta-s
+%for i=1:length(Dop2)
+%  if Dop2(i) >= 0  % 0 < eta < 180deg
+%    if Dop3(i) >= 0  % 0 < eta < 90deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i)) ;
+%    else  % 90deg < eta < 180deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+180 ;
+%    end
+%  else  % 180deg < eta < 360deg
+%    if Dop3(i) < 0  % 180deg < eta < 270deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+180 ;
+%    else  % 270deg < eta < 360deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+360 ;
+%    end
+%  end
+%end
+
+%% Calculation of original values for comparison as computed from the database
+
+psi_0=v.*sind(th) ;
+std_psi_0=std(psi_0) ;
+d_0=lambda./(2.*psi_0) ;  % original d-spacing
+std_d_0=std(d_0) ;
+
+for i=1:max(diftyp)
+  nof_thetatype(i)=0 ;
+  theta_0(i)=0 ; 
+  for j=1:length(diftyp)
+    if diftyp(j)==i
+      nof_thetatype(i)=nof_thetatype(i)+1;
+      theta_0(i)=theta_0(i)+th(j);
+    end
+  end
+  thetas_0(i)=theta_0(i)/nof_thetatype(i) ;
+end
+
+[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+valid_2thetas=results.centre ; % coloumn vector of all valid 2theta angles in degrees
+
+%% Display results
+
+mym('close')
+
+%tiltY=opt(1)*180/pi ; % alpha in degrees
+%tiltZ=opt(2)*180/pi ; % beta in degrees
+
+disp(' ')
+disp(' ')
+disp('Number of pairs used for correction:'), disp(length(diftyp)) ;
+disp('    Number of pairs per plane-family:'), disp(nof_thetatype);
+disp('Wavelength in angstroms:')
+disp(lambda)
+disp('Final value of the objective function:')
+disp(fval)
+disp('Standard deviation of original psi (lambda/2d):')
+disp(std_psi_0)
+disp('Standard deviation of optimized psi (lambda/2d):')
+disp(std_psi_op)
+disp('Standard deviation of the original d-spacing:')
+disp(std_d_0)
+disp('Standard deviation of the optimized d-spacing:')
+disp(std_d_op)
+disp('Optimized d-spacing of the first reflecting plane-family in angstroms:')
+disp(opt_d)
+disp('Diffraction angles computed from recorded energy and d-spacing in degrees')
+disp(valid_2thetas'/2)
+disp('Original diffraction angles from dataset in degrees:')
+disp(thetas_0)
+disp('Optimized diffraction angles in degrees:')
+disp(opt_thetas)
+disp('Rotation axis to detector distance as measured in mm-s:')
+disp(measured_rottodet_mm)
+disp('Rotation axis to detector distance optimized in mm-s:')
+disp(rottodet_mm)
+disp('Rotation axis to detector distance as measured in pixels:')
+disp(measured_rottodet_pix)
+disp('Rotation axis to detector distance optimized in pixels:')
+disp(rottodet_pix)
+disp('Rotation axis to detector distance optimized correction in mm-s:')
+disp(corr_rottodet_mm)
+disp('Rotation axis to detector distance optimized correction in pixels:')
+disp(corr_rottodet_pix)
+disp('Tilt around axis Y in lab system (in degrees):')
+disp(tiltY)
+disp('Tilt around axis Z in lab system (in degrees):')
+disp(tiltZ)
+disp(' ')
+toc
+disp(' ')
+
+
+if showresults~=0
+  close all;
+   
+  figure(9)
+  hist(th_op,length(diftyp)*4);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(th,nof_pairs*4) ;
+  xlabel('theta (deg)') ;
+  title('Histogram of original (blue) and optimized (green) thetas') ;
+
+  figure(8)
+  plot(th_op,eta_op,'.g','MarkerSize',6);
+  hold on ;
+  for i=1:length(opt_thetas)
+    if ~isempty(find(which_ref==i))
+      plot([opt_thetas(i) opt_thetas(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta OPTIMIZED') ;
+  
+  figure(7)
+  plot(th,eta,'.r','MarkerSize',6);
+  hold on ;
+  for i=1:length(thetas_0)
+    if ~isempty(find(which_ref==i))
+      plot([thetas_0(i) thetas_0(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta ORIGINAL') ;
+      
+  figure(6)
+  hist(d_op,length(diftyp)/8);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(d_0,nof_pairs/8) ;
+  xlabel('d-spacing (Angstroms)') ;
+  title('Histogram of original (blue) and optimized (green) d-spacings') ;
+  
+  figure(5)
+  plot(eta_op,d_op,'.g','MarkerSize',6);
+  hold on ;
+  plot([0 360],[opt_d opt_d],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('d (Angstroms)') ;
+  title('d - eta OPTIMIZED') ;
+
+  figure(4)
+  plot(eta,d_0,'.r','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(d_0) mean(d_0)],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('d (Angstroms)') ;
+  title('d - eta ORIGINAL') ;
+
+  figure(3);
+  hist(psi_op,length(diftyp)/8);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(psi_0,nof_pairs/8) ;
+  xlabel('psi') ;
+  title('Histogram of original (blue) and optimized (green) psi (=\lambda/2d)') ;
+   
+  figure(2)
+  plot(eta_op,psi_op,'.g','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(psi_op) mean(psi_op)],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('psi') ;
+  title('psi (=\lambda/2d)- eta OPTIMIZED') ;
+
+  figure(1)
+  plot(eta,psi_0,'.r','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(psi_0) mean(psi_0)],'k','LineWidth',1,'LineStyle','-.');
+  xlabel('eta (deg)') ;
+  ylabel('psi') ;
+  title('psi (=\lambda/2d) - eta ORIGINAL') ;
+  
+  %keyboard
+end % of show results
+  
+end % of function
+
+
+%% Sub-functions in use
+
+function [psi_error]=sfPsiError(var,v,inp1,inp2,inp3)
+  %input vectors:
+  %  var(1)= alpha
+  %  var(2)= beta
+  %  var(3)= r, rotation axis to detector distance (same unit as inp-s)
+  %  inp1= centXimA+centXimB-2*rotx 
+  %  inp2= centYimA+centYimB-2*sorZ 
+  %  inp3= centYimA-centYimB 
+
+  Dopt1=2*var(3)-sind(var(2))*inp1-sind(var(1))*cosd(var(2))*inp2 ;
+  Dopt2=cosd(var(2))*inp1-sind(var(1))*sind(var(2))*inp2 ;
+  Dopt3=-cosd(var(1))*(inp3) ;
+
+  %th=0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2)) ;
+  psi=v.*sind(0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2))) ;
+  
+  mean_psi=mean(psi) ;
+  %psi_error=std(psi) ;
+  psi_error=sum((psi-mean_psi).^2) ;
+end
+
+%% Sub-functions not in use
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
+
diff --git a/4_spot_sorting/gtCorrectGeo_test.m b/4_spot_sorting/gtCorrectGeo_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..7b1cb4ebd7191891b3b6f5efee19363966c0c8cf
--- /dev/null
+++ b/4_spot_sorting/gtCorrectGeo_test.m
@@ -0,0 +1,397 @@
+% 
+% Gives geometrical correction for the rotation axis to detector distance,
+% and detector tilts according to data in a Spotpair or Calibration table.
+% Based on that, it also gives optimized values of the d-spacing, and the
+% theta angles. Plane-families to be used can be set, a minimum of two is 
+% necessary.
+% 
+%
+% e.g. gtCorrectGeo(1,'s5_dct89_calibration',0)
+%      gtCorrectGeo(0,'s5_dct89_spotpairs',[1 3 4]) 
+%   
+%
+% INPUT:    gtCorrectGeo_v2c(showresults,pairtable,which_ref)
+%
+%           showresults = if not 0, figures are displayed for feedback
+%           pairtable = name of table to be used
+%           which_ref = number of plane-family type to be used for optimization, e.g [1 2 4]
+%                       if 0, all types are used
+%
+%
+% OUTPUT:   [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas] 
+%
+%             tiltY = tilt around axis Y in Lab system (in degrees)
+%             tiltZ = tilt around axis Z in Lab system (in degrees)
+%             corr_rottodet_mm = correction for the rotation axis to
+%               detector distance in millimeters
+%             corr_rottodet_pix = correction for the rotation axis to
+%               detector distance in pixels    
+%               (precise value = measured + correction)
+%             opt_d = optimized d-spacing of the first reflecting
+%               plane-family
+%             [opt_thetas] = optimized theta angles
+%             
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+function [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas]=gtCorrectGeo_test(showresults,which_ref,tY,tZ,parameters)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% read PARAMETERS from .mat file
+tic
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+if ~exist('which_ref','var')
+  which_ref=[];
+end
+
+measured_rottodet_mm= parameters.acq.dist
+measured_rottodet_pix= parameters.acq.dist/parameters.acq.pixelsize
+
+rotx= parameters.acq.rotx
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = floor(parameters.acq.ydet/2) % at the geometrical center of the image
+
+difspottable=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+
+pairtable=parameters.acq.pair_tablename ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% SET inputs for calculation
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+
+[tmp,results]=gtnew_calculate_twotheta;
+reflections=results.reflections; % type of reflections
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
+close all
+cent0X=1024.5;
+cent0Y=1024.5;
+sorZ=cent0Y;
+
+eta=(1:360)';
+th=ones(size(eta))*6;
+om=zeros(size(eta));
+
+r0=500;
+
+
+centXimA=cent0X+sind(eta)*r0;
+centYimA=cent0Y-cosd(eta)*r0;
+centXimB=cent0X+sind(eta)*r0;
+centYimB=cent0Y+cosd(eta)*r0;
+
+
+% effect of tiltY on data
+centXimA=cent0X+sind(eta)*r0;
+centYimA=cent0Y-cosd(eta)*r0*1.1; % plus offset
+
+% effect of tiltZ on data
+centXimB=cent0X+sind(eta)*r0;
+centYimB=cent0Y+cosd(eta)*r0*1.1;
+
+diftyp=ones(size(centXimA));
+
+
+
+eta2=(1:360)';
+th2=ones(size(eta2))*6;
+om2=zeros(size(eta2));
+
+r0=600;
+centXimA2=cent0X+sind(eta2)*r0;
+%centXimA2=cent0X+sind(eta2)*r0*1.1;
+centYimA2=cent0Y-cosd(eta2)*r0;
+
+centXimB2=cent0X+sind(eta2)*r0;
+%centXimB2=cent0X+sind(eta2)*r0*1.1;
+centYimB2=cent0Y+cosd(eta2)*r0;
+
+diftyp2=ones(size(centXimA2))*2;
+
+
+eta=[eta; eta2];
+th=[th; th2];
+om=[om; om2];
+
+centXimA=[centXimA; centXimA2];
+centYimA=[centYimA; centYimA2];
+centXimB=[centXimB; centXimB2];
+centYimB=[centYimB; centYimB2];
+diftyp=[diftyp; diftyp2];
+
+
+
+% 
+% figure
+% plot(centXimA,centYimA,'b.')
+% set(gca,'YDir','rev')
+% 
+% figure
+% plot(centXimB,centYimB,'g.')
+% set(gca,'YDir','rev')
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+disp('Processing data...')
+
+v=zeros(size(diftyp)) ;
+
+for i=1:length(diftyp)
+  v(i)=1./norm(reflections(diftyp(i),:)) ;   % in angstroms
+end
+
+inp1=(centXimA+centXimB-2*rotx)*parameters.acq.pixelsize ; % in mm
+inp2=(centYimA+centYimB-2*sorZ)*parameters.acq.pixelsize ; % in mm
+inp3=(centYimA-centYimB)*parameters.acq.pixelsize ;        % in mm
+
+%[opt,fval,exitflag]=fminsearch(@(var) sfPsiError(var,v,inp1,inp2,inp3),[0,0,measured_rottodet_mm],optimset('Display','iter'));
+
+
+
+
+
+
+
+%% trying %%%%%%%%%%%%%%%%
+fval=0;
+
+tiltY=tY ; % alpha in degrees
+tiltZ=tZ; % beta in degrees
+rottodet_mm=measured_rottodet_mm;
+%%%%%%%%%%%%%%%%
+
+
+
+
+
+
+rottodet_pix=rottodet_mm/parameters.acq.pixelsize ;
+corr_rottodet_pix=rottodet_pix-measured_rottodet_pix ;
+corr_rottodet_mm=corr_rottodet_pix*parameters.acq.pixelsize ;
+
+%% Calculation of optimized values
+
+th_op=gtThetaOfPairs(centXimA,centYimA,centXimB,centYimB,rottodet_pix,tiltY,tiltZ,rotx,sorZ);
+
+eta_op=gtEtaOfPairs(centXimA,centYimA,centXimB,centYimB,tiltY,tiltZ,rotx,sorZ);
+
+% Diffraction vector coordinates in Lab system
+%Dop1=2*rottodet_mm-sind(tiltZ)*inp1-sind(tiltY)*cosd(tiltZ)*inp2 ; 
+%Dop2=cosd(tiltZ)*inp1-sind(tiltY)*sind(tiltZ)*inp2 ;
+%Dop3=-cosd(tiltY)*(inp3) ;
+%th_op=0.5*acosd(Dop1./sqrt(Dop1.^2+Dop2.^2+Dop3.^2)); % vector of all measured thetas
+
+psi_op=v.*sind(th_op) ;
+std_psi_op=std(psi_op) ;
+
+d_op=lambda./(2.*psi_op) ;  % d-spacing
+std_d_op=std(d_op) ;
+opt_d=lambda/2/mean(psi_op) ;
+
+for i=1:size(reflections,1)
+  w(i)=1./norm(reflections(i,:)) ;   % plane geometry (in angstroms)
+end
+
+opt_thetas=asind(mean(psi_op)./w) ; % optimized diffraction angle for each plane family
+
+
+%% Calculation of original values for comparison as computed from the database
+
+psi_0=v.*sind(th) ;
+std_psi_0=std(psi_0) ;
+d_0=lambda./(2.*psi_0) ;  % original d-spacing
+std_d_0=std(d_0) ;
+
+for i=1:max(diftyp)
+  nof_thetatype(i)=0 ;
+  theta_0(i)=0 ; 
+  for j=1:length(diftyp)
+    if diftyp(j)==i
+      nof_thetatype(i)=nof_thetatype(i)+1;
+      theta_0(i)=theta_0(i)+th(j);
+    end
+  end
+  thetas_0(i)=theta_0(i)/nof_thetatype(i) ;
+end
+
+%[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+[tmp,results]=gtnew_calculate_twotheta ;
+valid_2thetas=results.centre ; % coloumn vector of all valid 2theta angles in degrees
+
+%% Display results
+
+disp(' ')
+disp(' ')
+disp('Number of pairs used for correction:'), disp(length(diftyp)) ;
+disp('    Number of pairs per plane-family:'), disp(nof_thetatype);
+disp('Wavelength in angstroms:')
+disp(lambda)
+disp('Final value of the objective function:')
+disp(fval)
+disp('Standard deviation of original psi (lambda/2d):')
+disp(std_psi_0)
+disp('Standard deviation of optimized psi (lambda/2d):')
+disp(std_psi_op)
+disp('Standard deviation of the original d-spacing:')
+disp(std_d_0)
+disp('Standard deviation of the optimized d-spacing:')
+disp(std_d_op)
+disp('Optimized d-spacing of the first reflecting plane-family in angstroms:')
+disp(opt_d)
+disp('Diffraction angles computed from recorded energy and d-spacing in degrees')
+disp(valid_2thetas'/2)
+disp('Original diffraction angles from dataset in degrees:')
+disp(thetas_0)
+disp('Optimized diffraction angles in degrees:')
+disp(opt_thetas)
+disp('Rotation axis to detector distance as measured in mm-s:')
+disp(measured_rottodet_mm)
+disp('Rotation axis to detector distance optimized in mm-s:')
+disp(rottodet_mm)
+disp('Rotation axis to detector distance as measured in pixels:')
+disp(measured_rottodet_pix)
+disp('Rotation axis to detector distance optimized in pixels:')
+disp(rottodet_pix)
+disp('Rotation axis to detector distance optimized correction in mm-s:')
+disp(corr_rottodet_mm)
+disp('Rotation axis to detector distance optimized correction in pixels:')
+disp(corr_rottodet_pix)
+disp('Tilt around axis Y in lab system (in degrees):')
+disp(tiltY)
+disp('Tilt around axis Z in lab system (in degrees):')
+disp(tiltZ)
+disp(' ')
+toc
+disp(' ')
+
+
+if showresults~=0
+  
+   
+%   figure(9)
+%   hist(th_op,length(diftyp)*4);
+%   h = findobj(gca,'Type','patch');
+%   set(h,'FaceColor','g','EdgeColor','g')
+%   hold on ;
+%   hist(th,nof_pairs*4) ;
+%   xlabel('theta (deg)') ;
+%   title('Histogram of original (blue) and optimized (green) thetas') ;
+
+  opt_thetas=[2.96692308492953 3.55473467862958];
+
+  figure(8)
+  plot(th_op,eta_op,'.g','MarkerSize',6);
+  hold on ;
+  for i=1:length(opt_thetas)
+    if ~isempty(find(which_ref==i))
+      plot([opt_thetas(i) opt_thetas(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta OPTIMIZED') ;
+  
+%   figure(7)
+%   plot(th,eta,'.r','MarkerSize',6);
+%   hold on ;
+%   for i=1:length(thetas_0)
+%     if ~isempty(find(which_ref==i))
+%       plot([thetas_0(i) thetas_0(i)],[0 360],'-.k','LineWidth',1);
+%     end
+%   end
+%   xlabel('theta (deg)') ;
+%   ylabel('eta (deg)') ;
+%   title('theta - eta ORIGINAL') ;
+      
+%   figure(6)
+%   hist(d_op,length(diftyp)/8);
+%   h = findobj(gca,'Type','patch');
+%   set(h,'FaceColor','g','EdgeColor','g')
+%   hold on ;
+%   hist(d_0,nof_pairs/8) ;
+%   xlabel('d-spacing (Angstroms)') ;
+%   title('Histogram of original (blue) and optimized (green) d-spacings') ;
+%   
+%   figure(5)
+%   plot(eta_op,d_op,'.g','MarkerSize',6);
+%   hold on ;
+%   plot([0 360],[opt_d opt_d],'-.k','LineWidth',1);
+%   xlabel('eta (deg)') ;
+%   ylabel('d (Angstroms)') ;
+%   title('d - eta OPTIMIZED') ;
+% 
+%   figure(4)
+%   plot(eta,d_0,'.r','MarkerSize',6);
+%   hold on ;
+%   plot([0 360],[mean(d_0) mean(d_0)],'-.k','LineWidth',1);
+%   xlabel('eta (deg)') ;
+%   ylabel('d (Angstroms)') ;
+%   title('d - eta ORIGINAL') ;
+% 
+%   figure(3);
+%   hist(psi_op,length(diftyp)/8);
+%   h = findobj(gca,'Type','patch');
+%   set(h,'FaceColor','g','EdgeColor','g')
+%   hold on ;
+%   hist(psi_0,nof_pairs/8) ;
+%   xlabel('psi') ;
+%   title('Histogram of original (blue) and optimized (green) psi (=\lambda/2d)') ;
+%    
+%   figure(2)
+%   plot(eta_op,psi_op,'.g','MarkerSize',6);
+%   hold on ;
+%   plot([0 360],[mean(psi_op) mean(psi_op)],'-.k','LineWidth',1);
+%   xlabel('eta (deg)') ;
+%   ylabel('psi') ;
+%   title('psi (=\lambda/2d)- eta OPTIMIZED') ;
+% 
+%   figure(1)
+%   plot(eta,psi_0,'.r','MarkerSize',6);
+%   hold on ;
+%   plot([0 360],[mean(psi_0) mean(psi_0)],'k','LineWidth',1,'LineStyle','-.');
+%   xlabel('eta (deg)') ;
+%   ylabel('psi') ;
+%   title('psi (=\lambda/2d) - eta ORIGINAL') ;
+  
+  %keyboard
+end % of show results
+  
+end % of function
+
+
+%% Sub-functions in use
+
+function [psi_error]=sfPsiError(var,v,tiltZ,rottodet,inp1,inp2,inp3)
+  %input vectors:
+  %  var(1)= alpha
+  %  var(2)= beta
+  %  var(3)= r, rotation axis to detector distance (same unit as inp-s)
+  %  inp1= centXimA+centXimB-2*rotx 
+  %  inp2= centYimA+centYimB-2*sorZ 
+  %  inp3= centYimA-centYimB 
+
+  Dopt1=2*var(3)-sind(var(2))*inp1-sind(var(1))*cosd(var(2))*inp2 ;
+  Dopt2=cosd(var(2))*inp1-sind(var(1))*sind(var(2))*inp2 ;
+  Dopt3=-cosd(var(1))*(inp3) ;
+
+  %th=0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2)) ;
+  psi=v.*sind(0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2))) ;
+  
+  mean_psi=mean(psi) ;
+  %psi_error=std(psi) ;
+  psi_error=sum((psi-mean_psi).^2) ;
+end
+
diff --git a/4_spot_sorting/gtCorrectGeo_v2c.m b/4_spot_sorting/gtCorrectGeo_v2c.m
new file mode 100755
index 0000000000000000000000000000000000000000..b98a48f9f9fabd6421b190db9fbd34603a951207
--- /dev/null
+++ b/4_spot_sorting/gtCorrectGeo_v2c.m
@@ -0,0 +1,516 @@
+% 
+% Gives geometrical correction for the rotation axis to detector distance,
+% and detector tilts according to data in a Spotpair or Calibration table.
+% Based on that, it also gives optimized values of the d-spacing, and the
+% theta angles. Plane-families to be used can be set, a minimum of two is 
+% necessary.
+% 
+%
+% e.g. gtCorrectGeo(1,'s5_dct89_calibration',0)
+%      gtCorrectGeo(0,'s5_dct89_spotpairs',[1 3 4]) 
+%   
+%
+% INPUT:    gtCorrectGeo_v2c(showresults,pairtable,which_ref)
+%
+%           showresults = if not 0, figures are displayed for feedback
+%           pairtable = name of table to be used
+%           which_ref = number of plane-family type to be used for optimization, e.g [1 2 4]
+%                       if 0, all types are used
+%
+%
+% OUTPUT:   [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas] 
+%
+%             tiltY = tilt around axis Y in Lab system (in degrees)
+%             tiltZ = tilt around axis Z in Lab system (in degrees)
+%             corr_rottodet_mm = correction for the rotation axis to
+%               detector distance in millimeters
+%             corr_rottodet_pix = correction for the rotation axis to
+%               detector distance in pixels    
+%               (precise value = measured + correction)
+%             opt_d = optimized d-spacing of the first reflecting
+%               plane-family
+%             [opt_thetas] = optimized theta angles
+%             
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+function [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas]=gtCorrectGeo_v2c(showresults,which_ref,parameters)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% read PARAMETERS from .mat file
+tic
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+%parameters.acq.pixelsize=0.00137
+%parameters.acq.dist=2.865
+
+measured_rottodet_mm= parameters.acq.dist
+measured_rottodet_pix= parameters.acq.dist/parameters.acq.pixelsize
+
+rotx= parameters.acq.rotx
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = floor(parameters.acq.ydet/2) % at the geometrical center of the image
+
+% table1=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+% table2=[parameters.acq.difB_name 'difspot'] ; % difspot table B set
+difspottable=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+
+pairtable=parameters.acq.pair_tablename ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% SET inputs for calculation
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+
+[tmp,results]=gtnew_calculate_twotheta;
+reflections=results.reflections; % type of reflections
+
+
+%reflections=gtGetSpaceGroupReflections(parameters.acq.spacegroup) 
+
+gtDBConnect ;
+
+nof_pairs= mym(sprintf('select count(*) from %s',pairtable)) 
+
+disp('Reading data from database...')
+
+%[th,eta,diftyp]=mym(sprintf('SELECT theta, eta, thetatype FROM %s',pairtable)) ;
+
+%[difAID,difBID,th,eta,diftyp]=mym(sprintf('SELECT difAID, difBID, theta, eta, thetatype FROM %s',pairtable)) ; 
+%
+%centXimA=zeros(nof_pairs,1) ;
+%centYimA=zeros(nof_pairs,1) ;
+%centXimB=zeros(nof_pairs,1) ;
+%centYimB=zeros(nof_pairs,1) ;
+%
+%for i=1:nof_pairs
+%  [centXimA(i),centYimA(i)]=mym(sprintf('SELECT CentroidX, CentroidY FROM %s WHERE difspotID=%d',table1,difAID(i))) ;
+%  [centXimB(i),centYimB(i)]=mym(sprintf('SELECT CentroidX, CentroidY FROM %s WHERE difspotID=%d',table2,difBID(i))) ;
+%end
+
+%[centXimA,centYimA]=mym(sprintf('SELECT %s. %s.CentroidX, %s.CentroidY FROM (%s INNER JOIN %s) INNER JOIN %s ON %s.difspotID=%s.difAID',...
+%  table1,table1,table1,pairtable,table1,pairtable)) ;
+%[centXimB,centYimB]=mym(sprintf('SELECT %s.CentroidX, %s.CentroidY FROM %s INNER JOIN %s ON %s.difspotID=%s.difBID',...
+%  table2,table2,table2,pairtable,table2,pairtable)) ;
+
+if which_ref == 0
+  %  [centXimA,centYimA,centXimB,centYimB,th,eta,om,diftyp]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, %s.CentroidX, %s.CentroidY, ' ...
+  %    '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID) INNER JOIN %s ON %s.difspotID=%s.difBID ' ...
+  %    ' WHERE %s.thetatype=4 ORDER BY %s.eta'], ...
+  %    table1,table1,table2,table2,pairtable,pairtable,pairtable,pairtable,table1,pairtable,table1,pairtable,table2,table2,pairtable,pairtable,pairtable)) ;
+  
+%   [centXimA,centYimA,centXimB,centYimB,th,eta,om,diftyp]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, %s.CentroidX, %s.CentroidY, ' ...
+%     '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID) INNER JOIN %s ON %s.difspotID=%s.difBID ' ...
+%     ' ORDER BY %s.eta'], ...
+%     table1,table1,table2,table2,pairtable,pairtable,pairtable,pairtable,table1,pairtable,table1,pairtable,table2,table2,pairtable,pairtable)) ;
+
+  
+
+% FROM (difspot INNER JOIN spotpairs ON difspot.difspotID=spotpairs.difAID) INNER JOIN difspot ON difspot.difspotID=spotpairs.difBID
+  
+  [centXimA,centYimA,th,eta,om,diftyp]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, ' ...
+    '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID)' ...
+    ' ORDER BY %s.pairID'], ...
+    difspottable,difspottable,pairtable,pairtable,pairtable,pairtable,difspottable,...
+    pairtable,difspottable,pairtable,pairtable)) ;
+
+
+  [centXimB,centYimB]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY ' ...
+    'FROM (%s INNER JOIN %s ON %s.difspotID=%s.difBID)' ...
+    ' ORDER BY %s.pairID'], ...
+    difspottable,difspottable,difspottable,...
+    pairtable,difspottable,pairtable,pairtable)) ;
+  
+  
+  
+  
+  
+  % cent values read from the database are in Scintillator system;
+  % th,eta,om values are computed according to that (thus not optimized)
+  
+  %jj=1;
+  %while jj<=length(diftyp)
+  %  if isempty(find(keep==diftyp(jj)))
+  %    centXimA(jj)=[];
+  %    centYimA(jj)=[];
+  %    centXimB(jj)=[];
+  %    centYimB(jj)=[];
+  %    th(jj)=[];
+  %    eta(jj)=[];
+  %    om(jj)=[];
+  %    diftyp(jj)=[];
+  %  else
+  %    jj=jj+1;
+  %  end
+  %end
+      
+  
+else
+  centXimA= [] ;
+  centYimA= [] ;
+  centXimB= [] ;
+  centYimB= [] ;
+  th=       [] ;
+  eta=      [] ;
+  om=       [] ;
+  diftyp=   [] ;
+  for ii=1:length(which_ref)
+
+    [centXimA_r,centYimA_r,th_r,eta_r,om_r,diftyp_r]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, ' ...
+      '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID)' ...
+      ' WHERE %s.thetatype=%d ORDER BY %s.pairID'], ...
+      difspottable,difspottable,pairtable,pairtable,pairtable,pairtable,difspottable,...
+      pairtable,difspottable,pairtable,pairtable,which_ref(ii),pairtable)) ;
+    
+    
+    [centXimB_r,centYimB_r]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY ' ...
+      ' FROM (%s INNER JOIN %s ON %s.difspotID=%s.difBID)' ...
+      ' WHERE %s.thetatype=%d ORDER BY %s.pairID'], ...
+      difspottable,difspottable,difspottable,...
+      pairtable,difspottable,pairtable,pairtable,which_ref(ii),pairtable)) ;
+
+%     [centXimA_r,centYimA_r,centXimB_r,centYimB_r,th_r,eta_r,om_r,diftyp_r]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, %s.CentroidX, %s.CentroidY, ' ...
+%       '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID) INNER JOIN %s ON %s.difspotID=%s.difBID ' ...
+%       'WHERE %s.thetatype=%d ORDER BY %s.eta'], ...
+%       table1,table1,table2,table2,pairtable,pairtable,pairtable,pairtable,table1,pairtable,table1,pairtable,table2,table2,pairtable,pairtable,which_ref(ii),pairtable)) ;
+    
+    centXimA= [centXimA; centXimA_r] ;
+    centYimA= [centYimA; centYimA_r] ;
+    centXimB= [centXimB; centXimB_r] ;
+    centYimB= [centYimB; centYimB_r] ;
+    th=       [th; th_r] ;
+    eta=      [eta; eta_r] ;
+    om=       [om; om_r] ;
+    diftyp=   [diftyp; diftyp_r] ;
+  end
+end
+
+[centXimA,centYimA]=gtTrImToSc(centXimA,centYimA);
+[centXimB,centYimB]=gtTrImToSc(centXimB,centYimB);
+
+disp('Processing data...')
+
+v=zeros(length(diftyp),1) ;
+
+for i=1:length(diftyp)
+  v(i)=1./norm(reflections(diftyp(i),:)) ;   % in angstroms
+end
+
+inp1=(centXimA+centXimB-2*rotx)*parameters.acq.pixelsize ; % in mm
+inp2=(centYimA+centYimB-2*sorZ)*parameters.acq.pixelsize ; % in mm
+inp3=(centYimA-centYimB)*parameters.acq.pixelsize ;        % in mm
+
+[opt,fval,exitflag]=fminsearch(@(var) sfPsiError(var,v,inp1,inp2,inp3),[0,0,measured_rottodet_mm],optimset('Display','iter'));
+
+if exitflag~=1
+  disp(' ')
+  disp('No optimized values for correction were found.')
+  disp(' ')
+  return
+end
+
+tiltY=opt(1) ; % alpha in degrees
+tiltZ=opt(2) ; % beta in degrees
+rottodet_mm=opt(3) ;
+
+rottodet_pix=rottodet_mm/parameters.acq.pixelsize ;
+corr_rottodet_pix=rottodet_pix-measured_rottodet_pix ;
+corr_rottodet_mm=corr_rottodet_pix*parameters.acq.pixelsize ;
+
+%% Calculation of optimized values
+
+th_op=gtThetaOfPairs(centXimA,centYimA,centXimB,centYimB,rottodet_pix,tiltY,tiltZ,rotx,sorZ);
+
+eta_op=gtEtaOfPairs(centXimA,centYimA,centXimB,centYimB,tiltY,tiltZ,rotx,sorZ);
+
+% Diffraction vector coordinates in Lab system
+%Dop1=2*rottodet_mm-sind(tiltZ)*inp1-sind(tiltY)*cosd(tiltZ)*inp2 ; 
+%Dop2=cosd(tiltZ)*inp1-sind(tiltY)*sind(tiltZ)*inp2 ;
+%Dop3=-cosd(tiltY)*(inp3) ;
+%th_op=0.5*acosd(Dop1./sqrt(Dop1.^2+Dop2.^2+Dop3.^2)); % vector of all measured thetas
+
+psi_op=v.*sind(th_op) ;
+std_psi_op=std(psi_op) ;
+
+d_op=lambda./(2.*psi_op) ;  % d-spacing
+std_d_op=std(d_op) ;
+opt_d=lambda/2/mean(psi_op) ;
+
+for i=1:size(reflections,1)
+  w(i)=1./norm(reflections(i,:)) ;   % plane geometry (in angstroms)
+end
+
+opt_thetas=asind(mean(psi_op)./w) ; % optimized diffraction angle for each plane family
+
+% optimized eta-s
+%for i=1:length(Dop2)
+%  if Dop2(i) >= 0  % 0 < eta < 180deg
+%    if Dop3(i) >= 0  % 0 < eta < 90deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i)) ;
+%    else  % 90deg < eta < 180deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+180 ;
+%    end
+%  else  % 180deg < eta < 360deg
+%    if Dop3(i) < 0  % 180deg < eta < 270deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+180 ;
+%    else  % 270deg < eta < 360deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+360 ;
+%    end
+%  end
+%end
+
+%% Calculation of original values for comparison as computed from the database
+
+psi_0=v.*sind(th) ;
+std_psi_0=std(psi_0) ;
+d_0=lambda./(2.*psi_0) ;  % original d-spacing
+std_d_0=std(d_0) ;
+
+for i=1:max(diftyp)
+  nof_thetatype(i)=0 ;
+  theta_0(i)=0 ; 
+  for j=1:length(diftyp)
+    if diftyp(j)==i
+      nof_thetatype(i)=nof_thetatype(i)+1;
+      theta_0(i)=theta_0(i)+th(j);
+    end
+  end
+  thetas_0(i)=theta_0(i)/nof_thetatype(i) ;
+end
+
+%[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+[tmp,results]=gtnew_calculate_twotheta ;
+valid_2thetas=results.centre ; % coloumn vector of all valid 2theta angles in degrees
+
+%% Display results
+
+mym('close')
+
+%tiltY=opt(1)*180/pi ; % alpha in degrees
+%tiltZ=opt(2)*180/pi ; % beta in degrees
+
+disp(' ')
+disp(' ')
+disp('Number of pairs used for correction:'), disp(length(diftyp)) ;
+disp('    Number of pairs per plane-family:'), disp(nof_thetatype);
+disp('Wavelength in angstroms:')
+disp(lambda)
+disp('Final value of the objective function:')
+disp(fval)
+disp('Standard deviation of original psi (lambda/2d):')
+disp(std_psi_0)
+disp('Standard deviation of optimized psi (lambda/2d):')
+disp(std_psi_op)
+disp('Standard deviation of the original d-spacing:')
+disp(std_d_0)
+disp('Standard deviation of the optimized d-spacing:')
+disp(std_d_op)
+disp('Optimized d-spacing of the first reflecting plane-family in angstroms:')
+disp(opt_d)
+disp('Diffraction angles computed from recorded energy and d-spacing in degrees')
+disp(valid_2thetas'/2)
+disp('Original diffraction angles from dataset in degrees:')
+disp(thetas_0)
+disp('Optimized diffraction angles in degrees:')
+disp(opt_thetas)
+disp('Rotation axis to detector distance as measured in mm-s:')
+disp(measured_rottodet_mm)
+disp('Rotation axis to detector distance optimized in mm-s:')
+disp(rottodet_mm)
+disp('Rotation axis to detector distance as measured in pixels:')
+disp(measured_rottodet_pix)
+disp('Rotation axis to detector distance optimized in pixels:')
+disp(rottodet_pix)
+disp('Rotation axis to detector distance optimized correction in mm-s:')
+disp(corr_rottodet_mm)
+disp('Rotation axis to detector distance optimized correction in pixels:')
+disp(corr_rottodet_pix)
+disp('Tilt around axis Y in lab system (in degrees):')
+disp(tiltY)
+disp('Tilt around axis Z in lab system (in degrees):')
+disp(tiltZ)
+disp(' ')
+toc
+disp(' ')
+
+
+if showresults~=0
+  close all;
+   
+  figure(9)
+  hist(th_op,length(diftyp)*4);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(th,nof_pairs*4) ;
+  xlabel('theta (deg)') ;
+  title('Histogram of original (blue) and optimized (green) thetas') ;
+
+  figure(8)
+  plot(th_op,eta_op,'.g','MarkerSize',6);
+  hold on ;
+  for i=1:length(opt_thetas)
+    if ~isempty(find(which_ref==i))
+      plot([opt_thetas(i) opt_thetas(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta OPTIMIZED') ;
+  
+  figure(7)
+  plot(th,eta,'.r','MarkerSize',6);
+  hold on ;
+  for i=1:length(thetas_0)
+    if ~isempty(find(which_ref==i))
+      plot([thetas_0(i) thetas_0(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta ORIGINAL') ;
+      
+  figure(6)
+  hist(d_op,length(diftyp)/8);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(d_0,nof_pairs/8) ;
+  xlabel('d-spacing (Angstroms)') ;
+  title('Histogram of original (blue) and optimized (green) d-spacings') ;
+  
+  figure(5)
+  plot(eta_op,d_op,'.g','MarkerSize',6);
+  hold on ;
+  plot([0 360],[opt_d opt_d],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('d (Angstroms)') ;
+  title('d - eta OPTIMIZED') ;
+
+  figure(4)
+  plot(eta,d_0,'.r','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(d_0) mean(d_0)],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('d (Angstroms)') ;
+  title('d - eta ORIGINAL') ;
+
+  figure(3);
+  hist(psi_op,length(diftyp)/8);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(psi_0,nof_pairs/8) ;
+  xlabel('psi') ;
+  title('Histogram of original (blue) and optimized (green) psi (=\lambda/2d)') ;
+   
+  figure(2)
+  plot(eta_op,psi_op,'.g','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(psi_op) mean(psi_op)],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('psi') ;
+  title('psi (=\lambda/2d)- eta OPTIMIZED') ;
+
+  figure(1)
+  plot(eta,psi_0,'.r','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(psi_0) mean(psi_0)],'k','LineWidth',1,'LineStyle','-.');
+  xlabel('eta (deg)') ;
+  ylabel('psi') ;
+  title('psi (=\lambda/2d) - eta ORIGINAL') ;
+  
+  %keyboard
+end % of show results
+  
+end % of function
+
+
+%% Sub-functions in use
+
+function [psi_error]=sfPsiError(var,v,inp1,inp2,inp3)
+  %input vectors:
+  %  var(1)= alpha
+  %  var(2)= beta
+  %  var(3)= r, rotation axis to detector distance (same unit as inp-s)
+  %  inp1= centXimA+centXimB-2*rotx 
+  %  inp2= centYimA+centYimB-2*sorZ 
+  %  inp3= centYimA-centYimB 
+
+  Dopt1=2*var(3)-sind(var(2))*inp1-sind(var(1))*cosd(var(2))*inp2 ;
+  Dopt2=cosd(var(2))*inp1-sind(var(1))*sind(var(2))*inp2 ;
+  Dopt3=-cosd(var(1))*(inp3) ;
+
+  %th=0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2)) ;
+  psi=v.*sind(0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2))) ;
+  
+  mean_psi=mean(psi) ;
+  %psi_error=std(psi) ;
+  psi_error=sum((psi-mean_psi).^2) ;
+end
+
+%% Sub-functions not in use
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
+
diff --git a/4_spot_sorting/gtCorrectGeo_v2f.m b/4_spot_sorting/gtCorrectGeo_v2f.m
new file mode 100755
index 0000000000000000000000000000000000000000..be28226ac52e98114b4a4bc151117305259419d0
--- /dev/null
+++ b/4_spot_sorting/gtCorrectGeo_v2f.m
@@ -0,0 +1,466 @@
+% 
+% Gives geometrical correction for the rotation axis to detector distance,
+% and detector tilts according to data in a Spotpair or Calibration table.
+% Based on that, it also gives optimized values of the d-spacing, and the
+% theta angles. Plane-families to be used can be set, a minimum of two is 
+% necessary.
+% 
+%
+% e.g. gtCorrectGeo(1,'s5_dct89_calibration',0)
+%      gtCorrectGeo(0,'s5_dct89_spotpairs',[1 3 4]) 
+%   
+%
+% INPUT:    gtCorrectGeo_v2c(showresults,pairtable,which_ref)
+%
+%           showresults = if not 0, figures are displayed for feedback
+%           pairtable = name of table to be used
+%           which_ref = number of plane-family type to be used for optimization, e.g [1 2 4]
+%                       if 0, all types are used
+%
+%
+% OUTPUT:   [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas] 
+%
+%             tiltY = tilt around axis Y in Lab system (in degrees)
+%             tiltZ = tilt around axis Z in Lab system (in degrees)
+%             corr_rottodet_mm = correction for the rotation axis to
+%               detector distance in millimeters
+%             corr_rottodet_pix = correction for the rotation axis to
+%               detector distance in pixels    
+%               (precise value = measured + correction)
+%             opt_d = optimized d-spacing of the first reflecting
+%               plane-family
+%             [opt_thetas] = optimized theta angles
+%             
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+function [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas]=gtCorrectGeo_v2f(showresults,which_ref,parameters)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% read PARAMETERS from .mat file
+tic
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+if ~exist('which_ref','var')
+  which_ref=[];
+end
+
+
+%parameters.acq.pixelsize=0.00137
+%parameters.acq.dist=2.865
+
+measured_rottodet_mm= parameters.acq.dist
+measured_rottodet_pix= parameters.acq.dist/parameters.acq.pixelsize
+
+rotx= parameters.acq.rotx
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = floor(parameters.acq.ydet/2) % at the geometrical center of the image
+
+% table1=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+% table2=[parameters.acq.difB_name 'difspot'] ; % difspot table B set
+difspottable=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+
+pairtable=parameters.acq.pair_tablename ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% SET inputs for calculation
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+
+[tmp,results]=gtnew_calculate_twotheta;
+reflections=results.reflections; % type of reflections
+
+
+%reflections=gtGetSpaceGroupReflections(parameters.acq.spacegroup) 
+
+gtDBConnect ;
+
+nof_pairs= mym(sprintf('select count(*) from %s',pairtable)) 
+
+disp('Reading data from database...')
+
+if isempty(which_ref)
+  
+  [centXimA,centYimA,th,eta,om,diftyp]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, ' ...
+    '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID)' ...
+    ' ORDER BY %s.pairID'], ...
+    difspottable,difspottable,pairtable,pairtable,pairtable,pairtable,difspottable,...
+    pairtable,difspottable,pairtable,pairtable)) ;
+
+  [centXimB,centYimB]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY ' ...
+    'FROM (%s INNER JOIN %s ON %s.difspotID=%s.difBID)' ...
+    ' ORDER BY %s.pairID'], ...
+    difspottable,difspottable,difspottable,...
+    pairtable,difspottable,pairtable,pairtable)) ;
+  
+else
+  centXimA= [] ;
+  centYimA= [] ;
+  centXimB= [] ;
+  centYimB= [] ;
+  th=       [] ;
+  eta=      [] ;
+  om=       [] ;
+  diftyp=   [] ;
+  for ii=1:length(which_ref)
+
+    [centXimA_r,centYimA_r,th_r,eta_r,om_r,diftyp_r]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, ' ...
+      '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID)' ...
+      ' WHERE %s.thetatype=%d ORDER BY %s.pairID'], ...
+      difspottable,difspottable,pairtable,pairtable,pairtable,pairtable,difspottable,...
+      pairtable,difspottable,pairtable,pairtable,which_ref(ii),pairtable)) ;
+    
+    [centXimB_r,centYimB_r]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY ' ...
+      ' FROM (%s INNER JOIN %s ON %s.difspotID=%s.difBID)' ...
+      ' WHERE %s.thetatype=%d ORDER BY %s.pairID'], ...
+      difspottable,difspottable,difspottable,...
+      pairtable,difspottable,pairtable,pairtable,which_ref(ii),pairtable)) ;
+
+    centXimA=[centXimA; centXimA_r];
+    centYimA=[centYimA; centYimA_r];
+    centXimB=[centXimB; centXimB_r];
+    centYimB=[centYimB; centYimB_r];
+    th=      [th; th_r];
+    eta=     [eta; eta_r];
+    om=      [om; om_r];
+    diftyp=  [diftyp; diftyp_r];
+  end
+end
+
+[centXimA,centYimA]=gtTrImToSc(centXimA,centYimA);
+[centXimB,centYimB]=gtTrImToSc(centXimB,centYimB);
+
+disp('Processing data...')
+
+v=zeros(length(diftyp),1) ;
+
+for i=1:length(diftyp)
+  v(i)=1./norm(reflections(diftyp(i),:)) ;   % in angstroms
+end
+
+inp1=(centXimA+centXimB-2*rotx)*parameters.acq.pixelsize ; % in mm
+inp2=(centYimA+centYimB-2*sorZ)*parameters.acq.pixelsize ; % in mm
+inp3=(centYimA-centYimB)*parameters.acq.pixelsize ;        % in mm
+
+[opt,fval,exitflag]=fminsearch(@(var) sfPsiError(var,v,inp1,inp2,inp3),[0,0,measured_rottodet_mm],optimset('Display','iter'));
+
+
+%% trying %%%%%%%%%%%%%%%%
+% opt=[5 0 measured_rottodet_mm];
+% fval=0;
+% exitflag=1;
+%%%%%%%%%%%%%%%%%%
+
+
+if exitflag~=1
+  disp(' ')
+  disp('No optimized values for correction were found.')
+  disp(' ')
+  return
+end
+
+tiltY=opt(1) ; % alpha in degrees
+tiltZ=opt(2) ; % beta in degrees
+rottodet_mm=opt(3) ;
+
+rottodet_pix=rottodet_mm/parameters.acq.pixelsize ;
+corr_rottodet_pix=rottodet_pix-measured_rottodet_pix ;
+corr_rottodet_mm=corr_rottodet_pix*parameters.acq.pixelsize ;
+
+%% Calculation of optimized values
+
+th_op=gtThetaOfPairs(centXimA,centYimA,centXimB,centYimB,rottodet_pix,tiltY,tiltZ,rotx,sorZ);
+
+eta_op=gtEtaOfPairs(centXimA,centYimA,centXimB,centYimB,tiltY,tiltZ,rotx,sorZ);
+
+% Diffraction vector coordinates in Lab system
+%Dop1=2*rottodet_mm-sind(tiltZ)*inp1-sind(tiltY)*cosd(tiltZ)*inp2 ; 
+%Dop2=cosd(tiltZ)*inp1-sind(tiltY)*sind(tiltZ)*inp2 ;
+%Dop3=-cosd(tiltY)*(inp3) ;
+%th_op=0.5*acosd(Dop1./sqrt(Dop1.^2+Dop2.^2+Dop3.^2)); % vector of all measured thetas
+
+psi_op=v.*sind(th_op) ;
+std_psi_op=std(psi_op) ;
+
+d_op=lambda./(2.*psi_op) ;  % d-spacing
+std_d_op=std(d_op) ;
+opt_d=lambda/2/mean(psi_op) ;
+
+for i=1:size(reflections,1)
+  w(i)=1./norm(reflections(i,:)) ;   % plane geometry (in angstroms)
+end
+
+opt_thetas=asind(mean(psi_op)./w) ; % optimized diffraction angle for each plane family
+
+% optimized eta-s
+%for i=1:length(Dop2)
+%  if Dop2(i) >= 0  % 0 < eta < 180deg
+%    if Dop3(i) >= 0  % 0 < eta < 90deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i)) ;
+%    else  % 90deg < eta < 180deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+180 ;
+%    end
+%  else  % 180deg < eta < 360deg
+%    if Dop3(i) < 0  % 180deg < eta < 270deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+180 ;
+%    else  % 270deg < eta < 360deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+360 ;
+%    end
+%  end
+%end
+
+%% Calculation of original values for comparison as computed from the database
+
+psi_0=v.*sind(th) ;
+std_psi_0=std(psi_0) ;
+d_0=lambda./(2.*psi_0) ;  % original d-spacing
+std_d_0=std(d_0) ;
+
+for i=1:max(diftyp)
+  nof_thetatype(i)=0 ;
+  theta_0(i)=0 ; 
+  for j=1:length(diftyp)
+    if diftyp(j)==i
+      nof_thetatype(i)=nof_thetatype(i)+1;
+      theta_0(i)=theta_0(i)+th(j);
+    end
+  end
+  thetas_0(i)=theta_0(i)/nof_thetatype(i) ;
+end
+
+%[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+[tmp,results]=gtnew_calculate_twotheta ;
+valid_2thetas=results.centre ; % coloumn vector of all valid 2theta angles in degrees
+
+%% Display results
+
+mym('close')
+
+%tiltY=opt(1)*180/pi ; % alpha in degrees
+%tiltZ=opt(2)*180/pi ; % beta in degrees
+
+disp(' ')
+disp(' ')
+disp('Number of pairs used for correction:'), disp(length(diftyp)) ;
+disp('    Number of pairs per plane-family:'), disp(nof_thetatype);
+disp('Wavelength in angstroms:')
+disp(lambda)
+disp('Final value of the objective function:')
+disp(fval)
+disp('Standard deviation of original psi (lambda/2d):')
+disp(std_psi_0)
+disp('Standard deviation of optimized psi (lambda/2d):')
+disp(std_psi_op)
+disp('Standard deviation of the original d-spacing:')
+disp(std_d_0)
+disp('Standard deviation of the optimized d-spacing:')
+disp(std_d_op)
+disp('Optimized d-spacing of the first reflecting plane-family in angstroms:')
+disp(opt_d)
+disp('Diffraction angles computed from recorded energy and d-spacing in degrees')
+disp(valid_2thetas'/2)
+disp('Original diffraction angles from dataset in degrees:')
+disp(thetas_0)
+disp('Optimized diffraction angles in degrees:')
+disp(opt_thetas)
+disp('Rotation axis to detector distance as measured in mm-s:')
+disp(measured_rottodet_mm)
+disp('Rotation axis to detector distance optimized in mm-s:')
+disp(rottodet_mm)
+disp('Rotation axis to detector distance as measured in pixels:')
+disp(measured_rottodet_pix)
+disp('Rotation axis to detector distance optimized in pixels:')
+disp(rottodet_pix)
+disp('Rotation axis to detector distance optimized correction in mm-s:')
+disp(corr_rottodet_mm)
+disp('Rotation axis to detector distance optimized correction in pixels:')
+disp(corr_rottodet_pix)
+disp('Tilt around axis Y in lab system (in degrees):')
+disp(tiltY)
+disp('Tilt around axis Z in lab system (in degrees):')
+disp(tiltZ)
+disp(' ')
+toc
+disp(' ')
+
+
+if showresults~=0
+  close all;
+   
+  figure(9)
+  hist(th_op,length(diftyp)*4);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(th,nof_pairs*4) ;
+  xlabel('theta (deg)') ;
+  title('Histogram of original (blue) and optimized (green) thetas') ;
+
+  figure(8)
+  plot(th_op,eta_op,'.g','MarkerSize',6);
+  hold on ;
+  for i=1:length(opt_thetas)
+    if ~isempty(find(which_ref==i))
+      plot([opt_thetas(i) opt_thetas(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta OPTIMIZED') ;
+  
+  figure(7)
+  plot(th,eta,'.r','MarkerSize',6);
+  hold on ;
+  for i=1:length(thetas_0)
+    if ~isempty(find(which_ref==i))
+      plot([thetas_0(i) thetas_0(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta ORIGINAL') ;
+      
+  figure(6)
+  hist(d_op,length(diftyp)/8);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(d_0,nof_pairs/8) ;
+  xlabel('d-spacing (Angstroms)') ;
+  title('Histogram of original (blue) and optimized (green) d-spacings') ;
+  
+  figure(5)
+  plot(eta_op,d_op,'.g','MarkerSize',6);
+  hold on ;
+  plot([0 360],[opt_d opt_d],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('d (Angstroms)') ;
+  title('d - eta OPTIMIZED') ;
+
+  figure(4)
+  plot(eta,d_0,'.r','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(d_0) mean(d_0)],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('d (Angstroms)') ;
+  title('d - eta ORIGINAL') ;
+
+  figure(3);
+  hist(psi_op,length(diftyp)/8);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(psi_0,nof_pairs/8) ;
+  xlabel('psi') ;
+  title('Histogram of original (blue) and optimized (green) psi (=\lambda/2d)') ;
+   
+  figure(2)
+  plot(eta_op,psi_op,'.g','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(psi_op) mean(psi_op)],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('psi') ;
+  title('psi (=\lambda/2d)- eta OPTIMIZED') ;
+
+  figure(1)
+  plot(eta,psi_0,'.r','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(psi_0) mean(psi_0)],'k','LineWidth',1,'LineStyle','-.');
+  xlabel('eta (deg)') ;
+  ylabel('psi') ;
+  title('psi (=\lambda/2d) - eta ORIGINAL') ;
+  
+  %keyboard
+end % of show results
+  
+end % of function
+
+
+%% Sub-functions in use
+
+function [psi_error]=sfPsiError(var,v,inp1,inp2,inp3)
+  %input vectors:
+  %  var(1)= alpha
+  %  var(2)= beta
+  %  var(3)= r, rotation axis to detector distance (same unit as inp-s)
+  %  inp1= centXimA+centXimB-2*rotx 
+  %  inp2= centYimA+centYimB-2*sorZ 
+  %  inp3= centYimA-centYimB 
+
+  Dopt1=2*var(3)-sind(var(2))*inp1-sind(var(1))*cosd(var(2))*inp2 ;
+  Dopt2=cosd(var(2))*inp1-sind(var(1))*sind(var(2))*inp2 ;
+  Dopt3=-cosd(var(1))*(inp3) ;
+
+  %th=0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2)) ;
+  psi=v.*sind(0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2))) ;
+  
+  mean_psi=mean(psi) ;
+  %psi_error=std(psi) ;
+  psi_error=sum((psi-mean_psi).^2) ;
+end
+
+%% Sub-functions not in use
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
+
diff --git a/4_spot_sorting/gtCorrectGeo_v3.m b/4_spot_sorting/gtCorrectGeo_v3.m
new file mode 100755
index 0000000000000000000000000000000000000000..8c0e075e60789a685ff1ce1774fc0f82e8095b45
--- /dev/null
+++ b/4_spot_sorting/gtCorrectGeo_v3.m
@@ -0,0 +1,443 @@
+% 
+% FUNCTION gtCorrectGeo_v3
+%
+% Gives geometrical correction for the /rotation axis to detector distance/,
+% and detector tilts according to data in a Spotpair or Calibration table.
+% Based on that, it also gives optimized values of the d-spacing, and the
+% theta angles. Plane-families to be used can be set, /a minimum of two is 
+% necessary/.
+% 
+%
+% e.g. gtCorrectGeo_v3('rottodet')
+%      gtCorrectGeo_v3('tilts',[1 3 4],0,parameters) 
+%   
+%
+% INPUT:    gtCorrectGeo_v3(optpar,which_ref,showresults,parameters)
+%
+%           optpar =    'rottodet' or 'tilts'
+%
+%           which_ref = number of plane-family type to be used for optimization, e.g [1 2 4]
+%                       if 0, all types are used
+%           showresults = if not 0, figures are displayed for feedback
+%           parameters
+%
+% OUTPUT:   [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas] 
+%
+%             tiltY = tilt around axis Y in Lab system (in degrees)
+%             tiltZ = tilt around axis Z in Lab system (in degrees)
+%             corr_rottodet_mm = correction for the rotation axis to
+%               detector distance in millimeters
+%             corr_rottodet_pix = correction for the rotation axis to
+%               detector distance in pixels    
+%               (precise value = measured + correction)
+%             opt_d = optimized d-spacing of the first reflecting
+%               plane-family
+%             [opt_thetas] = optimized theta angles
+%             
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+function [corr_rottodet_mm,corr_rottodet_pix,tiltY,tiltZ,opt_d,opt_thetas]=gtCorrectGeo_v3(optpar,which_ref,showresults,parameters)
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+if ~exist('which_ref','var')
+  which_ref=[];
+end
+
+if ~exist('showresults','var')
+  showresults=1;
+end
+
+tic
+
+measured_rottodet_mm= parameters.acq.dist
+measured_rottodet_pix= parameters.acq.dist/parameters.acq.pixelsize
+
+rotx= parameters.acq.rotx
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = floor(parameters.acq.ydet/2) % at the geometrical center of the image
+
+difspottable=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+
+pairtable=parameters.acq.pair_tablename ;
+
+
+%% SET inputs for calculation
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+
+[tmp,results]=gtnew_calculate_twotheta;
+reflections=results.reflections; % type of reflections
+
+%reflections=gtGetSpaceGroupReflections(parameters.acq.spacegroup) 
+
+gtDBConnect ;
+
+nof_pairs= mym(sprintf('select count(*) from %s',pairtable)) 
+
+disp('Reading data from database...')
+
+if isempty(which_ref)
+  
+  [centXimA,centYimA,th,eta,om,diftyp]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, ' ...
+    '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID)' ...
+    ' ORDER BY %s.pairID'], ...
+    difspottable,difspottable,pairtable,pairtable,pairtable,pairtable,difspottable,...
+    pairtable,difspottable,pairtable,pairtable)) ;
+
+  [centXimB,centYimB]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY ' ...
+    'FROM (%s INNER JOIN %s ON %s.difspotID=%s.difBID)' ...
+    ' ORDER BY %s.pairID'], ...
+    difspottable,difspottable,difspottable,...
+    pairtable,difspottable,pairtable,pairtable)) ;
+  
+else
+  centXimA= [] ;
+  centYimA= [] ;
+  centXimB= [] ;
+  centYimB= [] ;
+  th=       [] ;
+  eta=      [] ;
+  om=       [] ;
+  diftyp=   [] ;
+  for ii=1:length(which_ref)
+
+    [centXimA_r,centYimA_r,th_r,eta_r,om_r,diftyp_r]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY, ' ...
+      '%s.theta, %s.eta, %s.omega, %s.thetatype FROM (%s INNER JOIN %s ON %s.difspotID=%s.difAID)' ...
+      ' WHERE %s.thetatype=%d ORDER BY %s.pairID'], ...
+      difspottable,difspottable,pairtable,pairtable,pairtable,pairtable,difspottable,...
+      pairtable,difspottable,pairtable,pairtable,which_ref(ii),pairtable)) ;
+    
+    [centXimB_r,centYimB_r]=mym(sprintf(['SELECT %s.CentroidX, %s.CentroidY ' ...
+      ' FROM (%s INNER JOIN %s ON %s.difspotID=%s.difBID)' ...
+      ' WHERE %s.thetatype=%d ORDER BY %s.pairID'], ...
+      difspottable,difspottable,difspottable,...
+      pairtable,difspottable,pairtable,pairtable,which_ref(ii),pairtable)) ;
+
+    centXimA=[centXimA; centXimA_r];
+    centYimA=[centYimA; centYimA_r];
+    centXimB=[centXimB; centXimB_r];
+    centYimB=[centYimB; centYimB_r];
+    th=      [th; th_r];
+    eta=     [eta; eta_r];
+    om=      [om; om_r];
+    diftyp=  [diftyp; diftyp_r];
+  end
+end
+
+[centXimA,centYimA]=gtTrImToSc(centXimA,centYimA);
+[centXimB,centYimB]=gtTrImToSc(centXimB,centYimB);
+
+disp('Processing data...')
+
+v=zeros(length(diftyp),1) ;
+
+for i=1:length(diftyp)
+  v(i)=1./norm(reflections(diftyp(i),:)) ;   % in angstroms
+end
+
+inp1=(centXimA+centXimB-2*rotx)*parameters.acq.pixelsize ; % in mm
+inp2=(centYimA+centYimB-2*sorZ)*parameters.acq.pixelsize ; % in mm
+inp3=(centYimA-centYimB)*parameters.acq.pixelsize ;        % in mm
+
+%% Optimize tilts
+
+if strcmpi(optpar,'tilts') % optimize for the two tilts
+  [opt,fval,exitflag]=fminsearch(@(var) sfPsiError(var,v,measured_rottodet_mm,inp1,inp2,inp3),[0,0],optimset('Display','iter'));
+
+  if exitflag~=1
+    disp(' ')
+    disp('No optimized values for correction were found.')
+    disp(' ')
+    return
+  end
+
+  tiltY=opt(1) ; % alpha in degrees
+  tiltZ=opt(2) ; % beta in degrees
+  rottodet_mm=measured_rottodet_mm;
+end
+
+
+if strcmpi(optpar,'rottodet') % optimize for rottodet
+%   [opt,fval,exitflag]=fminsearch(@(var) sfPsiErrorRotx(var,v,0,0,inp1,inp2,inp3),measured_rottodet_mm,optimset('Display','iter'));
+% 
+%   if exitflag~=1
+%     disp(' ')
+%     disp('No optimized values for correction were found.')
+%     disp(' ')
+%     return
+%   end
+
+  lim_rottodet1=measured_rottodet_mm/1.1;
+  lim_rottodet2=measured_rottodet_mm*1.1;
+
+  opt=fminbnd(@(var) sfPsiErrorRotx(var,v,0,0,inp1,inp2,inp3),lim_rottodet1,lim_rottodet2);
+
+  fval=0;
+  tiltY=0; % alpha in degrees
+  tiltZ=0; % beta in degrees
+  rottodet_mm=opt;
+end
+
+
+
+rottodet_pix=rottodet_mm/parameters.acq.pixelsize ;
+corr_rottodet_pix=rottodet_pix-measured_rottodet_pix ;
+corr_rottodet_mm=corr_rottodet_pix*parameters.acq.pixelsize ;
+
+%% Calculation of optimized values
+
+th_op=gtThetaOfPairs(centXimA,centYimA,centXimB,centYimB,rottodet_pix,tiltY,tiltZ,rotx,sorZ);
+
+eta_op=gtEtaOfPairs(centXimA,centYimA,centXimB,centYimB,tiltY,tiltZ,rotx,sorZ);
+
+% Diffraction vector coordinates in Lab system
+%Dop1=2*rottodet_mm-sind(tiltZ)*inp1-sind(tiltY)*cosd(tiltZ)*inp2 ; 
+%Dop2=cosd(tiltZ)*inp1-sind(tiltY)*sind(tiltZ)*inp2 ;
+%Dop3=-cosd(tiltY)*(inp3) ;
+%th_op=0.5*acosd(Dop1./sqrt(Dop1.^2+Dop2.^2+Dop3.^2)); % vector of all measured thetas
+
+psi_op=v.*sind(th_op) ;
+std_psi_op=std(psi_op) ;
+
+d_op=lambda./(2.*psi_op) ;  % d-spacing
+std_d_op=std(d_op) ;
+opt_d=lambda/2/mean(psi_op) ;
+
+for i=1:size(reflections,1)
+  w(i)=1./norm(reflections(i,:)) ;   % plane geometry (in angstroms)
+end
+
+opt_thetas=asind(mean(psi_op)./w) ; % optimized diffraction angle for each plane family
+
+% optimized eta-s
+%for i=1:length(Dop2)
+%  if Dop2(i) >= 0  % 0 < eta < 180deg
+%    if Dop3(i) >= 0  % 0 < eta < 90deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i)) ;
+%    else  % 90deg < eta < 180deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+180 ;
+%    end
+%  else  % 180deg < eta < 360deg
+%    if Dop3(i) < 0  % 180deg < eta < 270deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+180 ;
+%    else  % 270deg < eta < 360deg
+%      eta_op(i)=atand(Dop2(i)/Dop3(i))+360 ;
+%    end
+%  end
+%end
+
+%% Calculation of original values for comparison as computed from the database
+
+psi_0=v.*sind(th) ;
+std_psi_0=std(psi_0) ;
+d_0=lambda./(2.*psi_0) ;  % original d-spacing
+std_d_0=std(d_0) ;
+
+for i=1:max(diftyp)
+  nof_thetatype(i)=0 ;
+  theta_0(i)=0 ; 
+  for j=1:length(diftyp)
+    if diftyp(j)==i
+      nof_thetatype(i)=nof_thetatype(i)+1;
+      theta_0(i)=theta_0(i)+th(j);
+    end
+  end
+  thetas_0(i)=theta_0(i)/nof_thetatype(i) ;
+end
+
+[tmp,results]=gtnew_calculate_twotheta ;
+valid_2thetas=results.centre ; % coloumn vector of all valid 2theta angles in degrees
+
+%% Display results
+
+disp(' ')
+disp(' ')
+disp('Number of pairs used for correction:'), disp(length(diftyp)) ;
+disp('    Number of pairs per plane-family:'), disp(nof_thetatype);
+disp('Wavelength in angstroms:')
+disp(lambda)
+disp('Final value of the objective function:')
+disp(fval)
+disp('Standard deviation of original psi (lambda/2d):')
+disp(std_psi_0)
+disp('Standard deviation of optimized psi (lambda/2d):')
+disp(std_psi_op)
+disp('Standard deviation of the original d-spacing:')
+disp(std_d_0)
+disp('Standard deviation of the optimized d-spacing:')
+disp(std_d_op)
+disp('Optimized d-spacing of the first reflecting plane-family in angstroms:')
+disp(opt_d)
+disp('Diffraction angles computed from recorded energy and d-spacing in degrees')
+disp(valid_2thetas'/2)
+disp('Original diffraction angles from dataset in degrees:')
+disp(thetas_0)
+disp('Optimized diffraction angles in degrees:')
+disp(opt_thetas)
+disp('Rotation axis to detector distance as measured in mm-s:')
+disp(measured_rottodet_mm)
+disp('Rotation axis to detector distance optimized in mm-s:')
+disp(rottodet_mm)
+disp('Rotation axis to detector distance as measured in pixels:')
+disp(measured_rottodet_pix)
+disp('Rotation axis to detector distance optimized in pixels:')
+disp(rottodet_pix)
+disp('Rotation axis to detector distance optimized correction in mm-s:')
+disp(corr_rottodet_mm)
+disp('Rotation axis to detector distance optimized correction in pixels:')
+disp(corr_rottodet_pix)
+disp('Tilt around axis Y in lab system (in degrees):')
+disp(tiltY)
+disp('Tilt around axis Z in lab system (in degrees):')
+disp(tiltZ)
+disp(' ')
+toc
+disp(' ')
+
+
+if showresults
+  close all;
+   
+  figure(9)
+  hist(th_op,length(diftyp)*4);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(th,nof_pairs*4) ;
+  xlabel('theta (deg)') ;
+  title('Histogram of original (blue) and optimized (green) thetas') ;
+
+  figure(8)
+  plot(th_op,eta_op,'.g','MarkerSize',6);
+  hold on ;
+  for i=1:length(opt_thetas)
+    if ~isempty(find(which_ref==i))
+      plot([opt_thetas(i) opt_thetas(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta OPTIMIZED') ;
+  
+  figure(7)
+  plot(th,eta,'.r','MarkerSize',6);
+  hold on ;
+  for i=1:length(thetas_0)
+    if ~isempty(find(which_ref==i))
+      plot([thetas_0(i) thetas_0(i)],[0 360],'-.k','LineWidth',1);
+    end
+  end
+  xlabel('theta (deg)') ;
+  ylabel('eta (deg)') ;
+  title('theta - eta ORIGINAL') ;
+      
+  figure(6)
+  hist(d_op,length(diftyp)/8);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(d_0,nof_pairs/8) ;
+  xlabel('d-spacing (Angstroms)') ;
+  title('Histogram of original (blue) and optimized (green) d-spacings') ;
+  
+  figure(5)
+  plot(eta_op,d_op,'.g','MarkerSize',6);
+  hold on ;
+  plot([0 360],[opt_d opt_d],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('d (Angstroms)') ;
+  title('d - eta OPTIMIZED') ;
+
+  figure(4)
+  plot(eta,d_0,'.r','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(d_0) mean(d_0)],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('d (Angstroms)') ;
+  title('d - eta ORIGINAL') ;
+
+  figure(3);
+  hist(psi_op,length(diftyp)/8);
+  h = findobj(gca,'Type','patch');
+  set(h,'FaceColor','g','EdgeColor','g')
+  hold on ;
+  hist(psi_0,nof_pairs/8) ;
+  xlabel('psi') ;
+  title('Histogram of original (blue) and optimized (green) psi (=\lambda/2d)') ;
+   
+  figure(2)
+  plot(eta_op,psi_op,'.g','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(psi_op) mean(psi_op)],'-.k','LineWidth',1);
+  xlabel('eta (deg)') ;
+  ylabel('psi') ;
+  title('psi (=\lambda/2d)- eta OPTIMIZED') ;
+
+  figure(1)
+  plot(eta,psi_0,'.r','MarkerSize',6);
+  hold on ;
+  plot([0 360],[mean(psi_0) mean(psi_0)],'k','LineWidth',1,'LineStyle','-.');
+  xlabel('eta (deg)') ;
+  ylabel('psi') ;
+  title('psi (=\lambda/2d) - eta ORIGINAL') ;
+  
+  %keyboard
+end % of show results
+  
+end % of function
+
+
+%% Sub-functions in use
+
+function [psi_error]=sfPsiError(var,v,r,inp1,inp2,inp3)
+  %input vectors:
+  %  var(1)= alpha
+  %  var(2)= beta
+  %  r   = rotation axis to detector distance (same unit as inp-s)
+  %  inp1= centXimA+centXimB-2*rotx 
+  %  inp2= centYimA+centYimB-2*sorZ 
+  %  inp3= centYimA-centYimB 
+
+  Dopt1=2*r-sind(var(2))*inp1-sind(var(1))*cosd(var(2))*inp2 ;
+  Dopt2=cosd(var(2))*inp1-sind(var(1))*sind(var(2))*inp2 ;
+  Dopt3=-cosd(var(1))*(inp3) ;
+
+  %th=0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2)) ;
+  psi=v.*sind(0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2))) ;
+  
+  mean_psi=mean(psi) ;
+  psi_error=sum((psi-mean_psi).^2) ;
+end
+
+
+function [psi_error]=sfPsiErrorRotx(var,v,tiltY,tiltZ,inp1,inp2,inp3)
+  %input vectors:
+  %  tiltY
+  %  tiltZ
+  %  var   = rotation axis to detector distance (same unit as inp-s)
+  %  inp1= centXimA+centXimB-2*rotx 
+  %  inp2= centYimA+centYimB-2*sorZ 
+  %  inp3= centYimA-centYimB 
+
+  Dopt1=2*var-sind(tiltZ)*inp1-sind(tiltY)*cosd(tiltZ)*inp2 ;
+  Dopt2=cosd(tiltZ)*inp1-sind(tiltY)*sind(tiltZ)*inp2 ;
+  Dopt3=-cosd(tiltY)*(inp3) ;
+
+  %th=0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2)) ;
+  psi=v.*sind(0.5*acosd(Dopt1./sqrt(Dopt1.^2+Dopt2.^2+Dopt3.^2))) ;
+  
+  mean_psi=mean(psi) ;
+  psi_error=sum((psi-mean_psi).^2) ;
+end
+
+
diff --git a/4_spot_sorting/gtCorrectRotToDetDist.m b/4_spot_sorting/gtCorrectRotToDetDist.m
new file mode 100755
index 0000000000000000000000000000000000000000..0f46a55935e458ea73df13ee1cc4191c141266b1
--- /dev/null
+++ b/4_spot_sorting/gtCorrectRotToDetDist.m
@@ -0,0 +1,565 @@
+% 
+% Gives geometrical correction for the rotation axis to detector distance
+% according to perfectly matching difspots from a 360 degree scan.
+%
+% VALID ONLY FOR FCC (225) CRYSTAL GROUP WITH NO STRAIN!
+%
+% INPUT:    Two data series of segmented diffraction spots 180 degrees
+%           offset from database.
+%               Images are stored as looking against the beam. The position CentroidX
+%               is measured from the left edge of the images and positive towards 
+%               the right in the images. The position CentroidY is measured from 
+%               the top of the images and positive downwards in the images.
+%
+% OUTPUT:   Correction for the distance (in mm-s and pixels).
+%               precise distance = measured + correction      
+%
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+
+function [corr_rottodet_mm,corr_rottodet_pix]=gtCorrectRotToDetDist(show_findings,button)
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+disp('Function is going to delete PairID-s in the difspot tables.')
+disp('Press any key to continue or Ctrl+c to stop!')
+pause
+disp(' ')
+disp('VALID ONLY FOR FCC (225) CRYSTAL GROUP WITH NO STRAIN!')
+disp('Press any key to continue!')
+pause
+tic
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% read PARAMETERS from .mat file
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Thresholds for image position 
+%thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees
+%thr_max_offset=parameters.match.thr_max_offset;     % MaxImage offset threshold; absolut value in #images
+%thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+%thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images
+%corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels  
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+%thr_intint=parameters.match.thr_intint;             % integrated intensity
+%thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box
+%thr_bbsize=parameters.match.thr_bbsize;             % bounding box size
+
+thr_ang= 0.5 %0.5          % angular threshold; absolute value in degrees
+thr_max_offset=1 %0    % MaxImage offset threshold; absolut value in #images
+thr_ext_offset=1 %0     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+thr_genim_offset=1 %0 ; % at least one of the three images should be offset as maximum this value in #images
+ 
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+thr_intint=1.3   %1.05             % integrated intensity
+thr_area=1.1   % 1.05                 % area of spots inside the bounding box
+thr_bbsize=1.1  %1.02             % bounding box size
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sample_radius= parameters.acq.bb(3)/2
+sample_top= parameters.acq.bb(2)
+sample_bot= parameters.acq.bb(2)+parameters.acq.bb(4)
+rot_to_det= parameters.acq.dist/parameters.acq.pixelsize
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = sample_top  % at the top of the sample bounding box (acquisition); lowest number in pixels
+
+fullimages1_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difA_name) ;
+difspotims1_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difA_name) ;
+fullimages2_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difB_name) ;
+difspotims2_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difB_name) ;
+
+table1=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+table2=[parameters.acq.difB_name 'difspot'] ; % difspot table B set
+pairtable=parameters.acq.pair_tablename ;
+
+% For image display
+lowhigh=[-100 100] ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Database search Get allowed TwoTheta data
+
+[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+reflections=results.reflections % type of reflections
+valid_2thetas=results.centre % coloumn vector of all valid 2theta angles in degrees
+
+gtDBconnect ;
+
+nof_spots1= mym(sprintf('select count(*) from %s',table1))
+nof_spots2= mym(sprintf('select count(*) from %s',table2))
+
+mym(sprintf('UPDATE %s SET PairID = NULL', table1)) ;
+mym(sprintf('UPDATE %s SET PairID = NULL', table2)) ;
+
+pairsfound=0 ;
+sps2.id=[] ;
+
+shown=false;
+
+disp('Processing data...')
+disp('Progress:')
+
+type(length(valid_2thetas)).radius=[] ;
+
+for i=1:nof_spots1      % main loop for spots1
+  
+   [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral,sp1.pair]=...
+     mym(sprintf(['select MaxImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+     'BoundingBoxXsize,BoundingBoxYsize,Integral,PairID from %s where difspotID=%d'],table1,i)) ;
+    
+    pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;
+    
+    if (sp1.maxim < thr_max_offset)
+        maxim1=parameters.acq.nproj-(thr_max_offset-sp1.maxim) ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (thr_max_offset <= sp1.maxim < parameters.acq.nproj-thr_max_offset)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=sp1.maxim+thr_max_offset ;
+        maxim3=sp1.maxim-thr_max_offset ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (parameters.acq.nproj-thr_max_offset <= sp1.maxim)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset-parameters.acq.nproj ;
+    end
+ 
+    
+    if (sp1.extstim < 2*thr_ext_offset)
+        extstim1=parameters.acq.nproj-(thr_ext_offset-sp1.extstim) ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extstim < parameters.acq.nproj-thr_ext_offset)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=sp1.extstim+thr_ext_offset ;
+        extstim3=sp1.extstim-thr_ext_offset ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extstim)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset-parameters.acq.nproj ;
+    end
+    
+    
+    if (sp1.extendim < thr_ext_offset)
+        extendim1=parameters.acq.nproj-(thr_ext_offset-sp1.extendim) ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extendim < parameters.acq.nproj-thr_ext_offset)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=sp1.extendim+thr_ext_offset ;
+        extendim3=sp1.extendim-thr_ext_offset ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extendim)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset-parameters.acq.nproj ;
+    end
+
+
+    % AT LEAST ONE OF MaxImage,ExtStartImage,ExtEndImage IS MAXIMUM 1 IMAGE OFFSET
+
+    if (sp1.maxim < thr_genim_offset)
+        maxim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.maxim) ;
+        maxim2_gen=parameters.acq.nproj-1 ;
+        maxim3_gen=0 ;
+        maxim4_gen=sp1.maxim+thr_genim_offset ;
+    elseif (thr_genim_offset <= sp1.maxim < parameters.acq.nproj-thr_genim_offset)
+        maxim1_gen=sp1.maxim-thr_genim_offset ;
+        maxim2_gen=sp1.maxim+thr_genim_offset ;
+        maxim3_gen=sp1.maxim-thr_genim_offset ;
+        maxim4_gen=sp1.maxim+thr_genim_offset ;
+    elseif (parameters.acq.nproj-thr_genim_offset <= sp1.maxim)
+        maxim1_gen=sp1.maxim-thr_genim_offset ;
+        maxim2_gen=parameters.acq.nproj-1 ;
+        maxim3_gen=0 ;
+        maxim4_gen=sp1.maxim+thr_genim_offset-parameters.acq.nproj ;
+    end
+ 
+    
+    if (sp1.extstim < thr_genim_offset)
+        extstim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extstim) ;
+        extstim2_gen=parameters.acq.nproj-1 ;
+        extstim3_gen=0 ;
+        extstim4_gen=sp1.extstim+thr_genim_offset ;
+    elseif (thr_genim_offset <= sp1.extstim < parameters.acq.nproj-thr_genim_offset)
+        extstim1_gen=sp1.extstim-thr_genim_offset ;
+        extstim2_gen=sp1.extstim+thr_genim_offset ;
+        extstim3_gen=sp1.extstim-thr_genim_offset ;
+        extstim4_gen=sp1.extstim+thr_genim_offset ;
+    elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extstim)
+        extstim1_gen=sp1.extstim-thr_genim_offset ;
+        extstim2_gen=parameters.acq.nproj-1 ;
+        extstim3_gen=0 ;
+        extstim4_gen=sp1.extstim+thr_genim_offset-parameters.acq.nproj ;
+    end
+    
+    
+    if (sp1.extendim < thr_genim_offset)
+        extendim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extendim) ;
+        extendim2_gen=parameters.acq.nproj-1 ;
+        extendim3_gen=0 ;
+        extendim4_gen=sp1.extendim+thr_genim_offset ;
+    elseif (thr_genim_offset <= sp1.extendim < parameters.acq.nproj-thr_genim_offset)
+        extendim1_gen=sp1.extendim-thr_genim_offset ;
+        extendim2_gen=sp1.extendim+thr_genim_offset ;
+        extendim3_gen=sp1.extendim-thr_genim_offset ;
+        extendim4_gen=sp1.extendim+thr_genim_offset ;
+    elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extendim)
+        extendim1_gen=sp1.extendim-thr_genim_offset ;
+        extendim2_gen=parameters.acq.nproj-1 ;
+        extendim3_gen=0 ;
+        extendim4_gen=sp1.extendim+thr_genim_offset-parameters.acq.nproj ;
+    end    
+        
+    % Select candidate spots2 from database by all thresholded criteria
+    
+    [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral, sps2.pair]= ...
+        mym(sprintf(['select difspotID, MaxImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+        'BoundingBoxYsize, Integral, PairID from %s WHERE ', ...
+        '(CentroidX between %f and %f) AND (CentroidY between %f and %f) ', ...
+        'AND (BoundingBoxXsize between %f and %f) AND (BoundingBoxYsize between %f and %f) ', ...
+        'AND (Integral between %f and %f) ', ...
+        'AND (Area between %f and %f) ', ...
+        'AND ((MaxImage between %d and %d) OR (MaxImage between %d and %d)) ', ...
+        'AND ((ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d)) ', ...
+        'AND ((ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d)) ', ...
+        'AND ( (MaxImage between %d and %d) OR (MaxImage between %d and %d) OR ', ...
+        '(ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d) OR ', ...
+        '(ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d) ) ', ...
+        'AND (PairID IS NULL)'], ... 
+        table2,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+        sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+        sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+        sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+        sp1.area/thr_area, sp1.area*thr_area, ...
+        maxim1, maxim2, maxim3, maxim4, ...
+        extstim1, extstim2, extstim3, extstim4, ...
+        extendim1, extendim2, extendim3, extendim4, ...
+        maxim1_gen, maxim2_gen, maxim3_gen, maxim4_gen, ...
+        extstim1_gen, extstim2_gen, extstim3_gen, extstim4_gen, ...
+        extendim1_gen, extendim2_gen, extendim3_gen, extendim4_gen )) ;
+    
+      
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+    
+    sqrsum=Inf ;
+    for j=1:length(sps2.id)
+        [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),rot_to_det,parameters.acq.rotx,valid_2thetas,thr_ang);
+        if theta_OK==true
+            sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+                         ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 ;  % angular contribution cancelled
+              %sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+              %             ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+              %             (min(abs(angle_diff))/thr_ang)^2;
+            if (sqrsumnew < sqrsum)
+                sqrsum=sqrsumnew ;
+                pairj=j ;
+                sp1.pair=sps2.id(j) ;
+                thetatype_out=thetatype ;
+            end
+        end
+    end
+    
+    if sqrsum < Inf
+        pairsfound=pairsfound+1 ;
+         
+%% Computing output parameters and writing in database
+        
+        cent1X=sp1.centX-parameters.acq.rotx ;
+        cent1Y=sp1.centY ;
+        cent2X=sps2.centX(pairj)-parameters.acq.rotx ;
+        cent2Y=sps2.centY(pairj) ; 
+        
+        deltaX=cent1X+cent2X ;
+        deltaY=-cent1Y+cent2Y ;
+        
+        type(thetatype_out).radius=[type(thetatype_out).radius, sqrt(deltaX^2+deltaY^2)/2] ;
+
+        
+        %theta=acosd(2*rot_to_det/norm([2*rot_to_det deltaX deltaY]))/2 ;
+        %
+        %if deltaX >= 0  % 0 < eta < 180deg
+        %  if deltaY >= 0  % 0 < eta < 90deg
+        %    eta=atand(deltaX/deltaY) ;
+        %  else  % 90deg < eta < 180deg
+        %    eta=atand(deltaX/deltaY)+180 ;
+        %  end
+        %else  % 180deg < eta < 360deg
+        %  if deltaY < 0  % 180deg < eta < 270deg
+        %    eta=atand(deltaX/deltaY)+180 ;
+        %  else  % 270deg < eta < 360deg
+        %    eta=atand(deltaX/deltaY)+360 ;
+        %  end  
+        %end
+        %               
+        % Spot centroid coordinates in the set-up absolute system
+        %
+        %diff_vec_setup = [2*rot_to_det deltaX deltaY]/norm([2*rot_to_det deltaX deltaY]) ;
+        %pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ;
+        %        
+        %omega = ( 180/parameters.acq.nproj*sp1.maxim + 180/parameters.acq.nproj*sps2.maxim(pairj) )/2 ;
+        %       
+        %diff_vec_sam = sfSetup_to_sample_cor(diff_vec_setup,omega) ;
+        %pl_vec_sam = sfSetup_to_sample_cor(pl_vec_setup,omega) ;
+        %abs_cent1 = sfSetup_to_sample_cor([rot_to_det cent1X -(cent1Y-sorZ)],omega) ;
+               
+        mym(sprintf('UPDATE %s SET PairID=%d WHERE difspotID=%d', table1, sp1.pair, i)) ;
+        mym(sprintf('UPDATE %s SET PairID=%d WHERE difspotID=%d', table2, i, sp1.pair)) ;
+             
+%% Display findings
+
+        % FULL IMAGES
+   
+        if show_findings == 1
+          figure(1);
+          fullim1=edf_read([fullimages1_directory, sprintf('/full%04d.edf',sp1.maxim)]) ;
+    
+          lim=max(fullim1(:)) ;
+          %lowhigh=1.2*[-lim,lim] ;
+          %lowhigh=autolim(fullim1) ;
+    
+          fullim2=edf_read([fullimages2_directory, sprintf('/full%04d.edf',sps2.maxim(pairj))]) ;
+          fullim2(parameters.acq.bb(2):(parameters.acq.bb(2)+parameters.acq.bb(4)), parameters.acq.bb(1):(parameters.acq.bb(1)+parameters.acq.bb(3)))=0;
+          totim=fullim1+fliplr(fullim2);
+          imshow(totim,lowhigh);
+          hold on ;
+ 
+          %title(sprintf('Difspot_A: %05d   Difspot_B: %05d           Omega: %5.2f deg    Theta: %5.2f deg    Eta: %5.2f deg', i, sp1.pair,omega,theta,eta)) ;
+        
+          rectangle('Position',[parameters.acq.bb(1)-2,parameters.acq.bb(2)-2,parameters.acq.bb(3)+4,parameters.acq.bb(4)+4],'EdgeColor','c') ;
+          rectangle('Position',[2*parameters.acq.rotx-pr_bb(1)-(pr_bb(3)-pr_bb(1)),pr_bb(2),(pr_bb(3)-pr_bb(1)),(pr_bb(4)-pr_bb(2))],'EdgeColor','b') ;
+          rectangle('Position',[sp1.bbX-2,sp1.bbY-2,sp1.bbXsize+4,sp1.bbYsize+4],'EdgeColor','r') ;
+          rectangle('Position',[2*parameters.acq.rotx-sps2.bbX(pairj)-sps2.bbXsize(pairj)-2,sps2.bbY(pairj)-2,sps2.bbXsize(pairj)+4,sps2.bbYsize(pairj)+4],'EdgeColor','g') ;
+
+          for k=1:length(sps2.id)
+            if k~=pairj
+            plot(2*parameters.acq.rotx-sps2.centX(k),sps2.centY(k),'g*') ;
+            end
+          end
+   
+          % LINE ALONG PROJECTION
+          plot([sp1.centX, 2*parameters.acq.rotx-sps2.centX(pairj)],[sp1.centY, sps2.centY(pairj) ],'c') ;
+           
+          % CIRCLES OF VALID 2THETAS
+          t=(0:1:360)' ;
+          circRthetas=2*rot_to_det*tand(valid_2thetas) ;
+          for k=1:length(circRthetas)
+            circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+            circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+            plot(circthetasX,circthetasY,'b') ;
+          end
+
+          if shown==false
+            circRthetas=2*rot_to_det*tand(valid_2thetas+thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+
+            circRthetas=2*rot_to_det*tand(valid_2thetas-thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+          end
+
+          hold off;
+
+          % DIFSPOTS
+    
+          figure(2);
+          difspim1=edf_read([difspotims1_directory, sprintf('/difspot%05d.edf', i)]) ;
+          imshow(difspim1, lowhigh) ;
+          rectangle('Position',[1,1,sp1.bbXsize,sp1.bbYsize],'EdgeColor','r') ;
+          title(sprintf('Difspot_A: %5d', i)) ;
+    
+          for k=1:length(sps2.id)
+            figure(k+2);
+            difspim2=edf_read([difspotims2_directory, sprintf('/difspot%05d.edf',sps2.id(k))]) ;
+            imshow(fliplr(difspim2), lowhigh) ;
+            no_im=k+2 ;
+            if k==pairj
+              rectangle('Position',[1,1,sps2.bbXsize(k),sps2.bbYsize(k)],'EdgeColor','g') ;
+              title(sprintf('Mathced difspot_B: %5d', sps2.id(k))) ;
+            else
+              title(sprintf('Difspot_B: %5d', sps2.id(k))) ;
+            end
+          end
+
+          if shown==true
+            for kk=no_im+1:pr_im
+              set(kk,'Visible','off') ;
+            end
+          end
+      
+          pr_im=length(sps2.id)+2 ;
+          shown=true;
+          drawnow ;
+         
+          if button==1
+            waitforbuttonpress
+          end
+          
+        end % show findings
+        
+    end % pair found
+    
+    if mod(i,100)==0
+      disp(sprintf('SpotID:  %d   Perfect pairs found:  %d   Perfect matching percentage:  %6.3f %s',i,pairsfound,(pairsfound/i*100),'%')) ;
+    end
+    
+end % end of main loop for spots1
+
+%% Calculation of correction (in pixels)
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+
+spacing=[] ;
+meanrad=[] ;
+nradius=[] ;
+thetas_vec=[] ;
+
+%for ii=1:length(type)
+%  spacing(ii)=parameters.acq.latticepar(1)/norm(reflections(ii,:))   % in angstroms
+%  if length(type(ii).radius) ~= 0
+%    meanrad(ii)=mean(type(ii).radius)      % in pixels
+%    nradius(ii)=length(type(ii).radius)
+%    thetas_vec(ii)=asind(lambda/(2*spacing(ii)))
+%  else
+%    meanrad(ii)=0
+%    nradius(ii)=0
+%    thetas_vec(ii)=0
+%  end
+%end
+
+for ii=1:length(type)
+  spacing(ii)=parameters.acq.latticepar(1)/norm(reflections(ii,:))   % in angstroms
+  nradius=[nradius, length(type(ii).radius)] 
+  if length(type(ii).radius) ~= 0
+    meanrad=[meanrad, mean(type(ii).radius)]      % in pixels
+    thetas_vec=[thetas_vec, asind(lambda/(2*spacing(ii)))] 
+  end
+end
+
+realdist_vec= meanrad./tand(2*thetas_vec)  % vector; in pixels
+corr_rottodet_pix_vec=realdist_vec-rot_to_det     % vector in pixels
+corr_rottodet_mm_vec=corr_rottodet_pix_vec*parameters.acq.pixelsize     % vector in mm-s
+
+%mean(realdist_vec.*nonzeros(nradius)')/sum(nradius)
+%corr_rottodet_pix=mean(corr_rottodet_pix_vec.*nonzeros(nradius)')
+%corr_rottodet_mm=mean(corr_rottodet_mm_vec.*nonzeros(nradius)')
+
+corr_rottodet_pix= (corr_rottodet_pix_vec*nonzeros(nradius)')/sum(nonzeros(nradius))
+corr_rottodet_mm = corr_rottodet_pix * parameters.acq.pixelsize
+
+
+% With strain:
+% d0=parameters.acq.latticepar(1)
+% theta=asind(lambda/2./(d0*[1-strain 1 1+strain])*norm(reflections(i,:)))
+
+mym(sprintf('UPDATE %s SET PairID = NULL', table1)) ;
+mym(sprintf('UPDATE %s SET PairID = NULL', table2)) ;
+
+mym('close')
+
+%=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels 
+
+disp('Total number of diffraction spots in set #1:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in set #2:'), disp(nof_spots2) ;
+disp('Number of pairs used for correction:'), disp(pairsfound) ;
+disp('    Number of pairs per plane family:'), disp(nradius) ;
+disp('')
+disp('Measured distance in pixels:')
+disp(rot_to_det)
+disp('')
+disp('Wavelength in angstroms:')
+disp(lambda)
+disp('')
+disp('D-spacings of the reflecting planes in angstroms:')
+disp(spacing)
+disp('')
+disp('Correction in mm-s:')
+disp(corr_rottodet_mm)
+disp('Correction in pixels:')
+disp(corr_rottodet_pix)
+
+toc
+
+end % of function
+
+
+%% Sub-functions used
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
+
diff --git a/4_spot_sorting/gtCorrectRotToDetDist_b.m b/4_spot_sorting/gtCorrectRotToDetDist_b.m
new file mode 100755
index 0000000000000000000000000000000000000000..4afda8fcad7965582ee02980f66bb2c43406c35c
--- /dev/null
+++ b/4_spot_sorting/gtCorrectRotToDetDist_b.m
@@ -0,0 +1,595 @@
+% 
+% Gives geometrical correction for the rotation axis to detector distance
+% according to perfectly matching difspots from a 360 degree scan.
+%
+% VALID ONLY FOR FCC (225) CRYSTAL GROUP WITH NO STRAIN!
+%
+% INPUT:    Two data series of segmented diffraction spots 180 degrees
+%           offset from database.
+%               Images are stored as looking against the beam. The position CentroidX
+%               is measured from the left edge of the images and positive towards 
+%               the right in the images. The position CentroidY is measured from 
+%               the top of the images and positive downwards in the images.
+%
+% OUTPUT:   Correction for the distance (in mm-s and pixels).
+%               precise distance = measured + correction      
+%
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+
+function [corr_rottodet_mm,corr_rottodet_pix]=gtCorrectRotToDetDist_b(show_findings,button,npairs)
+
+%%%%%%%%%%%%%%%% conv_rate,con_pix,
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+disp('Function is going to delete PairID-s in the difspot tables.')
+disp('Press any key to continue or Ctrl+c to stop!')
+pause
+disp(' ')
+disp('VALID ONLY FOR FCC (225) CRYSTAL GROUP WITH NO STRAIN!')
+disp('Press any key to continue!')
+pause
+tic
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% read PARAMETERS from .mat file
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Thresholds for image position 
+%thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees
+%thr_max_offset=parameters.match.thr_max_offset;     % MaxImage offset threshold; absolut value in #images
+%thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+%thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images
+%corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels  
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+%thr_intint=parameters.match.thr_intint;             % integrated intensity
+%thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box
+%thr_bbsize=parameters.match.thr_bbsize;             % bounding box size
+
+thr_ang=0.5          % angular threshold; absolute value in degrees
+thr_max_offset=1     % MaxImage offset threshold; absolut value in #images
+thr_ext_offset=1     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+%thr_genim_offset=0; % at least one of the three images should be offset as maximum this value in #images
+ 
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+thr_intint=1.1             % integrated intensity
+thr_area=1.05                 % area of spots inside the bounding box
+thr_bbsize=1.02             % bounding box size
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sample_radius= parameters.acq.bb(3)/2
+sample_top= parameters.acq.bb(2)
+sample_bot= parameters.acq.bb(2)+parameters.acq.bb(4)
+rot_to_det= parameters.acq.dist/parameters.acq.pixelsize
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = sample_top  % at the top of the sample bounding box (acquisition); lowest number in pixels
+
+fullimages1_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difA_name) ;
+difspotims1_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difA_name) ;
+fullimages2_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difB_name) ;
+difspotims2_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difB_name) ;
+
+table1=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+table2=[parameters.acq.difB_name 'difspot'] ; % difspot table B set
+pairtable=parameters.acq.pair_tablename ;
+
+% For image display
+lowhigh=[-100 100] ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% SET parameters
+
+[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+reflections=results.reflections % type of reflections
+valid_2thetas=results.centre % coloumn vector of all valid 2theta angles in degrees
+
+gtDBconnect ;
+
+nof_spots1= mym(sprintf('select count(*) from %s',table1))
+nof_spots2= mym(sprintf('select count(*) from %s',table2))
+
+mym(sprintf('TRUNCATE %s', pairtable)) ;
+
+pairsfound=0 ;
+sps2.id=[] ;
+
+if npairs == 0
+  npairs= -1 ;
+end
+
+shown=false;
+
+disp('Processing data...')
+disp('Progress:')
+
+type(length(valid_2thetas)).radius=[] ;
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+        
+meanrad=[] ;
+nradius=[] ;
+thetas_vec=[] ;
+
+for ii=1:length(type)
+  spacing(ii)=parameters.acq.latticepar(1)/norm(reflections(ii,:)) ;   % in angstroms
+end
+
+%% Loop through spots1
+
+for i=1:nof_spots1  
+ 
+   [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral]=...
+     mym(sprintf(['select MaxImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+     'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d'],table1,i)) ;
+   
+    pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;
+    
+    if (sp1.maxim < thr_max_offset)
+        maxim1=parameters.acq.nproj-(thr_max_offset-sp1.maxim) ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (thr_max_offset <= sp1.maxim < parameters.acq.nproj-thr_max_offset)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=sp1.maxim+thr_max_offset ;
+        maxim3=sp1.maxim-thr_max_offset ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (parameters.acq.nproj-thr_max_offset <= sp1.maxim)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset-parameters.acq.nproj ;
+    end
+ 
+    
+    if (sp1.extstim < 2*thr_ext_offset)
+        extstim1=parameters.acq.nproj-(thr_ext_offset-sp1.extstim) ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extstim < parameters.acq.nproj-thr_ext_offset)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=sp1.extstim+thr_ext_offset ;
+        extstim3=sp1.extstim-thr_ext_offset ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extstim)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset-parameters.acq.nproj ;
+    end
+    
+    
+    if (sp1.extendim < thr_ext_offset)
+        extendim1=parameters.acq.nproj-(thr_ext_offset-sp1.extendim) ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extendim < parameters.acq.nproj-thr_ext_offset)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=sp1.extendim+thr_ext_offset ;
+        extendim3=sp1.extendim-thr_ext_offset ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extendim)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset-parameters.acq.nproj ;
+    end
+
+
+    % AT LEAST ONE OF MaxImage,ExtStartImage,ExtEndImage IS MAXIMUM 1 IMAGE OFFSET
+
+   % if (sp1.maxim < thr_genim_offset)
+   %     maxim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.maxim) ;
+   %     maxim2_gen=parameters.acq.nproj-1 ;
+   %     maxim3_gen=0 ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.maxim < parameters.acq.nproj-thr_genim_offset)
+   %     maxim1_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim2_gen=sp1.maxim+thr_genim_offset ;
+   %     maxim3_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.maxim)
+   %     maxim1_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim2_gen=parameters.acq.nproj-1 ;
+   %     maxim3_gen=0 ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset-parameters.acq.nproj ;
+   % end
+   % 
+   % if (sp1.extstim < thr_genim_offset)
+   %     extstim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extstim) ;
+   %     extstim2_gen=parameters.acq.nproj-1 ;
+   %     extstim3_gen=0 ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.extstim < parameters.acq.nproj-thr_genim_offset)
+   %     extstim1_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim2_gen=sp1.extstim+thr_genim_offset ;
+   %     extstim3_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extstim)
+   %     extstim1_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim2_gen=parameters.acq.nproj-1 ;
+   %     extstim3_gen=0 ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset-parameters.acq.nproj ;
+   % end
+   % 
+   %if (sp1.extendim < thr_genim_offset)
+   %     extendim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extendim) ;
+   %     extendim2_gen=parameters.acq.nproj-1 ;
+   %     extendim3_gen=0 ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.extendim < parameters.acq.nproj-thr_genim_offset)
+   %     extendim1_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim2_gen=sp1.extendim+thr_genim_offset ;
+   %     extendim3_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extendim)
+   %     extendim1_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim2_gen=parameters.acq.nproj-1 ;
+   %     extendim3_gen=0 ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset-parameters.acq.nproj ;
+   % end    
+        
+    % Select candidate spots2 from database by all thresholded criteria
+    
+    [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral]= ...
+        mym(sprintf(['select difspotID, MaxImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+        'BoundingBoxYsize, Integral from %s WHERE ', ...
+        '(CentroidX between %f and %f) AND (CentroidY between %f and %f) ', ...
+        'AND (BoundingBoxXsize between %f and %f) AND (BoundingBoxYsize between %f and %f) ', ...
+        'AND (Integral between %f and %f) ', ...
+        'AND (Area between %f and %f) ', ...
+        'AND ((MaxImage between %d and %d) OR (MaxImage between %d and %d)) ', ...
+        'AND ((ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d)) ', ...
+        'AND ((ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d)) '], ...
+        table2,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+        sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+        sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+        sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+        sp1.area/thr_area, sp1.area*thr_area, ...
+        maxim1, maxim2, maxim3, maxim4, ...
+        extstim1, extstim2, extstim3, extstim4, ...
+        extendim1, extendim2, extendim3, extendim4)) ;    %, ...
+      %  maxim1_gen, maxim2_gen, maxim3_gen, maxim4_gen, ...
+      %  extstim1_gen, extstim2_gen, extstim3_gen, extstim4_gen, ...
+      %  extendim1_gen, extendim2_gen, extendim3_gen, extendim4_gen )) ;
+    
+      %  'AND ( (MaxImage between %d and %d) OR (MaxImage between %d and %d) OR ', ...
+      %  '(ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d) OR ', ...
+      %  '(ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d) ) '], ...
+      %  'AND (PairID IS NULL)'], ... 
+            
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+    
+    sqrsum=Inf ;
+    for j=1:length(sps2.id)
+      sp2.pair=mym(sprintf('select pairID from %s where difBID=%d', pairtable, sps2.id(j)));  % ??? perhaps with inner join later, if it can be faster
+      if ~isempty(sp2.pair)  % only proceed if spot is not already paired
+        continue
+      end   
+
+      [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),rot_to_det,parameters.acq.rotx,valid_2thetas,thr_ang);
+      if theta_OK==true
+        sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+          ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 ;  % angular contribution cancelled
+        %sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+        %             ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+        %             (min(abs(angle_diff))/thr_ang)^2;
+        if (sqrsumnew < sqrsum)
+          sqrsum=sqrsumnew ;
+          pairj=j ;
+          sp1.pair=sps2.id(j) ;
+          thetatype_out=thetatype ;
+        end
+      end
+    end
+    
+    if sqrsum < Inf
+        pairsfound=pairsfound+1 ;
+         
+%% Computing output parameters and writing in database
+        
+        cent1X=sp1.centX-parameters.acq.rotx ;
+        cent1Y=sp1.centY ;
+        cent2X=sps2.centX(pairj)-parameters.acq.rotx ;
+        cent2Y=sps2.centY(pairj) ; 
+        
+        deltaX=cent1X+cent2X ;
+        deltaY=-cent1Y+cent2Y ;
+        
+        type(thetatype_out).radius=[type(thetatype_out).radius, sqrt(deltaX^2+deltaY^2)/2] ;
+
+        %nradius(thetatype_out)=[nradius, length(type(thetatype_out).radius)] ;
+        %  if length(type(ii).radius) ~= 0
+        %    meanrad=[meanrad, mean(type(ii).radius)] ;    % in pixels
+        %    thetas_vec=[thetas_vec, asind(lambda/(2*spacing(ii)))] ;
+        %  end
+        
+
+        %realdist_vec= meanrad./tand(2*thetas_vec)  % vector; in pixels
+        %corr_rottodet_pix_vec=realdist_vec-rot_to_det     % vector in pixels
+        %corr_rottodet_mm_vec=corr_rottodet_pix_vec*parameters.acq.pixelsize     % vector in mm-s
+        
+        %mean(realdist_vec.*nonzeros(nradius)')/sum(nradius)
+        %corr_rottodet_pix=mean(corr_rottodet_pix_vec.*nonzeros(nradius)')
+        
+        theta=acosd(2*rot_to_det/norm([2*rot_to_det deltaX deltaY]))/2 ;
+        
+        if deltaX >= 0  % 0 < eta < 180deg
+          if deltaY >= 0  % 0 < eta < 90deg
+            eta=atand(deltaX/deltaY) ;
+          else  % 90deg < eta < 180deg
+            eta=atand(deltaX/deltaY)+180 ;
+          end
+        else  % 180deg < eta < 360deg
+          if deltaY < 0  % 180deg < eta < 270deg
+            eta=atand(deltaX/deltaY)+180 ;
+          else  % 270deg < eta < 360deg
+            eta=atand(deltaX/deltaY)+360 ;
+          end  
+        end
+                       
+        % Spot centroid coordinates in the set-up absolute system
+        
+        diff_vec_setup = [2*rot_to_det deltaX deltaY]/norm([2*rot_to_det deltaX deltaY]) ;
+        pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ;
+                
+        omega = ( 180/parameters.acq.nproj*sp1.maxim + 180/parameters.acq.nproj*sps2.maxim(pairj) )/2 ;
+               
+        diff_vec_sam = sfSetup_to_sample_cor(diff_vec_setup,omega) ;
+        pl_vec_sam = sfSetup_to_sample_cor(pl_vec_setup,omega) ;
+        abs_cent1 = sfSetup_to_sample_cor([rot_to_det cent1X -(cent1Y-sorZ)],omega) ;
+        
+        av_intint=(sp1.integral+sps2.integral(pairj))/2 ;
+        av_bbXsize=(sp1.bbXsize+sps2.bbXsize(pairj))/2 ;
+        av_bbYsize=(sp1.bbYsize+sps2.bbYsize(pairj))/2 ;
+              
+        sprintf(['INSERT INTO %s (difAID, difBID, theta, eta, omega, avintint, avbbXsize, avbbYsize, lorX, lorY, lorZ, ldirX, ldirY, ldirZ, plX, plY, plZ, thetatype) ',...
+         'VALUES (%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%d)'], pairtable, i, sp1.pair, theta, eta, omega, av_intint, av_bbXsize, av_bbYsize, abs_cent1(1), abs_cent1(2), abs_cent1(3), ...
+         diff_vec_sam(1), diff_vec_sam(2), diff_vec_sam(3), pl_vec_sam(1), pl_vec_sam(2), pl_vec_sam(3), thetatype_out) ;
+       
+        %mym(sprintf(['INSERT INTO %s (difAID, difBID) VALUES (%d,%d)'], pairtable, i, sp1.pair));
+       
+%% Display findings when a pair is found
+
+        % FULL IMAGES
+   
+        if show_findings == 1
+          figure(1);
+          fullim1=edf_read([fullimages1_directory, sprintf('/full%04d.edf',sp1.maxim)]) ;
+    
+          lim=max(fullim1(:)) ;
+          %lowhigh=1.2*[-lim,lim] ;
+          %lowhigh=autolim(fullim1) ;
+    
+          fullim2=edf_read([fullimages2_directory, sprintf('/full%04d.edf',sps2.maxim(pairj))]) ;
+          fullim2(parameters.acq.bb(2):(parameters.acq.bb(2)+parameters.acq.bb(4)), parameters.acq.bb(1):(parameters.acq.bb(1)+parameters.acq.bb(3)))=0;
+          totim=fullim1+fliplr(fullim2);
+          imshow(totim,lowhigh);
+          hold on ;
+ 
+          %title(sprintf('Difspot_A: %05d   Difspot_B: %05d           Omega: %5.2f deg    Theta: %5.2f deg    Eta: %5.2f deg', i, sp1.pair,omega,theta,eta)) ;
+        
+          rectangle('Position',[parameters.acq.bb(1)-2,parameters.acq.bb(2)-2,parameters.acq.bb(3)+4,parameters.acq.bb(4)+4],'EdgeColor','c') ;
+          rectangle('Position',[2*parameters.acq.rotx-pr_bb(1)-(pr_bb(3)-pr_bb(1)),pr_bb(2),(pr_bb(3)-pr_bb(1)),(pr_bb(4)-pr_bb(2))],'EdgeColor','b') ;
+          rectangle('Position',[sp1.bbX-2,sp1.bbY-2,sp1.bbXsize+4,sp1.bbYsize+4],'EdgeColor','r') ;
+          rectangle('Position',[2*parameters.acq.rotx-sps2.bbX(pairj)-sps2.bbXsize(pairj)-2,sps2.bbY(pairj)-2,sps2.bbXsize(pairj)+4,sps2.bbYsize(pairj)+4],'EdgeColor','g') ;
+
+          for k=1:length(sps2.id)
+            if k~=pairj
+            plot(2*parameters.acq.rotx-sps2.centX(k),sps2.centY(k),'g*') ;
+            end
+          end
+   
+          % LINE ALONG PROJECTION
+          plot([sp1.centX, 2*parameters.acq.rotx-sps2.centX(pairj)],[sp1.centY, sps2.centY(pairj) ],'c') ;
+           
+          % CIRCLES OF VALID 2THETAS
+          t=(0:1:360)' ;
+          circRthetas=2*rot_to_det*tand(valid_2thetas) ;
+          for k=1:length(circRthetas)
+            circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+            circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+            plot(circthetasX,circthetasY,'b') ;
+          end
+
+          if shown==false
+            circRthetas=2*rot_to_det*tand(valid_2thetas+thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+
+            circRthetas=2*rot_to_det*tand(valid_2thetas-thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+          end
+
+          hold off;
+
+          % DIFSPOTS
+    
+          figure(2);
+          difspim1=edf_read([difspotims1_directory, sprintf('/difspot%05d.edf', i)]) ;
+          imshow(difspim1, lowhigh) ;
+          rectangle('Position',[1,1,sp1.bbXsize,sp1.bbYsize],'EdgeColor','r') ;
+          title(sprintf('Difspot_A: %5d', i)) ;
+    
+          for k=1:length(sps2.id)
+            figure(k+2);
+            difspim2=edf_read([difspotims2_directory, sprintf('/difspot%05d.edf',sps2.id(k))]) ;
+            imshow(fliplr(difspim2), lowhigh) ;
+            no_im=k+2 ;
+            if k==pairj
+              rectangle('Position',[1,1,sps2.bbXsize(k),sps2.bbYsize(k)],'EdgeColor','g') ;
+              title(sprintf('Mathced difspot_B: %5d', sps2.id(k))) ;
+            else
+              title(sprintf('Difspot_B: %5d', sps2.id(k))) ;
+            end
+          end
+
+          if shown==true
+            for kk=no_im+1:pr_im
+              set(kk,'Visible','off') ;
+            end
+          end
+      
+          pr_im=length(sps2.id)+2 ;
+          shown=true;
+          drawnow ;
+         
+          if button==1
+            pause;
+          end
+          
+        end % show findings
+
+
+    
+    end % pair found
+    
+    if mod(i,100)==0
+      disp(sprintf('SpotID:  %d   Perfect pairs found:  %d   Perfect matching percentage:  %6.3f %s   Correction in pixels: %f',i,pairsfound,(pairsfound/i*100),'%', 0)) ;
+    end
+
+%    if ( <=conv_rate) | ( <=conv_pix) | (pairsfound==npairs)
+    if (pairsfound==npairs)
+      break ;
+    end
+    
+end % end of main loop for spots1
+
+%% Calculation of correction (in pixels)
+
+meanrad=[] ;
+nradius=[] ;
+thetas_vec=[] ;
+
+for ii=1:length(type)
+  spacing(ii)=parameters.acq.latticepar(1)/norm(reflections(ii,:)) ;   % in angstroms
+  nradius=[nradius, length(type(ii).radius)] ;
+  if length(type(ii).radius) ~= 0
+    meanrad=[meanrad, mean(type(ii).radius)] ;    % in pixels
+    thetas_vec=[thetas_vec, asind(lambda/(2*spacing(ii)))] ;
+  end
+end
+
+realdist_vec= meanrad./tand(2*thetas_vec)  % vector; in pixels
+corr_rottodet_pix_vec=realdist_vec-rot_to_det     % vector in pixels
+corr_rottodet_mm_vec=corr_rottodet_pix_vec*parameters.acq.pixelsize     % vector in mm-s
+
+mean(realdist_vec.*nonzeros(nradius)')
+corr_rottodet_pix=mean(corr_rottodet_pix_vec.*nonzeros(nradius)')
+corr_rottodet_mm=mean(corr_rottodet_mm_vec.*nonzeros(nradius)')
+
+% With strain:
+% d0=parameters.acq.latticepar(1)
+% theta=asind(lambda/2./(d0*[1-strain 1 1+strain])*norm(reflections(i,:)))
+
+%mym(sprintf('TRUNCATE %s',pairtable));
+
+mym('close')
+
+%=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels 
+
+disp(' ')
+disp(' ')
+disp('Total number of diffraction spots in set #1:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in set #2:'), disp(nof_spots2) ;
+disp('Number of pairs used for correction:'), disp(pairsfound) ;
+disp('    Number of pairs per plane family:'), disp(nradius) ;
+disp(' ')
+disp('Measured distance in pixels:')
+disp(rot_to_det)
+disp(' ')
+disp('Wavelength in angstroms:')
+disp(lambda)
+disp(' ')
+disp('D-spacings of the reflecting planes in angstroms:')
+disp(spacing)
+disp(' ')
+disp('Correction in mm-s:')
+disp(corr_rottodet_mm)
+disp('Correction in pixels:')
+disp(corr_rottodet_pix)
+
+disp(' ')
+toc
+disp(' ')
+
+end % of function
+
+
+%% Sub-functions used
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
+
diff --git a/4_spot_sorting/gtCorrectRotToDetDist_b_matchonly.m b/4_spot_sorting/gtCorrectRotToDetDist_b_matchonly.m
new file mode 100755
index 0000000000000000000000000000000000000000..b3da981b576a086c0fd1e1a812ad80ec16264da5
--- /dev/null
+++ b/4_spot_sorting/gtCorrectRotToDetDist_b_matchonly.m
@@ -0,0 +1,594 @@
+% 
+% Gives geometrical correction for the rotation axis to detector distance
+% according to perfectly matching difspots from a 360 degree scan.
+%
+% VALID ONLY FOR FCC (225) CRYSTAL GROUP WITH NO STRAIN!
+%
+% INPUT:    Two data series of segmented diffraction spots 180 degrees
+%           offset from database.
+%               Images are stored as looking against the beam. The position CentroidX
+%               is measured from the left edge of the images and positive towards 
+%               the right in the images. The position CentroidY is measured from 
+%               the top of the images and positive downwards in the images.
+%
+% OUTPUT:   Correction for the distance (in mm-s and pixels).
+%               precise distance = measured + correction      
+%
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+% As  gtCorrectRotToDetDist_b  on 23.01.2007, only for searching perfect matches
+
+function [corr_rottodet_mm,corr_rottodet_pix]=gtCorrectRotToDetDist_b_matchonly(show_findings,button,npairs)
+
+%%%%%%%%%%%%%%%% conv_rate,con_pix,
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+disp('Function is going to delete PairID-s in the difspot tables.')
+disp('Press any key to continue or Ctrl+c to stop!')
+pause
+disp(' ')
+disp('VALID ONLY FOR FCC (225) CRYSTAL GROUP WITH NO STRAIN!')
+disp('Press any key to continue!')
+pause
+tic
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% read PARAMETERS from .mat file
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Thresholds for image position 
+%thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees
+%thr_max_offset=parameters.match.thr_max_offset;     % MaxImage offset threshold; absolut value in #images
+%thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+%thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images
+%corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels  
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+%thr_intint=parameters.match.thr_intint;             % integrated intensity
+%thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box
+%thr_bbsize=parameters.match.thr_bbsize;             % bounding box size
+
+thr_ang=0.5          % angular threshold; absolute value in degrees
+thr_max_offset=1     % MaxImage offset threshold; absolut value in #images
+thr_ext_offset=1     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+%thr_genim_offset=0; % at least one of the three images should be offset as maximum this value in #images
+ 
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+thr_intint=1.1             % integrated intensity
+thr_area=1.05                 % area of spots inside the bounding box
+thr_bbsize=1.02             % bounding box size
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sample_radius= parameters.acq.bb(3)/2
+sample_top= parameters.acq.bb(2)
+sample_bot= parameters.acq.bb(2)+parameters.acq.bb(4)
+rot_to_det= parameters.acq.dist/parameters.acq.pixelsize
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = sample_top  % at the top of the sample bounding box (acquisition); lowest number in pixels
+
+fullimages1_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difA_name) ;
+difspotims1_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difA_name) ;
+fullimages2_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difB_name) ;
+difspotims2_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difB_name) ;
+
+table1=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+table2=[parameters.acq.difB_name 'difspot'] ; % difspot table B set
+pairtable=parameters.acq.pair_tablename ;
+
+% For image display
+lowhigh=[-100 100] ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% SET parameters
+
+[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+reflections=results.reflections % type of reflections
+valid_2thetas=results.centre % coloumn vector of all valid 2theta angles in degrees
+
+gtDBconnect ;
+
+nof_spots1= mym(sprintf('select count(*) from %s',table1))
+nof_spots2= mym(sprintf('select count(*) from %s',table2))
+
+mym(sprintf('TRUNCATE %s', pairtable)) ;
+
+pairsfound=0 ;
+sps2.id=[] ;
+
+if npairs == 0
+  npairs= -1 ;
+end
+
+shown=false;
+
+disp('Processing data...')
+disp('Progress:')
+
+type(length(valid_2thetas)).radius=[] ;
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+        
+meanrad=[] ;
+nradius=[] ;
+thetas_vec=[] ;
+
+for ii=1:length(type)
+  spacing(ii)=parameters.acq.latticepar(1)/norm(reflections(ii,:)) ;   % in angstroms
+end
+
+%% Loop through spots1
+
+for i=1:nof_spots1  
+ 
+   [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral]=...
+     mym(sprintf(['select MaxImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+     'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d'],table1,i)) ;
+   
+    pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;
+    
+    if (sp1.maxim < thr_max_offset)
+        maxim1=parameters.acq.nproj-(thr_max_offset-sp1.maxim) ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (thr_max_offset <= sp1.maxim < parameters.acq.nproj-thr_max_offset)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=sp1.maxim+thr_max_offset ;
+        maxim3=sp1.maxim-thr_max_offset ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (parameters.acq.nproj-thr_max_offset <= sp1.maxim)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset-parameters.acq.nproj ;
+    end
+ 
+    
+    if (sp1.extstim < 2*thr_ext_offset)
+        extstim1=parameters.acq.nproj-(thr_ext_offset-sp1.extstim) ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extstim < parameters.acq.nproj-thr_ext_offset)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=sp1.extstim+thr_ext_offset ;
+        extstim3=sp1.extstim-thr_ext_offset ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extstim)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset-parameters.acq.nproj ;
+    end
+    
+    
+    if (sp1.extendim < thr_ext_offset)
+        extendim1=parameters.acq.nproj-(thr_ext_offset-sp1.extendim) ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extendim < parameters.acq.nproj-thr_ext_offset)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=sp1.extendim+thr_ext_offset ;
+        extendim3=sp1.extendim-thr_ext_offset ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extendim)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset-parameters.acq.nproj ;
+    end
+
+
+    % AT LEAST ONE OF MaxImage,ExtStartImage,ExtEndImage IS MAXIMUM 1 IMAGE OFFSET
+
+   % if (sp1.maxim < thr_genim_offset)
+   %     maxim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.maxim) ;
+   %     maxim2_gen=parameters.acq.nproj-1 ;
+   %     maxim3_gen=0 ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.maxim < parameters.acq.nproj-thr_genim_offset)
+   %     maxim1_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim2_gen=sp1.maxim+thr_genim_offset ;
+   %     maxim3_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.maxim)
+   %     maxim1_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim2_gen=parameters.acq.nproj-1 ;
+   %     maxim3_gen=0 ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset-parameters.acq.nproj ;
+   % end
+   % 
+   % if (sp1.extstim < thr_genim_offset)
+   %     extstim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extstim) ;
+   %     extstim2_gen=parameters.acq.nproj-1 ;
+   %     extstim3_gen=0 ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.extstim < parameters.acq.nproj-thr_genim_offset)
+   %     extstim1_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim2_gen=sp1.extstim+thr_genim_offset ;
+   %     extstim3_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extstim)
+   %     extstim1_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim2_gen=parameters.acq.nproj-1 ;
+   %     extstim3_gen=0 ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset-parameters.acq.nproj ;
+   % end
+   % 
+   %if (sp1.extendim < thr_genim_offset)
+   %     extendim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extendim) ;
+   %     extendim2_gen=parameters.acq.nproj-1 ;
+   %     extendim3_gen=0 ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.extendim < parameters.acq.nproj-thr_genim_offset)
+   %     extendim1_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim2_gen=sp1.extendim+thr_genim_offset ;
+   %     extendim3_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extendim)
+   %     extendim1_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim2_gen=parameters.acq.nproj-1 ;
+   %     extendim3_gen=0 ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset-parameters.acq.nproj ;
+   % end    
+        
+    % Select candidate spots2 from database by all thresholded criteria
+    
+    [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral]= ...
+        mym(sprintf(['select difspotID, MaxImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+        'BoundingBoxYsize, Integral from %s WHERE ', ...
+        '(CentroidX between %f and %f) AND (CentroidY between %f and %f) ', ...
+        'AND (BoundingBoxXsize between %f and %f) AND (BoundingBoxYsize between %f and %f) ', ...
+        'AND (Integral between %f and %f) ', ...
+        'AND (Area between %f and %f) ', ...
+        'AND ((MaxImage between %d and %d) OR (MaxImage between %d and %d)) ', ...
+        'AND ((ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d)) ', ...
+        'AND ((ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d)) '], ...
+        table2,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+        sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+        sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+        sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+        sp1.area/thr_area, sp1.area*thr_area, ...
+        maxim1, maxim2, maxim3, maxim4, ...
+        extstim1, extstim2, extstim3, extstim4, ...
+        extendim1, extendim2, extendim3, extendim4)) ;    %, ...
+      %  maxim1_gen, maxim2_gen, maxim3_gen, maxim4_gen, ...
+      %  extstim1_gen, extstim2_gen, extstim3_gen, extstim4_gen, ...
+      %  extendim1_gen, extendim2_gen, extendim3_gen, extendim4_gen )) ;
+   
+      %  'AND ( (MaxImage between %d and %d) OR (MaxImage between %d and %d) OR ', ...
+      %  '(ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d) OR ', ...
+      %  '(ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d) ) '], ...
+      %  'AND (PairID IS NULL)'], ... 
+            
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+    
+    sqrsum=Inf ;
+    for j=1:length(sps2.id)
+      sp2.pair=mym(sprintf('select pairID from %s where difBID=%d', pairtable, sps2.id(j)));  % ??? perhaps with inner join later, if it can be faster
+      if ~isempty(sp2.pair)  % only proceed if spot is not already paired
+        continue
+      end   
+
+      [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),rot_to_det,parameters.acq.rotx,valid_2thetas,thr_ang);
+      if theta_OK==true
+        sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+          ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 ;  % angular contribution cancelled
+        %sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+        %             ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+        %             (min(abs(angle_diff))/thr_ang)^2;
+        if (sqrsumnew < sqrsum)
+          sqrsum=sqrsumnew ;
+          pairj=j ;
+          sp1.pair=sps2.id(j) ;
+          thetatype_out=thetatype ;
+        end
+      end
+    end
+    
+    if sqrsum < Inf
+        pairsfound=pairsfound+1 ;
+         
+%% Computing output parameters and writing in database
+        
+        cent1X=sp1.centX-parameters.acq.rotx ;
+        cent1Y=sp1.centY ;
+        cent2X=sps2.centX(pairj)-parameters.acq.rotx ;
+        cent2Y=sps2.centY(pairj) ; 
+        
+        deltaX=cent1X+cent2X ;
+        deltaY=-cent1Y+cent2Y ;
+        
+        type(thetatype_out).radius=[type(thetatype_out).radius, sqrt(deltaX^2+deltaY^2)/2] ;
+
+        %nradius(thetatype_out)=[nradius, length(type(thetatype_out).radius)] ;
+        %  if length(type(ii).radius) ~= 0
+        %    meanrad=[meanrad, mean(type(ii).radius)] ;    % in pixels
+        %    thetas_vec=[thetas_vec, asind(lambda/(2*spacing(ii)))] ;
+        %  end
+        
+
+        %realdist_vec= meanrad./tand(2*thetas_vec)  % vector; in pixels
+        %corr_rottodet_pix_vec=realdist_vec-rot_to_det     % vector in pixels
+        %corr_rottodet_mm_vec=corr_rottodet_pix_vec*parameters.acq.pixelsize     % vector in mm-s
+        
+        %mean(realdist_vec.*nonzeros(nradius)')/sum(nradius)
+        %corr_rottodet_pix=mean(corr_rottodet_pix_vec.*nonzeros(nradius)')
+        
+        theta=acosd(2*rot_to_det/norm([2*rot_to_det deltaX deltaY]))/2 ;
+        
+        if deltaX >= 0  % 0 < eta < 180deg
+          if deltaY >= 0  % 0 < eta < 90deg
+            eta=atand(deltaX/deltaY) ;
+          else  % 90deg < eta < 180deg
+            eta=atand(deltaX/deltaY)+180 ;
+          end
+        else  % 180deg < eta < 360deg
+          if deltaY < 0  % 180deg < eta < 270deg
+            eta=atand(deltaX/deltaY)+180 ;
+          else  % 270deg < eta < 360deg
+            eta=atand(deltaX/deltaY)+360 ;
+          end  
+        end
+                       
+        % Spot centroid coordinates in the set-up absolute system
+        
+        diff_vec_setup = [2*rot_to_det deltaX deltaY]/norm([2*rot_to_det deltaX deltaY]) ;
+        pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ;
+                
+        omega = ( 180/parameters.acq.nproj*sp1.maxim + 180/parameters.acq.nproj*sps2.maxim(pairj) )/2 ;
+               
+        diff_vec_sam = sfSetup_to_sample_cor(diff_vec_setup,omega) ;
+        pl_vec_sam = sfSetup_to_sample_cor(pl_vec_setup,omega) ;
+        abs_cent1 = sfSetup_to_sample_cor([rot_to_det cent1X -(cent1Y-sorZ)],omega) ;
+        
+        av_intint=(sp1.integral+sps2.integral(pairj))/2 ;
+        av_bbXsize=(sp1.bbXsize+sps2.bbXsize(pairj))/2 ;
+        av_bbYsize=(sp1.bbYsize+sps2.bbYsize(pairj))/2 ;
+              
+        mym(sprintf(['INSERT INTO %s (difAID, difBID, theta, eta, omega, avintint, avbbXsize, avbbYsize, lorX, lorY, lorZ, ldirX, ldirY, ldirZ, plX, plY, plZ, thetatype) ',...
+         'VALUES (%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%d)'], pairtable, i, sp1.pair, theta, eta, omega, av_intint, av_bbXsize, av_bbYsize, abs_cent1(1), abs_cent1(2), abs_cent1(3), ...
+         diff_vec_sam(1), diff_vec_sam(2), diff_vec_sam(3), pl_vec_sam(1), pl_vec_sam(2), pl_vec_sam(3), thetatype_out)) ;
+       
+        %mym(sprintf(['INSERT INTO %s (difAID, difBID) VALUES (%d,%d)'], pairtable, i, sp1.pair));
+       
+%% Display findings when a pair is found
+
+        % FULL IMAGES
+   
+        if show_findings == 1
+          figure(1);
+          fullim1=edf_read([fullimages1_directory, sprintf('/full%04d.edf',sp1.maxim)]) ;
+    
+          lim=max(fullim1(:)) ;
+          %lowhigh=1.2*[-lim,lim] ;
+          %lowhigh=autolim(fullim1) ;
+    
+          fullim2=edf_read([fullimages2_directory, sprintf('/full%04d.edf',sps2.maxim(pairj))]) ;
+          fullim2(parameters.acq.bb(2):(parameters.acq.bb(2)+parameters.acq.bb(4)), parameters.acq.bb(1):(parameters.acq.bb(1)+parameters.acq.bb(3)))=0;
+          totim=fullim1+fliplr(fullim2);
+          imshow(totim,lowhigh);
+          hold on ;
+ 
+          %title(sprintf('Difspot_A: %05d   Difspot_B: %05d           Omega: %5.2f deg    Theta: %5.2f deg    Eta: %5.2f deg', i, sp1.pair,omega,theta,eta)) ;
+        
+          rectangle('Position',[parameters.acq.bb(1)-2,parameters.acq.bb(2)-2,parameters.acq.bb(3)+4,parameters.acq.bb(4)+4],'EdgeColor','c') ;
+          rectangle('Position',[2*parameters.acq.rotx-pr_bb(1)-(pr_bb(3)-pr_bb(1)),pr_bb(2),(pr_bb(3)-pr_bb(1)),(pr_bb(4)-pr_bb(2))],'EdgeColor','b') ;
+          rectangle('Position',[sp1.bbX-2,sp1.bbY-2,sp1.bbXsize+4,sp1.bbYsize+4],'EdgeColor','r') ;
+          rectangle('Position',[2*parameters.acq.rotx-sps2.bbX(pairj)-sps2.bbXsize(pairj)-2,sps2.bbY(pairj)-2,sps2.bbXsize(pairj)+4,sps2.bbYsize(pairj)+4],'EdgeColor','g') ;
+
+          for k=1:length(sps2.id)
+            if k~=pairj
+            plot(2*parameters.acq.rotx-sps2.centX(k),sps2.centY(k),'g*') ;
+            end
+          end
+   
+          % LINE ALONG PROJECTION
+          plot([sp1.centX, 2*parameters.acq.rotx-sps2.centX(pairj)],[sp1.centY, sps2.centY(pairj) ],'c') ;
+           
+          % CIRCLES OF VALID 2THETAS
+          t=(0:1:360)' ;
+          circRthetas=2*rot_to_det*tand(valid_2thetas) ;
+          for k=1:length(circRthetas)
+            circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+            circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+            plot(circthetasX,circthetasY,'b') ;
+          end
+
+          if shown==false
+            circRthetas=2*rot_to_det*tand(valid_2thetas+thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+
+            circRthetas=2*rot_to_det*tand(valid_2thetas-thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+          end
+
+          hold off;
+
+          % DIFSPOTS
+    
+          figure(2);
+          difspim1=edf_read([difspotims1_directory, sprintf('/difspot%05d.edf', i)]) ;
+          imshow(difspim1, lowhigh) ;
+          rectangle('Position',[1,1,sp1.bbXsize,sp1.bbYsize],'EdgeColor','r') ;
+          title(sprintf('Difspot_A: %5d', i)) ;
+    
+          for k=1:length(sps2.id)
+            figure(k+2);
+            difspim2=edf_read([difspotims2_directory, sprintf('/difspot%05d.edf',sps2.id(k))]) ;
+            imshow(fliplr(difspim2), lowhigh) ;
+            no_im=k+2 ;
+            if k==pairj
+              rectangle('Position',[1,1,sps2.bbXsize(k),sps2.bbYsize(k)],'EdgeColor','g') ;
+              title(sprintf('Mathced difspot_B: %5d', sps2.id(k))) ;
+            else
+              title(sprintf('Difspot_B: %5d', sps2.id(k))) ;
+            end
+          end
+
+          if shown==true
+            for kk=no_im+1:pr_im
+              set(kk,'Visible','off') ;
+            end
+          end
+      
+          pr_im=length(sps2.id)+2 ;
+          shown=true;
+          drawnow ;
+         
+          if button==1
+            pause;
+          end
+          
+        end % show findings
+    
+    end % pair found
+    
+    if mod(i,100)==0
+      disp(sprintf('SpotID:  %d   Perfect pairs found:  %d   Perfect matching percentage:  %6.3f %s   Correction in pixels: %f',i,pairsfound,(pairsfound/i*100),'%', 0)) ;
+    end
+
+%    if ( <=conv_rate) | ( <=conv_pix) | (pairsfound==npairs)
+    if (pairsfound==npairs)
+      break ;
+    end
+    
+end % end of main loop for spots1
+
+%% Calculation of correction (in pixels)
+
+meanrad=[] ;
+nradius=[] ;
+thetas_vec=[] ;
+
+for ii=1:length(type)
+  spacing(ii)=parameters.acq.latticepar(1)/norm(reflections(ii,:)) ;   % in angstroms
+  nradius=[nradius, length(type(ii).radius)] ;
+  if length(type(ii).radius) ~= 0
+    meanrad=[meanrad, mean(type(ii).radius)] ;    % in pixels
+    thetas_vec=[thetas_vec, asind(lambda/(2*spacing(ii)))] ;
+  end
+end
+
+realdist_vec= meanrad./tand(2*thetas_vec)  % vector; in pixels
+corr_rottodet_pix_vec=realdist_vec-rot_to_det     % vector in pixels
+corr_rottodet_mm_vec=corr_rottodet_pix_vec*parameters.acq.pixelsize     % vector in mm-s
+
+mean(realdist_vec.*nonzeros(nradius)')
+corr_rottodet_pix=mean(corr_rottodet_pix_vec.*nonzeros(nradius)')
+corr_rottodet_mm=mean(corr_rottodet_mm_vec.*nonzeros(nradius)')
+
+% With strain:
+% d0=parameters.acq.latticepar(1)
+% theta=asind(lambda/2./(d0*[1-strain 1 1+strain])*norm(reflections(i,:)))
+
+%mym(sprintf('TRUNCATE %s',pairtable));
+
+mym('close')
+
+%=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels 
+
+disp(' ')
+disp(' ')
+disp('Total number of diffraction spots in set #1:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in set #2:'), disp(nof_spots2) ;
+disp('Number of pairs used for correction:'), disp(pairsfound) ;
+disp('    Number of pairs per plane family:'), disp(nradius) ;
+disp(' ')
+disp('Measured distance in pixels:')
+disp(rot_to_det)
+disp(' ')
+disp('Wavelength in angstroms:')
+disp(lambda)
+disp(' ')
+disp('D-spacings of the reflecting planes in angstroms:')
+disp(spacing)
+disp(' ')
+disp('Correction in mm-s:')
+disp(corr_rottodet_mm)
+disp('Correction in pixels:')
+disp(corr_rottodet_pix)
+
+disp(' ')
+toc
+disp(' ')
+
+end % of function
+
+
+%% Sub-functions used
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
+
diff --git a/4_spot_sorting/gtCorrelateDifspots.m b/4_spot_sorting/gtCorrelateDifspots.m
new file mode 100755
index 0000000000000000000000000000000000000000..54f89e60a0d4a3146523c1b60e8a6a0a25adcfde
--- /dev/null
+++ b/4_spot_sorting/gtCorrelateDifspots.m
@@ -0,0 +1,128 @@
+
+function [corrx,corry]=gtCorrelateDifspots(IDA,IDB,parameters,centmode,corrmode)
+
+%close all
+
+blobtable=[parameters.acq.difA_name 'difblobdetails'];
+%difspottable=[parameters.acq.difA_name 'difspot'];
+%spotpairtable=parameters.acq.pair_tablename;
+
+%[IDA,IDB]=mym(sprintf('SELECT difAID, difBID FROM %s where pairID=%d',spotpairtable,IDP));
+
+
+switch centmode
+  
+  case 1   % use difspot images (blobs or edf-s)
+    imA=gtGetSummedDifSpot(IDA, parameters, 1);
+    imB=fliplr(gtGetSummedDifSpot(IDB, parameters, 1));
+    %imB=gtGetSummedDifSpot(IDB, parameters, 1);
+
+  case 2   % use summed full images over the difblob bb (not thresholded on the edges) 
+ 
+    [volA,bbA]=gtDBBrowseDiffractionVolume(blobtable, IDA);
+
+    if isempty(volA)
+      sprintf('difspotID A %d has been exterminated',IDA)
+      corrx=[];
+      corry=[];
+      return
+    end
+
+    imA=zeros(bbA(5),bbA(4));
+    for fullIDA=bbA(3):bbA(3)+bbA(6)-1
+      imA=imA+edf_read(sprintf('1_preprocessing/full/full%04d.edf', fullIDA), bbA([1 2 4 5]));
+    end
+
+
+    [volB,bbB]=gtDBBrowseDiffractionVolume(blobtable, IDB);
+
+    if isempty(volB)
+      sprintf('difspotID B %d has been exterminated',IDB)
+      corrx=[];
+      corry=[];
+      return
+    end
+
+    imB=zeros(bbB(5),bbB(4));
+    for fullIDB=bbB(3):bbB(3)+bbB(6)-1
+      imB=imB+edf_read(sprintf('1_preprocessing/full/full%04d.edf', fullIDB), bbB([1 2 4 5]));
+    end
+
+end
+
+
+% sA1=size(imA,1);
+% sB1=size(imB,1);
+% sA2=size(imA,2);
+% sB2=size(imB,2);
+% 
+% imcA=imA;
+% imcB=imB;
+
+% from difspottable
+% [centXA,centYA,bbXAo,bbYAo]=mym(sprintf('SELECT CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin FROM %s where difspotID=%d',difspottable,IDA));
+% [centXB,centYB,bbXBo,bbYBo]=mym(sprintf('SELECT CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin FROM %s where difspotID=%d',difspottable,IDB));
+% 
+% centXAbb=centXA-bbXAo+1;
+% centYAbb=centYA-bbYAo+1;
+% 
+% centXBbb=centXB-bbXBo+1;
+% centXBbb=2*(sB2/2+0.5)-centXBbb; % flipped in the bb
+% centYBbb=centYB-bbYBo+1;
+
+%%%%%%
+%   xprofile=sum(imcA,1);
+%   yprofile=sum(imcA,2);
+%   centXAbb=(xprofile*(1:size(xprofile,2))')/sum(xprofile);
+%   centYAbb=(yprofile'*(1:size(yprofile,1))')/sum(yprofile);
+%   
+%   centXA=bbXAo+centXAbb-1
+%   centYA=bbYAo+centYAbb-1
+% %%%%%%
+% %%%%%%
+%   xprofile=sum(imcB,1);
+%   yprofile=sum(imcB,2);
+%   centXBbb=(xprofile*(1:size(xprofile,2))')/sum(xprofile)
+%   centYBbb=(yprofile'*(1:size(yprofile,1))')/sum(yprofile)
+% 
+%   centXB=bbXBo+centXBbb-1
+%   centYB=bbYBo+centYBbb-1
+%%%%%%
+
+%disp('centre of mass')
+%disp([centYAbb-centYBbb,centXAbb-centXBbb])
+
+%figure,imshow(imB,[])
+% hold on
+%  plot(centXBbb,centYBbb,'g+')
+%  plot(centXAbb,centYAbb,'r+')
+
+%figure,imshow(imA,[])
+% hold on
+%  plot(centXAbb,centYAbb,'g+')
+%  plot(centXBbb,centYBbb,'r+')
+ 
+
+
+
+imblank=zeros(max([size(imA,1) size(imB,1)]),max([size(imA,2) size(imB,2)]));
+
+imcA=gtPlaceSubImage(imA,imblank,1,1);
+imcB=gtPlaceSubImage(imB,imblank,1,1);
+
+switch corrmode
+  case 1
+    corr=correlate(imcA,imcB); % vector with which to move imcA into imcB
+  case 2
+    corr=correlaterealspace(imcA,imcB); % vector with which to move imcA into imcB
+end
+
+corrx=corr(2); % since imcB has been flipped, the negative of this correction 
+               %  should be applied to the original horizontal position of spot B
+corry=corr(1); % vertical correction
+
+
+
+findshifts2(imcA,imcB,'clims',[-100 100],'climt',[0 300])
+
+
diff --git a/4_spot_sorting/gtDiffPlaneNormInLab.m b/4_spot_sorting/gtDiffPlaneNormInLab.m
new file mode 100755
index 0000000000000000000000000000000000000000..3f3eaeeba948ef4abe7b2c152a5d92ad7f2ed212
--- /dev/null
+++ b/4_spot_sorting/gtDiffPlaneNormInLab.m
@@ -0,0 +1,42 @@
+%
+% FUNCTION plnorm=gtDiffPlaneNormInLab(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ)
+%
+% Given the Scintillator coordinates of pairs of diffraction spots, 
+% computes the diffracting plane normals they correspond to, according to
+% tilts and rotation axis to detector (scintillator) distance.
+%
+%   LAB system is right-handed and defined as: 
+%     origin X = on the rotation axis, positive towards the camera
+%     origin Y = on the rotation axis
+%     origin Z = floor(parameters.acq.ydet/2) in the middle of the central
+%                pixel row of the image, positive upwards
+% 
+% INPUT  scXA = coloumn vector of X coordinates on the Scintillator of point A (pixels or mm-s)
+%        scYA = coloumn vector of Y coordinates on the Scintillator of point A (pixels or mm-s)
+%        scXB = coloumn vector of X coordinates on the Scintillator of point B (pixels or mm-s)
+%        scYB = coloumn vector of Y coordinates on the Scintillator of point B (pixels or mm-s)
+%        rottodet = rotation axis to detector (scintillator) distance at rotx,sorZ (pixels or mm-s)
+%        /scX,scY,rottodet have to be in the same units; e.g. pixels or mm-s/
+%        tiltY = tilt around axis Y in Lab system (in degrees)
+%        tiltZ = tilt around axis Z in Lab system (in degrees)
+%        rotx = location of rotation axis in the images (X coord. in pixels)
+%        sorZ = Z=0 location in the images (Y coord. in pixels at the rotation axis) 
+%
+% OUTPUT plnorm = coloumn vector of plane normals of size(plnorm)=[n,3]
+%
+%
+
+
+function plnorm=gtDiffPlaneNormInLab(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ)
+
+dv= gtDiffVecInLab(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ); % diffraction vector
+
+plv= dv-repmat([1 0 0],size(dv,1),1); % plane vector
+
+plvnorm=sqrt(plv(:,1).^2+plv(:,2).^2+plv(:,3).^2) ; % norm of plane vectors
+
+plnorm(:,1)= plv(:,1)./plvnorm ; % normalized plane vectors
+plnorm(:,2)= plv(:,2)./plvnorm ;
+plnorm(:,3)= plv(:,3)./plvnorm ;
+
+end
diff --git a/4_spot_sorting/gtDiffVecInLab.m b/4_spot_sorting/gtDiffVecInLab.m
new file mode 100755
index 0000000000000000000000000000000000000000..9598c06fd3b3f05ceca2cf87c10e9a6155ccac6d
--- /dev/null
+++ b/4_spot_sorting/gtDiffVecInLab.m
@@ -0,0 +1,45 @@
+%
+% function Dv=gtDiffVecInLab(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ)
+%
+% Given the Scintillator coordinates of a pair of diffraction spots, 
+% computes the real theta angle they correspond to, according to tilts and 
+% rotation axis to detector (scintillator) distance.
+%
+%   LAB system is right-handed and defined as: 
+%     origin X = on the rotation axis, positive towards the camera
+%     origin Y = on the rotation axis
+%     origin Z = floor(parameters.acq.ydet/2) in the middle of the central
+%                pixel row of the image, positive upwards
+% 
+% INPUT  scXA = coloumn vector of X coordinates on the Scintillator of point A (pixels or mm-s)
+%        scYA = coloumn vector of Y coordinates on the Scintillator of point A (pixels or mm-s)
+%        scXB = coloumn vector of X coordinates on the Scintillator of point B (pixels or mm-s)
+%        scYB = coloumn vector of Y coordinates on the Scintillator of point B (pixels or mm-s)
+%        rottodet = rotation axis to detector (scintillator) distance at rotx,sorZ (pixels or mm-s)
+%        /scX,scY,rottodet have to be in the same units; e.g. pixels or mm-s/
+%        tiltY = tilt around axis Y in Lab system (in degrees)
+%        tiltZ = tilt around axis Z in Lab system (in degrees)
+%        rotx = location of rotation axis in the images (X coord. in pixels)
+%        sorZ = Z=0 location in the images (Y coord. in pixels at the rotation axis) 
+%
+%        e.g. ([234;334;434],[1444;1644;1944],[134;234;534],[555;545;535],
+%              3600,0.123,0.421,1026,1024)
+%
+% OUTPUT theta = coloumn vector of real theta angles
+%
+%        e.g. [7.3948; 7.1822; 6.9281]
+%
+%
+
+function Dv=gtDiffVecInLab(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ)
+
+Dv(:,1)=2*rottodet-sind(tiltZ).*(scXA+scXB-2*rotx)-sind(tiltY).*cosd(tiltZ).*(scYA+scYB-2*sorZ) ;
+Dv(:,2)=cosd(tiltZ).*(scXA+scXB-2*rotx)-sind(tiltY).*sind(tiltZ).*(scYA+scYB-2*sorZ) ;
+Dv(:,3)=-cosd(tiltY).*(scYA-scYB) ;
+
+Dnorm=sqrt(Dv(:,1).^2+Dv(:,2).^2+Dv(:,3).^2) ;
+Dv(:,1)=Dv(:,1)./Dnorm ; 
+Dv(:,2)=Dv(:,2)./Dnorm ;
+Dv(:,3)=Dv(:,3)./Dnorm ;
+
+end
diff --git a/4_spot_sorting/gtDoCombineGrains.m b/4_spot_sorting/gtDoCombineGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..10c9796161a9c1d2a04f3b5846dc068586eb8a83
--- /dev/null
+++ b/4_spot_sorting/gtDoCombineGrains.m
@@ -0,0 +1,169 @@
+function gtDoCombineGrains(list)
+
+%list, generated by combine_grains.m, is a list of which grains in the
+%4_grains/ directory should be merged [g1 g2 0; g3 0 0; g4 g9 0...]
+%create the "new" grains in a new directory for safety
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+
+
+%warning('starting combine grains from grain 100')
+for i=1:size(list,1)   %each of the new grains
+  
+old_grain_number = list(i,1);
+new_grain_number = i;%+ 150%to distinguish from centre slice grains
+%make the new directory
+mkdir(sprintf('4_grains/new_grains/grain%d_',new_grain_number))
+
+
+dummy=find(list(i,2:end)~=0);
+if isempty(dummy) %if no combining of grains, just a renumbering...
+  
+  tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',list(i,1),list(i,1)));%load the old grain
+  struct_ids=tmp.struct_ids;%need this for database update
+  pair_vector=tmp.pair_vector;%need this for database update
+  
+  %copy the old thresholded volume file (grain%d_2.edf) to the new place
+	try
+  cmd=sprintf('cp 4_grains/grain%d_/grain%d_2.edf 4_grains/new_grains/grain%d_/grain%d_2.edf',...
+    old_grain_number,old_grain_number,new_grain_number,new_grain_number);
+  unix(cmd)
+	end
+	try
+	%copy the old mat file to the new place
+  cmd=sprintf('cp 4_grains/grain%d_/grain%d_.mat 4_grains/new_grains/grain%d_/grain%d_.mat',...
+    old_grain_number,old_grain_number,new_grain_number,new_grain_number);
+  unix(cmd)
+	end
+	
+else%if two or more grains to be combined
+
+  %initialise variables fo the new grain
+  zstart=[];zend=[];
+  nx=[];x1=[];
+  ny=[];y1=[];
+  plane_normal=[];hkl=[];R_vector=[];
+  stack=[];
+  Omega=[];Theta=[];Eta=[];
+  struct_ids=[];
+  pair_vector=[];
+  index=[];replaced=[];lambda=[];
+  %some for calculations
+  maxx=[];maxy=[];
+  
+  for j=1:size(list,2) %max number of old grains to combine
+    if list(i,j)~=0    %ignoring zeros in list
+      tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',list(i,j),list(i,j)));%load the old grain
+      zstart = [zstart tmp.zstart];
+      zend = [zend tmp.zend];
+      x1 = [x1 tmp.x1];
+      y1 = [y1 tmp.y1];
+      maxx = [maxx (tmp.x1+tmp.nx)];
+      maxy = [maxy (tmp.y1+tmp.ny)];
+      stack = cat(3,stack,tmp.stack);
+      plane_normal = [plane_normal; tmp.plane_normal];
+			R_vector = [R_vector; tmp.R_vector];
+			lambda = [lambda; tmp.lambda];
+      hkl = [hkl; tmp.hkl];
+      Omega = [Omega tmp.Omega];
+      Theta = [Theta tmp.Theta];
+      Eta = [Eta tmp.Eta];
+      struct_ids = [struct_ids tmp.struct_ids];
+      
+      if isfield(tmp,'pair_vector')
+        pair_vector = [pair_vector tmp.pair_vector];
+      else
+        addpair_vector = logical(ones(1,length(tmp.struct_ids)));
+        pair_vector = [pair_vector tmp.pair_vector];
+      end
+
+      if isfield(tmp,'index') && length(tmp.index)==length(tmp.struct_ids)%some have wrong length index!
+        addindex = reshape(tmp.index,1,length(tmp.struct_ids));%make into a row
+        index = [index addindex];
+      else
+        addindex = logical(ones(1,length(tmp.struct_ids)));
+        index = [index addindex];
+      end
+      
+      if isfield(tmp,'replaced') && length(tmp.replaced)==length(tmp.struct_ids)
+        addreplaced = reshape(tmp.replaced,1,length(tmp.struct_ids));%make into a row
+        replaced = [replaced addreplaced];
+      else
+        addreplaced = logical(zeros(1,length(tmp.struct_ids)));
+        replaced = [replaced addreplaced];
+      end
+
+    end
+  end
+  
+  
+  %sort where needed
+  zstart = min(zstart);
+  zend = max(zend);
+  zcenter = ceil((zstart+zend)/2);
+  x1 = min(x1);
+  y1 = min(y1);
+  maxx = max(maxx);
+  maxy = max(maxy);
+  nx = maxx-x1;
+  ny = maxy-y1;
+	xcenter = ceil((x1+nx)/2);
+	ycenter = ceil((y1+ny)/2);
+  [Omega,tmp]=sort(Omega);
+  Theta = Theta(tmp);
+  Eta = Eta(tmp);
+  struct_ids = struct_ids(tmp);
+  pair_vector=pair_vector(tmp);
+  plane_normal = plane_normal(tmp,:);
+	R_vector=mean(R_vector,1);
+	lambda = mean(lambda,1);
+  hkl = hkl(tmp,:);
+  stack = stack(:,:,tmp);
+  index = index(tmp);
+  replaced = replaced(tmp);
+  
+  %may need also to remove duplicates....
+  [struct_ids,tmp]=unique(struct_ids);
+  pair_vector=pair_vector(tmp);
+  Omega=Omega(tmp);
+  Theta=Theta(tmp);
+  Eta=Eta(tmp);
+  index=index(tmp);
+  replaced=replaced(tmp);
+  plane_normal=plane_normal(tmp,:);
+  hkl=hkl(tmp,:);
+  stack=stack(:,:,tmp);
+  
+  
+  
+  %write the new grain%d_.mat
+  name = sprintf('4_grains/new_grains/grain%d_/grain%d_.mat',new_grain_number,new_grain_number);
+  save(name,'struct_ids','pair_vector','stack','Theta','Eta','Omega','plane_normal','hkl','R_vector',...
+		'zstart','zend','zcenter','x1','nx','xcenter','y1','ny','ycenter','index','replaced','lambda');
+  
+  
+end
+
+  %update database with new grainids
+  disp('update GrainID field in database')
+  for k=1:length(struct_ids)
+    
+    if pair_vector(k)==2
+      db_name=parameters.acq.pair_name;
+    else
+      db_name=parameters.acq.name;
+    end
+    
+    mym(sprintf('update %sextspot set GrainID=%d where extspotID=%d',...
+      db_name,new_grain_number,struct_ids(k)))
+    mym(sprintf('update %sbb set GrainID=%d where extspotID=%d',...
+      db_name,new_grain_number,struct_ids(k)))
+  end
+  
+end
+
+disp('Done!')
\ No newline at end of file
diff --git a/4_spot_sorting/gtDoCombineGrains2.m b/4_spot_sorting/gtDoCombineGrains2.m
new file mode 100755
index 0000000000000000000000000000000000000000..c27c4a6d965094289fa4812afa4e5a4f89149c37
--- /dev/null
+++ b/4_spot_sorting/gtDoCombineGrains2.m
@@ -0,0 +1,169 @@
+function gtDoCombineGrains2(list)
+
+%list, generated by combine_grains2.m, is a list of which grains in the
+%4_grains/ directory should be merged [g1 g2 0; g3 0 0; g4 g9 0...]
+
+%rather than moving everything around, rather just add data to the .mat
+%file of the first grain, and set the bad value of the others to 2.  Make
+%sure that the bad value of this first grain is 0 (could have been 0.5
+%before)
+
+  %avoid using this old version by mistake!
+  check=inputwdefault('should use version _360!!!  continue with this old version? (y/n)', 'n');
+    if check=='n'
+    return
+    end
+ 
+
+  load parameters.mat
+
+gtDBConnect
+
+for i=1:size(list,1)   %each of the new grains
+  
+  %initialise variables fo the new grain
+  zstart=[];zend=[];
+  nx=[];x1=[];
+  ny=[];y1=[];
+  plane_normal=[];hkl=[];R_vector=[];
+  stack=[];
+  Omega=[];Theta=[];Eta=[];
+  struct_ids=[];
+  pair_vector=[];
+  index=[];replaced=[];lambda=[];
+  %some for calculations
+  maxx=[];maxy=[];
+  
+  for j=1:size(list,2) %max number of old grains to combine
+    if list(i,j)~=0    %ignoring zeros in list
+  
+      tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',list(i,j),list(i,j)));%load the old grain
+      zstart = [zstart tmp.zstart];
+      zend = [zend tmp.zend];
+      x1 = [x1 tmp.x1];
+      y1 = [y1 tmp.y1];
+      maxx = [maxx (tmp.x1+tmp.nx)];
+      maxy = [maxy (tmp.y1+tmp.ny)];
+      stack = cat(3,stack,tmp.stack);
+      plane_normal = [plane_normal; tmp.plane_normal];
+			R_vector = [R_vector; tmp.R_vector]; %in fact will recalculate this!
+			lambda = [lambda; tmp.lambda];
+      hkl = [hkl; tmp.hkl];
+      Omega = [Omega tmp.Omega];
+      Theta = [Theta tmp.Theta];
+      Eta = [Eta tmp.Eta];
+      struct_ids = [struct_ids tmp.struct_ids];
+      
+      if isfield(tmp,'pair_vector')
+        pair_vector = [pair_vector tmp.pair_vector];
+			else
+				addpair_vector = logical(ones(1,length(tmp.struct_ids)));
+        pair_vector = [pair_vector addpair_vector]%tmp.pair_vector];
+      end
+
+      if isfield(tmp,'index') && length(tmp.index)==length(tmp.struct_ids)%some have wrong length index!
+        addindex = reshape(tmp.index,1,length(tmp.struct_ids));%make into a row
+        index = [index addindex];
+      else
+        addindex = logical(ones(1,length(tmp.struct_ids)));
+        index = [index addindex];
+      end
+      
+      if isfield(tmp,'replaced') && length(tmp.replaced)==length(tmp.struct_ids)
+        addreplaced = reshape(tmp.replaced,1,length(tmp.struct_ids));%make into a row
+        replaced = [replaced addreplaced];
+      else
+        addreplaced = logical(zeros(1,length(tmp.struct_ids)));
+        replaced = [replaced addreplaced];
+      end
+
+    end %ignoring zeros
+  end %for each grain to be combined
+  
+  
+  %sort where needed
+  zstart = min(zstart);
+  zend = max(zend);
+  zcenter = ceil((zstart+zend)/2);
+  x1 = min(x1);
+  y1 = min(y1);
+  maxx = max(maxx);
+  maxy = max(maxy);
+  nx = maxx-x1;
+  ny = maxy-y1;
+	xcenter = ceil((x1+nx)/2);
+	ycenter = ceil((y1+ny)/2);
+  [Omega,tmp]=sort(Omega);
+  Theta = Theta(tmp);
+  Eta = Eta(tmp);
+  struct_ids = struct_ids(tmp);
+  pair_vector=pair_vector(tmp);
+  plane_normal = plane_normal(tmp,:);
+	R_vector=mean(R_vector,1);
+	lambda = mean(lambda,1);
+  hkl = hkl(tmp,:);
+  stack = stack(:,:,tmp);
+  index = index(tmp);
+  replaced = replaced(tmp);
+  
+  %may need also to remove duplicates....
+  [struct_ids,tmp]=unique(struct_ids);
+  pair_vector=pair_vector(tmp);
+  Omega=Omega(tmp);
+  Theta=Theta(tmp);
+  Eta=Eta(tmp);
+  index=index(tmp);
+  replaced=replaced(tmp);
+  plane_normal=plane_normal(tmp,:);
+  hkl=hkl(tmp,:);
+  stack=stack(:,:,tmp);
+  
+  %now have collected the new data, ready to write to the new .mat
+  
+  %first check orientation / consistancy
+  [R_vector, good_list]=plot_rodrigues_consistancy(plane_normal(find(index),:),hkl(find(index),:),0);
+  
+
+  %set other bad flags to 2
+  for j=2:size(list,2) 
+    if list(i,j)~=0    %ignoring zeros in list
+      bad=2;
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',list(i,j),list(i,j)),'bad','-append');
+    end
+  end
+      
+      %bad flag for the new grain = 0 (good)
+      bad=0;
+  
+
+  
+  
+  %save combined info into the first grain mat file
+  name = sprintf('4_grains/grain%d_/grain%d_.mat',list(i,1),list(i,1));
+  save(name,'struct_ids','pair_vector','stack','Theta','Eta','Omega','plane_normal','hkl','R_vector',...
+		'zstart','zend','zcenter','x1','nx','xcenter','y1','ny','ycenter','index','replaced','lambda','bad','-append');
+  
+  
+
+  %update database with new grainids
+  disp('update GrainID field in database')
+  for k=1:length(struct_ids)
+    
+    if pair_vector(k)==2
+      db_name=parameters.acq.pair_name;
+    else
+      db_name=parameters.acq.name;
+    end
+    
+    mym(sprintf('update %sextspot set GrainID=%d where extspotID=%d',...
+      db_name,list(i,1),struct_ids(k)))
+
+  end
+  
+  %write the stack (replaced) for the combined grain
+  gtWriteStack_replaced(list(i,1));
+  
+  
+end
+
+disp('Done!')
\ No newline at end of file
diff --git a/4_spot_sorting/gtDoCombineGrains_360.m b/4_spot_sorting/gtDoCombineGrains_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..b53131a94417f268a4c451758d9a24638907d81d
--- /dev/null
+++ b/4_spot_sorting/gtDoCombineGrains_360.m
@@ -0,0 +1,266 @@
+function gtDoCombineGrains_360(list)
+
+%list, generated by combine_grains2.m, is a list of which grains in the
+%4_grains/ directory should be merged [g1 g2 0; g3 0 0; g4 g9 0...]
+
+%rather than moving everything around, rather just add data to the .mat
+%file of the first grain, and set the bad value of the others to 2.  Make
+%sure that the bad value of this first grain is 0 (could have been 0.5
+%before)
+
+%360 degree scan concept, no pair vectors
+
+  load parameters.mat
+
+gtDBConnect
+
+for i=1:size(list,1)   %each of the new grains
+  
+  %initialise variables fo the new grain
+  zstart=[];zend=[];
+  nx=[];x1=[];
+  ny=[];y1=[];
+  xcenter=[]; ycenter=[]; zcenter=[];
+  plane_normal=[];hkl=[];R_vector=[];
+  stack=[];
+  Omega=[];Theta=[];Eta=[];
+  struct_ids=[];
+  index=[];replaced=[];lambda=[];
+  %some for calculations
+  maxx=[];maxy=[];
+  
+  for j=1:size(list,2) %max number of old grains to combine
+    if list(i,j)~=0    %ignoring zeros in list
+        % modif sabine to keep original mat file
+        cmd = sprintf('cp 4_grains/grain%d_/grain%d_.mat 4_grains/grain%d_/grain%d_.mat_original', list(i,j), list(i,j), list(i,j), list(i,j));
+      % cmd = sprintf('cp grain%d_/grain%d_.mat grain%d_/grain%d_.mat_original', list(i,j), list(i,j), list(i,j), list(i,j));
+
+      unix(cmd);
+        % fin modif sabine
+      
+      tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',list(i,j),list(i,j)));%load the old grain
+    % tmp = load(sprintf('grain%d_/grain%d_.mat',list(i,j),list(i,j)));%load the old grain
+      zstart = [zstart tmp.zstart];
+      zend = [zend tmp.zend];
+      x1 = [x1 tmp.x1];
+      y1 = [y1 tmp.y1];
+      xcenter = [xcenter tmp.xcenter];
+      ycenter = [ycenter tmp.ycenter];
+      zcenter = [zcenter tmp.zcenter];
+      maxx = [maxx (tmp.x1+tmp.nx)];
+      maxy = [maxy (tmp.y1+tmp.ny)];
+      stack = cat(3,stack,tmp.stack);
+      plane_normal = [plane_normal; tmp.plane_normal];
+			R_vector = [R_vector; tmp.R_vector]; %in fact will recalculate this!
+			lambda = [lambda; tmp.lambda];
+      hkl = [hkl; tmp.hkl];
+      Omega = [Omega tmp.Omega];
+      Theta = [Theta tmp.Theta];
+      Eta = [Eta tmp.Eta];
+      struct_ids = [struct_ids tmp.struct_ids];
+      
+
+      if isfield(tmp,'index') && length(tmp.index)==length(tmp.struct_ids)%some have wrong length index!
+        addindex = reshape(tmp.index,1,length(tmp.struct_ids));%make into a row
+        index = [index addindex];
+      else
+        addindex = logical(ones(1,length(tmp.struct_ids)));
+        index = [index addindex];
+      end
+      
+      if isfield(tmp,'replaced') && length(tmp.replaced)==length(tmp.struct_ids)
+        addreplaced = reshape(tmp.replaced,1,length(tmp.struct_ids));%make into a row
+        replaced = [replaced addreplaced];
+      else
+        addreplaced = logical(zeros(1,length(tmp.struct_ids)));
+        replaced = [replaced addreplaced];
+      end
+
+    end %ignoring zeros
+  end %for each grain to be combined
+  
+  
+  %sort where needed
+  zstart = min(zstart);
+  zend = max(zend);
+  %zcenter = ceil((zstart+zend)/2);
+  zcenter=ceil(mean(zcenter));
+  x1 = min(x1);
+  y1 = min(y1);
+  maxx = max(maxx);
+  maxy = max(maxy);
+  nx = maxx-x1;
+  ny = maxy-y1;
+%	xcenter = ceil((x1+nx)/2);
+%	ycenter = ceil((y1+ny)/2);
+  xcenter=ceil(mean(xcenter));
+  ycenter=ceil(mean(ycenter));
+  [Omega,tmp]=sort(Omega);
+  Theta = Theta(tmp);
+  Eta = Eta(tmp);
+  struct_ids = struct_ids(tmp);
+  plane_normal = plane_normal(tmp,:);
+	R_vector=mean(R_vector,1);
+%	lambda = mean(lambda,1); % modif sabine
+  hkl = hkl(tmp,:);
+  stack = stack(:,:,tmp);
+  index = index(tmp);
+  replaced = replaced(tmp);
+  
+  %may need also to remove duplicates....
+  [struct_ids,tmp]=unique(struct_ids);
+  Omega=Omega(tmp);
+  Theta=Theta(tmp);
+  Eta=Eta(tmp);
+  index=index(tmp);
+  replaced=replaced(tmp);
+  plane_normal=plane_normal(tmp,:);
+  hkl=hkl(tmp,:);
+  stack=stack(:,:,tmp);
+  
+  % modif sabine
+  if length(struct_ids)>40
+      lambda = [0.1 0.05 0.02];
+  elseif length(struct_ids)>30
+      %lambda = [0.3 0.2 0.1]; %initial values
+      lambda = [0.2 0.1 0.05]; %initial values - sheared difspots
+  elseif length(struct_ids)>15
+      %lambda = [0.5 0.3 0.1]; %initial values
+      lambda = [0.3 0.2 0.1]; %initial values - sheared difspots
+  else
+      %lambda = [0.7 0.3 0.2]; %initial values
+      lambda = [0.4 0.25 0.15]; %initial values - sheared difspots
+  end
+  
+  % fin modif sabine
+  
+  if 1 %sheared difspots
+    acq=parameters.acq;
+  
+  %don't know why this isn't work.  use an average center for the moment  
+%       %If using sheared difspots, need to recalulate the grain centre, and then
+%     %rebuild the difstack
+%     %centre:
+%     lines=[];% [point, direction]
+%     %get all pair information available
+%     for k=1:length(struct_ids)
+%       mysqlcmd=sprintf('select samcentXA,samcentYA,samcentZA,ldirZ,ldirY,ldirZ from %s where difAID=%d or difBID=%d',...
+%         acq.pair_tablename, struct_ids(k), struct_ids(k));
+%       [a,b,c,d,e,f]=mym(mysqlcmd);
+%       if ~isempty(a)
+%         lines(end+1,:)=[a b c d e f];
+%       end
+%     end
+%     keyboard
+%     lines=unique(lines, 'rows');
+%     grain.center=pofintersectexp(lines)'; % new center of mass
+%     grain.xcenter= (acq.bb(3)/2)+grain.center(2);
+%     grain.ycenter= (acq.bb(3)/2)+grain.center(1);
+%     grain.zcenter= -grain.center(3)+acq.ydet/2-acq.bb(2);
+% 
+  
+
+  
+  %add other fields to grain to pass to dtShearDifspots
+  grain.struct_ids=struct_ids;
+  grain.theta=Theta;
+  grain.eta=Eta;
+  grain.xcenter=xcenter;
+  grain.ycenter=ycenter;
+  grain.zcenter=zcenter;
+  %get Omega from difspot table to ensure no confusion between real/sheared
+  %values
+  for k=1:length(struct_ids)
+    Omega(k)=mym(sprintf('select CentroidImage from %sdifspot where difspotid=%d', acq.name,struct_ids(k)));
+  end
+  Omega = Omega/(acq.nproj*2)*360;
+  grain.omega=Omega;
+  [stack, difomega]=gtShearDifspots(grain);
+  %finally save the sheared values to the .mat file
+  Omega=difomega;
+  end
+  
+  
+  %now have collected the new data, ready to write to the new .mat
+  
+  %first check orientation / consistancy
+  [R_vector, good_list]=plot_rodrigues_consistancy_test(plane_normal(find(index),:),hkl(find(index),:),0);
+  
+
+  %set other bad flags to 2
+  for j=2:size(list,2) 
+    if list(i,j)~=0    %ignoring zeros in list
+      bad=2;
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',list(i,j),list(i,j)),'bad','-append');
+    end
+  end
+      
+      %bad flag for the new grain = 0 (good)
+      bad=0;
+  
+
+  
+  
+  %save combined info into the first grain mat file
+  
+   name = sprintf('4_grains/grain%d_/grain%d_.mat',list(i,1),list(i,1));
+%  name = sprintf('grain%d_/grain%d_.mat',list(i,1),list(i,1));
+
+% modif sabine
+if length(struct_ids)>40
+      lambda = [0.1 0.05 0.02];
+  elseif length(struct_ids)>30
+      %lambda = [0.3 0.2 0.1]; %initial values
+      lambda = [0.2 0.1 0.05]; %initial values - sheared difspots
+  elseif length(struct_ids)>15
+      %lambda = [0.5 0.3 0.1]; %initial values
+      lambda = [0.3 0.2 0.1]; %initial values - sheared difspots
+  else
+      %lambda = [0.7 0.3 0.2]; %initial values
+      lambda = [0.4 0.25 0.15]; %initial values - sheared difspots
+end
+
+  
+% fin modif sabine
+
+
+
+  save(name,'struct_ids','stack','Theta','Eta','Omega','plane_normal','hkl','R_vector',...
+		'zstart','zend','zcenter','x1','nx','xcenter','y1','ny','ycenter','index','replaced','lambda','bad','-append');
+  
+
+  %update database with new grainids
+  disp('update GrainID field in database')
+  extspot_failed=0;
+  for k=1:length(struct_ids)
+    
+    try
+    mym(sprintf('update %sextspot set GrainID=%d where extspotID=%d',...
+      parameters.acq.name,list(i,1),struct_ids(k)))
+    catch
+    extspot_failed=1;
+    end
+
+    mym(sprintf('update %sdifspot set GrainID=%d where difspotID=%d',...
+      parameters.acq.name,list(i,1),struct_ids(k)))
+  end
+  if extspot_failed
+      disp('no extspot table found for this sample - not updating!')
+  end
+  
+  %write the stack (replaced) for the combined grain
+ 
+  gtWriteStack_360(list(i,1));
+  
+  
+  %repeat the autoselecting of which projections to use
+  try
+    %not many licences, and not  critical
+  gt_select_projections_auto(list(i,1), 0); %0 is plotflag
+  end
+  %rerun ART
+  gtDoART(list(i,1));
+  
+end
+
+disp('Done!')
\ No newline at end of file
diff --git a/4_spot_sorting/gtEtaOfPairs.m b/4_spot_sorting/gtEtaOfPairs.m
new file mode 100755
index 0000000000000000000000000000000000000000..f47dd458ae326adb9deb95a5900297a4aaab7f81
--- /dev/null
+++ b/4_spot_sorting/gtEtaOfPairs.m
@@ -0,0 +1,71 @@
+%
+% function etas=gtEtaOfPairs(scXA,scYA,scXB,scYB,tiltY,tiltZ,rotx,sorZ)
+%
+% Given the Scintillator coordinates of a pair of diffraction spots, 
+% computes the real eta angle they correspond to, according to tilts.
+%
+%   LAB system is right-handed and defined as: 
+%     origin X = on the rotation axis, positive towards the camera
+%     origin Y = on the rotation axis
+%     origin Z = floor(parameters.acq.ydet/2) in the middle of the central
+%                pixel row of the image, positive upwards
+% 
+% INPUT  scXA = coloumn vector of X coordinates on the Scintillator of point A (pixels or mm-s)
+%        scYA = coloumn vector of Y coordinates on the Scintillator of point A (pixels or mm-s)
+%        scXB = coloumn vector of X coordinates on the Scintillator of point B (pixels or mm-s)
+%        scYB = coloumn vector of Y coordinates on the Scintillator of point B (pixels or mm-s)
+%        /scX,scY have to be in the same units; e.g. pixels or mm-s/
+%        tiltY = tilt around axis Y in Lab system (in degrees)
+%        tiltZ = tilt around axis Z in Lab system (in degrees)
+%        rotx = location of rotation axis in the images (X coord. in pixels)
+%        sorZ = Z=0 location in the images (Y coord. in pixels at the rotation axis) 
+%
+%        e.g. ([234;334;434],[1444;1644;1944],[134;234;534],[555;545;535],
+%              0.123,0.421,1026,1024)
+%
+% OUTPUT etas = coloumn vector of real eta angles
+%
+%        e.g. [22.5448; 165.1822; 345.9281]
+%
+%
+
+function etas=gtEtaOfPairs(scXA,scYA,scXB,scYB,tiltY,tiltZ,rotx,sorZ)
+
+% Diffraction vector coordinates
+%Dv1=2*rottodet-sind(tiltZ).*(scXA+scXB-2*rotx)-sind(tiltY).*cosd(tiltZ).*(scYA+scYB-2*sorZ) ;
+Dv2=cosd(tiltZ).*(scXA+scXB-2*rotx)-sind(tiltY).*sind(tiltZ).*(scYA+scYB-2*sorZ) ;
+Dv3=-cosd(tiltY).*(scYA-scYB) ;
+
+etas=gtEtaOfPoint(Dv2,Dv3);
+
+% etas=zeros(length(Dv2),1);
+% 
+% for i=1:length(Dv2)
+%   if Dv2(i) > 0  % 0 < eta < 180deg
+%     if Dv3(i) > 0  % 0 < eta < 90deg
+%       etas(i)=atand(Dv2(i)/Dv3(i)) ;
+%     elseif Dv3(i) == 0 
+%       etas(i)=90;
+%     else  % 90deg < eta < 180deg
+%       etas(i)=atand(Dv2(i)/Dv3(i))+180 ;
+%     end
+%   elseif Dv2(i) == 0
+%     if Dv3(i) > 0
+%       etas(i)=0 ;
+%     elseif Dv3(i) == 0 
+%       etas(i)=0;
+%     else
+%       etas(i)=180 ;
+%     end
+%   else  % 180deg < eta < 360deg
+%     if Dv3(i) < 0  % 180deg < eta < 270deg
+%       etas(i)=atand(Dv2(i)/Dv3(i))+180 ;
+%     elseif Dv3(i) == 0
+%       etas(i)=270;
+%     else  % 270deg < eta < 360deg
+%       etas(i)=atand(Dv2(i)/Dv3(i))+360 ;
+%     end
+%   end
+% end
+
+end
diff --git a/4_spot_sorting/gtEtaOfPoint.m b/4_spot_sorting/gtEtaOfPoint.m
new file mode 100755
index 0000000000000000000000000000000000000000..ebd81dd0b2ab7efdff5ae1a453c1e07127b170d8
--- /dev/null
+++ b/4_spot_sorting/gtEtaOfPoint.m
@@ -0,0 +1,41 @@
+% Eta angle from lab coordinates (e.g. diff vectors).
+%
+% Lab coordinates (right-handed):
+%   x: along the beam
+%   y: horizontal (+x in images)
+%   z: vertical upwards (-y in images) 
+
+
+function etas=gtEtaOfPoint(y,z)
+
+etas=zeros(length(y),1);
+
+
+
+for i=1:length(y)
+  if y(i) > 0  % 0 < eta < 180deg
+    if z(i) > 0  % 0 < eta < 90deg
+      etas(i)=atand(y(i)/z(i)) ;
+    elseif z(i) == 0 
+      etas(i)=90;
+    else  % 90deg < eta < 180deg
+      etas(i)=atand(y(i)/z(i))+180 ;
+    end
+  elseif y(i) == 0
+    if z(i) > 0
+      etas(i)=0 ;
+    elseif z(i) == 0 
+      etas(i)=0;
+    else
+      etas(i)=180 ;
+    end
+  else  % 180deg < eta < 360deg
+    if z(i) < 0  % 180deg < eta < 270deg
+      etas(i)=atand(y(i)/z(i))+180 ;
+    elseif z(i) == 0
+      etas(i)=270;
+    else  % 270deg < eta < 360deg
+      etas(i)=atand(y(i)/z(i))+360 ;
+    end
+  end
+end
diff --git a/4_spot_sorting/gtEvaluateDifspotMatch.m b/4_spot_sorting/gtEvaluateDifspotMatch.m
new file mode 100755
index 0000000000000000000000000000000000000000..504cacabf2a07749ca1ff6f98af9d2f8cff499fa
--- /dev/null
+++ b/4_spot_sorting/gtEvaluateDifspotMatch.m
@@ -0,0 +1,332 @@
+%
+% FUNCTION gtEvaluateDifspotMatch(whichID,varargin)
+%
+% Does not modify any data, only gives feedback on how good
+% the matching of diffraction spots is by showing pairs from database 
+% according to the given difspotID-s from the first set.
+% Run from the main folder of the scan (it uses the parameters file).
+%
+% USAGE e.g.
+%    gtEvaluateDifspotMatch([],'pair_dist')
+%    gtEvaluateDifspotMatch([200:300],'pairfigure','pairdata','dopause','button')
+%    gtEvaluateDifspotMatch([1000:4000],'table','tol_hist')
+% 
+% INPUT  
+%   whichID:  vector of difspotID-s from the first set to be shown; if
+%             empty, all are shown
+%   'pairfigure': pairs found are shown graphically
+%   'pairdata':   table of spot properties for comparison
+%   'table':      table for comparison (feedback to check tolerances)           
+%   'tol_hist':   histogram of properties of pair members (to check tolerances)
+%   'pair_dist':  pair distribution vs omega, eta, and eta vs theta   
+%   'dopause':    pause in sec or 'button' after each pair. Use it in pair:
+%                  'dopause','button' or e.g. 'dopause',2 .
+% 
+% OUTPUT  figures and tables for comparison
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+
+
+function gtEvaluateDifspotMatch(whichID,varargin)
+
+
+load parameters.mat
+
+
+%% Set parameters %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+par.dopause=[];
+par.pairfigure=false;
+par.pairdata=false;
+par.table=false;
+par.tol_hist=false;
+par.pair_dist=false;
+
+par=sfParseFunctionInput(par,varargin);
+
+
+% Thresholds for image position 
+thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees
+thr_max_offset=parameters.match.thr_max_offset;     % MaxImage offset threshold; absolut value in #images
+thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images
+corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels  
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+thr_intint=parameters.match.thr_intint;             % integrated intensity
+thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box
+thr_bbsize=parameters.match.thr_bbsize;             % bounding box size
+
+sample_radius=parameters.acq.bb(3)/2;
+sample_top=parameters.acq.bb(2);
+sample_bot=parameters.acq.bb(2)+parameters.acq.bb(4);
+rot_to_det=parameters.acq.dist/parameters.acq.pixelsize + corr_rot_to_det;
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+%sorZ=sample_top;  % at the top of the sample bounding box (acquisition); lowest number in pixels
+
+%fullimages_directory=sprintf('%s/1_preprocessing/full',parameters.acq.dir) ;
+
+pairtable=parameters.acq.pair_tablename ;
+difspottable=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+
+nproj=parameters.acq.nproj; % number of preojections per 180 degrees
+
+gtDBConnect
+
+%close all
+
+[tmp,results]=gtnew_calculate_twotheta();
+comp_2thetas=results.centre; % coloumn vector of all valid 2theta angles in degrees
+
+
+if ~exist('whichID','var')
+  whichID=[];
+end
+  
+if isempty(whichID)
+  whichID=mym(sprintf('Select difspotID from %s',difspottable));
+end
+
+cmp=[];
+
+
+%% Main loop for spotsA
+if par.pairdata || par.pairfigure || par.tol_hist || par.table
+
+  for i=1:length(whichID)      
+ 
+   [sp1.id,sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral]=...
+        mym(sprintf(['select difspotID,CentroidImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+        'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d'],difspottable,whichID(i))) ;
+
+   [pairID,sp1.pair,theta,eta,omega]=mym(sprintf('select pairID,difBID,theta,eta,omega from %s where difAID=%d', pairtable, whichID(i)));   
+      
+   if isempty(sp1.pair)
+     if par.pairdata
+       disp(sprintf('Difspot of ID %d is not matched',whichID(i)))
+     end
+     continue
+   end
+     
+   [sp2.id,sp2.maxim,sp2.extstim,sp2.extendim,sp2.area,sp2.centX,sp2.centY,sp2.bbX,sp2.bbY,sp2.bbXsize,sp2.bbYsize,sp2.integral]=...
+        mym(sprintf(['select difspotID,CentroidImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+        'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d'],difspottable,sp1.pair)) ;
+
+   add_cmp.pairID=pairID;
+   add_cmp.id1=sp1.id;
+   add_cmp.id2=sp2.id;
+   add_cmp.maxim=sp2.maxim-sp1.maxim;
+   add_cmp.extstim=sp2.extstim-sp1.extstim;
+   add_cmp.extendim=sp2.extendim-sp1.extendim;
+   add_cmp.integral=sp2.integral/sp1.integral*100;
+   add_cmp.area=sp2.area/sp1.area*100;
+   add_cmp.bbXsize=sp2.bbXsize/sp1.bbXsize*100;
+   add_cmp.bbYsize=sp2.bbYsize/sp1.bbYsize*100;
+   
+   cmp=[cmp, add_cmp];
+     
+   pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;     
+      
+   if par.pairdata
+     disp(' ')
+     disp(' difspotID    CentroidIm   ExtStartIm   ExtEndIm     Integral     Area         BBoxXsize    BBoxYsize')
+     disp('+----------+ +----------+ +----------+ +----------+ +----------+ +----------+ +----------+ +----------+')
+     disp(sprintf(' %10d   %10.3f   %10d   %10d   %10d   %10d   %10d   %10d', ...
+       sp1.id,sp1.maxim,sp1.extstim,sp1.extendim,sp1.integral,sp1.area,sp1.bbXsize,sp1.bbYsize)) ;
+     disp(sprintf(' %10d   %10.3f   %10d   %10d   %10d   %10d   %10d   %10d', ...
+       sp2.id,sp2.maxim,sp2.extstim,sp2.extendim,sp2.integral,sp2.area,sp2.bbXsize,sp2.bbYsize)) ;
+     disp(sprintf(' Pair %5d   %8.3fim   %8dim   %8dim   %9.2f%%   %9.2f%%   %9.2f%%   %9.2f%% ', ...
+        pairID,add_cmp.maxim,add_cmp.extstim,add_cmp.extendim,add_cmp.integral,add_cmp.area,add_cmp.bbXsize,add_cmp.bbYsize));
+   end
+                
+   if par.pairfigure
+     gtShowPairFigure(1,parameters,sp1,sp2,pr_bb,comp_2thetas,0,[],[],[],omega,theta,eta)
+   end
+
+   if strcmpi('button',par.dopause)
+     waitforbuttonpress
+   else
+     pause(par.dopause)
+   end
+      
+  end % end of main loop for spots1
+end
+  
+if par.table
+  disp(' ')
+  disp(' TABLE FOR COMPARISON ')
+  disp(' ')
+  disp(' difspotIDA   difspotIDB   Pair ID      CentroidIm   ExtStartIm   ExtEndIm     Integral     Area         BBoxXsize    BBoxYsize')
+  disp('+----------+ +----------+ +----------+ +----------+ +----------+ +----------+ +----------+ +----------+ +----------+ +----------+')
+  for i=1:length(cmp)
+    if ~isempty(cmp(i).pairID)
+      disp(sprintf(' %10d   %10d   %10d   %8.3fim   %8dim   %8dim   %9.2f%%   %9.2f%%   %9.2f%%   %9.2f%% ', ...
+        cmp(i).id1,cmp(i).id2,cmp(i).pairID,cmp(i).maxim,cmp(i).extstim,cmp(i).extendim,cmp(i).integral,cmp(i).area,cmp(i).bbXsize,cmp(i).bbYsize));
+    end
+  end
+end
+
+if par.tol_hist
+ 
+  for i=1:length(cmp)
+    hist_maxim(i)=cmp(i).maxim;
+    hist_extstim(i)=cmp(i).extstim;
+    hist_extendim(i)=cmp(i).extendim;
+    hist_integral(i)=cmp(i).integral;
+    hist_area(i)=cmp(i).area;
+    hist_bbXsize(i)=cmp(i).bbXsize;
+    hist_bbYsize(i)=cmp(i).bbYsize;
+  end
+
+  bins=max([10 ceil(length(cmp)/20)]);
+  centbins=nproj-ceil(thr_max_offset):0.1:nproj+ceil(thr_max_offset);
+  extbins=(nproj-ceil(thr_ext_offset)):(nproj+ceil(thr_ext_offset));
+
+  figure('name','Difference in Centroid Images B-A')
+  hist(hist_maxim,centbins)
+  figure('name','Difference in Extinction Start Images; B-A')
+  hist(hist_extstim,extbins)
+  figure('name','Difference in Extinction End Images; B-A')
+  hist(hist_extendim,extbins)
+  figure('name','Ratio of Integrated Intensities; B/A %')
+  hist(hist_integral,bins)
+  figure('name','Ratio of Areas; B/A %')
+  hist(hist_area,bins)
+  figure('name','Ratio of BBox X size; B/A %')
+  hist(hist_bbXsize,bins)
+  figure('name','Ratio of BBox Y size; B/A %')
+  hist(hist_bbYsize,bins)
+ 
+end
+
+if par.pair_dist
+  % Matching percentage
+  binwidth=5;
+  [centimA]=mym(sprintf('SELECT CentroidImage from %s where CentroidImage<=%d',difspottable,nproj))*180/nproj;
+  [centimB]=mym(sprintf('SELECT CentroidImage from %s where CentroidImage>%d',difspottable,nproj))*180/nproj;
+  edgesA=0:binwidth:180;
+  edgesB=180:binwidth:360;
+  centimA=histc(centimA,edgesA);
+  centimB=histc(centimB,edgesB);
+  centom=min(centimA,centimB);
+
+  [theta,eta,omega]=mym(sprintf('SELECT theta,eta,omega from %s',pairtable));
+  match_omega=histc(omega,edgesA);
+  edges_eta=0:binwidth:360;
+  match_eta=histc(eta,edges_eta);
+  
+  matchpc=match_omega./centom*100;
+  
+
+  figure('name','Eta vs omega')
+   plot(omega,eta,'b.')
+   axis([0 180 0 380])
+   
+  figure('name','Theta vs omega')
+   plot(omega,theta,'b.')
+   hold on
+   for i=1:length(comp_2thetas)
+     plot([0 380],[comp_2thetas(i) comp_2thetas(i)]/2,'g-.')
+   end
+   axis([0 180 min(comp_2thetas)/2-1 max(comp_2thetas)/2+1])
+  
+  figure('name','Eta vs theta')
+   plot(theta,eta,'b.')
+   hold on
+   for i=1:length(comp_2thetas)
+     plot([comp_2thetas(i) comp_2thetas(i)]/2,[0 380],'g-.')
+   end
+   axis([min(comp_2thetas)/2-1 max(comp_2thetas)/2+1 0 380])
+
+  figure('name','No. of pairs vs theta')
+   edges_theta=round((min(comp_2thetas)/2-0.1:180/nproj/5:max(comp_2thetas)/2+0.1)*100)/100;
+   theta_h=histc(theta,edges_theta);
+   bar(edges_theta,theta_h)
+   h=findobj(gca,'Type','patch');
+   set(h,'EdgeColor','none')
+   hold on
+   for i=1:length(comp_2thetas)
+     plot([comp_2thetas(i) comp_2thetas(i)]/2,[0 max(theta_h)],'g-.')
+   end
+   xlim([min(edges_theta) max(edges_theta)])
+ 
+  figure('name','No. of pairs found vs eta')
+   bar((edges_eta+binwidth/2)',match_eta)
+   h=findobj(gca,'Type','patch');
+   set(h,'EdgeColor','none')
+   xlim([0,360])
+  
+  figure('name','Matching percentage vs omega')
+   bar((edgesA+binwidth/2)',matchpc)
+   xlim([0,180])
+   h=findobj(gca,'Type','patch');
+   set(h,'EdgeColor','none')
+   set(h,'FaceColor','r')
+   
+  figure('name','No. of spots and no. of pairs vs omega')
+   bar((edgesA+binwidth/2)',[centom,match_omega])
+   h=findobj(gca,'Type','patch');
+   set(h,'EdgeColor','none')
+   xlim([0,180])   
+end
+
+
+
+end % of function
+
+
+
+
+%% Parse input arguments
+function par=sfParseFunctionInput(par,addpar)
+
+  if length(addpar)<=0  % just return the defaults
+    return
+  end
+  if ~isstruct(par)
+    error 'No structure for defaults was supplied'
+  end
+  propnames = fieldnames(par);
+  lpropnames = lower(propnames);
+  
+  for i=1:length(lpropnames)
+    if islogical(par.(propnames{i}))
+      j=1;
+      while j<=length(addpar)
+        if strmatch(lpropnames{i},lower(addpar{j}),'exact')
+          par.(propnames{i})=~par.(propnames{i});
+          addpar(j)=[];
+        else
+          j=j+1;
+        end
+      end
+    end
+  end
+  
+  n=length(addpar)/2;
+  
+  if n~=floor(n)
+    error 'Property/value pairs must come in PAIRS.'
+  end
+  
+  for i=1:n
+    p_i=lower(addpar{2*i-1});
+    v_i=addpar{2*i};
+    ind=strmatch(p_i,lpropnames,'exact'); % index of matching property
+    if isempty(ind)
+      ind=find(strncmp(p_i,lpropnames,length(p_i)));
+      if isempty(ind)
+        error(['No matching property found for: ',addpar{2*i-1}])
+      elseif length(ind)>1
+        error(['Ambiguous property name: ',addpar{2*i-1}])
+      end
+    end
+    par.(propnames{ind})=v_i;
+  end
+
+end % of sfParseFunctionInput
+
diff --git a/4_spot_sorting/gtFindAngles.m b/4_spot_sorting/gtFindAngles.m
new file mode 100755
index 0000000000000000000000000000000000000000..bb62c9df0f1f2123132a78ca4f56dad1abef6e3d
--- /dev/null
+++ b/4_spot_sorting/gtFindAngles.m
@@ -0,0 +1,44 @@
+
+
+function [Theta,Eta] = gtFindAngles(struct_id, grainx, grainy, grainz, omega);
+global parameters;
+%calculate Theta angle between grain position (x,y,z) and difspot of
+%struct_id
+%struct_id can be a vector...
+%omega should be input in degrees
+%output angles are in degrees
+
+omega=omega*pi/180;%convert to Omega
+
+for i=1:length(struct_id)
+  
+%mysqlcmd=sprintf('select Xcentroid from %sbboxes inner join %sbb on bbID=bboxID where %sbb.extspotID=%d',...
+%	parameters.acq.name,parameters.acq.name,parameters.acq.name,struct_id(i))
+%xdirect(i)=parameters.acq.bb(1)+mym(mysqlcmd);
+
+[bb,cent]=gtGetBBProps(struct_id(i));
+CentroidX=cent(1);
+xdirect(i)=parameters.acq.bb(1) + CentroidX;
+ydirect(i)=parameters.acq.bb(2)+grainz;
+
+mysqlcmd=sprintf('select CentroidX,CentroidY from %sdifspot where difspotID=%d',parameters.acq.name,struct_id(i));
+[xdiffr(i),ydiffr(i)]=mym(mysqlcmd);
+
+end
+
+
+r=sqrt((xdirect-xdiffr).^2+(ydirect-ydiffr).^2);
+
+grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+dz=grain2rot.*sin(-omega+angle)+parameters.acq.dist/parameters.acq.pixelsize;
+
+Theta=((atan(r./dz))/2)*180/pi;
+
+Eta=atan2((xdiffr-xdirect),(ydirect-ydiffr))*180/pi;
+
+dummy= find(Eta<0);
+  Eta(dummy)=360+Eta(dummy);
+
+end
diff --git a/4_spot_sorting/gtFindAngles_360.m b/4_spot_sorting/gtFindAngles_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..668951750fc5a2d9adbbe3603edb632d07eecdcb
--- /dev/null
+++ b/4_spot_sorting/gtFindAngles_360.m
@@ -0,0 +1,53 @@
+
+
+function [Theta,Eta] = gtFindAngles_360(struct_id, grainx, grainy, grainz, omega, parameters);
+
+%replace an old gtFindAngles_360. 
+%this script based on gtFindAngles_pair, modified to work with single 360
+%degree scan.
+%works with grain position in the ART/back projection coordinate system,
+%rather than the setup/system coordinates used in pair matching scripts.
+
+%360degree scan convention - ak 10/2007
+
+if isempty(parameters)
+  load parameters.mat
+end
+
+%calculate Theta angle between grain position (x,y,z) and difspot of
+%struct_id
+%struct_id can be a vector...
+%omega should be input in degrees
+%output angles are in degrees
+
+omega=omega*pi/180;%convert to radians
+
+for i=1:length(struct_id)
+
+[bb,cent]=gtGetBBProps(struct_id(i),parameters);
+CentroidX=cent(1);
+xdirect(i)=parameters.acq.bb(1) + CentroidX;
+ydirect(i)=parameters.acq.bb(2)+grainz;
+
+
+name=parameters.acq.name;
+mysqlcmd=sprintf('select CentroidX,CentroidY from %sdifspot where difspotID=%d',name,struct_id(i));
+[xdiffr(i),ydiffr(i)]=mym(mysqlcmd);
+
+end
+
+r=sqrt((xdirect-xdiffr).^2+(ydirect-ydiffr).^2);
+
+grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+dz=grain2rot.*sin(-omega+angle)+parameters.acq.dist/parameters.acq.pixelsize;
+
+Theta=((atan(r./dz))/2)*180/pi;
+
+Eta=atan2((xdiffr-xdirect),(ydirect-ydiffr))*180/pi;
+
+dummy= find(Eta<0);
+Eta(dummy)=360+Eta(dummy);
+
+end
diff --git a/4_spot_sorting/gtFindAngles_pair.m b/4_spot_sorting/gtFindAngles_pair.m
new file mode 100755
index 0000000000000000000000000000000000000000..acefa7c5b012d08f443e9e587225638604421382
--- /dev/null
+++ b/4_spot_sorting/gtFindAngles_pair.m
@@ -0,0 +1,60 @@
+
+
+function [Theta,Eta] = gtFindAngles_pair(struct_id, pair, grainx, grainy, grainz, omega, parameters);
+
+
+
+
+if isempty(parameters)
+  load parameters.mat
+end
+%calculate Theta angle between grain position (x,y,z) and difspot of
+%struct_id
+%struct_id can be a vector...
+%omega should be input in degrees
+%output angles are in degrees
+%pair - 1 for this dataset, 2 if struct_id refers to the pair
+
+omega=omega*pi/180;%convert to radians
+
+for i=1:length(struct_id)
+  
+%mysqlcmd=sprintf('select Xcentroid from %sbboxes inner join %sbb on bbID=bboxID where %sbb.extspotID=%d',...
+%	parameters.acq.name,parameters.acq.name,parameters.acq.name,struct_id(i))
+%xdirect(i)=parameters.acq.bb(1)+mym(mysqlcmd);
+
+[bb,cent]=gtGetBBProps_pair(struct_id(i), pair(i));
+CentroidX=cent(1);
+xdirect(i)=parameters.acq.bb(1) + CentroidX;
+ydirect(i)=parameters.acq.bb(2)+grainz;
+
+if pair(i) == 2
+  name = parameters.acq.pair_name;
+elseif pair(i) == 1
+name=parameters.acq.name;
+else
+  error('need to specify which half of scan (pair=1 or 2)')
+  return
+end
+
+mysqlcmd=sprintf('select CentroidX,CentroidY from %sdifspot where difspotID=%d',name,struct_id(i));
+[xdiffr(i),ydiffr(i)]=mym(mysqlcmd);
+
+end
+
+
+r=sqrt((xdirect-xdiffr).^2+(ydirect-ydiffr).^2);
+
+grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+dz=grain2rot.*sin(-omega+angle)+parameters.acq.dist/parameters.acq.pixelsize;
+
+Theta=((atan(r./dz))/2)*180/pi;
+
+Eta=atan2((xdiffr-xdirect),(ydirect-ydiffr))*180/pi;
+
+dummy= find(Eta<0);
+  Eta(dummy)=360+Eta(dummy);
+
+end
diff --git a/4_spot_sorting/gtFindGroupInCand.m b/4_spot_sorting/gtFindGroupInCand.m
new file mode 100755
index 0000000000000000000000000000000000000000..309e476970f3f73e2dd93b1c492dff34e6252505
--- /dev/null
+++ b/4_spot_sorting/gtFindGroupInCand.m
@@ -0,0 +1,71 @@
+
+function [pgood,grainoutput]=gtFindGroupInCand(cand,tol,sample,ACM,spacegroup)
+% cand: all the lines that possibly belong to the same grain as the 1st line 
+%        (they are pair-consistent)
+%       1st line in "cand" is the actual line investigated
+
+% NOTE: p2 and p3 intersection might be far from the actual grain center if
+% they are near being parallel
+
+nof_cand=length(cand.id); 
+
+p1=1;
+
+for p2=2:nof_cand % loop to find a 2nd line of the grain
+  for p3=p2+1:nof_cand % loop to find a 3rd line of the grain
+    
+    pgood=false(nof_cand,1);
+    pgood([p1,p2])=true;
+    
+    % Assume p2 belong to p1, try a 3rd one:
+    %  is p1,p2,p3 group-consistent?
+    
+    ok=gtTryAddLineToGroup(p3,pgood,cand,tol,sample,ACM);
+    
+    if ok 
+      pgood(p3)=true; % p1,p2,p3 are group consistent
+
+      for p4=p3+1:nof_cand
+        % having a group of p1,p2,p3 does p4 fit as well?
+        ok=gtTryAddLineToGroup(p4,pgood,cand,tol,sample,ACM);
+      
+        if ok
+          % p1,p2,p3,p4 are group-consistent.
+          % We accept them as a good solution.
+          % Which else could belong to this group?
+          %  Loop through all the remaining candidates and try whether they
+          %  fit. Keep the result, that is all the lines from this grain. 
+          pgood(p4)=true;
+          
+          for pn=p4+1:nof_cand
+            ok=gtTryAddLineToGroup(pn,pgood,cand,tol,sample,ACM);
+            if ok
+              pgood(pn)=true;
+            end
+          end
+          
+          grainl=gtKeepLine(pgood,cand); % lines in the grain
+
+          % Grain info:
+           % modif sabine to run erik sample
+            grainoutput=gtIndexCreateGrainOutputBuild(grainl); %,spacegroup);
+         
+          % grainoutput=gtIndexCreateGrainOutput(grainl,ACM);
+          % end modif sabine
+          
+          return
+
+        end
+       
+      end
+    end
+
+  end
+end
+
+% If no grain is found:
+pgood=false(nof_cand,1);
+pgood(1)=true;
+grainoutput=[];
+
+end
diff --git a/4_spot_sorting/gtFindGroupInCand_sab.m b/4_spot_sorting/gtFindGroupInCand_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..f4d238eed26d0f8fcc74aa1a67a357eaf69ad77b
--- /dev/null
+++ b/4_spot_sorting/gtFindGroupInCand_sab.m
@@ -0,0 +1,77 @@
+
+function [pgood,grainoutput]=gtFindGroupInCand_sab(cand,tol,sample,ACM,spacegroup)
+% cand: all the lines that possibly belong to the same grain as the 1st line 
+%        (they are pair-consistent)
+%       1st line in "cand" is the actual line investigated
+
+% NOTE: p2 and p3 intersection might be far from the actual grain center if
+% they are near being parallel
+
+% keyboard
+nof_cand=length(cand.id); 
+
+p1=1;
+
+for p2=2:nof_cand % loop to find a 2nd line of the grain
+  for p3=p2+1:nof_cand % loop to find a 3rd line of the grain
+    
+      % p2
+     %  p3
+      
+    pgood=false(nof_cand,1);
+    pgood([p1,p2])=true;
+    
+    % Assume p2 belong to p1, try a 3rd one:
+    %  is p1,p2,p3 group-consistent?
+    
+    ok=gtTryAddLineToGroup(p3,pgood,cand,tol,sample,ACM);
+    
+    if ok 
+      pgood(p3)=true; % p1,p2,p3 are group consistent
+
+      for p4=p3+1:nof_cand
+          % p4
+        % having a group of p1,p2,p3 does p4 fit as well?
+        ok=gtTryAddLineToGroup(p4,pgood,cand,tol,sample,ACM)
+      
+        if ok
+          % p1,p2,p3,p4 are group-consistent.
+          % We accept them as a good solution.
+          % Which else could belong to this group?
+          %  Loop through all the remaining candidates and try whether they
+          %  fit. Keep the result, that is all the lines from this grain. 
+          pgood(p4)=true;
+          
+          for pn=p4+1:nof_cand
+              % ACM
+            ok=gtTryAddLineToGroup(pn,pgood,cand,tol,sample,ACM);
+            if ok
+              pgood(pn)=true;
+            end
+          end
+          
+          grainl=gtKeepLine(pgood,cand); % lines in the grain
+
+        
+          
+          % grainoutput=gtIndexCreateGrainOutputBuild(grainl); %,spacegroup);
+       
+          % grainoutput=gtIndexCreateGrainOutput(grainl,ACM); 
+          
+          % end modif sabine
+          return
+
+        end
+       
+      end
+    end
+
+  end
+end
+
+% If no grain is found:
+pgood=false(nof_cand,1);
+pgood(1)=true;
+grainoutput=[];
+
+end
diff --git a/4_spot_sorting/gtForwardSimulate.m b/4_spot_sorting/gtForwardSimulate.m
new file mode 100755
index 0000000000000000000000000000000000000000..62b84516f7817caeaafd749d7c39d3cd3859d2d0
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate.m
@@ -0,0 +1,78 @@
+%forward simulation - search database for missed spots...
+%Marcelo, Andy
+%31/10/2006
+
+
+function [output,all_normals] = gtForwardSimulate(grainid)
+
+%load data 
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+
+%calc grain orientation, g matrix etc...
+r = plot_rodrigues_precise(grain_data.plane_normal, grain_data.hkl, 0);
+g = Rod2g(r);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+  hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+else
+  disp('Sorry - only FCC currently supported')
+end
+
+%get all of the possible hkls
+all_hkls = [];
+for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+end
+
+%produce all possible plane normals
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+%produce output list
+output=[];
+for i=1:size(all_normals,1)
+  try
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions(all_normals(i,:), all_hkls(i,:), grainid, 0);
+  tmp = [image' xdirect' ydirect' xdiffr' ydiffr'];
+  output = [output; tmp];
+  end
+end
+
+%interogate database to find any missing extspot/difspot pairs,
+%or to find misassigned extspot/difspot - ie when difspot can be found in
+%the database, but the extspot is wrong.
+
+struct_id=grain_data.struct_ids
+
+for i=1:size(output,1)
+output(i)=output(i,1);
+
+for j=1:size(struct_id,2)
+	id=struct_id(j);
+	MaxImage=mym(sprintf('select MaxImage from s5_dct5_difspot where difspotID=%d',id));
+	for k=-10:10
+		foundimage=MaxImage+k;
+		if output == foundimage
+			disp('I found in the database')
+			found(i)=foundimage;
+		else
+			found(i)=0;
+		end
+	end
+end
+	if found(i)==0;
+		disp('Image not found in the database')
+	    not_found(i)=output(i);
+	end
+
+end
\ No newline at end of file
diff --git a/4_spot_sorting/gtForwardSimulate2.m b/4_spot_sorting/gtForwardSimulate2.m
new file mode 100755
index 0000000000000000000000000000000000000000..be49982155fd5047ace00e99094c32f99414df04
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate2.m
@@ -0,0 +1,160 @@
+%forward simulation - search database for missed spots...
+%modify to simplify, to use as part of gtHandleSpot2 process, before a
+%grain%d_.mat is written.
+%Arguments: grainCentroid [x,y,z], r-vector, existing struct_ids
+%returns a list of struct_ids to add to the grain - extspot/difspot pairs
+%where both spots are in valid position, and size is okay also.
+
+%keep in a list of spots where the difspot matchs but the extspot is in the
+%wrong place - possible rerun autofind cases
+
+%Marcelo, Andy
+%31/10/2006
+
+
+function ext_possibles = gtForwardSimulate2(grainCentroid, R_vector, struct_ids)
+
+%load data 
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%get ready to ask the database questions
+dif_possibles=[];%possible difspot struct_ids
+ext_possibles=[];%possible difspot/extspot pairs struct_ids - ie, those which can go straight into grain
+
+%get the mean difspot, extspot sizes for the current spots in the grain
+dif_Xsize=[]; dif_Ysize=[];ext_Xsize=[]; ext_Ysize=[];
+for i=1:length(struct_ids)
+query=sprintf(['select BoundingBoxXsize,BoundingBoxYsize,Xsize,Ysize from '...
+  '%sdifspot inner join %sbb on difspotID=%sbb.extspotID inner join %sbboxes on bbID=bboxID '...
+  'where difspotID=%d'],...
+  parameters.acq.name,parameters.acq.name,parameters.acq.name,parameters.acq.name,...
+  struct_ids(i));
+[dif_Xsize(i), dif_Ysize(i), ext_Xsize(i), ext_Ysize(i)]=mym(query);
+end
+dif_Xsize=mean(dif_Xsize);
+dif_Ysize=mean(dif_Ysize);
+ext_Xsize=mean(ext_Xsize);
+ext_Ysize=mean(ext_Ysize);
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+  hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+else
+  disp('Sorry - only FCC currently supported')
+end
+
+%produce all possible plane normals using R_vector
+g = Rod2g(R_vector);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+%produce output list - where do we expect dif and ext spots for this
+%grain?
+output=[];
+for i=1:size(all_normals,1)
+  try  % not all normals result in diffraction
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions2(all_normals(i,:), all_hkls(i,:), grainCentroid, 0);
+  tmp = [image' xdirect' ydirect' xdiffr' ydiffr'];
+  output = [output; tmp];
+  end
+end
+
+
+%interogate database to find the spots predicted in output
+%find any missing extspot/difspot pairs,
+%or to find misassigned extspot/difspot - ie when difspot can be found in
+%the database, but the extspot is wrong.
+%hopefully find most of the spot pairs already assigned to grain!
+
+%convert the extspot positions to direct beam coordinates...
+output(:,2) = output(:,2) - parameters.acq.bb(1);
+output(:,3) = output(:,3) - parameters.acq.bb(2);
+
+%%s5_dct5_ 15 pixel shift apply here?
+%warning('applying the usual 15 pixels to predicted positions')
+%dummy=find(output(:,1)>4000);
+%output(dummy,3)=output(dummy,3)+15;
+
+%produce a list of possibles - difspots that might belong to the grain.
+for i=1:size(output,1)
+  %disp(sprintf('asking database query %d',i))
+  
+  %is the predicted difspot likely to clip the edge of the detector?
+  %if so allow greater freedom for matching centroid
+  dif_Xsearch=0.35; dif_Ysearch=0.35; %fraction of spot size allowed
+  ext_Xsearch=0.35; ext_Ysearch=0.1; %clipping doesn't effect extspots, vertical size should be invarient
+  if (output(i,4)<(dif_Xsize/2) | output(i,4)>parameters.acq.xdet-(dif_Xsize/2))
+  dif_Xsearch=0.6;
+  end
+  if (output(i,5)<(dif_Ysize/2) | output(i,5)>parameters.acq.ydet-(dif_Ysize/2))
+  dif_Ysearch=0.6;
+  end
+  
+  %find possible difspots - main search
+  %"get difspotID,grainID,MaxImage where MaxImage within 10, difspot
+  %Centroid within search range in x and y, and difspot size with search
+  %range in x and y, order by size match to spots already in grain and return best only"
+  warning('grain rustling disabled!!!')
+	
+  query=sprintf(['select difspotID,%sextspot.grainID,MaxImage from %sdifspot inner join %sextspot on difspotID=extspotID where '...
+    '(%d between StartImage-10 and EndImage+10) and isnull(%sextspot.grainID)'...
+     'and (abs(%sdifspot.CentroidX-%d)/%d)<%f '...
+     'and (abs(%sdifspot.CentroidY-%d)/%d)<%f '...
+     'and (abs(BoundingBoxXsize-%d)/%d)<%f and (abs(BoundingBoxYsize-%d)/%d)<%f '...
+     'order by ((abs(BoundingBoxXsize-%d)/%d)+(abs(BoundingBoxYsize-%d)/%d)) limit 1'],...
+     parameters.acq.name, parameters.acq.name, parameters.acq.name,...
+     output(i,1), parameters.acq.name,...
+     parameters.acq.name,output(i,4),dif_Xsize,dif_Xsearch,...
+     parameters.acq.name,output(i,5),dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Xsearch,dif_Ysize,dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Ysize,dif_Ysize);
+   [difspotID,grainID,MaxImage] = mym(query);
+  
+  %has this difspot already been assigned to this grain?
+  if (~isempty(difspotID) && isempty(find(struct_ids==difspotID)))
+    
+    %record as a possible difspot to be added
+    dif_possibles = [dif_possibles difspotID];
+    
+    %now query the corresponding extspot - has this also a valid size 
+    %and position for this grain?
+    
+    query = sprintf(['select Xcentroid,Ycentroid,Xsize,Ysize from '...
+      '%sbboxes inner join %sbb on bbID=bboxID '...
+      'where %sbb.extspotID=%d'],...
+      parameters.acq.name,...
+      parameters.acq.name,...
+      parameters.acq.name,...
+      difspotID);
+    [test_Xpos, test_Ypos, test_Xsize, test_Ysize] = mym(query);
+    
+   if ( (abs(test_Xpos-output(i,2))/ext_Xsize)<ext_Xsearch & (abs(test_Ypos-output(i,3))/ext_Ysize)<ext_Ysearch & ...
+       (abs(test_Xsize-ext_Xsize)/ext_Xsize)<ext_Xsearch &  (abs(test_Ysize-ext_Ysize)/ext_Ysize)<ext_Ysearch )
+    
+    ext_possibles = [ext_possibles difspotID];
+   
+   end % if extspot good?
+  end  % if a possible difspot found
+end    % loop over predicted spot positions
+  
+
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtForwardSimulate2_360.m b/4_spot_sorting/gtForwardSimulate2_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..e48083d62e3d0270bba7d3b0d588966c20de11d0
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate2_360.m
@@ -0,0 +1,180 @@
+%forward simulation - search database for missed spots...
+%modify to simplify, to use as part of gtHandleSpot2 process, before a
+%grain%d_.mat is written.
+%Arguments: grainCentroid [x,y,z], r-vector, existing struct_ids
+%returns a list of struct_ids to add to the grain - extspot/difspot pairs
+%where both spots are in valid position, and size is okay also.
+
+%360 case - need to be able to searc in two databases
+
+%keep in a list of spots where the difspot matchs but the extspot is in the
+%wrong place - possible rerun autofind cases
+
+%Marcelo, Andy
+%31/10/2006
+
+
+function ext_possibles = gtForwardSimulate2_360(grainCentroid, R_vector, prior_pair_ids)
+
+%load data 
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+acq=parameters.acq;
+%get the root of the pair name
+pair_name=parameters.acq.pair_tablename;
+pair_name(end-8:end)=[];
+
+%get ready to ask the database questions
+dif_possibles=[];%possible difspot struct_ids
+ext_possibles=[];%possible difspot/extspot pairs struct_ids - ie, those which can go straight into grain
+
+%get the mean difspot, extspot sizes for the current spots in the grain
+dif_Xsize=[]; dif_Ysize=[];ext_Xsize=[]; ext_Ysize=[];
+for i=1:length(prior_pair_ids)
+
+  mysqlcmd = sprintf(['select ifnull(%sdifspot.BoundingBoxXsize,%sdifspot.BoundingBoxXsize), '...
+    'ifnull(%sdifspot.BoundingBoxYsize,%sdifspot.BoundingBoxYsize) '...
+    'from %s left join %sdifspot on difAID=%sdifspot.difspotID '...
+    'left join %sdifspot on difBID=%sdifspot.difspotID '...
+    'where %s.pairID=%d'],...
+    acq.difA_name, acq.difB_name,...
+    acq.difA_name, acq.difB_name,...
+    acq.pair_tablename,  acq.difA_name, acq.difA_name,...
+    acq.difB_name, acq.difB_name,...
+    acq.pair_tablename,prior_pair_ids(i));
+  [dif_Xsize(i), dif_Ysize(i)]=mym(mysqlcmd);
+
+  [ext_bb,ext_cent]=gtGetBBProps(prior_pair_ids(i));
+  ext_Xsize(i) = ext_bb(3);
+  ext_Ysize(i) = ext_bb(4);
+  
+end
+dif_Xsize=mean(dif_Xsize);
+dif_Ysize=mean(dif_Ysize);
+ext_Xsize=mean(ext_Xsize);
+ext_Ysize=mean(ext_Ysize);
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+  hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+else
+  disp('Sorry - only FCC currently supported')
+end
+
+%produce all possible plane normals using R_vector
+g = Rod2g(R_vector);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+%produce output list - where do we expect dif and ext spots for this
+%grain?
+output=[];
+for i=1:size(all_normals,1)
+  try  % not all normals result in diffraction
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions2(all_normals(i,:), all_hkls(i,:), grainCentroid, 0);
+  tmp = [image' xdirect' ydirect' xdiffr' ydiffr'];
+  output = [output; tmp];
+  end
+end
+
+
+%interogate database to find the spots predicted in output
+%find any missing extspot/difspot pairs,
+%or to find misassigned extspot/difspot - ie when difspot can be found in
+%the database, but the extspot is wrong.
+%hopefully find most of the spot pairs already assigned to grain!
+
+%convert the extspot positions to direct beam coordinates...
+output(:,2) = output(:,2) - parameters.acq.bb(1);
+output(:,3) = output(:,3) - parameters.acq.bb(2);
+
+
+%produce a list of possibles - difspots that might belong to the grain.
+for i=1:size(output,1)  
+  %is the predicted difspot likely to clip the edge of the detector?
+  %if so allow greater freedom for matching centroid
+  dif_Xsearch=0.35; dif_Ysearch=0.35; %fraction of spot size allowed
+  ext_Xsearch=0.35; ext_Ysearch=0.1; %clipping doesn't effect extspots, vertical size should be invarient
+  if (output(i,4)<(dif_Xsize/2) | output(i,4)>parameters.acq.xdet-(dif_Xsize/2))
+  dif_Xsearch=0.6;
+  end
+  if (output(i,5)<(dif_Ysize/2) | output(i,5)>parameters.acq.ydet-(dif_Ysize/2))
+  dif_Ysearch=0.6;
+  end
+  
+  %find possible difspots - main search
+  %"get difspotID,grainID,MaxImage where MaxImage within 10, difspot
+  %Centroid within search range in x and y, and difspot size with search
+  %range in x and y, order by size match to spots already in grain and return best only"
+  %360 - search the correct database - if omega>nproj, in B
+  warning('grain rustling disabled!!!')
+	if output(i,1)>=parameters.acq.nproj
+    dif_name = parameters.acq.difB_name;
+    difID='difBID'; %for mysql search statement
+    image_number=output(i,1)-parameters.acq.nproj;
+  else
+    dif_name = parameters.acq.difA_name;
+    difID='difAID';
+    image_number=output(i,1);
+  end
+  
+  
+  query=sprintf(['select %s.pairID, %s.grainID, MaxImage from '...
+    '%sdifspot inner join %s on difspotID=%s where '...
+    '(%d between StartImage-10 and EndImage+10) and isnull(%s.grainID)'...
+     'and (abs(%sdifspot.CentroidX-%d)/%d)<%f '...
+     'and (abs(%sdifspot.CentroidY-%d)/%d)<%f '...
+     'and (abs(BoundingBoxXsize-%d)/%d)<%f and (abs(BoundingBoxYsize-%d)/%d)<%f '...
+     'order by ((abs(BoundingBoxXsize-%d)/%d)+(abs(BoundingBoxYsize-%d)/%d)) limit 1'],...
+     acq.pair_tablename, acq.pair_tablename,...
+     dif_name,acq.pair_tablename,difID,...
+     image_number, acq.pair_tablename,...
+     dif_name,output(i,4),dif_Xsize,dif_Xsearch,...
+     dif_name,output(i,5),dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Xsearch,dif_Ysize,dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Ysize,dif_Ysize);
+   [pairID,grainID,MaxImage] = mym(query);
+  
+  %has this difspot already been assigned to this grain?
+  if (~isempty(pairID) && isempty(find(prior_pair_ids==pairID)))
+    
+    %record as a possible difspot to be added
+    dif_possibles = [dif_possibles pairID];
+    
+    %now query the corresponding extspot - has this also a valid size 
+    %and position for this grain?
+    [ext_bb,ext_cent]=gtGetBBProps(PairID);
+    test_Xpos=ext_cent(1);
+    test_Ypos=ext_cent(2);
+    test_Xsize=ext_bb(3);
+    test_Ysize=ext_bb(4);
+    
+   if ( (abs(test_Xpos-output(i,2))/ext_Xsize)<ext_Xsearch & (abs(test_Ypos-output(i,3))/ext_Ysize)<ext_Ysearch & ...
+       (abs(test_Xsize-ext_Xsize)/ext_Xsize)<ext_Xsearch &  (abs(test_Ysize-ext_Ysize)/ext_Ysize)<ext_Ysearch )
+    
+    ext_possibles = [ext_possibles pairID];
+   
+   end % if extspot good?
+  end  % if a possible difspot found
+end    % loop over predicted spot positions
+  
+
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtForwardSimulate2_pair.m b/4_spot_sorting/gtForwardSimulate2_pair.m
new file mode 100755
index 0000000000000000000000000000000000000000..f8a943b890d0f65a8797a0f47da7e1e8e824e2bb
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate2_pair.m
@@ -0,0 +1,202 @@
+%forward simulation - search database for missed spots...
+%modify to simplify, to use as part of gtHandleSpot2 process, before a
+%grain%d_.mat is written.
+%Arguments: grainCentroid [x,y,z], r-vector, existing struct_ids
+%returns a list of struct_ids to add to the grain - extspot/difspot pairs
+%where both spots are in valid position, and size is okay also.
+
+%keep in a list of spots where the difspot matchs but the extspot is in the
+%wrong place - possible rerun autofind cases
+
+%360 degree pairs format - search in both the "home" dataset, and the pair
+%dataset
+%return also a list of which half of the scan each predicted new spot pair
+%belongs to
+
+%Marcelo, Andy
+%31/10/2006
+
+
+function [ext_possibles, ext_possibles_pair] = gtForwardSimulate2_pair(grainCentroid, R_vector, struct_ids, pair_vector, parameters)
+
+%load data 
+if isempty(parameters)
+  load parameters.mat
+end
+
+%get ready to ask the database questions
+dif_possibles=[];%possible difspot struct_ids
+dif_possibles_pair=[];%which half of the scan
+ext_possibles=[];%possible difspot/extspot pairs struct_ids - ie, those which can go straight into grain
+ext_possibles_pair=[];%which half of scan
+
+
+%get the mean difspot, extspot sizes for the current spots in the grain
+dif_Xsize=[]; dif_Ysize=[];ext_Xsize=[]; ext_Ysize=[];
+for i=1:length(struct_ids)
+  
+  if pair_vector(i) == 2
+    name = parameters.acq.pair_name;
+  else pair_vector(i) == 1
+    name=parameters.acq.name;
+  end
+query=sprintf(['select BoundingBoxXsize,BoundingBoxYsize,Xsize,Ysize from '...
+  '%sdifspot inner join %sbb on difspotID=%sbb.extspotID inner join %sbboxes on bbID=bboxID '...
+  'where difspotID=%d'],...
+  name, name, name, name,...
+  struct_ids(i));
+
+[dif_Xsize(i), dif_Ysize(i), ext_Xsize(i), ext_Ysize(i)]=mym(query);
+
+end
+dif_Xsize=mean(dif_Xsize);
+dif_Ysize=mean(dif_Ysize);
+ext_Xsize=mean(ext_Xsize);
+ext_Ysize=mean(ext_Ysize);
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+  hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+elseif parameters.acq.spacegroup==229
+    hkl=[1 1 0 ; 0 0 2 ; 1 1 2];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+else
+  disp('Sorry - only FCC/BCC currently supported')
+end
+
+%produce all possible plane normals using R_vector
+g = Rod2g(R_vector);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+
+keyboard
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%produce output list - where do we expect dif and ext spots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+output=[];
+for i=1:size(all_normals,1)
+  try  % not all normals result in diffraction
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions2(all_normals(i,:), all_hkls(i,:), grainCentroid, 0, parameters);
+  tmp = [image' xdirect' ydirect' xdiffr' ydiffr'];
+  output = [output; tmp];
+  end
+end
+
+%convert the extspot positions to direct beam coordinates...
+output(:,2) = output(:,2) - parameters.acq.bb(1);
+output(:,3) = output(:,3) - parameters.acq.bb(2);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% interogate the database(s) to find predicted spot pairs
+%% and misassigned difspots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%produce a list of possibles - difspots that might belong to the grain.
+disp(sprintf('asking %d database queries',length(output)))
+
+for i=1:size(output,1)
+  
+  %is the predicted difspot likely to clip the edge of the detector?
+  %if so allow greater freedom for matching centroid
+  dif_Xsearch=0.35; dif_Ysearch=0.35; %fraction of spot size allowed
+  ext_Xsearch=0.35; ext_Ysearch=0.1; %clipping doesn't effect extspots, vertical size should be invarient
+  if (output(i,4)<(dif_Xsize/2) | output(i,4)>parameters.acq.xdet-(dif_Xsize/2))
+  dif_Xsearch=0.6;
+  end
+  if (output(i,5)<(dif_Ysize/2) | output(i,5)>parameters.acq.ydet-(dif_Ysize/2))
+  dif_Ysearch=0.6;
+  end
+  
+  %deal with which half of the 360 scan to look at
+  if output(i,1) >= parameters.acq.nproj
+    image=output(i,1)-parameters.acq.nproj;
+    name = parameters.acq.pair_name;
+    this_pair=2;
+  else
+    image=output(i,1);
+    name=parameters.acq.name;
+    this_pair=1;
+  end
+ 
+  %find possible difspots - main search
+  %get difspotID,grainID,MaxImage where MaxImage within 10, difspot
+  %Centroid within search range in x and y, and difspot size with search
+  %range in x and y, order by size match to spots already in grain and return best only"
+  warning('grain rustling disabled!!!')
+	
+  query=sprintf(['select difspotID,%sextspot.grainID,MaxImage from %sdifspot inner join %sextspot on difspotID=extspotID where '...
+    '(%d between StartImage-10 and EndImage+10) and isnull(%sextspot.grainID)'...
+     'and (abs(%sdifspot.CentroidX-%d)/%d)<%f '...
+     'and (abs(%sdifspot.CentroidY-%d)/%d)<%f '...
+     'and (abs(BoundingBoxXsize-%d)/%d)<%f and (abs(BoundingBoxYsize-%d)/%d)<%f '...
+     'order by ((abs(BoundingBoxXsize-%d)/%d)+(abs(BoundingBoxYsize-%d)/%d)) limit 1'],...
+    name, name, name,...
+     image, name,...
+     name,output(i,4),dif_Xsize,dif_Xsearch,...
+     name,output(i,5),dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Xsearch,dif_Ysize,dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Ysize,dif_Ysize);
+   [difspotID,grainID,MaxImage] = mym(query);
+  
+  %has this difspot already been assigned to this grain?
+  if ~isempty(difspotID)
+   
+    dummy1=find(struct_ids==difspotID) % max 2 entries - do we have a struct_id with this ID number?
+    
+    %if so, check if we have it in the right half of the scan
+    if isempty(dummy1) || ~any(this_pair==pair_vector(dummy1))
+      
+    %record as a possible difspot to be added, and which half of scan
+    dif_possibles = [dif_possibles difspotID];
+    dif_possibles_pair = [dif_possibles_pair this_pair];
+    
+    %now query the corresponding extspot - has this also a valid size 
+    %and position for this grain?
+    
+    query = sprintf(['select Xcentroid,Ycentroid,Xsize,Ysize from '...
+      '%sbboxes inner join %sbb on bbID=bboxID '...
+      'where %sbb.extspotID=%d'],...
+      name, name, name,...
+      difspotID);
+    [test_Xpos, test_Ypos, test_Xsize, test_Ysize] = mym(query);
+    
+   if ( (abs(test_Xpos-output(i,2))/ext_Xsize)<ext_Xsearch & (abs(test_Ypos-output(i,3))/ext_Ysize)<ext_Ysearch & ...
+       (abs(test_Xsize-ext_Xsize)/ext_Xsize)<ext_Xsearch &  (abs(test_Ysize-ext_Ysize)/ext_Ysize)<ext_Ysearch )
+    
+     %record as a difspot/extspot pair to add to grain, and which half of
+     %scan it is from
+    ext_possibles = [ext_possibles difspotID];
+    ext_possibles_pair = [ext_possibles_pair this_pair];
+   
+   end % if extspot good?
+  end  % if a possible difspot found
+  end % if the difspot does not already belong to the grain
+end    % loop over predicted spot positions
+  
+
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtForwardSimulate_360.m b/4_spot_sorting/gtForwardSimulate_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..01bacdacc636401b56fc573b013b5039756ba972
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate_360.m
@@ -0,0 +1,307 @@
+%forward simulation - search database for missed spots...
+%modify to simplify, to use as part of gtHandleSpot2 process, before a
+%grain%d_.mat is written.
+%Arguments: grainCentroid [x,y,z], r-vector, existing struct_ids
+%returns a list of struct_ids to add to the grain - extspot/difspot pairs
+%where both spots are in valid position, and size is okay also.
+
+%keep in a list of spots where the difspot matchs but the extspot is in the
+%wrong place - possible rerun autofind cases
+
+%360 degree pairs format - search in both the "home" dataset, and the pair
+%dataset
+%return also a list of which half of the scan each predicted new spot pair
+%belongs to
+
+%Marcelo, Andy
+%31/10/2006
+
+%360degree scan convention - ak 10/2007
+%output dif_possibles as well  - wl 01/2008 - no need to have a valid
+%extspot (replace autofind by Peters indexing)
+
+%need to add a grainid field to teh difspot table to stop grains "sharing"
+%difspots
+
+
+function [ext_possibles,dif_possibles] = gtForwardSimulate_360(grainCentroid, R_vector, struct_ids, parameters,test_extspot)
+
+%load data 
+if ~exist('parameters','var')
+  load parameters.mat
+end
+if ~exist('test_extspot','var')
+  test_extspot=1
+end  
+
+
+%get ready to ask the database questions
+dif_possibles=[];%possible difspot struct_ids
+dif_possibles_pair=[];%which half of the scan
+ext_possibles=[];%possible difspot/extspot pairs struct_ids - ie, those which can go straight into grain
+ext_possibles_pair=[];%which half of scan
+
+name=parameters.acq.name;
+
+%get the mean difspot, extspot sizes for the current spots in the grain
+dif_Xsize=[]; dif_Ysize=[];ext_Xsize=[]; ext_Ysize=[];
+for i=1:length(struct_ids)
+query=sprintf(['select BoundingBoxXsize,BoundingBoxYsize, Integral, Area from '...
+  '%sdifspot where difspotID=%d'],name,struct_ids(i));
+
+[dif_Xsize(i), dif_Ysize(i), dif_int(i), dif_area(i)]=mym(query);  
+   
+if test_extspot
+  try
+	query=sprintf(['select Xsize,Ysize from '...
+	  '%sdifspot inner join %sbb on difspotID=%sbb.extspotID inner join %sbboxes on bbID=bboxID '...
+	  'where difspotID=%d'],...
+	  name, name, name, name,...
+	  struct_ids(i));
+
+	[ext_Xsize(i), ext_Ysize(i)]=mym(query);
+  catch
+  ext_Xsize(i)=-1;
+  ext_Ysize(i)=-1;
+  disp('no extspot data for this difspot')
+  end
+end %if test_extspot
+end
+
+dif_Xsize=mean(dif_Xsize);
+dif_Ysize=mean(dif_Ysize);
+dif_int=mean(dif_int);
+dif_area=mean(dif_area);
+ext_Xsize=mean(ext_Xsize);
+ext_Ysize=mean(ext_Ysize);
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+    hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+    all_hkls = [];
+    for i = 1:size(hkl,1)
+        all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+    end
+    %normalise hkl vectors
+    tmp = sqrt(sum((all_hkls.*all_hkls),2));
+    normalised_hkls = all_hkls./(repmat(tmp,1,3));
+elseif parameters.acq.spacegroup==229
+   %  hkl=[1 1 0 ; 0 0 2 ; 1 1 2];
+    hkl=[...
+            1 1 0;...
+            2 0 0;...
+            2 1 1;...
+            2 2 0;...
+            3 1 0;...
+            ];
+    all_hkls = [];
+    for i = 1:size(hkl,1)
+        all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+    end
+    %normalise hkl vectors
+    tmp = sqrt(sum((all_hkls.*all_hkls),2));
+    normalised_hkls = all_hkls./(repmat(tmp,1,3));
+    % modif sabine
+elseif parameters.acq.spacegroup==663 || parameters.acq.spacegroup==194 || parameters.acq.spacegroup==167 %all hexagonal cases
+  
+  if parameters.acq.spacegroup==663 % snow
+    hkil = [...
+            0 0 0 2; ...
+            1 1 -2 0; ...
+            1 -1 0 0; ...
+            1 -1 0 1; ...
+            1 1 -2 2; ...
+            -2 0 2 1; ...
+            ];
+  elseif parameters.acq.spacegroup==194 % Mg
+      hkil = [...
+          1 0 -1 0;...
+          0 0 0 2; ...
+          1 0 -1 1; ...
+          1 0 -1 2; ...
+          1 1 -2 0; ...
+          1 0 -1 3; ...
+          ];
+  elseif parameters.acq.spacegroup==167 % alumina (removed 20-22 - v low intensity)
+      hkil =[...
+          0 1 -1 2; ...
+          1 0 -1 4; ...
+          1 1 -2 0; ...
+          1 1 -2 3; ...
+          0 2 -2 4; ...
+          1 1 -2 6; ...
+          ];
+  end
+          
+          all_hkils = [];
+          all_hkls = [];
+    for i = 1:size(hkil,1)
+        all_hkils = [all_hkils ; gtGetReflections_sab(hkil(i,:))];
+    end
+    % normalise hkls vector
+    % going to cartesian reciprocal space + normalisation of the cartesian
+    % space
+    for i=1:size(all_hkils)
+     all_hkls(i,1)= all_hkils(i,1) + 0.5 * all_hkils(i,2);
+     all_hkls(i,2)= 3^0.5/2 *all_hkils(i,2);
+     all_hkls(i,3)= all_hkils(i,4);
+     
+     all_hkls(i,1)=all_hkls(i,1)*2/(sqrt(3)*parameters.acq.latticepar(1));
+     all_hkls(i,2)=all_hkls(i,2)*2/(sqrt(3)*parameters.acq.latticepar(1));
+     all_hkls(i,3)=all_hkls(i,3)/parameters.acq.latticepar(3);
+    end
+     tmp = sqrt(sum((all_hkls.*all_hkls),2));
+     normalised_hkls = all_hkls./(repmat(tmp,1,3));
+    % unification des notations pour la suite
+    all_hkls = [];
+    all_hkls = all_hkils;
+    % fin modif sabine
+else
+    disp('Sorry - only FCC/BCC/Snow/Hexagonal/alumina currently supported')
+end
+
+%produce all possible plane normals using R_vector
+g = Rod2g(R_vector);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%produce output list - where do we expect dif and ext spots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+output=[];
+for i=1:size(all_normals,1)
+  try  % not all normals result in diffraction
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions_360(all_normals(i,:), all_hkls(i,:), grainCentroid, 0, parameters);
+  tmp = [image' xdirect' ydirect' xdiffr' ydiffr'];
+  output = [output; tmp];
+  end
+end
+size(output)
+%convert the extspot positions to direct beam coordinates...
+output(:,2) = output(:,2) - parameters.acq.bb(1);
+output(:,3) = output(:,3) - parameters.acq.bb(2);
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% interogate the database(s) to find predicted spot pairs
+%% and misassigned difspots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%produce a list of possibles - difspots that might belong to the grain.
+disp(sprintf('asking %d database queries',length(output)))
+
+for i=1:size(output,1)
+  
+  %is the predicted difspot likely to clip the edge of the detector?
+  %if so allow greater freedom for matching centroid
+  dif_Xsearch=0.35; dif_Ysearch=0.35; %fraction of spot size allowed
+  ext_Xsearch=0.35; ext_Ysearch=0.1; %clipping doesn't effect extspots, vertical size should be invarient
+  if (output(i,4)<(dif_Xsize/2) | output(i,4)>parameters.acq.xdet-(dif_Xsize/2))
+  dif_Xsearch=0.6;
+  end
+  if (output(i,5)<(dif_Ysize/2) | output(i,5)>parameters.acq.ydet-(dif_Ysize/2))
+  dif_Ysearch=0.6;
+  end
+  
+  %find possible difspots - main search
+  %get difspotID,grainID,MaxImage where MaxImage within 10, difspot
+  %Centroid within search range in x and y, and difspot size with search
+  %range in x and y, order by size match to spots already in grain and return best only"
+  %warning('grain rustling disabled!!!')
+	
+%   
+% %  query as original
+ if test_extspot
+   
+query=sprintf(['select difspotID,%sextspot.grainID,MaxImage from %sdifspot inner join %sextspot on difspotID=extspotID where ',...
+    '(%d between StartImage-10 and EndImage+10) and isnull(%sextspot.grainID) ',...
+     'and (abs(%sdifspot.CentroidX-%d)/%d)<%f ',...
+     'and (abs(%sdifspot.CentroidY-%d)/%d)<%f ',...
+     'and (abs(BoundingBoxXsize-%d)/%d)<%f and (abs(BoundingBoxYsize-%d)/%d)<%f ',...
+     'order by ((abs(BoundingBoxXsize-%d)/%d)+(abs(BoundingBoxYsize-%d)/%d)) limit 1'],...
+     name, name, name,...
+     output(i,1), name,...
+     name, output(i,4), dif_Xsize, dif_Xsearch,...
+     name, output(i,5), dif_Ysize, dif_Ysearch,...
+     dif_Xsize, dif_Xsize,dif_Xsearch, dif_Ysize, dif_Ysize, dif_Ysearch,...
+     dif_Xsize, dif_Xsize, dif_Ysize, dif_Ysize);
+   
+   
+   [difspotID,grainID,MaxImage] = mym(query);
+   
+ else %for case of using difspots only, no extspots
+
+   %do conditions as in match difspots, using the same parameters.match
+   %values
+   match=parameters.match;
+   
+  query=sprintf(['select difspotID from %sdifspot where '...
+    '(%d between CentroidImage-%d and CentroidImage+%d) '...
+     'and (abs(%sdifspot.CentroidX-%d)/%d)<%f '...
+     'and (abs(%sdifspot.CentroidY-%d)/%d)<%f '...
+     'and (BoundingBoxXsize between %f and %f) and (BoundingBoxYsize between %f and %f) '...
+     'and (Area between %f and %f) '...
+     'and isnull(grainID) '...
+     'order by ((abs(BoundingBoxXsize-%d)/%d)+(abs(BoundingBoxYsize-%d)/%d)) limit 1'],...
+     name,...
+     output(i,1), match.thr_max_offset, match.thr_max_offset,...
+     name, output(i,4), dif_Xsize, dif_Xsearch,...
+     name, output(i,5), dif_Ysize, dif_Ysearch,...
+     dif_Xsize/match.thr_bbsize, dif_Xsize*match.thr_bbsize, dif_Ysize/match.thr_bbsize, dif_Ysize*match.thr_bbsize,...
+     dif_area/match.thr_area, dif_area*match.thr_area,...
+     dif_Xsize, dif_Xsize, dif_Ysize, dif_Ysize);
+   
+ [difspotID] = mym(query);
+ 
+ end
+ 
+ 
+  %has this difspot already been assigned to this grain?
+  if ~isempty(difspotID)
+    
+    dummy1=find(struct_ids==difspotID); % do we have a struct_id with this ID number?
+    
+    if isempty(dummy1) 
+      
+    %record as a possible difspot to be added, and which half of scan
+    dif_possibles = [dif_possibles difspotID];
+    
+    %now query the corresponding extspot - has this also a valid size 
+    %and position for this grain?
+    
+	if test_extspot  % only if we do have extspot bb information from autofind...
+	  
+	  query = sprintf(['select Xcentroid,Ycentroid,Xsize,Ysize from '...
+      '%sbboxes inner join %sbb on bbID=bboxID '...
+      'where %sbb.extspotID=%d'],...
+      name, name, name,...
+      difspotID);
+	  [test_Xpos, test_Ypos, test_Xsize, test_Ysize] = mym(query);
+    
+	  if ( (abs(test_Xpos-output(i,2))/ext_Xsize)<ext_Xsearch & (abs(test_Ypos-output(i,3))/ext_Ysize)<ext_Ysearch & ...
+		  (abs(test_Xsize-ext_Xsize)/ext_Xsize)<ext_Xsearch &  (abs(test_Ysize-ext_Ysize)/ext_Ysize)<ext_Ysearch )
+    
+		%record as a difspot/extspot pair to add to grain, and which half of
+		%scan it is from
+		ext_possibles = [ext_possibles difspotID];
+	  end % if extspot good?
+	else
+	    ext_possibles = -1;   %  
+	end %if use extspot information ?
+  
+  end  % if a possible difspot found
+  end % if the difspot does not already belong to the grain
+end    % loop over predicted spot positions
+  
+
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtForwardSimulate_Si.m b/4_spot_sorting/gtForwardSimulate_Si.m
new file mode 100755
index 0000000000000000000000000000000000000000..66f78e2dfb0d61b48361beffd872e92ff5634fbb
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate_Si.m
@@ -0,0 +1,87 @@
+%forward simulation - search database for missed spots...
+%modify to simplify, to use as part of gtHandleSpot2 process, before a
+%grain%d_.mat is written.
+%Arguments: grainCentroid [x,y,z], r-vector, existing struct_ids
+%returns a list of struct_ids to add to the grain - extspot/difspot pairs
+%where both spots are in valid position, and size is okay also.
+
+%keep in a list of spots where the difspot matchs but the extspot is in the
+%wrong place - possible rerun autofind cases
+
+%Marcelo, Andy
+%31/10/2006
+
+
+function [output, output2] = gtForwardSimulate_Si( R_vector)
+
+
+% all possible hkls for Si
+  hkl=[1 1 1 ; 2 2 0; 4 0 0 ; 3 1 1; 4 2 2]
+  
+  
+  all_hkls = [];
+  %get all possible permutations
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors to unit vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+
+
+%produce all possible plane normals using R_vector
+g = Rod2g(R_vector);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+
+
+
+%produce output list - where do we expect dif and ext spots for this
+%grain?
+output=[];
+for i=1:size(all_normals,1)
+  try  % not all normals result in diffraction
+    [Theta,Eta,Omega] = gtPredictAngles_Si(all_normals(i,:), all_hkls(i,:));
+    
+    [xdiffr,ydiffr] = gtPredictPositions_Si(Theta', Eta');
+  %tmp = [image' xdirect' ydirect' xdiffr' ydiffr'];
+  tmp=[Omega' Eta' Theta' xdiffr ydiffr];
+  
+  for x=1:size(tmp,1)
+  tmp2(x,:)=all_hkls(i,:);
+  end
+  tmp=[tmp2 tmp];
+  
+  output = [output; tmp];
+  
+  end
+end
+
+%output is [h k l image xdirect,ydirect,xdiffr,ydiffr]
+
+%output(:,[5 6])=[];%remove direct beam info
+
+%output(:,4)=output(:,4)*180/parameters.acq.nproj; %back to degrees
+
+output=sortrows(output, 4);
+
+dummy=find(output(:,7)<0 | output(:,8)<0 | output(:,7)>2048 | output(:,8)>2048);
+output2=output(dummy, :);
+output(dummy, :)=[];
+
+
+
+disp('output is: h,k,l,   Omega, Eta,Theta   dif x pox, dif y pos')
+
+
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtForwardSimulate_ak.m b/4_spot_sorting/gtForwardSimulate_ak.m
new file mode 100755
index 0000000000000000000000000000000000000000..bc1cbc82283a4c12b5ce13ced756eb60921e9ef1
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate_ak.m
@@ -0,0 +1,222 @@
+%forward simulation - search database for missed spots...
+%Marcelo, Andy
+%31/10/2006
+
+
+function [output,dif_possibles,ext_possibles,errors, errors2] = gtForwardSimulate_ak(grainid)
+
+%load data 
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+
+
+%get ready to ask the database questions
+dif_possibles=[];%possible difspot struct_ids
+ext_possibles=[];%possible extspot struct_ids (in predicted position, but misassigned)
+errors=[];count=1;%in difspots already assigned
+errors2=[];count2=1;% in difspots we could add
+output_index=[];%useful (not already found) enteries in output
+
+
+%get the mean grain size from the database - test number of extspots in
+%grain
+query=sprintf('select extspotID,BoundingBoxXsize,BoundingBoxYsize from %sdifspot inner join %sextspot on difspotID=extspotID where grainID=%d',...
+  parameters.acq.name,parameters.acq.name,grainid);
+[tmp,Xsize,Ysize]=mym(query);
+if isempty(tmp)
+  %all the extspots belonging to this grain have been given to another -
+  %nothing left in this grain
+  output = 'nothing_left';
+  
+elseif length(tmp)<4
+  %if there are less than 4 extspots in the grain (because they've been
+  %stolen by others!), don't proceed
+  output = sprintf('only_%d_extspots_in_grain',length(tmp))
+  
+else
+%do the forward simulation to try and pick up new grains
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+
+%calc grain orientation, g matrix etc...
+r = plot_rodrigues_precise(grain_data.plane_normal, grain_data.hkl, 0);
+g = Rod2g(r);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+  hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+else
+  disp('Sorry - only FCC currently supported')
+end
+
+%get all of the possible hkls
+all_hkls = [];
+for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+end
+
+%produce all possible plane normals
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+%produce output list
+output=[];
+for i=1:size(all_normals,1)
+  try
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions(all_normals(i,:), all_hkls(i,:), grainid, 0);
+  tmp = [image' xdirect' ydirect' xdiffr' ydiffr'];
+  output = [output; tmp];
+  end
+end
+
+%interogate database to find any missing extspot/difspot pairs,
+%or to find misassigned extspot/difspot - ie when difspot can be found in
+%the database, but the extspot is wrong.
+
+%convert the extspot positions to direct beam coordinates...
+output(:,2) = output(:,2) - parameters.acq.bb(1);
+output(:,3) = output(:,3) - parameters.acq.bb(2);
+
+Xsize=mean(Xsize)
+Ysize=mean(Ysize)
+
+
+%produce a list of possibles - difspots that might belong to the grain.
+for i=1:size(output,1)
+  %disp(sprintf('asking database query %d',i))
+  
+  %is the predicted difspot likely to clip the edge of the detector?
+  %if so allow greater freedom for matching centroid
+  Xsearch=0.35; Ysearch=0.35; %fraction of spot size allowed
+  extXsearch=0.35; extYsearch=0.35; %clipping doesn't effect extspots
+  if (output(i,4)<(Xsize/2) | output(i,4)>parameters.acq.xdet-(Xsize/2))
+  Xsearch=0.6;
+  end
+  if (output(i,4)<(Xsize/2) | output(i,4)>parameters.acq.xdet-(Xsize/2))
+  Ysearch=0.6;
+  end
+  
+  %find possible difspots - main search
+  query=sprintf(['select difspotID,grainID,MaxImage from %sdifspot inner join %sextspot on difspotID=extspotID where (%d between StartImage-10 and EndImage+10) '...
+     'and (abs(%sdifspot.CentroidX-%d)/%d)<%f '...
+     'and (abs(%sdifspot.CentroidY-%d)/%d)<%f '...
+     'and (abs(BoundingBoxXsize-%d)/%d)<%f and (abs(BoundingBoxYsize-%d)/%d)<%f order by abs(MaxImage-%d) limit 1'],...
+     parameters.acq.name, parameters.acq.name,output(i,1),...
+     parameters.acq.name,output(i,4),Xsize,Xsearch,...
+     parameters.acq.name,output(i,5),Ysize,Ysearch,...
+     Xsize,Xsize,Xsearch,Ysize,Ysize,Ysearch,output(i,1));
+   [difspotIDs,grainIDs,MaxImage] = mym(query);
+  
+  %has this difspot already been assigned to this grain?
+  dummy = find(grainIDs == grainid);
+  if (isempty(dummy) & ~isempty(difspotIDs))
+    
+    %if not, record as a possible to be added
+    dif_possibles = [dif_possibles difspotIDs'];
+    output_index = [output_index i];
+    
+    
+    %for investigations - data related to possible difspots
+    for k=1:length(difspotIDs)  
+    
+      query=sprintf('select CentroidX,CentroidY,MaxImage from %sdifspot where difspotID=%d',parameters.acq.name,difspotIDs(k));
+    [difX,difY,difMax]=mym(query);
+errors2(count2,1)=difX-output(i,4);
+errors2(count2,2)=difY-output(i,5);
+errors2(count2,3)=difMax-output(i,1);
+errors2(count2,4)=difspotIDs(k);
+    query=sprintf('select GrainID from %sextspot where extspotID=%d',parameters.acq.name,difspotIDs(k));
+difGrainID = mym(query);
+
+query = sprintf('select Xsize,Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d',...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  difspotIDs(k));
+[extSizeX, extSizeY] = mym(query);
+
+
+errors2(count2,5)=difGrainID;
+errors2(count2,6)=extSizeX;
+errors2(count2,7)=extSizeY;
+
+
+    count2=count2+1;
+    
+    
+%check if the matched extinction spot is also in the right place and size
+%for this grain ie autofind has worked well, but handle spot has missed it
+%out for whatever reason
+%these should be ready to go straight into the grain mat file
+%difspots which are not linked to valid extspots could be missaigned by
+%autofind...  
+if (abs(extSizeX-Xsize)/Xsize)<extXsearch & (abs(extSizeY-Ysize)/Ysize)<extYsearch %size check
+
+query=sprintf('select ifnull(CentroidX,SearchCentroidX),ifnull(CentroidY,SearchCentroidY) from %sextspot where extspotID=%d',...
+  parameters.acq.name, difspotIDs(k));
+[extCentroidX,extCentroidY] = mym(query);
+%difspotIDs(k)
+dist=sqrt((extCentroidX-output(i,2))^2 + (extCentroidY-output(i,3))^2);
+radius=sqrt((Xsize^2 + Ysize^2))/2;
+
+if dist < radius %if ext centroid within a radius of the predicted position
+  ext_possibles = [ext_possibles difspotIDs(k)];
+end
+    end
+
+    end
+    
+
+%for investigations - data related to dispots already assigned to this
+%grain
+  elseif (~isempty(dummy) & ~isempty(difspotIDs))
+  
+    for k=1:length(difspotIDs)
+  
+    query=sprintf('select CentroidX,CentroidY,MaxImage from %sdifspot where difspotID=%d',parameters.acq.name,difspotIDs(k));
+    [difX,difY,difMax]=mym(query);
+errors(count,1)=difX-output(i,4);
+errors(count,2)=difY-output(i,5);
+errors(count,3)=difMax-output(i,1);
+errors(count,4)=difspotIDs(k);
+    query=sprintf('select GrainID from %sextspot where extspotID=%d',parameters.acq.name,difspotIDs(k));
+difGrainID = mym(query);
+errors(count,5)=difGrainID;
+count=count+1;
+    
+    end
+  end
+ 
+end
+
+%image / extspot x,y / difspot x,y for missing difspots
+output = output(output_index,:);
+%possibles - difspotIDs of spots that may belong to the grain.
+
+
+
+
+
+end
+
+
+
+%next step - autofind again, using forward simulation info.
+%case 1 - difspot fully in image, but autofind messed up
+
+%case 2 - difspot cropped by edge of image, autofind again with different
+%input
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtForwardSimulate_pair2grain.m b/4_spot_sorting/gtForwardSimulate_pair2grain.m
new file mode 100755
index 0000000000000000000000000000000000000000..6bb5ca9ede3d62227d4a6ff62661c5ab2f42f634
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate_pair2grain.m
@@ -0,0 +1,194 @@
+
+
+%   gtForwardSimulate_pair2grain
+%to work insode of gtPairs2Grains, difspot only grain indexing.
+%pick up higher order hkls, unpaired difspots, etc.  
+%only need to consider difspots.
+%different treatment of grain position, because calculated in sample space
+%from line intersect, rather than backproj.
+%know that r-vectors, plane normals, angles are consistant between 3d line
+%treatment and extspot treatment.
+
+
+
+%forward simulation - search database for missed spots...
+%modify to simplify, to use as part of gtHandleSpot2 process, before a
+%grain%d_.mat is written.
+%Arguments: grainCentroid [x,y,z], r-vector, existing struct_ids
+%returns a list of struct_ids to add to the grain - extspot/difspot pairs
+%where both spots are in valid position, and size is okay also.
+
+%keep in a list of spots where the difspot matchs but the extspot is in the
+%wrong place - possible rerun autofind cases
+
+%360 degree pairs format - search in both the "home" dataset, and the pair
+%dataset
+%return also a list of which half of the scan each predicted new spot pair
+%belongs to
+
+%Marcelo, Andy
+%31/10/2006
+
+
+function [dif_possibles, dif_possibles_pair] = gtForwardSimulate_pair2grain(grainCentroid, R_vector, struct_ids, pair_vector, parameters)
+
+%load data 
+if isempty(parameters)
+  load parameters.mat
+end
+
+%get ready to ask the database questions
+dif_possibles=[];%possible difspot struct_ids
+dif_possibles_pair=[];%which half of the scan
+
+%get the mean difspot, extspot sizes for the current spots in the grain
+dif_Xsize=[]; dif_Ysize=[];ext_Xsize=[]; ext_Ysize=[];
+for i=1:length(struct_ids)
+  if pair_vector(i) == 2
+    name = parameters.acq.pair_name;
+  else pair_vector(i) == 1
+    name=parameters.acq.name;
+  end
+query=sprintf(['select BoundingBoxXsize,BoundingBoxYsize from '...
+  '%sdifspot where difspotID=%d'],...
+  name,struct_ids(i));
+[dif_Xsize(i), dif_Ysize(i)]=mym(query);
+end
+dif_Xsize=mean(dif_Xsize);
+dif_Ysize=mean(dif_Ysize);
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+  hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+elseif parameters.acq.spacegroup==229
+    hkl=[1 1 0 ; 0 0 2 ; 1 1 2];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+else
+  disp('Sorry - only FCC/BCC currently supported')
+end
+
+%produce all possible plane normals using R_vector
+g = Rod2g(R_vector);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%produce output list - where do we expect dif and ext spots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+output=[];
+for i=1:size(all_normals,1)
+  try  % not all normals result in diffraction
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions_pair2grain(all_normals(i,:), all_hkls(i,:), grainCentroid, 0, parameters);
+  tmp = [image xdirect ydirect xdiffr ydiffr];
+  output = [output; tmp];
+  end
+end
+
+
+
+%not treating direct beam spots.
+%%convert the extspot positions to direct beam coordinates...
+%output(:,2) = output(:,2) - parameters.acq.bb(1);
+%output(:,3) = output(:,3) - parameters.acq.bb(2);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% interogate the database(s) to find predicted spot pairs
+%% and misassigned difspots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%produce a list of possibles - difspots that might belong to the grain.
+disp(sprintf('asking %d database queries',length(output)))
+
+for i=1:size(output,1)
+  
+  %is the predicted difspot likely to clip the edge of the detector?
+  %if so allow greater freedom for matching centroid
+  dif_Xsearch=0.2; dif_Ysearch=0.2; %fraction of spot size allowed
+ % ext_Xsearch=0.35; ext_Ysearch=0.1; %clipping doesn't effect extspots, vertical size should be invarient
+%   if (output(i,4)<(dif_Xsize/2) | output(i,4)>parameters.acq.xdet-(dif_Xsize/2))
+%   dif_Xsearch=0.6;
+%   end
+%   if (output(i,5)<(dif_Ysize/2) | output(i,5)>parameters.acq.ydet-(dif_Ysize/2))
+%   dif_Ysearch=0.6;
+%   end
+  
+  %deal with which half of the 360 scan to look at
+  if output(i,1) >= parameters.acq.nproj
+    image=output(i,1)-parameters.acq.nproj;
+    name = parameters.acq.pair_name;
+    this_pair=2;
+  else
+    image=output(i,1);
+    name=parameters.acq.name;
+    this_pair=1;
+  end
+ 
+  %find possible difspots - main search
+  %get difspotID,grainID,MaxImage where MaxImage within 10, difspot
+  %Centroid within search range in x and y, and difspot size with search
+  %range in x and y, order by size match to spots already in grain and return best only"
+  warning('grain rustling disabled!!!')
+	
+  query=sprintf(['select difspotID,MaxImage from %sdifspot where '...
+    '(%d between StartImage-10 and EndImage+10) '...
+     'and (abs(CentroidX-%d)/%d)<%f '...
+     'and (abs(CentroidY-%d)/%d)<%f '...
+     'and (abs(BoundingBoxXsize-%d)/%d)<%f and (abs(BoundingBoxYsize-%d)/%d)<%f '...
+     'order by ((abs(BoundingBoxXsize-%d)/%d)+(abs(BoundingBoxYsize-%d)/%d)) limit 1'],...
+    name,image,...
+     output(i,4),dif_Xsize,dif_Xsearch,...
+     output(i,5),dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Xsearch,dif_Ysize,dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Ysize,dif_Ysize);
+   [difspotID,MaxImage] = mym(query);
+  
+   
+   
+   %has this difspot already been assigned to this grain?
+   if ~isempty(difspotID)
+     dummy1=find(struct_ids==difspotID & pair_vector==this_pair) 
+
+     if isempty(dummy1) 
+
+       disp('need a check here on the pair table - if the spot is part of a pair, is it the right hkl type?')
+       %trust pair table over this forward simulation, so break out if the
+       %pair info disagrees.
+       
+       
+       %record as a possible difspot to be added, and which half of scan
+       dif_possibles = [dif_possibles difspotID];
+       dif_possibles_pair = [dif_possibles_pair this_pair];
+
+
+     end  % if a possible difspot found
+   end % if the difspot does not already belong to the grain
+  
+end    % loop over predicted spot positions
+  
+
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtForwardSimulate_pair2grain360.m b/4_spot_sorting/gtForwardSimulate_pair2grain360.m
new file mode 100755
index 0000000000000000000000000000000000000000..44e60135aef73b9d8031018c54d212ea8727e7c0
--- /dev/null
+++ b/4_spot_sorting/gtForwardSimulate_pair2grain360.m
@@ -0,0 +1,183 @@
+
+
+%   gtForwardSimulate_pair2grain
+%to work insode of gtPairs2Grains, difspot only grain indexing.
+%pick up higher order hkls, unpaired difspots, etc.  
+%only need to consider difspots.
+%different treatment of grain position, because calculated in sample space
+%from line intersect, rather than backproj.
+%know that r-vectors, plane normals, angles are consistant between 3d line
+%treatment and extspot treatment.
+% pair2grain360 - single 360 scan, no pair vector crap
+
+
+%forward simulation - search database for missed spots...
+%modify to simplify, to use as part of gtHandleSpot2 process, before a
+%grain%d_.mat is written.
+%Arguments: grainCentroid [x,y,z], r-vector, existing struct_ids
+%returns a list of struct_ids to add to the grain - extspot/difspot pairs
+%where both spots are in valid position, and size is okay also.
+
+%keep in a list of spots where the difspot matchs but the extspot is in the
+%wrong place - possible rerun autofind cases
+
+%360 degree pairs format - search in both the "home" dataset, and the pair
+%dataset
+%return also a list of which half of the scan each predicted new spot pair
+%belongs to
+
+%Marcelo, Andy
+%31/10/2006
+
+
+function [dif_possibles] = gtForwardSimulate_pair2grain360(grainCentroid, R_vector, struct_ids, parameters)
+
+%load data 
+if isempty(parameters)
+  load parameters.mat
+end
+
+%get ready to ask the database questions
+dif_possibles=[];%possible difspot struct_ids
+dif_possibles_pair=[];%which half of the scan
+
+%get the mean difspot, extspot sizes for the current spots in the grain
+dif_Xsize=[]; dif_Ysize=[];ext_Xsize=[]; ext_Ysize=[];
+name = parameters.acq.name;
+
+for i=1:length(struct_ids)
+query=sprintf(['select BoundingBoxXsize,BoundingBoxYsize from '...
+  '%sdifspot where difspotID=%d'],...
+  name,struct_ids(i));
+[dif_Xsize(i), dif_Ysize(i)]=mym(query);
+end
+dif_Xsize=mean(dif_Xsize);
+dif_Ysize=mean(dif_Ysize);
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+  hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+elseif parameters.acq.spacegroup==229
+    hkl=[1 1 0 ; 0 0 2 ; 1 1 2];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+else
+  disp('Sorry - only FCC/BCC currently supported')
+end
+
+%produce all possible plane normals using R_vector
+g = Rod2g(R_vector);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%produce output list - where do we expect dif and ext spots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+output=[];
+for i=1:size(all_normals,1)
+  try  % not all normals result in diffraction
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions_pair2grain360(all_normals(i,:), all_hkls(i,:), grainCentroid, 0, parameters);
+  tmp = [image xdirect ydirect xdiffr ydiffr];
+  output = [output; tmp];
+  end
+end
+
+
+
+%not treating direct beam spots.
+%%convert the extspot positions to direct beam coordinates...
+%output(:,2) = output(:,2) - parameters.acq.bb(1);
+%output(:,3) = output(:,3) - parameters.acq.bb(2);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% interogate the database(s) to find predicted spot pairs
+%% and misassigned difspots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%produce a list of possibles - difspots that might belong to the grain.
+disp(sprintf('asking %d database queries',length(output)))
+
+for i=1:size(output,1)
+  
+  %is the predicted difspot likely to clip the edge of the detector?
+  %if so allow greater freedom for matching centroid
+  dif_Xsearch=0.2; dif_Ysearch=0.2; %fraction of spot size allowed
+ % ext_Xsearch=0.35; ext_Ysearch=0.1; %clipping doesn't effect extspots, vertical size should be invarient
+%   if (output(i,4)<(dif_Xsize/2) | output(i,4)>parameters.acq.xdet-(dif_Xsize/2))
+%   dif_Xsearch=0.6;
+%   end
+%   if (output(i,5)<(dif_Ysize/2) | output(i,5)>parameters.acq.ydet-(dif_Ysize/2))
+%   dif_Ysearch=0.6;
+%   end
+  
+
+    image=output(i,1);
+
+ 
+  %find possible difspots - main search
+  %get difspotID,grainID,MaxImage where MaxImage within 10, difspot
+  %Centroid within search range in x and y, and difspot size with search
+  %range in x and y, order by size match to spots already in grain and return best only"
+  warning('grain rustling disabled!!!')
+	
+  query=sprintf(['select difspotID,MaxImage from %sdifspot where '...
+    '(%d between StartImage-10 and EndImage+10) '...
+     'and (abs(CentroidX-%d)/%d)<%f '...
+     'and (abs(CentroidY-%d)/%d)<%f '...
+     'and (abs(BoundingBoxXsize-%d)/%d)<%f and (abs(BoundingBoxYsize-%d)/%d)<%f '...
+     'order by ((abs(BoundingBoxXsize-%d)/%d)+(abs(BoundingBoxYsize-%d)/%d)) limit 1'],...
+    name,image,...
+     output(i,4),dif_Xsize,dif_Xsearch,...
+     output(i,5),dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Xsearch,dif_Ysize,dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Ysize,dif_Ysize);
+   [difspotID,MaxImage] = mym(query);
+  
+   
+   
+   %has this difspot already been assigned to this grain?
+   if ~isempty(difspotID)
+     dummy1=find(struct_ids==difspotID) 
+
+     if isempty(dummy1) 
+
+       disp('need a check here on the pair table - if the spot is part of a pair, is it the right hkl type?')
+       %trust pair table over this forward simulation, so break out if the
+       %pair info disagrees.
+       
+       
+       %record as a possible difspot to be added, and which half of scan
+       dif_possibles = [dif_possibles difspotID];
+
+
+     end  % if a possible difspot found
+   end % if the difspot does not already belong to the grain
+  
+end    % loop over predicted spot positions
+  
+
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtGetBBProps.m b/4_spot_sorting/gtGetBBProps.m
new file mode 100755
index 0000000000000000000000000000000000000000..638f31d15fc94b93adb130dc11f609169bdcb0a9
--- /dev/null
+++ b/4_spot_sorting/gtGetBBProps.m
@@ -0,0 +1,43 @@
+function [bb,centroid]=gtGetBBProps(struct_id, parameters, bbtype)
+% usage: [bb,centroid]=gtGetBBProps(struct_id);  % to get best bbox available
+%    or  [bb,centroid]=gtGetBBProps(struct_id,'search');  % to get search bbox
+
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+name_root=parameters.acq.name;
+
+if exist('bbtype','var')
+  % if specified, use the searchBB explicitly.
+  disp('Using search bounding box')
+
+  mysqlcmd=sprintf(...
+    'select searchbbID from %sextspot where extspotID=%d',...
+    name_root,struct_id);
+  searchbboxID=mym(mysqlcmd);
+
+  mysqlcmd=sprintf(...
+    'select Xorigin, Yorigin, Xsize, Ysize,Xcentroid,Ycentroid from %sbboxes where bboxID=%d',...
+    name_root,...
+    searchbboxID);
+
+
+else
+  % otherwise, use the bbview to return the best bounding box (and
+  % centroid)
+
+  mysqlcmd=sprintf(...
+    'select Xorigin,Yorigin,Xsize,Ysize,Xcentroid,Ycentroid from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+    name_root,...
+    name_root,...
+    name_root,...
+    name_root,...
+    name_root,...
+    struct_id);
+end
+
+[bb(1),bb(2),bb(3),bb(4),centroid(1),centroid(2)]=mym(mysqlcmd);
+
diff --git a/4_spot_sorting/gtGetBBProps_pair.m b/4_spot_sorting/gtGetBBProps_pair.m
new file mode 100755
index 0000000000000000000000000000000000000000..815a1c57ed7a00e020e3cf6225a6423d3270f40b
--- /dev/null
+++ b/4_spot_sorting/gtGetBBProps_pair.m
@@ -0,0 +1,57 @@
+function [bb,centroid]=gtGetBBProps_pair(struct_id, pair, bbtype)
+% usage: [bb,centroid]=gtGetBBProps(struct_id);  % to get best bbox available
+%    or  [bb,centroid]=gtGetBBProps(struct_id,'search');  % to get search bbox
+% pair: 1 for this scan, 2 if the struct_id refers to the pair dataset 
+global parameters;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+
+if pair == 2
+  name_root = parameters.acq.pair_name;
+elseif pair == 1
+name_root=parameters.acq.name;
+else
+  Error('Need to specify "pair" as 1 or 2 - ak 1/2007')
+return
+end
+
+if exist('bbtype','var')
+  % if specified, use the searchBB explicitly.
+  disp('Using search bounding box')
+
+  mysqlcmd=sprintf(...
+    'select searchbbID from %sextspot where extspotID=%d',...
+    name_root,struct_id);
+  searchbboxID=mym(mysqlcmd);
+
+  mysqlcmd=sprintf(...
+    'select Xorigin, Yorigin, Xsize, Ysize,Xcentroid,Ycentroid from %sbboxes where bboxID=%d',...
+    name_root,...
+    searchbboxID);
+
+
+else
+  % otherwise, use the bbview to return the best bounding box (and
+  % centroid)
+
+  mysqlcmd=sprintf(...
+    'select Xorigin,Yorigin,Xsize,Ysize,Xcentroid,Ycentroid from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+    name_root,...
+    name_root,...
+    name_root,...
+    name_root,...
+    name_root,...
+    struct_id);
+end
+
+[bb(1),bb(2),bb(3),bb(4),centroid(1),centroid(2)]=mym(mysqlcmd);
+
+
+
+
+%%get snake if possible, else use difspot silhouette
+%if mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',parameters.acq.name,struct_id)) == true;
\ No newline at end of file
diff --git a/4_spot_sorting/gtGetCubicSymOp.m b/4_spot_sorting/gtGetCubicSymOp.m
new file mode 100755
index 0000000000000000000000000000000000000000..1161fbc1ef486dba5894bd2d23e7ba74698adcb1
--- /dev/null
+++ b/4_spot_sorting/gtGetCubicSymOp.m
@@ -0,0 +1,30 @@
+function [gc]=GetCubicSymOp();
+
+% This function returns the 24 crystal symmetry operators for the cubic crystals.
+% The symmetry operators as tabulated from tabel 3.2 in Hansen et al.
+
+gc(1).g=[1 0 0 ; 0 1 0 ; 0 0 1];
+gc(2).g=[-1 0 0 ; 0 1 0 ; 0 0 -1];
+gc(3).g=[-1 0 0 ; 0 -1 0 ; 0 0 1];
+gc(4).g=[1 0 0 ; 0 -1 0 ; 0 0 -1];
+gc(5).g=[0 1 0 ; 0 0 1 ; 1 0 0];
+gc(6).g=[0 -1 0 ; 0 0 1 ; -1 0 0];
+gc(7).g=[0 -1 0 ; 0 0 -1 ; 1 0 0];
+gc(8).g=[0 1 0 ; 0 0 -1 ; -1 0 0];
+gc(9).g=[0 0 1 ; 1 0 0 ; 0 1 0];
+gc(10).g=[0 0 -1 ; 1 0 0 ; 0 -1 0];
+gc(11).g=[0 0 -1 ; -1 0 0 ; 0 1 0];
+gc(12).g=[0 0 1 ; -1 0 0 ; 0 -1 0];
+gc(13).g=[0 0 -1 ; 0 -1 0 ; -1 0 0];
+gc(14).g=[0 0 1 ; 0 -1 0 ; 1 0 0];
+gc(15).g=[0 0 1 ; 0 1 0 ; -1 0 0];
+gc(16).g=[0 0 -1 ; 0 1 0 ; 1 0 0];
+gc(17).g=[-1 0 0 ; 0 0 -1 ; 0 -1 0];
+gc(18).g=[1 0 0 ; 0 0 -1 ; 0 1 0];
+gc(19).g=[1 0 0 ; 0 0 1 ; 0 -1 0];
+gc(20).g=[-1 0 0 ; 0 0 1 ; 0 1 0];
+gc(21).g=[0 -1 0 ; -1 0 0 ; 0 0 -1];
+gc(22).g=[0 1 0 ; -1 0 0 ; 0 0 1];
+gc(23).g=[0 1 0 ; 1 0 0 ; 0 0 -1];
+gc(24).g=[0 -1 0 ; 1 0 0 ; 0 0 1];
+
diff --git a/4_spot_sorting/gtGetHexagonalSymOp_sab.m b/4_spot_sorting/gtGetHexagonalSymOp_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..4848ae1f97031a5619a0066671e3ce560aee1189
--- /dev/null
+++ b/4_spot_sorting/gtGetHexagonalSymOp_sab.m
@@ -0,0 +1,89 @@
+function [gh]=gtGetHexagonalSymOp_sab()
+
+
+% modif sabine
+load parameters.mat
+spacegroup = parameters.acq.spacegroup ; 
+
+
+switch spacegroup
+    case {663, 194, 167}
+
+%This function returns the  12 symmetry operators for the hexagonal crystal
+gh(1).g=[...
+  1 0 0 0;
+  0 1 0 0;
+  0 0 1 0;
+  0 0 0 1] ;
+
+gh(2).g=[...
+  0 0 1 0;
+  1 0 0 0;
+  0 1 0 0;
+  0 0 0 1];
+
+gh(3).g = [...
+  0 1 0 0;
+  0 0 1 0;
+  1 0 0 0;
+  0 0 0 1];
+
+gh(4).g=[...
+  1 0 0 0;
+  0 1 0 0;
+  0 0 1 0;
+  0 0 0 -1] ;
+
+gh(5).g=[...
+  0 0 1 0;
+  1 0 0 0;
+  0 1 0 0;
+  0 0 0 -1];
+
+gh(6).g = [...
+   0 1 0 0;
+  0 0 1 0;
+  1 0 0 0;
+  0 0 0 -1];
+
+gh(7).g=[...
+  -1 0 0 0;
+  0 -1 0 0;
+  0 0 -1 0;
+  0 0 0 1] ;
+
+gh(8).g=[...
+  0 0 -1 0;
+  -1 0 0 0;
+  0 -1 0 0;
+  0 0 0 1];
+
+gh(9).g = [...
+  0 -1 0 0;
+  0 0 -1 0;
+  -1 0 0 0;
+  0 0 0 1];
+
+gh(10).g=[...
+  -1 0 0 0;
+  0 -1 0 0;
+  0 0 -1 0;
+  0 0 0 -1] ;
+
+gh(11).g=[...
+  0 0 -1 0;
+  -1 0 0 0;
+  0 -1 0 0;
+  0 0 0 -1];
+
+gh(12).g = [...
+  0 -1 0 0;
+  0 0 -1 0;
+  -1 0 0 0;
+  0 0 0 -1];
+  
+    otherwise
+        disp('spacegroup not supported')
+            
+end
+
diff --git a/4_spot_sorting/gtGetOmega.m b/4_spot_sorting/gtGetOmega.m
new file mode 100755
index 0000000000000000000000000000000000000000..714a4122d812c8ea30b4e2a94711e98f63157a88
--- /dev/null
+++ b/4_spot_sorting/gtGetOmega.m
@@ -0,0 +1,22 @@
+function Omega = gtGetOmega(struct_ids, parameters)
+%get the omega angles corresponding to MaxImage of struct_ids vector
+%returns angle in radians!
+
+if isempty(parameters)
+  load parameters
+end
+
+%change to database query
+
+Omega=[];
+for i=1:length(struct_ids)
+  Omega(i) = mym(sprintf('select MaxImage from %sdifspot where difspotID = "%d"',parameters.acq.name,struct_ids(i)));
+end
+Omega = pi*(Omega./parameters.acq.nproj);
+
+
+% %To return the negative angle!
+% if strcmp(parameters.acq.name, 'Andreas3_')
+%   Omega=-Omega;
+%   disp('changing sign of OMEGA !!!')
+% end
\ No newline at end of file
diff --git a/4_spot_sorting/gtGetOmega_360.m b/4_spot_sorting/gtGetOmega_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..1b61a569bff0848190b5388008db71d22622b8f1
--- /dev/null
+++ b/4_spot_sorting/gtGetOmega_360.m
@@ -0,0 +1,30 @@
+function Omega = gtGetOmega_360(pair_ids)
+%get the omega angles corresponding to MaxImage of struct_ids vector
+%if there is a difA spot - omega is in range 0-180,
+%else if only a difB spot then omega will be in range 180-360
+%returns angle in DEGREES!
+
+%change to database query
+global parameters
+acq=parameters.acq;%to shorten sprintfs!
+Omega=[];
+
+
+for i=1:length(pair_ids)
+  
+  mysqlcmd = sprintf(['select ifnull(%sdifspot.MaxImage,%sdifspot.MaxImage+%d) '...
+    'from %s left join %sdifspot on difAID=%sdifspot.difspotID '...
+    'left join %sdifspot on difBID=%sdifspot.difspotID '...
+    'where %s.pairID=%d'],...
+    acq.difA_name, acq.difB_name, acq.nproj,...
+    acq.pair_tablename,  acq.difA_name, acq.difA_name,...
+    acq.difB_name, acq.difB_name,...
+    acq.pair_tablename,pair_ids(i));
+  
+  Omega(i) = mym(mysqlcmd);
+
+end
+
+Omega = 180*(Omega./parameters.acq.nproj);
+
+end
\ No newline at end of file
diff --git a/4_spot_sorting/gtGetOmega_pair.m b/4_spot_sorting/gtGetOmega_pair.m
new file mode 100755
index 0000000000000000000000000000000000000000..81fbc03362d5abb218f1c09894f0b77375866bc6
--- /dev/null
+++ b/4_spot_sorting/gtGetOmega_pair.m
@@ -0,0 +1,31 @@
+function Omega = gtGetOmega_pair(struct_ids, pair_vector, parameters)
+%get the omega angles corresponding to MaxImage of struct_ids vector
+%pair_vector - 1 or 2 for this half or other half of the scan
+%current directory.
+%returns angle in radians!
+
+
+
+%change to database query
+if isempty(parameters)
+  load parameters.mat
+end
+
+Omega=[];
+for i=1:length(struct_ids)
+  
+  if pair_vector(i)==2
+    Omega(i) = parameters.acq.nproj+mym(sprintf('select MaxImage from %sdifspot where difspotID = %d',parameters.acq.pair_name,struct_ids(i)));
+  elseif pair_vector(i)==1
+    Omega(i) = mym(sprintf('select MaxImage from %sdifspot where difspotID = %d',parameters.acq.name,struct_ids(i)));
+  end
+  
+end
+Omega = pi*(Omega./parameters.acq.nproj);
+warning('messing with omega!')
+%warning('Changed sign in gtGetOmega_pair!!!  For ID11 data...  ak')
+%Omega = -Omega;
+
+
+
+end
\ No newline at end of file
diff --git a/4_spot_sorting/gtGetReflections.m b/4_spot_sorting/gtGetReflections.m
new file mode 100755
index 0000000000000000000000000000000000000000..23d5203d5b3c0b6e3c57bf6004b5247f79a44215
--- /dev/null
+++ b/4_spot_sorting/gtGetReflections.m
@@ -0,0 +1,28 @@
+function hkl_reflections = gtnewGetReflections(hkl)    
+% from input hkl [h k l], return matrix(n x 3) of all symmetry related
+% reflections.  Uses Riso script GetCubicSymOp
+
+%get symmetry operators
+sym = gtGetCubicSymOp;
+
+%apply to input reflection
+for i=1:length(sym)
+  hkl_reflections(i,:) = hkl*sym(i).g;
+end
+
+
+% %remove duplicates
+
+% dummy=[];counter=1;
+% for i=1:length(sym)
+%   for j=(i+1):length(sym)    
+%     if hkl_reflections(i,:) == hkl_reflections(j,:)
+%       dummy(counter)=i;
+%       counter=counter+1;
+%     end
+%   end
+% end
+% hkl_reflections(dummy,:)=[];
+
+hkl_reflections=unique(hkl_reflections, 'rows');
+
diff --git a/4_spot_sorting/gtGetReflections_sab.m b/4_spot_sorting/gtGetReflections_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..493e1a937b85e2b040d48af6052486a2cf18f9f8
--- /dev/null
+++ b/4_spot_sorting/gtGetReflections_sab.m
@@ -0,0 +1,26 @@
+function hkil_reflections = gtGetReflections_sab(hkil)    
+% from input hkil [h k i l], return matrix(n x 4) of all symmetry related
+% reflections.  Uses gtGetHexagonalSymOp_sab modified from Risoe group
+
+%get symmetry operators
+sym = gtGetHexagonalSymOp_sab();
+
+%apply to input reflection
+for i=1:length(sym)
+  hkil_reflections(i,:) = hkil*sym(i).g;
+end
+
+hkil_reflections=unique(hkil_reflections, 'rows');
+
+
+% %remove duplicates
+% dummy=[];counter=1;
+% for i=1:length(sym)
+%   for j=(i+1):length(sym)    
+%     if hkil_reflections(i,:) == hkil_reflections(j,:)
+%       dummy(counter)=i;
+%       counter=counter+1;
+%     end
+%   end
+% end
+% hkil_reflections(dummy,:)=[];
diff --git a/4_spot_sorting/gtGetSpaceGroupReflections.m b/4_spot_sorting/gtGetSpaceGroupReflections.m
new file mode 100755
index 0000000000000000000000000000000000000000..ed767f52e5d88ef628e83876ea0be728cc90e3e7
--- /dev/null
+++ b/4_spot_sorting/gtGetSpaceGroupReflections.m
@@ -0,0 +1,20 @@
+% 
+% Return the main reflecting plane-families of a given spacegroup.
+%
+
+function reflections=gtGetSpaceGroupReflections(spacegroup)
+
+ %should try to only store these lists in a single place! ie in gtnew_calculate_twotheta.
+ %Otherwise can have total problems if two lists of reflections are not in the same order.
+
+try %get from gtnew_calculate_twotheta
+ [tmp, reflections]=gtnew_calculate_twotheta;
+  reflections=reflections.reflections;
+
+catch 
+  disp('No data available for the given spacegroup.')
+  disp('Please, modify gtnew_calculate_twotheta.m')
+  
+end
+
+end % of function
diff --git a/4_spot_sorting/gtGetSummedExtSpot.m b/4_spot_sorting/gtGetSummedExtSpot.m
new file mode 100755
index 0000000000000000000000000000000000000000..40b057993d9bd7bec5adb422f2ac9017b954a873
--- /dev/null
+++ b/4_spot_sorting/gtGetSummedExtSpot.m
@@ -0,0 +1,90 @@
+function im=gtGetSummedExtSpot(struct_id,varargin)
+% returns the summed full extinction spot image
+% conversion to database complete
+
+parameters=[];
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+warning('contains proper bodged bb faffing, make nice after rerunning autofind')
+
+
+[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select Xorigin,Yorigin,Xsize,Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  struct_id));
+
+%get snake if possible, else use difspot silhouette
+if mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',...
+    parameters.acq.name,...
+    struct_id)) == true;
+
+ 
+%put snake relative to boundingbox
+mysqlcmd=sprintf('select x,y from %ssnakes where snakeID=%d',parameters.acq.name,struct_id);
+
+[snakex,snakey]=mym(mysqlcmd);
+snakex = snakex - floor(bb(1));
+snakey = snakey - floor(bb(2));
+mask = poly2mask(snakex, snakey, bb(4), bb(3));
+
+
+
+else
+  disp('Not using snake')
+%if we don't have a snake
+summeddif=gtGetSummedDifSpot(struct_id);
+
+%chqnge all this - save snake input in table during autofind, and reread
+%after.  This recreation is stupuid
+summeddif_bw=summeddif>0.25*max(summeddif(:));
+summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+mask=bwmorph(summeddif_bw,'dilate',1);
+%%crop mask here
+tmp2=regionprops(double(mask),'BoundingBox');
+tmp2=tmp2.BoundingBox;
+  
+tmp2=ceil(tmp2);%gt convention
+
+mask = gtCrop(mask,tmp2);
+bb(3:4)=tmp2(3:4);%change this!
+
+
+end
+
+%put BoundingBox into coordinates of the full image
+%not needed if using ext images, only if using the middle bit of fulls
+%bb(1) = ceil(bb(1) + parameters.acq.bb(1));
+%bb(2) = ceil(bb(2) + parameters.acq.bb(2));
+
+im=zeros(bb(4), bb(3));
+
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',parameters.acq.name,struct_id);
+[first,last]=mym(mysqlcmd);
+
+%disp([num2str(last-first+1) ' images in sum'])
+
+for i=first:last
+  im = im + edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',parameters.acq.dir,i), bb);
+end
+
+%apply mask , either from snake or from difspot silhouette
+im = im.*mask;
+
+
diff --git a/4_spot_sorting/gtGetSummedExtSpot_360.m b/4_spot_sorting/gtGetSummedExtSpot_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..4ffd9c82702a9fe01a0cefd05e8defb9ab3bc17f
--- /dev/null
+++ b/4_spot_sorting/gtGetSummedExtSpot_360.m
@@ -0,0 +1,94 @@
+function im=gtGetSummedExtSpot_360(struct_id, parameters, varargin)
+% returns the summed full extinction spot image
+
+%360degree scan convention - ak 10/2007
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+warning('contains proper bodged bb faffing, make nice after rerunning autofind')
+
+%get the name for this scan
+name=parameters.acq.name;
+
+
+[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select Xorigin,Yorigin,Xsize,Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+  name, name, name, name, name, ...
+  struct_id));
+
+%get snake if possible, else use difspot silhouette
+if mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',...
+    name, struct_id)) == true;
+
+%put snake relative to boundingbox
+mysqlcmd=sprintf('select x,y from %ssnakes where snakeID=%d', name, struct_id);
+
+[snakex,snakey]=mym(mysqlcmd);
+snakex = snakex - floor(bb(1));
+snakey = snakey - floor(bb(2));
+mask = poly2mask(snakex, snakey, bb(4), bb(3));
+
+else
+  disp('Not using snake')
+%if we don't have a snake
+summeddif=gtGetSummedDifSpot(struct_id, parameters, 1);
+
+%change all this - save snake input in table during autofind, and reread
+%after.  This recreation is stupuid
+summeddif_bw=summeddif>0.25*max(summeddif(:));
+summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+mask=bwmorph(summeddif_bw,'dilate',1);
+%%crop mask here
+tmp2=regionprops(double(mask),'BoundingBox');
+tmp2=tmp2.BoundingBox;
+  
+tmp2=ceil(tmp2);%gt convention
+
+mask = gtCrop(mask,tmp2);
+bb(3:4)=tmp2(3:4);%change this!
+
+
+end
+
+%put BoundingBox into coordinates of the full image
+%not needed if using ext images, only if using the middle bit of fulls
+%bb(1) = ceil(bb(1) + parameters.acq.bb(1));
+%bb(2) = ceil(bb(2) + parameters.acq.bb(2));
+
+im=zeros(bb(4), bb(3));
+
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',name,struct_id);
+[first,last]=mym(mysqlcmd);
+
+%can have a problem because extspot bb extends beyond the edge of the ext image,
+%which has the size of parameters.acq.bb
+if bb(2)+bb(4) > parameters.acq.bb(4)
+  bb(4) = parameters.acq.bb(4)-bb(2);
+end
+if bb(1)+bb(3) > parameters.acq.bb(3)
+  bb(3) = parameters.acq.bb(3)-bb(1);
+end
+tmp_im=zeros(bb(4), bb(3)); % cropped image size
+
+for i=first:last
+  tmp_im = tmp_im + edf_read(sprintf('1_preprocessing/ext/ext%04d.edf',i), bb);
+end
+
+im=gtPlaceSubImage(tmp_im, im, 1, 1); % put the cropped image back into the correct size
+
+%apply mask , either from snake or from difspot silhouette
+im = im.*mask;
+
+
diff --git a/4_spot_sorting/gtGetSummedExtSpot_360_wl.m b/4_spot_sorting/gtGetSummedExtSpot_360_wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..a5e59e399dd4a1144a7923228b814dc7f3d98102
--- /dev/null
+++ b/4_spot_sorting/gtGetSummedExtSpot_360_wl.m
@@ -0,0 +1,100 @@
+function im=gtGetSummedExtSpot_360(struct_id, parameters, varargin)
+% returns the summed full extinction spot image
+
+%360degree scan convention - ak 10/2007
+
+if ~exist('parameters','var')
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+warning('contains proper bodged bb faffing, make nice after rerunning autofind')
+
+%get the name for this scan
+name=parameters.acq.name;
+
+
+%[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select Xorigin,Yorigin,Xsize,Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+ % name, name, name, name, name, ...
+%  struct_id));
+[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select Xorigin,Yorigin,Xsize,Ysize from %sextspot inner join %sbboxes on %sextspot.searchbbID=%sbboxes.bboxID where %sextspot.extspotID = %d', ...
+  name, name, name, name, name, ...
+  struct_id));
+
+bb(1)=max(bb(1)-10,1);
+bb(3)=bb(3)+20
+
+%get snake if possible, else use difspot silhouette
+if 0 % mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',...
+     % name, struct_id)) == true;
+
+%put snake relative to boundingbox
+mysqlcmd=sprintf('select x,y from %ssnakes where snakeID=%d', name, struct_id);
+
+[snakex,snakey]=mym(mysqlcmd);
+snakex = snakex - floor(bb(1));
+snakey = snakey - floor(bb(2));
+mask = poly2mask(snakex, snakey, bb(4), bb(3));
+
+else
+  disp('Not using snake')
+%if we don't have a snake
+summeddif=gtGetSummedDifSpot(struct_id, parameters, 1);
+
+%change all this - save snake input in table during autofind, and reread
+%after.  This recreation is stupuid
+summeddif_bw=summeddif>0.25*max(summeddif(:));
+summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+mask=bwmorph(summeddif_bw,'dilate',1);
+%%crop mask here
+tmp2=regionprops(double(mask),'BoundingBox');
+tmp2=tmp2.BoundingBox;
+  
+tmp2=ceil(tmp2);%gt convention
+
+mask = gtCrop(mask,tmp2);
+%bb(3:4)=tmp2(3:4);%change this!
+
+
+end
+
+%put BoundingBox into coordinates of the full image
+%not needed if using ext images, only if using the middle bit of fulls
+%bb(1) = ceil(bb(1) + parameters.acq.bb(1));
+%bb(2) = ceil(bb(2) + parameters.acq.bb(2));
+
+im=zeros(bb(4), bb(3)+20);
+
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',name,struct_id);
+[first,last]=mym(mysqlcmd);
+
+%can have a problem because extspot bb extends beyond the edge of the ext image,
+%which has the size of parameters.acq.bb
+if bb(2)+bb(4) > parameters.acq.bb(4)
+  bb(4) = parameters.acq.bb(4)-bb(2);
+end
+if bb(1)+bb(3) > parameters.acq.bb(3)
+  bb(3) = parameters.acq.bb(3)-bb(1);
+end
+tmp_im=zeros(bb(4), bb(3)); % cropped image size
+
+for i=first:last
+  tmp_im = tmp_im + edf_read(sprintf('1_preprocessing/ext/ext%04d.edf',i), bb);
+end
+
+im=gtPlaceSubImage(tmp_im, im, 1, 1); % put the cropped image back into the correct size
+
+%apply mask , either from snake or from difspot silhouette
+%im = im.*mask;
+
+
diff --git a/4_spot_sorting/gtGetSummedExtSpot_pair.m b/4_spot_sorting/gtGetSummedExtSpot_pair.m
new file mode 100755
index 0000000000000000000000000000000000000000..5b02d401591f3c85a5df155b93808f11659029cb
--- /dev/null
+++ b/4_spot_sorting/gtGetSummedExtSpot_pair.m
@@ -0,0 +1,105 @@
+function im=gtGetSummedExtSpot_pair(struct_id,pair,varargin)
+% returns the summed full extinction spot image
+% conversion to database complete
+%pair = 1 this dataset, pair = 2 pair dataset
+
+global parameters;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+warning('contains proper bodged bb faffing, make nice after rerunning autofind')
+
+%get the name for this scan, or the pair dataset
+if pair == 2
+  name=parameters.acq.pair_name;
+elseif pair ==1
+  name=parameters.acq.name;
+end
+%path for reading images (assume pair directory is in same parent
+%directory)
+path=sprintf('../%s/',name);
+
+
+[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select Xorigin,Yorigin,Xsize,Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+  name, name, name, name, name, ...
+  struct_id));
+
+%get snake if possible, else use difspot silhouette
+if mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',...
+    name, struct_id)) == true;
+
+%put snake relative to boundingbox
+mysqlcmd=sprintf('select x,y from %ssnakes where snakeID=%d', name, struct_id);
+
+[snakex,snakey]=mym(mysqlcmd);
+snakex = snakex - floor(bb(1));
+snakey = snakey - floor(bb(2));
+mask = poly2mask(snakex, snakey, bb(4), bb(3));
+
+
+
+else
+  disp('Not using snake')
+%if we don't have a snake
+summeddif=gtGetSummedDifSpot_pair(struct_id, pair);
+
+%change all this - save snake input in table during autofind, and reread
+%after.  This recreation is stupuid
+summeddif_bw=summeddif>0.25*max(summeddif(:));
+summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+mask=bwmorph(summeddif_bw,'dilate',1);
+%%crop mask here
+tmp2=regionprops(double(mask),'BoundingBox');
+tmp2=tmp2.BoundingBox;
+  
+tmp2=ceil(tmp2);%gt convention
+
+mask = gtCrop(mask,tmp2);
+bb(3:4)=tmp2(3:4);%change this!
+
+
+end
+
+%put BoundingBox into coordinates of the full image
+%not needed if using ext images, only if using the middle bit of fulls
+%bb(1) = ceil(bb(1) + parameters.acq.bb(1));
+%bb(2) = ceil(bb(2) + parameters.acq.bb(2));
+
+im=zeros(bb(4), bb(3));
+
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',name,struct_id);
+[first,last]=mym(mysqlcmd);
+
+%can have a problem because extspot bb extends beyond the edge of the ext image,
+%which has the size of parameters.acq.bb
+if bb(2)+bb(4) > parameters.acq.bb(4)
+  bb(4) = parameters.acq.bb(4)-bb(2);
+end
+if bb(1)+bb(3) > parameters.acq.bb(3)
+  bb(3) = parameters.acq.bb(3)-bb(1);
+end
+tmp_im=zeros(bb(4), bb(3)); % cropped image size
+
+for i=first:last
+  tmp_im = tmp_im + edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',path,i), bb);
+end
+
+im=gtPlaceSubImage(tmp_im, im, 1, 1); % put the cropped image back into the correct size
+
+%apply mask , either from snake or from difspot silhouette
+im = im.*mask;
+
+
diff --git a/4_spot_sorting/gtHKL2Cart.m b/4_spot_sorting/gtHKL2Cart.m
new file mode 100755
index 0000000000000000000000000000000000000000..0804795952ac00ac450ce48c06e3fb4711107f46
--- /dev/null
+++ b/4_spot_sorting/gtHKL2Cart.m
@@ -0,0 +1,45 @@
+
+
+function cartesian = gtHKL2Cart(hkl)
+
+% function to convert pale normals described by Miller indices 
+% (hkl, or hkil for hexagonal) to cartesian coordinates.
+% The output is a normalised vector
+% For cubic crystals than only effect is the normalisation
+% Extra cases can be added to deal with hexagonal, trigonal, othorhombic,
+% tetragonal crystals as neccessary.
+
+load parameters;
+spacegroup=parameters.acq.spacegroup;
+latticepar=parameters.acq.latticepar;
+
+
+switch spacegroup
+  case {225, 229} %cubic crytals
+    cartesian=hkl;
+   
+  case {194, 663, 167} %hexagonal crystals
+%if hexagonal but 3 index, convert to 4 index notation
+if size(hkl,2)==3
+  hkl(:,4)=hkl(:,3);
+  hkl(:,3)=-(hkl(:,1)+hkl(:,2));
+end
+% passage de l espace direct hexagonal en coordonnees cartesiennes
+cartesian(:,1)= hkl(:,1) + 0.5 * hkl(:,2);
+cartesian(:,2)= 3^0.5/2 *hkl(:,2);
+cartesian(:,3)= hkl(:,4);
+% allow for c/a ratio in hexagonal unit cell
+cartesian(:,1)=cartesian(:,1)*2/(sqrt(3)*latticepar(1));
+cartesian(:,2)=cartesian(:,2)*2/(sqrt(3)*latticepar(1));
+cartesian(:,3)=cartesian(:,3)/latticepar(3);
+
+  otherwise
+    error('Currently only spacegroups 225, 229, 194, 663 supported')
+end
+
+% normalise cartesian vector to unit vector
+cartesian=cartesian./repmat(sqrt(sum((cartesian.*cartesian),2)), 1, 3);
+
+
+
+
diff --git a/4_spot_sorting/gtHandleSpot.m b/4_spot_sorting/gtHandleSpot.m
new file mode 100755
index 0000000000000000000000000000000000000000..bd6d2837ae3517a5fa6e165dd7367d001adcba6e
--- /dev/null
+++ b/4_spot_sorting/gtHandleSpot.m
@@ -0,0 +1,403 @@
+function [accept,stack]=gtHandleSpot(spot_id,grainid)
+
+% function [stack,theta,struct_id,ind_orig,img2,accept]=handle_spot_wolf(spot_id,grainid)
+%
+% stack:    3D matrix containing the valid projections as determined by the backprojection and sine criterion
+% theta:    vector of the corresponding projection angles [radians]
+% struct_id vector containing the valid structure entries
+% ind_orig  vetor containing the indices od elements in struct_ind which belong to not replaced spots
+%             i.e.:  app.extspot(struct_id(ind_orig)).Replaced=[] for all ind_orig
+% img2      backprojection using the valid spots
+
+%add filter to use condition of known valid Theta angles to help...
+
+%try to simplify and automate
+%modify to gtnew format
+%sufficient to return "accept" only, all data written to grain%d_.mat
+
+%database enabled!
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+grainpos=[0 0 0];
+accept = 0;
+
+%get parameters of the seed spot
+warning('using 15 pixel offset in gtHandleSpot search')
+mysqlcmd=sprintf(...
+  'select Yorigin,Yorigin+Ysize,MaxImage from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID inner join %sdifspot on difspotID=%sbb.extspotID where %sbb.extspotID="%d"',...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  spot_id);
+[minY,maxY,MaxIm]=mym(mysqlcmd);
+
+if MaxIm>4000
+  minY=minY-15;
+  maxY=maxY-15;
+end
+
+%find related spots - database query replaces find_family.m
+AllowedError = max(5,ceil((maxY-minY)/parameters.match.heighttol));
+
+% in two commands, one for Greg to have a fiddle with! But already super fast...
+%mysqlcmd=sprintf(...
+ % 'select %sbb.extspotID from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where (isnull(GrainID)) and (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) order by %sbb.extspotID', ...
+%without isnull graind requirement
+% mysqlcmd=sprintf(...
+%  'select %sbb.extspotID from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where  (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) order by %sbb.extspotID', ...
+%with extspot y offset built in
+warning('using 15 pixel offset in gtHandleSpot search')
+mysqlcmd=sprintf([...
+  'select %sbb.extspotID from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID inner join %sdifspot on %sbb.extspotID=difspotID where '...
+  '(MaxImage<4000 AND (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) and isnull(GrainID)) or '...
+  '(MaxImage>4000 AND (abs((Yorigin-15) - %d)<%f) AND (abs((Yorigin-15)+Ysize-%d)<%f) and isnull(GrainID)) order by %sbb.extspotID'], ...
+parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  minY,AllowedError,...
+  maxY,AllowedError,...
+  minY,AllowedError,...
+  maxY,AllowedError,...
+  parameters.acq.name);
+
+struct_ids =mym(mysqlcmd);
+
+omega = gtGetOmega(struct_ids);
+
+%produce sinogram at mid-height of seed spot
+[stack,sino,z_of_sino]=gtReadSpots(spot_id,struct_ids);
+
+%which of struct_id vector is the original spot (spot_id)
+index = find(struct_ids==spot_id);
+
+figure;
+
+%make original spot centre line
+[orig_grad, orig_intersect] = sfMakeBackProLine(spot_id, struct_ids, sino, omega);
+
+%plot original centre line  % cannot represent vertical line with y=mx+b
+ez_orig=ezplot(sprintf('%f*x + %f',orig_grad,orig_intersect),[1 parameters.acq.bb(3)]);
+set(ez_orig,'color','g');
+axis ij
+axis equal
+axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+
+hold on
+
+%get allowed TwoTheta data
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=[tmp.elements{:}];
+tmp=[tmp{:}];
+twotheta=[tmp.centre];
+
+good_points=[];counter=1;
+disp('Examining spots...')
+%loop through all spots
+warning('assuming centre of rotation to be at centre of acq.bb - in sfMakeBackProLine')
+
+for i=1:length(struct_ids)
+  if i == index % don't need to do original spot
+    continue
+  end
+
+  %make spot centre line
+  [grad, intersect] = sfMakeBackProLine(struct_ids(i), struct_ids, sino, omega);
+  %calculate intersection with original spot line
+  tmpx = -(intersect-orig_intersect)/(grad-orig_grad);
+  tmpy = (orig_grad*tmpx) + orig_intersect;
+
+  % only continue if intersection is inside image
+  if tmpy<parameters.acq.bb(4) && tmpy>1 && tmpx<parameters.acq.bb(3) && tmpx>1
+    %    h_ez=ezplot(sprintf('%f*x + %f',grad,intersect),[1 parameters.acq.bb(3)]);
+    axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+    plot(tmpx, tmpy, 'xr')
+
+    %does intersection give good theta angles?  orig and current spots
+    %using grainpos = tmpx, tmpy, calc theta
+    [Theta_spot, Eta_spot] = sfFindAngles(struct_ids(i), tmpx, tmpy, z_of_sino,  omega(i));
+    [Theta_orig, Eta_orig] = sfFindAngles(struct_ids(index), tmpx, tmpy, z_of_sino,  omega(index));
+
+    %to use a percentage angle criteria
+%    min_spot_dif = min(abs((twotheta/2)-Theta_spot)./(twotheta/2));
+%    min_orig_dif = min(abs((twotheta/2)-Theta_orig)./(twotheta/2));
+
+%to use an absolute allowed margin of error (as in consistancy check)
+    min_spot_dif = min(abs((twotheta/2)-Theta_spot));
+    min_orig_dif = min(abs((twotheta/2)-Theta_orig));
+
+
+%    if (min_spot_dif<0.025 && min_orig_dif<0.025)% if both Thetas good to 2.5%
+    if (min_spot_dif<0.3 && min_orig_dif<0.3)% if both Thetas good to 0.3 degrees
+
+      %      [tmpx tmpy]
+      if (tmpx > 0 & tmpx <= parameters.acq.bb(3) & tmpy > 0 & tmpy <= parameters.acq.bb(3))% if point lies in image
+        plot(tmpx, tmpy, 'go') %plot point, record in good points
+        good_points(counter,1)=tmpx;
+        good_points(counter,2)=tmpy;
+        good_points(counter,3)=struct_ids(i);
+        counter=counter+1;
+      end
+    end
+  end
+end
+
+
+%find grain position from good_points
+if size(good_points,1)>4 % need at least 4 spots to proceed...
+  x_grain = fminbnd(@(x_grain) sfFindGrain(good_points, x_grain), min(good_points(:,1)), max(good_points(:,1)));
+  y_grain = (orig_grad*x_grain) + orig_intersect;
+  plot(x_grain, y_grain, 'cx', 'markersize', 20) % plot the chosen center
+
+  %find width of original projection
+  orig_sino = sino(:,index);
+  orig_binsino = orig_sino>0.1*max(orig_sino);
+  dummy=find(orig_binsino==1);
+  orig_min=min(dummy);
+  orig_max=max(dummy);
+  proj_radius = (orig_max - orig_min)/2;
+
+  %calc distance of intersections from grain position
+  good_points(:,4) = sqrt((good_points(:,1)-x_grain).^2+(good_points(:,2)-y_grain).^2);
+  dummy = find(good_points(:,4)>proj_radius);
+  good_points(dummy, :)=[];%remove intersections far from grain center
+
+  %plot the final set of intersections
+  plot(good_points(:,1), good_points(:,2), 'yo', 'markersize', 10)
+
+  %create binsino and omega for good spots only
+  good_sino(:,1)=orig_sino;
+  good_omega=omega(index);
+  good_stack(:,:,1) = stack(:,:,index);
+  good_struct_ids(1) = spot_id;
+  for j=1:size(good_points,1)
+    tmp = find(struct_ids == good_points(j,3));
+    good_sino(:,j+1) = sino(:,tmp);
+    good_omega(j+1) = omega(tmp);
+    good_stack(:,:,j+1) = stack(:,:,tmp);
+    good_struct_ids(j+1) = struct_ids(tmp);
+  end
+
+  struct_ids = good_struct_ids;
+  omega = good_omega;
+  stack = good_stack;
+  sino = good_sino;
+
+  %need at least four projections of grain for a useful reconstruction.
+  if length(struct_ids) > 3
+    accept =1;
+
+    %call sfFindAngles with the final grain position
+    %good also do this using the grain centroid after back projection
+    Theta = []; Eta = [];
+    for j=1:length(struct_ids)
+      [tmpTheta, tmpEta] = sfFindAngles(struct_ids(j), x_grain, y_grain, z_of_sino, omega(j));
+      Theta(j) = tmpTheta;
+      Eta(j) = tmpEta;
+    end
+    Omega = omega*180/pi;
+
+    %back project good spots only
+    binsino = sino>0.1*max(sino(:));
+    img2=backpro(binsino,omega);
+
+    %do imreconstruct from centre to threshold grain
+    x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+    marker=zeros(size(img2));
+    marker(y_grain, x_grain)=1;
+    mask=double((img2>0.8*img2(y_grain, x_grain)));
+    try
+      grain=imreconstruct(marker,mask);
+    catch
+      disp('Marker/mask problem - bombed out')
+      accept=false;
+      return
+    end
+
+    figure
+    h1=imshow(cat(3,img2,zeros(size(img2)),zeros(size(img2))),[]);
+    hold on
+    h2=imshow(cat(3,zeros(size(img2)),grain,zeros(size(img2))),[]);
+    set(h2,'alphadata',0.5);
+
+    
+    %get z limits
+    zstart=find(mean(sum(stack,3),2),1,'first');
+    zend=find(mean(sum(stack,3),2),1,'last');
+    zcenter=round((zend+zstart)/2);
+
+    s=regionprops(grain,'Area','BoundingBox','Centroid');
+    xgrain=s.Centroid(1);
+    ygrain=s.Centroid(2);
+    xstart = s.BoundingBox(1);
+    ystart = s.BoundingBox(2);
+    xcenter = s.BoundingBox(1)+s.BoundingBox(3)/2;
+    ycenter = s.BoundingBox(2)+s.BoundingBox(4)/2;
+    xend = xstart + s.BoundingBox(3);
+    yend = ystart + s.BoundingBox(4);
+
+    %add 20% to bounding box for luck
+    if  round(xstart -(s.BoundingBox(3)/5)) > 0
+      xstart = round(xstart - (s.BoundingBox(3)/5));
+    else
+      xstart = 1;
+    end
+
+    if round(ystart - (s.BoundingBox(4)/5)) > 0
+      ystart = round(ystart - (s.BoundingBox(4)/5));
+    else
+      ystart = 1;
+    end
+
+    if round(xend + (s.BoundingBox(3)/5)) <= parameters.acq.bb(3);
+      xend = round(xend + (s.BoundingBox(3)/5));
+    else
+      xend = parameters.acq.bb(3);
+    end
+
+    if round(yend + (s.BoundingBox(4)/5)) <= parameters.acq.bb(3);
+      yend = round(yend + (s.BoundingBox(4)/5));
+    else
+      yend = parameters.acq.bb(3);
+    end
+
+    if round(zend + ((zend-zstart)/5)) <= parameters.acq.bb(4);
+      zend = round(zend + ((zend-zstart)/5));
+    else
+      zend = parameters.acq.bb(4);
+    end
+
+    if round(zstart - ((zend-zstart)/5)) >= 1;
+      zstart = round(zstart - ((zend-zstart)/5));
+    else
+      zstart = 1;
+    end
+
+    ny = yend-ystart;
+    nx = xend-xstart;
+    nz = zend-zstart;
+
+    y1 = ystart;
+    x1 = xstart;
+
+    %grainid into database structure
+if 1%do save anything
+    
+    for i=1:length(struct_ids)
+      mysqlcmd=dbUpdate(sprintf('%sextspot',parameters.acq.name),'extspotID',struct_ids(i),'GrainID',grainid);
+      mym(mysqlcmd);
+    end
+
+    %probably don't need all of these, and certainly need to rationalise
+    %omega/theta use!
+    grainname=sprintf('grain%d_',grainid);
+    graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+    if ~exist(graindir,'dir')
+      mkdir(graindir);
+    end
+    name=sprintf('%s/%s.mat',graindir,grainname);    
+    save(name,'Omega','struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','xgrain','ygrain','Theta', 'Eta');
+    grainpos=[xgrain,ygrain,zcenter];
+
+end
+
+  else
+    disp(sprintf('only %d projections related to spot %d - skipping',length(struct_ids),spot_id))
+  end
+
+
+else
+  disp(sprintf('only %d good points on projection of spot %d - skipping',size(good_points,1),spot_id))
+end
+
+end
+
+
+function [m, c] = sfMakeBackProLine(spot_id, struct_ids, sino, theta)
+%function to return the parameters of a line passing through the proj of a
+%given spot, struct_ids is vector of spots in the sinogram, sino.
+index = find(struct_ids == spot_id);
+
+%get spot parameters
+spot_sino=sino(:,index);
+spot_com=(spot_sino'*[1:length(spot_sino)]')/sum(spot_sino);
+spot_omega=theta(index);
+
+%experiment parameters
+centre_of_backproimg_x = size(sino,1)/2;
+centre_of_backproimg_y = size(sino,1)/2;
+
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-length(spot_sino)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+function [Theta,Eta] = sfFindAngles(struct_id, grainx, grainy, grainz, omega);
+
+omega=omega*180/pi; %gtFindAngles works in radians...
+[Theta,Eta] = gtFindAngles(struct_id, grainx, grainy, grainz, omega);
+
+% global parameters;
+% %calculate Theta angle between grain position (x,y,z) and difspot of
+% %struct_id
+% 
+% mysqlcmd=sprintf('select ifnull(CentroidX,SearchCentroidX) from %sextspot where extspotID=%d',parameters.acq.name,struct_id);
+% 
+% xdirect=parameters.acq.bb(1)+mym(mysqlcmd);
+% ydirect=parameters.acq.bb(2)+grainz;
+% 
+% mysqlcmd=sprintf('select CentroidX,CentroidY from %sdifspot where difspotID=%d',parameters.acq.name,struct_id);
+% [xdiffr,ydiffr]=mym(mysqlcmd);
+% 
+% r=sqrt((xdirect-xdiffr)^2+(ydirect-ydiffr)^2);
+% 
+% grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+% angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+% 
+% dz=grain2rot.*sin(-omega+angle)+parameters.acq.dist/parameters.acq.pixelsize;
+% 
+% Theta=((atan(r./dz))/2)*180/pi;
+% 
+% Eta=atan2((xdiffr-xdirect),(ydirect-ydiffr))*180/pi;
+% if Eta<0
+%   Eta=360+Eta;
+% end
+
+end
+
+
+function output = sfFindGrain(good_points, x_grain)
+%function for fminbnd to find grain position along original projection
+dif = good_points(:,1)-x_grain;
+%minimise sum of squares for the closest half of the points, to reduce
+%effect of outliers
+dif = abs(dif);
+dif = sort(dif,1,'descend');
+tmp = ceil(size(dif,1)/2);
+dif(1:tmp)=[];
+output = dif'*dif;%sum of squares
+end
+
+
+
diff --git a/4_spot_sorting/gtHandleSpot2.m b/4_spot_sorting/gtHandleSpot2.m
new file mode 100755
index 0000000000000000000000000000000000000000..c063fc08d1f8f336ef09d78a3cc227c16f51d874
--- /dev/null
+++ b/4_spot_sorting/gtHandleSpot2.m
@@ -0,0 +1,560 @@
+function accept=gtHandleSpot2(input_id,grainid)
+
+% function [stack,theta,struct_id,ind_orig,img2,accept]=handle_spot_wolf(spot_id,grainid)
+%
+% stack:    3D matrix containing the valid projections as determined by the backprojection and sine criterion
+% theta:    vector of the corresponding projection angles [radians]
+% struct_id vector containing the valid structure entries
+% ind_orig  vetor containing the indices od elements in struct_ind which belong to not replaced spots
+%             i.e.:  app.extspot(struct_id(ind_orig)).Replaced=[] for all ind_orig
+% img2      backprojection using the valid spots
+
+%add filter to use condition of known valid Theta angles to help...
+
+%try to simplify and automate
+%modify to gtnew format
+%sufficient to return "accept" only, all data written to grain%d_.mat
+
+%simplify further - crazy to make sinogram for every extspot considered.
+%Instead, just use the centroid information contained in the database for
+%the first attempt
+%modify to also calculate the plane normals, hkls, so these can be passed
+%to a consistancy test
+
+%if dealing with pairs, the extspot id links with pair id.
+
+%database enabled!
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+if parameters.acq.type == '360degree'
+%get the root of the pair name
+name=parameters.acq.pair_tablename;
+name(end-8:end)=[];
+pair_id=input_id;
+[spot_id(1),spot_id(2)]=mym(sprintf('select difAID,difBID from %s where pairID=%d',parameters.acq.pair_tablename,pair_id));
+if ~isnan(spot_id(1))
+  spot_id=spot_id(1);
+  dif_name=parameters.acq.difA_name;
+  ABflag='A';
+elseif ~isnan(spot_id(2))
+  spot_id=spot_id(2);
+  dif_name=parameters.acq.difB_name;
+  ABflag='B';
+else
+  disp('empty pair table entry')
+  return
+end
+
+elseif parameters.acq.type == '180degree'
+  name=parameters.acq.name;
+dif_name=name;
+spot_id=input_id;
+ABflag='';
+else
+  disp('unrecognised data type!')
+return
+end
+
+
+grainpos=[0 0 0];
+accept = 0;
+
+%get parameters of the seed spot
+%warning('using 15 pixel offset in gtHandleSpot search')
+mysqlcmd=sprintf([...
+  'select Yorigin,Yorigin+Ysize,MaxImage from '... 
+  '%sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID inner join %sdifspot on difspotID=%sbb.extspotID '...
+  'where %sbb.extspotID="%d"'],...
+  name,...
+  name,...
+  name,...
+  name,...
+  dif_name,...
+  name,...
+  name,...
+  spot_id);
+[minY,maxY,MaxIm]=mym(mysqlcmd);
+
+%% 15 pixel offset for s5_dct5_
+%if MaxIm>4000
+%  minY=minY-15;
+%  maxY=maxY-15;
+%end
+
+%find related spots - database query replaces find_family.m
+AllowedError = max(5,ceil((maxY-minY)/parameters.match.heighttol));
+
+% in two commands, one for Greg to have a fiddle with! But already super fast...
+%mysqlcmd=sprintf(...
+ % 'select %sbb.extspotID from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where (isnull(GrainID)) and (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) order by %sbb.extspotID', ...
+
+ %without isnull graind requirement
+% mysqlcmd=sprintf(...
+%  'select %sbb.extspotID from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where  (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) order by %sbb.extspotID', ...
+
+%with extspot y offset built in, get Centroids also
+%warning('using 15 pixel offset in gtHandleSpot search')
+% mysqlcmd=sprintf([...
+%   'select %sbb.extspotID,ifnull(%sextspot.CentroidX,%sextspot.SearchCentroidX),ifnull(%sextspot.CentroidY,%sextspot.SearchCentroidY) '...
+%   'from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID inner join %sdifspot on %sbb.extspotID=difspotID inner join %sextspot on %sextspot.extspotID=difspotID where '...
+%   '(MaxImage<4000 AND (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) and isnull(%sextspot.GrainID)) or '...
+%   '(MaxImage>4000 AND (abs((Yorigin-15) - %d)<%f) AND (abs((Yorigin-15)+Ysize-%d)<%f) and isnull(%sextspot.GrainID)) order by %sbb.extspotID'], ...
+% parameters.acq.name,...
+%   parameters.acq.name,...
+%   parameters.acq.name,...
+%   parameters.acq.name,...
+% parameters.acq.name,...
+%   parameters.acq.name,...
+%   parameters.acq.name,...
+%   parameters.acq.name,...
+%   parameters.acq.name,...
+%   parameters.acq.name,...
+% parameters.acq.name,...
+%   parameters.acq.name,...
+%   parameters.acq.name,...
+%   minY,AllowedError,...
+%   maxY,AllowedError,...
+%   parameters.acq.name,...
+%   minY,AllowedError,...
+%   maxY,AllowedError,...
+%   parameters.acq.name,...
+%   parameters.acq.name);
+
+mysqlcmd=sprintf([...
+  'select %sbb.extspotID, Xcentroid, Ycentroid '...
+  'from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where '...
+  ' (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) AND isnull(GrainID) '...
+  ' order by %sbb.extspotID'], ...
+	name,...
+	name,...
+	name,...
+	name,...
+	name,.....
+  minY,AllowedError,...
+	maxY,AllowedError,...
+  name);
+
+[struct_ids,centroidx,centroidy] =mym(mysqlcmd);
+omega = gtGetOmega(struct_ids);
+
+%warning('applying 15 pixel shift in gtHandleSpot2 centroids')
+%dummy=find(omega>((120*pi)/180));
+%centroidy(dummy)=centroidy(dummy)-15;
+
+%which of struct_id vector is the original spot (spot_id)
+index = find(struct_ids==spot_id);
+
+figure;
+
+%make original spot centre line - don't use sino, use centroid only
+[orig_grad, orig_intersect] = sfMakeBackProLine2(spot_id, struct_ids, centroidx, omega);
+
+%plot original centre line  % cannot represent vertical line with y=mx+b
+ez_orig=ezplot(sprintf('%f*x + %f',orig_grad,orig_intersect),[1 parameters.acq.bb(3)]);
+set(ez_orig,'color','g');
+axis ij
+axis equal
+axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+
+hold on
+
+%get allowed TwoTheta data
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=[tmp.elements{:}];
+tmp=[tmp{:}];
+twotheta=[tmp.centre];
+
+good_points=[];counter=1;
+disp('Examining spots...')
+%loop through all spots
+warning('assuming centre of rotation to be at centre of acq.bb - in sfMakeBackProLine')
+
+for i=1:length(struct_ids)
+  if i == index % don't need to do original spot
+    continue
+  end
+
+  %make spot centre line
+  [grad, intersect] = sfMakeBackProLine2(struct_ids(i), struct_ids, centroidx, omega);
+  %calculate intersection with original spot line
+  tmpx = -(intersect-orig_intersect)/(grad-orig_grad);
+  tmpy = (orig_grad*tmpx) + orig_intersect;
+
+  % only continue if intersection is inside image
+  %  if tmpy<parameters.acq.bb(4) && tmpy>1 && tmpx<parameters.acq.bb(3) && tmpx>1
+  %circular sample case:
+  if ((tmpx-(parameters.acq.bb(3)/2))^2+(tmpx-(parameters.acq.bb(3)/2))^2)<(parameters.acq.bb(3)/2)^2
+
+    axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+    plot(tmpx, tmpy, 'xr')
+
+    %does intersection give good theta angles?  orig and current spots
+    %using grainpos = tmpx, tmpy, calc theta
+    %use the vertical position of the seed spot centroid
+    [Theta_spot, Eta_spot] = sfFindAngles(struct_ids(i), tmpx, tmpy, centroidy(index),  omega(i));
+    [Theta_orig, Eta_orig] = sfFindAngles(struct_ids(index), tmpx, tmpy, centroidy(index),  omega(index));
+
+		%to use a percentage angle criteria
+%    min_spot_dif = min(abs((twotheta/2)-Theta_spot)./(twotheta/2));
+%    min_orig_dif = min(abs((twotheta/2)-Theta_orig)./(twotheta/2));
+
+%to use an absolute allowed margin of error (as in consistancy check)
+    min_spot_dif = min(abs((twotheta/2)-Theta_spot));
+    min_orig_dif = min(abs((twotheta/2)-Theta_orig));
+		
+%    if (min_spot_dif<0.025 && min_orig_dif<0.025)% if both Thetas good to 2.5%
+    if (min_spot_dif<0.3 && min_orig_dif<0.3)% if both Thetas good to 0.3 degrees
+ 
+ plot(tmpx, tmpy, 'go') %plot point, record in good points
+ good_points(counter,1)=tmpx;
+ good_points(counter,2)=tmpy;
+ good_points(counter,3)=struct_ids(i);
+ counter=counter+1;
+ 
+    end
+  end
+end
+
+
+%find grain position from good_points
+if size(good_points,1)>4 % need at least 5 spots to proceed...(1)
+  
+  x_grain = fminbnd(@(x_grain) sfFindGrain(good_points, x_grain), min(good_points(:,1)), max(good_points(:,1)));
+  y_grain = (orig_grad*x_grain) + orig_intersect;
+  plot(x_grain, y_grain, 'cx', 'markersize', 20) % plot the chosen center
+
+  %find width of original projection
+  [a,orig_sino,a]=gtReadSpots(spot_id,spot_id);%produce sinogram for original spot only
+  %orig_sino = sino(:,index);
+  
+  if (max(orig_sino)>0)  %if the max of the sinogram is zero, then the extspot must be bad(2)
+    
+  orig_binsino = orig_sino>0.1*max(orig_sino);
+  dummy=find(orig_binsino==1);
+  orig_min=min(dummy);
+  orig_max=max(dummy);
+  proj_radius = (orig_max - orig_min)/2;
+
+  %calc distance of intersections from grain position
+  good_points(:,4) = sqrt((good_points(:,1)-x_grain).^2+(good_points(:,2)-y_grain).^2);
+  dummy = find(good_points(:,4)>proj_radius);
+  good_points(dummy, :)=[];%remove intersections far from grain center
+
+ 
+  %plot the final set of intersections
+  plot(good_points(:,1), good_points(:,2), 'ko', 'markersize', 10)
+
+  %collect the good struct_ids for this grain, and the z position
+  good_struct_ids(1) = spot_id;
+  z_pos=centroidy(find(struct_ids==spot_id));%collect average centroidy for grain vertical position
+  for j=1:size(good_points,1)
+    tmp = find(struct_ids == good_points(j,3));
+    good_struct_ids(j+1) = struct_ids(tmp);
+    z_pos=z_pos+centroidy(tmp);
+  end
+  struct_ids = good_struct_ids;
+  z_pos=z_pos/(length(struct_ids));
+  Omega =  (180/pi)*gtGetOmega(struct_ids);%put into degrees
+ 
+    %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  %(3)
+    
+    %call sfFindAngles with the initial guess at the grain centre
+    %after initial consistancy check and forward simulate, do a better calc
+    [Theta, Eta] = gtFindAngles(struct_ids, x_grain, y_grain, z_pos, Omega);
+    %calculate plane normal vectors for consistancy check
+    [plane_normal,  hkl] = gtIndexReflections(Theta,Eta,Omega);
+    %run consistancy check
+    [R_vector, good_plnorms] = plot_rodrigues_consistancy(plane_normal, hkl, 0);
+    %remove bad (inconsistant) data
+    kill_list = find(~good_plnorms);
+    Theta(kill_list)=[];
+    Eta(kill_list)=[];
+    Omega(kill_list)=[];
+    struct_ids(kill_list)=[];
+    plane_normal(kill_list,:)=[];
+    hkl(kill_list,:)=[];
+    
+   %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  % (4)
+    
+    %calculate a better centroid to use in forward simulation
+    [stack,sino,z_of_sino]=gtReadSpots(spot_id,struct_ids);
+    s=sfMakeGrain(sino, Omega, x_grain, y_grain);
+    grainCentroid=[s.Centroid z_pos];%x,y,z of grain
+    
+    %forward simulation here - returns struct_ids to be added
+    add_struct_ids=gtForwardSimulate2(grainCentroid,R_vector, struct_ids)
+    struct_ids = sort([struct_ids add_struct_ids]);
+    
+    %repeat stuff - calculate orientation, position etc with added
+    %struct_ids included - remake stack, sino
+    [stack,sino,z_of_sino]=gtReadSpots(spot_id,struct_ids);
+    Omega =  (180/pi)*gtGetOmega(struct_ids);%put into degrees
+    s=sfMakeGrain(sino, Omega, x_grain, y_grain);
+    %final calculations of Theta, Eta, plane_normals using grain centroid
+    [Theta, Eta] = gtFindAngles(struct_ids, s.Centroid(1), s.Centroid(2), z_pos, Omega);
+    %calculate plane normal vectors for consistancy check
+    [plane_normal,  hkl] = gtIndexReflections(Theta,Eta,Omega);
+    %run consistancy check
+    [R_vector, good_plnorms] = plot_rodrigues_consistancy(plane_normal, hkl, 0);
+    %remove bad (inconsistant) data - shouldn't be any at this point!
+    kill_list = find(~good_plnorms);
+    Theta(kill_list)=[];
+    Eta(kill_list)=[];
+    Omega(kill_list)=[];
+    struct_ids(kill_list)=[];
+    plane_normal(kill_list,:)=[];
+    hkl(kill_list,:)=[];
+    stack(:,:,kill_list)=[];
+    sino(:,kill_list)=[];
+    %Might need to consider grain rustling issues too.
+    %Add final size tests? shape tests?
+    
+    
+    
+  
+  %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  %(5)
+    accept =1;
+    
+    %collect data for .mat file, pad bounding boxes...
+    %get z position data from database
+    for i=1:length(struct_ids)
+query=sprintf(['select Yorigin,Yorigin+Ysize from '...
+  '%sbb inner join %sbboxes on bbID=bboxID '...
+  'where %sbb.extspotID=%d'],...
+  name,name,...
+  parameters.acq.name,struct_ids(i));
+[zstart(i),zend(i)]=mym(query);
+    end
+    %bounding box data
+zstart=min(zstart);
+zend=max(zend);
+x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+xend = x1 + s.BoundingBox(3);
+yend = y1 + s.BoundingBox(4);
+%centres     
+xcenter=round(s.Centroid(1));
+ycenter=round(s.Centroid(2));
+zcenter=round(z_pos);
+
+%add 20% to bounding box for luck (x-y plane only for extspot recon)
+x1 = round(x1 - (s.BoundingBox(3)/5));
+if x1 < 1
+  x1 = 1;
+end
+y1 = round(y1 - (s.BoundingBox(4)/5));
+if y1 <1
+  y1 = 1;
+end
+xend = round(xend + (s.BoundingBox(3)/5));
+if xend > parameters.acq.bb(3)
+  xend = parameters.acq.bb(3);
+end
+yend = round(yend + (s.BoundingBox(4)/5));
+if yend > parameters.acq.bb(3)
+  yend = parameters.acq.bb(3);
+end
+
+nx = xend-x1;
+ny = yend-y1;
+nz = zend-zstart;
+
+
+    
+    %grainid into database structure
+if 1%do save 
+    
+    for i=1:length(struct_ids)
+      %update grainID in extspot table
+			mysqlcmd=dbUpdate(sprintf('%sextspot',name),'extspotID',struct_ids(i),'GrainID',grainid);
+      mym(mysqlcmd);
+			%update grainID in bb table (!)
+      mysqlcmd=dbUpdate(sprintf('%sbb',name),'extspotID',struct_ids(i),'grainID',grainid);
+      mym(mysqlcmd);
+    end
+
+    %save mat file
+    grainname=sprintf('grain%d_',grainid);
+    graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+    if ~exist(graindir,'dir')
+      mkdir(graindir);
+    end
+    name=sprintf('%s/%s.mat',graindir,grainname);    
+    save(name,'struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector');
+else
+  disp('debug/test mode!')
+    keyboard
+end
+    
+
+  else
+    disp(sprintf('only %d projections related to spot %d after foward simulation+consistancy check2 - skipping',length(struct_ids),spot_id))
+  end  %(5)
+
+  else
+    disp(sprintf('only %d projections related to spot %d after consistancy check - skipping',length(struct_ids),spot_id))
+  end   % (4)
+
+ else
+disp(sprintf('only %d good points on projection of spot %d with similar positions- skipping',size(good_points,1),spot_id))
+  end    %(3)
+    
+  else
+    disp('Bad sinogram for this spot (negative extspot intensity!)')
+  end   %(2)
+  
+else
+  disp(sprintf('only %d good points on projection of spot %d - skipping',size(good_points,1),spot_id))
+  end   % (1)
+
+  
+  
+  
+  
+end  %end of the function
+
+
+
+
+
+
+
+function [m, c] = sfMakeBackProLine(spot_id, struct_ids, sino, theta)
+%function to return the parameters of a line passing through the proj of a
+%given spot, struct_ids is vector of spots in the sinogram, sino.
+index = find(struct_ids == spot_id);
+
+%get spot parameters
+spot_sino=sino(:,index);
+spot_com=(spot_sino'*[1:length(spot_sino)]')/sum(spot_sino);
+spot_omega=theta(index);
+
+%experiment parameters
+centre_of_backproimg_x = size(sino,1)/2;
+centre_of_backproimg_y = size(sino,1)/2;
+
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-length(spot_sino)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+function [m, c] = sfMakeBackProLine2(spot_id, struct_ids, centroidx, omega)
+%function to return the parameters of a line passing through the centroid of a
+%given spot, struct_ids is vector of spots in the sinogram, sino.
+index = find(struct_ids == spot_id);
+
+global parameters;
+
+%get spot parameters
+spot_com=centroidx(index);
+spot_omega=omega(index);
+
+%experiment parameters
+centre_of_backproimg_x = parameters.acq.bb(3)/2;
+centre_of_backproimg_y = parameters.acq.bb(3)/2;
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-parameters.acq.bb(3)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+function [Theta,Eta] = sfFindAngles(struct_id, grainx, grainy, grainz, omega);
+
+omega=omega*180/pi; %gtFindAngles works in radians...
+[Theta,Eta] = gtFindAngles(struct_id, grainx, grainy, grainz, omega);
+
+% global parameters;
+% %calculate Theta angle between grain position (x,y,z) and difspot of
+% %struct_id
+% 
+% mysqlcmd=sprintf('select ifnull(CentroidX,SearchCentroidX) from %sextspot where extspotID=%d',parameters.acq.name,struct_id);
+% 
+% xdirect=parameters.acq.bb(1)+mym(mysqlcmd);
+% ydirect=parameters.acq.bb(2)+grainz;
+% 
+% mysqlcmd=sprintf('select CentroidX,CentroidY from %sdifspot where difspotID=%d',parameters.acq.name,struct_id);
+% [xdiffr,ydiffr]=mym(mysqlcmd);
+% 
+% r=sqrt((xdirect-xdiffr)^2+(ydirect-ydiffr)^2);
+% 
+% grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+% angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+% 
+% dz=grain2rot.*sin(-omega+angle)+parameters.acq.dist/parameters.acq.pixelsize;
+% 
+% Theta=((atan(r./dz))/2)*180/pi;
+% 
+% Eta=atan2((xdiffr-xdirect),(ydirect-ydiffr))*180/pi;
+% if Eta<0
+%   Eta=360+Eta;
+% end
+
+end
+
+
+function output = sfFindGrain(good_points, x_grain)
+%function for fminbnd to find grain position along original projection
+dif = good_points(:,1)-x_grain;
+%minimise sum of squares for the closest half of the points, to reduce
+%effect of outliers
+dif = abs(dif);
+dif = sort(dif,1,'descend');
+tmp = ceil(size(dif,1)/2);
+dif(1:tmp)=[];
+output = dif'*dif;%sum of squares
+end
+
+function s = sfMakeGrain(sino, Omega, x_grain, y_grain)
+
+    %back project good spots only
+    binsino = sino>0.1*max(sino(:));
+    img2=backpro(binsino,(pi/180)*Omega);
+
+    %do imreconstruct from centre to threshold grain
+    x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+    marker=zeros(size(img2));
+    marker(y_grain, x_grain)=1;
+    mask=double((img2>0.8*img2(y_grain, x_grain)));
+    try
+      grain=imreconstruct(marker,mask);
+    catch
+      disp('Marker/mask problem - bombed out')
+      accept=false;
+      return
+    end
+
+    figure
+    h1=imshow(cat(3,img2,zeros(size(img2)),zeros(size(img2))),[]);
+    hold on
+    h2=imshow(cat(3,zeros(size(img2)),grain,zeros(size(img2))),[]);
+    set(h2,'alphadata',0.5);
+
+    s=regionprops(grain,'Area','BoundingBox','Centroid');
+    
+end
diff --git a/4_spot_sorting/gtHandleSpot2_180.m b/4_spot_sorting/gtHandleSpot2_180.m
new file mode 100755
index 0000000000000000000000000000000000000000..0fd064a1bb3cd41973e0eb775ec3c3b6ae966ad0
--- /dev/null
+++ b/4_spot_sorting/gtHandleSpot2_180.m
@@ -0,0 +1,472 @@
+function accept=gtHandleSpot2_180(spot_id,grainid)
+
+%make sure this works with 180 degree case!
+% function [stack,theta,struct_id,ind_orig,img2,accept]=handle_spot_wolf(spot_id,grainid)
+%
+% stack:    3D matrix containing the valid projections as determined by the backprojection and sine criterion
+% theta:    vector of the corresponding projection angles [radians]
+% struct_id vector containing the valid structure entries
+% ind_orig  vetor containing the indices od elements in struct_ind which belong to not replaced spots
+%             i.e.:  app.extspot(struct_id(ind_orig)).Replaced=[] for all ind_orig
+% img2      backprojection using the valid spots
+
+%add filter to use condition of known valid Theta angles to help...
+
+%try to simplify and automate
+%modify to gtnew format
+%sufficient to return "accept" only, all data written to grain%d_.mat
+
+%simplify further - crazy to make sinogram for every extspot considered.
+%Instead, just use the centroid information contained in the database for
+%the first attempt
+%modify to also calculate the plane normals, hkls, so these can be passed
+%to a consistancy test
+
+%if dealing with pairs, the extspot id links with pair id.
+
+%database enabled!
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+grainpos=[0 0 0];
+accept = 0;
+
+%get parameters of the seed spot
+mysqlcmd=sprintf([...
+  'select Yorigin,Yorigin+Ysize,MaxImage from '... 
+  '%sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID inner join %sdifspot on difspotID=%sbb.extspotID '...
+  'where %sbb.extspotID="%d"'],...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  spot_id);
+[minY,maxY,MaxIm]=mym(mysqlcmd);
+
+%find related spots - database query replaces find_family.m
+AllowedError = max(5,ceil((maxY-minY)/parameters.match.heighttol));
+AllowedError = max(5,ceil((maxY-minY)/3));
+
+mysqlcmd=sprintf([...
+  'select %sbb.extspotID, Xcentroid, Ycentroid '...
+  'from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where '...
+  ' (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) AND isnull(GrainID) '...
+  ' order by %sbb.extspotID'], ...
+	parameters.acq.name,...
+	parameters.acq.name,...
+	parameters.acq.name,...
+	parameters.acq.name,...
+	parameters.acq.name,.....
+  minY,AllowedError,...
+	maxY,AllowedError,...
+  parameters.acq.name);
+
+[struct_ids,centroidx,centroidy] =mym(mysqlcmd);
+omega = gtGetOmega(struct_ids);
+
+
+%which of struct_id vector is the original spot (spot_id)
+index = find(struct_ids==spot_id);
+figure;
+%make original spot centre line - don't use sino, use centroid only
+[orig_grad, orig_intersect] = sfMakeBackProLine2(spot_id, struct_ids, centroidx, omega);
+
+%plot original centre line  % cannot represent vertical line with y=mx+b
+ez_orig=ezplot(sprintf('%f*x + %f',orig_grad,orig_intersect),[1 parameters.acq.bb(3)]);
+set(ez_orig,'color','g');
+axis ij
+axis equal
+axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+
+hold on
+
+%get allowed TwoTheta data
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=[tmp.elements{:}];
+tmp=[tmp{:}];
+twotheta=[tmp.centre];
+
+good_points=[];counter=1;
+disp('Examining spots...')
+%loop through all spots
+warning('assuming centre of rotation to be at centre of acq.bb - in sfMakeBackProLine')
+
+for i=1:length(struct_ids)
+  if i == index % don't need to do original spot
+    continue
+  end
+
+  %make spot centre line
+  [grad, intersect] = sfMakeBackProLine2(struct_ids(i), struct_ids, centroidx, omega);
+  %calculate intersection with original spot line
+  tmpx = -(intersect-orig_intersect)/(grad-orig_grad);
+  tmpy = (orig_grad*tmpx) + orig_intersect;
+
+  % only continue if intersection is inside image
+  %  if tmpy<parameters.acq.bb(4) && tmpy>1 && tmpx<parameters.acq.bb(3) && tmpx>1
+  %circular sample case:
+  if ((tmpx-(parameters.acq.bb(3)/2))^2+(tmpx-(parameters.acq.bb(3)/2))^2)<(parameters.acq.bb(3)/2)^2
+
+    axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+    plot(tmpx, tmpy, 'xr')
+
+    %does intersection give good theta angles?  orig and current spots
+    %using grainpos = tmpx, tmpy, calc theta
+    %use the vertical position of the seed spot centroid
+    [Theta_spot, Eta_spot] = sfFindAngles(struct_ids(i), tmpx, tmpy, centroidy(index),  omega(i));
+    [Theta_orig, Eta_orig] = sfFindAngles(struct_ids(index), tmpx, tmpy, centroidy(index),  omega(index));
+
+		%to use a percentage angle criteria
+%    min_spot_dif = min(abs((twotheta/2)-Theta_spot)./(twotheta/2));
+%    min_orig_dif = min(abs((twotheta/2)-Theta_orig)./(twotheta/2));
+
+%to use an absolute allowed margin of error (as in consistancy check)
+    min_spot_dif = min(abs((twotheta/2)-Theta_spot));
+    min_orig_dif = min(abs((twotheta/2)-Theta_orig));
+		
+%    if (min_spot_dif<0.025 && min_orig_dif<0.025)% if both Thetas good to 2.5%
+    if (min_spot_dif<0.3 && min_orig_dif<0.3)% if both Thetas good to 0.3 degrees
+ 
+ plot(tmpx, tmpy, 'go') %plot point, record in good points
+ good_points(counter,1)=tmpx;
+ good_points(counter,2)=tmpy;
+ good_points(counter,3)=struct_ids(i);
+ counter=counter+1;
+ 
+    end
+  end
+end
+
+
+%find grain position from good_points
+if size(good_points,1)>4 % need at least 5 spots to proceed...(1)
+  
+  x_grain = fminbnd(@(x_grain) sfFindGrain(good_points, x_grain), min(good_points(:,1)), max(good_points(:,1)));
+  y_grain = (orig_grad*x_grain) + orig_intersect;
+  plot(x_grain, y_grain, 'cx', 'markersize', 20) % plot the chosen center
+
+  %find width of original projection
+  [a,orig_sino,a]=gtReadSpots(spot_id,spot_id);%produce sinogram for original spot only
+  %orig_sino = sino(:,index);
+  
+  if (max(orig_sino)>0)  %if the max of the sinogram is zero, then the extspot must be bad(2)
+    
+  orig_binsino = orig_sino>0.1*max(orig_sino);
+  dummy=find(orig_binsino==1);
+  orig_min=min(dummy);
+  orig_max=max(dummy);
+  proj_radius = (orig_max - orig_min)/2;
+
+  %calc distance of intersections from grain position
+  good_points(:,4) = sqrt((good_points(:,1)-x_grain).^2+(good_points(:,2)-y_grain).^2);
+  dummy = find(good_points(:,4)>proj_radius);
+  good_points(dummy, :)=[];%remove intersections far from grain center
+
+ 
+  %plot the final set of intersections
+  plot(good_points(:,1), good_points(:,2), 'ko', 'markersize', 10)
+
+  %collect the good struct_ids for this grain, and the z position
+  good_struct_ids(1) = spot_id;
+  z_pos=centroidy(find(struct_ids==spot_id));%collect average centroidy for grain vertical position
+  for j=1:size(good_points,1)
+    tmp = find(struct_ids == good_points(j,3));
+    good_struct_ids(j+1) = struct_ids(tmp);
+    z_pos=z_pos+centroidy(tmp);
+  end
+  struct_ids = good_struct_ids;
+  z_pos=z_pos/(length(struct_ids));
+  Omega =  (180/pi)*gtGetOmega(struct_ids);%put into degrees
+ 
+    %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  %(3)
+    
+    %call sfFindAngles with the initial guess at the grain centre
+    %after initial consistancy check and forward simulate, do a better calc
+    [Theta, Eta] = gtFindAngles(struct_ids, x_grain, y_grain, z_pos, Omega);
+    %calculate plane normal vectors for consistancy check
+    [plane_normal,  hkl] = gtIndexReflections(Theta,Eta,Omega);
+    %run consistancy check
+    [R_vector, good_plnorms] = plot_rodrigues_consistancy(plane_normal, hkl, 0);
+    %remove bad (inconsistant) data
+    kill_list = find(~good_plnorms);
+    Theta(kill_list)=[];
+    Eta(kill_list)=[];
+    Omega(kill_list)=[];
+    struct_ids(kill_list)=[];
+    plane_normal(kill_list,:)=[];
+    hkl(kill_list,:)=[];
+    
+   %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  % (4)
+    
+    %calculate a better centroid to use in forward simulation
+		[stack,sino,z_of_sino]=gtReadSpots(spot_id,struct_ids);
+		try
+    s=sfMakeGrain(sino, Omega, x_grain, y_grain);
+		catch
+			disp('sfMakeGrain failed!')
+			return
+		end
+
+    grainCentroid=[s.Centroid z_pos];%x,y,z of grain
+    
+    %forward simulation here - returns struct_ids to be added
+    add_struct_ids=gtForwardSimulate2(grainCentroid,R_vector, struct_ids)
+    struct_ids = sort([struct_ids add_struct_ids]);
+    
+    %repeat stuff - calculate orientation, position etc with added
+    %struct_ids included - remake stack, sino
+    [stack,sino,z_of_sino]=gtReadSpots(spot_id,struct_ids);
+    Omega =  (180/pi)*gtGetOmega(struct_ids);%put into degrees
+		try
+    s=sfMakeGrain(sino, Omega, x_grain, y_grain);
+		catch
+			disp('sfMakeGrain failed!')
+			return
+		end
+    
+    %final calculations of Theta, Eta, plane_normals using grain centroid
+    [Theta, Eta] = gtFindAngles(struct_ids, s.Centroid(1), s.Centroid(2), z_pos, Omega);
+    %calculate plane normal vectors for consistancy check
+    [plane_normal,  hkl] = gtIndexReflections(Theta,Eta,Omega);
+    %run consistancy check
+    [R_vector, good_plnorms] = plot_rodrigues_consistancy(plane_normal, hkl, 0);
+    %remove bad (inconsistant) data - shouldn't be any at this point!
+    kill_list = find(~good_plnorms);
+    Theta(kill_list)=[];
+    Eta(kill_list)=[];
+    Omega(kill_list)=[];
+    struct_ids(kill_list)=[];
+    plane_normal(kill_list,:)=[];
+    hkl(kill_list,:)=[];
+    stack(:,:,kill_list)=[];
+    sino(:,kill_list)=[];
+    %Might need to consider grain rustling issues too.
+    %Add final size tests? shape tests?
+    
+    
+    
+  
+  %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  %(5)
+    accept =1;
+    
+    %collect data for .mat file, pad bounding boxes...
+    %get z position data from database
+    for i=1:length(struct_ids)
+query=sprintf(['select Yorigin,Yorigin+Ysize from '...
+  '%sbb inner join %sbboxes on bbID=bboxID '...
+  'where %sbb.extspotID=%d'],...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  struct_ids(i));
+[zstart(i),zend(i)]=mym(query);
+    end
+    %bounding box data
+zstart=min(zstart);
+zend=max(zend);
+x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+xend = x1 + s.BoundingBox(3);
+yend = y1 + s.BoundingBox(4);
+%centres     
+xcenter=round(s.Centroid(1));
+ycenter=round(s.Centroid(2));
+zcenter=round(z_pos);
+
+%add 20% to bounding box for luck (x-y plane only for extspot recon)
+x1 = round(x1 - (s.BoundingBox(3)/5));
+if x1 < 1
+  x1 = 1;
+end
+y1 = round(y1 - (s.BoundingBox(4)/5));
+if y1 <1
+  y1 = 1;
+end
+xend = round(xend + (s.BoundingBox(3)/5));
+if xend > parameters.acq.bb(3)
+  xend = parameters.acq.bb(3);
+end
+yend = round(yend + (s.BoundingBox(4)/5));
+if yend > parameters.acq.bb(3)
+  yend = parameters.acq.bb(3);
+end
+
+nx = xend-x1;
+ny = yend-y1;
+nz = zend-zstart;
+
+
+    
+    %grainid into database structure
+if 1%do save 
+    
+    for i=1:length(struct_ids)
+      %update grainID in extspot table
+			mysqlcmd=dbUpdate(sprintf('%sextspot',parameters.acq.name),'extspotID',struct_ids(i),'GrainID',grainid);
+      mym(mysqlcmd);
+			%update grainID in bb table (!)
+      mysqlcmd=dbUpdate(sprintf('%sbb',parameters.acq.name),'extspotID',struct_ids(i),'grainID',grainid);
+      mym(mysqlcmd);
+    end
+
+    %save mat file
+    grainname=sprintf('grain%d_',grainid);
+    graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+    if ~exist(graindir,'dir')
+      mkdir(graindir);
+    end
+    name=sprintf('%s/%s.mat',graindir,grainname);    
+    save(name,'struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector');
+else
+  disp('debug/test mode!')
+
+end
+    
+
+  else
+    disp(sprintf('only %d projections related to spot %d after foward simulation+consistancy check2 - skipping',length(struct_ids),spot_id))
+  end  %(5)
+
+  else
+    disp(sprintf('only %d projections related to spot %d after consistancy check - skipping',length(struct_ids),spot_id))
+  end   % (4)
+
+ else
+disp(sprintf('only %d good points on projection of spot %d with similar positions- skipping',size(good_points,1),spot_id))
+  end    %(3)
+    
+  else
+    disp('Bad sinogram for this spot (negative extspot intensity!)')
+  end   %(2)
+  
+else
+  disp(sprintf('only %d good points on projection of spot %d - skipping',size(good_points,1),spot_id))
+  end   % (1)
+
+  
+  
+  
+  
+end  %end of the function
+
+
+
+
+
+
+
+function [m, c] = sfMakeBackProLine(spot_id, struct_ids, sino, theta)
+%function to return the parameters of a line passing through the proj of a
+%given spot, struct_ids is vector of spots in the sinogram, sino.
+index = find(struct_ids == spot_id);
+
+%get spot parameters
+spot_sino=sino(:,index);
+spot_com=(spot_sino'*[1:length(spot_sino)]')/sum(spot_sino);
+spot_omega=theta(index);
+
+%experiment parameters
+centre_of_backproimg_x = size(sino,1)/2;
+centre_of_backproimg_y = size(sino,1)/2;
+
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-length(spot_sino)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+function [m, c] = sfMakeBackProLine2(spot_id, struct_ids, centroidx, omega)
+%function to return the parameters of a line passing through the centroid of a
+%given spot, struct_ids is vector of spots in the sinogram, sino.
+index = find(struct_ids == spot_id);
+
+global parameters;
+
+%get spot parameters
+spot_com=centroidx(index);
+spot_omega=omega(index);
+
+%experiment parameters
+centre_of_backproimg_x = parameters.acq.bb(3)/2;
+centre_of_backproimg_y = parameters.acq.bb(3)/2;
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-parameters.acq.bb(3)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+function [Theta,Eta] = sfFindAngles(struct_id, grainx, grainy, grainz, omega);
+omega=omega*180/pi; %gtFindAngles works in radians...
+[Theta,Eta] = gtFindAngles(struct_id, grainx, grainy, grainz, omega);
+end
+
+
+function output = sfFindGrain(good_points, x_grain)
+%function for fminbnd to find grain position along original projection
+dif = good_points(:,1)-x_grain;
+%minimise sum of squares for the closest half of the points, to reduce
+%effect of outliers
+dif = abs(dif);
+dif = sort(dif,1,'descend');
+tmp = ceil(size(dif,1)/2);
+dif(1:tmp)=[];
+output = dif'*dif;%sum of squares
+end
+
+function s = sfMakeGrain(sino, Omega, x_grain, y_grain)
+
+    %back project good spots only
+    binsino = sino>0.1*max(sino(:));
+    img2=backpro(binsino,(pi/180)*Omega);
+
+    %do imreconstruct from centre to threshold grain
+    x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+    marker=zeros(size(img2));
+    marker(y_grain, x_grain)=1;
+    mask=double((img2>0.8*img2(y_grain, x_grain)));
+    try
+      grain=imreconstruct(marker,mask);    
+			figure
+    h1=imshow(cat(3,img2,zeros(size(img2)),zeros(size(img2))),[]);
+    hold on
+    h2=imshow(cat(3,zeros(size(img2)),grain,zeros(size(img2))),[]);
+    set(h2,'alphadata',0.5);
+
+    s=regionprops(grain,'Area','BoundingBox','Centroid');
+		
+    catch
+      disp('Marker/mask problem - bombed out')
+      accept=false;
+      return
+    end
+
+
+    
+end
diff --git a/4_spot_sorting/gtHandleSpot2_360.m b/4_spot_sorting/gtHandleSpot2_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..05945ef17f205c34742a41352afa9c3778895a0e
--- /dev/null
+++ b/4_spot_sorting/gtHandleSpot2_360.m
@@ -0,0 +1,583 @@
+function accept=gtHandleSpot2_360(spot_id,grainid, parameters)
+
+%modify to the new 360 data structure - two extspot tables and a pair table
+%containing all/any pair derived information.
+%gtDoAll2_360 should ensure that the working directory is the first half of
+%the scan.
+
+%add filter to use condition of known valid Theta angles to help...
+
+%sufficient to return "accept" only, all data written to grain%d_.mat
+
+%simplify further - crazy to make sinogram for every extspot considered.
+%Instead, just use the centroid information contained in the database for
+%the first attempt
+%modify to also calculate the plane normals, hkls, so these can be passed
+%to a consistancy test
+
+
+
+if isempty(parameters)
+  load parameters.mat
+end
+
+plot_flag=1; %set to one to see figures!
+debug_flag=0;% switch one keyboard statements
+replace_flag=1; %set to one to replace all extspot with difspots when making grains/sinos/stacks
+
+grainpos=[0 0 0];
+accept = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%      get parameters of the seed spot              %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mysqlcmd=sprintf([...
+  'select Yorigin,Yorigin+Ysize, Ycentroid from '... 
+  '%sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID '...
+  'where %sbb.extspotID="%d"'],...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  spot_id);
+[minY,maxY,spot_centroidy]=mym(mysqlcmd);
+
+AllowedError = max(5,ceil((maxY-minY)/parameters.match.heighttol));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%  find related spots - in this half of the 360 scan
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mysqlcmd=sprintf([...
+  'select %sbb.extspotID, Xcentroid, Ycentroid '...
+  'from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where '...
+  ' (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) AND isnull(GrainID) '...
+  ' order by %sbb.extspotID'], ...
+	parameters.acq.name,...
+	parameters.acq.name,...
+	parameters.acq.name,...
+	parameters.acq.name,...
+	parameters.acq.name,.....
+  minY,AllowedError,...
+	maxY,AllowedError,...
+  parameters.acq.name);
+[my_struct_ids,my_centroidx,my_centroidy] =mym(mysqlcmd);
+
+%which of struct_id vector is the original spot (spot_id)
+index = find(my_struct_ids==spot_id);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%  find related spots - in the _other_ half of the 360 scan
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mysqlcmd=sprintf([...
+  'select %sbb.extspotID, Xcentroid, Ycentroid '...
+  'from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where '...
+  ' (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) AND isnull(GrainID) '...
+  ' order by %sbb.extspotID'], ...
+	parameters.acq.pair_name,...
+	parameters.acq.pair_name,...
+	parameters.acq.pair_name,...
+	parameters.acq.pair_name,...
+	parameters.acq.pair_name,.....
+  minY,AllowedError,...
+	maxY,AllowedError,...
+  parameters.acq.pair_name);
+[pair_struct_ids,pair_centroidx,pair_centroidy] =mym(mysqlcmd);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% create a single vector of struct_ids / centroids / etc
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+struct_ids = [my_struct_ids; pair_struct_ids];
+centroidx = [my_centroidx; pair_centroidx];
+centroidy = [my_centroidy; pair_centroidy];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%use pair_vector to record which half of the scan a struct_id comes from
+%1=this half, 2=other (pair) half
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+pair_vector = 2*ones(size(struct_ids));
+pair_vector(1:length(my_struct_ids))=1;
+omega = gtGetOmega_pair(struct_ids, pair_vector, parameters);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% get allowed TwoTheta data for filter
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=[tmp.elements{:}];
+tmp=[tmp{:}];
+twotheta=[tmp.centre];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%make original spot centre line - don't use sino, use centroid only
+%pair_vector ensures spot from correct half of scan
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[orig_grad, orig_intersect] = sfMakeBackProLine2(spot_id, struct_ids, centroidx, omega,pair_vector(index),pair_vector, parameters);
+
+%plot original centre line  % cannot represent vertical line with y=mx+b
+if plot_flag
+figure;
+ez_orig=ezplot(sprintf('%f*x + %f',orig_grad,orig_intersect),[1 parameters.acq.bb(3)]);
+set(ez_orig,'color','g');
+axis ij
+axis equal
+axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+hold on
+end
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%loop through all spots using theta filter
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+good_points=[];counter=1;
+disp('Examining spots...')
+warning('assuming centre of rotation to be at centre of acq.bb - in sfMakeBackProLine')
+save_theta=[]
+for i=1:length(struct_ids)
+
+  if i == index % don't need to do original spot
+    continue
+  end
+
+  %make spot centre line
+  [grad, intersect] = sfMakeBackProLine2(struct_ids(i), struct_ids, centroidx, omega,pair_vector(i), pair_vector, parameters);
+
+  %calculate intersection with original spot line
+  tmpx = -(intersect-orig_intersect)/(grad-orig_grad);
+  tmpy = (orig_grad*tmpx) + orig_intersect;
+
+  % only continue if intersection is inside image
+  %  if tmpy<parameters.acq.bb(4) && tmpy>1 && tmpx<parameters.acq.bb(3) && tmpx>1
+  %circular sample case:
+  if ((tmpx-(parameters.acq.bb(3)/2))^2+(tmpx-(parameters.acq.bb(3)/2))^2)<(parameters.acq.bb(3)/2)^2
+
+    if plot_flag
+    axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+    plot(tmpx, tmpy, 'xr')
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %Theta filter  orig and current spots
+    %using grainpos = tmpx, tmpy, calc theta
+    %use the vertical position of the seed spot centroid   
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    [Theta_spot, Eta_spot] = gtFindAngles_pair(struct_ids(i), pair_vector(i), tmpx, tmpy, centroidy(index),  (180/pi)*omega(i), parameters);
+    [Theta_orig, Eta_orig] = gtFindAngles_pair(struct_ids(index), pair_vector(index), tmpx, tmpy, centroidy(index),  (180/pi)*omega(index), parameters);
+  
+    save_theta=[save_theta Theta_spot Theta_orig];
+		%to use a percentage angle criteria
+%    min_spot_dif = min(abs((twotheta/2)-Theta_spot)./(twotheta/2));
+%    min_orig_dif = min(abs((twotheta/2)-Theta_orig)./(twotheta/2));
+
+%to use an absolute allowed margin of error (as in consistancy check)
+    min_spot_dif = min(abs((twotheta/2)-Theta_spot));
+    min_orig_dif = min(abs((twotheta/2)-Theta_orig));
+		
+%    if (min_spot_dif<0.025 && min_orig_dif<0.025)% if both Thetas good to 2.5%
+    if (min_spot_dif<parameters.sort.theta_filter && min_orig_dif<parameters.sort.theta_filter)% if both Thetas good to 0.3 degrees
+ %plot good point
+ if plot_flag
+ plot(tmpx, tmpy, 'go') 
+ end
+ %record point in good points
+%good points(1)=x, (2)=y, (3)=struct_id, (4)=dist (later), (5)=pair,
+%(6)=ycentroid
+ good_points(counter,1)=tmpx;
+ good_points(counter,2)=tmpy;
+ good_points(counter,3)=struct_ids(i);
+ good_points(counter,5)=pair_vector(i);
+ good_points(counter,6)=centroidy(i);
+ counter=counter+1;
+ 
+    end
+  end
+end
+
+if debug_flag
+  keyboard
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%find grain position from good_points
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if size(good_points,1)>4 % need at least 5 spots to proceed...(1)
+  
+  x_grain = fminbnd(@(x_grain) sfFindGrain(good_points, x_grain), min(good_points(:,1)), max(good_points(:,1)));
+  y_grain = (orig_grad*x_grain) + orig_intersect;
+  if plot_flag
+  plot(x_grain, y_grain, 'cx', 'markersize', 20) % plot the chosen center
+  end
+  %find width of original projection
+  [a,orig_sino,a]=gtReadSpots_pair(spot_id,spot_id,pair_vector(index),pair_vector(index), replace_flag);%produce sinogram for original spot only
+  %orig_sino = sino(:,index);
+  
+  if (max(orig_sino)>0)  %if the max of the sinogram is zero, then the extspot must be bad(2)
+    
+  orig_binsino = orig_sino>0.1*max(orig_sino);
+  dummy=find(orig_binsino==1);
+  orig_min=min(dummy);
+  orig_max=max(dummy);
+  proj_radius = (orig_max - orig_min)/2;
+
+  %calc distance of intersections from grain position
+  good_points(:,4) = sqrt((good_points(:,1)-x_grain).^2+(good_points(:,2)-y_grain).^2);
+  %remove intersections far from grain center
+  dummy = find(good_points(:,4)>proj_radius);
+  good_points(dummy, :)=[];
+ 
+  %plot the final set of intersections
+  if plot_flag
+    plot(good_points(:,1), good_points(:,2), 'ko', 'markersize', 10)
+  end
+  %collect the good struct_ids, pair_vector, for this grain, and the z position
+  %need to be more careful because of two halves of the scan can have sam
+  %eids
+  good_struct_ids = [spot_id good_points(:,3)'];
+  good_pair_vector = [pair_vector(index) good_points(:,5)'];
+ z_pos = mean([spot_centroidy good_points(:,6)']);
+  
+% z_pos=centroidy(find(struct_ids==spot_id));%collect average centroidy for grain vertical position
+ % for j=1:size(good_points,1)
+  %  tmp = find(struct_ids == good_points(j,3));
+   % good_struct_ids(j+1) = struct_ids(tmp);
+    %good_pair_vector(j+1) = pair_vector(tmp);
+    %z_pos=z_pos+centroidy(tmp);
+  %end
+  struct_ids = good_struct_ids;
+  pair_vector = good_pair_vector;
+  %z_pos=z_pos/(length(struct_ids));
+  Omega =  (180/pi)*gtGetOmega_pair(struct_ids,pair_vector, parameters);%put into degrees
+ 
+    %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  %(3)
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %call gtFindAngles with the initial guess at the grain centre
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    [Theta, Eta] = gtFindAngles_pair(struct_ids, pair_vector, x_grain, y_grain, z_pos, Omega, parameters);
+
+
+    
+    %calculate plane normal vectors for consistancy check
+    [plane_normal,  hkl] = gtIndexReflections(Theta,Eta,Omega, parameters);
+    %run consistancy check
+    [R_vector, good_plnorms] = plot_rodrigues_consistancy(plane_normal, hkl, 0);
+    %remove bad (inconsistant) data
+    
+
+    
+    kill_list = find(~good_plnorms);
+   %warning('consistancy check disabled!!!') 
+   %kill_list=[];
+   
+     if debug_flag
+  keyboard
+end  
+    
+    Theta(kill_list)=[];
+    Eta(kill_list)=[];
+    Omega(kill_list)=[];
+    struct_ids(kill_list)=[];
+    pair_vector(kill_list)=[];
+    plane_normal(kill_list,:)=[];
+    hkl(kill_list,:)=[];
+    
+
+    
+   %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  % (4)
+    
+    %calculate a better centroid to use in forward simulation
+    [stack,sino,z_of_sino]=gtReadSpots_pair(spot_id,struct_ids,pair_vector(1),pair_vector, replace_flag);
+    try
+    s=sfMakeGrain(sino, Omega, x_grain, y_grain,plot_flag);
+    catch
+      disp('sfMakeGrain failed!')
+    return
+    end
+    
+    grainCentroid=[s.Centroid z_pos];%x,y,z of grain
+   
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %forward simulation here - search database for more spot pairs
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    [add_struct_ids, add_pair_vector]=gtForwardSimulate2_pair(grainCentroid,R_vector, struct_ids, pair_vector, parameters)
+    struct_ids = [struct_ids add_struct_ids];
+    pair_vector = [pair_vector add_pair_vector];
+    
+    Omega =  (180/pi)*gtGetOmega_pair(struct_ids, pair_vector, parameters);%put into degrees
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %repeat previous steps with added struct_ids
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    [stack,sino,z_of_sino]=gtReadSpots_pair(spot_id,struct_ids,pair_vector(1),pair_vector, replace_flag);
+    try
+    s=sfMakeGrain(sino, Omega, x_grain, y_grain, plot_flag);
+    catch
+      disp('sfMakeGrain failed!')
+      return
+    end
+    %final calculations of Theta, Eta, plane_normals using grain centroid
+    [Theta, Eta] = gtFindAngles_pair(struct_ids, pair_vector, s.Centroid(1), s.Centroid(2), z_pos, Omega, parameters);
+    %calculate plane normal vectors for consistancy check
+    [plane_normal,  hkl] = gtIndexReflections(Theta,Eta,Omega, parameters);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %repeat consistancy check with added spot pairs
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    [R_vector, good_plnorms] = plot_rodrigues_consistancy(plane_normal, hkl, 0);
+    %remove bad (inconsistant) data - shouldn't be any at this point!
+    kill_list = find(~good_plnorms);
+%   warning('consistancy check disabled!!!') 
+ %  kill_list=[];
+        if debug_flag
+          keyboard
+        end
+    Theta(kill_list)=[];
+    Eta(kill_list)=[];
+    Omega(kill_list)=[];
+    struct_ids(kill_list)=[];
+    pair_vector(kill_list)=[];
+    plane_normal(kill_list,:)=[];
+    hkl(kill_list,:)=[];
+    stack(:,:,kill_list)=[];
+    sino(:,kill_list)=[];    
+    
+  
+  %need at least five projections of grain for a useful reconstruction.
+  if length(struct_ids) > 4  %(5)
+    accept =1;
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %collect data for .mat file, pad bounding boxes...
+    %get z position data from database
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    for i=1:length(struct_ids)
+      
+      if pair_vector(i) == 2
+        name = parameters.acq.pair_name;
+      else pair_vector(i) == 1
+        name=parameters.acq.name;
+      end
+      query=sprintf(['select Yorigin,Yorigin+Ysize from '...
+        '%sbb inner join %sbboxes on bbID=bboxID '...
+        'where %sbb.extspotID=%d'],...
+        name, name, name,...
+        struct_ids(i));
+      [zstart(i),zend(i)]=mym(query);
+    end
+    
+    %bounding box data
+zstart=min(zstart);
+zend=max(zend);
+x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+xend = x1 + s.BoundingBox(3);
+yend = y1 + s.BoundingBox(4);
+%centres     
+xcenter=round(s.Centroid(1));
+ycenter=round(s.Centroid(2));
+zcenter=round(z_pos);
+
+%add 20% to bounding box for luck (x-y plane only for extspot recon)
+x1 = round(x1 - (s.BoundingBox(3)/5));
+if x1 < 1
+  x1 = 1;
+end
+y1 = round(y1 - (s.BoundingBox(4)/5));
+if y1 <1
+  y1 = 1;
+end
+xend = round(xend + (s.BoundingBox(3)/5));
+if xend > parameters.acq.bb(3)
+  xend = parameters.acq.bb(3);
+end
+yend = round(yend + (s.BoundingBox(4)/5));
+if yend > parameters.acq.bb(3)
+  yend = parameters.acq.bb(3);
+end
+
+nx = xend-x1;
+ny = yend-y1;
+nz = zend-zstart;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%save grainid into database structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if 1%do save 
+    
+    for i=1:length(struct_ids)
+      
+      if pair_vector(i) == 2
+        name = parameters.acq.pair_name;
+      else
+        name=parameters.acq.name;
+      end
+      
+      %update grainID in extspot table
+			mysqlcmd=dbUpdate(sprintf('%sextspot',name),'extspotID',struct_ids(i),'GrainID',grainid);
+      mym(mysqlcmd);
+			%update grainID in bb table (!)
+      mysqlcmd=dbUpdate(sprintf('%sbb',name),'extspotID',struct_ids(i),'grainID',grainid);
+      mym(mysqlcmd);
+      
+    end
+
+    %save mat file
+    grainname=sprintf('grain%d_',grainid);
+    graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+    if ~exist(graindir,'dir')
+      mkdir(graindir);
+    end
+    name=sprintf('%s/%s.mat',graindir,grainname);    
+    save(name,'struct_ids','pair_vector','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector');
+else
+  disp('debug/test mode!')
+
+end
+    
+
+  else
+    disp(sprintf('only %d projections related to spot %d after foward simulation+consistancy check2 - skipping',length(struct_ids),spot_id))
+  end  %(5)
+
+  else
+    disp(sprintf('only %d projections related to spot %d after consistancy check - skipping',length(struct_ids),spot_id))
+  end   % (4)
+
+ else
+disp(sprintf('only %d good points on projection of spot %d with similar positions- skipping',size(good_points,1),spot_id))
+  end    %(3)
+    
+  else
+    disp('Bad sinogram for this spot (negative extspot intensity!)')
+  end   %(2)
+  
+else
+  disp(sprintf('only %d good points on projection of spot %d - skipping',size(good_points,1),spot_id))
+  end   % (1)
+
+  
+  
+  
+  
+end  %end of the function
+
+
+
+
+
+
+
+function [m, c] = sfMakeBackProLine(spot_id, struct_ids, sino, theta)
+%function to return the parameters of a line passing through the proj of a
+%given spot, struct_ids is vector of spots in the sinogram, sino.
+index = find(struct_ids == spot_id);
+
+%get spot parameters
+spot_sino=sino(:,index);
+spot_com=(spot_sino'*[1:length(spot_sino)]')/sum(spot_sino);
+spot_omega=theta(index);
+
+%experiment parameters
+centre_of_backproimg_x = size(sino,1)/2;
+centre_of_backproimg_y = size(sino,1)/2;
+
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-length(spot_sino)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+function [m, c] = sfMakeBackProLine2(spot_id, struct_ids, centroidx, omega, pair, pair_vector, parameters)
+%function to return the parameters of a line passing through the centroid of a
+%given spot, struct_ids is vector of spots in the sinogram, sino.
+%could have the same struct_id number in both halves of scan.  Therefore
+%also use the condition that the pair_vector must be correct
+index = find(struct_ids==spot_id & pair_vector==pair);
+
+
+
+%get spot parameters
+spot_com=centroidx(index);
+spot_omega=omega(index);
+
+%experiment parameters
+centre_of_backproimg_x = parameters.acq.bb(3)/2;
+centre_of_backproimg_y = parameters.acq.bb(3)/2;
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-parameters.acq.bb(3)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+%function [Theta,Eta] = sfFindAngles(struct_id, pair, grainx, grainy, grainz, omega);
+%omega=omega*180/pi; %gtFindAngles works in radians...
+%[Theta,Eta] = gtFindAngles_pair(struct_id, pair, grainx, grainy, grainz, omega);
+%end
+
+
+function output = sfFindGrain(good_points, x_grain)
+%function for fminbnd to find grain position along original projection
+dif = good_points(:,1)-x_grain;
+%minimise sum of squares for the closest half of the points, to reduce
+%effect of outliers
+dif = abs(dif);
+dif = sort(dif,1,'descend');
+tmp = ceil(size(dif,1)/2);
+dif(1:tmp)=[];
+output = dif'*dif;%sum of squares
+end
+
+function s = sfMakeGrain(sino, Omega, x_grain, y_grain, plot_flag)
+
+    %back project good spots only
+    binsino = sino>0.1*max(sino(:));
+    img2=backpro(binsino,(pi/180)*Omega);
+
+    %do imreconstruct from centre to threshold grain
+    x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+    marker=zeros(size(img2));
+    marker(y_grain, x_grain)=1;
+    mask=double((img2>0.8*img2(y_grain, x_grain)));
+  
+    try
+      grain=imreconstruct(marker,mask);    
+      if plot_flag
+        figure
+        h1=imshow(cat(3,img2,zeros(size(img2)),zeros(size(img2))),[]);
+        hold on
+        h2=imshow(cat(3,zeros(size(img2)),grain,zeros(size(img2))),[]);
+        set(h2,'alphadata',0.5);
+      end
+    s=regionprops(grain,'Area','BoundingBox','Centroid');
+    
+    catch
+      disp('Marker/mask problem - bombed out')
+      accept=false;
+      return
+    end
+
+
+end
diff --git a/4_spot_sorting/gtHandleSpot_360.m b/4_spot_sorting/gtHandleSpot_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..69a762068840c56b033d8f6f29beda90193101de
--- /dev/null
+++ b/4_spot_sorting/gtHandleSpot_360.m
@@ -0,0 +1,552 @@
+function accept=gtHandleSpot_360(spot_id,grainid, parameters)
+
+%subtle renaming - gtHandleSpot_360 is gtHandleSpot2_360, reworked to deal
+%with a single 360 scan
+
+
+%modify to the new 360 data structure - two extspot tables and a pair table
+%containing all/any pair derived information.
+%gtDoAll2_360 should ensure that the working directory is the first half of
+%the scan.
+
+%add filter to use condition of known valid Theta angles to help...
+
+%sufficient to return "accept" only, all data written to grain%d_.mat
+
+%simplify further - crazy to make sinogram for every extspot considered.
+%Instead, just use the centroid information contained in the database for
+%the first attempt
+%modify to also calculate the plane normals, hkls, so these can be passed
+%to a consistancy test
+
+%360degree scan convention - ak 10/2007
+
+if isempty(parameters)
+    load parameters.mat
+end
+
+plot_flag=0; %set to one to see figures!
+debug_flag=0;% switch one keyboard statements
+replace_flag=0; %set to one to replace all extspot with difspots when making grains/sinos/stacks
+
+grainpos=[0 0 0];
+accept = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%      get parameters of the seed spot              %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mysqlcmd=sprintf([...
+    'select Yorigin,Yorigin+Ysize, Ycentroid from '...
+    '%sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID '...
+    'where %sbb.extspotID="%d"'],...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    spot_id);
+[minY,maxY,spot_centroidy]=mym(mysqlcmd);
+
+AllowedError = max(5,ceil((maxY-minY)/parameters.match.heighttol));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%  find related spots - single 360 scan
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mysqlcmd=sprintf([...
+    'select %sbb.extspotID, Xcentroid, Ycentroid '...
+    'from %sbboxes inner join %sbb on %sbboxes.bboxID=%sbb.bbID where '...
+    ' (abs(Yorigin - %d)<%f) AND (abs(Yorigin+Ysize-%d)<%f) AND isnull(GrainID) '...
+    ' order by %sbb.extspotID'], ...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,.....
+    minY,AllowedError,...
+    maxY,AllowedError,...
+    parameters.acq.name);
+[struct_ids,centroidx,centroidy] =mym(mysqlcmd);
+
+if debug_flag
+    keyboard
+end
+
+%which of struct_id vector is the original spot (spot_id)
+index = find(struct_ids==spot_id);
+%get omega angles
+omega = gtGetOmega(struct_ids, parameters);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% get allowed TwoTheta data for filter
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tmp=gtnew_calculate_twotheta;
+tmp=[tmp.elements{:}];
+tmp=[tmp{:}];
+twotheta=[tmp.centre];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%make original spot centre line - don't use sino, use centroid only
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[orig_grad, orig_intersect] = sfMakeBackProLine2(spot_id, struct_ids, centroidx, omega, parameters);
+
+%plot original centre line  % cannot represent vertical line with y=mx+b
+if plot_flag
+    figure;
+    ez_orig=ezplot(sprintf('%f*x + %f',orig_grad,orig_intersect),[1 parameters.acq.bb(3)]);
+    set(ez_orig,'color','g');
+    axis ij
+    axis equal
+    axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+    hold on
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%loop through all spots using theta filter
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+good_points=[];counter=1;
+disp('Examining spots...')
+warning('assuming centre of rotation to be at centre of acq.bb - in sfMakeBackProLine')
+save_theta=[];
+
+for i=1:length(struct_ids)
+
+    if i == index % don't need to do original spot
+        continue
+    end
+
+    %make spot centre line
+    [grad, intersect] = sfMakeBackProLine2(struct_ids(i), struct_ids, centroidx, omega, parameters);
+
+    %calculate intersection with original spot line
+    tmpx = -(intersect-orig_intersect)/(grad-orig_grad);
+    tmpy = (orig_grad*tmpx) + orig_intersect;
+
+    % only continue if intersection is inside image
+    %  if tmpy<parameters.acq.bb(4) && tmpy>1 && tmpx<parameters.acq.bb(3) && tmpx>1
+    %circular sample case:
+    %  if ((tmpx-(parameters.acq.bb(3)/2))^2+(tmpx-(parameters.acq.bb(3)/2))^2)<(parameters.acq.bb(3)/2)^2
+    %circular sample case, plus a 30% margin of error:
+    if ((tmpx-(parameters.acq.bb(3)/2))^2+(tmpx-(parameters.acq.bb(3)/2))^2)<(1.3*parameters.acq.bb(3)/2)^2
+
+        if plot_flag
+            axis([1 parameters.acq.bb(3) 1 parameters.acq.bb(3)])
+            plot(tmpx, tmpy, 'xr')
+        end
+
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        %Theta filter  orig and current spots
+        %using grainpos = tmpx, tmpy, calc theta
+        %use the vertical position of the seed spot centroid
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        [Theta_spot, Eta_spot] = gtFindAngles_360(struct_ids(i), tmpx, tmpy, centroidy(index),  (180/pi)*omega(i), parameters);
+        [Theta_orig, Eta_orig] = gtFindAngles_360(struct_ids(index), tmpx, tmpy, centroidy(index),  (180/pi)*omega(index), parameters);
+
+        save_theta=[save_theta Theta_spot Theta_orig];
+        %to use a percentage angle criteria
+        %    min_spot_dif = min(abs((twotheta/2)-Theta_spot)./(twotheta/2));
+        %    min_orig_dif = min(abs((twotheta/2)-Theta_orig)./(twotheta/2));
+
+        %to use an absolute allowed margin of error (as in consistancy check)
+        min_spot_dif = min(abs((twotheta/2)-Theta_spot));
+        min_orig_dif = min(abs((twotheta/2)-Theta_orig));
+
+        %    if (min_spot_dif<0.025 && min_orig_dif<0.025)% if both Thetas good to 2.5%
+        if (min_spot_dif<parameters.sort.theta_filter && min_orig_dif<parameters.sort.theta_filter)%use value from parameters.sort
+
+            %plot good point
+            if plot_flag
+                plot(tmpx, tmpy, 'go')
+            end
+            %record point in good points
+            %good points(1)=x, (2)=y, (3)=struct_id, (4)=dist (later), (5)=ycentroid
+            good_points(counter,1)=tmpx;
+            good_points(counter,2)=tmpy;
+            good_points(counter,3)=struct_ids(i);
+            good_points(counter,5)=centroidy(i);
+            counter=counter+1;
+
+        end
+    else
+        if debug_flag
+            disp('intersection outside of circular sample')
+        end
+    end
+end
+
+if debug_flag
+    keyboard
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%find grain position from good_points
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if size(good_points,1)>4 % need at least 5 spots to proceed...(1)
+
+    x_grain = fminbnd(@(x_grain) sfFindGrain(good_points, x_grain), min(good_points(:,1)), max(good_points(:,1)));
+    y_grain = (orig_grad*x_grain) + orig_intersect;
+    if plot_flag
+        plot(x_grain, y_grain, 'cx', 'markersize', 20) % plot the chosen center
+    end
+    %find width of original projection
+    [a,orig_sino,a]=gtReadSpots_360(spot_id, spot_id, replace_flag, parameters);%produce sinogram for original spot only
+
+    if (max(orig_sino)>0)  %if the max of the sinogram is zero, then the extspot must be bad(2)
+
+        orig_binsino = orig_sino>0.1*max(orig_sino);
+        dummy=find(orig_binsino==1);
+        orig_min=min(dummy);
+        orig_max=max(dummy);
+        proj_radius = (orig_max - orig_min)/2;
+
+        %calc distance of intersections from grain position
+        good_points(:,4) = sqrt((good_points(:,1)-x_grain).^2+(good_points(:,2)-y_grain).^2);
+        %remove intersections far from grain center
+        dummy = find(good_points(:,4)>proj_radius);
+        good_points(dummy, :)=[];
+
+        %plot the final set of intersections
+        if plot_flag
+            plot(good_points(:,1), good_points(:,2), 'ko', 'markersize', 10)
+        end
+
+        %collect the good struct_ids, pair_vector, for this grain, and the z
+        %position
+        good_struct_ids = [spot_id good_points(:,3)'];
+        z_pos = mean([spot_centroidy good_points(:,5)']);
+
+        struct_ids = good_struct_ids;
+
+        Omega =  (180/pi)*gtGetOmega(struct_ids, parameters);%put into degrees
+
+        %need at least five projections of grain for a useful reconstruction.
+        if length(struct_ids) > 4  %(3)
+
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            %%
+            %%
+            %call gtFindAngles with the initial guess at the grain centre
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+            [Theta, Eta] = gtFindAngles_360(struct_ids, x_grain, y_grain, z_pos, Omega, parameters);
+
+            %calculate plane normal vectors for consistancy check
+            [plane_normal,  hkl] = gtIndexReflections(Theta,Eta,Omega, parameters);
+            %run consistancy check
+            %modif sabine
+            % [R_vector, good_plnorms] = plot_rodrigues_consistancy(plane_normal, hkl, 0);
+            [R_vector, good_plnorms] = plot_rodrigues_consistancy_test(plane_normal, hkl, 0);
+            % fin modif sabine
+            %remove bad (inconsistant) data
+            kill_list = find(~good_plnorms);
+
+            %warning('consistancy check disabled!!!')
+            %kill_list=[];
+
+            if debug_flag
+                keyboard
+            end
+
+            Theta(kill_list)=[];
+            Eta(kill_list)=[];
+            Omega(kill_list)=[];
+            struct_ids(kill_list)=[];
+            plane_normal(kill_list,:)=[];
+            hkl(kill_list,:)=[];
+
+
+            %need at least five projections of grain for a useful reconstruction.
+            if length(struct_ids) > 4  % (4)
+
+                %calculate a better centroid to use in forward simulation
+                [stack,sino,z_of_sino]=gtReadSpots_360(spot_id, struct_ids, replace_flag, parameters);
+                try
+                    s=sfMakeGrain(sino, Omega, x_grain, y_grain, plot_flag);
+                catch
+                    disp('sfMakeGrain failed!')
+                    return
+                end
+
+
+                if max(s.BoundingBox(3:4))>(4*proj_radius) %very large bbox sign of messed up grain reconstruction
+                    grainCentroid=[x_grain y_grain z_pos];%x,y,z of grain
+                else
+                    grainCentroid=[s.Centroid z_pos];%x,y,z of grain
+                end
+
+
+                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                %forward simulation here - search database for more difspot-extspot pairs
+                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                add_struct_ids=gtForwardSimulate_360(grainCentroid,R_vector, struct_ids, parameters)
+                struct_ids = [struct_ids add_struct_ids];
+
+                Omega =  (180/pi)*gtGetOmega(struct_ids, parameters);%put into degrees
+
+                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                %repeat previous steps with added struct_ids
+                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                [stack,sino,z_of_sino]=gtReadSpots_360(spot_id, struct_ids, replace_flag, parameters);
+                try
+                    s=sfMakeGrain(sino, Omega, x_grain, y_grain, plot_flag);
+                catch
+                    disp('sfMakeGrain failed!')
+                    return
+                end
+
+
+                if max(s.BoundingBox(3:4))>(4*proj_radius) %very large bbox sign of messed up grain reconstruction
+                    grainCentroid=[x_grain y_grain z_pos];%x,y,z of grain
+                else
+                    grainCentroid=[s.Centroid z_pos];%x,y,z of grain
+                end
+
+                %final calculations of Theta, Eta, plane_normals using grain centroid
+                [Theta, Eta] = gtFindAngles_360(struct_ids, s.Centroid(1), s.Centroid(2), z_pos, Omega, parameters);
+                %calculate plane normal vectors for consistancy check
+                [plane_normal,  hkl] = gtIndexReflections(Theta,Eta,Omega, parameters);
+
+                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                %repeat consistancy check with added spot pairs
+                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                % modif sabine
+                %[R_vector, good_plnorms] = plot_rodrigues_consistancy(plane_normal, hkl, 0);
+                [R_vector, good_plnorms] = plot_rodrigues_consistancy_test(plane_normal, hkl, 0);
+                % fin modif sabine
+                %remove bad (inconsistant) data - shouldn't be any at this point!
+                kill_list = find(~good_plnorms);
+                %   warning('consistancy check disabled!!!')
+                %  kill_list=[];
+                if debug_flag
+                    keyboard
+                end
+                Theta(kill_list)=[];
+                Eta(kill_list)=[];
+                Omega(kill_list)=[];
+                struct_ids(kill_list)=[];
+                plane_normal(kill_list,:)=[];
+                hkl(kill_list,:)=[];
+                stack(:,:,kill_list)=[];
+                sino(:,kill_list)=[];
+
+
+                %need at least five projections of grain for a useful reconstruction.
+                if length(struct_ids) > 4  %(5)
+                    accept =1;
+
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                    %collect data for .mat file, pad bounding boxes...
+                    %get z position data from database
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+                    for i=1:length(struct_ids)
+                        query=sprintf(['select Yorigin,Yorigin+Ysize from '...
+                            '%sbb inner join %sbboxes on bbID=bboxID '...
+                            'where %sbb.extspotID=%d'],...
+                            parameters.acq.name, parameters.acq.name, parameters.acq.name,...
+                            struct_ids(i));
+                        [zstart(i),zend(i)]=mym(query);
+                    end
+
+                    %bounding box data
+                    zstart=min(zstart);
+                    zend=max(zend);
+                    x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+                    y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+                    xend = x1 + s.BoundingBox(3);
+                    yend = y1 + s.BoundingBox(4);
+                    %centres
+                    xcenter=round(s.Centroid(1));
+                    ycenter=round(s.Centroid(2));
+                    zcenter=round(z_pos);
+
+                    %add 20% to bounding box for luck (x-y plane only for extspot recon)
+                    x1 = round(x1 - (s.BoundingBox(3)/5));
+                    if x1 < 1
+                        x1 = 1;
+                    end
+                    y1 = round(y1 - (s.BoundingBox(4)/5));
+                    if y1 <1
+                        y1 = 1;
+                    end
+                    xend = round(xend + (s.BoundingBox(3)/5));
+                    if xend > parameters.acq.bb(3)
+                        xend = parameters.acq.bb(3);
+                    end
+                    yend = round(yend + (s.BoundingBox(4)/5));
+                    if yend > parameters.acq.bb(3)
+                        yend = parameters.acq.bb(3);
+                    end
+
+                    nx = xend-x1;
+                    ny = yend-y1;
+                    nz = zend-zstart;
+
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                    %save grainid into database structure
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+                    if 1%do save
+
+                        for i=1:length(struct_ids)
+
+                            %update grainID in extspot table
+                            mysqlcmd=dbUpdate(sprintf('%sextspot',parameters.acq.name),'extspotID',struct_ids(i),'GrainID',grainid);
+                            mym(mysqlcmd);
+                            %update grainID in bb table (!)
+                            mysqlcmd=dbUpdate(sprintf('%sbb',parameters.acq.name),'extspotID',struct_ids(i),'grainID',grainid);
+                            mym(mysqlcmd);
+
+                        end
+
+                        %save mat file
+                        grainname=sprintf('grain%d_',grainid);
+                        graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+                        if ~exist(graindir,'dir')
+                            mkdir(graindir);
+                        end
+                        name=sprintf('%s/%s.mat',graindir,grainname);
+                        save(name,'struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector');
+                    else
+                        disp('debug/test mode!')
+
+                    end
+
+
+                else
+                    disp(sprintf('only %d projections related to spot %d after foward simulation+consistancy check2 - skipping',length(struct_ids),spot_id))
+                end  %(5)
+
+            else
+                disp(sprintf('only %d projections related to spot %d after consistancy check - skipping',length(struct_ids),spot_id))
+            end   % (4)
+
+        else
+            disp(sprintf('only %d good points on projection of spot %d with similar positions- skipping',size(good_points,1),spot_id))
+        end    %(3)
+
+    else
+        disp('Bad original sinogram for this spot (negative extspot intensity!)')
+        if debug_flag
+            keyboard
+        end
+    end   %(2)
+
+else
+    disp(sprintf('only %d good points on projection of spot %d - skipping',size(good_points,1),spot_id))
+end   % (1)
+
+
+
+
+
+end  %end of the function
+
+
+
+
+
+
+
+function [m, c] = sfMakeBackProLine(spot_id, struct_ids, sino, theta)
+%function to return the parameters of a line passing through the proj of a
+%given spot, struct_ids is vector of spots in the sinogram, sino.
+index = find(struct_ids == spot_id);
+
+%get spot parameters
+spot_sino=sino(:,index);
+spot_com=(spot_sino'*[1:length(spot_sino)]')/sum(spot_sino);
+spot_omega=theta(index);
+
+%experiment parameters
+centre_of_backproimg_x = size(sino,1)/2;
+centre_of_backproimg_y = size(sino,1)/2;
+
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-length(spot_sino)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+function [m, c] = sfMakeBackProLine2(spot_id, struct_ids, centroidx, omega, parameters)
+%function to return the parameters of a line passing through the centroid of a
+%given spot, struct_ids is vector of spots in the sinogram.
+
+index = find(struct_ids==spot_id);
+
+%get spot parameters
+spot_com=centroidx(index);
+spot_omega=omega(index);
+%experiment parameters
+centre_of_backproimg_x = parameters.acq.bb(3)/2;
+centre_of_backproimg_y = parameters.acq.bb(3)/2;
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+%make line parameters
+grad=1/tan(spot_omega);
+%dist of com line from centre
+offset_com=spot_com-parameters.acq.bb(3)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+end
+
+
+%function [Theta,Eta] = sfFindAngles(struct_id, pair, grainx, grainy, grainz, omega);
+%omega=omega*180/pi; %gtFindAngles works in radians...
+%[Theta,Eta] = gtFindAngles_pair(struct_id, pair, grainx, grainy, grainz, omega);
+%end
+
+
+function output = sfFindGrain(good_points, x_grain)
+%function for fminbnd to find grain position along original projection
+dif = good_points(:,1)-x_grain;
+%minimise sum of squares for the closest half of the points, to reduce
+%effect of outliers
+dif = abs(dif);
+dif = sort(dif,1,'descend');
+tmp = ceil(size(dif,1)/2);
+dif(1:tmp)=[];
+output = dif'*dif;%sum of squares
+end
+
+function s = sfMakeGrain(sino, Omega, x_grain, y_grain, plot_flag)
+
+%back project good spots only
+binsino = sino>0.1*max(sino(:));
+img2=backpro(binsino,(pi/180)*Omega);
+
+%do imreconstruct from centre to threshold grain
+x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+marker=zeros(size(img2));
+marker(y_grain, x_grain)=1;
+mask=double((img2>0.8*img2(y_grain, x_grain)));
+
+try
+    grain=imreconstruct(marker,mask);
+    if plot_flag
+        figure
+        h1=imshow(cat(3,img2,zeros(size(img2)),zeros(size(img2))),[]);
+        hold on
+        h2=imshow(cat(3,zeros(size(img2)),grain,zeros(size(img2))),[]);
+        set(h2,'alphadata',0.5);
+    end
+    s=regionprops(grain,'Area','BoundingBox','Centroid');
+
+catch
+    disp('Marker/mask problem - bombed out')
+    accept=false;
+    return
+end
+
+
+end
diff --git a/4_spot_sorting/gtINUniquePlaneNormals.m b/4_spot_sorting/gtINUniquePlaneNormals.m
new file mode 100755
index 0000000000000000000000000000000000000000..6677e555882d58f55ef68cb71bb0d955bcb3aa00
--- /dev/null
+++ b/4_spot_sorting/gtINUniquePlaneNormals.m
@@ -0,0 +1,176 @@
+function grainsout=gtINUniquePlaneNormals(grainsinp,ACM)
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+% Loop through grains
+for i=1:nof_grains
+    i % modif sabine
+  nof_pl=size(grains{i}.pl,1);
+
+  % Load grain info into 'remaining' (these remain to be dealt with)
+  remainingl.pl=grains{i}.pl;
+  remainingl.thetatype=grains{i}.thetatype;
+  remainingl.theta=grains{i}.theta;
+  remainingl.eta=grains{i}.eta;
+  remainingl.hkl=grains{i}.hkl;
+
+  remainings=1:nof_pl % ; modif sabine
+
+  nof_unipl=0;
+
+  % Process all the planes in the grain
+  while length(remainings)>=1
+
+    nof_unipl=nof_unipl+1;
+
+    merge=1;
+
+    % Take the first in remaining and compare with all other remaining,
+    % look for possible identical planes.
+    for j=2:length(remainings)
+      if remainingl.thetatype(1)==remainingl.thetatype(j)
+        ACV=ACM{remainingl.thetatype(1),remainingl.thetatype(j)};
+        ang=gt2PlanesAngle(remainingl.pl(1,:),remainingl.pl(j,:));
+        [minval,minloc]=min(abs(ACV-ang));
+
+        if ACV(minloc)==0 % the same planes
+          merge=[merge, j];
+        end
+      end
+    end
+
+    % Merge identical planes, its new direction is the mean of the constituting
+    %  planes.
+
+    if length(merge)>1
+      al=sign(remainingl.pl(merge,:)*remainingl.pl(1,:)'); % direction same or opposite
+      al=repmat(al,1,3);
+
+      uniplmean=mean(remainingl.pl(merge,:).*al,1);
+      uniplmean=uniplmean/norm(uniplmean);
+
+      unitheta=mean(remainingl.theta(merge));
+
+      if remainingl.eta(merge(1))>180
+        unieta1=360-remainingl.eta(merge(1));
+      else
+        unieta1=remainingl.eta(merge(1));
+      end
+      
+      if remainingl.eta(merge(2))>180
+        unieta2=360-remainingl.eta(merge(2));
+      else
+        unieta2=remainingl.eta(merge(2));
+      end
+
+      if abs(unieta1-unieta2)<abs(unieta1+unieta2-180) % they are aligned
+        unieta=mean([unieta1,unieta2]);
+        deta_deg=abs(unieta1-unieta2);
+        deta=deg2rad(deta_deg);
+      else % they are mirrored to Y axis 
+        unieta=(unieta1-unieta2)/2+90;
+        deta_deg=abs(unieta1+unieta2-180);
+        deta=deg2rad(deta_deg);
+      end
+      
+      %%% Calculate discrepancy 
+      % here it's assumed that merge=2 always
+      % in case of wrong indexing merge might be >2
+      if length(merge)>2
+        disp(sprintf('Warning! Indexing error in grain %d, dubious plane normals are:',i))
+        disp(merge)
+      end
+      
+      twon=remainingl.pl(merge,:).*al;
+      dn=twon(1,:)-twon(2,:);
+      nn=twon(1,:)*twon(2,:)';
+      nnhor=twon(1,1:2)*twon(2,1:2)'/norm(twon(1,1:2))/norm(twon(2,1:2));
+      dang_deg=acosd(nn);
+      dang=acos(nn);
+      danghor_deg=acosd(nnhor);
+      danghor=acos(nnhor);
+      dtheta_deg=abs(remainingl.theta(merge(1))-remainingl.theta(merge(2)));
+      dtheta=deg2rad(dtheta_deg);
+      pixerrvernorm=abs(dn(3)*2*sind(unitheta)/cosd(2*unitheta));
+      pixerrfrometanorm=deta*2*sind(unitheta)/cosd(2*unitheta);
+      omfactor=(1/(1+(sind(2*unitheta)*sind(unieta)/(2*sind(unitheta)^2))^2)/...
+               (2*sind(unitheta)^2))^2*cosd(2*unitheta)^2;
+      %%%%%
+        
+    else % if length(merge)>1
+      uniplmean=remainingl.pl(1,:);
+      unitheta=remainingl.theta(1);
+      unieta=remainingl.eta(1);
+      dn=NaN(1,3);  %zeros(1,3);
+      nn=NaN;
+      pixerrvernorm=NaN;
+      pixerrfrometanorm=NaN;
+      dang=NaN;
+      % modif sabine
+      dang_deg=NaN;
+      danghor_deg=NaN;
+      dtheta_deg=NaN;
+      deta_deg=NaN;
+      % end modif sabine
+      
+      nnhor=NaN;
+      danghor=NaN;
+      dtheta=NaN;
+      deta=NaN;
+      omfactor=NaN;
+    end
+
+    % Save unique planes under grains.uni 
+    grains{i}.uni.plid(nof_unipl,:)=false(1,nof_pl);
+    grains{i}.uni.plid(nof_unipl,remainings(merge))=true; % which pair-lines are used
+    
+    grains{i}.uni.pl(nof_unipl,:)=uniplmean;
+    grains{i}.uni.thetatype(nof_unipl)=remainingl.thetatype(1);
+    grains{i}.uni.hkl(nof_unipl,:)=remainingl.hkl(1,:);
+    grains{i}.uni.pla(nof_unipl)=NaN;
+    
+    grains{i}.uni.theta(nof_unipl)=unitheta;
+    grains{i}.uni.eta(nof_unipl)=unieta;
+    
+    grains{i}.uni.dn(nof_unipl,:)=dn;    
+    grains{i}.uni.nn(nof_unipl)=nn;
+    grains{i}.uni.nnhor(nof_unipl)=nnhor;    
+    
+    grains{i}.uni.dang(nof_unipl)=dang;    
+    grains{i}.uni.dang_deg(nof_unipl)=dang_deg;    
+    grains{i}.uni.danghor(nof_unipl)=danghor;    
+    grains{i}.uni.danghor_deg(nof_unipl)=danghor_deg;    
+    grains{i}.uni.dtheta(nof_unipl)=dtheta;    
+    grains{i}.uni.dtheta_deg(nof_unipl)=dtheta_deg;    
+    grains{i}.uni.deta(nof_unipl)=deta;    
+    grains{i}.uni.deta_deg(nof_unipl)=deta_deg;    
+    grains{i}.uni.pixerrvernorm(nof_unipl)=pixerrvernorm;
+    grains{i}.uni.pixerrfrometanorm(nof_unipl)=pixerrfrometanorm;
+    grains{i}.uni.omfactor(nof_unipl)=omfactor;    
+
+    remainingl.pl(merge,:)=[];
+    remainingl.thetatype(merge)=[];
+    remainingl.theta(merge)=[];
+    remainingl.eta(merge)=[];
+    remainingl.hkl(merge,:)=[];
+
+    remainings(merge)=[];
+
+  end % of plane
+
+end % of grain
+
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+end % of function
diff --git a/4_spot_sorting/gtINWriteGrainFolder.m b/4_spot_sorting/gtINWriteGrainFolder.m
new file mode 100755
index 0000000000000000000000000000000000000000..3c62c6dbad32b6b67436b98e7071a5f49aea42bc
--- /dev/null
+++ b/4_spot_sorting/gtINWriteGrainFolder.m
@@ -0,0 +1,223 @@
+% Writes grains data from indexing into 4_grain/grainx_ folders.
+% (like gtHandleSpot_360 would do)
+
+
+function grain=gtINWriteGrainFolder(grain,parameters)
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+if ~exist('grain','var')
+  load sort_grains_lastrun.mat
+end
+
+gtDBConnect 
+
+do_forward_simulation=0;
+
+acq=parameters.acq;
+
+
+for i=22%1:length(grain)
+    i
+  struct_ids=grain{i}.difspots;
+  grain{i}.struct_ids=struct_ids;
+  replace_flag=0;
+
+  %% transform vectors back to full length...
+  Omega=[grain{i}.omega, grain{i}.omega+180];  % need one for each difspot
+  Theta=[grain{i}.theta, grain{i}.theta];
+  Eta=[grain{i}.eta, mod(grain{i}.eta+180,360)];             %
+  hkl=[grain{i}.hkl;grain{i}.hkl];
+  plane_normal=[grain{i}.pl;-grain{i}.pl];
+  R_vector=grain{i}.R_vector;
+
+  % and update grain structure  (not very elegant.... change length of
+  % vectors in sort_grain
+  grain{i}.omega=Omega;
+  grain{i}.theta=Theta;
+  grain{i}.eta=Eta;
+  grain{i}.hkl=hkl;
+  grain{i}.pl=plane_normal;
+
+
+  % Sample system coordinates of grain
+  grain{i}.xcenter= (acq.bb(3)/2)+grain{i}.center(2);
+  grain{i}.ycenter= (acq.bb(3)/2)+grain{i}.center(1);
+  grain{i}.zcenter= -grain{i}.center(3)+acq.ydet/2-acq.bb(2);
+  grainCentroid=[grain{i}.xcenter,grain{i}.ycenter,grain{i}.zcenter];
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % forward simulation here - search database for more difspots
+  %
+  % still to be done:
+  %
+  % - search for extinction spots from higher order reflections which do not have difspots
+  %
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  if do_forward_simulation
+
+    [dummy,add_struct_ids]=gtForwardSimulate_360(grainCentroid, R_vector, struct_ids, parameters,0);     % add optional variable to accept unpaired difspots, too
+
+    ndx=length(struct_ids);
+    [dummy,tt]=gtnew_calculate_twotheta;  % theoretical list of allowed reflections and TwoTHeta values
+
+    struct_ids = [struct_ids add_struct_ids];
+    grain{i}.struct_ids=struct_ids;
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % try to calculate in the missing information for the new forward
+    % simulated spots, based on the measured spot positions and known grain position
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    for j=1:length(add_struct_ids)
+      [CentroidImage,CentroidX,CentroidY]=mym(sprintf('select CentroidImage, CentroidX, CentroidY from %sdifspot where difspotID=%d',acq.name,add_struct_ids(j)));
+
+      Omega(ndx+j) = CentroidImage/(acq.nproj*2)*360;    % supposes 360 degree scans here
+      [grainx,grainy,grainz]=gtTrSamToLab(grain{i}.center(1),grain{i}.center(2),grain{i}.center(3),Omega(ndx+j));
+
+      % calculate the distances in pixels with respect to the laboratory system
+      dx= acq.dist/acq.pixelsize-grainx;
+      dy= CentroidX-acq.rotx-grainy;
+      dz= acq.ydet/2-CentroidY-grainz;
+      kh=[dx dy dz];
+      kh=kh/norm(kh);  % normalized difracted beam direction
+      k0=[1 0 0];      % normalized incoming beam direction
+      G= (kh-k0)/norm(kh-k0);        % normalized Laboratory system scattering vector
+
+      Eta(ndx+j)   = atan2(dy,dz)/pi*180;
+      Theta(ndx+j) = atand(sqrt(dy.^2+dz.^2)/dx)/2;
+      refl         = find(abs(tt.centre-Theta(ndx+j)*2)==min(abs(tt.centre-Theta(ndx+j)*2)));  % find out what type of reflection this Theta corresponds to
+      hkl(ndx+j,:) = tt.reflections(refl,:);
+      [pn(1),pn(2),pn(3)]= gtTrLabToSam(G(1),G(2),G(3),Omega(ndx+j)); % normalized plane_normal in sample coordinate system
+      plane_normal(ndx+j,:) = pn;
+
+      %query=sprintf(['select Yorigin,Yorigin+Ysize from %sbb inner join %sbboxes on bbID=bboxID where %sbb.extspotID=%d'],...
+      % acq.name, acq.name, acq.name,add_struct_ids(j));
+      %[zstart(ndx+j),zend(ndx+j)]=mym(query);
+    end
+    grain{i}.omega=Omega;
+
+  end % do_forward_simulation
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% build stack (including the new spots)  - and calculate  backprojection image
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  plot_flag=1;
+
+  [extstack,sino,z_pos,bb,index]=gtReadExtRoi_360(grain{i},parameters);
+  [difstack,omega_dif]=gtShearDifspots(grain{i});
+
+
+  if 1
+    s=gtMakeGrain(sino, Omega, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+  else
+    %at least for the Mg data this is better
+    difsino=squeeze(difstack(round(end/2),:,:));
+    s=gtMakeGrain(difsino, omega_dif, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+  end
+
+
+  if isempty(s)   %if MakeGrain fails to segment the grain...
+    x1=round(grain{i}.xcenter-bb(3)/2);
+    y1=round(grain{i}.ycenter-bb(3)/2);
+    xend=round(x1+bb(3));
+    yend=round(y1+bb(3));
+  else
+    x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+    y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+    xend = x1 + s.BoundingBox(3);
+    yend = y1 + s.BoundingBox(4);
+  end
+
+  zstart=bb(1,2);
+  zend=bb(1,2)+bb(1,4);
+
+
+
+  % add 20% to bounding box for luck (x-y plane only for extspot recon)
+  x1 = round(x1 - (s.BoundingBox(3)/5));
+  if x1 < 1
+    x1 = 1;
+  end
+  y1 = round(y1 - (s.BoundingBox(4)/5));
+  if y1 <1
+    y1 = 1;
+  end
+  xend = round(xend + (s.BoundingBox(3)/5));
+  if xend > acq.bb(3)
+    xend = acq.bb(3);
+  end
+  yend = round(yend + (s.BoundingBox(4)/5));
+  if yend > acq.bb(3)
+    yend = acq.bb(3);
+  end
+
+  nx = xend-x1;
+  ny = yend-y1;
+  nz = zend-zstart;
+  xcenter=round(grain{i}.xcenter);
+  ycenter=round(grain{i}.ycenter);
+  zcenter=round(grain{i}.zcenter);
+
+  % Write in database:
+  try % we may not have an extspot table!
+    for j=1:length(struct_ids)
+      %update grainID in extspot table
+      mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',struct_ids(j),'GrainID',i);
+      mym(mysqlcmd);
+    end
+  catch
+    disp('no suitable extspot table found - no update of extspot table')
+  end
+
+  % Save mat file
+  grainname=sprintf('grain%d_',i);
+  graindir=sprintf('%s/4_grains/%s',acq.dir,grainname);
+  if ~exist(graindir,'dir')
+    mkdir(graindir);
+  end
+
+
+  %write out the extspot stack
+  for j=1:length(struct_ids)
+    %write the spr/sdt projections
+    name=sprintf('%s/%s%d.sdt',graindir,grainname,j);
+    fid=fopen(name,'wb','l');
+    %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+    fwrite(fid,extstack(:,:,j)','float32');
+    fclose(fid);
+    name=sprintf('%s/%s%d.spr',graindir,grainname,j);
+    spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+  end
+
+  %write the difspot stack
+  for j=1:length(struct_ids)
+    %write the spr/sdt projections
+    name=sprintf('%s/%s%d.sdt',graindir,grainname,j+length(struct_ids));
+    fid=fopen(name,'wb','l');
+    %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+    fwrite(fid,difstack(:,:,j)','float32');
+    fclose(fid);
+    name=sprintf('%s/%s%d.spr',graindir,grainname,j);
+    spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+  end
+
+  stack=cat(3,extstack,difstack);
+  % add the omega difspot values to the stack
+  Omega=[Omega,omega_dif];
+  index=[index,index];
+
+  
+  name=sprintf('%s/%s.mat',graindir,grainname);
+  save(name,'struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector','index');
+
+
+
+end % of grain loop
+
+
+end % of function
diff --git a/4_spot_sorting/gtINWriteGrainFolder_3D.m b/4_spot_sorting/gtINWriteGrainFolder_3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..af360da44435d563f060b768f70375963f4ddf27
--- /dev/null
+++ b/4_spot_sorting/gtINWriteGrainFolder_3D.m
@@ -0,0 +1,469 @@
+% Writes grains data from indexing into 4_grain/grainx_ folders.
+% (like gtHandleSpot_360 would do)
+
+%version _ak  sorry...  get something running for the Mg data!
+%pass in parameter/value pairs
+%list : list of grains to do
+%ROI : to do only grainbs in a certain sub volume of the reconstructed
+%volume, eg after a rough reconstruction of all [xstart ystart zstart xsize
+%ysize zsize]
+%gt_select_projections_auto - can use this or not
+%do_forward_simulation - by default is on
+%update_db - update datebase with forward simulation results.
+
+% does forward simulate to pick up unpaired spots, skips this if R-vector
+% is NaN or Inf
+
+function [number_added, failed_grains] = gtINWriteGrainFolder_ak(grain,parameters, varargin)
+
+% if ~exist('parameters','var')
+%     load parameters.mat
+% end
+% if ~exist('grain','var')
+%     load sort_grains_lastrun.mat
+% end
+
+%get optional arguments passed in
+app.ROI = 'none';
+app.list=1:length(grain);
+app.gt_select_projections_auto=0;
+app.do_forward_simulation=0;
+app.update_db=1;
+
+app=parse_pv_pairs(app,varargin);
+
+
+gtDBConnect;
+
+; %while playing may not want to record anything
+
+acq=parameters.acq;
+number_added=[];
+failed_grains=[]; %any that are missed, for whatever reason
+
+%%%%%
+% Deal with issues surrounding keeping the database current
+%%%%%
+%if it doesn't already exist, we may need to add a grainid column to
+%difspot table
+[a,b,c,d,e,f]=mym(sprintf('show columns from %sdifspot like "grainID"',acq.name));
+if isempty(a)
+    %add the field
+    mym(sprintf('ALTER TABLE graintracking.%sdifspot ADD COLUMN grainID INT AFTER integral', acq.name));
+    disp('adding grainID field to the difspot table')
+end
+%even if the field already exists, we may need to update it
+a=mym(sprintf('select count(*) from %sdifspot where !isnull(grainid)', acq.name));
+b=mym(sprintf('select count(*) from %s where !isnull(grainid)', acq.pair_tablename));
+if a<(2*b)
+    %then need to update this field
+    [a,b,c]=mym(sprintf('select difAID, difBID, grainid from %s where !isnull(grainid)', acq.pair_tablename));
+    data=[a c; b c];
+    for i=1:length(data)
+        mym(dbUpdate(sprintf('%sdifspot', acq.name),'difspotID',data(i,1),'grainID',data(i,2)));
+        if mod(i, 1000)==0
+            disp(sprintf('updating difspot table grainIDs... done %0.1f percent', 100*i/length(data)))
+        end
+    end
+end
+%%%%%%
+
+
+for ndx=1:length(app.list)
+    i=app.list(ndx)
+
+    %add a conditional term - if we want to do only those grains in a certain
+    %subvolume of the sample for example
+    %there, move calculation of reconstructed center outside this "if"
+
+    % Sample system coordinates of grain - reconstruction coordinates
+    grain{i}.xcenter= (acq.bb(3)/2)+grain{i}.center(2);
+    grain{i}.ycenter= (acq.bb(3)/2)+grain{i}.center(1);
+    grain{i}.zcenter= -grain{i}.center(3)+acq.ydet/2-acq.bb(2);
+    grainCentroid=[grain{i}.xcenter,grain{i}.ycenter,grain{i}.zcenter];
+
+    if strcmp(app.ROI, 'none') || (all(grainCentroid>app.ROI(1:3)) & all(grainCentroid<(app.ROI(1:3)+app.ROI(4:6)-1)))
+
+        try
+
+            disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
+            disp('')
+            disp('')
+            disp(sprintf('doing GRAIN %d',i))
+            disp('')
+            disp('')
+            disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
+
+
+            struct_ids=grain{i}.difspots;
+            grain{i}.struct_ids=struct_ids;
+            replace_flag=0;
+
+            %% transform vectors back to full length...
+            Omega=[grain{i}.omega, grain{i}.omega+180];  % need one for each difspot
+            Theta=[grain{i}.theta, grain{i}.theta];
+            Eta=[grain{i}.eta, mod(grain{i}.eta+180,360)];             %
+            hkl=[grain{i}.hkl;grain{i}.hkl];
+            plane_normal=[grain{i}.pl;-grain{i}.pl];
+            R_vector=grain{i}.R_vector;
+
+            % and update grain structure  (not very elegant.... change length of
+            % vectors in sort_grain
+            grain{i}.omega=Omega;
+            grain{i}.theta=Theta;
+            grain{i}.eta=Eta;
+            grain{i}.hkl=hkl;
+            grain{i}.pl=plane_normal;
+
+
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            %
+            % forward simulation here - search database for more difspots
+            %
+            % note - don't try this if R-vector is NaN! Or Inf!
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+            if app.do_forward_simulation
+                if ~isnan(grain{i}.R_vector(1)) & ~isinf(grain{i}.R_vector(1))
+
+                    [dummy,add_struct_ids]=gtForwardSimulate_360(grainCentroid, R_vector, struct_ids, parameters,0);     % add optional variable to accept unpaired difspots, too
+                    % note that the last zero is "test extspot" for forward simulate
+                    number_added(i)=length(add_struct_ids);
+
+                    ndx=length(struct_ids);
+                    [dummy,tt]=gtnew_calculate_twotheta;  % theoretical list of allowed reflections and TwoTHeta values
+
+                    struct_ids = [struct_ids add_struct_ids];
+                    grain{i}.struct_ids=struct_ids;
+
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                    % try to calculate in the missing information for the new forward
+                    % simulated spots, based on the measured spot positions and known grain position
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                    for j=1:length(add_struct_ids)
+                        [CentroidImage,CentroidX,CentroidY]=mym(sprintf('select CentroidImage, CentroidX, CentroidY from %sdifspot where difspotID=%d',acq.name,add_struct_ids(j)));
+
+                        Omega(ndx+j) = CentroidImage/(acq.nproj*2)*360;    % supposes 360 degree scans here
+                        [grainx,grainy,grainz]=gtTrSamToLab(grain{i}.center(1),grain{i}.center(2),grain{i}.center(3),Omega(ndx+j));
+
+                        % calculate the distances in pixels with respect to the laboratory system
+                        dx= acq.dist/acq.pixelsize-grainx;
+                        dy= CentroidX-acq.rotx-grainy;
+                        dz= acq.ydet/2-CentroidY-grainz;
+                        kh=[dx dy dz];
+                        kh=kh/norm(kh);  % normalized difracted beam direction
+                        k0=[1 0 0];      % normalized incoming beam direction
+                        G= (kh-k0)/norm(kh-k0);        % normalized Laboratory system scattering vector
+
+                        Eta(ndx+j)   = atan2(dy,dz)/pi*180;
+                        Theta(ndx+j) = atand(sqrt(dy.^2+dz.^2)/dx)/2;
+                        refl         = find(abs(tt.centre-Theta(ndx+j)*2)==min(abs(tt.centre-Theta(ndx+j)*2)));  % find out what type of reflection this Theta corresponds to
+                        hkl(ndx+j,:) = tt.reflections(refl,:);
+                        [pn(1),pn(2),pn(3)]= gtTrLabToSam(G(1),G(2),G(3),Omega(ndx+j)); % normalized plane_normal in sample coordinate system
+                        plane_normal(ndx+j,:) = pn;
+
+                        %query=sprintf(['select Yorigin,Yorigin+Ysize from %sbb inner join %sbboxes on bbID=bboxID where %sbb.extspotID=%d'],...
+                        % acq.name, acq.name, acq.name,add_struct_ids(j));
+                        %[zstart(ndx+j),zend(ndx+j)]=mym(query);
+                    end
+                    %add data to the grain structure, so it can be passed to other
+                    %functions
+
+                    grain{i}.omega=Omega;
+                    grain{i}.theta=Theta;
+                    grain{i}.eta=Eta;
+                    grain{i}.pl=plane_normal;
+                    grain{i}.hkl=hkl;
+
+                    %update database here to avoid grain rustling issues
+                    if app.update_db
+                        % Write in database: (EXTSPOTS)
+                        try % we may not have an extspot table!
+                            for j=1:length(add_struct_ids)
+                                %update grainID in extspot table
+                                mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',add_struct_ids(j),'GrainID',i);
+                                mym(mysqlcmd);
+                            end
+                        catch
+                            disp('no suitable extspot table found - no update of extspot table')
+                        end
+                        % Write in database: (DIFSPOTS)
+                        for j=1:length(add_struct_ids)
+                            %update grainID in difspot table
+                            mysqlcmd=dbUpdate(sprintf('%sdifspot',acq.name),'difspotID',add_struct_ids(j),'GrainID',i);
+                            mym(mysqlcmd);
+                        end
+                        for j=1:length(add_struct_ids)
+                            %update grainID in pair table - some of the
+                            %added difspots may belong to pairs - if they
+                            %do, then we should also get the pair spot.
+                            tmp=mym(sprintf('select grainid from Mg_fatigue1_difspot where difspotid=%d', add_struct_ids(j)));
+                            [pid, gid]=mym(sprintf('select pairid, grainid from %s where difaid=%d or difbid=%d',acq.pair_tablename, add_struct_ids(j), add_struct_ids(j)));
+                            if ~isempty(pid) & isnan(gid) %if there is a pair, we can update the grainid to this grain to stop it being considered again if doing 
+                              % more than one iteration of sort grains (eg opening the tolerances on building grains and starting again)
+                            mysqlcmd=dbUpdate(acq.pair_tablename,'pairID',pid,'GrainID',i);
+                            mym(mysqlcmd);
+                            end
+                        end
+                    end
+
+                else
+                    disp('R-vector is NaN - skipping forward simulation for this grain')
+                end
+            end % do_forward_simulation
+
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            %% build stack (including the new spots)  - and calculate  backprojection image
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+            plot_flag=0;
+            grainname=sprintf('grain%d_',i);
+            graindir=sprintf('%s/4_grains/%s',acq.dir,grainname);
+            if ~exist(graindir,'dir')
+                mkdir(graindir);
+            end
+
+            %[extstack,sino,z_pos,bb,index]=gtReadExtRoi_360wl(grain{i},parameters); 
+   
+            [difstack,difstackbw]=gtWriteDifStack(i,grain,parameters);
+
+			%write the difspot stack
+            for k=1:length(grain{i}.pairid)
+                %write the spr/sdt projections
+                name=sprintf('%s/difspot%d',graindir,k);
+				sdt_write(name,difstack{k},'float32');
+               
+			end
+			
+            [shearstack,omega_dif]=gtShearDifspots(grain{i});
+
+            npairs=length(grain{i}.pairid);  
+
+            tmp=sum(sum(shearstack, 3), 2);
+			
+            zstart=acq.bb(4)/2-find(tmp, 1, 'last');
+            zend =acq.bb(4)/2-find(tmp, 1, 'first');
+			dimz = zend-zstart+1;   
+            
+            margin=30;
+
+            if 1
+                [extstack,sino,z_pos,bb,index]=gtReadExtRoi_360(grain{i},parameters);
+   
+				%reconstruct slightly bigger volume (+10 pixel each side) - in order to get rid
+                %of artifacts at the borders of the reconstruction
+				x1=-parameters.acq.bb(3)/2-margin;
+				nx=parameters.acq.bb(3)+2*margin;
+				y1=x1;
+				ny=nx;
+				z1=grain{i}.center(3)-1;
+				grain{i}.Omega=grain{i}.omega;
+				grain{i}.Eta=grain{i}.eta;
+				grain{i}.Theta=grain{i}.theta;
+				grain{i}.struct_ids=grain{i}.difspots;
+				nz=3;
+				
+				cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, i));
+                vol=gtMakeARTJob3D('difbw','slice.par',[1:npairs],[],grain{i},parameters,1,x1,nx,y1,ny,z1,nz,1);
+			
+				thresh=0.9*max(max(vol(margin+1:end-margin,margin+1:end-margin,2)));
+				voltr=bwlabel(vol(margin+1:end-margin,margin+1:end-margin,2)>thresh);
+				
+				%voltr=flipud(voltr');
+				marker=zeros(size(voltr));
+				hgrainA=parameters.acq.bb(3)/2-round(grain{i}.center(2));
+				vgrainA=parameters.acq.bb(3)/2+round(grain{i}.center(1));
+				
+				marker(vgrainA,hgrainA)=1;
+				voltr=imreconstruct(marker,voltr);
+				imshow(voltr);drawnow;
+				%waitforbuttonpress
+				
+				s=regionprops((voltr))
+				cd(parameters.acq.dir);
+				
+            else
+                %at least for the Mg data this is better
+
+                %calculate z position for sinogram
+                zsino=round(grain{i}.zcenter);
+                zsino=min(zsino, size(shearstack,1));
+                zsino=max(zsino, 1);
+
+                shearsino=squeeze(shearstack(zsino,:,:));
+                s=gtMakeGrain(shearsino, omega_dif, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+                if plot_flag
+                    pause(1);
+                    
+                end
+            end
+
+
+            
+			index=ones(1,length(grain{i}.pairid));
+
+           
+
+
+            if isempty(s)   %if MakeGrain fails to segment the grain...
+                %get average horizontal extent from the sinogram
+				
+                %!!! this still needs to be checked and updated for the 3D case !!!
+                
+				grain_width=max(sum(difsino>0, 1));
+                x1=round(grain{i}.xcenter-grain_width/2);
+                y1=round(grain{i}.ycenter-grain_width/2);
+                xend=round(x1+grain_width);
+                yend=round(y1+grain_width);
+            else
+                x1 = ceil(s.BoundingBox(1)-parameters.acq.bb(3)/2); %gt bbox ceil
+                y1 = ceil(s.BoundingBox(2)-parameters.acq.bb(3)/2); %gt bbox ceil
+                xend = x1 + s.BoundingBox(3);
+                yend = y1 + s.BoundingBox(4);
+            end
+
+
+
+
+            % add 20% to bounding box for luck (x-y plane only for extspot recon)
+            dimx=xend-x1;
+            dimy=yend-y1;
+            x1 = round(x1 - (dimx/5));
+            if x1 < -acq.bb(3)/2
+                x1 = -acq.bb(3)/2;
+            end
+            y1 = round(y1 - (dimy/5));
+            if y1 < -acq.bb(3)/2;
+                y1 = -acq.bb(3)/2;
+            end
+            xend = round(xend + (dimx/5));
+            if xend > acq.bb(3)/2
+                xend = acq.bb(3)/2;
+            end
+            yend = round(yend + (dimy/5));
+            if yend > acq.bb(3)/2
+                yend = acq.bb(3)/2;
+            end
+
+            nx = xend-x1;
+            ny = yend-y1;
+            
+			
+			%z1= grain{i}.center(3)-nz/2*1.2;    % need some security here
+			z1 = round(max(-acq.bb(4)/2, zstart - (dimz/5)));
+			zend = round(min(acq.bb(4)/2, zend + (dimz/5)));
+			nz = zend-z1+1;
+			
+            xcenter=round(grain{i}.xcenter);
+            ycenter=round(grain{i}.ycenter);
+            zcenter=round(grain{i}.zcenter);
+
+
+            %select appropriate lambda values for ART
+            if (parameters.acq.spacegroup == 663) % ie snow case % modif sabine
+                disp(' case 663')
+%                 if length(struct_ids)>55
+%                     lambda = [0.05 0.01 0.005];
+%                 elseif length(struct_ids)>45
+%                     lambda = [0.05 0.02 0.01];
+%                 elseif length(struct_ids)>17
+%                     lambda = [0.1 0.05 0.02];
+%                 else
+%                     lambda = [0.15 0.07 0.03];
+%                 end
+
+                disp(' case 663')
+                if length(struct_ids)>45
+                    lambda = [0.05 0.01 0.005];
+                elseif length(struct_ids)>17
+                    lambda = [0.05 0.02 0.01];
+                else
+                    lambda = [0.1 0.05 0.02];
+                end
+
+%                 disp(' case 663')
+%                 if length(struct_ids)>55
+%                     lambda = [0.05 0.01 0.005];
+%                 elseif length(struct_ids)>35
+%                     lambda = [0.05 0.02 0.01];
+%                 else length(struct_ids)
+%                     lambda = [0.1 0.05 0.02];
+%                 end
+
+			else
+			    lambda=[1:-0.1:0.6];
+
+%                 if length(struct_ids)>40
+%                     lambda = [1:-0.2:0.6];
+%                 elseif length(struct_ids)>30
+%                     
+%                     lambda = [0.2 0.1 0.05]; %initial values - sheared difspots
+%                 elseif length(struct_ids)>15
+%                     lambda = [0.5 0.3 0.1]; %initial values
+%                     %lambda = [0.3 0.2 0.1]; %initial values - sheared difspots
+%                 else
+%                     lambda = [0.7 0.3 0.2]; %initial values
+%                     %lambda = [0.4 0.25 0.15]; %initial values - sheared difspots
+%                 end
+
+            end
+
+
+            
+            j=0;
+            
+
+
+           
+
+			if 0
+                %write out the extspot stack
+                for j=1:length(grain{i}.pairid)
+                    %write the spr/sdt projections
+                    name=sprintf('%s/extspot%d.sdt',graindir,j);
+                    fid=fopen(name,'wb','l');
+                    %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+                    fwrite(fid,extstack(:,:,j)','float32');
+                    fclose(fid);
+                    name=sprintf('%s/extspot%d.spr',graindir,j);
+                    spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+                end
+            end
+			
+			
+  
+
+            name=sprintf('%s/%s.mat',graindir,grainname);
+            save(name,'struct_ids','difstack','extstack','zstart','zend','z1','nz','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector','index','lambda');
+            grain_data=load(name);  
+
+
+            %add in the reconstruction part a la DoAll
+            if app.gt_select_projections_auto
+              try %may not get a licence
+                gt_select_projections_auto(i, 0);
+              catch
+                disp('no optimisation toolbox licence available')
+              end
+            end
+            
+            gtDoART3D(i,grain_data,parameters);
+
+        catch
+            s = lasterror
+            keyboard
+            disp('this grain failed for some reason')
+            %record which failed...
+            failed_grains=[failed_grains, i];
+        end
+
+    else
+        %condition term for ROI
+        disp('this grain skipped')
+    end
+
+end % of grain loop
+disp([x1 y1])
+
+end % of function
diff --git a/4_spot_sorting/gtINWriteGrainFolder_ak.m b/4_spot_sorting/gtINWriteGrainFolder_ak.m
new file mode 100755
index 0000000000000000000000000000000000000000..d938f87c7e8efbacf64207001be8ede7c43b969f
--- /dev/null
+++ b/4_spot_sorting/gtINWriteGrainFolder_ak.m
@@ -0,0 +1,447 @@
+% Writes grains data from indexing into 4_grain/grainx_ folders.
+% (like gtHandleSpot_360 would do)
+
+%version _ak  sorry...  get something running for the Mg data!
+%pass in parameter/value pairs
+%list : list of grains to do
+%ROI : to do only grainbs in a certain sub volume of the reconstructed
+%volume, eg after a rough reconstruction of all [xstart ystart zstart xsize
+%ysize zsize]
+%gt_select_projections_auto - can use this or not
+%do_forward_simulation - by default is on
+%update_db - update datebase with forward simulation results.
+
+% does forward simulate to pick up unpaired spots, skips this if R-vector
+% is NaN or Inf
+
+function [number_added, failed_grains] = gtINWriteGrainFolder_ak(grain,parameters, varargin)
+
+if ~exist('parameters','var')
+    load parameters.mat
+end
+if ~exist('grain','var')
+    load sort_grains_lastrun.mat
+end
+
+%get optional arguments passed in
+app.ROI = 'none';
+app.list=1:length(grain);
+app.gt_select_projections_auto=0;
+app.do_forward_simulation=1;
+app.update_db=1;
+
+app=parse_pv_pairs(app,varargin);
+
+
+gtDBConnect;
+
+; %while playing may not want to record anything
+
+acq=parameters.acq;
+number_added=[];
+failed_grains=[]; %any that are missed, for whatever reason
+
+%%%%%
+% Deal with issues surrounding keeping the database current
+%%%%%
+%if it doesn't already exist, we may need to add a grainid column to
+%difspot table
+[a,b,c,d,e,f]=mym(sprintf('show columns from %sdifspot like "grainID"',acq.name));
+if isempty(a)
+    %add the field
+    mym(sprintf('ALTER TABLE graintracking.%sdifspot ADD COLUMN grainID INT AFTER integral', acq.name));
+    disp('adding grainID field to the difspot table')
+end
+%even if the field already exists, we may need to update it
+a=mym(sprintf('select count(*) from %sdifspot where !isnull(grainid)', acq.name));
+b=mym(sprintf('select count(*) from %s where !isnull(grainid)', acq.pair_tablename));
+if a<(2*b)
+    %then need to update this field
+    [a,b,c]=mym(sprintf('select difAID, difBID, grainid from %s where !isnull(grainid)', acq.pair_tablename));
+    data=[a c; b c];
+    for i=1:length(data)
+        mym(dbUpdate(sprintf('%sdifspot', acq.name),'difspotID',data(i,1),'grainID',data(i,2)));
+        if mod(i, 1000)==0
+            disp(sprintf('updating difspot table grainIDs... done %0.1f percent', 100*i/length(data)))
+        end
+    end
+end
+%%%%%%
+
+
+for ndx=1:length(app.list)
+    i=app.list(ndx)
+
+    
+    %don't repeat grains if they have already been done
+    if ~exist(sprintf('4_grains/grain%d_', i), 'dir')
+    
+    %add a conditional term - if we want to do only those grains in a certain
+    %subvolume of the sample for example
+    %there, move calculation of reconstructed center outside this "if"
+
+    % Sample system coordinates of grain - reconstruction coordinates
+    grain{i}.xcenter= (acq.bb(3)/2)+grain{i}.center(2);
+    grain{i}.ycenter= (acq.bb(3)/2)+grain{i}.center(1);
+    grain{i}.zcenter= -grain{i}.center(3)+acq.ydet/2-acq.bb(2);
+    grainCentroid=[grain{i}.xcenter,grain{i}.ycenter,grain{i}.zcenter];
+
+    if strcmp(app.ROI, 'none') || (all(grainCentroid>app.ROI(1:3)) & all(grainCentroid<(app.ROI(1:3)+app.ROI(4:6)-1)))
+
+        try
+
+            disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
+            disp('')
+            disp('')
+            disp(sprintf('doing GRAIN %d',i))
+            disp('')
+            disp('')
+            disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
+
+
+            struct_ids=grain{i}.difspots;
+            grain{i}.struct_ids=struct_ids;
+            replace_flag=0;
+
+            %% transform vectors back to full length...
+            Omega=[grain{i}.omega, grain{i}.omega+180];  % need one for each difspot
+            Theta=[grain{i}.theta, grain{i}.theta];
+            Eta=[grain{i}.eta, mod(180-grain{i}.eta,360)];             %changed to 180-eta here...
+            hkl=[grain{i}.hkl;grain{i}.hkl];
+            plane_normal=[grain{i}.pl;-grain{i}.pl];
+            R_vector=grain{i}.R_vector;
+
+            % and update grain structure  (not very elegant.... change length of
+            % vectors in sort_grain
+            grain{i}.omega=Omega;
+            grain{i}.theta=Theta;
+            grain{i}.eta=Eta;
+            grain{i}.hkl=hkl;
+            grain{i}.pl=plane_normal;
+
+
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            %
+            % forward simulation here - search database for more difspots
+            %
+            % note - don't try this if R-vector is NaN! Or Inf!
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+            if app.do_forward_simulation
+                if ~isnan(grain{i}.R_vector(1)) & ~isinf(grain{i}.R_vector(1))
+
+                    [dummy,add_struct_ids]=gtForwardSimulate_360(grainCentroid, R_vector, struct_ids, parameters,0);     % add optional variable to accept unpaired difspots, too
+                    % note that the last zero is "test extspot" for forward simulate
+                    number_added(i)=length(add_struct_ids);
+
+                    ndx=length(struct_ids);
+                    [dummy,tt]=gtnew_calculate_twotheta;  % theoretical list of allowed reflections and TwoTHeta values
+
+                    struct_ids = [struct_ids add_struct_ids];
+                    grain{i}.struct_ids=struct_ids;
+
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                    % try to calculate in the missing information for the new forward
+                    % simulated spots, based on the measured spot positions and known grain position
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                    for j=1:length(add_struct_ids)
+                        [CentroidImage,CentroidX,CentroidY]=mym(sprintf('select CentroidImage, CentroidX, CentroidY from %sdifspot where difspotID=%d',acq.name,add_struct_ids(j)));
+
+                        Omega(ndx+j) = CentroidImage/(acq.nproj*2)*360;    % supposes 360 degree scans here
+                        [grainx,grainy,grainz]=gtTrSamToLab(grain{i}.center(1),grain{i}.center(2),grain{i}.center(3),Omega(ndx+j));
+
+                        % calculate the distances in pixels with respect to the laboratory system
+                        dx= acq.dist/acq.pixelsize-grainx;
+                        dy= CentroidX-acq.rotx-grainy;
+                        dz= acq.ydet/2-CentroidY-grainz;
+                        kh=[dx dy dz];
+                        kh=kh/norm(kh);  % normalized difracted beam direction
+                        k0=[1 0 0];      % normalized incoming beam direction
+                        G= (kh-k0)/norm(kh-k0);        % normalized Laboratory system scattering vector
+
+                        Eta(ndx+j)   = atan2(dy,dz)/pi*180;
+                        Theta(ndx+j) = atand(sqrt(dy.^2+dz.^2)/dx)/2;
+                        refl         = find(abs(tt.centre-Theta(ndx+j)*2)==min(abs(tt.centre-Theta(ndx+j)*2)));  % find out what type of reflection this Theta corresponds to
+                        hkl(ndx+j,:) = tt.reflections(refl,:);
+                        [pn(1),pn(2),pn(3)]= gtTrLabToSam(G(1),G(2),G(3),Omega(ndx+j)); % normalized plane_normal in sample coordinate system
+                        plane_normal(ndx+j,:) = pn;
+
+                        %query=sprintf(['select Yorigin,Yorigin+Ysize from %sbb inner join %sbboxes on bbID=bboxID where %sbb.extspotID=%d'],...
+                        % acq.name, acq.name, acq.name,add_struct_ids(j));
+                        %[zstart(ndx+j),zend(ndx+j)]=mym(query);
+                    end
+                    %add data to the grain structure, so it can be passed to other
+                    %functions
+
+                    grain{i}.omega=Omega;
+                    grain{i}.theta=Theta;
+                    grain{i}.eta=Eta;
+                    grain{i}.pl=plane_normal;
+                    grain{i}.hkl=hkl;
+
+                    %update database here to avoid grain rustling issues
+                    if app.update_db
+                        % Write in database: (EXTSPOTS)
+                        try % we may not have an extspot table!
+                            for j=1:length(add_struct_ids)
+                                %update grainID in extspot table
+                                mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',add_struct_ids(j),'GrainID',i);
+                                mym(mysqlcmd);
+                            end
+                        catch
+                            disp('no suitable extspot table found - no update of extspot table')
+                        end
+                        % Write in database: (DIFSPOTS)
+                        for j=1:length(add_struct_ids)
+                            %update grainID in difspot table
+                            mysqlcmd=dbUpdate(sprintf('%sdifspot',acq.name),'difspotID',add_struct_ids(j),'GrainID',i);
+                            mym(mysqlcmd);
+                        end
+                        for j=1:length(add_struct_ids)
+                            %update grainID in pair table - some of the
+                            %added difspots may belong to pairs - if they
+                            %do, then we should also get the pair spot.
+                            tmp=mym(sprintf('select grainid from Mg_fatigue1_difspot where difspotid=%d', add_struct_ids(j)));
+                            [pid, gid]=mym(sprintf('select pairid, grainid from %s where difaid=%d or difbid=%d',acq.pair_tablename, add_struct_ids(j), add_struct_ids(j)));
+                            if ~isempty(pid) & isnan(gid) %if there is a pair, we can update the grainid to this grain to stop it being considered again if doing 
+                              % more than one iteration of sort grains (eg opening the tolerances on building grains and starting again)
+                            mysqlcmd=dbUpdate(acq.pair_tablename,'pairID',pid,'GrainID',i);
+                            mym(mysqlcmd);
+                            end
+                        end
+                    end
+
+                else
+                    disp('R-vector is NaN - skipping forward simulation for this grain')
+                end
+            end % do_forward_simulation
+
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            %% build stack (including the new spots)  - and calculate  backprojection image
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+            plot_flag=0;
+
+
+            [difstack,omega_dif]=gtShearDifspots(grain{i});
+
+
+
+            tmp=sum(sum(difstack, 3), 2);
+            zstart=find(tmp, 1, 'first');
+            zend=find(tmp, 1, 'last');
+            %use all, at least to start with
+            index=ones(size(struct_ids));
+
+            if 0
+                [extstack,sino,z_pos,bb,index]=gtReadExtRoi_360(grain{i},parameters);
+                %need to get bb without bothereing to do the extstack
+                s=gtMakeGrain(sino, Omega, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+            else
+                %at least for the Mg data this is better
+
+                %calculate z position for sinogram
+                zsino=round(grain{i}.zcenter);
+                zsino=min(zsino, size(difstack,1));
+                zsino=max(zsino, 1);
+
+                difsino=squeeze(difstack(zsino,:,:));
+                s=gtMakeGrain(difsino, omega_dif, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+                if plot_flag
+                    pause(1);
+                    close all
+                end
+            end
+
+
+            if isempty(s)   %if MakeGrain fails to segment the grain...
+                %get average horizontal extent from the sinogram
+                grain_width=max(sum(difsino>0, 1));
+                x1=round(grain{i}.xcenter-grain_width/2);
+                y1=round(grain{i}.ycenter-grain_width/2);
+                xend=round(x1+grain_width);
+                yend=round(y1+grain_width);
+            else
+                x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+                y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+                xend = x1 + s.BoundingBox(3);
+                yend = y1 + s.BoundingBox(4);
+            end
+
+
+
+
+            % add 20% to bounding box for luck (x-y plane only for extspot recon)
+            dimx=xend-x1;
+            dimy=yend-y1;
+            x1 = round(x1 - (dimx/5));
+            if x1 < 1
+                x1 = 1;
+            end
+            y1 = round(y1 - (dimy/5));
+            if y1 <1
+                y1 = 1;
+            end
+            xend = round(xend + (dimx/5));
+            if xend > acq.bb(3)
+                xend = acq.bb(3);
+            end
+            yend = round(yend + (dimy/5));
+            if yend > acq.bb(3)
+                yend = acq.bb(3);
+            end
+
+            nx = xend-x1;
+            ny = yend-y1;
+            nz = zend-zstart;
+            xcenter=round(grain{i}.xcenter);
+            ycenter=round(grain{i}.ycenter);
+            zcenter=round(grain{i}.zcenter);
+
+
+            %select appropriate lambda values for ART
+            if (parameters.acq.spacegroup == 663) % ie snow case % modif sabine
+                disp(' case 663')
+%                 if length(struct_ids)>55
+%                     lambda = [0.05 0.01 0.005];
+%                 elseif length(struct_ids)>45
+%                     lambda = [0.05 0.02 0.01];
+%                 elseif length(struct_ids)>17
+%                     lambda = [0.1 0.05 0.02];
+%                 else
+%                     lambda = [0.15 0.07 0.03];
+%                 end
+
+                disp(' case 663')
+                if length(struct_ids)>45
+                    lambda = [0.05 0.01 0.005];
+                elseif length(struct_ids)>17
+                    lambda = [0.05 0.02 0.01];
+                else
+                    lambda = [0.1 0.05 0.02];
+                end
+
+%                 disp(' case 663')
+%                 if length(struct_ids)>55
+%                     lambda = [0.05 0.01 0.005];
+%                 elseif length(struct_ids)>35
+%                     lambda = [0.05 0.02 0.01];
+%                 else length(struct_ids)
+%                     lambda = [0.1 0.05 0.02];
+%                 end
+
+            else
+
+                if length(struct_ids)>40
+                    lambda = [0.1 0.05 0.02];
+                elseif length(struct_ids)>30
+                    % lambda = [0.3 0.2 0.1]; %initial values
+                    lambda = [0.2 0.1 0.05]; %initial values - sheared difspots
+                elseif length(struct_ids)>15
+                    lambda = [0.5 0.3 0.1]; %initial values
+                    %lambda = [0.3 0.2 0.1]; %initial values - sheared difspots
+                else
+                    lambda = [0.7 0.3 0.2]; %initial values
+                    %lambda = [0.4 0.25 0.15]; %initial values - sheared difspots
+                end
+
+            end
+
+
+            % Save mat file
+            grainname=sprintf('grain%d_',i);
+            graindir=sprintf('%s/4_grains/%s',acq.dir,grainname);
+            if ~exist(graindir,'dir')
+                mkdir(graindir);
+            end
+
+           
+            
+			if 0
+                %write out the extspot stack
+                for j=1:length(struct_ids)
+                    %write the spr/sdt projections
+                    name=sprintf('%s/%s%d.sdt',graindir,grainname,j);
+                    fid=fopen(name,'wb','l');
+                    %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+                    fwrite(fid,extstack(:,:,j)','float32');
+                    fclose(fid);
+                    name=sprintf('%s/%s%d.spr',graindir,grainname,j);
+                    spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+                end
+            end
+
+
+            %write the difspot stack
+            for k=1:length(struct_ids)
+                %write the spr/sdt projections
+                name=sprintf('%s/%s%d.sdt',graindir,grainname,k);
+				%sdt_write(name,difstack{k},'float32');
+                fid=fopen(name,'wb','l');
+                %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+                fwrite(fid,difstack(:,:,k)','float32');
+                fclose(fid);
+                name=sprintf('%s/%s%d.spr',graindir,grainname,k);
+                spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+            end
+
+            if 0
+                stack=cat(3,extstack,difstack);
+            else
+                stack=difstack;
+            end
+
+
+            % add the omega difspot values to the stack
+            if 0
+                Omega=[Omega,omega_dif];
+                index=[index,index];
+                %for current gtReconstruction manager, all vecors need to be the same
+                %length.  Thus duplicate information for the difstack
+                Theta=[Theta, Theta];
+                Eta=[Eta, Eta];
+                plane_normal=[plane_normal; plane_normal];
+                hkl=[hkl; hkl];
+                %temporary, to distinguish difstack and extstack
+                struct_ids=[struct_ids struct_ids+0.1];
+            else
+                Omega=omega_dif;
+            end
+
+            name=sprintf('%s/%s.mat',graindir,grainname);
+            save(name,'struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector','index','lambda');
+
+
+
+            %add in the reconstruction part a la DoAll
+            if app.gt_select_projections_auto
+              try %may not get a licence
+                gt_select_projections_auto(i, 0);
+              catch
+                disp('no optimisation toolbox licence available')
+              end
+            end
+            
+            gtDoART(i);
+
+        catch
+            s = lasterror
+            keyboard
+            disp('this grain failed for some reason')
+            %record which failed...
+            failed_grains=[failed_grains, i];
+        end
+
+    else
+        %condition term for ROI
+        disp('this grain skipped')
+    end
+    else
+        disp('this grain folder already written - skipping')
+    end
+end % of grain loop
+
+
+end % of function
diff --git a/4_spot_sorting/gtINWriteGrainFolder_condor.m b/4_spot_sorting/gtINWriteGrainFolder_condor.m
new file mode 100755
index 0000000000000000000000000000000000000000..e1f358f4669710d2eab7ed99f7e9c5ade9fec03b
--- /dev/null
+++ b/4_spot_sorting/gtINWriteGrainFolder_condor.m
@@ -0,0 +1,350 @@
+% Writes grains data from indexing into 4_grain/grainx_ folders.
+% (like gtHandleSpot_360 would do)
+
+%version _ak  sorry...  get something running for the Mg data!
+% need to use difspots only - extspots crap
+% pass in list of grains to do as an argument.
+% does forward simulate to pick up unpaired spots, skips this if R-vector
+% is NaN
+
+function [number_added, failed_grains] = gtINWriteGrainFolder_condor(first, last, workingdirectory)
+
+
+  if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end % special case for running interactively in current directory
+
+  cd(workingdirectory)
+
+  load parameters.mat
+
+  load sort_grains_lastrun.mat
+
+  
+gtDBConnect;
+
+do_forward_simulation=0;
+update_db=1; %while playing may not want to record anything
+
+acq=parameters.acq;
+number_added=[];
+failed_grains=[]; %any that are missed, for whatever reason
+
+%if it doesn't already exist, we may need to add a grainid column to
+%difspot table
+[a,b,c,d,e,f]=mym(sprintf('show columns from %sdifspot like "grainID"',acq.name));
+if isempty(a)
+  %add the field
+  mym(sprintf('ALTER TABLE graintracking.%sdifspot ADD COLUMN grainID INT AFTER integral', acq.name));
+  disp('adding grainID field to the difspot table')
+end
+
+for i=first:last
+  
+  
+  try
+
+  disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
+  disp('')
+  disp('')
+  disp(sprintf('doing GRAIN %d',i))
+  disp('')
+  disp('')
+  disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
+  
+  
+  struct_ids=grain{i}.difspots;
+  grain{i}.struct_ids=struct_ids;
+  replace_flag=0;
+
+  %% transform vectors back to full length...
+  Omega=[grain{i}.omega, grain{i}.omega+180];  % need one for each difspot
+  Theta=[grain{i}.theta, grain{i}.theta];
+  Eta=[grain{i}.eta, mod(grain{i}.eta+180,360)];             %
+  hkl=[grain{i}.hkl;grain{i}.hkl];
+  plane_normal=[grain{i}.pl;-grain{i}.pl];
+  R_vector=grain{i}.R_vector;
+
+  % and update grain structure  (not very elegant.... change length of
+  % vectors in sort_grain
+  grain{i}.omega=Omega;
+  grain{i}.theta=Theta;
+  grain{i}.eta=Eta;
+  grain{i}.hkl=hkl;
+  grain{i}.pl=plane_normal;
+
+
+  % Sample system coordinates of grain
+  grain{i}.xcenter= (acq.bb(3)/2)+grain{i}.center(2);
+  grain{i}.ycenter= (acq.bb(3)/2)+grain{i}.center(1);
+  grain{i}.zcenter= -grain{i}.center(3)+acq.ydet/2-acq.bb(2);
+  grainCentroid=[grain{i}.xcenter,grain{i}.ycenter,grain{i}.zcenter];
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %
+  % forward simulation here - search database for more difspots
+  %
+  % note - don't try this if R-vector is NaN! Or Inf!
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  if do_forward_simulation 
+    if ~isnan(grain{i}.R_vector(1)) & ~isinf(grain{i}.R_vector(1))
+      
+    [dummy,add_struct_ids]=gtForwardSimulate_360(grainCentroid, R_vector, struct_ids, parameters,0);     % add optional variable to accept unpaired difspots, too
+
+    number_added(i)=length(add_struct_ids);
+    
+    ndx=length(struct_ids);
+    [dummy,tt]=gtnew_calculate_twotheta;  % theoretical list of allowed reflections and TwoTHeta values
+
+    struct_ids = [struct_ids add_struct_ids];
+    grain{i}.struct_ids=struct_ids;
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % try to calculate in the missing information for the new forward
+    % simulated spots, based on the measured spot positions and known grain position
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    for j=1:length(add_struct_ids)
+      [CentroidImage,CentroidX,CentroidY]=mym(sprintf('select CentroidImage, CentroidX, CentroidY from %sdifspot where difspotID=%d',acq.name,add_struct_ids(j)));
+
+      Omega(ndx+j) = CentroidImage/(acq.nproj*2)*360;    % supposes 360 degree scans here
+      [grainx,grainy,grainz]=gtTrSamToLab(grain{i}.center(1),grain{i}.center(2),grain{i}.center(3),Omega(ndx+j));
+
+      % calculate the distances in pixels with respect to the laboratory system
+      dx= acq.dist/acq.pixelsize-grainx;
+      dy= CentroidX-acq.rotx-grainy;
+      dz= acq.ydet/2-CentroidY-grainz;
+      kh=[dx dy dz];
+      kh=kh/norm(kh);  % normalized difracted beam direction
+      k0=[1 0 0];      % normalized incoming beam direction
+      G= (kh-k0)/norm(kh-k0);        % normalized Laboratory system scattering vector
+
+      Eta(ndx+j)   = atan2(dy,dz)/pi*180;
+      Theta(ndx+j) = atand(sqrt(dy.^2+dz.^2)/dx)/2;
+      refl         = find(abs(tt.centre-Theta(ndx+j)*2)==min(abs(tt.centre-Theta(ndx+j)*2)));  % find out what type of reflection this Theta corresponds to
+      hkl(ndx+j,:) = tt.reflections(refl,:);
+      [pn(1),pn(2),pn(3)]= gtTrLabToSam(G(1),G(2),G(3),Omega(ndx+j)); % normalized plane_normal in sample coordinate system
+      plane_normal(ndx+j,:) = pn;
+
+      %query=sprintf(['select Yorigin,Yorigin+Ysize from %sbb inner join %sbboxes on bbID=bboxID where %sbb.extspotID=%d'],...
+      % acq.name, acq.name, acq.name,add_struct_ids(j));
+      %[zstart(ndx+j),zend(ndx+j)]=mym(query);
+    end
+    %add data to the grain structure, so it can be passed to other
+    %functions
+
+    grain{i}.omega=Omega;
+    grain{i}.theta=Theta;
+    grain{i}.eta=Eta;
+    grain{i}.pl=plane_normal;
+    grain{i}.hkl=hkl;
+    
+    else
+      disp('R-vector is NaN - skipping forward simulation for this grain')
+    end   
+  end % do_forward_simulation
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %% build stack (including the new spots)  - and calculate  backprojection image
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  plot_flag=0;
+
+
+  [difstack,omega_dif]=gtShearDifspots(grain{i});
+  
+ 
+  
+  tmp=sum(sum(difstack, 3), 2);
+  zstart=find(tmp, 1, 'first');
+  zend=find(tmp, 1, 'last');
+  %use all, at least to start with
+  index=ones(size(struct_ids));
+
+  if 0  
+    [extstack,sino,z_pos,bb,index]=gtReadExtRoi_360(grain{i},parameters);
+    %need to get bb without bothereing to do the extstack
+    s=gtMakeGrain(sino, Omega, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+  else
+    %at least for the Mg data this is better
+    
+    %calculate z position for sinogram
+    zsino=round(grain{i}.zcenter);
+    zsino=min(zsino, size(difstack,1));
+    zsino=max(zsino, 1);
+    
+    difsino=squeeze(difstack(zsino,:,:));
+    s=gtMakeGrain(difsino, omega_dif, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+    if plot_flag
+    pause(1);
+    close all
+    end
+  end
+
+ 
+  if isempty(s)   %if MakeGrain fails to segment the grain...
+    %get average horizontal extent from the sinogram
+    grain_width=max(sum(difsino>0, 1));
+    x1=round(grain{i}.xcenter-grain_width/2);
+    y1=round(grain{i}.ycenter-grain_width/2);
+    xend=round(x1+grain_width);
+    yend=round(y1+grain_width);
+  else
+    x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+    y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+    xend = x1 + s.BoundingBox(3);
+    yend = y1 + s.BoundingBox(4);
+  end
+
+
+
+
+  % add 20% to bounding box for luck (x-y plane only for extspot recon)
+  dimx=xend-x1;
+  dimy=yend-y1;
+  x1 = round(x1 - (dimx/5));
+  if x1 < 1
+    x1 = 1;
+  end
+  y1 = round(y1 - (dimy/5));
+  if y1 <1
+    y1 = 1;
+  end
+  xend = round(xend + (dimx/5));
+  if xend > acq.bb(3)
+    xend = acq.bb(3);
+  end
+  yend = round(yend + (dimy/5));
+  if yend > acq.bb(3)
+    yend = acq.bb(3);
+  end
+
+  nx = xend-x1;
+  ny = yend-y1;
+  nz = zend-zstart;
+  xcenter=round(grain{i}.xcenter);
+  ycenter=round(grain{i}.ycenter);
+  zcenter=round(grain{i}.zcenter);
+
+  
+  %select appropriate lambda values for ART
+  if length(struct_ids)>40
+      lambda = [0.1 0.05 0.02];
+  elseif length(struct_ids)>30
+      %lambda = [0.3 0.2 0.1]; %initial values
+      lambda = [0.2 0.1 0.05]; %initial values - sheared difspots
+  elseif length(struct_ids)>15
+      %lambda = [0.5 0.3 0.1]; %initial values
+      lambda = [0.3 0.2 0.1]; %initial values - sheared difspots
+  else
+      %lambda = [0.7 0.3 0.2]; %initial values
+      lambda = [0.4 0.25 0.15]; %initial values - sheared difspots
+  end
+  
+  if update_db
+  % Write in database: (EXTSPOTS)
+  try % we may not have an extspot table!
+    for j=1:length(struct_ids)
+      %update grainID in extspot table
+      mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',struct_ids(j),'GrainID',i);
+      mym(mysqlcmd);
+    end
+  catch
+    disp('no suitable extspot table found - no update of extspot table')
+  end
+
+  % Write in database: (DIFSPOTS)
+  for j=1:length(struct_ids)
+    %update grainID in difspot table
+    mysqlcmd=dbUpdate(sprintf('%sdifspot',acq.name),'difspotID',struct_ids(j),'GrainID',i);
+    mym(mysqlcmd);
+  end
+  end  
+  
+  
+  % Save mat file
+  grainname=sprintf('grain%d_',i);
+  graindir=sprintf('%s/4_grains/%s',acq.dir,grainname);
+  if ~exist(graindir,'dir')
+    mkdir(graindir);
+  end
+
+j=0;
+  if 0
+  %write out the extspot stack
+  for j=1:length(struct_ids)
+    %write the spr/sdt projections
+    name=sprintf('%s/%s%d.sdt',graindir,grainname,j);
+    fid=fopen(name,'wb','l');
+    %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+    fwrite(fid,extstack(:,:,j)','float32');
+    fclose(fid);
+    name=sprintf('%s/%s%d.spr',graindir,grainname,j);
+    spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+  end
+  end
+
+  
+  %write the difspot stack
+  for k=1:length(struct_ids)
+    %write the spr/sdt projections
+    name=sprintf('%s/%s%d.sdt',graindir,grainname,k+j);
+    fid=fopen(name,'wb','l');
+    %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+    fwrite(fid,difstack(:,:,k)','float32');
+    fclose(fid);
+    name=sprintf('%s/%s%d.spr',graindir,grainname,k+j);
+    spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+  end
+
+  if 0
+  stack=cat(3,extstack,difstack);
+  else
+    stack=difstack;
+  end
+  
+  
+  % add the omega difspot values to the stack
+  if 0
+  Omega=[Omega,omega_dif];
+  index=[index,index];
+  %for current gtReconstruction manager, all vecors need to be the same
+  %length.  Thus duplicate information for the difstack
+  Theta=[Theta, Theta];
+  Eta=[Eta, Eta];
+  plane_normal=[plane_normal; plane_normal];
+  hkl=[hkl; hkl];
+  %temporary, to distinguish difstack and extstack
+  struct_ids=[struct_ids struct_ids+0.1];
+  else
+    Omega=omega_dif;
+  end
+  
+  name=sprintf('%s/%s.mat',graindir,grainname);
+  save(name,'struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector','index','lambda');
+
+  
+ 
+  %add in the reconstruction part a la DoAll
+  
+  try %may not get a licence
+    gt_select_projections_auto(i, 0);
+  catch
+    disp('no optimisation toolbox licence available')
+  end
+  
+  gtDoART(i);
+  
+  catch
+    disp('this grain failed for some reason')
+    %record which failed...
+    failed_grains=[failed_grains, i];
+  end
+
+end % of grain loop
+
+
+end % of function
diff --git a/4_spot_sorting/gtINWriteGrainFolder_sab.m b/4_spot_sorting/gtINWriteGrainFolder_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..be6150a865e3e1b33010f3ec2e5376591d7c06cc
--- /dev/null
+++ b/4_spot_sorting/gtINWriteGrainFolder_sab.m
@@ -0,0 +1,421 @@
+% Writes grains data from indexing into 4_grain/grainx_ folders.
+% (like gtHandleSpot_360 would do)
+
+%version _ak  sorry...  get something running for the Mg data!
+% need to use difspots only - extspots crap
+% pass in list of grains to do as an argument.
+% does forward simulate to pick up unpaired spots, skips this if R-vector
+% is NaN or Inf
+
+function [number_added, failed_grains] = gtINWriteGrainFolder_sab(grain,parameters, list)
+
+if ~exist('parameters','var')
+    load parameters.mat
+end
+if ~exist('grain','var')
+    load sort_grains_lastrun.mat
+end
+if ~exist('list','var')
+    list=1:length(grain);
+end
+
+gtDBConnect;
+
+do_forward_simulation=1;
+update_db=1; %while playing may not want to record anything
+
+acq=parameters.acq;
+number_added=[];
+failed_grains=[]; %any that are missed, for whatever reason
+
+%%%%%
+% Deal with issues surrounding keeping the database current
+%%%%%
+%if it doesn't already exist, we may need to add a grainid column to
+%difspot table
+[a,b,c,d,e,f]=mym(sprintf('show columns from %sdifspot like "grainID"',acq.name));
+if isempty(a)
+    %add the field
+    mym(sprintf('ALTER TABLE graintracking.%sdifspot ADD COLUMN grainID INT AFTER integral', acq.name));
+    disp('adding grainID field to the difspot table')
+end
+%even if the field already exists, we may need to update it
+a=mym(sprintf('select count(*) from %sdifspot where !isnull(grainid)', acq.name));
+b=mym(sprintf('select count(*) from %s where !isnull(grainid)', acq.pair_tablename));
+if a<(2*b)
+    %then need to update this field
+    [a,b,c]=mym(sprintf('select difAID, difBID, grainid from %s where !isnull(grainid)', acq.pair_tablename));
+    data=[a c; b c];
+    for i=1:length(data)
+        mym(dbUpdate(sprintf('%sdifspot', acq.name),'difspotID',data(i,1),'grainID',data(i,2)));
+        if mod(i, 1000)==0
+            disp(sprintf('updating difspot table grainIDs... done %d percent', 100*i/length(data)))
+        end
+    end
+end
+%%%%%%
+
+%define ROI for conditional term
+%from the calculation made in Mg_fatigue_tools
+%ROI=[xstart ystart zstart xend yend zend]
+ROI=[74 382 64 300 626 144]-20;%-20 for the border
+ROI = [1 parameters.acq.bb(3) 1 parameters.acq.bb(3) 1 parameters.acq.bb(4)]
+
+for ndx=1:length(list)
+    i=list(ndx)
+
+    %add a conditional term - if we want to do only those grains in a certain
+    %subvolume of the sample for example
+    %there, move calculation of reconstructed center outside this "if"
+
+    % Sample system coordinates of grain - reconstruction coordinates
+    grain{i}.xcenter= (acq.bb(3)/2)+grain{i}.center(2);
+    grain{i}.ycenter= (acq.bb(3)/2)+grain{i}.center(1);
+    grain{i}.zcenter= -grain{i}.center(3)+acq.ydet/2-acq.bb(2);
+    grainCentroid=[grain{i}.xcenter,grain{i}.ycenter,grain{i}.zcenter];
+
+    %if all(grainCentroid>ROI(1:3)) & all(grainCentroid<ROI(4:6))
+
+        try
+
+            disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
+            disp('')
+            disp('')
+            disp(sprintf('doing GRAIN %d',i))
+            disp('')
+            disp('')
+            disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
+
+
+            struct_ids=grain{i}.difspots;
+            grain{i}.struct_ids=struct_ids;
+            replace_flag=0;
+
+            %% transform vectors back to full length...
+            Omega=[grain{i}.omega, grain{i}.omega+180];  % need one for each difspot
+            Theta=[grain{i}.theta, grain{i}.theta];
+            Eta=[grain{i}.eta, mod(grain{i}.eta+180,360)];             %
+            hkl=[grain{i}.hkl;grain{i}.hkl];
+            plane_normal=[grain{i}.pl;-grain{i}.pl];
+            R_vector=grain{i}.R_vector;
+
+            % and update grain structure  (not very elegant.... change length of
+            % vectors in sort_grain
+            grain{i}.omega=Omega;
+            grain{i}.theta=Theta;
+            grain{i}.eta=Eta;
+            grain{i}.hkl=hkl;
+            grain{i}.pl=plane_normal;
+
+
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            %
+            % forward simulation here - search database for more difspots
+            %
+            % note - don't try this if R-vector is NaN! Or Inf!
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+            if do_forward_simulation
+                if ~isnan(grain{i}.R_vector(1)) & ~isinf(grain{i}.R_vector(1))
+
+                    [dummy,add_struct_ids]=gtForwardSimulate_360(grainCentroid, R_vector, struct_ids, parameters,0);     % add optional variable to accept unpaired difspots, too
+
+                    number_added(i)=length(add_struct_ids);
+
+                    ndx=length(struct_ids);
+                    [dummy,tt]=gtnew_calculate_twotheta;  % theoretical list of allowed reflections and TwoTHeta values
+
+                    struct_ids = [struct_ids add_struct_ids];
+                    grain{i}.struct_ids=struct_ids;
+
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                    % try to calculate in the missing information for the new forward
+                    % simulated spots, based on the measured spot positions and known grain position
+                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                    for j=1:length(add_struct_ids)
+                        [CentroidImage,CentroidX,CentroidY]=mym(sprintf('select CentroidImage, CentroidX, CentroidY from %sdifspot where difspotID=%d',acq.name,add_struct_ids(j)));
+
+                        Omega(ndx+j) = CentroidImage/(acq.nproj*2)*360;    % supposes 360 degree scans here
+                        [grainx,grainy,grainz]=gtTrSamToLab(grain{i}.center(1),grain{i}.center(2),grain{i}.center(3),Omega(ndx+j));
+
+                        % calculate the distances in pixels with respect to the laboratory system
+                        dx= acq.dist/acq.pixelsize-grainx;
+                        dy= CentroidX-acq.rotx-grainy;
+                        dz= acq.ydet/2-CentroidY-grainz;
+                        kh=[dx dy dz];
+                        kh=kh/norm(kh);  % normalized difracted beam direction
+                        k0=[1 0 0];      % normalized incoming beam direction
+                        G= (kh-k0)/norm(kh-k0);        % normalized Laboratory system scattering vector
+
+                        Eta(ndx+j)   = atan2(dy,dz)/pi*180;
+                        Theta(ndx+j) = atand(sqrt(dy.^2+dz.^2)/dx)/2;
+                        refl         = find(abs(tt.centre-Theta(ndx+j)*2)==min(abs(tt.centre-Theta(ndx+j)*2)));  % find out what type of reflection this Theta corresponds to
+                        hkl(ndx+j,:) = tt.reflections(refl,:);
+                        [pn(1),pn(2),pn(3)]= gtTrLabToSam(G(1),G(2),G(3),Omega(ndx+j)); % normalized plane_normal in sample coordinate system
+                        plane_normal(ndx+j,:) = pn;
+
+                        %query=sprintf(['select Yorigin,Yorigin+Ysize from %sbb inner join %sbboxes on bbID=bboxID where %sbb.extspotID=%d'],...
+                        % acq.name, acq.name, acq.name,add_struct_ids(j));
+                        %[zstart(ndx+j),zend(ndx+j)]=mym(query);
+                    end
+                    %add data to the grain structure, so it can be passed to other
+                    %functions
+
+                    grain{i}.omega=Omega;
+                    grain{i}.theta=Theta;
+                    grain{i}.eta=Eta;
+                    grain{i}.pl=plane_normal;
+                    grain{i}.hkl=hkl;
+
+                    %update database here to avoid grain rustling issues
+                    if update_db
+                        % Write in database: (EXTSPOTS)
+                        try % we may not have an extspot table!
+                            for j=1:length(add_struct_ids)
+                                %update grainID in extspot table
+                                mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',add_struct_ids(j),'GrainID',i);
+                                mym(mysqlcmd);
+                            end
+                        catch
+                            disp('no suitable extspot table found - no update of extspot table')
+                        end
+                        % Write in database: (DIFSPOTS)
+                        for j=1:length(add_struct_ids)
+                            %update grainID in difspot table
+                            mysqlcmd=dbUpdate(sprintf('%sdifspot',acq.name),'difspotID',add_struct_ids(j),'GrainID',i);
+                            mym(mysqlcmd);
+                        end
+                    end
+                   % keyboard
+
+                else
+                    disp('R-vector is NaN - skipping forward simulation for this grain')
+                end
+            end % do_forward_simulation
+
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            %% build stack (including the new spots)  - and calculate  backprojection image
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+            plot_flag=0;
+
+
+            [difstack,omega_dif]=gtShearDifspots(grain{i});
+
+
+
+            tmp=sum(sum(difstack, 3), 2);
+            zstart=find(tmp, 1, 'first');
+            zend=find(tmp, 1, 'last');
+            %use all, at least to start with
+            index=ones(size(struct_ids));
+
+            if 0
+                [extstack,sino,z_pos,bb,index]=gtReadExtRoi_360(grain{i},parameters);
+                %need to get bb without bothereing to do the extstack
+                s=gtMakeGrain(sino, Omega, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+            else
+                %at least for the Mg data this is better
+
+                %calculate z position for sinogram
+                zsino=round(grain{i}.zcenter);
+                zsino=min(zsino, size(difstack,1));
+                zsino=max(zsino, 1);
+
+                difsino=squeeze(difstack(zsino,:,:));
+                s=gtMakeGrain(difsino, omega_dif, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+                if plot_flag
+                    pause(1);
+                    close all
+                end
+            end
+
+
+            if isempty(s)   %if MakeGrain fails to segment the grain...
+                %get average horizontal extent from the sinogram
+                grain_width=max(sum(difsino>0, 1));
+                x1=round(grain{i}.xcenter-grain_width/2);
+                y1=round(grain{i}.ycenter-grain_width/2);
+                xend=round(x1+grain_width);
+                yend=round(y1+grain_width);
+            else
+                x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+                y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+                xend = x1 + s.BoundingBox(3);
+                yend = y1 + s.BoundingBox(4);
+            end
+
+
+
+
+            % add 20% to bounding box for luck (x-y plane only for extspot recon)
+            dimx=xend-x1;
+            dimy=yend-y1;
+            x1 = round(x1 - (dimx/5));
+            if x1 < 1
+                x1 = 1;
+            end
+            y1 = round(y1 - (dimy/5));
+            if y1 <1
+                y1 = 1;
+            end
+            xend = round(xend + (dimx/5));
+            if xend > acq.bb(3)
+                xend = acq.bb(3);
+            end
+            yend = round(yend + (dimy/5));
+            if yend > acq.bb(3)
+                yend = acq.bb(3);
+            end
+
+            nx = xend-x1;
+            ny = yend-y1;
+            nz = zend-zstart;
+            xcenter=round(grain{i}.xcenter);
+            ycenter=round(grain{i}.ycenter);
+            zcenter=round(grain{i}.zcenter);
+
+
+            %select appropriate lambda values for ART
+            if (parameters.acq.spacegroup == 663) % ie snow case % modif sabine
+                disp(' case 663')
+                if length(struct_ids)>55
+                    lambda = [0.05 0.01 0.005];
+                elseif length(struct_ids)>45
+                    lambda = [0.05 0.02 0.01];
+                elseif length(struct_ids)>17
+                    lambda = [0.1 0.05 0.02];
+                else
+                    lambda = [0.15 0.07 0.03];
+                end
+
+            else
+
+                if length(struct_ids)>40
+                    lambda = [0.1 0.05 0.02];
+                elseif length(struct_ids)>30
+                    % lambda = [0.3 0.2 0.1]; %initial values
+                    lambda = [0.2 0.1 0.05]; %initial values - sheared difspots
+                elseif length(struct_ids)>15
+                    lambda = [0.5 0.3 0.1]; %initial values
+                    %lambda = [0.3 0.2 0.1]; %initial values - sheared difspots
+                else
+                    lambda = [0.7 0.3 0.2]; %initial values
+                    %lambda = [0.4 0.25 0.15]; %initial values - sheared difspots
+                end
+
+            end
+
+            %moved to just after forward simulation
+            %   if update_db
+            %   % Write in database: (EXTSPOTS)
+            %   try % we may not have an extspot table!
+            %     for j=1:length(struct_ids)
+            %       %update grainID in extspot table
+            %       mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',struct_ids(j),'GrainID',i);
+            %       mym(mysqlcmd);
+            %     end
+            %   catch
+            %     disp('no suitable extspot table found - no update of extspot table')
+            %   end
+            %
+            %   % Write in database: (DIFSPOTS)
+            %   for j=1:length(struct_ids)
+            %     %update grainID in difspot table
+            %     mysqlcmd=dbUpdate(sprintf('%sdifspot',acq.name),'difspotID',struct_ids(j),'GrainID',i);
+            %     mym(mysqlcmd);
+            %   end
+            %   end
+
+
+            % Save mat file
+            grainname=sprintf('grain%d_',i);
+            graindir=sprintf('%s/4_grains/%s',acq.dir,grainname);
+            if ~exist(graindir,'dir')
+                mkdir(graindir);
+            end
+
+            j=0;
+            if 0
+                %write out the extspot stack
+                for j=1:length(struct_ids)
+                    %write the spr/sdt projections
+                    name=sprintf('%s/%s%d.sdt',graindir,grainname,j);
+                    fid=fopen(name,'wb','l');
+                    %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+                    fwrite(fid,extstack(:,:,j)','float32');
+                    fclose(fid);
+                    name=sprintf('%s/%s%d.spr',graindir,grainname,j);
+                    spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+                end
+            end
+
+
+            %write the difspot stack
+            for k=1:length(struct_ids)
+                %write the spr/sdt projections
+                name=sprintf('%s/%s%d.sdt',graindir,grainname,k+j);
+                fid=fopen(name,'wb','l');
+                %stack(:,:,i)=medfilt2(stack(:,:,i));
+
+                fwrite(fid,difstack(:,:,k)','float32');
+                fclose(fid);
+                name=sprintf('%s/%s%d.spr',graindir,grainname,k+j);
+                spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+            end
+
+            if 0
+                stack=cat(3,extstack,difstack);
+            else
+                stack=difstack;
+            end
+
+
+            % add the omega difspot values to the stack
+            if 0
+                Omega=[Omega,omega_dif];
+                index=[index,index];
+                %for current gtReconstruction manager, all vecors need to be the same
+                %length.  Thus duplicate information for the difstack
+                Theta=[Theta, Theta];
+                Eta=[Eta, Eta];
+                plane_normal=[plane_normal; plane_normal];
+                hkl=[hkl; hkl];
+                %temporary, to distinguish difstack and extstack
+                struct_ids=[struct_ids struct_ids+0.1];
+            else
+                Omega=omega_dif;
+            end
+
+            name=sprintf('%s/%s.mat',graindir,grainname);
+            save(name,'struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector','index','lambda');
+
+
+
+            %add in the reconstruction part a la DoAll
+
+            try %may not get a licence
+                gt_select_projections_auto(i, 0);
+            catch
+                disp('no optimisation toolbox licence available')
+            end
+
+            gtDoART(i);
+
+        catch
+            s = lasterror
+            disp('this grain failed for some reason')
+            %record which failed...
+            failed_grains=[failed_grains, i];
+        end
+
+    %else
+        %condition term for ROI
+        disp('this grain skipped')
+    %end
+
+end % of grain loop
+
+
+end % of function
diff --git a/4_spot_sorting/gtINWriteGrainFolder_wl.m b/4_spot_sorting/gtINWriteGrainFolder_wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..10ee1cffe925da630a2848b9c00e91b3d8ed856c
--- /dev/null
+++ b/4_spot_sorting/gtINWriteGrainFolder_wl.m
@@ -0,0 +1,152 @@
+% Writes grains data from indexing into 4_grain/grainx_ folders.
+% (like gtHandleSpot_360 would do)
+
+
+function gr=gtINWriteGrainFoldernew(grain,parameters)
+
+if ~exist('parameters','var')
+  load parameters.mat
+end  
+if ~exist('grain','var')
+  load sort_grains_lastrun.mat
+end
+
+do_forward_simulation=0;
+simulation=0;
+
+acq=parameters.acq;
+
+
+
+
+for i=22%:length(grain)
+  
+ struct_ids=grain{i}.difspots;
+ num_pairs=length(grain{i}.pairid);
+ grain{i}.struct_ids=struct_ids;
+ grain{i}.omega=[grain{i}.omega,grain{i}.omega+180];
+ replace_flag=0;
+  
+ 
+ gr=grain{i};
+ omega=grain{i}.omega;
+ eta=grain{i}.eta;
+ theta=grain{i}.theta;
+ 
+ 
+ 
+ 
+ [x,y,z]=gtTrLabToSamBB(grain{i}.center(1),grain{i}.center(2),grain{i}.center(3),parameters);
+  
+ plot_flag=1;
+ 
+ index=[1:num_pairs];
+ 
+ 
+ [extstack,sino,z_pos,bb,index]=gtReadExtRoi_360wl(grain{i},parameters); 
+   
+ [difstack,difstackbw]=gtWriteDifStack(i,grain,parameters);
+   
+ [shearstack,gr]=gtShearDifspots_wl2(grain,i,parameters,[1:num_pairs]);
+   
+ %keyboard
+   
+   
+   
+%   %s=gtMakeGrain(sino, grain{i}.omega, x, y, plot_flag);
+%    if isempty(s)   %if MakeGrain fails to segment the grain...
+%    	  x1=round(grain{i}.xcenter-bb(3)/2);
+% 	  y1=round(grain{i}.ycenter-bb(3)/2);
+% 	  xend=round(x1+bb(3));
+% 	  yend=round(y1+bb(3));
+%    else
+%       x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+%       y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+%       xend = x1 + s.BoundingBox(3);
+%       yend = y1 + s.BoundingBox(4);
+%    end
+% 
+    zstart=bb(1,2);
+    zend=bb(1,2)+bb(1,4);
+%   
+% 
+%  
+%   % add 20% to bounding box for luck (x-y plane only for extspot recon)
+%   x1 = round(x1 - (s.BoundingBox(3)/5));
+%   if x1 < 1
+%     x1 = 1;
+%   end
+%   y1 = round(y1 - (s.BoundingBox(4)/5));
+%   if y1 <1
+%     y1 = 1;
+%   end
+%   xend = round(xend + (s.BoundingBox(3)/5));
+%   if xend > acq.bb(3)
+%     xend = acq.bb(3);
+%   end
+%   yend = round(yend + (s.BoundingBox(4)/5));
+%   if yend > acq.bb(3)
+%     yend = acq.bb(3);
+%   end
+% 
+%   nx = xend-x1;
+%   ny = yend-y1;
+%   nz = zend-zstart;
+ % xcenter=round(grain{i}.xcenter);
+ % ycenter=round(grain{i}.ycenter);
+ % zcenter=round(grain{i}.zcenter);
+  
+  % Write in database:
+       for j=1:length(struct_ids)
+         %update grainID in extspot table
+   			mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',struct_ids(j),'GrainID',i);
+         mym(mysqlcmd);
+	   end 
+  % 	  %update grainID in bb table (!)      
+  %       mysqlcmd=dbUpdate(sprintf('%sbb',acq.name),'extspotID',struct_ids(i),'grainID',grainid);
+  %       mym(mysqlcmd);
+  %     end
+
+  % Save mat file
+  grainname=sprintf('grain%d_',i);
+  graindir=sprintf('%s/4_grains/%s',acq.dir,grainname);
+  if ~exist(graindir,'dir')
+    mkdir(graindir);
+  end
+  
+  
+%   for j=1:length(struct_ids)  
+%     %write the spr/sdt projections
+%     name=sprintf('%s/%s%d.sdt',graindir,grainname,j);
+% 	fid=fopen(name,'wb','l');
+%     %stack(:,:,i)=medfilt2(stack(:,:,i));
+%   
+% 	fwrite(fid,extstack(:,:,j)','float32');
+% 	fclose(fid);
+% 	name=sprintf('%s/%s%d.spr',graindir,grainname,j);
+%     spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+%   end	
+  
+% now write out the summed and flipped extstack images
+
+ for j=1:num_pairs  
+    %write the spr/sdt projections for the FLIPPED extinction spots
+    name=sprintf('%s/extspot%d',graindir,j);
+	fid=fopen(name,'wb','l');
+    stack(:,:,j)=wiener2(fliplr(extstack(:,:,j)))+wiener2(extstack(:,:,j+num_pairs),[10 10]);
+	stack(:,:,j)=1000*stack(:,:,j)/sum(sum(stack(:,:,j)));
+    sdt_write(name,stack(:,:,j),'float32');	
+ end
+
+ extstack=stack;
+ 
+ omegashear=gr.omegashear;
+ phi=gr.phi;
+ name=sprintf('%s/%s.mat',graindir,grainname);
+ save(name,'struct_ids','extstack','difstack','shearstack','difstackbw','omega','omegashear','phi','theta', 'eta','index');
+
+  
+end % of grain loop
+
+
+end % of function
diff --git a/4_spot_sorting/gtINWriteGrainFoldernew.m b/4_spot_sorting/gtINWriteGrainFoldernew.m
new file mode 100755
index 0000000000000000000000000000000000000000..98901b7577f732454b7571e8a53458b125ca1e35
--- /dev/null
+++ b/4_spot_sorting/gtINWriteGrainFoldernew.m
@@ -0,0 +1,206 @@
+% Writes grains data from indexing into 4_grain/grainx_ folders.
+% (like gtHandleSpot_360 would do)
+
+
+function grain=gtINWriteGrainFoldernew(grain,parameters)
+
+if ~exist('parameters','var')
+  load parameters.mat
+end  
+if ~exist('grain','var')
+  load sort_grains_lastrun.mat
+end
+
+do_forward_simulation=0;
+
+acq=parameters.acq;
+
+
+for i=2%:length(grain)
+  
+  struct_ids=grain{i}.difspots;
+  num_pairs=length(grain{i}.pairid);
+  grain{i}.struct_ids=struct_ids;
+  replace_flag=0;
+  
+  %% transform vectors back to full length...
+  
+  Omega=[grain{i}.omega,grain{i}.omega+180];  % need one for each difspot - we look only at the first half of the scan
+  Theta=[grain{i}.theta,grain{i}.theta];
+  Eta=[grain{i}.eta,mod(grain{i}.eta+180,360)];             % 
+  hkl=[grain{i}.hkl;grain{i}.hkl];
+  plane_normal=[grain{i}.pl;-grain{i}.pl];
+  R_vector=grain{i}.R_vector;
+  
+  % and update grain structure  (not very elegant.... change length of
+  % vectors in sort_grain
+  grain{i}.omega=Omega;
+  grain{i}.theta=Theta;
+  grain{i}.eta=Eta;
+  grain{i}.hkl=hkl;
+  grain{i}.pl=plane_normal;
+ 
+  
+  % Sample system coordinates of grain
+  grain{i}.xcenter= (acq.bb(3)/2)+grain{i}.center(2);           
+  grain{i}.ycenter= (acq.bb(3)/2)+grain{i}.center(1);
+  grain{i}.zcenter= -grain{i}.center(3)+acq.ydet/2-acq.bb(2);
+  grainCentroid=[grain{i}.xcenter,grain{i}.ycenter,grain{i}.zcenter];
+
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   % forward simulation here - search database for more difspots 
+   % 
+   % still to be done: 
+   % 
+   % - search for extinction spots from higher order reflections which do not have difspots
+   %
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   
+   if do_forward_simulation
+   
+   [dummy,add_struct_ids]=gtForwardSimulate_360(grainCentroid, R_vector, struct_ids, parameters,0);     % add optional variable to accept unpaired difspots, too
+  
+   ndx=length(struct_ids);
+   [dummy,tt]=gtnew_calculate_twotheta;  % theoretical list of allowed reflections and TwoTHeta values
+   
+   struct_ids = [struct_ids add_struct_ids];
+   grain{i}.struct_ids=struct_ids;
+   
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   % try to calculate in the missing information for the new forward
+   % simulated spots, based on the measured spot positions and known grain position
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   for j=1:length(add_struct_ids)
+	 [CentroidImage,CentroidX,CentroidY]=mym(sprintf('select CentroidImage, CentroidX, CentroidY from %sdifspot where difspotID=%d',acq.name,add_struct_ids(j)));
+	
+	 Omega(ndx+j) = CentroidImage/(acq.nproj*2)*360;    % supposes 360 degree scans here
+     [grainx,grainy,grainz]=gtTrSamToLab(grain{i}.center(1),grain{i}.center(2),grain{i}.center(3),Omega(ndx+j));
+	 
+	 % calculate the distances in pixels with respect to the laboratory system 
+	 dx= acq.dist/acq.pixelsize-grainx; 
+	 dy= CentroidX-acq.rotx-grainy;
+	 dz= acq.ydet/2-CentroidY-grainz;
+	 kh=[dx dy dz];
+	 kh=kh/norm(kh);  % normalized difracted beam direction
+	 k0=[1 0 0];      % normalized incoming beam direction
+	 G= (kh-k0)/norm(kh-k0);        % normalized Laboratory system scattering vector
+	 
+	 Eta(ndx+j)   = atan2(dy,dz)/pi*180;        
+     Theta(ndx+j) = atand(sqrt(dy.^2+dz.^2)/dx)/2;
+     refl         = find(abs(tt.centre-Theta(ndx+j)*2)==min(abs(tt.centre-Theta(ndx+j)*2)));  % find out what type of reflection this Theta corresponds to
+	 hkl(ndx+j,:) = tt.reflections(refl,:);  
+	 [pn(1),pn(2),pn(3)]= gtTrLabToSam(G(1),G(2),G(3),Omega(ndx+j)); % normalized plane_normal in sample coordinate system
+	 plane_normal(ndx+j,:) = pn; 
+	 
+	 %query=sprintf(['select Yorigin,Yorigin+Ysize from %sbb inner join %sbboxes on bbID=bboxID where %sbb.extspotID=%d'],...
+     % acq.name, acq.name, acq.name,add_struct_ids(j));
+     %[zstart(ndx+j),zend(ndx+j)]=mym(query);
+   end	 
+   grain{i}.omega=Omega;
+   
+   end % do_forward_simulation
+	
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   %% build stack (including the new spots)  - and calculate  backprojection image 
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    
+   plot_flag=1;
+   
+   [extstack,sino,z_pos,bb,index]=gtReadExtRoi_360(grain{i},parameters); 
+   %[difstack,omega_dif]=gtShearDifspots(grain{i});
+   [dif,difbw]=gtWriteDifStack(i,grain,parameters);
+   
+   
+   s=gtMakeGrain(sino, Omega, grain{i}.xcenter, grain{i}.ycenter, plot_flag);
+  
+   if isempty(s)   %if MakeGrain fails to segment the grain...
+   	 x1=round(grain{i}.xcenter-bb(3)/2);
+	 y1=round(grain{i}.ycenter-bb(3)/2);
+	 xend=round(x1+bb(3));
+	 yend=round(y1+bb(3));
+   else
+      x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+      y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+      xend = x1 + s.BoundingBox(3);
+      yend = y1 + s.BoundingBox(4);
+   end
+
+   zstart=bb(1,2);
+   zend=bb(1,2)+bb(1,4);
+  
+
+ 
+  % add 20% to bounding box for luck (x-y plane only for extspot recon)
+  x1 = round(x1 - (s.BoundingBox(3)/5));
+  if x1 < 1
+    x1 = 1;
+  end
+  y1 = round(y1 - (s.BoundingBox(4)/5));
+  if y1 <1
+    y1 = 1;
+  end
+  xend = round(xend + (s.BoundingBox(3)/5));
+  if xend > acq.bb(3)
+    xend = acq.bb(3);
+  end
+  yend = round(yend + (s.BoundingBox(4)/5));
+  if yend > acq.bb(3)
+    yend = acq.bb(3);
+  end
+
+  nx = xend-x1;
+  ny = yend-y1;
+  nz = zend-zstart;
+  xcenter=round(grain{i}.xcenter);
+  ycenter=round(grain{i}.ycenter);
+  zcenter=round(grain{i}.zcenter);
+  
+  % Write in database:
+       for j=1:length(struct_ids)
+         %update grainID in extspot table
+   			mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',struct_ids(j),'GrainID',i);
+         mym(mysqlcmd);
+	   end 
+  % 	  %update grainID in bb table (!)      
+  %       mysqlcmd=dbUpdate(sprintf('%sbb',acq.name),'extspotID',struct_ids(i),'grainID',grainid);
+  %       mym(mysqlcmd);
+  %     end
+
+  % Save mat file
+  grainname=sprintf('grain%d_',i);
+  graindir=sprintf('%s/4_grains/%s',acq.dir,grainname);
+  if ~exist(graindir,'dir')
+    mkdir(graindir);
+  end
+  
+  
+%   for j=1:length(struct_ids)  
+%     %write the spr/sdt projections
+%     name=sprintf('%s/%s%d.sdt',graindir,grainname,j);
+% 	fid=fopen(name,'wb','l');
+%     %stack(:,:,i)=medfilt2(stack(:,:,i));
+%   
+% 	fwrite(fid,extstack(:,:,j)','float32');
+% 	fclose(fid);
+% 	name=sprintf('%s/%s%d.spr',graindir,grainname,j);
+%     spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+%   end	
+  
+ for j=1:num_pairs  
+    %write the spr/sdt projections for the extinction spots
+    name=sprintf('%s/%s%d',graindir,grainname,j+num_pairs);
+	fid=fopen(name,'wb','l');
+    stack(:,:,j)=wiener2(fliplr(extstack(:,:,j)))+wiener2(extstack(:,:,j+num_pairs),[10 10]);
+	stack(:,:,j)=1000*stack(:,:,j)/sum(sum(stack(:,:,j)));
+    sdt_write(name,stack(:,:,j),'float32');	
+ end	
+ 
+  
+ name=sprintf('%s/%s.mat',graindir,grainname);
+ save(name,'struct_ids','extstack','stack','dif','difbw','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector','index');
+
+  
+end % of grain loop
+
+
+end % of function
diff --git a/4_spot_sorting/gtINWriteGrainFolderold.m b/4_spot_sorting/gtINWriteGrainFolderold.m
new file mode 100755
index 0000000000000000000000000000000000000000..53d7471101f2264b3005173b8f6f752bb122913f
--- /dev/null
+++ b/4_spot_sorting/gtINWriteGrainFolderold.m
@@ -0,0 +1,182 @@
+% Writes grains data from indexing into 4_grain folder.
+% (like gtHandleSpot_360 would do)
+% still falls over when no extspot data available for a given pair - fix
+% this...!
+
+function gtINWriteGrainFolder(grain,parameters)
+
+if ~exist('parameters','var')
+  load parameters.mat;
+end  
+
+acq=parameters.acq;
+
+
+for i=30%:length(grain)
+  
+  struct_ids=grain{i}.difspots;
+
+  replace_flag=0;
+  
+  %% Come back from pair logic to single spot logic...
+  
+  Omega=[grain{i}.omega,grain{i}.omega+180];     % need one Omega for each difspot
+  Theta=[grain{i}.theta,grain{i}.theta];         % same theta value 
+  Eta=[grain{i}.eta,mod(grain{i}.eta+180,360)];  % map eta values into 0 360 degrees   
+  hkl=[grain{i}.hkl;grain{i}.hkl];               % hkl type is copied 
+  plane_normal=[grain{i}.pl;-grain{i}.pl];       % negative normals for the paired spot
+  R_vector=grain{i}.R_vector;                    
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %collect data for .mat file, pad bounding boxes...
+  %get z position data from database
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  
+  [stack,sino,z_pos,index]=gtReadSpots_360(struct_ids(1), struct_ids, replace_flag, parameters);
+
+  
+  x_grain= (acq.bb(3)/2)+grain{i}.center(2);
+  y_grain= (acq.bb(3)/2)+grain{i}.center(1);
+  
+  plot_flag=1;
+  
+  try
+    s=gtMakeGrain(sino, Omega, x_grain, y_grain, plot_flag);
+  catch
+    disp(['WARNING gtMakeGrain failed! Grain: ' num2str(grain{i}.id)])
+    continue
+  end
+
+  
+  for j=find(index)
+    try
+      query=sprintf(['select Yorigin,Yorigin+Ysize from '...
+      '%sbb inner join %sbboxes on bbID=bboxID '...
+      'where %sbb.extspotID=%d'],...
+      acq.name, acq.name, acq.name,...
+      struct_ids(j));
+      [zstart(j),zend(j)]=mym(query);
+	catch
+      disp('no extspot data for this difspotid')
+    end
+  end
+
+  
+
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   %forward simulation here - search database for more difspot-extspot pairs
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   
+   if 0
+   
+   x_grain= (acq.bb(3)/2)+grain{i}.center(2);
+   y_grain= (acq.bb(3)/2)+grain{i}.center(1);
+   z_grain= -grain{i}.center(3)+acq.ydet/2-acq.bb(2);
+   grainCentroid=[x_grain, y_grain, z_grain];
+     
+   add_struct_ids=gtForwardSimulate_360(grainCentroid, R_vector, struct_ids, parameters)
+  
+   ndx=length(struct_ids);
+   [dummy,tt]=gtnew_calculate_twotheta;  % theoretical list of allowed reflections and TwoTHeta values
+   
+   struct_ids = [struct_ids add_struct_ids];
+   
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   % try to calculate in the missing information for the new forward
+   % simulated spots, based on the measured spot positions and known grain position
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   for j=1:length(add_struct_ids)
+	 [CentroidImage,CentroidX,CentroidY]=mym(sprintf('select CentroidImage, CentroidX, CentroidY from %sdifspot where difspotID=%d',acq.name,add_struct_ids(j)));
+	
+	 Omega(ndx+j) = CentroidImage/(acq.nproj*2)*360;    % supposes 360 degree scans here
+     [grainx,grainy,grainz]=gtTrSamToLab(grain{i}.center(1),grain{i}.center(2),grain{i}.center(3),Omega(ndx+j))
+	 
+	 % calculate the distances in pixels with respect to the laboratory system 
+	 dx= acq.dist/acq.pixelsize-grainx; 
+	 dy= CentroidX-acq.rotx-grainy;
+	 dz= acq.ydet/2-CentroidY-grainz
+	 kh=[dx dy dz];
+	 kh=kh/norm(kh);  % normalized difracted beam direction
+	 k0=[1 0 0];      % normalized incoming beam direction
+	 G= (kh-k0)/norm(kh-k0);        % normalized Laboratory system scattering vector
+	 
+	 Eta(ndx+j)   = atan2(dy,dz)/pi*180;        
+     Theta(ndx+j) = atand(sqrt(dy.^2+dz.^2)/dx)/2
+     refl         = find(abs(tt.centre-Theta(ndx+j)*2)==min(abs(tt.centre-Theta(ndx+j)*2)));  % find out what type of reflection this Theta corresponds to
+	 hkl(ndx+j,:) = tt.reflections(refl,:);  
+	 [pn(1),pn(2),pn(3)]= gtTrLabToSam(G(1),G(2),G(3),Omega(ndx+j)); % normalized plane_normal in sample coordinate system
+	 plane_normal(ndx+j,:) = pn; 
+	 
+	 query=sprintf(['select Yorigin,Yorigin+Ysize from %sbb inner join %sbboxes on bbID=bboxID where %sbb.extspotID=%d'],...
+      acq.name, acq.name, acq.name,add_struct_ids(j));
+     [zstart(ndx+j),zend(ndx+j)]=mym(query);
+   end	 
+	
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   %% rebuild stack (including the new spots)  - and calculate new backprojection image 
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    [stack,sino,z_pos,index]=gtReadSpots_360(struct_ids(1), struct_ids, replace_flag, parameters);
+    
+	s=gtMakeGrain(sino, Omega, x_grain, y_grain, plot_flag);
+  
+   end	
+	
+   % bounding box data
+   zstart=min(zstart(find(index)));    % only look at valid extspots given by index==1
+   zend=max(zend(find(index)));
+  x1 = ceil(s.BoundingBox(1)); %gt bbox ceil
+  y1 = ceil(s.BoundingBox(2)); %gt bbox ceil
+  xend = x1 + s.BoundingBox(3);
+  yend = y1 + s.BoundingBox(4);
+  % centres
+  xcenter=round(s.Centroid(1));
+  ycenter=round(s.Centroid(2));
+  zcenter=round(z_grain);   % changed from z_pos          
+
+ 
+  % add 20% to bounding box for luck (x-y plane only for extspot recon)
+  x1 = round(x1 - (s.BoundingBox(3)/5));
+  if x1 < 1
+    x1 = 1;
+  end
+  y1 = round(y1 - (s.BoundingBox(4)/5));
+  if y1 <1
+    y1 = 1;
+  end
+  xend = round(xend + (s.BoundingBox(3)/5));
+  if xend > acq.bb(3)
+    xend = acq.bb(3);
+  end
+  yend = round(yend + (s.BoundingBox(4)/5));
+  if yend > acq.bb(3)
+    yend = acq.bb(3);
+  end
+
+  nx = xend-x1;
+  ny = yend-y1;
+  nz = zend-zstart;
+
+
+  % Write in database:
+  %     for i=1:length(struct_ids)
+  %       %update grainID in extspot table
+  % 			mysqlcmd=dbUpdate(sprintf('%sextspot',acq.name),'extspotID',struct_ids(i),'GrainID',grainid);
+  %       mym(mysqlcmd);
+  % 			%update grainID in bb table (!)
+  %       mysqlcmd=dbUpdate(sprintf('%sbb',acq.name),'extspotID',struct_ids(i),'grainID',grainid);
+  %       mym(mysqlcmd);
+  %     end
+
+  % Save mat file
+  grainname=sprintf('grain%d_',i);
+  graindir=sprintf('%s/4_grains/%s',acq.dir,grainname);
+  if ~exist(graindir,'dir')
+    mkdir(graindir);
+  end
+  name=sprintf('%s/%s.mat',graindir,grainname);
+  save(name,'struct_ids','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','Omega','Theta', 'Eta','plane_normal','hkl','R_vector','index');
+
+end % of grain loop
+
+
+end % of function
diff --git a/4_spot_sorting/gtIndexFitSinglesToGrains.m b/4_spot_sorting/gtIndexFitSinglesToGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..7ac5a82704602247a4cc6e5d5f3f6dd3773a19f2
--- /dev/null
+++ b/4_spot_sorting/gtIndexFitSinglesToGrains.m
@@ -0,0 +1,87 @@
+function [grain,changedg,singlesfit]=gtIndexFitSinglesToGrains(singlel,grain,strategy_s,spacegroup,latticepar)
+
+nof_singlel=length(singlel.id);
+nof_grains=length(grain);
+
+changedg=[];
+singlesfit.pairid=[];
+
+%singlesfit(1:nof_singlel,1:nof_grains,1:5).goodness=0; %zeros(nof_singlel,nof_grains,5);
+%singlesfit(1:nof_singlel,1:nof_grains,1:5).sumgoodness=0; %zeros(nof_singlel,nof_grains,5);
+%singlesfit(1:nof_singlel,1:nof_grains,1:5).sqrgoodness=0; %zeros(nof_singlel,nof_grains,5);
+
+for i=1:nof_singlel
+
+  sl=gtIndexSelectLines(i,singlel);
+  Rv=gtRodriguesVectors2(sl.pl,sl.hkl,spacegroup,latticepar);
+
+  for j=1:nof_grains
+
+		% Single (line) to grain (point) distance in Rodrigues space:
+    sl.Rdist=min(pointtolinedist(grain{j}.R_vector,Rv));
+
+    % Single (line) to grain (point) location distance in real space:
+    sl.distcom=pointtolinedist(grain{j}.center,[sl.ca sl.dir]);
+
+    goodness=sfSingleFitGoodness(sl,grain{j});
+    
+%     singlesfit.goodness(i,j,1)=goodness(1);
+%     singlesfit.goodness(i,j,2)=goodness(2);
+%     singlesfit.goodness(i,j,3)=goodness(3);
+%     singlesfit.goodness(i,j,4)=goodness(4);
+%     singlesfit.goodness(i,j,5)=goodness(5);
+%     
+%     singlesfit.sumgoodness(i,j)=sum(goodness);
+%     singlesfit.sqrgoodness(i,j)=sum(goodness*goodness');
+
+		singlesfit.Rdist(i,j)=goodness(1);
+    singlesfit.distcom(i,j)=goodness(2);
+    singlesfit.int(i,j)=goodness(3);
+    singlesfit.bbx(i,j)=goodness(4);
+    singlesfit.bby(i,j)=goodness(5);
+    
+    singlesfit.sumgoodness(i,j)=sum(goodness);
+    singlesfit.sqrgoodness(i,j)=sqrt(goodness*goodness');
+
+	end
+	
+	[minval,minloc]=min(singlesfit.sqrgoodness(i,:));
+	
+	goodfit=(singlesfit.Rdist(i,minloc)<strategy_s) & ...
+		      (singlesfit.distcom(i,minloc)<strategy_s) & ...
+  				(singlesfit.int(i,minloc)<strategy_s) & ...
+					(singlesfit.bbx(i,minloc)<strategy_s) & ...
+					(singlesfit.bby(i,minloc)<strategy_s);
+
+	if goodfit
+		grain{minloc}.lid=[grain{minloc}.lid, sl.id];
+		changedg=[changedg, minloc];
+		singlesfit.pairid=[singlesfit.pairid sl.pairid];
+	end
+	
+end
+
+changedg=unique(changedg);
+
+end
+
+
+% function outl=sfCheckSingleFit(singlel,grain,tol_outl)
+%   outl(1)=gtOutliers(singlel.Rdist, tol.outl, grain.stat.lRdistmean, grain.stat.lRdiststd);
+%   outl(2)=gtOutliers(singlel.distcom, tol.outl, grain.stat.distcommean, grain.stat.distcomstd);
+%   outl(3)=gtOutliers(singlel.int, tol.outl, grain.stat.intmean, grain.stat.intstd);
+%   outl(4)=gtOutliers(singlel.bbxs, tol.outl, grain.stat.bbxsmean, grain.stat.bbxsstd);
+%   outl(5)=gtOutliers(singlel.bbys, tol.outl, grain.stat.bbysmean, grain.stat.bbysstd);
+%   outl=~outl;
+% end
+
+function goodness=sfSingleFitGoodness(singlel,grain)
+
+  goodness(1)=abs((singlel.Rdist-grain.stat.Rdistmean)/grain.stat.Rdiststd);
+  goodness(2)=abs((singlel.distcom-grain.stat.distcommean)/grain.stat.distcomstd);
+  goodness(3)=abs((singlel.int-grain.stat.intmean)/grain.stat.intstd);
+  goodness(4)=abs((singlel.bbxs-grain.stat.bbxsmean)/grain.stat.bbxsstd);
+  goodness(5)=abs((singlel.bbys-grain.stat.bbysmean)/grain.stat.bbysstd);
+
+end
+
diff --git a/4_spot_sorting/gtIndexReflections.m b/4_spot_sorting/gtIndexReflections.m
new file mode 100755
index 0000000000000000000000000000000000000000..4d2fb2f797467c4aa7fb606f12166171ed5a473a
--- /dev/null
+++ b/4_spot_sorting/gtIndexReflections.m
@@ -0,0 +1,108 @@
+function [plane_normal, hkl] = gtIndexReflections(Theta, Eta, Omega, parameters)
+%generate the plane_normal vectors, determine the hkl types
+%takes all angles in degrees
+
+
+if isempty(parameters)
+  load parameters.mat
+end
+
+%convert to radians for calculation
+Omega = Omega*pi/180;
+Theta = Theta*pi/180;
+Eta = Eta*pi/180;
+
+%~~~~~~~~calculate plane normals in sample coordinates~~~~~~~~~~~~
+for i=1:length(Omega);
+  plane_normal(i,1) = -sin(Theta(i))*cos(Omega(i)) - cos(Theta(i))*sin(Eta(i))*sin(Omega(i));
+  plane_normal(i,2) = cos(Theta(i))*sin(Eta(i))*cos(Omega(i)) - sin(Theta(i))*sin(Omega(i));%30/10 - signs change in this line
+  plane_normal(i,3) = cos(Theta(i))*cos(Eta(i));
+end
+
+
+%~~~~~~~~~~index reflections~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+%determine which Theta is which hkl
+% modif sabine
+% hkl=zeros(length(Theta),3);
+% fin modif sabine
+hkl_list=zeros(length(Theta),1);%tmp = 1 means hkl = {111}, 2 means {002} etc
+
+[tmp, tmp2]=gtnew_calculate_twotheta; %(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+allowed_Theta = (twotheta/2)*pi/180;
+
+dif = abs(repmat(Theta',1,length(allowed_Theta)) - repmat(allowed_Theta,length(Theta),1));
+[min_dif,hkl_list]=min(dif,[],2);
+
+%check line is within 5% of prediction
+for i=1:length(hkl_list)
+    if min_dif(i)/allowed_Theta(hkl_list(i))>0.05
+        hkl_list(i)=0;
+    end
+end
+
+
+%old system, can produce ambiguous results for closely spaced lines
+
+%allowed_Theta = [0.95*allowed_Theta; 1.05*allowed_Theta];% %5 tolerance
+
+%for i=1:length(allowed_Theta)% run through the allow thetas calculated above
+%  dummy = find(Theta>allowed_Theta(1,i) & Theta<allowed_Theta(2,i));
+%  hkl_list(dummy)=i;
+%end
+
+
+
+%this is dangerous, because the list here must in the in same order as the
+%list in gtnew_calculate_twotheta.  Therefore, if possible get the list of
+%reflections from the second output of gtnew_calculate_twotheta.
+hkl_table=tmp2.reflections;
+hkl=zeros(length(Theta), size(hkl_table,2));
+
+
+
+
+
+% switch parameters.acq.spacegroup
+%   case 225 % if FCC
+%     %hkl lookup table... for FCC
+%     % modif sabine
+%     hkl=zeros(length(Theta),3);
+%     % fin modif sabine
+%     hkl_table = [1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1 ; 0 0 4 ; 3 3 1];
+%   case 229 % if BCC
+%           % modif sabine
+%     hkl=zeros(length(Theta),3);
+%     % fin modif sabine
+%     hkl_table = [1 1 0; 0 0 2; 1 1 2];
+%     % sabine
+%   case 663
+%           % modif sabine
+%     hkl=zeros(length(Theta),4);
+%     % fin modif sabine
+%     hkl_table = [...
+%             0 0 0 2; ...
+%             1 1 -2 0; ...
+%             1 -1 0 0; ...
+%             1 -1 0 1; ...
+%             1 1 -2 2; ...
+%             -2 0 2 1; ...
+%             ]; 
+%         
+%     % sabine
+%   otherwise
+%     disp('sorry, FCC or BCC only for the mo!')
+% end%fill in hkl matrix
+
+
+
+for i=1:size(hkl_table,1)
+  dummy = find(hkl_list == i);
+  for d=1:length(dummy)
+    hkl(dummy(d),:) = hkl_table(i,:);
+  end
+end
+  
diff --git a/4_spot_sorting/gtIsPointInSample.m b/4_spot_sorting/gtIsPointInSample.m
new file mode 100755
index 0000000000000000000000000000000000000000..eef5275bc0e6a4a90732b853442f760d6b7ad3af
--- /dev/null
+++ b/4_spot_sorting/gtIsPointInSample.m
@@ -0,0 +1,25 @@
+%
+% out=gtIsPointInSample(pcoord,sample_rad,sample_top,sample_bot,thr_geo)
+%
+% True, if the given in point is inside the illuminated cylindrical sample
+% volume. It works in LAB or Sample system.
+%
+% INPUT   pcoord = [X,Y,Z] coordinates of the point
+%         sample.rad = sample radius
+%         sample.top = top of the sample
+%         sample.bot = bottom of sample
+%         tol_geo = geometrical tolerance (normally pos.)
+%       
+%         /all the input parameters must be in the same system and units/
+%
+% OUTPUT  out = true if the given point is in the sample
+%
+
+function out=gtIsPointInSample(pcoord,sample,tol)
+
+out1=(pcoord(:,3) < sample.top+tol.geo) & (pcoord(:,3) > sample.bot-tol.geo);
+out2=(sqrt(pcoord(:,1).*pcoord(:,1)+pcoord(:,2).*pcoord(:,2)) < sample.rad+tol.geo);
+
+out=(out1&out2);
+
+end % of function
diff --git a/4_spot_sorting/gtMakeGrain.m b/4_spot_sorting/gtMakeGrain.m
new file mode 100755
index 0000000000000000000000000000000000000000..d2c49b80e7b24d13465e58115173321430bba08e
--- /dev/null
+++ b/4_spot_sorting/gtMakeGrain.m
@@ -0,0 +1,39 @@
+%
+% Seperated from gtHandleSpot_360.
+
+function s = gtMakeGrain(sino, Omega, x_grain, y_grain, plot_flag)
+
+    %back project good spots only
+   
+	binsino = sino>0.1*max(sino(:));
+    img2=backpro(binsino,(pi/180)*Omega);
+
+    
+    
+	%do imreconstruct from centre to threshold grain
+    x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+    marker=zeros(size(img2));
+    marker(y_grain, x_grain)=1;
+    mask=double((img2>0.8*img2(y_grain, x_grain)));
+    mask=imfill(mask,'holes');
+	
+    try
+      grain=imreconstruct(marker,mask);    
+      if plot_flag
+        figure
+        h1=imshow(cat(3,img2,zeros(size(img2)),zeros(size(img2))),[]);
+        hold on
+        h2=imshow(cat(3,zeros(size(img2)),grain,zeros(size(img2))),[]);
+        set(h2,'alphadata',0.5);
+      end
+      s=regionprops(grain,'Area','BoundingBox','Centroid');
+    
+    catch
+      disp('Marker/mask problem - bombed out')
+      accept=false;
+      s=[];
+      return
+    end
+
+
+end
diff --git a/4_spot_sorting/gtMakeGrain3D.m b/4_spot_sorting/gtMakeGrain3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..d2c49b80e7b24d13465e58115173321430bba08e
--- /dev/null
+++ b/4_spot_sorting/gtMakeGrain3D.m
@@ -0,0 +1,39 @@
+%
+% Seperated from gtHandleSpot_360.
+
+function s = gtMakeGrain(sino, Omega, x_grain, y_grain, plot_flag)
+
+    %back project good spots only
+   
+	binsino = sino>0.1*max(sino(:));
+    img2=backpro(binsino,(pi/180)*Omega);
+
+    
+    
+	%do imreconstruct from centre to threshold grain
+    x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+    marker=zeros(size(img2));
+    marker(y_grain, x_grain)=1;
+    mask=double((img2>0.8*img2(y_grain, x_grain)));
+    mask=imfill(mask,'holes');
+	
+    try
+      grain=imreconstruct(marker,mask);    
+      if plot_flag
+        figure
+        h1=imshow(cat(3,img2,zeros(size(img2)),zeros(size(img2))),[]);
+        hold on
+        h2=imshow(cat(3,zeros(size(img2)),grain,zeros(size(img2))),[]);
+        set(h2,'alphadata',0.5);
+      end
+      s=regionprops(grain,'Area','BoundingBox','Centroid');
+    
+    catch
+      disp('Marker/mask problem - bombed out')
+      accept=false;
+      s=[];
+      return
+    end
+
+
+end
diff --git a/4_spot_sorting/gtMatchDifspots.m b/4_spot_sorting/gtMatchDifspots.m
new file mode 100755
index 0000000000000000000000000000000000000000..c020b1f8020e7a79fefe788e1b586d61d6494602
--- /dev/null
+++ b/4_spot_sorting/gtMatchDifspots.m
@@ -0,0 +1,475 @@
+%
+% FUNCTION gtMatchDifspots(par_match,savepar,show_findings,dopause)
+%
+%   (Used to be gtMatchDifspots_v3)
+%   Matches difspots of a 360 degree scan, from a single difspot table.
+%   It can take into account tilts and correlate difspots (check if it 
+%   gives any improvement) for better angular precision.
+%   Speed shouldn't depend much on the number of difspots, since it works
+%   on a fraction of the spots (creates and uses a smaller spotpairtable, 
+%   named 'processtable').
+%
+% USAGE e.g. gtMatchDifspots
+%            gtMatchDifspots(par_match)
+%            gtMatchDifspots(par_match,0,0,'button')
+%
+% OPTIONAL INPUT    
+%
+%  par_match:     matching parameters; if not specified it looks into
+%                 the parameters file
+%  savepar:       saves the last used match parameters in the parameters file
+%  show_findings: if true, the pairs found and candidates are shown in figures
+%  dopause:       pause time in sec after a pair is found; if set as 'button',
+%                 it waits for button press
+%
+% OUTPUT  loads data in spotpairs table given in the parameters file
+%
+%
+% MATCHING TOLERANCES read from parameters.match (default values in brackets)
+%
+%   centmode:          centroid of difspots based on: 
+%                        0 or []: uses center of mass from difspot table (default)
+%                        1:       difspots from blobs or edf-s are correlated
+%                        2:       difspots - from summed fulls - are correlated
+%   addconstr:         additional constraints on which spots to consider in the database           
+%
+%  Scintillator tilts:
+%   tiltY:             tilt around lab Y (horizontal) axis in degrees (0)
+%   tiltZ:             tilt around lab Z (vertical) axis in degreees  (0)
+%
+%  Given spotA, which spotB-s to consider.
+%
+%  Diffraction vector:
+%   thr_ang:           theta angular deviation; absolute value in degrees (0.2)
+%   corr_rot_to_det:   correction of rotation-axis - detector dist. in pixels (0)
+%
+%  Thresholds for full image positions:
+%   thr_max_offset:    CentroidImage offset threshold; absolut value in #images (2)
+%   thr_ext_offset:    ExtStartImage and ExtEndImage offset threshold; absolut value in #images (10)
+%   thr_genim_offset:  at least one of the three images should be offset as maximum this value in #images (1)
+%
+%  Thresholds for difspot images (for search between the limits: basevalue/thr & basevalue*thr)
+%   thr_intint:        integrated intensity (3)
+%   thr_area:          area of spots inside the bounding box (1.2)
+%   thr_bbsize:        bounding box size (1.2)
+%
+%
+%
+%  by Peter Reischig, ESRF, 11/2007
+%
+%%
+
+
+function gtMatchDifspots(par_match,savepar,show_findings,dopause)
+
+% modif sabine
+load parameters.mat
+% parameters=load('parameters.mat');
+
+tic
+
+if ~exist('par_match','var')
+  par_match=[];
+end
+
+if ~exist('savepar','var')
+  savepar=false;
+end
+
+if ~exist('show_findings','var')
+  show_findings=false;
+end
+
+if ~exist('dopause','var')
+  dopause=0;
+end
+
+
+% Default parameters
+if isempty(par_match) && ~isfield(parameters,'match')
+  disp('Using default parameters.')
+  parameters.match.thr_ang=0.2;
+  parameters.match.thr_max_offset=2;
+  parameters.match.thr_ext_offset=10;
+  parameters.match.thr_genim_offset=1;
+  parameters.match.corr_rot_to_det=0;
+
+  parameters.match.thr_intint=3;
+  parameters.match.thr_area=1.2;
+  parameters.match.thr_bbsize=1.2;
+
+	parameters.match.tiltY=0;
+	parameters.match.tiltZ=0;
+	parameters.match.centmode=0;
+	parameters.match.addconstr=[];
+elseif ~isempty(par_match)
+  parameters.match=par_match;
+end
+
+disp(parameters.match)
+
+if savepar
+  save('parameters.mat','parameters')
+  disp(' ')
+  disp('Actual matching parameters are saved in the parameters file.')
+end
+
+%% Set up search parameters
+
+% Tolerances for image position
+thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees (0.2)
+thr_max_offset=parameters.match.thr_max_offset;     % CentroidImage offset threshold; absolut value in #images (2)
+thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images (10)
+thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images (1)
+corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels (0)
+
+% Tolerances (for search within the limits: basevalue/thr & basevalue*thr)
+thr_intint=parameters.match.thr_intint;             % integrated intensity (3)
+thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box (1.2)
+thr_bbsize=parameters.match.thr_bbsize;             % bounding box size (1.2)
+
+% Other options
+centmode=parameters.match.centmode;
+tiltY=parameters.match.tiltY;
+tiltZ=parameters.match.tiltZ;
+addconstr=parameters.match.addconstr;
+if ~isempty(parameters.match.addconstr)
+  addconstr=[' and ' addconstr];
+end
+
+sample_radius=parameters.acq.bb(3)/2;
+% Sample geometry in imagesm:
+sample_top=parameters.acq.bb(2);
+sample_bot=parameters.acq.bb(2)+parameters.acq.bb(4);
+rot_to_det=parameters.acq.dist/parameters.acq.pixelsize+corr_rot_to_det;
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition
+% sorY = on the rotation axis by definition
+sample=gtSampleGeoInSampleSystem(parameters);
+sorZ=sample.sorZim;                     % floor(parameters.acq.ydet/2);
+
+if isfield(parameters.acq, 'difA_name')
+  difspottable=[parameters.acq.difA_name 'difspot'];
+  makeprocesstable=[parameters.acq.difA_name 'process_'];
+  processtable=[parameters.acq.difA_name 'process_difspot'];
+else
+  difspottable=[parameters.acq.name 'difspot'];
+  makeprocesstable=[parameters.acq.name 'process_'];
+  processtable=[parameters.acq.name 'process_difspot'];
+end
+
+pairtable=parameters.acq.pair_tablename ;
+nproj=parameters.acq.nproj; % number of preojections per 180 degrees
+
+nofspotspertable=2000; % no.of spots in the processtable (2000 seems good)
+
+[tmp,results]=gtnew_calculate_twotheta() ;
+comp_2thetas=results.centre; % coloumn vector of all valid 2theta angles in degrees
+
+disp(' ')
+%close all
+
+gtDBCreateDifspotTable(makeprocesstable,1)
+gtDBCreateSpotPairTable(pairtable,1)
+
+nof_spots1=mym(sprintf('select count(*) from %s where CentroidImage between %0.20g and %0.20g %s',difspottable,0,nproj,addconstr))
+nof_spots2=mym(sprintf('select count(*) from %s where CentroidImage between %0.20g and %0.20g %s',difspottable,nproj,2*nproj,addconstr))
+
+[spotsA,centim]=mym(sprintf(['select difspotID,CentroidImage from %s where CentroidImage<=%d %s',...
+' order by CentroidImage asc, Integral desc'],difspottable,nproj+thr_max_offset,addconstr));
+
+max_difspotID=mym(sprintf('select max(difspotID) from %s',difspottable));
+pairedspots=false(max_difspotID,1);
+
+%if isempty(startat)
+  mym(sprintf('truncate %s',pairtable)) ;
+  disp('Data in spotpairs table have been deleted, if there were any.') ;
+  istart=1;  
+%else
+%  error('Update this part if needed at all...')
+%   pairedA=mym(sprintf('select difAID from %s',pairtable));
+%   pairedB=mym(sprintf('select difBID from %s',pairtable));
+%   pairedspots(pairedA)=true;
+%   pairedspots(pairedB)=true;
+%   [tmp,istart]=min(abs(values_orderby-startat));
+%end
+
+pairsfound=0;
+show_bands=true;
+
+disp('Processing data...')
+disp('Progress:')
+disp('    #Spots     SpotID A     Integral  Pairs found  Matching');
+
+%% Main loop for spots from first half
+for i=istart:length(spotsA)    
+
+  
+  
+  sp1.id=spotsA(i);
+
+  if pairedspots(sp1.id)
+    continue
+  end
+
+  % create new processtable
+  if mod(i-istart,nofspotspertable)==0
+    centim_begin=centim(i)+nproj-thr_max_offset;
+    centim_end=centim(min([i+nofspotspertable length(centim)]))+nproj+thr_max_offset;
+   
+    mym(sprintf('TRUNCATE %s',processtable))
+    mysqlcmd=sprintf(['INSERT INTO %s SELECT difspotID,StartImage,EndImage,MaxImage,ExtStartImage,ExtEndImage, Area, CentroidX, CentroidY,'...
+	   'CentroidImage, BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize,Integral FROM %s WHERE CentroidImage BETWEEN %0.20g AND %0.20g']...
+      ,processtable,difspottable,centim_begin,centim_end);
+    mym(mysqlcmd);
+  end
+    
+  
+  
+  [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral]=...
+    mym(sprintf(['select CentroidImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+    'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d %s'],difspottable,sp1.id,addconstr)) ;
+
+  pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;
+
+  % Set limits for search between lim1..lim2
+
+  % CentroidImage, ExtStart, Extend limits for pair
+  [maxim1,maxim2]=sfCalcBoundaries(sp1.maxim,thr_max_offset,nproj);
+  [extstim1,extstim2]=sfCalcBoundaries(sp1.extstim,thr_ext_offset,nproj);
+  [extendim1,extendim2]=sfCalcBoundaries(sp1.extendim,thr_ext_offset,nproj);
+
+  % At least one of them should also fulfill thr_genim_offset
+  [maxim1_gen,maxim2_gen]=sfCalcBoundaries(sp1.maxim,thr_genim_offset,nproj);
+  [extstim1_gen,extstim2_gen]=sfCalcBoundaries(sp1.extstim,thr_genim_offset,nproj);
+  [extendim1_gen,extendim2_gen]=sfCalcBoundaries(sp1.extendim,thr_genim_offset,nproj);
+
+
+  % Select candidate spots2 from database by all the criteria
+  [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral]= ...
+    mym(sprintf(['SELECT difspotID, CentroidImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+    'BoundingBoxYsize, Integral FROM %s WHERE ', ...
+    '(CentroidX between %0.20g and %0.20g) AND (CentroidY between %0.20g and %0.20g) ', ...
+    'AND (BoundingBoxXsize between %0.20g and %0.20g) AND (BoundingBoxYsize between %0.20g and %0.20g) ', ...
+    'AND (Integral between %0.20g and %0.20g) ', ...
+    'AND (Area between %0.20g and %0.20g) ', ...
+    'AND (CentroidImage between %0.20g and %0.20g) ', ...
+    'AND (ExtStartImage between %d and %d) ', ...
+    'AND (ExtEndImage between %d and %d) ', ...
+    'AND ((CentroidImage between %0.20g and %0.20g) OR ', ...
+    '(ExtStartImage between %d and %d) OR ', ...
+    '(ExtEndImage between %d and %d)) ', ...
+    ' %s'], ...
+    processtable,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+    sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+    sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+    sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+    sp1.area/thr_area, sp1.area*thr_area, ...
+    maxim1, maxim2, ...
+    extstim1, extstim2, ...
+    extendim1, extendim2, ...
+    maxim1_gen, maxim2_gen, ...
+    extstim1_gen, extstim2_gen, ...
+    extendim1_gen, extendim2_gen, ...
+    addconstr)) ;
+
+  % Delete candidates already paired
+  sps2.maxim(pairedspots(sps2.id))=[];
+  sps2.extstim(pairedspots(sps2.id))=[];
+  sps2.extendim(pairedspots(sps2.id))=[];
+  sps2.area(pairedspots(sps2.id))=[];
+  sps2.centX(pairedspots(sps2.id))=[];
+  sps2.centY(pairedspots(sps2.id))=[];
+  sps2.bbX(pairedspots(sps2.id))=[];
+  sps2.bbY(pairedspots(sps2.id))=[];
+  sps2.bbXsize(pairedspots(sps2.id))=[];
+  sps2.bbYsize(pairedspots(sps2.id))=[];
+  sps2.integral(pairedspots(sps2.id))=[];
+  sps2.id(pairedspots(sps2.id))=[];
+
+
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+
+  sqrsum=Inf ;
+
+  for j=1:length(sps2.id)
+    
+     [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),...
+       rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ,comp_2thetas,thr_ang);
+    
+    if theta_OK==true
+      sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+        ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+        (min(abs(angle_diff))/thr_ang)^2 + ...
+        ((sps2.extstim(j)-sp1.extstim)/thr_ext_offset)^2 + ((sps2.extendim(j)-sp1.extendim)/thr_ext_offset)^2 ;
+      if (sqrsumnew < sqrsum)
+        sqrsum=sqrsumnew ;
+        pairj=j ;
+        thetatype_out=thetatype ;
+      end
+    end
+  end
+
+  
+%% Being left with the right pair spot, compute output parameters and loading database
+
+  if sqrsum < Inf
+    pairsfound=pairsfound+1 ;
+    
+    % Save pair data sp2
+    sp2.id=sps2.id(pairj);
+    sp2.maxim=sps2.maxim(pairj);
+    sp2.extstim=sps2.extstim(pairj);
+    sp2.extendim=sps2.extendim(pairj);
+    sp2.area=sps2.area(pairj);
+    sp2.centX=sps2.centX(pairj);
+    sp2.centY=sps2.centY(pairj);
+    sp2.integral=sps2.integral(pairj);
+    sp2.bbXsize=sps2.bbXsize(pairj);
+    sp2.bbYsize=sps2.bbYsize(pairj);
+    sp2.bbX=sps2.bbX(pairj);
+    sp2.bbY=sps2.bbY(pairj);
+
+    % Leave only the wrong candidates in sps2
+    sps2.maxim(pairj)=[];
+    sps2.extstim(pairj)=[];
+    sps2.extendim(pairj)=[];
+    sps2.area(pairj)=[];
+    sps2.centX(pairj)=[];
+    sps2.centY(pairj)=[];
+    sps2.bbX(pairj)=[];
+    sps2.bbY(pairj)=[];
+    sps2.bbXsize(pairj)=[];
+    sps2.bbYsize(pairj)=[];
+    sps2.integral(pairj)=[];
+    sps2.id(pairj)=[];
+   
+    pairedspots(sp1.id)=true;
+    pairedspots(sp2.id)=true;
+    
+  
+    switch centmode
+  
+      case {0, []}
+      
+      case 1 % correlate difspots (edf-s or blobs)
+        [corrx,corry]=gtCorrelateDifspots(sp1.id,sp2.id,parameters,centmode,1);
+        sp2.centX=sp2.centX-corrx; % the negative of corr is applied, since
+                                   %  corr referred to the flipped image 
+        sp2.centY=sp2.centY+corry;                         
+
+      case 2 % correlate summed fulls over the difspot bb
+        [corrx,corry]=gtCorrelateDifspots(sp1.id,sp2.id,parameters,centmode,1);
+        sp2.centX=sp2.centX-corrx; % the negative of corr is applied, since
+                                   %  corr referred to the flipped image 
+        sp2.centY=sp2.centY+corry;                         
+
+    end
+
+    
+    theta= gtThetaOfPairs(sp1.centX,sp1.centY,sp2.centX,sp2.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+    eta= gtEtaOfPairs(sp1.centX,sp1.centY,sp2.centX,sp2.centY,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+
+    diff_vec_setup= gtDiffVecInLab(sp1.centX,sp1.centY,sp2.centX,sp2.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+
+    pl_vec_setup= gtDiffPlaneNormInLab(sp1.centX,sp1.centY,sp2.centX,sp2.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ);
+
+    omega1=180/nproj*sp1.maxim;
+    omega2=180/nproj*sp2.maxim; % (sp2.maxim should always be larger)
+    omega=(omega1+omega2-180)/2; % the average of the two
+
+    [diff_vec_sam(1),diff_vec_sam(2),diff_vec_sam(3)] = gtTrLabToSam(diff_vec_setup(1),diff_vec_setup(2),diff_vec_setup(3),omega) ;
+    [pl_vec_sam(1),pl_vec_sam(2),pl_vec_sam(3)] = gtTrLabToSam(pl_vec_setup(1),pl_vec_setup(2),pl_vec_setup(3),omega) ;
+
+    [lab_cent1(1),lab_cent1(2),lab_cent1(3)] = gtTrScToLab(sp1.centX,sp1.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+    [lab_cent2(1),lab_cent2(2),lab_cent2(3)] = gtTrScToLab(sp2.centX,sp2.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+
+    [samcentA(1),samcentA(2),samcentA(3)] = gtTrLabToSam(lab_cent1(1),lab_cent1(2),lab_cent1(3),omega1) ;
+    [samcentB(1),samcentB(2),samcentB(3)] = gtTrLabToSam(lab_cent2(1),lab_cent2(2),lab_cent2(3),omega2) ;
+    
+    
+    av_intint=(sp1.integral+sp2.integral)/2 ;
+    av_bbXsize=(sp1.bbXsize+sp2.bbXsize)/2 ;
+    av_bbYsize=(sp1.bbYsize+sp2.bbYsize)/2 ;
+ 
+    % Variables in table
+    % samcent: difspot centroid in the sample system
+    % lines connecing the two spots in the sample system
+    % lor: line origin (centroid of spot A);
+    % ldir: unit vector of line direction
+    % pl: plane normal in sample system
+    mysqlcmd=sprintf(['INSERT INTO %s (difAID, difBID, theta, eta, omega, avintint, avbbXsize, avbbYsize, '...
+      'samcentXA, samcentYA, samcentZA, samcentXB, samcentYB, samcentZB, '...
+      'ldirX, ldirY, ldirZ, plX, plY, plZ, thetatype) ',...
+      'VALUES (%d,%d,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%d)'],...
+      pairtable,sp1.id,sp2.id,theta,eta,omega,av_intint,av_bbXsize,av_bbYsize,...
+      samcentA(1),samcentA(2),samcentA(3),samcentB(1),samcentB(2),samcentB(3),...
+      diff_vec_sam(1),diff_vec_sam(2),diff_vec_sam(3),pl_vec_sam(1),pl_vec_sam(2),pl_vec_sam(3),thetatype_out) ;
+    mym(mysqlcmd);
+
+    
+%% Display findings
+
+    if show_findings
+
+      gtShowPairFigure(1,parameters,sp1,sp2,pr_bb,comp_2thetas,show_bands,...
+                       sps2,[],[],omega,theta,eta)
+      show_bands=false;
+      if strcmpi('button',dopause)
+        waitforbuttonpress
+      else
+        pause(dopause)
+      end
+    end
+
+  end % pair found
+
+  if mod(i,100)==0
+    disp(sprintf('%10d   %10d   %10.1f   %10d   %3.2f%%',i,sp1.id,sp1.integral,pairsfound,pairsfound/(i-istart+1)*100)) ;
+  end
+
+end % end of main loop for spotsA
+
+disp('Total number of diffraction spots in first half:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in second half:'), disp(nof_spots2) ;
+disp('Number of pairs found:'), disp(pairsfound) ;
+disp('Total number of pairs in spotpairtable:')
+disp(mym(sprintf('Select count(pairID) from %s',pairtable)));
+
+disp(' ');
+toc
+disp(' ')
+
+gtEvaluateDifspotMatch([],'pair_dist')
+
+end % of function
+
+
+%% Sub-functions used
+
+% Given an image number, returns the boundaries of two ranges (as image numbers)
+% with an offset of 180degree +-tol offset.
+function [b1,b2]=sfCalcBoundaries(imno1,tol,nproj)
+  b1=imno1+nproj-tol;
+  b2=imno1+nproj+tol;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ,comp_2thetas,thr_ang)
+% Checks whether the position of two spots gives a diffraction vector which
+% corresponds to a valid 2theta angle within the given threshold.
+
+  angle=2*gtThetaOfPairs(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ);
+
+  diff=comp_2thetas-angle;
+
+  if all(abs(comp_2thetas-angle) > thr_ang) % checks if all values are non-zero
+    theta_OK=false ;
+    thetatype=[] ;
+  else
+    theta_OK=true ;
+    [mini,thetatype]=min(abs(comp_2thetas-angle));
+  end
+
+end
diff --git a/4_spot_sorting/gtMatchDifspotsForCalibration.m b/4_spot_sorting/gtMatchDifspotsForCalibration.m
new file mode 100755
index 0000000000000000000000000000000000000000..65c33c01fcf054fa50fd2dc293c9e784df80bef9
--- /dev/null
+++ b/4_spot_sorting/gtMatchDifspotsForCalibration.m
@@ -0,0 +1,544 @@
+% 
+% 
+% 
+% INPUT:    Two data series of segmented diffraction spots 180 degrees
+%           offset from database.
+%               Images are stored as looking against the beam. The position CentroidX
+%               is measured from the left edge of the images and positive towards 
+%               the right in the images. The position CentroidY is measured from 
+%               the top of the images and positive downwards in the images.
+%
+% OUTPUT:  
+%
+%
+%
+%   Peter Reischig, ESRF, 01/2007
+%
+%%
+
+function gtMatchDifspotsForCalibration(show_findings,button,calibtable,npairs,thresholds)
+
+%%%%%%%%%%%%%%%% conv_rate,con_pix,
+
+global parameters
+if isempty(parameters)
+  disp('Loading parameters.mat')
+  load parameters.mat
+end
+
+%parameters.acq.dist=2.865
+
+%disp('Function is going to delete PairID-s in the difspot tables.')
+%disp('Press any key to continue or Ctrl+c to stop!')
+%pause
+%disp(' ')
+%disp('VALID ONLY FOR FCC (225) CRYSTAL GROUP WITH NO STRAIN!')
+%disp('Press any key to continue!')
+%pause
+tic
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% read PARAMETERS from .mat file
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Thresholds for image position 
+%thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees
+%thr_max_offset=parameters.match.thr_max_offset;     % MaxImage offset threshold; absolut value in #images
+%thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+%thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images
+%corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels  
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+%thr_intint=parameters.match.thr_intint;             % integrated intensity
+%thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box
+%thr_bbsize=parameters.match.thr_bbsize;             % bounding box size
+
+if length(thresholds)==6
+  thr_ang=thresholds(1)
+  thr_max_offset=thresholds(2)
+  thr_ext_offset=thresholds(3)
+  thr_intint=thresholds(4)
+  thr_area=thresholds(5)
+  thr_bbsize=thresholds(6)
+else
+  disp('Using default thresholds.')
+  thr_ang=0.7                % angular threshold; absolute value in degrees
+  thr_max_offset=1           % MaxImage offset threshold; absolut value in #images
+  thr_ext_offset=1           % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+  %thr_genim_offset=0;       % at least one of the three images should be offset as maximum this value in #images
+  
+  % Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+  thr_intint=1.1             % integrated intensity
+  thr_area=1.05              % area of spots inside the bounding box
+  thr_bbsize=1.02            % bounding box size
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sample_radius= parameters.acq.bb(3)/2
+sample_top= parameters.acq.bb(2)
+sample_bot= parameters.acq.bb(2)+parameters.acq.bb(4)
+rot_to_det= parameters.acq.dist/parameters.acq.pixelsize
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = sample_top  % at the top of the sample bounding box (acquisition); lowest number in pixels
+
+fullimages1_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difA_name) ;
+difspotims1_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difA_name) ;
+fullimages2_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difB_name) ;
+difspotims2_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difB_name) ;
+
+table1=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+table2=[parameters.acq.difB_name 'difspot'] ; % difspot table B set
+%pairtable=parameters.acq.pair_tablename ;
+%calibtable=parameters.acq.calib_tablename ;
+
+% For image display
+lowhigh=[-100 100] ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% SET parameters
+
+[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+reflections=results.reflections % type of reflections
+valid_2thetas=results.centre % coloumn vector of all valid 2theta angles in degrees
+
+gtDBconnect ;
+
+nof_spots1= mym(sprintf('select count(*) from %s',table1))
+nof_spots2= mym(sprintf('select count(*) from %s',table2))
+
+mym(sprintf('TRUNCATE %s', calibtable)) ;
+
+pairsfound=0 ;
+sps2.id=[] ;
+
+if (npairs == 0)
+  npairs= -1;
+end
+
+shown=false;
+
+disp('Processing data...')
+disp('Progress:')
+
+%type(length(valid_2thetas)).radius=[] ;
+
+%lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+
+%% Loop through spots1
+
+for i=1:nof_spots1  
+ 
+   [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral]=...
+     mym(sprintf(['select MaxImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+     'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d'],table1,i)) ;
+   
+      %if isnan(sp1.maxim)
+   warning('changed is empty here')
+   if isempty(sp1.maxim)
+   continue
+   end
+   
+    pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;
+    
+    if (sp1.maxim < thr_max_offset)
+        maxim1=parameters.acq.nproj-(thr_max_offset-sp1.maxim) ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (thr_max_offset <= sp1.maxim < parameters.acq.nproj-thr_max_offset)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=sp1.maxim+thr_max_offset ;
+        maxim3=sp1.maxim-thr_max_offset ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (parameters.acq.nproj-thr_max_offset <= sp1.maxim)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset-parameters.acq.nproj ;
+    end
+ 
+    
+    if (sp1.extstim < 2*thr_ext_offset)
+        extstim1=parameters.acq.nproj-(thr_ext_offset-sp1.extstim) ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extstim < parameters.acq.nproj-thr_ext_offset)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=sp1.extstim+thr_ext_offset ;
+        extstim3=sp1.extstim-thr_ext_offset ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extstim)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset-parameters.acq.nproj ;
+    end
+    
+    
+    if (sp1.extendim < thr_ext_offset)
+        extendim1=parameters.acq.nproj-(thr_ext_offset-sp1.extendim) ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extendim < parameters.acq.nproj-thr_ext_offset)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=sp1.extendim+thr_ext_offset ;
+        extendim3=sp1.extendim-thr_ext_offset ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extendim)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset-parameters.acq.nproj ;
+    end
+
+
+    % AT LEAST ONE OF MaxImage,ExtStartImage,ExtEndImage IS MAXIMUM 1 IMAGE OFFSET
+
+   % if (sp1.maxim < thr_genim_offset)
+   %     maxim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.maxim) ;
+   %     maxim2_gen=parameters.acq.nproj-1 ;
+   %     maxim3_gen=0 ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.maxim < parameters.acq.nproj-thr_genim_offset)
+   %     maxim1_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim2_gen=sp1.maxim+thr_genim_offset ;
+   %     maxim3_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.maxim)
+   %     maxim1_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim2_gen=parameters.acq.nproj-1 ;
+   %     maxim3_gen=0 ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset-parameters.acq.nproj ;
+   % end
+   % 
+   % if (sp1.extstim < thr_genim_offset)
+   %     extstim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extstim) ;
+   %     extstim2_gen=parameters.acq.nproj-1 ;
+   %     extstim3_gen=0 ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.extstim < parameters.acq.nproj-thr_genim_offset)
+   %     extstim1_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim2_gen=sp1.extstim+thr_genim_offset ;
+   %     extstim3_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extstim)
+   %     extstim1_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim2_gen=parameters.acq.nproj-1 ;
+   %     extstim3_gen=0 ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset-parameters.acq.nproj ;
+   % end
+   % 
+   %if (sp1.extendim < thr_genim_offset)
+   %     extendim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extendim) ;
+   %     extendim2_gen=parameters.acq.nproj-1 ;
+   %     extendim3_gen=0 ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.extendim < parameters.acq.nproj-thr_genim_offset)
+   %     extendim1_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim2_gen=sp1.extendim+thr_genim_offset ;
+   %     extendim3_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extendim)
+   %     extendim1_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim2_gen=parameters.acq.nproj-1 ;
+   %     extendim3_gen=0 ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset-parameters.acq.nproj ;
+   % end    
+        
+    % Select candidate spots2 from database by all thresholded criteria
+    
+    [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral]= ...
+        mym(sprintf(['select difspotID, MaxImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+        'BoundingBoxYsize, Integral from %s WHERE ', ...
+        '(CentroidX between %f and %f) AND (CentroidY between %f and %f) ', ...
+        'AND (BoundingBoxXsize between %f and %f) AND (BoundingBoxYsize between %f and %f) ', ...
+        'AND (Integral between %f and %f) ', ...
+        'AND (Area between %f and %f) ', ...
+        'AND ((MaxImage between %d and %d) OR (MaxImage between %d and %d)) ', ...
+        'AND ((ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d)) ', ...
+        'AND ((ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d)) '], ...
+        table2,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+        sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+        sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+        sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+        sp1.area/thr_area, sp1.area*thr_area, ...
+        maxim1, maxim2, maxim3, maxim4, ...
+        extstim1, extstim2, extstim3, extstim4, ...
+        extendim1, extendim2, extendim3, extendim4)) ;    %, ...
+      %  maxim1_gen, maxim2_gen, maxim3_gen, maxim4_gen, ...
+      %  extstim1_gen, extstim2_gen, extstim3_gen, extstim4_gen, ...
+      %  extendim1_gen, extendim2_gen, extendim3_gen, extendim4_gen )) ;
+   
+      %  'AND ( (MaxImage between %d and %d) OR (MaxImage between %d and %d) OR ', ...
+      %  '(ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d) OR ', ...
+      %  '(ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d) ) '], ...
+      %  'AND (PairID IS NULL)'], ... 
+            
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+    
+    sqrsum=Inf ;
+    for j=1:length(sps2.id)
+      sp2.pair=mym(sprintf('select pairID from %s where difBID=%d', calibtable, sps2.id(j)));  % ??? perhaps with inner join later, if it can be faster
+      if ~isempty(sp2.pair)  % only proceed if spot is not already paired
+        continue
+      end   
+
+      [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),rot_to_det,parameters.acq.rotx,valid_2thetas,thr_ang);
+      if theta_OK==true
+        sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+          ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 ;  % angular contribution cancelled
+        %sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+        %             ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+        %             (min(abs(angle_diff))/thr_ang)^2;
+        if (sqrsumnew < sqrsum)
+          sqrsum=sqrsumnew ;
+          pairj=j ;
+          sp1.pair=sps2.id(j) ;
+          thetatype_out=thetatype ;
+        end
+      end
+    end
+    
+    if sqrsum < Inf
+        pairsfound=pairsfound+1 ;
+         
+%% Computing output parameters and writing in database
+        
+        cent1X=sp1.centX-parameters.acq.rotx ;
+        cent1Y=sp1.centY ;
+        cent2X=sps2.centX(pairj)-parameters.acq.rotx ;
+        cent2Y=sps2.centY(pairj) ; 
+        
+        deltaX=cent1X+cent2X ;
+        deltaY=-cent1Y+cent2Y ;
+
+        theta=acosd(2*rot_to_det/norm([2*rot_to_det deltaX deltaY]))/2 ;
+        
+        if deltaX >= 0  % 0 < eta < 180deg
+          if deltaY >= 0  % 0 < eta < 90deg
+            eta=atand(deltaX/deltaY) ;
+          else  % 90deg < eta < 180deg
+            eta=atand(deltaX/deltaY)+180 ;
+          end
+        else  % 180deg < eta < 360deg
+          if deltaY < 0  % 180deg < eta < 270deg
+            eta=atand(deltaX/deltaY)+180 ;
+          else  % 270deg < eta < 360deg
+            eta=atand(deltaX/deltaY)+360 ;
+          end  
+        end
+                       
+        % Spot centroid coordinates in the Lab system
+        
+        diff_vec_setup = [2*rot_to_det deltaX deltaY]/norm([2*rot_to_det deltaX deltaY]) ;
+        pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ;
+                
+        omega = ( 180/parameters.acq.nproj*sp1.maxim + 180/parameters.acq.nproj*sps2.maxim(pairj) )/2 ;
+               
+        diff_vec_sam = sfSetup_to_sample_cor(diff_vec_setup,omega) ;
+        pl_vec_sam = sfSetup_to_sample_cor(pl_vec_setup,omega) ;
+        abs_cent1 = sfSetup_to_sample_cor([rot_to_det cent1X -(cent1Y-sorZ)],omega) ;
+        
+        av_intint=(sp1.integral+sps2.integral(pairj))/2 ;
+        av_bbXsize=(sp1.bbXsize+sps2.bbXsize(pairj))/2 ;
+        av_bbYsize=(sp1.bbYsize+sps2.bbYsize(pairj))/2 ;
+              
+        mym(sprintf(['INSERT INTO %s (difAID, difBID, theta, eta, omega, avintint, avbbXsize, avbbYsize, lorX, lorY, lorZ, ldirX, ldirY, ldirZ, plX, plY, plZ, thetatype) ',...
+         'VALUES (%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%d)'], calibtable, i, sp1.pair, theta, eta, omega, av_intint, av_bbXsize, av_bbYsize, abs_cent1(1), abs_cent1(2), abs_cent1(3), ...
+         diff_vec_sam(1), diff_vec_sam(2), diff_vec_sam(3), pl_vec_sam(1), pl_vec_sam(2), pl_vec_sam(3), thetatype_out)) ;
+       
+        %mym(sprintf(['INSERT INTO %s (difAID, difBID) VALUES (%d,%d)'], calibtable, i, sp1.pair));
+       
+%% Display findings when a pair is found
+
+        % FULL IMAGES
+   
+        if show_findings == 1
+          figure(1);
+          fullim1=edf_read([fullimages1_directory, sprintf('/full%04d.edf',sp1.maxim)]) ;
+    
+          lim=max(fullim1(:)) ;
+          %lowhigh=1.2*[-lim,lim] ;
+          %lowhigh=autolim(fullim1) ;
+    
+          fullim2=edf_read([fullimages2_directory, sprintf('/full%04d.edf',sps2.maxim(pairj))]) ;
+          fullim2(parameters.acq.bb(2):(parameters.acq.bb(2)+parameters.acq.bb(4)), parameters.acq.bb(1):(parameters.acq.bb(1)+parameters.acq.bb(3)))=0;
+          totim=fullim1+fliplr(fullim2);
+          imshow(totim,lowhigh);
+          hold on ;
+ 
+          %title(sprintf('Difspot_A: %05d   Difspot_B: %05d           Omega: %5.2f deg    Theta: %5.2f deg    Eta: %5.2f deg', i, sp1.pair,omega,theta,eta)) ;
+        
+          rectangle('Position',[parameters.acq.bb(1)-2,parameters.acq.bb(2)-2,parameters.acq.bb(3)+4,parameters.acq.bb(4)+4],'EdgeColor','c') ;
+          rectangle('Position',[2*parameters.acq.rotx-pr_bb(1)-(pr_bb(3)-pr_bb(1)),pr_bb(2),(pr_bb(3)-pr_bb(1)),(pr_bb(4)-pr_bb(2))],'EdgeColor','b') ;
+          rectangle('Position',[sp1.bbX-2,sp1.bbY-2,sp1.bbXsize+4,sp1.bbYsize+4],'EdgeColor','r') ;
+          rectangle('Position',[2*parameters.acq.rotx-sps2.bbX(pairj)-sps2.bbXsize(pairj)-2,sps2.bbY(pairj)-2,sps2.bbXsize(pairj)+4,sps2.bbYsize(pairj)+4],'EdgeColor','g') ;
+
+          for k=1:length(sps2.id)
+            if k~=pairj
+            plot(2*parameters.acq.rotx-sps2.centX(k),sps2.centY(k),'g*') ;
+            end
+          end
+   
+          % LINE ALONG PROJECTION
+          plot([sp1.centX, 2*parameters.acq.rotx-sps2.centX(pairj)],[sp1.centY, sps2.centY(pairj) ],'c') ;
+           
+          % CIRCLES OF VALID 2THETAS
+          t=(0:1:360)' ;
+          circRthetas=2*rot_to_det*tand(valid_2thetas) ;
+          for k=1:length(circRthetas)
+            circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+            circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+            plot(circthetasX,circthetasY,'b') ;
+          end
+
+          if shown==false
+            circRthetas=2*rot_to_det*tand(valid_2thetas+thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+
+            circRthetas=2*rot_to_det*tand(valid_2thetas-thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+          end
+
+          hold off;
+
+          % DIFSPOTS
+    
+          figure(2);
+%          difspim1=edf_read([difspotims1_directory, sprintf('/difspot%05d.edf', i)]) ;
+difspim1=gtGetSummedDifSpot_pair(i, 1, 1);
+imshow(difspim1, lowhigh) ;
+          rectangle('Position',[1,1,sp1.bbXsize,sp1.bbYsize],'EdgeColor','r') ;
+          title(sprintf('Difspot_A: %5d', i)) ;
+    
+          for k=1:length(sps2.id)
+            figure(k+2);
+ %           difspim2=edf_read([difspotims2_directory, sprintf('/difspot%05d.edf',sps2.id(k))]) ;
+ difspim2=gtGetSummedDifSpot_pair(sps2.id(k), 2, 1);  
+ imshow(fliplr(difspim2), lowhigh) ;
+            no_im=k+2 ;
+            if k==pairj
+              rectangle('Position',[1,1,sps2.bbXsize(k),sps2.bbYsize(k)],'EdgeColor','g') ;
+              title(sprintf('Mathced difspot_B: %5d', sps2.id(k))) ;
+            else
+              title(sprintf('Difspot_B: %5d', sps2.id(k))) ;
+            end
+          end
+
+          if shown==true
+            for kk=no_im+1:pr_im
+              set(kk,'Visible','off') ;
+            end
+          end
+      
+          pr_im=length(sps2.id)+2 ;
+          shown=true;
+          drawnow ;
+         
+          if button==1
+            pause;
+          end
+          
+        end % show findings
+%% Load pair data into database    
+    end % pair found
+    
+    if mod(i,100)==0
+      disp(sprintf('SpotID:  %d   Perfect pairs found:  %d   Perfect matching percentage:  %6.3f %s',i,pairsfound,(pairsfound/i*100),'%')) ;
+    end
+
+    if (pairsfound==npairs)
+      break ;
+    end
+    
+end % end of main loop for spots1
+
+for ii=1:length(valid_2thetas)
+  ntypes(ii)=mym(sprintf('SELECT COUNT(thetatype) FROM %s WHERE thetatype=%d',calibtable,ii));
+end
+
+mym('close')
+
+disp(' ')
+disp(' ')
+disp('Total number of diffraction spots in set #1:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in set #2:'), disp(nof_spots2) ;
+disp('Number of pairs found for correction:'), disp(pairsfound) ;
+disp('    Number of pairs per plane family:'), disp(ntypes) ;
+disp(' ')
+toc
+disp(' ')
+
+end % of function
+
+
+%% Sub-functions used
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
+
diff --git a/4_spot_sorting/gtMatchDifspotsForCalibration_v3.m b/4_spot_sorting/gtMatchDifspotsForCalibration_v3.m
new file mode 100755
index 0000000000000000000000000000000000000000..e16ddf05415a538376a63e850156379dd8452bfc
--- /dev/null
+++ b/4_spot_sorting/gtMatchDifspotsForCalibration_v3.m
@@ -0,0 +1,562 @@
+%
+%
+% function gtMatchDifspotsForCalibration_v3(show_findings,button,calibtable,npairs,thresholds)
+%
+% Looks for perfectly matching diffraction spots from two difspot tables
+% of a 360 degrees scan, using strict tolerances and not trusting on
+% angular information.
+%
+% INPUT:    show_findings = if 1, pairs found are shown graphically
+%           button = if 1, waits for buttonpress after each pair found
+%           measured_2thetas = measured two theta values after calibration
+%           corr = row vector of geometrical corrections:
+%                corr_rottodet_pix = rotation axis to detector distance in pixels
+%                tiltY = tilt around axis Y in Lab system
+%                tiltZ = tilt around axis Z in Lab system
+%             if 0, no cerrections will be applied
+%           thr_geo = geometrical tolerance for the projected sample volume in pixels 
+%
+%
+%
+% OUTPUT:   filling of spotpairs table given in the parameters file
+%
+%
+%
+%   Peter Reischig, ESRF, 02/2006
+%
+%%
+
+
+function gtMatchDifspotsForCalibration_v3(show_findings,button,calibtable,npairs,thresholds)
+
+%%%%%%%%%%%%%%%% conv_rate,con_pix,
+
+global parameters
+if isempty(parameters)
+  disp('Loading parameters.mat')
+  load parameters.mat
+end
+
+%parameters.acq.dist=2.865
+
+%disp('Function is going to delete PairID-s in the difspot tables.')
+%disp('Press any key to continue or Ctrl+c to stop!')
+%pause
+%disp(' ')
+%disp('VALID ONLY FOR FCC (225) CRYSTAL GROUP WITH NO STRAIN!')
+%disp('Press any key to continue!')
+%pause
+tic
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% read PARAMETERS from .mat file
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Thresholds for image position 
+%thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees
+%thr_max_offset=parameters.match.thr_max_offset;     % MaxImage offset threshold; absolut value in #images
+%thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+%thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images
+%corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels  
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+%thr_intint=parameters.match.thr_intint;             % integrated intensity
+%thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box
+%thr_bbsize=parameters.match.thr_bbsize;             % bounding box size
+
+if length(thresholds)==6
+  thr_ang=thresholds(1)
+  thr_max_offset=thresholds(2)
+  thr_ext_offset=thresholds(3)
+  thr_intint=thresholds(4)
+  thr_area=thresholds(5)
+  thr_bbsize=thresholds(6)
+else
+  disp('No proper thresholds were set.')
+  disp('Using default thresholds.')
+  pause (3);
+  thr_ang=0.7                % angular threshold; absolute value in degrees
+  thr_max_offset=1           % MaxImage offset threshold; absolut value in #images
+  thr_ext_offset=1           % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+  %thr_genim_offset=0;       % at least one of the three images should be offset as maximum this value in #images
+  
+  % Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+  thr_intint=1.1             % integrated intensity
+  thr_area=1.05              % area of spots inside the bounding box
+  thr_bbsize=1.02            % bounding box size
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sample_radius= parameters.acq.bb(3)/2
+sample_top= parameters.acq.bb(2)
+sample_bot= parameters.acq.bb(2)+parameters.acq.bb(4)
+rot_to_det= parameters.acq.dist/parameters.acq.pixelsize+parameters.match.corr_rot_to_det
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = floor(parameters.acq.ydet/2)  % in the middle of the central pixel row of the image 
+
+fullimages1_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difA_name) ;
+difspotims1_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difA_name) ;
+fullimages2_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.difB_name) ;
+difspotims2_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.difB_name) ;
+
+table1=[parameters.acq.difA_name 'difspot'] ; % difspot table A set
+table2=[parameters.acq.difB_name 'difspot'] ; % difspot table B set
+%pairtable=parameters.acq.pair_tablename ;
+
+if calibtable==0
+  calibtable=parameters.acq.calib_tablename ;
+end
+
+% For image display
+lowhigh=[-100 100] ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% SET parameters
+
+[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+reflections=results.reflections % type of reflections
+valid_2thetas=results.centre % coloumn vector of all valid 2theta angles in degrees
+
+gtDBconnect ;
+
+nof_spots1= mym(sprintf('select count(*) from %s',table1))
+nof_spots2= mym(sprintf('select count(*) from %s',table2))
+
+mym(sprintf('TRUNCATE %s', calibtable)) ;
+
+pairsfound=0 ;
+sps2.id=[] ;
+
+if (npairs == 0)
+  npairs= -1;
+end
+
+shown=false;
+
+disp('Processing data...')
+disp('Progress:')
+
+%type(length(valid_2thetas)).radius=[] ;
+
+%lambda=gtConvEnergyToWavelength(parameters.acq.energy)   % in angstroms
+
+%% Loop through spots1
+
+for i=1:nof_spots1  
+ 
+   [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral]=...
+     mym(sprintf(['select MaxImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+     'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d'],table1,i)) ;
+   
+    [sp1.centX,sp1.centY]=gtTrImToSc(sp1.centX,sp1.centY);
+   
+    pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;
+    
+    [pr_bb(1),pr_bb(2)]=gtTrScToIm(pr_bb(1),pr_bb(2)) ;
+    [pr_bb(3),pr_bb(4)]=gtTrScToIm(pr_bb(3),pr_bb(4)) ;
+    
+    if (sp1.maxim < thr_max_offset)
+        maxim1=parameters.acq.nproj-(thr_max_offset-sp1.maxim) ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (thr_max_offset <= sp1.maxim < parameters.acq.nproj-thr_max_offset)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=sp1.maxim+thr_max_offset ;
+        maxim3=sp1.maxim-thr_max_offset ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (parameters.acq.nproj-thr_max_offset <= sp1.maxim)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset-parameters.acq.nproj ;
+    end
+ 
+    
+    if (sp1.extstim < 2*thr_ext_offset)
+        extstim1=parameters.acq.nproj-(thr_ext_offset-sp1.extstim) ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extstim < parameters.acq.nproj-thr_ext_offset)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=sp1.extstim+thr_ext_offset ;
+        extstim3=sp1.extstim-thr_ext_offset ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extstim)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset-parameters.acq.nproj ;
+    end
+    
+    
+    if (sp1.extendim < thr_ext_offset)
+        extendim1=parameters.acq.nproj-(thr_ext_offset-sp1.extendim) ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extendim < parameters.acq.nproj-thr_ext_offset)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=sp1.extendim+thr_ext_offset ;
+        extendim3=sp1.extendim-thr_ext_offset ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extendim)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset-parameters.acq.nproj ;
+    end
+
+
+    % AT LEAST ONE OF MaxImage,ExtStartImage,ExtEndImage IS MAXIMUM 1 IMAGE OFFSET
+
+   % if (sp1.maxim < thr_genim_offset)
+   %     maxim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.maxim) ;
+   %     maxim2_gen=parameters.acq.nproj-1 ;
+   %     maxim3_gen=0 ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.maxim < parameters.acq.nproj-thr_genim_offset)
+   %     maxim1_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim2_gen=sp1.maxim+thr_genim_offset ;
+   %     maxim3_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.maxim)
+   %     maxim1_gen=sp1.maxim-thr_genim_offset ;
+   %     maxim2_gen=parameters.acq.nproj-1 ;
+   %     maxim3_gen=0 ;
+   %     maxim4_gen=sp1.maxim+thr_genim_offset-parameters.acq.nproj ;
+   % end
+   % 
+   % if (sp1.extstim < thr_genim_offset)
+   %     extstim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extstim) ;
+   %     extstim2_gen=parameters.acq.nproj-1 ;
+   %     extstim3_gen=0 ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.extstim < parameters.acq.nproj-thr_genim_offset)
+   %     extstim1_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim2_gen=sp1.extstim+thr_genim_offset ;
+   %     extstim3_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extstim)
+   %     extstim1_gen=sp1.extstim-thr_genim_offset ;
+   %     extstim2_gen=parameters.acq.nproj-1 ;
+   %     extstim3_gen=0 ;
+   %     extstim4_gen=sp1.extstim+thr_genim_offset-parameters.acq.nproj ;
+   % end
+   % 
+   %if (sp1.extendim < thr_genim_offset)
+   %     extendim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extendim) ;
+   %     extendim2_gen=parameters.acq.nproj-1 ;
+   %     extendim3_gen=0 ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset ;
+   % elseif (thr_genim_offset <= sp1.extendim < parameters.acq.nproj-thr_genim_offset)
+   %     extendim1_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim2_gen=sp1.extendim+thr_genim_offset ;
+   %     extendim3_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset ;
+   % elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extendim)
+   %     extendim1_gen=sp1.extendim-thr_genim_offset ;
+   %     extendim2_gen=parameters.acq.nproj-1 ;
+   %     extendim3_gen=0 ;
+   %     extendim4_gen=sp1.extendim+thr_genim_offset-parameters.acq.nproj ;
+   % end    
+        
+    % Select candidate spots2 from database by all thresholded criteria
+    
+    [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral]= ...
+        mym(sprintf(['select difspotID, MaxImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+        'BoundingBoxYsize, Integral from %s WHERE ', ...
+        '(CentroidX between %f and %f) AND (CentroidY between %f and %f) ', ...
+        'AND (BoundingBoxXsize between %f and %f) AND (BoundingBoxYsize between %f and %f) ', ...
+        'AND (Integral between %f and %f) ', ...
+        'AND (Area between %f and %f) ', ...
+        'AND ((MaxImage between %d and %d) OR (MaxImage between %d and %d)) ', ...
+        'AND ((ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d)) ', ...
+        'AND ((ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d)) '], ...
+        table2,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+        sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+        sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+        sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+        sp1.area/thr_area, sp1.area*thr_area, ...
+        maxim1, maxim2, maxim3, maxim4, ...
+        extstim1, extstim2, extstim3, extstim4, ...
+        extendim1, extendim2, extendim3, extendim4)) ;    %, ...
+      %  maxim1_gen, maxim2_gen, maxim3_gen, maxim4_gen, ...
+      %  extstim1_gen, extstim2_gen, extstim3_gen, extstim4_gen, ...
+      %  extendim1_gen, extendim2_gen, extendim3_gen, extendim4_gen )) ;
+   
+      %  'AND ( (MaxImage between %d and %d) OR (MaxImage between %d and %d) OR ', ...
+      %  '(ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d) OR ', ...
+      %  '(ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d) ) '], ...
+      %  'AND (PairID IS NULL)'], ... 
+            
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+    
+    [sps2.centX,sps2.centY]=gtTrImToSc(sps2.centX,sps2.centY) ;
+    
+    sqrsum=Inf ;
+    for j=1:length(sps2.id)
+      sp2.pair=mym(sprintf('select pairID from %s where difBID=%d', calibtable, sps2.id(j)));  % ??? perhaps with inner join later, if it can be faster
+      if ~isempty(sp2.pair)  % only proceed if spot is not already paired
+        continue
+      end   
+      
+      [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),rot_to_det,parameters.acq.rotx,valid_2thetas,thr_ang);
+      if theta_OK==true
+        sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+          ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+          ((sps2.extstim(j)-sp1.extstim)/thr_ext_offset)^2 + ((sps2.extendim(j)-sp1.extendim)/thr_ext_offset)^2 ; % angular contribution cancelled
+        if (sqrsumnew < sqrsum)
+          sqrsum=sqrsumnew ;
+          pairj=j ;
+          sp1.pair=sps2.id(j) ;
+          thetatype_out=thetatype ;
+        end
+      end
+    end
+    
+    if sqrsum < Inf
+        pairsfound=pairsfound+1 ;
+         
+%% Computing output parameters and writing in database
+        
+        cent1X=sp1.centX-parameters.acq.rotx ;
+        cent1Y=sp1.centY ;
+        cent2X=sps2.centX(pairj)-parameters.acq.rotx ;
+        cent2Y=sps2.centY(pairj) ; 
+        
+        deltaX=cent1X+cent2X ;
+        deltaY=-cent1Y+cent2Y ;
+
+        theta=acosd(2*rot_to_det/norm([2*rot_to_det deltaX deltaY]))/2 ;
+        
+        if deltaX >= 0  % 0 < eta < 180deg
+          if deltaY >= 0  % 0 < eta < 90deg
+            eta=atand(deltaX/deltaY) ;
+          else  % 90deg < eta < 180deg
+            eta=atand(deltaX/deltaY)+180 ;
+          end
+        else  % 180deg < eta < 360deg
+          if deltaY < 0  % 180deg < eta < 270deg
+            eta=atand(deltaX/deltaY)+180 ;
+          else  % 270deg < eta < 360deg
+            eta=atand(deltaX/deltaY)+360 ;
+          end  
+        end
+                       
+        % Spot centroid coordinates in the Lab system
+        
+        diff_vec_setup = [2*rot_to_det deltaX deltaY]/norm([2*rot_to_det deltaX deltaY]) ;
+        pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ;
+                
+        omega = ( 180/parameters.acq.nproj*sp1.maxim + 180/parameters.acq.nproj*sps2.maxim(pairj) )/2 ;
+               
+        %diff_vec_sam = sfSetup_to_sample_cor(diff_vec_setup,omega) ;
+        %pl_vec_sam = sfSetup_to_sample_cor(pl_vec_setup,omega) ;
+        %abs_cent1 = sfSetup_to_sample_cor([rot_to_det cent1X -(cent1Y-sorZ)],omega) ;
+       
+        [diff_vec_sam(1),diff_vec_sam(2),diff_vec_sam(3)] = gtTrLabToSam(diff_vec_setup(1),diff_vec_setup(2),diff_vec_setup(3),omega) ;
+        [pl_vec_sam(1),pl_vec_sam(2),pl_vec_sam(3)] = gtTrLabToSam(pl_vec_setup(1),pl_vec_setup(2),pl_vec_setup(3),omega) ;
+        [abs_cent1(1),abs_cent1(2),abs_cent1(3)] = gtTrLabToSam(rot_to_det,cent1X,-(cent1Y-sorZ),omega) ;
+        [abs_cent2(1),abs_cent2(2),abs_cent2(3)] = gtTrLabToSam(rot_to_det,cent2X,-(cent2Y-sorZ),omega+180) ;
+                
+        av_intint=(sp1.integral+sps2.integral(pairj))/2 ;
+        av_bbXsize=(sp1.bbXsize+sps2.bbXsize(pairj))/2 ;
+        av_bbYsize=(sp1.bbYsize+sps2.bbYsize(pairj))/2 ;
+              
+        mysqlcmd=sprintf(['INSERT INTO %s (difAID, difBID, theta, eta, omega, avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, thetatype) ',...
+         'VALUES (%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%d)'], calibtable, i, sp1.pair, theta, eta, omega, av_intint, av_bbXsize, av_bbYsize, abs_cent1(1), abs_cent1(2), abs_cent1(3),  abs_cent2(1), abs_cent2(2), abs_cent2(3), ...
+         diff_vec_sam(1), diff_vec_sam(2), diff_vec_sam(3), pl_vec_sam(1), pl_vec_sam(2), pl_vec_sam(3), thetatype_out) ;
+        mym(mysqlcmd) ;
+       
+        %mym(sprintf(['INSERT INTO %s (difAID, difBID) VALUES (%d,%d)'], calibtable, i, sp1.pair));
+       
+%% Display findings when a pair is found
+
+        % FULL IMAGES
+   
+        if show_findings == 1
+          figure(1);
+          fullim1=edf_read([fullimages1_directory, sprintf('/full%04d.edf',sp1.maxim)]) ;
+    
+          %lim=max(fullim1(:)) ;
+          %lowhigh=1.2*[-lim,lim] ;
+          %lowhigh=autolim(fullim1) ;
+    
+          fullim2=edf_read([fullimages2_directory, sprintf('/full%04d.edf',sps2.maxim(pairj))]) ;
+          fullim2(parameters.acq.bb(2):(parameters.acq.bb(2)+parameters.acq.bb(4)), parameters.acq.bb(1):(parameters.acq.bb(1)+parameters.acq.bb(3)))=0;
+          totim=fullim1+fliplr(fullim2);
+          imshow(totim,lowhigh);
+          hold on ;
+ 
+          %title(sprintf('Difspot_A: %05d   Difspot_B: %05d           Omega: %5.2f deg    Theta: %5.2f deg    Eta: %5.2f deg', i, sp1.pair,omega,theta,eta)) ;
+        
+          rectangle('Position',[parameters.acq.bb(1)-2,parameters.acq.bb(2)-2,parameters.acq.bb(3)+4,parameters.acq.bb(4)+4],'EdgeColor','c') ;
+          rectangle('Position',[2*parameters.acq.rotx-pr_bb(1)-(pr_bb(3)-pr_bb(1)),pr_bb(2),(pr_bb(3)-pr_bb(1)),(pr_bb(4)-pr_bb(2))],'EdgeColor','b') ;
+          rectangle('Position',[sp1.bbX-2,sp1.bbY-2,sp1.bbXsize+4,sp1.bbYsize+4],'EdgeColor','r') ;
+          rectangle('Position',[2*parameters.acq.rotx-sps2.bbX(pairj)-sps2.bbXsize(pairj)-2,sps2.bbY(pairj)-2,sps2.bbXsize(pairj)+4,sps2.bbYsize(pairj)+4],'EdgeColor','g') ;
+
+          for k=1:length(sps2.id)
+            if k~=pairj
+            plot(2*parameters.acq.rotx-sps2.centX(k),sps2.centY(k),'g*') ;
+            end
+          end
+   
+          % LINE ALONG PROJECTION
+          plot([sp1.centX, 2*parameters.acq.rotx-sps2.centX(pairj)],[sp1.centY, sps2.centY(pairj) ],'c') ;
+           
+          % CIRCLES OF VALID 2THETAS
+          t=(0:1:360)' ;
+          circRthetas=2*rot_to_det*tand(valid_2thetas) ;
+          for k=1:length(circRthetas)
+            circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+            circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+            plot(circthetasX,circthetasY,'b') ;
+          end
+
+          if shown==false
+            circRthetas=2*rot_to_det*tand(valid_2thetas+thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+
+            circRthetas=2*rot_to_det*tand(valid_2thetas-thr_ang) ;
+            for k=1:length(circRthetas)
+              circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+              circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+              plot(circthetasX,circthetasY,'y') ;
+            end
+          end
+
+          hold off;
+
+          % DIFSPOTS
+    
+          figure(2);
+          difspim1=edf_read([difspotims1_directory, sprintf('/difspot%05d.edf', i)]) ;
+          imshow(difspim1, lowhigh) ;
+          rectangle('Position',[1,1,sp1.bbXsize,sp1.bbYsize],'EdgeColor','r') ;
+          title(sprintf('Difspot_A: %5d', i)) ;
+    
+          for k=1:length(sps2.id)
+            figure(k+2);
+            difspim2=edf_read([difspotims2_directory, sprintf('/difspot%05d.edf',sps2.id(k))]) ;
+            imshow(fliplr(difspim2), lowhigh) ;
+            no_im=k+2 ;
+            if k==pairj
+              rectangle('Position',[1,1,sps2.bbXsize(k),sps2.bbYsize(k)],'EdgeColor','g') ;
+              title(sprintf('Mathced difspot_B: %5d', sps2.id(k))) ;
+            else
+              title(sprintf('Difspot_B: %5d', sps2.id(k))) ;
+            end
+          end
+
+          if shown==true
+            for kk=no_im+1:pr_im
+              set(kk,'Visible','off') ;
+            end
+          end
+      
+          pr_im=length(sps2.id)+2 ;
+          shown=true;
+          drawnow ;
+         
+          if button==1
+            pause;
+          end
+          
+        end % show findings
+%% Load pair data into database    
+    end % pair found
+    
+    if mod(i,100)==0
+      disp(sprintf('SpotID:  %d   Perfect pairs found:  %d   Perfect matching percentage:  %6.3f %s',i,pairsfound,(pairsfound/i*100),'%')) ;
+    end
+
+    if (pairsfound==npairs)
+      break ;
+    end
+    
+end % end of main loop for spots1
+
+for ii=1:length(valid_2thetas)
+  ntypes(ii)=mym(sprintf('SELECT COUNT(thetatype) FROM %s WHERE thetatype=%d',calibtable,ii));
+end
+
+mym('close')
+
+disp(' ')
+disp(' ')
+disp('Total number of diffraction spots in set #1:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in set #2:'), disp(nof_spots2) ;
+disp('Number of pairs found for correction:'), disp(pairsfound) ;
+disp('    Number of pairs per plane family:'), disp(ntypes) ;
+disp(' ')
+toc
+disp(' ')
+
+end % of function
+
+
+%% Sub-functions used
+
+%function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+%  % om = omega angle in degrees
+%  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+%  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+%  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+%  insample_vec(3)= insetup_vec(3) ;
+%end
+
+
+%function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+%  % om = omega angle in degrees
+%  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+%  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+%  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+%  insetup_vec(3)= insample_vec(3) ;
+%end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
diff --git a/4_spot_sorting/gtMatchDifspots_snow.m b/4_spot_sorting/gtMatchDifspots_snow.m
new file mode 100755
index 0000000000000000000000000000000000000000..37548cac6f14edf8842819081993e279d2d5eec6
--- /dev/null
+++ b/4_spot_sorting/gtMatchDifspots_snow.m
@@ -0,0 +1,489 @@
+%
+% FUNCTION gtMatchDifspots(par_match,centmode,tiltY,tiltZ,addconstr,
+%                             savepar,show_findings,dopause)
+%
+%   (Used to be gtMatchDifspots_v3)
+%   Matches difspots of a 360 degree scan, from a single difspot table.
+%   It can take into account tilts and correlate difspots (check if it 
+%   gives any improvement) for better angular precision.
+%   Speed shouldn't depend much on the number of difspots, since it works
+%   on a fraction of the spots (creates and uses a smaller spotpairtable, 
+%   named 'processtable').
+%
+% USAGE e.g. gtMatchDifspots
+%            gtMatchDifspots(par_match)
+%            gtMatchDifspots(par_match,1,0,0,'BoundingBoxXsize>10 and BoundingBoxYsize>10')
+%            gtMatchDifspots(par_match,[],0.1,0.2,[],[],1,'button')
+%
+% OPTIONAL INPUT    
+%
+%  par_match:     matching parameters; if not specified it looks into
+%                 the parameters file
+%  centmode:      centroid of difspots based on: 
+%                    0 or []: uses center of mass from difspot table
+%                    1:       difspots from blobs or edf-s are correlated
+%                    2:       difspots - from summed fulls - are correlated
+%  tiltY:         tilt around horizontal axis (in degrees)
+%  tiltZ:         tilt around vertical axis (in degreees)
+%  addconstr:     additional constraints on which spots to consider in the database           
+%  savepar:       saves the last used match parameters in the parameters file
+%  show_findings: if true, the pairs found and candidates are shown in figures
+%  dopause:       pause time in sec after a pair is found; if set as 'button',
+%                 it waits for button press
+%
+% OUTPUT  loads data in spotpairs table given in the parameters file
+%
+%
+% MATCH TOLERANCES parameters.match... and default values in brackets
+%
+%  Given spotA, which spotB-s to consider.
+%
+%  Diffraction vector:
+%   thr_ang:           theta angular deviation; absolute value in degrees (0.2)
+%   corr_rot_to_det:   correction of rotation-axis - detector dist. in pixels (0)
+%
+%  Thresholds for full image positions:
+%   thr_max_offset:    CentroidImage offset threshold; absolut value in #images (2)
+%   thr_ext_offset:    ExtStartImage and ExtEndImage offset threshold; absolut value in #images (10)
+%   thr_genim_offset:  at least one of the three images should be offset as maximum this value in #images (1)
+%
+%  Thresholds for difspot images (for search between the limits: basevalue/thr & basevalue*thr)
+%   thr_intint:        integrated intensity (3)
+%   thr_area:          area of spots inside the bounding box (1.2)
+%   thr_bbsize:        bounding box size (1.2)
+%
+%
+%
+%
+%  by Peter Reischig, ESRF, 11/2007
+%
+%%
+
+
+function gtMatchDifspots(par_match,centmode,tiltY,tiltZ,addconstr,savepar,show_findings,dopause)
+
+load parameters.mat
+
+tic
+
+if ~exist('par_match','var')
+  par_match=[];
+end
+
+if ~exist('centmode','var')
+  centmode=[];
+end
+
+if isempty(centmode)
+  centmode=0;
+end
+
+if ~exist('tiltY','var')
+  tiltY=0;
+end
+
+if ~exist('tiltZ','var')
+  tiltZ=0;
+end
+
+if ~exist('addconstr','var')
+  addconstr=[];
+elseif isempty(addconstr)
+  addconstr=[];
+else
+  addconstr=[' and ' addconstr];
+end
+
+if ~exist('savepar','var')
+  savepar=false;
+end
+
+if ~exist('show_findings','var')
+  show_findings=false;
+end
+
+if ~exist('startat','var')
+  startat=[];
+end
+
+
+%% Default parameters
+if isempty(par_match) && ~isfield(parameters.match,'thr_ang') % modif sabine || 
+    % replaced by && otherwise it doesnot read the match parameters you add
+    % in the parameters file
+  disp('Using default parameters.')
+  parameters.match.thr_ang=0.2;
+  parameters.match.thr_max_offset=2;
+  parameters.match.thr_ext_offset=10;
+  parameters.match.thr_genim_offset=1;
+  parameters.match.corr_rot_to_det=0;
+
+  parameters.match.thr_intint=3;
+  parameters.match.thr_area=1.2;
+  parameters.match.thr_bbsize=1.2;
+elseif ~isempty(par_match)
+  parameters.match=par_match;
+end
+
+parameters.match.centmode=centmode;
+parameters.match.tiltY=tiltY;  
+parameters.match.tiltZ=tiltZ;
+parameters.match.addconstr=addconstr;
+
+disp(parameters.match)
+
+if savepar
+  save('parameters.mat','parameters')
+  disp(' ')
+  disp('Actual matching parameters are saved in the parameters file.')
+end
+
+%% Set up search parameters
+
+% Tolerances for image position
+thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees (0.2)
+thr_max_offset=parameters.match.thr_max_offset;     % CentroidImage offset threshold; absolut value in #images (2)
+thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images (10)
+thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images (1)
+corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels (0)
+% Tolerances (for search within the limits: basevalue/thr & basevalue*thr)
+thr_intint=parameters.match.thr_intint;             % integrated intensity (3)
+thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box (1.2)
+thr_bbsize=parameters.match.thr_bbsize;             % bounding box size (1.2)
+
+sample_radius=parameters.acq.bb(3)/2;
+% Sample geometry in imagesm:
+sample_top=parameters.acq.bb(2);
+sample_bot=parameters.acq.bb(2)+parameters.acq.bb(4);
+rot_to_det=parameters.acq.dist/parameters.acq.pixelsize+corr_rot_to_det;
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition
+% sorY = on the rotation axis by definition
+sample=gtSampleGeoInSampleSystem(parameters);
+sorZ=sample.sorZim;                     % floor(parameters.acq.ydet/2);
+
+if isfield(parameters.acq, 'difA_name')
+  difspottable=[parameters.acq.difA_name 'difspot'];
+  makeprocesstable=[parameters.acq.difA_name 'process_'];
+  processtable=[parameters.acq.difA_name 'process_difspot'];
+else
+  difspottable=[parameters.acq.name 'difspot'];
+  makeprocesstable=[parameters.acq.name 'process_'];
+  processtable=[parameters.acq.name 'process_difspot'];
+end
+
+pairtable=parameters.acq.pair_tablename ;
+nproj=parameters.acq.nproj; % number of preojections per 180 degrees
+
+nofspotspertable=2000; % no.of spots in the processtable (2000 seems good)
+
+[tmp,results]=gtnew_calculate_twotheta() ;
+comp_2thetas=results.centre; % coloumn vector of all valid 2theta angles in degrees
+
+disp(' ')
+%close all
+
+gtDBCreateDifspotTable(makeprocesstable,1)
+gtDBCreateSpotPairTable(pairtable,1)
+
+nof_spots1=mym(sprintf('select count(*) from %s where CentroidImage between %0.20g and %0.20g %s and Area>300',difspottable,0,nproj,addconstr))
+nof_spots2=mym(sprintf('select count(*) from %s where CentroidImage between %0.20g and %0.20g %s and Area>300',difspottable,nproj,2*nproj,addconstr))
+
+[spotsA,centim]=mym(sprintf(['select difspotID,CentroidImage from %s where CentroidImage<=%d %s and Area>300',...
+' order by CentroidImage asc, Integral desc'],difspottable,nproj+thr_max_offset,addconstr));
+
+max_difspotID=mym(sprintf('select max(difspotID) from %s',difspottable));
+pairedspots=false(max_difspotID,1);
+
+if isempty(startat)
+  mym(sprintf('truncate %s',pairtable)) ;
+  disp('Data in spotpairs table have been deleted, if there were any.') ;
+  istart=1;  
+else
+  error('Update this part if needed at all...')
+%   pairedA=mym(sprintf('select difAID from %s',pairtable));
+%   pairedB=mym(sprintf('select difBID from %s',pairtable));
+%   pairedspots(pairedA)=true;
+%   pairedspots(pairedB)=true;
+%   [tmp,istart]=min(abs(values_orderby-startat));
+end
+
+pairsfound=0;
+show_bands=true;
+
+disp('Processing data...')
+disp('Progress:')
+disp('    #Spots     SpotID A     Integral  Pairs found  Matching');
+
+%% Main loop for spots from first half
+for i=istart:length(spotsA)    
+
+  
+  
+  sp1.id=spotsA(i);
+
+  if pairedspots(sp1.id)
+    continue
+  end
+
+  % create new processtable
+  if mod(i-istart,nofspotspertable)==0
+    centim_begin=centim(i)+nproj-thr_max_offset;
+    centim_end=centim(min([i+nofspotspertable length(centim)]))+nproj+thr_max_offset;
+   
+    mym(sprintf('TRUNCATE %s',processtable))
+    mysqlcmd=sprintf(['INSERT INTO %s SELECT difspotID,StartImage,EndImage,MaxImage,ExtStartImage,ExtEndImage, Area, CentroidX, CentroidY,'...
+	   'CentroidImage, BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize,Integral FROM %s WHERE CentroidImage BETWEEN %0.20g AND %0.20g']...
+      ,processtable,difspottable,centim_begin,centim_end);
+    mym(mysqlcmd);
+  end
+    
+  
+  
+  [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral]=...
+    mym(sprintf(['select CentroidImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+    'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d %s'],difspottable,sp1.id,addconstr)) ;
+
+  pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;
+
+  % Set limits for search between lim1..lim2
+
+  % CentroidImage, ExtStart, Extend limits for pair
+  [maxim1,maxim2]=sfCalcBoundaries(sp1.maxim,thr_max_offset,nproj);
+  [extstim1,extstim2]=sfCalcBoundaries(sp1.extstim,thr_ext_offset,nproj);
+  [extendim1,extendim2]=sfCalcBoundaries(sp1.extendim,thr_ext_offset,nproj);
+
+  % At least one of them should also fulfill thr_genim_offset
+  [maxim1_gen,maxim2_gen]=sfCalcBoundaries(sp1.maxim,thr_genim_offset,nproj);
+  [extstim1_gen,extstim2_gen]=sfCalcBoundaries(sp1.extstim,thr_genim_offset,nproj);
+  [extendim1_gen,extendim2_gen]=sfCalcBoundaries(sp1.extendim,thr_genim_offset,nproj);
+
+
+  % Select candidate spots2 from database by all the criteria
+  [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral]= ...
+    mym(sprintf(['SELECT difspotID, CentroidImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+    'BoundingBoxYsize, Integral FROM %s WHERE ', ...
+    '(CentroidX between %0.20g and %0.20g) AND (CentroidY between %0.20g and %0.20g) ', ...
+    'AND (BoundingBoxXsize between %0.20g and %0.20g) AND (BoundingBoxYsize between %0.20g and %0.20g) ', ...
+    'AND (Integral between %0.20g and %0.20g) ', ...
+    'AND (Area between %0.20g and %0.20g) ', ...
+    'AND (CentroidImage between %0.20g and %0.20g) ', ...
+    'AND (ExtStartImage between %d and %d) ', ...
+    'AND (ExtEndImage between %d and %d) ', ...
+    'AND ((CentroidImage between %0.20g and %0.20g) OR ', ...
+    '(ExtStartImage between %d and %d) OR ', ...
+    '(ExtEndImage between %d and %d)) ', ...
+    ' %s'], ...
+    processtable,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+    sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+    sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+    sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+    sp1.area/thr_area, sp1.area*thr_area, ...
+    maxim1, maxim2, ...
+    extstim1, extstim2, ...
+    extendim1, extendim2, ...
+    maxim1_gen, maxim2_gen, ...
+    extstim1_gen, extstim2_gen, ...
+    extendim1_gen, extendim2_gen, ...
+    addconstr)) ;
+
+  % Delete candidates already paired
+  sps2.maxim(pairedspots(sps2.id))=[];
+  sps2.extstim(pairedspots(sps2.id))=[];
+  sps2.extendim(pairedspots(sps2.id))=[];
+  sps2.area(pairedspots(sps2.id))=[];
+  sps2.centX(pairedspots(sps2.id))=[];
+  sps2.centY(pairedspots(sps2.id))=[];
+  sps2.bbX(pairedspots(sps2.id))=[];
+  sps2.bbY(pairedspots(sps2.id))=[];
+  sps2.bbXsize(pairedspots(sps2.id))=[];
+  sps2.bbYsize(pairedspots(sps2.id))=[];
+  sps2.integral(pairedspots(sps2.id))=[];
+  sps2.id(pairedspots(sps2.id))=[];
+
+
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+
+  sqrsum=Inf ;
+
+  for j=1:length(sps2.id)
+    
+     [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),...
+       rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ,comp_2thetas,thr_ang);
+    
+    if theta_OK==true
+      sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+        ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+        (min(abs(angle_diff))/thr_ang)^2 + ...
+        ((sps2.extstim(j)-sp1.extstim)/thr_ext_offset)^2 + ((sps2.extendim(j)-sp1.extendim)/thr_ext_offset)^2 ;
+      if (sqrsumnew < sqrsum)
+        sqrsum=sqrsumnew ;
+        pairj=j ;
+        thetatype_out=thetatype ;
+      end
+    end
+  end
+
+  
+%% Being left with the right pair spot, compute output parameters and loading database
+
+  if sqrsum < Inf
+    pairsfound=pairsfound+1 ;
+    
+    % Save pair data sp2
+    sp2.id=sps2.id(pairj);
+    sp2.maxim=sps2.maxim(pairj);
+    sp2.extstim=sps2.extstim(pairj);
+    sp2.extendim=sps2.extendim(pairj);
+    sp2.area=sps2.area(pairj);
+    sp2.centX=sps2.centX(pairj);
+    sp2.centY=sps2.centY(pairj);
+    sp2.integral=sps2.integral(pairj);
+    sp2.bbXsize=sps2.bbXsize(pairj);
+    sp2.bbYsize=sps2.bbYsize(pairj);
+    sp2.bbX=sps2.bbX(pairj);
+    sp2.bbY=sps2.bbY(pairj);
+
+    % Leave only the wrong candidates in sps2
+    sps2.maxim(pairj)=[];
+    sps2.extstim(pairj)=[];
+    sps2.extendim(pairj)=[];
+    sps2.area(pairj)=[];
+    sps2.centX(pairj)=[];
+    sps2.centY(pairj)=[];
+    sps2.bbX(pairj)=[];
+    sps2.bbY(pairj)=[];
+    sps2.bbXsize(pairj)=[];
+    sps2.bbYsize(pairj)=[];
+    sps2.integral(pairj)=[];
+    sps2.id(pairj)=[];
+   
+    pairedspots(sp1.id)=true;
+    pairedspots(sp2.id)=true;
+    
+  
+    switch centmode
+  
+      case {0, []}
+      
+      case 1 % correlate difspots (edf-s or blobs)
+        [corrx,corry]=gtCorrelateDifspots(sp1.id,sp2.id,parameters,centmode,1);
+        sp2.centX=sp2.centX-corrx; % the negative of corr is applied, since
+                                   %  corr referred to the flipped image 
+        sp2.centY=sp2.centY+corry;                         
+
+      case 2 % correlate summed fulls over the difspot bb
+        [corrx,corry]=gtCorrelateDifspots(sp1.id,sp2.id,parameters,centmode,1);
+        sp2.centX=sp2.centX-corrx; % the negative of corr is applied, since
+                                   %  corr referred to the flipped image 
+        sp2.centY=sp2.centY+corry;                         
+
+    end
+
+    
+    theta= gtThetaOfPairs(sp1.centX,sp1.centY,sp2.centX,sp2.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+    eta= gtEtaOfPairs(sp1.centX,sp1.centY,sp2.centX,sp2.centY,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+
+    diff_vec_setup= gtDiffVecInLab(sp1.centX,sp1.centY,sp2.centX,sp2.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+
+    pl_vec_setup= gtDiffPlaneNormInLab(sp1.centX,sp1.centY,sp2.centX,sp2.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ);
+
+    omega1=180/nproj*sp1.maxim;
+    omega2=180/nproj*sp2.maxim; % (sp2.maxim should always be larger)
+    omega=(omega1+omega2-180)/2; % the average of the two
+
+    [diff_vec_sam(1),diff_vec_sam(2),diff_vec_sam(3)] = gtTrLabToSam(diff_vec_setup(1),diff_vec_setup(2),diff_vec_setup(3),omega) ;
+    [pl_vec_sam(1),pl_vec_sam(2),pl_vec_sam(3)] = gtTrLabToSam(pl_vec_setup(1),pl_vec_setup(2),pl_vec_setup(3),omega) ;
+
+    [lab_cent1(1),lab_cent1(2),lab_cent1(3)] = gtTrScToLab(sp1.centX,sp1.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+    [lab_cent2(1),lab_cent2(2),lab_cent2(3)] = gtTrScToLab(sp2.centX,sp2.centY,rot_to_det,tiltY,tiltZ,parameters.acq.rotx,sorZ) ;
+
+    [samcentA(1),samcentA(2),samcentA(3)] = gtTrLabToSam(lab_cent1(1),lab_cent1(2),lab_cent1(3),omega1) ;
+    [samcentB(1),samcentB(2),samcentB(3)] = gtTrLabToSam(lab_cent2(1),lab_cent2(2),lab_cent2(3),omega2) ;
+    
+    
+    av_intint=(sp1.integral+sp2.integral)/2 ;
+    av_bbXsize=(sp1.bbXsize+sp2.bbXsize)/2 ;
+    av_bbYsize=(sp1.bbYsize+sp2.bbYsize)/2 ;
+ 
+    % Variables in table
+    % samcent: difspot centroid in the sample system
+    % lines connecing the two spots in the sample system
+    % lor: line origin (centroid of spot A);
+    % ldir: unit vector of line direction
+    % pl: plane normal in sample system
+    mysqlcmd=sprintf(['INSERT INTO %s (difAID, difBID, theta, eta, omega, avintint, avbbXsize, avbbYsize, '...
+      'samcentXA, samcentYA, samcentZA, samcentXB, samcentYB, samcentZB, '...
+      'ldirX, ldirY, ldirZ, plX, plY, plZ, thetatype) ',...
+      'VALUES (%d,%d,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%0.20g,%d)'],...
+      pairtable,sp1.id,sp2.id,theta,eta,omega,av_intint,av_bbXsize,av_bbYsize,...
+      samcentA(1),samcentA(2),samcentA(3),samcentB(1),samcentB(2),samcentB(3),...
+      diff_vec_sam(1),diff_vec_sam(2),diff_vec_sam(3),pl_vec_sam(1),pl_vec_sam(2),pl_vec_sam(3),thetatype_out) ;
+    mym(mysqlcmd);
+
+    
+%% Display findings
+
+    if show_findings
+
+      gtShowPairFigure(1,parameters,sp1,sp2,pr_bb,comp_2thetas,show_bands,...
+                       sps2,[],[],omega,theta,eta)
+      show_bands=false;
+      if strcmpi('button',dopause)
+        waitforbuttonpress
+      else
+        pause(dopause)
+      end
+    end
+
+  end % pair found
+
+  if mod(i,100)==0
+    disp(sprintf('%10d   %10d   %10.1f   %10d   %3.2f%%',i,sp1.id,sp1.integral,pairsfound,pairsfound/(i-istart+1)*100)) ;
+  end
+
+end % end of main loop for spotsA
+
+disp('Total number of diffraction spots in first half:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in second half:'), disp(nof_spots2) ;
+disp('Number of pairs found:'), disp(pairsfound) ;
+disp('Total number of pairs in spotpairtable:')
+disp(mym(sprintf('Select count(pairID) from %s',pairtable)));
+
+disp(' ');
+toc
+disp(' ')
+
+gtEvaluateDifspotMatch([],'pair_dist')
+
+end % of function
+
+
+%% Sub-functions used
+
+% Given an image number, returns the boundaries of two ranges (as image numbers)
+% with an offset of 180degree +-tol offset.
+function [b1,b2]=sfCalcBoundaries(imno1,tol,nproj)
+  b1=imno1+nproj-tol;
+  b2=imno1+nproj+tol;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ,comp_2thetas,thr_ang)
+% Checks whether the position of two spots gives a diffraction vector which
+% corresponds to a valid 2theta angle within the given threshold.
+
+  angle=2*gtThetaOfPairs(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ);
+
+  diff=comp_2thetas-angle;
+
+  if all(abs(comp_2thetas-angle) > thr_ang) % checks if all values are non-zero
+    theta_OK=false ;
+    thetatype=[] ;
+  else
+    theta_OK=true ;
+    [mini,thetatype]=min(abs(comp_2thetas-angle));
+  end
+
+end
diff --git a/4_spot_sorting/gtMoveDifspotsIntoSingleTable.m b/4_spot_sorting/gtMoveDifspotsIntoSingleTable.m
new file mode 100755
index 0000000000000000000000000000000000000000..9b9cc4bbb31be6ddfa99c06d57ffc7352778dde4
--- /dev/null
+++ b/4_spot_sorting/gtMoveDifspotsIntoSingleTable.m
@@ -0,0 +1,95 @@
+%
+% FUNCTION gtMoveDifspotsIntoSingleTable(parameters,deleteolddata)
+%
+%  Copies 2 difspot tables into a single one.
+%  
+% OPTIONAL INPUT
+%   parameters: if empty, it will look for the parameters file, otherwise 
+%               define the following fields: 
+%                 parameters.acq.nproj
+%                 parameters.acq.difA_name (without 'difspot' at the end)
+%                 parameters.acq.difB_name (without 'difspot' at the end)
+%   deletetolddata: if true, old tables will be dropped afterwards. 
+%
+
+function gtMoveDifspotsIntoSingleTable(parameters,deletetolddata)
+
+if ~exist('deletetolddata','var')
+  deletetolddata=[];
+end
+
+if ~exist('parameters','var')
+  parameters=[];
+end
+
+par_loaded=false;
+if isempty(parameters)
+  par_loaded=true;
+  load parameters.mat
+end
+
+nproj=parameters.acq.nproj;
+difnameA=[parameters.acq.difA_name 'difspot'];
+difnameAarch=[parameters.acq.difA_name 'difspot_xxx'];
+difnameB=[parameters.acq.difB_name 'difspot'];
+difnameBarch=[parameters.acq.difB_name 'difspot_xxx'];
+newtablename=parameters.acq.difA_name;
+
+
+gtDBConnect('admin')
+
+disp(' ')
+disp('Processing tables...')
+disp('  Values of CentroidImage will be taken from MaxImage.')
+disp(' ')
+
+mym(sprintf('DROP TABLE IF EXISTS %s',difnameAarch));
+mym(sprintf('DROP TABLE IF EXISTS %s',difnameBarch));
+
+mym(sprintf('RENAME TABLE %s TO %s',difnameA,difnameAarch))
+mym(sprintf('RENAME TABLE %s TO %s',difnameB,difnameBarch))
+
+gtDBCreateDifspotTable(newtablename)
+newtablename=[newtablename 'difspot'];
+
+disp(sprintf('Copying data from %s...',difnameA))
+mysqlcmd=sprintf(['INSERT INTO %s '...
+  '(StartImage,EndImage,MaxImage,CentroidImage,ExtStartImage,ExtEndImage,'...
+  'Area,CentroidX,CentroidY,BoundingBoxXorigin,'...
+  'BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize,Integral) '...
+  'SELECT '...
+  'StartImage,EndImage,MaxImage,MaxImage,ExtStartImage,ExtEndImage,'...
+  'Area,CentroidX,CentroidY,BoundingBoxXorigin,'...
+  'BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize,Integral '...
+  'FROM %s'],newtablename,...
+  difnameAarch);
+mym(mysqlcmd);
+
+disp(sprintf('Copying data from %s...',difnameB))
+mysqlcmd=sprintf(['INSERT INTO %s '...
+  '(StartImage,EndImage,MaxImage,CentroidImage,ExtStartImage,ExtEndImage,'...
+  'Area,CentroidX,CentroidY,BoundingBoxXorigin,'...
+  'BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize,Integral) '...
+  'SELECT '...
+  'StartImage+%d,EndImage+%d,MaxImage+%d,MaxImage+%d,ExtStartImage+%d,ExtEndImage+%d,'...
+  'Area,CentroidX,CentroidY,BoundingBoxXorigin,'...
+  'BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize,Integral '...
+  'FROM %s'],newtablename,nproj,nproj,nproj,nproj,nproj,nproj,...
+  difnameBarch);
+mym(mysqlcmd);
+
+if deletetolddata
+  mym(sprintf('DROP TABLE %s',difnameAarch));
+  mym(sprintf('DROP TABLE %s',difnameBarch));
+  disp(sprintf('Table %s and %s have been dropped.',difnameA,difnameB))
+  parameters.acq.difA_name=newtablename;
+  parameters.acq.difB_name=[];
+  if par_loaded
+    save('parameters.mat',parameters)
+    disp('Table names in the parameters file have been updated.')
+  end
+end
+
+disp('Finished.')
+
+end % of function
diff --git a/4_spot_sorting/gtPairs2Grains.m b/4_spot_sorting/gtPairs2Grains.m
new file mode 100755
index 0000000000000000000000000000000000000000..c61019345c42a6ea4d72df728edab650f6f3ec82
--- /dev/null
+++ b/4_spot_sorting/gtPairs2Grains.m
@@ -0,0 +1,343 @@
+%for Andreas2_ multilayer dataset.  Try indexing based on scattering
+%vectors only.  
+%Simple approach for the small dataset
+function [difAID, difBID, r_vector, grain_pos] = gtPairs2Grains(x)
+
+dev_test=1;%what angular tolerence? (degrees)
+real_test=4;%what real space tolerance? (grainsize/real_test)
+plot_flag=1; %plot figures? - slow because of looking up spot images
+
+gtDBConnect
+parameters=[];
+load parameters
+
+%first need to pick a large, paired 111 or 002 (or anything?)
+candidates = sfSelectPairedCandidates;
+%candidates is the pairID
+
+candidate=candidates(x);
+
+
+
+%get the data that will be used
+[pairIDs,plX,plY,plZ,thetatype]=mym('select pairID, plX, plY, plZ, thetatype from ss_crackedAB_spotpairs where thetatype=1 or thetatype=2');
+[lorX, lorY, lorZ, ldirX, ldirY, ldirZ]=mym('select lorX, lorY, lorZ, ldirX, ldirY, ldirZ from ss_crackedAB_spotpairs where thetatype=1 or thetatype=2');
+[difAIDs, difBIDs]=mym('select difAID, difBID from ss_crackedAB_spotpairs where thetatype=1 or thetatype=2');
+linedata=[lorX, lorY, lorZ, ldirX, ldirY, ldirZ];
+plane_normals = zeros(length(plX), 3);
+plane_normals(:,1) = plX;
+plane_normals(:,2) = plY;
+plane_normals(:,3) = plZ;
+hkls=zeros(length(thetatype), 3);
+hkls(find(thetatype==1),:)=repmat([1 1 1],length(find(thetatype==1)),1);
+hkls(find(thetatype==2),:)=repmat([0 0 2],length(find(thetatype==2)),1);
+
+%deal with the first two diffraction rings only - low multiplicities means
+%less spots to consider - mixed blessing.
+allowed_angles11=sfGetAllowedAngles([1 1 1], [1 1 1]);
+allowed_angles12=sfGetAllowedAngles([1 1 1], [0 0 2]);
+allowed_angles22=sfGetAllowedAngles([0 0 2], [0 0 2]);
+allowed_angles11=repmat(allowed_angles11,length(plane_normals),1);
+allowed_angles12=repmat(allowed_angles12,length(plane_normals),1);
+allowed_angles22=repmat(allowed_angles22,length(plane_normals),1);
+
+%pick out the candidate
+testpair=find(pairIDs==candidate);
+
+subject_normal=plane_normals(testpair,:);
+subject_normal=repmat(subject_normal, size(plane_normals,1), 1);
+%interplanar angles in degrees
+angles=(180/pi)*acos(dot(subject_normal, plane_normals, 2));
+
+shortlist=[];
+
+if thetatype(testpair)==1
+  %test against all 111-111 allowed angles
+  dev_angles = abs(repmat(angles,1,size(allowed_angles11,2)) - allowed_angles11);
+  dev_angles = min(dev_angles,[],2);
+  shortlist=find(dev_angles<dev_test & thetatype==1);
+  %plus do the 111-002 combinations
+  dev_angles = abs(repmat(angles,1,size(allowed_angles12,2)) - allowed_angles12);
+  dev_angles = min(dev_angles,[],2);
+  shortlist = [shortlist; find(dev_angles<dev_test & thetatype==2)];
+elseif thetatype(testpair)==2
+  %test against all 002-002 allowed angles
+  dev_angles = abs(repmat(angles,1,size(allowed_angles22,2)) - allowed_angles22);
+  dev_angles = min(dev_angles,[],2);
+  shortlist=find(dev_angles<dev_test & thetatype==2);
+  %plus do the 111-002 combinations
+  dev_angles = abs(repmat(angles,1,size(allowed_angles12,2)) - allowed_angles12);
+  dev_angles = min(dev_angles,[],2);
+  shortlist = [shortlist; find(dev_angles<dev_test & thetatype==1)];
+end
+
+
+%This is a shortlist of possible plane normals according to scattering
+%vector direction.  
+%...now, do real space
+
+%get difspot data
+[difAID, difBID]=mym(sprintf('select difAID, difBID from ss_crackedAB_spotpairs where pairID=%d',candidate));
+[spotsizex(1), spotsizey(1)]=mym(sprintf('select boundingboxXsize, boundingboxYsize from ss_crackedA_difspot where difspotid=%d',difAID));
+[spotsizex(2), spotsizey(2)]=mym(sprintf('select boundingboxXsize, boundingboxYsize from ss_crackedB_difspot where difspotid=%d',difBID));
+spotsizex=mean(spotsizex);
+spotsizey=mean(spotsizey);
+spotsize=mean([spotsizex spotsizey]);
+
+distance=zeros(size(shortlist));
+points=zeros(length(shortlist),3);
+
+if plot_flag
+%testpair line:
+point1=linedata(testpair,1:3);
+point1=point1-3000*linedata(testpair,4:6);
+point2=point1-1000*linedata(testpair,4:6);
+pdata=[point1; point2];
+figure
+hold on
+plot3(pdata(:,1), pdata(:,2), pdata(:,3),'r')
+end
+
+%pick out intersections from which a grain position can be refined
+grainpoints=[];
+for a=1:length(shortlist)
+  point=pofintersectexp(linedata([testpair shortlist(a)], :))'; %best point between the two lines
+  distance(a)=pointtolinedist(point, linedata(testpair, :));
+  points(a,:)=point;
+  
+  %if lines are ~ parallel, this gets ugly
+  if distance(a)>25
+  plot3(point(1), point(2), point(3), 'go')
+  elseif distance(a) >5
+    plot3(point(1), point(2), point(3), 'ro')
+  else
+    if angles(shortlist(a))>5 %only plot if the angle is greater than 5 degrees
+      %similarly, can only get grain position from lines more than a few
+      %degrees apart.
+      if plot_flag
+        plot3(point(1), point(2), point(3), 'bo')
+      end
+      grainpoints=[grainpoints; point];%use to refine position
+    end
+  end
+end
+
+
+%then, refine grain position
+%need outlier rejecting least squares approach from grainpoints.
+%to work in a single variable, use t, where t is a coordinate along the path
+%of the original spot
+
+%hard code some sensible limits
+tmin=3000
+tmax=4000
+
+t_grain = fminbnd(@(t) sfFindGrain(grainpoints, t), tmin, tmax);
+
+x_grain=linedata(testpair,1)-t_grain*linedata(testpair,4);
+y_grain=linedata(testpair,2)-t_grain*linedata(testpair,5);
+z_grain=linedata(testpair,3)-t_grain*linedata(testpair,6);
+
+plot3(x_grain, y_grain, z_grain, 'xr', 'markersize', 20)
+
+%Finally (?) reject those lines which intersect too far from the grain
+%position
+dist = points-repmat([x_grain y_grain z_grain], size(points, 1), 1);
+dist = sqrt(sum((dist.*dist),2)); % distance of each point from grain
+shortlist2 = shortlist;
+shortlist2(find(dist>spotsize/real_test))=[];
+points2=points;
+points2(find(dist>spotsize/real_test), :)=[]; %points is now same length as shortlist2
+
+
+if plot_flag
+  %look at these spots
+  figure
+  for a=1:length(shortlist2)
+    im=gtGetSummedDifSpot_pair(difAIDs(shortlist2(a)), 1);
+    subplot(2,length(shortlist2), a); imshow(im, [])
+    im=gtGetSummedDifSpot_pair(difBIDs(shortlist2(a)), 2);
+    subplot(2,length(shortlist2), a+length(shortlist2)); imshow(im, [])
+  end
+end
+
+%run consistancy test of the final group of spots
+[r_vector, goods]=plot_rodrigues_consistancy(plane_normals(shortlist2,:), hkls(shortlist2,:),plot_flag);
+points3=points2(goods,:)
+shortlist3=shortlist2(goods)
+
+if plot_flag
+  figure
+  for a=1:length(shortlist3)
+    im=gtGetSummedDifSpot_pair(difAIDs(shortlist3(a)), 1);
+    subplot(2,length(shortlist3), a); imshow(im, [])
+    im=gtGetSummedDifSpot_pair(difBIDs(shortlist3(a)), 2);
+    subplot(2,length(shortlist3), a+length(shortlist3)); imshow(im, [])
+  end
+end
+
+
+%for output
+difAID=difAIDs(shortlist3)
+difBID=difBIDs(shortlist3)
+
+%should refine grain position again, having done the consistancy check
+t_grain = fminbnd(@(t) sfFindGrain(points3, t), tmin, tmax);
+
+x_grain=linedata(testpair,1)-t_grain*linedata(testpair,4);
+y_grain=linedata(testpair,2)-t_grain*linedata(testpair,5);
+z_grain=linedata(testpair,3)-t_grain*linedata(testpair,6);
+
+grain_pos=[x_grain y_grain z_grain];
+
+%then, call forward simulate to get anything missed, any unpaired spots,
+%and any higher order {hkl} pairs.
+%assemble data
+struct_ids=[difAID; difBID];
+pair_vector=[ones(size(difAID)); 2*ones(size(difBID))];
+[struct_ids_new, pair_vector_new] = gtForwardSimulate_pair2grain(grain_pos, r_vector, struct_ids, pair_vector, parameters)
+
+%now, assemble all info for these new spots.  
+struct_ids=[struct_ids; struct_ids_new'];
+pair_vector=[pair_vector; pair_vector_new'];
+grainTheta=[]; grainEta=[]; grainOmega=[]; GrainPlane_normals=[];
+
+for i=1:length(struct_ids)
+  %get info from pair table if spots are paired
+  if pair_vector(i)==1
+    mysqlcmd=sprintf('select theta, eta, omega, plX, plY, plZ from ss_crackedAB_spotpairs where difAID=%d',struct_ids(i));
+  else
+    mysqlcmd=sprintf('select theta, eta, omega, plX, plY, plZ from ss_crackedAB_spotpairs where difBID=%d',struct_ids(i));
+  end
+  [th,et,om,plX,plY,plZ]=mym(mysqlcmd);
+
+  if ~isnan(th)
+    if pair_vector(i)==1
+      grainTheta(i)=th; grainEta(i)=et; grainOmega(i)=om;
+      grainPlane_normals(i,1:3)=[plX plY plZ];
+    else
+      grainTheta(i)=th; grainEta(i)=180-et; grainOmega(i)=om+180;
+      if grainEta(i)<0
+        grainEta(i)=grainEta(i)+360;
+      end
+      grainPlane_normals(i,1:3)=[-plX -plY -plZ];
+    end
+
+  else%if no info found in pair table, calculate it from grain position
+    [th,et,om,plX,plY,plZ]=sfCalcAngles(struct_ids(i), pair_vector(i), grain_pos);
+    grainTheta(i)=th; grainEta(i)=et; grainOmega(i)=om;
+    grainPlane_normals(i,1:3)=[plX plY plZ];
+  end
+
+end
+
+%consistancy check again to be sure, shouldn't discard anything...
+%at this point, really need to have hkls assigned. For pairs, this in table,
+%but for others it needs to be done from scratch
+%note, gtIndexReflections can also return plane normals
+[tmp, hkls] = gtIndexReflections(grainTheta, grainEta, grainOmega, parameters)
+
+
+keyboard
+%do we need a pseudo-twin ckeck somewhere?
+
+
+%remove everything claimed by a grain from the lists, and go again with the
+%next candidate.
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function output = sfFindGrain(good_points, t_grain)
+%function for fminbnd to find grain position along original projection
+x_grain=linedata(testpair,1)-t_grain*linedata(testpair,4);
+y_grain=linedata(testpair,2)-t_grain*linedata(testpair,5);
+z_grain=linedata(testpair,3)-t_grain*linedata(testpair,6);
+
+dist = good_points-repmat([x_grain y_grain z_grain], size(good_points, 1), 1);
+dist = sqrt(sum((dist.*dist),2)); % distance of each point from grain
+%minimise sum of squares for the closest half of the points, to reduce
+%effect of outliers
+dist = sort(dist,1,'descend');
+tmp = ceil(size(dist,1)/2);
+dist(1:tmp)=[];
+output = dist'*dist;%sum of squares
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function cand = sfSelectPairedCandidates
+    %returns all paired thetatype=1 pairids
+  difA_name='ss_crackedA_';
+  pairtablename='ss_crackedAB_';
+  cand=mym(sprintf([...
+  'select %sspotpairs.pairID from %sspotpairs inner join %sdifspot on difAID=difspotID '...
+  'where thetatype=1 or thetatype=2 order by boundingboxYsize desc'],...
+  pairtablename,pairtablename,difA_name));
+  end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function allowed_angles = sfGetAllowedAngles(hkl_1,hkl_2)
+%get the allowed interplanar angles
+hkl_m1 = gtGetReflections(hkl_1);
+hkl_m2 = gtGetReflections(hkl_2);
+allowed_angles = [];counter = 1;
+for i=1:size(hkl_m1,1)
+  for j=1:size(hkl_m2,1)
+    tmp = acos ( dot(hkl_m1(i,:), hkl_m2(j,:)) / (sqrt( (hkl_m1(i,:)*hkl_m1(i,:)')*(hkl_m2(j,:)*hkl_m2(j,:)') )) );
+    tmp = tmp*180/pi;
+    allowed_angles(counter) = tmp;
+    counter = counter+1;
+  end
+end
+allowed_angles=unique(allowed_angles)
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [th, et, om, normalX normalY normalZ]= sfCalcAngles(struct_id, pair_id, grainPos_sample);
+%get difspot pos
+if pair_id==1
+[spotX,spotY,spotIm]=mym(sprintf('select CentroidX,CentroidY,MaxImage from ss_crackedA_difspot where difspotID=%d',struct_id));
+else
+[spotX,spotY,spotIm]=mym(sprintf('select CentroidX,CentroidY,MaxImage from ss_crackedB_difspot where difspotID=%d',struct_id));
+spotIm=spotIm+parameters.acq.nproj;
+end
+%calc omega
+om=180*(spotIm/parameters.acq.nproj);
+
+%put grain pos in setup (lab) reference
+grainPos_setup(1)= cosd(om)*grainPos_sample(1)+sind(om)*grainPos_sample(2) ;
+grainPos_setup(2)= -sind(om)*grainPos_sample(1)+cosd(om)*grainPos_sample(2) ;
+grainPos_setup(3)= grainPos_sample(3) ;
+
+%spot position in setup (lab) reference
+spotPos_setup=[(parameters.acq.dist/parameters.acq.pixelsize), spotX-parameters.acq.rotx, parameters.acq.bb(2)-spotY];
+
+%calc theta, eta
+deltaX = spotPos_setup(2)-grainPos_setup(2);
+deltaY = spotPos_setup(3)-grainPos_setup(3);%compared to gtMatchDifspots_v2b, sign of y has already been flipped
+grain_to_det = spotPos_setup(1)-grainPos_setup(1);
+
+th=acosd(grain_to_det / norm([grain_to_det deltaX deltaY]))/2;
+et=(180/pi)*atan2(deltaX, deltaY);
+if et<0
+  et=360+et;
+end
+
+%calc plane normal (scattering vector)
+diff_vec_setup = [grain_to_det deltaX deltaY]/norm([grain_to_det deltaX deltaY]);
+pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ;
+%transform to sample coordinates
+normalX = cosd(om)*pl_vec_setup(1)-sind(om)*pl_vec_setup(2) ;
+normalY = sind(om)*pl_vec_setup(1)+cosd(om)*pl_vec_setup(2) ;
+normalZ = pl_vec_setup(3) ;
+
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+end
diff --git a/4_spot_sorting/gtPairs2Grains360.m b/4_spot_sorting/gtPairs2Grains360.m
new file mode 100755
index 0000000000000000000000000000000000000000..9537d4cc01745c8776b6daa7804dfc8ddf5e5fd5
--- /dev/null
+++ b/4_spot_sorting/gtPairs2Grains360.m
@@ -0,0 +1,353 @@
+%for Andreas2_ multilayer dataset.  Try indexing based on scattering
+%vectors only.  
+%Simple approach for the small dataset
+function [difAID, difBID, r_vector, grain_pos] = gtPairs2Grains360(x)
+
+dev_test=2;%what angular tolerence? (degrees)
+real_test=2;%what real space tolerance? (grainsize/real_test)
+plot_flag=1; %plot figures? - slow because of looking up spot images
+
+gtDBConnect
+parameters=[];
+load parameters
+
+%first need to pick a large, paired 111 or 002 (or anything?)
+candidates = sfSelectPairedCandidates;
+%candidates is the pairID
+
+candidate=candidates(x);
+
+
+
+%get the data that will be used
+[pairIDs,plX,plY,plZ,thetatype]=mym('select pairID, plX, plY, plZ, thetatype from Andreas2_spotpairs where thetatype=1 or thetatype=2');
+[lorXA, lorYA, lorZA,lorXB, lorYB, lorZB, ldirX, ldirY, ldirZ]=mym('select samcentXA, samcentYA, samcentZA,samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ from Andreas2_spotpairs where thetatype=1 or thetatype=2');
+[difAIDs, difBIDs]=mym('select difAID, difBID from Andreas2_spotpairs where thetatype=1 or thetatype=2');
+
+linedata=[lorXA, lorYA, lorZA, ldirX, ldirY, ldirZ];
+keyboard
+
+plane_normals = zeros(length(plX), 3);
+plane_normals(:,1) = plX;
+plane_normals(:,2) = plY;
+plane_normals(:,3) = plZ;
+hkls=zeros(length(thetatype), 3);
+hkls(find(thetatype==1),:)=repmat([1 1 1],length(find(thetatype==1)),1);
+hkls(find(thetatype==2),:)=repmat([0 0 2],length(find(thetatype==2)),1);
+
+%deal with the first two diffraction rings only - low multiplicities means
+%less spots to consider - mixed blessing.
+allowed_angles11=sfGetAllowedAngles([1 1 1], [1 1 1]);
+allowed_angles12=sfGetAllowedAngles([1 1 1], [0 0 2]);
+allowed_angles22=sfGetAllowedAngles([0 0 2], [0 0 2]);
+allowed_angles11=repmat(allowed_angles11,length(plane_normals),1);
+allowed_angles12=repmat(allowed_angles12,length(plane_normals),1);
+allowed_angles22=repmat(allowed_angles22,length(plane_normals),1);
+
+%pick out the candidate
+testpair=find(pairIDs==candidate);
+
+subject_normal=plane_normals(testpair,:);
+subject_normal=repmat(subject_normal, size(plane_normals,1), 1);
+%interplanar angles in degrees
+angles=(180/pi)*acos(dot(subject_normal, plane_normals, 2));
+
+shortlist=[];
+
+if thetatype(testpair)==1
+  %test against all 111-111 allowed angles
+  dev_angles = abs(repmat(angles,1,size(allowed_angles11,2)) - allowed_angles11);
+  dev_angles = min(dev_angles,[],2);
+  shortlist=find(dev_angles<dev_test & thetatype==1);
+  %plus do the 111-002 combinations
+  dev_angles = abs(repmat(angles,1,size(allowed_angles12,2)) - allowed_angles12);
+  dev_angles = min(dev_angles,[],2);
+  shortlist = [shortlist; find(dev_angles<dev_test & thetatype==2)];
+elseif thetatype(testpair)==2
+  %test against all 002-002 allowed angles
+  dev_angles = abs(repmat(angles,1,size(allowed_angles22,2)) - allowed_angles22);
+  dev_angles = min(dev_angles,[],2);
+  shortlist=find(dev_angles<dev_test & thetatype==2);
+  %plus do the 111-002 combinations
+  dev_angles = abs(repmat(angles,1,size(allowed_angles12,2)) - allowed_angles12);
+  dev_angles = min(dev_angles,[],2);
+  shortlist = [shortlist; find(dev_angles<dev_test & thetatype==1)];
+end
+
+keyboard
+
+%This is a shortlist of possible plane normals according to scattering
+%vector direction.  
+%...now, do real space
+
+%get difspot data
+[difAID, difBID]=mym(sprintf('select difAID, difBID from Andreas2_spotpairs where pairID=%d',candidate));
+[spotsizex(1), spotsizey(1)]=mym(sprintf('select boundingboxXsize, boundingboxYsize from Andreas2_difspot where difspotid=%d',difAID));
+[spotsizex(2), spotsizey(2)]=mym(sprintf('select boundingboxXsize, boundingboxYsize from Andreas2_difspot where difspotid=%d',difBID));
+spotsizex=mean(spotsizex);
+spotsizey=mean(spotsizey);
+spotsize=mean([spotsizex spotsizey]);
+
+distance=zeros(size(shortlist));
+points=zeros(length(shortlist),3);
+
+%quadratic...  at^2 + bt +c = 0
+a= linedata(testpair,4)^2 + linedata(testpair,5)^2;
+b= -2*((linedata(testpair,1)*linedata(testpair,4))+(linedata(testpair,2)*linedata(testpair,5)));
+c= linedata(testpair,1)^2 + linedata(testpair,2)^2 - 200^2
+
+t(1)= (-b+sqrt(b^2-(4*a*c)))/(2*a);
+t(2)= (-b-sqrt(b^2-(4*a*c)))/(2*a);
+tmin=min(t);
+tmax=max(t);
+
+
+
+if plot_flag
+%testpair line:
+point1=linedata(testpair,1:3);
+point1=point1-tmin*linedata(testpair,4:6);
+point2=point1-tmax*linedata(testpair,4:6);
+pdata=[point1; point2];
+figure
+hold on
+plot3(pdata(:,1), pdata(:,2), pdata(:,3),'r')
+end
+
+%pick out intersections from which a grain position can be refined
+grainpoints=[];
+for a=1:length(shortlist)
+  point=pofintersectexp(linedata([testpair shortlist(a)], :))'; %best point between the two lines
+  distance(a)=pointtolinedist(point, linedata(testpair, :));
+  points(a,:)=point;
+  
+  %if lines are ~ parallel, this gets ugly
+  if distance(a)>25
+  plot3(point(1), point(2), point(3), 'go')
+  elseif distance(a) >10
+    plot3(point(1), point(2), point(3), 'ro')
+  else
+    if angles(shortlist(a))>5 %only plot if the angle is greater than 5 degrees
+      %similarly, can only get grain position from lines more than a few
+      %degrees apart.
+      if plot_flag
+        plot3(point(1), point(2), point(3), 'bo')
+      end
+      grainpoints=[grainpoints; point];%use to refine position
+    end
+  end
+end
+
+
+%then, refine grain position
+%need outlier rejecting least squares approach from grainpoints.
+%to work in a single variable, use t, where t is a coordinate along the path
+%of the original spot
+
+%hard code some sensible limits
+%tmin=3000
+%tmax=4000
+
+
+t_grain = fminbnd(@(t) sfFindGrain(grainpoints, t), tmin, tmax);
+
+x_grain=linedata(testpair,1)-t_grain*linedata(testpair,4);
+y_grain=linedata(testpair,2)-t_grain*linedata(testpair,5);
+z_grain=linedata(testpair,3)-t_grain*linedata(testpair,6);
+
+plot3(x_grain, y_grain, z_grain, 'xr', 'markersize', 20)
+
+%Finally (?) reject those lines which intersect too far from the grain
+%position
+dist = points-repmat([x_grain y_grain z_grain], size(points, 1), 1);
+dist = sqrt(sum((dist.*dist),2)); % distance of each point from grain
+shortlist2 = shortlist;
+shortlist2(find(dist>spotsize/real_test))=[];
+points2=points;
+points2(find(dist>spotsize/real_test), :)=[]; %points is now same length as shortlist2
+
+
+if plot_flag
+  %look at these spots
+  figure
+  for a=1:length(shortlist2)
+    im=gtGetSummedDifSpot(difAIDs(shortlist2(a)));
+    subplot(2,length(shortlist2), a); imshow(im, [])
+    im=gtGetSummedDifSpot(difBIDs(shortlist2(a)));
+    subplot(2,length(shortlist2), a+length(shortlist2)); imshow(im, [])
+  end
+end
+
+%run consistancy test of the final group of spots
+[r_vector, goods]=plot_rodrigues_consistancy(plane_normals(shortlist2,:), hkls(shortlist2,:),plot_flag);
+points3=points2(goods,:)
+shortlist3=shortlist2(goods)
+
+if plot_flag
+  figure
+  for a=1:length(shortlist3)
+    im=gtGetSummedDifSpot(difAIDs(shortlist3(a)));
+    subplot(2,length(shortlist3), a); imshow(im, [])
+    im=gtGetSummedDifSpot(difBIDs(shortlist3(a)));
+    subplot(2,length(shortlist3), a+length(shortlist3)); imshow(im, [])
+  end
+end
+
+
+%for output
+difAID=difAIDs(shortlist3)
+difBID=difBIDs(shortlist3)
+
+%should refine grain position again, having done the consistancy check
+t_grain = fminbnd(@(t) sfFindGrain(points3, t), tmin, tmax);
+
+x_grain=linedata(testpair,1)-t_grain*linedata(testpair,4);
+y_grain=linedata(testpair,2)-t_grain*linedata(testpair,5);
+z_grain=linedata(testpair,3)-t_grain*linedata(testpair,6);
+
+grain_pos=[x_grain y_grain z_grain];
+
+%then, call forward simulate to get anything missed, any unpaired spots,
+%and any higher order {hkl} pairs.
+%assemble data
+struct_ids=[difAID; difBID];
+[struct_ids_new] = gtForwardSimulate_pair2grain360(grain_pos, r_vector, struct_ids, parameters)
+
+%now, assemble all info for these new spots.  
+struct_ids=[struct_ids; struct_ids_new'];
+grainTheta=[]; grainEta=[]; grainOmega=[]; GrainPlane_normals=[];
+
+for i=1:length(struct_ids)
+  %get info from pair table if spots are paired
+
+    mysqlcmd=sprintf('select theta, eta, omega, plX, plY, plZ from Andreas2_spotpairs where difAID=%d',struct_ids(i));
+
+  [th,et,om,plX,plY,plZ]=mym(mysqlcmd);
+
+  if ~isnan(th)
+    if om<=180
+      grainTheta(i)=th; grainEta(i)=et; grainOmega(i)=om;
+      grainPlane_normals(i,1:3)=[plX plY plZ];
+    else
+      grainTheta(i)=th; grainEta(i)=180-et; grainOmega(i)=om+180;
+      if grainEta(i)<0
+        grainEta(i)=grainEta(i)+360;
+      end
+      grainPlane_normals(i,1:3)=[-plX -plY -plZ];
+    end
+
+  else%if no info found in pair table, calculate it from grain position
+    [th,et,om,plX,plY,plZ]=sfCalcAngles(struct_ids(i), grain_pos);
+    grainTheta(i)=th; grainEta(i)=et; grainOmega(i)=om;
+    grainPlane_normals(i,1:3)=[plX plY plZ];
+  end
+
+end
+
+%consistancy check again to be sure, shouldn't discard anything...
+%at this point, really need to have hkls assigned. For pairs, this in table,
+%but for others it needs to be done from scratch
+%note, gtIndexReflections can also return plane normals
+[tmp, grainHKLs] = gtIndexReflections(grainTheta, grainEta, grainOmega, parameters)
+
+
+keyboard
+%do we need a pseudo-twin ckeck somewhere?
+
+
+%remove everything claimed by a grain from the lists, and go again with the
+%next candidate.
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function output = sfFindGrain(good_points, t_grain)
+%function for fminbnd to find grain position along original projection
+x_grain=linedata(testpair,1)-t_grain*linedata(testpair,4);
+y_grain=linedata(testpair,2)-t_grain*linedata(testpair,5);
+z_grain=linedata(testpair,3)-t_grain*linedata(testpair,6);
+
+dist = good_points-repmat([x_grain y_grain z_grain], size(good_points, 1), 1);
+dist = sqrt(sum((dist.*dist),2)); % distance of each point from grain
+%minimise sum of squares for the closest half of the points, to reduce
+%effect of outliers
+dist = sort(dist,1,'descend');
+tmp = ceil(size(dist,1)/2);
+dist(1:tmp)=[];
+output = dist'*dist;%sum of squares
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function cand = sfSelectPairedCandidates
+    %returns all paired thetatype=1 pairids
+  difA_name='Andreas2_';
+  pairtablename='Andreas2_';
+  cand=mym(sprintf([...
+  'select %sspotpairs.pairID from %sspotpairs inner join %sdifspot on difAID=difspotID '...
+  'where thetatype=1 or thetatype=2 order by boundingboxYsize desc'],...
+  pairtablename,pairtablename,difA_name));
+  end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function allowed_angles = sfGetAllowedAngles(hkl_1,hkl_2)
+%get the allowed interplanar angles
+hkl_m1 = gtGetReflections(hkl_1);
+hkl_m2 = gtGetReflections(hkl_2);
+allowed_angles = [];counter = 1;
+for i=1:size(hkl_m1,1)
+  for j=1:size(hkl_m2,1)
+    tmp = acos ( dot(hkl_m1(i,:), hkl_m2(j,:)) / (sqrt( (hkl_m1(i,:)*hkl_m1(i,:)')*(hkl_m2(j,:)*hkl_m2(j,:)') )) );
+    tmp = tmp*180/pi;
+    allowed_angles(counter) = tmp;
+    counter = counter+1;
+  end
+end
+allowed_angles=unique(allowed_angles)
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [th, et, om, normalX normalY normalZ]= sfCalcAngles(struct_id, grainPos_sample);
+%get difspot pos
+
+[spotX,spotY,spotIm]=mym(sprintf('select CentroidX,CentroidY,MaxImage from Andreas2_difspot where difspotID=%d',struct_id));
+
+%calc omega
+om=180*(spotIm/parameters.acq.nproj);
+
+%put grain pos in setup (lab) reference
+grainPos_setup(1)= cosd(om)*grainPos_sample(1)+sind(om)*grainPos_sample(2) ;
+grainPos_setup(2)= -sind(om)*grainPos_sample(1)+cosd(om)*grainPos_sample(2) ;
+grainPos_setup(3)= grainPos_sample(3) ;
+
+%spot position in setup (lab) reference
+spotPos_setup=[(parameters.acq.dist/parameters.acq.pixelsize), spotX-parameters.acq.rotx, parameters.acq.bb(2)-spotY];
+
+%calc theta, eta
+deltaX = spotPos_setup(2)-grainPos_setup(2);
+deltaY = spotPos_setup(3)-grainPos_setup(3);%compared to gtMatchDifspots_v2b, sign of y has already been flipped
+grain_to_det = spotPos_setup(1)-grainPos_setup(1);
+
+th=acosd(grain_to_det / norm([grain_to_det deltaX deltaY]))/2;
+et=(180/pi)*atan2(deltaX, deltaY);
+if et<0
+  et=360+et;
+end
+
+%calc plane normal (scattering vector)
+diff_vec_setup = [grain_to_det deltaX deltaY]/norm([grain_to_det deltaX deltaY]);
+pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ;
+%transform to sample coordinates
+normalX = cosd(om)*pl_vec_setup(1)-sind(om)*pl_vec_setup(2) ;
+normalY = sind(om)*pl_vec_setup(1)+cosd(om)*pl_vec_setup(2) ;
+normalZ = pl_vec_setup(3) ;
+
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+end
diff --git a/4_spot_sorting/gtPredictAngles.m b/4_spot_sorting/gtPredictAngles.m
new file mode 100755
index 0000000000000000000000000000000000000000..6e7d70a90a040a8f72b27a892d521cedcafbc81d
--- /dev/null
+++ b/4_spot_sorting/gtPredictAngles.m
@@ -0,0 +1,76 @@
+function [Theta,Eta,Omega]=gtPredictAngles(normal, hkl, parameters)
+
+%calculates the Omega position at which diffraction will occur from a plane
+%defined by its plane normal and hkl type [h k l]
+
+%30/10/2006 - modify to follow change in gtConsistancyCheck, and to produce
+%only the theta/eta/omega from the plane normal (not its inverse as well)
+
+%load data
+
+if isempty(parameters)
+  load parameters.mat
+end
+
+%put plane normal in cylindrical polar coords
+length = sqrt(normal(1)^2 + normal(2)^2);
+alpha = atan2(normal(2), normal(1));
+vert = normal(3);
+
+%calc Theta for diffraction
+lambda = 12.398/parameters.acq.energy;
+
+    %%%%%%%%   cubic cases   %%%%%%%%%%%%%
+if parameters.acq.spacegroup == 225 | parameters.acq.spacegroup == 227 | parameters.acq.spacegroup == 229
+    d=parameters.acq.latticepar(1)/sqrt(hkl*hkl');
+    % modif sabine
+    %%%%%%%%   hexagonal cases   %%%%%%%%%%%%%
+elseif parameters.acq.spacegroup == 663 | parameters.acq.spacegroup == 194 | parameters.acq.spacegroup == 167
+    h=hkl(1);k=hkl(2) ;l=hkl(4);
+    d=parameters.acq.latticepar(1)/(4/3*(h^2+k^2+h*k)+(l*parameters.acq.latticepar(1)/parameters.acq.latticepar(3))^2)^0.5;
+    % fin modif sabine
+else
+    warning('unknown spacegroup!')
+    return
+end
+Theta = asin(lambda/(2*d));
+
+%try
+  %produce Omega angles - find four Omegas (hkl ->2, -h-k-l ->2)
+  if ((cos((pi/2)-Theta))/length)<=1
+  temp(1) = acos((cos((pi/2)-Theta))/length);
+  temp(2) = -temp(1);
+  Omega = alpha + pi + temp;
+  else
+    disp('no diffraction from this plane normal!')
+    Theta=[];
+    return
+  end
+  
+  %calc Eta, make Theta to output
+  %in our convention, Eta is measured clockwise from vertical on the
+  %images.
+  
+  alpha2 = alpha - Omega;%plane normal angles at diffraction
+
+  y = length*sin(alpha2);
+  x = length*cos(alpha2);
+ 
+  Eta = atan2(y,vert);%this was y, now +ve because of 'looking into beam" sense
+  Theta(1:2) = Theta(1);%all Thetas are the same
+  
+  %put Omega in 0-2pi interval
+  dummy = find(Omega<0);
+  Omega(dummy) = Omega(dummy) + (2*pi);
+  dummy = find(Omega>(2*pi));
+  Omega(dummy) = Omega(dummy) - (2*pi);
+ 
+  %put in degrees for human users
+  Omega = Omega*180/pi;
+  Theta = Theta*180/pi;
+  Eta = Eta*180/pi;
+
+
+
+
+
diff --git a/4_spot_sorting/gtPredictAngles_Si.m b/4_spot_sorting/gtPredictAngles_Si.m
new file mode 100755
index 0000000000000000000000000000000000000000..c93db5ba677bc3af4e4233a1b22bc60222f0ce7a
--- /dev/null
+++ b/4_spot_sorting/gtPredictAngles_Si.m
@@ -0,0 +1,74 @@
+function [Theta,Eta,Omega]=gtPredictAngles_Si(normal, hkl)
+
+%calculates the Omega position at which diffraction will occur from a plane
+%defined by its plane normal and hkl type [h k l]
+
+%30/10/2006 - modify to follow change in gtConsistancyCheck, and to produce
+%only the theta/eta/omega from the plane normal (not its inverse as well)
+
+%_Si - simplified version - no parameters.mat
+%hard code stuff
+disp('hard coded variables - change in gtPredictAngles_Si')
+energy=40.2837
+latticepar=5.431
+
+%put plane normal in cylindrical polar coords
+length = sqrt(normal(1)^2 + normal(2)^2);
+alpha = atan2(normal(2), normal(1));
+vert = normal(3);
+
+%calc Theta for diffraction
+lambda = 12.398/energy;
+d=latticepar/sqrt(hkl*hkl');
+
+Theta = asin(lambda/(2*d));
+
+%try
+  %produce Omega angles 
+  if ((cos((pi/2)-Theta))/length)<=1
+  temp(1) = acos((cos((pi/2)-Theta))/length);
+  temp(2) = -temp(1);
+  Omega = alpha + pi + temp;
+  else
+    disp('no diffraction from this plane normal!')
+    Theta=[];
+    return
+  end
+  
+  %calc Eta, make Theta to output
+  %in our convention, Eta is measured clockwise from vertical on the
+  %images.
+  
+  alpha2 = alpha - Omega;%plane normal angles at diffraction
+
+  y = length*sin(alpha2);
+  x = length*cos(alpha2);
+ 
+  Eta = atan2(y,vert);%this was y, now +ve because of 'looking into beam" sense
+  Theta(1:2) = Theta(1);%all Thetas are the same
+  
+ 
+  
+  %put all in -(1/2)*pi - (3/2)*pi interval
+  dummy = find(Omega<-pi/2);
+  Omega(dummy) = Omega(dummy) + (2*pi);
+  dummy = find(Omega>((1.5)*pi));
+  Omega(dummy) = Omega(dummy) - (2*pi);
+ 
+  %dummy = find(Eta<0);
+  %Eta(dummy) = Eta(dummy) + (2*pi);
+  %dummy = find(Eta>(2*pi));
+  %Eta(dummy) = Eta(dummy) - (2*pi);
+   
+  %put in degrees for human users
+  Omega = Omega*180/pi;
+  Theta = Theta*180/pi;
+  Eta = Eta*180/pi;
+
+%catch%if no solutions
+%  disp('no diffraction from this plane normal!')
+%end
+
+
+
+
diff --git a/4_spot_sorting/gtPredictPositions.m b/4_spot_sorting/gtPredictPositions.m
new file mode 100755
index 0000000000000000000000000000000000000000..47f059ede57499ca51e0a3691e132e183a57b328
--- /dev/null
+++ b/4_spot_sorting/gtPredictPositions.m
@@ -0,0 +1,94 @@
+%predict positions of spots in images
+%Marcelo, Andy, 30/10
+
+function [images,x_direct,y_direct,x_diffr,y_diffr] = gtPredictPositions(normal, hkl, grainid, plot_flag)
+%take a plane normal, its hkl type (to calc Theta), and a grainID (to calc
+%grain position in sample), and returns lists of max images, and x and y
+%positions of the ext and dif spots.
+%plot_flag=1 plots images
+
+%load data 
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+grainx = grain_data.x1 + (grain_data.nx/2);
+grainy = grain_data.y1 + (grain_data.ny/2);
+zcenter = grain_data.zcenter;
+
+%use gtPredictAngles to get Theta, Eta, Omega - note gives a pair of angles
+[Theta,Eta,Omega] = gtPredictAngles(normal, hkl);
+%convert to radians
+Theta=Theta*pi/180;
+Eta=Eta*pi/180;
+Omega=Omega*pi/180;
+
+%get only Omegas within 0-180 degrees
+if parameters.acq.type=='180degree'
+  %disp('180 degree data')
+  dummy=find(Omega<0 | Omega>pi);
+  Theta(dummy)=[];
+  Eta(dummy)=[];
+  Omega(dummy)=[];
+end
+
+%deal with grain position
+grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+%extinction spot position
+% y correction with the omega offset in the sample, that is a value to be added to X in the screen
+x_direct = parameters.acq.bb(1)+(parameters.acq.bb(3)/2)+(grain2rot.*cos(-Omega+angle)); 
+y_direct(1:length(Omega)) = parameters.acq.bb(2)+zcenter;
+
+%diffraction spot position
+% radius on the screen (in pixels) with the corrected distance from the sample to the
+% detector (y in sample coordinates) with the omega offset
+radius = tan(2*Theta).*((parameters.acq.dist/parameters.acq.pixelsize)+(grain2rot*sin(-Omega+angle)));
+x_diffr =  x_direct + (radius.*sin(Eta)); % spot position (x position) in the screen 
+y_diffr = y_direct - (radius.*cos(Eta)); % vertical coordinate on the screeen
+
+
+%get full image
+	images = round((Omega/pi)*parameters.acq.proj);
+
+  %plot results on full images
+  if plot_flag
+  
+for i=1:size(Omega,2)
+
+	%convert Omega to image number
+
+	start_image = images(i)-5;
+	if start_image<0
+		start_image=0;
+	end
+	end_image = images(i)+5;
+	if end_image>5999
+		end_image=5999;
+	end
+	
+  start_image
+  end_image
+	
+	full=zeros(parameters.acq.xdet,parameters.acq.ydet);
+	for im=start_image:end_image
+		full=full+edf_read(sprintf('1_preprocessed/full/full%04d.edf',im));
+	end
+	full=full./(end_image-start_image+1);
+
+  figure
+	imshow(full,[]);
+	hold on;
+	plot(x_direct(i),y_direct(i),'og')
+	plot(x_diffr(i),y_diffr(i),'ro')
+  drawnow
+  disp('click image to close and see next spot (if exists...)')
+  k=waitforbuttonpress;
+  
+end
+
+  end
+  
diff --git a/4_spot_sorting/gtPredictPositions2.m b/4_spot_sorting/gtPredictPositions2.m
new file mode 100755
index 0000000000000000000000000000000000000000..dfde5ae94ff48daff54f3ba3eeafd333961f8332
--- /dev/null
+++ b/4_spot_sorting/gtPredictPositions2.m
@@ -0,0 +1,104 @@
+%predict positions of spots in images
+%version2 - designed to work in gtHandleSpot2 sequence, with no
+%grain%d_.mat yet written, all information passed as arguments
+
+%Marcelo, Andy, 30/10
+
+function [images,x_direct,y_direct,x_diffr,y_diffr] = gtPredictPositions2(normal, hkl, grainCentroid, plot_flag, parameters)
+%take a plane normal, its hkl type (to calc Theta), and a grainCentroid [x,y,z], and returns lists of max images, and x and y
+%positions of the ext and dif spots.
+%plot_flag=1 plots images
+
+%load data 
+if isempty(parameters)
+  load parameters.mat
+end
+grainx = grainCentroid(1);
+grainy =grainCentroid(2);
+zcenter = grainCentroid(3);
+
+%use gtPredictAngles to get Theta, Eta, Omega - note gives a pair of angles
+[Theta,Eta,Omega] = gtPredictAngles(normal, hkl);
+%convert to radians
+Theta=Theta*pi/180;
+Eta=Eta*pi/180;
+Omega=Omega*pi/180;
+
+%get only Omegas within 0-180 degrees for 180deg data
+if parameters.acq.type=='180degree'
+  %disp('180 degree data')
+  dummy=find(Omega<0 | Omega>pi);
+  Theta(dummy)=[];
+  Eta(dummy)=[];
+  Omega(dummy)=[];
+end
+
+%deal with grain position
+grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+%extinction spot position
+% y correction with the omega offset in the sample, that is a value to be added to X in the screen
+x_direct = parameters.acq.bb(1)+(parameters.acq.bb(3)/2)+(grain2rot.*cos(-Omega+angle)); 
+y_direct(1:length(Omega)) = parameters.acq.bb(2)+zcenter;
+
+%diffraction spot position
+% radius on the screen (in pixels) with the corrected distance from the sample to the
+% detector (y in sample coordinates) with the omega offset
+radius = tan(2*Theta).*((parameters.acq.dist/parameters.acq.pixelsize)+(grain2rot*sin(-Omega+angle)));
+x_diffr =  x_direct + (radius.*sin(Eta)); % spot position (x position) in the screen 
+y_diffr = y_direct - (radius.*cos(Eta)); % vertical coordinate on the screeen
+
+%round to integer values
+x_direct = round(x_direct);
+y_direct = round(y_direct);
+x_diffr = round(x_diffr);
+y_diffr = round(y_diffr);
+
+%get full image
+images = round((Omega/pi)*parameters.acq.nproj);
+
+  
+  
+  
+  %~~~~~~~~plot results on full images~~~~~~~~~~~~~~~~~~~~~~
+  if plot_flag
+    for i=1:size(Omega,2)
+      
+	%convert Omega to image number
+  if images(i) >= parameters.acq.nproj
+    images(i)=images(i)-parameters.acq.nproj;
+    path=sprintf('../%s/',parameters.acq.difB_name);
+  else
+    path=sprintf('../%s/',parameters.acq.difA_name);
+  end
+  
+	start_image = images(i)-3;
+	if start_image<0
+		start_image=0;
+	end
+	end_image = images(i)+3;
+	if end_image>parameters.acq.nproj-1;
+		end_image=parameters.acq.nproj-1;
+	end
+	
+  start_image
+  end_image
+	
+	full=zeros(parameters.acq.xdet,parameters.acq.ydet);
+	for im=start_image:end_image
+		full=full+edf_read(sprintf('%s1_preprocessing/full/full%04d.edf',path,im));
+	end
+	full=full./(end_image-start_image+1);
+
+  figure
+	imshow(full,[]);
+	hold on;
+	plot(x_direct(i),y_direct(i),'og')
+	plot(x_diffr(i),y_diffr(i),'ro')
+  drawnow
+  disp('click image to close and see next spot (if exists...)')
+  k=waitforbuttonpress;
+    end
+  end
+  %~~~~~~~~plot results on full images~~~~~~~~~~~~~~~~~~~~~~  
diff --git a/4_spot_sorting/gtPredictPositions_360.m b/4_spot_sorting/gtPredictPositions_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..005929481354a8f7390e26fdb21a3cf9209161b8
--- /dev/null
+++ b/4_spot_sorting/gtPredictPositions_360.m
@@ -0,0 +1,99 @@
+%predict positions of spots in images
+%version2 - designed to work in gtHandleSpot2 sequence, with no
+%grain%d_.mat yet written, all information passed as arguments
+
+%Marcelo, Andy, 30/10
+
+function [images,x_direct,y_direct,x_diffr,y_diffr] = gtPredictPositions_360(normal, hkl, grainCentroid, plot_flag, parameters)
+%take a plane normal, its hkl type (to calc Theta), and a grainCentroid [x,y,z], and returns lists of max images, and x and y
+%positions of the ext and dif spots.
+%plot_flag=1 plots images
+
+%load data 
+if isempty(parameters)
+  load parameters.mat
+end
+grainx = grainCentroid(1);
+grainy =grainCentroid(2);
+zcenter = grainCentroid(3);
+
+%use gtPredictAngles to get Theta, Eta, Omega - note gives a pair of angles
+[Theta,Eta,Omega] = gtPredictAngles(normal, hkl, parameters);
+%convert to radians
+Theta=Theta*pi/180;
+Eta=Eta*pi/180;
+Omega=Omega*pi/180;
+
+%get only Omegas within 0-180 degrees for 180deg data
+if parameters.acq.type=='180degree'
+  %disp('180 degree data')
+  dummy=find(Omega<0 | Omega>pi);
+  Theta(dummy)=[];
+  Eta(dummy)=[];
+  Omega(dummy)=[];
+end
+
+%deal with grain position
+grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+%extinction spot position
+% y correction with the omega offset in the sample, that is a value to be added to X in the screen
+x_direct = parameters.acq.bb(1)+(parameters.acq.bb(3)/2)+(grain2rot.*cos(-Omega+angle)); 
+y_direct(1:length(Omega)) = parameters.acq.bb(2)+zcenter;
+
+%diffraction spot position
+% radius on the screen (in pixels) with the corrected distance from the sample to the
+% detector (y in sample coordinates) with the omega offset
+radius = tan(2*Theta).*((parameters.acq.dist/parameters.acq.pixelsize)+(grain2rot*sin(-Omega+angle)));
+x_diffr =  x_direct + (radius.*sin(Eta)); % spot position (x position) in the screen 
+y_diffr = y_direct - (radius.*cos(Eta)); % vertical coordinate on the screeen
+
+%round to integer values
+x_direct = round(x_direct);
+y_direct = round(y_direct);
+x_diffr = round(x_diffr);
+y_diffr = round(y_diffr);
+
+%get full image
+images = round((Omega/pi)*parameters.acq.nproj);
+
+  % modif sabine
+  %plot_flag=1
+  
+  %~~~~~~~~plot results on full images~~~~~~~~~~~~~~~~~~~~~~
+  if plot_flag
+    for i=1:size(Omega,2)
+      
+	%convert Omega to image number
+	start_image = images(i)-3;
+	if start_image<0
+		start_image=0;
+	end
+	end_image = images(i)+3;
+	if end_image>(2*parameters.acq.nproj)-1;
+		end_image=(2*parameters.acq.nproj)-1;
+	end
+	
+  start_image
+  end_image
+	
+	full=zeros(parameters.acq.xdet,parameters.acq.ydet);
+	for im=start_image:end_image
+		full=full+edf_read(sprintf('1_preprocessing/full/full%04d.edf',im));
+	end
+	full=full./(end_image-start_image+1);
+   
+    % ajout sabine% 
+    close all 
+  figure
+	imshow(full,[]);
+	hold on;
+	plot(x_direct(i),y_direct(i),'og')
+	plot(x_diffr(i),y_diffr(i),'ro')
+  drawnow
+  disp('click image to close and see next spot (if exists...)')
+  k=waitforbuttonpress;
+    end
+  end
+  %~~~~~~~~plot results on full images~~~~~~~~~~~~~~~~~~~~~~  
diff --git a/4_spot_sorting/gtPredictPositions_Si.m b/4_spot_sorting/gtPredictPositions_Si.m
new file mode 100755
index 0000000000000000000000000000000000000000..5110aa6e1edb0f009c4cc736633539750d2fd8b5
--- /dev/null
+++ b/4_spot_sorting/gtPredictPositions_Si.m
@@ -0,0 +1,32 @@
+%predict positions of spots in images
+
+%_Si  - simpler version.  relative to "grain" at center of image and on
+%rotation axis, predict image coordinates from eta, theta
+
+%Marcelo, Andy, 30/10
+
+function [x_diffr,y_diffr] = gtPredictPositions_Si(Theta, Eta)
+
+disp('hard coded distance and pixel size in gtPredictPositions_Si')
+distance=11.452
+pixelsize=0.0024
+
+%convert to radians
+Theta=Theta*pi/180;
+Eta=Eta*pi/180;
+
+
+%diffraction spot position
+% radius on the screen (in pixels) with the corrected distance from the sample to the
+% detector (y in sample coordinates) with the omega offset
+radius = tan(2*Theta).*(distance/pixelsize);
+
+x_diffr =  1024 + (radius.*sin(Eta)); % spot position (x position) in the screen 
+y_diffr = 1024 - (radius.*cos(Eta)); % vertical coordinate on the screeen
+disp('there might be a problem with this! but I dont know why...')
+
+
+%round to integer values
+x_diffr = round(x_diffr);
+y_diffr = round(y_diffr);
+
diff --git a/4_spot_sorting/gtPredictPositions_pair2grain.m b/4_spot_sorting/gtPredictPositions_pair2grain.m
new file mode 100755
index 0000000000000000000000000000000000000000..0da176c2bfaa98aa093b5db3fc94413650f24884
--- /dev/null
+++ b/4_spot_sorting/gtPredictPositions_pair2grain.m
@@ -0,0 +1,119 @@
+%predict positions of spots in images
+
+% gtPredictPositions_pair2grain 
+%work with difspotpair grain indexing process.  Different grain position
+%defination
+
+
+%Marcelo, Andy, 30/10
+
+function [images,x_direct,y_direct,x_diffr,y_diffr] = gtPredictPositions_pair2grain(normal, hkl, grainCentroid, plot_flag, parameters)
+%take a plane normal, its hkl type (to calc Theta), and a grainCentroid [x,y,z], and returns lists of max images, and x and y
+%positions of the ext and dif spots.
+%plot_flag=1 plots images
+
+%load data 
+if isempty(parameters)
+  load parameters.mat
+end
+
+
+%use gtPredictAngles to get Theta, Eta, Omega - note gives a pair of angles
+[Theta,Eta,Omega] = gtPredictAngles(normal, hkl);
+%returns in degree
+
+%get only Omegas within 0-180 degrees for 180deg data
+if parameters.acq.type=='180degree'
+  %disp('180 degree data')
+  dummy=find(Omega<0 | Omega>180);
+  Theta(dummy)=[];
+  Eta(dummy)=[];
+  Omega(dummy)=[];
+end
+
+
+
+  
+%deal with grain position
+[grainCentroid_om] = sfSample_to_setup_cor(grainCentroid, Omega');
+
+%extinction spot position
+x_direct = parameters.acq.rotx + grainCentroid_om(:,2); % y coord of grainpos corresponds to x on detector
+y_direct = parameters.acq.bb(2)-grainCentroid_om(:,3); 
+%z in relative to the top to the sample bb, positive z moves spot towards top of image, hence negative
+
+%diffraction spot position
+radius = tand(2*Theta').*((parameters.acq.dist/parameters.acq.pixelsize)-grainCentroid_om(:,1));
+x_diffr =  x_direct + (radius.*sind(Eta')); % spot position (x position) in the screen 
+y_diffr = y_direct - (radius.*cosd(Eta')); % vertical coordinate on the screeen
+
+%round to integer values
+x_direct = round(x_direct);
+y_direct = round(y_direct);
+x_diffr = round(x_diffr);
+y_diffr = round(y_diffr);
+
+%get full image
+images = round((Omega'/180)*parameters.acq.nproj);
+
+  
+
+  
+  %~~~~~~~~plot results on full images~~~~~~~~~~~~~~~~~~~~~~
+  if plot_flag
+    for i=1:size(Omega,2)
+      
+	%convert Omega to image number
+  if images(i) >= parameters.acq.nproj
+    images(i)=images(i)-parameters.acq.nproj;
+    path=sprintf('../%s/',parameters.acq.difB_name);
+  else
+    path=sprintf('../%s/',parameters.acq.difA_name);
+  end
+  
+	start_image = images(i)-3;
+	if start_image<0
+		start_image=0;
+	end
+	end_image = images(i)+3;
+	if end_image>parameters.acq.nproj-1;
+		end_image=parameters.acq.nproj-1;
+	end
+	
+  start_image
+  end_image
+	
+	full=zeros(parameters.acq.xdet,parameters.acq.ydet);
+	for im=start_image:end_image
+		full=full+edf_read(sprintf('%s1_preprocessing/full/full%04d.edf',path,im));
+	end
+	full=full./(end_image-start_image+1);
+
+  figure
+	imshow(full,[]);
+	hold on;
+	plot(x_direct(i),y_direct(i),'og')
+	plot(x_diffr(i),y_diffr(i),'ro')
+  drawnow
+  disp('click image to close and see next spot (if exists...)')
+  k=waitforbuttonpress;
+    end
+  end
+  %~~~~~~~~plot results on full images~~~~~~~~~~~~~~~~~~~~~~  
+  
+  
+  
+  function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+    % om = omega angle in degrees
+    %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0
+    %1]*insample_vec')' ;
+    insetup_vec(:,1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+    insetup_vec(:,2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+    insetup_vec(:,3)= insample_vec(3) ;
+  end
+
+
+end
+  
+  
+  
diff --git a/4_spot_sorting/gtPredictPositions_pair2grain360.m b/4_spot_sorting/gtPredictPositions_pair2grain360.m
new file mode 100755
index 0000000000000000000000000000000000000000..bad48f78467facc688fcc7294c1c580b9dbe3783
--- /dev/null
+++ b/4_spot_sorting/gtPredictPositions_pair2grain360.m
@@ -0,0 +1,77 @@
+%predict positions of spots in images
+
+% gtPredictPositions_pair2grain 
+%work with difspotpair grain indexing process.  Different grain position
+%defination
+%360 no a / b half scans
+
+%Marcelo, Andy, 30/10
+
+function [images,x_direct,y_direct,x_diffr,y_diffr] = gtPredictPositions_pair2grain360(normal, hkl, grainCentroid, plot_flag, parameters)
+%take a plane normal, its hkl type (to calc Theta), and a grainCentroid [x,y,z], and returns lists of max images, and x and y
+%positions of the ext and dif spots.
+%plot_flag=1 plots images
+
+%load data 
+if isempty(parameters)
+  load parameters.mat
+end
+
+
+%use gtPredictAngles to get Theta, Eta, Omega - note gives a pair of angles
+[Theta,Eta,Omega] = gtPredictAngles(normal, hkl);
+%returns in degree
+
+%get only Omegas within 0-180 degrees for 180deg data
+if parameters.acq.type=='180degree'
+  %disp('180 degree data')
+  dummy=find(Omega<0 | Omega>180);
+  Theta(dummy)=[];
+  Eta(dummy)=[];
+  Omega(dummy)=[];
+end
+
+
+
+  
+%deal with grain position
+[grainCentroid_om] = sfSample_to_setup_cor(grainCentroid, Omega');
+
+%extinction spot position
+x_direct = parameters.acq.rotx + grainCentroid_om(:,2); % y coord of grainpos corresponds to x on detector
+y_direct = parameters.acq.bb(2)-grainCentroid_om(:,3); 
+%z in relative to the top to the sample bb, positive z moves spot towards top of image, hence negative
+
+%diffraction spot position
+radius = tand(2*Theta').*((parameters.acq.dist/parameters.acq.pixelsize)-grainCentroid_om(:,1));
+x_diffr =  x_direct + (radius.*sind(Eta')); % spot position (x position) in the screen 
+y_diffr = y_direct - (radius.*cosd(Eta')); % vertical coordinate on the screeen
+
+%round to integer values
+x_direct = round(x_direct);
+y_direct = round(y_direct);
+x_diffr = round(x_diffr);
+y_diffr = round(y_diffr);
+
+%get full image
+images = round((Omega'/180)*parameters.acq.nproj);
+
+  
+
+
+  
+  
+  function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+    % om = omega angle in degrees
+    %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0
+    %1]*insample_vec')' ;
+    insetup_vec(:,1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+    insetup_vec(:,2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+    insetup_vec(:,3)= insample_vec(3) ;
+  end
+
+
+end
+  
+  
+  
diff --git a/4_spot_sorting/gtReadExtRoi_360.m b/4_spot_sorting/gtReadExtRoi_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..7864bd877e1dd7b504f5769f16c39a0e237a82f3
--- /dev/null
+++ b/4_spot_sorting/gtReadExtRoi_360.m
@@ -0,0 +1,76 @@
+function [extstack,sino,centerslice,bb,index]=gtReadExtRoi_360(grain,parameters); 
+
+np=length(grain.struct_ids);
+
+for j=1:np
+     % get lab system grain COM Coordinates from grain structure (produced by PEter's
+     % Indexing)
+	 grain.center(1)=grain.ycenter-parameters.acq.bb(3)/2;   % not very elegant: transform back for compatibility with calls of gtReadextroi outside of gtINWriteGrainFolder...
+	 grain.center(2)=grain.xcenter-parameters.acq.bb(3)/2;
+	 grain.center(3)=parameters.acq.ydet/2-parameters.acq.bb(2)-grain.zcenter;
+	
+     [xl,yl,zl]=gtTrSamToLab(grain.center(1),grain.center(2),grain.center(3),grain.omega(j));
+	 xim = yl+ parameters.acq.bb(3)/2;   % grain COM coordinates in the direct beam images   (assumes center of rotation in the center of the beam)
+ 	 yim = parameters.acq.ydet/2-zl-parameters.acq.bb(2);
+	
+	 
+	 % get Boundingbox sizes and integration range from all difspots
+	 mymcmd=sprintf('select BoundingBoxXSize, BoundingBoxYSize, ExtStartImage, ExtEndImage, StartImage, EndImage, Integral  from %sdifspot where difspotID=%d',parameters.acq.name,grain.struct_ids(j));
+	 [bbxs,bbys,startndx,endndx,difstartndx,difendndx,int]=mym(mymcmd);
+	 difbb(j,1)=max(1,round(xim-bbxs/2)); 
+	 difbb(j,2)=max(1,round(yim-bbys/2));
+	 
+	 bbxs=round(bbxs*1.1);  %add 10% margin to bb
+	 bbys=round(bbys*1.1);
+	 integral(j)=int;
+	 ndx(j,:)=[startndx,endndx];
+	 difndx(j,:)=[difstartndx, difendndx];
+	 range(j)=endndx-startndx+1;
+	 difrange(j)=difendndx-difstartndx+1;
+	 bb(j,1)=max(1,round(xim-bbxs/2));    % horizontal start of bb in Ext image
+	 hend=min(parameters.acq.bb(3),bb(j,1)+bbxs-1);  % limit horizontal extend to size of Ext image...
+	 bb(j,3)=hend-bb(j,1)+1;
+	 
+	 bb(j,4)=bbys;               
+
+	 
+end	 
+
+% vertical bounds are identical for all extspots
+vertsize=mean(bb(:,4));   % first estimate of vertical size from average vertical size in difspots
+vertbeg=max(1,round(yim-vertsize/2));
+bb(:,2)=repmat(vertbeg,np,1);                         
+vertend=min(parameters.acq.bb(4),round(yim+vertsize/2));
+vertsize=vertend-vertbeg;  % update vertical size of bb, taking into account finite size of ext image
+bb(:,4)=repmat(vertsize,np,1);
+centerslice=round(vertbeg+0.5*vertsize);
+
+
+
+% now read and sum under bb mask
+extstack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),np);
+difstack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),np);
+
+tmp=zeros(parameters.acq.bb(4),parameters.acq.bb(3));
+meanint=mean(integral);
+
+for j=1:np
+  % get summed diffraction spot
+  %dif=gtGetSummedDifspot(grain.struct_ids(j),parameters,1);
+  %difstack(:,:,j)=gtPlaceSubImage(dif,tmp,difbb(j,1),difbb(j,2));
+  %difstack(:,:,j)=meanint*difstack(:,:,j)/integral(j);
+  im=zeros(bb(j,4),bb(j,3));
+  for k=1:difrange(j)
+	im = im+edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',parameters.acq.dir,difndx(j,1)+k-1),bb(j,:));
+  end
+ 
+  % place back into ext image and normalize with meanintensity of difspots
+  
+  extstack(:,:,j)=gtPlaceSubImage(im,tmp,bb(j,1),bb(j,2));
+  extstack(:,:,j) = meanint*extstack(:,:,j)/integral(j);
+end
+
+index=ones(1,np);    % think of some clever rejection of outliers here....
+
+sino=squeeze(extstack(centerslice,:,:));
+
diff --git a/4_spot_sorting/gtReadExtRoi_360wl.m b/4_spot_sorting/gtReadExtRoi_360wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..a0f15e7a708871c28534cf2a53758588f81129b8
--- /dev/null
+++ b/4_spot_sorting/gtReadExtRoi_360wl.m
@@ -0,0 +1,74 @@
+function [extstack,sino,centerslice,bb,index]=gtReadExtRoi_360(grain,parameters); 
+
+np=length(grain.struct_ids);
+%grain.omega=[grain.omega,grain.omega];
+
+for j=1:np
+     % get lab system grain COM Coordinates from grain structure (produced by PEter's
+     % Indexing)
+	 
+	
+     [xl,yl,zl]=gtTrSamToLab(grain.center(1),grain.center(2),grain.center(3),grain.omega(j));
+	 xim = yl+ parameters.acq.bb(3)/2+0.5;   % grain COM coordinates in the direct beam images   (assumes center of rotation in the center of the beam)
+ 	 yim = parameters.acq.ydet/2-zl-parameters.acq.bb(2)+0.5;
+	
+	 
+	 % get Boundingbox sizes and integration range from all difspots
+	 mymcmd=sprintf('select BoundingBoxXSize, BoundingBoxYSize, ExtStartImage, ExtEndImage, StartImage, EndImage, Integral  from %sdifspot where difspotID=%d',parameters.acq.name,grain.struct_ids(j));
+	 [bbxs,bbys,startndx,endndx,difstartndx,difendndx,int]=mym(mymcmd);
+	 
+	 
+	 bbxs=round(bbxs*1.15);  %add 15% margin to bb
+	 bbys=round(bbys*1.15);
+	 integral(j)=int;
+	 ndx(j,:)=[startndx,endndx];
+	 difndx(j,:)=[difstartndx, difendndx];
+	 range(j)=endndx-startndx+1;
+	 difrange(j)=difendndx-difstartndx+1;
+	 bb(j,1)=max(1,round(xim-bbxs/2));    % horizontal start of bb in Ext image
+	 hend=min(parameters.acq.bb(3),bb(j,1)+bbxs-1);  % limit horizontal extend to size of Ext image...
+	 bb(j,3)=hend-bb(j,1)+1;
+	 
+	 bb(j,4)=bbys;               
+
+	 
+end	 
+
+% vertical bounds are identical for all extspots
+vertsize=mean(bb(:,4));   % first estimate of vertical size from average vertical size in difspots
+vertbeg=max(1,round(yim-vertsize/2));
+bb(:,2)=repmat(vertbeg,np,1);                         
+vertend=min(parameters.acq.bb(4),round(yim+vertsize/2));
+vertsize=vertend-vertbeg+1;  % update vertical size of bb, taking into account finite size of ext image
+bb(:,4)=repmat(vertsize,np,1);
+centerslice=round(vertbeg+0.5*vertsize);
+
+
+
+% now read and sum under bb mask
+extstack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),np);
+difstack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),np);
+
+tmp=zeros(parameters.acq.bb(4),parameters.acq.bb(3));
+meanint=mean(integral);
+
+for j=1:np
+  % get summed diffraction spot
+  %dif=gtGetSummedDifspot(grain.struct_ids(j),parameters,1);
+  %difstack(:,:,j)=gtPlaceSubImage(dif,tmp,difbb(j,1),difbb(j,2));
+  %difstack(:,:,j)=meanint*difstack(:,:,j)/integral(j);
+  im=zeros(bb(j,4),bb(j,3));
+  for k=1:difrange(j)
+	im = im+edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',parameters.acq.dir,difndx(j,1)+k-1),bb(j,:));
+  end
+ 
+  % place back into ext image and normalize with meanintensity of difspots
+  
+  extstack(:,:,j)=gtPlaceSubImage(im,tmp,bb(j,1),bb(j,2));
+  extstack(:,:,j) = meanint*extstack(:,:,j)/integral(j);
+end
+
+index=ones(1,np);    % think of some clever rejection of outliers here....
+
+sino=squeeze(extstack(centerslice,:,:));
+
diff --git a/4_spot_sorting/gtReadGrains.m b/4_spot_sorting/gtReadGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..dbff9529ec09b8c786017bf44e417b6ae93b0b77
--- /dev/null
+++ b/4_spot_sorting/gtReadGrains.m
@@ -0,0 +1,53 @@
+function [r_vectors, positions, positions2, bads] = gtReadGrains
+
+%create list of r_vectors and grain positions
+r_vectors=[];  %r_vectors = [grainid rx ry rz]
+positions =[]; %positions = [grainid grainx grainy grainz grainsize]
+positions2 =[]; %positions = [grainid grainx grainy grainz grainsize]
+bads=[];
+grainids=[];
+
+count=1;
+for i=1:1133
+  i
+  try 
+    
+    tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',i,i), 'R_vector', 'xcenter', 'ycenter', 'zcenter', 'nx', 'ny', 'zstart', 'zend', 'bad');
+    % tmp = load(sprintf('grain%d_/grain%d_.mat',i,i));
+		
+    %if ~(tmp.bad==1)
+         
+    %if isfield(tmp,'R_vector2')
+     %r_vectors(count,:) = [i tmp.R_vector2];
+    
+     %record ids
+     grainids(count)=i;
+     
+     %R-vector information
+    if isfield(tmp,'R_vector')
+     r_vectors(count,:) = [i tmp.R_vector];
+    else
+    r_vectors(count,:) = [i plot_rodrigues_precise(tmp.plane_normal, tmp.hkl, 0)];
+    end
+   
+    %Position info
+   positions(count,:) = [i tmp.xcenter tmp.ycenter tmp.zcenter (tmp.nx+tmp.ny+(tmp.zend-tmp.zstart))/3];
+   if isfield(tmp,'postcent')
+   positions2(count,:) = [i tmp.postcent (tmp.nx+tmp.ny+(tmp.zend-tmp.zstart))/3];
+   end
+    
+   %bad grain info
+if isfield(tmp,'bad')
+       bads(count)=tmp.bad;
+else                     % added to have same length for all output vectors
+       bads(count)=0;
+end
+    
+   count=count+1;
+   % end %if not bad
+    
+  end%try
+end
+
+save r_vectors r_vectors
+save positions positions
diff --git a/4_spot_sorting/gtReadSpots.m b/4_spot_sorting/gtReadSpots.m
new file mode 100755
index 0000000000000000000000000000000000000000..682f234c721962c42f932d58bcfc4601f0b3a9ed
--- /dev/null
+++ b/4_spot_sorting/gtReadSpots.m
@@ -0,0 +1,79 @@
+function [stack,sino,z_of_sino] = gtReadSpots(spot_id, struct_ids)
+% function [stack,sino,z_of_sino,varargout]=read_spots(struct_ids)
+% produce sinogram of all spots in struct_ids vector at the mid-height
+% of the seed spot (spot_id).
+% optional output argument orig holds original projection (Max)images for verification
+%could add orig, not currently supported
+
+%database enable!
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+
+
+
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_ids));
+
+z_of_sino = mym(sprintf(...
+  'select ceil(Yorigin + (Ysize/2)) from %sbb inner join %sbboxes on %sbb.bbID = %sbboxes.bboxID where %sbb.extspotID = %d',...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  spot_id));
+
+%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+% consider 15 pixel shift - s5_dct5_ only
+%warning('15 pixel shift (s5_dct5_ only) active in gtReadSpots')
+%spot_Omega = (180/pi)*gtGetOmega(spot_id);
+%if spot_Omega>120
+%z_of_sino = z_of_sino-15;
+%end
+
+Omega = (180/pi)*gtGetOmega(struct_ids);%convert to degrees
+%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+%read images to produce sinogram at position z_of_sino
+for i=1:length(struct_ids)
+  
+  [BoundingBox(1),BoundingBox(2)] = mym(sprintf('select Xorigin,Yorigin from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d',...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    struct_ids(i)));
+  
+  im = gtGetSummedExtSpot(struct_ids(i),1);% - 1 - already connected
+  warning('bodge - change zero origin bounding boxes in gtReadSpots - fix in autofind')
+  if BoundingBox(1)==0
+    BoundingBox(1)=1;
+  end
+  if BoundingBox(2)==0
+    BoundingBox(2)=1;
+  end
+  
+  %place in stack
+  stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  
+  %!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  %15 pixel offset - apply here
+ % warning('15 pixel shift (s5_dct5_ only) active in gtReadSpots')
+ % if(Omega(i)>120);%these need to be shifted by -15
+ % stack(1:end-15,:,i) = stack(16:end,:,i);
+ % stack(end-14:end,:,i) = zeros(15,parameters.acq.bb(3));%write zeros over the last 15 pixels
+ % end
+  %!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  
+  stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+  %read sino from stack
+  sino(:,i) = stack(z_of_sino, :, i);
+
+end
+
+end
diff --git a/4_spot_sorting/gtReadSpots_360.m b/4_spot_sorting/gtReadSpots_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..e144db154a6dae4be5dce7481cb00a2d52457305
--- /dev/null
+++ b/4_spot_sorting/gtReadSpots_360.m
@@ -0,0 +1,82 @@
+function [stack,sino,z_of_sino,index] = gtReadSpots_360(spot_id, struct_ids, replaced, parameters)
+% function [stack,sino,z_of_sino]=gtReadSpots_360(spot_id, struct_ids, replaced, parameters)
+
+% produce sinogram of all spots in struct_ids vector at the mid-height
+% of the seed spot (spot_id).
+%replaced: 0=use extspots, 1=replace all with difspots (like WriteStack_replaced)
+%_360 for single 360dgree scan convention
+
+%360degree scan convention - ak 10/2007
+
+if isempty(parameters)
+  load parameters;
+end
+
+index=ones(length(struct_ids),1);
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_ids));
+name=parameters.acq.name;
+
+%get the z position for the sinogram
+z_of_sino = mym(sprintf(...
+  'select ceil(Yorigin + (Ysize/2)) from %sbb inner join %sbboxes on %sbb.bbID = %sbboxes.bboxID where %sbb.extspotID = %d',...
+  name,name,name,name,name,...
+  spot_id));
+
+Omega = (180/pi)*gtGetOmega(struct_ids, parameters);%convert to degrees
+
+%read images to produce sinogram at position z_of_sino
+for i=1:length(struct_ids)
+  
+  if ~replaced
+  try
+	
+	[BoundingBox(1),BoundingBox(2)] = mym(sprintf('select Xorigin,Yorigin from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d',...
+    name,name,name,name,name,...
+    struct_ids(i)));
+  
+    im = gtGetSummedExtSpot_360(struct_ids(i), parameters ,1);% - 1 - already connected
+    %warning('bodge - change zero origin bounding boxes in gtReadSpots - fix in autofind')
+    if BoundingBox(1)==0
+	  BoundingBox(1)=1;
+	end
+	if BoundingBox(2)==0
+	  BoundingBox(2)=1;
+	end
+  
+	%place in stack
+	stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+	%scaling
+	stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+  catch
+	disp(sprintf('no extspot information for difspot %d - stack will have an empty image',struct_ids(i)));
+	disp('setting corresponding index to 0');
+	index(i)=0;
+  end
+  
+	
+  else %if replacing extspots with difspots
+  
+    BoundingBox=gtGetBBProps(struct_ids(i), parameters, 1);
+    im = gtGetSummedDifSpot(struct_ids(i), parameters, 1);
+    %warning('bodge - change zero origin bounding boxes in gtReadSpots - fix in autofind')
+	if BoundingBox(1)==0
+	  BoundingBox(1)=1;
+	end
+	if BoundingBox(2)==0
+	  BoundingBox(2)=1;
+	end
+  
+	%place in stack
+	stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+	%scaling
+	stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+  
+  end
+  
+  %read sino from stack
+  sino(:,i) = stack(z_of_sino, :, i);
+  
+ 
+end
+
+end
diff --git a/4_spot_sorting/gtReadSpots_360wl.m b/4_spot_sorting/gtReadSpots_360wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..e144db154a6dae4be5dce7481cb00a2d52457305
--- /dev/null
+++ b/4_spot_sorting/gtReadSpots_360wl.m
@@ -0,0 +1,82 @@
+function [stack,sino,z_of_sino,index] = gtReadSpots_360(spot_id, struct_ids, replaced, parameters)
+% function [stack,sino,z_of_sino]=gtReadSpots_360(spot_id, struct_ids, replaced, parameters)
+
+% produce sinogram of all spots in struct_ids vector at the mid-height
+% of the seed spot (spot_id).
+%replaced: 0=use extspots, 1=replace all with difspots (like WriteStack_replaced)
+%_360 for single 360dgree scan convention
+
+%360degree scan convention - ak 10/2007
+
+if isempty(parameters)
+  load parameters;
+end
+
+index=ones(length(struct_ids),1);
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_ids));
+name=parameters.acq.name;
+
+%get the z position for the sinogram
+z_of_sino = mym(sprintf(...
+  'select ceil(Yorigin + (Ysize/2)) from %sbb inner join %sbboxes on %sbb.bbID = %sbboxes.bboxID where %sbb.extspotID = %d',...
+  name,name,name,name,name,...
+  spot_id));
+
+Omega = (180/pi)*gtGetOmega(struct_ids, parameters);%convert to degrees
+
+%read images to produce sinogram at position z_of_sino
+for i=1:length(struct_ids)
+  
+  if ~replaced
+  try
+	
+	[BoundingBox(1),BoundingBox(2)] = mym(sprintf('select Xorigin,Yorigin from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d',...
+    name,name,name,name,name,...
+    struct_ids(i)));
+  
+    im = gtGetSummedExtSpot_360(struct_ids(i), parameters ,1);% - 1 - already connected
+    %warning('bodge - change zero origin bounding boxes in gtReadSpots - fix in autofind')
+    if BoundingBox(1)==0
+	  BoundingBox(1)=1;
+	end
+	if BoundingBox(2)==0
+	  BoundingBox(2)=1;
+	end
+  
+	%place in stack
+	stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+	%scaling
+	stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+  catch
+	disp(sprintf('no extspot information for difspot %d - stack will have an empty image',struct_ids(i)));
+	disp('setting corresponding index to 0');
+	index(i)=0;
+  end
+  
+	
+  else %if replacing extspots with difspots
+  
+    BoundingBox=gtGetBBProps(struct_ids(i), parameters, 1);
+    im = gtGetSummedDifSpot(struct_ids(i), parameters, 1);
+    %warning('bodge - change zero origin bounding boxes in gtReadSpots - fix in autofind')
+	if BoundingBox(1)==0
+	  BoundingBox(1)=1;
+	end
+	if BoundingBox(2)==0
+	  BoundingBox(2)=1;
+	end
+  
+	%place in stack
+	stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+	%scaling
+	stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+  
+  end
+  
+  %read sino from stack
+  sino(:,i) = stack(z_of_sino, :, i);
+  
+ 
+end
+
+end
diff --git a/4_spot_sorting/gtReadSpots_grain.m b/4_spot_sorting/gtReadSpots_grain.m
new file mode 100755
index 0000000000000000000000000000000000000000..4dd3da9727588bfe33890c4968366c765e2fb6e7
--- /dev/null
+++ b/4_spot_sorting/gtReadSpots_grain.m
@@ -0,0 +1,96 @@
+function [stack,sino,z_of_sino] = gtReadSpots_grain(grainid)
+% function [stack,sino,z_of_sino,varargout]=read_spots(struct_ids)
+% produce sinogram of all spots in struct_ids vector at the mid-height
+% of the seed spot (spot_id).
+% optional output argument orig holds original projection (Max)images for verification
+%could add orig, not currently supported
+
+%can be used to "refresh" stack!
+
+%database enable!
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+grain_data=load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid))
+struct_ids=grain_data.struct_ids;
+spot_id=struct_ids(1);%the first of the stack...
+
+
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_ids));
+
+%if it doesn't already exist, add an index of replaced projections
+if isfield(grain_data,'replaced')
+  replaced = logical(grain_data.replaced);
+else
+  replaced = logical(zeros(length(struct_ids),1));  
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'replaced', '-append') 
+end
+
+
+z_of_sino = mym(sprintf(...
+  'select ceil(Yorigin + (Ysize/2)) from %sbb inner join %sbboxes on %sbb.bbID = %sbboxes.bboxID where %sbb.extspotID = %d',...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  spot_id));
+
+
+
+%read images to produce sinogram at position z_of_sino
+for i=1:length(struct_ids)
+  
+  if replaced(i)==0
+  [BoundingBox(1),BoundingBox(2)] = mym(sprintf('select Xorigin,Yorigin from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d',...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    struct_ids(i)));
+  
+  im = gtGetSummedExtSpot(struct_ids(i));
+  %place in stack
+  stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  
+  stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+  %read sino from stack
+  sino(:,i) = stack(z_of_sino, :, i);
+
+  elseif replaced(i)==1
+  [BoundingBox(1),BoundingBox(2)] = mym(sprintf('select Xorigin,Yorigin from %sbboxes inner join %sextspot on SearchbbID=bboxID where %sbboxes.extspotID = %d',...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    parameters.acq.name,...
+    struct_ids(i)));
+  
+  warning('bodge because some SearchBoundingBoxes have zero origins')
+  if BoundingBox(1)==0
+    BoundingBox(1)=1;
+  end
+  if BoundingBox(2)==0
+    BoundingBox(2)=1;
+  end
+  
+  im=edf_read(sprintf('2_difspot/difspot%05d.edf',struct_ids(i)));
+  disp('Using transpose of summed dif image')
+  im=transpose(im);
+  disp('Transposing difspot')
+  
+  %place in stack
+  stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+  %read sino from stack
+  sino(:,i) = stack(z_of_sino,:,i);
+  
+end
+  
+end
+
+
+save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'stack','-append')
\ No newline at end of file
diff --git a/4_spot_sorting/gtReadSpots_pair.m b/4_spot_sorting/gtReadSpots_pair.m
new file mode 100755
index 0000000000000000000000000000000000000000..be5e1dea33cca3e7fd684119d717162210a5912c
--- /dev/null
+++ b/4_spot_sorting/gtReadSpots_pair.m
@@ -0,0 +1,88 @@
+function [stack,sino,z_of_sino] = gtReadSpots_pair(spot_id, struct_ids,pair,pair_vector,replaced)
+% function [stack,sino,z_of_sino,varargout]=read_spots(struct_ids)
+% produce sinogram of all spots in struct_ids vector at the mid-height
+% of the seed spot (spot_id).
+%pair, pair_vector (1 for currect dataset, 2 for pair dataset)
+%replaced: 0=use extspots, 1=replace all with difspots (like WriteStack_replaced)
+
+%database enable!
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+
+
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_ids));
+
+%get the z position for the sinogram
+if pair == 2
+  name=parameters.acq.pair_name;
+elseif pair ==1
+  name=parameters.acq.name;
+end
+z_of_sino = mym(sprintf(...
+  'select ceil(Yorigin + (Ysize/2)) from %sbb inner join %sbboxes on %sbb.bbID = %sbboxes.bboxID where %sbb.extspotID = %d',...
+  name,name,name,name,name,...
+  spot_id));
+
+  
+Omega = (180/pi)*gtGetOmega_pair(struct_ids,pair_vector, parameters);%convert to degrees
+
+
+%read images to produce sinogram at position z_of_sino
+for i=1:length(struct_ids)
+
+  if pair_vector(i) == 2
+  name=parameters.acq.pair_name;
+elseif pair_vector(i) ==1
+  name=parameters.acq.name;
+  end
+
+  
+  if ~replaced
+  
+  [BoundingBox(1),BoundingBox(2)] = mym(sprintf('select Xorigin,Yorigin from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d',...
+    name,name,name,name,name,...
+    struct_ids(i)));
+  
+  im = gtGetSummedExtSpot_pair(struct_ids(i), pair_vector(i) ,1);% - 1 - already connected
+  warning('bodge - change zero origin bounding boxes in gtReadSpots - fix in autofind')
+  if BoundingBox(1)==0
+    BoundingBox(1)=1;
+  end
+  if BoundingBox(2)==0
+    BoundingBox(2)=1;
+  end
+  
+  %place in stack
+  stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));  
+  %scaling
+  stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+  else %if replacing extspots with difspots
+  
+    BoundingBox=gtGetBBProps_pair(struct_ids(i), pair_vector(i));
+    im = gtGetSummedDifSpot_pair(struct_ids(i), pair_vector(i));
+    warning('bodge - change zero origin bounding boxes in gtReadSpots - fix in autofind')
+  if BoundingBox(1)==0
+    BoundingBox(1)=1;
+  end
+  if BoundingBox(2)==0
+    BoundingBox(2)=1;
+  end
+  
+  %place in stack
+  stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  %scaling
+  stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+ 
+  end
+  
+  %read sino from stack
+  sino(:,i) = stack(z_of_sino, :, i);
+
+end
+
+end
diff --git a/4_spot_sorting/gtRefMultiplicity.m b/4_spot_sorting/gtRefMultiplicity.m
new file mode 100755
index 0000000000000000000000000000000000000000..c8bd37e0650eea606a6703b96851648ecac15a96
--- /dev/null
+++ b/4_spot_sorting/gtRefMultiplicity.m
@@ -0,0 +1,10 @@
+function mult=gtRefMultiplicity(spacegroup)
+
+ref=gtGetSpaceGroupReflections(spacegroup);
+
+for i=1:size(ref,1)
+  mult(i)=size(gtGetReflections(ref(i,:)),1) ;
+end
+
+end
+
diff --git a/4_spot_sorting/gtResetGrainID.m b/4_spot_sorting/gtResetGrainID.m
new file mode 100755
index 0000000000000000000000000000000000000000..f3a51e752eb0d4ec7931090740f927eabb9a2efa
--- /dev/null
+++ b/4_spot_sorting/gtResetGrainID.m
@@ -0,0 +1,9 @@
+function gtResetGrainID(struct_ids)
+%resets to [] the extspot.GrainID fields of the given struct_ids
+load parameters
+
+numbers=sprintf('%d,',struct_ids);
+numbers(end)=[];
+
+mysqlcmd=sprintf('update %sextspot set GrainID=NULL where extspotID in (%s)',parameters.acq.name,numbers);
+mym(mysqlcmd)
\ No newline at end of file
diff --git a/4_spot_sorting/gtRodriguesFundZone.m b/4_spot_sorting/gtRodriguesFundZone.m
new file mode 100755
index 0000000000000000000000000000000000000000..c9c54364c68564f0de5142c89599e48d09284217
--- /dev/null
+++ b/4_spot_sorting/gtRodriguesFundZone.m
@@ -0,0 +1,52 @@
+function faces=gtRodriguesFundZone(spacegroup,sm)
+
+if ~exist('sm','var')
+	sm=0;
+end
+
+
+switch spacegroup
+
+	case {225, 229}    % Cubic
+		
+		% Sides of the polyhedron:
+		limcube=sqrt(2)-1;  % half the edge of the cube
+		cube=  [ 1  0  0  1  0  0;
+			-1  0  0 -1  0  0;
+			0  1  0  0  1  0;
+			0 -1  0  0 -1  0;
+			0  0  1  0  0  1;
+			0  0 -1  0  0 -1]*(limcube+sm);
+
+		% Facets:
+		limfacet=1/sqrt(3); % distance from cube center
+		facets=[ 1  1  1  1  1  1;
+			1  1 -1  1  1 -1;
+			1 -1  1  1 -1  1;
+			1 -1 -1  1 -1 -1;
+			-1  1  1 -1  1  1;
+			-1  1 -1 -1  1 -1;
+			-1 -1  1 -1 -1  1;
+			-1 -1 -1 -1 -1 -1]/sqrt(3)*(limfacet+sm);
+
+		faces=[cube; facets];
+
+	case {663, 194, 167}    % Hexagonal
+		
+		% Bottom and top of the polyhedron:
+		limbase=2-sqrt(3);  % half thickness along basal plane
+		basal= [ 0  0  1  0  0  1;
+			0  0 -1  0  0 -1]*(limbase+sm);
+
+		% Facets:
+		limfacet=1;         % extension laterally
+		t=(0:(pi/6):2*pi)';
+		t=t(1:end-1);
+		facets=[cos(t) sin(t) zeros(12,1)]*(limfacet+sm);
+		facets=[facets, facets];
+
+		faces=[basal; facets];
+
+end
+
+end
\ No newline at end of file
diff --git a/4_spot_sorting/gtRodriguesTest.m b/4_spot_sorting/gtRodriguesTest.m
new file mode 100755
index 0000000000000000000000000000000000000000..e61bd13b2258dee73603d986170763bd9e635a95
--- /dev/null
+++ b/4_spot_sorting/gtRodriguesTest.m
@@ -0,0 +1,444 @@
+
+function [Rout, good_plnorms]=gtRodriguesTest(plane_normal,hkl,spacegroup,latticepar,plot_flag,tol)
+
+%plane_normal = list of plane normals in sample coords
+%hkl a vector of reflection type eg [1 1 1; 0 0 2; 2 2 0 etc]
+%for hexagonal this this be a 4 index notation
+%plot_flag: 1 to plot figure, 0 to not plot anything
+
+%tic
+
+if ~exist('tol','var')
+  tol.d=0.02; % default=0.02; distance tolerance in Rodrigues's space
+	tol.pd=tol.d/5; % 0.002;
+	tol.pc=cos(tol.pd);
+	tol.sm=tol.d;
+end
+
+if ~exist('plot_flag','var')
+  plot_flag=false;
+end
+
+nof_pln=size(plane_normal,1);  % number of plane normals
+
+good_plnorms=false(1,nof_pln);
+Rout=[];
+R.l=[];
+R.wpl=[];
+R.enda=[];
+R.endb=[];
+
+fzone=gtRodriguesFundZone(spacegroup,tol.sm);  % fund. zone with safety margin
+fzone_e=gtRodriguesFundZone(spacegroup,0);     % exact fund. zone
+
+for i=1:nof_pln                                % loop through plane_normals
+	[Rvec,isec1,isec2]=gtRodriguesVectors2(plane_normal(i,:),hkl(i,:),spacegroup,latticepar,tol.sm);
+
+	R.l=[R.l; Rvec];                             % all lines in Rodrigues's space
+	R.wpl=[R.wpl; repmat(i,size(Rvec,1),1)];     % which plane normal it belongs to
+	R.enda=[R.enda; isec1];                      % intersection A with fund zone
+	R.endb=[R.endb; isec2];                      % intersection B with fund zone
+end
+
+nof_lines=length(R.wpl);
+
+Lp=false(nof_lines);
+Ld=zeros(nof_lines);   % distance of Rlines pairwise
+Lc=zeros(nof_lines);   % angle of Rlines pairwise
+
+Lrx=zeros(nof_lines);
+Lry=zeros(nof_lines);
+Lrz=zeros(nof_lines);
+
+[Lidb,Lida]=meshgrid(1:nof_lines);
+
+Pida=repmat(R.wpl,1,nof_lines);
+Pidb=Pida';
+
+for i=1:nof_lines-1
+	Ld(i,i+1:end)=gt2LinesDist(R.l(i,:),R.l(i+1:end,:));
+	Lc(i,i+1:end)=sum(repmat(R.l(i,4:6),nof_lines-i,1).*R.l(i+1:end,4:6),2);
+
+	r=gt2LinesIntersection(R.l(i,:),R.l(i+1:end,:));
+	Lrx(i,i+1:end)=r(:,1);
+	Lry(i,i+1:end)=r(:,2);
+	Lrz(i,i+1:end)=r(:,3);
+end
+
+Lp=(Ld<tol.pd) & (abs(Lc)>tol.pc);
+
+Ld=Ld+Ld';
+Lc=Lc+Lc';
+Lp=Lp | Lp';
+
+Lrx=Lrx+Lrx';
+Lry=Lry+Lry';
+Lrz=Lrz+Lrz';
+
+Lnear=Ld<tol.d;
+for i=1:nof_lines
+	Lnear(i,i)=false;
+end
+
+baseset=Lnear & (~Lp);
+
+Nbase=[Lrx(baseset),Lry(baseset),Lrz(baseset)];
+LAbase=Lida(baseset);
+LBbase=Lidb(baseset);
+PLAbase=Pida(baseset);
+PLBbase=Pidb(baseset);
+
+inzone=false(size(Nbase,1),1);
+
+for i=1:size(Nbase,1)
+	inzone(i)=gtIsPointInPolyhedron(Nbase(i,:),fzone);
+end
+
+Nbase=Nbase(inzone,:);
+LAbase=LAbase(inzone);
+LBbase=LBbase(inzone);
+PLAbase=PLAbase(inzone);
+PLBbase=PLBbase(inzone);
+
+d=tol.d^2;
+
+nof_N=size(Nbase,1);        % no. of nodes
+Nneib=false(nof_N);         % neighbouring nodes
+
+for i=1:nof_N-1
+  for j=i+1:nof_N
+		dist=(Nbase(i,:)-Nbase(j,:));
+		dist=dist*dist';
+		if dist<d
+			Nneib(i,j)=true;      % nodes are close to each other  
+			Nneib(j,i)=true;
+		end
+	end	
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+
+Nnb=zeros(nof_N,1); % number of planes belonging to the nodes
+nof_ints=0;         % no. of intersections (groups of nodes)
+
+finish=false;
+
+while ismember(true,Nneib)
+
+	nof_ints=nof_ints+1;
+	
+	for i=1:nof_N
+		inb=Nneib(:,i);           % index of remaining neighbouring nodes
+
+		pls=PLAbase(inb);
+		pls=[pls; PLBbase(inb)];
+		pls=unique(pls);
+		Nnb(i)=length(pls);       % no. of neighbouring nodes around this node
+		Npls{i}=pls;              % planes being close to this node
+
+		ls=LAbase(inb);
+		ls=[ls; LBbase(inb)];
+		ls=unique(ls);
+		Nls{i}=ls;        % lines being close to this node
+
+		if length(pls)==nof_pln
+			%ints{nof_ints}.nof_planes=noplsbn;
+			%ints{nof_ints}.planes=pls';
+			%ints{nof_ints}.lines=Nls{ibn};
+			Rvec=pofintersectexp(R.l(ls,:))';
+			%ints{nof_ints}.Rvec=Rvec;
+
+			if gtIsPointInPolyhedron(Rvec,fzone_e)
+				finish=true;
+				break  % for loop
+			end
+		end
+		
+	end
+
+	
+	if finish
+		int.lines=ls;
+		int.planes=pls';
+		int.Rvec=Rvec;
+		break % while loop
+	else
+		[noplsbn,ibn]=max(Nnb); % no. of belonging planes and index of best node
+
+		%ints{nof_ints}.nof_planes=noplsbn;
+		%ints{nof_ints}.planes=(Npls{ibn})';
+		%ints{nof_ints}.lines=Nls{ibn};
+		Rvec=pofintersectexp(R.l(Nls{ibn},:))';
+		%ints{nof_ints}.Rvec=Rvec;
+			
+		if gtIsPointInPolyhedron(Rvec,fzone_e)
+			int.lines=(Nls{ibn})';
+			int.planes=(Npls{ibn})';
+			int.Rvec=Rvec;
+			break % while loop
+		end
+	end
+	
+	Nneib(Nneib(:,ibn),:)=false;  % reduced neighbours matrix
+	Nneib(:,Nneib(ibn,:))=false;  % reduced neighbours matrix
+
+	Nneib(ibn,:)=false;  % reduced neighbours matrix
+	Nneib(:,ibn)=false;  % reduced neighbours matrix
+
+end
+
+if plot_flag
+	
+  sfPlotInts(int,R,fzone_e)
+end
+
+%Rout=ints{nof_ints}.Rvec;
+%good_plnorms(ints{nof_ints}.planes)=true;
+
+Rout=int.Rvec;
+good_plnorms(int.planes)=true;
+
+%toc
+	
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+
+% % Plot
+% if plot_flag
+% 	if all(hkl(j,:)==[1 1 1]) %(111) - red
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+% 
+% 	elseif all(hkl(j,:)==[0 0 2]) %(002) - blue
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+% 
+% 	elseif all(hkl(j,:)==[2 2 0]) %(220)  - green
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+% 
+% 	elseif all(hkl(j,:)==[3 1 1]) %(311)   -  black
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+% 
+% 	else %all others in pink
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+% 
+% 	end
+% end
+% 
+% %____plot______ % adapted to the snow case
+% if plot_flag
+% 	hkil_hex=hkl;
+% 
+% 	if all(hkil_hex(j,:)==[0 0 0 2])
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+% 
+% 	elseif all(hkil_hex(j,:)==[1 1 -2 0])
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+% 
+% 	elseif all(hkil_hex(j,:)==[1 -1 0 0])
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+% 	elseif all(hkil_hex(j,:)==[1 0 -1 0])%for Mg
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+% 
+% 	elseif all(hkil_hex(j,:)==[1 -1 0 1])
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+% 	elseif all(hkil_hex(j,:)==[1 0 -1 1]) %for Mg
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+% 
+% 	elseif all(hkil_hex(j,:)==[1 1 -2 2])
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'c');
+% 
+% 	else %all others use pink
+% 		plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+% 
+% 	end
+% 
+% end
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SUB-FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%  Fundamental zone - cubic
+function faces=sfZoneCubic(sm)
+
+% Sides of the polyhedron:
+limcube=sqrt(2)-1;  % half the edge of the cube
+cube=  [ 1  0  0  1  0  0;
+	      -1  0  0 -1  0  0;
+			   0  1  0  0  1  0;
+				 0 -1  0  0 -1  0;
+				 0  0  1  0  0  1;
+				 0  0 -1  0  0 -1]*(limcube+sm);
+
+% Facets:			 
+limfacet=1/sqrt(3); % distance from cube center
+facets=[ 1  1  1  1  1  1;
+	       1  1 -1  1  1 -1;
+				 1 -1  1  1 -1  1;
+				 1 -1 -1  1 -1 -1;
+				-1  1  1 -1  1  1;
+				-1  1 -1 -1  1 -1;
+				-1 -1  1 -1 -1  1;
+				-1 -1 -1 -1 -1 -1]/sqrt(3)*(limfacet+sm);
+	      
+faces=[cube; facets];
+
+end
+
+% figure, hold on, axis equal
+% plot3(l(1),l(2),l(3),'ro')
+% quiver3(l(1),l(2),l(3),-l(4),-l(5),-l(6),1,'r')
+% z0=zeros(6,1);
+% quiver3(z0,z0,z0,cube(:,4),cube(:,5),cube(:,6),0,'b')
+% z0=zeros(8,1);
+% quiver3(z0,z0,z0,facets(:,4),facets(:,5),facets(:,6),0,'g')
+% plot3(isecs(:,1),isecs(:,2),isecs(:,3),'bo')
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Fundamental zone - hexagonal
+
+function faces=sfZoneHexagonal(sm)
+% sm: safety margin (>=1)
+
+% Bottom and top of the polyhedron:
+limbase=2-sqrt(3);  % half thickness along basal plane
+basal= [ 0  0  1  0  0  1;
+				 0  0 -1  0  0 -1]*(limbase+sm);
+
+% Facets:			 
+limfacet=1;         % extension laterally
+t=(0:(pi/6):2*pi)';
+t=t(1:end-1);
+facets=[cos(t) sin(t) zeros(12,1)]*(limfacet+sm);
+facets=[facets, facets];
+
+faces=[basal; facets];
+
+end
+
+% figure, hold on, axis equal
+% plot3(l(1),l(2),l(3),'ro')
+% quiver3(l(1),l(2),l(3),-l(4),-l(5),-l(6),2,'r')
+% z0=zeros(2,1);
+% quiver3(z0,z0,z0,basal(:,4),basal(:,5),basal(:,6),0,'b')
+% z0=zeros(12,1);
+% quiver3(z0,z0,z0,facets(:,4),facets(:,5),facets(:,6),0,'g')
+% plot3(isecs(:,1),isecs(:,2),isecs(:,3),'bo')
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Plotting
+
+function sfPlotInts(int,R,fzone_e)
+
+figure, hold on, axis equal
+xlabel('x')
+ylabel('y')
+zlabel('z')
+grid
+
+rangemin=min(fzone_e(:,1:3));
+rangemax=max(fzone_e(:,1:3));
+
+xlim([rangemin(1) rangemax(1)]);
+ylim([rangemin(2) rangemax(2)]);
+zlim([rangemin(3) rangemax(3)]);
+
+%z0=zeros(6,1);
+%quiver3(z0,z0,z0,cube(:,4),cube(:,5),cube(:,6),0,'k')
+%z0=zeros(8,1);
+%quiver3(z0,z0,z0,facets(:,4),facets(:,5),facets(:,6),0,'k.-')
+
+nof_lines=size(R.l,1);
+
+lc=autumn(nof_lines);
+for i=1:nof_lines
+	
+	isec=[];
+	
+	isec=gtLinePolyhedronIntersection(R.l(i,:),fzone_e);
+	
+	if ~isempty(isec)
+		R.enda(i,:)=isec(1,:);
+		R.endb(i,:)=isec(2,:);
+	
+		if ismember(i,int.lines)
+			plot3([R.enda(i,1) R.endb(i,1)],[R.enda(i,2) R.endb(i,2)],[R.enda(i,3) R.endb(i,3)],'Color','k') %lc(i,:))
+		else
+			plot3([R.enda(i,1) R.endb(i,1)],[R.enda(i,2) R.endb(i,2)],[R.enda(i,3) R.endb(i,3)],'Color',lc(i,:))
+		end
+	end
+end
+
+
+plot3(int.Rvec(1),int.Rvec(2),int.Rvec(3),'bo')
+plot3(int.Rvec(1),int.Rvec(2),int.Rvec(3),'bo','MarkerSize',15)
+
+
+% 	if ismember(i,int.lines)
+% 		plot3([R.enda(i,1) R.endb(i,1)],[R.enda(i,2) R.endb(i,2)],[R.enda(i,3) R.endb(i,3)],'Color','k') %lc(i,:))
+% 	else
+% 		plot3([R.enda(i,1) R.endb(i,1)],[R.enda(i,2) R.endb(i,2)],[R.enda(i,3) R.endb(i,3)],'Color',lc(i,:))
+% 	end
+
+% nof_ints=length(ints);
+% ic=flipud(winter(nof_ints));
+% for i=1:nof_ints
+% 	plot3(ints{i}.Rvec(1),ints{i}.Rvec(2),ints{i}.Rvec(3),'o','Color',ic(i,:))
+% end
+% 
+% plot3(ints{end}.Rvec(1),ints{end}.Rvec(2),ints{end}.Rvec(3),'bo','MarkerSize',15)
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% function sfPlot(sm,isec)
+% 
+% limcube=sqrt(2)-1;  % half the edge of the cube
+% limfacet=1/sqrt(3); % distance from cube center
+% 
+% % Faces of the polyhedron:
+% cube=  [ 1  0  0  1  0  0;
+% 	      -1  0  0 -1  0  0;
+% 			   0  1  0  0  1  0;
+% 				 0 -1  0  0 -1  0;
+% 				 0  0  1  0  0  1;
+% 				 0  0 -1  0  0 -1]*(limcube+sm);
+% 
+% facets=[ 1  1  1  1  1  1;
+% 	       1  1 -1  1  1 -1;
+% 				 1 -1  1  1 -1  1;
+% 				 1 -1 -1  1 -1 -1;
+% 				-1  1  1 -1  1  1;
+% 				-1  1 -1 -1  1 -1;
+% 				-1 -1  1 -1 -1  1;
+% 				-1 -1 -1 -1 -1 -1]/sqrt(3)*(limfacet+sm);
+% 	      
+% faces=[cube; facets];
+% 
+% figure, hold on, axis equal
+% %plot3(l(1),l(2),l(3),'ro')
+% %quiver3(l(1),l(2),l(3),-l(4),-l(5),-l(6),1,'r')
+% z0=zeros(6,1);
+% quiver3(z0,z0,z0,cube(:,4),cube(:,5),cube(:,6),0,'b')
+% z0=zeros(8,1);
+% quiver3(z0,z0,z0,facets(:,4),facets(:,5),facets(:,6),0,'g')
+% %plot3(isecs(:,1),isecs(:,2),isecs(:,3),'bo')
+% %plot3(Lrx(Lnear),Lry(Lnear),Lrz(Lnear),'bo')
+% %plot3(Pg(:,1),Pg(:,2),Pg(:,3),'bo')
+% lc=autumn(size(isec,1));
+% for i=1:size(isec,1)
+% 	plot3(isec(i,[1 4])',isec(i,[2 5])',isec(i,[3 6])','Color',lc(i,:))
+% end
+% 
+% 
+% end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
diff --git a/4_spot_sorting/gtRodriguesVectors.m b/4_spot_sorting/gtRodriguesVectors.m
new file mode 100755
index 0000000000000000000000000000000000000000..b1f936a48ede9a215aa1006036640369b7850b7a
--- /dev/null
+++ b/4_spot_sorting/gtRodriguesVectors.m
@@ -0,0 +1,88 @@
+% Gives Rodrigues vectors (line in R-space) for a given plane normal, {hkl} family,
+% spacegroup (and lattice parameter).
+
+function Rv=gtRodriguesVectors(plnorm,hkl,spacegroup)
+
+Rv=[];
+% modif sabine 13-12-07
+load parameters
+latticepar=parameters.acq.latticepar;
+% end modif sabine
+
+switch spacegroup
+  case {225, 229} % ie cubic lattice
+
+    %________calculate h vector___________
+    %from eq (3.7) in Poulsen
+    %B is identity matrix in cubic material
+    %gtGetReflections returns matrix of all reflections related by symmetry
+    %to hkl, using Riso GetCubicSymOp.m
+    hkl_reflections = gtGetReflections(hkl);
+
+    Rv=zeros(size(hkl_reflections,1),6);
+    
+    for i=1:size(hkl_reflections,1) % loop of hkl reflections
+    
+      h = hkl_reflections(i,:);
+      h = h./(sqrt(h*h'));
+      %________calculate y vector___________
+      % y is the normalised scattering vector in sample system = plane normal
+      y = plnorm;
+
+      %_____calculate rodrigues space vector_____
+      %formulae (3.16), (3.17) in Poulsen
+
+      r_zero = cross(h,y)./(1+(dot(h,y)));
+      r_direction = (h + y)./(1+(dot(h,y)));
+    
+      Rv(i,1:6)=[r_zero r_direction];
+      
+    end
+
+    
+  case {663, 194}     % hexagonal, snow
+
+    plnorm_cart=plnorm;
+
+    hkil_reflections_hex = gtGetReflections_sab(hkl);
+
+    Rv=zeros(size(hkil_reflections_hex,1),6);
+    
+    for i=1:size(hkil_reflections_hex,1) % loop of hkil reflections
+
+      % passage de l espace direct hexagonal en coordonnees cartesiennes
+      h(1)= hkil_reflections_hex(i,1) + 0.5 * hkil_reflections_hex(i,2);
+      h(2)= 3^0.5/2 *hkil_reflections_hex(i,2);
+      h(3)= hkil_reflections_hex(i,4);
+
+      % normalisation of the cartesian coordinates space
+      % allow for c/a ratio in hexagonal unit cell
+      h(1)=h(1)*2/(sqrt(3)*latticepar(1));
+      h(2)=h(2)*2/(sqrt(3)*latticepar(1));
+      h(3)=h(3)/latticepar(3);
+
+      % normalise to unit vector
+      h = h./(sqrt(h*h'));
+
+      %________calculate y vector___________
+      % y is the normalised scattering vector in cartesian system = plane normal
+      y = plnorm_cart;
+      y = y./(sqrt(y*y'));
+
+      %_____calculate rodrigues space vector_____
+      %formulae (3.16), (3.17) in Poulsen
+
+      r_zero = cross(h,y)./(1+(dot(h,y)));
+      r_direction = (h + y)./(1+(dot(h,y)));
+
+      Rv(i,1:6)=[r_zero r_direction];
+
+    end
+
+  otherwise
+    error('Sorry, only spacegroup 225,229,663,194 are recognised.')
+
+end
+
+
+end % of function
diff --git a/4_spot_sorting/gtRodriguesVectors2.m b/4_spot_sorting/gtRodriguesVectors2.m
new file mode 100755
index 0000000000000000000000000000000000000000..b25b82d750140e283827dfe9648f1dfec2166615
--- /dev/null
+++ b/4_spot_sorting/gtRodriguesVectors2.m
@@ -0,0 +1,115 @@
+% Gives Rodrigues vectors (line in R-space) for a given plane normal, {hkl} family,
+% spacegroup (and lattice parameter).
+
+function [Rvec,isec1,isec2]=gtRodriguesVectors2(plnorm,hkl,spacegroup,latticepar,sm)
+
+if ~exist('sm','var')
+	sm=0;
+end
+
+Rvec=[];
+isec1=[];
+isec2=[];
+
+switch spacegroup
+  
+	case {225, 229} % Cubic lattice
+
+    %  gtGetReflections returns matrix of all reflections related by symmetry
+    %   to hkl, using Riso GetCubicSymOp.m
+
+		hkl_reflections = gtGetReflections(hkl);
+
+		fzone=gtRodriguesFundZone(spacegroup,sm); % faces of the fundamental zone
+		
+    for i=1:size(hkl_reflections,1) % loop of hkl reflections
+   
+			% Calculate h vector
+			%  from eq (3.7) in Poulsen
+			%  B is identity matrix in cubic material
+  
+      h = hkl_reflections(i,:);
+      h = h./(sqrt(h*h'));
+
+			% Normalised scattering vector in sample system = plane normal :
+      y = plnorm;
+
+      % Rodrigues space vector
+      %  formulae (3.16), (3.17) in Poulsen
+
+      r_zero = cross(h,y)./(1+(dot(h,y)));
+      r_direction = (h + y)./(1+(dot(h,y)));
+    
+			r_direction = r_direction/sqrt(r_direction*r_direction');
+			
+      Rv=[r_zero r_direction];
+			
+			% Does the line intersect with the fundamental zone?
+			isec=gtLinePolyhedronIntersection(Rv,fzone);
+	
+			if ~isempty(isec)
+				Rvec=[Rvec; Rv];
+				
+				isec1=[isec1; isec(1,:)];
+				isec2=[isec2; isec(2,:)];
+			end
+		
+		end
+    
+  case {663, 194, 167} % Hexagonal lattice
+
+    plnorm_cart=plnorm;
+
+    hkil_reflections_hex = gtGetReflections_sab(hkl);
+
+		fzone=gtRodriguesFundZone(spacegroup,sm); % faces of the fundamental zone
+    
+    for i=1:size(hkil_reflections_hex,1) % loop of hkil reflections
+
+      % passage de l espace direct hexagonal en coordonnees cartesiennes
+      h(1)= hkil_reflections_hex(i,1) + 0.5 * hkil_reflections_hex(i,2);
+      h(2)= 3^0.5/2 *hkil_reflections_hex(i,2);
+      h(3)= hkil_reflections_hex(i,4);
+
+      % normalisation of the cartesian coordinates space
+      % allow for c/a ratio in hexagonal unit cell
+      h(1)=h(1)*2/(sqrt(3)*latticepar(1));
+      h(2)=h(2)*2/(sqrt(3)*latticepar(1));
+      h(3)=h(3)/latticepar(3);
+
+      % normalise to unit vector
+      h = h./(sqrt(h*h'));
+
+      % Normalised scattering vector in cartesian system = plane normal :
+      y = plnorm_cart;
+      y = y./(sqrt(y*y'));
+
+      % Rodrigues space vector
+      %  formulae (3.16), (3.17) in Poulsen
+
+      r_zero = cross(h,y)./(1+(dot(h,y)));
+      r_direction = (h + y)./(1+(dot(h,y)));
+
+			r_direction = r_direction/sqrt(r_direction*r_direction');
+
+      Rv=[r_zero r_direction];
+
+			% Does the line intersect with the fundamental zone?
+			isec=gtLinePolyhedronIntersection(Rv,fzone);
+	
+			if ~isempty(isec)
+				Rvec=[Rvec; Rv];
+				
+				isec1=[isec1; isec(1,:)];
+				isec2=[isec2; isec(2,:)];
+			end
+
+    end
+
+  otherwise
+    error('Sorry, only spacegroup 225,229,663,194 are recognised.')
+
+end
+
+
+end % of function
diff --git a/4_spot_sorting/gtSampleGeoInSampleSystem.m b/4_spot_sorting/gtSampleGeoInSampleSystem.m
new file mode 100755
index 0000000000000000000000000000000000000000..cfb8608ae4f6cda3e9ae288ff5366ecf31e19398
--- /dev/null
+++ b/4_spot_sorting/gtSampleGeoInSampleSystem.m
@@ -0,0 +1,32 @@
+% FUNCTION sample=gtSampleGeoInSampleSystem(parameters)
+% 
+% Defines the origin of Z axis of the sample coordinate system, and gives 
+%  sample radius, top, bottom and volume in the sample system, in pixels.
+%
+% Sample is fixed in the lab reference at omega=0 (right-handed):
+%   X axis: along the beam, origin on the rotation axis
+%   Y axis: horizontal
+%   Z axis: vertical, positive upwards
+%
+
+function sample=gtSampleGeoInSampleSystem(parameters)
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+% Sample coordinate system
+% origin X = on the rotation axis
+% origin Y = on the rotation axis
+
+% origin Z in image coordinates:
+sorZim = floor(parameters.acq.ydet/2); % central pixel in images (the one higher)   
+sample.sorZim=sorZim;
+
+% Radius, top, bottom, volume:
+sample.rad= parameters.acq.bb(3)/2;   
+sample.top= sorZim-parameters.acq.bb(2);   
+sample.bot= sorZim-(parameters.acq.bb(2)+parameters.acq.bb(4));
+sample.vol= (sample.top-sample.bot)*sample.rad^2*pi ;
+
+end
diff --git a/4_spot_sorting/gtSelectCandidates.m b/4_spot_sorting/gtSelectCandidates.m
new file mode 100755
index 0000000000000000000000000000000000000000..91706de9b0290c06866e1c33532fa3766bbc6285
--- /dev/null
+++ b/4_spot_sorting/gtSelectCandidates.m
@@ -0,0 +1,41 @@
+function cand=gtSelectCandidates(zstart,zend,Ysize)
+% function [cand_id]=select_candidates(zstart,zend,Intensity)
+% cand_id:     list of "good" initial spots
+% zstart:      vertical filter: only spots which are contained between
+% zend         zstart and zend will be selected
+% Intensity    only spots stronger than average Intensity will be selected
+
+% db enabled
+parameters=[];
+if isempty(parameters)
+  load parameters.mat
+end
+
+% if parameters.acq.type == '360degree'
+% %get the root of the pair name
+% name=parameters.acq.pair_tablename;
+% name(end-8:end)=[];
+% elseif parameters.acq.type == '180degree'
+  name=parameters.acq.name;
+% else
+%   disp('unrecognised data type!')
+% return
+% end
+
+cand=[];
+
+int=[];
+counter=1;
+mym('close')
+gtDBConnect
+% want ro return list of struct_ids where boundingbox of spot is within
+% range of zstart and zend, and intensity is great than intensity
+
+cand=mym(sprintf([...
+  'select %sbb.extspotID from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+  'where (Yorigin<%d) and (Yorigin+Ysize)>%d and Ysize>%d and isnull(GrainID) order by Ysize desc'],...
+  name,name,name,name,name,...%
+	zend,zstart,Ysize));
+
+
+
diff --git a/4_spot_sorting/gtShearDifspots.m b/4_spot_sorting/gtShearDifspots.m
new file mode 100755
index 0000000000000000000000000000000000000000..d2b9d1b04025e92784332a9365005fbea768b5cc
--- /dev/null
+++ b/4_spot_sorting/gtShearDifspots.m
@@ -0,0 +1,97 @@
+function [difstack,omegadif]=gtShearDifspots(grain)
+
+if ~exist('parameters','var')
+  load parameters
+end  
+
+for i=1:length(grain.struct_ids)
+
+
+	% n= unit vector along the direction of the diffracted beam
+
+	n=[cosd(2*grain.theta(i));sind(2*grain.theta(i))*sind(grain.eta(i));sind(2*grain.theta(i))*cosd(grain.eta(i))];
+	n=n/norm(n);
+
+	
+	% unit vectors of the Laboratory (image) coordinate system
+	X=[1; 0; 0];
+	Y=[0; 1; 0];
+	Z=[0; 0; 1];
+
+	
+	% calculate the angle delta between X and np (projection of n onto the X-Y
+	% plane)  cos(delta)= dot (np,X)/norm)n');
+	
+	delta=asind(n(2)/sqrt(n(1)^2+n(2)^2));
+	
+	
+	% 2D coordinates of the corners of the undeformed triangle in the detector
+	% system
+
+	U=[0 0; 1 0; 0 1];
+
+	% r: rotation of X by 2*grain.theta(i) around r will result in n  
+
+	r=cross(X,n)/sqrt((1-dot(n,X)^2));
+
+	% calculate diffracted beam coordinate system
+
+	x=RotVecArAxed(X,r,2*grain.theta(i));
+	y=RotVecArAxed(Y,r,2*grain.theta(i));
+	z=RotVecArAxed(Z,r,2*grain.theta(i));
+
+	% calculate intersection of the 3 diffracted beams (starting from the cormers of the 
+	% undeformed triangle in the dector plane) with the diffracted beam
+	% coordinate system (still expressed in the Laboratory coordinate system)
+
+	XP=[0;0;0]-dot([0;0;0],n)*n;      
+	YP=Y-dot(Y,n)*n;
+	ZP=Z-dot(Z,n)*n;
+
+	% now express these points in the diffracted beam coordinate system
+
+	A=[x,y,z];
+
+	sx=inv(A)*XP;
+	sy=inv(A)*YP;
+	sz=inv(A)*ZP;
+
+	UP=[sx(2) sx(3);sy(2) sy(3);sz(2) sz(3)];
+
+    omegadif(i)=grain.omega(i)+delta;
+
+	T=maketform('affine',U,UP);
+	
+    tmp=zeros(parameters.acq.bb(4),parameters.acq.bb(3));
+	
+	%get summed diffraction spot
+	grain.center(1)=grain.ycenter-parameters.acq.bb(3)/2;   % not very elegant: transform back for compatibility with calls of gtReadextroi outside of gtINWriteGrainFolder...
+	grain.center(2)=grain.xcenter-parameters.acq.bb(3)/2;
+	grain.center(3)=parameters.acq.ydet/2-parameters.acq.bb(2)-grain.zcenter;
+	
+     [xl,yl,zl]=gtTrSamToLab(grain.center(1),grain.center(2),grain.center(3),grain.omega(i)+delta);
+	 xim = yl+ parameters.acq.bb(3)/2;   % grain COM coordinates in the direct beam images   (assumes center of rotation in the center of the beam)
+ 	 yim = parameters.acq.ydet/2-zl-parameters.acq.bb(2);
+	
+	 mymcmd=sprintf('select BoundingBoxXOrigin, BoundingBoxYOrigin, BoundingBoxXSize, BoundingBoxYSize, CentroidX, CentroidY, Integral  from %sdifspot where difspotID=%d',parameters.acq.name,grain.struct_ids(i));
+	 [bbxo,bbyo,bbxs,bbys,cenx,ceny,integral(i)]=mym(mymcmd);
+	 cenx=cenx-bbxo;     % horizontal distance to the center of mass of the difspot
+	 ceny=ceny-bbyo;     % vertical distance
+	 
+	 difbb(1)=max(1,round(xim-cenx)); 
+	 difbb(2)=max(1,round(yim-ceny));
+	 
+	 difspot=gtGetSummedDifspot(grain.struct_ids(i),parameters,1);
+	 difspot2=imtransform(difspot,T);
+	
+	
+	difstack(:,:,i)=gtPlaceSubImage(difspot2,tmp,difbb(1),difbb(2));
+	difstack(:,:,i)=difstack(:,:,i)/sum(sum(difstack(:,:,i))); %don't trust integral value in table!
+
+	
+end	
+
+
+difstack=difstack.*mean(integral);
+
+
diff --git a/4_spot_sorting/gtShearDifspots_flip.m b/4_spot_sorting/gtShearDifspots_flip.m
new file mode 100755
index 0000000000000000000000000000000000000000..d808586230686e69c203f7073a9c2f13f99ea85a
--- /dev/null
+++ b/4_spot_sorting/gtShearDifspots_flip.m
@@ -0,0 +1,137 @@
+function [difstack,grain]=gtShearDifspots_wl(grain,parameters,index)
+
+if ~exist('parameters','var')
+  load parameters
+end
+
+for i=index
+
+
+	% n= unit vector along the direction of the diffracted beam
+
+	n=[cosd(2*grain.theta(i));sind(2*grain.theta(i))*sind(grain.eta(i));sind(2*grain.theta(i))*cosd(grain.eta(i))];
+	n=n/norm(n);
+
+	
+	% unit vectors of the Laboratory (image) coordinate system
+	X=[1; 0; 0];
+	Y=[0; 1; 0];
+	Z=[0; 0; 1];
+
+	
+	% calculate the angle delta between X and np (projection of n onto the X-Y
+	% plane)  cos(delta)= dot (np,X)/norm(np);
+	
+	delta=asind(n(2)/sqrt(n(1)^2+n(2)^2));
+	phi(i)=asind(n(3));
+	
+	
+	% 2D coordinates of the corners of the undeformed triangle in the detector
+	% system
+
+	U=[0 0; 1 0; 0 1];
+
+	% r: rotation of X by 2*grain.theta(i) around r will result in n  
+
+	r=cross(X,n)/sqrt((1-dot(n,X)^2));
+
+	% calculate diffracted beam coordinate system
+
+	x=RotVecArAxed(X,r,2*grain.theta(i));
+	y=RotVecArAxed(Y,r,2*grain.theta(i));
+	z=RotVecArAxed(Z,r,2*grain.theta(i));
+
+	% calculate intersection of the 3 diffracted beams (starting from the cormers of the 
+	% undeformed triangle in the dector plane) with the diffracted beam
+	% coordinate system (still expressed in the Laboratory coordinate system)
+
+	XP=[0;0;0]-dot([0;0;0],n)*n;      
+	YP=Y-dot(Y,n)*n;
+	ZP=Z-dot(Z,n)*n;
+
+	% now express these points in the diffracted beam coordinate system
+
+	A=[x,y,z];
+
+	sx=inv(A)*XP;
+	sy=inv(A)*YP;
+	sz=inv(A)*ZP;
+
+	UP=[sx(2) sx(3);sy(2) sy(3);sz(2) sz(3)];
+
+    grain.omegashear(i)=grain.omega(i)-delta;
+	grain.phi(i)=phi(i);
+
+
+	T=maketform('affine',U,UP);
+	
+    tmp=zeros(parameters.acq.bb(4),parameters.acq.bb(3));
+	
+	%get summed diffraction spot
+	
+	
+     [xl,yl,zl]=gtTrSamToLab2(grain.center(1),grain.center(2),grain.center(3),grain.omegashear(i),phi(i));  % two successive rotations
+	 xim = parameters.acq.bb(3)/2-yl+0.5;   % grain COM coordinates in the direct beam images   (assumes center of rotation in the center of the beam)
+ 	 yim = parameters.acq.ydet/2+1.5-zl-parameters.acq.bb(2);
+	
+	
+	 
+	 %mymcmd=sprintf('select BoundingBoxXOrigin, BoundingBoxYOrigin, BoundingBoxXSize, BoundingBoxYSize, CentroidX, CentroidY, Integral  from %sdifspot where difspotID=%d',parameters.acq.name,grain.struct_ids(i));
+	 %[bbxo,bbyo,bbxs,bbys,cenx,ceny,integral(i)]=mym(mymcmd);
+	 name=sprintf('difspot%d',i);
+	 difspot=sdt_read(name);
+	 difspot([1:100,end-99:end],:)=[];
+	 difspot(:,[1:100,end-99:end])=[];
+	 
+	 difspot2=imtransform(difspot,T);
+     
+	 s=regionprops(bwlabel(difspot2));
+	 
+	 bbxo=s.BoundingBox(1)+0.5;
+	 bbyo=s.BoundingBox(2)+0.5;
+	 bbxs=s.BoundingBox(3);
+	 bbys=s.BoundingBox(4);
+	 cenx=sum(difspot2)*[1:size(difspot2,2)]'/sum(difspot2(:));
+	 ceny=sum(difspot2,2)'*[1:size(difspot2,1)]'/sum(difspot2(:));
+	 
+	 
+	 cenx=cenx-bbxo;     % horizontal distance to the center of mass of the difspot
+	 ceny=ceny-bbyo;     % vertical distance
+	 
+	 x1=xim-cenx;
+	 y1=yim-ceny;
+	 
+	 sx=round(x1)-x1;
+	 sy=round(y1)-y1;
+	 % shift the spot to have COM in center of pixel
+	 
+	 difspot2=interp2(difspot2,[1+sx:size(difspot,2)+sx],[1+sy:size(difspot,1)+sy]','linear',0);
+	 
+	 difbb(1)=max(1,round(x1));
+	 difbb(2)=max(1,round(y1));
+	 %difbb(1)=max(1,round(xim-cenx)); 
+	 %difbb(2)=max(1,round(yim-ceny));
+	 
+	 %difspot=gtGetSummedDifspot(grain.struct_ids(i),parameters,1);
+	 
+	
+	difstack(:,:,i)=gtPlaceSubImage(difspot2,tmp,difbb(1),difbb(2));
+    test=difstack(:,:,i);
+	cx=sum(test)*[1:size(test,2)]'/sum(test(:));
+	cy=sum(test,2)'*[1:size(test,1)]'/sum(test(:));
+	disp([cx,xim])
+	disp([cy,yim])
+	%keyboard
+	%integral=100;
+	%difstack(:,:,i)=difstack(:,:,i)/sum(sum(difstack(:,:,i))); %don't trust integral value in table!
+    %difstack=difstack.*mean(integral);
+	name=sprintf('shearspot%d',i);   % 
+    
+	sdt_write(name,difstack(:,:,i),'float32');
+	
+end	
+
+
+
+
+
diff --git a/4_spot_sorting/gtShearDifspots_wl.m b/4_spot_sorting/gtShearDifspots_wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..2f662c1d1399d9e977db233a0fc04c22c923a9ef
--- /dev/null
+++ b/4_spot_sorting/gtShearDifspots_wl.m
@@ -0,0 +1,151 @@
+function [difstack,grain]=gtShearDifspots_wl(grain,grainid,parameters,index)
+
+if ~exist('parameters','var')
+  load parameters
+end
+
+grain=grain{grainid};
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+simulation=0;
+
+
+for i=index
+
+
+	% n= unit vector along the direction of the diffracted beam
+
+	n=[cosd(2*grain.theta(i));sind(2*grain.theta(i))*sind(grain.eta(i));sind(2*grain.theta(i))*cosd(grain.eta(i))];
+	n=n/norm(n);
+
+	
+	% unit vectors of the Laboratory (image) coordinate system
+	X=[1; 0; 0];
+	Y=[0; 1; 0];
+	Z=[0; 0; 1];
+
+	
+	% calculate the angle delta between X and np (projection of n onto the X-Y
+	% plane)  cos(delta)= dot (np,X)/norm(np);
+	
+	delta=asind(n(2)/sqrt(n(1)^2+n(2)^2));
+	phi(i)=asind(n(3));
+	
+	
+	% 2D coordinates of the corners of the undeformed triangle in the detector
+	% system
+
+	U=[0 0; 1 0; 0 1];
+
+	% r: rotation of X by 2*grain.theta(i) around r will result in n  
+
+	r=cross(X,n)/sqrt((1-dot(n,X)^2));
+
+	% calculate diffracted beam coordinate system
+
+	x=RotVecArAxed(X,r,2*grain.theta(i));
+	y=RotVecArAxed(Y,r,2*grain.theta(i));
+	z=RotVecArAxed(Z,r,2*grain.theta(i));
+
+	% calculate intersection of the 3 diffracted beams (starting from the cormers of the 
+	% undeformed triangle in the dector plane) with the diffracted beam
+	% coordinate system (still expressed in the Laboratory coordinate system)
+
+	XP=[0;0;0]-dot([0;0;0],n)*n;      
+	YP=Y-dot(Y,n)*n;
+	ZP=Z-dot(Z,n)*n;
+
+	% now express these points in the diffracted beam coordinate system
+
+	A=[x,y,z];
+
+	sx=inv(A)*XP;
+	sy=inv(A)*YP;
+	sz=inv(A)*ZP;
+
+	UP=[sx(2) sx(3);sy(2) sy(3);sz(2) sz(3)];
+
+    grain.omegashear(i)=grain.omega(i)-delta;    
+	grain.phi(i)=phi(i);
+
+
+	T=maketform('affine',U,UP);
+	
+    tmp=zeros(parameters.acq.bb(4),parameters.acq.bb(3));
+	
+	%get summed diffraction spot
+	
+	
+     [xl,yl,zl]=gtTrSamToLab2(grain.center(1),grain.center(2),grain.center(3),grain.omegashear(i),phi(i));  % two successive rotations
+	 xim = parameters.acq.bb(3)/2-yl+0.5;   % grain COM coordinates in the direct beam images   (assumes center of rotation in the center of the beam)
+ 	 yim = parameters.acq.ydet/2+1.5-zl-parameters.acq.bb(2);
+	
+	
+	 
+	 if simulation
+	   name=sprintf('difspot%d',i);
+	 else
+       % read the summed and flipped difspot
+	   name=sprintf('%s/difspot%d',graindir,i); 
+	 end
+	 
+	 difspot=sdt_read(name);
+	 
+	 difspot([1:100,end-99:end],:)=[];
+	 difspot(:,[1:100,end-99:end])=[]; 
+	 difspot2=imtransform(difspot,T);
+     
+	 s=regionprops(bwlabel(difspot2));
+	 
+	 bbxo=s.BoundingBox(1)+0.5;
+	 bbyo=s.BoundingBox(2)+0.5;
+	 bbxs=s.BoundingBox(3);
+	 bbys=s.BoundingBox(4);
+	 cenx=sum(difspot2)*[1:size(difspot2,2)]'/sum(difspot2(:));
+	 ceny=sum(difspot2,2)'*[1:size(difspot2,1)]'/sum(difspot2(:));
+	 
+	 
+	 cenx=cenx-bbxo;     % horizontal distance to the center of mass of the difspot
+	 ceny=ceny-bbyo;     % vertical distance
+	 
+	 x1=xim-cenx;
+	 y1=yim-ceny;
+	 
+	 sx=round(x1)-x1;
+	 sy=round(y1)-y1;
+	 % shift the spot to have COM in center of pixel
+	 
+	 difspot2=interp2(difspot2,[1+sx:size(difspot,2)+sx],[1+sy:size(difspot,1)+sy]','linear',0);
+	 
+	 difbb(1)=max(1,round(x1));
+	 difbb(2)=max(1,round(y1));
+	 %difbb(1)=max(1,round(xim-cenx)); 
+	 %difbb(2)=max(1,round(yim-ceny));
+	 
+	 %difspot=gtGetSummedDifspot(grain.struct_ids(i),parameters,1);
+	 
+	
+	difstack(:,:,i)=gtPlaceSubImage(difspot2,tmp,difbb(1),difbb(2));
+    test=difstack(:,:,i);
+	cx=sum(test)*[1:size(test,2)]'/sum(test(:));
+	cy=sum(test,2)'*[1:size(test,1)]'/sum(test(:));
+	disp([cx,xim])
+	disp([cy,yim])
+	%keyboard
+	%integral=100;
+	%difstack(:,:,i)=difstack(:,:,i)/sum(sum(difstack(:,:,i))); %don't trust integral value in table!
+    %difstack=difstack.*mean(integral);
+	if simulation
+	  name=sprintf('shearspot%d',i);   % 
+	else
+	  name=sprintf('%s/shearspot%d',graindir,i);
+	end  
+	sdt_write(name,difstack(:,:,i),'float32');
+	
+end	
+
+
+
+
+
diff --git a/4_spot_sorting/gtShearDifspots_wl2.m b/4_spot_sorting/gtShearDifspots_wl2.m
new file mode 100755
index 0000000000000000000000000000000000000000..ff0cab1f80839bc5bb4afbeb83ebf4b3d4709748
--- /dev/null
+++ b/4_spot_sorting/gtShearDifspots_wl2.m
@@ -0,0 +1,154 @@
+function [difstack,grain]=gtShearDifspots_wl(grain,grainid,parameters,index)
+
+if ~exist('parameters','var')
+  load parameters
+end
+
+grain=grain{grainid};
+% account for flipping of images...
+
+grain.eta=-grain.eta;
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+simulation=0;
+
+
+for i=index
+
+
+	% n= unit vector along the direction of the diffracted beam
+
+	n=[cosd(2*grain.theta(i));sind(2*grain.theta(i))*sind(grain.eta(i));sind(2*grain.theta(i))*cosd(grain.eta(i))];
+	n=n/norm(n);
+
+	
+	% unit vectors of the Laboratory (image) coordinate system
+	X=[1; 0; 0];
+	Y=[0; 1; 0];
+	Z=[0; 0; 1];
+
+	
+	% calculate the angle delta between X and np (projection of n onto the X-Y
+	% plane)  cos(delta)= dot (np,X)/norm(np);
+	
+	delta=asind(n(2)/sqrt(n(1)^2+n(2)^2));
+	phi(i)=asind(n(3));
+	
+	
+	% 2D coordinates of the corners of the undeformed triangle in the detector
+	% system
+
+	U=[0 0; 1 0; 0 1];
+
+	% r: rotation of X by 2*grain.theta(i) around r will result in n  
+
+	r=cross(X,n)/sqrt((1-dot(n,X)^2));
+
+	% calculate diffracted beam coordinate system
+
+	x=RotVecArAxed(X,r,2*grain.theta(i));
+	y=RotVecArAxed(Y,r,2*grain.theta(i));
+	z=RotVecArAxed(Z,r,2*grain.theta(i));
+
+	% calculate intersection of the 3 diffracted beams (starting from the cormers of the 
+	% undeformed triangle in the dector plane) with the diffracted beam
+	% coordinate system (still expressed in the Laboratory coordinate system)
+
+	XP=[0;0;0]-dot([0;0;0],n)*n;      
+	YP=Y-dot(Y,n)*n;
+	ZP=Z-dot(Z,n)*n;
+
+	% now express these points in the diffracted beam coordinate system
+
+	A=[x,y,z];
+
+	sx=inv(A)*XP;
+	sy=inv(A)*YP;
+	sz=inv(A)*ZP;
+
+	UP=[sx(2) sx(3);sy(2) sy(3);sz(2) sz(3)];
+
+    grain.omegashear(i)=grain.omega(i)-delta;    
+	grain.phi(i)=phi(i);
+
+
+	T=maketform('affine',U,UP);
+	
+    tmp=zeros(parameters.acq.bb(4),parameters.acq.bb(3));
+	
+	%get summed diffraction spot
+	
+	
+     [xl,yl,zl]=gtTrSamToLab2(grain.center(1),grain.center(2),grain.center(3),grain.omegashear(i),phi(i));  % two successive rotations
+	 xim = parameters.acq.bb(3)/2-yl+0.5;   % grain COM coordinates in the direct beam images   (assumes center of rotation in the center of the beam)
+ 	 yim = parameters.acq.ydet/2+1.5-zl-parameters.acq.bb(2);
+	
+	
+	 
+	 if simulation
+	   name=sprintf('difspot%d',i);
+	 else
+       % read the summed and flipped difspot
+	   name=sprintf('%s/difspot%d',graindir,i); 
+	 end
+	 
+	 difspot=sdt_read(name);
+	 
+	 difspot([1:100,end-99:end],:)=[];
+	 difspot(:,[1:100,end-99:end])=[]; 
+	 difspot2=imtransform(difspot,T);
+     
+	 s=regionprops(bwlabel(difspot2));
+	 
+	 bbxo=s.BoundingBox(1)+0.5;
+	 bbyo=s.BoundingBox(2)+0.5;
+	 bbxs=s.BoundingBox(3);
+	 bbys=s.BoundingBox(4);
+	 cenx=sum(difspot2)*[1:size(difspot2,2)]'/sum(difspot2(:));
+	 ceny=sum(difspot2,2)'*[1:size(difspot2,1)]'/sum(difspot2(:));
+	 
+	 
+	 cenx=cenx-bbxo;     % horizontal distance to the center of mass of the difspot
+	 ceny=ceny-bbyo;     % vertical distance
+	 
+	 x1=xim-cenx;
+	 y1=yim-ceny;
+	 
+	 sx=round(x1)-x1;
+	 sy=round(y1)-y1;
+	 % shift the spot to have COM in center of pixel
+	 
+	 difspot2=interp2(difspot2,[1+sx:size(difspot,2)+sx],[1+sy:size(difspot,1)+sy]','linear',0);
+	 
+	 difbb(1)=max(1,round(x1));
+	 difbb(2)=max(1,round(y1));
+	 %difbb(1)=max(1,round(xim-cenx)); 
+	 %difbb(2)=max(1,round(yim-ceny));
+	 
+	 %difspot=gtGetSummedDifspot(grain.struct_ids(i),parameters,1);
+	 
+	
+	difstack(:,:,i)=gtPlaceSubImage(difspot2,tmp,difbb(1),difbb(2));
+    test=difstack(:,:,i);
+	cx=sum(test)*[1:size(test,2)]'/sum(test(:));
+	cy=sum(test,2)'*[1:size(test,1)]'/sum(test(:));
+	disp([cx,xim])
+	disp([cy,yim])
+	%keyboard
+	%integral=100;
+	%difstack(:,:,i)=difstack(:,:,i)/sum(sum(difstack(:,:,i))); %don't trust integral value in table!
+    %difstack=difstack.*mean(integral);
+	if simulation
+	  name=sprintf('shearspot%d',i);   % 
+	else
+	  name=sprintf('%s/shearspot%d',graindir,i);
+	end  
+	sdt_write(name,difstack(:,:,i),'float32');
+	
+end	
+
+
+
+
+
diff --git a/4_spot_sorting/gtShowDifspots.m b/4_spot_sorting/gtShowDifspots.m
new file mode 100755
index 0000000000000000000000000000000000000000..6e402a03aa2eca43beaca9aafcde1178a1e89fdd
--- /dev/null
+++ b/4_spot_sorting/gtShowDifspots.m
@@ -0,0 +1,404 @@
+%
+% /currently, it's using an old matching script to display candidates in
+% the spot matching/
+%
+% FUNCTION gtShowDifspots(whichID,spottype,omega_tol_range,dopause)
+%
+% Shows difspots from a 360 degree scan (a single difspot table) along 
+% with the search area and candidate pairs, if there is any found.
+% To look at paired difspots, use gtEvaluateDifspotMatch
+%
+% INPUT  gtShowDifspots
+%        gtShowDifspots([],[],1)
+%        gtShowDifspots([200:500],'matched',0,'button')
+%
+%   Two data series of segmented diffraction spots of a 360 degree
+%   scan from database (one difspot table containing all the spots).
+%
+% OPTIONAL INPUTS
+%   whichID:   vector of difspot ID-s to be shown; if empty, all are shown
+%   spottype:  only 'unmatched' or 'matched' (with all the candidiates) 
+%              are shown; if empty, all shown
+%   omega_tol_range: if true, full images of the omega search range inside 
+%                    the tolerance band is shown
+%   dopause:   pause time in sec after a pair is found; if equals 'button',
+%              it waits for button press
+%
+% OUTPUT   figures of difspots and their location in fullimages
+%
+%
+%
+%   Peter Reischig, ESRF, 10/2007
+%
+%%
+
+
+function gtShowDifspots(whichID,spottype,omega_tol_range,dopause)
+
+disp('NOTE: an old searching macro is being used for display.')
+
+load parameters.mat
+
+tic
+
+close all
+
+% Example for tolerance values:
+% parameters.match.thr_ang=0.2;
+% parameters.match.thr_max_offset=2;
+% parameters.match.thr_ext_offset=10;
+% parameters.match.thr_genim_offset=1;
+% parameters.match.corr_rot_to_det=0;
+% 
+% parameters.match.thr_intint=3;
+% parameters.match.thr_area=1.2;
+% parameters.match.thr_bbsize=1.2;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Set parameters
+
+% Tolerances of image locations
+thr_ang=parameters.match.thr_ang;                   % angular threshold; absolute value in degrees
+thr_max_offset=parameters.match.thr_max_offset;     % CentroidImage offset threshold; absolut value in #images
+thr_ext_offset=parameters.match.thr_ext_offset;     % ExtStartImage and ExtEndImage offset threshold; absolut value in #images
+thr_genim_offset=parameters.match.thr_genim_offset; % at least one of the three images should be offset as maximum this value in #images
+corr_rot_to_det=parameters.match.corr_rot_to_det;   % correction of rot_to_det in pixels
+% Tolerances (for search within the limits: basevalue/thr & basevalue*thr)
+thr_intint=parameters.match.thr_intint;             % integrated intensity
+thr_area=parameters.match.thr_area;                 % area of spots inside the bounding box
+thr_bbsize=parameters.match.thr_bbsize;             % bounding box size
+
+sample_radius=parameters.acq.bb(3)/2;
+sample_top=parameters.acq.bb(2);
+sample_bot=parameters.acq.bb(2)+parameters.acq.bb(4);
+rot_to_det=parameters.acq.dist/parameters.acq.pixelsize + corr_rot_to_det;
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition
+% sorY = on the rotation axis by definition
+% sorZ=sample_top  % at the top of the sample bounding box (acquisition); lowest number in pixels
+
+difspottable=[parameters.acq.difA_name 'difspot'];
+pairtable=parameters.acq.pair_tablename;
+
+nproj=parameters.acq.nproj; % number of preojections per 180 degrees
+
+if ~exist('whichID','var')
+  whichID=[];
+end
+
+if ~exist('dopause','var')
+  dopause=[];
+end
+
+if ~exist('omega_tol_range','var')
+  omega_tol_range=false;
+end
+
+if ~exist('spottype','var')
+  spottype=[];
+end
+
+%% Database search
+
+[tmp,results]=gtnew_calculate_twotheta() ;
+valid_2thetas=results.centre; % coloumn vector of all valid 2theta angles in degrees
+
+gtDBConnect ;
+
+nof_spots1=mym(sprintf('select count(*) from %s where CentroidImage between %f and %f',difspottable,0,nproj));
+nof_spots2=mym(sprintf('select count(*) from %s where CentroidImage between %f and %f',difspottable,nproj,2*nproj));
+
+if isempty(whichID)
+  whichID=mym(sprintf('Select difspotID from %s',difspottable));
+end
+
+if strcmpi('matched',spottype)
+  [pairedspotsA,pairedspotsB]=mym(sprintf('select difAID, difBID from %s',pairtable));
+  pairedspots=[pairedspotsA;pairedspotsB];
+  whichID=intersect(whichID,pairedspots);
+elseif strcmpi('unmatched',spottype)
+  [pairedspotsA,pairedspotsB]=mym(sprintf('select difAID, difBID from %s',pairtable));
+  pairedspots=[pairedspotsA;pairedspotsB];
+  whichID=setdiff(whichID,pairedspots);
+end
+
+pairsfound=0;
+shown=false;
+
+%disp('Reading from database...')
+
+for i=1:length(whichID)      % main loop for whichID
+
+  sp1.id=whichID(i);
+
+  [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral]=...
+    mym(sprintf(['select CentroidImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+    'BoundingBoxXsize,BoundingBoxYsize,Integral from %s where difspotID=%d'],difspottable,sp1.id));
+
+  if isempty(sp1.maxim)
+    continue
+  end
+  
+  pr_bb=projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx);
+  
+  % Set limits for search between lim1..lim2 and lim3..lim4
+
+  % CentroidImage, ExtStart, Extend limits for pair
+  [maxim1,maxim2,maxim3,maxim4]=sfCalcBoundaries(sp1.maxim,thr_max_offset,nproj);
+  [extstim1,extstim2,extstim3,extstim4]=sfCalcBoundaries(sp1.extstim,thr_ext_offset,nproj);
+  [extendim1,extendim2,extendim3,extendim4]=sfCalcBoundaries(sp1.extendim,thr_ext_offset,nproj);
+
+  % At least one of them should also fulfill thr_genim_offset
+  [maxim1_gen,maxim2_gen,maxim3_gen,maxim4_gen]=sfCalcBoundaries(sp1.maxim,thr_genim_offset,nproj);
+  [extstim1_gen,extstim2_gen,extstim3_gen,extstim4_gen]=sfCalcBoundaries(sp1.extstim,thr_genim_offset,nproj);
+  [extendim1_gen,extendim2_gen,extendim3_gen,extendim4_gen]=sfCalcBoundaries(sp1.extendim,thr_genim_offset,nproj);
+
+
+  % Select candidate spots2 from database by all the criteria
+
+  [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral]= ...
+    mym(sprintf(['select difspotID, CentroidImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+    'BoundingBoxYsize, Integral from %s WHERE ', ...
+    '(CentroidX between %f and %f) AND (CentroidY between %f and %f) ', ...
+    'AND (BoundingBoxXsize between %f and %f) AND (BoundingBoxYsize between %f and %f) ', ...
+    'AND (Integral between %f and %f) ', ...
+    'AND (Area between %f and %f) ', ...
+    'AND ((CentroidImage between %d and %d) OR (CentroidImage between %d and %d)) ', ...
+    'AND ((ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d)) ', ...
+    'AND ((ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d)) ', ...
+    'AND ( (CentroidImage between %d and %d) OR (CentroidImage between %d and %d) OR ', ...
+    '(ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d) OR ', ...
+    '(ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d) ) '], ...
+    difspottable,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+    sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+    sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+    sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+    sp1.area/thr_area, sp1.area*thr_area, ...
+    maxim1, maxim2, maxim3, maxim4, ...
+    extstim1, extstim2, extstim3, extstim4, ...
+    extendim1, extendim2, extendim3, extendim4, ...
+    maxim1_gen, maxim2_gen, maxim3_gen, maxim4_gen, ...
+    extstim1_gen, extstim2_gen, extstim3_gen, extstim4_gen, ...
+    extendim1_gen, extendim2_gen, extendim3_gen, extendim4_gen )) ;
+
+
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+
+  sqrsum=Inf ;
+  pairj=[];
+  sp2.id=[];
+
+  for j=1:length(sps2.id)
+
+    [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),rot_to_det,parameters.acq.rotx,valid_2thetas,thr_ang);
+
+    if theta_OK==true
+      sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+        ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+        (min(abs(angle_diff))/thr_ang)^2;
+      if (sqrsumnew < sqrsum)
+        sqrsum=sqrsumnew ;
+        pairj=j ;
+        thetatype_out=thetatype ;
+      end
+    end
+  end
+
+%% Being left with the right pair spot, compute output parameters
+
+  if sqrsum < Inf
+    pairsfound=pairsfound+1 ;
+    
+    sp2.id=sps2.id(pairj);
+    sp2.maxim=sps2.maxim(pairj);
+    sp2.extstim=sps2.extstim(pairj);
+    sp2.extendim=sps2.extendim(pairj);
+    sp2.area=sps2.area(pairj);
+    sp2.centX=sps2.centX(pairj);
+    sp2.centY=sps2.centY(pairj);
+    sp2.integral=sps2.integral(pairj);
+    sp2.bbXsize=sps2.bbXsize(pairj);
+    sp2.bbYsize=sps2.bbYsize(pairj);
+    sp2.bbX=sps2.bbX(pairj);
+    sp2.bbY=sps2.bbY(pairj);
+
+    sps2.maxim(pairj)=[];
+    sps2.extstim(pairj)=[];
+    sps2.extendim(pairj)=[];
+    sps2.area(pairj)=[];
+    sps2.centX(pairj)=[];
+    sps2.centY(pairj)=[];
+    sps2.bbX(pairj)=[];
+    sps2.bbY(pairj)=[];
+    sps2.bbXsize(pairj)=[];
+    sps2.bbYsize(pairj)=[];
+    sps2.integral(pairj)=[];
+    sps2.id(pairj)=[];
+
+   
+    cent1X=sp1.centX-parameters.acq.rotx ;
+    cent1Y=sp1.centY ;
+    cent2X=sp2.centX-parameters.acq.rotx ;
+    cent2Y=sp2.centY ;
+
+    deltaX=cent1X+cent2X ;
+    deltaY=-cent1Y+cent2Y ;
+
+    theta=acosd(2*rot_to_det/norm([2*rot_to_det deltaX deltaY]))/2 ;
+
+    if deltaX >= 0  % 0 < eta < 180deg
+      if deltaY >= 0  % 0 < eta < 90deg
+        eta=atand(deltaX/deltaY) ;
+      else  % 90deg < eta < 180deg
+        eta=atand(deltaX/deltaY)+180 ;
+      end
+    else  % 180deg < eta < 360deg
+      if deltaY < 0  % 180deg < eta < 270deg
+        eta=atand(deltaX/deltaY)+180 ;
+      else  % 270deg < eta < 360deg
+        eta=atand(deltaX/deltaY)+360 ;
+      end
+    end
+
+%     diff_vec_setup = [2*rot_to_det deltaX deltaY]/norm([2*rot_to_det deltaX deltaY]) ; % normalized diffraction vector in lab system
+%     pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ; % normal vector of diffracting plane in lab system
+
+    omega1=180/nproj*sp1.maxim;
+    omega2=180/nproj*sp2.maxim; % (sp2.maxim should always be larger)
+    omega=(omega1+omega2-180)/2; % the average of the two
+
+  end % if pair is found
+    
+
+%% Display findings
+
+  if shown
+    theta_tol=false;
+  else
+    theta_tol=true;
+  end
+  
+  if isempty(sp2.id) 
+    sp2.maxim=mod(sp1.maxim+nproj,2*nproj);
+    omega=[];
+    theta=[];
+    eta=[];
+  end
+
+  if omega_tol_range
+    gtShowPairFigure(1,parameters,sp1,sp2,pr_bb,valid_2thetas,theta_tol,sps2,sp1.maxim,round(sp2.maxim)-thr_max_offset,omega,theta,eta)
+    if strcmpi('button',dopause)
+      waitforbuttonpress
+    else
+      pause(dopause)
+    end
+    
+    for ifig=-thr_max_offset+1:thr_max_offset
+      gtShowPairFigure(0,parameters,sp1,sp2,pr_bb,valid_2thetas,theta_tol,sps2,sp1.maxim,round(sp2.maxim)+ifig,omega,theta,eta)
+      if strcmpi('button',dopause)
+        waitforbuttonpress
+      else
+        pause(dopause)
+      end
+    end
+  else
+    gtShowPairFigure(1,parameters,sp1,sp2,pr_bb,valid_2thetas,theta_tol,sps2,sp1.maxim,round(sp2.maxim),omega,theta,eta)
+    if strcmpi('button',dopause)
+      waitforbuttonpress
+    else
+      pause(dopause)
+    end
+  end
+
+  shown=true;
+  
+  if mod(i,100)==0
+    disp(sprintf('SpotID:  %d   Pairs found:  %d   Matching percentage:  %3.2f%%',sp1.id,pairsfound,pairsfound/i*100)) ;
+  end
+
+end % end of main loop for whichID
+
+mym('close')
+
+disp('Total number of diffraction spots in first half:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in second half:'), disp(nof_spots2) ;
+disp('Number of pairs found:'), disp(pairsfound) ;
+
+disp(' ');
+toc
+disp(' ')
+
+end % of function
+
+
+%% Sub-functions used
+
+% Given an image number, returns the boundaries of two ranges (as image numbers)
+% with an offset of 180degree +-tol offset.
+function [b1,b2,b3,b4]=sfCalcBoundaries(imno1,tol,nproj)
+  b1=mod(imno1+nproj-tol,2*nproj);
+  b2=mod(imno1+nproj+tol,2*nproj);
+  b3=0;
+  b4=-1;
+  if b1>b2
+    b4=b2;
+    b2=2*nproj;
+  end
+end
+
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  % insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  % insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+% Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill
+%   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+%   within the given threshold).
+%
+% INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+%           Rotation axis to detector plane distance = rot_to_det
+%           Position X of the rotation axis projected on the detector plane in pixels = rotx
+%           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+%           Angular threshold for 2theta angles in DEGREES = thr_ang
+%
+% OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+%           diff = difference relative to the theoretical twotheta angles
+%           thetatype = index of the closest valid twotheta angle
+%
+
+  spot1X=spot1X-rotx ;
+  spot2X=spot2X-rotx ;
+
+  angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+
+  diff=valid_2thetas-angle;
+
+  if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+    theta_OK=false ;
+    thetatype=[] ;
+  else
+    theta_OK=true ;
+    [mini,thetatype]=min(abs(valid_2thetas-angle));
+  end
+
+end
+
+
+
diff --git a/4_spot_sorting/gtShowPairFigure.m b/4_spot_sorting/gtShowPairFigure.m
new file mode 100755
index 0000000000000000000000000000000000000000..5c10a2b1b166b88f8152a9c2760fb5f26199b2ce
--- /dev/null
+++ b/4_spot_sorting/gtShowPairFigure.m
@@ -0,0 +1,211 @@
+%
+% FUNCTION gtShowPairFigure(fig,parameters,spA,spB,pr_bb,comp_2thetas,
+%           theta_tol,spC,fullimnoA,fullimnoB,omega,theta,eta)
+%
+%  Used by gtMatchDifspots, gtShowDifspots, gtShowPairs, ...
+%
+% INPUT
+%   fig:   figure number for display (e.g. gcf); if 0, only fullimage is
+%          updated
+%   parameters: parameters loaded from parameters file
+%   spA,spB: data of spot A and its pair B (e.g. from database) with the 
+%            fields:
+%                 spA.id:  difspotID
+%                 spA.maxim:  # of maximum or centroid image
+%                 spA.bbX,spA.bbY,spA.bbXsize,spA.bbYsize:  bounding box 
+%                 spA.centX,spA.centY:  centroid of spot 
+%            if spB.id is empty, spot B is not displayed
+% OPTIONAL INPUT
+%   pr_bb:         projected sample bounding box; if 0, it's calculated from 
+%                  parameters; not displayed if empty or not specified 
+%   comp_2thetas:  vector of computed 2theta-s
+%   theta_band:    if true, tolerance bands are displayed for first pair
+%   spC:           any other spot candidates with a structure like spB    
+%   fullimnoA,fullimnoB:  # of full images to be displayed; if not
+%                         specified, spA and spB.maxim (or spA.maxim+nproj)
+%                         will be displayed
+%   omega,theta,eta:  to be displayed above the full images
+%
+% 
+%
+%  by Peter Reischig ESRF,10/2007
+%
+
+function gtShowPairFigure(fig,parameters,spA,spB,pr_bb,comp_2thetas,theta_band,spC,fullimnoA,fullimnoB,omega,theta,eta)
+
+  text_dist=20;
+  rot_to_det=parameters.acq.dist/parameters.acq.pixelsize+parameters.match.corr_rot_to_det;
+
+  % Projected sample bb
+  if ~exist('pr_bb','var')
+    pr_bb=[];
+  end
+  if pr_bb==0
+    sample_radius=parameters.acq.bb(3)/2;
+    sample_top=parameters.acq.bb(2);
+    sample_bot=parameters.acq.bb(2)+parameters.acq.bb(4);
+    pr_bb=projected_sample(spA.centX,spA.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx);
+  end
+  
+  % 2thetas and candidate spots
+  if ~exist('comp_2thetas','var')
+    comp_2thetas=[];
+  end
+  if ~exist('theta_band','var')
+    theta_band=false;
+  end  
+  if ~exist('spC','var')
+    spC=[];
+  end
+  if ~isfield(spC,'id')
+    spC.id=[];
+  end
+  
+  % Full images to display 
+  if ~exist('fullimnoA','var')
+    fullimnoA=[];
+  end
+  if isempty(fullimnoA)
+    fullimnoA=spA.maxim;
+  end
+  
+  if ~exist('fullimnoB','var')
+    fullimnoB=[];
+  end
+  if isempty(fullimnoB)
+    fullimnoB=spB.maxim;
+  end
+  if isempty(fullimnoB)
+    fullimnoB=mod(fullimnoA+parameters.acq.nproj,2*parameters.acq.nproj);
+  end
+
+  fullimnoA=round(fullimnoA);
+  fullimnoB=round(fullimnoB);
+  
+  % Angles
+  if ~exist('theta','var')
+    theta=[];
+  end
+  if ~exist('eta','var')
+    eta=[];
+  end
+  if ~exist('omega','var')
+    omega=[];
+  end
+
+  fullimages_directory=sprintf('%s/1_preprocessing/full',parameters.acq.dir) ;
+  fullimA=edf_read([fullimages_directory, sprintf('/full%0.4d.edf',fullimnoA)]);
+  fullimB=edf_read([fullimages_directory, sprintf('/full%0.4d.edf',fullimnoB)]);
+
+  spotimA=gtCrop(fullimA,[spA.bbX spA.bbY spA.bbXsize spA.bbYsize]);
+  directim=gtCrop(fullimA,parameters.acq.bb);
+
+  clims=[-max(spotimA(:)) max(spotimA(:))];
+ 
+  % Spot images
+  if fig==0
+    figure(gcf) % only updates full image (search pair of same spot )
+  else
+    figure(fig) % updates the whole figure with new spot
+    clf(fig)
+    set(gcf,'name','Difspot Pairs')
+    set(gcf,'Units','normalized','Position',[0 0 1 1]);
+
+    subp_totheight=max([0.2 1/round(length(spC.id)/2+1)]);
+    subp_height=subp_totheight-0.02;
+    subp_width=0.19;
+
+    % Image of specified spot
+    subplot('position',[0 1-subp_totheight subp_width subp_height])
+     difspim=gtGetSummedDifSpot(spA.id,parameters,1);
+     imshow(difspim,clims)
+     hold on
+     rectangle('Position',[0.5,0.5,spA.bbXsize,spA.bbYsize],'EdgeColor','r');
+     plot(spA.centX-spA.bbX+1,spA.centY-spA.bbY+1,'r+');
+     title(sprintf('DifspotA: %d', spA.id));
+     axis([0,spA.bbXsize+1,0,spA.bbYsize+1])
+
+    % Image of pair if exists
+    if ~isempty(spB.id)
+      subplot('position',[subp_width 1-subp_totheight subp_width subp_height])
+       difspim=gtGetSummedDifSpot(spB.id,parameters,1);
+       imshow(fliplr(difspim),clims)
+       hold on
+       rectangle('Position',[0.5,0.5,spB.bbXsize,spB.bbYsize],'EdgeColor','g');
+       plot(2*(spB.bbXsize/2+0.5)-(spB.centX-spB.bbX+1),spB.centY-spB.bbY+1,'g+'); % spot id flipped
+       title(sprintf('DifspotB: %d', spB.id));
+       axis([0,spB.bbXsize+1,0,spB.bbYsize+1])
+    end
+
+    % Images of candidate spots
+    for spi=1:length(spC.id)
+      subplot('position',[mod(spi+1,2)*subp_width floor((-spi-2)/2)*subp_totheight+1 subp_width subp_height])
+      difspim=gtGetSummedDifSpot(spC.id(spi),parameters,1);
+      imshow(fliplr(difspim),clims)
+      hold on
+      plot(2*(spC.bbXsize(spi)/2+0.5)-(spC.centX(spi)-spC.bbX(spi)+1),spC.centY(spi)-spC.bbY(spi)+1,'b+'); % spot flipped
+      title(sprintf('DifspotB: %d',spC.id(spi)));
+      axis([0,spC.bbXsize(spi),0,spC.bbYsize(spi)])
+    end
+  end
+
+  % Display full images 
+  subplot('Position',[0.4 0 0.6 1])
+  totim=gtPlaceSubImage(directim,fliplr(fullimB),parameters.acq.bb(1),parameters.acq.bb(2));
+  totim=gtPlaceSubImage(spotimA,totim,spA.bbX,spA.bbY);
+  imshow(totim,clims);
+  hold on
+  title(sprintf('#FullimA: %d  #FullimB: %d    DifspotA: %d  DifspotB: %d    Omega: %5.2fdeg   Theta: %5.2fdeg   Eta: %5.2fdeg',fullimnoA,fullimnoB,spA.id,spB.id,omega,theta,eta)) ;
+
+  rectangle('Position',[parameters.acq.bb(1)-2,parameters.acq.bb(2)-2,parameters.acq.bb(3)+4,parameters.acq.bb(4)+4],'EdgeColor','c');
+  rectangle('Position',[spA.bbX-2,spA.bbY-2,spA.bbXsize+4,spA.bbYsize+4],'EdgeColor','r') ;
+  text(spA.bbX+spA.bbXsize+text_dist,spA.bbY+spA.bbYsize+text_dist,int2str(spA.id),'Color','r');
+
+  if ~isempty(pr_bb)
+    rectangle('Position',[2*parameters.acq.rotx-pr_bb(1)-(pr_bb(3)-pr_bb(1)),pr_bb(2),(pr_bb(3)-pr_bb(1)),(pr_bb(4)-pr_bb(2))],'EdgeColor','b');
+  end
+  
+  % Display pair if exists
+  if ~isempty(spB.id)
+    rectangle('Position',[2*parameters.acq.rotx-spB.bbX-spB.bbXsize-2,spB.bbY-2,spB.bbXsize+4,spB.bbYsize+4],'EdgeColor','g') ;
+    plot([spA.centX, 2*parameters.acq.rotx-spB.centX],[spA.centY, spB.centY],'c') ;
+    text(2*parameters.acq.rotx-spB.bbX,spB.bbY+spB.bbYsize+text_dist,int2str(spB.id),'color','g');
+  end
+
+  % Candidate spot centroids in full image
+  for k=1:length(spC.id)
+    plot(2*parameters.acq.rotx-spC.centX(k),spC.centY(k),'g+') ;
+    text(2*parameters.acq.rotx-spC.centX(k)+text_dist,spC.centY(k)+text_dist,int2str(spC.id(k)),'color','g');
+  end
+
+  %Circles along 2theta cones
+  t=(0:1:360)' ;
+
+  if ~isempty(comp_2thetas)
+    circRthetas=2*rot_to_det*tand(comp_2thetas) ;
+    for k=1:length(circRthetas)
+      circthetasX=spA.centX+cosd(t)*circRthetas(k) ;
+      circthetasY=spA.centY+sind(t)*circRthetas(k) ;
+      plot(circthetasX,circthetasY,'b') ;
+    end
+
+    if theta_band
+      circRthetas=2*rot_to_det*tand(comp_2thetas+parameters.match.thr_ang) ;
+      for k=1:length(circRthetas)
+        circthetasX=spA.centX+cosd(t)*circRthetas(k) ;
+        circthetasY=spA.centY+sind(t)*circRthetas(k) ;
+        plot(circthetasX,circthetasY,'y') ;
+      end
+
+      circRthetas=2*rot_to_det*tand(comp_2thetas-parameters.match.thr_ang) ;
+      for k=1:length(circRthetas)
+        circthetasX=spA.centX+cosd(t)*circRthetas(k) ;
+        circthetasY=spA.centY+sind(t)*circRthetas(k) ;
+        plot(circthetasX,circthetasY,'y') ;
+      end
+    end
+  end
+
+  drawnow
+     
+end % of function
diff --git a/4_spot_sorting/gtShowPairs.m b/4_spot_sorting/gtShowPairs.m
new file mode 100755
index 0000000000000000000000000000000000000000..96864c319fe3cd3db8a014cdbd32aecd8a33665d
--- /dev/null
+++ b/4_spot_sorting/gtShowPairs.m
@@ -0,0 +1,63 @@
+%
+% FUNCTION gtShowPairs(pairID,dopause)
+%
+% Shows difspot pairs from a 360 degree scan.
+% To look at difspots only, use gtEvaluateDifspotMatch.
+%
+% INPUT  gtShowPairs
+%        gtShowDifspots([1 5 67])
+%        gtShowDifspots([200:500],1)
+%
+%   + Spotpairtable, difspottable.
+%
+% OPTIONAL INPUTS
+%   whichID:   vector of pair ID-s to be shown; if empty, all are shown
+%   dopause:   pause time in sec after a pair is found; if not specified,
+%              it waits for button press
+%
+% OUTPUT   Figures of the paired difspots and their location in the
+%           fullimage.
+%
+%
+%
+%   Peter Reischig, ESRF, 11/2007
+%
+%%
+
+
+function gtShowPairs(pairID,dopause)
+
+if ~exist('dopause','var')
+  dopause='button';
+end
+
+%if ~exist('show_omega_tol','var')
+%  show_omega_tol=0;
+%end
+
+load parameters.mat
+
+gtDBConnect
+
+pairtable=parameters.acq.pair_tablename;
+
+if ~exist('pairID','var')
+    [spA,spB]=mym(sprintf('select difAID,difBID from %s',pairtable));
+else
+  for i=1:length(pairID)
+    [spA(i),spB(i)]=mym(sprintf('select difAID,difBID from %s where pairID=%d',pairtable,pairID(i)));
+  end
+end
+
+gtEvaluateDifspotMatch(spA,'pairfigure','dopause',dopause);
+
+end
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/gtThetaOfPairs.m b/4_spot_sorting/gtThetaOfPairs.m
new file mode 100755
index 0000000000000000000000000000000000000000..1af56e28d5f7f874c7f81c929b5acd1074ebe76f
--- /dev/null
+++ b/4_spot_sorting/gtThetaOfPairs.m
@@ -0,0 +1,46 @@
+%
+% function theta=gtThetaOfPairs(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ)
+%
+% Given the Scintillator coordinates of a pair of diffraction spots, 
+% computes the real theta angle they correspond to, according to tilts and 
+% rotation axis to detector (scintillator) distance.
+%
+%   LAB system is right-handed and defined as: 
+%     origin X = on the rotation axis, positive towards the camera
+%     origin Y = on the rotation axis
+%     origin Z = floor(parameters.acq.ydet/2) in the middle of the central
+%                pixel row of the image, positive upwards
+% 
+% INPUT  scXA = coloumn vector of X coordinates on the Scintillator of point A (pixels or mm-s)
+%        scYA = coloumn vector of Y coordinates on the Scintillator of point A (pixels or mm-s)
+%        scXB = coloumn vector of X coordinates on the Scintillator of point B (pixels or mm-s)
+%        scYB = coloumn vector of Y coordinates on the Scintillator of point B (pixels or mm-s)
+%        rottodet = rotation axis to detector (scintillator) distance at rotx,sorZ (pixels or mm-s)
+%        /scX,scY,rottodet have to be in the same units; e.g. pixels or mm-s/
+%        tiltY = tilt around axis Y in Lab system (in degrees)
+%        tiltZ = tilt around axis Z in Lab system (in degrees)
+%        rotx = location of rotation axis in the images (X coord. in pixels)
+%        sorZ = Z=0 location in the images (Y coord. in pixels at the rotation axis) 
+%
+%        e.g. ([234;334;434],[1444;1644;1944],[134;234;534],[555;545;535],
+%              3600,0.123,0.421,1026,1024)
+%
+% OUTPUT theta = coloumn vector of real theta angles
+%
+%        e.g. [7.3948; 7.1822; 6.9281]
+%
+%
+
+function theta=gtThetaOfPairs(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ)
+
+% Dv1=2*rottodet-sind(tiltZ).*(scXA+scXB-2*rotx)-sind(tiltY).*cosd(tiltZ).*(scYA+scYB-2*sorZ) ;
+% Dv2=cosd(tiltZ).*(scXA+scXB-2*rotx)-sind(tiltY).*sind(tiltZ).*(scYA+scYB-2*sorZ) ;
+% Dv3=-cosd(tiltY).*(scYA-scYB) ;
+% 
+% theta=0.5*acosd(Dv1./sqrt(Dv1.^2+Dv2.^2+Dv3.^2)) ;
+
+Dv=gtDiffVecInLab(scXA,scYA,scXB,scYB,rottodet,tiltY,tiltZ,rotx,sorZ);
+
+theta=0.5*acosd(Dv(:,1)./sqrt(Dv(:,1).^2+Dv(:,2).^2+Dv(:,3).^2));
+
+end
diff --git a/4_spot_sorting/gtTrImToSc.m b/4_spot_sorting/gtTrImToSc.m
new file mode 100755
index 0000000000000000000000000000000000000000..fe9c50e6881f3237abe990b81085a4baac4cf414
--- /dev/null
+++ b/4_spot_sorting/gtTrImToSc.m
@@ -0,0 +1,26 @@
+%
+%  function [scX,scY]=gtTrImToSc(imX,imY)
+%
+%  Given the Image coordinates of a point, transforms them into Scintillator 
+%  coordinates according to optics distortion.
+% 
+% INPUT  imX = coloumn vector of X coordinates in an image 
+%        imY = coloumn vector of Y coordinates in an image 
+%
+%        e.g. ([234; 334; 434],[1444; 1644; 1944])
+%
+%
+% OUTPUT scX = coloumn vector of X coordinates in the Scintillator system 
+%        scY = coloumn vector of Y coordinates in the Scintillator system 
+%
+%        e.g. [236.56; 336.87; 437.04],[1441.32; 1640.54; 1939.97]
+%
+%
+
+
+function [scX,scY]=gtTrImToSc(imX,imY)
+
+scX=imX ;
+scY=imY ;
+
+end
diff --git a/4_spot_sorting/gtTrLabToSam.m b/4_spot_sorting/gtTrLabToSam.m
new file mode 100755
index 0000000000000000000000000000000000000000..873b363520c03cb46a096a87c985dc62490463ef
--- /dev/null
+++ b/4_spot_sorting/gtTrLabToSam.m
@@ -0,0 +1,33 @@
+%
+% function [samX,samY,samZ]=gtTrLabToSam(labX,labY,labZ,om)
+%
+% Given the LAB coordinates of a point, transforms them into Sample 
+% coordinates according to omega (where omega is normally positive between
+% 0 and 360 degrees)
+%
+%   LAB system is right-handed and defined as: 
+%     origin X = on the rotation axis, positive towards the camera
+%     origin Y = on the rotation axis
+%     origin Z = floor(parameters.acq.ydet/2) in the middle of the central
+%                pixel row of the image, positive upwards
+%
+% INPUT  labX = coloumn vector of X coordinates in LAB system (arb. units)
+%        labY = coloumn vector of Y coordinates in LAB system (arb. units)
+%        labZ = coloumn vector of Z coordinates in LAB system (arb. units)
+%        om = coloumn vector of omega angles (in degrees) 
+%
+%        e.g. ([3234;3334;3434],[444;644;944],[545;824;632],[32.210;43.984;21.534])
+%
+% OUTPUT labX = coloumn vector of X coordinates in the LAB system 
+%        labY = coloumn vector of Y coordinates in the LAB system 
+%
+%        e.g. [2499.6;1951.7;2847.8],[2099.5;2778.7;2138.6],[545;824;632]
+%
+
+
+function [samX,samY,samZ]=gtTrLabToSam(labX,labY,labZ,om)
+  % om = omega angle in degrees
+  samX= cosd(om).*labX - sind(om).*labY ;
+  samY= sind(om).*labX + cosd(om).*labY ;
+  samZ= labZ ;
+end
diff --git a/4_spot_sorting/gtTrSamToLab.m b/4_spot_sorting/gtTrSamToLab.m
new file mode 100755
index 0000000000000000000000000000000000000000..aa5c21eb2354c4e32796ba8163724635d087422e
--- /dev/null
+++ b/4_spot_sorting/gtTrSamToLab.m
@@ -0,0 +1,34 @@
+%
+% function [labX,labY,labZ]=gtTrSamToLab(samX,samY,samZ,om)
+%
+% Given the Sample coordinates of a point, transforms them into LAB 
+% coordinates according to omega (omega as where the diffraction event occured,
+% thus normally positive between 0 and 360 degrees).
+%
+%   LAB system is right-handed and defined as: 
+%     origin X = on the rotation axis, positive towards the camera
+%     origin Y = on the rotation axis
+%     origin Z = floor(parameters.acq.ydet/2) in the middle of the central
+%                pixel row of the image, positive upwards
+%
+% INPUT  samX = coloumn vector of X coordinates in Sample system (arb. units)
+%        samY = coloumn vector of Y coordinates in Sample system (arb. units)
+%        samZ = coloumn vector of Z coordinates in Sample system (arb. units)
+%        om = coloumn vector of omega angles (in degrees) 
+%
+%        e.g. ([2499.6;1951.7;2847.8],[2099.5;2778.7;2138.6],[545;824;632],[32.210;43.984;21.534])
+%
+% OUTPUT labX = coloumn vector of X coordinates in the LAB system 
+%        labY = coloumn vector of Y coordinates in the LAB system 
+%        labZ = coloumn vector of Z coordinates in the LAB system 
+%
+%        e.g. [3234;3334;3434],[444;644;944],[545;824;632]
+%
+
+
+function [labX,labY,labZ]=gtTrSamToLab(samX,samY,samZ,om)
+  % om = omega angle in degrees
+  labX= cosd(om).*samX + sind(om).*samY ;
+  labY= -sind(om).*samX + cosd(om).*samY ;
+  labZ= samZ ;
+end
diff --git a/4_spot_sorting/gtTrSamToLab2.m b/4_spot_sorting/gtTrSamToLab2.m
new file mode 100755
index 0000000000000000000000000000000000000000..abbd37bc48a5cc7f17e52ab48b2eecd44e5c3542
--- /dev/null
+++ b/4_spot_sorting/gtTrSamToLab2.m
@@ -0,0 +1,38 @@
+%
+% function [labX,labY,labZ]=gtTrSamToLab(samX,samY,samZ,om,phi)
+%
+% Given the Sample coordinates of a point, transforms them into LAB 
+% coordinates according to omega AND phi (omega as where the diffraction event occured,
+% thus normally positive between 0 and 360 degrees, phi being the vertical tilt angle for oblique angle ART reconstruction).
+%
+%   LAB system is right-handed and defined as: 
+%     origin X = on the rotation axis, positive towards the camera
+%     origin Y = on the rotation axis
+%     origin Z = floor(parameters.acq.ydet/2) in the middle of the central
+%                pixel row of the image, positive upwards
+%
+% INPUT  samX = coloumn vector of X coordinates in Sample system (arb. units)
+%        samY = coloumn vector of Y coordinates in Sample system (arb. units)
+%        samZ = coloumn vector of Z coordinates in Sample system (arb. units)
+%        om = coloumn vector of omega angles (in degrees) 
+%
+%        e.g. ([2499.6;1951.7;2847.8],[2099.5;2778.7;2138.6],[545;824;632],[32.210;43.984;21.534])
+%
+% OUTPUT labX = coloumn vector of X coordinates in the LAB system 
+%        labY = coloumn vector of Y coordinates in the LAB system 
+%        labZ = coloumn vector of Z coordinates in the LAB system 
+%
+%        e.g. [3234;3334;3434],[444;644;944],[545;824;632]
+%
+
+
+function [labX,labY,labZ]=gtTrSamToLab(samX,samY,samZ,om,phi)
+  % first apply rotation around labz by omega (angle in degrees)
+  labXp= cosd(om).*samX + sind(om).*samY ;
+  labYp= -sind(om).*samX + cosd(om).*samY ;
+  labZp= samZ ;
+  % and now apply rotation around laby by phi (angle in degrees)
+  labX= cosd(phi).*labXp + sind(phi).*labZp ;
+  labZ= -sind(phi).*labXp + cosd(phi).*labZp ; 
+  labY=labYp;
+end
diff --git a/4_spot_sorting/gtTrScToIm.m b/4_spot_sorting/gtTrScToIm.m
new file mode 100755
index 0000000000000000000000000000000000000000..2c4ad065b7522bbbfd1bdb3667676140e4147adc
--- /dev/null
+++ b/4_spot_sorting/gtTrScToIm.m
@@ -0,0 +1,26 @@
+%
+%  function [imX,imY]=gtTrScToIm(scX,scY)
+%
+%  Given the Scintillator coordinates of a point, transforms them into Image 
+%  coordinates according to optics distortion.
+% 
+% INPUT  scX = coloumn vector of X coordinates in the Scintillator system 
+%        scY = coloumn vector of Y coordinates in the Scintillator system 
+%        
+%        e.g. [236.56; 336.87; 437.04],[1441.32; 1640.54; 1939.97]
+%
+% OUTPUT imX = coloumn vector of X coordinates in the image 
+%        imY = coloumn vector of Y coordinates in the image 
+%
+%        e.g. ([234; 334; 434],[1444; 1644; 1944])
+%        
+%
+%
+
+
+function [imX,imY]=gtTrScToIm(scX,scY)
+
+imX=scX ;
+imY=scY ;
+
+end
diff --git a/4_spot_sorting/gtTrScToLab.m b/4_spot_sorting/gtTrScToLab.m
new file mode 100755
index 0000000000000000000000000000000000000000..f72b98ff1eaa50b31102514141eec222d40470b8
--- /dev/null
+++ b/4_spot_sorting/gtTrScToLab.m
@@ -0,0 +1,38 @@
+%
+% function [labX,labY,labZ]=gtTrScToLab(scX,scY,rottodet,tiltY,tiltZ,rotx,sorZ))
+%
+% Given the Scintillator coordinates of a point, transforms them into LAB 
+% coordinates according to tilts and rotation axis to detector (scintillator)
+% distance.
+%   LAB system is right-handed and defined as: 
+%     origin X = on the rotation axis, positive towards the camera
+%     origin Y = on the rotation axis
+%     origin Z = floor(parameters.acq.ydet/2) in the middle of the central
+%                pixel row of the image, positive upwards
+% 
+% INPUT  scX = coloumn vector of X coordinates on the Scintillator (pixels or mm-s)
+%        scY = coloumn vector of Y coordinates on the Scintillator (pixels or mm-s)
+%        rottodet = rotation axis to detector (scintillator) distance at rotx,sorZ (pixels or mm-s)
+%        /scX,scY,rottodet have to be in the same units; e.g. pixels or mm-s/
+%        tiltY = tilt around axis Y in Lab system (in degrees)
+%        tiltZ = tilt around axis Z in Lab system (in degrees)
+%        rotx = location of rotation axis in the images (X coord. in pixels)
+%        sorZ = Z=0 location in the images (Y coord. in pixels at the rotation axis) 
+%
+%        e.g. ([234; 334; 434],[1444; 1644; 1944],3600,0.123,0.421,1026,1024)
+%
+% OUTPUT labX = coloumn vector of X coordinates in the LAB system 
+%        labY = coloumn vector of Y coordinates in the LAB system 
+%        labZ = coloumn vector of Z coordinates in the LAB system 
+%
+%        e.g. [236.56; 336.87; 437.04],[1441.32; 1640.54; 1939.97],[0.12; 0.29; 0.47]
+%
+%
+
+function [labX,labY,labZ]=gtTrScToLab(scX,scY,rottodet,tiltY,tiltZ,rotx,sorZ)
+
+labX = rottodet-sind(tiltZ).*(scX-rotx)-sind(tiltY).*cosd(tiltZ).*(scY-sorZ) ;
+labY = cosd(tiltZ).*(scX-rotx)-sind(tiltY).*sind(tiltZ).*(scY-sorZ) ;
+labZ = -cosd(tiltY).*(scY-sorZ) ;
+
+end
diff --git a/4_spot_sorting/gtTryAddLineToGroup.m b/4_spot_sorting/gtTryAddLineToGroup.m
new file mode 100755
index 0000000000000000000000000000000000000000..e5a77a8c9b326303a5b8661089c6c7c4e3ab620f
--- /dev/null
+++ b/4_spot_sorting/gtTryAddLineToGroup.m
@@ -0,0 +1,12 @@
+% Given some pair-lines among which 'pgood' are accepted, it checks if 'ptry'
+% fits to the group.
+%
+% NOTE: p2 and p3 intersection might be far from the actual grain center if
+% they are near being parallel
+
+function ok=gtTryAddLineToGroup(ptry,pgood,cand,tol,sample,ACM)
+  tryline=gtIndexSelectLines(ptry,cand);
+  goodl=gtIndexSelectLines(pgood,cand);
+  goodpofinters=pofintersectexp([goodl.ca goodl.dir])';
+  ok=gtIndexCheckGroupCons(tryline,goodl,goodpofinters,tol,sample,ACM);
+end
diff --git a/4_spot_sorting/gtUpdateDifspotGrainIDs.m b/4_spot_sorting/gtUpdateDifspotGrainIDs.m
new file mode 100755
index 0000000000000000000000000000000000000000..3dc04c714d787585eecb3ff2137dbabfab8bb20e
--- /dev/null
+++ b/4_spot_sorting/gtUpdateDifspotGrainIDs.m
@@ -0,0 +1,22 @@
+function gtUpdateDifspotGrainIDs(grain, parameters)
+
+
+%if it doesn't already exist, we may need to add a grainid column to
+%difspot table
+[a,b,c,d,e,f]=mym(sprintf('show columns from %sdifspot like "grainID"',parameters.acq.name));
+if isempty(a)
+  %add the field
+  mym(sprintf('ALTER TABLE graintracking.%sdifspot ADD COLUMN grainID INT AFTER integral', parameters.acq.name));
+  disp('adding grainID field to the difspot table')
+end
+
+
+%then loop through, updating according to the grain structure information
+for i=1:length(grain)
+  disp(sprintf('doing grain %d', i))
+  ids=grain{i}.difspots;
+  for j=1:length(ids)
+      mysqlcmd=dbUpdate(sprintf('%sdifspot',parameters.acq.name),'difspotID',ids(j),'GrainID',i);
+      mym(mysqlcmd);
+  end 
+end
diff --git a/4_spot_sorting/gt_simulate_fcc.m b/4_spot_sorting/gt_simulate_fcc.m
new file mode 100755
index 0000000000000000000000000000000000000000..914c20884b47851af576609da32981175c35cc3a
--- /dev/null
+++ b/4_spot_sorting/gt_simulate_fcc.m
@@ -0,0 +1,75 @@
+
+
+
+clear ttheta ind d;
+
+maxind=10;
+d0= 4.04;
+energy=15;
+minangle=70;
+maxangle=110;
+
+
+lambda=12.39/energy;
+
+i=1;
+
+for h=0:2:maxind
+    for k=0:2:maxind
+        for l=0:2:maxind
+           hkl(i,:)=[h,k,l];
+            
+           d(i)=d0/sqrt(h.^2+k.^2+l.^2);
+           
+           x=lambda/2/d(i);
+           if x<1
+               
+              ttheta(i)=2*asind(lambda/2/d(i));
+           end
+           i=i+1;
+        end
+    end
+end
+
+
+for h=1:2:maxind
+    for k=1:2:maxind
+        for l=1:2:maxind
+           hkl(i,:)=[h,k,l];
+            
+           d(i)=d0/sqrt(h.^2+k.^2+l.^2);
+           
+           x=lambda/2/d(i);
+           if x<1
+               
+              ttheta(i)=2*asind(lambda/2/d(i));
+           end
+           i=i+1;
+        end
+    end
+end
+
+
+
+
+ind=find(ttheta>minangle &ttheta<maxangle);
+
+titi=ttheta(ind);
+titi=unique(titi);
+bar(titi)
+shg
+
+keyboard
+hkls=hkl(ind,:)
+
+
+
+
+
+
+
+
+
+
+
+            
\ No newline at end of file
diff --git a/4_spot_sorting/hist_omega_extstim.jpg b/4_spot_sorting/hist_omega_extstim.jpg
new file mode 100755
index 0000000000000000000000000000000000000000..b23a8d815c60187c1ed6f7ffdf4cd01f74c6c4f8
Binary files /dev/null and b/4_spot_sorting/hist_omega_extstim.jpg differ
diff --git a/4_spot_sorting/hist_omega_maxim.jpg b/4_spot_sorting/hist_omega_maxim.jpg
new file mode 100755
index 0000000000000000000000000000000000000000..363feb7dfb75fd68be1a408f2c09b6ef78a911ad
Binary files /dev/null and b/4_spot_sorting/hist_omega_maxim.jpg differ
diff --git a/4_spot_sorting/look_at_possibles.m b/4_spot_sorting/look_at_possibles.m
new file mode 100755
index 0000000000000000000000000000000000000000..a04f3af37575d1a5413a735fa41ac3c801cabedb
--- /dev/null
+++ b/4_spot_sorting/look_at_possibles.m
@@ -0,0 +1,61 @@
+function spot_viewer(struct_ids, pairs, theta, eta, hkl, parameters)
+%show the relevant full images, marking the dif and ext spots
+%theta, eta, hkl just for comments, not used by the function
+
+
+%load data 
+if isempty(parameters)
+  load parameters.mat
+end
+
+for i=1:length(struct_ids)
+  
+  if pairs(i)==1
+    name=parameters.acq.name  
+  else
+    name=parameters.acq.pair_name
+  end
+  
+      [im,x,y]=mym(sprintf('select MaxImage,CentroidX,CentroidY from %sdifspot where difspotID=%d',name,struct_ids(i)));
+     if i==1
+      full=edf_read(sprintf('../%s/1_preprocessing/full/full%04d.edf',name,im));
+
+  imshow(full,[])
+  hold on
+     end
+     switch hkl(i,1)
+       case 1
+  plot(x,y,'x')
+       case 0
+         plot(x,y,'o')
+       case 2
+         plot(x,y,'xr')
+       case 3
+         plot(x,y,'or')
+     end
+         
+  
+  %plot the extspot position that the difspot has been linked to by
+  %autofind
+[bb,centroid]=gtGetBBProps_pair(struct_ids(i), pairs(i))
+
+plot(parameters.acq.bb(1)+bb(1),parameters.acq.bb(2)+bb(2),'ro')
+plot(parameters.acq.bb(1)+bb(1)+bb(4),parameters.acq.bb(2)+bb(2)+bb(4),'ro')
+
+     switch hkl(i,1)
+       case 1
+  plot(parameters.acq.bb(1)+centroid(1),parameters.acq.bb(2)+centroid(2),'x')
+       case 0
+         plot(parameters.acq.bb(1)+centroid(1),parameters.acq.bb(2)+centroid(2),'o')
+       case 2
+         plot(parameters.acq.bb(1)+centroid(1),parameters.acq.bb(2)+centroid(2),'xr')
+       case 3
+         plot(parameters.acq.bb(1)+centroid(1),parameters.acq.bb(2)+centroid(2),'or')
+     end
+
+
+disp(sprintf('should be theta=%f, eta=%f, (%d %d %d)',theta(i),eta(i),hkl(i,1:3)))
+  
+ % k=waitforbuttonpress;
+  %close
+end
\ No newline at end of file
diff --git a/4_spot_sorting/look_at_possibles2.m b/4_spot_sorting/look_at_possibles2.m
new file mode 100755
index 0000000000000000000000000000000000000000..7f07ef64522269b6d811c7e25f1df05e3bdfcc2b
--- /dev/null
+++ b/4_spot_sorting/look_at_possibles2.m
@@ -0,0 +1,38 @@
+function look_at_possibles2(grainid)
+%version of look_at_possibles to look at the projections making up a grain,
+%showing the full images with the dif and ext spots marked
+
+
+%load data 
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+grain_data=load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+struct_ids = grain_data.struct_ids;
+
+
+for i=1:length(struct_ids)
+  
+  [im1,im2,im,x,y]=mym(sprintf('select ExtStartImage,ExtEndImage,MaxImage,CentroidX,CentroidY from s5_dct5_difspot where difspotID=%d',struct_ids(i)));
+  
+  full=zeros(2048);
+  for im=im1:im2
+  full=full+edf_read(sprintf('1_preprocessed/full/full%04d.edf',im));
+  end
+  
+  
+  imshow(full,[])
+  hold on
+  plot(x,y,'x')
+  
+  %plot the extspot position that the difspot has been linked to by
+  %autofind
+   [x,y]=mym(sprintf('select CentroidX,CentroidY from s5_dct5_extspot where extspotID=%d',struct_ids(i)));
+  plot(parameters.acq.bb(1)+x,parameters.acq.bb(2)+y,'ro')
+
+  
+  k=waitforbuttonpress;
+  close
+end
\ No newline at end of file
diff --git a/4_spot_sorting/match_difspots_v2.m b/4_spot_sorting/match_difspots_v2.m
new file mode 100755
index 0000000000000000000000000000000000000000..7b5c154f6ec262d72df1c0536039abc61f75d894
--- /dev/null
+++ b/4_spot_sorting/match_difspots_v2.m
@@ -0,0 +1,576 @@
+%
+% INPUT:    Two data series of segmented diffraction spots 180 degrees
+%           offset from database.
+%               Images are stored as looking against the beam. The position CentroidX
+%               is measured from the left edge of the images and positive towards 
+%               the right in the images. The position CentroidY is measured from 
+%               the top of the images and positive downwards in the images.
+%
+% OUTPUT:   filling of spotpairs table given in the parameters file
+%
+%           pairs [pair1,pair2] = matching pairs
+%
+%           problematic [difspotid1,difspotid2] = difficulties in matching         
+%
+%           unmatched [unmatched1, unmatched2] = difspots that failed to be matched
+%
+%   Peter Reischig, ESRF, 11/2006
+%
+%%
+
+
+function match_difspots_v2(show_findings,button)
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SET PARAMETERS
+
+thr_ang=0.2          % 0.2    % angular threshold; absolute value in degrees
+thr_max_offset=5     % 5      % MaxImage offset threshold; absolut value in images
+thr_ext_offset=10    % 10     % ExtStartImage and ExtEndImage offset threshold; absolut value in images
+thr_genim_offset=1   % 1      % at least one of the three images should be offset as maximum this value
+
+% Thresholds ( for search within the limits: basevalue/thr & basevalue*thr )
+thr_intint=2.7       % 2.7    % integrated intensity
+thr_area=1.59        % 1.59   % area of spots inside the bounding box
+thr_bbsize=1.31      % 1.34   % bounding box size
+
+corr_rot_to_det=30    % correction of rot_to_det in pixels  
+
+sample_radius= parameters.acq.bb(3)/2
+sample_top= parameters.acq.bb(2)
+sample_bot= parameters.acq.bb(2)+parameters.acq.bb(4)
+rot_to_det= parameters.acq.dist/parameters.acq.pixelsize + corr_rot_to_det % in pixels
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ = sample_top  % at the top of the sample (acquisition) bounding box - lowest number of pixels in full image in Y
+
+fullimages1_directory='1_preprocessing/full' ;
+difspotims1_directory='2_difspot/difspot' ;
+fullimages2_directory=sprintf('../%s/1_preprocessing/full',parameters.acq.pair_name) ;
+difspotims2_directory=sprintf('../%s/2_difspot/difspot',parameters.acq.pair_name) ;
+
+table1=parameters.acq.difA_tablename ;
+table2=parameters.acq.difB_tablename ;
+pairtable=parameters.acq.pair_tablename ;
+
+% For image display
+lowhigh=[-100 100] ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Database search Get allowed TwoTheta data
+
+[tmp,results]=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy) ;
+reflections=results.reflections % type of reflections
+valid_2thetas=results.centre % coloumn vector of all valid 2theta angles in degrees
+
+gtDBconnect ;
+%mym('open','mysql.esrf.fr','gtuser','gtuser')
+%mym(['use ',database])
+
+nof_spots1= mym(sprintf('select count(*) from %s',table1))
+nof_spots2= mym(sprintf('select count(*) from %s',table2))
+
+mym(sprintf('truncate %s',pairtable)) ;
+disp('Previous spotpairs table is truncated.') ;
+
+pairsfound=0 ;
+sps2.id=[] ;
+pair1=[] ;
+pair2=[] ;
+unmatched1=[] ;
+unmatched2=[] ;
+shown=false;
+
+disp('Processing data...')
+disp('Progress:')
+
+for i=1:nof_spots1      % main loop for spots1
+  
+   [sp1.maxim,sp1.extstim,sp1.extendim,sp1.area,sp1.centX,sp1.centY,sp1.bbX,sp1.bbY,sp1.bbXsize,sp1.bbYsize,sp1.integral,sp1.pair]=...
+     mym(sprintf(['select MaxImage,ExtStartImage,ExtEndImage,Area,CentroidX,CentroidY,BoundingBoxXorigin,BoundingBoxYorigin,'...
+     'BoundingBoxXsize,BoundingBoxYsize,Integral,PairID from %s where difspotID=%d'],table1,i)) ;
+    
+    pr_bb = projected_sample(sp1.centX,sp1.centY,sample_radius,sample_top,sample_bot,rot_to_det,parameters.acq.rotx) ;
+    
+    if (sp1.maxim < thr_max_offset)
+        maxim1=parameters.acq.nproj-(thr_max_offset-sp1.maxim) ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (thr_max_offset <= sp1.maxim < parameters.acq.nproj-thr_max_offset)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=sp1.maxim+thr_max_offset ;
+        maxim3=sp1.maxim-thr_max_offset ;
+        maxim4=sp1.maxim+thr_max_offset ;
+    elseif (parameters.acq.nproj-thr_max_offset <= sp1.maxim)
+        maxim1=sp1.maxim-thr_max_offset ;
+        maxim2=parameters.acq.nproj-1 ;
+        maxim3=0 ;
+        maxim4=sp1.maxim+thr_max_offset-parameters.acq.nproj ;
+    end
+ 
+    
+    if (sp1.extstim < 2*thr_ext_offset)
+        extstim1=parameters.acq.nproj-(thr_ext_offset-sp1.extstim) ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extstim < parameters.acq.nproj-thr_ext_offset)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=sp1.extstim+thr_ext_offset ;
+        extstim3=sp1.extstim-thr_ext_offset ;
+        extstim4=sp1.extstim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extstim)
+        extstim1=sp1.extstim-thr_ext_offset ;
+        extstim2=parameters.acq.nproj-1 ;
+        extstim3=0 ;
+        extstim4=sp1.extstim+thr_ext_offset-parameters.acq.nproj ;
+    end
+    
+    
+    if (sp1.extendim < thr_ext_offset)
+        extendim1=parameters.acq.nproj-(thr_ext_offset-sp1.extendim) ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (thr_ext_offset <= sp1.extendim < parameters.acq.nproj-thr_ext_offset)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=sp1.extendim+thr_ext_offset ;
+        extendim3=sp1.extendim-thr_ext_offset ;
+        extendim4=sp1.extendim+thr_ext_offset ;
+    elseif (parameters.acq.nproj-thr_ext_offset <= sp1.extendim)
+        extendim1=sp1.extendim-thr_ext_offset ;
+        extendim2=parameters.acq.nproj-1 ;
+        extendim3=0 ;
+        extendim4=sp1.extendim+thr_ext_offset-parameters.acq.nproj ;
+    end
+
+
+    % AT LEAST ONE OF MaxImage,ExtStartImage,ExtEndImage IS MAXIMUM 1 IMAGE OFFSET
+
+    if (sp1.maxim < thr_genim_offset)
+        maxim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.maxim) ;
+        maxim2_gen=parameters.acq.nproj-1 ;
+        maxim3_gen=0 ;
+        maxim4_gen=sp1.maxim+thr_genim_offset ;
+    elseif (thr_genim_offset <= sp1.maxim < parameters.acq.nproj-thr_genim_offset)
+        maxim1_gen=sp1.maxim-thr_genim_offset ;
+        maxim2_gen=sp1.maxim+thr_genim_offset ;
+        maxim3_gen=sp1.maxim-thr_genim_offset ;
+        maxim4_gen=sp1.maxim+thr_genim_offset ;
+    elseif (parameters.acq.nproj-thr_genim_offset <= sp1.maxim)
+        maxim1_gen=sp1.maxim-thr_genim_offset ;
+        maxim2_gen=parameters.acq.nproj-1 ;
+        maxim3_gen=0 ;
+        maxim4_gen=sp1.maxim+thr_genim_offset-parameters.acq.nproj ;
+    end
+ 
+    
+    if (sp1.extstim < thr_genim_offset)
+        extstim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extstim) ;
+        extstim2_gen=parameters.acq.nproj-1 ;
+        extstim3_gen=0 ;
+        extstim4_gen=sp1.extstim+thr_genim_offset ;
+    elseif (thr_genim_offset <= sp1.extstim < parameters.acq.nproj-thr_genim_offset)
+        extstim1_gen=sp1.extstim-thr_genim_offset ;
+        extstim2_gen=sp1.extstim+thr_genim_offset ;
+        extstim3_gen=sp1.extstim-thr_genim_offset ;
+        extstim4_gen=sp1.extstim+thr_genim_offset ;
+    elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extstim)
+        extstim1_gen=sp1.extstim-thr_genim_offset ;
+        extstim2_gen=parameters.acq.nproj-1 ;
+        extstim3_gen=0 ;
+        extstim4_gen=sp1.extstim+thr_genim_offset-parameters.acq.nproj ;
+    end
+    
+    
+    if (sp1.extendim < thr_genim_offset)
+        extendim1_gen=parameters.acq.nproj-(thr_genim_offset-sp1.extendim) ;
+        extendim2_gen=parameters.acq.nproj-1 ;
+        extendim3_gen=0 ;
+        extendim4_gen=sp1.extendim+thr_genim_offset ;
+    elseif (thr_genim_offset <= sp1.extendim < parameters.acq.nproj-thr_genim_offset)
+        extendim1_gen=sp1.extendim-thr_genim_offset ;
+        extendim2_gen=sp1.extendim+thr_genim_offset ;
+        extendim3_gen=sp1.extendim-thr_genim_offset ;
+        extendim4_gen=sp1.extendim+thr_genim_offset ;
+    elseif (parameters.acq.nproj-thr_genim_offset <= sp1.extendim)
+        extendim1_gen=sp1.extendim-thr_genim_offset ;
+        extendim2_gen=parameters.acq.nproj-1 ;
+        extendim3_gen=0 ;
+        extendim4_gen=sp1.extendim+thr_genim_offset-parameters.acq.nproj ;
+    end    
+        
+    % Select candidate spots2 from database by all thresholded criteria
+    
+     [sps2.id, sps2.maxim, sps2.extstim, sps2.extendim, sps2.area, sps2.centX, sps2.centY, sps2.bbX, sps2.bbY, sps2.bbXsize, sps2.bbYsize, sps2.integral, sps2.pair]= ...
+        mym(sprintf(['select difspotID, MaxImage, ExtStartImage, ExtEndImage, Area, CentroidX, CentroidY, BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, ', ...
+        'BoundingBoxYsize, Integral, PairID from %s WHERE ', ...
+        '(CentroidX between %f and %f) AND (CentroidY between %f and %f) ', ...
+        'AND (BoundingBoxXsize between %f and %f) AND (BoundingBoxYsize between %f and %f) ', ...
+        'AND (Integral between %f and %f) ', ...
+        'AND (Area between %f and %f) ', ...
+        'AND ((MaxImage between %d and %d) OR (MaxImage between %d and %d)) ', ...
+        'AND ((ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d)) ', ...
+        'AND ((ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d)) ', ...
+        'AND ( (MaxImage between %d and %d) OR (MaxImage between %d and %d) OR ', ...
+        '(ExtStartImage between %d and %d) OR (ExtStartImage between %d and %d) OR ', ...
+        '(ExtEndImage between %d and %d) OR (ExtEndImage between %d and %d) ) ', ...
+        'AND (PairID IS NULL)'], ... 
+        table2,pr_bb(1),pr_bb(3),pr_bb(2),pr_bb(4), ...
+        sp1.bbXsize/thr_bbsize, sp1.bbXsize*thr_bbsize, ...
+        sp1.bbYsize/thr_bbsize, sp1.bbYsize*thr_bbsize, ...
+        sp1.integral/thr_intint, sp1.integral*thr_intint, ...
+        sp1.area/thr_area, sp1.area*thr_area, ...
+        maxim1, maxim2, maxim3, maxim4, ...
+        extstim1, extstim2, extstim3, extstim4, ...
+        extendim1, extendim2, extendim3, extendim4, ...
+        maxim1_gen, maxim2_gen, maxim3_gen, maxim4_gen, ...
+        extstim1_gen, extstim2_gen, extstim3_gen, extstim4_gen, ...
+        extendim1_gen, extendim2_gen, extendim3_gen, extendim4_gen )) ;
+    
+      
+%% Theta angle check and selection of best candidate by area, integral, bbXsize, bbYsize, deviation from theoretical theta
+    
+    sqrsum=Inf ;
+    for j=1:length(sps2.id)
+           
+        [theta_OK,angle_diff,thetatype] = sfCheck_thetas(sp1.centX,sp1.centY,sps2.centX(j),sps2.centY(j),rot_to_det,parameters.acq.rotx,valid_2thetas,thr_ang);
+        
+        if theta_OK==true
+            
+            sqrsumnew = ((sps2.area(j)-sp1.area)/sp1.area)^2 + ((sps2.bbXsize(j)-sp1.bbXsize)/sp1.bbXsize)^2 + ...
+                         ((sps2.bbYsize(j)-sp1.bbYsize)/sp1.bbYsize)^2 + ((sps2.integral(j)-sp1.integral)/sp1.integral)^2 + ...
+                         (min(abs(angle_diff))/thr_ang)^2;
+            
+            if (sqrsumnew < sqrsum)
+                sqrsum=sqrsumnew ;
+                pairj=j ;
+                sp1.pair=sps2.id(j) ;
+                thetatype_out=thetatype ;
+            end
+        end
+    end
+    
+    if sqrsum < Inf
+        pairsfound=pairsfound+1 ;
+         
+%% Computing output parameters and loading database
+        
+        cent1X=sp1.centX-parameters.acq.rotx ;
+        cent1Y=sp1.centY ;
+        cent2X=sps2.centX(pairj)-parameters.acq.rotx ;
+        cent2Y=sps2.centY(pairj) ; 
+        
+        deltaX=cent1X+cent2X ;
+        deltaY=-cent1Y+cent2Y ;
+        
+        theta=acosd(2*rot_to_det/norm([2*rot_to_det deltaX deltaY])) ;
+                
+        if deltaX >= 0  % 0 < eta < 180deg
+          if deltaY >= 0  % 0 < eta < 90deg
+            eta=atand(deltaX/deltaY) ;
+          else  % 90deg < eta < 180deg
+            eta=atand(deltaX/deltaY)+180 ;
+          end
+        else  % 180deg < eta < 360deg
+          if deltaY < 0  % 180deg < eta < 270deg
+            eta=atand(deltaX/deltaY)+180 ;
+          else  % 270deg < eta < 360deg
+            eta=atand(deltaX/deltaY)+360 ;
+          end  
+        end
+                       
+        % Spot centroid coordinates in the set-up absolute system
+        
+        diff_vec_setup = [2*rot_to_det deltaX deltaY]/norm([2*rot_to_det deltaX deltaY]) ;
+        pl_vec_setup = (diff_vec_setup-[1 0 0])/norm(diff_vec_setup-[1 0 0]) ;
+                
+        omega = ( 180/parameters.acq.nproj*sp1.maxim + 180/parameters.acq.nproj*sps2.maxim(pairj) )/2 ;
+               
+        diff_vec_sam = sfSetup_to_sample_cor(diff_vec_setup,omega) ;
+        pl_vec_sam = sfSetup_to_sample_cor(pl_vec_setup,omega) ;
+        abs_cent1 = sfSetup_to_sample_cor([rot_to_det cent1X -(cent1Y-sorZ)],omega) ;
+        %[abs2X abs2Y abs2Z] = sfSetup_to_sample_cor( [rot_to_det -cent2X -(cent2Y-sorZ)], omega) ;
+        
+        %abs1X=sqrt(cent1X^2+rot_to_det^2)*cosd(180/parameters.acq.nproj*sp1.maxim-atand(cent1X/rot_to_det)) ;
+        %abs1Y=sqrt(cent1X^2+rot_to_det^2)*sind(180/parameters.acq.nproj*sp1.maxim-atand(cent1X/rot_to_det)) ;
+        %abs1Z= -(cent1Y-sorZ) ;
+        %
+        %abs2X=sqrt(cent2X^2+rot_to_det^2)*cosd(180/parameters.acq.nproj*sps2.maxim(pairj)-atand(cent2X/rot_to_det)) ;
+        %abs2Y=sqrt(cent2X^2+rot_to_det^2)*sind(180/parameters.acq.nproj*sps2.maxim(pairj)-atand(cent2X/rot_to_det)) ;
+        %abs2Z= -(cent2Y-sorZ) ;
+        
+        mysqlcmd=sprintf(['INSERT INTO %s (difAID, difBID, theta, eta, omega, lorX, lorY, lorZ, ldirX, ldirY, ldirZ, plX, plY, plZ, thetatype) ',...
+          'VALUES (%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%d)'], pairtable, i, sp1.pair, theta, eta, omega, abs_cent1(1), abs_cent1(2), abs_cent1(3), ...
+          diff_vec_sam(1), diff_vec_sam(2), diff_vec_sam(3), pl_vec_sam(1), pl_vec_sam(2), pl_vec_sam(3), thetatype_out) ;
+        
+        mym(mysqlcmd);
+        
+        %mym(sprintf('UPDATE %s SET PairID=%d WHERE difspotID=%d', table2, i, sp1.pair )) ;
+        
+        %pair1=[pair1; i] ;
+        %pair2=[pair2; sp1.pair] ;
+        
+%% Display findings
+
+    % FULL IMAGES
+   
+    if show_findings == 1
+        
+    figure(1);
+    
+    fullim1=edf_read([fullimages1_directory, sprintf('/full%04d.edf',sp1.maxim)]) ;
+    
+    lim=max(fullim1(:)) ;
+    %lowhigh=1.2*[-lim,lim] ;
+    %lowhigh=autolim(fullim1) ;
+    
+    fullim2=edf_read([fullimages2_directory, sprintf('/full%04d.edf',sps2.maxim(pairj))]) ;
+    fullim2(parameters.acq.bb(2):(parameters.acq.bb(2)+parameters.acq.bb(4)), parameters.acq.bb(1):(parameters.acq.bb(1)+parameters.acq.bb(3)))=0;
+    
+    totim=fullim1+fliplr(fullim2);        
+    imshow(totim,lowhigh);
+    hold on ;
+ 
+    title(sprintf('Difspot_A: %05d   Difspot_B: %05d           Omega: %5.2f deg    Theta: %5.2f deg    Eta: %5.2f deg', i, sp1.pair,omega,theta,eta)) ;
+        
+    rectangle('Position',[parameters.acq.bb(1)-2,parameters.acq.bb(2)-2,parameters.acq.bb(3)+4,parameters.acq.bb(4)+4],'EdgeColor','c') ;
+    rectangle('Position',[2*parameters.acq.rotx-pr_bb(1)-(pr_bb(3)-pr_bb(1)),pr_bb(2),(pr_bb(3)-pr_bb(1)),(pr_bb(4)-pr_bb(2))],'EdgeColor','b') ;
+    rectangle('Position',[sp1.bbX-2,sp1.bbY-2,sp1.bbXsize+4,sp1.bbYsize+4],'EdgeColor','r') ;
+    rectangle('Position',[2*parameters.acq.rotx-sps2.bbX(pairj)-sps2.bbXsize(pairj)-2,sps2.bbY(pairj)-2,sps2.bbXsize(pairj)+4,sps2.bbYsize(pairj)+4],'EdgeColor','g') ;
+
+    for k=1:length(sps2.id)
+        if k~=pairj
+            plot(2*parameters.acq.rotx-sps2.centX(k),sps2.centY(k),'g*') ;
+        end
+    end
+    
+   
+    % LINES ALONG PROJECTION
+
+    plot([sp1.centX, 2*parameters.acq.rotx-sps2.centX(pairj)],[sp1.centY, sps2.centY(pairj) ],'c') ;  
+    
+           
+    % CIRCLES OF VALID 2THETAS
+    
+    t=(0:1:360)' ;
+    
+    circRthetas=2*rot_to_det*tand(valid_2thetas) ;
+    for k=1:length(circRthetas)
+        circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+        circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+        plot(circthetasX,circthetasY,'b') ;
+    end
+
+    if shown==false
+        circRthetas=2*rot_to_det*tand(valid_2thetas+thr_ang) ;
+        for k=1:length(circRthetas)
+            circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+            circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+            plot(circthetasX,circthetasY,'y') ;
+        end
+
+        circRthetas=2*rot_to_det*tand(valid_2thetas-thr_ang) ;
+        for k=1:length(circRthetas)
+            circthetasX=sp1.centX+cosd(t)*circRthetas(k) ;
+            circthetasY=sp1.centY+sind(t)*circRthetas(k) ;
+            plot(circthetasX,circthetasY,'y') ;
+        end
+        
+    end
+
+    hold off;
+
+    % DIFSPOTS
+    
+    figure(2);
+    difspim1=edf_read([difspotims1_directory, sprintf('/difspot%05d.edf', i)]) ;
+    imshow(difspim1, lowhigh) ;
+    rectangle('Position',[1,1,sp1.bbXsize,sp1.bbYsize],'EdgeColor','r') ;
+    title(sprintf('Difspot_A: %5d', i)) ;
+    
+    
+    for k=1:length(sps2.id)
+        figure(k+2);
+        difspim2=edf_read([difspotims2_directory, sprintf('/difspot%05d.edf',sps2.id(k))]) ;
+        imshow(fliplr(difspim2), lowhigh) ;
+        no_im=k+2 ;
+        if k==pairj
+            rectangle('Position',[1,1,sps2.bbXsize(k),sps2.bbYsize(k)],'EdgeColor','g') ;
+            title(sprintf('Mathced difspot_B: %5d', sps2.id(k))) ;
+        else
+            title(sprintf('Difspot_B: %5d', sps2.id(k))) ;
+        end
+    end
+
+    if shown==true
+      for kk=no_im+1:pr_im
+        set(kk,'Visible','off') ;
+      end
+    end
+      
+    pr_im=length(sps2.id)+2 ;
+    shown=true;        
+    drawnow ;
+         
+    if button==1
+        waitforbuttonpress
+    end
+        
+    end % show findings
+    
+    %keyboard
+    
+    end % pair found
+    
+    if mod(i,100)==0
+      disp(sprintf('SpotID:  %d   Pairs found:  %d   Matching percentage:  %d',i,pairsfound,round(pairsfound/i*100))) ;
+    end
+    
+end % end of main loop for spots1
+
+%unmacthed1=mym(sprintf('select difspotID from %s where PairID IS NULL',table1)) ;
+%unmatched2=mym(sprintf('select difspotID from %s where PairID IS NULL',table2)) ;   
+
+mym('close')
+
+
+disp('Total number of diffraction spots in set #1:'), disp(nof_spots1) ;
+disp('Total number of diffraction spots in set #2:'), disp(nof_spots2) ;
+disp('Number of pairs found:'), disp(pairsfound) ;
+
+end % of function
+
+
+
+%function figure_keypress
+%figure('KeyPressFcn',@stop);
+%end
+%
+%
+%function stop
+%if evnt.Character == '5'
+%    pause
+%end
+%end
+
+%% Functions used
+
+function [insample_vec]=sfSetup_to_sample_cor(insetup_vec,om)
+  % om = omega angle in degrees
+  %insample_vec=([cosd(om) -sind(om) 0; sind(om) cosd(om) 0; 0 0 1]*insetup_vec')' ;
+  insample_vec(1)= cosd(om)*insetup_vec(1)-sind(om)*insetup_vec(2) ;
+  insample_vec(2)= sind(om)*insetup_vec(1)+cosd(om)*insetup_vec(2) ;
+  insample_vec(3)= insetup_vec(3) ;
+end
+
+
+function [insetup_vec]=sfSample_to_setup_cor(insample_vec,om)
+  % om = omega angle in degrees
+  %insetup_vec=([cosd(om) sind(om) 0; -sind(om) cosd(om) 0; 0 0 1]*insample_vec')' ;
+  insetup_vec(1)= cosd(om)*insample_vec(1)+sind(om)*insample_vec(2) ;
+  insetup_vec(2)= -sind(om)*insample_vec(1)+cosd(om)*insample_vec(2) ;
+  insetup_vec(3)= insample_vec(3) ;
+end
+
+
+function [theta_OK,diff,thetatype]=sfCheck_thetas(spot1X,spot1Y,spot2X,spot2Y,rot_to_det,rotx,valid_2thetas,thr_ang)
+
+    % Checks whether the positions of two diffraction spots in a pair of images 180 degrees offset fulfill 
+    %   the crystallographic criterium (the line connecting them corresponds to a 2theta diffraction angle
+    %   within the given threshold).
+    %
+    % INPUT:    Spot positions X and Y in their own image (origin and direction arbitrary) = spot1X,spot1Y,spot2X,spot2Y
+    %           Rotation axis to detector plane distance = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %           Coloumn vector of all valid crystollagraphic 2theta angles in DEGREES = valid_2thetas
+    %           Angular threshold for 2theta angles in DEGREES = thr_ang
+    %           
+    % OUTPUT:   theta_OK = True if crystallographic consistency is fulfilled
+    %           diff = difference relative to the theoretical twotheta angles
+    %           thetatype = index of the closest valid twotheta angle
+    %
+    
+    spot1X=spot1X-rotx ;
+    spot2X=spot2X-rotx ;
+    
+    angle=acosd(2*rot_to_det/norm([spot1X+spot2X spot1Y-spot2Y 2*rot_to_det])) ;
+    
+    diff=valid_2thetas-angle;
+    
+    if all(abs(valid_2thetas-angle) > thr_ang) % checks if all values are non-zero
+        theta_OK=false ;
+        thetatype=[] ;
+    else
+        theta_OK=true ;
+        [mini,thetatype]=min(abs(valid_2thetas-angle));
+    end
+      
+end
+
+
+
+%% Functions not in use
+
+function cross=check_sample_cross(c,spot1Y,spot2X,spot2Y,sample_bot,sample_top,rot_to_det,thr_geom)
+    
+    %
+    % Checks whether the position of two diffraction spots offset fulfill 
+    % the geometrical criterium (if the line connecting them crosses the precise illuminated
+    % sample volume). Computation refers to images with exactly 180 degrees offset.
+    %
+    % INPUT:    spot positions X and Y RELATIVE TO THE ROTATION AXIS in their own coordinate sstem! = spot1X,spot1Y,spot2X,spot2Y
+    %               origin: spot1X=0 at the position of the rotation axis; positive to the right on image #1
+    %                       spot1Y=0 at the bottom of the illuminated part of the sample; positive upwards
+    %                       spot2X=0 at the position of the rotation axis; positive to the right on image #2
+    %                       spot2Y=0 at the bottom of the illuminated part of the sample; positive upwards
+    %           rotation axis to detector plane distance = rot_to_det
+    %
+    % OUTPUT:   1 if geometrical consistency is fulfilled
+    %
+    % /NOT Verified/
+    %
+    
+    a=(1+(2*rot_to_det/(spot1X+spot2X))^2)
+    b=-4*rot_to_det^2/(spot1X+spot2X)+4*rot_to_det*spot2X/(spot1X+spot2X)
+    c=-4*rot_to_det^2*spot2X/(spot1X+spot2X)+(2*rot_to_det/(spot1X+spot2X)*spotX2)^2+rot_to_det^2-(sample_radius+thr_geom)^2
+    
+    cyl_X1 = 1/2/a*(b+(b^2-4*a*c)^(1/2))
+    cyl_X2 = 1/2/a*(-b+(b^2-4*a*c)^(1/2))
+ 
+    cyl_Y1=(spot1Y-spot2Y)/(spot1X+spot2X)*cyl_X1+spot2Y
+    cyl_Y2=(spot1Y-spot2Y)/(spot1X+spot2X)*cyl_X2+spot2Y
+        
+    if ((cyl_Y1 <= sample_top+thr_geom) && (cyl_Y1 >= sample_bot-thr_geom))
+        cross = true
+    elseif ((cyl_Y2 <= sample_top+thr_geom) && (cyl_Y2 >= sample_bot-thr_geom))
+        cross = true
+    else
+        circ_ZB=2*d/(spot1Y-spot2Y)*(sample_bot-spot2Y)-rot_to_det
+        circ_XB=(spotX1+spotX2)/(spot1Y-spot2Y)*(sample_bot-spot2Y)-spot2X
+       
+        if (circ_ZB^2+circ_XB^2 <= (rot_to_det+thr_geom)^2)
+            cross=true
+        else
+            circ_ZT=2*d/(spot1Y-spot2Y)*(sample_top-spot2Y)-rot_to_det
+            circ_XT=(spotX1+spotX2)/(spot1Y-spot2Y)*(sample_top-spot2Y)-spot2X
+            
+            if (circ_ZT^2+circ_XT^2 <= (rot_to_det+thr_geom)^2)
+                cross=true
+            else
+                cross=false
+            end
+        end
+    end
+end  
+
+
diff --git a/4_spot_sorting/normlinedir.m b/4_spot_sorting/normlinedir.m
new file mode 100755
index 0000000000000000000000000000000000000000..b381a94e62ed67e4bbaa93869a1a40489b39c364
--- /dev/null
+++ b/4_spot_sorting/normlinedir.m
@@ -0,0 +1,17 @@
+%
+% Normalize the direction vectors of 3D lines given in matrix form.
+%
+% INPUT:  l(n,6) [ point_X point_Y point_Z norm_dir_X norm_dir_Y norm_dir_Z] =
+%           any number of 3D lines in matrix form
+%             
+% OUTPUT: l(n,6) [ point_X point_Y point_Z norm_dir_X norm_dir_Y norm_dir_Z] =
+%           3D lines in matrix form with direction vectors normalized
+%
+
+
+
+function norm_l=normlinedir(l)
+
+n=sqrt(sum(l(:,4:6).*l(:,4:6),2));
+
+norm_l=[l(:,1:3) l(:,4)./n l(:,5)./n l(:,6)./n];
diff --git a/4_spot_sorting/old/Snake.m b/4_spot_sorting/old/Snake.m
new file mode 100755
index 0000000000000000000000000000000000000000..efa62c915683682d8069a83350013c2277c78770
--- /dev/null
+++ b/4_spot_sorting/old/Snake.m
@@ -0,0 +1,192 @@
+function Snake (struct_id)
+
+extmean=gtnewGetMeanFullImage(struct_id);
+
+
+im=gaussianBlur(extmean,1);
+
+% polarity of image not important because only magnitude of gradient is used
+[fx,fy]=gradient(im);
+fmag=sqrt(fx.^2+fy.^2);
+
+% use a small part of the image to find the starting snake
+[roffset,coffset]=find(summeddif_perim_mask);
+
+[x_orig,y_orig]=gtMask2Poly(...
+  summeddif_perim_mask(...
+  min(roffset):max(roffset),...
+  min(coffset):max(coffset)));
+
+% adjust back to original coordinates
+x_orig=x_orig+min(coffset)-1;
+y_orig=y_orig+min(roffset)-1;
+
+x=x_orig;y=y_orig;
+
+
+%%%%%%%%%%%%%%
+% make some measures of the spot we are considering:
+defaultmaskarea=29000;
+maskarea=numel(summeddif_bw);
+arearatio=maskarea/defaultmaskarea;
+fprintf('Area ratio: %3.2f\n',arearatio);
+
+defaultmaskperim=575;
+tmp=regionprops(double(summeddif_bw),'perimeter');
+maskperim=round(tmp.Perimeter);
+perimratio=maskperim/defaultmaskperim;
+fprintf('Perimeter ratio: %3.2f\n',perimratio);
+
+% intensity variation
+% need bw mask of spot:
+if 1
+  bwtmp=poly2mask(x_orig,y_orig,size(extmean,2),size(extmean,1));
+  tmp_inside=extmean(bwtmp);
+  tmp_outside=extmean(~bwtmp);
+  mean_inside=mean(tmp_inside(:))*1e3;
+  mean_outside=mean(tmp_outside(:))*1e3;
+  defaultmeanratio=2.88/0.6; % stndxruct_id 700
+  meanratio=mean_inside/mean_outside;
+  % when intensity ratio is lower, snake is harder to bind to perimeter
+  intensityratio=meanratio/defaultmeanratio;
+  fprintf('Intensity ratio: %3.2f\n',intensityratio);
+end
+
+snakeoptions.elasticity=3;
+snakeoptions.rigidity=15;  % keep this high to prevent spurs from local features
+snakeoptions.viscosity=3;
+snakeoptions.forcefactor=5;
+snakeoptions.iterations=10;
+
+snakeoptions.elasticity=snakeoptions.elasticity*arearatio.^2;
+%  snakeoptions.rigidity=10;  % keep this high to prevent spurs from local features
+%  snakeoptions.viscosity=5;
+%    snakeoptions.forcefactor=snakeoptions.forcefactor*perimratio;
+%  snakeoptions.iterations=5;
+snakeoptions;
+
+%%%%%%%%%%%%%%%
+
+pad=25;
+tmp_bbox=round([min(x(:))-pad min(y(:))-pad gtRange(x)+(2*pad) gtRange(y)+(2*pad)]);
+
+[u,v] = GVF(gtExtract(fmag,tmp_bbox), 0.05, 15);  % 0.2,80 % 0.3 15
+% Normalizing the GVF external force
+mag = sqrt(u.^2+v.^2);
+pxnorm = u./(mag+1e-10);pynorm = v./(mag+1e-10);
+
+forcefield.x=pxnorm;
+forcefield.y=pynorm;
+
+x=x-(tmp_bbox(1)+1);
+y=y-(tmp_bbox(2)+1);
+% should now remove points that are outside bbox
+if 0
+  x(y>size(mag,1))=[];
+  y(y>size(mag,1))=[];
+
+  y(x>size(mag,2))=[];
+  x(x>size(mag,2))=[];
+end
+if graphics.show_gvf
+  h_gvf=figure;
+  imagesc(mag,autolim(mag))
+  colorbar
+  hold on
+  quiver(pxnorm,pynorm,'r');
+  axis ij
+  axis equal
+  h_ax(1)=gca;
+end
+
+if graphics.show_snakeprogress && graphics.show_initialmatch
+  figure(h_initialmatch)
+  imagesc(gtExtract(extmean,tmp_bbox)),axis image,colormap(gray)
+  hold on
+  snakedisp(x,y,'r-')
+  h_ax(2)=gca;
+  if h_ax(1)~=0
+    linkaxes(h_ax,'xy')
+  end
+  axis image
+  drawnow
+end
+
+[x,y]=snakeinterp(x,y,20,1);
+origlength=length(x);
+clear hp
+converged=false;
+sfConverged([]); % reset sfConverged
+i=0;
+while not(converged)
+  i=i+1;
+  if i>100
+    break % get out of loop - we've taken too long
+  end
+  if length(x)<origlength/2
+    %      disp('Snake is too short!')
+    % break
+  end
+  [x2,y2]=snakedeform(x,y,forcefield,snakeoptions);
+  tmp=poly2mask(x,y,round(max(x)+5),round(max(y)+5));
+  area=sum(tmp(:));
+  converged=sfConverged(area);
+
+  [x,y]=snakeinterp(x2,y2,20,1);
+  if graphics.show_snakeprogress && graphics.show_initialmatch
+    figure(h_initialmatch)
+    if exist('hp','var')
+      delete(hp)
+    end
+    hp=snakedisp(x,y,'g.-');
+    axis image
+    title(['Deformation in progress,  iter = ' num2str(i*snakeoptions.iterations)])
+    drawnow
+  end
+end
+if converged
+  disp('Converged')
+else
+  disp('Did NOT converge')
+end
+
+if graphics.show_snakefinal && graphics.show_initialmatch
+  if graphics.show_gvf
+    figure(h_gvf);
+    snakedisp(x,y,'g-')
+    title(['Structure ' num2str(struct_id)])
+  end
+  figure(h_initialmatch)
+  if graphics.show_snakeprogress
+    snakedisp(x,y,'g-');
+  else
+    snakedisp(x+(tmp_bbox(1)+1),y+(tmp_bbox(2)+1),'g-')
+  end
+  title(['Structure ' num2str(struct_id)])
+end
+% restore snake coordinates to that of extinction image
+x=x+tmp_bbox(1);  % mussing +??
+y=y+tmp_bbox(2);
+
+% write snake to sql table
+tmp=repmat(struct_id,1,length(x));  % produce vector of repeated struct_id
+values=sprintf('("%f","%f","%f"),',[tmp;x;y]);
+values(end)=[];  % remove final comma
+keyboard
+mysqlcmd=sprintf('insert into %s (snakeID,x,y) values %s',table_snakes,values);
+mym(mysqlcmd)
+
+tmp = poly2mask(x,y, parameters.acq.bb(4), parameters.acq.bb(3));
+props=regionprops(double(tmp),'Area','BoundingBox','Centroid');
+
+
+mysqlcmd=dbUpdate(table_extspot,'extspotID',struct_id,...
+  'CentroidX',props.Centroid(1),...
+  'CentroidY',props.Centroid(2),...
+  'BoundingBoxXorigin',props.BoundingBox(1),...
+  'BoundingBoxYorigin',props.BoundingBox(2),...
+  'BoundingBoxXsize',props.BoundingBox(3),...
+  'BoundingBoxYsize',props.BoundingBox(4),...
+  'Area',prop.Area,...
+  'snakeID',struct_id);
+mym(mysqlcmd);
diff --git a/4_spot_sorting/old/generate_extinctionmask.m b/4_spot_sorting/old/generate_extinctionmask.m
new file mode 100755
index 0000000000000000000000000000000000000000..ed90e07dcbde0d9f898bfd18909a0f5c0a9c7426
--- /dev/null
+++ b/4_spot_sorting/old/generate_extinctionmask.m
@@ -0,0 +1,73 @@
+function mask=generate_extinctionmask(im,point)
+% im=edf_read('full0000.edf');
+% point.x=1591; point.y=1312;
+global app
+if ~exist('app','var')
+  error('Please load the common/parameter file before using this function')
+end
+
+bb=app.bb.directbeam;
+ext_axis=[bb(2) bb(2)+bb(4) bb(1) bb(1)+bb(3)];
+im_ext=im(bb(2):bb(2)+bb(4),bb(1):bb(1)+bb(3));
+
+%calculate the cones that emmanate from the selected point
+
+% distance from diffraction spot to near and far edge of sample
+
+sample_hbb=[850-20 1200+20];  % this should NOT be hardcoded like this!
+sample_vbb=[780 1260];  % nor this!
+sample_width=diff(sample_hbb);
+
+% 111 8.6
+% 002 9.9
+% 220 14.1
+% 311 16.5
+% stainless steel a=3.61A 40keV
+
+theta=[8.6 9.9 14.1 16.5];
+tmp=calculate_twotheta(3.61,'FCC',40);
+% this uses hashtables - very powerful, but perhaps a little too weird???
+tmp=tmp.elements;
+for n=1:length(tmp)
+  theta(n)=tmp{n}.centre;
+end
+
+dist_rear=app.dist+(sample_width*app.pixelsize); % assume sample is cuboid
+dist_front=app.dist-(sample_width*app.pixelsize);
+
+rad_front=dist_front*tan(deg2rad(theta))/app.pixelsize;
+rad_rear=dist_rear*tan(deg2rad(theta))/app.pixelsize;
+
+
+tmask=zeros(size(im));
+for n=1:length(rad_front)
+ [xf{n},yf{n}]=circlepoints(point.x,point.y,rad_front(n),40);
+ tmp_maskf=poly2mask(xf{n},yf{n},size(im,2),size(im,1));
+ [xr{n},yr{n}]=circlepoints(point.x,point.y,rad_rear(n),40);
+ tmp_maskr=poly2mask(xr{n},yr{n},size(im,2),size(im,1));
+ tmask=tmask | xor(tmp_maskr,tmp_maskf);
+end
+ 
+mask=zeros(size(im));
+mask(tmask)=1;
+
+
+return
+
+
+% calc theta and eta
+point2=ginput(1);% grain in image2
+
+offset=point_mirror-point2;
+Theta=atan((sqrt(offset*offset'))/(10/0.0014));
+Theta=(Theta*180/pi)/2;%divide by 2 for 2theta -> theta
+
+Eta=atan2(offset(1,1),offset(1,2))*180/pi;
+if Eta<0
+  Eta=360+Eta;
+end
+
+
+Theta
+Eta
+
diff --git a/4_spot_sorting/old/gtnewGetSummedExtSpot.m b/4_spot_sorting/old/gtnewGetSummedExtSpot.m
new file mode 100755
index 0000000000000000000000000000000000000000..3f6ff98359760ec141b20cb245d426622fcf5d4a
--- /dev/null
+++ b/4_spot_sorting/old/gtnewGetSummedExtSpot.m
@@ -0,0 +1,56 @@
+function im=gtnewGetSummedExtSpot(ndx)
+% returns the summed full extinction spot image
+
+
+global parameters; global difspot; global extspot;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+if isempty(difspot)
+  disp('Loading difspot file')
+  load('2_difspot/difspot.mat');
+end
+if isempty(extspot)
+  disp('Loading extspot file')
+  load('3_extspot/extspot.mat');
+end
+
+%get bounding box of extinction spot
+%get spot outline too
+if ~isempty(extspot(ndx).BoundingBox)  
+bb.BoundingBox = extspot(ndx).BoundingBox;
+%put snake relative to boundingbox
+snakex = extspot(ndx).snakex - floor(bb.BoundingBox(1));
+snakey = extspot(ndx).snakey - floor(bb.BoundingBox(2));
+snake_mask = poly2mask(snakex, snakey, bb.BoundingBox(4), bb.BoundingBox(3));
+
+else
+bb = extspot(ndx).SearchBoundingBox;
+%get summed difspot outline instead of snake
+difsummed=gtnewGetSummedDifSpot(ndx);
+tmp1=difsummed>0;
+tmp2=bwmorph(tmp1,'spur',inf);
+tmp3=bwmorph(tmp2,'erode',1);
+snake_mask=bwmorph(tmp3,'dilate',1);
+
+end
+
+%put BoundingBox into coordinates of the full image
+bb.BoundingBox(1) = ceil(bb.BoundingBox(1) + parameters.acq.bb(1));
+bb.BoundingBox(2) = ceil(bb.BoundingBox(2) + parameters.acq.bb(2));
+
+im=zeros(bb.BoundingBox(4), bb.BoundingBox(3));
+
+disp([num2str(difspot(ndx).ExtEndImage-difspot(ndx).ExtStartImage+1) ' images in sum'])
+
+for i=difspot(ndx).ExtStartImage:difspot(ndx).ExtEndImage
+  im = im + edf_read(sprintf('%s/1_preprocessed/full/full%04d.edf',parameters.acq.dir,i), bb.BoundingBox);
+end
+
+im = im.*snake_mask;
+
+im = -im; %make spot positive, on zeros background
+
+end
diff --git a/4_spot_sorting/old/gtnewGetSummedExtSpot_db.m b/4_spot_sorting/old/gtnewGetSummedExtSpot_db.m
new file mode 100755
index 0000000000000000000000000000000000000000..be50012cccbbaffc3e103ade03dddf7e683d3bfc
--- /dev/null
+++ b/4_spot_sorting/old/gtnewGetSummedExtSpot_db.m
@@ -0,0 +1,42 @@
+function im=gtnewGetSummedExtSpot_db(struct_id)
+% returns the summed full extinction spot image
+%uses database
+
+global parameters;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+
+%get bounding box of extinction spot
+%get spot outline too
+if ~isempty(extspot(ndx).BoundingBox)  
+bb.BoundingBox = extspot(ndx).BoundingBox;
+%put snake relative to boundingbox
+snakex = extspot(ndx).snakex - floor(bb.BoundingBox(1));
+snakey = extspot(ndx).snakey - floor(bb.BoundingBox(2));
+snake_mask = poly2mask(snakex, snakey, bb.BoundingBox(4), bb.BoundingBox(3));
+
+[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sextspot where extspotID = %d', ...
+  parameters.acq.name,struct_id));
+
+warning('this is not finished yet - ak 5/10/06 - need to finish updating to database')
+
+%put BoundingBox into coordinates of the full image
+bb.BoundingBox(1) = ceil(bb.BoundingBox(1) + parameters.acq.bb(1));
+bb.BoundingBox(2) = ceil(bb.BoundingBox(2) + parameters.acq.bb(2));
+
+im=zeros(bb.BoundingBox(4), bb.BoundingBox(3));
+
+disp([num2str(difspot(ndx).ExtEndImage-difspot(ndx).ExtStartImage+1) ' images in sum'])
+
+for i=difspot(ndx).ExtStartImage:difspot(ndx).ExtEndImage
+  im = im + edf_read(sprintf('%s/1_preprocessed/full/full%04d.edf',parameters.acq.dir,i), bb.BoundingBox);
+end
+
+im = im.*snake_mask;
+
+im = -im; %make spot positive, on zeros background
+
+end
diff --git a/4_spot_sorting/old/gtnewHandleSpot.m b/4_spot_sorting/old/gtnewHandleSpot.m
new file mode 100755
index 0000000000000000000000000000000000000000..102557799336a86d52c66f663e59eaed2ab700c2
--- /dev/null
+++ b/4_spot_sorting/old/gtnewHandleSpot.m
@@ -0,0 +1,350 @@
+%function [stack,theta,struct_id,ind_orig,img2,accept,grainpos]=gtnewHandleSpot(spot_id,grainid)
+
+function [accept,stack]=gtnewHandleSpot(spot_id,grainid)
+
+% function [stack,theta,struct_id,ind_orig,img2,accept]=handle_spot_wolf(spot_id,grainid)
+% 
+% stack:    3D matrix containing the valid projections as determined by the backprojection and sine criterion
+% theta:    vector of the corresponding projection angles [radians] 
+% struct_id vector containing the valid structure entries
+% ind_orig  vetor containing the indices od elements in struct_ind which belong to not replaced spots 
+%             i.e.:  app.extspot(struct_id(ind_orig)).Replaced=[] for all ind_orig
+% img2      backprojection using the valid spots
+
+%add filter to use condition of known valid Theta angles to help...
+
+%try to simplify and automate
+%modify to gtnew format
+%sufficient to return "accept" only, all data written to grain%d_.mat
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+global difspot
+if isempty(difspot)
+  load 2_difspot/difspot.mat
+end
+global extspot
+if isempty(extspot)
+  load 3_extspot/extspot.mat
+end
+
+grainpos=[0 0 0];
+accept = 0;
+
+%find related spots
+struct_id = gtnew_find_family(spot_id);
+omega = sfGetOmega(struct_id);
+%produce sinogram at mid-height of seed spot
+
+[stack,sino,z_of_sino]=gtnew_read_spots(spot_id,struct_id);
+
+%which of struct_id vector is the original spot (spot_id)
+index = find(struct_id==spot_id);
+
+%setup the figure
+img1 = zeros(parameters.acq.bb(3));
+figure;
+imshow(img1, []);
+hold on
+
+%make original spot centre line
+[orig_grad, orig_intersect] = sfMakeBackProLine(spot_id, struct_id, sino, omega);
+%plot original centre line
+tmpx = 1:parameters.acq.bb(3);
+tmpy = (orig_grad*tmpx) + orig_intersect;
+plot(tmpx, tmpy);
+
+%get allowed TwoTheta data
+tmp=gtnew_calculate_twotheta(parameters.acq.latticepar(1),parameters.acq.spacegroup,parameters.acq.energy);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+
+good_points=[];counter=1;
+
+%loop through all spots
+for i=1:length(struct_id)
+if i ~= index %don't need to do original spot
+
+  %make spot centre line
+  [grad, intersect] = sfMakeBackProLine(struct_id(i), struct_id, sino, omega);
+
+  %calculate intersection with original spot line
+  tmpx = -(intersect-orig_intersect)/(grad-orig_grad);
+  tmpy = (orig_grad*tmpx) + orig_intersect;
+  
+  %plot point
+  plot(tmpx, tmpy, 'xr')
+ 
+  %does intersection give good theta angles?  orig and current spots
+  %using grainpos = tmpx, tmpy, calc theta
+ [Theta_spot, Eta_spot] = sfFindAngles(struct_id(i), tmpx, tmpy, z_of_sino,  omega(i));
+ [Theta_orig, Eta_orig] = sfFindAngles(struct_id(index), tmpx, tmpy, z_of_sino,  omega(index));
+  
+ min_spot_dif = min(abs((twotheta/2)-Theta_spot)./(twotheta/2));
+ min_orig_dif = min(abs((twotheta/2)-Theta_orig)./(twotheta/2));
+ 
+ if (min_spot_dif<0.025 & min_orig_dif<0.025)% if both Thetas good to 2.5%
+   if (tmpx > 0 & tmpx <= parameters.acq.bb(3) & tmpy > 0 & tmpy <= parameters.acq.bb(3))% if point lies in image 
+plot(tmpx, tmpy, 'go')%plot point, record in good points
+good_points(counter,1)=tmpx;
+good_points(counter,2)=tmpy;
+good_points(counter,3)=struct_id(i);
+counter=counter+1;
+   end
+ end
+ 
+end
+end
+
+%find grain position from good_points
+if size(good_points,1)>4%need at least 4 spots to proceed...
+x_grain = fminbnd(@(x_grain) sfFindGrain(good_points, x_grain), min(good_points(:,1)), max(good_points(:,1)));
+y_grain = (orig_grad*x_grain) + orig_intersect;  
+plot(x_grain, y_grain, 'cx', 'markersize', 20)% plot the chosen center
+
+%find width of original projection
+orig_sino = sino(:,index);
+orig_binsino = orig_sino>0.1*max(orig_sino);
+dummy=find(orig_binsino==1);
+orig_min=min(dummy);
+orig_max=max(dummy);
+proj_radius = (orig_max - orig_min)/2;
+
+%calc distance of intersections from grain position
+good_points(:,4) = sqrt((good_points(:,1)-x_grain).^2+(good_points(:,2)-y_grain).^2);
+dummy = find(good_points(:,4)>proj_radius);
+good_points(dummy, :)=[];%remove intersections far from grain center
+
+%plot the final set of intersections
+plot(good_points(:,1), good_points(:,2), 'yo', 'markersize', 10)
+
+%create binsino and omega for good spots only
+good_sino(:,1)=orig_sino; 
+good_omega=omega(index);
+good_stack(:,:,1) = stack(:,:,index);
+good_struct_id(1) = spot_id;
+for j=1:size(good_points,1)
+  tmp = find(struct_id == good_points(j,3));
+  good_sino(:,j+1) = sino(:,tmp);
+  good_omega(j+1) = omega(tmp);
+  good_stack(:,:,j+1) = stack(:,:,tmp);
+  good_struct_id(j+1) = struct_id(tmp);
+end
+struct_id = good_struct_id;
+omega = good_omega;
+stack = good_stack;
+sino = good_sino;
+
+%need at least four projections of grain for a useful reconstruction.
+if length(struct_id) > 3
+  accept =1;
+
+  %call sfFindAngles with the final grain position
+  %good also do this using the grain centroid after back projection
+  Theta = []; Eta = [];
+  for j=1:length(struct_id)
+    [tmpTheta, tmpEta] = sfFindAngles(struct_id(j), x_grain, y_grain, z_of_sino, omega(j));
+    Theta(j) = tmpTheta;
+    Eta(j) = tmpEta;
+  end
+  Omega = omega*180/pi;
+
+  %back project good spots only
+  binsino = sino>0.1*max(sino(:));
+  img2=backpro(binsino,omega);
+
+  %do imreconstruct from centre to threshold grain
+  x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+  marker=zeros(size(img2));
+  marker(y_grain, x_grain)=1;
+  mask=double((img2>0.8*img2(y_grain, x_grain)));
+  grain=imreconstruct(marker,mask);
+
+  %get z limits
+  zstart=find(mean(sum(stack,3),2),1,'first');
+  zend=find(mean(sum(stack,3),2),1,'last');
+  zcenter=round((zend+zstart)/2);
+
+  s=regionprops(grain,'Area','BoundingBox','Centroid');
+  xgrain=s.Centroid(1);
+  ygrain=s.Centroid(2);
+  xstart = s.BoundingBox(1);
+  ystart = s.BoundingBox(2);
+  xcenter = s.BoundingBox(1)+s.BoundingBox(3)/2;
+  ycenter = s.BoundingBox(2)+s.BoundingBox(4)/2;
+  xend = xstart + s.BoundingBox(3);
+  yend = ystart + s.BoundingBox(4);
+
+  %add 20% to bounding box for luck
+  if  round(xstart -(s.BoundingBox(3)/5)) > 0
+    xstart = round(xstart - (s.BoundingBox(3)/5));
+  else
+    xstart = 1;
+  end
+
+  if round(ystart - (s.BoundingBox(4)/5)) > 0
+    ystart = round(ystart - (s.BoundingBox(4)/5));
+  else
+    ystart = 1;
+  end
+
+  if round(xend + (s.BoundingBox(3)/5)) <= parameters.acq.bb(3);
+    xend = round(xend + (s.BoundingBox(3)/5));
+  else
+    xend = parameters.acq.bb(3);
+  end
+
+  if round(yend + (s.BoundingBox(4)/5)) <= parameters.acq.bb(3);
+    yend = round(yend + (s.BoundingBox(4)/5));
+  else
+    yend = parameters.acq.bb(3);
+  end
+
+  if round(zend + ((zend-zstart)/5)) <= parameters.acq.bb(4);
+    zend = round(zend + ((zend-zstart)/5));
+  else
+    zend = parameters.acq.bb(4);
+  end
+
+  if round(zstart - ((zend-zstart)/5)) >= 1;
+    zstart = round(zstart - ((zend-zstart)/5));
+  else
+    zstart = 1;
+  end
+  
+  ny = yend-ystart;
+  nx = xend-xstart;
+  nz = zend-zstart;
+
+  y1 = ystart;
+  x1 = xstart;
+
+  %grainid into structure
+  for i=1:length(struct_id)
+    extspot(struct_id(i)).GrainID=grainid;
+  end
+  save('3_extspot/extspot.mat', 'extspot');
+
+
+  fprintf('for reconstruct_art_roi:\n z1 = %d, nz = %d, x1 = %d, nx = %d, y1 = %d, ny = %d\n',zstart,nz,x1,nx,y1,ny);
+  %write stack and information about scan
+
+  disp(sprintf('writing projections for grain %d',grainid));
+  gtnew_write_stack(stack,grainid);
+  grainname=sprintf('grain%d_',grainid);
+  graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+  name=sprintf('%s/%s.mat',graindir,grainname);
+
+  %probably don't need all of these, and certainly need to rationalise
+  %omega/theta use!
+
+  save(name,'Omega','struct_id','stack','zstart','zend','zcenter','x1','nx','y1','ny','xcenter','ycenter','xgrain','ygrain','Theta', 'Eta');
+  grainpos=[xgrain,ygrain,zcenter];
+
+  figure
+  imshow(grain,[])
+
+else
+  disp(sprintf('only %d projections related to spot %d - skipping',length(struct_id),spot_id))
+end
+
+
+else
+  disp(sprintf('only %d good points on projection of spot %d - skipping',size(good_points,1),spot_id))
+end
+
+ end
+
+
+  function [m, c] = sfMakeBackProLine(spot_id, struct_id, sino, theta)
+%function to return the parameters of a line passing through the proj of a
+%given spot, struct_id is vector of spots in the sinogram, sino.
+index = find(struct_id == spot_id);
+
+%get spot parameters 
+spot_sino=sino(:,index);
+spot_com=(spot_sino'*[1:length(spot_sino)]')/sum(spot_sino);
+spot_omega=theta(index);
+
+%experiment parameters
+disp('assuming centre of rotation to be at centre of acq.bb')
+centre_of_backproimg_x = size(sino,1)/2;
+centre_of_backproimg_y = size(sino,1)/2;
+
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-length(spot_sino)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+  end
+  
+  function [Theta,Eta] = sfFindAngles(struct_id, grainx, grainy, grainz, omega);
+  global parameters;
+  global difspot;
+  global extspot;
+  %calculate Theta angle between grain position (x,y,z) and difspot of
+  %struct_id
+  
+if ~isempty(extspot(struct_id).Centroid)  
+  xdirect=parameters.acq.bb(1)+extspot(struct_id).Centroid(1);
+else
+  xdirect=parameters.acq.bb(1)+extspot(struct_id).SearchCentroid(1);
+end
+  ydirect=parameters.acq.bb(2)+grainz;
+  
+  xdiffr=difspot(struct_id).Centroid(1);
+  ydiffr=difspot(struct_id).Centroid(2);
+
+  r=sqrt((xdirect-xdiffr)^2+(ydirect-ydiffr)^2);
+
+  grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+  angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+  dz=grain2rot.*sin(-omega+angle)+parameters.acq.dist/parameters.acq.pixelsize;
+
+  Theta=((atan(r./dz))/2)*180/pi;
+
+  Eta=atan2((xdiffr-xdirect),(ydirect-ydiffr))*180/pi;
+  if Eta<0
+    Eta=360+Eta;
+  end
+
+  end
+
+    
+  function output = sfFindGrain(good_points, x_grain)
+  %function for fminbnd to find grain position along original projection
+  dif = good_points(:,1)-x_grain;
+  %minimise sum of squares for the closest half of the points, to reduce
+  %effect of outliers
+  dif = abs(dif);
+  dif = sort(dif,1,'descend');
+  tmp = ceil(size(dif,1)/2);
+  dif(1:tmp)=[];
+  output = dif'*dif;%sum of squares
+  end
+  
+  function Omega = sfGetOmega(struct_id)
+  %get the omega angles corresponding to MaxImage of struct_id vector
+  %in radians!
+  global parameters
+  global difspot
+  Omega=[];
+  for i=1:length(struct_id)
+  Omega(i) = difspot(struct_id(i)).MaxImage;
+  end
+  Omega = pi*(Omega./parameters.acq.proj);
+  end
+  
\ No newline at end of file
diff --git a/4_spot_sorting/old/gtnew_find_family.m b/4_spot_sorting/old/gtnew_find_family.m
new file mode 100755
index 0000000000000000000000000000000000000000..7ce2847e98a5e96d5ffee25f04b65074cdf3573e
--- /dev/null
+++ b/4_spot_sorting/old/gtnew_find_family.m
@@ -0,0 +1,59 @@
+% function struct_id = gtnew_find_family(seed) 
+%
+% seed:      struct_id (!) of a good extinction spot candidate
+% struct_id  indices of possibly associated spots in datastructure extspot(struct_id)
+%
+%modify to new world order - ak 27/09/06
+
+function[struct_id,varargout] = gtnew_find_family(seed,varargin)
+ 
+%load data
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+global extspot
+if isempty(extspot)
+  load 3_extspot/extspot.mat
+end
+
+%get BoundingBox parameters from a good ext spot (the one at the input)
+if isempty(extspot(seed).SearchBoundingBox)
+	disp('bad seedpoint:  no extspot properties available')
+ 	struct_id=-1;
+	return;
+end	
+
+%if possible use extspot.BoundingBox (from snake), otherwise use
+%.SearchBoundingBox (from difspot outline)
+if ~isempty(extspot(seed).BoundingBox)  
+top = extspot(seed).BoundingBox(2);
+height =  extspot(seed).BoundingBox(4);
+else
+top = extspot(seed).SearchBoundingBox.BoundingBox(2);
+height =  extspot(seed).SearchBoundingBox.BoundingBox(4);
+end
+
+AllowedError = max(5,ceil(height/parameters.match.heighttol));    %use an error of 10% (from parameters) - but at least 5 pixels
+counter = 1;
+
+%loop over all extspots
+for i=1:length(extspot)
+  if and(~isempty(extspot(i).SearchBoundingBox), extspot(i).GrainID==0)% if not empty, then check position of ExtSpot
+  %if ~isempty(extspot(i).Area)% for testing, doesn't ignore previously assigned extspots
+
+    if ~isempty(extspot(i).BoundingBox)  
+toptest = extspot(i).BoundingBox(2);
+heighttest =  extspot(i).BoundingBox(4);
+    else
+toptest = extspot(i).SearchBoundingBox.BoundingBox(2);
+heighttest =  extspot(i).SearchBoundingBox.BoundingBox(4);
+    end
+    
+	  if (abs(top-toptest) < AllowedError & abs(height-heighttest) < 2*AllowedError)
+		  struct_id(counter) = i;
+		  counter = counter+1;
+    end
+    
+  end
+end
diff --git a/4_spot_sorting/old/gtnew_read_spots.m b/4_spot_sorting/old/gtnew_read_spots.m
new file mode 100755
index 0000000000000000000000000000000000000000..6e5c233db5e681e825ab1805778bf17b8b28b8f0
--- /dev/null
+++ b/4_spot_sorting/old/gtnew_read_spots.m
@@ -0,0 +1,55 @@
+function [stack,sino,z_of_sino] = gtnew_read_spots(spot_id, struct_id)
+% function [stack,sino,z_of_sino,varargout]=read_spots(struct_id)
+% produce sinogram of all spots in struct_id vector at the mid-height 
+% of the seed spot (spot_id).
+% optional output argument orig holds original projection (Max)images for verification
+%could add orig, not currently supported
+
+%load data
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+global difspot
+if isempty(difspot)
+  load 2_difspot/difspot.mat
+end
+global extspot
+if isempty(extspot)
+  load 3_extspot/extspot.mat
+end
+
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_id));
+
+%if possible use extspot.BoundingBox (from snake), otherwise use
+%.SearchBoundingBox (from difspot outline)
+if ~isempty(extspot(spot_id).BoundingBox)  
+z_of_sino = ceil(extspot(spot_id).BoundingBox(2) + (extspot(spot_id).BoundingBox(4)/2));
+else
+z_of_sino = ceil(extspot(spot_id).SearchBoundingBox.BoundingBox(2) + (extspot(spot_id).SearchBoundingBox.BoundingBox(4)/2));
+end
+
+%read images to produce sinogram at position z_of_sino
+   for i=1:length(struct_id)
+     
+     %get bounding box of extinction spot
+     if ~isempty(extspot(struct_id(i)).BoundingBox)
+       bb.BoundingBox = extspot(struct_id(i)).BoundingBox;
+     else
+       bb = extspot(struct_id(i)).SearchBoundingBox;
+     end
+
+     %read extspot
+     try %try because some bounding boxes really dodgy (517) due to rolling of difspot outline
+     im = gtnewGetSummedExtSpot(struct_id(i));
+     %place in stack
+     stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)), ceil(bb.BoundingBox(1)), ceil(bb.BoundingBox(2))); 
+     stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+     end
+
+     %read sino from stack
+     sino(:,i) = stack(z_of_sino, :, i);
+     
+   end
+   
+end
\ No newline at end of file
diff --git a/4_spot_sorting/old/gtnew_read_spots_db.m b/4_spot_sorting/old/gtnew_read_spots_db.m
new file mode 100755
index 0000000000000000000000000000000000000000..4cc6462f95c0c8b60fcf1fad93cb874edeba2523
--- /dev/null
+++ b/4_spot_sorting/old/gtnew_read_spots_db.m
@@ -0,0 +1,55 @@
+function [stack,sino,z_of_sino] = gtnew_read_spots_db(spot_id, struct_id)
+% function [stack,sino,z_of_sino,varargout]=read_spots(struct_id)
+% produce sinogram of all spots in struct_id vector at the mid-height 
+% of the seed spot (spot_id).
+% optional output argument orig holds original projection (Max)images for verification
+%could add orig, not currently supported
+
+%database enable!
+
+%load data
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_id));
+% 
+% %if possible use extspot.BoundingBox (from snake), otherwise use
+% %.SearchBoundingBox (from difspot outline)
+% if ~isempty(extspot(spot_id).BoundingBox)  
+% z_of_sino = ceil(extspot(spot_id).BoundingBox(2) + (extspot(spot_id).BoundingBox(4)/2));
+% else
+% z_of_sino = ceil(extspot(spot_id).SearchBoundingBox.BoundingBox(2) + (extspot(spot_id).SearchBoundingBox.BoundingBox(4)/2));
+% end
+z_of_sino = mym(sprintf('select ceil(BoundingBoxYorigin + (BoundingBoxYsize/2)) from %sextspot where extspotID = %d',parameters.acq.name,spot_id));
+
+
+
+%read images to produce sinogram at position z_of_sino
+   for i=1:length(struct_id)
+     
+     %get bounding box of extinction spot
+%      if ~isempty(extspot(struct_id(i)).BoundingBox)
+%        bb.BoundingBox = extspot(struct_id(i)).BoundingBox;
+%      else
+%        bb = extspot(struct_id(i)).SearchBoundingBox;
+%      end
+[BoundingBox(1),BoundingBox(2)] = mym(sprintf('select BoundingBoxXorigin,BoundingBoxYorigin from %sextspot where extspotID = %d',parameters.acq.name,struct_id(i)));
+
+warning('this is not finished yet - ak 5/10/06 - need to finish updating to database')
+     %read extspot
+     try %try because some bounding boxes really dodgy (517) due to rolling of difspot outline
+     im = gtnewGetSummedExtSpot_db(struct_id(i));
+     %place in stack
+     stack(:,:,i) = gtPlaceSubImage(im, zeros(
+     parameters.acq.bb(4), parameters.acq.bb(3)), ceil(BoundingBox(1)), ceil(BoundingBox(2))); 
+     stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+     end
+
+     %read sino from stack
+     sino(:,i) = stack(z_of_sino, :, i);
+     
+   end
+   
+end
\ No newline at end of file
diff --git a/4_spot_sorting/old/handle_spot_theta.m b/4_spot_sorting/old/handle_spot_theta.m
new file mode 100755
index 0000000000000000000000000000000000000000..4355cd074b7c15b243cdc95a090803d8fdc14928
--- /dev/null
+++ b/4_spot_sorting/old/handle_spot_theta.m
@@ -0,0 +1,387 @@
+function [stack,theta,struct_id,ind_orig,img2,accept,grainpos]=handle_spot_theta_auto(spot_id,grainid)
+
+% function [stack,theta,struct_id,ind_orig,img2,accept]=handle_spot_wolf(spot_id,grainid)
+% 
+% stack:    3D matrix containing the valid projections as determined by the backprojection and sine criterion
+% theta:    vector of the corresponding projection angles [radians] 
+% struct_id vector containing the valid structure entries
+% ind_orig  vetor containing the indices od elements in struct_ind which belong to not replaced spots 
+%             i.e.:  app.extspot(struct_id(ind_orig)).Replaced=[] for all ind_orig
+% img2      backprojection using the valid spots
+
+%add filter to use condition of known valid Theta angles to help...
+
+%try to simplify and automate
+
+
+
+global app
+accept=1;
+grainpos=[0 0 0];
+%find related spots
+[struct_id,spot_id_vector,theta]=find_family(spot_id);
+[stack,sino,z_of_sino]=read_spots(struct_id);
+
+
+size(sino)
+size(theta)
+
+%threshold sinogram and backproject
+binsino=sino>0.1*max(sino(:));
+img1=backpro(binsino,theta);
+
+%show backprojection results
+figure(1);
+imshow(img1,[])
+
+%make overlay to show backprojection of original spot
+single_bp = backpro(binsino(:,find(struct_id==spot_id)),theta(find(struct_id==spot_id)));
+overlay_bp(:,:,1)=zeros(size(single_bp)); 
+overlay_bp(:,:,2)=single_bp;
+overlay_bp(:,:,3)=zeros(size(single_bp));
+
+hold on
+h_img=image(overlay_bp,'XData',[1:size(img1,2)],'YData',[1:size(img1,1)]);
+set(h_img,'AlphaData',0.1*ones(size(img1)));
+
+%extend to all spots
+test_final=zeros(size(img1));
+for i=1:length(struct_id)
+  %for i=1:3
+%add a line along centre of mass of original spot
+%orig_sino=sino(:,find(struct_id==spot_id));
+%orig_com=(orig_sino'*[1:length(orig_sino)]')/sum(orig_sino);
+%orig_omega=theta(find(struct_id==spot_id));
+
+orig_sino=sino(:,i);
+orig_binsino=binsino(:,i);
+orig_com=(orig_sino'*[1:length(orig_sino)]')/sum(orig_sino);
+orig_omega=theta(i);
+
+%find orig_binsino width, relative to com
+dummy=find(orig_binsino==1);
+orig_min=min(dummy);
+orig_max=max(dummy);
+
+%calculate line passing through centre of spot projection
+grad=1/tan(orig_omega);
+point=size(img1)./2;
+offset_com=orig_com-length(orig_sino)/2;
+point=point+(offset_com*[cos(orig_omega) -sin(orig_omega)]);
+
+%define line by point and angle - what if angle = 0?
+line=[-(ceil(size(img1,1)*1.4/2)):ceil(size(img1,1)*1.4/2)];%points along a line
+  
+plot_data(1,:)=point(1,1)+(line*(sin(orig_omega)));
+plot_data(2,:)=point(1,2)+(line*(cos(orig_omega)));
+
+%dummy = find(plot_data < 1);
+%plot_data(dummy) = 1;
+%dummy = find(plot_data > size(img1,1));
+%plot_data(dummy) = size(img1,1);
+
+figure(1);
+plot(plot_data(1,:),plot_data(2,:),'r');
+
+%now add allowed Theta condition...
+%pasted from find_angles_andy and modified to suit
+%xdirect=app.bb.directbeam(1)+app.extspot(spot_id).ExtCentroid(1);
+%ydirect=app.bb.directbeam(2)+z_of_sino(:,find(struct_id==spot_id));
+
+xdirect=app.bb.directbeam(1)+app.extspot(struct_id(i)).ExtCentroid(1);
+ydirect=app.bb.directbeam(2)+z_of_sino(i);
+
+
+%ydirect=app.bb.directbeam(2)+zgrain+200;  %+app.extspot(struct_id).ExtCentroid(2)-app.border;
+%zgrain is defined relative to the center, not the edge.
+
+%xdiffr=app.extspot(spot_id).Centroid(1);
+%ydiffr=app.extspot(spot_id).Centroid(2);
+
+xdiffr=app.extspot(struct_id(i)).Centroid(1);
+ydiffr=app.extspot(struct_id(i)).Centroid(2);
+
+
+r=sqrt((xdirect-xdiffr)^2+(ydirect-ydiffr)^2);
+
+%grain2rot and angle now vectors
+grain2rot=sqrt((plot_data(1,:)-app.data.ext.xsize/2).^2+(plot_data(2,:)-app.data.ext.xsize/2).^2);
+angle=atan2(app.data.ext.xsize/2-plot_data(2,:),plot_data(1,:)-app.data.ext.xsize/2);
+%angle*180/pi;%angle needs o be in radians for calculations...  ok, this
+%doesn't change it.
+
+%xdircal=app.bb.directbeam(1)+app.data.ext.xsize/2+grain2rot*cos(-omega+angle);
+
+dz=grain2rot.*sin(-orig_omega+angle)+app.dist/app.pixelsize;
+
+Theta=((atan(r./dz))/2)*180/pi;
+good_Theta=[7.63 8.81 12.52 14.72 15.39 17.85];
+good_Theta=[good_Theta*0.98; good_Theta*1.02];%+- 2% tolerance (note //direct beam
+
+dummy=[];
+for j=1:length(good_Theta)
+dummy=[dummy find(Theta>good_Theta(1,j) & Theta<good_Theta(2,j))];
+
+end
+%Theta=Theta(dummy);
+good_plot_data=plot_data(:,dummy);
+plot(good_plot_data(1,:),good_plot_data(2,:),'gx');
+
+%plot an area, rather than just a line.
+%define a rectangle
+
+
+%make image, then rotate and sum
+%save test_images for each projection, to use in Theta filter later....
+test_image(:,:,i)=zeros(size(img1));
+
+good_y = line(dummy)+ceil(size(img1,2)/2);
+%good_y = line+ceil(size(img1,2)/2);
+good_x = [orig_min:orig_max];
+
+dummy=find(good_y < 1 | good_y > size(img1,2));
+good_y(dummy)=[];
+dummy=find(good_x < 1 | good_x > size(img1,1));
+good_x(dummy)=[];
+
+test_image(good_y,good_x,i)=1;
+test_image(:,:,i) = imrotate(test_image(:,:,i), orig_omega*180/pi, 'crop');
+test_final = test_final + test_image(:,:,i);%test_final is the sum of each projection
+
+
+
+
+end
+figure(2)
+imshow(test_final, []);
+%add the original projection overlay
+hold on
+h_img=image(overlay_bp,'XData',[1:size(img1,2)],'YData',[1:size(img1,1)]);
+set(h_img,'AlphaData',0.1*ones(size(img1)));
+
+%can now use the Theta filtered backproection (test_final) as before...
+
+%get the centre of the grain from user
+fprintf('click on the centre of the grain, or outside image to skip...\n');
+points(1,:)=round(ginput(1));
+
+%if user skips this family, abort.
+if points(1,1)<1 | points(1,2)<1 | points(1,1) > app.data.ext.xsize | points(1,2) > app.data.ext.xsize 
+   disp('skip current family... try another!');
+   ind_orig=[];
+   img2=[];
+   accept=0;
+   
+%try to select the grain area automatically   
+else   
+	%calculate the COM of the most intense spot
+	marker=zeros(size(img1));
+	marker(points(1,2),points(1,1))=1;
+	mask=double((img1>0.8*img1(points(1,2),points(1,1))));
+	grain=imreconstruct(marker,mask);
+	
+	overlay=grain;
+	overlay(:,:,2)=zeros(size(grain));
+	overlay(:,:,3)=zeros(size(grain));
+	
+  figure(2)
+ 	grain=bwlabel(grain);
+	h_img=image(overlay,'XData',[1:size(grain,2)],'YData',[1:size(grain,1)]);
+	set(h_img,'AlphaData',0.3*ones(size(grain)));
+	s=regionprops(grain,'Area','Centroid');
+    hold off;
+
+  figure(1)%label grain on normal backpro image also
+  h_img=image(overlay,'XData',[1:size(grain,2)],'YData',[1:size(grain,1)]);
+	set(h_img,'AlphaData',0.3*ones(size(grain)));
+	s=regionprops(grain,'Area','Centroid');
+    
+    figure(2)
+    
+%else find grain manually
+
+	fprintf('click at the edge of the grain in order to define radius manually -\n or outside the image to accept present value\n');
+	points(2,:)=round(ginput(1));
+	
+    if points(2,1) < 1 | points(2,2) < 1 | points(2,1) > app.data.ext.xsize | points(2,2) > app.data.ext.xsize
+	    disp('using Area and centroid as calculated automatically');
+	else	
+		s.Centroid=round(points(1,:));
+		
+		rad=sqrt((s.Centroid-points(2,:))*(s.Centroid-points(2,:))');
+		s.Area=pi*rad*rad;
+	end
+
+
+%distance between grain center and rotation axis
+dist=sqrt((size(img1)/2-s.Centroid)*(size(img1)/2-s.Centroid)');
+
+%get the phase offset angle (offangle) correct
+offangle = atan((s.Centroid(1)-size(img1,1)/2)/(s.Centroid(2)-size(img1,2)/2));
+
+if s.Centroid(2) > size(img1,2)/2;%case for lower half of image  
+    offangle = offangle + pi();
+elseif  s.Centroid(1) > size(img1,1)/2;%case for top right
+    offangle = offangle + 2*pi();    
+else %case for top left  
+    offangle = offangle;
+end
+
+%in sino_function params are [amplitude, phase, centre]
+params0=[dist offangle size(img1,1)/2];
+
+%calculate the COMs of grains in the sinogram
+expcom=sum(sino.*repmat([1:size(sino,1)]',1,size(sino,2)))./sum(sino);
+
+%calculate the expected positions of the grain
+calcom= sino_function(params0, theta);
+
+%make a line to show the fit.
+dummytheta=0:0.1:pi();
+dummycom= sino_function(params0, dummytheta);
+
+%show the experimental grain positions
+figure(3); plot(theta,expcom,'bx');
+hold on
+
+plot(dummytheta, dummycom, 'r-');
+
+%now filter out all spots for which the expcom does not lie within half the
+%grain radius of the expected position 
+ind=find(abs(expcom-calcom)<0.4*sqrt(s.Area/pi));
+struct_id=struct_id(ind);
+stack=stack(:,:,ind);
+theta=theta(ind);
+sino=sino(:,ind);
+binsino=binsino(:,ind);
+expcom=expcom(ind);
+z_of_sino=z_of_sino(ind);
+test_image=test_image(:,:,ind);
+%binsino=sino>0.1*max(sino(:));
+
+%mark the selected spots in the sinogram plot
+figure(3);
+plot(theta,expcom,'ko', 'markersize', 10)
+
+%now apply the Theta filter to remove invalid projections
+for i=1:length(struct_id)%now only projections which pass the sino filter
+remove(i)=0;
+if test_image(round(s.Centroid(2)),round(s.Centroid(1)),i)==0%if Theta is not good at the grain center
+    remove(i)=1;
+  end    
+end
+
+dummy=find(remove==1);
+disp('bad projections!:')
+struct_id(dummy)
+struct_id(dummy)=[];
+stack(:,:,dummy)=[];
+theta(dummy)=[];
+sino(:,dummy)=[];
+binsino(:,dummy)=[];
+expcom(dummy)=[];
+test_image(:,:,dummy)=[];
+
+%mark the selected spots in the sinogram plot
+figure(3);
+plot(theta,expcom,'go', 'markersize', 12)
+hold off;
+
+%could use a non-linear fit at this point to refine params0
+ 
+%back project with only the good spots
+img2=backpro(binsino,theta);
+
+
+
+%check with user that grain has been well selected
+figure(1);imshow(img2,[])
+fprintf('click image if ok, or click outside to reject this selection\n');
+point=ginput(1);
+if point(1)< 1 | point(2) <1 | point(1) > size(img2,2) | point(2) >size(img2,1)
+		  disp('skipping spot');
+		  accept=0;
+
+%if grain is good, write grainid into structure and create a vector containing the indices of the NOT replaced spots
+else
+  
+ for i=1:length(struct_id)
+   app.extspot(struct_id(i)).GrainID=grainid;
+   ind_orig(i)=isempty(app.extspot(struct_id(i)).Replaced);
+ end
+ ind_orig=find(ind_orig==1)
+  
+	%calculate the limits of the region to be reconstructed
+	bb=app.extspot(struct_id(1)).BoundingBox;
+	
+  %get z limits
+	zstart=find(mean(sum(stack,3),2),1,'first')-floor(app.data.ext.ysize/2)
+	zend=find(mean(sum(stack,3),2),1,'last')-floor(app.data.ext.ysize/2)
+	zcenter=round((zend+zstart)/2)
+  
+  %get x and y limits
+  %calculate the COM of the most intense spot
+	marker=zeros(size(img2));
+	marker(points(1,2),points(1,1))=1;%same intital point
+	mask=double((img2>0.8*img2(points(1,2),points(1,1))));
+	grain=imreconstruct(marker,mask);
+		
+	s=regionprops(grain,'BoundingBox','Centroid');
+  xgrain=s.Centroid(1);
+  ygrain=s.Centroid(2);
+  xstart = s.BoundingBox(1);
+  ystart = s.BoundingBox(2);
+  xcenter = s.BoundingBox(1)+s.BoundingBox(3)/2;
+  ycenter = s.BoundingBox(2)+s.BoundingBox(4)/2;
+  xend = xstart + s.BoundingBox(3);
+  yend = ystart + s.BoundingBox(4);
+  
+  %add 20% to bounding box for luck
+  if  round(xstart -(s.BoundingBox(3)/5)) > 0
+    xstart = round(xstart - (s.BoundingBox(3)/5));
+  else
+    xstart = 1;
+  end
+  
+  if round(ystart - (s.BoundingBox(4)/5)) > 0
+    ystart = round(ystart - (s.BoundingBox(4)/5));
+  else
+    ystart = 1;
+  end
+  
+  if round(xend + (s.BoundingBox(3)/5)) <= size(img2,1);
+    xend = round(xend + (s.BoundingBox(3)/5));
+  else
+    xend = size(img2,1);
+  end
+  
+  if round(yend + (s.BoundingBox(4)/5)) <= size(img2,2);
+    yend = round(yend + (s.BoundingBox(4)/5));
+  else
+    yend = size(img2,2);
+  end
+    
+ ny = yend-ystart;
+ nx = xend-xstart;
+ nz = zend-zstart;
+
+ y1 = ystart;
+ x1 = xstart;
+ 
+ fprintf('for reconstruct_art_roi:\n z1 = %d, nz = %d, x1 = %d, nx = %d, y1 = %d, ny = %d\n',zstart,nz,x1,nx,y1,ny);
+  %write stack and information about scan
+  
+  disp(sprintf('writing projections for grain %d',grainid));
+  write_stack(stack,grainid);
+  grainname=sprintf('grain%d_',grainid);
+  graindir=sprintf('%s/%s',app.dir,grainname);
+  name=sprintf('%s/%s.mat',graindir,grainname);
+  save(name,'theta','struct_id','ind_orig','stack','zstart','zend','zcenter','x1','nx','y1','ny','ycenter','xgrain','ygrain');
+	grainpos=[xgrain,ygrain,zcenter];
+  grainid=grainid+1;
+end	  
+  
+  
+  
+end
+end
\ No newline at end of file
diff --git a/4_spot_sorting/old/handle_spot_theta_auto.m b/4_spot_sorting/old/handle_spot_theta_auto.m
new file mode 100755
index 0000000000000000000000000000000000000000..35b449f13baf43a2728f043217bcd985e07e4a6c
--- /dev/null
+++ b/4_spot_sorting/old/handle_spot_theta_auto.m
@@ -0,0 +1,274 @@
+function [stack,theta,struct_id,ind_orig,img2,accept,grainpos]=handle_spot_theta_auto(spot_id,grainid)
+
+% function [stack,theta,struct_id,ind_orig,img2,accept]=handle_spot_wolf(spot_id,grainid)
+% 
+% stack:    3D matrix containing the valid projections as determined by the backprojection and sine criterion
+% theta:    vector of the corresponding projection angles [radians] 
+% struct_id vector containing the valid structure entries
+% ind_orig  vetor containing the indices od elements in struct_ind which belong to not replaced spots 
+%             i.e.:  app.extspot(struct_id(ind_orig)).Replaced=[] for all ind_orig
+% img2      backprojection using the valid spots
+
+%add filter to use condition of known valid Theta angles to help...
+
+%try to simplify and automate
+
+
+
+global app
+
+grainpos=[0 0 0];
+%find related spots
+[struct_id,spot_id_vector,omega]=find_family(spot_id);
+[stack,sino,z_of_sino]=read_spots(struct_id);
+
+%which of struct_id vector is the original spot (spot_id)
+index = find(struct_id==spot_id);
+
+%setup the figure
+img1 = zeros(size(sino,1));
+figure;
+imshow(img1, []);
+hold on
+
+%make original spot centre line
+[orig_grad, orig_intersect] = sfMakeBackProLine(spot_id, struct_id, sino, omega);
+%plot original centre line
+tmpx = 1:size(sino,1);
+tmpy = (orig_grad*tmpx) + orig_intersect;
+plot(tmpx, tmpy);
+
+%get allowed TwoTheta data
+tmp=gtnew_calculate_twotheta(4.05,225,19.98);
+tmp=tmp.elements;
+for n=1:length(tmp)
+  twotheta(n)=tmp{n}.centre;
+end
+
+good_points=[];counter=1;
+
+%loop through all spots
+for i=1:length(struct_id)
+if i ~= index %don't need to do original spot
+
+  %make spot centre line
+  [grad, intersect] = sfMakeBackProLine(struct_id(i), struct_id, sino, omega);
+
+  %calculate intersection with original spot line
+  tmpx = -(intersect-orig_intersect)/(grad-orig_grad);
+  tmpy = (orig_grad*tmpx) + orig_intersect;
+  
+  %plot point
+  plot(tmpx, tmpy, 'xr')
+ 
+  %does intersection give good theta angles?  orig and current spots
+  %using grainpos = tmpx, tmpy, calc theta
+ Theta_spot = sfFindAngles(struct_id(i), tmpx, tmpy, z_of_sino(i),  omega(i));
+ Theta_orig = sfFindAngles(struct_id(index), tmpx, tmpy, z_of_sino(index),  omega(index));
+  
+ min_spot_dif = min(abs((twotheta/2)-Theta_spot)./(twotheta/2));
+ min_orig_dif = min(abs((twotheta/2)-Theta_orig)./(twotheta/2));
+ 
+ if (min_spot_dif<0.025 & min_orig_dif<0.025)% if both Thetas good to 2.5%
+   if (tmpx > 0 & tmpx <= size(sino,1) & tmpy > 0 & tmpy <= size(sino,1))% if point lies in image 
+plot(tmpx, tmpy, 'go')%plot point, record in good points
+good_points(counter,1)=tmpx;
+good_points(counter,2)=tmpy;
+good_points(counter,3)=struct_id(i);
+counter=counter+1;
+   end
+ end
+ 
+end
+end
+
+%find grain position from good_points
+if size(good_points,1)>4%need at least 4 spots to proceed...
+x_grain = fminbnd(@(x_grain) sfFindGrain(good_points, x_grain), min(good_points(:,1)), max(good_points(:,1)));
+y_grain = (orig_grad*x_grain) + orig_intersect;  
+plot(x_grain, y_grain, 'x', 'markersize', 20)% plot the chosen center
+
+%find width of original projection
+orig_sino = sino(:,index);
+orig_binsino = orig_sino>0.1*max(orig_sino);
+dummy=find(orig_binsino==1);
+orig_min=min(dummy);
+orig_max=max(dummy);
+proj_radius = (orig_max - orig_min)/2;
+
+%calc distance of intersections from grain position
+good_points(:,4) = sqrt((good_points(:,1)-x_grain).^2+(good_points(:,2)-y_grain).^2);
+dummy = find(good_points(:,4)>proj_radius);
+good_points(dummy, :)=[];%remove intersections far from grain center
+
+%create binsino and omega for good spots only
+good_sino(:,1)=orig_sino; 
+good_omega=omega(index);
+good_stack(:,:,1) = stack(:,:,index);
+good_struct_id(1) = spot_id;
+for j=1:size(good_points,1)
+  tmp = find(struct_id == good_points(j,3));
+  good_sino(:,j+1) = sino(:,tmp);
+  good_omega(j+1) = omega(tmp);
+  good_stack(:,:,j+1) = stack(:,:,tmp);
+  good_struct_id(j+1) = struct_id(tmp);
+end
+struct_id = good_struct_id;
+omega = good_omega;
+stack = good_stack;
+sino = good_sino;
+
+%back project good spots only
+binsino = sino>0.1*max(sino(:));
+img2=backpro(binsino,omega);
+
+%do imreconstruct from centre to threshold grain
+x_grain = ceil(x_grain); y_grain = ceil(y_grain);
+marker=zeros(size(img2));
+marker(y_grain, x_grain)=1;
+mask=double((img2>0.8*img2(y_grain, x_grain)));
+grain=imreconstruct(marker,mask);
+ 	
+%get z limits
+zstart=find(mean(sum(stack,3),2),1,'first')-floor(app.data.ext.ysize/2);
+zend=find(mean(sum(stack,3),2),1,'last')-floor(app.data.ext.ysize/2);
+zcenter=round((zend+zstart)/2);
+
+s=regionprops(grain,'Area','BoundingBox','Centroid');
+  xgrain=s.Centroid(1);
+  ygrain=s.Centroid(2);
+  xstart = s.BoundingBox(1);
+  ystart = s.BoundingBox(2);
+  xcenter = s.BoundingBox(1)+s.BoundingBox(3)/2;
+  ycenter = s.BoundingBox(2)+s.BoundingBox(4)/2;
+  xend = xstart + s.BoundingBox(3);
+  yend = ystart + s.BoundingBox(4);
+  
+  %add 20% to bounding box for luck
+  if  round(xstart -(s.BoundingBox(3)/5)) > 0
+    xstart = round(xstart - (s.BoundingBox(3)/5));
+  else
+    xstart = 1;
+  end
+  
+  if round(ystart - (s.BoundingBox(4)/5)) > 0
+    ystart = round(ystart - (s.BoundingBox(4)/5));
+  else
+    ystart = 1;
+  end
+  
+  if round(xend + (s.BoundingBox(3)/5)) <= size(img2,1);
+    xend = round(xend + (s.BoundingBox(3)/5));
+  else
+    xend = size(img2,1);
+  end
+  
+  if round(yend + (s.BoundingBox(4)/5)) <= size(img2,2);
+    yend = round(yend + (s.BoundingBox(4)/5));
+  else
+    yend = size(img2,2);
+  end
+    
+ ny = yend-ystart;
+ nx = xend-xstart;
+ nz = zend-zstart;
+
+ y1 = ystart;
+ x1 = xstart;
+ 
+ %grainid into structure and create a vector containing the indices of the NOT replaced spots
+   for i=1:length(struct_id)
+   app.extspot(struct_id(i)).GrainID=grainid;
+   ind_orig(i)=isempty(app.extspot(struct_id(i)).Replaced);
+ end
+
+ 
+ fprintf('for reconstruct_art_roi:\n z1 = %d, nz = %d, x1 = %d, nx = %d, y1 = %d, ny = %d\n',zstart,nz,x1,nx,y1,ny);
+  %write stack and information about scan
+  
+  disp(sprintf('writing projections for grain %d',grainid));
+  write_stack(stack,grainid);
+  grainname=sprintf('grain%d_',grainid);
+  graindir=sprintf('%s/%s',app.dir,grainname);
+  name=sprintf('%s/%s.mat',graindir,grainname);
+
+  %probably don't need all of these, and certainly need to rationalise
+  %omega/theta use!
+  
+  save(name,'omega','struct_id','ind_orig','stack','zstart','zend','zcenter','x1','nx','y1','ny','ycenter','xgrain','ygrain');
+	grainpos=[xgrain,ygrain,zcenter];
+    
+figure
+imshow(grain,[])
+
+else
+  disp(sprintf('only %d good points on projection of spot %d - skipping',size(good_points,1),spot_id))
+end
+
+
+ end
+
+
+  function [m, c] = sfMakeBackProLine(spot_id, struct_id, sino, theta)
+%function to return the parameters of a line passing through the proj of a
+%given spot, struct_id is vector of spots in the sinogram, sino.
+index = find(struct_id == spot_id);
+
+%get spot parameters 
+spot_sino=sino(:,index);
+spot_com=(spot_sino'*[1:length(spot_sino)]')/sum(spot_sino);
+spot_omega=theta(index);
+
+%experiment parameters
+centre_of_backproimg_x = size(sino,1)/2;
+centre_of_backproimg_y = size(sino,1)/2;
+
+point=[centre_of_backproimg_x, centre_of_backproimg_y];
+
+%make line parameters
+grad=1/tan(spot_omega);
+
+%dist of com line from centre
+offset_com=spot_com-length(spot_sino)/2;
+%centre point of line though the projection
+point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+
+%put into format y = mx + c
+m = grad;
+c = point(2) - (m*point(1));
+  end
+  
+    function Theta = sfFindAngles(struct_id, grainx, grainy, grainz, omega);
+    global app;
+%calculate Theta angle between grain position (x,y,z) and difspot of
+%struct_id
+    
+xdirect=app.bb.directbeam(1)+app.extspot(struct_id).ExtCentroid(1);
+ydirect=app.bb.directbeam(2)+grainz;
+
+xdiffr=app.extspot(struct_id).Centroid(1);
+ydiffr=app.extspot(struct_id).Centroid(2);
+
+r=sqrt((xdirect-xdiffr)^2+(ydirect-ydiffr)^2);
+
+grain2rot=sqrt((grainx-app.data.ext.xsize/2).^2+(grainy-app.data.ext.xsize/2).^2);
+angle=atan2(app.data.ext.xsize/2-grainy,grainx-app.data.ext.xsize/2);
+
+dz=grain2rot.*sin(-omega+angle)+app.dist/app.pixelsize;
+
+Theta=((atan(r./dz))/2)*180/pi;
+  
+    end
+
+    
+  function output = sfFindGrain(good_points, x_grain)
+%function for fminbnd to find grain position along original projection
+  dif = good_points(:,1)-x_grain;
+  %minimise sum of squares for the closest half of the points, to reduce
+  %effect of outliers
+  dif = abs(dif);
+  dif = sort(dif,1,'descend');
+  tmp = ceil(size(dif,1)/2);
+  dif(1:tmp)=[];
+output = dif'*dif;%sum of squares
+  end
\ No newline at end of file
diff --git a/4_spot_sorting/old_gtFindAngles_360.m b/4_spot_sorting/old_gtFindAngles_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..479d39d95ab9028b5502c49817f123a6959d833a
--- /dev/null
+++ b/4_spot_sorting/old_gtFindAngles_360.m
@@ -0,0 +1,51 @@
+function [Theta,Eta] = gtFindAngles_360(pair_ids, grainx, grainy, grainz);
+global parameters;
+acq=parameters.acq;
+%calculate Theta angle between grain position (x,y,z) and difspot of
+%struct_id
+%struct_id can be a vector...
+%output angles are in degrees
+
+omega=gtGetOmega_360(pair_ids); %if Omega is >180, need to get difspot info from difB database
+
+for i=1:length(pair_ids)
+
+%get extspot properties
+[bb,cent]=gtGetBBProps(pair_ids(i));
+CentroidX=cent(1);
+xdirect(i)=parameters.acq.bb(1) + CentroidX;
+ydirect(i)=parameters.acq.bb(2)+grainz;
+
+%get difspot properties - from A(0-180) if pos, else B (180-360)
+mysqlcmd = sprintf(['select ifnull(%sdifspot.CentroidX,%sdifspot.CentroidX), '...
+  'ifnull(%sdifspot.CentroidY,%sdifspot.CentroidY) '...
+  'from %s left join %sdifspot on difAID=%sdifspot.difspotID '...
+  'left join %sdifspot on difBID=%sdifspot.difspotID '...
+  'where %s.pairID=%d'],...
+  acq.difA_name, acq.difB_name,...
+  acq.difA_name, acq.difB_name,...
+  acq.pair_tablename,  acq.difA_name, acq.difA_name,...
+  acq.difB_name, acq.difB_name,...
+  acq.pair_tablename,pair_ids(i));
+  
+[xdiffr(i),ydiffr(i)]=mym(mysqlcmd);
+
+end
+
+omega=omega*pi/180;%convert to radians
+
+r=sqrt((xdirect-xdiffr).^2+(ydirect-ydiffr).^2);
+
+grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+dz=grain2rot.*sin(-omega+angle)+parameters.acq.dist/parameters.acq.pixelsize;
+
+Theta=((atan(r./dz))/2)*180/pi;
+
+Eta=atan2((xdiffr-xdirect),(ydirect-ydiffr))*180/pi;
+
+dummy= find(Eta<0);
+  Eta(dummy)=360+Eta(dummy);
+
+end
diff --git a/4_spot_sorting/old_gtForwardSimulate2_360.m b/4_spot_sorting/old_gtForwardSimulate2_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..e48083d62e3d0270bba7d3b0d588966c20de11d0
--- /dev/null
+++ b/4_spot_sorting/old_gtForwardSimulate2_360.m
@@ -0,0 +1,180 @@
+%forward simulation - search database for missed spots...
+%modify to simplify, to use as part of gtHandleSpot2 process, before a
+%grain%d_.mat is written.
+%Arguments: grainCentroid [x,y,z], r-vector, existing struct_ids
+%returns a list of struct_ids to add to the grain - extspot/difspot pairs
+%where both spots are in valid position, and size is okay also.
+
+%360 case - need to be able to searc in two databases
+
+%keep in a list of spots where the difspot matchs but the extspot is in the
+%wrong place - possible rerun autofind cases
+
+%Marcelo, Andy
+%31/10/2006
+
+
+function ext_possibles = gtForwardSimulate2_360(grainCentroid, R_vector, prior_pair_ids)
+
+%load data 
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+acq=parameters.acq;
+%get the root of the pair name
+pair_name=parameters.acq.pair_tablename;
+pair_name(end-8:end)=[];
+
+%get ready to ask the database questions
+dif_possibles=[];%possible difspot struct_ids
+ext_possibles=[];%possible difspot/extspot pairs struct_ids - ie, those which can go straight into grain
+
+%get the mean difspot, extspot sizes for the current spots in the grain
+dif_Xsize=[]; dif_Ysize=[];ext_Xsize=[]; ext_Ysize=[];
+for i=1:length(prior_pair_ids)
+
+  mysqlcmd = sprintf(['select ifnull(%sdifspot.BoundingBoxXsize,%sdifspot.BoundingBoxXsize), '...
+    'ifnull(%sdifspot.BoundingBoxYsize,%sdifspot.BoundingBoxYsize) '...
+    'from %s left join %sdifspot on difAID=%sdifspot.difspotID '...
+    'left join %sdifspot on difBID=%sdifspot.difspotID '...
+    'where %s.pairID=%d'],...
+    acq.difA_name, acq.difB_name,...
+    acq.difA_name, acq.difB_name,...
+    acq.pair_tablename,  acq.difA_name, acq.difA_name,...
+    acq.difB_name, acq.difB_name,...
+    acq.pair_tablename,prior_pair_ids(i));
+  [dif_Xsize(i), dif_Ysize(i)]=mym(mysqlcmd);
+
+  [ext_bb,ext_cent]=gtGetBBProps(prior_pair_ids(i));
+  ext_Xsize(i) = ext_bb(3);
+  ext_Ysize(i) = ext_bb(4);
+  
+end
+dif_Xsize=mean(dif_Xsize);
+dif_Ysize=mean(dif_Ysize);
+ext_Xsize=mean(ext_Xsize);
+ext_Ysize=mean(ext_Ysize);
+
+%get all possible hkls
+if parameters.acq.spacegroup == 225
+  hkl=[1 1 1 ; 0 0 2 ; 2 2 0 ; 3 1 1];
+  all_hkls = [];
+  for i = 1:size(hkl,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkl(i,:))];
+  end
+  %normalise hkl vectors
+  tmp = sqrt(sum((all_hkls.*all_hkls),2));
+  normalised_hkls = all_hkls./(repmat(tmp,1,3));
+else
+  disp('Sorry - only FCC currently supported')
+end
+
+%produce all possible plane normals using R_vector
+g = Rod2g(R_vector);
+warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+all_normals = (g * normalised_hkls')';
+%all_normals = (inv_g * all_hkls')'; %should be like this?
+
+%produce output list - where do we expect dif and ext spots for this
+%grain?
+output=[];
+for i=1:size(all_normals,1)
+  try  % not all normals result in diffraction
+  [image,xdirect,ydirect,xdiffr,ydiffr] = gtPredictPositions2(all_normals(i,:), all_hkls(i,:), grainCentroid, 0);
+  tmp = [image' xdirect' ydirect' xdiffr' ydiffr'];
+  output = [output; tmp];
+  end
+end
+
+
+%interogate database to find the spots predicted in output
+%find any missing extspot/difspot pairs,
+%or to find misassigned extspot/difspot - ie when difspot can be found in
+%the database, but the extspot is wrong.
+%hopefully find most of the spot pairs already assigned to grain!
+
+%convert the extspot positions to direct beam coordinates...
+output(:,2) = output(:,2) - parameters.acq.bb(1);
+output(:,3) = output(:,3) - parameters.acq.bb(2);
+
+
+%produce a list of possibles - difspots that might belong to the grain.
+for i=1:size(output,1)  
+  %is the predicted difspot likely to clip the edge of the detector?
+  %if so allow greater freedom for matching centroid
+  dif_Xsearch=0.35; dif_Ysearch=0.35; %fraction of spot size allowed
+  ext_Xsearch=0.35; ext_Ysearch=0.1; %clipping doesn't effect extspots, vertical size should be invarient
+  if (output(i,4)<(dif_Xsize/2) | output(i,4)>parameters.acq.xdet-(dif_Xsize/2))
+  dif_Xsearch=0.6;
+  end
+  if (output(i,5)<(dif_Ysize/2) | output(i,5)>parameters.acq.ydet-(dif_Ysize/2))
+  dif_Ysearch=0.6;
+  end
+  
+  %find possible difspots - main search
+  %"get difspotID,grainID,MaxImage where MaxImage within 10, difspot
+  %Centroid within search range in x and y, and difspot size with search
+  %range in x and y, order by size match to spots already in grain and return best only"
+  %360 - search the correct database - if omega>nproj, in B
+  warning('grain rustling disabled!!!')
+	if output(i,1)>=parameters.acq.nproj
+    dif_name = parameters.acq.difB_name;
+    difID='difBID'; %for mysql search statement
+    image_number=output(i,1)-parameters.acq.nproj;
+  else
+    dif_name = parameters.acq.difA_name;
+    difID='difAID';
+    image_number=output(i,1);
+  end
+  
+  
+  query=sprintf(['select %s.pairID, %s.grainID, MaxImage from '...
+    '%sdifspot inner join %s on difspotID=%s where '...
+    '(%d between StartImage-10 and EndImage+10) and isnull(%s.grainID)'...
+     'and (abs(%sdifspot.CentroidX-%d)/%d)<%f '...
+     'and (abs(%sdifspot.CentroidY-%d)/%d)<%f '...
+     'and (abs(BoundingBoxXsize-%d)/%d)<%f and (abs(BoundingBoxYsize-%d)/%d)<%f '...
+     'order by ((abs(BoundingBoxXsize-%d)/%d)+(abs(BoundingBoxYsize-%d)/%d)) limit 1'],...
+     acq.pair_tablename, acq.pair_tablename,...
+     dif_name,acq.pair_tablename,difID,...
+     image_number, acq.pair_tablename,...
+     dif_name,output(i,4),dif_Xsize,dif_Xsearch,...
+     dif_name,output(i,5),dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Xsearch,dif_Ysize,dif_Ysize,dif_Ysearch,...
+     dif_Xsize,dif_Xsize,dif_Ysize,dif_Ysize);
+   [pairID,grainID,MaxImage] = mym(query);
+  
+  %has this difspot already been assigned to this grain?
+  if (~isempty(pairID) && isempty(find(prior_pair_ids==pairID)))
+    
+    %record as a possible difspot to be added
+    dif_possibles = [dif_possibles pairID];
+    
+    %now query the corresponding extspot - has this also a valid size 
+    %and position for this grain?
+    [ext_bb,ext_cent]=gtGetBBProps(PairID);
+    test_Xpos=ext_cent(1);
+    test_Ypos=ext_cent(2);
+    test_Xsize=ext_bb(3);
+    test_Ysize=ext_bb(4);
+    
+   if ( (abs(test_Xpos-output(i,2))/ext_Xsize)<ext_Xsearch & (abs(test_Ypos-output(i,3))/ext_Ysize)<ext_Ysearch & ...
+       (abs(test_Xsize-ext_Xsize)/ext_Xsize)<ext_Xsearch &  (abs(test_Ysize-ext_Ysize)/ext_Ysize)<ext_Ysearch )
+    
+    ext_possibles = [ext_possibles pairID];
+   
+   end % if extspot good?
+  end  % if a possible difspot found
+end    % loop over predicted spot positions
+  
+
+
+
+
+
+
+
+
+
+
diff --git a/4_spot_sorting/old_gtGetSummedExtSpot_360.m b/4_spot_sorting/old_gtGetSummedExtSpot_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..83b6f42f58989c1c8044857c0d5e4aa1bea1b956
--- /dev/null
+++ b/4_spot_sorting/old_gtGetSummedExtSpot_360.m
@@ -0,0 +1,108 @@
+function im=gtGetSummedExtSpot_360(pair_id)
+% returns the summed full extinction spot image
+% conversion to database complete
+%360 - in using the difspot outline, get the right one!
+
+global parameters;
+
+if isempty(parameters)
+  disp('Loading parameter file')
+  load('parameters.mat');
+end
+acq=parameters.acq;
+
+%get the root of the pair name
+pair_name=parameters.acq.pair_tablename;
+pair_name(end-8:end)=[];
+
+warning('contains proper bodged bb faffing, make nice after rerunning autofind')
+
+[bb,tmp]=gtGetBBProps(pair_id);%get the better bounding box
+
+%get snake if possible, else use difspot silhouette
+if mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',...
+    pair_name,...
+    pair_id)) == true;
+ 
+%put snake relative to boundingbox
+mysqlcmd=sprintf('select x,y from %ssnakes where snakeID=%d',...
+  pair_name,pair_id);
+[snakex,snakey]=mym(mysqlcmd);
+snakex = snakex - floor(bb(1));
+snakey = snakey - floor(bb(2));
+mask = poly2mask(snakex, snakey, bb(4), bb(3));
+
+else
+  disp('Not using snake')
+  %if we don't have a snake
+  summeddif=gtGetSummedDifSpot_360(pair_id);
+
+%change all this - save snake input in table during autofind, and reread
+%after.  This recreation is stupid
+summeddif_bw=summeddif>0.25*max(summeddif(:));
+summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+mask=bwmorph(summeddif_bw,'dilate',1);
+%%crop mask here
+tmp2=regionprops(double(mask),'BoundingBox');
+tmp2=tmp2.BoundingBox;
+  
+tmp2=ceil(tmp2);%gt convention
+
+mask = gtCrop(mask,tmp2);
+bb(3:4)=tmp2(3:4);%change this!
+
+
+end
+
+%put BoundingBox into coordinates of the full image
+%not needed if using ext images, only if using the middle bit of fulls
+%bb(1) = ceil(bb(1) + parameters.acq.bb(1));
+%bb(2) = ceil(bb(2) + parameters.acq.bb(2));
+
+
+  mysqlcmd = sprintf(['select !isnull(difAID),ifnull(%sdifspot.ExtStartImage,%sdifspot.ExtStartImage), '...
+    'ifnull(%sdifspot.ExtEndImage,%sdifspot.ExtEndImage) '...
+    'from %s left join %sdifspot on difAID=%sdifspot.difspotID '...
+    'left join %sdifspot on difBID=%sdifspot.difspotID '...
+    'where %s.pairID=%d'],...
+    acq.difA_name, acq.difB_name,...
+    acq.difA_name, acq.difB_name,...
+    acq.pair_tablename,  acq.difA_name, acq.difA_name,...
+    acq.difB_name, acq.difB_name,...
+    acq.pair_tablename,pair_id);
+  
+[A,first,last]=mym(mysqlcmd);
+
+if A %if the first half of the scan
+  name=parameters.acq.difA_name;
+  disp('reading difspot info from A')
+else
+  name=parameters.acq.difB_name;
+  disp('reading difspot info from B')
+end
+path=sprintf('../%s/',name);
+
+%if mask area extends outside acq.bb
+if bb(2)+bb(4)>=acq.bb(4) %correct if search bb extends beyond acq.bb
+  bb(4)=acq.bb(4)-bb(2)-1;
+end
+if bb(1)+bb(3)>=acq.bb(3) %correct if search bb extends beyond acq.bb
+  bb(3)=acq.bb(3)-bb(1)-1;
+end
+
+
+%disp([num2str(last-first+1) ' images in sum'])
+%read ext images from the relevent half of the scan
+im=zeros(bb(4), bb(3));
+for i=first:last
+  im = im + edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',path,i), bb);
+end
+
+%apply mask , either from snake or from difspot silhouette
+imsize=size(im);
+mask((imsize(1)+1):end,:)=[];%remove any mask extending outside acq.bb
+mask(:,(imsize(2)+1):end)=[];
+im = im.*mask;
+
+
diff --git a/4_spot_sorting/old_gtPredictPositions.m b/4_spot_sorting/old_gtPredictPositions.m
new file mode 100755
index 0000000000000000000000000000000000000000..47f059ede57499ca51e0a3691e132e183a57b328
--- /dev/null
+++ b/4_spot_sorting/old_gtPredictPositions.m
@@ -0,0 +1,94 @@
+%predict positions of spots in images
+%Marcelo, Andy, 30/10
+
+function [images,x_direct,y_direct,x_diffr,y_diffr] = gtPredictPositions(normal, hkl, grainid, plot_flag)
+%take a plane normal, its hkl type (to calc Theta), and a grainID (to calc
+%grain position in sample), and returns lists of max images, and x and y
+%positions of the ext and dif spots.
+%plot_flag=1 plots images
+
+%load data 
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+grainx = grain_data.x1 + (grain_data.nx/2);
+grainy = grain_data.y1 + (grain_data.ny/2);
+zcenter = grain_data.zcenter;
+
+%use gtPredictAngles to get Theta, Eta, Omega - note gives a pair of angles
+[Theta,Eta,Omega] = gtPredictAngles(normal, hkl);
+%convert to radians
+Theta=Theta*pi/180;
+Eta=Eta*pi/180;
+Omega=Omega*pi/180;
+
+%get only Omegas within 0-180 degrees
+if parameters.acq.type=='180degree'
+  %disp('180 degree data')
+  dummy=find(Omega<0 | Omega>pi);
+  Theta(dummy)=[];
+  Eta(dummy)=[];
+  Omega(dummy)=[];
+end
+
+%deal with grain position
+grain2rot=sqrt((grainx-parameters.acq.bb(3)/2).^2+(grainy-parameters.acq.bb(3)/2).^2);
+angle=atan2(parameters.acq.bb(3)/2-grainy,grainx-parameters.acq.bb(3)/2);
+
+%extinction spot position
+% y correction with the omega offset in the sample, that is a value to be added to X in the screen
+x_direct = parameters.acq.bb(1)+(parameters.acq.bb(3)/2)+(grain2rot.*cos(-Omega+angle)); 
+y_direct(1:length(Omega)) = parameters.acq.bb(2)+zcenter;
+
+%diffraction spot position
+% radius on the screen (in pixels) with the corrected distance from the sample to the
+% detector (y in sample coordinates) with the omega offset
+radius = tan(2*Theta).*((parameters.acq.dist/parameters.acq.pixelsize)+(grain2rot*sin(-Omega+angle)));
+x_diffr =  x_direct + (radius.*sin(Eta)); % spot position (x position) in the screen 
+y_diffr = y_direct - (radius.*cos(Eta)); % vertical coordinate on the screeen
+
+
+%get full image
+	images = round((Omega/pi)*parameters.acq.proj);
+
+  %plot results on full images
+  if plot_flag
+  
+for i=1:size(Omega,2)
+
+	%convert Omega to image number
+
+	start_image = images(i)-5;
+	if start_image<0
+		start_image=0;
+	end
+	end_image = images(i)+5;
+	if end_image>5999
+		end_image=5999;
+	end
+	
+  start_image
+  end_image
+	
+	full=zeros(parameters.acq.xdet,parameters.acq.ydet);
+	for im=start_image:end_image
+		full=full+edf_read(sprintf('1_preprocessed/full/full%04d.edf',im));
+	end
+	full=full./(end_image-start_image+1);
+
+  figure
+	imshow(full,[]);
+	hold on;
+	plot(x_direct(i),y_direct(i),'og')
+	plot(x_diffr(i),y_diffr(i),'ro')
+  drawnow
+  disp('click image to close and see next spot (if exists...)')
+  k=waitforbuttonpress;
+  
+end
+
+  end
+  
diff --git a/4_spot_sorting/old_gtReadSpots_360.m b/4_spot_sorting/old_gtReadSpots_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..cb221dc1c668b6153ebb74325132d32863fe3185
--- /dev/null
+++ b/4_spot_sorting/old_gtReadSpots_360.m
@@ -0,0 +1,60 @@
+function [stack,sino,z_of_sino] = gtReadSpots_360(orig_pair_id, pair_ids)
+% function [stack,sino,z_of_sino,varargout]=read_spots(struct_ids)
+% produce sinogram of all spots in struct_ids vector at the mid-height
+% of the seed spot (spot_id).
+% optional output argument orig holds original projection (Max)images for verification
+%could add orig, not currently supported
+%for the 360 degree, pair table case
+%database enable!
+
+
+
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(pair_ids));
+
+%get pair database name
+pair_name=parameters.acq.pair_tablename;
+pair_name(end-8:end)=[];
+
+z_of_sino = mym(sprintf(...
+  'select ceil(Yorigin + (Ysize/2)) from %sbb inner join %sbboxes on %sbb.bbID = %sbboxes.bboxID where %sbb.extspotID = %d',...
+  pair_name,...
+  pair_name,...
+  pair_name,...
+  pair_name,...
+  pair_name,...
+  orig_pair_id));
+
+Omega = gtGetOmega_360(pair_ids);%in degrees
+
+
+%read images to produce sinogram at position z_of_sino
+for i=1:length(pair_ids)
+  
+  [BoundingBox,tmp]=gtGetBBProps(pair_ids(i));
+  im = gtGetSummedExtSpot_360(pair_ids(i));
+  
+  warning('bodge - change zero origin bounding boxes in gtReadSpots - fix in autofind')
+  if BoundingBox(1)==0
+    BoundingBox(1)=1;
+  end
+  if BoundingBox(2)==0
+    BoundingBox(2)=1;
+  end
+  
+  %place in stack
+  stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  
+  stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+  %read sino from stack
+  sino(:,i) = stack(z_of_sino, :, i);
+
+end
+
+end
diff --git a/4_spot_sorting/plot_rodrigues.m b/4_spot_sorting/plot_rodrigues.m
new file mode 100755
index 0000000000000000000000000000000000000000..37b44ed4f8f8b59e2b05c1832ac6c7d6a0e8f518
--- /dev/null
+++ b/4_spot_sorting/plot_rodrigues.m
@@ -0,0 +1,116 @@
+function max_coords=plot_rodrigues(plane_normal,hkl)
+
+%plane_normal = list of plane normals in sample coords
+%hkl a vector of reflection type eg [1 1 1; 0 0 2; 2 2 0 etc]
+
+save_plot=[];
+figure;
+hold on;
+
+for j=1:size(plane_normal,1)
+
+%________calculate h vector___________
+%from eq (3.7) in Poulsen
+%B is identity matrix in cubic material
+%gtnewGetReflections returns matrix of all reflections related by symmetry
+%to hkl, using Riso GetCubicSymOp.m
+
+hkl_reflections = gtGetReflections(hkl(j,:));
+
+for i=1:length(hkl_reflections)
+h = hkl_reflections(i,:); 
+h = h./(sqrt(h*h'));
+
+%________calculate y vector___________
+% y is the normalised scattering vector in sample system
+% == plane normal
+y = plane_normal(j,:);
+
+
+%_____calculate rodrigues space vector_____
+%formulae (3.16), (3.17) in Poulsen
+
+r_zero = cross(h,y)./(1+(dot(h,y)));
+r_direction = (h + y)./(1+(dot(h,y)));
+
+%max line length needed ~1.5, say +-1.5 for saftey
+t=(-1.5:0.01:1.5)';
+r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+
+
+
+%remove everything outside of a fundamental region (assume cube)
+lim=sqrt(2)-1;
+for i=1:3
+dummy=find(r_plot(:,i)<-lim | r_plot(:,i)>lim);
+r_plot(dummy,:)=[];
+end
+
+%collect all plot data for analysis
+save_plot=[save_plot; r_plot];
+
+
+
+%____plot______
+  if hkl(j,:)*hkl(j,:)'==[1 1 1]*[1 1 1]' %(111) - red
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+  
+  elseif hkl(j,:)*hkl(j,:)'==[0 0 2]*[0 0 2]' %(002) - blue
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+
+  elseif hkl(j,:)*hkl(j,:)'==[2 2 0]*[2 2 0]' %(220)  - green
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+
+  elseif hkl(j,:)*hkl(j,:)'==[3 1 1]*[3 1 1]' %(311)   -  black
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+
+  end
+
+
+end%loop through all hkl variants
+
+%uncomment this to see line by line in rodrigues space.
+%k=waitforbuttonpress %can watch as each is plotted in turn
+
+end%loop through all normals
+
+axis equal
+
+
+%find intersections
+
+inc=0.04;%scan space in these steps (size of the sampling element)
+max_score=0;
+max_coords=[0 0 0];
+score=[];
+count=1;
+for i=-lim:inc:lim
+for j=-lim:inc:lim
+for k=-lim:inc:lim
+  
+dummy = find(save_plot(:,1)>i & save_plot(:,1)<(i+inc) &save_plot(:,2)>j & save_plot(:,2)<(j+inc) &save_plot(:,3)>k & save_plot(:,3)<(k+inc));
+score(count)=length(dummy);
+if (score(count)>max_score)
+  max_score=score;
+  max_coords=[i j k];
+end
+
+count=count+1;
+end
+end
+end
+
+max_score;
+max_coords;
+element = inc*[0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1];
+max_element = repmat(max_coords,8,1)+element;
+max_coords = max_coords+0.5*[inc inc inc];%this is the approximate solution
+
+plot3(max_element(:,1),max_element(:,2),max_element(:,3),'go')
+plot3(max_coords(:,1),max_coords(:,2),max_coords(:,3),'co')
+
+
+
+
+
+
diff --git a/4_spot_sorting/plot_rodrigues_consistancy.m b/4_spot_sorting/plot_rodrigues_consistancy.m
new file mode 100755
index 0000000000000000000000000000000000000000..a23fe21628671016afed4a0c63d87006034f02a2
--- /dev/null
+++ b/4_spot_sorting/plot_rodrigues_consistancy.m
@@ -0,0 +1,218 @@
+function [pof, good_plnorms, dsqr]=plot_rodrigues_consistancy(plane_normal,hkl,plot_flag)
+
+%plane_normal = list of plane normals in sample coords
+%hkl a vector of reflection type eg [1 1 1; 0 0 2; 2 2 0 etc]
+%plot_flag: 1 to plot figure, 0 to not plot anything
+%add a consistancy check - which plane normals don't join at the
+%intersection?
+
+inc=0.1;                % scan space in these steps (size of the sampling element) for coarse solution
+inc_ext=1.1*inc;         % extended space to determine precise point of intersection; (should be larger than 0.87*inc)
+consistancy_test=0.2;   %select those lines within distance consistancy_test*inc of the intersection (was 0.2)
+
+save_plot=[];
+
+if plot_flag
+figure;
+hold on;
+end
+
+lines.cor=[];   %[...; r_zero r_direction; ...] equations
+lines.plnorm=[];   %[...; j; ...] which plane normal
+
+for j=1:size(plane_normal,1) % loop of plane_normals
+
+%________calculate h vector___________
+%from eq (3.7) in Poulsen
+%B is identity matrix in cubic material
+%gtnewGetReflections returns matrix of all reflections related by symmetry
+%to hkl, using Riso GetCubicSymOp.m
+
+hkl_reflections = gtGetReflections(hkl(j,:));
+if size(hkl_reflections,1)~=1%skip if hkl = [0 0 0]
+  
+for i=1:length(hkl_reflections) % loop of hkl reflections
+h = hkl_reflections(i,:); 
+h = h./(sqrt(h*h'));
+
+%________calculate y vector___________
+% y is the normalised scattering vector in sample system
+% == plane normal
+y = plane_normal(j,:);
+
+
+%_____calculate rodrigues space vector_____
+%formulae (3.16), (3.17) in Poulsen
+
+r_zero = cross(h,y)./(1+(dot(h,y)));
+r_direction = (h + y)./(1+(dot(h,y)));
+
+%collect plot data
+lines.cor=[lines.cor; r_zero r_direction];
+lines.plnorm=[lines.plnorm; j];
+
+%max line length needed ~1.5, say +-1.5 for saftey
+t=(-1.5:0.01:1.5)';
+r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+
+%remove everything outside of a fundamental region (assume cube)
+lim=sqrt(2)-1;
+for i=1:3
+dummy=find(r_plot(:,i)<-lim | r_plot(:,i)>lim);
+r_plot(dummy,:)=[];
+end
+
+%remove the corners of the truncated cube
+lim=1/sqrt(3);
+%calculate distance of each point along each <111> directions
+vector=[1 1 1]./sqrt(3);%normalise
+vector=repmat(vector,size(r_plot,1),1);
+tmp = sum( ((abs(r_plot)).*vector),2); %projections along <111>
+dummy=find(tmp>lim);
+length(dummy);
+r_plot(dummy,:)=[];
+
+
+%collect all plot data for analysis
+save_plot=[save_plot; r_plot];
+
+
+%____plot______
+if plot_flag
+  if all(hkl(j,:)==[1 1 1]) %(111) - red
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+  elseif all(hkl(j,:)==[1 1 0]) %(110) - cyan - BCC
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'c');
+  elseif all(hkl(j,:)==[0 0 2]) %(002) - blue
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+  elseif all(hkl(j,:)==[2 1 1]) %(110) - magenta - BCC
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+  elseif all(hkl(j,:)==[2 2 0]) %(220)  - green
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+  elseif all(hkl(j,:)==[3 1 1]) %(311)   -  black
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+  end
+end
+
+end%loop through all hkl variants
+end%if hkl is okay (skip hkl = [0 0 0])
+
+%uncomment this to see line by line in rodrigues space.
+%k=waitforbuttonpress %can watch as each is plotted in turn
+
+end%loop through all normals
+
+if plot_flag
+axis equal
+end
+
+
+%find intersections
+lim=sqrt(2)-1;
+max_score=0;
+max_coords=[0 0 0];
+score=[];
+count=1;
+for i=-lim:inc:lim
+for j=-lim:inc:lim
+for k=-lim:inc:lim
+  
+dummy = find(save_plot(:,1)>i & save_plot(:,1)<(i+inc) &save_plot(:,2)>j & save_plot(:,2)<(j+inc) &save_plot(:,3)>k & save_plot(:,3)<(k+inc));
+score(count)=length(dummy);
+if (score(count)>max_score)
+  max_score=score;
+  max_coords=[i j k];
+end
+
+count=count+1;
+end
+end
+end
+
+max_score;
+max_coords;
+element = inc*[0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1];
+max_element = repmat(max_coords,8,1)+element;
+max_coords = max_coords+0.5*[inc inc inc]; %this is the approximate solution
+
+
+
+
+if plot_flag
+  plot3(max_element(:,1),max_element(:,2),max_element(:,3),'go')
+  plot3(max_coords(:,1),max_coords(:,2),max_coords(:,3),'co')
+end
+
+%Peter's bit - more precise handling of intersections
+% Determine precise point of intersection inside the sampling element
+
+%normalise the r_direction part of the line equations
+%note that it is necessary to normalise vectors for the distance calculations to
+%work!
+lines.cor=normlinedir(lines.cor);
+
+line_cand.cor=[];%line equations which pass close to max_coords
+line_cand.plnorm=[];%to which plane normal (struct_id entry) does line belong - to ensure only one line from each normal
+
+% pick lines which pass close to the sampling element: candidate lines
+distances=pointtolinedist(max_coords,lines.cor);
+dummy=find(distances< inc_ext);
+line_cand.cor = lines.cor(dummy,:);
+line_cand.plnorm = lines.plnorm(dummy);
+
+
+% If more than one line from a given plane is present in the set, then choose the one that fits the best.
+pof_prel=pofintersectexp(line_cand.cor)'; %initial least squares best intersection
+
+% Alternative (cleaner!) loop to find the closest line from a given plane
+% to the point of intersection, if more than one is present
+  distances=pointtolinedist(pof_prel, line_cand.cor);%distance from each candidate line to point
+dummy2=[];%list of lines to delete
+for k=1:size(plane_normal,1)
+  dummy=find(plane_normal==k);
+  if length(dummy)>2%if more than one line, delete all but the closest
+    %- make a list of those to delete
+    dummy2 = [dummy2 find(distances~=min(distances(dummy)) & line_cand.plnorm ==k)];
+  end
+end
+line_cand.cor(dummy2,:)=[];%do the deletion
+line_cand.plnorm(dummy2,:)=[];%do the deletion
+
+%line_cand now contains information only about lines which pass near the
+%approx intersection, and only the best line arising from each plane
+%normal
+
+%repeat loop, to try and choose more precisely
+pof_prel=pofintersectexp(line_cand.cor)'; %least squares best intersection
+
+%find distances of remaining lines to point
+distances=pointtolinedist(pof_prel, line_cand.cor);%distance from each candidate line to point
+test_distance = consistancy_test*inc;
+dummy2=find(distances>test_distance);
+
+%%display the distances and which plane normals they come from
+%distances
+%line_cand.plnorm
+
+line_cand.cor(dummy2,:)=[];%do the deletion
+line_cand.plnorm(dummy2,:)=[];%do the deletion
+
+
+%%[line_cand.cor,line_cand.plnorm]
+
+%final least squares fit with good lines only, display results
+max_coords;
+pof_prel;
+pof=pofintersectexp(line_cand.cor)'
+dsqr=pointtolinedistsqrsum(max_coords, line_cand.cor)
+
+%consistancy check part
+good_plnorms = 1:size(plane_normal,1);%index of plane normals
+good_plnorms = ismember(good_plnorms,line_cand.plnorm);
+
+
+if plot_flag
+  plot3(pof(1),pof(2),pof(3),'mo','markersize',25);
+  plot3(pof(1),pof(2),pof(3),'m*','markersize',25);
+end
+
diff --git a/4_spot_sorting/plot_rodrigues_consistancy_grain.m b/4_spot_sorting/plot_rodrigues_consistancy_grain.m
new file mode 100755
index 0000000000000000000000000000000000000000..fa19537fdc883c3defdf8c290da98c77feccfe55
--- /dev/null
+++ b/4_spot_sorting/plot_rodrigues_consistancy_grain.m
@@ -0,0 +1,257 @@
+function [read_out, pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_grain(grainids, plot_flag)
+
+%plane_normal = list of plane normals in sample coords
+%hkl a vector of reflection type eg [1 1 1; 0 0 2; 2 2 0 etc]
+%plot_flag: 1 to plot figure, 0 to not plot anything
+%add a consistancy check - which plane normals don't join at the
+%intersection?
+
+%grain - tool for looking at grains/twins post reconstruction.  Given one or more
+%grainids, do the consistancy check.
+
+inc=0.03;                % scan space in these steps (size of the sampling element) for coarse solution
+inc_ext=1.1*inc;         % extended space to determine precise point of intersection; (should be larger than 0.87*inc)
+consistancy_test=0.2;   %select those lines within distance consistancy_test*inc of the intersection (was 0.2)
+
+save_plot=[];
+
+if isempty(plot_flag)
+plot_flag=1;%always plot
+end
+
+
+%read in data
+plane_normal=[];
+hkl=[];
+read_out=[];
+for i=grainids
+  tmp=load(sprintf('4_grains/grain%d_/grain%d_.mat', i, i), 'plane_normal', 'hkl', 'index');
+  plane_normal=[plane_normal; tmp.plane_normal(find(tmp.index), :)];%try using only selected reflections
+  hkl=[hkl; tmp.hkl(find(tmp.index), :)];%try using only selected reflections
+  read_out=[read_out length(find(tmp.index))];
+end
+
+
+[pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test(plane_normal,hkl,plot_flag)  
+    
+
+good_plnorms2=good_plnorms;
+
+for i=1:length(read_out)
+  tmp=good_plnorms2(1:read_out(i));
+  good_plnorms2(1:read_out(i))=[];
+  read_out(i)=length(find(tmp))/length(tmp);
+end
+
+
+
+
+% lines.cor=[];   %[...; r_zero r_direction; ...] equations
+% lines.plnorm=[];   %[...; j; ...] which plane normal
+% 
+% for j=1:size(plane_normal,1) % loop of plane_normals
+% 
+% %________calculate h vector___________
+% %from eq (3.7) in Poulsen
+% %B is identity matrix in cubic material
+% %gtnewGetReflections returns matrix of all reflections related by symmetry
+% %to hkl, using Riso GetCubicSymOp.m
+% 
+% hkl_reflections = gtGetReflections(hkl(j,:));
+% if size(hkl_reflections,1)~=1%skip if hkl = [0 0 0]
+%   
+% for i=1:length(hkl_reflections) % loop of hkl reflections
+% h = hkl_reflections(i,:); 
+% h = h./(sqrt(h*h'));
+% 
+% %________calculate y vector___________
+% % y is the normalised scattering vector in sample system
+% % == plane normal
+% y = plane_normal(j,:);
+% 
+% 
+% %_____calculate rodrigues space vector_____
+% %formulae (3.16), (3.17) in Poulsen
+% 
+% r_zero = cross(h,y)./(1+(dot(h,y)));
+% r_direction = (h + y)./(1+(dot(h,y)));
+% 
+% %collect plot data
+% lines.cor=[lines.cor; r_zero r_direction];
+% lines.plnorm=[lines.plnorm; j];
+% 
+% %max line length needed ~1.5, say +-1.5 for saftey
+% t=(-1.5:0.01:1.5)';
+% r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+% 
+% %remove everything outside of a fundamental region (assume cube)
+% lim=sqrt(2)-1;
+% for i=1:3
+% dummy=find(r_plot(:,i)<-lim | r_plot(:,i)>lim);
+% r_plot(dummy,:)=[];
+% end
+% 
+% %remove the corners of the truncated cube
+% lim=1/sqrt(3);
+% %calculate distance of each point along each <111> directions
+% vector=[1 1 1]./sqrt(3);%normalise
+% vector=repmat(vector,size(r_plot,1),1);
+% tmp = sum( ((abs(r_plot)).*vector),2); %projections along <111>
+% dummy=find(tmp>lim);
+% length(dummy);
+% r_plot(dummy,:)=[];
+% 
+% 
+% %collect all plot data for analysis
+% save_plot=[save_plot; r_plot];
+% 
+% 
+% %____plot______
+% if plot_flag
+%   if all(hkl(j,:)==[1 1 1]) %(111) - red
+%   plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+%   elseif all(hkl(j,:)==[1 1 0]) %(110) - cyan - BCC
+%   plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'c');
+%   elseif all(hkl(j,:)==[0 0 2]) %(002) - blue
+%   plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+%   elseif all(hkl(j,:)==[2 1 1]) %(110) - magenta - BCC
+%   plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+%   elseif all(hkl(j,:)==[2 2 0]) %(220)  - green
+%   plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+%   elseif all(hkl(j,:)==[3 1 1]) %(311)   -  black
+%   plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+%   end
+% end
+% 
+% end%loop through all hkl variants
+% end%if hkl is okay (skip hkl = [0 0 0])
+% 
+% %uncomment this to see line by line in rodrigues space.
+% %k=waitforbuttonpress %can watch as each is plotted in turn
+% 
+% end%loop through all normals
+% 
+% if plot_flag
+% axis equal
+% end
+% 
+% 
+% %find intersections
+% lim=sqrt(2)-1;
+% max_score=0;
+% max_coords=[0 0 0];
+% score=[];
+% count=1;
+% for i=-lim:inc:lim
+% for j=-lim:inc:lim
+% for k=-lim:inc:lim
+%   
+% dummy = find(save_plot(:,1)>i & save_plot(:,1)<(i+inc) &save_plot(:,2)>j & save_plot(:,2)<(j+inc) &save_plot(:,3)>k & save_plot(:,3)<(k+inc));
+% score(count)=length(dummy);
+% if (score(count)>max_score)
+%   max_score=score;
+%   max_coords=[i j k];
+% end
+% 
+% count=count+1;
+% end
+% end
+% end
+% 
+% max_score;
+% max_coords;
+% element = inc*[0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1];
+% max_element = repmat(max_coords,8,1)+element;
+% max_coords = max_coords+0.5*[inc inc inc]; %this is the approximate solution
+% 
+% 
+% 
+% 
+% if plot_flag
+%   plot3(max_element(:,1),max_element(:,2),max_element(:,3),'go')
+%   plot3(max_coords(:,1),max_coords(:,2),max_coords(:,3),'co')
+% end
+% 
+% %Peter's bit - more precise handling of intersections
+% % Determine precise point of intersection inside the sampling element
+% 
+% %normalise the r_direction part of the line equations
+% %note that it is necessary to normalise vectors for the distance calculations to
+% %work!
+% lines.cor=normlinedir(lines.cor);
+% 
+% line_cand.cor=[];%line equations which pass close to max_coords
+% line_cand.plnorm=[];%to which plane normal (struct_id entry) does line belong - to ensure only one line from each normal
+% 
+% % pick lines which pass close to the sampling element: candidate lines
+% distances=pointtolinedist(max_coords,lines.cor);
+% dummy=find(distances< inc_ext);
+% line_cand.cor = lines.cor(dummy,:);
+% line_cand.plnorm = lines.plnorm(dummy);
+% 
+% 
+% % If more than one line from a given plane is present in the set, then choose the one that fits the best.
+% pof_prel=pofintersectexp(line_cand.cor)'; %initial least squares best intersection
+% 
+% % Alternative (cleaner!) loop to find the closest line from a given plane
+% % to the point of intersection, if more than one is present
+%   distances=pointtolinedist(pof_prel, line_cand.cor);%distance from each candidate line to point
+% dummy2=[];%list of lines to delete
+% for k=1:size(plane_normal,1)
+%   dummy=find(plane_normal==k);
+%   if length(dummy)>2%if more than one line, delete all but the closest
+%     %- make a list of those to delete
+%     dummy2 = [dummy2 find(distances~=min(distances(dummy)) & line_cand.plnorm ==k)];
+%   end
+% end
+% line_cand.cor(dummy2,:)=[];%do the deletion
+% line_cand.plnorm(dummy2,:)=[];%do the deletion
+% 
+% %line_cand now contains information only about lines which pass near the
+% %approx intersection, and only the best line arising from each plane
+% %normal
+% 
+% %repeat loop, to try and choose more precisely
+% pof_prel=pofintersectexp(line_cand.cor)'; %least squares best intersection
+% 
+% %find distances of remaining lines to point
+% distances=pointtolinedist(pof_prel, line_cand.cor);%distance from each candidate line to point
+% test_distance = consistancy_test*inc;
+% dummy2=find(distances>test_distance);
+% 
+% %%display the distances and which plane normals they come from
+% %distances
+% %line_cand.plnorm
+% 
+% line_cand.cor(dummy2,:)=[];%do the deletion
+% line_cand.plnorm(dummy2,:)=[];%do the deletion
+% 
+% 
+% %%[line_cand.cor,line_cand.plnorm]
+% 
+% %final least squares fit with good lines only, display results
+% max_coords;
+% pof_prel;
+% pof=pofintersectexp(line_cand.cor)'
+% dsqr=pointtolinedistsqrsum(max_coords, line_cand.cor)
+% 
+% %consistancy check part
+% good_plnorms = 1:size(plane_normal,1);%index of plane normals
+% good_plnorms = ismember(good_plnorms,line_cand.plnorm);
+% 
+% good_plnorms2=good_plnorms;
+% 
+% for i=1:length(read_out)
+%   tmp=good_plnorms2(1:read_out(i));
+%   good_plnorms2(1:read_out(i))=[];
+%   read_out(i)=length(find(tmp))/length(tmp);
+% end
+% 
+% 
+% 
+% 
+% if plot_flag
+%   plot3(pof(1),pof(2),pof(3),'mo','markersize',25);
+%   plot3(pof(1),pof(2),pof(3),'m*','markersize',25);
+% end
+% 
diff --git a/4_spot_sorting/plot_rodrigues_consistancy_sortgrains.m b/4_spot_sorting/plot_rodrigues_consistancy_sortgrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..61fee9a1c4cd8eeaa4d49f3bc569820bd172f4f0
--- /dev/null
+++ b/4_spot_sorting/plot_rodrigues_consistancy_sortgrains.m
@@ -0,0 +1,409 @@
+function [pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_sortgrains(plane_normal,hkl,plot_flag)
+
+% Peter's modification of plot_rodrigues_consistancy_test for sorting grains; 
+
+%plane_normal = list of plane normals in sample coords
+%hkl a vector of reflection type eg [1 1 1; 0 0 2; 2 2 0 etc]
+%for hexagonal this this be a 4 index notation
+%plot_flag: 1 to plot figure, 0 to not plot anything
+
+% andy 19/10/2007 - add consistancy check
+
+
+save_plot=[];
+
+if plot_flag
+    figure;
+    hold on;
+end
+
+lines.cor=[];
+lines.plnorm=[];
+consistancy_test=0.2;   %select those lines within distance consistancy_test*inc of the intersection (was 0.2)
+
+load('parameters.mat');
+acq=parameters.acq;
+spacegroup=acq.spacegroup;
+
+switch spacegroup
+    case {225, 229} % ie cubic lattice
+        inc=0.1; % scan space in these steps (size of the sampling element)
+        inc_ext=1.1*inc; % extended space to determine precise point of intersection; (should be larger than 0.87*inc)
+        lim=sqrt(2)-1;
+        limz=sqrt(2)-1;
+        for j=1:size(plane_normal,1) % loop of plane_normals
+
+            %________calculate h vector___________
+            %from eq (3.7) in Poulsen
+            %B is identity matrix in cubic material
+            %gtnewGetReflections returns matrix of all reflections related by symmetry
+            %to hkl, using Riso GetCubicSymOp.m
+
+            hkl_reflections = gtGetReflections(hkl(j,:));
+            if size(hkl_reflections,1)~=1%skip if hkl = [0 0 0]
+                for i=1:size(hkl_reflections,1) % loop of hkl reflections
+                    h = hkl_reflections(i,:);
+                    h = h./(sqrt(h*h'));
+                    %________calculate y vector___________
+                    % y is the normalised scattering vector in sample system
+                    % == plane normal
+                    y = plane_normal(j,:);
+
+                    %_____calculate rodrigues space vector_____
+                    %formulae (3.16), (3.17) in Poulsen
+
+                    r_zero = cross(h,y)./(1+(dot(h,y)));
+                    r_direction = (h + y)./(1+(dot(h,y)));
+
+                    lines.cor=[lines.cor; r_zero r_direction];
+                    lines.plnorm=[lines.plnorm; j];
+
+                    %max line length needed ~1.5, say +-1.5 for saftey
+                    t=(-1.5:0.01:1.5)';
+                    r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+
+                    %remove everything outside of a fundamental region (assume cube)
+                    lim=sqrt(2)-1;
+                    for i=1:3
+                        dummy=find(r_plot(:,i)<-lim | r_plot(:,i)>lim);
+                        r_plot(dummy,:)=[];
+                    end
+
+                    %remove the corners of this region also
+                    lim=1/sqrt(3);
+                    %calculate distance of each point along each <111> directions
+                    vector=[1 1 1]./sqrt(3);%normalise
+                    vector=repmat(vector,size(r_plot,1),1);
+                    tmp = sum( ((abs(r_plot)).*vector),2); %projections along <111>
+                    dummy=find(tmp>lim);
+                    r_plot(dummy,:)=[];
+
+
+
+                    %collect all plot data for analysis
+                    save_plot=[save_plot; r_plot];
+
+
+
+                    %____plot______
+                    if plot_flag
+                        if all(hkl(j,:)==[1 1 1]) %(111) - red
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+
+                        elseif all(hkl(j,:)==[0 0 2]) %(002) - blue
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+
+                        elseif all(hkl(j,:)==[2 2 0]) %(220)  - green
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+
+                        elseif all(hkl(j,:)==[3 1 1]) %(311)   -  black
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+
+                        else %all others in pink
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+
+                        end
+                    end
+
+                end%loop through all hkl variants
+            end%if hkl is okay (skip hkl = [0 0 0])
+            %uncomment this to see line by line in rodrigues space.
+            %k=waitforbuttonpress %can watch as each is plotted in turn
+
+        end%loop through all normals
+        %%%%%%%end case 225/ 229
+
+
+    case 663
+
+        inc=0.08;% scan space in these steps (size of the sampling element)
+        inc_ext=1.1*inc; % extended space to determine precise point of intersection; (should be larger than 0.87*inc)
+        lim=1;
+        limz=2-sqrt(3);
+
+        plane_normal_cart=plane_normal;
+        for j=1:size(plane_normal_cart,1) % loop of plane_normals
+            %________calculate h vector___________
+            %from eq (3.7) in Poulsen
+            %B is identity matrix in cubic material
+            %gtnewGetReflections returns matrix of all reflections related by symmetry
+            %to hkl, using Riso GetCubicSymOp.m
+
+            hkil_reflections_hex = gtGetReflections_sab(hkl(j,:));
+
+            if size(hkil_reflections_hex,1)~=1%skip if hkl = [0 0 0]
+                for i=1:size(hkil_reflections_hex,1) % loop of hkil reflections
+
+                    % passage de l espace direct hexagonal en coordonnees cartesiennes
+                    h(1)= hkil_reflections_hex(i,1) + 0.5 * hkil_reflections_hex(i,2);
+                    h(2)= 3^0.5/2 *hkil_reflections_hex(i,2);
+                    h(3)= hkil_reflections_hex(i,4);
+                    % normalisation of the cartesian coordinates space
+                    % allow for c/a ratio in hexagonal unit cell
+                    h(1)=h(1)*2/(sqrt(3)*acq.latticepar(1));
+                    h(2)=h(2)*2/(sqrt(3)*acq.latticepar(1));
+                    h(3)=h(3)/acq.latticepar(3);
+                    % normalise to unit vector
+                    h = h./(sqrt(h*h'));
+
+                    %________calculate y vector___________
+                    % y is the normalised scattering vector in cartesian system
+                    % == plane normal
+                    y = plane_normal_cart(j,:);
+                    y = y./(sqrt(y*y'));
+
+                    %_____calculate rodrigues space vector_____
+                    %formulae (3.16), (3.17) in Poulsen
+
+                    r_zero = cross(h,y)./(1+(dot(h,y)));
+                    r_direction = (h + y)./(1+(dot(h,y)));
+
+                    lines.cor=[lines.cor; r_zero r_direction];
+                    lines.plnorm=[lines.plnorm; j];
+
+
+                    %max line length needed ~1.5, say +-1.5 for saftey
+                    t=(-3:0.01:3)';
+                    r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+
+                    %remove everything outside of a fundamental region (assume cf Heinz_Neumann acta. crist.)
+                    % base and top of the prism
+                    dummy=find(abs(r_plot(:,1))>=1 | abs(r_plot(:,2))>=1 | abs(r_plot(:,3))>=(2-sqrt(3)) );
+                    r_plot(dummy,:)=[];
+                    % remove facette of the faces
+                    dummy=find((r_plot(:,1)+sqrt(3)*r_plot(:,2)>=2) | (r_plot(:,1)-sqrt(3)*r_plot(:,2))>=2);
+                    r_plot(dummy,:)=[];
+                    dummy=find((-r_plot(:,1)+sqrt(3)*r_plot(:,2)>=2) | (-r_plot(:,1)-sqrt(3)*r_plot(:,2))>=2);
+                    r_plot(dummy,:)=[];
+                    dummy=find((r_plot(:,2)+sqrt(3)*r_plot(:,1))>=2 | (r_plot(:,2)-sqrt(3)*r_plot(:,1))>=2);
+                    r_plot(dummy,:)=[];
+                    dummy=find((-r_plot(:,2)+sqrt(3)*r_plot(:,1))>=2 | (-r_plot(:,2)-sqrt(3)*r_plot(:,1))>=2);
+                    r_plot(dummy,:)=[];
+                    %collect all plot data for analysis
+                    save_plot=[save_plot; r_plot];
+
+
+
+                    %____plot______ % adapted to the snow case
+                    if plot_flag
+                        %  keyboard
+                        %plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+                        hkil_hex=hkl;
+                        if all(hkil_hex(j,:)==[0 0 0 2])
+               
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+                            %figure(2)
+                            %quiver3(0,0,0,h(1),h(2),h(3),'r')
+
+                        elseif all(hkil_hex(j,:)==[1 1 -2 0])
+
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+                            %figure(2)
+                            %quiver3(0,0,0,h(1),h(2),h(3),'b')
+
+                        elseif all(hkil_hex(j,:)==[1 -1 0 0])
+
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+                            %figure(2)
+                            %quiver3(0,0,0,h(1),h(2),h(3),'g')
+                        elseif all(hkil_hex(j,:)==[1 -1 0 1])
+
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+                            %figure(2)
+                            %quiver3(0,0,0,h(1),h(2),h(3),'k')
+                        elseif all(hkil_hex(j,:)==[1 1 -2 2])
+
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'c');
+                            %figure(2)
+                            %quiver3(0,0,0,h(1),h(2),h(3),'c')
+
+                            %                                         elseif all(hkil_hex(j,:)==[1 1 -2 1])
+                            %                                             plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+                            %
+                            %                                         elseif all(hkil_hex(j,:)==[1 -1 0 2])
+                            %                                             plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+                            %
+                            %                                         elseif all(hkil_hex(j,:)==[1 1 -2 3])
+                            %                                             plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'c');
+                            %
+                            %                                         elseif all(hkil_hex(j,:)==[1 -1 0 3])
+                            %                                             plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'y');
+                            %
+                            %                                         elseif all(hkil_hex(j,:)==[1 1 -2 4])
+                            %                                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r:');
+                            %
+                            %                                          elseif all(hkil_hex(j,:)==[1 -1 0 4])
+                            %                                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b:');
+                            %
+                            %                                         elseif all(hkil_hex(j,:)==[0 0 0 4])
+                            %                                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g:');
+                            %
+                            %                                          elseif all(hkil_hex(j,:)==[-2 0 2 1])
+                            %                                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m:');
+                            %
+                            %                                          elseif all(hkil_hex(j,:)==[-2 0 2 3])
+                            %                                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'c:');
+                            %
+                            %                                          elseif all(hkil_hex(j,:)==[-3 1 2 1])
+                            %                                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'y:');
+                            %
+                            %                                          elseif all(hkil_hex(j,:)==[-3 1 2 0])
+                            %                                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b-');
+                            %                                         else
+                            %                                             plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+                            %
+                        end
+                        %     legend(' 0 0 0 -2', '1 1 -2 0', '1 -1 0 0', '1 1 -2 1', '1 -1 0 2','1 1 -2 3', '1 1 -2 4','1 -1 0 4', ' 0 0 0 4','-2 0 2 1','-2 0 2 3','-3 1 2 3','-3 1 2 0');
+                    end
+
+                end %loop through all hkl variants
+            end %if hkl is okay (skip hkl = [0 0 0])
+            % uncomment this to see line by line in rodrigues space.
+            % k=waitforbuttonpress %can watch as each is plotted in turn
+
+        end%loop through all normals
+
+end % end switch space group
+
+
+
+if plot_flag
+    axis equal
+end
+lines.cor;
+lines.plnorm;
+size(lines.cor)
+
+
+
+%find intersections
+tic
+max_score=0;
+max_coords=[0 0 0];
+score=[];
+count=1;
+for i=-lim:inc:lim
+    for j=-lim:inc:lim
+        for k=-limz:inc:limz
+
+            dummy = find(save_plot(:,1)>i & save_plot(:,1)<(i+inc) &save_plot(:,2)>j & save_plot(:,2)<(j+inc) &save_plot(:,3)>k & save_plot(:,3)<(k+inc));
+            score(count)=length(dummy);
+            if (score(count)>max_score)
+                max_score=score;
+                max_coords=[i j k];
+            end
+
+            count=count+1;
+        end
+    end
+end
+
+max_score;
+max_coords;
+element = inc*[0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1];
+max_element = repmat(max_coords,8,1)+element;
+max_coords = max_coords+0.5*[inc inc inc]; %this is the approximate solution
+
+if plot_flag
+    plot3(max_element(:,1),max_element(:,2),max_element(:,3),'go')
+    plot3(max_coords(:,1),max_coords(:,2),max_coords(:,3),'co')
+end
+
+
+% Determine precise point of intersection inside the sampling element
+
+lines.cor=normlinedir(lines.cor);
+
+line_cand.cor=[];%line equations which pass close to max_coords
+line_cand.plnorm=[];%to which plane normal (struct_id entry) does line belong - to ensure only one line from each normal
+
+%for j=1:size(lines.cor,1) % picks lines which pass close to the sampling element: candidate lines
+%    if (pointtolinedist(max_coords, lines.cor(j,:)) < inc_ext)
+%        line_cand.cor=[line_cand.cor; lines.cor(j,:)];
+%        line_cand.plnorm=[line_cand.plnorm; lines.plnorm(j)];
+%    end
+%end
+distances=pointtolinedist(max_coords,lines.cor);
+dummy=find(distances< inc_ext);
+line_cand.cor = lines.cor(dummy,:);
+line_cand.plnorm = lines.plnorm(dummy);
+
+
+% If more than one line from a given plane is present in the set, then
+% choose the one that fits the best.
+pof_prel=pofintersectexp(line_cand.cor)';
+
+% for k=1:size(plane_normal,1)    % delete redundant lines from line_cand
+%     dis=1e+38;
+%     m=1;
+%     while (m <= size(line_cand.cor,1))
+%         if (line_cand.plnorm(m) == k)
+%             if pointtolinedist(pof_prel, line_cand.cor(m,:)) < dis
+%                 dis=pointtolinedist(pof_prel, line_cand.cor(m,:));
+%                 dis_line.cor=line_cand.cor(m,:);
+%             end
+%             line_cand.cor(m,:)=[];
+%             line_cand.plnorm(m)=[];
+%             m=m-1;
+%         end
+%         m=m+1;
+%     end
+%     if dis ~= 1e+38
+%         line_cand.cor=[line_cand.cor; dis_line.cor(1:6)];
+%         line_cand.plnorm=[line_cand.plnorm; k];
+%     end
+% end
+
+% Alternative (cleaner!) loop to find the closest line from a given plane
+% to the point of intersection, if more than one is present
+distances=pointtolinedist(pof_prel, line_cand.cor);%distance from each candidate line to point
+dummy2=[];%list of lines to delete
+for k=1:size(plane_normal,1)
+    dummy=find(plane_normal==k);
+    if length(dummy)>2%if more than one line, delete all but the closest
+        %- make a list of those to delete
+        dummy2 = [dummy2 find(distances~=min(distances(dummy)) & line_cand.plnorm ==k)];
+    end
+end
+line_cand.cor(dummy2,:)=[];%do the deletion
+line_cand.plnorm(dummy2,:)=[];%do the deletion
+
+
+%line_cand now contains information only about lines which pass near the
+%approx intersection, and only the best line arising from each plane
+%normal
+
+%repeat loop, to try and choose more precisely
+pof_prel=pofintersectexp(line_cand.cor)'; %least squares best intersection
+
+%find distances of remaining lines to point
+distances=pointtolinedist(pof_prel, line_cand.cor);%distance from each candidate line to point
+test_distance = consistancy_test*inc;
+dummy2=find(distances>test_distance);
+
+%%display the distances and which plane normals they come from
+%distances
+%line_cand.plnorm
+
+line_cand.cor(dummy2,:)=[];%do the deletion
+line_cand.plnorm(dummy2,:)=[];%do the deletion
+
+
+%%[line_cand.cor,line_cand.plnorm]
+
+%final least squares fit with good lines only, display results
+max_coords;
+pof_prel;
+pof=pofintersectexp(line_cand.cor)'
+dsqr=pointtolinedistsqrsum(max_coords, line_cand.cor)
+
+%consistancy check part
+good_plnorms = 1:size(plane_normal,1);%index of plane normals
+good_plnorms = ismember(good_plnorms,line_cand.plnorm);
+
+
+if plot_flag
+    plot3(pof(1),pof(2),pof(3),'mo','markersize',25);
+    plot3(pof(1),pof(2),pof(3),'m*','markersize',25);
+end
+toc
diff --git a/4_spot_sorting/plot_rodrigues_consistancy_test.m b/4_spot_sorting/plot_rodrigues_consistancy_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..993449a8e2c2a9152e62ca33a0c6906a36148ba2
--- /dev/null
+++ b/4_spot_sorting/plot_rodrigues_consistancy_test.m
@@ -0,0 +1,416 @@
+function [pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test(plane_normal,hkl,plot_flag,tol)
+
+%plane_normal = list of plane normals in sample coords
+%hkl a vector of reflection type eg [1 1 1; 0 0 2; 2 2 0 etc]
+%for hexagonal this this be a 4 index notation
+%plot_flag: 1 to plot figure, 0 to not plot anything
+
+% andy 19/10/2007 - add consistancy check
+
+tic % modif Peter
+
+save_plot=[];
+
+if plot_flag
+    figure;
+    hold on;
+    %  figure(2);
+    %  hold on;
+end
+
+% modif by Peter; tol can be input for spacegroup {225, 229}
+
+inc=0.1; % default=0.1; scan space in these steps (size of the sampling element)
+consistancy_test=0.2;   %default=0.2; select those lines within distance consistancy_test*inc of the intersection (was 0.2)
+dotspacing=0.01; % default=0.01; spacing of dots constituting a line (should be much smaller than tol.inc)
+
+if exist('tol','var')
+  if isfield(tol,'inc')
+    inc=tol.inc; 
+  end
+
+  if isfield(tol,'cons')
+    consistancy_test=tol.cons;   %select those lines within distance consistancy_test*inc of the intersection (was 0.2)
+  end
+
+  if isfield(tol,'dotspacing')
+    dotspacing=tol.dotspacing; 
+  end
+end
+
+
+lines.cor=[];
+lines.plnorm=[];
+
+load('parameters.mat');
+acq=parameters.acq;
+spacegroup=acq.spacegroup;
+
+switch spacegroup
+    case {225, 229} % ie cubic lattice
+        inc_ext=1.1*inc; % extended space to determine precise point of intersection; (should be larger than 0.87*inc)
+        lim=sqrt(2)-1;
+        limz=sqrt(2)-1;
+        for j=1:size(plane_normal,1) % loop of plane_normals
+
+            %________calculate h vector___________
+            %from eq (3.7) in Poulsen
+            %B is identity matrix in cubic material
+            %gtnewGetReflections returns matrix of all reflections related by symmetry
+            %to hkl, using Riso GetCubicSymOp.m
+
+            hkl_reflections = gtGetReflections(hkl(j,:));
+            if size(hkl_reflections,1)~=1%skip if hkl = [0 0 0]
+                for i=1:size(hkl_reflections,1) % loop of hkl reflections
+                    h = hkl_reflections(i,:);
+                    h = h./(sqrt(h*h'));
+                    %________calculate y vector___________
+                    % y is the normalised scattering vector in sample system
+                    % == plane normal
+                    y = plane_normal(j,:);
+
+                    %_____calculate rodrigues space vector_____
+                    %formulae (3.16), (3.17) in Poulsen
+
+                    r_zero = cross(h,y)./(1+(dot(h,y)));
+                    r_direction = (h + y)./(1+(dot(h,y)));
+
+                    lines.cor=[lines.cor; r_zero r_direction];
+                    lines.plnorm=[lines.plnorm; j];
+
+                    %max line length needed ~1.5, say +-1.5 for saftey
+                    t=(-1.5:dotspacing:1.5)';
+                    r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+
+                    %remove everything outside of a fundamental region (assume cube)
+                    lim=sqrt(2)-1;
+                    for i=1:3
+                        dummy=find(r_plot(:,i)<-lim | r_plot(:,i)>lim);
+                        r_plot(dummy,:)=[];
+                    end
+
+                    %remove the corners of this region also
+                    lim=1/sqrt(3);
+                    %calculate distance of each point along each <111> directions
+                    vector=[1 1 1]./sqrt(3);%normalise
+                    vector=repmat(vector,size(r_plot,1),1);
+                    tmp = sum( ((abs(r_plot)).*vector),2); %projections along <111>
+                    dummy=find(tmp>lim);
+                    r_plot(dummy,:)=[];
+
+
+
+                    %collect all plot data for analysis
+                    save_plot=[save_plot; r_plot];
+
+
+
+                    %____plot______
+                    if plot_flag
+                        if all(hkl(j,:)==[1 1 1]) %(111) - red
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+
+                        elseif all(hkl(j,:)==[0 0 2]) %(002) - blue
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+
+                        elseif all(hkl(j,:)==[2 2 0]) %(220)  - green
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+
+                        elseif all(hkl(j,:)==[3 1 1]) %(311)   -  black
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+
+                        else %all others in pink
+                            plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+
+                        end
+                    end
+
+                end%loop through all hkl variants
+            end%if hkl is okay (skip hkl = [0 0 0])
+            %uncomment this to see line by line in rodrigues space.
+            %k=waitforbuttonpress %can watch as each is plotted in turn
+
+        end%loop through all normals
+        %%%%%%%end case 225/ 229
+
+
+    case {663, 194, 167}
+        %%%%%%%%%%%%  Hexagonal materials case  %%%%%%%%%%%%%%%%
+        inc=0.08;% scan space in these steps (size of the sampling element)
+        if exist('tol','var')
+          if isfield(tol,'inc')
+            inc=tol.inc;
+          end
+
+          if isfield(tol,'cons')
+            consistancy_test=tol.cons;   %select those lines within distance consistancy_test*inc of the intersection (was 0.2)
+          end
+
+          dotspacing=0.01;
+          if isfield(tol,'dotspacing')
+            dotspacing=tol.dotspacing;
+          end
+        end
+        
+        inc_ext=1.1*inc; % extended space to determine precise point of intersection; (should be larger than 0.87*inc)
+        lim=1;
+        limz=2-sqrt(3);
+
+        plane_normal_cart=plane_normal;
+        for j=1:size(plane_normal_cart,1) % loop of plane_normals
+            %________calculate h vector___________
+            %from eq (3.7) in Poulsen
+            %B is identity matrix in cubic material
+            %gtnewGetReflections returns matrix of all reflections related by symmetry
+            %to hkl, using Riso GetCubicSymOp.m
+
+            hkil_reflections_hex = gtGetReflections_sab(hkl(j,:));
+
+            if size(hkil_reflections_hex,1)~=1%skip if hkl = [0 0 0]
+                for i=1:size(hkil_reflections_hex,1) % loop of hkil reflections
+
+                    % passage de l espace direct hexagonal en coordonnees cartesiennes
+                    h(1)= hkil_reflections_hex(i,1) + 0.5 * hkil_reflections_hex(i,2);
+                    h(2)= 3^0.5/2 *hkil_reflections_hex(i,2);
+                    h(3)= hkil_reflections_hex(i,4);
+                    % normalisation of the cartesian coordinates space
+                    % allow for c/a ratio in hexagonal unit cell
+                    h(1)=h(1)*2/(sqrt(3)*acq.latticepar(1));
+                    h(2)=h(2)*2/(sqrt(3)*acq.latticepar(1));
+                    h(3)=h(3)/acq.latticepar(3);
+                    % normalise to unit vector
+                    h = h./(sqrt(h*h'));
+
+                    %________calculate y vector___________
+                    % y is the normalised scattering vector in cartesian system
+                    % == plane normal
+                    y = plane_normal_cart(j,:);
+                    y = y./(sqrt(y*y'));
+
+                    %_____calculate rodrigues space vector_____
+                    %formulae (3.16), (3.17) in Poulsen
+
+                    r_zero = cross(h,y)./(1+(dot(h,y)));
+                    r_direction = (h + y)./(1+(dot(h,y)));
+
+                    lines.cor=[lines.cor; r_zero r_direction];
+                    lines.plnorm=[lines.plnorm; j];
+
+
+                    %max line length needed ~1.5, say +-1.5 for saftey
+                    t=(-3:dotspacing:3)';
+                    r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+
+                    %remove everything outside of a fundamental region (assume cf Heinz_Neumann acta. crist.)
+                    % base and top of the prism
+                    dummy=find(abs(r_plot(:,1))>=1 | abs(r_plot(:,2))>=1 | abs(r_plot(:,3))>=(2-sqrt(3)) );
+                    r_plot(dummy,:)=[];
+                    % remove facette of the faces
+                    dummy=find((r_plot(:,1)+sqrt(3)*r_plot(:,2)>=2) | (r_plot(:,1)-sqrt(3)*r_plot(:,2))>=2);
+                    r_plot(dummy,:)=[];
+                    dummy=find((-r_plot(:,1)+sqrt(3)*r_plot(:,2)>=2) | (-r_plot(:,1)-sqrt(3)*r_plot(:,2))>=2);
+                    r_plot(dummy,:)=[];
+                    dummy=find((r_plot(:,2)+sqrt(3)*r_plot(:,1))>=2 | (r_plot(:,2)-sqrt(3)*r_plot(:,1))>=2);
+                    r_plot(dummy,:)=[];
+                    dummy=find((-r_plot(:,2)+sqrt(3)*r_plot(:,1))>=2 | (-r_plot(:,2)-sqrt(3)*r_plot(:,1))>=2);
+                    r_plot(dummy,:)=[];
+                    %collect all plot data for analysis
+                    save_plot=[save_plot; r_plot];
+
+
+
+                    %____plot______ % adapted to the snow case
+                    if plot_flag
+                      hkil_hex=hkl;
+                      
+                      if all(hkil_hex(j,:)==[0 0 0 2])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+
+                      elseif all(hkil_hex(j,:)==[1 1 -2 0])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+
+                          %some specific to alumina
+                      elseif all(hkil_hex(j,:)==[0 1 -1 2])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+                      elseif all(hkil_hex(j,:)==[1 0 -1 4])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+                      elseif all(hkil_hex(j,:)==[1 1 -2 3])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'c');
+                      elseif all(hkil_hex(j,:)==[0 2 -2 4])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+
+                      elseif all(hkil_hex(j,:)==[1 -1 0 0])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+                      elseif all(hkil_hex(j,:)==[1 0 -1 0])%for Mg
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+
+                      elseif all(hkil_hex(j,:)==[1 -1 0 1])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+
+                      elseif all(hkil_hex(j,:)==[1 0 -1 1]) %for Mg
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+
+                      elseif all(hkil_hex(j,:)==[1 1 -2 2])
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'c');
+
+                      else %all others use pink
+                          plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+
+                      end
+
+                    end
+
+                end %loop through all hkl variants
+            end %if hkl is okay (skip hkl = [0 0 0])
+            % uncomment this to see line by line in rodrigues space.
+            % k=waitforbuttonpress %can watch as each is plotted in turn
+
+        end%loop through all normals
+
+end % end switch space group
+
+
+
+if plot_flag
+    axis equal
+    axis vis3d
+end
+lines.cor;
+lines.plnorm;
+size(lines.cor)
+
+
+
+%find intersections
+%tic   % commented - modif Peter
+max_score=0;
+max_coords=[0 0 0];
+score=[];
+count=1;
+for i=-lim:inc:lim  
+    for j=-lim:inc:lim
+        for k=-limz:inc:limz
+
+            dummy = find(save_plot(:,1)>i & save_plot(:,1)<(i+inc) &save_plot(:,2)>j & save_plot(:,2)<(j+inc) &save_plot(:,3)>k & save_plot(:,3)<(k+inc));
+            score(count)=length(dummy);
+            if (score(count)>max_score)
+                max_score=score;
+                max_coords=[i j k];
+            end
+
+            count=count+1;
+        end
+    end
+end
+
+max_score;
+max_coords;
+
+element = inc*[0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1];
+max_element = repmat(max_coords,8,1)+element;
+max_coords = max_coords+0.5*[inc inc inc]; %this is the approximate solution
+
+if plot_flag
+    plot3(max_element(:,1),max_element(:,2),max_element(:,3),'go')
+    plot3(max_coords(:,1),max_coords(:,2),max_coords(:,3),'co')
+end
+
+
+% Determine precise point of intersection inside the sampling element
+
+lines.cor=normlinedir(lines.cor);
+
+line_cand.cor=[];%line equations which pass close to max_coords
+line_cand.plnorm=[];%to which plane normal (struct_id entry) does line belong - to ensure only one line from each normal
+
+%for j=1:size(lines.cor,1) % picks lines which pass close to the sampling element: candidate lines
+%    if (pointtolinedist(max_coords, lines.cor(j,:)) < inc_ext)
+%        line_cand.cor=[line_cand.cor; lines.cor(j,:)];
+%        line_cand.plnorm=[line_cand.plnorm; lines.plnorm(j)];
+%    end
+%end
+distances=pointtolinedist(max_coords,lines.cor);
+dummy=find(distances< inc_ext);
+line_cand.cor = lines.cor(dummy,:);
+line_cand.plnorm = lines.plnorm(dummy);
+
+
+% If more than one line from a given plane is present in the set, then
+% choose the one that fits the best.
+pof_prel=pofintersectexp(line_cand.cor)';
+
+% for k=1:size(plane_normal,1)    % delete redundant lines from line_cand
+%     dis=1e+38;
+%     m=1;
+%     while (m <= size(line_cand.cor,1))
+%         if (line_cand.plnorm(m) == k)
+%             if pointtolinedist(pof_prel, line_cand.cor(m,:)) < dis
+%                 dis=pointtolinedist(pof_prel, line_cand.cor(m,:));
+%                 dis_line.cor=line_cand.cor(m,:);
+%             end
+%             line_cand.cor(m,:)=[];
+%             line_cand.plnorm(m)=[];
+%             m=m-1;
+%         end
+%         m=m+1;
+%     end
+%     if dis ~= 1e+38
+%         line_cand.cor=[line_cand.cor; dis_line.cor(1:6)];
+%         line_cand.plnorm=[line_cand.plnorm; k];
+%     end
+% end
+
+% Alternative (cleaner!) loop to find the closest line from a given plane
+% to the point of intersection, if more than one is present
+distances=pointtolinedist(pof_prel, line_cand.cor);%distance from each candidate line to point
+dummy2=[];%list of lines to delete
+for k=1:size(plane_normal,1)
+    %dummy=find(plane_normal==k); % BUG should be: dummy=find(line_cand.plnorm==k);
+    dummy=find(line_cand.plnorm==k);
+    if length(dummy)>2%if more than one line, delete all but the closest
+        %- make a list of those to delete
+        dummy2 = [dummy2 find(distances~=min(distances(dummy)) & line_cand.plnorm ==k)];
+    end
+end
+line_cand.cor(dummy2,:)=[];%do the deletion
+line_cand.plnorm(dummy2,:)=[];%do the deletion
+
+
+%line_cand now contains information only about lines which pass near the
+%approx intersection, and only the best line arising from each plane
+%normal
+
+%repeat loop, to try and choose more precisely
+pof_prel=pofintersectexp(line_cand.cor)'; %least squares best intersection
+
+%find distances of remaining lines to point
+distances=pointtolinedist(pof_prel, line_cand.cor);%distance from each candidate line to point
+test_distance = consistancy_test*inc;
+dummy2=find(distances>test_distance);
+
+%%display the distances and which plane normals they come from
+%distances
+%line_cand.plnorm
+
+line_cand.cor(dummy2,:)=[];%do the deletion
+line_cand.plnorm(dummy2,:)=[];%do the deletion
+
+
+%%[line_cand.cor,line_cand.plnorm]
+
+%final least squares fit with good lines only, display results
+max_coords;
+pof_prel;
+pof=pofintersectexp(line_cand.cor)';
+dsqr=pointtolinedistsqrsum(max_coords, line_cand.cor);
+
+%consistancy check part
+good_plnorms = 1:size(plane_normal,1);%index of plane normals
+good_plnorms = ismember(good_plnorms,line_cand.plnorm);
+
+
+if plot_flag
+    plot3(pof(1),pof(2),pof(3),'mo','markersize',25);
+    plot3(pof(1),pof(2),pof(3),'m*','markersize',25);
+end
+toc
diff --git a/4_spot_sorting/plot_rodrigues_indexed.m b/4_spot_sorting/plot_rodrigues_indexed.m
new file mode 100755
index 0000000000000000000000000000000000000000..d3497ba294ea93081877969a1272defbe7799f86
--- /dev/null
+++ b/4_spot_sorting/plot_rodrigues_indexed.m
@@ -0,0 +1,111 @@
+function max_coords=plot_rodrigues_indexed(plane_normal,hkl)
+
+%plane_normal = list of plane normals in sample coords
+% for caase where reflections have been indexed - ie (0 2 -2) 
+% rather than {2 2 0}
+%hkl a vector of reflections  [1 -1 1; 0 0 2; -2 2 0 etc]
+
+save_plot=[];
+figure;
+hold on;
+
+for j=1:size(plane_normal,1)
+
+%________calculate h vector___________
+%from eq (3.7) in Poulsen
+%B is identity matrix in cubic material
+%gtnewGetReflections returns matrix of all reflections related by symmetry
+%to hkl, using Riso GetCubicSymOp.m
+
+
+h = hkl(j,:); 
+h = h./(sqrt(h*h'));
+
+%________calculate y vector___________
+% y is the normalised scattering vector in sample system
+% == plane normal
+y = plane_normal(j,:);
+
+
+%_____calculate rodrigues space vector_____
+%formulae (3.16), (3.17) in Poulsen
+
+r_zero = cross(h,y)./(1+(dot(h,y)));
+r_direction = (h + y)./(1+(dot(h,y)));
+
+%max line length needed ~1.5, say +-1.5 for saftey
+t=(-1.5:0.01:1.5)';
+r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+
+%remove everything outside of a fundamental region (assume cube)
+lim=sqrt(2)-1;
+for i=1:3
+dummy=find(r_plot(:,i)<-lim | r_plot(:,i)>lim);
+r_plot(dummy,:)=[];
+end
+
+%collect all plot data for analysis
+save_plot=[save_plot; r_plot];
+
+
+
+%____plot______
+  if hkl(j,:)*hkl(j,:)'==[1 1 1]*[1 1 1]' %(111) - red
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+  
+  elseif hkl(j,:)*hkl(j,:)'==[0 0 2]*[0 0 2]' %(002) - blue
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+
+  elseif hkl(j,:)*hkl(j,:)'==[2 2 0]*[2 2 0]' %(220)  - green
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+
+  elseif hkl(j,:)*hkl(j,:)'==[3 1 1]*[3 1 1]' %(311)   -  black
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+
+  end
+
+%uncomment this to see line by line in rodrigues space.
+%k=waitforbuttonpress %can watch as each is plotted in turn
+
+end%loop through all normals
+
+axis equal
+
+
+%find intersections
+
+inc=0.04;%scan space in these steps (size of the sampling element)
+max_score=0;
+max_coords=[0 0 0];
+score=[];
+count=1;
+for i=-lim:inc:lim
+for j=-lim:inc:lim
+for k=-lim:inc:lim
+  
+dummy = find(save_plot(:,1)>i & save_plot(:,1)<(i+inc) &save_plot(:,2)>j & save_plot(:,2)<(j+inc) &save_plot(:,3)>k & save_plot(:,3)<(k+inc));
+score(count)=length(dummy);
+if (score(count)>max_score)
+  max_score=score;
+  max_coords=[i j k];
+end
+
+count=count+1;
+end
+end
+end
+
+max_score;
+max_coords;
+element = inc*[0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1];
+max_element = repmat(max_coords,8,1)+element;
+max_coords = max_coords+0.5*[inc inc inc];%this is the approximate solution
+
+plot3(max_element(:,1),max_element(:,2),max_element(:,3),'go')
+plot3(max_coords(:,1),max_coords(:,2),max_coords(:,3),'co')
+
+
+
+
+
+
diff --git a/4_spot_sorting/plot_rodrigues_precise.m b/4_spot_sorting/plot_rodrigues_precise.m
new file mode 100755
index 0000000000000000000000000000000000000000..d7c0bd76ea7f3f05fc5471c6309a2b82a308003b
--- /dev/null
+++ b/4_spot_sorting/plot_rodrigues_precise.m
@@ -0,0 +1,211 @@
+function [pof, dsqr]=plot_rodrigues(plane_normal,hkl,plot_flag)
+
+%plane_normal = list of plane normals in sample coords
+%hkl a vector of reflection type eg [1 1 1; 0 0 2; 2 2 0 etc]
+%plot_flag: 1 to plot figure, 0 to not plot anything
+
+inc=0.1;                % scan space in these steps (size of the sampling element)
+inc_ext=1.1*inc;         % extended space to determine precise point of intersection; (should be larger than 0.87*inc)
+
+save_plot=[];
+
+if plot_flag
+figure;
+hold on;
+end
+
+lines.cor=[];
+lines.plnorm=[];
+
+for j=1:size(plane_normal,1) % loop of plane_normals
+
+%________calculate h vector___________
+%from eq (3.7) in Poulsen
+%B is identity matrix in cubic material
+%gtnewGetReflections returns matrix of all reflections related by symmetry
+%to hkl, using Riso GetCubicSymOp.m
+
+hkl_reflections = gtGetReflections(hkl(j,:));
+
+if size(hkl_reflections,1)~=1%skip if hkl = [0 0 0]
+for i=1:size(hkl_reflections,1) % loop of hkl reflections
+h = hkl_reflections(i,:); 
+h = h./(sqrt(h*h'));
+
+%________calculate y vector___________
+% y is the normalised scattering vector in sample system
+% == plane normal
+y = plane_normal(j,:);
+
+
+%_____calculate rodrigues space vector_____
+%formulae (3.16), (3.17) in Poulsen
+
+r_zero = cross(h,y)./(1+(dot(h,y)));
+r_direction = (h + y)./(1+(dot(h,y)));
+
+
+
+
+
+
+lines.cor=[lines.cor; r_zero r_direction];
+lines.plnorm=[lines.plnorm; j];
+
+
+
+
+
+%max line length needed ~1.5, say +-1.5 for saftey
+t=(-1.5:0.01:1.5)';
+r_plot = repmat(r_zero,length(t),1) + (t*r_direction);
+
+%remove everything outside of a fundamental region (assume cube)
+lim=sqrt(2)-1;
+for i=1:3
+dummy=find(r_plot(:,i)<-lim | r_plot(:,i)>lim);
+r_plot(dummy,:)=[];
+end
+
+%remove the corners of this region also
+lim=1/sqrt(3);
+%calculate distance of each point along each <111> directions
+vector=[1 1 1]./sqrt(3);%normalise
+vector=repmat(vector,size(r_plot,1),1);
+tmp = sum( ((abs(r_plot)).*vector),2); %projections along <111>
+dummy=find(tmp>lim);
+r_plot(dummy,:)=[];
+
+
+
+%collect all plot data for analysis
+save_plot=[save_plot; r_plot];
+
+
+
+%____plot______
+if plot_flag
+  if all(hkl(j,:)==[1 1 1]) %(111) - red
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'r');
+  
+  elseif all(hkl(j,:)==[0 0 2]) %(002) - blue
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'b');
+
+  elseif all(hkl(j,:)==[2 2 0]) %(220)  - green
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'g');
+
+  elseif all(hkl(j,:)==[3 1 1]) %(311)   -  black
+  plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'k');
+  
+  else %all others in pink
+    plot3(r_plot(:,1),r_plot(:,2),r_plot(:,3),'m');
+
+  end
+end
+
+end%loop through all hkl variants
+end%if hkl is okay (skip hkl = [0 0 0])
+%uncomment this to see line by line in rodrigues space.
+%k=waitforbuttonpress %can watch as each is plotted in turn
+
+end%loop through all normals
+
+if plot_flag
+axis equal
+end
+
+%find intersections
+
+max_score=0;
+max_coords=[0 0 0];
+score=[];
+count=1;
+for i=-lim:inc:lim
+for j=-lim:inc:lim
+for k=-lim:inc:lim
+  
+dummy = find(save_plot(:,1)>i & save_plot(:,1)<(i+inc) &save_plot(:,2)>j & save_plot(:,2)<(j+inc) &save_plot(:,3)>k & save_plot(:,3)<(k+inc));
+score(count)=length(dummy);
+if (score(count)>max_score)
+  max_score=score;
+  max_coords=[i j k];
+end
+
+count=count+1;
+end
+end
+end
+
+max_score;
+max_coords;
+element = inc*[0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1];
+max_element = repmat(max_coords,8,1)+element;
+max_coords = max_coords+0.5*[inc inc inc]; %this is the approximate solution
+
+if plot_flag
+  plot3(max_element(:,1),max_element(:,2),max_element(:,3),'go')
+  plot3(max_coords(:,1),max_coords(:,2),max_coords(:,3),'co')
+end
+
+
+
+
+
+
+
+
+
+
+% Determine precise point of intersection inside the sampling element
+
+lines.cor=normlinedir(lines.cor);
+
+line_cand.cor=[];%line equations which pass close to max_coords
+line_cand.plnorm=[];%to which plane normal (struct_id entry) does line belong - to ensure only one line from each normal
+
+for j=1:size(lines.cor,1) % picks lines which pass close to the sampling element: candidate lines
+    if (pointtolinedist(max_coords, lines.cor(j,:)) < inc_ext)
+        line_cand.cor=[line_cand.cor; lines.cor(j,:)];
+        line_cand.plnorm=[line_cand.plnorm; lines.plnorm(j)];
+    end    
+end
+
+%normlinedir(line_cand.cor);
+
+  % If more than one line from a given plane is present in the set, then choose the one that fits the best.
+  
+pof_prel=pofintersectexp(line_cand.cor)';
+
+for k=1:size(plane_normal,1)    % delete redundant lines from line_cand 
+    dis=1e+38;
+    m=1;
+    while (m <= size(line_cand.cor,1))
+        if (line_cand.plnorm(m) == k)
+            if pointtolinedist(pof_prel, line_cand.cor(m,:)) < dis
+               dis=pointtolinedist(pof_prel, line_cand.cor(m,:));
+               dis_line.cor=line_cand.cor(m,:);
+            end
+            line_cand.cor(m,:)=[];
+            line_cand.plnorm(m)=[];
+            m=m-1;
+        end
+        m=m+1;
+    end
+    if dis ~= 1e+38
+        line_cand.cor=[line_cand.cor; dis_line.cor(1:6)];
+        line_cand.plnorm=[line_cand.plnorm; k];
+    end
+end
+
+%%[line_cand.cor,line_cand.plnorm]
+
+max_coords
+pof_prel
+pof=pofintersectexp(line_cand.cor)'
+dsqr=pointtolinedistsqrsum(max_coords, line_cand.cor)
+
+if plot_flag
+  plot3(pof(1),pof(2),pof(3),'mo','markersize',25);
+  plot3(pof(1),pof(2),pof(3),'m*','markersize',25);
+end
+
diff --git a/4_spot_sorting/pofintersectexp.m b/4_spot_sorting/pofintersectexp.m
new file mode 100755
index 0000000000000000000000000000000000000000..2978602134d5715165ca681b5337c2dc6c9725c9
--- /dev/null
+++ b/4_spot_sorting/pofintersectexp.m
@@ -0,0 +1,29 @@
+%
+% Gives the closest point to any number of 3D lines given; `point of intersection` in 3D
+% space (using explicit solution of least squares method; HIGHEST PERFORMANCE POSSIBLE)
+%
+% INPUT:  l(n,6) [ point_X point_Y point_Z norm_dir_X norm_dir_Y norm_dir_Z] =
+%           any number of 3D lines in matrix form, direction vector normalized
+%             
+% OUTPUT: out[ X;Y;Z ] = `point of intersection` in 3D space
+%   
+
+function out = pofintersectexp(l)
+
+    A(1,1) = sum(l(:,6).^2 + l(:,5).^2) ;    %    A(1,1) + v(3)^2+v(2)^2 ;
+    A(1,2) = sum(-l(:,5).*l(:,4)) ;        %    A(1,2) - v(2)*v(1) ;
+    A(1,3) = sum(-l(:,6).*l(:,4)) ;         %    A(1,3) - v(3)*v(1) ;
+
+    A(2,1) = sum(-l(:,5).*l(:,4)) ;           %    A(2,1) - v(2)*v(1) ;
+    A(2,2) = sum(l(:,6).^2 + l(:,4).^2) ;       %    A(2,2) + v(3)^2+v(1)^2 ;
+    A(2,3) = sum(-l(:,6).*l(:,5)) ;          %    A(2,3) - v(3)*v(2) ;
+
+    A(3,1) = sum(-l(:,4).*l(:,6)) ;           %    A(3,1) - v(1)*v(3) ;
+    A(3,2) = sum(-l(:,5).*l(:,6)) ;            %    A(3,2) - v(2)*v(3) ;
+    A(3,3) = sum(l(:,4).^2 + l(:,5).^2) ;       %    A(3,3) + v(1)^2+v(2)^2 ;
+
+    b(1,1) = sum( (l(:,6).^2+l(:,5).^2).*l(:,1) - l(:,4).*(l(:,6).*l(:,3)+l(:,5).*l(:,2)) ) ;  %  v(3)^2*p(1) + v(2)^2*p(1) - v(3)*v(1)*p(3) - v(2)*v(1)*p(2) ;
+    b(2,1) = sum( (l(:,6).^2+l(:,4).^2).*l(:,2) - l(:,5).*(l(:,6).*l(:,3)+l(:,4).*l(:,1)) ) ;  %  v(3)^2*p(2) + v(1)^2*p(2) - v(3)*v(2)*p(3) - v(2)*v(1)*p(1) ;
+    b(3,1) = sum( (l(:,5).^2+l(:,4).^2).*l(:,3) - l(:,6).*(l(:,5).*l(:,2)+l(:,4).*l(:,1)) ) ;  %  v(2)^2*p(3) + v(1)^2*p(3) - v(3)*v(2)*p(2) - v(1)*v(3)*p(1) ;
+
+out=A\b ;
\ No newline at end of file
diff --git a/4_spot_sorting/pointtolinedist.m b/4_spot_sorting/pointtolinedist.m
new file mode 100755
index 0000000000000000000000000000000000000000..3e67c32fd7e6b5a6924e33cd2fe8d38f629271d8
--- /dev/null
+++ b/4_spot_sorting/pointtolinedist.m
@@ -0,0 +1,20 @@
+%
+% Gives the spatial distance between a point and a line in 3D space.
+% 
+% FUNCTION: pointtolinedist(q,l)
+%
+% INPUT:    coordinates of the point = q[ q_X q_Y q_Z ] 
+%           coordinates of lines = l(i,6) [ line_X line_Y line_Z line_dir_X line_dir_Y line_dir_Z ]
+%
+% OUTPUT:   distance(i,1)
+%
+
+
+function distance = pointtolinedist(q,l)
+
+%distance= norm(cross((q-l(1:3)),l(4:6))/norm(l(4:6)));
+
+for i=1:size(l,1)
+   distance(i,1) = norm(cross((q-l(i,1:3)),l(i,4:6),2)/norm(l(i,4:6)));
+end
+
diff --git a/4_spot_sorting/pointtolinedistsqrsum.m b/4_spot_sorting/pointtolinedistsqrsum.m
new file mode 100755
index 0000000000000000000000000000000000000000..1bb70d74734c40e3557f2cf6a2a384916b34a822
--- /dev/null
+++ b/4_spot_sorting/pointtolinedistsqrsum.m
@@ -0,0 +1,22 @@
+% 
+% FUNCTION pointtolinedistsqrsum(q,l)
+%
+% Given a point 'q' and any number of lines 'l' in 3D space, gives the sum of square of the 'q' to 'l' distances.
+%
+% INPUT:    q [q_X q_Y q_Z]
+%           l(i,6) [ l_X l_Y l_Z l_dir_X l_dir_Y l_dir_Z ]
+%
+% OUTPUT:   distance squared sum
+%
+
+function sqrsum = pointtolinedistsqrsum(q,l)
+
+sqrsum=0 ;
+
+for i=1:size(l,1) 
+    
+    a=cross((q-l(i,1:3)),l(i,4:6))/norm(l(i,4:6));
+    sqrsum = sqrsum + dot(a,a);
+    
+end    
+    
diff --git a/4_spot_sorting/projected_sample.m b/4_spot_sorting/projected_sample.m
new file mode 100755
index 0000000000000000000000000000000000000000..7162c5bb3a389e0971bd4ad677941990a609dc98
--- /dev/null
+++ b/4_spot_sorting/projected_sample.m
@@ -0,0 +1,95 @@
+    %%
+    % Gives the bounding box of the projection of a cylindrical sample as visible on
+    % the detector plane exactly 180 degrees offset
+    % 
+    % INPUT:    Spot position X in its own image = spotX,spotY
+    %             origin: spotX=0 anywhere, e.g. at the left edge of the image; positive to the right in the image
+    %                     spotY=0 anywhere, e.g. at the top of the image, positive downwards
+    %           Radius of the cylindrical sample = sample_radius
+    %           
+    %           Y coordinate in pixels of the top of the illuminated part = sample_top
+    %           Y coordinate in pixels of the bottom of the illuminated part = sample_bot  /sample_top < sample_bot/ 
+    %           Rotation axis to detector plane distance in pixels = rot_to_det
+    %           Position X of the rotation axis projected on the detector plane in pixels = rotx
+    %
+    % OUTPUT:   Bounding-box of projection, upper left and lower right corners in the offset image
+    %             = out[up_leftX; up_leftY; bo_rightX; bo_rightY] or equally [left_edgeX; top_edgeY; right_edgeX; bottom_edgeY]
+    %
+    %   Peter Reischig, ESRF, 11/2006
+    %
+    %   /Verified/
+    %%
+    
+%don't understand why, but seems to not give enough vertical range for a
+%wide but flat sample volume.
+
+
+    
+    
+function out=projected_sample(spotX, spotY, sample_radius, sample_top, sample_bot, rot_to_det, rotx)  
+    
+    spotX=spotX-rotx ;
+    
+    a=sqrt(rot_to_det^2+spotX^2) ;
+    
+    beta=asind(sample_radius/a) ;
+
+    if spotX >=0
+        alpha=asind(rot_to_det/a) ;
+    else
+        alpha=180-asind(rot_to_det/a) ;
+    end
+    
+    out(1,1)=rotx - spotX+2*rot_to_det*cotd(alpha+beta) ;    % upper-left X (left edge)
+    
+    out(2,1)=spotY+(sample_top-spotY)*(2*rot_to_det/(rot_to_det+sign(sample_top-spotY)*sample_radius)) ;   % upper-left Y (top edge, lowest Y)
+    
+    out(3,1)=rotx - spotX+2*rot_to_det*cotd(alpha-beta) ;   % bottom right X (right edge)
+    
+    out(4,1)=spotY+(sample_bot-spotY)*(2*rot_to_det/(rot_to_det-sign(sample_bot-spotY)*sample_radius)) ;   % bottom-right Y (bottom edge, highest Y)
+
+    
+    
+end
+    
+% keyboard
+% 
+% %define sample "corners"
+% corners(1,:) = [sample_radius sample_bot rot_to_det-sample_radius];
+% corners(2,:) = [-sample_radius sample_bot rot_to_det-sample_radius];
+% corners(3,:) = [sample_radius sample_top rot_to_det-sample_radius];
+% corners(4,:) = [-sample_radius sample_top rot_to_det-sample_radius];
+% corners(5,:) = [sample_radius sample_bot rot_to_det+sample_radius];
+% corners(6,:) = [-sample_radius sample_bot rot_to_det+sample_radius];
+% corners(7,:) = [sample_radius sample_top rot_to_det+sample_radius];
+% corners(8,:) = [-sample_radius sample_top rot_to_det+sample_radius];
+% 
+% %done above
+% %spotX=spotX-rotx;
+% 
+% %relative distance from spot to corner
+% deltaX=corners(:,1)-spotX;
+% deltaY=corners(:,2)-spotY;
+% %relative distance from spot to projection of corner
+% deltaX=deltaX.*(2*rot_to_det./corners(:,3));
+% deltaY=deltaY.*(2*rot_to_det./corners(:,3));
+% %take extremes
+% deltaXmin=min(deltaX);
+% deltaXmax=max(deltaX);
+% deltaYmin=min(deltaY);
+% deltaYmax=max(deltaY);
+% %assemble output
+% % leftX (min X)
+% out(1)=spotX+deltaXmin;
+% %allow for rotated detector
+% out(1)=rotx-out(1);
+% % upY (min Y)
+% out(2)=spotY+deltaYmin;
+% % rightX (max X)
+% out(3)=spotX+deltaXmax;
+% %allow for rotated detector
+% out(3)=rotx-out(3);
+% % botY (max Y)
+% out(4)=spotY+deltaYmax;
+
+
diff --git a/4_spot_sorting/sort_grains.m b/4_spot_sorting/sort_grains.m
new file mode 100755
index 0000000000000000000000000000000000000000..be1f2c3f0c7bdfc48290296bbcd46427185f96a5
--- /dev/null
+++ b/4_spot_sorting/sort_grains.m
@@ -0,0 +1,361 @@
+%
+% INPUT:    Two data series of segmented and paired diffraction spots 180 degrees
+%           offset from Spotpair or Calibration tables.
+%
+%
+%   
+% OUTPUT:   Diffraction spots grouped into grains. Location, orientation
+%           and volume of grains are determined. 
+%
+%           
+%           
+
+function [grain,allgrainstat,probl,singlesfit]=sort_grains(dongrains, flag_update, flag_reset)
+
+load parameters.mat
+
+tic
+
+if ~exist('dongrains','var')
+  dongrains=[];
+end
+if isempty(dongrains)
+  dongrains=Inf;
+end
+
+if ~exist('flag_update','var')
+  flag_update=false;
+end
+if ~exist('flag_reset','var')
+  flag_reset=false;
+end
+%% SET PARAMETERS  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% tol.ang=0.2; % (in degrees) later from optimization
+% tol.int=parameters.match.thr_intint; % relative value (>=1)
+% tol.bb=parameters.match.thr_bbsize;
+% tol.geo=10; % (in ) later perhaps from optimization
+% tol.dist=5*parameters.acq.pixelsize; % later perhaps from optimization
+% %tol.distgroup=2*tol.dist % thr_dist of line distance of group consistency 
+
+if isfield(parameters, 'sortgrains')
+    tol=parameters.sortgrains;
+else %use defaults
+  tol.buildgs.ang=1.2;
+  tol.buildgs.int=40;
+  tol.buildgs.bbxs=5;
+  tol.buildgs.bbys=1.4;
+  tol.buildgs.geo=10;
+  tol.buildgs.dist=20
+
+  tol.rodr.inc=0.05;
+  tol.rodr.cons=0.2;
+  tol.rodr.dotspacing=0.001;
+end
+
+
+%% Sample geometry and coordinates in SAMPLE system
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+
+% sorZ = floor(parameters.acq.ydet/2)*parameters.acq.pixelsize
+% 
+% sample.rad= parameters.acq.bb(3)/2*parameters.acq.pixelsize
+% sample.top= sorZ-parameters.acq.bb(2)*parameters.acq.pixelsize
+% sample.bot= sorZ-(parameters.acq.bb(2)+parameters.acq.bb(4))*parameters.acq.pixelsize
+% rottodet=   parameters.acq.dist+parameters.match.corr_rot_to_det*parameters.acq.pixelsize
+% sample.vol= abs(sample_top-sample_bot)*sample_radius^2*pi ; % sample volume in micron^3
+
+sample=gtSampleGeoInSampleSystem(parameters);
+spacegroup=parameters.acq.spacegroup;
+latticepar=parameters.acq.latticepar;
+
+%% Generate angular consistency matrix (ACM)
+
+% allowed angles and their multiplicity according to plane family pairs
+[ACM,ACMU]=gtAngConsMat(spacegroup);  % (in degrees)
+
+[tmp,reflections]=gtnew_calculate_twotheta;
+%comp_2thetas=reflections.centre; % coloumn vector of all valid 2theta angles in degrees
+reflections=reflections.reflections;
+
+
+%% Load data from database
+
+%difspottable=[parameters.acq.difA_name 'difspot'] ;
+pairtable=parameters.acq.pair_tablename ;
+
+gtDBConnect ;
+
+if flag_reset
+  mym(sprintf('UPDATE %s SET grainID=null', pairtable)) ;
+  nof_grains=0; %start from grain 0
+  first_grain=1;
+  %if starting from nothing, initialise
+  allgrainstat.intrel=[];
+  allgrainstat.intrat=[];
+  allgrainstat.bbxsrel=[];
+  allgrainstat.bbysrel=[];
+  allgrainstat.bbxsrat=[];
+  allgrainstat.bbysrat=[];
+  allgrainstat.distcom=[];
+  allgrainstat.distlines=[];
+  allgrainstat.angplanes=[];
+  % Detected problems:
+  probl.grains_rodr=[];
+  probl.pair_int=[];
+  probl.pair_bbxs=[];
+  probl.pair_bbys=[];
+  probl.pair_distcom=[];
+else
+  %don't reset grain ids
+  nof_grains=mym(sprintf('select max(grainid) from %s', pairtable));
+  first_grain=nof_grains+1;
+  load sort_grains_lastrun   %%%%%%%%%%modif sabine
+end
+
+mymcmd=sprintf(['SELECT pairID, difAID, difBID, theta, eta, omega, '...
+  'avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, '...
+  'samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, '...
+  'thetatype FROM %s ORDER BY avintint desc'],pairtable);
+
+
+if strcmp(parameters.acq.name, 'Andras8_') | strcmp(parameters.acq.name, 'Mg_fatigue1_')
+  %to work with only the remaining unassigned to grains) pairs
+  mymcmd=sprintf(['SELECT pairID, difAID, difBID, theta, eta, omega, '...
+  'avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, '...
+  'samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, '...
+  'thetatype FROM %s WHERE isnull(grainid) ORDER BY avintint desc'],pairtable);
+end
+
+
+[tot.pairid,tot.aid,tot.bid,tot.theta,tot.eta,tot.omega,tot.int,tot.bbxs,tot.bbys, ...
+  tot.ca(:,1),tot.ca(:,2),tot.ca(:,3),tot.cb(:,1),tot.cb(:,2),tot.cb(:,3),tot.dir(:,1),tot.dir(:,2),tot.dir(:,3), ...
+  tot.pl(:,1),tot.pl(:,2),tot.pl(:,3),tot.thetatype]=mym(mymcmd);
+
+nof_lines=length(tot.pairid) ;
+nof_thetatypes=max(tot.thetatype);
+grouped=false(nof_lines,1);
+
+
+% Make sure directions are normalized 
+% (e.g. acosd function after rounding errors from database)
+pllength=sqrt(tot.pl(:,1).^2 + tot.pl(:,2).^2 + tot.pl(:,3).^2) ;
+tot.pl=[tot.pl(:,1)./pllength tot.pl(:,2)./pllength tot.pl(:,3)./pllength] ;
+
+dirlength=sqrt(tot.dir(:,1).^2 + tot.dir(:,2).^2 + tot.dir(:,3).^2) ;
+tot.dir=[tot.dir(:,1)./dirlength tot.dir(:,2)./dirlength tot.dir(:,3)./dirlength] ;
+
+% id-s will not correspond to pairID-s !!!
+tot.id=(1:nof_lines)';
+
+tot.hkl=zeros(nof_lines,3);
+for i=1:nof_thetatypes
+  for j=1:nof_lines
+    if tot.thetatype(j)==i
+        %modif sabine
+       if (spacegroup==663 || spacegroup==194) %ie if hexagonal
+           tot.hkl(j,1:4)=reflections(i,1:4);
+       else
+           tot.hkl(j,1:3)=reflections(i,1:3);
+       end
+            %fin modif sabine
+      %tot.hkl(j,1:3)=reflections(i,1:3);
+      %Rv=gtRodriguesVectors(tot.pl(j,:),tot.hkl(j,:),spacegroup);
+      %tot.lRv(1:size(Rv,1),1:size(Rv,2),i)=Rv;
+    end
+  end
+end
+
+
+%% Search for groups (grains)
+
+remaining=1:nof_lines; % list of all lines not yet grouped
+singles=[];
+
+
+
+while length(remaining)>=1
+  
+  act=gtKeepLine(remaining(1),tot);
+  cand_rem=gtKeepLine(remaining(2:end),tot);
+  
+  [paircons,progress,cand0]=gtCheckPairCons(act,cand_rem,tol.buildgs,sample,ACM);
+  % modif sabine
+  %[pgood,grainoutput]=gtFindGroupInCand(cand,tol,sample,ACM,spacegroup)
+  %[pgood,grainoutput]=gtFindGroupInCand(cand0,tol,sample,ACM,spacegroup)
+  % end modif sabine
+  
+  if length(paircons)>3
+    cand_paircons=gtKeepLine([act.id; cand0.id],tot);
+    %keyboard
+    [pgroup,grainoutput]=gtFindGroupInCand(cand_paircons,tol.buildgs,sample,ACM,spacegroup);
+    
+    if sum(pgroup)>1
+      nof_grains=nof_grains+1;
+      grain{nof_grains}=grainoutput;
+      grain{nof_grains}.id=nof_grains;
+      disp(['Grain ' num2str(nof_grains)])
+      disp(grain{nof_grains}.pairid)
+      todel=cand_paircons.id(pgroup);
+    else
+      singles=[singles; act.id];
+      todel=act.id;
+    end
+  else
+    singles=[singles; act.id];
+    todel=act.id;
+  end
+
+  for i=1:length(todel)
+    remaining(remaining==todel(i))=[];
+  end
+  
+  if nof_grains>=dongrains
+    break
+  end
+
+end
+
+
+% Grain statistics for output, grain check
+%do just the "new" grains - those created in this run
+% modif sabine
+
+
+for i=first_grain:nof_grains
+   % i
+  allgrainstat.intrel=[allgrainstat.intrel, grain{i}.stat.intrel];
+  allgrainstat.intrat=[allgrainstat.intrat, grain{i}.stat.intrat];
+  allgrainstat.bbxsrel=[allgrainstat.bbxsrel, grain{i}.stat.bbxsrel];
+  allgrainstat.bbysrel=[allgrainstat.bbysrel, grain{i}.stat.bbysrel];
+  allgrainstat.bbxsrat=[allgrainstat.bbxsrat, grain{i}.stat.bbxsrat];
+  allgrainstat.bbysrat=[allgrainstat.bbysrat, grain{i}.stat.bbysrat];
+  allgrainstat.distcom=[allgrainstat.distcom, grain{i}.stat.distcom];
+  allgrainstat.distlines=[allgrainstat.distlines, grain{i}.stat.distlines];
+  allgrainstat.angplanes=[allgrainstat.angplanes, grain{i}.stat.angplanes];
+ 
+  grouped(grain{i}.lid)=true;
+  
+  % Check grain consistency in Rodrigues space
+  [R_vector,rodr_goods]=plot_rodrigues_consistancy_test(grain{i}.pl,grain{i}.hkl,0,tol.rodr);
+  if ~all(rodr_goods)
+    probl.grains_rodr=[probl.grains_rodr, i]; % mark as problematic
+  end
+  grain{i}.R_vector=R_vector;  
+
+  difAID=[];
+  difBID=[];
+  
+  % Set grainID in pairtable
+  for j=1:length(grain{i}.pairid)
+    if flag_update
+      mysqlcmd=sprintf('UPDATE %s SET grainID=%d WHERE pairID=%d',pairtable,i,grain{i}.pairid(j));
+      mym(mysqlcmd);
+    end
+    
+    mysqlcmd=sprintf('SELECT difAID,difBID FROM %s WHERE pairID=%d',pairtable,grain{i}.pairid(j));
+    [difAID(j),difBID(j)]=mym(mysqlcmd);
+
+    % Line to grain (point) distance in Rodrigues space:
+    Rv=gtRodriguesVectors(grain{i}.pl(j,:),grain{i}.hkl(j,:),spacegroup);
+
+    grain{i}.stat.lRdist(j)=min(pointtolinedist(grain{i}.R_vector,Rv));
+    
+  end
+  
+  grain{i}.difspots=[difAID, difBID];
+
+
+  % Mean and standard deviation of distance in Rodrigues space
+  grain{i}.stat.lRdistmean=mean(grain{i}.stat.lRdist);
+  grain{i}.stat.lRdiststd=std(grain{i}.stat.lRdist);
+
+
+  if ~isempty(grain{i}.stat.outl.int)
+    probl.pair_int=[probl.pair_int; [i grain{i}.stat.outl.int]]; % mark as problem
+  end
+  if ~isempty(grain{i}.stat.outl.bbxs)
+    probl.pair_bbxs=[probl.pair_bbxs; [i grain{i}.stat.outl.bbxs]]; % mark as problem
+  end
+  if ~isempty(grain{i}.stat.outl.bbys)
+    probl.pair_bbys=[probl.pair_bbys; [i grain{i}.stat.outl.bbys]]; % mark as problem
+  end
+  if ~isempty(grain{i}.stat.outl.distcom)
+    probl.pair_distcom=[probl.pair_distcom; [i grain{i}.stat.outl.distcom]]; % mark as problem
+  end
+
+end
+
+
+group=gtKeepLine(grouped,tot);
+singles=gtKeepLine(singles,tot);
+
+disp(' ')
+disp('Total number of diffraction spot pairs:'), disp(length(tot.id)) ;
+disp('Number of diffraction spots grouped:'), disp(length(group.id)) ;
+disp('Number of singles in the set:'), disp(length(singles.id)) ;
+disp('Number of grains found:'), disp(length(grain)) ;
+disp('Incosistent grains in Rodrigues space:')
+disp(probl.grains_rodr)
+
+toc
+
+nof_bins=nof_grains;
+
+figure('name','Eta vs theta from grouped pairs')
+ plot(group.theta,group.eta,'b.')
+
+figure('name','Grain stat.: relative intensities')
+ hist(allgrainstat.intrel,nof_bins)
+
+figure('name','Grain stat.: intensities max ratio')
+ hist(allgrainstat.intrat,round(nof_bins/10))
+ 
+figure('name','Grain stat.: relative bbox X size')
+ hist(allgrainstat.bbxsrel,nof_bins)
+ 
+figure('name','Grain stat.: relative bbox Y size')
+ hist(allgrainstat.bbysrel,nof_bins)
+
+figure('name','Grain stat.: bbox X size max ratio')
+ hist(allgrainstat.bbxsrat,round(nof_bins/10))
+ 
+figure('name','Grain stat.: bbox Y size max ratio')
+ hist(allgrainstat.bbysrat,round(nof_bins/10))
+ 
+figure('name','Grain stat.: distances to grain center')
+ hist(allgrainstat.distcom,nof_bins)
+
+figure('name','Grain stat.: line distances')
+ hist(allgrainstat.distlines,nof_bins)
+ 
+figure('name','Grain stat.: plane angle deviation')
+ hist(allgrainstat.angplanes,nof_bins)
+
+ 
+save('sort_grains_intermediate.mat','grain','group','allgrainstat');  % intermediate saving before singles 
+ 
+
+disp('Treating singles...')
+if ~isempty(singles.id) %if no singles, then skip
+  singlesfit=gtIndexFitSinglesToGrains(singles,grain,spacegroup);
+else
+  singlesfit=[];
+end
+
+grain=gtINUniquePlaneNormals_sab(grain,ACM);
+grain=gtAddGrainLatticePar(grain); 
+
+
+if flag_update
+  save('sort_grains_lastrun.mat','grain','singles','singlesfit','allgrainstat','probl','tol');
+end
+
+end % of function
+
+
+
+
diff --git a/4_spot_sorting/sort_grains_sab.m b/4_spot_sorting/sort_grains_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..db3bb0e55c669c2eff42d93abef96aa3b558ad6c
--- /dev/null
+++ b/4_spot_sorting/sort_grains_sab.m
@@ -0,0 +1,371 @@
+%
+% INPUT:    Two data series of segmented and paired diffraction spots 180 degrees
+%           offset from Spotpair or Calibration tables.
+%
+%
+%   
+% OUTPUT:   Diffraction spots grouped into grains. Location, orientation
+%           and volume of grains are determined. 
+%
+%           
+%           
+
+function [grain,allgrainstat,probl,singlesfit]=sort_grains(dongrains, flag_update, flag_reset)
+
+load parameters.mat
+
+tic
+
+if ~exist('dongrains','var')
+  dongrains=[];
+end
+if isempty(dongrains)
+  dongrains=Inf;
+end
+
+if ~exist('flag_update','var')
+  flag_update=false;
+end
+if ~exist('flag_reset','var')
+  flag_reset=false;
+end
+%% SET PARAMETERS  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% tol.ang=0.2; % (in degrees) later from optimization
+% tol.int=parameters.match.thr_intint; % relative value (>=1)
+% tol.bb=parameters.match.thr_bbsize;
+% tol.geo=10; % (in ) later perhaps from optimization
+% tol.dist=5*parameters.acq.pixelsize; % later perhaps from optimization
+% %tol.distgroup=2*tol.dist % thr_dist of line distance of group consistency 
+
+if isfield(parameters, 'sortgrains')
+    tol=parameters.sortgrains;
+else %use defaults
+  tol.buildgs.ang=1.2;
+  tol.buildgs.int=40;
+  tol.buildgs.bbxs=5;
+  tol.buildgs.bbys=1.4;
+  tol.buildgs.geo=10;
+  tol.buildgs.dist=20
+
+  tol.rodr.inc=0.05;
+  tol.rodr.cons=0.2;
+  tol.rodr.dotspacing=0.001;
+end
+
+
+%% Sample geometry and coordinates in SAMPLE system
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+
+% sorZ = floor(parameters.acq.ydet/2)*parameters.acq.pixelsize
+% 
+% sample.rad= parameters.acq.bb(3)/2*parameters.acq.pixelsize
+% sample.top= sorZ-parameters.acq.bb(2)*parameters.acq.pixelsize
+% sample.bot= sorZ-(parameters.acq.bb(2)+parameters.acq.bb(4))*parameters.acq.pixelsize
+% rottodet=   parameters.acq.dist+parameters.match.corr_rot_to_det*parameters.acq.pixelsize
+% sample.vol= abs(sample_top-sample_bot)*sample_radius^2*pi ; % sample volume in micron^3
+
+sample=gtSampleGeoInSampleSystem(parameters);
+spacegroup=parameters.acq.spacegroup;
+latticepar=parameters.acq.latticepar;
+
+%% Generate angular consistency matrix (ACM)
+
+% allowed angles and their multiplicity according to plane family pairs
+[ACM,ACMU]=gtAngConsMat(spacegroup);  % (in degrees)
+
+[tmp,reflections]=gtnew_calculate_twotheta;
+%comp_2thetas=reflections.centre; % coloumn vector of all valid 2theta angles in degrees
+reflections=reflections.reflections;
+
+
+%% Load data from database
+
+%difspottable=[parameters.acq.difA_name 'difspot'] ;
+pairtable=parameters.acq.pair_tablename ;
+
+gtDBConnect ;
+
+if flag_reset
+  mym(sprintf('UPDATE %s SET grainID=null', pairtable)) ;
+  nof_grains=0; %start from grain 0
+  first_grain=1;
+  %if starting from nothing, initialise
+  allgrainstat.intrel=[];
+  allgrainstat.intrat=[];
+  allgrainstat.bbxsrel=[];
+  allgrainstat.bbysrel=[];
+  allgrainstat.bbxsrat=[];
+  allgrainstat.bbysrat=[];
+  allgrainstat.distcom=[];
+  allgrainstat.distlines=[];
+  allgrainstat.angplanes=[];
+  % Detected problems:
+  probl.grains_rodr=[];
+  probl.pair_int=[];
+  probl.pair_bbxs=[];
+  probl.pair_bbys=[];
+  probl.pair_distcom=[];
+else
+  %don't reset grain ids
+  nof_grains=mym(sprintf('select max(grainid) from %s', pairtable));
+  first_grain=nof_grains+1;
+  load sort_grains_lastrun   %%%%%%%%%%modif sabine
+end
+
+mymcmd=sprintf(['SELECT pairID, difAID, difBID, theta, eta, omega, '...
+  'avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, '...
+  'samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, '...
+  'thetatype FROM %s ORDER BY avintint desc'],pairtable);
+
+
+if strcmp(parameters.acq.name, 'Andras8_') | strcmp(parameters.acq.name, 'Mg_fatigue1_')
+  %to work with only the remaining unassigned to grains) pairs
+  mymcmd=sprintf(['SELECT pairID, difAID, difBID, theta, eta, omega, '...
+  'avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, '...
+  'samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, '...
+  'thetatype FROM %s WHERE isnull(grainid) ORDER BY avintint desc'],pairtable);
+end
+
+
+[tot.pairid,tot.aid,tot.bid,tot.theta,tot.eta,tot.omega,tot.int,tot.bbxs,tot.bbys, ...
+  tot.ca(:,1),tot.ca(:,2),tot.ca(:,3),tot.cb(:,1),tot.cb(:,2),tot.cb(:,3),tot.dir(:,1),tot.dir(:,2),tot.dir(:,3), ...
+  tot.pl(:,1),tot.pl(:,2),tot.pl(:,3),tot.thetatype]=mym(mymcmd);
+
+nof_lines=length(tot.pairid) ;
+nof_thetatypes=max(tot.thetatype);
+grouped=false(nof_lines,1);
+
+
+% Make sure directions are normalized 
+% (e.g. acosd function after rounding errors from database)
+pllength=sqrt(tot.pl(:,1).^2 + tot.pl(:,2).^2 + tot.pl(:,3).^2) ;
+tot.pl=[tot.pl(:,1)./pllength tot.pl(:,2)./pllength tot.pl(:,3)./pllength] ;
+
+dirlength=sqrt(tot.dir(:,1).^2 + tot.dir(:,2).^2 + tot.dir(:,3).^2) ;
+tot.dir=[tot.dir(:,1)./dirlength tot.dir(:,2)./dirlength tot.dir(:,3)./dirlength] ;
+
+% id-s will not correspond to pairID-s !!!
+tot.id=(1:nof_lines)';
+
+tot.hkl=zeros(nof_lines,3);
+for i=1:nof_thetatypes
+  for j=1:nof_lines
+    if tot.thetatype(j)==i
+        %modif sabine
+       if (spacegroup==663 || spacegroup==194) %ie if hexagonal
+           tot.hkl(j,1:4)=reflections(i,1:4);
+       else
+           tot.hkl(j,1:3)=reflections(i,1:3);
+       end
+            %fin modif sabine
+      %tot.hkl(j,1:3)=reflections(i,1:3);
+      %Rv=gtRodriguesVectors(tot.pl(j,:),tot.hkl(j,:),spacegroup);
+      %tot.lRv(1:size(Rv,1),1:size(Rv,2),i)=Rv;
+    end
+  end
+end
+
+
+%% Search for groups (grains)
+
+remaining=1:nof_lines; % list of all lines not yet grouped
+singles=[];
+
+
+
+while length(remaining)>=1
+  
+  act=gtKeepLine(remaining(1),tot);
+  cand_rem=gtKeepLine(remaining(2:end),tot);
+  
+  [paircons,progress,cand0]=gtCheckPairCons(act,cand_rem,tol.buildgs,sample,ACM);
+  % [pgood,grainoutput]=gtFindGroupInCand(cand,tol,sample,ACM,spacegroup)
+  
+  if length(paircons)>3
+    cand_paircons=gtKeepLine([act.id; cand0.id],tot);
+    [pgroup,grainoutput]=gtFindGroupInCand_sab(cand_paircons,tol.buildgs,sample,ACM,spacegroup);
+    
+    if sum(pgroup)>1
+      nof_grains=nof_grains+1;
+      grain{nof_grains}=grainoutput;
+      grain{nof_grains}.id=nof_grains;
+      disp(['Grain ' num2str(nof_grains)])
+      disp(grain{nof_grains}.pairid)
+      todel=cand_paircons.id(pgroup);
+    else
+      singles=[singles; act.id];
+      todel=act.id;
+    end
+  else
+    singles=[singles; act.id];
+    todel=act.id;
+  end
+
+  for i=1:length(todel)
+    remaining(remaining==todel(i))=[];
+  end
+  
+  if nof_grains>=dongrains
+    break
+  end
+
+end
+
+
+% Grain statistics for output, grain check
+%do just the "new" grains - those created in this run
+
+% keyboard 
+
+
+
+for i=first_grain:nof_grains
+   % i
+%    allgrainstat.intrel=[allgrainstat.intrel, grain{i}.stat.intrel];
+%   allgrainstat.intrat=[allgrainstat.intrat, grain{i}.stat.intrat];
+%   allgrainstat.bbxsrel=[allgrainstat.bbxsrel, grain{i}.stat.bbxsrel];
+%   allgrainstat.bbysrel=[allgrainstat.bbysrel, grain{i}.stat.bbysrel];
+%   allgrainstat.bbxsrat=[allgrainstat.bbxsrat, grain{i}.stat.bbxsrat];
+%   allgrainstat.bbysrat=[allgrainstat.bbysrat, grain{i}.stat.bbysrat];
+%   allgrainstat.distcom=[allgrainstat.distcom, grain{i}.stat.distcom];
+%   allgrainstat.distlines=[allgrainstat.distlines, grain{i}.stat.distlines];
+%   allgrainstat.angplanes=[allgrainstat.angplanes, grain{i}.stat.angplanes];
+ 
+  grouped(grain{i}.lid)=true;
+  
+  % Check grain consistency in Rodrigues space
+  [R_vector,rodr_goods]=plot_rodrigues_consistancy_test(grain{i}.pl,grain{i}.hkl,0,tol.rodr);
+  if ~all(rodr_goods)
+    probl.grains_rodr=[probl.grains_rodr, i]; % mark as problematic
+  end
+  grain{i}.R_vector=R_vector;  
+
+  difAID=[];
+  difBID=[];
+  
+  % Set grainID in pairtable
+  for j=1:length(grain{i}.pairid)
+    if flag_update
+      mysqlcmd=sprintf('UPDATE %s SET grainID=%d WHERE pairID=%d',pairtable,i,grain{i}.pairid(j));
+      mym(mysqlcmd);
+    end
+    
+    mysqlcmd=sprintf('SELECT difAID,difBID FROM %s WHERE pairID=%d',pairtable,grain{i}.pairid(j));
+    [difAID(j),difBID(j)]=mym(mysqlcmd);
+
+    % Line to grain (point) distance in Rodrigues space:
+    Rv=gtRodriguesVectors(grain{i}.pl(j,:),grain{i}.hkl(j,:),spacegroup);
+
+    grain{i}.stat.lRdist(j)=min(pointtolinedist(grain{i}.R_vector,Rv));
+    
+  end
+  
+  grain{i}.difspots=[difAID, difBID];
+
+
+  % Mean and standard deviation of distance in Rodrigues space
+  grain{i}.stat.lRdistmean=mean(grain{i}.stat.lRdist);
+  grain{i}.stat.lRdiststd=std(grain{i}.stat.lRdist);
+
+
+  if ~isempty(grain{i}.stat.outl.int)
+      % modif sabine a tester
+      diff=size(probl.pair_int,2)-(size(grain{i}.stat.outl.int,2)+1);
+      if diff >= 0
+          toto=zeros(size(probl.pair_int,2),1)';
+          toto(1:size(grain{i}.stat.outl.int,2)+1)=[i grain{i}.stat.outl.int]';
+          probl.pair_int=[probl.pair_int; toto];% mark as problem
+      elseif isempty(probl.pair_int)
+          probl.pair_int=[i grain{i}.stat.outl.int];
+      else
+          keyboard
+          disp('to do...');
+      end
+    % fin modif sabine
+  end
+  if ~isempty(grain{i}.stat.outl.bbxs)
+    probl.pair_bbxs=[probl.pair_bbxs; [i grain{i}.stat.outl.bbxs]]; % mark as problem
+  end
+  if ~isempty(grain{i}.stat.outl.bbys)
+    probl.pair_bbys=[probl.pair_bbys; [i grain{i}.stat.outl.bbys]]; % mark as problem
+  end
+  if ~isempty(grain{i}.stat.outl.distcom)
+    probl.pair_distcom=[probl.pair_distcom; [i grain{i}.stat.outl.distcom]]; % mark as problem
+  end
+
+end
+
+
+group=gtKeepLine(grouped,tot);
+singles=gtKeepLine(singles,tot);
+
+disp(' ')
+disp('Total number of diffraction spot pairs:'), disp(length(tot.id)) ;
+disp('Number of diffraction spots grouped:'), disp(length(group.id)) ;
+disp('Number of singles in the set:'), disp(length(singles.id)) ;
+disp('Number of grains found:'), disp(length(grain)) ;
+disp('Incosistent grains in Rodrigues space:')
+disp(probl.grains_rodr)
+
+toc
+
+nof_bins=nof_grains;
+
+figure('name','Eta vs theta from grouped pairs')
+ plot(group.theta,group.eta,'b.')
+
+figure('name','Grain stat.: relative intensities')
+ hist(allgrainstat.intrel,nof_bins)
+
+figure('name','Grain stat.: intensities max ratio')
+ hist(allgrainstat.intrat,round(nof_bins/10))
+ 
+figure('name','Grain stat.: relative bbox X size')
+ hist(allgrainstat.bbxsrel,nof_bins)
+ 
+figure('name','Grain stat.: relative bbox Y size')
+ hist(allgrainstat.bbysrel,nof_bins)
+
+figure('name','Grain stat.: bbox X size max ratio')
+ hist(allgrainstat.bbxsrat,round(nof_bins/10))
+ 
+figure('name','Grain stat.: bbox Y size max ratio')
+ hist(allgrainstat.bbysrat,round(nof_bins/10))
+ 
+figure('name','Grain stat.: distances to grain center')
+ hist(allgrainstat.distcom,nof_bins)
+
+figure('name','Grain stat.: line distances')
+ hist(allgrainstat.distlines,nof_bins)
+ 
+figure('name','Grain stat.: plane angle deviation')
+ hist(allgrainstat.angplanes,nof_bins)
+
+ 
+save('sort_grains_intermediate.mat','grain','group','allgrainstat');  % intermediate saving before singles 
+ 
+
+disp('Treating singles...')
+if ~isempty(singles.id) %if no singles, then skip
+  singlesfit=gtIndexFitSinglesToGrains(singles,grain,spacegroup);
+else
+  singlesfit=[];
+end
+
+grain=gtINUniquePlaneNormals_sab(grain,ACM);
+grain=gtAddGrainLatticePar(grain); 
+
+
+if flag_update
+  save('sort_grains_lastrun.mat','grain','singles','singlesfit','allgrainstat','probl','tol');
+end
+
+end % of function
+
+
+
+
diff --git a/5_reconstruction/Difspot_lastandprevious.m b/5_reconstruction/Difspot_lastandprevious.m
new file mode 100755
index 0000000000000000000000000000000000000000..4dace96581ce09cad5c9a592d5b85f9e47bea1e1
--- /dev/null
+++ b/5_reconstruction/Difspot_lastandprevious.m
@@ -0,0 +1,25 @@
+function spot=Difspot_lastandprevious(ndx, dataset)
+%returns the summed difspot image (saved as difspot%05d.edf)
+%for 360 datasets, can refer to either half of scan (A or B).  If ABflag is
+%empty, defaults to the working directory as normal
+
+global parameters
+
+clear parameters
+load(sprintf('/data/id19/graintracking/graingrowth/%s/parameters.mat', dataset));
+
+%if isempty(parameters)
+ % disp('Loading parameter file')
+  %load('parameters.mat');
+%end
+
+name=parameters.acq.name;
+path=sprintf('../%s/',name);
+
+difID = ndx;
+
+spot=edf_read(sprintf('%s2_difspot/difspot/difspot%05d.edf',path,difID));
+
+
+
+end
diff --git a/5_reconstruction/Difspot_lastandprevious2.m b/5_reconstruction/Difspot_lastandprevious2.m
new file mode 100755
index 0000000000000000000000000000000000000000..4be855a4af2e266627239d3343df515d7ea6248b
--- /dev/null
+++ b/5_reconstruction/Difspot_lastandprevious2.m
@@ -0,0 +1,25 @@
+function spot=DifSpot_lastandprevious2(ndx, dataset)
+%returns the summed difspot image (saved as difspot%05d.edf)
+%for 360 datasets, can refer to either half of scan (A or B).  If ABflag is
+%empty, defaults to the working directory as normal
+
+global parameters
+
+clear parameters
+load(sprintf('/data/id19/graintracking/graingrowth/%s/parameters.mat', dataset))
+
+%if isempty(parameters)
+ % disp('Loading parameter file')
+  %load('parameters.mat');
+%end
+
+name=parameters.acq.name;
+path=sprintf('../%s/',name);
+
+difID = ndx;
+
+spot=edf_read(sprintf('%s2_difspot/difspot/difspot%05d.edf',path,difID));
+
+
+
+end
diff --git a/5_reconstruction/ExtSpot_lastandprevious.m b/5_reconstruction/ExtSpot_lastandprevious.m
new file mode 100755
index 0000000000000000000000000000000000000000..40be270310096a57972a59387026ae399a2d6171
--- /dev/null
+++ b/5_reconstruction/ExtSpot_lastandprevious.m
@@ -0,0 +1,93 @@
+function [im, bb3, bb4]=ExtSpot_lastandprevious(struct_id,dataset, varargin)
+% returns the summed full extinction spot image
+% conversion to database complete
+
+global parameters;
+clear parameters
+load(sprintf('/data/id19/graintracking/graingrowth/%s/parameters.mat', dataset));
+%if isempty(parameters)
+  %disp('Loading parameter file')
+  %load('parameters.mat');
+%end
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+warning('contains proper bodged bb faffing, make nice after rerunning autofind')
+
+
+[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select Xorigin,Yorigin,Xsize,Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  struct_id));
+
+bb3=bb(3);
+bb4=bb(4);
+%get snake if possible, else use difspot silhouette
+if mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',...
+    parameters.acq.name,...
+    struct_id)) == true;
+
+ 
+%put snake relative to boundingbox
+mysqlcmd=sprintf('select x,y from %ssnakes where snakeID=%d',parameters.acq.name,struct_id);
+
+[snakex,snakey]=mym(mysqlcmd);
+snakex = snakex - floor(bb(1));
+snakey = snakey - floor(bb(2));
+mask = poly2mask(snakex, snakey, bb(4), bb(3));
+
+
+
+else
+  disp('Not using snake')
+%if we don't have a snake
+summeddif=gtGetSummedDifSpot(struct_id);
+
+%chqnge all this - save snake input in table during autofind, and reread
+%after.  This recreation is stupuid
+summeddif_bw=summeddif>0.25*max(summeddif(:));
+summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+mask=bwmorph(summeddif_bw,'dilate',1);
+%%crop mask here
+tmp2=regionprops(double(mask),'BoundingBox');
+tmp2=tmp2.BoundingBox;
+  
+tmp2=ceil(tmp2);%gt convention
+
+mask = gtCrop(mask,tmp2);
+bb(3:4)=tmp2(3:4);%change this!
+
+
+end
+
+%put BoundingBox into coordinates of the full image
+%not needed if using ext images, only if using the middle bit of fulls
+%bb(1) = ceil(bb(1) + parameters.acq.bb(1));
+%bb(2) = ceil(bb(2) + parameters.acq.bb(2));
+
+im=zeros(bb(4), bb(3));
+
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',parameters.acq.name,struct_id);
+[first,last]=mym(mysqlcmd);
+
+%disp([num2str(last-first+1) ' images in sum'])
+
+for i=first:last
+  im = im + edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',parameters.acq.dir,i), bb);
+end
+
+%apply mask , either from snake or from difspot silhouette
+im = im.*mask;
+
+
diff --git a/5_reconstruction/ExtSpot_lastandprevious2.m b/5_reconstruction/ExtSpot_lastandprevious2.m
new file mode 100755
index 0000000000000000000000000000000000000000..7eaf76c351f9d21b7b19c4371f0e0eba5826882b
--- /dev/null
+++ b/5_reconstruction/ExtSpot_lastandprevious2.m
@@ -0,0 +1,99 @@
+function [im, bb3, bb4]=ExtSpot_lastandprevious2(struct_id, bb53, bb54, dataset, varargin)
+% returns the summed full extinction spot image
+% conversion to database complete
+
+global parameters;
+clear parameters
+load(sprintf('/data/id19/graintracking/graingrowth/%s/parameters.mat',dataset))
+%if isempty(parameters)
+  %disp('Loading parameter file')
+  %load('parameters.mat');
+%end
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+warning('contains proper bodged bb faffing, make nice after rerunning autofind')
+
+
+[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select Xorigin,Yorigin,Xsize,Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  struct_id));
+
+if bb(3)<bb53
+	bb(3)=bb53;
+end
+if bb(4)<bb54
+	bb(4)=bb54;
+end
+bb3=bb(3);
+bb4=bb(4);
+
+%get snake if possible, else use difspot silhouette
+if mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',...
+    parameters.acq.name,...
+    struct_id)) == true;
+
+ 
+%put snake relative to boundingbox
+mysqlcmd=sprintf('select x,y from %ssnakes where snakeID=%d',parameters.acq.name,struct_id);
+
+[snakex,snakey]=mym(mysqlcmd);
+snakex = snakex - floor(bb(1));
+snakey = snakey - floor(bb(2));
+mask = poly2mask(snakex, snakey, bb(4), bb(3));
+
+
+
+else
+  disp('Not using snake')
+%if we don't have a snake
+summeddif=gtGetSummedDifSpot(struct_id);
+
+%chqnge all this - save snake input in table during autofind, and reread
+%after.  This recreation is stupuid
+summeddif_bw=summeddif>0.25*max(summeddif(:));
+summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+mask=bwmorph(summeddif_bw,'dilate',1);
+%%crop mask here
+tmp2=regionprops(double(mask),'BoundingBox');
+tmp2=tmp2.BoundingBox;
+  
+tmp2=ceil(tmp2);%gt convention
+
+mask = gtCrop(mask,tmp2);
+bb(3:4)=tmp2(3:4);%change this!
+
+end
+
+%put BoundingBox into coordinates of the full image
+%not needed if using ext images, only if using the middle bit of fulls
+%bb(1) = ceil(bb(1) + parameters.acq.bb(1));
+%bb(2) = ceil(bb(2) + parameters.acq.bb(2));
+
+im=zeros(bb(4), bb(3));
+
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',parameters.acq.name,struct_id);
+[first,last]=mym(mysqlcmd);
+
+%disp([num2str(last-first+1) ' images in sum'])
+
+for i=first:last
+  im = im + edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',parameters.acq.dir,i), bb);
+end
+
+%apply mask , either from snake or from difspot silhouette
+im = im.*mask;
+
+
diff --git a/5_reconstruction/ExtSpot_lastandprevious3.m b/5_reconstruction/ExtSpot_lastandprevious3.m
new file mode 100755
index 0000000000000000000000000000000000000000..5c66dbc48ce364656a726b695022ecf04a4b4562
--- /dev/null
+++ b/5_reconstruction/ExtSpot_lastandprevious3.m
@@ -0,0 +1,93 @@
+function im=ExtSpot_lastandprevious3(struct_id,bb3,bb4,dataset, varargin)
+% returns the summed full extinction spot image
+% conversion to database complete
+
+global parameters;
+clear parameters
+load(sprintf('/data/id19/graintracking/graingrowth/%s/parameters.mat', dataset))
+%if isempty(parameters)
+  %disp('Loading parameter file')
+  %load('parameters.mat');
+%end
+
+% connect to database
+connected=0;
+if ~isempty(varargin)
+	connected=varargin{1};
+end
+if ~connected
+gtDBConnect
+end
+
+warning('contains proper bodged bb faffing, make nice after rerunning autofind')
+
+
+[bb(1),bb(2),bb(3),bb(4)]=mym(sprintf('select Xorigin,Yorigin,Xsize,Ysize from %sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID where %sbb.extspotID = %d', ...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  parameters.acq.name,...
+  struct_id));
+
+bb(3)=bb3;
+bb(4)=bb4;
+%get snake if possible, else use difspot silhouette
+if mym(sprintf('select !isnull(bbID) from %sextspot where extspotID=%d',...
+    parameters.acq.name,...
+    struct_id)) == true;
+
+ 
+%put snake relative to boundingbox
+mysqlcmd=sprintf('select x,y from %ssnakes where snakeID=%d',parameters.acq.name,struct_id);
+
+[snakex,snakey]=mym(mysqlcmd);
+snakex = snakex - floor(bb(1));
+snakey = snakey - floor(bb(2));
+mask = poly2mask(snakex, snakey, bb(4), bb(3));
+
+
+
+else
+  disp('Not using snake')
+%if we don't have a snake
+summeddif=gtGetSummedDifSpot(struct_id);
+
+%chqnge all this - save snake input in table during autofind, and reread
+%after.  This recreation is stupuid
+summeddif_bw=summeddif>0.25*max(summeddif(:));
+summeddif_bw=bwmorph(summeddif_bw,'spur',inf);
+summeddif_bw=bwmorph(summeddif_bw,'erode',1);
+mask=bwmorph(summeddif_bw,'dilate',1);
+%%crop mask here
+tmp2=regionprops(double(mask),'BoundingBox');
+tmp2=tmp2.BoundingBox;
+  
+tmp2=ceil(tmp2);%gt convention
+
+mask = gtCrop(mask,tmp2);
+bb(3:4)=tmp2(3:4);%change this!
+
+
+end
+
+%put BoundingBox into coordinates of the full image
+%not needed if using ext images, only if using the middle bit of fulls
+%bb(1) = ceil(bb(1) + parameters.acq.bb(1));
+%bb(2) = ceil(bb(2) + parameters.acq.bb(2));
+
+im=zeros(bb(4), bb(3));
+
+mysqlcmd=sprintf('select ExtStartImage,ExtEndImage from %sdifspot where difspotID=%d',parameters.acq.name,struct_id);
+[first,last]=mym(mysqlcmd);
+
+%disp([num2str(last-first+1) ' images in sum'])
+
+for i=first:last
+  im = im + edf_read(sprintf('%s/1_preprocessing/ext/ext%04d.edf',parameters.acq.dir,i), bb);
+end
+
+%apply mask , either from snake or from difspot silhouette
+im = im.*mask;
+
+
diff --git a/5_reconstruction/GJgtART3D.m b/5_reconstruction/GJgtART3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..f22c9fb92c922ca7d1484db2b4397812b9d4c18f
--- /dev/null
+++ b/5_reconstruction/GJgtART3D.m
@@ -0,0 +1,256 @@
+function gtART3D(...
+  scanname,...
+  parfilename,...
+  p_numbers,...
+  psi_angles,...
+  xsi_angles,...
+  delta_angles,...
+  twotheta,...
+  eta,...
+  lambda,...
+  nbiter,...
+  pixsize,...
+  braggangle,...
+  np,nq,...
+  offset,...
+  z1,nz,...
+  x1,nx,...
+  y1,ny)
+% write .par file ready for rec_alg to use
+%
+%
+% function make_art_parfile(scanname,parfilename,p_numbers,psi_angles,xsi_angles,delta_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% 
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% p_numbers: vector containing the projections to be taken into account, e.g. [0:10:180]
+% p_angles : vector containing the correpsonding projection angles in degree e.g. [0:20:360]
+% lambda   : ART loop update parameter
+% nbiter   : number of ART iterations
+% pixsize  : pixelsize [mm]
+% braggangle: Bragg angle
+% np        : number of pixels in projections (hoizontal)
+% nq        : number of pixel in projections (vertical)
+% offset    : offset of the rotation axis with respect to the center of the image (in pixels) 
+% z1        : z start of reconstructed volume
+% nz        : number of reconstructed slices 
+% x1        : x start of reconstructed volume //andy 21/6/06
+% nx        : size of reconstructed volume in x
+% y1        : y start of reconstructed volume
+% ny        : size of reconstructed volume in y(attention: pixelsize in reconstructed image will be half
+% the pixel size in original projection images
+
+
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+fid=fopen(parfilename,'w');
+nbradio=length(p_numbers);
+
+% Algorithm paramters
+nbiter = nbiter;
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 1;
+block_size = length(p_numbers);  % for straight back projection, block_size should be = num projections
+% if block_size=N it will forward project after each N projections
+proj_mng = 'A';
+nb_resol = 1;
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+param1 = 0.1;  % paramX not used for ART (algo_type=1 or =2)
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+%geometry paramters
+fgd = 145000;         % Distance source detector [mm]  - put it far away, to approximate a parallel beam
+disp('*****************************')
+
+
+psi = psi_angles;     % first Euler angle (==omega)  [degrees]
+xsi = xsi_angles;     % second Euler angle
+delta = delta_angles; % third Euler angle
+np=2048;
+nq=2048;
+pepd= pixsize;        % horizontal Pixel size, [mm]
+peqd= pixsize;        % vertical Pixel size [mm]
+
+p1d=-1023.5;          % pixels
+q1d=-1023.5;          % pixels
+
+%[alphap,alphaq]=gtGT2ARTangles(twotheta,eta);
+ang=30;
+alphap=[-ang -ang ang ang];
+alphaq=[-ang ang ang -ang];
+
+pdisp=tan(deg2rad(alphap))*fgd;
+qdisp=tan(deg2rad(alphaq))*fgd;
+%pdisp=repmat(0,size(qdisp));
+%qdisp=repmat(0,size(pdisp));
+
+
+% at the moment, moving pgd and p0 in opposite directions, but equal
+% amounts.  Probably only works when VOI is centred over detector!!!
+pgd=-pdisp/pixsize;  % -
+qgd=-qdisp/pixsize;
+
+
+%%%%%%%%%%%%% m0,p0,q0 - coordinate of O in F
+m0=-(fgd);  % reconstruction object is centred over detector!
+%m0=-fgd;                   % mm
+p0=pdisp;          % mm
+q0=qdisp;          % mm
+
+
+ipd = 0;              % ROI begin horizontal [pixels] 
+iqd = 0;              % ROI begin vertical [pixels]
+ipf=2047;
+iqf=2047;
+
+%Reconstruction paramters
+
+% this is for object from -512:8:512
+ x1=-(256*pixsize),
+  y1=x1-700;
+  z1=x1;
+  pex=8*pixsize,pey=pex;pez=pex;
+  nx=64;ny=nx;nz=nx;
+
+%  x1=-512,
+%  y1=x1-400;
+%  z1=x1;
+%  pex=16,pey=pex;pez=pex;
+%  nx=2*abs(x1)/pex;ny=nx;nz=nx;
+
+% this is for object from -64:1:64
+%x1=-(.5);y1=x1;z1=x1;  % mm
+%nx=101;ny=nx;nz=nx;   % num pixels
+%pex=0.01;pey=pex;pez=pex;   % size of pixel in mm
+
+
+% approximate sample size
+%x1=-(256*pixsize),y1=x1;z1=x1;
+%pex=4*pixsize,pey=pex;pez=pex;
+%nx=128;ny=nx;nz=nx;
+
+% uncomment this for: object from -1024:4:1024
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  decimation=4;
+%  pex=decimation*pixsize;pey=pex;pez=pex;
+%  nx=2048/decimation;ny=nx;nz=nx;
+
+
+%if 0  % full resolution - voxel size in object = detector pixel size  REC_ALG FAILS - CANNOT ALLOCATE SO MUCH MEMORY!!
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  pex=pixsize;pey=pex;pez=pex;
+%  nx=2048;ny=2048;nz=2048;
+%end
+
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+for i=1:nbradio
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,p_numbers(i));
+end
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd(mod(i-1,length(pgd))+1));
+fprintf(fid,'QGD = %f\n',qgd(mod(i-1,length(qgd))+1));	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(mod(i-1,length(p1d))+1));
+fprintf(fid,'Q1D = %f\n',q1d(mod(i-1,length(q1d))+1));
+fprintf(fid,'NP =  %d\n',np(mod(i-1,length(np))+1));
+fprintf(fid,'NQ =  %d\n',nq(mod(i-1,length(nq))+1));
+% this next line uses each value for the angles, if it exists.  Otherwise
+% it just repeats the single value over and over.  GJ
+fprintf(fid,'PSI = %f\n',psi(mod(i-1,length(psi))+1));
+fprintf(fid,'XSI = %f\n',xsi(mod(i-1,length(xsi))+1));
+fprintf(fid,'DELTA = %f\n',delta(mod(i-1,length(delta))+1));
+fprintf(fid,'PO = %f\n',p0(mod(i-1,length(p0))+1));	
+fprintf(fid,'QO = %f\n',q0(mod(i-1,length(q0))+1));
+fprintf(fid,'MO = %f\n',m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf);
+fprintf(fid,'IQF = %d\n',iqf);
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
diff --git a/5_reconstruction/GJgtDoART3D.m b/5_reconstruction/GJgtDoART3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..aa7ccf5a82d9c591cb8782d7ea3b50dcc937461b
--- /dev/null
+++ b/5_reconstruction/GJgtDoART3D.m
@@ -0,0 +1,127 @@
+%function gtDoART3D(grainid)
+grainid=3;
+%simply launch the reconstruction of a grain for a standard set of
+%parameters
+%use the index of good reflections if it exists
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%read in data
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+%struct_ids = grain_data.struct_ids;
+
+%if it doesn't already exist, add an index of projections to use
+if isfield(grain_data,'index')
+  index = grain_data.index;
+else
+  index = ones(1,length(grain_data.struct_ids));
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'index', '-append')
+end
+
+scanname = sprintf('grain%d_',grainid);
+parfilename = sprintf('grain%d_.par',grainid);
+whole_parfilename = sprintf('grain%d_whole.par',grainid);
+
+if 0 %isfield(grain_data,'lambda')
+  art_params = grain_data.lambda;%if assigned manually
+else
+  art_params = [0.6 0.2 0.1]; %default values
+  art_params = 1;  % just do back projection, no ART effects
+  lambda=art_params;
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'lambda', '-append')
+end
+
+
+%cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+
+nbiter = length(art_params);
+pixsize = 1; %0.0014;
+
+np = parameters.acq.bb(3);
+nq = parameters.acq.bb(4);
+offset = 0;
+
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+psi_angles = -grain_data.Omega(find(index));
+twotheta=2*grain_data.Theta(find(index));
+eta=grain_data.Eta(find(index));
+
+psi_angles=repmat(0,size(twotheta));
+twotheta=[10 10 10 10 ];
+eta=[0 0 0 0 ]; %-90 90];
+if 0
+  p_numbers = find(index);
+%  p_numbers(4:end)=[];
+%  disp('REMOVE A FUNNY ONE ***')
+%  p_numbers(4)=[];
+else
+  p_numbers=repmat(99,size(psi_angles));  % 1 - test with real spot 99 - test with syntheic centred projection
+  p_numbers=[ 101 102 103 104 ];
+end
+
+
+
+cd(parameters.acq.dir);
+if 0
+  mym('open','mysql','gtadmin','gtadmin')
+  mym('use graintracking')
+  composite=zeros(2048);
+  for n=p_numbers
+    sid=grain_data.struct_ids(n);
+    dspot_im=gtnewGetSummedDifSpot(sid);
+    dspot_im= 100*dspot_im/sum(dspot_im(:));
+    [bb(1) bb(2) bb(3) bb(4)]=mym(sprintf(...
+      'select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from s5_dct5_difspot where difspotID=%d',sid));
+
+    fname=sprintf('tmp/%s%d',scanname,n)
+    im=gtPlaceSubImage(dspot_im,zeros(2048,2048),bb(1),bb(2));
+    disp('DEBUG')
+    sdt_write(fname,im,'float32');
+    composite=composite+im;
+    imagesc(composite)
+    title(n)
+    drawnow
+  end
+  return
+end
+%cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+cd tmp
+
+xsi_angles= [90];
+delta_angles=[0];
+
+% if we know the spot height above the detector centre (centroidY of spot)
+% and we know the two theta it should use
+% then we should move teh source (fgd) to the correct distance so t
+
+%write .par file for the whole grain, add to batch file
+gtART3D(...
+  scanname,...
+  whole_parfilename,...
+  p_numbers,psi_angles,xsi_angles,delta_angles,twotheta,eta,...
+  art_params,nbiter,pixsize,braggangle,...
+  np,nq,offset, ...
+  parameters.acq.bb(2)-1024,parameters.acq.bb(4),...
+  parameters.acq.bb(1)-1024,parameters.acq.bb(3),...
+  parameters.acq.bb(1)-1024,parameters.acq.bb(3));
+
+
+disp('Not starting condor job!')
+if 0
+  gtMakeCondorJob(grainid);
+else
+  %  cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+  % clear all previous work
+  %  system('rm *spr *sdt');
+  system(sprintf('%s %s',rec_alg,whole_parfilename));
+  for n=1:nbiter
+    system(sprintf('%s %s_res0_%d\n\n',seg2view,scanname,n));
+  end
+  cd(parameters.acq.dir);
+end
+
diff --git a/5_reconstruction/apply_z_shift.m b/5_reconstruction/apply_z_shift.m
new file mode 100755
index 0000000000000000000000000000000000000000..35ea8c7c158cc486744530b28e69b4e807901897
--- /dev/null
+++ b/5_reconstruction/apply_z_shift.m
@@ -0,0 +1,29 @@
+
+
+function apply_z_shift
+
+%apply bodge - shift stack images with MaxImage>4000 by 15 pixels to
+%account for "issue" in s5_dct5_
+%don't know why...
+%AK, 8/11/2006
+
+for i=100:131%for all grains
+  
+  
+  tmp=load(sprintf('4_grains/grain%d_/grain%d_.mat',i,i));
+
+  %make stack from scratch, to make sure all spots are in right place
+  %(shift by 15 pixels once and once only)
+  stack = gtReadSpots(tmp.struct_ids(1), tmp.struct_ids); 
+  Omega = tmp.Omega;
+  
+  dummy=find(Omega>120);%these need to be shifted by -15
+  
+  stack(1:end-15,:,dummy) = stack(16:end,:,dummy);
+  
+  save(sprintf('4_grains/grain%d_/grain%d_.mat',i,i),'stack','-append')
+  
+  gtWriteStack(i);%write projections for ART
+  
+  i
+end
\ No newline at end of file
diff --git a/5_reconstruction/correlate_crack.m b/5_reconstruction/correlate_crack.m
new file mode 100755
index 0000000000000000000000000000000000000000..68ede9114a1c5ccd7439b98a4063bd537e07e637
--- /dev/null
+++ b/5_reconstruction/correlate_crack.m
@@ -0,0 +1,325 @@
+%correlation of crack with boundaries
+%ak january 2008
+function [shift,data, crack_out] = correlate_crack(crack, boundaries, deg_freedom, starting_shift)
+%degrees of freedom x/y/z/rot, eg [0 0 1 1]
+%note rotation is around the centre of the volumes
+%shift = [x,y,z,rot?] of maximum correlation
+%data = correlation history
+%starting_shift - for more iterative approachs - gives a starting positions
+%other than [0 0 0 0]
+
+%work in uint8
+%cast if not already
+crack=uint8(crack);
+boundaries=uint8(boundaries);
+
+
+[sizex,sizey,sizez]=size(crack);
+data=[];
+
+if ~exist('deg_freedom', 'var')
+  deg_freedom=[1 1 1 1];
+  disp('doing all degrees of freedom (x/y/z/rot) by default')
+end
+if ~exist('starting_shift', 'var')
+  starting_shift=[0 0 0 0];
+  disp('starting from reference position by default')
+end
+
+
+%initial variables - do a range of 10%
+%in x
+if deg_freedom(1)
+  xhigh=10;%ceil(sizex/40);
+  xlow=-xhigh;
+  xinc=ceil((xhigh-xlow)/5);
+  xhigh=max([xlow:xinc:xhigh]);
+else
+  xlow=0;
+  xinc=1;
+  xhigh=0;
+end
+%in y
+if deg_freedom(2)
+  yhigh=10;%ceil(sizey/40);
+  ylow=-yhigh;
+  yinc=ceil((yhigh-ylow)/5);
+  yhigh=max([ylow:yinc:yhigh]);
+else
+  ylow=0;
+  yinc=1;
+  yhigh=0;
+end
+%in z
+if deg_freedom(3)
+  zhigh=10; %ceil(sizez/40);%changed here from 20 for small volumes
+  zlow=-zhigh;
+  zinc=ceil((zhigh-zlow)/5);
+  zhigh=max([zlow:zinc:zhigh]);
+else
+  zlow=0;
+  zinc=1;
+  zhigh=0;
+end
+%in rotation
+if deg_freedom(4)
+  rotlow=-5; 
+  rotinc=2.5;
+  rothigh=5;
+  rothigh=max([rotlow:rotinc:rothigh]);
+else
+  rotlow=0;
+  rotinc=1;
+  rothigh=0;
+end
+
+%apply intial shift
+xlow=xlow+starting_shift(1);
+xhigh=xhigh+starting_shift(1);
+ylow=ylow+starting_shift(2);
+yhigh=yhigh+starting_shift(2);
+zlow=zlow+starting_shift(3);
+zhigh=zhigh+starting_shift(3);
+rotlow=rotlow+starting_shift(4);
+rothigh=rothigh+starting_shift(4);
+
+finished=0;
+count=0;
+
+while finished==0
+  %tic;
+  count=count+1;
+
+  %offset for writing into data variable
+  %if offset~=max(-[xlow ylow zlow rotlow])+20;
+  %data=[]; %if changing offset erase data so far.
+  %offset=max(-[xlow ylow zlow rotlow])+20;
+  %end
+
+  %display status
+  disp(sprintf('correlation loop %d', count))
+   disp('x range')
+   xlow:xinc:xhigh
+   disp('y range')
+   ylow:yinc:yhigh
+   disp('z range')
+   zlow:zinc:zhigh
+   disp('rot range')
+   rotlow:rotinc:rothigh
+
+  %correlation loop
+  %rotation range
+  for rot=rotlow:rotinc:rothigh
+    disp('...')
+    if rot
+      tmpA=imrotate(crack, rot, 'nearest', 'crop');
+    else
+      tmpA=crack;
+    end
+
+    %xrange:
+    for x=xlow:xinc:xhigh
+      %yrange:
+      for y=ylow:yinc:yhigh
+        %zrange:
+        for z=zlow:zinc:zhigh
+
+          %has this point been done already?
+          if isempty(data) || isempty(find(data(:,1)==x & data(:,2)==y & data(:,3)==z & data(:,4)==rot, 1));
+
+            %calculate indexes to apply the shift
+            xout1=max(x+1, 1);
+            xout2=min(sizex, sizex+x);
+
+            xin1=max(1-x, 1);
+            xin2=min(sizex, sizex-x);
+
+            yout1=max(y+1, 1);
+            yout2=min(sizey, sizey+y);
+
+            yin1=max(1-y, 1);
+            yin2=min(sizey, sizey-y);
+
+            zout1=max(z+1, 1);
+            zout2=min(sizez, sizez+z);
+
+            zin1=max(1-z, 1);
+            zin2=min(sizez, sizez-z);
+
+            %apply the shifts
+            tmp=uint8(zeros(size(crack)));
+            tmp(xout1:xout2,yout1:yout2,zout1:zout2)=tmpA(xin1:xin2,yin1:yin2,zin1:zin2);
+            %do the correlation
+            
+            tmp=tmp.*boundaries;
+            %record result
+            %data(x+offset,y+offset,z+offset,rot+offset)=sum(tmp(:));
+            data(end+1,:)=[x, y, z, rot, sum(tmp(:))];
+
+          end
+        end
+      end
+    end
+  end
+
+  % %read from data to find coorelation maximum
+  % [val, ind]=max(data(:));
+  % [x,y,z,rot]=ind2sub(size(data), ind);
+  % x=x-offset;
+  % y=y-offset;
+  % z=z-offset;
+  % rot=rot-offset;
+
+  [val,ind]=max(data(:,5));
+  shift=data(ind, 1:4);
+  x=shift(1); y=shift(2); z=shift(3); rot=shift(4);
+
+  finished=1;%test
+
+  %can only be finshed we are using fine increments (==1)
+  if xinc~=1 | yinc~=1 | zinc~=1 | rotinc~=1
+    %  if zinc~=1 | rotinc~=1
+    finished=0;
+  end
+
+  %adjust limits
+  if deg_freedom(1)
+    if x<xhigh & x>xlow
+      disp('happy in x')
+      if xinc>1
+        xlow=x-2;%xinc+1;
+        xhigh=x+2;%xinc-1;
+        xinc=1;
+      else
+        xlow=x-1;
+        xhigh=x+1;
+      end
+    elseif x==xlow
+      disp('adjust x range-')
+      finished=0;
+      shift=round((xhigh-xlow)/2);
+      xlow=xlow-shift;
+      xhigh=xhigh-shift;
+    elseif x==xhigh
+      disp('adjust x range+')
+      finished=0;
+      shift=round((xhigh-xlow)/2);
+      xlow=xlow+shift;
+      xhigh=xhigh+shift;
+    end
+  end
+  if deg_freedom(2)
+    if y<yhigh & y>ylow
+      disp('happy in y')
+      if yinc>1
+        ylow=y-2;%yinc+1;
+        yhigh=y+2;%yinc-1;
+        yinc=1;
+      else
+        ylow=y-1;
+        yhigh=y+1;
+      end
+    elseif y==ylow
+      disp('adjust y range-')
+      finished=0;
+      shift=round((yhigh-ylow)/2);
+      ylow=ylow-shift;
+      yhigh=yhigh-shift;
+    elseif y==yhigh
+      disp('adjust y range+')
+      finished=0;
+      shift=round((yhigh-ylow)/2);
+      ylow=ylow+shift;
+      yhigh=yhigh+shift;
+    end
+  end
+  if deg_freedom(3)
+    if z<zhigh & z>zlow
+      disp('happy in z')
+      if zinc>1
+        zlow=z-2;%zinc+1;
+        zhigh=z+2;%zinc-1;
+        zinc=1;
+      else
+        zlow=z-1;
+        zhigh=z+1;
+      end
+    elseif z==zlow
+      disp('adjust z range-')
+      finished=0;
+      shift=round((zhigh-zlow)/2);
+      zlow=zlow-shift;
+      zhigh=zhigh-shift;
+    elseif z==zhigh
+      disp('adjust z range+')
+      finished=0;
+      shift=round((zhigh-zlow)/2);
+      zlow=zlow+shift;
+      zhigh=zhigh+shift;
+    end
+  end
+  if deg_freedom(4)
+    if rot<rothigh & rot>rotlow
+      disp('happy in rotation')
+      if rotinc>1
+        rotlow=rot-rotinc+1;
+        rothigh=rot+rotinc-1;
+        rotinc=1;
+      else
+        rotlow=rot-1;
+        rothigh=rot+1;
+      end
+    elseif rot==rotlow
+      disp('adjust rot range-')
+      finished=0;
+      shift=round((rothigh-rotlow)/2);
+      rotlow=rotlow-shift;
+      rothigh=rothigh-shift;
+    elseif rot==rothigh
+      disp('adjust rot range+')
+      finished=0;
+      shift=round((rothigh-rotlow)/2);
+      rotlow=rotlow+shift;
+      rothigh=rothigh+shift;
+    end
+  end
+
+%  toc
+end
+
+%apply the shift to give crack_out volume
+%have already read x,y,z,rot from shift
+
+%apply rotation
+tmpA=imrotate(crack, rot, 'nearest', 'crop');
+%calc indices
+xout1=max(x+1, 1);
+xout2=min(sizex, sizex+x);
+
+xin1=max(1-x, 1);
+xin2=min(sizex, sizex-x);
+
+yout1=max(y+1, 1);
+yout2=min(sizey, sizey+y);
+
+yin1=max(1-y, 1);
+yin2=min(sizey, sizey-y);
+
+zout1=max(z+1, 1);
+zout2=min(sizez, sizez+z);
+
+zin1=max(1-z, 1);
+zin2=min(sizez, sizez-z);
+
+%apply the shifts
+tmp=uint8(zeros(size(crack)));
+tmp(xout1:xout2,yout1:yout2,zout1:zout2)=tmpA(xin1:xin2,yin1:yin2,zin1:zin2);
+crack_out=tmp;
+
+  [val,ind]=max(data(:,5));
+  shift=data(ind, 1:4);
+shift(end+1)=val;%add the correlation value
+
+
+
+
diff --git a/5_reconstruction/fichier b/5_reconstruction/fichier
new file mode 100755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/5_reconstruction/gtART3D.m b/5_reconstruction/gtART3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..491791e1c2eeae5a1723a82689bb23efaa764560
--- /dev/null
+++ b/5_reconstruction/gtART3D.m
@@ -0,0 +1,284 @@
+function gtART3D(...
+  scanname,...
+  parfilename,...
+  p_numbers,...
+  psi_angles,...
+  xsi_angles,...
+  delta_angles,...
+  twotheta,...
+  eta,...
+  lambda,...
+  nbiter,...
+  pixsize,...
+  braggangle,...
+  np,nq,...
+  offset,...
+  zdetector,...
+  voxsize,...
+  z1,nz,...
+  x1,nx,...
+  y1,ny)
+% write .par file ready for rec_alg to use
+%
+%
+% function make_art_parfile(scanname,parfilename,p_numbers,psi_angles,xsi_angles,delta_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% 
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% p_numbers: vector containing the projections to be taken into account, e.g. [0:10:180]
+% p_angles : vector containing the correpsonding projection angles in degree e.g. [0:20:360]
+% lambda   : ART loop update parameter
+% nbiter   : number of ART iterations
+% pixsize  : pixelsize [mm]
+% braggangle: Bragg angle
+% np        : number of pixels in projections (hoizontal)
+% nq        : number of pixel in projections (vertical)
+% offset    : offset of the rotation axis with respect to the center of the image (in pixels) 
+% z1        : z start of reconstructed volume
+% nz        : number of reconstructed slices 
+% x1        : x start of reconstructed volume //andy 21/6/06
+% nx        : size of reconstructed volume in x
+% y1        : y start of reconstructed volume
+% ny        : size of reconstructed volume in y(attention: pixelsize in reconstructed image will be half
+% the pixel size in original projection images
+
+
+fid=fopen(parfilename,'w');
+nbradio=length(p_numbers);
+
+% Algorithm paramters
+nbiter = nbiter;
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 1;
+block_size = length(p_numbers);  % for straight back projection,
+%block_size should be = num projections
+% block_size=1;
+% if block_size=N it will forward project after each N projections
+proj_mng = 'A';
+nb_resol = 1;
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+param1 = 0.1;  % paramX not used for ART (algo_type=1 or =2)
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+%geometry paramters
+fgd = 145000;         % Distance source detector [mm]  - put it far away, to approximate a parallel beam
+disp('*****************************')
+
+
+psi = psi_angles;     % first Euler angle (==omega)  [degrees]
+xsi = xsi_angles;     % second Euler angle
+delta = delta_angles; % third Euler angle
+
+np=np;
+nq=nq;
+
+pepd= pixsize;        % horizontal Pixel size, [mm]
+peqd= pixsize;        % vertical Pixel size [mm]
+
+
+% this +0.5 is needed to center the projections
+
+p1d=(-np/2)+0.5;
+q1d=(-nq/2)+0.5;
+
+[alphap,alphaq]=gtGT2ARTangles(twotheta,eta);
+disp('********FLIPPING Ps and Qs***')
+p=alphap;q=alphaq;
+alphap=q;
+alphaq=p;
+alphap=alphap;
+
+pdisp=tan(deg2rad(alphap))*fgd;
+qdisp=tan(deg2rad(alphaq))*fgd;
+%pdisp=repmat(0,size(qdisp));
+%qdisp=repmat(0,size(pdisp));
+
+
+% at the moment, moving pgd and p0 in opposite directions, but equal
+% amounts.  Probably only works when VOI is centred over detector!!!
+pgd=-pdisp/pixsize;  % -
+qgd=-qdisp/pixsize;
+
+
+%%%%%%%%%%%%% m0,p0,q0 - coordinate of O in F
+%m0=-(fgd-2000);  % reconstruction object is centred over detector!
+% m0 must be correct for eta variations to be centred
+
+%***m0=-(fgd+zdetector)                 % mm
+m0=-(fgd-zdetector);
+
+
+p0=pdisp;          % mm
+q0=qdisp;          % mm
+
+
+ipd = 0;              % ROI begin horizontal [pixels] 
+iqd = 0;              % ROI begin vertical [pixels]
+disp('NO ROI ON DETECTOR - full image used')
+ipf=np-1;
+iqf=nq-1;
+% having too big an ROI causes a seg fault - no error message
+
+if ((ipf-ipd)>np || (iqf-iqd)>nq)
+  warning('Your detector ROI might be too big!')
+end
+
+%Reconstruction paramters
+
+% THIS ONLY WORKS WITH PSI_ANGLES ALL ZERO.  OTHERWISE, VOI MUST BE CENTRED
+% ON O
+% x1=-(250*pixsize),
+%  y1=x1-900;   % -900  for synthetic, -2000 real
+%  z1=x1;
+%  pex=5*pixsize,pey=pex;pez=pex;
+%  nx=100;ny=nx;nz=nx;
+
+
+%%% **
+%x1=-(200*pixsize);y1=x1;z1=x1;
+%pex=5*pixsize;pey=pex;pez=pex;
+%nx=80;ny=nx;nz=nx;
+
+
+%x1=-20*pixsize;y1=x1;z1=x1;
+pex=voxsize;pey=pex;pez=pex;
+%nx=40;ny=nx;nz=nx;
+
+%  x1=-512,
+%  y1=x1-400;
+%  z1=x1;
+%  pex=16,pey=pex;pez=pex;
+%  nx=2*abs(x1)/pex;ny=nx;nz=nx;
+
+% this is for object from -64:1:64
+%x1=-(.5);y1=x1;z1=x1;  % mm
+%nx=101;ny=nx;nz=nx;   % num pixels
+%pex=0.01;pey=pex;pez=pex;   % size of pixel in mm
+
+
+% approximate sample size
+%x1=-(256*pixsize),y1=x1;z1=x1;
+%pex=4*pixsize,pey=pex;pez=pex;
+%nx=128;ny=nx;nz=nx;
+
+% uncomment this for: object from -1024:4:1024
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  decimation=4;
+%  pex=decimation*pixsize;pey=pex;pez=pex;
+%  nx=2048/decimation;ny=nx;nz=nx;
+
+
+%if 0  % full resolution - voxel size in object = detector pixel size  REC_ALG FAILS - CANNOT ALLOCATE SO MUCH MEMORY!!
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  pex=pixsize;pey=pex;pez=pex;
+%  nx=2048;ny=2048;nz=2048;
+%end
+
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+for i=1:nbradio
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,p_numbers(i));
+end
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd(mod(i-1,length(pgd))+1));
+fprintf(fid,'QGD = %f\n',qgd(mod(i-1,length(qgd))+1));	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(mod(i-1,length(p1d))+1));
+fprintf(fid,'Q1D = %f\n',q1d(mod(i-1,length(q1d))+1));
+fprintf(fid,'NP =  %d\n',np(mod(i-1,length(np))+1));
+fprintf(fid,'NQ =  %d\n',nq(mod(i-1,length(nq))+1));
+% this next line uses each value for the angles, if it exists.  Otherwise
+% it just repeats the single value over and over.  GJ
+fprintf(fid,'PSI = %f\n',psi(mod(i-1,length(psi))+1));
+fprintf(fid,'XSI = %f\n',xsi(mod(i-1,length(xsi))+1));
+fprintf(fid,'DELTA = %f\n',delta(mod(i-1,length(delta))+1));
+fprintf(fid,'PO = %f\n',p0(mod(i-1,length(p0))+1));	
+fprintf(fid,'QO = %f\n',q0(mod(i-1,length(q0))+1));
+fprintf(fid,'MO = %f\n',m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf);
+fprintf(fid,'IQF = %d\n',iqf);
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
diff --git a/5_reconstruction/gtART3D_GJ.m b/5_reconstruction/gtART3D_GJ.m
new file mode 100755
index 0000000000000000000000000000000000000000..009c7b1389668e4df6a2ca0164ec6ab68739f38e
--- /dev/null
+++ b/5_reconstruction/gtART3D_GJ.m
@@ -0,0 +1,268 @@
+function gtART3D(...
+  scanname,...
+  parfilename,...
+  p_numbers,...
+  psi_angles,...
+  xsi_angles,...
+  delta_angles,...
+  twotheta,...
+  eta,...
+  lambda,...
+  nbiter,...
+  pixsize,...
+  braggangle,...
+  np,nq,...
+  offset,...
+  z1,nz,...
+  x1,nx,...
+  y1,ny)
+% write .par file ready for rec_alg to use
+%
+%
+% function make_art_parfile(scanname,parfilename,p_numbers,psi_angles,xsi_angles,delta_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% 
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% p_numbers: vector containing the projections to be taken into account, e.g. [0:10:180]
+% p_angles : vector containing the correpsonding projection angles in degree e.g. [0:20:360]
+% lambda   : ART loop update parameter
+% nbiter   : number of ART iterations
+% pixsize  : pixelsize [mm]
+% braggangle: Bragg angle
+% np        : number of pixels in projections (hoizontal)
+% nq        : number of pixel in projections (vertical)
+% offset    : offset of the rotation axis with respect to the center of the image (in pixels) 
+% z1        : z start of reconstructed volume
+% nz        : number of reconstructed slices 
+% x1        : x start of reconstructed volume //andy 21/6/06
+% nx        : size of reconstructed volume in x
+% y1        : y start of reconstructed volume
+% ny        : size of reconstructed volume in y(attention: pixelsize in reconstructed image will be half
+% the pixel size in original projection images
+
+
+fid=fopen(parfilename,'w');
+nbradio=length(p_numbers);
+
+% Algorithm paramters
+nbiter = nbiter;
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 1;
+block_size = length(p_numbers);  % for straight back projection,
+%block_size should be = num projections
+% block_size=1;
+% if block_size=N it will forward project after each N projections
+proj_mng = 'A';
+nb_resol = 1;
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+param1 = 0.1;  % paramX not used for ART (algo_type=1 or =2)
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+
+
+
+%geometry paramters
+fgd = 145000;         % Distance source detector [mm]  - put it far away, to approximate a parallel beam
+
+psi = psi_angles;     % first Euler angle (==omega)  [degrees]
+xsi = xsi_angles;     % second Euler angle
+delta = delta_angles; % third Euler angle
+np=2048;
+nq=2048;
+pepd= pixsize;        % horizontal Pixel size, [mm]
+peqd= pixsize;        % vertical Pixel size [mm]
+
+p1d=-1023.5;          % pixels
+q1d=-1023.5;          % pixels
+
+[alphap,alphaq]=gtGT2ARTangles(twotheta,eta);
+
+%ang=15;
+%alphap=[-ang+.1 -ang-.1 ang ang];
+%alphaq=[-ang ang ang -ang];
+
+pdisp=tan(deg2rad(alphap))*fgd
+qdisp=tan(deg2rad(alphaq))*fgd
+%pdisp=repmat(0,size(qdisp));
+%qdisp=repmat(0,size(pdisp));
+
+
+% at the moment, moving pgd and p0 in opposite directions, but equal
+% amounts.  Probably only works when VOI is centred over detector!!!
+%pgd=-pdisp/pixsize;  % -
+%qgd=-qdisp/pixsize;
+pgd=0;
+qgd=0;
+
+%%%%%%%%%%%%% m0,p0,q0 - coordinate of O in F
+m0=-(fgd-2000);  % reconstruction object is centred over detector!
+%m0=-fgd;                   % mm
+p0=pdisp;          % mm
+q0=qdisp;          % mm
+
+
+ipd = 0;              % ROI begin horizontal [pixels] 
+iqd = 0;              % ROI begin vertical [pixels]
+ipf=2047;
+iqf=2047;
+
+%Reconstruction paramters
+
+% THIS ONLY WORKS WITH PSI_ANGLES ALL ZERO.  OTHERWISE, VOI MUST BE CENTRED
+% ON O
+% x1=-(250*pixsize),
+%  y1=x1-900;   % -900  for synthetic, -2000 real
+%  z1=x1;
+%  pex=5*pixsize,pey=pex;pez=pex;
+%  nx=100;ny=nx;nz=nx;
+
+
+%x1=-(200*pixsize);y1=x1;z1=x1;
+%pex=5*pixsize;pey=pex;pez=pex;
+%nx=80;ny=nx;nz=nx;
+
+
+%  x1=-512,
+%  y1=x1-400;
+%  z1=x1;
+%  pex=16,pey=pex;pez=pex;
+%  nx=2*abs(x1)/pex;ny=nx;nz=nx;
+
+% this is for object from -64:1:64
+%x1=-(.5);y1=x1;z1=x1;  % mm
+%nx=101;ny=nx;nz=nx;   % num pixels
+%pex=0.01;pey=pex;pez=pex;   % size of pixel in mm
+
+
+% approximate sample size
+%x1=-(256*pixsize),y1=x1;z1=x1;
+%pex=4*pixsize,pey=pex;pez=pex;
+%nx=128;ny=nx;nz=nx;
+
+% uncomment this for: object from -1024:4:1024
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  decimation=4;
+%  pex=decimation*pixsize;pey=pex;pez=pex;
+%  nx=2048/decimation;ny=nx;nz=nx;
+
+pixsize=0.8;
+x1=-1024*pixsize;y1=x1;z1=x1;
+decimation=32
+pex=decimation*pixsize;pey=pex;pez=pex;
+nx=2048/decimation;ny=nx;nz=nx;
+
+
+%if 0  % full resolution - voxel size in object = detector pixel size  REC_ALG FAILS - CANNOT ALLOCATE SO MUCH MEMORY!!
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  pex=pixsize;pey=pex;pez=pex;
+%  nx=2048;ny=2048;nz=2048;
+%end
+
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+for i=1:nbradio
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,p_numbers(i));
+end
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd(mod(i-1,length(pgd))+1));
+fprintf(fid,'QGD = %f\n',qgd(mod(i-1,length(qgd))+1));	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(mod(i-1,length(p1d))+1));
+fprintf(fid,'Q1D = %f\n',q1d(mod(i-1,length(q1d))+1));
+fprintf(fid,'NP =  %d\n',np(mod(i-1,length(np))+1));
+fprintf(fid,'NQ =  %d\n',nq(mod(i-1,length(nq))+1));
+% this next line uses each value for the angles, if it exists.  Otherwise
+% it just repeats the single value over and over.  GJ
+fprintf(fid,'PSI = %f\n',psi(mod(i-1,length(psi))+1));
+fprintf(fid,'XSI = %f\n',xsi(mod(i-1,length(xsi))+1));
+fprintf(fid,'DELTA = %f\n',delta(mod(i-1,length(delta))+1));
+fprintf(fid,'PO = %f\n',p0(mod(i-1,length(p0))+1));	
+fprintf(fid,'QO = %f\n',q0(mod(i-1,length(q0))+1));
+fprintf(fid,'MO = %f\n',m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf);
+fprintf(fid,'IQF = %d\n',iqf);
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
diff --git a/5_reconstruction/gtAaxisCmap.m b/5_reconstruction/gtAaxisCmap.m
new file mode 100755
index 0000000000000000000000000000000000000000..a42241c8d1aecea8f34a33d5bca6ba2b09772f3d
--- /dev/null
+++ b/5_reconstruction/gtAaxisCmap.m
@@ -0,0 +1,94 @@
+
+
+function a_axismap=gtAaxisCmap_sab
+% make a colourmap according to c-axis orientation
+% c_axis - calculated from r_vectors list as produced by gtReadGrains
+% r_vectors -> c-axis -> phi/psi -> hsl -> rgb colormap
+% use psi to give brightness; phi to give colour
+
+%%%%%%%%%%%%%%on s interesse a l axe a
+load parameters
+load r_vectors
+
+ 
+all_hkils=[];
+hkil = [...
+    1 0 -1 0; ...
+    ];
+for i = 1:size(hkil,1)
+    all_hkils = [all_hkils ; gtGetReflections_sab(hkil(i,:))];
+end
+% normalise hkls vector
+% going to cartesian reciprocal space + normalisation of the cartesian
+% space
+for i=1:size(all_hkils)
+    all_hkls(i,1)= all_hkils(i,1) + 0.5 * all_hkils(i,2);
+    all_hkls(i,2)= 3^0.5/2 *all_hkils(i,2);
+    all_hkls(i,3)= all_hkils(i,4);
+
+    all_hkls(i,1)=all_hkls(i,1)*2/(sqrt(3)*parameters.acq.latticepar(1));
+    all_hkls(i,2)=all_hkls(i,2)*2/(sqrt(3)*parameters.acq.latticepar(1));
+    all_hkls(i,3)=all_hkls(i,3)/parameters.acq.latticepar(3);
+end
+tmp = sqrt(sum((all_hkls.*all_hkls),2));
+normalised_hkls = all_hkls./(repmat(tmp,1,3));
+% unification des notations pour la suite
+all_hkls = [];
+all_hkls = all_hkils;
+
+
+for i=1:size(r_vectors,1)
+    g = Rod2g(r_vectors(i,2:4));
+    all_normals = (g * normalised_hkls')';
+    a_axis(i,1)=r_vectors(i,1);
+    if all_normals(6,1)>=0
+        a_axis(i,2)=all_normals(6,1);
+        a_axis(i,3)=all_normals(6,2);
+        a_axis(i,4)=all_normals(6,3);
+    else
+        a_axis(i,2)=all_normals(1,1);
+        a_axis(i,3)=all_normals(1,2);
+        a_axis(i,4)=all_normals(1,3);
+    end
+end
+
+
+save a_axis a_axis % list of the c axis
+
+
+psi=acosd(a_axis(:,4));
+phi=atan2(a_axis(:,3), a_axis(:,2));
+
+
+
+%get everything in degrees, and on the right interval
+phi=phi*180/pi;
+% %want all psi between 0 and 90
+% psi(find(psi>90))=180-psi(find(psi>90));
+% %if we change psi, should also change phi
+% phi(find(psi>90))=phi(find(psi>90))+180;
+
+dummy=find(psi>90);
+psi(dummy)=180-psi(dummy);
+%if we change psi, should also change phi
+phi(dummy)=phi(dummy)+180;
+
+phi(find(phi<0))=phi(find(phi<0))+360;
+phi(find(phi>360))=phi(find(phi>360))-360;
+
+%use hsl2rgb.m
+%hue
+h=phi/360;
+%saturation
+s=ones(size(h));
+%lightness (white //z, black in x-y plane)
+l=0.9-(0.8*(psi/90));
+
+rgb=hsl2rgb([h s l]);
+
+%add black background
+a_axismap=zeros(size(rgb, 1)+1, 3);
+a_axismap(2:end, :)=rgb;
+
+%save the caxis colourmap
+save a_axismap a_axismap
\ No newline at end of file
diff --git a/5_reconstruction/gtAaxisCmap_sab.m b/5_reconstruction/gtAaxisCmap_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..a42241c8d1aecea8f34a33d5bca6ba2b09772f3d
--- /dev/null
+++ b/5_reconstruction/gtAaxisCmap_sab.m
@@ -0,0 +1,94 @@
+
+
+function a_axismap=gtAaxisCmap_sab
+% make a colourmap according to c-axis orientation
+% c_axis - calculated from r_vectors list as produced by gtReadGrains
+% r_vectors -> c-axis -> phi/psi -> hsl -> rgb colormap
+% use psi to give brightness; phi to give colour
+
+%%%%%%%%%%%%%%on s interesse a l axe a
+load parameters
+load r_vectors
+
+ 
+all_hkils=[];
+hkil = [...
+    1 0 -1 0; ...
+    ];
+for i = 1:size(hkil,1)
+    all_hkils = [all_hkils ; gtGetReflections_sab(hkil(i,:))];
+end
+% normalise hkls vector
+% going to cartesian reciprocal space + normalisation of the cartesian
+% space
+for i=1:size(all_hkils)
+    all_hkls(i,1)= all_hkils(i,1) + 0.5 * all_hkils(i,2);
+    all_hkls(i,2)= 3^0.5/2 *all_hkils(i,2);
+    all_hkls(i,3)= all_hkils(i,4);
+
+    all_hkls(i,1)=all_hkls(i,1)*2/(sqrt(3)*parameters.acq.latticepar(1));
+    all_hkls(i,2)=all_hkls(i,2)*2/(sqrt(3)*parameters.acq.latticepar(1));
+    all_hkls(i,3)=all_hkls(i,3)/parameters.acq.latticepar(3);
+end
+tmp = sqrt(sum((all_hkls.*all_hkls),2));
+normalised_hkls = all_hkls./(repmat(tmp,1,3));
+% unification des notations pour la suite
+all_hkls = [];
+all_hkls = all_hkils;
+
+
+for i=1:size(r_vectors,1)
+    g = Rod2g(r_vectors(i,2:4));
+    all_normals = (g * normalised_hkls')';
+    a_axis(i,1)=r_vectors(i,1);
+    if all_normals(6,1)>=0
+        a_axis(i,2)=all_normals(6,1);
+        a_axis(i,3)=all_normals(6,2);
+        a_axis(i,4)=all_normals(6,3);
+    else
+        a_axis(i,2)=all_normals(1,1);
+        a_axis(i,3)=all_normals(1,2);
+        a_axis(i,4)=all_normals(1,3);
+    end
+end
+
+
+save a_axis a_axis % list of the c axis
+
+
+psi=acosd(a_axis(:,4));
+phi=atan2(a_axis(:,3), a_axis(:,2));
+
+
+
+%get everything in degrees, and on the right interval
+phi=phi*180/pi;
+% %want all psi between 0 and 90
+% psi(find(psi>90))=180-psi(find(psi>90));
+% %if we change psi, should also change phi
+% phi(find(psi>90))=phi(find(psi>90))+180;
+
+dummy=find(psi>90);
+psi(dummy)=180-psi(dummy);
+%if we change psi, should also change phi
+phi(dummy)=phi(dummy)+180;
+
+phi(find(phi<0))=phi(find(phi<0))+360;
+phi(find(phi>360))=phi(find(phi>360))-360;
+
+%use hsl2rgb.m
+%hue
+h=phi/360;
+%saturation
+s=ones(size(h));
+%lightness (white //z, black in x-y plane)
+l=0.9-(0.8*(psi/90));
+
+rgb=hsl2rgb([h s l]);
+
+%add black background
+a_axismap=zeros(size(rgb, 1)+1, 3);
+a_axismap(2:end, :)=rgb;
+
+%save the caxis colourmap
+save a_axismap a_axismap
\ No newline at end of file
diff --git a/5_reconstruction/gtAbsorptionSlice.m b/5_reconstruction/gtAbsorptionSlice.m
new file mode 100755
index 0000000000000000000000000000000000000000..76c7101aa333664f229332a2bce5deee47b2cfea
--- /dev/null
+++ b/5_reconstruction/gtAbsorptionSlice.m
@@ -0,0 +1,36 @@
+function [slice,sino]=gtAbsorptionSlice(parameters,slicenumber,varargin)
+% reconstructs a single absorption slice using matlabs irandon function
+% slicenumber:   number of the slice to be reconstructed
+%
+% optional input argument: interval
+%
+% int = 10  uses only one out of 10 projections  (speed up...)
+
+if nargin>2
+  int=varargin{1};
+else
+  int=1;
+end
+
+
+acq=parameters.acq;
+
+
+step=180/acq.nproj*int;
+
+theta=[0:step:180-step];
+
+sino=zeros(acq.bb(3),length(theta));
+
+
+j=1;
+disp('assembling sinogram..');
+for i=0:int:acq.nproj-1
+  sino(:,j)=edf_read(sprintf('%s/1_preprocessing/abs/abs%04d.edf',acq.dir,i),[1,slicenumber,acq.bb(3),1]);
+  j=j+1;
+end
+
+disp('backprojecting...')
+sino=-log(sino);
+slice=iradon(sino,theta,'linear','Ram-Lak',1,acq.bb(3));
+imshow(slice,[])
\ No newline at end of file
diff --git a/5_reconstruction/gtAnalyseBoundaryIndexPlane.m b/5_reconstruction/gtAnalyseBoundaryIndexPlane.m
new file mode 100755
index 0000000000000000000000000000000000000000..593a18d46b7c31b738f784356b7c09ad2570e511
--- /dev/null
+++ b/5_reconstruction/gtAnalyseBoundaryIndexPlane.m
@@ -0,0 +1,136 @@
+
+
+
+function [voldev, volhkl, poles]=gtAnalyseBoundaryIndexPlane(bounds_vol, grain_vol, boundaries_structure, boxsize, list)
+
+%think about analysing the local variations in character of boundaries, in
+%terms of their index plane.
+%consider a local neighbourhood of <boxsize> aound each point on the
+%boundary.  Calculate how far each section of boundary is from a low index
+%plane, and which boundary it is.
+
+%this is information which can also be usefully displayed on a pole figure,
+%giving a pole figure weighted by area (amount of boundary) rather than by
+%frequency of boundaries.  Collect this info at the same time.
+
+%considering every voxel if very slow and unnecessary.  Need to do some
+%kind of coarser grid.  How to do this, knowing that the boundaries are not
+%necessarily flat?
+
+%looking at a (very) few examples - it seems that an area of around 10x10
+%voxels is needed to avoid a lot of noise in the data.  However, it can be
+%nice to sample more points than just one every 10x10 voxels.  Really want
+%a grid spacing - ie a list of points to look at - and then a sample area - around each point.
+%exporting a long list of pole data makes gtMakePoleFigure very slow to
+%run.  Would be better to collect the data on the fly in the form of the
+%phi/psi/density or x/y/density variable inside gtMPF, and export this.
+
+
+if isempty(list)
+  list=1:max(bounds_vol(:));
+disp('doing all boundaries...')
+end
+
+voldev=zeros(size(bounds_vol));%output vol
+volhkl=zeros(size(bounds_vol));%output vol
+poles=[];
+
+%low index hkls to consider
+hkls=[1 0 0; 1 1 0; 1 1 1; 2 1 0; 2 1 1; 2 2 1; 3 1 0; 3 1 1; 3 2 0; 3 2 1; 3 2 2; 1 1 4];
+%expand to all variants
+all_hkls=[];
+hkl_type=[]
+for i = 1:size(hkls,1)
+  all_hkls = [all_hkls ; gtGetReflections(hkls(i,:))];
+  hkl_type=[hkl_type; repmat(i,size( gtGetReflections(hkls(i,:)), 1),1)]; %list of hkl type
+end
+%normalise hkl vectors
+tmp = sqrt(sum((all_hkls.*all_hkls),2));
+normalised_hkls = all_hkls./(repmat(tmp,1,3));
+
+
+for i=1:length(list) % list(i) is the id of the boundary in the volume
+  
+  disp(sprintf('doing boundary %d... %d of %d', list(i), i, length(list)))
+  
+  %get boundaries_structure data
+  grainids=[boundaries_structure(list(i)).grain1 boundaries_structure(list(i)).grain2];
+  R=[boundaries_structure(list(i)).grain1_R_vector; boundaries_structure(list(i)).grain2_R_vector];
+  
+  if any(grainids==0) | boundaries_structure(list(i)).count<4 %skip external boundaries / small boundaries
+    continue
+  end
+
+  warning('doing one half only')
+  for j=2; %do one half of the boundary at a time
+  
+  %pick out the boundary of interest
+  [y,x,z]=ind2sub(size(bounds_vol),find(bounds_vol==list(i) & grain_vol==grainids(j))); %voxels of boundary
+   
+  %could reduce points to be considered here by using something like:
+%  find(mod(x,2)==0 & mod(y,2)==0 & mod(z,2)==0)
+%or by using a grid of the boxsize (/2?) to create subregions
+ 
+%get g matrix
+  g=Rod2g(R(j,:));
+  
+  %loop through this volume, calculating local character
+  %may want to do this in larger steps
+
+  for k=1:length(x)
+    xx=x(k); yy=y(k); zz=z(k);   
+        
+% from gtReadBoundaryProperties - reference
+%[x,y,z]=ind2sub(size(test), find(test));
+%[origin, a]=lsplane([x y z]);
+%gb_normal=a;
+%gb_normal(3)=-gb_normal(3);
+
+dummy=find(x>=xx-boxsize & x<=xx+boxsize & y>=yy-boxsize & y<=yy+boxsize & z>=zz-boxsize & z<=zz+boxsize);
+
+if length(dummy)>3
+[origin, a]=lsplane([y(dummy) x(dummy) z(dummy)]);
+a(3)=-a(3);
+local_normal=a;%should be equivalent to previous
+
+%normal in crystallographic axes
+plane1=inv(g)*local_normal;
+
+% % %find closest low index plane
+% % dev=acosd(dot(repmat(plane1',size(normalised_hkls,1),1), normalised_hkls,2));
+% % [ang, ind]=min(dev);
+% % hkl=hkl_type(ind);
+
+%collect pole data
+poles=[poles; plane1'];
+
+%write output - if there is no low index plane close, assign 15 - non low
+%index
+% % if ang<5
+% %   voldev(yy,xx,zz)=ang;
+% %   volhkl(yy,xx,zz)=hkl;
+% % else
+% %   voldev(yy,xx,zz)=ang;
+% %   volhkl(yy,xx,zz)=15;
+% % end
+
+end
+      end
+
+  
+  end
+  
+end
+
+
+
+%apply the symmetry operators to pole data
+sym = gtGetCubicSymOp;
+poles2=[];
+for i=1:length(sym)
+  poles2=[poles2; poles*sym(i).g];
+end
+%add this to correspond to line in gtMakePoleFigure
+poles2=[poles2; -poles2];
+%poles=unique(poles2, 'rows');
+poles=poles2;
\ No newline at end of file
diff --git a/5_reconstruction/gtAnalyseBoundaryWrapper.m b/5_reconstruction/gtAnalyseBoundaryWrapper.m
new file mode 100755
index 0000000000000000000000000000000000000000..fd4b72b6f454416b95bb167be75de9479f54fdf7
--- /dev/null
+++ b/5_reconstruction/gtAnalyseBoundaryWrapper.m
@@ -0,0 +1,72 @@
+
+
+
+
+
+%wrapper
+
+
+function gtAnalyseBoundaryWrapper(first, last, workingdirectory)
+
+%standard stuff
+  if isdeployed
+    first=str2double(first);
+    last=str2double(last);
+  end % special case for running interactively in current directory
+
+  if ~exist('workingdirectory','var')
+    workingdirectory=pwd;
+  end
+
+  fprintf('Changing directory to %s\n',workingdirectory)
+  cd(workingdirectory)
+
+  gtDBConnect
+  
+%hard coded filenames - very bad
+grains=edf_read('5_reconstruction/ss2007_A_twin_dil10_mask.edf');
+bounds=edf_read('5_reconstruction/ss2007_A_boundaries.edf');
+bounds_dil=edf_read('5_reconstruction/ss2007_A_bounds_dil10.edf');
+a=load('boundaries_structure.mat');
+boundaries_structure=a.boundaries_structure;
+a=load('r_vectors.mat');
+r_vectors=a.r_vectors;
+tablename='ss2007_boundary_analysis'; %set this up first
+
+%%>> mym('drop table ss2007_boundary_analysis')
+%%>> mym('create table ss2007_boundary_analysis (grainID int unsigned not null auto_increment, primary key (grainID))')
+
+%parameters
+smoothR=4
+reduce_factor=0.5
+max_grainID=1038
+
+%rather than do a sequence first to last, use a table so that the first big
+%grains are well shared out
+
+grainID=0;
+while grainID<=max_grainID
+
+    mym(sprintf('insert into %s (grainID) values("0")', tablename));
+    grainID=mym('select last_insert_id()')
+    disp(sprintf('doing grain %d...', grainID))
+
+    if find(grains(:)==grainID, 1, 'first')
+    
+        %mesh grain
+    fv=gtGrainBoundarySurfaceMesh(grains, smoothR, grainID);
+    %extract pole data
+    [poles, weights, pole_data]=gtAnalyseGrainBoundarySurface(fv, reduce_factor, grainID, [], boundaries_structure, r_vectors, bounds_dil);
+
+    %for each boundary calculate density for pole figure
+    pole_figure_density=[];
+    for i=1:length(pole_data)
+        if ~isempty(pole_data(i).poles)
+            disp(sprintf('    doing boundary %d...', i))
+        [pole_figure_density(i).density, pole_figure_density(i).valid_poles_weight]=gtMakePoleFigure('poles', pole_data(i).poles, 'weights', pole_data(i).weights, 'plot_figure', 0);
+        end
+    end
+    
+    save(sprintf('4_grains/grain%d_/pole_figure_density.mat',grainID), 'pole_figure_density')
+    end
+end
\ No newline at end of file
diff --git a/5_reconstruction/gtBackproGrain.m b/5_reconstruction/gtBackproGrain.m
new file mode 100755
index 0000000000000000000000000000000000000000..b4f6d47300d213a27305d65b9f9473cad58fdaf1
--- /dev/null
+++ b/5_reconstruction/gtBackproGrain.m
@@ -0,0 +1,45 @@
+function [img,img2] = gtBackproGrain(grainid, z_of_sino)
+%same structure as gtnew_read_spots
+%do the backproject of the spots at the z position specified
+%use only those projections selected in index
+
+%load data
+parameters=[];
+if isempty(parameters)
+  load parameters.mat
+end
+
+
+Omega=[]; index=[]; stack=[];
+
+for i=1:length(grainid)
+graindata = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid(i),grainid(i)));
+
+Omega = [Omega graindata.Omega];
+stack=cat(3, stack, graindata.stack);
+
+if ~exist('z_of_sino', 'var')
+  z_of_sino=graindata.zcenter;
+end
+
+if isfield(graindata, 'index')
+index=[index graindata.index];
+else
+  index=[index ones(1,length(graindata.Omega))];
+end
+
+end
+
+%read images to produce sinogram at position z_of_sino
+for i=1:size(stack,3)
+%read sino from stack
+sino(:,i) = stack(z_of_sino, :, i);     
+end
+   
+binsino = sino>0.1*max(sino(:));
+img = backpro(binsino(:,find(index)),Omega(find(index))*pi/180);
+  
+img2 = backpro(sino(:,find(index)),Omega(find(index))*pi/180);
+   
+   
+end
diff --git a/5_reconstruction/gtBoundaryPoles.m b/5_reconstruction/gtBoundaryPoles.m
new file mode 100755
index 0000000000000000000000000000000000000000..2fffdaff1c16108277d14856f7878c5bdc0de836
--- /dev/null
+++ b/5_reconstruction/gtBoundaryPoles.m
@@ -0,0 +1,104 @@
+function [output, save_angles]=gtBoundaryPoles(list, boundaries_structure, crack_vol)
+
+%read(+plot), on a standard stereographic triangle(001, 101, 111), the poles of each boundary in
+%the coordinates of the relevant grains.
+
+
+save_angles=[];
+output=[];
+
+sym = gtGetCubicSymOp;
+    
+if isempty(list)
+  list=1:length(boundaries_structure);
+end
+
+
+for k=1:length(list) %just look at the possible twin boundaries
+  i=list(k)
+%for i=2:1987  
+%k=i;
+
+%skip "open" boundaries (grain-air)
+  if boundaries_structure(i).grain1==0 || boundaries_structure(i).grain2==0 || boundaries_structure(i).count<4
+    continue
+    
+% else
+ elseif boundaries_structure(i).sigma==3 
+%disp('sigma 3')
+%     %to use only those from a crack
+%     elseif boundaries_structure(i).crack8_count>4 %& (boundaries_structure(i).crack8_count/boundaries_structure(i).count)>0.2%/boundaries_list(i,4)>0.5
+%     
+%     i
+%     test=crack_vol==i;
+%      [x,y,z]=ind2sub(size(test), find(test));
+%     [origin, a, d, normd]=lsplane([x y z]);
+%     crack_facet=a;
+%     crack_facet(3)=-crack_facet(3);
+%     
+%     %angle between crack facet and grain boundary
+%     test_angle=acos(dot(crack_facet, boundaries_structure(i).gb_norm))
+%     save_angles=[save_angles; test_angle];
+%     
+%     if test_angle<30*pi/180 | test_angle>150*pi/180
+
+      
+   gb_normal=boundaries_structure(i).gb_norm'; 
+   
+   %playing with orientations here for id11 data
+  % gb_normal(1)=-gb_normal(1);
+    %  gb_normal(2)=-gb_normal(2);
+   
+   
+   
+    %get the grain orientations
+    R1=boundaries_structure(i).grain1_R_vector;
+    g1=Rod2g(R1);
+
+    R2=boundaries_structure(i).grain2_R_vector;
+    g2=Rod2g(R2);
+    
+    gb_normal1=inv(g1)*gb_normal;
+    gb_normal2=inv(g2)*gb_normal;
+% 
+% %should be able to read straight from the structure when not faffing
+%   gb_normal1=boundaries_structure(i).gb_norm_grain1';
+%   gb_normal2=boundaries_structure(i).gb_norm_grain2';
+  
+  
+    %need to search symmetry equivelents for the pole in the SST
+    tmp1=[];tmp2=[];
+    
+    for j=1:24
+      tmp1(j,:) = gb_normal1'*sym(j).g;
+      tmp2(j,:) = gb_normal2'*sym(j).g;
+    end
+    
+%  output=[output; tmp1; tmp2];
+  output=[output; repmat(i, 24, 1) tmp1; repmat(i, 24, 1) tmp2];
+    
+%    end %for crack condition
+  
+  end
+
+  
+end
+  %end
+  
+%plot the poles
+
+if 0 
+figure(1)
+a=sqrt(output(1:2:(end-1),1).^2 + output(1:2:(end-1),2).^2);
+b=atan2(output(1:2:(end-1),2),output(1:2:(end-1),1));
+plot(a.*cos(b), a.*sin(b), 'o');
+
+a=sqrt(output(2:2:end,1).^2 + output(2:2:end,2).^2);
+b=atan2(output(2:2:end,2),output(2:2:end,1));
+plot(a.*cos(b), a.*sin(b), 'ro');
+
+figure(2)
+plot3(output(1:2:(end-1),1), output(1:2:(end-1),2), output(1:2:(end-1),3), 'bo')
+
+plot3(output(2:2:end,1), output(2:2:end,2), output(2:2:end,3), 'ro')
+end
diff --git a/5_reconstruction/gtCaxisCmap.m b/5_reconstruction/gtCaxisCmap.m
new file mode 100755
index 0000000000000000000000000000000000000000..a736af7f9e9b87cfdd0181064209c7a90fa66e5e
--- /dev/null
+++ b/5_reconstruction/gtCaxisCmap.m
@@ -0,0 +1,94 @@
+
+
+function c_axismap=gtCaxisCmap
+% make a colourmap according to c-axis orientation
+% c_axis - calculated from r_vectors list as produced by gtReadGrains
+% r_vectors -> c-axis -> phi/psi -> hsl -> rgb colormap
+% use psi to give brightness; phi to give colour
+
+%%%%%%%%%%%%%%on s interesse a l axe c
+load parameters
+load r_vectors
+
+ 
+all_hkils=[];
+hkil = [...
+    0 0 0 2; ...
+    ];
+for i = 1:size(hkil,1)
+    all_hkils = [all_hkils ; gtGetReflections_sab(hkil(i,:))];
+end
+% normalise hkls vector
+% going to cartesian reciprocal space + normalisation of the cartesian
+% space
+for i=1:size(all_hkils)
+    all_hkls(i,1)= all_hkils(i,1) + 0.5 * all_hkils(i,2);
+    all_hkls(i,2)= 3^0.5/2 *all_hkils(i,2);
+    all_hkls(i,3)= all_hkils(i,4);
+
+    all_hkls(i,1)=all_hkls(i,1)*2/(sqrt(3)*parameters.acq.latticepar(1));
+    all_hkls(i,2)=all_hkls(i,2)*2/(sqrt(3)*parameters.acq.latticepar(1));
+    all_hkls(i,3)=all_hkls(i,3)/parameters.acq.latticepar(3);
+end
+tmp = sqrt(sum((all_hkls.*all_hkls),2));
+normalised_hkls = all_hkls./(repmat(tmp,1,3));
+% unification des notations pour la suite
+all_hkls = [];
+all_hkls = all_hkils;
+
+
+for i=1:size(r_vectors,1)
+    g = Rod2g(r_vectors(i,2:4));
+    all_normals = (g * normalised_hkls')';
+    c_axis(i,1)=r_vectors(i,1);
+    if all_normals(2,3)>=0
+        c_axis(i,2)=all_normals(2,1);
+        c_axis(i,3)=all_normals(2,2);
+        c_axis(i,4)=all_normals(2,3);
+    else
+        c_axis(i,2)=all_normals(1,1);
+        c_axis(i,3)=all_normals(1,2);
+        c_axis(i,4)=all_normals(1,3);
+    end
+end
+
+
+save c_axis c_axis % list of the c axis
+
+
+psi=acosd(c_axis(:,4));
+phi=atan2(c_axis(:,3), c_axis(:,2));
+% phi=atan2(c_axis(:,2), c_axis(:,3));
+%get everything in degrees, and on the right interval
+phi=phi*180/pi;
+% %want all psi between 0 and 90
+% psi(find(psi>90))=180-psi(find(psi>90));
+% %if we change psi, should also change phi
+% phi(find(psi>90))=phi(find(psi>90))+180;
+
+dummy=find(psi>90);
+psi(dummy)=180-psi(dummy);
+%if we change psi, should also change phi
+phi(dummy)=phi(dummy)+180;
+
+phi(find(phi<0))=phi(find(phi<0))+360;
+phi(find(phi>360))=phi(find(phi>360))-360;
+
+%use hsl2rgb.m
+%hue
+h=phi/360;
+%saturation
+s=ones(size(h));
+%lightness (white //z, black in x-y plane)
+l=0.9-(0.8*(psi/90));
+
+rgb=hsl2rgb([h s l]);
+
+%add black background and expand list length of max(grainid)+1
+c_axismap=zeros(max(c_axis(:,1))+1, 3);
+for i=1:length(c_axis)
+  c_axismap(c_axis(i,1)+1, :)=rgb(i,:);
+end
+
+%save the caxis colourmap
+save c_axismap c_axismap
\ No newline at end of file
diff --git a/5_reconstruction/gtCaxisCmap_key.m b/5_reconstruction/gtCaxisCmap_key.m
new file mode 100755
index 0000000000000000000000000000000000000000..b3c3da002685b9406e81b1bf24f409f6b2af0ddc
--- /dev/null
+++ b/5_reconstruction/gtCaxisCmap_key.m
@@ -0,0 +1,69 @@
+
+%make a figure showing the CaxisCmap
+%present in steorographic projection
+
+%colours - whether from gtCaxisCmap or from gtAnalyseCrackPlane - are
+%calculated from vectors in instrument coordinate system.  
+%TOMO: x: left to right; y: top to bottom; z: positive is into page/screen
+%INST: x: //y tomo; y: //x tomo; z: // negative z tomo
+
+%colours: red-> green-> blue-> red as phi=0( // inst x
+%axis)-> phi=120-> 240-> 360, anticlockwise.
+
+%therefore red is at bottom of the screen, green is uppper right, blue is
+%upper left.
+
+
+function gtCaxisCmap_key
+
+id=figure;
+
+inc=pi/100;
+
+for phi=-inc:inc:(2*pi)+inc; %around z-axis
+    for psi=0:inc:pi/2; %away from z axis
+
+        r1=tan(psi/2);
+        r2=tan((psi+inc)/2);
+
+        %offset phi by -(pi/2) to put phi=0 at bottom of the image
+        x=[r1*cos(phi-(pi/2)) r1*cos(phi+inc-(pi/2)) r2*cos(phi+inc-(pi/2)) r2*cos(phi-(pi/2))];
+        y=[r1*sin(phi-(pi/2)) r1*sin(phi+inc-(pi/2)) r2*sin(phi+inc-(pi/2)) r2*sin(phi-(pi/2))];
+
+        %centre of patch to give mean colour
+        mpsi=psi+inc/2;
+        mphi=phi+inc/2;
+
+        %keep edges within limits
+        if mphi<0
+            mphi=0;
+        end
+        if mphi>2*pi
+            mphi=2*pi;
+        end
+        if mpsi>pi/2
+            mpsi=pi/2;
+        end
+
+        %calculate colour
+        h=mphi/(2*pi);
+        %saturation
+        s=ones(size(h));
+        %lightness (white //z, black in x-y plane)
+        l=0.9-(0.8*(mpsi/(pi/2)));
+
+        rgb=hsl2rgb([h s l]);
+
+        %draw patch
+        p=patch(x,y,rgb);
+        set(p, 'edgecolor', 'none');
+    end
+end
+
+axis square
+id=gca(id);
+set(id, 'xticklabel', '');
+set(id, 'yticklabel', '');
+set(id, 'xcolor', 'w')
+set(id, 'ycolor', 'w')
+
diff --git a/5_reconstruction/gtCaxisCmap_sab.m b/5_reconstruction/gtCaxisCmap_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..aaecd3754f5f57924ef6d1b30e4d0416246d5934
--- /dev/null
+++ b/5_reconstruction/gtCaxisCmap_sab.m
@@ -0,0 +1,92 @@
+
+
+function c_axismap=gtCaxisCmap_sab
+% make a colourmap according to c-axis orientation
+% c_axis - calculated from r_vectors list as produced by gtReadGrains
+% r_vectors -> c-axis -> phi/psi -> hsl -> rgb colormap
+% use psi to give brightness; phi to give colour
+
+%%%%%%%%%%%%%%on s interesse a l axe c
+load parameters
+load r_vectors
+
+ 
+all_hkils=[];
+hkil = [...
+    0 0 0 2; ...
+    ];
+for i = 1:size(hkil,1)
+    all_hkils = [all_hkils ; gtGetReflections_sab(hkil(i,:))];
+end
+% normalise hkls vector
+% going to cartesian reciprocal space + normalisation of the cartesian
+% space
+for i=1:size(all_hkils)
+    all_hkls(i,1)= all_hkils(i,1) + 0.5 * all_hkils(i,2);
+    all_hkls(i,2)= 3^0.5/2 *all_hkils(i,2);
+    all_hkls(i,3)= all_hkils(i,4);
+
+    all_hkls(i,1)=all_hkls(i,1)*2/(sqrt(3)*parameters.acq.latticepar(1));
+    all_hkls(i,2)=all_hkls(i,2)*2/(sqrt(3)*parameters.acq.latticepar(1));
+    all_hkls(i,3)=all_hkls(i,3)/parameters.acq.latticepar(3);
+end
+tmp = sqrt(sum((all_hkls.*all_hkls),2));
+normalised_hkls = all_hkls./(repmat(tmp,1,3));
+% unification des notations pour la suite
+all_hkls = [];
+all_hkls = all_hkils;
+
+
+for i=1:size(r_vectors,1)
+    g = Rod2g(r_vectors(i,2:4));
+    all_normals = (g * normalised_hkls')';
+    c_axis(i,1)=r_vectors(i,1);
+    if all_normals(2,3)>=0
+        c_axis(i,2)=all_normals(2,1);
+        c_axis(i,3)=all_normals(2,2);
+        c_axis(i,4)=all_normals(2,3);
+    else
+        c_axis(i,2)=all_normals(1,1);
+        c_axis(i,3)=all_normals(1,2);
+        c_axis(i,4)=all_normals(1,3);
+    end
+end
+
+
+save c_axis_temp c_axis % list of the c axis
+
+
+psi=acosd(c_axis(:,4));
+phi=atan2(c_axis(:,3), c_axis(:,2));
+phi=phi*180/pi;
+% %want all psi between 0 and 90
+% psi(find(psi>90))=180-psi(find(psi>90));
+% %if we change psi, should also change phi
+% phi(find(psi>90))=phi(find(psi>90))+180;
+
+%dummy=find(psi>90)
+% psi(dummy)=180-psi(dummy);
+% %if we change psi, should also change phi
+% phi(dummy)=phi(dummy)+180;
+
+phi(find(phi<0))=phi(find(phi<0))+360;
+%phi(find(phi>360))=phi(find(phi>360))-360;
+
+%use hsl2rgb.m
+%hue
+h=phi/360;
+%saturation
+s=ones(size(h));
+%lightness (white //z, black in x-y plane)
+l=0.9-(0.8*(psi/90));
+
+rgb=hsl2rgb([h s l]);
+
+%add black background and expand list length of max(grainid)+1
+c_axismap=zeros(max(c_axis(:,1))+1, 3);
+for i=1:length(c_axis)
+  c_axismap(c_axis(i,1)+1, :)=rgb(i,:);
+end
+
+%save the caxis colourmap
+save c_axismap_temp c_axismap
\ No newline at end of file
diff --git a/5_reconstruction/gtChangeARTbb.m b/5_reconstruction/gtChangeARTbb.m
new file mode 100755
index 0000000000000000000000000000000000000000..a6d199dbdac84391c87e6b1f5c70c3403baa3800
--- /dev/null
+++ b/5_reconstruction/gtChangeARTbb.m
@@ -0,0 +1,28 @@
+function [x1,y1,nx,ny]=gtChangeARTbb(grainid);
+%to interactively change the ART ROI.
+%update new bb and center in .mat
+
+filename=sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid);
+tmp=load(filename);
+
+zcenter=tmp.zcenter;
+im=gtBackproGrain(grainid,zcenter);
+
+imshow(im,[])
+hold on
+
+  disp('click the top-right, and then bottom-left corners for ROI')
+  points=ginput(2);
+  plot(points(1,1),points(1,2),'rx')
+  plot(points(2,1),points(2,2),'gx')
+  
+x1=round(points(1,1));
+y1=round(points(1,2));
+nx=round(points(2,1)-x1);
+ny=round(points(2,2)-y1);
+xcenter=round(x1+(nx/2));
+ycenter=round(y1+(ny/2));
+
+
+save(filename, 'x1','y1','nx','ny','xcenter','ycenter', '-append')
+
diff --git a/5_reconstruction/gtColourCrack.m b/5_reconstruction/gtColourCrack.m
new file mode 100755
index 0000000000000000000000000000000000000000..56d194d8505d00bae2fe9dc7b35d922b362c3c42
--- /dev/null
+++ b/5_reconstruction/gtColourCrack.m
@@ -0,0 +1,113 @@
+%having aligned crack and boundaries by correlation, assign crack voxels to
+%grain boundaries according to which boundaries are closest.  Hence allow a
+%bit of flexibility to overcome distortions and misalignments.
+%maxradius is the maximum distance between crack and boundary that will be
+%considered
+
+function crack = gtColourCrack(crack_in, boundaries_in, maxradius)
+
+%crack - the crack
+%boundaries - the labelled boundaries
+
+
+crack=crack_in;
+boundaries=boundaries_in;
+% 
+% for i=1:size(crack,1)
+%     i
+% for j=1:size(crack,2)
+% for k=1:size(crack,3)
+%   
+%   if crack(i,j,k)==0
+%     continue
+%   else %a crack voxel
+%     %find the closest boundary label, within a maximum distance
+%     
+%     
+[yy, xx, zz]=ind2sub(size(crack), find(crack));
+
+for a=1:length(xx)
+    
+    if mod(a, 1000)==0
+        a/length(xx)
+    end
+    
+    i=yy(a);
+    j=xx(a);
+    k=zz(a);
+    
+    if boundaries(i,j,k)~=0
+      crack(i,j,k)=boundaries(i,j,k);
+    else
+      
+    found=0;%found a boundary label voxel
+    radius=1;
+    while found==0
+    
+      %loop through a neighbourhood
+      label=[];
+      for x=i-radius:i+radius
+        if x>size(crack,1) || x<1
+          continue
+        end
+        for y=j-radius:j+radius
+        if y>size(crack,2) || y<1
+          continue
+        end
+          for z=k-radius:k+radius
+            if z>size(crack,3) || z<1
+              continue
+            end
+  
+            %if distance greater than radius
+            if sqrt(([x y z]-[i j k])*([x y z]-[i j k])')>radius
+        continue
+            end
+            %likewise, if distance less than radius-1
+            if sqrt(([x y z]-[i j k])*([x y z]-[i j k])')<radius-1
+        continue
+            end
+            
+            if boundaries(x,y,z)~=0%if a label is found
+            label=[label boundaries(x,y,z)];%record all labels within radius
+            end
+            
+          end
+        end
+      end
+    
+      if ~isempty(label)
+        crack(i,j,k)=mode(label);%found a label
+        found=1;
+      elseif radius>maxradius;% used 6 for ss_crackedA_;
+        crack(i,j,k)=0;%failed to find a label
+        found=1;
+      else
+        radius=radius+1;%search wider
+      end
+      
+    end%while searching
+      
+    end%if we need to search
+    
+  end%if this is a crack voxel
+
+% end%loop through crack volume
+% end
+% i/size(crack,1);
+% end
+
+% %colour the output volume
+% crack_in(y1:y2, x1:x2, z1:z2)=crack;
+% 
+% %loop through subvolumes
+% 
+% xx
+% yy
+% zz
+%     end
+%   end
+% end
+if 0
+edf_write(crack, 'crack_coloured.edf', 'uint16')
+end
diff --git a/5_reconstruction/gtColourCrack2.m b/5_reconstruction/gtColourCrack2.m
new file mode 100755
index 0000000000000000000000000000000000000000..abf22b28952c2d508c43e2d7076340e0ff8c2e6a
--- /dev/null
+++ b/5_reconstruction/gtColourCrack2.m
@@ -0,0 +1,92 @@
+
+
+function crack_out = gtColourCrack2(crack, boundaries, boundaries_structure)
+
+%colour crack according to boundary labels
+%use criteria of local boundary plane
+
+%calculate crack plane from this size neighbourhood
+crackR=3;
+%consider boundaries within this neighborhood
+boundsR=10;
+  
+[crackx, cracky, crackz]=ind2sub(size(crack), find(crack));
+[sizex, sizey, sizez]=size(boundaries);
+
+%make a distance map for later
+distmap=zeros((2*boundsR)+1, (2*boundsR)+1, (2*boundsR)+1);
+distmap(boundsR+1, boundsR+1, boundsR+1)=1;
+distmap=bwdist(distmap);
+
+%crack_out is coloured by boundaries
+crack_out=zeros(size(crack));
+
+for i=1:length(crackx)
+  
+  if mod(i, 1000)==0
+    i/length(crackx)
+  end
+  
+  %get the crack voxel location
+  x=crackx(i);  y=cracky(i);  z=crackz(i);
+  
+  %get the crack neighbourhood to calculate crack plane
+  xc1=x-crackR;yc1=y-crackR;zc1=z-crackR;
+  xc2=x+crackR;yc2=y+crackR;zc2=z+crackR;
+  
+  dum=find(crackx>xc1 & crackx<xc2 & cracky>yc1 & cracky<yc2 & crackz>zc1 & crackz<zc2);
+  
+  if length(dum)>3
+  
+  crackx_local=crackx(dum);
+  cracky_local=cracky(dum);
+  crackz_local=crackz(dum);
+  
+  %check that this is okay x y z
+  
+  [crack_origin, crack_normal]=lsplane([crackx_local cracky_local crackz_local]);
+  crack_normal(3)=-crack_normal(3); %should match boundaries_structure.mat  
+  
+  %which boundaries are close?
+  xb1=max(1,x-boundsR);yb1=max(1,y-boundsR);zb1=max(1,z-boundsR);
+  xb2=min(sizex,x+boundsR);yb2=min(sizey,y+boundsR);zb2=min(sizez,z+boundsR);
+  
+  bounds_local=boundaries(xb1:xb2, yb1:yb2, zb1:zb2);
+  bounds_list=unique(bounds_local);
+  bounds_list(find(bounds_list==0))=[];
+  
+ dev=[]; dist=[];
+  for j=1:length(bounds_list)
+    %are these boundaries close in angle? read from boundaries_structure
+    bound_normal=boundaries_structure(bounds_list(j)).gb_norm;
+    if ~isempty(bound_normal)
+      bound_dev=acosd(dot(bound_normal, crack_normal));
+      dev(j)=90-abs(bound_dev-90);
+    else
+      dev(j)=11;%default for external boundaries
+      
+ %     nb external boundaries shouldn't really crack! only where there are internal gaps in the map
+      
+    end
+  
+    %are they close in distance? use distmap
+    dist(j)=min(distmap(find(bounds_local==bounds_list(j))));
+  end
+  
+  %choose best boundary
+  
+  %   can adjust things here
+  
+  rating=(dev/10)+(dist/boundsR);
+%  rating=(dev/10)+(dist/boundsR);
+  boundary=bounds_list(find(rating==min(rating)));
+  
+  if ~isempty(boundary)
+  crack_out(x,y,z)=min(boundary);
+  else
+  crack_out(x,y,z)=0;
+  end
+  
+    
+  end
+end
diff --git a/5_reconstruction/gtCorrelate_lastandprevious.m b/5_reconstruction/gtCorrelate_lastandprevious.m
new file mode 100755
index 0000000000000000000000000000000000000000..1c7d3480ae5a653684be65944973285d685f81c3
--- /dev/null
+++ b/5_reconstruction/gtCorrelate_lastandprevious.m
@@ -0,0 +1,47 @@
+%correlating two different grains into two different datasets - for a given grainID it finds the
+%correlated grain in the S5_dct1_ for graingrowth data
+%Marcelo
+%06/11/2006 - modified in 24/01/2007
+
+
+function [C] = gtcorrelate_lastandprevious(number_of_grains,last_dataset,first_dataset) %number_of_grains correspond to the number
+% of grains in the last dataset, usually the last growth step
+% last dataset last growth step that you want to use
+% first dataset step that you want to use
+
+C=zeros(88,3); % set the number of grains in the first dataset, given by the user 
+
+for j=1:number_of_grains
+	grain_data = load(sprintf('/data/id19/graintracking/graingrowth/%s/4_grains/grain%d_/grain%d_.mat',last_dataset,j,j));
+	A=fieldnames(grain_data);
+	if size(A,1) == 27
+		z_center = grain_data.vol_z_origin+(grain_data.vol_z_size/2);
+		grain_x = grain_data.vol_x_origin+(grain_data.vol_x_size/2);
+		grain_y = grain_data.vol_y_origin+(grain_data.vol_y_size/2);
+		R_vector_s5 = grain_data.R_vector;
+
+    for i=1:88
+			tmp1=load(sprintf('/data/id19/graintracking/graingrowth/%s/4_grains/grain%d_/grain%d_.mat',first_dataset,i,i));
+			B=fieldnames(tmp1);
+			
+			if size(B,1) == 27
+				zcenter=tmp1.vol_z_origin+(tmp1.vol_z_size/2);
+				xgrain=tmp1.vol_x_origin+(tmp1.vol_x_size/2);
+				ygrain=tmp1.vol_y_origin+(tmp1.vol_y_size/2);
+				R_vector_s1 = tmp1.R_vector;
+				if zcenter >= (z_center-17) && zcenter <= (z_center+17) && xgrain <= (grain_x+17) && xgrain >= (grain_x-17) && ygrain <= (grain_y+28) && ygrain >= (grain_y-28) && R_vector_s1(1) <= (R_vector_s5(1)+0.005) && R_vector_s1(1) >= (R_vector_s5(1)-0.005) && R_vector_s1(2) <= (R_vector_s5(2)+0.005) && R_vector_s1(2) >= (R_vector_s5(2)-0.005) && R_vector_s1(3) <= (R_vector_s5(3)+0.005) && R_vector_s1(3) >= (R_vector_s5(3)-0.005) 
+						disp('I found the correlated grain')
+						C(j,1)=j;
+						if C(j,2)==0
+						C(j,2)=i;
+						else
+							C(j,3)=i;
+						end
+        else
+				end
+			else
+			end
+		end
+	else
+	end
+end
\ No newline at end of file
diff --git a/5_reconstruction/gtDoART.m b/5_reconstruction/gtDoART.m
new file mode 100755
index 0000000000000000000000000000000000000000..4a4c2b4b1ccb19066230f576dc9c56c2304f392d
--- /dev/null
+++ b/5_reconstruction/gtDoART.m
@@ -0,0 +1,81 @@
+function gtDoART(grainid)
+%simply launch the reconstruction of a grain for a standard set of
+%parameters
+%use the index of good reflections if it exists
+
+
+  load parameters.mat
+
+
+%read in data
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+%struct_ids = grain_data.struct_ids;
+
+%if it doesn't already exist, add an index of projections to use
+if isfield(grain_data,'index')
+  index = grain_data.index;
+else
+  index = ones(1,length(grain_data.struct_ids));
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'index', '-append') 
+end
+
+scanname = sprintf('grain%d_',grainid);
+parfilename = sprintf('grain%d_.par',grainid);
+whole_parfilename = sprintf('grain%d_whole.par',grainid);
+
+if isfield(grain_data,'lambda')
+  art_params = grain_data.lambda;%if assigned manually
+else
+  art_params = [0.6 0.2 0.1]; % 0.2 0.1]; %default values
+  lambda=art_params;
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'lambda', '-append')
+end
+
+
+cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+
+nbiter = length(art_params);
+pixsize = 1;
+braggangle = 0;
+np = parameters.acq.bb(3);
+nq = parameters.acq.bb(4);
+offset = 0;
+
+x1 = grain_data.x1;
+y1 = grain_data.y1;
+nx = grain_data.nx;
+ny = grain_data.ny;
+
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+p_angles = -grain_data.Omega(find(index));
+p_numbers = find(index);
+
+%write .par file for the whole grain, add to batch file
+gtMakeARTJob(scanname,whole_parfilename,p_numbers,p_angles,art_params,nbiter,pixsize,braggangle,np,nq,offset, ... 
+  grain_data.zstart,grain_data.zend-grain_data.zstart,x1,nx,y1,ny);
+
+
+%start reconstruction and write batch file for volume conversions
+cd(parameters.acq.dir);
+fid = fopen('seg2view.sh','a');
+command=sprintf('%s 4_grains/grain%d_/%s_res0_%d\n\n',seg2view,grainid,scanname,nbiter);
+fprintf(fid,command); 
+fclose(fid);
+
+if 1
+  gtMakeCondorJob(grainid);
+else
+disp('Not starting condor job!')
+
+  cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+  % clear all previous work
+%  system('rm *spr *sdt');
+  system(sprintf('/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg %s',whole_parfilename));
+  for n=1:nbiter
+    system(sprintf('%s %s_res0_%d\n\n',seg2view,scanname,n));
+  end
+  cd(parameters.acq.dir);
+end
+  
diff --git a/5_reconstruction/gtDoART3D.m b/5_reconstruction/gtDoART3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..1fbe14f8a45cb1f6f7667a3600d79eba5d285da6
--- /dev/null
+++ b/5_reconstruction/gtDoART3D.m
@@ -0,0 +1,82 @@
+function gtDoART3D(grainid,grain_data,parameters)
+%simply launch the reconstruction of a grain for a standard set of
+%parameters
+%use the index of good reflections if it exists
+
+
+
+
+%read in data
+%grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+%grain_data=grain{grainid};
+
+%if it doesn't already exist, add an index of projections to use
+if isfield(grain_data,'index')
+  index = grain_data.index;
+else
+  index = ones(1,length(grain_data.pairid));
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'index', '-append') 
+end
+
+scanname = sprintf('grain%d_',grainid);
+parfilename = sprintf('grain%d_.par',grainid);
+whole_parfilename = sprintf('grain%d_whole.par',grainid);
+
+if isfield(grain_data,'lambda')
+  lambda = grain_data.lambda;%if assigned manually
+else
+  lambda = [1:-0.2:0.6]; % 0.2 0.1]; %default values
+  
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'lambda', '-append')
+end
+
+
+cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+
+nbiter = length(lambda);
+pixsize = 1;
+braggangle = 0;
+np = parameters.acq.bb(3);
+nq = parameters.acq.bb(4);
+offset = 0;
+
+x1 = grain_data.x1;
+y1 = grain_data.y1;
+nx = grain_data.nx;
+ny = grain_data.ny;
+z1 = grain_data.z1;
+nz = grain_data.nz;
+
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+
+p_numbers = find(index);
+
+%write .par file for the whole grain, add to batch file
+
+gtMakeARTJob3D('difspot',whole_parfilename,find(index),[],grain_data,parameters,lambda,x1,nx,y1,ny,z1,nz,0);
+
+
+%start reconstruction and write batch file for volume conversions
+cd(parameters.acq.dir);
+fid = fopen('seg2view.sh','a');
+command=sprintf('%s 4_grains/grain%d_/difspot_res0_%d\n\n',seg2view,grainid,nbiter);
+fprintf(fid,command); 
+fclose(fid);
+
+if 1
+  gtMakeCondorJob(grainid);
+else
+disp('Not starting condor job!')
+
+  cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+  % clear all previous work
+%  system('rm *spr *sdt');
+  system(sprintf('/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg %s',whole_parfilename));
+  for n=1:nbiter
+    system(sprintf('%s %s_res0_%d\n\n',seg2view,scanname,n));
+  end
+  cd(parameters.acq.dir);
+end
+  
diff --git a/5_reconstruction/gtDoART3D2.m b/5_reconstruction/gtDoART3D2.m
new file mode 100755
index 0000000000000000000000000000000000000000..314226e2965fc15ee750e6f81792434471b30f03
--- /dev/null
+++ b/5_reconstruction/gtDoART3D2.m
@@ -0,0 +1,74 @@
+scanname = sprintf('test_');
+parfilename = sprintf('test_.par');
+whole_parfilename = sprintf('test_whole.par');
+
+art_params = 1;  % just do back projection, no ART effects
+lambda=art_params;
+
+nbiter = length(art_params);
+
+pixsize = 1; %0.0014;
+
+np = 100;
+nq = 100;
+offset = 0;
+braggangle =0;
+rec_alg='~/matlab/graintracking/aNotSorted/rec_alg';
+seg2view='~/matlab/graintracking/aNotSorted/seg2view';
+
+psi_angles = -[0 0 0 0];
+twotheta=[0 0 0 0];
+eta=[0 90 180 270];
+
+%disp('not generating projections')
+if 1
+composite=[];
+for n=1:length(psi_angles)
+  im=ones(2048);
+  disp('unity images')
+%  im=gtGenFP(twotheta(n),eta(n));
+  fname=sprintf('%s%d',scanname,n)
+  sdt_write(fname,im,'float32');
+  size(im)
+%  composite=composite+im;
+  imagesc(im)
+  title(n)
+  axis image
+  drawnow
+  shg
+end
+end
+z1=-size(im,1)/2
+x1=z1;y1=x1;
+nz=size(im,1);
+nx=nz;ny=nx;
+
+xsi_angles= [90];
+delta_angles=[0];
+
+% if we know the spot height above the detector centre (centroidY of spot)
+% and we know the two theta it should use
+% then we should move teh source (fgd) to the correct distance so t
+
+%write .par file for the whole grain, add to batch file
+gtART3D_GJ(...
+  scanname,...
+  whole_parfilename,...
+  1:length(psi_angles),psi_angles,xsi_angles,delta_angles,twotheta,eta,...
+  art_params,nbiter,pixsize,braggangle,...
+  np,nq,offset, ...
+  z1,nz,...
+  x1,nx,...
+  y1,ny...
+  );
+
+%  parameters.acq.bb(2)-1024,parameters.acq.bb(4),...
+%  parameters.acq.bb(1)-1024,parameters.acq.bb(3),...
+%  parameters.acq.bb(1)-1024,parameters.acq.bb(3));
+
+
+system(sprintf('%s %s',rec_alg,whole_parfilename));
+for n=1:nbiter
+  system(sprintf('%s %s_res0_%d\n\n',seg2view,scanname,n));
+end
+
diff --git a/5_reconstruction/gtDoART_jun07test.m b/5_reconstruction/gtDoART_jun07test.m
new file mode 100755
index 0000000000000000000000000000000000000000..6f6de67f17e95420bef09aa80a1c059800b493ff
--- /dev/null
+++ b/5_reconstruction/gtDoART_jun07test.m
@@ -0,0 +1,82 @@
+function gtDoART(grainid)
+%simply launch the reconstruction of a grain for a standard set of
+%parameters
+%use the index of good reflections if it exists
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%read in data
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+%struct_ids = grain_data.struct_ids;
+
+%if it doesn't already exist, add an index of projections to use
+if isfield(grain_data,'index')
+  index = grain_data.index;
+else
+  index = ones(1,length(grain_data.struct_ids));
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'index', '-append') 
+end
+
+scanname = sprintf('grain%d_',grainid);
+parfilename = sprintf('grain%d_.par',grainid);
+whole_parfilename = sprintf('grain%d_whole.par',grainid);
+
+if isfield(grain_data,'lambda')
+  art_params = grain_data.lambda;%if assigned manually
+else
+  art_params = [0.6 0.2 0.1]; % 0.2 0.1]; %default values
+  lambda=art_params;
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'lambda', '-append')
+end
+
+
+cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+
+nbiter = length(art_params);
+pixsize = 1;
+braggangle = 0;
+np = parameters.acq.bb(3);
+nq = parameters.acq.bb(4);
+offset = 0;
+
+x1 = grain_data.x1;
+y1 = grain_data.y1;
+nx = grain_data.nx;
+ny = grain_data.ny;
+
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+p_angles = -grain_data.Omega(find(index));
+p_numbers = find(index);
+
+%write .par file for the whole grain, add to batch file
+gtMakeARTJob(scanname,whole_parfilename,p_numbers,p_angles,art_params,nbiter,pixsize,braggangle,np,nq,offset, ... 
+  grain_data.zstart,grain_data.zend-grain_data.zstart,x1,nx,y1,ny);
+
+
+%start reconstruction and write batch file for volume conversions
+cd(parameters.acq.dir);
+fid = fopen('seg2view.sh','a');
+command=sprintf('%s 4_grains/grain%d_/%s_res0_%d\n\n',seg2view,grainid,scanname,nbiter);
+fprintf(fid,command); 
+fclose(fid);
+
+if 0
+  gtMakeCondorJob(grainid);
+else
+disp('Not starting condor job!')
+
+  cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+  % clear all previous work
+%  system('rm *spr *sdt');
+  system(sprintf('/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg %s',whole_parfilename));
+  for n=1:nbiter
+    system(sprintf('%s %s_res0_%d\n\n',seg2view,scanname,n));
+  end
+  cd(parameters.acq.dir);
+end
+  
diff --git a/5_reconstruction/gtFillGrain.m b/5_reconstruction/gtFillGrain.m
new file mode 100755
index 0000000000000000000000000000000000000000..4a022b3d29dbc8ff072586bf53d5a04dd53aa069
--- /dev/null
+++ b/5_reconstruction/gtFillGrain.m
@@ -0,0 +1,106 @@
+function vol_out = gtFillGrain(grainid, varargin)
+
+%vol is a greyscale grain volume.
+%use Greg's gtSnakeBW to fill holes in th grain, going slice by slice.
+%try to remove odd features...
+
+%varargin : saveflag to save an edf in the grain directory
+saveflag=0;
+if ~isempty(varargin)
+	saveflag=varargin{1};
+end
+
+
+tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid, grainid));
+
+if isfield(tmp, 'bad') & tmp.bad>0
+  
+  disp('grain is already set to bad')
+  vol_out=[];
+  return
+
+end
+  
+vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',grainid,grainid));
+
+%threshold - this could use the automatic function graythresh
+
+%     a=max(vol(:));
+%     val1=mean(vol(find(vol>(a/10))))-std(vol(find(vol>(a/10))));%std dev, ignoring low (background) values
+%     %further playing...
+%     [n,x]=hist(vol(:),500);
+%     n(find(x>val1))=[];
+%     x(find(x>val1))=[];
+%     val2=min(x(find(n==min(n))));
+%     thresh_val=min(val1, val2);
+thresh_val=graythresh(vol);
+%volgrey=vol;%save grey vol
+vol=vol>thresh_val;
+keyboard
+%volA=vol;
+
+%label vol
+vol=bwlabeln(vol, 6);
+
+%discard small bits (smaller than 10% of the largest non-zero bit)
+[n,x]=hist(vol(:), max(vol(:)));
+%remove zeros
+n(1)=n(1)-length(find(vol==0));
+x=x+0.5;
+%keep only the labels of large things
+x(find(n<(max(n)/10)))=[];
+vol2=zeros(size(vol));
+for i=1:length(x)
+vol2=vol2+(vol==x(i));
+end
+vol=vol2;
+
+%volB=vol;
+
+%try to kill spurs without changing shape
+%spurs are horizontal plane only, so can use only vertical strel
+%pad top and bottom of vol with zeros to help erosion
+vol2=zeros(size(vol)+[0 0 2]);
+vol2(:,:,2:end-1)=vol;
+
+%bigger range can be used on big grains
+a=max(10, ceil(size(vol,3)/10))
+
+vol2=imerode(vol2, ones(1,1,a));
+vol2=imdilate(vol2, ones(1,1,2*a));
+%vol2 should have no spurs, but hopefully the over dilate will prevent
+%anything real from disappearing. 
+
+%unpad vol2
+vol2(:,:,1)=[];
+vol2(:,:,end)=[];
+
+%now use vol2 to mask vol
+vol=vol.*vol2;
+
+%volC=vol;
+
+%now work slice by slice
+for i=1:size(vol,3)
+
+  if length(find(vol(:,:,i)))>0
+  
+  %test on aspect ratio
+  
+  %use snake to fill holes
+  try
+vol(:,:,i)=gtSnakeBW(vol(:,:,i));%can pass snakeoptions here
+  end
+
+  end
+  
+end
+
+vol_out=vol;
+
+
+if saveflag
+name=sprintf('4_grains/grain%d_/grain%d_filled.edf',grainid,grainid);
+disp(sprintf('writing volume %s',name));
+edf_write(vol_out,name,'uint8');
+end
\ No newline at end of file
diff --git a/5_reconstruction/gtFillGrain2D.m b/5_reconstruction/gtFillGrain2D.m
new file mode 100755
index 0000000000000000000000000000000000000000..a7aacad9915fb1494c040c8a35521dbf59b718ff
--- /dev/null
+++ b/5_reconstruction/gtFillGrain2D.m
@@ -0,0 +1,112 @@
+function [vol_out,thresh_val] = gtFillGrain(grainid, varargin)
+
+%vol is a greyscale grain volume.
+%use Greg's gtSnakeBW to fill holes in th grain, going slice by slice.
+%try to remove odd features...
+
+%varargin : saveflag to save an edf in the grain directory
+saveflag=0;
+
+
+
+
+tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid, grainid));
+
+if isfield(tmp, 'bad') & tmp.bad>0
+  
+  disp('grain is already set to bad')
+  vol_out=[];
+  return
+
+end
+  
+vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',grainid,grainid));
+volorig=vol;
+%threshold - this could use the automatic function graythresh
+
+%     a=max(vol(:));
+%     val1=mean(vol(find(vol>(a/10))))-std(vol(find(vol>(a/10))));%std dev, ignoring low (background) values
+%     %further playing...
+%     [n,x]=hist(vol(:),500);
+%     n(find(x>val1))=[];
+%     x(find(x>val1))=[];
+%     val2=min(x(find(n==min(n))));
+%     thresh_val=min(val1, val2);
+if ~isempty(varargin)
+	thresh_val=varargin{1};
+else
+    thresh_val=graythresh(vol);
+end
+	%volgrey=vol;%save grey vol
+vol=vol>thresh_val;
+
+%volA=vol;
+
+%label vol
+vol=bwlabeln(vol, 6);
+
+%discard small bits (smaller than 10% of the largest non-zero bit)
+[n,x]=hist(vol(:), max(vol(:)));
+%remove zeros
+n(1)=n(1)-length(find(vol==0));
+x=x+0.5;
+%keep only the labels of large things
+x(find(n<(max(n)/10)))=[];
+vol2=zeros(size(vol));
+for i=1:length(x)
+vol2=vol2+(vol==x(i));
+end
+vol=vol2;
+
+figure(2);imshow(volorig(:,:,3)-2*thresh_val*vol(:,:,3),[-3*thresh_val,10*thresh_val])
+
+
+%volB=vol;
+
+%try to kill spurs without changing shape
+%spurs are horizontal plane only, so can use only vertical strel
+%pad top and bottom of vol with zeros to help erosion
+%vol2=zeros(size(vol)+[0 0 2]);
+%vol2(:,:,2:end-1)=vol;
+
+%bigger range can be used on big grains
+%a=max(10, ceil(size(vol,3)/10))
+
+%vol2=imerode(vol2, ones(1,1,a));
+%vol2=imdilate(vol2, ones(1,1,2*a));
+%vol2 should have no spurs, but hopefully the over dilate will prevent
+%anything real from disappearing. 
+
+%unpad vol2
+%vol2(:,:,1)=[];
+%vol2(:,:,end)=[];
+
+%now use vol2 to mask vol
+%vol=vol.*vol2;
+
+%volC=vol;
+
+%now work slice by slice
+for i=3
+
+  if length(find(vol(:,:,i)))>0
+  
+  %test on aspect ratio
+  
+  %use snake to fill holes
+  try
+    vol(:,:,i)=gtSnakeBW(vol(:,:,i));%can pass snakeoptions here
+  end
+
+  end
+  
+end
+
+vol_out=vol(:,:,3);
+
+
+if saveflag
+name=sprintf('4_grains/grain%d_/grain%d_filled.edf',grainid,grainid);
+disp(sprintf('writing volume %s',name));
+edf_write(vol_out,name,'uint8');
+end
\ No newline at end of file
diff --git a/5_reconstruction/gtFillGrain_wrapper.m b/5_reconstruction/gtFillGrain_wrapper.m
new file mode 100755
index 0000000000000000000000000000000000000000..5349c4f08f0f5391dbf0dedb6e2991aa5a20ea74
--- /dev/null
+++ b/5_reconstruction/gtFillGrain_wrapper.m
@@ -0,0 +1,68 @@
+function gtFillGrain_wrapper(first, last, workingdirectory)
+
+
+warning('off','Images:initSize:adjustingMag');
+
+if isdeployed
+  first=str2double(first);
+  last=str2double(last);
+end % special case for running interactively in current directory
+
+if ~exist('workingdirectory','var')
+  workingdirectory=pwd;
+end
+
+cd(workingdirectory)
+
+gtDBConnect;
+
+parameters=[];
+load parameters
+
+fill_table=[parameters.acq.name '_fill'];
+
+min_id=1;
+max_id=[];
+try 
+  max_id=mym(sprintf('select max(grainid) from %sextspot', parameters.acq.name))
+  disp(sprintf('doing grainids up to %d', max_id))
+catch
+  disp('no extspot table found, will try grainids up to 1000')
+  max_id=1000;
+end
+zA=0;
+zB=parameters.acq.bb(4);
+
+
+for grainid=min_id:max_id
+
+  test=0;
+  try
+    test=mym(sprintf('insert into %s (grainid) values (%d)', fill_table, grainid));
+  end
+
+  if test==1 %no other job is doing this grain...
+
+
+    tmp=load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+
+    if isfield(tmp, 'bad') & tmp.bad>0
+      disp(sprintf('%d is a bad grain', grainid))
+      continue
+    end
+
+    if tmp.zstart>zB | tmp.zend<zA
+      disp(sprintf('%d is outside of the ROI', grainid))
+      continue
+    end
+    
+    disp(sprintf('doing grain %d', grainid))
+    gtFillGrain(grainid, 1);
+
+  end
+
+  disp(sprintf('another job has taken grain %d', grainid))
+
+end
+
+
diff --git a/5_reconstruction/gtFindSimilarGrains.m b/5_reconstruction/gtFindSimilarGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..43a552b40df9c67c88f0c8e21ecfa1d4ccab96c5
--- /dev/null
+++ b/5_reconstruction/gtFindSimilarGrains.m
@@ -0,0 +1,97 @@
+%find similar grains
+%given the grain structure generated by sort_grains, containing positions
+%and R-vectors, and the parameters files, containing pixel size data...
+
+function output = gtFindSimilarGrains(g1, g2, parameters1, parameters2)
+
+%read out data
+for i=1:length(g1)
+map1.R_vec(i,:)=g1{i}.R_vector;
+map1.pos(i,:)=g1{i}.center;
+end
+for i=1:length(g2)
+map2.R_vec(i,:)=g2{i}.R_vector;
+map2.pos(i,:)=g2{i}.center;
+end
+
+switch parameters1.acq.spacegroup
+  case {225, 229} %cubic
+    sym=gtGetCubicSymOp;
+  case{663, 194} %hexagonal
+    sym=gtGetHexagonalSymOp_sab;
+    
+%%%try producing symmetry operators in 3x3 format    
+a=0
+for i=1:6
+test(i).g=[cosd(a) -sind(a) 0; sind(a) cosd(a) 0; 0 0 1];
+%test2(i).g=[cosd(a) sind(a) 0; -sind(a) cosd(a) 0; 0 0 1];
+a=a+60;
+end
+a=0
+for i=7:12
+test(i).g=[cosd(a) -sind(a) 0; sind(a) cosd(a) 0; 0 0 -1];
+%test2(i).g=[cosd(a) sind(a) 0; -sind(a) cosd(a) 0; 0 0 -1];
+a=a+60;
+end
+sym=test;
+%%%end of bodge
+    
+  otherwise
+    disp('This spacegroup not supported')
+    return
+end
+
+
+
+
+%try to deal with shifts here.
+map1.pos=map1.pos-repmat(mean(map1.pos,1), length(map1.pos), 1);
+map2.pos=map2.pos-repmat(mean(map2.pos,1), length(map2.pos), 1);
+%scale to pixelsize of map 1
+map2.pos=map2.pos*parameters2.acq.pixelsize/parameters1.acq.pixelsize;
+
+
+
+
+%go through grain map 1, looking for matches in grain map 2
+output=[];
+for i=1:length(map1.R_vec)
+  
+  %calculate misorientations
+  misorientation=[];
+  for j=1:length(map2.R_vec)
+          
+    g1=Rod2g(map1.R_vec(i,:));
+    g2=Rod2g(map2.R_vec(j,:));
+    %need to search symmetry equivilents for the minimum misorientation
+    rot_offset=[];
+    for k=1:length(sym)
+      g1equiv = sym(k).g*g1;
+      netg = inv(g1equiv)*g2;
+      rot_offset(k) = acos((trace(netg)-1)/2);  
+    end
+  
+    misorientation(j)=min(abs(rot_offset));
+  end
+  
+  %calculate distances
+  dif = map2.pos-repmat(map1.pos(i,:),size(map2.pos,1),1);
+  distance = sqrt(sum((dif.^2),2));
+  
+i
+pos=find(distance<70 & misorientation'<5*pi/180)
+output(i).possibles=pos;
+  output(i).dif=dif(pos,:);
+  output(i).distance=distance(pos);
+  
+  output(i).misorientations=misorientation(pos);
+  
+  
+end
+  
+
+
+keyboard
+
+
+
diff --git a/5_reconstruction/gtFindSimilarSpots.m b/5_reconstruction/gtFindSimilarSpots.m
new file mode 100755
index 0000000000000000000000000000000000000000..e79ffdb254a72a454fde56a21d506ad0b66112b6
--- /dev/null
+++ b/5_reconstruction/gtFindSimilarSpots.m
@@ -0,0 +1,223 @@
+
+%find spots corresponding to a dct grain in the taper data
+%for the moment indexing straight from taper seems sketchy
+
+function output = gtFindSimilarSpots(dct_grain, taper_name)
+
+parameters=[];
+load parameters
+output=[]
+
+taper_name=[taper_name 'spotpairs'];
+
+%angular resolution for searching (eta, omega)
+tol=2;
+
+
+for DCT_grainid=1:5
+
+%read from grain structure produced by sort grains  
+DCT_pairids=dct_grain{DCT_grainid}.pairid;
+DCT_theta=dct_grain{DCT_grainid}.theta;
+DCT_eta=dct_grain{DCT_grainid}.eta;
+DCT_omega=dct_grain{DCT_grainid}.omega;
+DCT_thetatype=dct_grain{DCT_grainid}.thetatype;
+
+%forward simulate for all diffraction data
+R_vector=dct_grain{DCT_grainid}.R_vector;
+[theta_fs, eta_fs, omega_fs, thetatype_fs]=sfForwardSimulate(R_vector); 
+
+%use / don't use foward simulated data
+if 1
+  theta=theta_fs;
+  thetatype=thetatype_fs;
+  eta=eta_fs;
+  omega=omega_fs;
+end
+
+save_possibles=[];
+
+for i=1:length(theta)
+
+%searching pairs based on angles...  size/intensity surely not proportional,
+%though could still be useful.
+%should one search spots, based on position, to get unpaired spots?
+%in taper data ~60% paired, so for the moment this should be okay.
+[pairID, eta_shift, omega_shift] = sfFindClosestSpot(theta(i), thetatype(i), eta(i), omega(i), tol);
+
+%collect results
+if isempty(pairID)
+  disp('nothing found here')
+  %output=[output; DCT_grainid, thetatype(i), NaN, NaN, NaN];
+else
+  output=[output; DCT_grainid, thetatype(i), pairID, eta_shift, omega_shift];
+end
+  
+%to display spots found / manual search
+if 1%%%%%%%%%%%
+
+  DCT_id=DCT_pairids(find(DCT_thetatype==thetatype(i) & DCT_eta>eta(i)-tol & DCT_eta<eta(i)+tol & DCT_omega>omega(i)-tol & DCT_omega<omega(i)+tol));
+  
+  if ~isempty(DCT_id)
+    %get difspot data (difspot difA) and load image
+    [DCT_maxim, DCT_x, DCT_y]=mym(sprintf(['select maximage, centroidx, centroidy from '...
+      'magnesium_dct_1_spotpairs inner join magnesium_dct_1_difspot on difAID=difspotID '...
+      'where pairID=%d'],DCT_id))
+    DCT_im=edf_read(sprintf('/data/id19/graintracking/november/magnesium_dct_1_/1_preprocessing/full/full%04d.edf',DCT_maxim));
+  subplot(1,2,1); imshow(DCT_im, [-30 30]); hold on
+  plot(DCT_x, DCT_y, 'rx')
+  else
+    %get images around predicted omega
+    im=round((omega(i)/180)*3600);
+    first=max(0, im-4);
+    last=min(7200, im+4); %should be unnecessary
+    DCT_im=zeros(2048);
+    for im=first:last
+      DCT_im=DCT_im+edf_read(sprintf('/data/id19/graintracking/november/magnesium_dct_1_/1_preprocessing/full/full%04d.edf',im));
+    end
+    DCT_im=DCT_im/(last-first+1);
+    subplot(1,2,1); imshow(DCT_im, [-30 30]); hold on
+    %plot a line to show where spot should be....
+    plot([1024 1024+500*sind(eta(i))],[1024 1024-500*cosd(eta(i))],'b')
+  end
+  
+  
+  if ~isempty(pairID)
+  %get taper difspot data (difspot difA) and load image
+    [tap_maxim, tap_x, tap_y]=mym(sprintf(['select maximage, centroidx, centroidy from '...
+      'magnesium_taper_0_spotpairs inner join magnesium_taper_0_difspot on difAID=difspotID '...
+      'where pairID=%d'],pairID))
+    tap_im=edf_read(sprintf('/data/id19/graintracking/november/magnesium_taper_0_/1_preprocessing/full/full%04d.edf',tap_maxim));
+  subplot(1,2,2); imshow(tap_im, [0 150]); hold on
+  plot(tap_x, tap_y, 'rx')
+  else
+    %get images around predicted omega
+    im=round((omega(i)/180)*3600);
+    first=max(0, im-4);
+    last=min(7200, im+4); %should be unnecessary
+    tap_im=zeros(2048);
+    for im=first:last
+      tap_im=tap_im+edf_read(sprintf('/data/id19/graintracking/november/magnesium_taper_0_/1_preprocessing/full/full%04d.edf',im));
+    end
+    tap_im=tap_im/(last-first+1);
+    subplot(1,2,2); imshow(tap_im, [0 150]); hold on
+    %plot a line to show where spot should be....
+    plot([1024 1024+500*sind(eta(i))],[1024 1024-500*cosd(eta(i))],'b')
+  end
+  
+  
+keyboard
+end %%%%%%%%%%%
+
+
+end
+
+
+end
+
+
+%SubFunction for foward simulate, just return a list of angles
+function [th, et, om, th_type] = sfForwardSimulate(R_vector)
+
+  [a,b]=gtnew_calculate_twotheta;
+  
+  if parameters.acq.spacegroup==194 | parameters.acq.spacegroup==663
+  %hexagonal cases
+  hkil = b.reflections;        
+  all_hkils=[];
+  all_hkls=[];
+  hkl_type=[];
+  for i = 1%:size(hkil,1)
+    disp('do first family only')
+    hkil_varients = gtGetReflections_sab(hkil(i,:));
+    all_hkils = [all_hkils ; hkil_varients];
+    %save also the theta type
+    hkl_type=[hkl_type; repmat(i, size(hkil_varients, 1), 1)];
+  end
+    % normalise hkls vector
+    % going to cartesian reciprocal space + normalisation of the cartesian
+    % space
+    for i=1:size(all_hkils)
+     all_hkls(i,1)= all_hkils(i,1) + 0.5 * all_hkils(i,2);
+     all_hkls(i,2)= 3^0.5/2 *all_hkils(i,2);
+     all_hkls(i,3)= all_hkils(i,4);
+     
+     all_hkls(i,1)=all_hkls(i,1)*2/(sqrt(3)*parameters.acq.latticepar(1));
+     all_hkls(i,2)=all_hkls(i,2)*2/(sqrt(3)*parameters.acq.latticepar(1));
+     all_hkls(i,3)=all_hkls(i,3)/parameters.acq.latticepar(3);
+    end
+     tmp = sqrt(sum((all_hkls.*all_hkls),2));
+     normalised_hkls = all_hkls./(repmat(tmp,1,3));
+    % unification des notations pour la suite
+    all_hkls = [];
+    all_hkls = all_hkils;
+  elseif parameters.acq.spacegroup==225 | parameters.acq.spacegroup==229
+    disp('fill this in!')
+  else
+    disp('space group not supported')
+  end
+    
+  %transform according to grain orientation
+  g = Rod2g(R_vector);
+  warning('using g, rather than inv(g), in eq. 3.6 in Poulsen - Rod2g or coords problem?')
+  all_normals = (g * normalised_hkls')';
+  
+  %predict the diffraction angles
+  th=[];th_type=[];et=[];om=[];
+
+for i=1:length(all_hkls)
+  try
+    [tmp1, tmp2, tmp3] = gtPredictAngles(all_normals(i,:), all_hkls(i,:), parameters);
+    %record angles
+    th=[th; tmp1'];et=[et; tmp2'];om=[om; tmp3'];
+    %record theta type
+    th_type=[th_type; repmat(hkl_type(i), length(tmp1), 1)];
+  end
+end
+
+%remove thoses outside of 0-180 degrees (not needed to search for pairs)
+dum=find(om>180);
+th(dum)=[];et(dum)=[];om(dum)=[];th_type(dum)=[];
+
+end
+
+
+  function [id, et_shift, om_shift] = sfFindClosestSpot(th, th_type, et, om, tol)
+    
+    id=[]; et_shift=[]; om_shift=[];
+    [th et om]
+    cmd=sprintf(['select pairid, eta, omega, plX, plY, plZ from %s where (omega between %f and %f) and '...
+      '(thetatype=%d) and (eta between %f and %f)'],...
+      taper_name, om-tol, om+tol, thetatype(i), et-tol, et+tol);
+    
+    [possibles, et_pos, om_pos, pl1, pl2, pl3]=mym(cmd);
+    tap_pl=[pl1 pl2 pl3];
+    
+    if isempty(possibles)
+      disp('no corresponding pair found')
+     return
+    else
+      disp('found something')
+      if length(possibles)==1
+        id=possibles;
+        et_shift=et_pos-et;
+        om_shift=om_pos-om;
+      else %try using criteria of closest plane normal vector to chose
+        DCT_pl(1) = -sind(th)*cosd(om) - cosd(th)*sind(et)*sind(om);
+        DCT_pl(2) = cosd(th)*sind(et)*cosd(om) - sind(th)*sind(om);
+        DCT_pl(3) = cosd(th)*cosd(et);
+        
+        dev=real(acosd(dot(repmat(DCT_pl, length(possibles), 1), tap_pl, 2)));
+        [dum, dum]=min(dev);%index of the closest vector
+        id=possibles(dum);
+        et_shift=et_pos(dum)-et;
+        om_shift=om_pos(dum)-om;
+      end
+    end
+  end
+
+
+
+end %end of main function
+
+
diff --git a/5_reconstruction/gtFindTwinGrains.m b/5_reconstruction/gtFindTwinGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..d42a7539361d18aeba00a82bd7ca8ad9c1b4d995
--- /dev/null
+++ b/5_reconstruction/gtFindTwinGrains.m
@@ -0,0 +1,347 @@
+%Automatically indentify twins and combines when assembling volume
+%as for gtnew_assemble_volX, but if two grains overlap, calc
+%misorientation angle/axis.
+
+% 4/3/2008 simplify to work with ART bboxes, and un-postprocessed sdt
+% volumes
+
+function [twin_list, combine_list]=gtFindTwinGrains
+
+num_grains=1038;
+parameters=[];
+load parameters;
+sym = gtGetCubicSymOp;
+    
+twin_list=[];
+combine_list=[];
+touching_matrix=zeros(num_grains);
+bboxlist=zeros(num_grains, 6);
+rvectors=zeros(num_grains, 3);
+
+%sigma s: type, angle, axis {, brandon criteria}
+    warning('sigma axis indices must be positive, normalised, and in descending order...')
+    pause(1)
+sigmas=[3 60 1 1 1;...
+  5 36.86 1 0 0;...
+  7 38.21 1 1 1;
+  9 38.94 1 1 0];
+%add brandon criteria
+sigmas(:,6)=15*sigmas(:,1).^(-0.5);
+%normalise axis
+sigmas(:,3:5)=sigmas(:,3:5)./repmat(sqrt(sum(sigmas(:,3:5).*sigmas(:,3:5),2)),1,3);
+
+
+
+if ~exist('r_vectors.mat')
+
+
+%work from bounding boxes initially
+%%%%%%%%%%%  Read data from .mat files   %%%%%%%%%%%%%%%%%%%
+for i=1:num_grains %for all grains
+  
+  disp(sprintf('loading data %d percent', round(100*i/num_grains)))
+  
+  tmp=load(sprintf('4_grains/grain%d_/grain%d_.mat', i,i), 'R_vector', 'bad', 'x1','y1','nx','ny','zend','zstart');
+  if isfield(tmp,'bad') && tmp.bad~=0
+    continue
+  end
+  %work with the ART resconstruction boundingbox
+  bboxlist(i,:)=[tmp.x1 tmp.y1 tmp.zstart tmp.nx tmp.ny tmp.zend-tmp.zstart];
+  rvectors(i,:)=tmp.R_vector;
+r_vectors(i,:)=[i tmp.R_vector];
+end
+
+save r_vectors r_vectors
+
+else
+  load r_vectors
+end
+
+
+if ~exist('touching_matrix.mat')
+
+
+
+%%%%%%%%%%%%%%   Determine which grains touch %%%%%%%%%%%%%%%%%%%
+for i=1:num_grains
+  
+  disp(sprintf('progress %d percent', round(100*i/num_grains)))
+  
+  mygrain=bboxlist(i,:);
+%  myvol=sfGetPartialGrain(i, bboxlist, bboxlist(i,:));
+  
+  %find overlapping bboxes
+  xtest=find(bboxlist(:,1)<(mygrain(1)+mygrain(4)) & (bboxlist(:,1)+bboxlist(:,4))>mygrain(1));
+  ytest=find(bboxlist(:,2)<(mygrain(2)+mygrain(5)) & (bboxlist(:,2)+bboxlist(:,5))>mygrain(2));
+  ztest=find(bboxlist(:,3)<(mygrain(3)+mygrain(6)) & (bboxlist(:,3)+bboxlist(:,6))>mygrain(3));
+  
+  candidates=intersect(xtest, intersect(ytest, ztest)); %ugly...
+  candidates(find(candidates==i))=[];
+  
+  for j=1:length(candidates)
+    
+    if i>candidates(j)
+      continue
+    end 
+   
+    %try without this test - use something simpler
+  %testvol=sfGetPartialGrain(candidates(j), bboxlist, bboxlist(i,:));
+  %test=length(find(testvol & myvol));
+  %if test>0
+  
+  testgrain=bboxlist(candidates(j),:);
+  %new test - if more than 50% bbox volume shared,say they are touching
+  %more the 50% in any dimension
+  xstart=max(mygrain(1), testgrain(1));
+  xend=min(mygrain(1)+mygrain(4), testgrain(1)+testgrain(4));
+  xoverlap=xend-xstart;
+  xlength=min(mygrain(4), testgrain(4));
+  xtest=xoverlap/xlength; 
+  
+  ystart=max(mygrain(2), testgrain(2));
+  yend=min(mygrain(2)+mygrain(5), testgrain(2)+testgrain(5));
+  yoverlap=yend-ystart;
+  ylength=min(mygrain(5), testgrain(5));
+  ytest=yoverlap/ylength; 
+  
+  zstart=max(mygrain(3), testgrain(3));
+  zend=min(mygrain(3)+mygrain(6), testgrain(3)+testgrain(6));
+  zoverlap=zend-zstart;
+  zlength=min(mygrain(6), testgrain(6));
+  ztest=zoverlap/zlength; 
+  
+  if (xtest>0.5 | ytest>0.5 | ztest>0.5)
+      touching_matrix(i, candidates(j))=1;
+    end
+  end
+
+end
+
+save touching_matrix touching_matrix
+
+else
+  
+ load touching_matrix
+ 
+end
+
+
+
+%now need to check out the touching grains.  Touching grains can be
+%twins, grains that should be combined, or neither of these.
+for i=1:num_grains
+  
+  if mod(i, 100)==0
+   disp(sprintf('checking twins/combines: progress %d percent', round(100*i/num_grains)))
+  end
+   
+   for j=1:num_grains
+    
+    if touching_matrix(i,j)==1
+      
+      sigma = sfTwinTest(rvectors(i,:), rvectors(j,:)); %are these a twin?
+    
+      if ~isempty(sigma)
+        if length(sigma==1)
+          %disp('found a twin')
+          twin_list(end+1, :)=[i, j, sigma];
+        else
+          disp('oops, two possible sigmas')
+          keyboard
+        end
+      end
+
+      if 0 % skip combine test for the moment - slow
+      read_out = sfCombineTest(i,j); %should grains be combined?
+      
+      if ~isempty(read_out)
+        combine_list(end+1,:)=[i j read_out];
+      end
+      end
+      
+    end
+  end
+end
+
+keyboard
+
+if ~isempty(twin_list)
+twin_list=sfSortList(twin_list(:,1:2));
+end
+if ~isempty(combine_list)
+combine_list=sfSortList(combine_list(:,1:2));
+end
+
+
+
+
+
+%%%%%%%%%%    SubFunctions    %%%%%%%%%%
+
+  function sigma=sfTwinTest(R1, R2)
+    
+    g1=Rod2g(R1);
+    g2=Rod2g(R2);
+        
+    %need to search symmetry equivelents for the minimum misorientation
+    rot_offset=[];
+    
+    for k=1:24
+      g1equiv = g1*sym(k).g;
+      netg = inv(g1equiv)*g2;
+      rot_offset(k) = acos((trace(netg)-1)/2);  
+    end
+
+    dummy = find(rot_offset ==min(rot_offset));
+    g1equiv = g1*sym(dummy).g;
+    netg = inv(g1equiv)*g2;
+      
+    mis_angle = (180/pi)*acos((trace(netg)-1)/2);
+    
+    [eigVec, eigVal]=eig(netg);
+    
+    %eigVal=real(eigVal);
+    %dummy=find((abs(eigVal-1))<0.00001);
+    %[r,c]=ind2sub(size(eigVal), dummy);
+    for p=1:3  
+      if isreal(eigVec(:,p))  %find the real eigenvector
+        mis_axis=eigVec(:,p);
+      end
+    end
+      
+    %mis_axis=eigVec(:,c);
+    
+    
+    if ~isempty(mis_axis) 
+      
+
+    mis_axis=sort(abs(mis_axis), 'descend');
+
+    %determine sigma type - intially check just sigma three
+    test_angle=abs(mis_angle-sigmas(:,2))<sigmas(:,6);
+    test_axis=(180/pi)*abs(acos(dot(repmat(mis_axis',size(sigmas,1),1), sigmas(:,3:5), 2)))<sigmas(:,6);
+    sigma=sigmas(find(test_angle & test_axis), 1);
+    
+    end
+    
+  end
+
+
+
+  function read_out = sfCombineTest(grain1, grain2)
+    
+    %call plot_rodrigues_consistancy_grain for the two grains.  If more
+    %than 90% of the used projections are consistant, consider this a
+    %possible combine.
+    read_out=plot_rodrigues_consistancy_grain([grain1 grain2], 0);
+    if ~all(read_out>0.9)
+      read_out=[];
+    end
+   
+  end
+
+
+
+
+
+function temp_output = sfGetPartialGrain(grainid, bboxlist, outputbbox);
+%i is the grainid
+%supply a bounding box, function returns just the part of the grain which
+%extends into this bounding box.
+
+temp_output = zeros(outputbbox(5), outputbbox(4), outputbbox(6));
+
+%vol_filename = sprintf('4_grains/grain%d_/grain%d_2.edf',grainid, grainid);
+%vol = edf_read(vol_filename);
+vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',grainid,grainid));
+                
+
+%limits withhin outputbbox volume
+min3 = bboxlist(grainid,3) - outputbbox(3)+1;
+max3 = min3 + bboxlist(grainid,6)-1;
+min1 = bboxlist(grainid,2) - outputbbox(2)+1;
+max1 = min1 + bboxlist(grainid,5)-1;
+min2 = bboxlist(grainid,1) - outputbbox(1)+1;
+max2 = min2 + bboxlist(grainid,4)-1;
+
+%have to deal with bounding boxs that exceed the slice size
+if min1<1
+  tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+  min1=1;
+  vol=vol(tmp:end,:,:);
+end
+if min2<1
+  tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+  min2=1;
+  vol=vol(:,tmp:end,:);
+end
+if min3<1
+  tmp=2-min3;%if z1==0, crop one row of voxels from vol
+  min3=1;
+  vol=vol(:,:,tmp:end);
+end
+if max1>outputbbox(5);
+  tmp=max1-outputbbox(5);%if x2 is one too big, crop one row of voxels
+  max1=outputbbox(5);
+  vol=vol(1:end-tmp,:,:);
+end
+if max2>outputbbox(4);
+  tmp=max2-outputbbox(4);%if y2 is one too big, crop one row of voxels
+  max2=outputbbox(4);
+  vol=vol(:,1:end-tmp,:);
+end
+if max3>outputbbox(6);
+  tmp=max3-outputbbox(6);%if z2 is one too big, crop one row of voxels
+  max3=outputbbox(6);
+  vol=vol(:,:,1:end-tmp);
+end
+
+%grain volume into output volume
+temp_output(min1:max1, min2:max2, min3:max3)=temp_output(min1:max1, min2:max2, min3:max3)+vol;
+
+end
+%end of sfGetPartialGrain
+  
+  
+% sort out twin list
+% twin_list - pairs of twins
+% want to sort this into groups - set of twins
+  function outlist = sfSortList(twins)
+    outlist=[]
+    for i=1:length(twins)
+
+      new_group=twins(i,:);
+
+      if any(any(new_group(1)==outlist)) || any(any(new_group(2)==outlist))
+        continue
+      end
+
+      new_length=length(new_group)
+      old_length=0;
+      group=new_group;
+      addtwins=[];
+
+      while new_length>old_length
+        old_length=new_length;
+
+        for k=1:length(group)
+          [r,c]=ind2sub(size(twins), find(twins==group(k)));
+          addtwins=twins(r, :);
+          addtwins=addtwins(:)';
+          group=[group addtwins];
+        end
+
+        group=unique(group);
+        new_length=length(group);
+      end
+
+      outlist(end+1,1:length(group))=group;
+    end
+
+  end
+
+  
+end %of main function
+
+  
+  
diff --git a/5_reconstruction/gtGT2ARTangles.m b/5_reconstruction/gtGT2ARTangles.m
new file mode 100755
index 0000000000000000000000000000000000000000..4783e32c1bfd51b64371c45ffe31353d7210fc7c
--- /dev/null
+++ b/5_reconstruction/gtGT2ARTangles.m
@@ -0,0 +1,6 @@
+function [alphap,alphaq]=gtGT2ARTangles(twotheta,eta)
+% gtGT2ART Converts from twotheta and eta coordinate system to orthogonal
+% detector angles alphap and alphaq for use in REC_ALG ART system
+
+alphap=-(sin(deg2rad(-eta+360)).*twotheta);
+alphaq=-(cos(deg2rad(-eta+360)).*twotheta);
diff --git a/5_reconstruction/gtMakeARTJob.m b/5_reconstruction/gtMakeARTJob.m
new file mode 100755
index 0000000000000000000000000000000000000000..93fc32c4bd889b32ea1fb19116c7f99ed7adc3c2
--- /dev/null
+++ b/5_reconstruction/gtMakeARTJob.m
@@ -0,0 +1,196 @@
+function gtMakeARTJob(scanname,parfilename,p_numbers,p_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% write .par file ready for rec_alg to use
+%
+%
+% function make_art_parfile(scanname,parfilename,p_numbers,p_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% 
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% p_numbers: vector containing the projections to be taken into account, e.g. [0:10:180]
+% p_angles : vector containing the correpsonding projection angles in degree e.g. [0:20:360]
+% lambda   : ART loop update parameter
+% nbiter   : number of ART iterations
+% pixsize  : pixelsize [mm]
+% braggangle: Bragg angle
+% np        : number of pixels in projections (hoizontal)
+% nq        : number of pixel in projections (vertical)
+% offset    : offset of the rotation axis with respect to the center of the image (in pixels) 
+% z1        : z start of reconstructed volume
+% nz        : number of reconstructed slices 
+% x1        : x start of reconstructed volume //andy 21/6/06
+% nx        : size of reconstructed volume in x
+% y1        : y start of reconstructed volume
+% ny        : size of reconstructed volume in y(attention: pixelsize in reconstructed image will be half
+% the pixel size in original projection images
+
+
+%gtnew - change to use parameters.acq
+%gtnew - change to use z coordinates of grain relative to top of sample
+
+
+
+%global parameters
+%if isempty(parameters)
+%  load parameters.mat
+%end
+
+fid=fopen(parfilename,'w');
+nbradio=length(p_numbers);
+
+% Algorithm paramters
+nbiter = nbiter;
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;
+block_size = 1;
+proj_mng = 'A';
+nb_resol = 1;
+disp('MODIFIED BY GJ HERE')
+thresh_supp = 0;
+
+%thresh_supp = 100;
+
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+%geometry paramters
+fgd = 145000;         % Distance source detector [mm]
+qgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+pgd = -tan(braggangle/180*pi)*fgd/pixsize;   % vertical Distance (source projection)-(detector center) [pixels]
+pepd= pixsize;        % horizontal Pixel size, [mm]
+peqd= pixsize;        % vertical Pixel size [mm]
+p1d = -(np/2-0.5)+offset;  % left detector corner [pixels]
+q1d = -(nq/2-0.5);    % upper detector corner [pixels]     
+np=np;                % horizontal detector size [pixels]  
+nq=nq;                % vertical detector size [pixels]
+psi = p_angles;       % first Euler angle (==omega)  [degrees]
+xsi = 90.0;           % second Euler angle
+delta = 0.0;          % third Euler angle
+q0 = 0.0;             % horizontal  distance source - object center [mm]
+p0= tan(braggangle/180*pi)*fgd;  % vertical distance source - object center [mm]
+m0 = -fgd;             % distance source - object center [mm] (<0)
+ipd = 0;              % ROI begin horizontal [pixels] 
+iqd = 0;              % ROI begin vertical [pixels]
+ipf = np-1;           % ROI end horizontal [pixels]
+iqf = nq-1;           % ROI end vertical [pixels]  
+
+%Reconstruction paramters
+pex = pixsize;            % sampling step size [mm]
+pey = pixsize;            % sampling step size [mm]
+pez = pixsize;            % sampling step size [mm] 
+%x1 = -np/2*pixsize;               % start of reconstructed zone [mm]
+%y1 = -np/2*pixsize;;               % start of reconstructed zone [mm]
+x1 = (x1-(np/2))*pixsize; % start of reconstructed zone [mm]
+y1 = (y1-(np/2))*pixsize; % start of reconstructed zone [mm]
+z1 = (z1-(nq/2))*pixsize; % start of reconstructed zone [mm] 
+%nx = np;               % X Size of reconstruction [pixels]
+%ny = np;               % Y Size of reconstruction [pixels]
+nx = nx;               % X Size of reconstruction [pixels]
+ny = ny;               % Y Size of reconstruction [pixels]
+nz = nz;               % Number of layers
+
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+for i=1:nbradio
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,p_numbers(i));
+end
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d);
+fprintf(fid,'Q1D = %f\n',q1d);
+fprintf(fid,'NP =  %d\n',np);
+fprintf(fid,'NQ =  %d\n',nq);
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi);
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0);	
+fprintf(fid,'QO = %f\n',q0);
+fprintf(fid,'MO = %f\n',m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf);
+fprintf(fid,'IQF = %d\n',iqf);
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
diff --git a/5_reconstruction/gtMakeARTJob3D.m b/5_reconstruction/gtMakeARTJob3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..3a90634bc9142b8b5f8207aef99403fe8c2bf10f
--- /dev/null
+++ b/5_reconstruction/gtMakeARTJob3D.m
@@ -0,0 +1,272 @@
+function vol=gtMakeARTJob3D(scanname,parfilename,dif_numbers,ext_numbers,grain,parameters,lambda,x1,nx,y1,ny,z1,nz,do_reconstruction)
+% write .par file ready for rec_alg to use
+%
+%
+% function
+% make_art_parfile(scanname,parfilename,dif_numbers,shear_numbers,ext_numbe
+% rs, grain, lambda,parameters,slice)
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% dif_numbers: indices of diffraction spots to be taken into account, e.g. [1:14]
+% shear_numbers: indices of sheared diffraction spots to be taken into account 
+% ext_numbers:   : indices of extinction spots to be taken into account
+% grain:
+% lambda: 
+% parameters:
+% 
+
+
+%load parameters.mat
+
+
+
+blocksize= length(dif_numbers)+length(ext_numbers);
+
+
+offset=0;
+
+fid=fopen(parfilename,'w');
+nbradio=length(dif_numbers)+length(ext_numbers);
+
+% Algorithm paramters
+nbiter = length(lambda);
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 0;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 10000000;      % Distance source to detector ~ 10^7 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd= 1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = fgd-parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (positive here: -m0 will be given to AREMIS 
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+% nx=parameters.acq.bb(3);
+% ny=parameters.acq.bb(3);
+% 
+% x1=-parameters.acq.bb(3)/2;
+% y1=-parameters.acq.bb(3)/2;
+
+% if ~exist('slice','var')
+%   nz=grain.zend-grain.zstart+1;
+%   z1= parameters.acq.bb(4)/2-grain.zend;
+% elseif length(slice)>1
+%   z1= parameters.acq.bb(4)/2-slice(2)-0.5;
+%   nz=slice(2)-slice(1)+1;
+% else
+%   z1= parameters.acq.bb(4)/2-slice(1)-1.5;
+%   nz=3;
+% end  
+
+
+
+
+% write diffraction spot section (3D-ART) 
+
+for i=1:length(dif_numbers)
+
+  Omega =   grain.Omega(dif_numbers(i));
+  Theta =   grain.Theta(dif_numbers(i));
+  Eta   =   -grain.Eta(dif_numbers(i));    
+  psi(i)=   Omega;               % first Euler angle (==omega)  [degrees]
+  xsi(i)=   90.0;                % second Euler angle
+  delta =   0.0;                 % third Euler angle
+
+  
+  query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.struct_ids(dif_numbers(i)));
+  [bb(1),bb(2),bb(3),bb(4)]=mym(query);
+  % now take into account the flip of the images...
+  bb(1)=2*parameters.acq.rotx-bb(1)-bb(3)+1;
+  bb=bb+[-100 -100 200 200];
+   
+  %bb=parameters.bb(dif_numbers(i),1:4) +[-100 -100 200 200];
+  
+  p1d(i) =      m0*tand(2*Theta)*sind(Eta)+bb(1)-parameters.acq.rotx;      % orig left  detector corner [pixels]
+  
+  q1d(i) =      m0*tand(2*Theta)*cosd(Eta)+parameters.acq.ydet/2-bb(2);    % orig upper detector corner [pixels]     
+ 
+  np(i)=bb(3);                % horizontal detector size [pixels]  
+  nq(i)=bb(4);                % vertical detector size [pixels]
+
+  p0(i) =    m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+  q0(i) =    m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+  iqf(i) = nq(i)-1;      % ROI end vertical
+
+end
+
+% now write extinction spots...
+
+off2=length(dif_numbers);
+
+for i=1:length(ext_numbers)
+ 
+  Omega =   grain.omega(ext_numbers(i))+90  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off2) = Omega;           % first Euler angle (==omega)  [degrees]
+  xsi(i+off2) = 90.0;            % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off2) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off2) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off2)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off2)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off2) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off2) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off2) = np(i+off2)-1;      % ROI end horizontal [pixels]
+  iqf(i+off2) = nq(i+off2)-1;      % ROI end vertical
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+
+for i=1:length(dif_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,i);
+end
+% for i=1:length(shear_numbers)
+%   fprintf(fid,'EXT_PROJ%d = %d\n',i+off-1,i+off);
+% end
+for i=1:length(ext_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off2-1,i+off2);
+end  
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi(i));
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',-m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view'
+if do_reconstruction
+  % now do the reconstructioon
+  command=sprintf('%s %s;%s %s_res0_%d',rec_alg,parfilename,seg2view,scanname,nbiter);
+  unix(command);
+  volname=sprintf('%s_res0_%d',scanname,nbiter);
+  vol=sdt_read(volname);
+  imshow(vol(:,:,round(nz/2)),[])
+  shg;
+else
+  vol=[];
+end  
diff --git a/5_reconstruction/gtMakeCondorJob.m b/5_reconstruction/gtMakeCondorJob.m
new file mode 100755
index 0000000000000000000000000000000000000000..6be2483b10d620cb676e2988e7e15e295f2e0f56
--- /dev/null
+++ b/5_reconstruction/gtMakeCondorJob.m
@@ -0,0 +1,17 @@
+function gtMakeCondorJob(grainid)
+% now misnamed, but runs on a single other machine anyhow
+  %load data
+  load parameters.mat;
+
+
+  graindir=sprintf('%s/4_grains/grain%d_',parameters.acq.dir,grainid);
+
+  rec_cmd='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+  rec_parameters=sprintf('grain%d_whole.par',grainid);
+  
+  % modified to open up group permissions even if the user doesn't usually
+  % do so
+  cmd=sprintf('ssh coral "umask g+w;cd %s;%s %s" &',graindir,rec_cmd,rec_parameters)
+  unix(cmd);
+
+
diff --git a/5_reconstruction/gtMakeHSTParfile.m b/5_reconstruction/gtMakeHSTParfile.m
new file mode 100755
index 0000000000000000000000000000000000000000..bc4204ec26f8ff127baafb3d5c3e4ba92633bcc4
--- /dev/null
+++ b/5_reconstruction/gtMakeHSTParfile.m
@@ -0,0 +1,95 @@
+function par=gtMakeHSTParfile(parameters)
+  
+acq=parameters.acq;
+
+%% default values
+par.parfilename=sprintf('%s/%s_test.par',acq.dir,acq.name);
+
+par.num_first_image=0;
+par.number_length_varies='NO';
+par.length_of_numerical_part=num2str(4);
+par.file_postfix='.edf';
+par.file_interval=1;
+
+par.correct=0;
+par.correct_flatfield='NO';
+par.subtract_background='NO';
+
+par.take_logarithm='YES';
+par.rotation_vertical='YES';
+par.output_sino='NO';
+par.output_rec='YES';
+par.oversampling_factor=num2str(4);
+par.angle_offset=num2str(0);
+par.cache_kilobytes=num2str(256);
+par.sino_megabytes=num2str(400);
+par.correct_spikes='YES';
+par.ccd_filter='"CCD_FILTER"';
+par.correct_spikes_threshold=num2str(0.04);
+par.correct_rings='NO';   % all the stuff needed here ?
+par.correct_rings_nb=0;
+par.correct_axis='NO';
+par.correct_axis_file='';
+par.padding='E';
+par.axis_to_the_center='N';
+par.graph_out='NO';
+
+% modif sabine
+% if strcmp(acq.scantype,'360degree')
+%     scanrange=360;
+% else
+%     scanrange=180;
+% end
+if isfield(acq,'scantype')
+    if strcmp(acq.scantype,'360degree') || strcmp(acq.type,'360')
+        scanrange=360;
+    else
+        scanrange=180;
+    end
+elseif isfield(acq,'type')
+        if strcmp(acq.type,'360degree') || strcmp(acq.type,'360')
+            scanrange=360;
+        else
+            scanrange=180;
+        end
+else
+    disp('can not read scan range');
+    return;
+end
+
+% modif sabine
+
+%% scan specific values
+par.prefix=sprintf('%s/1_preprocessing/abs/abs',acq.dir);
+par.num_image_1=num2str(acq.bb(3));
+par.num_image_2=num2str(acq.bb(4));
+par.first=num2str(0);
+% modif sabine
+% par.last=num2str(acq.nproj-1);
+% par.angle_between_projections=num2str(scanrange/acq.nproj);
+if ~isfield(acq,'interlaced_turns') || acq.interlaced_turns==0
+    par.last=num2str(acq.nproj-1);
+	
+    par.angle_between_projections=num2str(scanrange/2/acq.nproj);   %quick fix (2*acq.nproj) wolfgang 04/2008
+else if acq.interlaced_turns==1
+        par.last=num2str((acq.interlaced_turns+1)*acq.nproj-1); 
+        par.angle_between_projections=num2str(scanrange/((acq.interlaced_turns+1)*acq.nproj))
+    else
+        disp('to be adjsuted')
+        return
+    end
+end
+% fin modif sabine
+par.image_pixel_size_1=num2str(acq.pixelsize);
+par.image_pixel_size_2=num2str(acq.pixelsize);
+
+par.rotation_axis_position=num2str(acq.bb(3)/2+0.5);
+par.start_voxel_1=num2str(1);
+par.start_voxel_2=num2str(1);
+par.start_voxel_3=num2str(1);
+par.end_voxel_1=num2str(acq.bb(3));
+par.end_voxel_2=num2str(acq.bb(3));
+par.end_voxel_3=num2str(acq.bb(4));
+par.output_file=sprintf('%s/%s.vol',acq.dir,acq.name);
+
+par_write(par);
\ No newline at end of file
diff --git a/5_reconstruction/gtMakePoleFigure.m b/5_reconstruction/gtMakePoleFigure.m
new file mode 100755
index 0000000000000000000000000000000000000000..edf7e57ee54e114563e14a6f4f571f300e6eaf54
--- /dev/null
+++ b/5_reconstruction/gtMakePoleFigure.m
@@ -0,0 +1,339 @@
+function [save_density, valid_poles_weight]=gtMakePoleFigure(varargin)
+%
+% gtMakePoleFigure(poles, {varargin})
+%
+% make a pole figure given a list of poles.
+% the poles should cover a larger angular area than required, to avoio
+% depleted pole density at the edges.  Any un-needed poles will be crops to
+% improve speed.
+%
+%
+%can pass in either poles or a density matrix.  If the density matrix, YOU
+%have to make sure the other variables are consistant with it's size.
+% if passing in desnity also need to pass valid_poles_weight for
+% normalising
+%
+% poles=[x y z, x2 y2 z2; ...]
+% 
+% varargin: parse parameter pairs format.
+% can use:
+% 'range' - 'sst', 'phi90', 'phi360' - standard stereographic triangle, or
+% quarter or whole hemisphere.
+%
+% 'label_poles' - 'all', 'main', 'none' - all hkl poles or just the corners of the sst.
+%
+% 'mark_poles' - 'all', 'main', 'none' 
+%
+% 'weights' - can supply a vector the same length as poles to weight the
+% pole data.
+%
+% 'searchR' - smoothing radius in pole figure - default is 0.05 radians
+%
+% 'increment' - data point density in pole figure - default is 0.02 radians
+%
+% 'plot_figure' - can choose not to plot figure, and use the returned
+% density values (non normalised) for something
+%
+% could be improved to pass in a list of which hkl poles to plot and to
+% label.
+% AK - mod 9/2008
+
+%read in the specs
+appdefaults.poles=[];
+appdefaults.density=[];
+appdefaults.valid_poles_weight=[];
+appdefaults.weights=[];
+appdefaults.range='sst';
+appdefaults.label_poles='all';
+appdefaults.mark_poles='all';
+appdefaults.increment=0.01;
+appdefaults.searchR=0.03;
+appdefaults.new_figure=true;
+appdefaults.plot_figure=1;
+
+app=parse_pv_pairs(appdefaults,varargin);
+
+poles=app.poles;
+density=app.density;
+searchR=app.searchR;
+inc=app.increment;
+weights=app.weights;
+valid_poles_weight=app.valid_poles_weight;
+
+if ~isempty(poles)
+    
+    %if no weighting data passed in
+    if isempty(weights)
+        weights=ones(size(poles, 1),1);
+    end
+
+%before building figure, take only those poles that fall in the range 0-phimax,
+%0-psimax (allowing for seach radius)
+if strcmp(app.range, 'sst')
+    %for standard stereographic triangle
+    phimax=pi/4;
+    psimax=atan(sqrt(2));
+    dum=find(poles(:,2)>-sin(searchR) & poles(:,2)<poles(:,1)+(sqrt(2)*sin(searchR)) & poles(:,3)>poles(:,1)-(sqrt(2)*sin(searchR)));
+    poles=poles(dum, :);
+    weights=weights(dum);
+    valid_poles_weight=sum(weights(find(poles(:,2)>=0 & poles(:,2)<=poles(:,1) & poles(:,3)>=poles(:,1))));
+    total_solid_angle=pi/12;
+elseif strcmp(app.range, 'phi90')
+    %for a 90 degree section of the pole figure
+    phimax=pi/2;
+    psimax=pi/2;
+    dum=find(poles(:,1)>-sin(searchR) & poles(:,2)>-sin(searchR) & poles(:,3)>cos(psimax)-sin(searchR));
+    poles=poles(dum, :);
+    weights=weights(dum);
+    valid_poles_weight=sum(weights(find(poles(:,1)>=0 & poles(:,2)>=0 & poles(:,3)>=0)));
+    total_solid_angle=pi/2;
+elseif strcmp(app.range, 'phi360')
+    %for 360 pole figure - reduce only using psi
+    phimax=2*pi;
+    psimax=pi/2;
+    poles=poles(find(poles(:,3)>cos(psimax)-sin(searchR)),:);
+    valid_poles_weight=sum(weights(find(poles(:,3)>=0)));
+    total_solid_angle=2*pi;
+else
+    disp('unrecognised plot range :-(')
+    return
+end
+
+
+%analyse the pole data
+i=1;j=1;
+for phi=[0:inc:phimax phimax] %around z-axis
+    j=1;
+    for psi=[0:inc:psimax psimax] % out from z-axis
+
+        z=cos(psi);
+        x=sin(psi)*cos(phi);
+        y=sin(psi)*sin(phi);
+        test_normal=[x y z];
+
+        angle_dev = acos((dot(poles, repmat(test_normal, size(poles,1), 1), 2)));
+        density(i,j)=sum(weights(find(angle_dev<searchR)));
+        j=j+1;
+    end
+    if mod(i, round(length([0:inc:phimax phimax])/10))==0
+        disp(sprintf('%d percent done', round(100*i/length([0:inc:phimax phimax]))))
+    end
+    i=i+1;
+end
+
+%before normalising, save raw density values
+save_density=density;
+%normalise density into something meaningful
+%total solid angle covered 4pi for a whole sphere
+%we have reduced the search area
+search_solid_angle=pi*(searchR^2);
+%random density is
+random_density=valid_poles_weight*(search_solid_angle/total_solid_angle);
+density=density./random_density;
+
+else
+    %we need the range of phi and phi
+    if strcmp(app.range, 'sst')
+        %for standard stereographic triangle
+        phimax=pi/4;
+        psimax=atan(sqrt(2));
+        total_solid_angle=pi/12;
+    elseif strcmp(app.range, 'phi90')
+        %for a 90 degree section of the pole figure
+        phimax=pi/2;
+        psimax=pi/2;
+        total_solid_angle=pi/2;
+    elseif strcmp(app.range, 'phi360')
+        phimax=2*pi;
+        psimax=pi/2;
+        total_solid_angle=2*pi;
+    else
+        disp('unrecognised plot range :-(')
+        return
+    end
+    %normalise density passed in using valid poles_weight
+    search_solid_angle=pi*(searchR^2);
+    random_density=valid_poles_weight*(search_solid_angle/total_solid_angle);
+    density=density/random_density;
+end
+
+
+
+
+
+if app.plot_figure
+
+% build the figure
+% have: density as a function of phi and psi.  
+% Can convert to x,y,z, and use surf.
+% modify for steorographic projection
+phi=[0:inc:phimax phimax]; %around z-axis
+psi=[0:inc:psimax psimax]; %away from z axis
+%radius distorted for stereographic proj
+r=tan(psi/2);
+[phi,r]=meshgrid(phi,r);
+[x,y]=pol2cart(phi,r);
+
+if app.new_figure
+figure
+end
+
+surf(x,y,density')
+hold on
+shading('interp')
+axis equal
+
+if ~strcmp(app.mark_poles, 'none') %draw poles
+
+    if strcmp(app.mark_poles, 'main')
+        uvw_poles=[0 0 1; 1 0 1; 1 1 1];
+    elseif strcmp(app.mark_poles, 'all')
+        uvw_poles=[0 0 1; 1 0 1; 1 1 1;...
+            2 0 1; 2 1 1; 2 2 1;...
+            3 0 1; 3 1 1; 3 2 0; 3 2 1; 3 2 2; 3 3 1; 3 3 2;...
+            4 0 1; 4 1 1; 4 2 1; 4 3 0; 4 3 1; 4 3 2; 4 3 3; 4 4 1; 4 4 3];
+    else
+        disp('unrecognised "mark_poles" option - should be all/main/none')
+    end
+
+    sym = gtGetCubicSymOp;
+    uvw_poles2=[];
+    for i=1:length(sym)
+        uvw_poles2=[uvw_poles2; uvw_poles*sym(i).g];
+    end
+    uvw_poles=[uvw_poles2; -uvw_poles2];
+
+
+    % get the relevent uvw_poles
+    if strcmp(app.range, 'sst')
+        %for standard stereographic triangle
+        dum=find(uvw_poles(:,2)>=0 & uvw_poles(:,2)<=uvw_poles(:,1) & uvw_poles(:,3)>=uvw_poles(:,1));
+        uvw_poles=uvw_poles(dum, :);
+    elseif strcmp(app.range, 'phi90')
+        %for a 90 degree section of the pole figure
+        dum=find(uvw_poles(:,1)>=0 & uvw_poles(:,2)>=0 & uvw_poles(:,3)>=0);
+        uvw_poles=uvw_poles(dum, :);
+    elseif strcmp(app.range, 'phi360')
+        %for 360 pole figure - reduce only using psi
+        uvw_poles=uvw_poles(find(uvw_poles(:,3)>=0),:);
+    end
+
+    % plot these uvw/hkl poles
+    phi_uvw=atan2(uvw_poles(:,2), uvw_poles(:,1));
+    psi_uvw=acos(uvw_poles(:,3)./(sqrt(sum(uvw_poles.*uvw_poles, 2))));
+    r_uvw=tan(psi_uvw/2);
+    dummy=find(r_uvw>1);
+    r_uvw(dummy)=[];
+    phi_uvw(dummy)=[];
+    [x_uvw,y_uvw]=pol2cart(phi_uvw, r_uvw);
+    dummy=find(x_uvw<-1 | x_uvw>1 | y_uvw<-1 | y_uvw>1);
+    x_uvw(dummy)=[];
+    y_uvw(dummy)=[];
+
+    plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density(:))+1), 'k*')
+end
+
+
+% tidy the figure
+set(gca, 'XTickLabel','')
+set(gca, 'YTickLabel','')
+set(gca, 'GridLineStyle','none')
+set(gca, 'Ycolor', 'w')
+set(gca, 'Xcolor', 'w')
+colorbar
+
+%change to x-y view
+set(gca, 'CameraPosition', [(min(x(:))+max(x(:)))/2 (min(y(:))+max(y(:)))/2 5*(max(density(:))+1)]);
+set(gca, 'CameraUpVector', [0 1 0]);
+
+
+
+
+
+if strcmp(app.range, 'sst')
+%for sst - apply a mask to the figure
+
+%line from 101 to 111 is z=x
+line_phi=[0:0.01:pi/4 pi/4];
+linex=cos(line_phi);
+linez=linex;
+liney=sin(line_phi);
+line_points=[linex' liney' linez'];
+%normalise
+line_points=line_points./repmat(sqrt(sum(line_points.*line_points, 2)), 1, 3);
+%convert to stereographic proj.
+line_psi=acos(line_points(:,3));
+line_r=tan(line_psi/2);
+[line_x,line_y]=pol2cart(line_phi', line_r);
+
+%white patch over unwanted bit of figure
+mask_x=[line_x ; sqrt(2)-1+0.045 ; sqrt(2)-1+0.045 ; line_x(1)];
+mask_y=[line_y ; line_y(end) ; 0 ; 0];
+mask_z=ones(size(mask_y))*(max(density(:))+0.5); %between the pole points and the surface
+p=patch(mask_x, mask_y, mask_z, 'w');
+set(p, 'edgecolor', 'w')
+
+%black outline on polefigure
+mask_x=[line_x ; 0 ; line_x(1)];
+mask_y=[line_y ; 0 ; 0];
+mask_z=ones(size(mask_y))*(max(density(:))+1);
+plot3(mask_x, mask_y, mask_z, 'k')
+
+%tweak axis limits and therefore adjust camera position
+set(gca, 'xlim', [-0.02 sqrt(2)-1+0.045])
+set(gca, 'ylim', [-0.025 0.3769])
+set(gca, 'CameraPosition', [(sqrt(2)-1+0.025)/2 (-0.025+0.3769)/2 (max(density(:))+2)]); 
+set(gca, 'CameraUpVector', [0 1 0]);
+
+
+%redo the colorbar, and adjust position
+%warning('nice sst colorbar switched off')
+c=colorbar;
+set(c, 'Position', [0.18 0.3 0.04 0.6])
+end
+
+%label poles
+if ~strcmp(app.label_poles, 'none')
+
+    label_z=max(density(:))+1;
+
+    if strcmp(app.label_poles, 'all') | strcmp(app.label_poles, 'main')
+        %label the poles son the corners of the sst
+        text(0, 0-0.015, label_z, '(001)')
+        text(0.366+0.01, 0.366-0.005, label_z, '(111)')
+        text(0.4142-0.015, -0.015, label_z, '(101)')
+    end
+
+    if strcmp(app.label_poles, 'all')
+        %label the long list of poles
+        text(0.1213-0.04, 0.1213, label_z, '(114)')
+        text(0.1583-0.04, 0.1583, label_z, '(113)')
+        text(0.2247-0.04, 0.2247, label_z, '(112)')
+        text(0.2808-0.04, 0.2808, label_z, '(223)')
+        text(0.3052-0.045, 0.3052, label_z, '(334)')
+
+        text(0.3845+0.01, 0.2884, label_z, '(434)')
+        text(0.3901+0.01, 0.2601, label_z, '(323)')
+        text(0.4000+0.01, 0.2000, label_z, '(212)')
+        text(0.4077+0.01, 0.1359, label_z, '(313)')
+        text(0.4105+0.01, 0.1026, label_z, '(414)')
+
+        text(0.1231-0.02, -0.015, label_z, '(104)')
+        text(0.1623-0.01, -0.015, label_z, '(103)')
+        text(0.2361-0.015, -0.015, label_z, '(102)')
+        text(0.3028-0.02, -0.015, label_z, '(203)')
+        text(0.3333-0.01, -0.015, label_z, '(304)')
+
+        text(0.2967+0.01, 0.1483, label_z, '(213)')
+        text(0.2330+0.01, 0.1165, label_z, '(214)')
+        text(0.3297+0.01, 0.1099, label_z, '(314)')
+        text(0.3197+0.01, 0.2131, label_z, '(324)')
+    end
+end
+
+end
+
+
+
+
+
diff --git a/5_reconstruction/gtMakePoleFigure2.m b/5_reconstruction/gtMakePoleFigure2.m
new file mode 100755
index 0000000000000000000000000000000000000000..c85ecfd07262a9d35546a0f0cd7f2218b8b14db5
--- /dev/null
+++ b/5_reconstruction/gtMakePoleFigure2.m
@@ -0,0 +1,82 @@
+function gtMakePoleFigure2(poles, weights)
+
+% as for gtMakePoleFigure...  however, given poles, gtMakePoleFigure uses a
+% search radius to find all poles close to each data point on the pole
+% figure, thus doing some inherent smoothing.  This is also slow for large
+% numbers of poles.  If the data going in does not require smoothing
+% (remains to be seen!) maybe can construct the pole figue data in a faster
+% way.
+
+%at the mo this is quick (~10x cf gtMakePoleFigure) but not clever enough
+%because the sampling areas get too small near the pole, and thus noise
+% here overpowers the signal.  Needs something cleverer...  Triangle mesh
+% from isosurface on a sphere?
+
+
+%step size in pole figure
+inc=0.02;
+
+%change this if you want a 360deg or 90deg view
+phimax=pi/2;
+%phimax=2*pi;
+psimax=pi/2;
+phi_range=0:inc:(phimax-inc);
+psi_range=0:inc:(psimax-inc);
+
+
+%before building figure, take only those poles that fall in the range 0-phimax,
+%0-psimax (allowing for seach radius)
+if phimax==pi/2
+   %for a 90 degree section of the pole figure
+   poles=poles(find(poles(:,1)>0 & poles(:,2)>0 & poles(:,3)>0),:);
+elseif phimax==2*pi
+    %for 360 pole figure - reduce only using psi
+   poles=poles(find(poles(:,3)>cos(psimax)-sin(searchR)),:);
+else
+    disp('dont know how take a subset of the poles input')
+end
+
+
+
+%preallocate density
+density=zeros(length(phi_range), length(psi_range));
+
+%calc phi and psi for all poles
+psi=acos(poles(:,3));
+phi=atan2(poles(:,2), poles(:,1));
+
+for i=1:length(phi_range)
+    i
+    for j=1:length(psi_range)
+        dum=find(phi>=phi_range(i) & phi<phi_range(i)+inc & psi>=psi_range(j) & psi<psi_range(j)+inc);
+        density(i, j)=sum(weights(dum));     
+    end
+end
+
+%normalise density values
+%needs to be wrt random population, and account for the search area
+%increment size as function of psi:
+inc_area=inc*[-cos(psi_range+inc)+cos(psi_range)];
+inc_area=repmat(inc_area, length(phi_range), 1);
+density2=density./inc_area;
+
+%total density/total area
+total_density=sum(density(:));
+total_area=sum(inc_area(:));
+
+
+density2=10*density2/max(density2(:));
+
+keyboard
+phi=0:inc:phimax; %around z-axis
+psi=0:inc:psimax; %away from z axis
+%radius distorted for stereographic proj
+r=tan((psi_range+(inc/2))/2);
+[phi,r]=meshgrid((phi_range+(inc/2)),r);
+[x,y]=pol2cart(phi,r);
+
+figure
+surf(x,y,density2')
+hold on
+shading('interp')
+axis equal
diff --git a/5_reconstruction/gtMakePoleFigure_hex.m b/5_reconstruction/gtMakePoleFigure_hex.m
new file mode 100755
index 0000000000000000000000000000000000000000..021bea81607a5fb71b6aec6c7f88cd14852e7df8
--- /dev/null
+++ b/5_reconstruction/gtMakePoleFigure_hex.m
@@ -0,0 +1,160 @@
+function gtMakePoleFigure_hex(poles)
+% make a pole figure on the given a list of poles.
+% poles=[x y z, x2 y2 z2; ...]
+% get poles from gtReadBoundariesStructure
+
+load parameters
+
+i=1;j=1;
+figure
+searchR=0.1; %was 0.05
+
+%step size in pole figures
+%inc=0.02;
+inc=0.02;
+
+for omega=0:inc:2*pi%/2 %around z-axis
+  j=1;
+  for eta=0:inc:pi/2 % out from z-axis 
+    
+    z=cos(eta);
+    x=sin(eta)*cos(omega);
+    y=sin(eta)*sin(omega);
+    test_normal=[x y z];
+    
+    if 1%z>y %1
+      angle_dev = acos((dot(poles, repmat(test_normal, size(poles,1), 1), 2)));
+      density(i,j)=length(find(angle_dev<searchR));
+      %density2(i,j)=length(find(angle_dev<0.08));
+      %density3(i,j)=length(find(angle_dev<0.02));
+
+    else
+      density(i,j)=NaN;
+    end
+    
+    j=j+1;
+    
+  end
+  i=i+1;
+end
+
+
+%normalise density into smething meaningful
+%total solid angle covered 4pi for a whole sphere
+%If we have poles covering a whole sphere, random density is
+random_density=(length(poles))*((searchR^2)/4); %pi's cancel
+density=density./random_density;
+
+%have: density as a function of omega and eta.  Can convert to x,y,z, and
+%use surf.
+%modify for steorographic projection
+omega=0:inc:2*pi;%/2;%/4; %around z-axis
+eta=0:inc:pi/2; %away from z axis
+
+r=tan(eta/2);
+[omega,r]=meshgrid(omega,r);
+[x,y]=pol2cart(omega,r);
+
+%figure(1)
+surf(x,y,density')
+hold on
+shading('interp')
+axis equal
+
+% figure(2)
+% surf(x,y,density2')
+% hold on
+% shading('interp')
+% axis equal
+% 
+% figure(3)
+% surf(x,y,density3')
+% hold on
+% shading('interp')
+% axis equal
+
+
+
+
+if parameters.acq.spacegroup == 663
+    uvw_poles_a=[0 0 0 2; ...
+        1 1 -2 0; ...
+        1 -1 0 0; ...
+        1 -1 0 1; ...
+        1 1 -2 2; ...
+        -2 0 2 1; ...
+        ];
+else
+    disp('this spacegroup is not impleted yes')
+end
+
+
+sym=gtGetHexagonalSymOp_sab; % plans qui diffractent
+uvw_poles_final=[];
+for i=1:size(uvw_poles_a,1)
+ %i=1
+  uvw_poles_hex=[];
+  for j=1:size(sym,2)
+    uvw_poles_hex(j,:)=uvw_poles_a(i,:)*sym(j).g;
+  end  
+    uvw_poles_hex=unique(uvw_poles_hex,'rows'); % a mettre ?
+    
+    for j=1:size(uvw_poles_hex,1)
+        uvw_poles(j,1)= uvw_poles_hex(j,1) + 0.5 * uvw_poles_hex(j,2);
+        uvw_poles(j,2)= 3^0.5/2 *uvw_poles_hex(j,2);
+        uvw_poles(j,3)= uvw_poles_hex(j,4);
+    end
+
+ 
+
+    uvw_poles=[uvw_poles; -uvw_poles];
+    uvw_poles_final=[ uvw_poles_final;uvw_poles];
+  %uvw_poles=unique(uvw_poles,'rows'); % a mettre ? 
+
+  %%%%%%%%%%%%%correct until here
+  
+  % hexagonal to cartesian
+    
+ 
+  %
+  
+om_uvw=atan2(uvw_poles(:,2), uvw_poles(:,1));
+
+et_uvw=acos(uvw_poles(:,3)./(sqrt(sum(uvw_poles.*uvw_poles, 2))));
+r_uvw=tan(et_uvw/2);
+dummy=find(r_uvw>1);
+r_uvw(dummy)=[];
+om_uvw(dummy)=[];
+[x_uvw,y_uvw]=pol2cart(om_uvw, r_uvw);
+dummy=find(x_uvw<-1 | x_uvw>1 | y_uvw<-1 | y_uvw>1);
+x_uvw(dummy)=[];
+y_uvw(dummy)=[];
+
+figure(1)
+hold on
+if i==1 ; plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density(:))+1), 'ko'); end
+if i==2 ; plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density(:))+1), 'r*'); end
+if i==3 ; plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density(:))+1), 'g*'); end
+if i==4 ; plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density(:))+1), 'y*'); end
+if i==5 ; plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density(:))+1), 'b*'); end
+if i>5 ; plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density(:))+1), 'k*'); end
+
+hold off
+
+% figure(2)
+% plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density2(:))+1), 'k*')
+% figure(3)
+% plot3(x_uvw, y_uvw, ones(size(x_uvw))*(max(density3(:))+1), 'k*')
+
+end
+set(gca, 'XTickLabel','')
+set(gca, 'YTickLabel','')
+set(gca, 'GridLineStyle','none')
+colorbar
+
+
+
+
+
+
+
diff --git a/5_reconstruction/gtMergeSpot.m b/5_reconstruction/gtMergeSpot.m
new file mode 100755
index 0000000000000000000000000000000000000000..9f735633e9ad1ca84130e592d2cdbb0d9c3c733f
--- /dev/null
+++ b/5_reconstruction/gtMergeSpot.m
@@ -0,0 +1,39 @@
+%function [c,ea,eb]=gtMergeSpot(a,b)
+
+  for i=1:14;
+
+  a=sdt_read(sprintf('grain2_/grain2_dif%d',i));
+  b=sdt_read(sprintf('grain2_/grain2_dif%d',i+14));
+
+
+  xs=min([size(a,2),size(b,2)]);
+  ys=min([size(a,1),size(b,1)]);
+  
+  a=a(1:ys,1:xs);
+  b=b(1:ys,1:xs);
+  b=fliplr(b);
+  a=wiener2(a,[10 10]);
+  b=wiener2(b,[10 10]);
+  
+  ea=edge(a,'canny');
+  eb=edge(b,'canny');
+  
+  
+  c=correlate(ea,eb);
+  
+  bc=interpolatef(b,c(1),c(2));
+  
+  
+  c=a+bc;
+  t=graythresh(c);
+  proj=im2bw(c,0.28*t);
+  
+  name=sprintf('grain2_/grain2_difs%d',i);
+  sdt_write(name,proj,'float32')
+  
+  %imshow([im2bw(c,0.25*t),1000*c],[])
+  findshifts3(a,bc,'clims','block','on',[-0.001 0.001],'climt',[-0.01 0.01])
+  
+
+  end  
+  
\ No newline at end of file
diff --git a/5_reconstruction/gtRandCmap.m b/5_reconstruction/gtRandCmap.m
new file mode 100755
index 0000000000000000000000000000000000000000..e5bcda19f5e6498d03234b67dbc9ea7222bbc356
--- /dev/null
+++ b/5_reconstruction/gtRandCmap.m
@@ -0,0 +1,20 @@
+function map=gtRandCmap(vol)
+%make a random colourmap corresponding to the given volume
+%save typing...
+
+a=max(vol(:));
+map=rand(a+1, 3);
+map(1,:)=[0 0 0];%black background
+
+
+%map(1,:)=[1 1 1];%white background
+
+%increase brightness of dim colours
+int=sum(map,2);
+dum=find(int<1);
+dum(find(dum==1))=[];%don't scale the zeros!
+map(dum, :)=2*map(dum, :)./repmat(int(dum), 1, 3);
+map(find(map>1))=1;
+
+imap=map; %what does this do?  
+end
diff --git a/5_reconstruction/gtReadBoundariesStructure.m b/5_reconstruction/gtReadBoundariesStructure.m
new file mode 100755
index 0000000000000000000000000000000000000000..bd997c2650a71b8efe45992aaf5c3fbd33dc1a86
--- /dev/null
+++ b/5_reconstruction/gtReadBoundariesStructure.m
@@ -0,0 +1,118 @@
+function [output, output2] = gtReadBoundariesStructure(boundaries_structure, boundaries_structure_test, bridges)
+
+
+%boundaries_structure is a .mat file used to store boundary data.
+%it contains: boundaries_structure(i).
+% grain1
+% grain2
+% count
+% crack1_count
+% crack2_count
+% crack5_count
+% gb_norm
+% gb_norm_confidence
+% gb_centre
+% misorientation_angle
+% misorientation_axis
+% gb_norm_grain1
+% gb_norm_grain2
+% sigma
+% grain1_R_vector
+% grain2_R_vector
+
+%therefore, can pull out the poles for a pole figure according to different
+%criteria, as well as producing symmetry equivelent (for xtallographic
+%things) if required.
+
+% add - in a crude way - the stuff to read from the the
+% boundaries_structure_test - the pole figure density for each boundary
+% after dealing with curved boundaries.
+
+%output is either poles or density - either way then used in gtMakePoleFigure
+%output2 is valid poles weight, not used for poles case
+%should be able to combine boundaries_structure and
+%boundaries_structure_test.  Keep separate for the moment while testing.
+
+poles=[];
+count=1;
+sym = gtGetCubicSymOp;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if 0 % if using boundaries_structure
+%loop through structure
+for i=1:length(boundaries_structure)
+%for i=bridges
+    %criteria
+  if  boundaries_structure(i).grain1~=0 & boundaries_structure(i).grain2~=0 & ~isempty(boundaries_structure(i).gb_norm)
+  
+   %if 1 %no test
+%    if boundaries_structure(i).crack5_count>100
+   % if isempty(boundaries_structure(i).sigma) | boundaries_structure(i).sigma~=3
+    if isempty(boundaries_structure(i).sigma)
+  %if boundaries_structure(i).sigma==3
+  %    poles(end+1,:)=boundaries_structure(i).gb_norm;
+%
+
+    poles(end+1,:)=boundaries_structure(i).gb_norm_grain1;
+    poles(end+1,:)=boundaries_structure(i).gb_norm_grain2;
+
+    end  
+  end%criteria
+end%loop
+
+%apply the symmetry operators
+poles2=[];
+for i=1:length(sym)
+  poles2=[poles2; poles*sym(i).g];
+end
+%add this to correspond to line in gtMakePoleFigure
+poles2=[poles2; -poles2];
+%poles=unique(poles2, 'rows');
+poles=poles2;
+output=poles;
+output2=[];
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if 1
+    %find a non-empty density map to preallocate
+    i=1;
+    density=[];
+    count=0;
+    vpw=0;%valid poles_weight for normalising
+    while isempty(density)
+        density=zeros(size(boundaries_structure_test(i).grain1_pole_density));
+        i=i+1;
+    end
+
+    %for i=1:length(boundaries_structure_test)
+for i=bridges
+        %criteria
+        %if  boundaries_structure(i).grain1~=0 & boundaries_structure(i).grain2~=0 & ~isempty(boundaries_structure(i).gb_norm)
+
+        if 1 %no test
+        %    if boundaries_structure(i).crack5_count>100
+%        if isempty(boundaries_structure(i).sigma) | boundaries_structure(i).sigma~=3
+%if (isempty(boundaries_structure(i).sigma) | boundaries_structure(i).sigma~=3) & boundaries_structure(i).grain1~=0 & boundaries_structure(i).grain2~=0
+        %  if isempty(boundaries_structure(i).sigma)
+   %  if boundaries_structure(i).sigma==3
+%     if boundaries_structure(i).sigma==9
+%  if boundaries_structure(i).misorientation_angle>15
+   %
+            if ~isempty(boundaries_structure_test(i).grain1_pole_density)
+            density=density+boundaries_structure_test(i).grain1_pole_density;
+            vpw=vpw+boundaries_structure_test(i).grain1_valid_poles_weight;
+            end
+            if ~isempty(boundaries_structure_test(i).grain2_pole_density)
+            density=density+boundaries_structure_test(i).grain2_pole_density;
+            vpw=vpw+boundaries_structure_test(i).grain2_valid_poles_weight;
+            end
+count=count+1;
+        end%criteria
+    end%loop
+    output=density;
+    output2=vpw;
+    count
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/5_reconstruction/gtReadBoundaryProperties.m b/5_reconstruction/gtReadBoundaryProperties.m
new file mode 100755
index 0000000000000000000000000000000000000000..83a56ae772454c311c015752f65cb65522569f50
--- /dev/null
+++ b/5_reconstruction/gtReadBoundaryProperties.m
@@ -0,0 +1,132 @@
+function gtReadBoundaryProperties(boundaries_structure, vol_boundaries)%, r_vectors)
+
+%continue to add to boundaries_structure.mat - orientations,
+%disorientation, r-vectors etc.
+
+
+
+
+maxgrain=0;
+for i=1:length(boundaries_structure)
+  maxgrain=max(maxgrain, boundaries_structure(i).grain1);
+  maxgrain=max(maxgrain, boundaries_structure(i).grain2);
+end
+
+r_vectors=[];
+if exist('r_vectors.mat', 'file')
+  load r_vectors
+else
+  r_vectors=zeros(maxgrain,4);%keep a record to save loading .mats
+end
+
+sym = gtGetCubicSymOp;
+
+%for k=1:length(list) %just look at the possible twin boundaries
+%  i=list(k)
+for i=1:size(boundaries_structure, 2)
+  %k=i;
+
+  % if boundaries_structure(i).grain1==0 || boundaries_structure(i).grain2==0 || boundaries_structure(i).count<4
+  if boundaries_structure(i).count<4 %can still be useful to calc index planes where we have only one of the grains
+    continue
+  else
+
+    %Read in the data of the two grains
+    i
+    grain1=boundaries_structure(i).grain1;
+    grain2=boundaries_structure(i).grain2;
+
+    if grain1==0
+      g1=[];
+      g1equiv=[];
+    else
+      if all(r_vectors(grain1,:)==0)
+        tmp1=load(sprintf('4_grains/grain%d_/grain%d_.mat',grain1,grain1), 'R_vector');
+        R1=tmp1.R_vector;
+        r_vectors(grain1,:)=[grain1 R1];
+      else
+        R1= r_vectors(grain1,2:4);
+      end
+      boundaries_structure(i).grain1_R_vector=R1;
+      g1=Rod2g(R1);
+    end
+    if grain2==0
+      g2=[];
+    else
+      if all(r_vectors(grain2,:)==0)
+        tmp2=load(sprintf('4_grains/grain%d_/grain%d_.mat',grain2,grain2), 'R_vector');
+        R2=tmp2.R_vector;
+        r_vectors(grain2,:)=[grain2 R2];
+      else
+        R2= r_vectors(grain2,2:4);
+      end
+      boundaries_structure(i).grain2_R_vector=R2;
+      g2=Rod2g(R2);
+    end
+
+
+    if ~isempty(g1) & ~isempty(g2)
+      %if we have both grains
+      %need to search symmetry equivelents for the minimum misorientation
+      rot_offset=[];
+      % warning('g*sym.g maybe should be sym.g*g')
+      for j=1:24
+        g1equiv = g1*sym(j).g;
+        netg = inv(g1equiv)*g2;
+        rot_offset(j) = acos((trace(netg)-1)/2);
+      end
+
+      dummy = find(rot_offset ==min(rot_offset));
+      g1equiv = g1*sym(dummy).g;
+      netg = inv(g1equiv)*g2;
+
+      misorientation_angle = (180/pi)*acos((trace(netg)-1)/2);
+
+      [eigVec, eigVal]=eig(netg);
+      for p=1:3
+        if isreal(eigVec(:,p))  %find the real eigenvector - should be just one
+          misorientation_axis=eigVec(:,p);
+        end
+      end
+
+
+      boundaries_structure(i).misorientation_axis=misorientation_axis';
+      boundaries_structure(i).misorientation_angle=misorientation_angle;
+    end
+
+    %even if we have only one grain, can deal with the boundary plane
+    test = vol_boundaries==i;
+    [x,y,z]=ind2sub(size(test), find(test));
+    [origin, a]=lsplane([x y z]);
+
+    gb_normal=a;
+    gb_normal(3)=-gb_normal(3);
+
+    boundaries_structure(i).gb_norm = gb_normal';
+    boundaries_structure(i).gb_centre = origin';
+
+    if ~isempty(g1equiv)
+      plane1=inv(g1equiv)*gb_normal;
+    elseif ~isempty(g1)
+      plane1=inv(g1)*gb_normal;
+    else
+      plane1=[];
+    end
+
+    if ~isempty(g2)
+      plane2=inv(g2)*gb_normal;
+    else
+      plane2=[];
+    end
+
+    boundaries_structure(i).gb_norm_grain1=plane1';
+    boundaries_structure(i).gb_norm_grain2=plane2';
+
+    %
+  end
+end
+
+save('boundaries_structure.mat', 'boundaries_structure')
+save('r_vectors.mat', 'r_vectors')
+
+
diff --git a/5_reconstruction/gtReconstructionManager.m b/5_reconstruction/gtReconstructionManager.m
new file mode 100755
index 0000000000000000000000000000000000000000..4df4e174ab05fcef211a7486b9c7badf0e31de11
--- /dev/null
+++ b/5_reconstruction/gtReconstructionManager.m
@@ -0,0 +1,583 @@
+%GUI to choose art params, select and replace reflections, and fix bounding
+%boxes...
+%like gtnew_new_choose_art...  but better!
+
+%loop through a series of grains
+
+
+function gtReconstructionManager(grainid)
+
+  parameters=[];
+  load parameters;
+  gtDBConnect;
+
+  block='on'; %don't return the command line until the user is finished
+
+  %avoid using this old version by mistake!
+  check=inputwdefault('For recent data use gtReconstructionManager_360 instead!  continue with this old version? (y/n)', 'n');
+    if check=='n'
+    return
+    end
+  
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %read in data, sort for convinience
+  g=load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+  struct_ids=g.struct_ids;
+
+  if isfield(g, 'bad') && g.bad>=1
+    disp(sprintf('grain %d is already set to bad=%d',grainid, g.bad))
+    return
+  end
+  
+  if isfield(g, 'done') && g.done==1
+    check=inputwdefault(sprintf('grain %d already been done! Do you want to proceed anyway? y/n',grainid), 'n');
+    if check=='n'
+    return
+    end
+  end
+
+
+  %if it doesn't already exist, add an index, replaced, pair_vector
+  if isfield(g, 'index')
+    index=g.index;
+  else
+    index = ones(1,length(struct_ids));
+  end
+  if isfield(g, 'replaced')
+    replaced=g.replaced;
+  else
+    replaced = zeros(1,length(struct_ids));
+  end
+  if isfield(g, 'pair_vector')
+    pair_vector=g.pair_vector;
+  else
+    pair_vector = ones(1,length(struct_ids));
+  end
+  if isfield(g, 'bad')
+    bad=g.bad;
+  else
+    bad=0;
+  end
+  %estimate art parameters
+  if length(struct_ids)>50
+    lambda = [0.2 0.1 0.05];
+  elseif length(struct_ids)>30
+    lambda = [0.3 0.2 0.1]; %initial values
+  elseif length(struct_ids)>15
+    lambda = [0.5 0.3 0.1]; %initial values
+  else
+    lambda = [0.7 0.3 0.2]; %initial values
+  end
+
+  %unpacking...
+  Omega=g.Omega;Theta=g.Theta;Eta=g.Eta;
+  plane_normal=g.plane_normal;hkl=g.hkl;
+  stack=g.stack;
+  %for editable ART bounding box
+  x1 = g.x1;
+  y1 = g.y1;
+  nx = g.nx;
+  ny = g.ny;
+
+
+  %do the sorting by Omega
+  [Omega,tmp]=sort(Omega);
+
+  %if we need to, sort other fields, save, and rewrite stack to ART input
+  if ~all(tmp==1:length(Omega))
+
+    %    %may need also to remove duplicates....
+    %   [struct_ids,tmp]=unique(struct_ids);
+    %   pair_vector=pair_vector(tmp);
+    %   Omega=Omega(tmp);
+    %   Theta=Theta(tmp);
+    %   Eta=Eta(tmp);
+    %   index=index(tmp);
+    %   replaced=replaced(tmp);
+    %   plane_normal=plane_normal(tmp,:);
+    %   hkl=hkl(tmp,:);
+    %   stack=stack(:,:,tmp);
+
+
+    Theta = Theta(tmp);
+    Eta = Eta(tmp);
+    struct_ids = struct_ids(tmp);
+    pair_vector=pair_vector(tmp);
+    plane_normal = plane_normal(tmp,:);
+    hkl = hkl(tmp,:);
+    stack = stack(:,:,tmp);
+    index = index(tmp);
+    replaced = replaced(tmp);
+
+    %save in new order
+
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),...
+      'struct_ids','pair_vector','stack','Theta','Eta','Omega','plane_normal','hkl',...
+      'index','replaced','bad','-append');
+    gtWriteStack_replaced(grainid);%write the stak in new order
+  end
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  
+  %%%%%%%%%%%%%%%%%
+  %remove bad projections automatically
+  if 0
+  gt_select_projections_auto(grainid)
+  pause(1)
+  close; close;
+  else
+    disp('auto selection of projections disabled')
+  end
+  %%%%%%%%%%%%%%%%%
+  
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %Now the interactive part
+  refresh=1;
+
+  app.quit=0;
+
+  %setup the figures
+  
+  scrsz = get(0,'ScreenSize');
+
+  fig_handle=figure;
+   set(fig_handle, 'Position',[50 150 0.75*scrsz(3) .75*scrsz(4)]);
+   
+  StackAxes=subplot(1,3,1);%stack image
+
+  app.stack_slider=uicontrol('style', 'slider');
+  set(app.stack_slider, 'callback', @sfSliderFunction)
+  set(fig_handle,'windowbuttonmotionfcn',@sfSliderFunction)
+  set(fig_handle,'windowbuttondownfcn',@sfTestFunction) %@sfSliderFunction)
+  set(fig_handle,'windowbuttonupfcn',@sfSliderFunction)
+  
+  set(app.stack_slider,'units','normalized');
+  set(app.stack_slider,'position',[0 0 .4 0.05])
+  set(app.stack_slider,'min',1,'max',size(stack,3),'sliderstep',[1/size(stack,3) 1/size(stack,3)]);
+  set(app.stack_slider,'value',1);
+  imshow(stack(:,:,1), [])
+  app.currentImage=1;
+
+
+  BackproAxes=subplot(1,3,2);%crude backpro image
+  %set(fig_handle, 'windowbuttondownfcn', @sfDragBBFunction1)
+  %set(fig_handle, 'windowbuttonupfcn', @sfDragBBFunction2)
+  %set(BackproAxes, 'ButtonDownFcn', @sfDragBBFunction1)
+  title('click to change ART bb')
+
+
+  
+  
+  
+  buttongroup=uibuttongroup('Position', [.4 0 .6 .05]);
+
+  UseButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'use', 'position', [0 0 50 20]);
+  set(UseButton, 'callback', @sfUseButtonFunction)
+    
+  UseAllButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'use all', 'position', [50 0 50 20]);
+  set(UseAllButton, 'callback', @sfUseAllButtonFunction)
+  
+  ReplaceButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'replace', 'position', [100 0 50 20]);
+  set(ReplaceButton, 'callback', @sfReplaceButtonFunction)
+  ARTButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'Do ART', 'position', [150 0 50 20]);
+  set(ARTButton, 'callback', @sfARTButtonFunction)
+
+  lambdastring=num2str(lambda);
+  lambdastring=lambdastring([1:4 13:16 25:27]);
+
+  LambdaBox=uicontrol(buttongroup, 'Style', 'edit', 'String', lambdastring, 'position', [200 0 70 20]);
+
+  BadButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'bad grain', 'position', [270 0 50 20]);
+  set(BadButton, 'callback', @sfBadButtonFunction)
+  AcceptButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'ACCEPT!', 'position', [320 0 50 20]);
+  set(AcceptButton, 'callback', @sfAcceptButtonFunction)
+
+
+%add a button to escape without making changes
+    exitbuttongroup=uibuttongroup('Position', [.85 .95 .15 .05]);
+  ExitButton=uicontrol(exitbuttongroup, 'Style', 'pushbutton', 'string', 'quit, no changes', 'position', [0 0 100 20]);
+  set(ExitButton, 'callback', @sfExitButtonFunction)
+    
+  
+
+  %make overlays for backproim, prepare a big image to show in the left
+  %hand window
+  %get max range of spots
+  tmp=sum(sum(stack, 3), 2);
+  first=min(find(tmp));
+  last=max(find(tmp));
+  range=last-first+1;
+  big_image=zeros((size(stack,3)+6)*range, size(stack,2)); %pad by three images top and bottom
+  app.overlays=zeros([size(stack,2), size(stack,2), size(stack,3)]);
+  %collect sino
+  for i=1:size(stack,3)
+    sino(:,i) = stack(g.zcenter, :, i)';
+    big_image(((i+2)*range)+1:(i+3)*range, :) =  stack(first:last,:,i);
+  end
+  binsino=sino>0;
+  for i=1:size(stack,3)
+    app.overlays(:,:,i)=backpro(binsino(:,i),Omega(i)*pi/180);
+    app.centroidx(i) = sino(:,i)'*(1:size(sino,1))'/sum(sino(:,i));
+  end
+  app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+
+
+
+
+
+  ARTAxes=subplot(1,3,3);
+  sfSliderFunction
+  sfARTButtonFunction %first "press" of the button
+
+  if strcmp(block,'on')
+    % if user wants nothing to return until findshift is finished
+    while 1
+      drawnow
+      if app.quit==1
+        break
+      end
+    end
+  end
+
+
+    function sfTestFunction(varargin)%which subfunction should the button down go to?
+        if isequal(gco,app.stack_slider)
+            sfSliderFunction
+        elseif isequal(gca,BackproAxes)
+        sfDragBBFunction1
+        end
+    end
+
+        
+  
+
+  function sfSliderFunction(varargin)
+
+    if (isequal(gco,app.stack_slider) || refresh)
+      tmp=round(get(app.stack_slider,'value'));
+      if (tmp~=app.currentImage | refresh)
+          
+        subplot(1,3,1)% update stack figure
+        hold off
+        app.currentImage=tmp;
+        %get 7 image subsection of big_image
+        im_start=((app.currentImage-1)*range)+1;
+        im_end=(app.currentImage+6)*range;
+        
+        imshow(big_image(im_start:im_end, :), [])
+        hold on
+        %highlight current image
+        xdata=[1 size(big_image,2) size(big_image, 2) 1 1];
+        ydata=[(3*range)+1 (3*range)+1 4*range 4*range (3*range)+1];
+        %adjust line colour according to index
+        
+        if index(app.currentImage)==1 %if using, green
+        plot(xdata, ydata, 'g');
+        else %if not using, red
+        plot(xdata, ydata, 'r');    
+        end
+        
+        title(sprintf('id: %d, pair: %d, use: %d, replaced: %d', struct_ids(app.currentImage), pair_vector(app.currentImage), index(app.currentImage), replaced(app.currentImage)))
+        drawnow
+
+        subplot(1,3,2)% update backpro image overlay
+        hold off
+        imshow(app.BPimage, []); %show the first backprojection
+        %colormap jet
+        hold on
+        title('click to change ART bb')
+        
+        if 0 %if alpha thing is working?
+        app.BPoverlay=zeros([size(app.BPimage) 3]);
+        %adjust overlay colour according to index
+        if index(app.currentImage)==1 %if using, green
+        app.BPoverlay(:,:,2)=app.overlays(:,:,app.currentImage);
+        else %if not using, red
+        app.BPoverlay(:,:,1)=app.overlays(:,:,app.currentImage);
+        end
+        app.BPoverlay=image(app.BPoverlay, 'XData', [1:size(app.BPimage,2)], 'YData', [1:size(app.BPimage,1)]);
+        set(app.BPoverlay, 'AlphaData', 0.04*ones(size(app.BPimage)))
+        
+        %%%%%%%%  alternative display mode if alpha overlay isn't working
+       else %plot a simple line over the current projection
+          
+          spot_com=app.centroidx(app.currentImage);
+          spot_omega=Omega(app.currentImage)*pi/180; %Omega in degreees
+          %experiment parameters
+          centre_of_backproimg_x = parameters.acq.bb(3)/2;
+          centre_of_backproimg_y = parameters.acq.bb(3)/2;
+          point=[centre_of_backproimg_x, centre_of_backproimg_y];
+          %make line parameters
+          grad=1/tan(spot_omega);
+          %dist of com line from centre
+          offset_com=spot_com-parameters.acq.bb(3)/2;
+          %centre point of line though the projection
+          point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+          %put into format y = mx + c
+          m = grad;
+          c = point(2) - (m*point(1));
+          ez_line=ezplot(sprintf('%f*x + %f - y = 0',m,c),[1 parameters.acq.bb(3)]);
+          
+          if index(app.currentImage)==1 %if using, green
+          set(ez_line,'color','g');
+          else %if not using, red
+          set(ez_line, 'color', 'r');
+          end
+            
+        end
+        
+        refresh=0;
+      end
+    end
+  end
+
+  %drag out a new bounding box
+  function sfDragBBFunction1(varargin)
+      
+
+     %      point1 = get(BackproAxes,'CurrentPoint'); % button down detected
+     %point1=point1(1, 1:2)      
+    %       pointx=point1(1, 1);
+    %       pointy=point1(1, 2);
+    %       if pointx>0 && pointx<size(app.BPimage,2) && pointy>0 && pointy<size(app.BPimage,2) %if point within image
+    %           app.newx1=ceil(pointx);
+    %           app.newy1=ceil(pointy);
+    %       end
+    p1 = get(BackproAxes,'CurrentPoint');
+    p1=p1(1, 1:2);
+    bbox=rbbox;
+    p2 = get(BackproAxes,'CurrentPoint');
+    p2=p2(1, 1:2);
+    point1=min(p1, p2);
+    offset=abs(p1-p2);
+    
+    pointx1=point1(1);
+    pointy1=point1(2);
+    pointx2=point1(1)+offset(1);
+    pointy2=point1(2)+offset(2);
+    points=[pointx1 pointy1 pointx2 pointy2];
+    
+
+    if all(points>-10 & points<size(app.BPimage,2)+10) %if both points ~within image
+      %correct if point is slightly outside image
+      if pointx1<1
+          pointx1=1;
+      end
+      if pointy1<1
+          pointy1=1;
+      end
+      if pointx2>size(app.BPimage,2)
+          pointx2=size(app.BPimage,2);
+      end
+      if pointy2>size(app.BPimage,2)
+          pointy2=size(app.BPimage,2);
+      end
+      x1=ceil(pointx1);
+      y1=ceil(pointy1);
+      nx=ceil(pointx2-x1);
+      ny=ceil(pointy2-y1);
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'x1', 'y1', 'nx', 'ny', '-append');
+      sfARTButtonFunction %rerun ART
+    end
+
+  end
+
+  %     function sfDragBBFunction2(varargin)
+  %         point1 = get(BackproAxes,'CurrentPoint'); % button up detected
+  %         pointx=point1(1, 1);
+  %         pointy=point1(1, 2);
+  %         if pointx>0 && pointx<size(app.BPimage,2) && pointy>0 && pointy<size(app.BPimage,2) %if point within image
+  %             x1=app.newx1;
+  %             y1=app.newy1;
+  %             nx=ceil(pointx-x1);
+  %             ny=ceil(pointy-y1);
+  %             save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'x1', 'y1', 'nx', 'ny', '-append');
+  %             sfARTButtonFunction %rerun ART
+  %         end
+  %     end
+
+
+  %%%sf to replace a projection
+  function sfReplaceButtonFunction(varargin)
+    %change replaced
+    replaced(app.currentImage)=~replaced(app.currentImage);
+
+    if pair_vector(app.currentImage)==2
+      name=parameters.acq.pair_name;
+    else
+      name=parameters.acq.name;
+    end
+
+    %update stack with extspot / difspot
+    if replaced(app.currentImage)==0 %extspot case
+
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+        'where %sbb.extspotID = %d'],...
+        name, name, name, name, name,...
+        struct_ids(app.currentImage))
+
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      im = gtGetSummedExtSpot_pair(struct_ids(app.currentImage), pair_vector(app.currentImage));
+
+      %place in stack
+      stack(:,:,app.currentImage) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,app.currentImage)= 100*stack(:,:,app.currentImage)/sum(sum(stack(:,:,app.currentImage)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,app.currentImage) = stack(g.zcenter,:,app.currentImage);
+      
+    else %extspot replaced by difspot
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+        'where %sbboxes.extspotID = %d'],...
+        name, name, name,...
+        struct_ids(app.currentImage))
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      warning('bodge because some SearchBoundingBoxes have zero origins')
+      if BoundingBox(1)==0
+        BoundingBox(1)=1;
+      end
+      if BoundingBox(2)==0
+        BoundingBox(2)=1;
+      end
+
+      % im=edf_read(sprintf('2_difspot/difspot/difspot%05d.edf',struct_ids(ca)));
+      im = gtGetSummedDifSpot_pair(struct_ids(app.currentImage), pair_vector(app.currentImage));
+
+      %place in stack
+      stack(:,:,app.currentImage) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,app.currentImage)= 100*stack(:,:,app.currentImage)/sum(sum(stack(:,:,app.currentImage)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,app.currentImage) = stack(g.zcenter,:,app.currentImage);
+    
+    end
+
+    %rewrite the changed projection .sdt
+    name=sprintf('4_grains/grain%d_/grain%d_%d.sdt',grainid, grainid, app.currentImage);
+    fid=fopen(name,'wb','l');
+    stack(:,:,i)=medfilt2(stack(:,:,app.currentImage));
+    fwrite(fid,stack(:,:,i)','float32');
+    fclose(fid);
+    %no need to rewrite .spr
+    % name=sprintf('4_grains/grain%d_/grain%d_%d.spr',grainid, grainid, app.currentImage)
+    % %name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+    % spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'replaced','-append');
+    %redo backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    %update big image
+    big_image(((app.currentImage+2)*range)+1:(app.currentImage+3)*range, :) =  stack(first:last,:,app.currentImage);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+
+
+
+  %%%sf to use/not use a projection
+  function sfUseButtonFunction(varargin)
+    index(app.currentImage)=~index(app.currentImage);
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'index','-append');
+    %redo the backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+
+  %%%sf to use/not use all projections
+  function sfUseAllButtonFunction(varargin)
+      if all(index==1)
+          index=zeros(size(index));
+      else
+          index=ones(size(index));
+      end
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'index','-append');
+    %redo the backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+  %%subfunction for doing ART on a central section of the grain to test
+  %%parameters
+  function sfARTButtonFunction(varargin)
+    %first read the string in LambdaBox
+    lambdastringnew=get(LambdaBox, 'String');
+    lambdastringnew=['[ ' lambdastringnew ' ]'];
+    lambdanew=str2num(lambdastringnew);
+    if length(lambdanew)==3
+      lambda=lambdanew;
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'lambda','-append');
+    end
+
+    scanname = sprintf('4_grains/grain%d_/grain%d_',grainid,grainid);
+    parfilename = sprintf('4_grains/grain%d_/grain%d_.par',grainid,grainid);
+    z1_sub = g.zcenter-2;
+    nz_sub = 5; %do 5 slices (more representative)
+    nbiter = 3;
+    pixsize = 1;
+    braggangle = 0;
+    np = parameters.acq.bb(3);
+    nq = parameters.acq.bb(4);
+    offset = 0;
+
+    rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+    seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+    p_angles = -Omega(find(index));
+    p_numbers = find(index);
+%    keyboard
+    gtMakeARTJob(scanname,parfilename,p_numbers,p_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset, ...
+      z1_sub,nz_sub,x1,nx,y1,ny);
+
+    command=sprintf('%s %s',rec_alg,parfilename);
+    [s,w]=unix(command);
+    command=sprintf('%s %s_res0_%d',seg2view,scanname,nbiter);
+    [s,w]=unix(command);
+    name=sprintf('%s_res0_%d.sdt',scanname,nbiter);
+    im=volread(name,'float32',0,nx,ny,nz_sub,'l');
+
+    app.ARTimage = im(:,:,ceil(nz_sub/2))';%collect middle slice
+
+    subplot(1,3,3)
+    imshow(app.ARTimage, [])
+    title('ART output')
+  end
+
+  function sfBadButtonFunction(varargin)
+    bad=1;
+    done=1;
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'bad', 'done','-append');
+    app.quit=1;
+    done=0;
+    close
+  end
+
+  function sfAcceptButtonFunction(varargin)
+    %launch full ART reconstruction
+    done=1;
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'done','-append');
+    done=0;
+    gtDoART(grainid);
+    app.quit=1;
+    close
+  end
+
+  function sfExitButtonFunction(varargin)
+    %finish without changes
+    done=1;
+    app.quit=1;
+    close
+  end
+
+
+
+end
+
diff --git a/5_reconstruction/gtReconstructionManager3D.m b/5_reconstruction/gtReconstructionManager3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..175402fbf294f621adc5c3ea1ee762db52994bb7
--- /dev/null
+++ b/5_reconstruction/gtReconstructionManager3D.m
@@ -0,0 +1,31 @@
+function gtReconstructionManager3D(grainid)
+  app=[];
+
+  if grainid<0
+    sfCreateData
+  else
+    sfReadData(grainid)
+  end
+
+  sfSetupFigure
+  sfUpdateFigure
+
+
+
+  function sfCreateData
+  end
+
+  function sfReadData(grainid)
+  end
+
+  function sfSetupFigure
+    warning('off','Images:initSize:adjustingMag');
+    warning('off','Images:imshow:magnificationMustBeFitForDockedFigure');
+    warning('off','MATLAB:divideByZero')
+
+  end
+
+  function sfUpdateFigure
+  end
+
+end
diff --git a/5_reconstruction/gtReconstructionManager_360.m b/5_reconstruction/gtReconstructionManager_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..392c11e8eab55c02c81e5ebf797c467a1fb2ea60
--- /dev/null
+++ b/5_reconstruction/gtReconstructionManager_360.m
@@ -0,0 +1,665 @@
+%GUI to choose art params, select and replace reflections, and fix bounding
+%boxes...
+%like gtnew_new_choose_art...  but better!
+
+%loop through a series of grains
+
+%don't worry about pair_vectors
+%360 degree concept
+
+
+function gtReconstructionManager_360(grainid,autoselect)
+
+  parameters=[];
+  load parameters;
+  gtDBConnect;
+
+  block='on'; %don't return the command line until the user is finished
+  
+  % modif for Peter K. 
+  if ~exist('autoselect','var')
+    autoselect=1
+  end  
+  
+  
+    %%%%%%%%%%%%%%%%%
+  %remove bad projections automatically
+  % do this before starting the manager, so index information is up to date
+  if autoselect
+    try %licence check
+  gt_select_projections_auto(grainid)
+  pause(1)
+  close; close;
+    catch
+      disp('no optimisation licence available')
+    end
+  else
+    disp('auto selection of projections disabled')
+  end
+  %%%%%%%%%%%%%%%%%
+  
+  
+  
+  
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %read in data, sort for convinience
+  g=load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+  struct_ids=g.struct_ids;
+
+  if isfield(g, 'bad') && g.bad>=1
+    disp(sprintf('grain %d is already set to bad=%d',grainid, g.bad))
+    return
+  end
+  
+  if isfield(g, 'done') && g.done==1
+    check=inputwdefault(sprintf('grain %d already been done! Do you want to proceed anyway? y/n',grainid), 'n');
+    if check=='n'
+    return
+    end
+  end
+
+
+  %if it doesn't already exist, add an index, replaced
+  if isfield(g, 'index')
+    index=g.index;
+  else
+    index = ones(1,length(struct_ids));
+  end
+  if isfield(g, 'replaced')
+    replaced=g.replaced;
+  else
+    replaced = zeros(1,length(struct_ids));
+  end
+  if isfield(g, 'bad')
+    bad=g.bad;
+  else
+    bad=0;
+  end
+  %estimate art parameters
+  %  I have the impression that for the sheared difspots we need smaller
+  %  values here (less but better projections typically...)  Try...
+  if length(struct_ids)>45
+    lambda = [0.1 0.05 0.02];
+  elseif length(struct_ids)>30
+    %lambda = [0.3 0.2 0.1]; %initial values
+    lambda = [0.2 0.1 0.05]; %initial values - sheared difspots
+  elseif length(struct_ids)>15
+    %lambda = [0.5 0.3 0.1]; %initial values
+    lambda = [0.3 0.2 0.1]; %initial values - sheared difspots
+  else
+    %lambda = [0.7 0.3 0.2]; %initial values
+    lambda = [0.4 0.25 0.15]; %initial values - sheared difspots
+  end
+
+  %unpacking...
+  Omega=g.Omega;Theta=g.Theta;Eta=g.Eta;
+  plane_normal=g.plane_normal;hkl=g.hkl;
+  stack=g.stack;
+  %for editable ART bounding box
+  x1 = g.x1;
+  y1 = g.y1;
+  nx = g.nx;
+  ny = g.ny;
+
+
+  %do the sorting by Omega
+  [Omega,tmp]=sort(Omega);
+
+  %if we need to, sort other fields, save, and rewrite stack to ART input
+  if ~all(tmp==1:length(Omega))
+
+    Theta = Theta(tmp);
+    Eta = Eta(tmp);
+    struct_ids = struct_ids(tmp);
+    plane_normal = plane_normal(tmp,:);
+    hkl = hkl(tmp,:);
+    stack = stack(:,:,tmp);
+    index = index(tmp);
+    replaced = replaced(tmp);
+
+    %save in new order
+
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),...
+      'struct_ids','stack','Theta','Eta','Omega','plane_normal','hkl',...
+      'index','replaced','bad','-append');
+    
+    gtWriteStack_360(grainid, 0);%write the stack in new order, don't replace projections by default
+  end
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  
+
+  
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %Now the interactive part
+  refresh=1;
+
+  app.quit=0;
+
+  %setup the figures
+  
+  scrsz = get(0,'ScreenSize');
+
+  fig_handle=figure;
+   set(fig_handle, 'Position',[50 150 0.75*scrsz(3) .75*scrsz(4)]);
+   
+  StackAxes=subplot(1,3,1);%stack image
+
+  app.stack_slider=uicontrol('style', 'slider');
+  set(app.stack_slider, 'callback', @sfSliderFunction)
+  set(fig_handle,'windowbuttonmotionfcn',@sfSliderFunction)
+  set(fig_handle,'windowbuttondownfcn',@sfTestFunction) %@sfSliderFunction)
+  set(fig_handle,'windowbuttonupfcn',@sfSliderFunction)
+  
+  set(app.stack_slider,'units','normalized');
+  set(app.stack_slider,'position',[0 0 .4 0.05])
+  set(app.stack_slider,'min',1,'max',size(stack,3),'sliderstep',[1/size(stack,3) 1/size(stack,3)]);
+  set(app.stack_slider,'value',1);
+  imshow(stack(:,:,1), [])
+  app.currentImage=1;
+
+
+  BackproAxes=subplot(1,3,2);%crude backpro image
+  %set(fig_handle, 'windowbuttondownfcn', @sfDragBBFunction1)
+  %set(fig_handle, 'windowbuttonupfcn', @sfDragBBFunction2)
+  %set(BackproAxes, 'ButtonDownFcn', @sfDragBBFunction1)
+  title('click to change ART bb')
+
+
+  
+  
+  
+  buttongroup=uibuttongroup('Position', [.4 0 .6 .05]);
+
+  UseButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'use', 'position', [0 0 50 20]);
+  set(UseButton, 'callback', @sfUseButtonFunction)
+    
+  UseAllButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'use all', 'position', [50 0 50 20]);
+  set(UseAllButton, 'callback', @sfUseAllButtonFunction)
+  
+  ReplaceButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'replace', 'position', [100 0 50 20]);
+  set(ReplaceButton, 'callback', @sfReplaceButtonFunction)
+  
+  ReplaceAllButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'replace all', 'position', [150 0 80 20]);
+  set(ReplaceAllButton, 'callback', @sfReplaceAllButtonFunction)
+ 
+  ARTButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'Do ART', 'position', [230 0 50 20]);
+  set(ARTButton, 'callback', @sfARTButtonFunction)
+
+  lambdastring=num2str(lambda);
+  lambdastring=lambdastring([1:4 13:16 25:27]);
+
+  LambdaBox=uicontrol(buttongroup, 'Style', 'edit', 'String', lambdastring, 'position', [280 0 70 20]);
+
+  BadButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'bad grain', 'position', [350 0 50 20]);
+  set(BadButton, 'callback', @sfBadButtonFunction)
+  AcceptButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'ACCEPT!', 'position', [400 0 50 20]);
+  set(AcceptButton, 'callback', @sfAcceptButtonFunction)
+
+
+%add a button to escape without making changes
+    exitbuttongroup=uibuttongroup('Position', [.85 .95 .15 .05]);
+  ExitButton=uicontrol(exitbuttongroup, 'Style', 'pushbutton', 'string', 'quit, no changes', 'position', [0 0 100 20]);
+  set(ExitButton, 'callback', @sfExitButtonFunction)
+    
+  
+
+  %make overlays for backproim, prepare a big image to show in the left
+  %hand window
+  %get max range of spots
+  tmp=sum(sum(stack, 3), 2);
+  first=min(find(tmp));
+  last=max(find(tmp));
+  range=last-first+1;
+  big_image=zeros((size(stack,3)+6)*range, size(stack,2)); %pad by three images top and bottom
+  app.overlays=zeros([size(stack,2), size(stack,2), size(stack,3)]);
+  %collect sino
+  for i=1:size(stack,3)
+    sino(:,i) = stack(g.zcenter, :, i)';
+    big_image(((i+2)*range)+1:(i+3)*range, :) =  stack(first:last,:,i);
+  end
+  binsino=sino>0;
+  for i=1:size(stack,3)
+    app.overlays(:,:,i)=backpro(binsino(:,i),Omega(i)*pi/180);
+    app.centroidx(i) = sino(:,i)'*(1:size(sino,1))'/sum(sino(:,i));
+  end
+  app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+
+
+
+
+
+  ARTAxes=subplot(1,3,3);
+  sfSliderFunction
+  sfARTButtonFunction %first "press" of the button
+
+  if strcmp(block,'on')
+    % if user wants nothing to return until findshift is finished
+    while 1
+      drawnow
+      if app.quit==1
+        break
+      end
+    end
+  end
+
+
+    function sfTestFunction(varargin)%which subfunction should the button down go to?
+        if isequal(gco,app.stack_slider)
+            sfSliderFunction
+        elseif isequal(gca,BackproAxes)
+        sfDragBBFunction1
+        end
+    end
+
+        
+  
+
+  function sfSliderFunction(varargin)
+
+    if (isequal(gco,app.stack_slider) || refresh)
+      tmp=round(get(app.stack_slider,'value'));
+      if (tmp~=app.currentImage | refresh)
+          
+        subplot(1,3,1)% update stack figure
+        hold off
+        app.currentImage=tmp;
+        %get 7 image subsection of big_image
+        im_start=((app.currentImage-1)*range)+1;
+        im_end=(app.currentImage+6)*range;
+        
+        imshow(big_image(im_start:im_end, :), [])
+        hold on
+        %highlight current image
+        xdata=[1 size(big_image,2) size(big_image, 2) 1 1];
+        ydata=[(3*range)+1 (3*range)+1 4*range 4*range (3*range)+1];
+        %adjust line colour according to index
+        
+        if index(app.currentImage)==1 %if using, green
+        plot(xdata, ydata, 'g');
+        else %if not using, red
+        plot(xdata, ydata, 'r');    
+        end
+        
+        title(sprintf('id: %d, use: %d, replaced: %d', struct_ids(app.currentImage), index(app.currentImage), replaced(app.currentImage)))
+        drawnow
+
+        subplot(1,3,2)% update backpro image overlay
+        hold off
+        imshow(app.BPimage, []); %show the first backprojection
+        %colormap jet
+        hold on
+        title('click to change ART bb')
+        
+        if 0 %if alpha thing is working?
+          app.BPoverlay=zeros([size(app.BPimage) 3]);
+          %adjust overlay colour according to index
+          if index(app.currentImage)==1 %if using, green
+            app.BPoverlay(:,:,2)=app.overlays(:,:,app.currentImage);
+          else %if not using, red
+            app.BPoverlay(:,:,1)=app.overlays(:,:,app.currentImage);
+          end
+          app.BPoverlay=image(app.BPoverlay, 'XData', [1:size(app.BPimage,2)], 'YData', [1:size(app.BPimage,1)]);
+          set(app.BPoverlay, 'AlphaData', 0.04*ones(size(app.BPimage)))
+
+         %%%%%%%%  alternative display mode if alpha overlay isn't working
+       else %plot a simple line over the current projection
+          
+          spot_com=app.centroidx(app.currentImage);
+          spot_omega=Omega(app.currentImage)*pi/180; %Omega in degreees
+          %experiment parameters
+          centre_of_backproimg_x = parameters.acq.bb(3)/2;
+          centre_of_backproimg_y = parameters.acq.bb(3)/2;
+          point=[centre_of_backproimg_x, centre_of_backproimg_y];
+          %make line parameters
+          grad=1/tan(spot_omega);
+          %dist of com line from centre
+          offset_com=spot_com-parameters.acq.bb(3)/2;
+          %centre point of line though the projection
+          point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+          %put into format y = mx + c
+          m = grad;
+          c = point(2) - (m*point(1));
+          ez_line=ezplot(sprintf('%f*x + %f - y = 0',m,c),[1 parameters.acq.bb(3)]);
+          
+          if index(app.currentImage)==1 %if using, green
+          set(ez_line,'color','g');
+          else %if not using, red
+          set(ez_line, 'color', 'r');
+          end
+            
+        end
+        
+        
+        
+        refresh=0;
+      end
+    end
+  end
+
+  %drag out a new bounding box
+  function sfDragBBFunction1(varargin)
+      
+
+     %      point1 = get(BackproAxes,'CurrentPoint'); % button down detected
+     %point1=point1(1, 1:2)      
+    %       pointx=point1(1, 1);
+    %       pointy=point1(1, 2);
+    %       if pointx>0 && pointx<size(app.BPimage,2) && pointy>0 && pointy<size(app.BPimage,2) %if point within image
+    %           app.newx1=ceil(pointx);
+    %           app.newy1=ceil(pointy);
+    %       end
+    p1 = get(BackproAxes,'CurrentPoint');
+    p1=p1(1, 1:2);
+    bbox=rbbox;
+    p2 = get(BackproAxes,'CurrentPoint');
+    p2=p2(1, 1:2);
+    point1=min(p1, p2);
+    offset=abs(p1-p2);
+    
+    pointx1=point1(1);
+    pointy1=point1(2);
+    pointx2=point1(1)+offset(1);
+    pointy2=point1(2)+offset(2);
+    points=[pointx1 pointy1 pointx2 pointy2];
+    
+
+    if all(points>-10 & points<size(app.BPimage,2)+10) %if both points ~within image
+      %correct if point is slightly outside image
+      if pointx1<1
+          pointx1=1;
+      end
+      if pointy1<1
+          pointy1=1;
+      end
+      if pointx2>size(app.BPimage,2)
+          pointx2=size(app.BPimage,2);
+      end
+      if pointy2>size(app.BPimage,2)
+          pointy2=size(app.BPimage,2);
+      end
+      x1=ceil(pointx1);
+      y1=ceil(pointy1);
+      nx=ceil(pointx2-x1);
+      ny=ceil(pointy2-y1);
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'x1', 'y1', 'nx', 'ny', '-append');
+      sfARTButtonFunction %rerun ART
+    end
+
+  end
+
+  %     function sfDragBBFunction2(varargin)
+  %         point1 = get(BackproAxes,'CurrentPoint'); % button up detected
+  %         pointx=point1(1, 1);
+  %         pointy=point1(1, 2);
+  %         if pointx>0 && pointx<size(app.BPimage,2) && pointy>0 && pointy<size(app.BPimage,2) %if point within image
+  %             x1=app.newx1;
+  %             y1=app.newy1;
+  %             nx=ceil(pointx-x1);
+  %             ny=ceil(pointy-y1);
+  %             save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'x1', 'y1', 'nx', 'ny', '-append');
+  %             sfARTButtonFunction %rerun ART
+  %         end
+  %     end
+
+
+  %%%sf to replace a projection
+  function sfReplaceButtonFunction(varargin)
+    %change replaced
+    replaced(app.currentImage)=~replaced(app.currentImage);
+
+      name=parameters.acq.name;
+
+
+    %update stack with extspot / difspot
+    if replaced(app.currentImage)==0 %extspot case
+
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+        'where %sbb.extspotID = %d'],...
+        name, name, name, name, name,...
+        struct_ids(app.currentImage))
+
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      im = gtGetSummedExtSpot_360(struct_ids(app.currentImage), parameters);
+
+      %place in stack
+      stack(:,:,app.currentImage) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,app.currentImage)= 100*stack(:,:,app.currentImage)/sum(sum(stack(:,:,app.currentImage)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,app.currentImage) = stack(g.zcenter,:,app.currentImage);
+      
+    else %extspot replaced by difspot
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+        'where %sbboxes.extspotID = %d'],...
+        name, name, name,...
+        struct_ids(app.currentImage))
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      warning('bodge because some SearchBoundingBoxes have zero origins')
+      if BoundingBox(1)==0
+        BoundingBox(1)=1;
+      end
+      if BoundingBox(2)==0
+        BoundingBox(2)=1;
+      end
+
+      im = gtGetSummedDifSpot(struct_ids(app.currentImage), parameters);
+
+      %place in stack
+      stack(:,:,app.currentImage) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,app.currentImage)= 100*stack(:,:,app.currentImage)/sum(sum(stack(:,:,app.currentImage)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,app.currentImage) = stack(g.zcenter,:,app.currentImage);
+    
+    end
+
+    %rewrite the changed projection .sdt
+    name=sprintf('4_grains/grain%d_/grain%d_%d.sdt',grainid, grainid, app.currentImage);
+    fid=fopen(name,'wb','l');
+    stack(:,:,app.currentImage)=medfilt2(stack(:,:,app.currentImage));
+    fwrite(fid,stack(:,:,app.currentImage)','float32');
+    fclose(fid);
+    %no need to rewrite .spr
+    % name=sprintf('4_grains/grain%d_/grain%d_%d.spr',grainid, grainid, app.currentImage)
+    % %name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+    % spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'replaced','-append');
+    %redo backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    %update big image
+    big_image(((app.currentImage+2)*range)+1:(app.currentImage+3)*range, :) =  stack(first:last,:,app.currentImage);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+%%%sf to replace all/none of the projections
+  function sfReplaceAllButtonFunction(varargin)
+  %change replaced to be all the same as the first image
+  if replaced(1)==1
+    replaced=zeros(size(replaced));
+  else
+    replaced=ones(size(replaced));
+  end
+  
+  for i=1:length(replaced)%replace all projections...
+    
+  name=parameters.acq.name;
+      %update stack with extspot / difspot
+    if replaced(i)==0 %extspot case
+
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+        'where %sbb.extspotID = %d'],...
+        name, name, name, name, name,...
+        struct_ids(i))
+
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      im = gtGetSummedExtSpot_360_wl(struct_ids(i), parameters);
+
+      %place in stack
+      stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,i) = stack(g.zcenter,:,i);
+      
+    else %extspot replaced by difspot
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+        'where %sbboxes.extspotID = %d'],...
+        name, name, name,...
+        struct_ids(i))
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      warning('bodge because some SearchBoundingBoxes have zero origins')
+      if BoundingBox(1)==0
+        BoundingBox(1)=1;
+      end
+      if BoundingBox(2)==0
+        BoundingBox(2)=1;
+      end
+
+      im = gtGetSummedDifSpot(struct_ids(i), parameters);
+
+      %place in stack
+      stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,i) = stack(g.zcenter,:,i);
+    
+    end
+
+    %rewrite the changed projection .sdt
+    name=sprintf('4_grains/grain%d_/grain%d_%d.sdt',grainid, grainid, i);
+    fid=fopen(name,'wb','l');
+    stack(:,:,i)=medfilt2(stack(:,:,i));
+    fwrite(fid,stack(:,:,i)','float32');
+    fclose(fid);
+    %no need to rewrite .spr
+    
+    %update big image
+  big_image(((i+2)*range)+1:(i+3)*range, :) =  stack(first:last,:,i);
+  
+  end%loop over all spots
+    
+  save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'replaced','-append');
+  
+  %redo backprojection
+  app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+  refresh=1;% update the backpro figure
+  sfSliderFunction;
+  disp('finished')
+  
+  end
+
+
+  %%%sf to use/not use a projection
+  function sfUseButtonFunction(varargin)
+    index(app.currentImage)=~index(app.currentImage);
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'index','-append');
+    %redo the backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+
+  %%%sf to use/not use all projections
+  function sfUseAllButtonFunction(varargin)
+      if all(index==1)
+          index=zeros(size(index));
+      else
+          index=ones(size(index));
+      end
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'index','-append');
+    %redo the backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+  %%subfunction for doing ART on a central section of the grain to test
+  %%parameters
+  function sfARTButtonFunction(varargin)
+    %first read the string in LambdaBox
+    lambdastringnew=get(LambdaBox, 'String');
+    lambdastringnew=['[ ' lambdastringnew ' ]'];
+    lambdanew=str2num(lambdastringnew);
+    if length(lambdanew)==3
+      lambda=lambdanew;
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'lambda','-append');
+    end
+
+    scanname = sprintf('4_grains/grain%d_/grain%d_',grainid,grainid);
+    parfilename = sprintf('4_grains/grain%d_/grain%d_.par',grainid,grainid);
+    z1_sub = g.zcenter-2;
+    nz_sub = 5; %do 5 slices (more representative)
+    nbiter = 3;
+    pixsize = 1;
+    braggangle = 0;
+    np = parameters.acq.bb(3);
+    nq = parameters.acq.bb(4);
+    offset = 0;
+
+    rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+    seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+    p_angles = -Omega(find(index));
+    p_numbers = find(index);
+%    keyboard
+    gtMakeARTJob(scanname,parfilename,p_numbers,p_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset, ...
+      z1_sub,nz_sub,x1,nx,y1,ny);
+
+    command=sprintf('%s %s',rec_alg,parfilename);
+    [s,w]=unix(command);
+    command=sprintf('%s %s_res0_%d',seg2view,scanname,nbiter);
+    [s,w]=unix(command);
+    name=sprintf('%s_res0_%d.sdt',scanname,nbiter);
+    im=volread(name,'float32',0,nx,ny,nz_sub,'l');
+
+    app.ARTimage = im(:,:,ceil(nz_sub/2))';%collect middle slice
+
+    subplot(1,3,3)
+    imshow(app.ARTimage, [])
+    title('ART output')
+  end
+
+  function sfBadButtonFunction(varargin)
+    bad=1;
+    done=1;
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'bad', 'done','-append');
+    app.quit=1;
+    done=0;
+    close
+  end
+
+  function sfAcceptButtonFunction(varargin)
+    %launch full ART reconstruction
+    done=1;
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'stack', 'done','-append');
+    done=0;
+    gtDoART(grainid);
+    app.quit=1;
+    close
+  end
+
+  function sfExitButtonFunction(varargin)
+    %finish without changes
+    done=1;
+    app.quit=1;
+    close
+  end
+
+
+
+end
+
diff --git a/5_reconstruction/gtReconstructionManager_360_wl.m b/5_reconstruction/gtReconstructionManager_360_wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..17cebe6f6d9373704635a306f10f7df28fc171db
--- /dev/null
+++ b/5_reconstruction/gtReconstructionManager_360_wl.m
@@ -0,0 +1,663 @@
+%GUI to choose art params, select and replace reflections, and fix bounding
+%boxes...
+%like gtnew_new_choose_art...  but better!
+
+%loop through a series of grains
+
+%don't worry about pair_vectors
+%360 degree concept
+
+
+function img=gtReconstructionManager_360(grainid,varargin)
+
+  parameters=[];
+  load parameters.mat;
+  gtDBConnect;
+
+  
+  
+  block='on'; %don't return the command line until the user is finished
+
+  
+  
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %read in data, sort for convinience
+  g=load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+  struct_ids=g.struct_ids;
+
+  
+  if nargin==2
+    g.zcenter=varargin{1};
+  end
+  
+  if isfield(g, 'bad') && g.bad>=1
+    disp(sprintf('grain %d is already set to bad=%d',grainid, g.bad))
+    return
+  end
+  
+  if isfield(g, 'done') && g.done==1
+    check=inputwdefault(sprintf('grain %d already been done! Do you want to proceed anyway? y/n',grainid), 'n');
+    if check=='n'
+    return
+    end
+  end
+
+
+  %if it doesn't already exist, add an index, replaced
+  if isfield(g, 'index')
+    index=g.index;
+  else
+    index = ones(1,length(struct_ids));
+  end
+  if isfield(g, 'replaced')
+    replaced=g.replaced;
+  else
+    replaced = zeros(1,length(struct_ids));
+  end
+  if isfield(g, 'bad')
+    bad=g.bad;
+  else
+    bad=0;
+  end
+  %estimate art parameters
+  if isfield(g, 'lambda')
+	lambda=g.lambda;
+  else
+	if length(struct_ids)>45
+	  lambda = [0.1 0.05 0.02];
+	elseif length(struct_ids)>30
+	  lambda = [0.2 0.1 0.05]; %initial values
+	elseif length(struct_ids)>15
+	  lambda = [0.3 0.2 0.1]; %initial values
+	else
+	  lambda = [0.5 0.3 0.2]; %initial values
+	end
+  end
+  %unpacking...
+  Omega=g.Omega;Theta=g.Theta;Eta=g.Eta;
+  plane_normal=g.plane_normal;hkl=g.hkl;
+  stack=g.stack;
+  %for editable ART bounding box
+  x1 = g.x1;
+  y1 = g.y1;
+  nx = g.nx;
+  ny = g.ny;
+
+
+  %do the sorting by Omega
+  [Omega,tmp]=sort(Omega);
+
+  %if we need to, sort other fields, save, and rewrite stack to ART input
+  if ~all(tmp==1:length(Omega))
+
+    Theta = Theta(tmp);
+    Eta = Eta(tmp);
+    struct_ids = struct_ids(tmp);
+    plane_normal = plane_normal(tmp,:);
+    hkl = hkl(tmp,:);
+    stack = stack(:,:,tmp);
+    index = index(tmp);
+    replaced = replaced(tmp);
+
+    %save in new order
+
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),...
+      'struct_ids','stack','Theta','Eta','Omega','plane_normal','hkl',...
+      'index','replaced','bad','-append');
+    
+    gtWriteStack_360(grainid, 0);%write the stack in new order, don't replace projections by default
+  end
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  
+  %%%%%%%%%%%%%%%%%
+  %remove bad projections automatically
+  if 0
+  gt_select_projections_auto(grainid)
+  pause(1)
+  close; close;
+  else
+    disp('auto selection of projections disabled')
+  end
+  %%%%%%%%%%%%%%%%%
+  
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %Now the interactive part
+  refresh=1;
+
+  app.quit=0;
+  clims=[0 median(max(max(stack)))];
+  
+  %clims=
+  %setup the figures
+  
+  scrsz = get(0,'ScreenSize');
+
+  fig_handle=figure;
+   set(fig_handle, 'Position',[50 150 0.75*scrsz(3) .75*scrsz(4)]);
+   
+  StackAxes=subplot(1,3,1);%stack image
+
+  app.stack_slider=uicontrol('style', 'slider');
+  set(app.stack_slider, 'callback', @sfSliderFunction)
+  set(fig_handle,'windowbuttonmotionfcn',@sfSliderFunction)
+  set(fig_handle,'windowbuttondownfcn',@sfTestFunction) %@sfSliderFunction)
+  set(fig_handle,'windowbuttonupfcn',@sfSliderFunction)
+  
+  set(app.stack_slider,'units','normalized');
+  set(app.stack_slider,'position',[0 0 .4 0.05])
+  set(app.stack_slider,'min',1,'max',size(stack,3),'sliderstep',[1/size(stack,3) 1/size(stack,3)]);
+  set(app.stack_slider,'value',1);
+  imshow(stack(:,:,1), clims)
+  app.currentImage=1;
+
+
+  BackproAxes=subplot(1,3,2);%crude backpro image
+  %set(fig_handle, 'windowbuttondownfcn', @sfDragBBFunction1)
+  %set(fig_handle, 'windowbuttonupfcn', @sfDragBBFunction2)
+  %set(BackproAxes, 'ButtonDownFcn', @sfDragBBFunction1)
+  title('click to change ART bb')
+
+
+  
+  
+  
+  buttongroup=uibuttongroup('Position', [.4 0 .6 .05]);
+
+  UseButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'use', 'position', [0 0 50 20]);
+  set(UseButton, 'callback', @sfUseButtonFunction)
+    
+  UseAllButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'use all', 'position', [50 0 50 20]);
+  set(UseAllButton, 'callback', @sfUseAllButtonFunction)
+  
+  ReplaceButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'replace', 'position', [100 0 50 20]);
+  set(ReplaceButton, 'callback', @sfReplaceButtonFunction)
+  
+  ReplaceAllButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'replace all', 'position', [150 0 80 20]);
+  set(ReplaceAllButton, 'callback', @sfReplaceAllButtonFunction)
+ 
+  ARTButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'Do ART', 'position', [230 0 50 20]);
+  set(ARTButton, 'callback', @sfARTButtonFunction)
+
+  lambdastring=num2str(lambda);
+  lambdastring=lambdastring([1:4 13:16 25:27]);
+
+  LambdaBox=uicontrol(buttongroup, 'Style', 'edit', 'String', lambdastring, 'position', [280 0 70 20]);
+
+  BadButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'bad grain', 'position', [350 0 50 20]);
+  set(BadButton, 'callback', @sfBadButtonFunction)
+  AcceptButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'ACCEPT!', 'position', [400 0 50 20]);
+  set(AcceptButton, 'callback', @sfAcceptButtonFunction)
+
+
+%add a button to escape without making changes
+    exitbuttongroup=uibuttongroup('Position', [.85 .95 .15 .05]);
+  ExitButton=uicontrol(exitbuttongroup, 'Style', 'pushbutton', 'string', 'quit, no changes', 'position', [0 0 100 20]);
+  set(ExitButton, 'callback', @sfExitButtonFunction)
+    
+  
+
+  %make overlays for backproim, prepare a big image to show in the left
+  %hand window
+  %get max range of spots
+  tmp=sum(sum(stack, 3), 2);
+  first=min(find(tmp));
+  last=max(find(tmp));
+  range=last-first+1;
+  big_image=zeros((size(stack,3)+6)*range, size(stack,2)); %pad by three images top and bottom
+  app.overlays=zeros([size(stack,2), size(stack,2), size(stack,3)]);
+  %collect sino
+  for i=1:size(stack,3)
+    sino(:,i) = stack(g.zcenter, :, i)';
+    big_image(((i+2)*range)+1:(i+3)*range, :) =  stack(first:last,:,i);
+  end
+  binsino=sino>0;
+  for i=1:size(stack,3)
+    app.overlays(:,:,i)=backpro(binsino(:,i),Omega(i)*pi/180);
+    app.centroidx(i) = sino(:,i)'*(1:size(sino,1))'/sum(sino(:,i));
+  end
+  app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+
+
+
+
+
+  ARTAxes=subplot(1,3,3);
+  sfSliderFunction
+  sfARTButtonFunction %first "press" of the button
+
+  if strcmp(block,'on')
+    % if user wants nothing to return until findshift is finished
+    while 1
+      drawnow
+      if app.quit==1
+        break
+      end
+    end
+  end
+
+
+    function sfTestFunction(varargin)%which subfunction should the button down go to?
+        if isequal(gco,app.stack_slider)
+            sfSliderFunction
+        elseif isequal(gca,BackproAxes)
+        sfDragBBFunction1
+        end
+    end
+
+        
+  
+
+  function sfSliderFunction(varargin)
+
+    if (isequal(gco,app.stack_slider) || refresh)
+      tmp=round(get(app.stack_slider,'value'));
+      if (tmp~=app.currentImage | refresh)
+          
+        subplot(1,3,1)% update stack figure
+        hold off
+        app.currentImage=tmp;
+        %get 7 image subsection of big_image
+        im_start=((app.currentImage-1)*range)+1;
+        im_end=(app.currentImage+6)*range;
+        
+        imshow(big_image(im_start:im_end, :), [clims])
+        hold on
+        %highlight current image
+        xdata=[1 size(big_image,2) size(big_image, 2) 1 1];
+        ydata=[(3*range)+1 (3*range)+1 4*range 4*range (3*range)+1];
+        %adjust line colour according to index
+        
+        if index(app.currentImage)==1 %if using, green
+        plot(xdata, ydata, 'g');
+        else %if not using, red
+        plot(xdata, ydata, 'r');    
+        end
+        
+        title(sprintf('id: %d, use: %d, replaced: %d', struct_ids(app.currentImage), index(app.currentImage), replaced(app.currentImage)))
+        drawnow
+
+        subplot(1,3,2)% update backpro image overlay
+        hold off
+        imshow(app.BPimage, []); %show the first backprojection
+        %colormap jet
+        hold on
+        title('click to change ART bb')
+        
+        if 0 %if alpha thing is working?
+        app.BPoverlay=zeros([size(app.BPimage) 3]);
+        %adjust overlay colour according to index
+        if index(app.currentImage)==1 %if using, green
+        app.BPoverlay(:,:,2)=app.overlays(:,:,app.currentImage);
+        else %if not using, red
+        app.BPoverlay(:,:,1)=app.overlays(:,:,app.currentImage);
+        end
+        app.BPoverlay=image(app.BPoverlay, 'XData', [1:size(app.BPimage,2)], 'YData', [1:size(app.BPimage,1)]);
+        set(app.BPoverlay, 'AlphaData', 0.04*ones(size(app.BPimage)))
+
+         %%%%%%%%  alternative display mode if alpha overlay isn't working
+       else %plot a simple line over the current projection
+          
+          spot_com=app.centroidx(app.currentImage);
+          spot_omega=Omega(app.currentImage)*pi/180; %Omega in degreees
+          %experiment parameters
+          centre_of_backproimg_x = parameters.acq.bb(3)/2;
+          centre_of_backproimg_y = parameters.acq.bb(3)/2;
+          point=[centre_of_backproimg_x, centre_of_backproimg_y];
+          %make line parameters
+          grad=1/tan(spot_omega);
+          %dist of com line from centre
+          offset_com=spot_com-parameters.acq.bb(3)/2;
+          %centre point of line though the projection
+          point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+          %put into format y = mx + c
+          m = grad;
+          c = point(2) - (m*point(1));
+          ez_line=ezplot(sprintf('%f*x + %f - y = 0',m,c),[1 parameters.acq.bb(3)]);
+          
+          if index(app.currentImage)==1 %if using, green
+          set(ez_line,'color','g');
+          else %if not using, red
+          set(ez_line, 'color', 'r');
+          end
+            
+        end
+        
+        
+        
+        refresh=0;
+      end
+    end
+  end
+
+  %drag out a new bounding box
+  function sfDragBBFunction1(varargin)
+      
+
+     %      point1 = get(BackproAxes,'CurrentPoint'); % button down detected
+     %point1=point1(1, 1:2)      
+    %       pointx=point1(1, 1);
+    %       pointy=point1(1, 2);
+    %       if pointx>0 && pointx<size(app.BPimage,2) && pointy>0 && pointy<size(app.BPimage,2) %if point within image
+    %           app.newx1=ceil(pointx);
+    %           app.newy1=ceil(pointy);
+    %       end
+    p1 = get(BackproAxes,'CurrentPoint');
+    p1=p1(1, 1:2);
+    bbox=rbbox;
+    p2 = get(BackproAxes,'CurrentPoint');
+    p2=p2(1, 1:2);
+    point1=min(p1, p2);
+    offset=abs(p1-p2);
+    
+    pointx1=point1(1);
+    pointy1=point1(2);
+    pointx2=point1(1)+offset(1);
+    pointy2=point1(2)+offset(2);
+    points=[pointx1 pointy1 pointx2 pointy2];
+    
+
+    if all(points>-10 & points<size(app.BPimage,2)+10) %if both points ~within image
+      %correct if point is slightly outside image
+      if pointx1<1
+          pointx1=1;
+      end
+      if pointy1<1
+          pointy1=1;
+      end
+      if pointx2>size(app.BPimage,2)
+          pointx2=size(app.BPimage,2);
+      end
+      if pointy2>size(app.BPimage,2)
+          pointy2=size(app.BPimage,2);
+      end
+      x1=ceil(pointx1);
+      y1=ceil(pointy1);
+      nx=ceil(pointx2-x1);
+      ny=ceil(pointy2-y1);
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'x1', 'y1', 'nx', 'ny', '-append');
+      sfARTButtonFunction %rerun ART
+    end
+
+  end
+
+  %     function sfDragBBFunction2(varargin)
+  %         point1 = get(BackproAxes,'CurrentPoint'); % button up detected
+  %         pointx=point1(1, 1);
+  %         pointy=point1(1, 2);
+  %         if pointx>0 && pointx<size(app.BPimage,2) && pointy>0 && pointy<size(app.BPimage,2) %if point within image
+  %             x1=app.newx1;
+  %             y1=app.newy1;
+  %             nx=ceil(pointx-x1);
+  %             ny=ceil(pointy-y1);
+  %             save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'x1', 'y1', 'nx', 'ny', '-append');
+  %             sfARTButtonFunction %rerun ART
+  %         end
+  %     end
+
+
+  %%%sf to replace a projection
+  function sfReplaceButtonFunction(varargin)
+    %change replaced
+    replaced(app.currentImage)=~replaced(app.currentImage);
+
+      name=parameters.acq.name;
+
+
+    %update stack with extspot / difspot
+    if replaced(app.currentImage)==0 %extspot case
+
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+        'where %sbb.extspotID = %d'],...
+        name, name, name, name, name,...
+        struct_ids(app.currentImage))
+
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      im = gtGetSummedExtSpot_360_wl(struct_ids(app.currentImage), parameters);
+
+      %place in stack
+      stack(:,:,app.currentImage) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      
+      stack(:,:,app.currentImage)= 100*stack(:,:,app.currentImage)/sum(sum(stack(:,:,app.currentImage)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,app.currentImage) = stack(g.zcenter,:,app.currentImage);
+      
+    else %extspot replaced by difspot
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+        'where %sbboxes.extspotID = %d'],...
+        name, name, name,...
+        struct_ids(app.currentImage))
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      warning('bodge because some SearchBoundingBoxes have zero origins')
+      if BoundingBox(1)==0
+        BoundingBox(1)=1;
+      end
+      if BoundingBox(2)==0
+        BoundingBox(2)=1;
+      end
+
+      im = gtGetSummedDifSpot(struct_ids(app.currentImage), parameters);
+
+      %place in stack
+      stack(:,:,app.currentImage) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,app.currentImage)= 100*stack(:,:,app.currentImage)/sum(sum(stack(:,:,app.currentImage)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,app.currentImage) = stack(g.zcenter,:,app.currentImage);
+    
+    end
+
+    %rewrite the changed projection .sdt
+    name=sprintf('4_grains/grain%d_/grain%d_%d.sdt',grainid, grainid, app.currentImage);
+    fid=fopen(name,'wb','l');
+    stack(:,:,app.currentImage)=medfilt2(stack(:,:,app.currentImage));
+    fwrite(fid,stack(:,:,app.currentImage)','float32');
+    fclose(fid);
+    %no need to rewrite .spr
+    % name=sprintf('4_grains/grain%d_/grain%d_%d.spr',grainid, grainid, app.currentImage)
+    % %name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+    % spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'replaced','-append');
+    %redo backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    %update big image
+    big_image(((app.currentImage+2)*range)+1:(app.currentImage+3)*range, :) =  stack(first:last,:,app.currentImage);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+%%%sf to replace all/none of the projections
+  function sfReplaceAllButtonFunction(varargin)
+  %change replaced to be all the same as the first image
+  if replaced(1)==1
+    replaced=zeros(size(replaced));
+  else
+    replaced=ones(size(replaced));
+  end
+  
+  for i=1:length(replaced)%replace all projections...
+    
+  name=parameters.acq.name;
+      %update stack with extspot / difspot
+    if replaced(i)==0 %extspot case
+
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+        'where %sbb.extspotID = %d'],...
+        name, name, name, name, name,...
+        struct_ids(i))
+
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      im = gtGetSummedExtSpot_360_wl(struct_ids(i), parameters);
+
+      %place in stack
+      stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,i) = stack(g.zcenter,:,i);
+      
+    else %extspot replaced by difspot
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+        'where %sbboxes.extspotID = %d'],...
+        name, name, name,...
+        struct_ids(i))
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      warning('bodge because some SearchBoundingBoxes have zero origins')
+      if BoundingBox(1)==0
+        BoundingBox(1)=1;
+      end
+      if BoundingBox(2)==0
+        BoundingBox(2)=1;
+      end
+
+      im = gtGetSummedDifSpot(struct_ids(i), parameters);
+
+      %place in stack
+      stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,i) = stack(g.zcenter,:,i);
+    
+    end
+
+    %rewrite the changed projection .sdt
+    name=sprintf('4_grains/grain%d_/grain%d_%d.sdt',grainid, grainid, i);
+    fid=fopen(name,'wb','l');
+    stack(:,:,i)=medfilt2(stack(:,:,i));
+    fwrite(fid,stack(:,:,i)','float32');
+    fclose(fid);
+    %no need to rewrite .spr
+    
+    %update big image
+  big_image(((i+2)*range)+1:(i+3)*range, :) =  stack(first:last,:,i);
+  
+  end%loop over all spots
+    
+  save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'replaced','-append');
+  
+  %redo backprojection
+  app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+  refresh=1;% update the backpro figure
+  sfSliderFunction;
+  disp('finished')
+  
+  end
+
+
+  %%%sf to use/not use a projection
+  function sfUseButtonFunction(varargin)
+    index(app.currentImage)=~index(app.currentImage);
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'index','-append');
+    %redo the backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+
+  %%%sf to use/not use all projections
+  function sfUseAllButtonFunction(varargin)
+      if all(index==1)
+          index=zeros(size(index));
+      else
+          index=ones(size(index));
+      end
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'index','-append');
+    %redo the backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+  %%subfunction for doing ART on a central section of the grain to test
+  %%parameters
+  function sfARTButtonFunction(varargin)
+    %first read the string in LambdaBox
+    lambdastringnew=get(LambdaBox, 'String');
+    lambdastringnew=['[ ' lambdastringnew ' ]'];
+    lambdanew=str2num(lambdastringnew);
+    if length(lambdanew)==3
+      lambda=lambdanew;
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'lambda','-append');
+	  disp('updating lambda values in grain.mat file...');
+    end
+
+    scanname = sprintf('4_grains/grain%d_/grain%d_',grainid,grainid);
+    parfilename = sprintf('4_grains/grain%d_/grain%d_.par',grainid,grainid);
+    z1_sub = g.zcenter-2;
+    nz_sub = 5; %do 5 slices (more representative)
+    nbiter = 3;
+    pixsize = 1;
+    braggangle = 0;
+    np = parameters.acq.bb(3);
+    nq = parameters.acq.bb(4);
+    offset = 0;
+
+    rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+    seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+    p_angles = -Omega(find(index));
+    p_numbers = find(index);
+%    keyboard
+    gtMakeARTJob(scanname,parfilename,p_numbers,p_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset, ...
+      z1_sub,nz_sub,x1,nx,y1,ny);
+
+    command=sprintf('%s %s',rec_alg,parfilename);
+    [s,w]=unix(command);
+    command=sprintf('%s %s_res0_%d',seg2view,scanname,nbiter);
+    [s,w]=unix(command);
+    name=sprintf('%s_res0_%d.sdt',scanname,nbiter);
+    im=volread(name,'float32',0,nx,ny,nz_sub,'l');
+
+    app.ARTimage = im(:,:,ceil(nz_sub/2))';%collect middle slice
+
+    subplot(1,3,3)
+    imshow(app.ARTimage, [])
+    title('ART output')
+  end
+
+  function sfBadButtonFunction(varargin)
+    bad=1;
+    done=1;
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'bad', 'done','-append');
+    app.quit=1;
+    done=0;
+    close
+  end
+
+  function sfAcceptButtonFunction(varargin)
+    %launch full ART reconstruction
+    done=1;
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'stack', 'done','-append');
+    done=0;
+    if nargin==1     % do not start full volume when slice is given as additional input argument
+	  gtDoART(grainid);
+	end  
+    app.quit=1;
+	img=app.ARTimage;   % output the current slice
+    close
+  end
+
+  function sfExitButtonFunction(varargin)
+    %finish without changes
+    done=1;
+    app.quit=1;
+    close
+  end
+
+
+
+end
+
diff --git a/5_reconstruction/gtReconstructionManager_360special.m b/5_reconstruction/gtReconstructionManager_360special.m
new file mode 100755
index 0000000000000000000000000000000000000000..916d0337dcc78cbb1eb9ed4d8d80a34c6a0b9894
--- /dev/null
+++ b/5_reconstruction/gtReconstructionManager_360special.m
@@ -0,0 +1,715 @@
+%GUI to choose art params, select and replace reflections, and fix bounding
+%boxes...
+%like gtnew_new_choose_art...  but better!
+
+%loop through a series of grains
+
+%don't worry about pair_vectors
+%360 degree concept
+
+%special...  Do a particular slice, and show the grain in the context of
+%the other grains in that slice
+% 'slice' input is relative to the whole volume
+%continue to show the mid-height of the grain in backprojection
+% vol is a current best 3d volume
+
+function gtReconstructionManager_360special(grainid, slice, vol)
+
+  parameters=[];
+  load parameters;
+  gtDBConnect;
+
+  block='on'; %don't return the command line until the user is finished
+
+  
+  
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %read in data, sort for convinience
+  tmp_slice=vol(:,:,slice);
+%   grain_list=unique(tmp_slice);
+%   grain_list(1)=[];
+%   max_grain_id=mym(sprintf('select max(grainid) from %sextspot',parameters.acq.name));
+%   grain_list(find(grain_list>max_grain_id))=[];
+%   if any(grain_list==grainid)
+%     grain_list(find(grain_list==grainid))=[];%will build slice without this one
+%   else
+%     disp('This grain not in the relevant slice! quitting...')
+%     return
+%   end
+%   slice_image=gtnew_assemble_slice_special(slice, grain_list);
+slice_image=tmp_slice;
+slice_image(find(slice_image==grainid))=0;
+
+
+
+  g=load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+  struct_ids=g.struct_ids;
+
+  if isfield(g, 'bad') && g.bad>=1
+    disp(sprintf('grain %d is already set to bad=%d',grainid, g.bad))
+    return
+  end
+  
+  if isfield(g, 'done') && g.done==1
+    check=inputwdefault(sprintf('grain %d already been done! Do you want to proceed anyway? y/n',grainid), 'n');
+    if check=='n'
+    return
+    end
+  end
+
+
+  %if it doesn't already exist, add an index, replaced
+  if isfield(g, 'index')
+    index=g.index;
+  else
+    index = ones(1,length(struct_ids));
+  end
+  if isfield(g, 'replaced')
+    replaced=g.replaced;
+  else
+    replaced = zeros(1,length(struct_ids));
+  end
+  if isfield(g, 'bad')
+    bad=g.bad;
+  else
+    bad=0;
+  end
+  %estimate art parameters
+  if length(struct_ids)>45
+    lambda = [0.2 0.1 0.05];
+  elseif length(struct_ids)>30
+    lambda = [0.3 0.2 0.1]; %initial values
+  elseif length(struct_ids)>15
+    lambda = [0.5 0.3 0.1]; %initial values
+  else
+    lambda = [0.7 0.3 0.2]; %initial values
+  end
+
+  %unpacking...
+  Omega=g.Omega;Theta=g.Theta;Eta=g.Eta;
+  plane_normal=g.plane_normal;hkl=g.hkl;
+  stack=g.stack;
+  %for editable ART bounding box
+  x1 = g.x1;
+  y1 = g.y1;
+  nx = g.nx;
+  ny = g.ny;
+
+
+  %do the sorting by Omega
+  [Omega,tmp]=sort(Omega);
+
+  %if we need to, sort other fields, save, and rewrite stack to ART input
+  if ~all(tmp==1:length(Omega))
+
+    Theta = Theta(tmp);
+    Eta = Eta(tmp);
+    struct_ids = struct_ids(tmp);
+    plane_normal = plane_normal(tmp,:);
+    hkl = hkl(tmp,:);
+    stack = stack(:,:,tmp);
+    index = index(tmp);
+    replaced = replaced(tmp);
+
+    %save in new order
+
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),...
+      'struct_ids','stack','Theta','Eta','Omega','plane_normal','hkl',...
+      'index','replaced','bad','-append');
+    
+    gtWriteStack_360(grainid, 0);%write the stack in new order, don't replace projections by default
+  end
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  
+  %%%%%%%%%%%%%%%%%
+  %remove bad projections automatically
+  if 0
+  gt_select_projections_auto(grainid)
+  pause(1)
+  close; close;
+  else
+    disp('auto selection of projections disabled')
+  end
+  %%%%%%%%%%%%%%%%%
+  
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  %Now the interactive part
+  refresh=1;
+
+  app.quit=0;
+
+  %setup the figures
+  
+  scrsz = get(0,'ScreenSize');
+
+  fig_handle=figure;
+   set(fig_handle, 'Position',[50 150 0.75*scrsz(3) .75*scrsz(4)]);
+   
+  StackAxes=subplot(1,3,1);%stack image
+
+  app.stack_slider=uicontrol('style', 'slider');
+  set(app.stack_slider, 'callback', @sfSliderFunction)
+  set(fig_handle,'windowbuttonmotionfcn',@sfSliderFunction)
+  set(fig_handle,'windowbuttondownfcn',@sfTestFunction) %@sfSliderFunction)
+  set(fig_handle,'windowbuttonupfcn',@sfSliderFunction)
+  
+  set(app.stack_slider,'units','normalized');
+  set(app.stack_slider,'position',[0 0 .4 0.05])
+  set(app.stack_slider,'min',1,'max',size(stack,3),'sliderstep',[1/size(stack,3) 1/size(stack,3)]);
+  set(app.stack_slider,'value',1);
+  imshow(stack(:,:,1), [])
+  app.currentImage=1;
+
+
+  BackproAxes=subplot(1,3,2);%crude backpro image
+  %set(fig_handle, 'windowbuttondownfcn', @sfDragBBFunction1)
+  %set(fig_handle, 'windowbuttonupfcn', @sfDragBBFunction2)
+  %set(BackproAxes, 'ButtonDownFcn', @sfDragBBFunction1)
+  title('click to change ART bb')
+
+
+  
+  
+  %set up the buttons
+  buttongroup=uibuttongroup('Position', [.4 0 .6 .05]);
+
+  UseButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'use', 'position', [0 0 50 20]);
+  set(UseButton, 'callback', @sfUseButtonFunction)
+    
+  UseAllButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'use all', 'position', [50 0 50 20]);
+  set(UseAllButton, 'callback', @sfUseAllButtonFunction)
+  
+  ReplaceButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'replace', 'position', [100 0 50 20]);
+  set(ReplaceButton, 'callback', @sfReplaceButtonFunction)
+  
+  ReplaceAllButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'replace all', 'position', [150 0 80 20]);
+  set(ReplaceAllButton, 'callback', @sfReplaceAllButtonFunction)
+ 
+  ARTButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'Do ART', 'position', [230 0 50 20]);
+  set(ARTButton, 'callback', @sfARTButtonFunction)
+
+  lambdastring=num2str(lambda);
+  lambdastring=lambdastring([1:4 13:16 25:27]);
+
+  LambdaBox=uicontrol(buttongroup, 'Style', 'edit', 'String', lambdastring, 'position', [280 0 70 20]);
+
+  BadButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'bad grain', 'position', [350 0 50 20]);
+  set(BadButton, 'callback', @sfBadButtonFunction)
+  AcceptButton=uicontrol(buttongroup, 'Style', 'pushbutton', 'string', 'ACCEPT!', 'position', [400 0 50 20]);
+  set(AcceptButton, 'callback', @sfAcceptButtonFunction)
+
+  %add a button to escape without making changes
+  exitbuttongroup=uibuttongroup('Position', [.85 .95 .15 .05]);
+  ExitButton=uicontrol(exitbuttongroup, 'Style', 'pushbutton', 'string', 'quit, no changes', 'position', [0 0 100 20]);
+  set(ExitButton, 'callback', @sfExitButtonFunction)
+    
+  
+
+  %make overlays for backproim, prepare a big image to show in the left
+  %hand window
+  %get max range of spots
+  tmp=sum(sum(stack, 3), 2);
+  first=min(find(tmp));
+  last=max(find(tmp));
+  range=last-first+1;
+  big_image=zeros((size(stack,3)+6)*range, size(stack,2)); %pad by three images top and bottom
+  app.overlays=zeros([size(stack,2), size(stack,2), size(stack,3)]);
+  %collect sino
+  for i=1:size(stack,3)
+    sino(:,i) = stack(slice, :, i)';
+    big_image(((i+2)*range)+1:(i+3)*range, :) =  stack(first:last,:,i);
+  end
+  binsino=sino>0;
+  for i=1:size(stack,3)
+    app.overlays(:,:,i)=backpro(binsino(:,i),Omega(i)*pi/180);
+    app.centroidx(i) = sino(:,i)'*(1:size(sino,1))'/sum(sino(:,i));
+  end
+  app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+
+
+
+
+
+  ARTAxes=subplot(1,3,3);
+  sfSliderFunction
+  sfARTButtonFunction %first "press" of the button
+
+  if strcmp(block,'on')
+    % if user wants nothing to return until findshift is finished
+    while 1
+      drawnow
+      if app.quit==1
+        break
+      end
+    end
+  end
+
+
+    function sfTestFunction(varargin)%which subfunction should the button down go to?
+        if isequal(gco,app.stack_slider)
+            sfSliderFunction
+        elseif isequal(gca,BackproAxes)
+        sfDragBBFunction1
+        end
+    end
+
+        
+  
+
+  function sfSliderFunction(varargin)
+
+    if (isequal(gco,app.stack_slider) || refresh)
+      tmp=round(get(app.stack_slider,'value'));
+      if (tmp~=app.currentImage | refresh)
+          
+        subplot(1,3,1)% update stack figure
+        hold off
+        app.currentImage=tmp;
+        %get 7 image subsection of big_image
+        im_start=((app.currentImage-1)*range)+1;
+        im_end=(app.currentImage+6)*range;
+        
+        imshow(big_image(im_start:im_end, :), [])
+        hold on
+        %highlight current image
+        xdata=[1 size(big_image,2) size(big_image, 2) 1 1];
+        ydata=[(3*range)+1 (3*range)+1 4*range 4*range (3*range)+1];
+        %adjust line colour according to index
+        
+        if index(app.currentImage)==1 %if using, green
+        plot(xdata, ydata, 'g');
+        else %if not using, red
+        plot(xdata, ydata, 'r');    
+        end
+        
+        title(sprintf('id: %d, use: %d, replaced: %d', struct_ids(app.currentImage), index(app.currentImage), replaced(app.currentImage)))
+        drawnow
+
+        subplot(1,3,2)% update backpro image overlay
+        hold off
+        imshow(app.BPimage, []); %show the first backprojection
+        %colormap jet
+        hold on
+        title('click to change ART bb')
+        
+        if 0 %if alpha thing is working?
+        app.BPoverlay=zeros([size(app.BPimage) 3]);
+        %adjust overlay colour according to index
+        if index(app.currentImage)==1 %if using, green
+        app.BPoverlay(:,:,2)=app.overlays(:,:,app.currentImage);
+        else %if not using, red
+        app.BPoverlay(:,:,1)=app.overlays(:,:,app.currentImage);
+        end
+        app.BPoverlay=image(app.BPoverlay, 'XData', [1:size(app.BPimage,2)], 'YData', [1:size(app.BPimage,1)]);
+        set(app.BPoverlay, 'AlphaData', 0.04*ones(size(app.BPimage)))
+
+         %%%%%%%%  alternative display mode if alpha overlay isn't working
+       else %plot a simple line over the current projection
+          
+          spot_com=app.centroidx(app.currentImage);
+          spot_omega=Omega(app.currentImage)*pi/180; %Omega in degreees
+          %experiment parameters
+          centre_of_backproimg_x = parameters.acq.bb(3)/2;
+          centre_of_backproimg_y = parameters.acq.bb(3)/2;
+          point=[centre_of_backproimg_x, centre_of_backproimg_y];
+          %make line parameters
+          grad=1/tan(spot_omega);
+          %dist of com line from centre
+          offset_com=spot_com-parameters.acq.bb(3)/2;
+          %centre point of line though the projection
+          point=point+(offset_com*[cos(spot_omega) -sin(spot_omega)]);
+          %put into format y = mx + c
+          m = grad;
+          c = point(2) - (m*point(1));
+          ez_line=ezplot(sprintf('%f*x + %f - y = 0',m,c),[1 parameters.acq.bb(3)]);
+          
+          if index(app.currentImage)==1 %if using, green
+          set(ez_line,'color','g');
+          else %if not using, red
+          set(ez_line, 'color', 'r');
+          end
+            
+        end
+        
+        
+        
+        refresh=0;
+      end
+    end
+  end
+
+  %drag out a new bounding box
+  function sfDragBBFunction1(varargin)
+      
+
+     %      point1 = get(BackproAxes,'CurrentPoint'); % button down detected
+     %point1=point1(1, 1:2)      
+    %       pointx=point1(1, 1);
+    %       pointy=point1(1, 2);
+    %       if pointx>0 && pointx<size(app.BPimage,2) && pointy>0 && pointy<size(app.BPimage,2) %if point within image
+    %           app.newx1=ceil(pointx);
+    %           app.newy1=ceil(pointy);
+    %       end
+    p1 = get(BackproAxes,'CurrentPoint');
+    p1=p1(1, 1:2);
+    bbox=rbbox;
+    p2 = get(BackproAxes,'CurrentPoint');
+    p2=p2(1, 1:2);
+    point1=min(p1, p2);
+    offset=abs(p1-p2);
+    
+    pointx1=point1(1);
+    pointy1=point1(2);
+    pointx2=point1(1)+offset(1);
+    pointy2=point1(2)+offset(2);
+    points=[pointx1 pointy1 pointx2 pointy2];
+    
+
+    if all(points>-10 & points<size(app.BPimage,2)+10) %if both points ~within image
+      %correct if point is slightly outside image
+      if pointx1<1
+          pointx1=1;
+      end
+      if pointy1<1
+          pointy1=1;
+      end
+      if pointx2>size(app.BPimage,2)
+          pointx2=size(app.BPimage,2);
+      end
+      if pointy2>size(app.BPimage,2)
+          pointy2=size(app.BPimage,2);
+      end
+      x1=ceil(pointx1);
+      y1=ceil(pointy1);
+      nx=ceil(pointx2-x1);
+      ny=ceil(pointy2-y1);
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'x1', 'y1', 'nx', 'ny', '-append');
+      sfARTButtonFunction %rerun ART
+    end
+
+  end
+
+  %     function sfDragBBFunction2(varargin)
+  %         point1 = get(BackproAxes,'CurrentPoint'); % button up detected
+  %         pointx=point1(1, 1);
+  %         pointy=point1(1, 2);
+  %         if pointx>0 && pointx<size(app.BPimage,2) && pointy>0 && pointy<size(app.BPimage,2) %if point within image
+  %             x1=app.newx1;
+  %             y1=app.newy1;
+  %             nx=ceil(pointx-x1);
+  %             ny=ceil(pointy-y1);
+  %             save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'x1', 'y1', 'nx', 'ny', '-append');
+  %             sfARTButtonFunction %rerun ART
+  %         end
+  %     end
+
+
+  %%%sf to replace a projection
+  function sfReplaceButtonFunction(varargin)
+    %change replaced
+    replaced(app.currentImage)=~replaced(app.currentImage);
+
+      name=parameters.acq.name;
+
+
+    %update stack with extspot / difspot
+    if replaced(app.currentImage)==0 %extspot case
+
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+        'where %sbb.extspotID = %d'],...
+        name, name, name, name, name,...
+        struct_ids(app.currentImage))
+
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      im = gtGetSummedExtSpot_360(struct_ids(app.currentImage), parameters);
+
+      %place in stack
+      stack(:,:,app.currentImage) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,app.currentImage)= 100*stack(:,:,app.currentImage)/sum(sum(stack(:,:,app.currentImage)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,app.currentImage) = stack(g.zcenter,:,app.currentImage);
+      
+    else %extspot replaced by difspot
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+        'where %sbboxes.extspotID = %d'],...
+        name, name, name,...
+        struct_ids(app.currentImage))
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      warning('bodge because some SearchBoundingBoxes have zero origins')
+      if BoundingBox(1)==0
+        BoundingBox(1)=1;
+      end
+      if BoundingBox(2)==0
+        BoundingBox(2)=1;
+      end
+
+      im = gtGetSummedDifSpot(struct_ids(app.currentImage), parameters);
+
+      %place in stack
+      stack(:,:,app.currentImage) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,app.currentImage)= 100*stack(:,:,app.currentImage)/sum(sum(stack(:,:,app.currentImage)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,app.currentImage) = stack(g.zcenter,:,app.currentImage);
+    
+    end
+
+    %rewrite the changed projection .sdt
+    name=sprintf('4_grains/grain%d_/grain%d_%d.sdt',grainid, grainid, app.currentImage);
+    fid=fopen(name,'wb','l');
+    stack(:,:,app.currentImage)=medfilt2(stack(:,:,app.currentImage));
+    fwrite(fid,stack(:,:,app.currentImage)','float32');
+    fclose(fid);
+    %no need to rewrite .spr
+    % name=sprintf('4_grains/grain%d_/grain%d_%d.spr',grainid, grainid, app.currentImage)
+    % %name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+    % spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'replaced','-append');
+    %redo backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    %update big image
+    big_image(((app.currentImage+2)*range)+1:(app.currentImage+3)*range, :) =  stack(first:last,:,app.currentImage);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+%%%sf to replace all/none of the projections
+  function sfReplaceAllButtonFunction(varargin)
+  %change replaced to be all the same as the first image
+  if replaced(1)==1
+    replaced=zeros(size(replaced));
+  else
+    replaced=ones(size(replaced));
+  end
+  
+  for i=1:length(replaced)%replace all projections...
+    
+  name=parameters.acq.name;
+      %update stack with extspot / difspot
+    if replaced(i)==0 %extspot case
+
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+        'where %sbb.extspotID = %d'],...
+        name, name, name, name, name,...
+        struct_ids(i))
+
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      im = gtGetSummedExtSpot_360(struct_ids(i), parameters);
+
+      %place in stack
+      stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,i) = stack(slice,:,i);
+      
+    else %extspot replaced by difspot
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+        'where %sbboxes.extspotID = %d'],...
+        name, name, name,...
+        struct_ids(i))
+      [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+
+      warning('bodge because some SearchBoundingBoxes have zero origins')
+      if BoundingBox(1)==0
+        BoundingBox(1)=1;
+      end
+      if BoundingBox(2)==0
+        BoundingBox(2)=1;
+      end
+
+      im = gtGetSummedDifSpot(struct_ids(i), parameters);
+
+      %place in stack
+      stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+      stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+
+      %read sino from stack
+      sino(:,i) = stack(slice,:,i);
+    
+    end
+
+    %rewrite the changed projection .sdt
+    name=sprintf('4_grains/grain%d_/grain%d_%d.sdt',grainid, grainid, i);
+    fid=fopen(name,'wb','l');
+    stack(:,:,i)=medfilt2(stack(:,:,i));
+    fwrite(fid,stack(:,:,i)','float32');
+    fclose(fid);
+    %no need to rewrite .spr
+    
+    %update big image
+  big_image(((i+2)*range)+1:(i+3)*range, :) =  stack(first:last,:,i);
+  
+  end%loop over all spots
+    
+  save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'replaced','-append');
+  
+  %redo backprojection
+  app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+  refresh=1;% update the backpro figure
+  sfSliderFunction;
+  disp('finished')
+  
+  end
+
+
+  %%%sf to use/not use a projection
+  function sfUseButtonFunction(varargin)
+    index(app.currentImage)=~index(app.currentImage);
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'index','-append');
+    %redo the backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+
+  %%%sf to use/not use all projections
+  function sfUseAllButtonFunction(varargin)
+      if all(index==1)
+          index=zeros(size(index));
+      else
+          index=ones(size(index));
+      end
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'index','-append');
+    %redo the backprojection
+    app.BPimage=backpro(sino(:, find(index==1)),Omega(find(index==1))*pi/180);
+    refresh=1;% update the backpro figure
+    sfSliderFunction;
+  end
+
+  %%subfunction for doing ART on a central section of the grain to test
+  %%parameters
+  function sfARTButtonFunction(varargin)
+    %first read the string in LambdaBox
+    lambdastringnew=get(LambdaBox, 'String');
+    lambdastringnew=['[ ' lambdastringnew ' ]'];
+    lambdanew=str2num(lambdastringnew);
+    if length(lambdanew)==3
+      lambda=lambdanew;
+      save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'lambda','-append');
+    end
+
+    scanname = sprintf('4_grains/grain%d_/grain%d_',grainid,grainid);
+    parfilename = sprintf('4_grains/grain%d_/grain%d_.par',grainid,grainid);
+
+    %do the slice of interest
+    
+    z1_sub = slice-2; %g.zcenter-2;
+    nz_sub = 5; %do 5 slices (more representative)
+    nbiter = 3;
+    pixsize = 1;
+    braggangle = 0;
+    np = parameters.acq.bb(3);
+    nq = parameters.acq.bb(4);
+    offset = 0;
+
+    rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+    seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+    p_angles = -Omega(find(index));
+    p_numbers = find(index);
+%    keyboard
+    gtMakeARTJob(scanname,parfilename,p_numbers,p_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset, ...
+      z1_sub,nz_sub,x1,nx,y1,ny);
+
+    command=sprintf('%s %s',rec_alg,parfilename);
+    [s,w]=unix(command);
+    command=sprintf('%s %s_res0_%d',seg2view,scanname,nbiter);
+    [s,w]=unix(command);
+    name=sprintf('%s_res0_%d.sdt',scanname,nbiter);
+    vol=volread(name,'float32',0,nx,ny,nz_sub,'l');
+    %threshold grain
+  %  a=max(vol(:));
+  %  thresh_val = mean(vol(find(vol>(a/10))))-std(vol(find(vol>(a/10))));%std dev, ignoring low (background) values
+  %  vol=vol>thresh_val;
+  
+    %make image of the art output in the wider context
+    border=20;
+    min2 = x1+border;
+    max2 = min2 + nx-1;
+    min1 = y1+border;
+    max1 = min1 + ny-1;
+    
+if min1<1
+  tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+  min1=1;
+  vol=vol(tmp:end,:,:);
+end
+if min2<1
+  tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+  min2=1;
+  vol=vol(:,tmp:end,:);
+end
+  if max1>parameters.acq.bb(3)+(2*border);
+  tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+  max1=parameters.acq.bb(3)+(2*border);
+  vol=vol(1:end-tmp,:,:);
+end
+if max2>parameters.acq.bb(3)+(2*border);
+  tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+  max2=parameters.acq.bb(3)+(2*border);
+  vol=vol(:,1:end-tmp,:);
+end  
+ app.ARTimage = vol(:,:,ceil(nz_sub/2))';%collect middle slice
+
+
+ slice_image2=slice_image;
+ %add our grain
+ slice_image2(min1:max1, min2:max2)=slice_image2(min1:max1, min2:max2)+app.ARTimage;
+ 
+    subplot(1,3,3)
+    imshow(slice_image2,[0 max(app.ARTimage(:))])
+        title('ART output')
+    
+%    figure(2)
+%    imshow(slice_image2, [0 max(slice_image2(:))])
+%    map=gtRandCmap(slice_image2)/2;
+%    map(grainid+1,:)=[1 0 0];
+%    colormap(map)
+%title('ART output, grain in red')
+%figure(1)
+
+  end
+
+  function sfBadButtonFunction(varargin)
+    bad=1;
+    done=1;
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'bad', 'done','-append');
+    app.quit=1;
+    done=0;
+    close
+  end
+
+  function sfAcceptButtonFunction(varargin)
+    %launch full ART reconstruction
+    done=1;
+    save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'stack', 'done','-append');
+    done=0;
+    gtDoART(grainid);
+    app.quit=1;
+    close
+  end
+
+  function sfExitButtonFunction(varargin)
+    %finish without changes
+    done=1;
+    app.quit=1;
+    close
+  end
+
+
+
+end
+
diff --git a/5_reconstruction/gtSigmaTest.m b/5_reconstruction/gtSigmaTest.m
new file mode 100755
index 0000000000000000000000000000000000000000..9799721753c9f5ab383b99aa96e6d27ab92f0836
--- /dev/null
+++ b/5_reconstruction/gtSigmaTest.m
@@ -0,0 +1,50 @@
+  function gtSigmaTest(boundaries_structure)
+    
+  %fill in the sigma field of boundaries_structure.mat
+  
+  %sigmas: type, angle, axis {, brandon criteria}
+sigmas=[3 60 1 1 1;...
+  5 36.86 1 0 0;...
+  7 38.21 1 1 1;
+  9 38.94 1 1 0;...
+  11 50.47 1 1 0;...
+  13.1 22.62 1 0 0;...
+  13.2 27.79 1 1 1;...
+  15 48.19 2 1 0;...
+  17.1 28.07 1 0 0;...
+  17.2 60.92 2 2 1;...
+  19.1 26.53 1 1 0;...
+  19.2 46.83 1 1 1;...
+  21.1 21.78 1 1 1;...
+  21.2 44.41 2 1 1;...
+  23 40.45 3 1 1;...
+  25.1 16.26 1 0 0;...
+  25.2 51.68 3 3 1;...
+  27.1 31.59 1 1 0;...
+  27.2 35.43 2 1 0;...
+  29.1 43.60 1 0 0;...
+  29.2 46.40 2 2 1];
+%add brandon criteria
+sigmas(:,6)=15*sigmas(:,1).^(-0.5);
+%normalise axis
+sigmas(:,3:5)=sigmas(:,3:5)./repmat(sqrt(sum(sigmas(:,3:5).*sigmas(:,3:5),2)),1,3);
+warning('sigma axis indices must be positive, normalised, and in descending order...')
+  
+  
+  for i=1:length(boundaries_structure)
+    if ~isempty(boundaries_structure(i).misorientation_axis) 
+      
+
+    mis_axis=sort(abs(boundaries_structure(i).misorientation_axis), 'descend');
+    mis_angle=boundaries_structure(i).misorientation_angle;
+    
+    %determine sigma type - intially check just sigma three
+    test_angle=abs(mis_angle-sigmas(:,2))<sigmas(:,6);
+    test_axis=(180/pi)*abs(acos(dot(repmat(mis_axis,size(sigmas,1),1), sigmas(:,3:5), 2)))<sigmas(:,6);
+    %if we have a choice, take the lowest sigma value
+    boundaries_structure(i).sigma=min(sigmas(find(test_angle & test_axis), 1));
+    
+    end
+  end
+  
+  save('boundaries_structure.mat', 'boundaries_structure')
\ No newline at end of file
diff --git a/5_reconstruction/gtThinCrack.m b/5_reconstruction/gtThinCrack.m
new file mode 100755
index 0000000000000000000000000000000000000000..1649d1655fbeac924c6c082e965c4950965d02c3
--- /dev/null
+++ b/5_reconstruction/gtThinCrack.m
@@ -0,0 +1,103 @@
+%close a crack, allowing for a bifurcated crack
+%after treatment, whole crack has an opening of 2 voxels
+%Remove spurious "crack" voxels at the surface of the sample.
+
+function volout = gtThinCrack(vol)
+
+
+%vol is the crack volume (crack>0, material==0)
+%close the crack along the z (3rd) direction
+% pushes towards a (fixed) middle, not the middle of the
+%crack
+
+
+%%%%%%  Close the crack   %%%%%%%
+volout=zeros(size(vol));
+vol=uint8(vol>0); %crack=1, material=0
+
+
+
+for i=1:size(vol,1)
+
+  for j=1:size(vol,2)
+
+ 
+    tmp=squeeze(vol(i,j,:));
+    tmpout=zeros(size(tmp));
+    
+  %  if all(tmp~=0)
+  %    tmpout=ones(size(tmp));
+  %    disp('solid')
+  %    continue
+  %  end
+    
+    if max(tmp)~=0
+    tmp=double(tmp);
+    gradtmp=abs(gradient(tmp));
+    centertmp=round(mean(find(tmp)));
+    
+    %deal with the two halves, and then combine
+    
+    %second half
+    position=centertmp;
+    for k=centertmp:length(tmp)
+      if tmp(k)==0 & gradtmp(k)==0
+        %disp('1')
+        tmpout(position)=0;
+        position=position+1;
+      elseif tmp(k)==0 & gradtmp(k) ~=0
+        %disp('2')
+        tmpout(position)=1;
+        position=position+1;
+      end
+    end
+      
+      %first half - reverse order
+    position=centertmp;
+    for k=centertmp:-1:1
+      if tmp(k)==0 & gradtmp(k)==0
+        %disp('1')
+        tmpout(position)=0;
+        position=position-1;
+      elseif tmp(k)==0 & gradtmp(k) ~=0
+        %disp('2')
+        tmpout(position)=1;
+        position=position-1;
+      end      
+    end
+
+    
+    end
+    
+    volout(i,j,1:length(tmpout))=tmpout;      
+    
+  end
+end
+
+
+if 0
+%%%%%   Remove surface voxels  %%%%%
+
+%estimate max crack opening displacement
+tmp=sum(vol,3);
+tmp=tmp(find(tmp<(size(vol,3)/5))); % discard apparently large crack openings
+tmp(find(tmp<4))=[]; % discard zeros and very low values (noise)
+[count, bin]=hist(tmp, ceil(size(vol,3)/10)); %histogram
+a=max(count(end-9:end)); %max of the ten largest bins
+max_opening=max(bin(find(count>a))); %find the edge of histogram peak
+
+vol_dil = imerode(vol, ones(1,1,round(max_opening)));
+vol_dil = imdilate(vol_dil, ones(1,1,round(max_opening)));
+vol_dil = imdilate(vol_dil, ones(11,11,1));
+
+%apply this mask
+volout(find(vol_dil))=0;
+
+
+%%%%%%%%%
+end
+
+
+
+
+
diff --git a/5_reconstruction/gtThresholdGrain.m b/5_reconstruction/gtThresholdGrain.m
new file mode 100755
index 0000000000000000000000000000000000000000..17e8bb296a73551db6ba9ef4639c556db58cdbe6
--- /dev/null
+++ b/5_reconstruction/gtThresholdGrain.m
@@ -0,0 +1,27 @@
+            
+function [vol, thresh_val]=gtThresholdGrain(vol);
+
+%Theshold a grey scale volume, ie the output of the ART reconstruction
+%improve the calculation of this value with respect to using graythresh
+
+%explanation - we expect a histogram with a peak corresponding to the
+%grain, and a peak a low values corresponding to the background of zeros.
+%We want a threshold value below the peak corresponding to the grain, but
+%above the background peak. Here we calculate one std dev below teh mean
+%after excuding low values as a first estimate.  If there is a minimum in
+%the histogram below this value, we will take it instead.
+
+a=max(vol(:));
+% one standard dev below the mean, excluding low (background) values 
+val1=mean(vol(find(vol>(a/10))))-std(vol(find(vol>(a/10))));
+% take histogram of the whole value
+[n,x]=hist(vol(:),500);
+% remove the part of the histogram above val1
+n(find(x>val1))=[];
+x(find(x>val1))=[];
+% find the minimum in this region
+val2=min(x(find(n==min(n))));
+
+thresh_val=min(val1, val2);
+
+vol=vol>thresh_val;
\ No newline at end of file
diff --git a/5_reconstruction/gtWriteDifStack.m b/5_reconstruction/gtWriteDifStack.m
new file mode 100755
index 0000000000000000000000000000000000000000..693667824d92c9cf28b75d259da22741d5da8547
--- /dev/null
+++ b/5_reconstruction/gtWriteDifStack.m
@@ -0,0 +1,72 @@
+function [proj,projbw]=gtWriteDifStack(grainid,grain,parameters)
+%write input files for ART reconstruction
+%simplified version more appropriate to new process - write only those
+%projections retained after consistancy check has been run
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+if ~exist(graindir,'dir')
+  mkdir(graindir);
+end
+
+%read stack from the grain%d_.mat file
+%
+%graindata=load(sprintf('%s/4_grains/%s/%s.mat',parameters.acq.dir,grainname,grainname));
+
+struct_ids=grain{grainid}.difspots;
+num_pairs=length(grain{grainid}.pairid);
+
+
+disp('diffraction spots will be flipped !');
+for n=1:num_pairs
+
+  % read, zeropad and filter and flip first difspot
+  query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,struct_ids(n));
+  [bb(1),bb(2),bb(3),bb(4)]=mym(query);
+  dif1=gtGetSummedDifSpot(struct_ids(n),parameters,1);
+  
+  dif1=wiener2(dif1,[10 10]);
+  % zeros padding
+  tmp=zeros(bb(4)+200,bb(3)+200);
+  dif1=gtPlaceSubImage(dif1,tmp,101,101);
+  dif1=fliplr(dif1);
+  
+  % read, zeropad, filter and flip the second difspot
+  
+  dif2=gtGetSummedDifSpot(struct_ids(n+num_pairs),parameters,1);
+  dif2=wiener2(dif2,[10 10]);
+  
+  dif2=gtPlaceSubImage(dif2,tmp,101,101);
+  
+  
+  % now determine relative shift by correlation of edge images...
+  e1=edge(dif1,'canny');
+  e2=edge(dif2,'canny');
+  cor=correlate(e1,e2);
+  dif2=interpolatef(dif2,cor(1),cor(2));
+  
+  % create the summed difspot and threshhold it
+  dif=(dif1+dif2)/1000;    % graythresh does not seem to work out of the range [0 1] ... 
+  
+  t=graythresh(dif);
+  difbw=im2bw(dif,0.15*t);
+  %keyboard
+  dif=1000*dif/sum(dif(:));
+  
+  proj{n}=dif;
+  projbw{n}=difbw;
+  
+  fname=sprintf('%s/difspot%d',graindir,n);
+  sdt_write(fname,dif,'float32');
+  fname=sprintf('%s/difbw%d',graindir,n);
+  sdt_write(fname,difbw,'float32');
+  
+end
+
+
+
+
diff --git a/5_reconstruction/gtWriteDifStackold.m b/5_reconstruction/gtWriteDifStackold.m
new file mode 100755
index 0000000000000000000000000000000000000000..b8ef64533b80b5eab500f2b832be1902466b316b
--- /dev/null
+++ b/5_reconstruction/gtWriteDifStackold.m
@@ -0,0 +1,42 @@
+function gtWriteDifStack(grainid)
+%write input files for ART reconstruction
+%simplified version more appropriate to new process - write only those
+%projections retained after consistancy check has been run
+
+global parameters;
+if isempty(parameters)
+  load parameters.mat
+end
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+if ~exist(graindir,'dir')
+  mkdir(graindir);
+end
+
+%read stack from the grain%d_.mat file
+% ***
+graindata=load(sprintf('%s/4_grains/%s/%s.mat',parameters.acq.dir,grainname,grainname));
+stack = graindata.stack;
+struct_ids=graindata.struct_ids;
+keyboard
+for n=1:length(struct_ids)
+
+  % find the difspot
+  im=edf_read(sprintf('2_difspot/difspot%05d.edf',struct_ids(n)));
+  im=transpose(im);
+  disp('Transposing difspot')
+  
+  [xo,yo]=mym(sprintf('select BoundingBoxXorigin,BoundingBoxYorigin from s5_dct5_difspot where difspotID=%d',struct_ids(n)))
+  imbig=gtPlaceSubImage(im,zeros(2048,2048),xo,yo);
+
+
+  % write the difspot as an ART projection
+  fname=sprintf('%s/%sdif%d',graindir,grainname,n);
+
+  sdt_write(fname,imbig,'float32');
+end
+
+
+
+
diff --git a/5_reconstruction/gtWriteStack.m b/5_reconstruction/gtWriteStack.m
new file mode 100755
index 0000000000000000000000000000000000000000..3a8e5a7d91cf91da11ee461eae9175f7a850a61d
--- /dev/null
+++ b/5_reconstruction/gtWriteStack.m
@@ -0,0 +1,33 @@
+function gtWriteStack(grainid)
+%write input files for ART reconstruction
+%simplified version more appropriate to new process - write only those
+%projections retained after consistancy check has been run
+
+%old version in 5_reconstruction/old/
+
+  load parameters.mat
+
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+if ~exist(graindir,'dir')
+  mkdir(graindir);
+end
+
+%read stack from the grain%d_.mat file
+graindata=load(sprintf('%s/4_grains/%s/%s.mat',parameters.acq.dir,grainname,grainname));
+stack = graindata.stack;
+
+%write the projections
+for i=1:size(stack,3)
+	name=sprintf('%s/%s%d.sdt',graindir,grainname,i);
+	fid=fopen(name,'wb','l');
+  stack(:,:,i)=medfilt2(stack(:,:,i));
+  
+	fwrite(fid,stack(:,:,i)','float32');
+	fclose(fid);
+	name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+  spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+end	
+
+
diff --git a/5_reconstruction/gtWriteStack_360.m b/5_reconstruction/gtWriteStack_360.m
new file mode 100755
index 0000000000000000000000000000000000000000..8c8b08477b0127199fcec6c3eacbf3ba88f1ea87
--- /dev/null
+++ b/5_reconstruction/gtWriteStack_360.m
@@ -0,0 +1,119 @@
+function gtWriteStack_360(grainid, varargin)
+%write input files for ART reconstruction
+%simplified version more appropriate to new process - write only those
+%projections retained after consistancy check has been run
+
+%360degree scan convention - ak 10/2007
+
+% upgrade to do sheared difspots - ak 14/10/2008 
+% for use in gtDoCombineGrains_360
+
+
+load parameters
+
+%second input is "projections" - can be empty - whatever projections are
+%there will be written.  can be "replaced" - will replace spots with
+%difspots. can be "sheared_difspots" - will shear difspots and handle omega
+%values
+
+
+projections=[];
+if ~isempty(varargin)
+  projections=varargin{1};
+end
+
+if strcmp(projections, 'replaced')
+  disp('replacing all extspots with difspots')
+elseif strcmp(projections, 'sheared_difspots')
+    disp('using sheared difspots')
+end
+
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+
+%read stack from the grain%d_.mat file
+graindata=load(sprintf('%s/4_grains/%s/%s.mat',parameters.acq.dir,grainname,grainname));
+struct_ids=graindata.struct_ids;
+stack=graindata.stack;
+
+if isfield(graindata, 'replaced')
+  replaced=graindata.replaced;
+else
+  replaced=zeros(size(struct_ids));
+end
+
+
+if strcmp(projections, 'replaced')
+%build the "all-replaced" stack
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_ids));
+%new replaced vector - all replaced
+replaced = logical(ones(length(struct_ids),1));  
+
+for i=1:size(stack,3)
+  
+    db_name=parameters.acq.name;
+
+
+  mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+    '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+    'where %sbboxes.extspotID = %d'],...
+    db_name, db_name, db_name,...
+    struct_ids(i))
+  [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+  
+  warning('bodge because some SearchBoundingBoxes have zero origins')
+  if BoundingBox(1)==0
+    BoundingBox(1)=1;
+  end
+  if BoundingBox(2)==0
+    BoundingBox(2)=1;
+  end
+  
+  % im=edf_read(sprintf('2_difspot/difspot/difspot%05d.edf',struct_ids(ca)));
+  im = gtGetSummedDifSpot(struct_ids(i));
+  
+  %place in stack
+  stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !  
+  
+  
+end
+end
+  
+
+if strcmp(projections, 'sheared_difspots')
+
+    %prepare a variable to pass to gtShearDifspots
+    graindataA.struct_ids=graindata.struct_ids;
+    %make sure Omega is correct (unsheared)
+    graindataA.omega=(180/pi)*gtGetOmega(graindata.struct_ids, parameters);
+    graindataA.eta=graindata.Eta;
+    graindataA.theta=graindata.Theta;
+    graindataA.xcenter=graindata.xcenter;
+    graindataA.ycenter=graindata.ycenter;
+    graindataA.zcenter=graindata.zcenter;
+
+    [difstack,Omega]=gtShearDifspots(graindataA);
+    %resave Omega
+    save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'Omega', '-append') ;
+
+end
+    
+    
+% write the stack to sdt files
+
+for i=1:size(stack,3)  
+  %write the spr/sdt projections
+  name=sprintf('%s/%s%d.sdt',graindir,grainname,i);
+	fid=fopen(name,'wb','l');
+  stack(:,:,i)=medfilt2(stack(:,:,i));
+  
+	fwrite(fid,stack(:,:,i)','float32');
+	fclose(fid);
+	name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+  spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+end	
+
+save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'replaced', 'stack', '-append') ;
+        
diff --git a/5_reconstruction/gtWriteStack_360_wl.m b/5_reconstruction/gtWriteStack_360_wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..c89e570d6b32f317b466f9a3fab14048642706dd
--- /dev/null
+++ b/5_reconstruction/gtWriteStack_360_wl.m
@@ -0,0 +1,77 @@
+function gtWriteStack_360_wl(grainid, varargin)
+%write input files for ART reconstruction
+%simplified version more appropriate to new process - write only those
+%projections retained after consistancy check has been run
+
+%360degree scan convention - ak 10/2007
+
+load parameters
+
+replace_all=0
+if ~isempty(varargin)
+  replace_all=varargin{1};
+end
+
+if replace_all
+  disp('replacing all extspots with difspots')
+end
+
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+
+%read stack from the grain%d_.mat file
+graindata=load(sprintf('%s/4_grains/%s/%s.mat',parameters.acq.dir,grainname,grainname));
+struct_ids=graindata.struct_ids;
+stack=graindata.stack;
+if isfield(graindata, 'replaced')
+  replaced=graindata.replaced;
+else
+  replaced=zeros(size(struct_ids));
+end
+
+if replace_all
+%build the "all-replaced" stack
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_ids));
+%new replaced vector - all replaced
+replaced = logical(ones(length(struct_ids),1));  
+
+for i=1:size(stack,3)
+  
+     [xl,yl,zl]=gtTrSamToLab(grain.center(1),grain.center(2),grain.center(3),grain.omega(i));
+	 xim = yl+ parameters.acq.bb(3)/2;   % grain COM coordinates in the direct beam images   (assumes center of rotation in the center of the beam)
+ 	 yim = parameters.acq.ydet/2-zl-parameters.acq.bb(2);
+	
+	 
+	 % get Boundingbox sizes and integration range from all difspots
+	 mymcmd=sprintf('select BoundingBoxXSize, BoundingBoxYSize, ExtStartImage, ExtEndImage, StartImage, EndImage, Integral  from %sdifspot where difspotID=%d',parameters.acq.name,grain.difspots(j));
+	 [bbxs,bbys,startndx,endndx,difstartndx,difendndx,int]=mym(mymcmd);  
+  
+     bb(1)=max(1,round(xim-bbxs/2));    % this should probably be replaced by a modfied autofind at the insertion position 
+     bb(2)=max(1,round(yim-bbys/2));
+  
+     % im=edf_read(sprintf('2_difspot/difspot/difspot%05d.edf',struct_ids(ca)));
+     im = gtGetSummedDifSpot(struct_ids(i));
+  
+     %place in stack
+     stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),);
+     stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !  
+  
+  
+end
+end
+  
+for i=1:size(stack,3)  
+  %write the spr/sdt projections
+  name=sprintf('%s/%s%d.sdt',graindir,grainname,i);
+	fid=fopen(name,'wb','l');
+  stack(:,:,i)=medfilt2(stack(:,:,i));
+  
+	fwrite(fid,stack(:,:,i)','float32');
+	fclose(fid);
+	name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+  spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+end	
+
+save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'replaced', 'stack', '-append') ;
+        
diff --git a/5_reconstruction/gtWriteStack_replaced.m b/5_reconstruction/gtWriteStack_replaced.m
new file mode 100755
index 0000000000000000000000000000000000000000..6d5b347444afdcfcd08c5f21d6771ac8089115a5
--- /dev/null
+++ b/5_reconstruction/gtWriteStack_replaced.m
@@ -0,0 +1,75 @@
+function gtWriteStack_replaced(grainid)
+%write input files for ART reconstruction
+%simplified version more appropriate to new process - write only those
+%projections retained after consistancy check has been run
+%_replaced - replace all extspots in the stack with difspots, write
+%projections accordingly.
+
+%old version in 5_reconstruction/old/
+
+  load parameters.mat
+
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+
+%read stack from the grain%d_.mat file
+graindata=load(sprintf('%s/4_grains/%s/%s.mat',parameters.acq.dir,grainname,grainname));
+
+struct_ids=graindata.struct_ids;
+
+if isfield(graindata,'pair_vector')
+	pair_vector=graindata.pair_vector;
+else
+	pair_vector=ones(size(struct_ids));
+end
+
+%new replaced vector - all replaced
+replaced = logical(ones(length(struct_ids),1));  
+
+%build the "all-replaced" stack
+stack=zeros(parameters.acq.bb(4),parameters.acq.bb(3),length(struct_ids));
+
+for i=1:size(stack,3)
+  
+  if pair_vector(i)==2
+    db_name=parameters.acq.pair_name;
+  else
+    db_name=parameters.acq.name;
+  end
+
+  mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+    '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+    'where %sbboxes.extspotID = %d'],...
+    db_name, db_name, db_name,...
+    struct_ids(i))
+  [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+  
+  warning('bodge because some SearchBoundingBoxes have zero origins')
+  if BoundingBox(1)==0
+    BoundingBox(1)=1;
+  end
+  if BoundingBox(2)==0
+    BoundingBox(2)=1;
+  end
+  
+  % im=edf_read(sprintf('2_difspot/difspot/difspot%05d.edf',struct_ids(ca)));
+  im = gtGetSummedDifSpot_pair(struct_ids(i), pair_vector(i));
+  
+  %place in stack
+  stack(:,:,i) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  stack(:,:,i)= 100*stack(:,:,i)/sum(sum(stack(:,:,i)));  % think about some proper scaling here !
+ 
+  %write the spr/sdt projections
+  name=sprintf('%s/%s%d.sdt',graindir,grainname,i);
+	fid=fopen(name,'wb','l');
+  stack(:,:,i)=medfilt2(stack(:,:,i));
+  
+	fwrite(fid,stack(:,:,i)','float32');
+	fclose(fid);
+	name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+  spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+end	
+
+save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'replaced', 'stack', '-append') ;
+        
diff --git a/5_reconstruction/gt_dilate_grains.m b/5_reconstruction/gt_dilate_grains.m
new file mode 100755
index 0000000000000000000000000000000000000000..97229580d4615a8e340e72772dff33b66f0d74a8
--- /dev/null
+++ b/5_reconstruction/gt_dilate_grains.m
@@ -0,0 +1,75 @@
+% dilate grains to fill gaps between them.
+% one grain colour must not overgrow another.
+
+
+
+function vol_out = gt_dilate_grains(vol, dilate_length)
+
+
+%look for zero voxels, find the lowest non-zero neighbour, and change voxel
+%to that colour
+
+vol_out=vol;
+[size_x, size_y, size_z]=size(vol);
+voxels_done=[]
+
+for a=1:dilate_length
+ a
+
+ %rather than loop though everything, make a shortlist of voxels that need
+ %looking at by monochrome dilation of the grains
+mono_vol=vol>0;
+mono_dilated=imdilate(mono_vol, ones(3,3,3));
+mono_dilated=mono_dilated-mono_vol;
+todo_voxels=find(mono_dilated);
+voxels_done(a)=length(todo_voxels); 
+
+for i=1:length(todo_voxels)
+      
+  [x,y,z]=ind2sub(size(vol), todo_voxels(i));
+  
+      if vol(x,y,z) == 0 %if voxel is zero, look at neighbours...
+     
+%look at voxel neighbourhood
+xstart=x-1;
+xend=x+1;
+ystart=y-1;
+yend=y+1;
+zstart=z-1;
+zend=z+1;
+if xstart==0
+  xstart=1;
+end
+if ystart==0
+  ystart=1;
+end
+if zstart==0
+  zstart=1;
+end
+if xend>size_x
+  xend=size_x;
+end
+if yend>size_y
+  yend=size_y;
+end
+if zend>size_z
+  zend=size_z;
+end
+
+neighbours=vol(xstart:xend, ystart:yend, zstart:zend);
+neighbours=neighbours(:);
+neighbours(find(neighbours==0))=[];
+if ~isempty(neighbours)
+local_colour=min(neighbours); %lowest, non-zero neighbour
+vol_out(x,y,z)=local_colour;
+end
+        
+      end%if looking at neighbourhood
+      
+end%loop though todo_voxels
+
+vol=vol_out;%ready for next iteration
+
+end
+figure
+plot(voxels_done,'x-')
diff --git a/5_reconstruction/gt_find_grain_boundaries.m b/5_reconstruction/gt_find_grain_boundaries.m
new file mode 100755
index 0000000000000000000000000000000000000000..fe9c3fedda97cdc6691ce8ec65606ede78c47db2
--- /dev/null
+++ b/5_reconstruction/gt_find_grain_boundaries.m
@@ -0,0 +1,107 @@
+% now need to read the grain boundaries from the stack with dilated grains
+
+
+function [vol_out, boundaries, boundaries_count]=gt_find_grain_boundaries(vol)
+
+%start writing the boundaries structure.mat file
+
+
+boundaries=[];
+boundaries_count=0;
+boundaries_structure=[];
+boundary_number=1;
+[size_x, size_y, size_z]=size(vol);
+vol_out=zeros(size(vol));
+
+%find the voxels that need to be studied
+%dilates colours
+vol_dilated=imdilate(vol, ones(3,3,3));
+vol_eroded=imerode(vol,ones(3,3,3));
+dif=vol_dilated-vol_eroded;
+todo_voxels=find(dif~=0);
+
+
+for i=1:length(todo_voxels)
+  
+  
+  [x,y,z]=ind2sub(size(vol), todo_voxels(i));
+  
+%look at voxel neighbourhood
+xstart=x-1;
+xend=x+1;
+ystart=y-1;
+yend=y+1;
+zstart=z-1;
+zend=z+1;
+if xstart==0
+  xstart=1;
+end
+if ystart==0
+  ystart=1;
+end
+if zstart==0
+  zstart=1;
+end
+if xend>size_x
+  xend=size_x;
+end
+if yend>size_y
+  yend=size_y;
+end
+if zend>size_z
+  zend=size_z;
+end
+
+neighbours=vol(xstart:xend, ystart:yend, zstart:zend);
+neighbours=neighbours(:);
+%neighbours(find(neighbours==0))=[];%don't consider boundaries to zeros
+
+voxel_colour=vol(x,y,z);
+%find any different coloured neighbours
+neighbours=neighbours(find(neighbours~=voxel_colour));
+if ~isempty(neighbours)
+  neighbour_colour=min(neighbours);%lowest non-zero neighbour colour
+
+  %has this combination of voxel_colour and neighbour_colour already been
+  %treated? look for rows in boundaries
+  dummy1=find(boundaries(:)==voxel_colour);
+  [dummy1,a]=ind2sub(size(boundaries),dummy1);
+  dummy2=find(boundaries(:)==neighbour_colour);
+  [dummy2,a]=ind2sub(size(boundaries),dummy2);
+  
+  %any common rows?
+  boundary_number=dummy1(find(ismember(dummy1,dummy2)));
+  
+  if ~isempty(boundary_number) %a previously encountered boundary
+  vol_out(x,y,z)=boundary_number;
+  boundaries_count(boundary_number)=boundaries_count(boundary_number)+1;
+  %add to boundaries_structure
+  boundaries_structure(boundary_number).count=boundaries_structure(boundary_number).count+1;
+  boundary_number=[];
+  else %a new boundary
+    boundary_number=size(boundaries,1)+1
+    disp(sprintf('now on boundary %d', boundary_number))
+    vol_out(x,y,z)=boundary_number;
+    boundaries(boundary_number,:)=[voxel_colour, neighbour_colour];
+    boundaries_count(boundary_number)=1;
+    %add to boundaries_structure
+    boundaries_structure(boundary_number).grain1=voxel_colour;
+    boundaries_structure(boundary_number).grain2=neighbour_colour;
+    boundaries_structure(boundary_number).count=1;
+    boundary_number=[];
+  end
+  
+end%if a boundary voxel
+
+
+
+end %loop over todo voxels
+
+save('boundaries_structure.mat', 'boundaries_structure')
+try
+edf_write(vol_out, '5_reconstruction/boundaries_volume.edf')
+%edf_write(vol_out, 'boundaries_volume.edf')
+catch
+  disp('Had trouble writing, so putting in current directory')
+  edf_write(vol_out,'boundaries_volumes.edf');
+end
diff --git a/5_reconstruction/gt_select_projections_auto.m b/5_reconstruction/gt_select_projections_auto.m
new file mode 100755
index 0000000000000000000000000000000000000000..452a38c58a91487f32a995635c90dda1745bc86a
--- /dev/null
+++ b/5_reconstruction/gt_select_projections_auto.m
@@ -0,0 +1,179 @@
+
+function gt_select_projections_auto(grainid, varargin)
+  %function gt_select_projections_auto(grainid, varargin)
+  %varargin - flag to display figures - default true
+
+
+  plotflag=1;
+  if ~isempty(varargin)
+    plotflag=varargin{1};
+  end
+
+  filename=sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid);
+  tmp=load(filename);
+
+  if isfield(tmp, 'bad') && tmp.bad>=1
+    disp('grain already marked as bad')
+    return
+  end
+
+
+
+
+  %read stack from mat file
+  stack=tmp.stack;
+  zcenter=tmp.zcenter;
+  Omega=tmp.Omega;
+
+  [a,b,c]=size(stack);
+
+  %plot the backpro of this grain
+  if plotflag
+    figure
+    [im]=gtBackproGrain(grainid,zcenter);
+    imshow(im,[])
+  end
+
+  %get the sinogram and derived data
+  sino=stack(zcenter,:,:);
+  sino=reshape(sino,b,c);
+  binsino=sino>0.1*max(sino(:));
+  sino_centers=[];
+  sino_widths=[];
+
+  for i=1:size(sino,2)
+
+    %greyscale center
+    sino_centers(i)=(sino(:,i)'*[1:length(sino)]')/sum(sino(:,i));
+
+    %width from the thresholded sino
+    if max(binsino(:,i))~=0
+      dummy=find(binsino(:,i));
+      sino_widths(i)=max(dummy)-min(dummy);
+      sino_edge1(i)=min(dummy);
+      sino_edge2(i)=max(dummy);
+    else %case where no intensity in sinogram
+      sino_widths(i)=NaN;
+      sino_edge1(i)=NaN;
+      sino_edge2(i)=NaN;
+
+    end
+
+  end
+
+
+  %plot the sinogram data - this wil be used to try and select bad
+  %projections
+
+  if plotflag
+    figure
+    plot(Omega,sino_centers,'xr')
+    hold on
+    plot(Omega,sino_widths,'xb')
+    plot(Omega,sino_edge1,'xg')
+    plot(Omega,sino_edge2,'xk')
+
+  end
+
+  %fit sine function to the plots
+  %fist guess: x0=[A, B, C]
+  %options=optimset('lsqcurvefit');
+  options=optimset('MaxFunEvals',200);
+
+
+  bad_initially = find(isnan(sino_centers)); %take these out straight away
+  bad_initially = [bad_initially find(isnan(sino_widths))]; %take these out straight away
+
+  dummy=find(~isnan(sino_centers) & ~isnan(sino_widths) & ~isnan(sino_edge1) & ~isnan(sino_edge2)); %don't use bad ones
+  Omzero=Omega(find(sino_centers==max(sino_centers)));
+  Omzero=(Omzero*pi/180)+pi/2;
+  x0=[std(sino_centers(dummy)), Omzero, mean(sino_centers(dummy))];
+  [x_centers,a,residuals_centers] = lsqcurvefit(@sfSinoFunction, x0, Omega(dummy), sino_centers(dummy));
+
+  %dummy=find(~isnan(sino_widths)); %don't use bad ones
+  Omzero=Omega(find(sino_widths==max(sino_widths)));
+  Omzero=(Omzero*pi/180)+pi/2;
+  x0=[std(sino_widths(dummy)), 0, mean(sino_widths(dummy))];
+  [x_widths,a,residuals_widths] = lsqcurvefit(@sfSinoFunction, x0, Omega(dummy), sino_widths(dummy));
+
+  %dummy=find(~isnan(sino_edge1)); %don't use bad ones
+  Omzero=Omega(find(sino_edge1==max(sino_edge1)));
+  Omzero=(Omzero*pi/180)+pi/2;
+  x0=[std(sino_edge1(dummy)), 0, mean(sino_edge1(dummy))];
+  [x_edge1,a,residuals_edge1] = lsqcurvefit(@sfSinoFunction, x0, Omega(dummy), sino_edge1(dummy));
+
+  %dummy=find(~isnan(sino_edge2)); %don't use bad ones
+  Omzero=Omega(find(sino_edge2==max(sino_edge2)));
+  Omzero=(Omzero*pi/180)+pi/2;
+  x0=[std(sino_edge2(dummy)), 0, mean(sino_edge2(dummy))];
+  [x_edge2,a,residuals_edge2] = lsqcurvefit(@sfSinoFunction, x0, Omega(dummy), sino_edge2(dummy));
+
+
+
+  if plotflag
+    x1=1:360;
+    %x1=-x1;
+    y1 = sfSinoFunction(x_centers,x1);
+    plot(x1,y1, 'r-')
+    y1 = sfSinoFunction(x_widths,x1);
+    plot(x1,y1, 'b-')
+    y1 = sfSinoFunction(x_edge1,x1);
+    plot(x1,y1, 'g-')
+    y1 = sfSinoFunction(x_edge2,x1);
+    plot(x1,y1, 'k-')
+  end
+
+  %use the residuals to select bad projections (2*std dev test)
+  if length(Omega)>50
+    range=0.8
+  elseif length(Omega)>30
+    range=1.2
+  else
+    range=1.7;
+  end
+
+
+  bad_centers = dummy(find(abs(residuals_centers)>range*std(residuals_centers)));
+  bad_widths = dummy(find(abs(residuals_widths)>range*std(residuals_widths)));
+
+  bad_edge1 = dummy(find(abs(residuals_edge1)>range*std(residuals_edge1)));
+  bad_edge2 = dummy(find(abs(residuals_edge2)>range*std(residuals_edge2)));
+
+
+
+
+
+  index=ones(size(Omega));
+
+  index(bad_initially)=0;
+  index(bad_centers)=0;
+  index(bad_widths)=0;
+  index(bad_edge1)=0;
+  index(bad_edge2)=0;
+  
+  %avoid problem where almost all projections are excluded
+  if length(find(index))/length(index)<0.7
+    disp('select projections auto not happy - ignoring results - no changes')
+    disp(sprintf('would use only %0.2f of projections', length(find(index))/length(index)))
+    %reset index to ones, ignore automatic result
+    return
+  end
+
+  if 1
+    %save this index of spots to use into the .mat file
+    save(filename, 'index', '-append');
+  else
+    disp('not saving changes!')
+  end
+
+end
+
+%sinogram function
+function predicted_data=sfSinoFunction(x, Omega)
+  %function y = A*sin(omega+B) + C
+  predicted_data = (x(1)*sin((Omega*pi/180)+x(2))) + x(3);
+end
+
+
+
+
diff --git a/5_reconstruction/gtassemble_lastandprevious.m b/5_reconstruction/gtassemble_lastandprevious.m
new file mode 100755
index 0000000000000000000000000000000000000000..2ccd75a75196ede84b8d9d6af99984b9e5e5c446
--- /dev/null
+++ b/5_reconstruction/gtassemble_lastandprevious.m
@@ -0,0 +1,52 @@
+% this macro takes the size of the thresholded grains in last and
+% first dataset respectivelly, using the table (C) generated by
+% gtcorrelatenewandolddata_marcelo_2, usually, first is the first step of growth
+% and last is the last step of growth 
+
+function G=gtassemble_lastandprevious(grainIDs5, grainIDs1, last_dataset, first_dataset) %grain IDs in the last and first dataset
+
+A=sprintf('/data/id19/graintracking/graingrowth/%s/4_grains/grain%d_/grain%d_2.edf', last_dataset, grainIDs5, grainIDs5);
+A1=edf_read(A);
+B=size(A1);
+C=sprintf('/data/id19/graintracking/graingrowth/%s/4_grains/grain%d_/grain%d_2.edf',first_dataset, grainIDs1, grainIDs1);
+C1=edf_read(C);
+D=size(C1);
+E=[];
+
+	if D(1)>B(1)
+		E(1)=D(1).*2;
+	else
+		E(1)=B(1).*2;
+	end
+	
+	if D(2)>B(2)
+		E(2)=D(2);
+	else
+		E(2)=B(2);
+	end
+	
+	if D(3)>B(3)
+		E(3)=D(3);
+	else
+		E(3)=B(3);
+	end
+	
+F(1)=E(1)/2;
+
+G=zeros(E(1),E(2),E(3));
+
+for i=1:B(1)
+	for j=1:B(2)
+		for k=1:B(3)
+			G(i,j,k)=A1(i,j,k);
+		end
+	end
+end
+
+for i=F(1):(F(1)+D(1)-1)
+	for j=1:D(2)
+		for k=1:D(3)
+			G(i,j,k)=C1(((i+1)-(F(1))),j,k);
+		end
+	end
+end
\ No newline at end of file
diff --git a/5_reconstruction/gtnew_assemble_slice.m b/5_reconstruction/gtnew_assemble_slice.m
new file mode 100755
index 0000000000000000000000000000000000000000..a72689e9926c8aae95f0697b1a1348dc055e3f12
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_slice.m
@@ -0,0 +1,66 @@
+function [output,combined] = gtnew_assemble_slice(z_position)
+
+%load data
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+output = zeros(parameters.acq.bb(3), parameters.acq.bb(3),88);
+combined = zeros(parameters.acq.bb(3));
+
+for i=1:131
+  
+  disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+  
+  try 
+    
+%    vol = sdtread(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+vol = threshold_grain_auto(i);
+%    vol = edf_read(sprintf('4_grains/grain%d_/grain%d_.vol',i,i));
+
+ %   tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',i,i));
+    
+   % gtDoART(i);%to relaunch with different parameteres
+   
+   
+    
+zstart = tmp.zstart;
+slice = z_position - zstart;
+% 
+% %generally more to be done on this script...
+% 
+% if (slice > size(vol,3)*0.25 & slice <= size(vol,3)*0.75)
+ img = vol(:,:,slice);
+% lims=autolim(vol(:));
+% if lims(2)>0
+%   img = img/lims(2);
+%   img = img>0.1;
+% end
+
+%seem to have to transpose ART reconstruction output to matck backpro
+
+img = gtPlaceSubImage(img, zeros(parameters.acq.bb(3)), tmp.x1, tmp.y1);
+output(:,:,i)=img;
+
+if 1%interactive
+imshow(img,[])
+disp('click in image to add to summed slice, outside to skip')
+point=ginput(1)
+if (point(1)<1 | point(1)>parameters.acq.bb(3) | point(2)<1 | point(2)>parameters.acq.bb(3))
+  disp('skipping...')
+else
+  combined = combined+(img*i);
+end
+end
+
+%end
+
+
+
+  catch
+disp('try failed')
+  end
+  
+
+end
diff --git a/5_reconstruction/gtnew_assemble_slice_special.m b/5_reconstruction/gtnew_assemble_slice_special.m
new file mode 100755
index 0000000000000000000000000000000000000000..2f564e16bd11f202bb2635615e602cef656cf67d
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_slice_special.m
@@ -0,0 +1,182 @@
+function output = gtnew_assemble_slice_special(slice, grains)
+%output - volume the size of the sample
+%version 2 - bad grain info is in the .mat file, not hardcoded here
+
+%add some useful info to the mat file - bounding box and CoM of
+%postprocessed grain
+
+%load data
+
+  load parameters.mat
+
+
+%add a border to allow grains to overflow acq.bb limits
+border=20;
+output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+bboxes=[];
+
+  for k=1:length(grains)
+    i=grains(k)
+    
+disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+  try 
+
+% gtDoART(i);%to relaunch with different parameteres
+   
+vol_filename = sprintf('4_grains/grain%d_/grain%d_2.edf',i,i);
+mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',i,i);
+tmp = load(mat_filename);
+
+
+
+if isfield(tmp, 'bad') && (tmp.bad==1 | tmp.bad==2)% | tmp.bad==0.5) %1=bad / 2=combined / 0.5=bad-ish
+    
+    disp(sprintf('skipping grain %d', i))
+    
+  continue
+else
+
+  if 0%~exist(vol_filename,'file')  %if no post-processed file exists
+
+    %to use threshold grain.m
+    vol = threshold_grain_auto(i);
+    %get grain data (again, new stuff will have been added by threshold grain)
+    tmp = load(mat_filename);
+    %limits, allowing for the extra border
+    min3 = tmp.vol_z_origin;
+    max3 = min3 + tmp.vol_z_size-1;
+    min1 = tmp.vol_y_origin+border;
+    max1 = min1 + tmp.vol_y_size-1;
+    min2 = tmp.vol_x_origin+border;
+    max2 = min2 + tmp.vol_x_size-1;
+
+  elseif 0
+    %use previously thresholded grain
+    vol = edf_read(vol_filename);
+    %get grain data
+    tmp = load(mat_filename);
+    %limits, allowing for the extra border
+    min3 = tmp.vol_z_origin;
+    max3 = min3 + tmp.vol_z_size-1;
+    min1 = tmp.vol_y_origin+border;
+    max1 = min1 + tmp.vol_y_size-1;
+    min2 = tmp.vol_x_origin+border;
+    max2 = min2 + tmp.vol_x_size-1;
+    
+
+
+  else
+    %old style - this works with the .mat values, and the original .sdt
+    %dimensions
+    %for a crude threshold
+    vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+    %improve the calculation of this value.
+    a=max(vol(:));
+    thresh_val = mean(vol(find(vol>(a/10))))-std(vol(find(vol>(a/10))));%std dev, ignoring low (background) values
+    vol=vol>thresh_val;
+    
+    %get grain data
+    tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',i,i));
+    min3 = tmp.zstart;
+    max3 = tmp.zend-1;
+    min2 = tmp.x1+border;
+    max2 = min2 + tmp.nx-1;
+    min1 = tmp.y1+border;
+    max1 = min1 + tmp.ny-1;
+
+  end %how to threshold grain choise
+
+
+%have to deal with bounding boxs that exceed the slice size
+if min1<1
+  tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+  min1=1;
+  vol=vol(tmp:end,:,:);
+end
+if min2<1
+  tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+  min2=1;
+  vol=vol(:,tmp:end,:);
+end
+if min3<1
+  tmp=2-min3;%if z1==0, crop one row of voxels from vol
+  min3=1;
+  vol=vol(:,:,tmp:end);
+end
+if max1>parameters.acq.bb(3)+(2*border);
+  tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+  max1=parameters.acq.bb(3)+(2*border);
+  vol=vol(1:end-tmp,:,:);
+end
+if max2>parameters.acq.bb(3)+(2*border);
+  tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+  max2=parameters.acq.bb(3)+(2*border);
+  vol=vol(:,1:end-tmp,:);
+end
+if max3>parameters.acq.bb(4);
+  tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+  max3=parameters.acq.bb(4);
+  vol=vol(:,:,1:end-tmp);
+end
+
+%add grain to volume, colour coded
+vol=vol*i;
+size(vol)
+length([min1:max1])
+length([min2:max2])
+length([min3:max3])
+
+
+output(min1:max1, min2:max2, min3:max3)=output(min1:max1, min2:max2, min3:max3)+vol;
+
+%get bounding box of the post processed grain
+zpro=squeeze(sum(sum(vol, 1),2));
+postbb(3)=min(find(zpro));
+postbb(6)=max(find(zpro))-postbb(3);
+zpro=reshape(zpro, 1, length(zpro));
+postcent(3)=zpro*(1:length(zpro))'/sum(zpro);
+
+xpro=squeeze(sum(sum(vol, 3),1));
+postbb(1)=min(find(xpro));
+postbb(4)=max(find(xpro))-postbb(1);
+%xpro=reshape(xpro, 1, length(xpro));
+postcent(1)=xpro*(1:length(xpro))'/sum(xpro);
+
+ypro=squeeze(sum(sum(vol, 3),2));
+postbb(2)=min(find(ypro));
+postbb(5)=max(find(ypro))-postbb(2);
+ypro=reshape(ypro, 1, length(ypro));
+postcent(2)=ypro*(1:length(ypro))'/sum(ypro);
+
+postbb=postbb+[min2 min1 min3 0 0 0];
+postcent=postcent+[min2 min1 min3];
+
+bboxes(i,:)=[postbb postcent];
+save(mat_filename, 'postbb', 'postcent', '-append')
+
+
+if 0%interactive
+imshow(img,[])
+disp('click in image to add to summed slice, outside to skip')
+point=ginput(1)
+if (point(1)<1 | point(1)>parameters.acq.bb(3) | point(2)<1 | point(2)>parameters.acq.bb(3))
+  disp('skipping...')
+else
+  combined = combined+(img*i);
+end
+end
+
+%end
+
+
+  end%bads check if bad skip/else try to do grain
+  
+  
+  catch
+disp('try failed')
+end%try catch loop
+
+end%loop through all grains
+
+output=output(:,:,slice);
+
diff --git a/5_reconstruction/gtnew_assemble_slice_wl.m b/5_reconstruction/gtnew_assemble_slice_wl.m
new file mode 100755
index 0000000000000000000000000000000000000000..07e05c3b7e2928ab93a311b8816e508f1b83795e
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_slice_wl.m
@@ -0,0 +1,131 @@
+function [colour_slice,art_out_seg] = gtnew_assemble_slice_wl
+
+% create colourmap for grain;
+
+lim=sqrt(2)-1;%extent of the fundamental cube - rescale to 0-1
+lim=lim+0.05; %some r_vectors apparently just outside the zone
+
+
+  snakeoptions.elasticity=.3; ;
+  snakeoptions.rigidity=10;  % keep this high to prevent spurs from local features
+  snakeoptions.viscosity=1;
+  snakeoptions.forcefactor=1;
+  snakeoptions.iterations=3;
+
+
+%load data
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+% replace this by a database search of the grains belonging to the slice...
+grain_ids=load('slice.mat');
+grain_ids=grain_ids.slice;
+
+
+art_out_raw = zeros(parameters.acq.bb(3), parameters.acq.bb(3),length(grain_ids));    % raw art output
+art_out_seg = zeros(parameters.acq.bb(3), parameters.acq.bb(3),length(grain_ids));    % segmented art output stack
+colour_slice = zeros(parameters.acq.bb(3),parameters.acq.bb(3),3);                    % colour coded slice (R-vector) - overlaps removed  
+labeled_slice=zeros(parameters.acq.bb(3));                                            % labeled slice (grainID) - overlaps removed
+overlap=false(size(labeled_slice));                                                   % logical array containing overlapping pixels
+
+j=1;
+
+for i=grain_ids
+  
+  disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+  vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+  %    vol = threshold_grain_auto(i);
+  %    vol = edf_read(sprintf('4_grains/grain%d_/grain%d_filled.edf',i,i));
+
+  tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',i,i));
+  img = vol(:,:,3);
+  
+  % try to segment the grain via image reconstruction
+  thresh_val=0.5*graythresh(img);   % 0.5 seems to be a reasonable value
+  
+  h=figure(1);
+  
+  [thresh_val,mask]=gtAdjustThreshold(thresh_val,img,h);
+  
+  
+ 
+  title('click into grain to proceed / outside image to skip grain');
+  
+  point=round(ginput(1));
+  if (point(1)<1 | point(1)>size(img,2) | point(2)<1 | point(2)>size(img,1))
+	disp('skipping...')
+	j=j+1;
+  else
+	
+	marker=zeros(size(img));
+	marker(point(2),point(1))=1;
+	imgs=imreconstruct(marker,mask);  % segmented image
+    imgss=gtSnakeBW(imgs,snakeoptions);
+	
+	title('click into image to accept, outside to change settings');
+	point=round(ginput(1));
+    while (point(1)<1 | point(1)>size(img,2) | point(2)<1 | point(2)>size(img,1))
+	  disp('enter new snakeoption values...')
+	  snakeoptions
+	  keyboard;
+	  mask=double(img>thresh_val);
+	  imgs=imreconstruct(marker,mask);
+	  subplot(1,2,2)
+      imshow(imgs,[]);
+	  imgss=gtSnakeBW(imgs,snakeoptions);
+	  disp('click in image to accept result, outside to change parameters')
+      point=round(ginput(1));
+	end
+	imgs=logical(imgss);
+ 
+	% give the grain a colour linked to its r-vector
+
+	mapval=abs(tmp.R_vector)/lim;
+
+	img = gtPlaceSubImage(imgs, zeros(parameters.acq.bb(3)), tmp.x1, tmp.y1);   % put grain back in sample coordinates
+	
+	
+	
+	art_out_seg(:,:,j)=j*img;     % segmented and labeled grain image stack 
+
+	overlap=overlap|(j*img+labeled_slice>j);    
+
+	overlapc=cat(3,overlap,false(size(overlap)),false(size(overlap)));  % assign red to overlapping pixels
+
+	labeled_slice=labeled_slice+j*img;
+	labeled_slice(overlap)=0;     % set overlapping pixels to zero
+
+	% add colour to current grain
+	imgc=cat(3,img*mapval(1),img*mapval(2),img*mapval(3));
+	
+	
+	colour_slice=colour_slice+imgc;  % add grain to slice
+
+	colour_slice1=colour_slice(:,:,1);
+	colour_slice1(overlap)=1;
+	colour_slice2=colour_slice(:,:,2);
+	colour_slice2(overlap)=0;
+	colour_slice3=colour_slice(:,:,3);
+	colour_slice3(overlap)=0;
+	colour_slice=cat(3,colour_slice1,colour_slice2,colour_slice3);    % set overlapping pixels to red
+
+	j=j+1;
+
+  end
+
+  
+%   refine=1;
+%   while refine
+% 	
+% 	figure(2);imshow(labeled_slice,[])
+% 	[x,y]=ginput(1);
+% 	j=labeled_slice(y,x);
+
+
+end  % for i=grain_ids
+
+end
+
+
diff --git a/5_reconstruction/gtnew_assemble_vol.m b/5_reconstruction/gtnew_assemble_vol.m
new file mode 100755
index 0000000000000000000000000000000000000000..b419dba847f62f22c4c165dd4405be719b09f0cf
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_vol.m
@@ -0,0 +1,191 @@
+function output = gtnew_assemble_vol
+%output - volume the size of the sample
+
+%load data
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%add a border to allow grains to overflow acq.bb limits
+border=20;
+output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+
+%bads - grains to be ignored
+
+bads=[];
+if 1
+% ss_crackedA_ bads list
+bads=[2 14 25 38 44];
+bads=[bads 9 30 45];
+%definate bads
+bads=[bads 56 59 72 83 84 86 107 112 119 151 157 165 188 191 193 194 209 212 213 215 274 276 306 ...
+  314 315 318 323 326 332 337 341 347 349 354 355 356 364 366 373 374 376 380 382 389 390 391 396 403 405 406 ...
+  411 415 417 428 431 435 443 444 452 454 457 460 470 474 481 483 491 494];
+%less bad bads
+if 1 % if removing these
+bads=[bads 64 85 88 98 107 122 128 130 132 133 140 150 154 162 182 186 198 210 217 221 227 229 267 ...
+  270 277 282 289 300 303 307 308 309 333 351 384 420 441 446 450 462 468 473 480 493];
+end
+
+
+%%to accomodate renumbering!
+%redos=[48 41 154 303 367 104 305 388]; %grains removed by renumbering
+%for j=1:length(redos)
+%dummy=find(bads>redos(j))
+%bads(dummy)=bads(dummy)-1;
+%end
+
+end
+
+%bads=[22 37 53 71 72]; % list of grains to skip
+
+%bads = [42 97 54 65 85 129 81 99 118];%for central slice grains 0-130ish
+%bads=[bads 224 271 358 220 361 382 205 350 357 260 360 365];%for bottom half
+%bads = [bads 159 172 279 236 227 306];%for bottom half, duplicates of central slice grains
+
+
+%for i=1:499
+test=[1 48 3 131 33 367 49 65 63 69 79 148 81 96 89 100 114 170 125 218 136 138 139 172 176 216 178 305 180 250 208 258 234 489 238 245 313 372 407 461 53 61 62 57 74 123 153 187 249 117 118 167]
+  for j=1:52
+    i=test(j)
+    
+%for i=131:-1:1 %for central slice
+%for i=424:-1:151%for bottom half
+  
+dummy=find(bads==i);
+if ~isempty(dummy)
+  continue
+else
+  
+disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+  
+  try 
+
+% gtDoART(i);%to relaunch with different parameteres
+   
+vol_filename = sprintf('4_grains/grain%d_/grain%d_2.edf',i,i);
+mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',i,i);
+
+if ~exist(vol_filename,'file')  %if no post-processed file exists
+
+%to use threshold grain.m
+vol = threshold_grain_auto(i);
+%get grain data
+tmp = load(mat_filename);
+%limits, allowing for the extra border
+min3 = tmp.vol_z_origin;
+max3 = min3 + tmp.vol_z_size-1;
+min1 = tmp.vol_y_origin+border;
+max1 = min1 + tmp.vol_y_size-1;
+min2 = tmp.vol_x_origin+border;
+max2 = min2 + tmp.vol_x_size-1;
+
+elseif 1
+%use previously thresholded grain
+vol = edf_read(vol_filename);
+%get grain data
+tmp = load(mat_filename);    
+%limits, allowing for the extra border
+min3 = tmp.vol_z_origin;
+max3 = min3 + tmp.vol_z_size-1;
+min1 = tmp.vol_y_origin+border;
+max1 = min1 + tmp.vol_y_size-1;
+min2 = tmp.vol_x_origin+border;
+max2 = min2 + tmp.vol_x_size-1;
+
+
+
+else
+%old style - this works with the .mat values, and the original .sdt
+%dimensions
+%for a crude threshold   
+vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+thresh_val = std(vol(find(vol~=0)));%std dev, ignoring zeros
+vol=vol>thresh_val;
+
+%get grain data
+tmp = load(sprintf('4_grains/grain%d_/grain%d_.mat',i,i));    
+min3 = tmp.zstart;
+max3 = tmp.zend-1;
+min2 = tmp.x1+border;
+max2 = min2 + tmp.nx-1;
+min1 = tmp.y1+border;
+max1 = min1 + tmp.ny-1;
+
+end %if after threshold grain
+
+
+%have to deal with bounding boxs that exceed the slice size
+if min1<1
+  tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+  min1=1;
+  vol=vol(tmp:end,:,:);
+end
+if min2<1
+  tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+  min2=1;
+  vol=vol(:,tmp:end,:);
+end
+if min3<1
+  tmp=2-min3;%if z1==0, crop one row of voxels from vol
+  min3=1;
+  vol=vol(:,:,tmp:end);
+end
+if max1>parameters.acq.bb(3)+(2*border);
+  tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+  max1=parameters.acq.bb(3)+(2*border);
+  vol=vol(1:end-tmp,:,:);
+end
+if max2>parameters.acq.bb(3)+(2*border);
+  tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+  max2=parameters.acq.bb(3)+(2*border);
+  vol=vol(:,1:end-tmp,:);
+end
+if max3>parameters.acq.bb(4);
+  tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+  max3=parameters.acq.bb(4);
+  vol=vol(:,:,1:end-tmp);
+end
+
+
+
+%add grain to volume, colour coded
+vol=vol*(i+25);
+size(vol)
+length([min1:max1])
+length([min2:max2])
+length([min3:max3])
+
+
+output(min1:max1, min2:max2, min3:max3)=output(min1:max1, min2:max2, min3:max3)+vol;
+
+
+if 0%interactive
+imshow(img,[])
+disp('click in image to add to summed slice, outside to skip')
+point=ginput(1)
+if (point(1)<1 | point(1)>parameters.acq.bb(3) | point(2)<1 | point(2)>parameters.acq.bb(3))
+  disp('skipping...')
+else
+  combined = combined+(img*i);
+end
+end
+
+%end
+
+
+
+  catch
+disp('try failed')
+end%try catch loop
+
+  end%bads check if bad skip/else try to do grain
+end%loop through all grains
+
+%output(find(output>255))=255;
+if 0 %to save
+  name=sprintf('5_reconstruction/%s_volume3.edf',parameters.acq.name);
+  disp(sprintf('writing volume %s',name));
+  edf_write(output,name,'uint16');
+end
\ No newline at end of file
diff --git a/5_reconstruction/gtnew_assemble_vol2.m b/5_reconstruction/gtnew_assemble_vol2.m
new file mode 100755
index 0000000000000000000000000000000000000000..29738a62b64eed875aa5ea6459245f2c8d85b9f0
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_vol2.m
@@ -0,0 +1,211 @@
+function [output, redo] = gtnew_assemble_vol2(list, varargin)
+%output - volume the size of the sample
+%version 2 - bad grain info is in the .mat file, not hardcoded here
+
+%add some useful info to the mat file - bounding box and CoM of
+%postprocessed grain
+
+%varargin - overlaps - 'zeros' causes overlapping regions to be set to
+%zero.  Otherwise, overlapping labels are summed.
+
+savefilename=[];
+if ~isempty(varargin)
+  savefilename=varargin{1};
+else
+  disp('not saving data - to save, supply a filename as the second argument')
+  pause(2)
+end
+
+overlaps=[];
+if ~isempty(varargin) && length(varargin)==2
+    overlaps=varargin{2};
+end
+
+display_error_messages=0;
+
+
+%load data
+
+load parameters.mat
+
+
+%add a border to allow grains to overflow acq.bb limits
+border=20;
+output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+bboxes=[];
+redo=[];
+
+%for i=234:304
+
+      for k=1:length(list)
+
+        i=list(k);
+% modif sabine
+% keyboard
+% end modif sabine
+    disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+   try
+
+        % gtDoART(i);%to relaunch with different parameteres
+
+        vol_filename = sprintf('4_grains/grain%d_/grain%d_filled.edf',i,i);
+        mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',i,i);
+        tmp = load(mat_filename, 'bad', 'zstart', 'zend', 'x1','y1','nx','ny');
+
+
+
+        if isfield(tmp, 'bad') && (tmp.bad==1 | tmp.bad==2)% | tmp.bad==0.5) %1=bad / 2=combined / 0.5=bad-ish
+
+            disp(sprintf('skipping grain %d', i))
+
+            continue
+        else
+
+            if exist(vol_filename,'file')  %if no post-processed file exists
+
+                vol=edf_read(vol_filename);
+
+                % modif sabine
+                %   elseif 1
+                %     'skipping other grains'
+                % fin modif sabine
+
+            else
+
+                %old style - this works with the .mat values, and the original .sdt
+                %dimensions
+                %for a crude threshold
+                disp(' old version')
+                vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+                %put calculation in a function - works better than
+                % graythresh
+                vol=gtThresholdGrain(vol);
+
+
+            end
+
+            %get grain data
+            min3 = tmp.zstart;
+            max3 = tmp.zend-1;
+            min2 = tmp.x1+border;
+            max2 = min2 + tmp.nx-1;
+            min1 = tmp.y1+border;
+            max1 = min1 + tmp.ny-1;
+
+
+            %have to deal with bounding boxs that exceed the slice size
+            if min1<1
+                tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+                min1=1;
+                vol=vol(tmp:end,:,:);
+            end
+            if min2<1
+                tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+                min2=1;
+                vol=vol(:,tmp:end,:);
+            end
+            if min3<1
+                tmp=2-min3;%if z1==0, crop one row of voxels from vol
+                min3=1;
+                vol=vol(:,:,tmp:end);
+            end
+            if max1>parameters.acq.bb(3)+(2*border);
+                tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+                max1=parameters.acq.bb(3)+(2*border);
+                vol=vol(1:end-tmp,:,:);
+            end
+            if max2>parameters.acq.bb(3)+(2*border);
+                tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+                max2=parameters.acq.bb(3)+(2*border);
+                vol=vol(:,1:end-tmp,:);
+            end
+            if max3>parameters.acq.bb(4);
+                tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+                max3=parameters.acq.bb(4);
+                vol=vol(:,:,1:end-tmp);
+            end
+
+            %add grain to volume, colour coded
+            vol=vol*i;
+            %for display only:
+            %size(vol)
+            %length([min1:max1])
+            %length([min2:max2])
+            %length([min3:max3])
+
+            if strcmp(overlaps,'zeros')
+                %stop overlapping...
+                tmp_output=zeros(size(output));
+                tmp_output(min1:max1, min2:max2, min3:max3)=vol;
+                output(find(output==0 & tmp_output))=i;%set undisputed voxels to i
+                output(find(output~=i & tmp_output))=-1;%set overlaps to -1
+            else
+                output(min1:max1, min2:max2, min3:max3)=output(min1:max1, min2:max2, min3:max3)+vol;
+            end
+
+            %get bounding box of the post processed grain
+            zpro=squeeze(sum(sum(vol, 1),2));
+            postbb(3)=min(find(zpro));
+            postbb(6)=max(find(zpro))-postbb(3);
+            zpro=reshape(zpro, 1, length(zpro));
+            postcent(3)=zpro*(1:length(zpro))'/sum(zpro);
+
+            xpro=squeeze(sum(sum(vol, 3),1));
+            postbb(1)=min(find(xpro));
+            postbb(4)=max(find(xpro))-postbb(1);
+            %xpro=reshape(xpro, 1, length(xpro));
+            postcent(1)=xpro*(1:length(xpro))'/sum(xpro);
+
+            ypro=squeeze(sum(sum(vol, 3),2));
+            postbb(2)=min(find(ypro));
+            postbb(5)=max(find(ypro))-postbb(2);
+            ypro=reshape(ypro, 1, length(ypro));
+            postcent(2)=ypro*(1:length(ypro))'/sum(ypro);
+
+            postbb=postbb+[min2 min1 min3 0 0 0];
+            postcent=postcent+[min2 min1 min3];
+
+            bboxes(i,:)=[postbb postcent];
+            save(mat_filename, 'postbb', 'postcent', '-append')
+
+
+            if 0%interactive
+                imshow(img,[])
+                disp('click in image to add to summed slice, outside to skip')
+                point=ginput(1)
+                if (point(1)<1 | point(1)>parameters.acq.bb(3) | point(2)<1 | point(2)>parameters.acq.bb(3))
+                    disp('skipping...')
+                else
+                    combined = combined+(img*i);
+                end
+            end
+
+            %end
+
+
+        end%bads check if bad skip/else try to do grain
+
+
+   catch
+
+     if display_error_messages
+     disp('try failed')
+   msg=lasterror;
+   msg.message
+     end
+   
+   redo=[redo i];
+   
+   end%try catch loop
+
+end%loop through all grains
+
+
+output(find(output==-1))=0;%set overlapping regions to zero - this could be another label colour
+
+
+if ~isempty(savefilename)
+    name=sprintf('5_reconstruction/%s',savefilename);
+    disp(sprintf('writing volume %s',name));
+    edf_write(output,name,'uint16');
+end
diff --git a/5_reconstruction/gtnew_assemble_vol3.m b/5_reconstruction/gtnew_assemble_vol3.m
new file mode 100755
index 0000000000000000000000000000000000000000..5d65af5bb656470fb69f81e57d5d9ac50c707e11
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_vol3.m
@@ -0,0 +1,281 @@
+%dilate the grains to fill gaps between them
+%only dilate grain into space, not one grain into another.
+
+%then to read the grain boundaries, need to handle overlaps/twins
+
+%perhaps as a first measure, set non-twin overlaps to zero, based on the
+%previously determined "twin list"
+
+%perhaps twin overlaps should be coloured differently, or the overlaps
+%shouldn't be summed.
+
+%easiest might be to use the twin list to make twined grains first, and
+%then add the twin to the main volume following standard rules on overlap.
+
+%need to do this at the point of constructing the volume (before labels
+%overlap and get confused)
+
+%take framework from gtnew_assemble_vol2.m
+
+function output = gtnew_assemble_vol3(twin_list)
+
+%for ss_crackedA_
+%twin_list=[342 412 0; 224 284 0; 108 198 0; 161 195 0; 63 472 0; 137 279 0; 79 148 0;...
+%  136 138 0; 89 100 0; 145 226 0; 4 288 440; 42 46 0; 156 159 0; 143 330 0; 105 282 0;... 
+%93 113 0; 238 245 0; 179 309 0; 177 223 0; 196 327 0; 126 210 0; 66 76 0]
+
+%for ss2007_A_
+%twin_list=[196 209; 156 458; 9 10; 2 4; 564 1042; 329 420; 21 35; 75 85; 138 214; 152 184]
+
+
+%load data
+  load parameters.mat
+
+
+
+
+%add a border to allow grains to overflow acq.bb limits
+border=20;
+%volume for output
+output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+
+%do twinned grains
+for i=1:size(twin_list,1)
+  i
+  grain_list=twin_list(i,:);
+  grain_list(find(grain_list==0))=[];
+  grain_sizes=[];
+
+  %get grain sizes so they can be added in order
+  for j=1:length(grain_list)
+    grain_sizes(j)=sfGetGrainSize(grain_list(j), parameters);
+  end
+  [grain_sizes,index]=sort(grain_sizes, 'descend');
+  %grains in order, largest first
+  grain_list=grain_list(index);
+
+  %add grains in order to make twin grain
+  twin_output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+  for j=1:length(grain_list)
+    j
+    mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',grain_list(j), grain_list(j));
+    tmp = load(mat_filename, 'bad', 'x1', 'nx', 'y1', 'ny', 'zstart', 'zend');
+    if (isfield(tmp, 'bad') && (tmp.bad==1 | tmp.bad==2)) %which grains to include
+      disp(sprintf('skipping grain %d', grain_list(j)))
+      continue %if skipping this grain
+    else
+      temp_output=sfGetGrain(grain_list(j), tmp, border, parameters);
+      twin_output(find(temp_output))=grain_list(j);
+    end
+  end
+  %twin output contains the twinned grain, to add to the main output
+
+  %set overlaps to -1 (will set to zero at end)
+  output(find(twin_output~=0 & output~=0))=-1;
+  %add non-overlapping bits to output
+  output(find(twin_output>0 & output==0))=twin_output(find(twin_output>0 & output==0));
+  %clear twin_output
+
+  clear twin_output;
+
+end
+
+%set overlaps to zero
+output(find(output==-1))=0;
+    
+
+%do all other grains
+%skip grains already dealt with
+skip=twin_list(:);
+skip(find(skip==0))=[];
+
+for i=1:1038
+  disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+   if any(skip==i)
+     continue
+   end
+  
+  try
+
+    mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',i,i);
+    tmp = load(mat_filename, 'bad', 'x1', 'nx', 'y1', 'ny', 'zstart', 'zend');
+    
+    if (isfield(tmp, 'bad') && (tmp.bad==1 | tmp.bad==2))% | tmp.bad==0.5)  %which grains to include
+
+            disp(sprintf('skipping grain %d', i))
+      continue %if skipping this grain
+    else
+
+      %define a subfunction to read the grain volume and paste it into the
+      %right place in a volume the same size as the output volume
+      temp_output=sfGetGrain(i, tmp, border, parameters);
+      
+      %set overlaps to -1 (will set to zero at end)
+      output(find(temp_output~=0 & output~=0))=-1;
+      %add non-overlapping bits to output
+      output(find(temp_output>0 & output==0))=i*temp_output(find(temp_output>0 & output==0));
+      %clear temp_output
+      clear temp_output;
+
+
+
+
+    end
+
+
+    end
+
+end
+
+%set overlaps to zero
+output(find(output==-1))=0;
+    
+
+edf_write(output, '5_reconstruction/ss2007_A_twin_vol4.edf')
+
+
+end%end of function
+      
+      
+%sfGetGrain
+function temp_output = sfGetGrain(i, tmp, border, parameters);
+%i is the grainid
+%tmp is the matfile data structure
+%border is the border size
+%returns the grain placed in a volume the size of the final volume
+temp_output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+
+if 1 % newer style grain filled by snake
+
+  vol_filename = sprintf('4_grains/grain%d_/grain%d_filled.edf',i,i);
+%get and threshold grain volume
+  if exist(vol_filename,'file')  %if post-processed file exists
+    vol=edf_read(vol_filename);
+  else
+    %old style - this works with the .mat values, and the original .sdt
+    %dimensions
+    %for a crude threshold
+    disp(' old version')
+    vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+    vol=gtThresholdGrain(vol);
+  end
+
+     %get grain data
+            min3 = tmp.zstart;
+            max3 = tmp.zend-1;
+            min2 = tmp.x1+border;
+            max2 = min2 + tmp.nx-1;
+            min1 = tmp.y1+border;
+            max1 = min1 + tmp.ny-1;
+
+
+            %have to deal with bounding boxs that exceed the slice size
+            if min1<1
+                tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+                min1=1;
+                vol=vol(tmp:end,:,:);
+            end
+            if min2<1
+                tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+                min2=1;
+                vol=vol(:,tmp:end,:);
+            end
+            if min3<1
+                tmp=2-min3;%if z1==0, crop one row of voxels from vol
+                min3=1;
+                vol=vol(:,:,tmp:end);
+            end
+            if max1>parameters.acq.bb(3)+(2*border);
+                tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+                max1=parameters.acq.bb(3)+(2*border);
+                vol=vol(1:end-tmp,:,:);
+            end
+            if max2>parameters.acq.bb(3)+(2*border);
+                tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+                max2=parameters.acq.bb(3)+(2*border);
+                vol=vol(:,1:end-tmp,:);
+            end
+            if max3>parameters.acq.bb(4);
+                tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+                max3=parameters.acq.bb(4);
+                vol=vol(:,:,1:end-tmp);
+            end
+%paste grain vol into full size volume            
+temp_output(min1:max1, min2:max2, min3:max3)=temp_output(min1:max1, min2:max2, min3:max3)+vol;
+  
+
+
+  
+  
+elseif 0 % older style filling of holes
+  
+vol_filename = sprintf('4_grains/grain%d_/grain%d_2.edf',i,i);
+vol = edf_read(vol_filename);
+
+%limits, allowing for the extra border
+min3 = tmp.vol_z_origin;
+max3 = min3 + tmp.vol_z_size-1;
+min1 = tmp.vol_y_origin+border;
+max1 = min1 + tmp.vol_y_size-1;
+min2 = tmp.vol_x_origin+border;
+max2 = min2 + tmp.vol_x_size-1;
+
+
+%have to deal with bounding boxs that exceed the slice size
+if min1<1
+  tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+  min1=1;
+  vol=vol(tmp:end,:,:);
+end
+if min2<1
+  tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+  min2=1;
+  vol=vol(:,tmp:end,:);
+end
+if min3<1
+  tmp=2-min3;%if z1==0, crop one row of voxels from vol
+  min3=1;
+  vol=vol(:,:,tmp:end);
+end
+if max1>parameters.acq.bb(3)+(2*border);
+  tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+  max1=parameters.acq.bb(3)+(2*border);
+  vol=vol(1:end-tmp,:,:);
+end
+if max2>parameters.acq.bb(3)+(2*border);
+  tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+  max2=parameters.acq.bb(3)+(2*border);
+  vol=vol(:,1:end-tmp,:);
+end
+if max3>parameters.acq.bb(4);
+  tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+  max3=parameters.acq.bb(4);
+  vol=vol(:,:,1:end-tmp);
+end
+
+%grain volume into output volume
+temp_output(min1:max1, min2:max2, min3:max3)=temp_output(min1:max1, min2:max2, min3:max3)+vol;
+
+end
+
+end
+%end of sfGetGrain
+
+
+  
+%sfGetGrainSize
+function size = sfGetGrainSize(i, parameters);
+%i is the grainid
+
+
+vol_filename = sprintf('4_grains/grain%d_/grain%d_filled.edf',i,i);
+if exist(vol_filename,'file')
+vol = edf_read(vol_filename);
+else
+      vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+    vol=gtThresholdGrain(vol);
+end
+dummy=find(vol~=0);
+size=length(dummy);
+end
+%end of sfGetGrainSize
diff --git a/5_reconstruction/gtnew_assemble_vol3D.m b/5_reconstruction/gtnew_assemble_vol3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..ff552713374e4f658501818805b68d7af56f0d2f
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_vol3D.m
@@ -0,0 +1,216 @@
+function [output, redo] = gtnew_assemble_vol2(list, varargin)
+%output - volume the size of the sample
+%version 2 - bad grain info is in the .mat file, not hardcoded here
+
+%add some useful info to the mat file - bounding box and CoM of
+%postprocessed grain
+
+%varargin - overlaps - 'zeros' causes overlapping regions to be set to
+%zero.  Otherwise, overlapping labels are summed.
+
+savefilename=[];
+if ~isempty(varargin)
+  savefilename=varargin{1};
+else
+  disp('not saving data - to save, supply a filename as the second argument')
+  pause(2)
+end
+
+overlaps=[];
+if ~isempty(varargin) && length(varargin)==2
+    overlaps=varargin{2};
+end
+
+display_error_messages=0;
+
+
+%load data
+
+load parameters.mat
+acq=parameters.acq;
+
+%add a border to allow grains to overflow acq.bb limits
+border=20;
+output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+bboxes=[];
+redo=[];
+
+%for i=234:304
+
+      for k=1:length(list)
+
+        i=list(k);
+% modif sabine
+% keyboard
+% end modif sabine
+    disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+   try
+
+        % gtDoART(i);%to relaunch with different parameteres
+
+        vol_filename = sprintf('4_grains/grain%d_/grain%d_filled.edf',i,i);
+        mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',i,i);
+        tmp = load(mat_filename, 'bad', 'z1', 'nz', 'x1','y1','nx','ny');
+ 
+        tmp.x1=round(tmp.x1+acq.bb(3)/2);
+		tmp.y1=round(tmp.y1+acq.bb(3)/2);
+		tmp.zstart=round(acq.bb(4)/2-tmp.z1);
+        tmp.zend=round(acq.bb(4)/2-tmp.z1+tmp.nz);
+		
+      		
+        if isfield(tmp, 'bad') && (tmp.bad==1 | tmp.bad==2)% | tmp.bad==0.5) %1=bad / 2=combined / 0.5=bad-ish
+
+            disp(sprintf('skipping grain %d', i))
+
+            continue
+        else
+
+            if exist(vol_filename,'file')  %if no post-processed file exists
+
+                vol=edf_read(vol_filename);
+
+                % modif sabine
+                %   elseif 1
+                %     'skipping other grains'
+                % fin modif sabine
+
+            else
+
+                %old style - this works with the .mat values, and the original .sdt
+                %dimensions
+                %for a crude threshold
+                disp(' old version')
+                vol = sdt_read(sprintf('4_grains/grain%d_/difspot_res0_5',i));
+                %put calculation in a function - works better than
+                % graythresh
+				%keyboard
+                vol=gtThresholdGrain(vol);
+                
+
+            end
+
+            %get grain data
+            min3 = tmp.zstart;
+            max3 = tmp.zend-1;
+            min2 = tmp.x1+border;
+            max2 = min2 + tmp.nx-1;
+            min1 = tmp.y1+border;
+            max1 = min1 + tmp.ny-1;
+
+
+            %have to deal with bounding boxs that exceed the slice size
+            if min1<1
+                tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+                min1=1;
+                vol=vol(tmp:end,:,:);
+            end
+            if min2<1
+                tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+                min2=1;
+                vol=vol(:,tmp:end,:);
+            end
+            if min3<1
+                tmp=2-min3;%if z1==0, crop one row of voxels from vol
+                min3=1;
+                vol=vol(:,:,tmp:end);
+            end
+            if max1>parameters.acq.bb(3)+(2*border);
+                tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+                max1=parameters.acq.bb(3)+(2*border);
+                vol=vol(1:end-tmp,:,:);
+            end
+            if max2>parameters.acq.bb(3)+(2*border);
+                tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+                max2=parameters.acq.bb(3)+(2*border);
+                vol=vol(:,1:end-tmp,:);
+            end
+            if max3>parameters.acq.bb(4);
+                tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+                max3=parameters.acq.bb(4);
+                vol=vol(:,:,1:end-tmp);
+            end
+
+            %add grain to volume, colour coded
+            vol=vol*i;
+            %for display only:
+            %size(vol)
+            %length([min1:max1])
+            %length([min2:max2])
+            %length([min3:max3])
+
+            if strcmp(overlaps,'zeros')
+                %stop overlapping...
+                tmp_output=zeros(size(output));
+                tmp_output(min1:max1, min2:max2, min3:max3)=vol;
+                output(find(output==0 & tmp_output))=i;%set undisputed voxels to i
+                output(find(output~=i & tmp_output))=-1;%set overlaps to -1
+            else
+                output(min1:max1, min2:max2, min3:max3)=output(min1:max1, min2:max2, min3:max3)+vol;
+            end
+
+            %get bounding box of the post processed grain
+            zpro=squeeze(sum(sum(vol, 1),2));
+            postbb(3)=min(find(zpro));
+            postbb(6)=max(find(zpro))-postbb(3);
+            zpro=reshape(zpro, 1, length(zpro));
+            postcent(3)=zpro*(1:length(zpro))'/sum(zpro);
+
+            xpro=squeeze(sum(sum(vol, 3),1));
+            postbb(1)=min(find(xpro));
+            postbb(4)=max(find(xpro))-postbb(1);
+            %xpro=reshape(xpro, 1, length(xpro));
+            postcent(1)=xpro*(1:length(xpro))'/sum(xpro);
+
+            ypro=squeeze(sum(sum(vol, 3),2));
+            postbb(2)=min(find(ypro));
+            postbb(5)=max(find(ypro))-postbb(2);
+            ypro=reshape(ypro, 1, length(ypro));
+            postcent(2)=ypro*(1:length(ypro))'/sum(ypro);
+
+            postbb=postbb+[min2 min1 min3 0 0 0];
+            postcent=postcent+[min2 min1 min3];
+
+            bboxes(i,:)=[postbb postcent];
+            save(mat_filename, 'postbb', 'postcent', '-append')
+
+
+            if 0%interactive
+                imshow(img,[])
+                disp('click in image to add to summed slice, outside to skip')
+                point=ginput(1)
+                if (point(1)<1 | point(1)>parameters.acq.bb(3) | point(2)<1 | point(2)>parameters.acq.bb(3))
+                    disp('skipping...')
+                else
+                    combined = combined+(img*i);
+                end
+            end
+
+            %end
+
+
+        end%bads check if bad skip/else try to do grain
+
+
+   catch
+
+     if display_error_messages
+     disp('try failed')
+   msg=lasterror;
+   msg.message
+     end
+   
+   redo=[redo i];
+   
+   end%try catch loop
+   
+end%loop through all grains
+
+
+output(find(output==-1))=0;%set overlapping regions to zero - this could be another label colour
+
+
+if ~isempty(savefilename)
+    name=sprintf('5_reconstruction/%s',savefilename);
+    disp(sprintf('writing volume %s',name));
+    edf_write(output,name,'uint16');
+end
diff --git a/5_reconstruction/gtnew_assemble_vol4.m b/5_reconstruction/gtnew_assemble_vol4.m
new file mode 100755
index 0000000000000000000000000000000000000000..b5f726283c81889af3cc9abf9a88aec2e6508c29
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_vol4.m
@@ -0,0 +1,227 @@
+
+
+function output = gtnew_assemble_vol4(overlaps)
+%another approach to filling a grain volume, accounting for twins
+% similar to gtnew_assemble_vol3, except that twins are assesed on the
+% fly, so we calculate the "twinlist" input as we go (knowing exactly what
+% overlaps and what doesn't)
+
+parameters=[];
+load parameters;
+maxgrainid=1038;
+
+%need to read in r-vectors if available
+r_vectors=[];
+load r_vectors;
+
+%get symmetry operators
+sym = gtGetCubicSymOp;
+    
+%how to deal with overlapping, non-twin grains
+if ~exist(overlaps, 'var')
+  overlaps='zeros';
+end
+
+%read grain sizes
+for i=1:maxgrainid
+grainsize(i)=sfGetGrainSize(i);
+end
+%sort - to do largest grain first
+[grainsize, index]=sort(grainsize, 'descend');
+
+%add a border to allow grains to overflow acq.bb limits
+border=20;
+%volume for output
+output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+
+%sigma s: type, angle, axis {, brandon criteria}
+warning('sigma axis indices must be positive, normalised, and in descending order...')
+pause(1)
+sigmas=[3 60 1 1 1;...
+  5 36.86 1 0 0;...
+  7 38.21 1 1 1;
+  9 38.94 1 1 0];
+%add brandon criteria
+sigmas(:,6)=15*sigmas(:,1).^(-0.5);
+%normalise axis
+sigmas(:,3:5)=sigmas(:,3:5)./repmat(sqrt(sum(sigmas(:,3:5).*sigmas(:,3:5),2)),1,3);
+
+
+
+
+for i=1:length(index)
+  
+  grainid=index(i);% is this the right sense?
+  
+  mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',grainid, grainid);
+  tmp = load(mat_filename, 'bad', 'x1', 'nx', 'y1', 'ny', 'zstart', 'zend');
+  
+    if (isfield(tmp, 'bad') && (tmp.bad==1 | tmp.bad==2)) %which grains to include
+      disp(sprintf('skipping grain %d', grainid))
+      continue %if skipping this grain
+    end
+
+    %get the current grain placed in the volume
+    grain_vol=sfGetGrain(grainid);
+    %add to output, without overlapping
+    output(find(output==0 & grain_vol))=grainid;
+    %what grains overlap?
+    list=output(find(grain_vol));
+    list=unique(list);
+    list(find(list==0))=[];
+    list(find(list==grainid))=[];
+    
+    %what are these grains?
+    if ~isempty(list)
+      for j=1:length(list)    
+        sigma = sfTwinTest(r_vectors(grainid,2:4), r_vectors(list(j),2:4)); %are these a twin?
+    
+        if isempty(sigma)
+          %set overlaps to either 0 / sum / minimum here
+          switch overlaps
+            case 'zeros'
+              output(find(output==list(j) & grain_vol))=0;
+            case 'minimum'
+              %ie no change here
+            case 'sum'
+              output(find(output==list(j) & grain_vol))=grainid+list(j);
+          end              
+              
+        else
+          %this is a twin.  Allow the new grain (smaller) to overwrite the
+          %older grain
+          output(find(output==list(j) & grain_vol))=grainid;
+        end
+          
+      end
+    end
+    
+    
+    disp(sprintf('done grain %d... %d of %d', grainid, i, maxgrainid))
+  
+end
+
+
+edf_write(output, '5_reconstruction/ss2007_A_twin_vol5.edf')
+
+
+
+% sub functions
+
+function temp_output = sfGetGrain(id)
+%i is the grainid
+%tmp is the matfile data structure
+%border is the border size
+%returns the grain placed in a volume the size of the final volume
+temp_output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+
+%for a crude threshold
+disp(' old version')
+vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',id,id));
+vol=gtThresholdGrain(vol);
+
+%get grain data
+min3 = tmp.zstart;
+max3 = tmp.zend-1;
+min2 = tmp.x1+border;
+max2 = min2 + tmp.nx-1;
+min1 = tmp.y1+border;
+max1 = min1 + tmp.ny-1;
+
+%have to deal with bounding boxs that exceed the slice size
+if min1<1
+  tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+  min1=1;
+  vol=vol(tmp:end,:,:);
+end
+if min2<1
+  tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+  min2=1;
+  vol=vol(:,tmp:end,:);
+end
+if min3<1
+  tmp=2-min3;%if z1==0, crop one row of voxels from vol
+  min3=1;
+  vol=vol(:,:,tmp:end);
+end
+if max1>parameters.acq.bb(3)+(2*border);
+  tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+  max1=parameters.acq.bb(3)+(2*border);
+  vol=vol(1:end-tmp,:,:);
+end
+if max2>parameters.acq.bb(3)+(2*border);
+  tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+  max2=parameters.acq.bb(3)+(2*border);
+  vol=vol(:,1:end-tmp,:);
+end
+if max3>parameters.acq.bb(4);
+  tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+  max3=parameters.acq.bb(4);
+  vol=vol(:,:,1:end-tmp);
+end
+%paste grain vol into full size volume
+temp_output(min1:max1, min2:max2, min3:max3)=temp_output(min1:max1, min2:max2, min3:max3)+vol;
+
+end
+%end of sfGetGrain
+
+
+
+%sfGetGrainSize
+function size = sfGetGrainSize(id)
+%i is the grainid
+
+vol_filename = sprintf('4_grains/grain%d_/grain%d_filled.edf',id,id);
+if exist(vol_filename,'file')
+  vol = edf_read(vol_filename);
+else
+  vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',id,id));
+  vol=gtThresholdGrain(vol);
+end
+dummy=find(vol~=0);
+size=length(dummy);
+end
+%end of sfGetGrainSize
+
+
+% sfTwinTest
+  function sigma=sfTwinTest(R1, R2)
+    g1=Rod2g(R1);
+    g2=Rod2g(R2);
+    %need to search symmetry equivelents for the minimum misorientation
+    rot_offset=[];
+    
+    for k=1:24
+      g1equiv = g1*sym(k).g;
+      netg = inv(g1equiv)*g2;
+      rot_offset(k) = acos((trace(netg)-1)/2);  
+    end
+
+    dummy = find(rot_offset ==min(rot_offset));
+    
+    g1equiv = g1*sym(dummy).g;
+    netg = inv(g1equiv)*g2;
+    
+    mis_angle = (180/pi)*acos((trace(netg)-1)/2);
+
+    [eigVec, eigVal]=eig(netg);
+    
+    for p=1:3  
+      if isreal(eigVec(:,p))  %find the real eigenvector
+        mis_axis=eigVec(:,p);
+      end
+    end
+    if ~isempty(mis_axis) 
+      mis_axis=sort(abs(mis_axis), 'descend');
+      %determine sigma type
+      test_angle=abs(mis_angle-sigmas(:,2))<sigmas(:,6);
+      test_axis=(180/pi)*abs(acos(dot(repmat(mis_axis',size(sigmas,1),1), sigmas(:,3:5), 2)))<sigmas(:,6);
+      sigma=sigmas(find(test_angle & test_axis), 1);
+    end
+  end
+% end of sfTwinTest
+
+%end of main function
+end
+
+  
\ No newline at end of file
diff --git a/5_reconstruction/gtnew_assemble_vol_sab2.m b/5_reconstruction/gtnew_assemble_vol_sab2.m
new file mode 100755
index 0000000000000000000000000000000000000000..f2f89392e895072ca819db72e0f92813c5e1e6a8
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_vol_sab2.m
@@ -0,0 +1,245 @@
+function [output, redo] = gtnew_assemble_vol_sab2(list, varargin)
+%output - volume the size of the sample
+%version 2 - bad grain info is in the .mat file, not hardcoded here
+
+%add some useful info to the mat file - bounding box and CoM of
+%postprocessed grain
+
+%varargin - overlaps - 'zeros' causes overlapping regions to be set to
+%zero.  Otherwise, overlapping labels are summed.
+
+savefilename=[];
+if ~isempty(varargin)
+  savefilename=varargin{1};
+else
+  disp('not saving data - to save, supply a filename as the second argument')
+  pause(2)
+end
+
+overlaps=[];
+if ~isempty(varargin) && length(varargin)==2
+    overlaps=varargin{2};
+end
+
+display_error_messages=0;
+
+
+%load data
+
+load parameters.mat
+
+
+%add a border to allow grains to overflow acq.bb limits
+border=20;
+output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+bboxes=[];
+redo=[];
+
+%for i=234:304
+
+      for k=1:length(list)
+
+        i=list(k);
+% modif sabine
+% keyboard
+% end modif sabine
+    disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+   try
+
+        % gtDoART(i);%to relaunch with different parameteres
+
+        vol_filename = sprintf('4_grains/grain%d_/grain%d_filled.edf',i,i);
+        mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',i,i);
+        tmp = load(mat_filename, 'bad', 'zstart', 'zend', 'x1','y1','nx','ny');
+
+
+
+        if isfield(tmp, 'bad') && (tmp.bad==1 | tmp.bad==2)% | tmp.bad==0.5) %1=bad / 2=combined / 0.5=bad-ish
+
+            disp(sprintf('skipping grain %d', i))
+
+            continue
+        else
+
+            if exist(vol_filename,'file')  %if no post-processed file exists
+
+                vol=edf_read(vol_filename);
+
+                % modif sabine
+                %   elseif 1
+                %     'skipping other grains'
+                % fin modif sabine
+
+            else
+
+                %old style - this works with the .mat values, and the original .sdt
+                %dimensions
+                %for a crude threshold
+                disp(' old version')
+                vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+                %put calculation in a function - works better than
+                % graythresh
+                vol=gtThresholdGrain(vol);
+
+
+            end
+
+            %get grain data
+            min3 = tmp.zstart;
+            max3 = tmp.zend-1;
+            min2 = tmp.x1+border;
+            max2 = min2 + tmp.nx-1;
+            min1 = tmp.y1+border;
+            max1 = min1 + tmp.ny-1;
+
+
+            %have to deal with bounding boxs that exceed the slice size
+            if min1<1
+                tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+                min1=1;
+                vol=vol(tmp:end,:,:);
+            end
+            if min2<1
+                tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+                min2=1;
+                vol=vol(:,tmp:end,:);
+            end
+            if min3<1
+                tmp=2-min3;%if z1==0, crop one row of voxels from vol
+                min3=1;
+                vol=vol(:,:,tmp:end);
+            end
+            if max1>parameters.acq.bb(3)+(2*border);
+                tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+                max1=parameters.acq.bb(3)+(2*border);
+                vol=vol(1:end-tmp,:,:);
+            end
+            if max2>parameters.acq.bb(3)+(2*border);
+                tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+                max2=parameters.acq.bb(3)+(2*border);
+                vol=vol(:,1:end-tmp,:);
+            end
+            if max3>parameters.acq.bb(4);
+                tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+                max3=parameters.acq.bb(4);
+                vol=vol(:,:,1:end-tmp);
+            end
+
+            %add grain to volume, colour coded
+            vol=vol*i;
+            %for display only:
+            %size(vol)
+            %length([min1:max1])
+            %length([min2:max2])
+            %length([min3:max3])
+
+            if strcmp(overlaps,'zeros')
+                %stop overlapping...
+                tmp_output=zeros(size(output));
+                tmp_output(min1:max1, min2:max2, min3:max3)=vol;
+                output(find(output==0 & tmp_output))=i;%set undisputed voxels to i
+                output(find(output~=i & tmp_output))=-1;%set overlaps to -1
+            else
+                output(min1:max1, min2:max2, min3:max3)=output(min1:max1, min2:max2, min3:max3)+vol;
+            end
+
+            %get bounding box of the post processed grain
+            zpro=squeeze(sum(sum(vol, 1),2));
+            postbb(3)=min(find(zpro));
+            postbb(6)=max(find(zpro))-postbb(3);
+            zpro=reshape(zpro, 1, length(zpro));
+            postcent(3)=zpro*(1:length(zpro))'/sum(zpro);
+
+            xpro=squeeze(sum(sum(vol, 3),1));
+            postbb(1)=min(find(xpro));
+            postbb(4)=max(find(xpro))-postbb(1);
+            %xpro=reshape(xpro, 1, length(xpro));
+            postcent(1)=xpro*(1:length(xpro))'/sum(xpro);
+
+            ypro=squeeze(sum(sum(vol, 3),2));
+            postbb(2)=min(find(ypro));
+            postbb(5)=max(find(ypro))-postbb(2);
+            ypro=reshape(ypro, 1, length(ypro));
+            postcent(2)=ypro*(1:length(ypro))'/sum(ypro);
+
+            postbb=postbb+[min2 min1 min3 0 0 0];
+            postcent=postcent+[min2 min1 min3];
+
+            bboxes(i,:)=[postbb postcent];
+            save(mat_filename, 'postbb', 'postcent', '-append')
+
+
+            if 0%interactive
+                imshow(img,[])
+                disp('click in image to add to summed slice, outside to skip')
+                point=ginput(1)
+                if (point(1)<1 | point(1)>parameters.acq.bb(3) | point(2)<1 | point(2)>parameters.acq.bb(3))
+                    disp('skipping...')
+                else
+                    combined = combined+(img*i);
+                end
+            end
+
+            %end
+
+
+        end%bads check if bad skip/else try to do grain
+
+
+   catch
+
+     if display_error_messages
+     disp('try failed')
+   msg=lasterror;
+   msg.message
+     end
+   
+   redo=[redo i];
+   
+   end%try catch loop
+
+end%loop through all grains
+
+
+output(find(output==-1))=0;%set overlapping regions to zero - this could be another label colour
+
+
+if ~isempty(savefilename)
+    name=sprintf('5_reconstruction/%s',savefilename);
+    disp(sprintf('writing volume %s',name));
+    edf_write(output,name,'uint16');
+end
+
+clear vol;
+%vol2=volread('/data/id19/inhouse/sabine/sam3_dct_500g_2bis_/sam3_dct_500g_2bis_482_482_497.raw','uint8',0,482,482,497); 
+%vol2=volread('/data/id19/inhouse/sabine/ma513/sam3_dct3_bin_482_482_497.raw','uint8',0,482,482,497);
+%vol2=volread('/data/id19/graintracking/data/snow/ma513_mars08_/sam8_dct1_/sam8_dct1_.raw','uint8',0,508,508,610);
+%vol2=volread('/data/id19/inhouse/sabine/ma513/sam8_dct2_bin_508_508_610.raw','uint8',0,508,508,610);
+vol2=volread('/data/id19/inhouse/sabine/ma513/sam8_dct3_bin_508_508_610.raw','uint8',0,508,508,610);
+%vol2=volread('/data/id19/inhouse/sabine/ma513/sam8_dct4_bin_508_508_610.raw','uint8',0,508,508,610);
+%vol2=volread('/data/id19/graintracking/data/snow/ma513_mars08_/sam8_dct5_/sam8_dct5_522_522_158.raw','uint8',0,522,522,158,'l');
+
+vol3=zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+vol3(border+1:border+parameters.acq.bb(3),border+1:border+parameters.acq.bb(3),:)=vol2(:,:,:);
+ clear vol2;
+ bw=zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+ for i=1:parameters.acq.bb(4)
+     bw(:,:,i)=im2bw(vol3(:,:,i)/255,0.5);
+     bw(:,:,i)=imrotate(fliplr(bw(:,:,i)),90,'nearest','crop');   
+ end
+% 
+ output=output.*bw;
+ clear vol3;
+
+if ~isempty(savefilename)
+    name=sprintf('5_reconstruction/abs_%s',savefilename);
+    disp(sprintf('writing volume %s',name));
+    edf_write(output,name,'uint16');
+end
+ 
+output=output+255*bw;
+if ~isempty(savefilename)
+    name=sprintf('5_reconstruction/sum_%s',savefilename);
+    disp(sprintf('writing volume %s',name));
+    edf_write(output,name,'uint16');
+end
diff --git a/5_reconstruction/gtnew_assemble_vol_sab3.m b/5_reconstruction/gtnew_assemble_vol_sab3.m
new file mode 100755
index 0000000000000000000000000000000000000000..4c4283481e72812a0b861a83dc1220b1545b56da
--- /dev/null
+++ b/5_reconstruction/gtnew_assemble_vol_sab3.m
@@ -0,0 +1,245 @@
+function [output, redo] = gtnew_assemble_vol_sab3(list, varargin)
+%output - volume the size of the sample
+%version 2 - bad grain info is in the .mat file, not hardcoded here
+
+%add some useful info to the mat file - bounding box and CoM of
+%postprocessed grain
+
+%varargin - overlaps - 'zeros' causes overlapping regions to be set to
+%zero.  Otherwise, overlapping labels are summed.
+
+savefilename=[];
+if ~isempty(varargin)
+  savefilename=varargin{1};
+else
+  disp('not saving data - to save, supply a filename as the second argument')
+  pause(2)
+end
+
+overlaps=[];
+if ~isempty(varargin) && length(varargin)==2
+    overlaps=varargin{2};
+end
+
+display_error_messages=0;
+
+
+%load data
+
+load parameters.mat
+
+
+%add a border to allow grains to overflow acq.bb limits
+border=20;
+output = zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+bboxes=[];
+redo=[];
+
+%for i=234:304
+
+      for k=1:length(list)
+
+        i=list(k);
+% modif sabine
+% keyboard
+% end modif sabine
+    disp(sprintf('~~~~~~~~  doing grain %d  ~~~~~~~~~',i))
+   try
+
+        % gtDoART(i);%to relaunch with different parameteres
+
+        vol_filename = sprintf('4_grains/grain%d_/grain%d_filled.edf',i,i);
+        mat_filename =  sprintf('4_grains/grain%d_/grain%d_.mat',i,i);
+        tmp = load(mat_filename, 'bad', 'zstart', 'zend', 'x1','y1','nx','ny');
+
+
+
+        if isfield(tmp, 'bad') && (tmp.bad==1 | tmp.bad==2)% | tmp.bad==0.5) %1=bad / 2=combined / 0.5=bad-ish
+
+            disp(sprintf('skipping grain %d', i))
+
+            continue
+        else
+
+            if exist(vol_filename,'file')  %if no post-processed file exists
+
+                vol=edf_read(vol_filename);
+
+                % modif sabine
+                %   elseif 1
+                %     'skipping other grains'
+                % fin modif sabine
+
+            else
+
+                %old style - this works with the .mat values, and the original .sdt
+                %dimensions
+                %for a crude threshold
+                disp(' old version')
+                vol = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',i,i));
+                %put calculation in a function - works better than
+                % graythresh
+                vol=gtThresholdGrain(vol);
+
+
+            end
+
+            %get grain data
+            min3 = tmp.zstart;
+            max3 = tmp.zend-1;
+            min2 = tmp.x1+border;
+            max2 = min2 + tmp.nx-1;
+            min1 = tmp.y1+border;
+            max1 = min1 + tmp.ny-1;
+
+
+            %have to deal with bounding boxs that exceed the slice size
+            if min1<1
+                tmp=2-min1;%if min of first index==0, crop one row of voxels from vol
+                min1=1;
+                vol=vol(tmp:end,:,:);
+            end
+            if min2<1
+                tmp=2-min2;%if min of second index==0, crop one row of voxels from vol
+                min2=1;
+                vol=vol(:,tmp:end,:);
+            end
+            if min3<1
+                tmp=2-min3;%if z1==0, crop one row of voxels from vol
+                min3=1;
+                vol=vol(:,:,tmp:end);
+            end
+            if max1>parameters.acq.bb(3)+(2*border);
+                tmp=max1-(parameters.acq.bb(3)+(2*border));%if x2 is one too big, crop one row of voxels
+                max1=parameters.acq.bb(3)+(2*border);
+                vol=vol(1:end-tmp,:,:);
+            end
+            if max2>parameters.acq.bb(3)+(2*border);
+                tmp=max2-(parameters.acq.bb(3)+(2*border));%if y2 is one too big, crop one row of voxels
+                max2=parameters.acq.bb(3)+(2*border);
+                vol=vol(:,1:end-tmp,:);
+            end
+            if max3>parameters.acq.bb(4);
+                tmp=max3-parameters.acq.bb(4);%if z2 is one too big, crop one row of voxels
+                max3=parameters.acq.bb(4);
+                vol=vol(:,:,1:end-tmp);
+            end
+
+            %add grain to volume, colour coded
+            vol=vol*i;
+            %for display only:
+            %size(vol)
+            %length([min1:max1])
+            %length([min2:max2])
+            %length([min3:max3])
+
+            if strcmp(overlaps,'zeros')
+                %stop overlapping...
+                tmp_output=zeros(size(output));
+                tmp_output(min1:max1, min2:max2, min3:max3)=vol;
+                output(find(output==0 & tmp_output))=i;%set undisputed voxels to i
+                output(find(output~=i & tmp_output))=-1;%set overlaps to -1
+            else
+                output(min1:max1, min2:max2, min3:max3)=output(min1:max1, min2:max2, min3:max3)+vol;
+            end
+
+            %get bounding box of the post processed grain
+            zpro=squeeze(sum(sum(vol, 1),2));
+            postbb(3)=min(find(zpro));
+            postbb(6)=max(find(zpro))-postbb(3);
+            zpro=reshape(zpro, 1, length(zpro));
+            postcent(3)=zpro*(1:length(zpro))'/sum(zpro);
+
+            xpro=squeeze(sum(sum(vol, 3),1));
+            postbb(1)=min(find(xpro));
+            postbb(4)=max(find(xpro))-postbb(1);
+            %xpro=reshape(xpro, 1, length(xpro));
+            postcent(1)=xpro*(1:length(xpro))'/sum(xpro);
+
+            ypro=squeeze(sum(sum(vol, 3),2));
+            postbb(2)=min(find(ypro));
+            postbb(5)=max(find(ypro))-postbb(2);
+            ypro=reshape(ypro, 1, length(ypro));
+            postcent(2)=ypro*(1:length(ypro))'/sum(ypro);
+
+            postbb=postbb+[min2 min1 min3 0 0 0];
+            postcent=postcent+[min2 min1 min3];
+
+            bboxes(i,:)=[postbb postcent];
+            save(mat_filename, 'postbb', 'postcent', '-append')
+
+
+            if 0%interactive
+                imshow(img,[])
+                disp('click in image to add to summed slice, outside to skip')
+                point=ginput(1)
+                if (point(1)<1 | point(1)>parameters.acq.bb(3) | point(2)<1 | point(2)>parameters.acq.bb(3))
+                    disp('skipping...')
+                else
+                    combined = combined+(img*i);
+                end
+            end
+
+            %end
+
+
+        end%bads check if bad skip/else try to do grain
+
+
+   catch
+
+     if display_error_messages
+     disp('try failed')
+   msg=lasterror;
+   msg.message
+     end
+   
+   redo=[redo i];
+   
+   end%try catch loop
+
+end%loop through all grains
+
+
+output(find(output==-1))=0;%set overlapping regions to zero - this could be another label colour
+
+
+if ~isempty(savefilename)
+    name=sprintf('5_reconstruction/%s',savefilename);
+    disp(sprintf('writing volume %s',name));
+    edf_write(output,name,'uint16');
+end
+
+clear vol;
+%vol2=volread('/data/id19/inhouse/sabine/sam3_dct_500g_2bis_/sam3_dct_500g_2bis_482_482_497.raw','uint8',0,482,482,497); 
+%vol2=volread('/data/id19/inhouse/sabine/ma513/sam3_dct3_bin_482_482_497.raw','uint8',0,482,482,497);
+%vol2=volread('/data/id19/graintracking/data/snow/ma513_mars08_/sam8_dct1_/sam8_dct1_.raw','uint8',0,508,508,610);
+%vol2=volread('/data/id19/inhouse/sabine/ma513/sam8_dct2_bin_508_508_610.raw','uint8',0,508,508,610);
+%vol2=volread('/data/id19/inhouse/sabine/ma513/sam8_dct3_bin_508_508_610.raw','uint8',0,508,508,610);
+%vol2=volread('/data/id19/inhouse/sabine/ma513/sam8_dct4_bin_508_508_610.raw','uint8',0,508,508,610);
+vol2=volread('/data/id19/graintracking/data/snow/ma513_mars08_/sam8_dct5_/sam8_dct5_522_522_158.raw','uint8',0,522,522,158,'l');
+
+vol3=zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+vol3(border+1:border+parameters.acq.bb(3),border+1:border+parameters.acq.bb(3),:)=vol2(:,:,:);
+ clear vol2;
+ bw=zeros(parameters.acq.bb(3)+border*2, parameters.acq.bb(3)+border*2,parameters.acq.bb(4));
+ for i=1:parameters.acq.bb(4)
+     bw(:,:,i)=im2bw(vol3(:,:,i)/255,0.5);
+     bw(:,:,i)=imrotate(fliplr(bw(:,:,i)),90,'nearest','crop');   
+ end
+% 
+ output=output.*bw;
+ clear vol3;
+
+if ~isempty(savefilename)
+    name=sprintf('5_reconstruction/abs_%s',savefilename);
+    disp(sprintf('writing volume %s',name));
+    edf_write(output,name,'uint16');
+end
+ 
+output=output+255*bw;
+if ~isempty(savefilename)
+    name=sprintf('5_reconstruction/sum_%s',savefilename);
+    disp(sprintf('writing volume %s',name));
+    edf_write(output,name,'uint16');
+end
diff --git a/5_reconstruction/gtnew_choose_art_params_wolf.m b/5_reconstruction/gtnew_choose_art_params_wolf.m
new file mode 100755
index 0000000000000000000000000000000000000000..437b3707c8e43fc6c8d7218c116d2ceadad4ca30
--- /dev/null
+++ b/5_reconstruction/gtnew_choose_art_params_wolf.m
@@ -0,0 +1,175 @@
+function [lambda,use_grain]=gtnew_choose_art_params_wolf(grainid)
+
+%read in the grain parameters, try reconstructing and allow users to 
+%adjust the ART params
+%if grain is okay, returns use_grain = 1, if not = 0.
+%modify to new world order
+
+
+load parameters.mat
+
+
+
+%read in data
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+struct_id = grain_data.struct_ids;
+
+%if it doesn't already exist, add an index of projections to use
+if isfield(grain_data,'index')
+  index = grain_data.index;
+else
+  index = ones(1,length(grain_data.struct_ids));
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'index', '-append') 
+end
+
+
+disp('try adjusting the art parameters interactively');
+fprintf('grain is %d slices high.  will look at top, middle, and bottom\n',grain_data.zend-grain_data.zstart);
+
+%reconstruction parameters...
+test = 0; %when user is happy with params, test=1
+
+z1array = ceil(([0.3 0.5 0.7]*(grain_data.zend-grain_data.zstart))+grain_data.zstart); %three z positions
+nzarray = [5 5 5]; %do 5 slices (more representative) at each position
+
+scanname = sprintf('4_grains/grain%d_/grain%d_',grainid,grainid);
+parfilename = sprintf('4_grains/grain%d_/grain%d_.par',grainid,grainid);
+whole_parfilename = sprintf('4_grains/grain%d_/grain%d_whole.par',grainid,grainid);
+
+if length(index)>30
+art_params = [0.3 0.2 0.1]; %initial values
+elseif length(index)>15
+art_params = [0.5 0.3 0.1]; %initial values
+else
+art_params = [0.7 0.3 0.2]; %initial values
+end
+
+nbiter = 3;
+pixsize = 1;
+braggangle = 0;
+np = parameters.acq.bb(3);
+nq = parameters.acq.bb(4);
+offset = 0;
+
+x1 = grain_data.x1;
+y1 = grain_data.y1;
+nx = grain_data.nx;
+ny = grain_data.ny;
+
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+while test==0
+
+%number of projections changes with user selectio
+
+p_angles = -grain_data.Omega(find(index));
+p_numbers = find(index);
+
+
+for i=1:3
+  
+gtMakeARTJob(scanname,parfilename,p_numbers,p_angles,art_params,nbiter,pixsize,braggangle,np,nq,offset, ... 
+  z1array(i),nzarray(i),x1,nx,y1,ny);
+
+command=sprintf('%s %s',rec_alg,parfilename);
+[s,w]=unix(command);
+command=sprintf('%s %s_res0_%d',seg2view,scanname,nbiter);
+[s,w]=unix(command);
+name=sprintf('%s_res0_%d.sdt',scanname,nbiter);
+im=volread(name,'float32',0,nx,ny,nzarray(i),'l');
+
+image(:,:,i) = im(:,:,ceil(nzarray(i)/2))';%collect three images top middle bottom
+%image2(:,:,i)=image(:,:,i);
+
+end
+
+%display 3 slices with same greyscale
+min_image = min(image(:));
+max_image = max(image(:));
+for i=1:3
+subplot(1,3,i);
+imshow(image(:,:,i),[min_image max_image]);
+end
+
+drawnow
+ 
+%get new ART params
+disp(sprintf('current ART params: [%f %f %f]',art_params(1),art_params(2),art_params(3)));
+
+
+%interaction: change params / finish / modify projections
+new_art_params = input('adjust params? input in brackets [] / return if happy / "s" to select, "r" to replace projections / "b" set bbox: ');
+
+%if user is happy with params
+if isempty(new_art_params)
+ test = 1;
+ lambda=art_params;
+%close subplot figure, save params
+close 
+image = image(:,:,2);
+save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'lambda', 'image', 'index', '-append') 
+
+
+gtDoART(grainid);
+
+
+% 
+% %write .par file for the whole grain, add to batch file
+% gtMakeARTJob(scanname,whole_parfilename,p_numbers,p_angles,art_params,nbiter,pixsize,braggangle,np,nq,offset, ... 
+%   grain_data.zstart,grain_data.zend-grain_data.zstart,x1,nx,y1,ny);
+% 
+% %start reconstruction and write batch file for volume conversions
+% cd(parameters.acq.dir);
+% fid = fopen('seg2view.sh','a');
+% command=sprintf('%s 4_grains/grain%d_/%s_res0_%d\n\n',seg2view,grainid,scanname,nbiter);
+% fprintf(fid,command); 
+% fclose(fid);
+% 
+% gtnew_make_condorjob(grainid);
+use_grain=1;
+
+% consistancy check should have already removed spots belonging to other
+% grains.  Index should be only to stop bad projections (overlapping spots,
+% bad outlines, etc) being used in reconstruction.
+
+% %set grain_id=0 on rejected projections
+% rejected=grain_data.struct_id(find(index==0));
+% for i=1:length(rejected)
+% fprintf('setting rejected extspot(%d).GrainID=0\n',rejected(i));
+% extspot(rejected(i)).GrainID=0;
+% end
+% save(sprintf('%s/3_extspot/extspot.mat',parameters.acq.dir), 'extspot')
+
+%to edit/remove projections
+elseif new_art_params=='s'
+index = gtnew_select_projectionsgui_grain(grainid);
+close
+
+elseif new_art_params=='r'
+index = gtnew_replace_projectionsgui_grain(grainid);
+close
+
+elseif new_art_params=='b'
+  close
+ [x1,y1,nx,ny]=gtChangeARTbb(grainid);
+ clear image %resizing image
+ close
+
+%to escape, and mark this grain as bad
+elseif new_art_params=='x'
+test=1;  
+
+bad=1;%set bad in the grain%d_.mat to 1
+disp(sprintf('Setting field \"bad=1\" in grain%d_.mat',grainid))
+save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'bad', '-append')
+
+%trial reconstruction with new parameters
+else
+  art_params=new_art_params;
+end
+
+
+end %while loop
+
+cd(parameters.acq.dir)
diff --git a/5_reconstruction/gtnew_replace_projectionsgui_grain.m b/5_reconstruction/gtnew_replace_projectionsgui_grain.m
new file mode 100755
index 0000000000000000000000000000000000000000..886b2e1c82636eea7f50efbac05b495c0e0f78c7
--- /dev/null
+++ b/5_reconstruction/gtnew_replace_projectionsgui_grain.m
@@ -0,0 +1,189 @@
+function index = gtnew_replace_projectionsgui_grain(grainid)
+
+%version of select_projectionsgui_grain to replace extspots with difspots
+%to deal with bad snakes, bad overlap, whatever...
+
+%modify to read from the grain%d_.mat structure...
+
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+% read in data
+grain_data = load(sprintf('%s/4_grains/grain%d_/grain%d_.mat',parameters.acq.dir,grainid,grainid));
+stack = grain_data.stack;
+Omega = grain_data.Omega;
+struct_ids = grain_data.struct_ids;
+
+%get the pair information
+if isfield(grain_data, 'pair_vector')
+pair_vector = grain_data.pair_vector;
+else
+  pair_vector = logical(ones(length(struct_ids),1)); %if not specified, assume all in this dataset
+end
+
+close all
+
+%if it doesn't already exist, add an index of projections to use
+if isfield(grain_data,'index')
+  index = logical(grain_data.index);
+else
+  index = logical(ones(length(struct_ids),1));  
+  save (sprintf('%s/4_grains/grain%d_/grain%d_.mat',parameters.acq.dir,grainid,grainid), 'index', '-append') 
+end
+
+%if it doesn't already exist, add an index of replaced projections
+if isfield(grain_data,'replaced')
+  replaced = logical(grain_data.replaced);
+else
+  replaced = logical(zeros(length(struct_ids),1));  
+  save (sprintf('%s/4_grains/grain%d_/grain%d_.mat',parameters.acq.dir,grainid,grainid), 'replaced', '-append') 
+end
+
+%construct sinogram from the stack saved in grain%d_.mat
+for i=1:length(struct_ids)
+z_sino = grain_data.zcenter; 
+sino(:,i) = stack(z_sino,:,i); 
+end
+
+n=size(stack,3);
+gridx = 4;
+gridy = ceil(n/gridx);
+h_fig1=figure(1);
+
+app.quit=0;
+
+for i=1:n
+	ax(i)=subplot(gridy,gridx,i); 
+  %imagetmp = gtnewGetSummedExtSpot(struct_ids(i)); %on-the-fly make extspot
+  imagetmp = stack(:,:,i);%show stack image - not as good because of the size...
+  %  imagetmp = edfread(sprintf('../extspot/extspot%05d.edf',app.extspot(struct_ids(i)).ID));
+  
+  imshow(imagetmp,[]);
+  
+end
+set(h_fig1,'KeyPressFcn',@sfKeyPress);
+set(h_fig1,'WindowButtonDownFcn',@sfButtonPress);
+	
+sfUpdateFigure([1:n]);
+
+% if user wants nothing to return until is finished
+    while 1
+      drawnow
+      if app.quit==1
+        break
+      end
+    end
+ 
+
+%% sfUpdateFigure
+function sfUpdateFigure(ca)
+	 
+		figure(2);
+		img=backpro(sino(:,index),Omega(index)*pi/180);
+		imshow(img,[])
+    
+		figure(1);
+		for i=1:length(ca)
+			subplot(gridy,gridx,ca(i));title(ax(ca(i)),sprintf('replaced:%d (%d)',replaced(ca(i)), struct_ids(ca(i)) ));
+		end
+	
+end	
+
+
+%%  sfKeyPress
+  function sfKeyPress(varargin)  
+    % varargin{2} contains the event details
+    
+	c=varargin{2};
+	
+    switch c.Key
+      case 'return'
+        disp('accept selection')
+        %save replaced index in grain%d_.mat
+        save (sprintf('%s/4_grains/grain%d_/grain%d_.mat',parameters.acq.dir,grainid,grainid), 'replaced', 'stack', '-append') ;
+        %also need to rewrite the ART input files
+        gtWriteStack(grainid);
+        set(h_fig1,'KeyPressFcn',[]);
+		set(h_fig1,'WindowButtonDownFcn',[]);
+		app.quit=1;
+	end
+  end
+
+
+%%  sfButtonPress
+  function sfButtonPress(varargin)  
+    % varargin{2} contains the event details
+    src=varargin{1};
+	toto=varargin{2};
+	ca=gca;
+	ca=find(ax==ca);
+  %change replaced index
+  replaced(ca)=~replaced(ca);
+        
+  if pair_vector(ca)==2
+    name=parameters.acq.pair_name;
+  else
+    name=parameters.acq.name;
+  end
+      
+  %update stack with extspot / difspot
+  if replaced(ca)==0 %extspot case
+    
+    mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+      '%sbb inner join %sbboxes on %sbb.bbID=%sbboxes.bboxID '...
+      'where %sbb.extspotID = %d'],...
+      name, name, name, name, name,...
+      struct_ids(ca))
+    
+    [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+    
+    im = gtGetSummedExtSpot_pair(struct_ids(ca), pair_vector(ca));
+    
+  %place in stack
+  stack(:,:,ca) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  stack(:,:,ca)= 100*stack(:,:,ca)/sum(sum(stack(:,:,ca)));  % think about some proper scaling here !
+  
+  %read sino from stack
+  sino(:,ca) = stack(z_sino,:,ca);
+  
+  else %extspot replaced by difspot
+      mysqlcmd = sprintf(['select Xorigin,Yorigin from '...
+        '%sbboxes inner join %sextspot on SearchbbID=bboxID '...
+        'where %sbboxes.extspotID = %d'],...
+      name, name, name,...
+      struct_ids(ca))
+    [BoundingBox(1),BoundingBox(2)] = mym(mysqlcmd);
+  
+    warning('bodge because some SearchBoundingBoxes have zero origins')
+  if BoundingBox(1)==0
+    BoundingBox(1)=1;
+  end
+  if BoundingBox(2)==0
+    BoundingBox(2)=1;
+  end
+  
+ % im=edf_read(sprintf('2_difspot/difspot/difspot%05d.edf',struct_ids(ca)));
+  im = gtGetSummedDifSpot_pair(struct_ids(ca), pair_vector(ca));
+  
+  %place in stack
+  stack(:,:,ca) = gtPlaceSubImage(im, zeros(parameters.acq.bb(4), parameters.acq.bb(3)),ceil(BoundingBox(1)), ceil(BoundingBox(2)));
+  stack(:,:,ca)= 100*stack(:,:,ca)/sum(sum(stack(:,:,ca)));  % think about some proper scaling here !
+  
+  %read sino from stack
+  sino(:,ca) = stack(z_sino,:,ca);
+  
+    end
+   
+  figure(1);
+	subplot(gridy,gridx,ca);imagetmp = stack(:,:,ca);imshow(imagetmp,[]);
+  
+    
+	sfUpdateFigure(ca);
+  end	
+ 
+
+end	
+
diff --git a/5_reconstruction/gtnew_select_projectionsgui_grain.m b/5_reconstruction/gtnew_select_projectionsgui_grain.m
new file mode 100755
index 0000000000000000000000000000000000000000..96b3ec0b494ea5125026b0944954ca747008ba3e
--- /dev/null
+++ b/5_reconstruction/gtnew_select_projectionsgui_grain.m
@@ -0,0 +1,115 @@
+%function index=select_projectionsgui(stack,sino,theta,struct_id)
+function index = gtnew_select_projectionsgui_grain(grainid)
+
+%modify to read from the grain%d_.mat structure...
+
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+% read in data
+grain_data = load(sprintf('%s/4_grains/grain%d_/grain%d_.mat',parameters.acq.dir,grainid,grainid));
+
+stack = grain_data.stack;
+Omega = grain_data.Omega;
+struct_id = grain_data.struct_ids;
+
+
+
+close all
+
+%if it doesn't already exist, add an index of projections to use
+if isfield(grain_data,'index')
+  index = logical(grain_data.index);
+else
+  index = logical(ones(length(struct_id),1));  
+  save (sprintf('%s/4_grains/grain%d_/grain%d_.mat',parameters.acq.dir,grainid,grainid), 'index', '-append') 
+end
+
+%construct sinogram from the stack saved in grain%d_.mat
+for i=1:length(struct_id)
+z_sino = grain_data.zcenter; 
+sino(:,i) = stack(z_sino,:,i); 
+end
+
+n=size(stack,3);
+gridx = 4;
+gridy = ceil(n/gridx);
+h_fig1=figure(1);
+
+app.quit=0;
+
+for i=1:n
+	ax(i)=subplot(gridy,gridx,i); 
+  %imagetmp = gtnewGetSummedExtSpot(struct_id(i)); %on-the-fly make extspot
+  imagetmp = stack(:,:,i);%show stack image - not as good because of the size...
+  %  imagetmp = edfread(sprintf('../extspot/extspot%05d.edf',app.extspot(struct_id(i)).ID));
+  
+  imshow(imagetmp,[]);
+  
+end
+set(h_fig1,'KeyPressFcn',@sfKeyPress);
+set(h_fig1,'WindowButtonDownFcn',@sfButtonPress);
+	
+sfUpdateFigure([1:n]);
+
+% if user wants nothing to return until is finished
+    while 1
+      drawnow
+      if app.quit==1
+        break
+      end
+    end
+ 
+
+%% sfUpdateFigure
+function sfUpdateFigure(ca)
+	 
+		figure(2);
+		
+		img=backpro(sino(:,index),Omega(index)*pi/180);
+		imshow(img,[])
+		
+	
+		figure(1);
+		for i=1:length(ca)
+			subplot(gridy,gridx,ca(i));title(ax(ca(i)),sprintf('%d (%d)',index(ca(i)), struct_id(ca(i)) ));
+		end
+	
+end	
+
+%%  sfKeyPress
+  function sfKeyPress(varargin)  
+    % varargin{2} contains the event details
+    
+	c=varargin{2};
+	
+    switch c.Key
+
+      case 'return'
+        disp('accept selection')
+        save (sprintf('%s/4_grains/grain%d_/grain%d_.mat',parameters.acq.dir,grainid,grainid), 'index', '-append') ;
+        set(h_fig1,'KeyPressFcn',[]);
+		set(h_fig1,'WindowButtonDownFcn',[]);
+		app.quit=1;
+	end
+  end
+
+
+%%  sfButtonPress
+  function sfButtonPress(varargin)  
+    % varargin{2} contains the event details
+    src=varargin{1};
+	toto=varargin{2};
+	ca=gca;
+	ca=find(ax==ca);
+    index(ca)=~index(ca);
+	
+	sfUpdateFigure(ca);
+  end	
+ 
+
+end	
+
diff --git a/5_reconstruction/gtratiovolumes_lastandprevious.m b/5_reconstruction/gtratiovolumes_lastandprevious.m
new file mode 100755
index 0000000000000000000000000000000000000000..6540476adb08951d4b3c6a60e7c94105029cce36
--- /dev/null
+++ b/5_reconstruction/gtratiovolumes_lastandprevious.m
@@ -0,0 +1,30 @@
+% this macro takes the size of the thresholded grains in s5_dct5_ and
+% s5_dct1_ respectivelly, using the table (C) generated by
+% gtcorrelatenewandolddata_marcelo
+
+function gtratiovolumes_lastandprevious(C, last_dataset, first_dataset)
+
+E=[];
+
+	for i=1:size(C,1)
+		if C(i,1)>0
+			A=sprintf('/data/id19/graintracking/graingrowth/%s/4_grains/grain%d_/grain%d_2.edf',last_dataset, C(i,1),C(i,1));
+			A1=edf_read(A);
+			B=sum(A1);
+			D=sum(B);
+			E=sum(D);
+			F=sprintf('/data/id19/graintracking/graingrowth/%s/4_grains/grain%d_/grain%d_2.edf',first_dataset, C(i,2),C(i,2));
+			F1=edf_read(F);
+			G=sum(F1);
+			H=sum(G);
+			I=sum(H);
+			J(i)=(E/I);
+		end
+	end
+	figure
+	for i=1:size(J,2)		
+		if C(i,1)>0
+			plot(i,J(i),'*r')
+			hold on
+		end
+	end
\ No newline at end of file
diff --git a/5_reconstruction/gtsee_lastandprevious.m b/5_reconstruction/gtsee_lastandprevious.m
new file mode 100755
index 0000000000000000000000000000000000000000..7adef80c97a094d731c1331715a53a5d5e59a642
--- /dev/null
+++ b/5_reconstruction/gtsee_lastandprevious.m
@@ -0,0 +1,268 @@
+%once the grains are correlated take the grainIDS from the C list and
+%compare their volumes (slice) and one of their projections
+%Marcelo
+%08/02/2007
+
+
+function gtsee_lastandprevious(new_data, old_data, last_dataset, first_dataset) %grainID's from s5_dct5_ and s5_dct1_, respectivelly
+
+global parameters
+clear parameters
+load(sprintf('/data/id19/graintracking/graingrowth/%s/parameters.mat', last_dataset));
+gtDBconnect
+%load full_image, center_slice,extspot and difspot image from lastdataset
+
+extspot1=mym(sprintf('select extspotID from %sextspot where grainID=%d',last_dataset, new_data));
+extspotID_s5_dct5_=min(extspot1);
+nd=size(extspot1)/2;
+ndtry=fix(nd(1));
+extspotID_s5_dct5_2=extspot1(ndtry)
+bbID_s5_dct5_=mym(sprintf('select bbID from %sextspot where extspotID=%d',last_dataset, extspotID_s5_dct5_));
+bbID_s5_dct5_2=mym(sprintf('select bbID from %sextspot where extspotID=%d',last_dataset, extspotID_s5_dct5_2));
+[CentroidX, CentroidY, Start_dct5, End_dct5, max_image_s5_dct5_]=mym(sprintf('select CentroidX, CentroidY, StartImage, EndImage, MaxImage from %sdifspot where difspotID=%d', last_dataset, extspotID_s5_dct5_));
+[CentroidX_2, CentroidY_2, Start_dct5_2, End_dct5_2, max_image_s5_dct5_2]=mym(sprintf('select CentroidX, CentroidY, StartImage, EndImage, MaxImage from %sdifspot where difspotID=%d',last_dataset, extspotID_s5_dct5_2));
+[Xcentroid, Ycentroid]=mym(sprintf('select Xcentroid, Ycentroid from %sbboxes where bboxID=%d',last_dataset, bbID_s5_dct5_));
+[Xcentroid_2, Ycentroid_2]=mym(sprintf('select Xcentroid, Ycentroid from %sbboxes where bboxID=%d',last_dataset, bbID_s5_dct5_2));
+%A=sprintf('/data/id19/graintracking/graingrowth/s5_dct5_/1_preprocessing/full/full%04d.edf',max_image_s5_dct5_);
+%B=edf_read(A);
+%B=B*0;
+%st5=(max_image_s5_dct5_)-2;
+%en5=(max_image_s5_dct5_)+2;
+[W, bb53, bb54]=ExtSpot_lastandprevious(extspotID_s5_dct5_, last_dataset,0);
+W5=DifSpot_lastandprevious(extspotID_s5_dct5_, last_dataset);
+sizeW5=size(W5);
+[W_2, bb53_2, bb54_2]=ExtSpot_lastandprevious(extspotID_s5_dct5_2, last_dataset, 0);
+W5_2=DifSpot_lastandprevious(extspotID_s5_dct5_2, last_dataset);
+sizeW5_2=size(W5_2);
+%for i=st5:en5
+%	R=sprintf('/data/id19/graintracking/graingrowth/s5_dct5_/1_preprocessing/full/full%04d.edf',i);
+%	S=edf_read(R);
+%	B=B+S;
+%end;
+%imshow(B,[-600 1000])
+%hold on
+%bbx=parameters.acq.bb(1);
+%bby=parameters.acq.bb(2);
+%plot(bbx+Xcentroid,bby+Ycentroid,'*b');
+%plot(CentroidX,CentroidY,'*r');
+
+%load volume s5_dct5_
+
+%C=sprintf('/data/id19/graintracking/graingrowth/s5_dct5_/4_grains/grain%d_/grain%d__res0_3',new_data,new_data);
+%D=sdt_read(C);
+%E=size(D);
+%F=fix(E(3)/2);
+%figure
+%imshow(D(:,:,F),[])
+CentroidXmin=CentroidX-50;
+CentroidXmin_2=CentroidX_2-50;
+CentroidXmax=CentroidX+50;
+CentroidXmax_2=CentroidX_2+50;
+CentroidYmin=CentroidY-50;
+CentroidYmin_2=CentroidY_2-50;
+CentroidYmax=CentroidY+50;
+CentroidYmax_2=CentroidY_2+50;
+
+
+clear parameters
+parameters=load(sprintf('/data/id19/graintracking/graingrowth/%s/parameters.mat', first_dataset));
+
+%load extspot image first dataset
+extspot2=mym(sprintf('select extspotID from %sextspot where grainID=%d',first_dataset, old_data));
+difspotID1=[];
+for i=1:size(extspot2)
+	[CentroidXs1, CentroidYs1, Start_dct1, End_dct1, max_image_s5_dct1_, difspotID]=mym(sprintf('select CentroidX, CentroidY, StartImage, EndImage, MaxImage, difspotID from %sdifspot where difspotID=%d and CentroidX>%d and CentroidX<%d and CentroidY>%d and CentroidY<%d',first_dataset, extspot2(i), CentroidXmin, CentroidXmax, CentroidYmin, CentroidYmax));
+	
+	if ~isempty(difspotID)
+		difspotID1=difspotID;
+		extspotID_s5_dct1_=difspotID;
+		bbID_s5_dct1_=mym(sprintf('select bbID from %sextspot where extspotID=%d',first_dataset, extspotID_s5_dct1_));
+		[Xcentroid_dct1, Ycentroid_dct1]=mym(sprintf('select Xcentroid, Ycentroid from %sbboxes where bboxID=%d',first_dataset, bbID_s5_dct1_));
+		%G=sprintf('/data/id19/graintracking/graingrowth/s5_dct1_/1_preprocessing/full/full%04d.edf',max_image_s5_dct1_);
+		maxim=max_image_s5_dct1_;
+		centrX=CentroidXs1;
+		centrY=CentroidYs1;
+		[V, bbf3, bbf4]=ExtSpot_lastandprevious2(extspotID_s5_dct1_, bb53, bb54,first_dataset, 0);
+		V5=DifSpot_lastandprevious2(extspotID_s5_dct1_, first_dataset);
+		sizeV5=size(V5);
+		
+		if sizeV5(1)<sizeW5(1)
+			cV5=zeros(sizeW5(1),sizeV5(2));
+			for i=1:sizeV5(1)
+				for j=1:sizeV5(2)
+				cV5(i,j)=V5(i,j);
+				end
+			end
+			V5=cV5;
+			sizeV5=size(V5);
+		end
+		
+		if sizeV5(2)<sizeW5(2)
+			cV5=zeros(sizeV5(1),sizeW5(2));
+			for i=1:sizeV5(1)
+				for j=1:sizeV5(2)
+				cV5(i,j)=V5(i,j);
+				end
+			end
+			V5=cV5;
+			sizeV5=size(V5);
+		end
+		
+		if sizeW5(1)<sizeV5(1)
+			cW5=zeros(sizeV5(1),sizeW5(2));
+			for i=1:sizeW5(1)
+				for j=1:sizeW5(2)
+				cW5(i,j)=W5(i,j);
+				end
+			end
+			W5=cW5;
+			sizeW5=size(W5);
+		end
+		
+		if sizeW5(2)<sizeV5(2)
+			cW5=zeros(sizeW5(1),sizeV5(2));
+			for i=1:sizeW5(1)
+				for j=1:sizeW5(2)
+				cW5(i,j)=W5(i,j);
+				end
+			end
+			W5=cW5;
+			sizeW5=size(W5);
+		end
+		
+	end
+	
+end
+
+difspotID2=[];
+if isempty(difspotID1)
+	
+	for i=1:size(extspot2)
+		[CentroidXs1, CentroidYs1, Start_dct1, End_dct1, max_image_s5_dct1_, difspotID]=mym(sprintf('select CentroidX, CentroidY, StartImage, EndImage, MaxImage, difspotID from %sdifspot where difspotID=%d and CentroidX>%d and CentroidX<%d and CentroidY>%d and CentroidY<%d',first_dataset, extspot2(i), CentroidXmin_2, CentroidXmax_2, CentroidYmin_2, CentroidYmax_2));
+	
+		if ~isempty(difspotID)
+			difspotID2=difspotID;
+			extspotID_s5_dct1_=difspotID;
+			bbID_s5_dct1_=mym(sprintf('select bbID from %sextspot where extspotID=%d',first_dataset, extspotID_s5_dct1_));
+			[Xcentroid_dct1, Ycentroid_dct1]=mym(sprintf('select Xcentroid, Ycentroid from %sbboxes where bboxID=%d',first_dataset, bbID_s5_dct1_));
+			%G=sprintf('/data/id19/graintracking/graingrowth/s5_dct1_/1_preprocessing/full/full%04d.edf',max_image_s5_dct1_);
+			maxim=max_image_s5_dct1_;
+			centrX=CentroidXs1;
+			centrY=CentroidYs1;
+			[V, bbf3, bbf4]=ExtSpot_lastandprevious2(extspotID_s5_dct1_, bb53, bb54, first_dataset, 0);
+			V5=DifSpot_lastandprevious2(extspotID_s5_dct1_, first_dataset);
+			sizeV5=size(V5);
+		
+			if sizeV5(1)<sizeW5_2(1)
+				cV5=zeros(sizeW5_2(1),sizeV5(2));
+				for i=1:sizeV5(1)
+					for j=1:sizeV5(2)
+						cV5(i,j)=V5(i,j);
+					end
+				end
+				V5=cV5;
+				sizeV5=size(V5);
+			end
+		
+			if sizeV5(2)<sizeW5_2(2)
+				cV5=zeros(sizeV5(1),sizeW5_2(2));
+				for i=1:sizeV5(1)
+					for j=1:sizeV5(2)
+						cV5(i,j)=V5(i,j);
+					end
+				end
+				V5=cV5;
+				sizeV5=size(V5);
+			end
+		
+			if sizeW5_2(1)<sizeV5(1)
+				cW5_2=zeros(sizeV5(1),sizeW5_2(2));
+				for i=1:sizeW5_2(1)
+					for j=1:sizeW5_2(2)
+						cW5_2(i,j)=W5_2(i,j);
+					end
+				end
+				W5_2=cW5_2;
+				sizeW5_2=size(W5_2);
+			end
+		
+			if sizeW5_2(2)<sizeV5(2)
+				cW5_2=zeros(sizeW5_2(1),sizeV5(2));
+				for i=1:sizeW5_2(1)
+					for j=1:sizeW5_2(2)
+						cW5_2(i,j)=W5_2(i,j);
+					end
+				end
+				W5_2=cW5_2;
+				sizeW5_2=size(W5_2);
+			end
+		
+		end
+	end
+end
+
+	
+%H=edf_read(G);
+%H=H*0;
+%st1=(maxim)-2;
+%en1=(maxim)+2;
+
+%for i=st1:en1
+%	T=sprintf('/data/id19/graintracking/graingrowth/s5_dct1_/1_preprocessing/full/full%04d.edf',i);
+%	U=edf_read(T);
+%	H=U+H;
+%end
+%figure
+%imshow(H,[-600 1000])
+%hold on
+%bbx_dct1=parameters.acq.bb(1);
+%bby_dct1=parameters.acq.bb(2);
+%plot(bbx_dct1+Xcentroid_dct1,bby_dct1+Ycentroid_dct1,'*b');
+%plot(centrX,centrY,'*r');
+
+if ~isempty(difspotID1)
+	W=ExtSpot_lastandprevious3(extspotID_s5_dct5_,bbf3,bbf4, last_dataset, 0);
+	figure
+	imshow(W,[]);
+	figure
+	imshow(V,[]);
+	figure
+	findshifts(W,V)
+	disp('to play with EXTSPOTS move the ARROWS, to play with DIFSPOTS, CLICK on the image')
+	mouse=waitforbuttonpress
+	if mouse==0
+		figure
+		imshow(W5,[]);
+		figure
+		imshow(V5,[]);
+		figure
+		findshifts(W5,V5)
+	end
+end
+
+if ~isempty(difspotID2)
+	W_2=ExtSpot_lastandprevious3(extspotID_s5_dct5_2,bbf3,bbf4,last_dataset, 0);
+	figure
+	imshow(W_2,[]);
+	figure
+	imshow(V,[]);
+	figure
+	findshifts(W_2,V)
+	disp('to play with EXTSPOTS move the ARROWS, to play with DIFSPOTS, CLICK on the image')
+	mouse=waitforbuttonpress
+	if mouse==0
+		figure
+		imshow(W5_2,[]);
+		figure
+		imshow(V5,[]);
+		figure
+		findshifts(W5_2,V5)
+	end
+end
+%load volume s5_dct1_
+%I=sprintf('/data/id19/graintracking/graingrowth/s5_dct1_/4_grains/grain%d_/grain%d__res0_3',old_data,old_data);
+%K=sdt_read(I);
+%L=size(K);
+%M=fix(L(3)/2);
+%figure
+%imshow(K(:,:,M),[])
\ No newline at end of file
diff --git a/5_reconstruction/old/gtWriteStack_old.m b/5_reconstruction/old/gtWriteStack_old.m
new file mode 100755
index 0000000000000000000000000000000000000000..51d25ad344a950f6040301acb67d72d8df28aa6d
--- /dev/null
+++ b/5_reconstruction/old/gtWriteStack_old.m
@@ -0,0 +1,26 @@
+function gtWriteStack(stack,grainid)
+%write input files for ART reconstruction
+
+global parameters;
+if isempty(parameters)
+  load parameters.mat
+end
+
+grainname=sprintf('grain%d_',grainid);
+graindir=sprintf('%s/4_grains/%s',parameters.acq.dir,grainname);
+if ~exist(graindir,'dir')
+  mkdir(graindir);
+end
+
+for i=1:size(stack,3)
+	name=sprintf('%s/%s%d.sdt',graindir,grainname,i);
+	fid=fopen(name,'wb','l');
+  stack(:,:,i)=medfilt2(stack(:,:,i));
+  
+	fwrite(fid,stack(:,:,i)','float32');
+	fclose(fid);
+	name=sprintf('%s/%s%d.spr',graindir,grainname,i);
+  spr_write(name,2,parameters.acq.bb(3),parameters.acq.bb(4),3);
+end	
+
+
diff --git a/5_reconstruction/parfile.par b/5_reconstruction/parfile.par
new file mode 100755
index 0000000000000000000000000000000000000000..4af9794e9530aec2f9bf010666eeeb1c51d48375
--- /dev/null
+++ b/5_reconstruction/parfile.par
@@ -0,0 +1,63 @@
+PAGBEGIN SYSTEMAL
+PROJ_GENE_FILENAME = scanname
+EXT_PROJ0 = 1
+NBITER = 1
+NBITER_HALF_QUADRA = 1
+NBSAUV = 1
+REC_GENE_FILENAME = scanname
+EXT_REC0 = 1
+LAMBDA_FLAG = 0
+LAMBDA = 1.000000
+ERR_FLAG = 0
+ALGO_TYPE = 2
+BLOCK_SIZE = 1
+PROJ_MNG = A
+NB_RESOL = 1
+THRESH_SUPP = 0
+CLIP_SUPP = 4
+CLIP_SPHERE = 0
+HISTO_SIZE = 100
+MAXVOL = 1000.000000
+MINVOL = -10.000000
+VOL_TYPE = 3
+PARAM1 = 0.100000
+PARAM2 = 0.000050
+PARAM3 = 0.000050
+PARAM4 = 0.050000
+PARAM5 = 0.820000
+PAGEND SYSTEMAL
+PAGBEGIN ACQGEO
+NBRADIO = 1
+#radio 1 origine position
+POSITION = 1
+FGD = 145000.000000
+PGD = -0.000000
+QGD = 0.000000
+PEPD = 1.000000
+PEQD = 1.000000
+P1D = -49.500000
+Q1D = -49.500000
+NP =  100
+NQ =  100
+PSI = 0.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 0.000000
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 99
+IQF = 99
+PAGEND ACQGEO
+PAGBEGIN OBJET
+PEX = 1.000000
+PEY = 1.000000
+PEZ = 1.000000
+X1 = -49.000000
+Y1 = -49.000000
+Z1 = -49.000000
+NX = 100
+NY = 100
+NZ = 100
+PAGEND OBJET
diff --git a/5_reconstruction/sdt_read.m b/5_reconstruction/sdt_read.m
new file mode 100755
index 0000000000000000000000000000000000000000..135db6b96135455b20f7a62b1fd1c0341ff5816f
--- /dev/null
+++ b/5_reconstruction/sdt_read.m
@@ -0,0 +1,33 @@
+function vol=sdt_read(fname)
+% for reading *.sdt files
+% fname: filename without the extension
+% Wolfgang and Marcelo on 19/06/2006
+
+name=sprintf('%s.spr',fname);
+A=floor(textread(name,'%f', 8));
+dimension=A(1);
+
+switch dimension
+    case 2
+        zsize=1;
+    case 3    
+		zsize=A(8);
+	otherwise
+		disp('unsupported file dimension');
+		return;
+end
+
+xsize=A(2);
+ysize=A(5);
+
+sdtname=sprintf('%s.sdt',fname);
+vol=volread_single(sdtname,'float32',0,xsize,ysize,zsize,'l');
+
+if ndims(vol)==3 % 3D volume
+  vol=permute(vol,[2 1 3]); % reorganise dimensions
+else % 2D image
+  vol=transpose(vol);
+end
+
+ 
+    
diff --git a/5_reconstruction/sdt_write.m b/5_reconstruction/sdt_write.m
new file mode 100755
index 0000000000000000000000000000000000000000..35d8f409fab9e4a0bc15535b457dd598ee216f6f
--- /dev/null
+++ b/5_reconstruction/sdt_write.m
@@ -0,0 +1,40 @@
+function stat=sdtwrite(name,vol,type)
+% writes 2D or 3D binary files (.sdt) and associated descriptor file (.spr)
+% for the moment only 'float32' is implemented as type...
+% ATTENTION : the name has to be given without extension (.sdt) !
+% IS THIS IMAGE TRANSPOSED??? GJ
+sdt=sprintf('%s.sdt',name);
+spr=sprintf('%s.spr',name);
+
+switch type
+  case 'float32'
+    typenum=3;
+%    disp(sprintf('writing file %s',sdt));
+  otherwise
+    disp('datatype not yet supported - use float32')
+    return;
+end
+s=size(vol);
+%disp('Writing header')
+fid_spr=fopen(spr,'w');
+fprintf(fid_spr,'%d\n',length(s));
+fprintf(fid_spr,'%d\n',s(2));   % was s(2) before
+fprintf(fid_spr,'0\n1\n');
+fprintf(fid_spr,'%d\n',s(1));    % was s(1) before
+fprintf(fid_spr,'0\n1\n');
+if length(s)==3
+  fprintf(fid_spr,'%d\n',s(3));
+  fprintf(fid_spr,'0\n1\n');
+end
+fprintf(fid_spr,'%d\n',typenum);
+fprintf(fid_spr,'0\n1\n');
+fclose(fid_spr);
+
+%disp('Writing data')
+% 3D volumes might not be in correct order!
+fid_sdt=fopen(sdt,'w');
+fwrite(fid_sdt,vol',type);
+
+fclose(fid_sdt);
+
+
diff --git a/5_reconstruction/sdtwrite.m b/5_reconstruction/sdtwrite.m
new file mode 100755
index 0000000000000000000000000000000000000000..4b9c41444013a7885b4c539cd5e93e68bc51cd88
--- /dev/null
+++ b/5_reconstruction/sdtwrite.m
@@ -0,0 +1,39 @@
+function stat=sdtwrite(name,vol,type)
+% writes 2D or 3D binary files (.sdt) and associated descriptor file (.spr)
+% for the moment only 'float32' is implemented as type...
+% ATTENTION : the name has to be given without extension (.sdt) !
+% IS THIS IMAGE TRANSPOSED??? GJ
+sdt=sprintf('%s.sdt',name);
+spr=sprintf('%s.spr',name);
+
+switch type
+  case 'float32'
+    typenum=3;
+    disp(sprintf('writing file %s',sdt));
+  otherwise
+    disp('datatype not yet supported - use float32')
+    return;
+end
+s=size(vol);
+disp('Writing header')
+fid_spr=fopen(spr,'w');
+fprintf(fid_spr,'%d\n',length(s));
+fprintf(fid_spr,'%d\n',s(2));
+fprintf(fid_spr,'0\n1\n');
+fprintf(fid_spr,'%d\n',s(1));
+fprintf(fid_spr,'0\n1\n');
+if length(s)==3
+  fprintf(fid_spr,'%d\n',s(3));
+  fprintf(fid_spr,'0\n1\n');
+end
+fprintf(fid_spr,'%d\n',typenum);
+fprintf(fid_spr,'0\n1\n');
+fclose(fid_spr);
+
+disp('Writing data')
+fid_sdt=fopen(sdt,'w');
+fwrite(fid_sdt,vol',type);
+
+fclose(fid_sdt);
+
+
diff --git a/5_reconstruction/test b/5_reconstruction/test
new file mode 100755
index 0000000000000000000000000000000000000000..ca44c3973bfdcdabf33b86818ac7043e94965fa4
--- /dev/null
+++ b/5_reconstruction/test
@@ -0,0 +1,2021 @@
+PAGBEGIN SYSTEMAL
+PROJ_GENE_FILENAME = proj
+EXT_PROJ0 = 1
+EXT_PROJ1 = 2
+EXT_PROJ2 = 3
+EXT_PROJ3 = 4
+EXT_PROJ4 = 5
+EXT_PROJ5 = 6
+EXT_PROJ6 = 7
+EXT_PROJ7 = 8
+EXT_PROJ8 = 9
+EXT_PROJ9 = 10
+EXT_PROJ10 = 11
+EXT_PROJ11 = 12
+EXT_PROJ12 = 13
+EXT_PROJ13 = 14
+EXT_PROJ14 = 15
+EXT_PROJ15 = 16
+EXT_PROJ16 = 17
+EXT_PROJ17 = 18
+EXT_PROJ18 = 19
+EXT_PROJ19 = 20
+EXT_PROJ20 = 21
+EXT_PROJ21 = 22
+EXT_PROJ22 = 23
+EXT_PROJ23 = 24
+EXT_PROJ24 = 25
+EXT_PROJ25 = 26
+EXT_PROJ26 = 27
+EXT_PROJ27 = 28
+EXT_PROJ28 = 29
+EXT_PROJ29 = 30
+EXT_PROJ30 = 31
+EXT_PROJ31 = 32
+EXT_PROJ32 = 33
+EXT_PROJ33 = 34
+EXT_PROJ34 = 35
+EXT_PROJ35 = 36
+EXT_PROJ36 = 37
+EXT_PROJ37 = 38
+EXT_PROJ38 = 39
+EXT_PROJ39 = 40
+EXT_PROJ40 = 41
+EXT_PROJ41 = 42
+EXT_PROJ42 = 43
+EXT_PROJ43 = 44
+EXT_PROJ44 = 45
+EXT_PROJ45 = 46
+EXT_PROJ46 = 47
+EXT_PROJ47 = 48
+EXT_PROJ48 = 49
+EXT_PROJ49 = 50
+EXT_PROJ50 = 51
+EXT_PROJ51 = 52
+EXT_PROJ52 = 53
+EXT_PROJ53 = 54
+EXT_PROJ54 = 55
+EXT_PROJ55 = 56
+EXT_PROJ56 = 57
+EXT_PROJ57 = 58
+EXT_PROJ58 = 59
+EXT_PROJ59 = 60
+EXT_PROJ60 = 61
+EXT_PROJ61 = 62
+EXT_PROJ62 = 63
+EXT_PROJ63 = 64
+EXT_PROJ64 = 65
+EXT_PROJ65 = 66
+EXT_PROJ66 = 67
+EXT_PROJ67 = 68
+EXT_PROJ68 = 69
+EXT_PROJ69 = 70
+EXT_PROJ70 = 71
+EXT_PROJ71 = 72
+EXT_PROJ72 = 73
+EXT_PROJ73 = 74
+EXT_PROJ74 = 75
+EXT_PROJ75 = 76
+EXT_PROJ76 = 77
+EXT_PROJ77 = 78
+EXT_PROJ78 = 79
+EXT_PROJ79 = 80
+EXT_PROJ80 = 81
+EXT_PROJ81 = 82
+EXT_PROJ82 = 83
+EXT_PROJ83 = 84
+EXT_PROJ84 = 85
+EXT_PROJ85 = 86
+EXT_PROJ86 = 87
+EXT_PROJ87 = 88
+EXT_PROJ88 = 89
+EXT_PROJ89 = 90
+NBITER = 1
+NBITER_HALF_QUADRA = 1
+NBSAUV = 1
+REC_GENE_FILENAME = proj
+EXT_REC0 = 1
+LAMBDA_FLAG = 0
+LAMBDA = 0.100000
+ERR_FLAG = 0
+ALGO_TYPE = 2
+BLOCK_SIZE = 90
+PROJ_MNG = A
+NB_RESOL = 1
+THRESH_SUPP = 100
+CLIP_SUPP = 4
+CLIP_SPHERE = 0
+HISTO_SIZE = 100
+MAXVOL = 1000.000000
+MINVOL = -10.000000
+VOL_TYPE = 3
+PARAM1 = 0.100000
+PARAM2 = 0.000050
+PARAM3 = 0.000050
+PARAM4 = 0.050000
+PARAM5 = 0.820000
+PAGEND SYSTEMAL
+PAGBEGIN ACQGEO
+NBRADIO = 90
+#radio 1 origine position
+POSITION = 1
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 0.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 2 origine position
+POSITION = 2
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 4.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 3 origine position
+POSITION = 3
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 8.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 4 origine position
+POSITION = 4
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 12.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 5 origine position
+POSITION = 5
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 16.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 6 origine position
+POSITION = 6
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 20.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 7 origine position
+POSITION = 7
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 24.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 8 origine position
+POSITION = 8
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 28.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 9 origine position
+POSITION = 9
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 32.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 10 origine position
+POSITION = 10
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 36.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 11 origine position
+POSITION = 11
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 40.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 12 origine position
+POSITION = 12
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 44.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 13 origine position
+POSITION = 13
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 48.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 14 origine position
+POSITION = 14
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 52.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 15 origine position
+POSITION = 15
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 56.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 16 origine position
+POSITION = 16
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 60.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 17 origine position
+POSITION = 17
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 64.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 18 origine position
+POSITION = 18
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 68.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 19 origine position
+POSITION = 19
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 72.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 20 origine position
+POSITION = 20
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 76.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 21 origine position
+POSITION = 21
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 80.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 22 origine position
+POSITION = 22
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 84.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 23 origine position
+POSITION = 23
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 88.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 24 origine position
+POSITION = 24
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 92.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 25 origine position
+POSITION = 25
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 96.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 26 origine position
+POSITION = 26
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 100.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 27 origine position
+POSITION = 27
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 104.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 28 origine position
+POSITION = 28
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 108.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 29 origine position
+POSITION = 29
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 112.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 30 origine position
+POSITION = 30
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 116.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 31 origine position
+POSITION = 31
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 120.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 32 origine position
+POSITION = 32
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 124.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 33 origine position
+POSITION = 33
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 128.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 34 origine position
+POSITION = 34
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 132.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 35 origine position
+POSITION = 35
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 136.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 36 origine position
+POSITION = 36
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 140.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 37 origine position
+POSITION = 37
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 144.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 38 origine position
+POSITION = 38
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 148.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 39 origine position
+POSITION = 39
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 152.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 40 origine position
+POSITION = 40
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 156.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 41 origine position
+POSITION = 41
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 160.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 42 origine position
+POSITION = 42
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 164.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 43 origine position
+POSITION = 43
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 168.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 44 origine position
+POSITION = 44
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 172.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 45 origine position
+POSITION = 45
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 176.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 46 origine position
+POSITION = 46
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 180.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 47 origine position
+POSITION = 47
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 184.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 48 origine position
+POSITION = 48
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 188.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 49 origine position
+POSITION = 49
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 192.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 50 origine position
+POSITION = 50
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 196.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 51 origine position
+POSITION = 51
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 200.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 52 origine position
+POSITION = 52
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 204.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 53 origine position
+POSITION = 53
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 208.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 54 origine position
+POSITION = 54
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 212.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 55 origine position
+POSITION = 55
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 216.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 56 origine position
+POSITION = 56
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 220.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 57 origine position
+POSITION = 57
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 224.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 58 origine position
+POSITION = 58
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 228.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 59 origine position
+POSITION = 59
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 232.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 60 origine position
+POSITION = 60
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 236.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 61 origine position
+POSITION = 61
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 240.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 62 origine position
+POSITION = 62
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 244.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 63 origine position
+POSITION = 63
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 248.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 64 origine position
+POSITION = 64
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 252.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 65 origine position
+POSITION = 65
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 256.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 66 origine position
+POSITION = 66
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 260.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 67 origine position
+POSITION = 67
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 264.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 68 origine position
+POSITION = 68
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 268.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 69 origine position
+POSITION = 69
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 272.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 70 origine position
+POSITION = 70
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 276.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 71 origine position
+POSITION = 71
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 280.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 72 origine position
+POSITION = 72
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 284.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 73 origine position
+POSITION = 73
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 288.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 74 origine position
+POSITION = 74
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 292.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 75 origine position
+POSITION = 75
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 296.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 76 origine position
+POSITION = 76
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 300.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 77 origine position
+POSITION = 77
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 304.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 78 origine position
+POSITION = 78
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 308.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 79 origine position
+POSITION = 79
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 312.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 80 origine position
+POSITION = 80
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 316.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 81 origine position
+POSITION = 81
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 320.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 82 origine position
+POSITION = 82
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 324.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 83 origine position
+POSITION = 83
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 328.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 84 origine position
+POSITION = 84
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 332.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 85 origine position
+POSITION = 85
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 336.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 86 origine position
+POSITION = 86
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 340.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 87 origine position
+POSITION = 87
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 344.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 88 origine position
+POSITION = 88
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 348.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 89 origine position
+POSITION = 89
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 352.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+#radio 90 origine position
+POSITION = 90
+FGD = 145000.000000
+PGD = 0.000000
+QGD = -4012870.572360
+PEPD = 0.002400
+PEQD = 0.002400
+P1D = -167.500000
+Q1D = -87.000000
+NP =  336
+NQ =  175
+PSI = 356.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = 0.000000
+QO = 9630.889374
+MO = -145000.000000
+IPD = 0
+IQD = 0
+IPF = 335
+IQF = 174
+PAGEND ACQGEO
+PAGBEGIN OBJET
+PEX = 0.002400
+PEY = 0.002400
+PEZ = 0.002400
+X1 = -0.403200
+Y1 = -0.403200
+Z1 = -0.018000
+NX = 336
+NY = 336
+NZ = 3
+PAGEND OBJET
diff --git a/5_reconstruction/testART.m b/5_reconstruction/testART.m
new file mode 100755
index 0000000000000000000000000000000000000000..7e5033dddee6698bd7e1ba453008368e50523651
--- /dev/null
+++ b/5_reconstruction/testART.m
@@ -0,0 +1,305 @@
+function vol=testART(scanname,parfilename,dif_numbers,shear_numbers,ext_numbers,grain,lambda,parameters,slice)
+% write .par file ready for rec_alg to use
+%
+%
+% function
+% make_art_parfile(scanname,parfilename,dif_numbers,shear_numbers,ext_numbe
+% rs, grain, lambda,parameters,slice)
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% dif_numbers: indices of diffraction spots to be taken into account, e.g. [1:14]
+% shear_numbers: indices of sheared diffraction spots to be taken into account 
+% ext_numbers:   : indices of extinction spots to be taken into account
+% grain:
+% lambda: 
+% parameters:
+% slice :     [zstart, zend]
+%              z               single slice
+%             empty            full volume
+
+
+%load parameters.mat
+
+gtMakeLinks(dif_numbers,shear_numbers,ext_numbers);
+
+blocksize= length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+
+offset=0;
+
+fid=fopen(parfilename,'w');
+nbradio=length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+% Algorithm paramters
+nbiter = length(lambda);
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 0;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 10000000;      % Distance source to detector ~ 10^7 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd= 1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = fgd-parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (positive here: -m0 will be given to AREMIS 
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+nx=parameters.acq.bb(3);
+ny=parameters.acq.bb(3);
+
+x1=-parameters.acq.bb(3)/2;
+y1=-parameters.acq.bb(3)/2;
+
+if ~exist('slice','var')
+  nz=grain.zend-grain.zstart+1;
+  z1= parameters.acq.bb(4)/2-grain.zend;
+elseif length(slice)>1
+  z1= parameters.acq.bb(4)/2-slice(2)-0.5;
+  nz=slice(2)-slice(1)+1;
+else
+  z1= parameters.acq.bb(4)/2-slice(1)-1.5;
+  nz=3;
+end  
+
+%p_numbers=find(index);
+
+
+% write diffraction spots 
+
+for i=1:length(dif_numbers)
+
+  Omega =   (grain.omega(dif_numbers(i))+0);
+  Theta =   grain.theta(dif_numbers(i));
+  Eta   =   -grain.eta(dif_numbers(i));    % needs a negtive sign for real data (flipped)
+  psi(i)=   Omega;               % first Euler angle (==omega)  [degrees]
+  xsi(i)=   90.0;                % second Euler angle
+  delta =   0.0;                 % third Euler angle
+
+  
+  query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.difspots(dif_numbers(i)));
+  [bb(1),bb(2),bb(3),bb(4)]=mym(query);
+  % now take into account the flip of the images...
+  bb(1)=2*parameters.acq.rotx-bb(1)-bb(3)+1;
+  bb=bb+[-100 -100 200 200];
+   
+  %bb=parameters.bb(dif_numbers(i),1:4) +[-100 -100 200 200];
+  
+  p1d(i) =      m0*tand(2*Theta)*sind(Eta)+bb(1)-parameters.acq.rotx;      % orig left  detector corner [pixels]
+  %p1d(i) =      m0*tand(2*Theta)*sind(Eta)+bb(1)+bb(3)-parameters.acq.rotx;
+  q1d(i) =      m0*tand(2*Theta)*cosd(Eta)+parameters.acq.ydet/2-bb(2);    % orig upper detector corner [pixels]     
+  %q1d(i) =     -m0*tand(2*Theta)*cosd(Eta)-parameters.acq.ydet/2+bb(2);
+  np(i)=bb(3);                % horizontal detector size [pixels]  
+  nq(i)=bb(4);                % vertical detector size [pixels]
+
+  p0(i) =    m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+  q0(i) =    m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+  iqf(i) = nq(i)-1;      % ROI end vertical
+
+end
+
+% now do the same for the sheared spots (inserted into direct beam BB)
+
+off=length(dif_numbers);
+
+for i=1:length(shear_numbers)
+  %disp('attention omega in direct beam has been modified !');
+  Omega =   -grain.omegashear(shear_numbers(i));  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off) = Omega;            % first Euler angle (==omega)  [degrees]
+  xsi(i+off) = 90.0+grain.phi(shear_numbers(i));      % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off) = np(i+off)-1;      % ROI end horizontal [pixels]
+  iqf(i+off) = nq(i+off)-1;      % ROI end vertical
+
+end
+
+% now write extinction spots...
+
+off2=length(dif_numbers)+length(shear_numbers);
+
+for i=1:length(ext_numbers)
+  disp('attention omega in direct beam has been modified !');
+  Omega =   -grain.omega(ext_numbers(i))  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off2) = Omega;           % first Euler angle (==omega)  [degrees]
+  xsi(i+off2) = 90.0;            % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off2) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off2) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off2)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off2)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off2) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off2) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off2) = np(i+off2)-1;      % ROI end horizontal [pixels]
+  iqf(i+off2) = nq(i+off2)-1;      % ROI end vertical
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+
+for i=1:length(dif_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,i);
+end
+for i=1:length(shear_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off-1,i+off);
+end
+for i=1:length(ext_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off2-1,i+off2);
+end  
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi(i));
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',-m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view'
+if 1
+  % now do the reconstructioon
+  command=sprintf('%s %s;%s %s_res0_%d',rec_alg,parfilename,seg2view,scanname,nbiter);
+  unix(command);
+  volname=sprintf('%s_res0_%d',scanname,nbiter);
+  vol=sdt_read(volname);
+  imshow(vol(:,:,round(nz/2)),[])
+  shg;
+else
+  vol=[];
+end  
diff --git a/5_reconstruction/testART2.m b/5_reconstruction/testART2.m
new file mode 100755
index 0000000000000000000000000000000000000000..eaa1bf5a3af2bd1e6320aea1286bf302fbdd728c
--- /dev/null
+++ b/5_reconstruction/testART2.m
@@ -0,0 +1,304 @@
+function vol=testART(scanname,parfilename,dif_numbers,shear_numbers,ext_numbers,grain,lambda,parameters,slice)
+% write .par file ready for rec_alg to use
+%
+%
+% function
+% make_art_parfile(scanname,parfilename,dif_numbers,shear_numbers,ext_numbe
+% rs, grain, lambda,parameters,slice)
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% dif_numbers: indices of diffraction spots to be taken into account, e.g. [1:14]
+% shear_numbers: indices of sheared diffraction spots to be taken into account 
+% ext_numbers:   : indices of extinction spots to be taken into account
+% grain:
+% lambda: 
+% parameters:
+% slice :     [zstart, zend]
+%              z               single slice
+%             empty            full volume
+
+
+%load parameters.mat
+
+gtMakeLinks(dif_numbers,shear_numbers,ext_numbers);
+
+blocksize= length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+
+offset=0;
+
+fid=fopen(parfilename,'w');
+nbradio=length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+% Algorithm paramters
+nbiter = length(lambda);
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 10000000;      % Distance source to detector ~ 10^7 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd=  1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = fgd-parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (positive here: -m0 will be given to AREMIS 
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+nx=parameters.acq.bb(3);
+ny=parameters.acq.bb(3);
+
+x1=-parameters.acq.bb(3)/2;
+y1=-parameters.acq.bb(3)/2;
+
+if ~exist('slice','var')
+  nz=grain.zend-grain.zstart+1;
+  z1= parameters.acq.bb(4)/2-grain.zend;
+elseif length(slice)>1
+  z1= parameters.acq.bb(4)/2-slice(2)-0.5;
+  nz=slice(2)-slice(1)+1;
+else
+  z1= parameters.acq.bb(4)/2-slice(1)-1.5;
+  nz=3;
+end  
+
+%p_numbers=find(index);
+
+
+% write diffraction spots 
+
+for i=1:length(dif_numbers)
+
+  Omega =   grain.omega(dif_numbers(i));
+  Theta =   grain.theta(dif_numbers(i));
+  Eta   =   grain.eta(dif_numbers(i));    % needs a negtive sign for real data (flipped)
+  psi(i)=   Omega;               % first Euler angle (==omega)  [degrees]
+  xsi(i)=   90.0;                % second Euler angle
+  delta =   0.0;                 % third Euler angle
+
+
+  query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.struct_ids(dif_numbers(i)));
+  [bb(1),bb(2),bb(3),bb(4)]=mym(query);
+  % now take into account the flip of the images...
+  %bb(1)=2*parameters.acq.rotx-bb(1)-bb(3)+1;
+  bb=bb+[-100 -100 200 200];
+  
+  %bb=parameters.bb(dif_numbers(i),1:4) +[-100 -100 200 200];
+  
+  p1d(i) =     m0*tand(2*Theta)*sind(Eta)+bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i) =     m0*tand(2*Theta)*cosd(Eta)+parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  %q1d(i) =     m0*tand(2*Theta)*cosd(Eta)-parameters.acq.ydet/2+bb(2);
+  np(i)=bb(3);                % horizontal detector size [pixels]  
+  nq(i)=bb(4);                % vertical detector size [pixels]
+
+  p0(i) =    m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+  q0(i) =    m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+  iqf(i) = nq(i)-1;      % ROI end vertical
+
+end
+
+% now do the same for the sheared spots (inserted into direct beam BB)
+
+off=length(dif_numbers);
+
+for i=1:length(shear_numbers)
+  %disp('attention omega in direct beam has been modified !');
+  Omega =   -grain.omegashear(shear_numbers(i));  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off) = Omega;            % first Euler angle (==omega)  [degrees]
+  xsi(i+off) = 90.0+grain.phi(shear_numbers(i));      % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off) = np(i+off)-1;      % ROI end horizontal [pixels]
+  iqf(i+off) = nq(i+off)-1;      % ROI end vertical
+
+end
+
+% now write extinction spots...
+
+off2=length(dif_numbers)+length(shear_numbers);
+
+for i=1:length(ext_numbers)
+  disp('attention omega in direct beam has been modified !');
+  Omega =   -grain.omega(ext_numbers(i))  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off2) = Omega;           % first Euler angle (==omega)  [degrees]
+  xsi(i+off2) = 90.0;            % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off2) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off2) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off2)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off2)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off2) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off2) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off2) = np(i+off2)-1;      % ROI end horizontal [pixels]
+  iqf(i+off2) = nq(i+off2)-1;      % ROI end vertical
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+
+for i=1:length(dif_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,i);
+end
+for i=1:length(shear_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off-1,i+off);
+end
+for i=1:length(ext_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off2-1,i+off2);
+end  
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi(i));
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',-m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view'
+if 1
+  % now do the reconstructioon
+  command=sprintf('%s %s;%s %s_res0_%d',rec_alg,parfilename,seg2view,scanname,nbiter);
+  unix(command);
+  volname=sprintf('%s_res0_%d',scanname,nbiter);
+  vol=sdt_read(volname);
+  imshow(vol(:,:,round(nz/2)),[])
+  shg;
+else
+  vol=[];
+end  
diff --git a/5_reconstruction/testARTbackup.m b/5_reconstruction/testARTbackup.m
new file mode 100755
index 0000000000000000000000000000000000000000..596f2a4ce6ccd60e9a6f9be5cfb13950e698fdc2
--- /dev/null
+++ b/5_reconstruction/testARTbackup.m
@@ -0,0 +1,232 @@
+function testART(scanname,parfilename,p_numbers,grain,lambda,nbiter,blocksize,braggangle,offset,parameters,slice)
+% write .par file ready for rec_alg to use
+%
+%
+% function make_art_parfile(scanname,parfilename,p_numbers,p_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% 
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% p_numbers: vector containing the projections to be taken into account, e.g. [0:10:180]
+% p_angles : vector containing the correpsonding projection angles in degree e.g. [0:20:360]
+% lambda   : ART loop update parameter
+% nbiter   : number of ART iterations
+% blocksize: ART is updated after blocksize projections
+% pixsize  : pixelsize [mm]
+% braggangle: Bragg angle
+% np        : number of pixels in projections (hoizontal)
+% nq        : number of pixel in projections (vertical)
+% offset    : offset of the rotation axis with respect to the center of the image (in pixels) 
+% z1        : z start of reconstructed volume
+% nz        : number of reconstructed slices 
+% x1        : x start of reconstructed volume //andy 21/6/06
+% nx        : size of reconstructed volume in x
+% y1        : y start of reconstructed volume
+% ny        : size of reconstructed volume in y(attention: pixelsize in reconstructed image will be half
+% the pixel size in original projection images
+
+
+%gtnew - change to use parameters.acq
+%gtnew - change to use z coordinates of grain relative to top of sample
+
+
+%load parameters.mat
+
+
+
+
+fid=fopen(parfilename,'w');
+nbradio=length(p_numbers);
+
+% Algorithm paramters
+nbiter = nbiter;
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 100000000;      % Distance source to detector ~ 10^8 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd=  1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = -fgd+parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (<0)
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+nx=parameters.acq.bb(3);
+ny=parameters.acq.bb(3);
+
+x1=-parameters.acq.bb(3)/2;
+y1=-parameters.acq.bb(3)/2;
+
+if ~exist('slice','var')
+  nz=grain.zend-grain.zstart+1;
+  z1= parameters.acq.bb(4)/2-grain.zend;
+else
+  z1= parameters.acq.bb(4)/2-slice-2;
+  nz=5;
+end  
+
+%p_numbers=find(index);
+nbradio=length(p_numbers);
+
+for i=1:nbradio
+
+Omega =  -grain.Omega(p_numbers(i));
+Theta =  grain.Theta(p_numbers(i));
+Eta   =  grain.Eta(p_numbers(i));
+  
+psi(i) = Omega;               % first Euler angle (==omega)  [degrees]
+xsi =    90.0-braggangle;     % second Euler angle
+delta = 0.0;                  % third Euler angle
+
+if Theta>0
+  query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.struct_ids(p_numbers(i)));
+  [bb(1),bb(2),bb(3),bb(4)]=mym(query);
+ 
+  bb=bb+[-100 -100 200 200];
+  
+  %bb=parameters.bb(i,:);
+else
+  bb=parameters.acq.bb;
+end  
+
+
+
+
+p1d(i) = -m0*tand(2*Theta)*sind(Eta)+bb(1)-parameters.acq.rotx;    % left detector corner [pixels]
+q1d(i) = -m0*tand(2*Theta)*cosd(Eta)+parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+np(i)=bb(3);                % horizontal detector size [pixels]  
+nq(i)=bb(4);                % vertical detector size [pixels]
+ 
+
+p0(i) = -m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+q0(i) = -m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+      
+ipd = 0;               % ROI begin horizontal [pixels] 
+iqd = 0;               % ROI begin vertical [pixels]
+ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+iqf(i) = nq(i)-1;      % ROI end vertical
+
+
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+for i=1:nbradio
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,p_numbers(i));
+end
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi);
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
diff --git a/5_reconstruction/testARTp.m b/5_reconstruction/testARTp.m
new file mode 100755
index 0000000000000000000000000000000000000000..50277edbd88649c64c59e5926cd4c62e729bf529
--- /dev/null
+++ b/5_reconstruction/testARTp.m
@@ -0,0 +1,306 @@
+function vol=testARTp(scanname,parfilename,bbin,dif_numbers,shear_numbers,ext_numbers,grain,lambda,parameters,slice)
+% write .par file ready for rec_alg to use
+%
+%
+% function
+% make_art_parfile(scanname,parfilename,dif_numbers,shear_numbers,ext_numbe
+% rs, grain, lambda,parameters,slice)
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% dif_numbers: indices of diffraction spots to be taken into account, e.g. [1:14]
+% shear_numbers: indices of sheared diffraction spots to be taken into account 
+% ext_numbers:   : indices of extinction spots to be taken into account
+% grain:
+% lambda: 
+% parameters:
+% slice :     [zstart, zend]
+%              z               single slice
+%             empty            full volume
+
+
+%load parameters.mat
+
+gtMakeLinks(dif_numbers,shear_numbers,ext_numbers);
+
+blocksize=1%; length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+
+offset=0;
+
+fid=fopen(parfilename,'w');
+nbradio=length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+% Algorithm paramters
+nbiter = length(lambda);
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 0;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 10000000;      % Distance source to detector ~ 10^7 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd= 1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = fgd-parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (positive here: -m0 will be given to AREMIS 
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+nx=parameters.acq.bb(3);
+ny=parameters.acq.bb(3);
+
+x1=-parameters.acq.bb(3)/2;
+y1=-parameters.acq.bb(3)/2;
+
+if ~exist('slice','var')
+  nz=grain.zend-grain.zstart+1;
+  z1= parameters.acq.bb(4)/2-grain.zend;
+elseif length(slice)>1
+  z1= parameters.acq.bb(4)/2-slice(2)-0.5;
+  nz=slice(2)-slice(1)+1;
+else
+  z1= parameters.acq.bb(4)/2-slice(1)-1.5;
+  nz=3;
+end  
+
+%p_numbers=find(index);
+
+
+% write diffraction spots 
+
+for i=1:length(dif_numbers)
+
+  Omega =   grain.omega(dif_numbers(i));
+  Theta =   grain.theta(dif_numbers(i));
+  Eta   =   -grain.eta(dif_numbers(i));    % needs a negtive sign for real data (flipped)
+  psi(i)=   Omega;               % first Euler angle (==omega)  [degrees]
+  xsi(i)=   90.0;                % second Euler angle
+  delta =   0.0;                 % third Euler angle
+
+%   disp('modif line 112 !')
+%   query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.struct_ids(dif_numbers(i)));
+%   [bb(1),bb(2),bb(3),bb(4)]=mym(query);
+%   % now take into account the flip of the images...
+%   bb(1)=2*parameters.acq.rotx-bb(1)-bb(3)+1;
+%   bb=bb+[-100 -100 200 200];
+%   
+   %bb=parameters.bb(dif_numbers(i),1:4) +[-100 -100 200 200];
+   bb=bbin(i,1:4)+[-100 -100 200 200];
+   
+  p1d(i) =      m0*tand(2*Theta)*sind(Eta)-(bb(1)-parameters.acq.rotx);      % orig left  detector corner [pixels]
+  %p1d(i) =      m0*tand(2*Theta)*sind(Eta)+bb(1)+bb(3)-parameters.acq.rotx;
+  q1d(i) =      m0*tand(2*Theta)*cosd(Eta)-(bb(2)-parameters.acq.ydet/2);    % orig upper detector corner [pixels]     
+  %q1d(i) =     -m0*tand(2*Theta)*cosd(Eta)-parameters.acq.ydet/2+bb(2);
+  np(i)=bb(3);                % horizontal detector size [pixels]  
+  nq(i)=bb(4);                % vertical detector size [pixels]
+
+  p0(i) =    m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+  q0(i) =    m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+  iqf(i) = nq(i)-1;      % ROI end vertical
+
+end
+
+% now do the same for the sheared spots (inserted into direct beam BB)
+
+off=length(dif_numbers);
+
+for i=1:length(shear_numbers)
+  %disp('attention omega in direct beam has been modified !');
+  Omega =   -grain.omegashear(shear_numbers(i));  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off) = Omega;            % first Euler angle (==omega)  [degrees]
+  xsi(i+off) = 90.0+grain.phi(shear_numbers(i));      % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off) = np(i+off)-1;      % ROI end horizontal [pixels]
+  iqf(i+off) = nq(i+off)-1;      % ROI end vertical
+
+end
+
+% now write extinction spots...
+
+off2=length(dif_numbers)+length(shear_numbers);
+
+for i=1:length(ext_numbers)
+  disp('attention omega in direct beam has been modified !');
+  Omega =   -grain.omega(ext_numbers(i))  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off2) = Omega;           % first Euler angle (==omega)  [degrees]
+  xsi(i+off2) = 90.0;            % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off2) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off2) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off2)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off2)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off2) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off2) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off2) = np(i+off2)-1;      % ROI end horizontal [pixels]
+  iqf(i+off2) = nq(i+off2)-1;      % ROI end vertical
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+
+for i=1:length(dif_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,i);
+end
+for i=1:length(shear_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off-1,i+off);
+end
+for i=1:length(ext_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off2-1,i+off2);
+end  
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi(i));
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',-m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view'
+if 1
+  % now do the reconstructioon
+  command=sprintf('%s %s;%s %s_res0_%d',rec_alg,parfilename,seg2view,scanname,nbiter);
+  unix(command);
+  volname=sprintf('%s_res0_%d',scanname,nbiter);
+  vol=sdt_read(volname);
+  imshow(vol(:,:,round(nz/2)),[])
+  shg;
+else
+  vol=[];
+end  
diff --git a/5_reconstruction/threshold_grain.m b/5_reconstruction/threshold_grain.m
new file mode 100755
index 0000000000000000000000000000000000000000..f44eaa3900c1e737cd8a33399e9915e1a4568d34
--- /dev/null
+++ b/5_reconstruction/threshold_grain.m
@@ -0,0 +1,84 @@
+function im3 = threshold_grain(grainid);
+
+%argument is the grain ID (the number of the grain folder)
+%im is the greyscale, reconstructed grain, which can be read in from
+%the .sdt file
+
+%load data
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+im = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',grainid,grainid));
+   
+%find maximum in im, to use a seed point for region growth
+marker = zeros(size(im));
+maxval=max(im(:));
+[x,y]=find(im==maxval);
+marker(x,y)=1;
+
+
+%make SE for closing holes in 3D
+SE = ones(5,5,5);
+
+thresh_val=0.1;
+if grainid>80
+  thresh_val=0.2
+end
+
+test=0;
+
+while test==0
+
+mask=double(im>thresh_val*maxval);
+im2=imreconstruct(marker,mask,26);  
+
+% dilate / erode / fill holes routine
+im3=imdilate(im2,SE);
+im3=imerode(im3,SE);
+im3=imfill(im3,'holes');
+  
+
+%%show thresholded slices to user for interaction
+zarray = ceil(([0.3 0.5 0.7]*size(im,3))); %three z positions
+
+for i=1:3
+image(:,:,1) = im(:,:,zarray(i))';%collect three images top middle bottom
+subplot(3,3,i);
+imshow(image(:,:,1),[],'InitialMagnification',6);
+image(:,:,1) = im2(:,:,zarray(i))';%corresponding three thresholded
+subplot(3,3,i+3);
+imshow(image(:,:,1),[],'InitialMagnification',6);
+image(:,:,1) = im3(:,:,zarray(i))';%corresponding three thresholded+holes filled
+subplot(3,3,i+6);
+imshow(image(:,:,1),[],'InitialMagnification',6);
+end
+
+drawnow
+
+%%convert thresh_val to an absolute value
+%thresh_val_abs=thresh_val*maxval;
+
+if 1%interactive
+
+  message=sprintf('try new threshold value? (old value %f)',thresh_val);
+  thresh_val=input(message);
+  if isempty(thresh_val)
+    test=1;
+    %write a new volume
+    name=sprintf('4_grains/grain%d_/grain%d_.vol',grainid,grainid);
+    disp(sprintf('writing volume %s',name));
+    edf_write(im3,name,'uint8');
+  end
+
+else
+  test=1
+  %write a new volume
+  name=sprintf('4_grains/grain%d_/grain%d_.vol',grainid,grainid);
+  disp(sprintf('writing volume %s',name));
+  edf_write(im3,name,'uint8');
+
+end
+
+end%when parameters are good
diff --git a/5_reconstruction/threshold_grain_auto.m b/5_reconstruction/threshold_grain_auto.m
new file mode 100755
index 0000000000000000000000000000000000000000..9c33dc1db43433d2294886d10a7a07436d427865
--- /dev/null
+++ b/5_reconstruction/threshold_grain_auto.m
@@ -0,0 +1,177 @@
+function im5 = threshold_grain_auto(grainid);
+
+%argument is the grain ID (the number of the grain folder)
+%im is the greyscale, reconstructed grain, which can be read in from
+%the .sdt file
+%auto - remove interaction, make a bit more clever to compensate
+%sets threshold by statistics,
+%dilates and erodes to fill holes using an estimation of how hollow the
+%grain is.  erodes and dilate to remove spurs, but by a fixed SE=ones(6,6,6)
+
+
+%load data
+parameters=[];
+if isempty(parameters)
+  load parameters.mat
+end
+
+im = sdt_read(sprintf('4_grains/grain%d_/grain%d__res0_3',grainid,grainid));
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));%load the grain.mat
+      
+%find threshold automatically
+thresh_val = std(im(find(im~=0)));%std dev, ignoring zeros  
+im2=im>thresh_val;
+
+%label routine to remove disconnected bits
+im2=bwlabeln(im2,26);
+mode_val = mode(im2(find(im2>0)));
+im2 = (im2==mode_val);
+
+%how hollow is the grain? - estimate how much dilate/erode is needed
+%estimate tight bounding box of the grain
+total = sum(im2(:));%total white voxels
+%use 1,2,3 as follows.  convert to x,y,z after
+[size1,size2,size3]=size(im2);
+
+tmp = sum(im2,3);
+tmp1 = sum(tmp,2);%find range in 1
+thresh=0.1*mean(tmp1(find(tmp1~=0)));
+dummy = find(tmp1>thresh);
+min1=min(dummy);
+max1=max(dummy);
+dummy = find(tmp1>0);
+min1_0=min(dummy);
+max1_0=max(dummy);
+
+
+tmp1 = sum(tmp,1);%find range in 2
+thresh=0.1*mean(tmp1(find(tmp1~=0)));
+dummy = find(tmp1>thresh);
+min2=min(dummy);
+max2=max(dummy);
+dummy = find(tmp1>0);
+min2_0=min(dummy);
+max2_0=max(dummy);
+
+tmp = sum(im2,1);%find range in 3 (z)
+tmp = reshape(tmp,size(im2,2),size(im2,3));
+tmp1 = sum(tmp,1);
+thresh=0.1*mean(tmp1(find(tmp1~=0)));
+dummy = find(tmp1>thresh);
+min3=min(dummy);
+max3=max(dummy);
+dummy = find(tmp1>0);
+min3_0=min(dummy);
+max3_0=max(dummy);
+
+tight_vol = im2(min1:max1,min2:max2,min3:max3);
+loose_vol = im2(min1_0:max1_0,min2_0:max2_0,min3_0:max3_0);
+
+%estimate how solid this grain is.  Take "core samples" along each
+%direction
+[size1,size2,size3]=size(tight_vol);
+core1 = tight_vol(:,ceil(3*size2/8):ceil(5*size2/8),ceil(3*size3/8):ceil(5*size3/8));
+count = length(find(core1==1));
+total = count + length(find(core1==0));
+frac1 = count/total;
+
+core2 = tight_vol(ceil(3*size1/8):ceil(5*size1/8),:,ceil(3*size3/8):ceil(5*size3/8));
+count = length(find(core2==1));
+total = count + length(find(core2==0));
+frac2 = count/total;
+
+core3 = tight_vol(ceil(3*size1/8):ceil(5*size1/8),ceil(3*size2/8):ceil(5*size2/8),:);
+count = length(find(core3==1));
+total = count + length(find(core3==0));
+frac3 = count/total;
+
+frac = mean([frac1,frac2,frac3]);
+dilate_length = round((1-frac) * 0.5 * mean([size1,size2,size3]));
+disp('factor 0.5 in dilate length to reduce shape change!!')
+
+
+%pad loose vol with the dilate length so doesn't touch sides
+[fullsize1,fullsize2,fullsize3]=size(loose_vol);
+loose_vol_padded = zeros([size(loose_vol)]+2*(dilate_length+1));
+loose_vol_padded([1:fullsize1]+dilate_length+1, [1:fullsize2]+dilate_length+1, [1:fullsize3]+dilate_length+1)=loose_vol;
+original_size=size(loose_vol_padded)
+
+%adjustable decimation to go faster, based on size of loose_vol_padded:
+decimate = 2  
+if (fullsize1*fullsize2*fullsize3)>1000000
+  decimate = 3
+elseif (fullsize1*fullsize2*fullsize3)>6000000
+  decimate = 4
+end
+
+do_scale_and_fill = 1
+if do_scale_and_fill %do the dilate erode to fill holes
+%down sample - by factor "decimate", 
+loose_vol_sampled = loose_vol_padded(1:decimate:end,1:decimate:end,1:decimate:end);
+dilate_length_sampled = dilate_length/decimate
+sampled_size=size(loose_vol_sampled)
+
+%SE = strel('ball',round(dilate_length_sampled/2),round(dilate_length_sampled),0);
+centre=ceil(dilate_length_sampled/2)+1;
+[x,y,z]=meshgrid(1:(centre*2)-1,1:(centre*2)-1,1:(centre*2)-1);
+distance=sqrt((x-centre).^2+(y-centre).^2+(z-centre).^2);
+SE=distance<centre;
+
+tic
+% dilate / erode / fill holes routine
+im3sampled=imdilate(loose_vol_sampled,SE);
+im4sampled=imerode(im3sampled,SE);
+im4sampled=imfill(im4sampled,'holes');
+toc
+
+
+%erode / dilate to remove spurs
+erodeSE=ones(3,3,3);
+im4sampled=imerode(im4sampled,erodeSE);
+im4sampled=imdilate(im4sampled,erodeSE);
+
+%scale up by factor decimate
+[size1,size2,size3]=size(im4sampled);
+[grid1,grid2,grid3]=meshgrid(1:(1/decimate):size2,1:(1/decimate):size1,1:(1/decimate):size3);
+im4 = interpn(im4sampled,grid2,grid1,grid3);
+new_size=size(im4)
+im5 = im4 > 0.5;
+
+%label routine to remove disconnected bits
+im5=bwlabeln(im5,26);
+mode_val = mode(im5(find(im5>0)));
+im5 = (im5==mode_val);
+
+else%if not eroding, dilating
+  
+%erodeSE=ones(6,6,6);
+%im5=imerode(loose_vol_padded,erodeSE);
+%im5=imdilate(im5,erodeSE);
+im5=loose_vol_padded;
+end
+
+
+%get the correct origin to place in sample
+%initial origin, size:
+%when pasting old (.sdt) vol into volume, reverse x1,y1 and nx,ny
+x_origin = grain_data.x1;
+y_origin = grain_data.y1;
+z_origin = grain_data.zstart;
+vol_x_origin = x_origin + min2_0 - (dilate_length+1);
+vol_y_origin = y_origin + min1_0 - (dilate_length+1);
+vol_z_origin = z_origin + min3_0 - (dilate_length+1);
+[vol_y_size,vol_x_size,vol_z_size]=size(im5);
+
+
+
+if 1
+%write a new volume
+name=sprintf('4_grains/grain%d_/grain%d_2.edf',grainid,grainid);
+disp(sprintf('writing volume %s',name));
+edf_write(im5,name,'uint8');
+
+%add new info to .mat (how to paste .vol into sample volume)
+save(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid),'vol_x_origin','vol_y_origin','vol_z_origin',...
+  'vol_x_size','vol_x_size','vol_y_size','vol_z_size','-append');
+
+end
\ No newline at end of file
diff --git a/5_reconstruction/tmpART3D.m b/5_reconstruction/tmpART3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..8519cf83447a99cb0ea48f80924ba7852d959cc3
--- /dev/null
+++ b/5_reconstruction/tmpART3D.m
@@ -0,0 +1,243 @@
+function gtART3D(...
+  scanname,...
+  parfilename,...
+  p_numbers,...
+  psi_angles,...
+  xsi_angles,...
+  delta_angles,...
+  twotheta,...
+  eta,...
+  lambda,...
+  nbiter,...
+  pixsize,...
+  braggangle,...
+  np,nq,...
+  offset,...
+  z1,nz,...
+  x1,nx,...
+  y1,ny)
+% write .par file ready for rec_alg to use
+%
+%
+% function make_art_parfile(scanname,parfilename,p_numbers,psi_angles,xsi_angles,delta_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% 
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% p_numbers: vector containing the projections to be taken into account, e.g. [0:10:180]
+% p_angles : vector containing the correpsonding projection angles in degree e.g. [0:20:360]
+% lambda   : ART loop update parameter
+% nbiter   : number of ART iterations
+% pixsize  : pixelsize [mm]
+% braggangle: Bragg angle
+% np        : number of pixels in projections (hoizontal)
+% nq        : number of pixel in projections (vertical)
+% offset    : offset of the rotation axis with respect to the center of the image (in pixels) 
+% z1        : z start of reconstructed volume
+% nz        : number of reconstructed slices 
+% x1        : x start of reconstructed volume //andy 21/6/06
+% nx        : size of reconstructed volume in x
+% y1        : y start of reconstructed volume
+% ny        : size of reconstructed volume in y(attention: pixelsize in reconstructed image will be half
+% the pixel size in original projection images
+
+
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+fid=fopen(parfilename,'w');
+nbradio=length(p_numbers);
+
+% Algorithm paramters
+nbiter = nbiter;
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 1;
+block_size = length(p_numbers);  % for straight back projection, block_size should be = num projections
+% if block_size=N it will forward project after each N projections
+proj_mng = 'A';
+nb_resol = 1;
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+param1 = 0.1;  % paramX not used for ART (algo_type=1 or =2)
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+%geometry paramters
+fgd = 145000;         % Distance source detector [mm]  - put it far away, to approximate a parallel beam
+disp('*****************************')
+
+
+psi = psi_angles;     % first Euler angle (==omega)  [degrees]
+xsi = xsi_angles;     % second Euler angle
+delta = delta_angles; % third Euler angle
+np=2048;
+nq=2048;
+pepd= pixsize;        % horizontal Pixel size, [mm]
+peqd= pixsize;        % vertical Pixel size [mm]
+
+p1d=-1023.5;          % pixels
+q1d=-1023.5;          % pixels
+
+[alphap,alphaq]=gtGT2ARTangles(twotheta,eta);
+
+pdisp=tan(deg2rad(alphap))*fgd;
+qdisp=tan(deg2rad(alphaq))*fgd;
+%pdisp=repmat(0,size(qdisp));
+%qdisp=repmat(0,size(pdisp));
+
+pgd=-pdisp/pixsize;
+qgd=-qdisp/pixsize;
+
+% *** THE NUMBERS IN pdisp and qdisp don't seem to do anything!!!
+
+%%%%%%%%%%%%% m0,p0,q0 - coordinate of O in F
+m0=-(fgd);  % reconstruction object is centred over detector!
+%m0=-fgd;                   % mm
+p0=pdisp*pixsize;          % mm
+q0=qdisp*pixsize;          % mm
+
+
+ipd = 0;              % ROI begin horizontal [pixels] 
+iqd = 0;              % ROI begin vertical [pixels]
+ipf=2047;
+iqf=2047;
+keyboard
+%Reconstruction paramters
+
+% this is for object from -512:8:512
+  x1=-(512*pixsize),y1=x1;z1=x1;
+  pex=16*pixsize,pey=pex;pez=pex;
+  nx=64;ny=nx;nz=nx;
+
+% this is for object from -64:1:64
+%x1=-(1.5);y1=x1;z1=x1;  % mm
+%nx=151;ny=nx;nz=nx;   % num pixels
+%pex=0.02;pey=pex;pez=pex;   % size of pixel in mm
+
+
+% approximate sample size
+%x1=-(256*pixsize),y1=x1;z1=x1;
+%pex=4*pixsize,pey=pex;pez=pex;
+%nx=128;ny=nx;nz=nx;
+
+% uncomment this for: object from -1024:4:1024
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  decimation=4;
+%  pex=decimation*pixsize;pey=pex;pez=pex;
+%  nx=2048/decimation;ny=nx;nz=nx;
+
+
+%if 0  % full resolution - voxel size in object = detector pixel size  REC_ALG FAILS - CANNOT ALLOCATE SO MUCH MEMORY!!
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  pex=pixsize;pey=pex;pez=pex;
+%  nx=2048;ny=2048;nz=2048;
+%end
+
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+for i=1:nbradio
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,p_numbers(i));
+end
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd(mod(i-1,length(pgd))+1));
+fprintf(fid,'QGD = %f\n',qgd(mod(i-1,length(qgd))+1));	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(mod(i-1,length(p1d))+1));
+fprintf(fid,'Q1D = %f\n',q1d(mod(i-1,length(q1d))+1));
+fprintf(fid,'NP =  %d\n',np(mod(i-1,length(np))+1));
+fprintf(fid,'NQ =  %d\n',nq(mod(i-1,length(nq))+1));
+% this next line uses each value for the angles, if it exists.  Otherwise
+% it just repeats the single value over and over.  GJ
+fprintf(fid,'PSI = %f\n',psi(mod(i-1,length(psi))+1));
+fprintf(fid,'XSI = %f\n',xsi(mod(i-1,length(xsi))+1));
+fprintf(fid,'DELTA = %f\n',delta(mod(i-1,length(delta))+1));
+fprintf(fid,'PO = %f\n',p0(mod(i-1,length(p0))+1));	
+fprintf(fid,'QO = %f\n',q0(mod(i-1,length(q0))+1));
+fprintf(fid,'MO = %f\n',m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf);
+fprintf(fid,'IQF = %d\n',iqf);
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
diff --git a/5_reconstruction/tmpDoART3D.m b/5_reconstruction/tmpDoART3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..eb9dc5ad2b660cbd06fb45298c74f4e7a6f186aa
--- /dev/null
+++ b/5_reconstruction/tmpDoART3D.m
@@ -0,0 +1,128 @@
+%function gtDoART3D(grainid)
+grainid=3;
+%simply launch the reconstruction of a grain for a standard set of
+%parameters
+%use the index of good reflections if it exists
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+%read in data
+grain_data = load(sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid));
+%struct_ids = grain_data.struct_ids;
+
+%if it doesn't already exist, add an index of projections to use
+if isfield(grain_data,'index')
+  index = grain_data.index;
+else
+  index = ones(1,length(grain_data.struct_ids));
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'index', '-append')
+end
+
+scanname = sprintf('grain%d_',grainid);
+parfilename = sprintf('grain%d_.par',grainid);
+whole_parfilename = sprintf('grain%d_whole.par',grainid);
+
+if 0 %isfield(grain_data,'lambda')
+  art_params = grain_data.lambda;%if assigned manually
+else
+  art_params = [0.6 0.2 0.1]; %default values
+  art_params = 1;  % just do back projection, no ART effects
+  lambda=art_params;
+  save (sprintf('4_grains/grain%d_/grain%d_.mat',grainid,grainid), 'lambda', '-append')
+end
+
+
+%cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+
+nbiter = length(art_params);
+pixsize = 1; %0.0014;
+braggangle = 0;
+disp('Changed')
+np = parameters.acq.bb(3);
+nq = parameters.acq.bb(4);
+offset = 0;
+
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+psi_angles = -grain_data.Omega(find(index));
+twotheta=2*grain_data.Theta(find(index));
+eta=grain_data.Eta(find(index));
+
+psi_angles=repmat(0,size(twotheta));
+%twotheta=[30 -30 30 30];
+%eta=[0 0 -90 90];
+if 1
+  p_numbers = find(index);
+%  p_numbers(4:end)=[];
+%  disp('REMOVE A FUNNY ONE ***')
+%  p_numbers(4)=[];
+else
+  p_numbers=repmat(99,size(psi_angles));  % 1 - test with real spot 99 - test with syntheic centred projection
+  p_numbers=[ 99 99 99 99];
+end
+
+
+
+cd(parameters.acq.dir);
+if 0
+  mym('open','mysql','gtadmin','gtadmin')
+  mym('use graintracking')
+  composite=zeros(2048);
+  for n=p_numbers
+    sid=grain_data.struct_ids(n);
+    dspot_im=gtnewGetSummedDifSpot(sid);
+    dspot_im= 100*dspot_im/sum(dspot_im(:));
+    [bb(1) bb(2) bb(3) bb(4)]=mym(sprintf(...
+      'select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from s5_dct5_difspot where difspotID=%d',sid));
+
+    fname=sprintf('tmp2/%s%d',scanname,n)
+    im=gtPlaceSubImage(dspot_im,zeros(2048,2048),bb(1),bb(2));
+    disp('DEBUG')
+    sdt_write(fname,im,'float32');
+    composite=composite+im;
+    imagesc(composite)
+    title(n)
+    drawnow
+  end
+  return
+end
+%cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+cd tmp
+
+xsi_angles= [90];
+delta_angles=[0];
+
+% if we know the spot height above the detector centre (centroidY of spot)
+% and we know the two theta it should use
+% then we should move teh source (fgd) to the correct distance so t
+
+%write .par file for the whole grain, add to batch file
+gtART3D(...
+  scanname,...
+  whole_parfilename,...
+  p_numbers,psi_angles,xsi_angles,delta_angles,twotheta,eta,...
+  art_params,nbiter,pixsize,braggangle,...
+  np,nq,offset, ...
+  parameters.acq.bb(2)-1024,parameters.acq.bb(4),...
+  parameters.acq.bb(1)-1024,parameters.acq.bb(3),...
+  parameters.acq.bb(1)-1024,parameters.acq.bb(3));
+
+
+disp('Not starting condor job!')
+if 0
+  gtMakeCondorJob(grainid);
+else
+  %  cd(sprintf('%s/4_grains/grain%d_',parameters.acq.dir, grainid));
+  % clear all previous work
+  %  system('rm *spr *sdt');
+  system(sprintf('%s %s',rec_alg,whole_parfilename));
+  for n=1:nbiter
+    system(sprintf('%s %s_res0_%d\n\n',seg2view,scanname,n));
+  end
+  cd(parameters.acq.dir);
+end
+
diff --git a/5_reconstruction/try.m b/5_reconstruction/try.m
new file mode 100755
index 0000000000000000000000000000000000000000..c4ad00d2c535e344265a985684184d559bb8bbe7
--- /dev/null
+++ b/5_reconstruction/try.m
@@ -0,0 +1,232 @@
+function testART(scanname,parfilename,p_numbers,grain,lambda,nbiter,blocksize,braggangle,offset,parameters,slice)
+% write .par file ready for rec_alg to use
+%
+%
+% function make_art_parfile(scanname,parfilename,p_numbers,p_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% 
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% p_numbers: vector containing the projections to be taken into account, e.g. [0:10:180]
+% p_angles : vector containing the correpsonding projection angles in degree e.g. [0:20:360]
+% lambda   : ART loop update parameter
+% nbiter   : number of ART iterations
+% blocksize: ART is updated after blocksize projections
+% pixsize  : pixelsize [mm]
+% braggangle: Bragg angle
+% np        : number of pixels in projections (hoizontal)
+% nq        : number of pixel in projections (vertical)
+% offset    : offset of the rotation axis with respect to the center of the image (in pixels) 
+% z1        : z start of reconstructed volume
+% nz        : number of reconstructed slices 
+% x1        : x start of reconstructed volume //andy 21/6/06
+% nx        : size of reconstructed volume in x
+% y1        : y start of reconstructed volume
+% ny        : size of reconstructed volume in y(attention: pixelsize in reconstructed image will be half
+% the pixel size in original projection images
+
+
+%gtnew - change to use parameters.acq
+%gtnew - change to use z coordinates of grain relative to top of sample
+
+
+%load parameters.mat
+
+
+
+
+fid=fopen(parfilename,'w');
+nbradio=length(p_numbers);
+
+% Algorithm paramters
+nbiter = nbiter;
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 100000000;      % Distance source to detector ~ 10^8 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd=  1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = -fgd+parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (<0)
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+nx=parameters.acq.bb(3);
+ny=parameters.acq.bb(3);
+
+x1=-parameters.acq.bb(3)/2;
+y1=-parameters.acq.bb(3)/2;
+
+if ~exist('slice','var')
+  nz=grain.zend-grain.zstart+1;
+  z1= parameters.acq.bb(4)/2-grain.zend;
+else
+  z1= parameters.acq.bb(4)/2-slice-2;
+  nz=5;
+end  
+
+%p_numbers=find(index);
+nbradio=length(p_numbers);
+
+for i=1:nbradio
+
+Omega =   grain.Omega(p_numbers(i));
+Theta =   grain.Theta(p_numbers(i));
+Eta   =  -grain.Eta(p_numbers(i));
+  
+psi(i) = Omega;               % first Euler angle (==omega)  [degrees]
+xsi =    90.0-braggangle;     % second Euler angle
+delta = 0.0;                  % third Euler angle
+
+if Theta>0
+  query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.struct_ids(p_numbers(i)));
+  [bb(1),bb(2),bb(3),bb(4)]=mym(query);
+ 
+  bb=bb+[-100 -100 200 200];
+  
+  %bb=parameters.bb(i,:);
+else
+  bb=parameters.acq.bb;
+end  
+
+
+
+
+p1d(i) = -m0*tand(2*Theta)*sind(Eta)+bb(1)-parameters.acq.rotx;    % left detector corner [pixels]
+q1d(i) = -m0*tand(2*Theta)*cosd(Eta)+parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+np(i)=bb(3);                % horizontal detector size [pixels]  
+nq(i)=bb(4);                % vertical detector size [pixels]
+ 
+
+p0(i) = -m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+q0(i) = -m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+      
+ipd = 0;               % ROI begin horizontal [pixels] 
+iqd = 0;               % ROI begin vertical [pixels]
+ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+iqf(i) = nq(i)-1;      % ROI end vertical
+
+
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+for i=1:nbradio
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,p_numbers(i));
+end
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi);
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
diff --git a/5_reconstruction/tryART.m b/5_reconstruction/tryART.m
new file mode 100755
index 0000000000000000000000000000000000000000..cb0354bd7405246d8319ff4613b6d13e0b5997fc
--- /dev/null
+++ b/5_reconstruction/tryART.m
@@ -0,0 +1,304 @@
+function vol=testART(scanname,parfilename,dif_numbers,shear_numbers,ext_numbers,grain,lambda,parameters,slice)
+% write .par file ready for rec_alg to use
+%
+%
+% function
+% make_art_parfile(scanname,parfilename,dif_numbers,shear_numbers,ext_numbe
+% rs, grain, lambda,parameters,slice)
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% dif_numbers: indices of diffraction spots to be taken into account, e.g. [1:14]
+% shear_numbers: indices of sheared diffraction spots to be taken into account 
+% ext_numbers:   : indices of extinction spots to be taken into account
+% grain:
+% lambda: 
+% parameters:
+% slice :     [zstart, zend]
+%              z               single slice
+%             empty            full volume
+
+
+%load parameters.mat
+
+gtMakeLinksflip(dif_numbers,shear_numbers,ext_numbers);
+
+blocksize= length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+
+offset=0;
+
+fid=fopen(parfilename,'w');
+nbradio=length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+% Algorithm paramters
+nbiter = length(lambda);
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 10000000;      % Distance source to detector ~ 10^7 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd=  1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = fgd-parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (positive here: -m0 will be given to AREMIS 
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+nx=parameters.acq.bb(3);
+ny=parameters.acq.bb(3);
+
+x1=-parameters.acq.bb(3)/2;
+y1=-parameters.acq.bb(3)/2;
+
+if ~exist('slice','var')
+  nz=grain.zend-grain.zstart+1;
+  z1= parameters.acq.bb(4)/2-grain.zend;
+elseif length(slice)>1
+  z1= parameters.acq.bb(4)/2-slice(2)-0.5;
+  nz=slice(2)-slice(1)+1;
+else
+  z1= parameters.acq.bb(4)/2-slice(1)-1.5;
+  nz=3;
+end  
+
+%p_numbers=find(index);
+
+
+% write diffraction spots 
+
+for i=1:length(dif_numbers)
+
+  Omega =   grain.omega(dif_numbers(i));
+  Theta =   grain.theta(dif_numbers(i));
+  Eta   =   grain.eta(dif_numbers(i));    % needs a negtive sign for real data (flipped)
+  psi(i)=   Omega;               % first Euler angle (==omega)  [degrees]
+  xsi(i)=   90.0;                % second Euler angle
+  delta =   0.0;                 % third Euler angle
+
+
+  %query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.struct_ids(dif_numbers(i)));
+  %[bb(1),bb(2),bb(3),bb(4)]=mym(query);
+  % now take into account the flip of the images...
+  %bb(1)=2*parameters.acq.rotx-bb(1)-bb(3)+1;
+  %bb=bb+[-100 -100 200 200];
+  
+  bb=parameters.bb(dif_numbers(i),1:4) +[-100 -100 200 200];
+  
+  p1d(i) =     m0*tand(2*Theta)*sind(Eta)+bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i) =     m0*tand(2*Theta)*cosd(Eta)+parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  %q1d(i) =     m0*tand(2*Theta)*cosd(Eta)-parameters.acq.ydet/2+bb(2);
+  np(i)=bb(3);                % horizontal detector size [pixels]  
+  nq(i)=bb(4);                % vertical detector size [pixels]
+
+  p0(i) =    m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+  q0(i) =    m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+  iqf(i) = nq(i)-1;      % ROI end vertical
+
+end
+
+% now do the same for the sheared spots (inserted into direct beam BB)
+
+off=length(dif_numbers);
+
+for i=1:length(shear_numbers)
+  %disp('attention omega in direct beam has been modified !');
+  Omega =   grain.omegashear(shear_numbers(i));  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off) = Omega;            % first Euler angle (==omega)  [degrees]
+  xsi(i+off) = 90.0+grain.phi(shear_numbers(i));      % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off) = np(i+off)-1;      % ROI end horizontal [pixels]
+  iqf(i+off) = nq(i+off)-1;      % ROI end vertical
+
+end
+
+% now write extinction spots...
+
+off2=length(dif_numbers)+length(shear_numbers);
+
+for i=1:length(ext_numbers)
+  disp('attention omega in direct beam has been modified !');
+  Omega =   grain.omega(ext_numbers(i))  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off2) = Omega;           % first Euler angle (==omega)  [degrees]
+  xsi(i+off2) = 90.0;            % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off2) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off2) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off2)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off2)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off2) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off2) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off2) = np(i+off2)-1;      % ROI end horizontal [pixels]
+  iqf(i+off2) = nq(i+off2)-1;      % ROI end vertical
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+
+for i=1:length(dif_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,i);
+end
+for i=1:length(shear_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off-1,i+off);
+end
+for i=1:length(ext_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off2-1,i+off2);
+end  
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi(i));
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',-m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view'
+if 1
+  % now do the reconstructioon
+  command=sprintf('%s %s;%s %s_res0_%d',rec_alg,parfilename,seg2view,scanname,nbiter);
+  unix(command);
+  volname=sprintf('%s_res0_%d',scanname,nbiter);
+  vol=sdt_read(volname);
+  imshow(vol(:,:,round(nz/2)),[])
+  shg;
+else
+  vol=[];
+end  
diff --git a/5_reconstruction/tryART2.m b/5_reconstruction/tryART2.m
new file mode 100755
index 0000000000000000000000000000000000000000..5b600f000fea45541f50ffe64a16ed4c02efe337
--- /dev/null
+++ b/5_reconstruction/tryART2.m
@@ -0,0 +1,303 @@
+function vol=testART(scanname,parfilename,dif_numbers,shear_numbers,ext_numbers,grain,lambda,parameters,slice)
+% write .par file ready for rec_alg to use
+%
+%
+% function
+% make_art_parfile(scanname,parfilename,dif_numbers,shear_numbers,ext_numbe
+% rs, grain, lambda,parameters,slice)
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% dif_numbers: indices of diffraction spots to be taken into account, e.g. [1:14]
+% shear_numbers: indices of sheared diffraction spots to be taken into account 
+% ext_numbers:   : indices of extinction spots to be taken into account
+% grain:
+% lambda: 
+% parameters:
+% slice :     [zstart, zend]
+%              z               single slice
+%             empty            full volume
+
+
+%load parameters.mat
+
+gtMakeLinks(dif_numbers,shear_numbers,ext_numbers);
+
+blocksize=1 % length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+
+offset=0;
+
+fid=fopen(parfilename,'w');
+nbradio=length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+% Algorithm paramters
+nbiter = length(lambda);
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 100000000;      % Distance source to detector ~ 10^8 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd=  1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = fgd-parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (positive here: -m0 will be given to AREMIS 
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+nx=parameters.acq.bb(3);
+ny=parameters.acq.bb(3);
+
+x1=-parameters.acq.bb(3)/2;
+y1=-parameters.acq.bb(3)/2;
+
+if ~exist('slice','var')
+  nz=grain.zend-grain.zstart+1;
+  z1= parameters.acq.bb(4)/2-grain.zend;
+elseif length(slice)>1
+  z1= parameters.acq.bb(4)/2-slice(2)-0.5;
+  nz=slice(2)-slice(1)+1;
+else
+  z1= parameters.acq.bb(4)/2-slice(1)-1.5;
+  nz=3;
+end  
+
+%p_numbers=find(index);
+
+
+% write diffraction spots 
+
+for i=1:length(dif_numbers)
+
+  Omega =   grain.omega(dif_numbers(i));
+  Theta =   grain.theta(dif_numbers(i));
+  Eta   =   grain.eta(dif_numbers(i));    % needs a negtive sign for real data (flipped)
+  psi(i)=   Omega;               % first Euler angle (==omega)  [degrees]
+  xsi(i)=   90.0;                % second Euler angle
+  delta =   0.0;                 % third Euler angle
+
+
+  %query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.struct_ids(dif_numbers(i)));
+  %[bb(1),bb(2),bb(3),bb(4)]=mym(query);
+  % now take into account the flip of the images...
+  %bb(1)=2*parameters.acq.rotx-bb(1)-bb(3)+1;
+  %bb=bb+[-100 -100 200 200];
+  
+  bb=parameters.bb(dif_numbers(i),1:4) +[-100 -100 200 200];
+  
+  p1d(i) =     m0*tand(2*Theta)*sind(Eta)+bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i) =     m0*tand(2*Theta)*cosd(Eta)+parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i)=bb(3);                % horizontal detector size [pixels]  
+  nq(i)=bb(4);                % vertical detector size [pixels]
+
+  p0(i) =    m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+  q0(i) =    m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+  iqf(i) = nq(i)-1;      % ROI end vertical
+
+end
+
+% now do the same for the sheared spots (inserted into direct beam BB)
+
+off=length(dif_numbers);
+
+for i=1:length(shear_numbers)
+  %disp('attention omega in direct beam has been modified !');
+  Omega =   -grain.omegashear(shear_numbers(i));  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off) = Omega;            % first Euler angle (==omega)  [degrees]
+  xsi(i+off) = 90.0-grain.phi(shear_numbers(i));      % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off) = np(i+off)-1;      % ROI end horizontal [pixels]
+  iqf(i+off) = nq(i+off)-1;      % ROI end vertical
+
+end
+
+% now write extinction spots...
+
+off2=length(dif_numbers)+length(shear_numbers);
+
+for i=1:length(ext_numbers)
+  disp('attention omega in direct beam has been modified !');
+  Omega =   -grain.omega(ext_numbers(i))  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off2) = Omega;           % first Euler angle (==omega)  [degrees]
+  xsi(i+off2) = 90.0;            % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off2) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off2) =     parameters.acq.ydet/2-bb(2);    % upper detector corner [pixels]     
+  np(i+off2)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off2)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off2) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off2) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off2) = np(i+off2)-1;      % ROI end horizontal [pixels]
+  iqf(i+off2) = nq(i+off2)-1;      % ROI end vertical
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+
+for i=1:length(dif_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,i);
+end
+for i=1:length(shear_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off-1,i+off);
+end
+for i=1:length(ext_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off2-1,i+off2);
+end  
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi(i));
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',-m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view'
+if 1
+  % now do the reconstructioon
+  command=sprintf('%s %s;%s %s_res0_%d',rec_alg,parfilename,seg2view,scanname,nbiter);
+  unix(command);
+  volname=sprintf('%s_res0_%d',scanname,nbiter);
+  vol=sdt_read(volname);
+  imshow(vol(:,:,round(nz/2)),[])
+  shg;
+else
+  vol=[];
+end  
diff --git a/5_reconstruction/tryARTflip.m b/5_reconstruction/tryARTflip.m
new file mode 100755
index 0000000000000000000000000000000000000000..7415d33d20cc3b0edfb994153c48b1ee840f2684
--- /dev/null
+++ b/5_reconstruction/tryARTflip.m
@@ -0,0 +1,305 @@
+function vol=testART(scanname,parfilename,dif_numbers,shear_numbers,ext_numbers,grain,lambda,parameters,slice)
+% write .par file ready for rec_alg to use
+%
+%
+% function
+% make_art_parfile(scanname,parfilename,dif_numbers,shear_numbers,ext_numbe
+% rs, grain, lambda,parameters,slice)
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% dif_numbers: indices of diffraction spots to be taken into account, e.g. [1:14]
+% shear_numbers: indices of sheared diffraction spots to be taken into account 
+% ext_numbers:   : indices of extinction spots to be taken into account
+% grain:
+% lambda: 
+% parameters:
+% slice :     [zstart, zend]
+%              z               single slice
+%             empty            full volume
+
+
+%load parameters.mat
+
+gtMakeLinksflip(dif_numbers,shear_numbers,ext_numbers);
+
+blocksize= length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+
+offset=0;
+
+fid=fopen(parfilename,'w');
+nbradio=length(dif_numbers)+length(shear_numbers)+length(ext_numbers);
+
+% Algorithm paramters
+nbiter = length(lambda);
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 2;    %ART
+block_size = blocksize;
+proj_mng = 'A';   
+nb_resol = 1;
+
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+
+% not used
+param1 = 0.1;
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+% fixed Geometry parameters
+% we set pixelsize = 1mm
+% geometry paramters: set [PGd QGd] = 0 0 for all images
+fgd = 10000000;      % Distance source to detector ~ 10^7 times pixelsize
+pgd = 0;              % horizontal Distance (source projection)-(detector center) [pixels]
+qgd = 0;              % vertical Distance (source projection)-(detector center) [pixels]
+pepd=  1;        % horizontal Pixel size, [mm]
+peqd= -1;        % vertical Pixel size [mm]:  has to be negative for scanning direction from top to bottom
+m0    = fgd-parameters.acq.dist/parameters.acq.pixelsize;             % distance source - rotation axis [mm] (positive here: -m0 will be given to AREMIS 
+
+%Reconstruction paramters
+pex = 1;            % sampling step size [mm]
+pey = 1;            % sampling step size [mm]
+pez = 1;            % sampling step size [mm] 
+
+nx=parameters.acq.bb(3);
+ny=parameters.acq.bb(3);
+
+x1=-parameters.acq.bb(3)/2+0.5;
+y1=-parameters.acq.bb(3)/2+0.5;
+
+if ~exist('slice','var')
+  nz=grain.zend-grain.zstart+1;
+  z1= parameters.acq.bb(4)/2-grain.zend+0.5;
+elseif length(slice)>1
+  z1= parameters.acq.bb(4)/2-slice(2)+0.5;
+  nz=slice(2)-slice(1)+1;
+else
+  z1= parameters.acq.bb(4)/2+0.5-slice(1)-1;
+  nz=3;
+end  
+
+%p_numbers=find(index);
+
+
+% write diffraction spots 
+
+for i=1:length(dif_numbers)
+
+  Omega =   grain.omega(dif_numbers(i));
+  Theta =   grain.theta(dif_numbers(i));
+  Eta   =   grain.eta(dif_numbers(i));    % needs a negtive sign for real data (flipped)
+  psi(i)=   Omega;               % first Euler angle (==omega)  [degrees]
+  xsi(i)=   90.0;                % second Euler angle
+  delta =   0.0;                 % third Euler angle
+
+
+  %query=sprintf('select BoundingBoxXorigin,BoundingBoxYorigin,BoundingBoxXsize,BoundingBoxYsize from %sdifspot where DifspotID=%d',parameters.acq.name,grain.struct_ids(dif_numbers(i)));
+  %[bb(1),bb(2),bb(3),bb(4)]=mym(query);
+  % now take into account the flip of the images...
+  %bb(1)=2*parameters.acq.rotx-bb(1)-bb(3)+1;
+  %bb=bb+[-100 -100 200 200];
+  
+  bb=parameters.bb(dif_numbers(i),1:4) +[-100 -100 200 200];
+  bb(1)=2*parameters.acq.rotx-bb(1)-bb(3)+1;
+  
+  p1d(i) =     m0*tand(2*Theta)*sind(Eta)+bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i) =     m0*tand(2*Theta)*cosd(Eta)+parameters.acq.ydet/2-bb(2)+0.5;    % upper detector corner [pixels]     
+  
+  np(i)=bb(3);                % horizontal detector size [pixels]  
+  nq(i)=bb(4);                % vertical detector size [pixels]
+
+  p0(i) =    m0*tand(2*Theta)*sind(Eta);             % horizontal  distance source - object center [mm]
+  q0(i) =    m0*tand(2*Theta)*cosd(Eta);             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i) = np(i)-1;      % ROI end horizontal [pixels]
+  iqf(i) = nq(i)-1;      % ROI end vertical
+
+end
+
+% now do the same for the sheared spots (inserted into direct beam BB)
+
+off=length(dif_numbers);
+
+for i=1:length(shear_numbers)
+  %disp('attention omega in direct beam has been modified !');
+  Omega =   grain.omegashear(shear_numbers(i));  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off) = Omega;            % first Euler angle (==omega)  [degrees]
+  xsi(i+off) = 90.0+grain.phi(shear_numbers(i));      % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off) =     parameters.acq.ydet/2-bb(2)+0.5;    % upper detector corner [pixels]     
+  np(i+off)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off) = np(i+off)-1;      % ROI end horizontal [pixels]
+  iqf(i+off) = nq(i+off)-1;      % ROI end vertical
+
+end
+
+% now write extinction spots...
+
+off2=length(dif_numbers)+length(shear_numbers);
+
+for i=1:length(ext_numbers)
+  disp('attention omega in direct beam has been modified !');
+  Omega =   grain.omega(ext_numbers(i))  %-180;   % we use the summed extspots
+  Theta =   0;
+  Eta   =   0;    
+
+  psi(i+off2) = Omega;           % first Euler angle (==omega)  [degrees]
+  xsi(i+off2) = 90.0;            % second Euler angle
+  delta =  0.0;                  % third Euler angle
+
+  bb=parameters.acq.bb;
+
+  p1d(i+off2) =     bb(1)-parameters.acq.rotx;      % left  detector corner [pixels]
+  q1d(i+off2) =     parameters.acq.ydet/2-bb(2)+0.5;    % upper detector corner [pixels]     
+  np(i+off2)=bb(3);                % horizontal detector size [pixels]  
+  nq(i+off2)=bb(4);                % vertical detector size [pixels]
+
+  p0(i+off2) =    0;             % horizontal  distance source - object center [mm]
+  q0(i+off2) =    0;             % vertical distance source - object center [mm]
+
+  ipd = 0;               % ROI begin horizontal [pixels] 
+  iqd = 0;               % ROI begin vertical [pixels]
+  ipf(i+off2) = np(i+off2)-1;      % ROI end horizontal [pixels]
+  iqf(i+off2) = nq(i+off2)-1;      % ROI end vertical
+
+end
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+
+for i=1:length(dif_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,i);
+end
+for i=1:length(shear_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off-1,i+off);
+end
+for i=1:length(ext_numbers)
+  fprintf(fid,'EXT_PROJ%d = %d\n',i+off2-1,i+off2);
+end  
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd);
+fprintf(fid,'QGD = %f\n',qgd);	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(i));
+fprintf(fid,'Q1D = %f\n',q1d(i));
+fprintf(fid,'NP =  %d\n',np(i));
+fprintf(fid,'NQ =  %d\n',nq(i));
+fprintf(fid,'PSI = %f\n',psi(i));
+fprintf(fid,'XSI = %f\n',xsi(i));
+fprintf(fid,'DELTA = %f\n',delta);
+fprintf(fid,'PO = %f\n',p0(i));	
+fprintf(fid,'QO = %f\n',q0(i));
+fprintf(fid,'MO = %f\n',-m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf(i));
+fprintf(fid,'IQF = %d\n',iqf(i));
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view'
+if 1
+  % now do the reconstructioon
+  command=sprintf('%s %s;%s %s_res0_%d',rec_alg,parfilename,seg2view,scanname,nbiter);
+  unix(command);
+  volname=sprintf('%s_res0_%d',scanname,nbiter);
+  vol=sdt_read(volname);
+  imshow(vol(:,:,round(nz/2)),[])
+  shg;
+else
+  vol=[];
+end  
diff --git a/6_rendering/gtAnalyseBoundaryIndexPlaneMesh.m b/6_rendering/gtAnalyseBoundaryIndexPlaneMesh.m
new file mode 100755
index 0000000000000000000000000000000000000000..beab230e0a587aaa16271eadb75d181e410649ae
--- /dev/null
+++ b/6_rendering/gtAnalyseBoundaryIndexPlaneMesh.m
@@ -0,0 +1,184 @@
+
+function grain_surface=gtAnalyseBoundaryIndexPlaneMesh(grains, bounds, bounds_dil, r_vectors, boundaries_structure, grainID, bounds_list2)
+
+
+%this seems to work reasonably quickly
+% procedure:
+% smooth grain volume, considering relevent voxels only (faster than smooth3)
+% isosurface
+% assign points on isosurface to particular boundaries
+% return grain_surface: this contains the face-vertex structure, together
+% with another variable assigning vertices to specific grain boundaries
+% this can then be simplified using reduce patch for further analysis
+
+
+% this has been split into gtGrainBoundarySurfaceMesh and gtAnalyseGrainBoundarySurface
+% and as such is redundant...
+
+tmp=grains==grainID;
+R=r_vectors(grainID,2:4);
+g=Rod2g(R);
+sym = gtGetCubicSymOp;
+cmap=gtRandCmap(bounds);
+
+%which boundaries are relevent?
+bounds_list=[];
+for i=1:length(boundaries_structure)
+    if boundaries_structure(i).grain1==grainID | boundaries_structure(i).grain2==grainID
+        bounds_list=[bounds_list i];
+    end
+end
+
+
+%find relevent voxels
+j=9
+tic
+todo=find(imdilate(tmp, ones(j,j,j))-imerode(tmp, ones(j,j,j)));
+toc
+tmp2=zeros(size(tmp));
+
+%do smoothing
+i=4;
+tic 
+for k=1:length(todo)
+    
+    [y,x,z]=ind2sub(size(tmp), todo(k));
+
+    x1=max(x-i,1);
+    y1=max(y-i,1);
+    z1=max(z-i,1);
+    x2=min(x+i,size(tmp,2));
+    y2=min(y+i,size(tmp,1));
+    z2=min(z+i,size(tmp,3));
+    
+neighbourhood=tmp(y1:y2, x1:x2, z1:z2);
+tmp2(y,x,z)=mean(neighbourhood(:));
+
+if mod(k, round(length(todo)/10))==0
+    k/length(todo)
+end
+
+end
+toc
+
+%complete smoothed grain interior
+tmp2(find(tmp2==0 & tmp))=1;
+
+%isosurface
+fv_orig=isosurface(tmp2, 0.5);
+%initial triangle area is about 1
+approx_triangle_area=(length(todo)/j)/length(fv_orig.vertices)
+%reduce mesh to give triangle area ~10
+fv=reducepatch(fv_orig,0.1);
+
+%get those vertices that relate to a certain boundary?
+% use a dilated boundary map [ gt_dilate_grains(bounds, 10) ] - looks very
+% odd!
+
+%pass this in for the mo
+%bounds_dil=edf_read('/data/id19/graintracking/data/ss2007/ss2007_A_/5_reconstruction/ss2007_A_bounds_dil10.edf');
+
+
+%loop through vertices, assigning each to a boundary of the original grain
+%may not pick up some very small boundaries, but I guess this doesn't
+%matter- for grain 1 these are of size 1-39 voxels volume ie max diameter 4
+%voxels
+faces_bounds=zeros(size(fv.faces));
+for i=1:length(fv.vertices)
+    a=round(fv.vertices(i,:));
+    boundaryID=bounds_dil(a(2), a(1), a(3));
+    faces_bounds(find(fv.faces==i))=boundaryID;
+end
+
+if 0 % to render - causes matlab to struggle with memory
+figure
+fv2=fv;
+for i=1:length(bounds_list)
+    fv2.faces=fv.faces(all(faces_bounds==bounds_list(i), 2),:);
+    p=patch(fv2);
+    set(p, 'facecolor', cmap(bounds_list(i),:))
+end
+end
+    
+%read this data
+
+%record all normals and all triangle area for weighting
+normals=zeros(length(fv.faces), 3);
+areas=zeros(length(fv.faces), 1);
+
+
+if ~isempty(bounds_list2)
+    bounds_list=bounds_list2;
+end
+
+
+
+for k=1:length(bounds_list)
+    k
+    poles=[];
+    poles_areas=[];
+
+    dum=find(all(faces_bounds==bounds_list(k), 2));
+    if ~isempty(dum)
+        
+        for j=1:length(dum)
+            i=dum(j);
+            face=fv.faces(i,:);
+            %get the three vertices -
+            v1=fv.vertices(face(1), [2 1 3]);
+            v2=fv.vertices(face(2),  [2 1 3]);
+            v3=fv.vertices(face(3),  [2 1 3]);
+            %normal:
+            n=cross(v1-v2, v3-v2);
+            %fix this to follow lsplane output - change sign of third component
+            n(3)=-n(3);
+            normals(i,:)=n/norm(n);%may not need to save this info
+
+            %area
+            angle=acos(dot((v1-v2)/norm(v1-v2), (v3-v2)/norm(v3-v2)));
+            areas(i)=norm(v1-v2)*norm(v3-v2)*sin(angle)*0.5;
+
+            %convert to crystallographic plane/pole
+            poles(end+1,:)=inv(g)*normals(i,:)';
+            poles_areas(end+1)=areas(i);
+
+        end
+
+
+        poles2=[];
+        for i=1:length(sym)
+            poles2=[poles2; poles*sym(i).g];
+        end
+        %add this to correspond to line in gtMakePoleFigure
+        poles2=[poles2; -poles2];
+        poles=poles2;
+   
+        % this unique doesn't seems to work properly, and not sure if it
+        % should even be here!
+        %  [poles, ndx]=unique(poles2, 'rows');
+        
+        
+        poles_areas=repmat(poles_areas', 48, 1);
+     %   poles_areas=poles_areas(ndx);
+
+        gtmakePoleFigure(poles, poles_areas)
+        title(sprintf('boundary %d', bounds_list(k)))
+
+        gtmakePoleFigure(poles)
+        title(sprintf('boundary %d (not weighted by mesh areas', bounds_list(k)))
+
+        keyboard
+        
+        
+
+    end
+end
+
+
+
+
+
+
+
+
+
diff --git a/6_rendering/gtAnalyseCrackPlane.m b/6_rendering/gtAnalyseCrackPlane.m
new file mode 100755
index 0000000000000000000000000000000000000000..cfb91ca6af8499a4ce518e4d66ea9ffbc9621bbf
--- /dev/null
+++ b/6_rendering/gtAnalyseCrackPlane.m
@@ -0,0 +1,92 @@
+function [data, vol, map, surface_view]=gtAnalyseCrackPlane(crack);
+
+%returns the crack plane data as a list [x y z nx ny nz]
+%also returns a labelled volume and tle corresponding colourmap
+%surface_view is a top down image
+
+
+
+%read the x,y,z points of the crack
+[y,x,z]=ind2sub(size(crack),find(crack)); %voxels of crack
+
+boxsize=5;
+%data out =[x y z nx ny nz]
+data=zeros(length(find(crack)), 6);
+
+
+for i=1:length(x)
+  
+  xx=x(i); yy=y(i); zz=z(i);
+  
+
+dummy=find(x>xx-boxsize & x<xx+boxsize & y>yy-boxsize & y<yy+boxsize & z>zz-boxsize & z<zz+boxsize);
+
+if length(dummy)>3
+  
+%this is right in tomography coordinates (ie as in volview, x l->r, y
+%top->bot, z up->down)
+
+  [origin, a]=lsplane([x(dummy) y(dummy) z(dummy)]);
+  
+%convert to instrument coordinates to agree with gtCaxisCmap conventions
+a=a([2 1 3]);
+a(3)=-a(3);
+
+data(i, :)=[xx yy zz a(1) a(2) a(3)];
+
+if mod(i, 1000)==0
+  100*i/length(x)
+end
+
+end
+
+end
+
+%cut the empty bits of data
+data(find(data(:,1)==0), :)=[]; 
+
+%now produce a labelled volume, and the corresponding colormap
+%volume
+vol=zeros(size(crack));
+for i=1:length(data)
+  vol(data(i,2), data(i,1), data(i,3))=i;
+end
+%colormap
+%as in gtCaxisCmap
+psi=acosd(data(:,6));
+phi=atan2(data(:,5), data(:,4));
+
+%get everything in degrees, and on the right interval
+phi=phi*180/pi;
+dummy=find(psi>90);
+psi(dummy)=180-psi(dummy);
+phi(dummy)=phi(dummy)+180;
+phi(find(phi<0))=phi(find(phi<0))+360;
+phi(find(phi>360))=phi(find(phi>360))-360;
+
+%hue
+h=phi/360;
+%saturation
+s=ones(size(h));
+%lightness (white //z, black in x-y plane)
+l=0.9-(0.8*(psi/90));
+rgb=hsl2rgb([h s l]);
+%add black background
+map=zeros(size(data,1)+1, 3);
+map(2:end, :)=rgb; %ie rgb plus zero background
+
+
+%read out "bird's eye" view of coloured crack;
+surface_view=zeros(size(crack, 1), size(crack, 2));
+for y=1:size(crack, 1)
+    for x=1:size(crack, 2)
+a=squeeze(vol(y,x,:));
+a=a(find(a, 1, 'first'));
+if ~isempty(a)
+    surface_view(y,x)=a;
+end
+    end
+end
+
+
+
diff --git a/6_rendering/gtAnalyseGrainBoundarySurface.m b/6_rendering/gtAnalyseGrainBoundarySurface.m
new file mode 100755
index 0000000000000000000000000000000000000000..e786a2095cd23d70a156029eb92a6132ecfabc1a
--- /dev/null
+++ b/6_rendering/gtAnalyseGrainBoundarySurface.m
@@ -0,0 +1,142 @@
+
+
+function [poles_all, poles_areas_all, pole_data]=gtAnalyseGrainBoundarySurface(fv_in, reduce_factor, grainID, bounds_list, boundaries_structure, r_vectors, bounds_dil)
+
+%nb - this was part of gtAnalyseBoundaryIndexPlaneMesh.m
+%this has been split into this file (analyse mesh) and
+% gtGrainBoundarySurfaceMesh (make mesh)
+%
+%grain_surface is fv , the facevertex data for patch
+%
+% bounds_list - which boundaries to analyse
+% reduce_factor (should be less than 1) passed to reduce patch
+%
+% return pole_data - a structure containing the pole data separated into each boundary
+
+
+sym=gtGetCubicSymOp;
+R=r_vectors(grainID,2:4);
+g=Rod2g(R);
+
+%if no list supplied which boundaries are relevent?
+if isempty(bounds_list)
+for i=1:length(boundaries_structure)
+    if boundaries_structure(i).grain1==grainID | boundaries_structure(i).grain2==grainID
+        bounds_list=[bounds_list i];
+    end
+end
+end
+
+for rf=1:length(reduce_factor)
+
+%down sample mesh using reducepatch
+fv=reducepatch(fv_in, reduce_factor(rf));
+
+
+%loop through vertices, assigning each to a boundary of the original grain
+%may not pick up some very small boundaries, but I guess this doesn't
+%matter- for grain 1 these are of size 1-39 voxels volume ie max diameter 4
+%voxels
+faces_bounds=zeros(size(fv.faces));
+for i=1:length(fv.vertices)
+    a=round(fv.vertices(i,:));
+    boundaryID=bounds_dil(a(2), a(1), a(3));
+    faces_bounds(find(fv.faces==i))=boundaryID;
+end
+
+%record down sampled grain surface / boundaries data?
+grain_surface.fv=fv;
+grain_surface.faces_bounds=faces_bounds;
+
+%record all normals and all triangle area for weighting
+normals=zeros(length(fv.faces), 3);
+areas=zeros(length(fv.faces), 1);
+
+
+poles_all=[];
+poles_areas_all=[];
+
+for k=1:length(bounds_list)
+    
+    
+    poles=[];
+    poles_areas=[];
+
+    dum=find(all(faces_bounds==bounds_list(k), 2));
+    if ~isempty(dum)
+        
+        for j=1:length(dum)
+            i=dum(j);
+            face=fv.faces(i,:);
+            %get the three vertices -
+            v1=fv.vertices(face(1), [2 1 3]);
+            v2=fv.vertices(face(2),  [2 1 3]);
+            v3=fv.vertices(face(3),  [2 1 3]);
+            %normal:
+            n=cross(v1-v2, v3-v2);
+            %fix this to follow lsplane output - change sign of third component
+            n(3)=-n(3);
+            normals(i,:)=n/norm(n);%may not need to save this info
+
+            %area
+            angle=acos(dot((v1-v2)/norm(v1-v2), (v3-v2)/norm(v3-v2)));
+            areas(i)=norm(v1-v2)*norm(v3-v2)*sin(angle)*0.5;
+
+            %can get co-linear points
+            if ~isreal(areas(i))
+                areas(i)=0;
+            end
+            
+            
+            %convert to crystallographic plane/pole
+            poles(end+1,:)=inv(g)*normals(i,:)';
+            poles_areas(end+1)=areas(i);
+
+        end
+
+
+        %apply the symmetry operators
+        poles2=[];
+        for i=1:length(sym)
+            poles2=[poles2; poles*sym(i).g];
+        end
+        %add this to correspond to line in gtMakePoleFigure
+        poles2=[poles2; -poles2];
+        poles=poles2;
+
+        poles_areas=repmat(poles_areas', 48, 1);
+
+
+
+        %%%%%%%%%% FIGURE PLOTTING %%%%%%%%%%%
+        %plot a pole figure of this boundary?
+        if 0
+            gtMakePoleFigure(poles, 'weights', poles_areas, 'inc', 0.01, 'searchR', 0.03)
+            title(sprintf('boundary %d - mesh reduced %f', bounds_list(k), reduce_factor(rf)))
+        end
+        %make some kind of fancy pants coloured 3d figure
+        if 0
+            fv_fig.vertices=fv.vertices;
+            fv_fig.faces=fv.faces(dum,:);
+            p=patch(fv_fig)
+            if bounds_list(k)==3076
+
+                set(p, 'facecolor', 'r')
+            else
+                set(p, 'facecolor', rand(3,1))
+            end
+        end
+        %%%%%%%%%% FIGURE PLOTTING %%%%%%%%%%%
+
+
+        %keep all pole data for the grain
+        poles_all=[poles_all; poles];
+        poles_areas_all=[poles_areas_all; poles_areas];
+
+    end
+    
+    pole_data(bounds_list(k)).poles=poles;
+    pole_data(bounds_list(k)).weights=poles_areas;
+    
+end
+end
diff --git a/6_rendering/gtAnalyseGrainBoundarySurface2.m b/6_rendering/gtAnalyseGrainBoundarySurface2.m
new file mode 100755
index 0000000000000000000000000000000000000000..bffa15693fa77820bf28e42e9fa8058200b94f21
--- /dev/null
+++ b/6_rendering/gtAnalyseGrainBoundarySurface2.m
@@ -0,0 +1,209 @@
+
+
+function [poles_all,poles_areas_all]=gtAnalyseGrainBoundarySurface2(fv_in, reduce_factor, grainID, bounds_list, boundaries_structure, r_vectors, bounds_dil)
+
+%version 2 - rather than return the poles/pole figure for the boundaries,
+%colour code the boudaries according to the index plane ( see gtSSTCmap )
+
+
+%nb - this was part of gtAnalyseBoundaryIndexPlaneMesh.m
+%this has been split into this file (analyse mesh) and
+% gtGrainBoundarySurfaceMesh (make mesh)
+%
+%grain_surface is fv , the facevertex data for patch
+%
+% bounds_list - which boundaries to analyse
+% reduce_factor (should be less than 1) passed to reduce patch
+
+sym=gtGetCubicSymOp;
+R=r_vectors(grainID,2:4);
+g=Rod2g(R);
+
+%if no list supplied which boundaries are relevent?
+if isempty(bounds_list)
+for i=1:length(boundaries_structure)
+    if boundaries_structure(i).grain1==grainID | boundaries_structure(i).grain2==grainID
+        bounds_list=[bounds_list i];
+    end
+end
+end
+
+
+%reduce mesh - single value only
+fv=reducepatch(fv_in, reduce_factor);
+
+
+%loop through vertices, assigning each to a boundary of the original grain
+%may not pick up some very small boundaries, but I guess this doesn't
+%matter- for grain 1 these are of size 1-39 voxels volume ie max diameter 4
+%voxels
+faces_bounds=zeros(size(fv.faces));
+for i=1:length(fv.vertices)
+    a=round(fv.vertices(i,:));
+    boundaryID=bounds_dil(a(2), a(1), a(3));
+    faces_bounds(find(fv.faces==i))=boundaryID;
+end
+
+%record down sampled grain surface / boundaries data?
+grain_surface.fv=fv;
+grain_surface.faces_bounds=faces_bounds;
+
+%record all normals and all triangle area for weighting
+normals=zeros(length(fv.faces), 3);
+areas=zeros(length(fv.faces), 1);
+
+
+poles_all=[];
+poles_areas_all=[];
+
+f1=figure;
+
+%llop through the boundaries being considered, analysing the planes of the
+%facets
+for k=1:length(bounds_list)
+
+    poles=[];
+    poles_areas=[];
+    bad_faces=[];
+
+    dum=find(all(faces_bounds==bounds_list(k), 2));
+    if ~isempty(dum)
+        
+        %loop through the triangles of this boundary
+        for j=1:length(dum)
+            i=dum(j);
+            face=fv.faces(i,:);
+            %get the three vertices -
+            v1=fv.vertices(face(1), [2 1 3]);
+            v2=fv.vertices(face(2),  [2 1 3]);
+            v3=fv.vertices(face(3),  [2 1 3]);
+            
+            %normal:
+            n=cross(v1-v2, v3-v2);
+            %fix this to follow lsplane output - change sign of third component
+            n(3)=-n(3);
+            normals(i,:)=n/norm(n);%may not need to save this info
+
+            %area
+            angle=acos(dot((v1-v2)/norm(v1-v2), (v3-v2)/norm(v3-v2)));
+            areas(i)=norm(v1-v2)*norm(v3-v2)*sin(angle)*0.5;
+
+            %can get co-linear points - these leave NaNs in poles
+            %can also get colinear points that don't causecomplex areas -
+            %low angle test
+            if ~isreal(areas(i)) | abs(angle)<0.00001
+                areas(i)=0;
+                bad_faces=[bad_faces; j];
+            end
+            
+            %convert to crystallographic plane/pole
+            poles(end+1,:)=inv(g)*normals(i,:)';
+            poles_areas(end+1)=areas(i); 
+        end
+
+        %remove NaN faces from dum
+        dum(bad_faces)=[];
+        poles(bad_faces, :)=[];
+        poles_areas(bad_faces)=[];
+        
+        
+        %apply the symmetry operators
+        poles2=[];
+        poles_for_pole_fig=[]
+        
+        for i=1:length(sym)
+            %deal with this in a 3d array
+            poles2=cat(3, poles2, poles*sym(i).g);
+            %keep a 2d array for gtMakePoleFigure
+            poles_for_pole_fig=[poles_for_pole_fig; poles*sym(i).g];
+        end
+        %add this to correspond to line in gtMakePoleFigure
+        poles2=cat(3,poles2,-poles2);
+        poles_for_pole_fig=[poles_for_pole_fig; -poles_for_pole_fig];
+        poles_areas_for_pole_fig=repmat(poles_areas', 48, 1);
+     
+        %keep all pole data for the grain
+        poles_all=[poles_all; poles_for_pole_fig];
+        poles_areas_all=[poles_areas_all; poles_areas_for_pole_fig];
+        
+        %get those poles which lie in the SST
+        a=find(poles2(:,2,:)>=0 & poles2(:,2,:)<=poles2(:,1,:) & poles2(:,3,:)>=poles2(:,1,:));
+        %a is effectively an index in an 2d array, size(poles2, 1) by size(poles2, 3) (48)
+        [a1,a2]=ind2sub([size(poles2, 1), size(poles2, 3)], a);
+        %but - this scrambles the order (i think)  should sort by a1 to keep poles3 in
+        %orignal order
+        [a1,i]=sort(a1);
+        a2=a2(i);
+
+  %get the relevent poles back out of the 3d thing
+  %temp use poles3
+  poles3=zeros(size(poles));
+  for p=1:size(poles2, 1)
+      poles3(p,:)=poles2(a1(p),:,a2(p));
+  end
+  
+  %get the colour
+  x=poles3(:,1);
+  y=poles3(:,2);
+  z=poles3(:,3);
+
+  alpha=atan(x./z); % in sst alpha 0->pi/4
+  phi=atan2(y,x);
+
+  rgb=[1-(alpha/(pi/4)) (alpha/(pi/4)).*(1-(phi/(pi/4))) (alpha/(pi/4)).*(phi/(pi/4))];
+  for i=1:size(rgb, 1)
+      rgb(i,:)=rgb(i,:)/max(rgb(i,:));
+  end
+
+  figure(f1)
+  fv_fig.vertices=fv.vertices;
+  fv_fig.faces=fv.faces(dum,:);
+  p=patch(fv_fig);
+  set(p, 'facevertexcdata', rgb)
+  shading faceted
+
+
+  %      poles=poles2;
+  %not really needed if 3d thing works
+        %poles_areas=repmat(poles_areas', 48, 1);
+        
+        %plot a pole figure of this boundary?
+        if 0
+            
+            gtMakePoleFigure(poles_for_pole_fig, 'weights', poles_areas_for_pole_fig, 'inc', 0.01, 'searchR', 0.03)
+            title(sprintf('boundary %d - mesh reduced %f', bounds_list(k), reduce_factor))
+        end
+        
+%         %make some kind of fancy pants coloured 3d figure
+%         %grain figure with the individual boundaries coloured
+%        figure(f1)
+%         fv_fig.vertices=fv.vertices;
+%         fv_fig.faces=fv.faces(dum,:);
+%         p=patch(fv_fig)
+%         if bounds_list(k)==3076
+%             set(p, 'facecolor', 'r')
+%         else
+%             set(p, 'facecolor', rand(3,1))
+%         end
+%         
+        
+
+
+    end
+end
+
+%optional - add the facets that do not belong uniquely to one boundary,
+%coloured black.
+if 1
+ dum=find(faces_bounds(:,1)~=faces_bounds(:,2) | faces_bounds(:,1)~=faces_bounds(:,3));
+  figure(f1)
+  fv_fig.vertices=fv.vertices;
+  fv_fig.faces=fv.faces(dum,:);
+  p=patch(fv_fig)
+set(p, 'facevertexcdata', zeros(length(dum), 3))
+shading faceted
+end
+
+axis equal
+axis vis3d
+
diff --git a/6_rendering/gtDCT2EBSD.m b/6_rendering/gtDCT2EBSD.m
new file mode 100755
index 0000000000000000000000000000000000000000..ff5b0b54d526a40aee2d810a8f242e340bf94550
--- /dev/null
+++ b/6_rendering/gtDCT2EBSD.m
@@ -0,0 +1,78 @@
+function gtDCT2EBSD(grain_volume, r_vectors)
+%export grain map to ebsd data format:
+% x ; y ; euler1 ; euler2 ; euler3 ;
+%euler angles seems to be between 0-2pi, precision to 4 dp
+% e1 0-2pi
+% e2 0-0.9ish
+% e3 0-1.5ish
+
+% convert r_vector to euler angles using x2t, t2x
+% r_vectors format is [grainid, r1 r2 r3]
+for i=1:size(r_vectors, 1)
+    x=[0 0 0 1 r_vectors(i,2:4) 0]';
+    t=x2t(x, 'erp');
+    xo=t2x(t,'rpm'); %euler z-x-z
+    euler_zxz(i,:)=xo(5:7)';
+    xo=t2x(t,'rpy'); %euler x-y-z
+    euler_xyz(i,:)=xo(5:7)';
+end
+
+%put all angles in positive range
+euler_zxz(find(euler_zxz<0))=euler_zxz(find(euler_zxz<0))+(2*pi);
+euler_xyz(find(euler_xyz<0))=euler_xyz(find(euler_xyz<0))+(2*pi);
+
+
+
+% %make a file for zxz euler convention
+% % file open
+% fid=fopen('EBSD_test_export1.txt', 'w');
+% 
+% % header line
+% fprintf(fid, 'X ; Y ; Euler1 ; Euler2 ; Euler3 ; \n');
+% 
+% % export the slice
+% [sizey, sizex]=size(grain_slice);
+% for x=1:sizex
+%     for y=1:sizey
+%         grainid=grain_slice(y,x);
+%         if grainid~=0
+%             e=euler_xyz(grainid,:);
+%         else
+%             e=[0 0 0];
+%         end
+%         fprintf(fid, '%d ; %d ; %0.4f ; %0.4f ; %0.4f ; \n', x-1,y-1,e(1),e(2),e(3));
+%     end
+% end
+% 
+% fclose(fid);
+
+%repeat for other convention
+
+
+% export the volume
+[sizey, sizex, sizez]=size(grain_volume);
+
+for z=1:sizez
+    
+% file open
+disp(sprintf('slice %d ...', z))
+fid=fopen(sprintf('/tmp_14_days/andy/EBSD_test/EBSD_export_slice_%d.txt', z), 'w');
+
+% header line
+fprintf(fid, 'X ; Y ; Euler1 ; Euler2 ; Euler3 ; \n');
+
+for x=1:sizex
+    for y=1:sizey
+        grainid=grain_volume(y,x,z);
+        if grainid~=0
+            e=euler_xyz(grainid,:);
+        else
+            e=[0 0 0];
+        end
+        fprintf(fid, '%d ; %d ; %0.4f ; %0.4f ; %0.4f ; \n', x-1,y-1,e(1),e(2),e(3));
+    end
+end
+
+fclose(fid);
+
+end
\ No newline at end of file
diff --git a/6_rendering/gtGrainBoundarySurfaceMesh.m b/6_rendering/gtGrainBoundarySurfaceMesh.m
new file mode 100755
index 0000000000000000000000000000000000000000..31290dd6b9366ab40c4f25f7405de5c081bcd559
--- /dev/null
+++ b/6_rendering/gtGrainBoundarySurfaceMesh.m
@@ -0,0 +1,72 @@
+
+function fv=gtGrainBoundarySurfaceMesh(grains, smoothR, grainID)
+
+%this seems to work reasonably quickly
+% procedure:
+% smooth grain volume, considering relevent voxels only (faster than smooth3)
+% isosurface
+% assign points on isosurface to particular boundaries
+% returns the face-vertex structure,
+% this can then be simplified using reduce patch for further analysis
+
+%nb - this was gtAnalyseBoundaryIndexPlaneMesh.m
+%this has been split into this file (generate mesh) and
+% gtAnalyseGrainBoundarySurface.
+
+tmp=grains==grainID;
+
+%smooth grain volume before isosurface
+%find relevent voxels
+smoothD=(2*smoothR)+1;
+disp('find target voxels for smoothing')
+tic
+todo=find(imdilate(tmp, ones(smoothD,smoothD,smoothD))-imerode(tmp, ones(smoothD,smoothD,smoothD)));
+toc
+tmp2=zeros(size(tmp));
+
+%do smoothing
+disp('do smoothing')
+tic 
+for k=1:length(todo)
+    
+    [y,x,z]=ind2sub(size(tmp), todo(k));
+
+    x1=max(x-smoothR,1);
+    y1=max(y-smoothR,1);
+    z1=max(z-smoothR,1);
+    x2=min(x+smoothR,size(tmp,2));
+    y2=min(y+smoothR,size(tmp,1));
+    z2=min(z+smoothR,size(tmp,3));
+    
+neighbourhood=tmp(y1:y2, x1:x2, z1:z2);
+tmp2(y,x,z)=mean(neighbourhood(:));
+
+if mod(k, round(length(todo)/10))==0
+    disp(sprintf('%0.1f',k/length(todo)))
+end
+
+end
+toc
+
+%complete smoothed grain interior
+tmp2(find(tmp2==0 & tmp))=1;
+
+%isosurface
+fv=isosurface(tmp2, 0.5);
+%initial triangle area is about 1
+approx_triangle_area=(length(todo)/smoothD)/length(fv.vertices)
+%reduce mesh to give triangle area ~10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/6_rendering/gtGrains2STL.m b/6_rendering/gtGrains2STL.m
new file mode 100755
index 0000000000000000000000000000000000000000..39e9e279ee3ef74afbdca26b487ddbd1e75f82a4
--- /dev/null
+++ b/6_rendering/gtGrains2STL.m
@@ -0,0 +1,30 @@
+%gtGrains2STL
+
+% converts all grains into STL polygon meshes for rendering
+
+d=dir('4_grains/grain*');  % get all grain directories
+
+for n=1:length(d)
+  
+  d2=dir(['4_grains/' d(n).name '/*.edf']);
+  if isempty(d2)
+    continue
+  end
+  fprintf('Looking at %s\n',d2.name);
+  matname=sprintf('4_grains/%s/%s.mat',d(n).name,d(n).name);
+  load(matname)
+
+  edfname=sprintf('4_grains/%s/%s',d(n).name,d2.name);
+  
+  vol=edf_read(edfname);
+  imagesc(vol(:,:,round(size(vol,3)/2)))
+  title(num2str(n))
+  drawnow,shg
+  fv=isosurface(vol,0.5);
+  fprintf('Moving to %.2f,%.2f,%.2f\n',vol_x_origin,vol_y_origin,vol_z_origin);
+  fv.vertices=fv.vertices+repmat([vol_x_origin vol_y_origin vol_z_origin],length(fv.vertices),1);
+  fname=sprintf('6_render/%s.stl',d(n).name);
+  stlwrite2(fv,fname,'ascii')
+end
+ 
+
diff --git a/6_rendering/gtMakeSigmaCmap.m b/6_rendering/gtMakeSigmaCmap.m
new file mode 100755
index 0000000000000000000000000000000000000000..9819443f9752c849f278bf1fde2fddb195c470bf
--- /dev/null
+++ b/6_rendering/gtMakeSigmaCmap.m
@@ -0,0 +1,45 @@
+function sigma_map = gtMakeSigmaCmap(vol_bounds, boundaries_structure)
+%rather than make a volume labelled by sigma, make a single (large)
+%colourmap to give the right colours to boundaries.  
+%save the output, so that it only has to be run once.
+
+
+
+sigma_map=zeros(max(vol_bounds(:))+1, 3);
+
+%  non-special boundaries are grey
+sigma_map(2:end, :)=0.7;
+
+%  prepare the key for colouring the rest
+colour_key(1,:) =[1     1 1 0] % sigma 1,  yellow
+colour_key(2,:) =[3     1 0 0] % sigma 3,  red
+colour_key(3,:) =[5     1 0 1] % sigma 5,  pink/purple
+colour_key(4,:) =[7     1 0 1] % sigma 7,  pink/purple
+colour_key(5,:) =[9     0 0 1] % sigma 9,  blue
+colour_key(6,:) =[11    1 0 1] % sigma 11  pink/purple
+colour_key(7,:) =[13.1  1 0 1] % sigma 13a pink/purple
+colour_key(8,:) =[13.2  1 0 1] % sigma 13b pink/purple
+colour_key(9,:) =[15    1 0 1] % sigma 15  pink/purple
+colour_key(10,:)=[17.1  1 0 1] % sigma 17a pink/purple
+colour_key(11,:)=[17.2  1 0 1] % sigma 17b pink/purple
+colour_key(12,:)=[19.1  1 0 1] % sigma 19a pink/purple
+colour_key(13,:)=[19.2  1 0 1] % sigma 19b pink/purple
+colour_key(14,:)=[21.1  1 0 1] % sigma 21a pink/purple
+colour_key(15,:)=[21.2  1 0 1] % sigma 21b pink/purple
+colour_key(16,:)=[23    1 0 1] % sigma 23 pink/purple
+colour_key(17,:)=[25.1  1 0 1] % sigma 25a pink/purple
+colour_key(18,:)=[25.2  1 0 1] % sigma 25b pink/purple
+colour_key(19,:)=[27.1  1 0 1] % sigma 27a pink/purple
+colour_key(20,:)=[27.2  1 0 1] % sigma 27b pink/purple
+colour_key(21,:)=[29.1  1 0 1] % sigma 2ab pink/purple
+colour_key(22,:)=[29.2  1 0 1] % sigma 29b pink/purple
+
+%loop through boundaries structure
+for i=1:length(boundaries_structure)
+  if ~isempty(boundaries_structure(i).sigma)
+    sigma_map(i+1,:) = colour_key(find(colour_key(:,1)==boundaries_structure(i).sigma), 2:4);
+  end
+end
+
+save sigma_map sigma_map
+
diff --git a/6_rendering/gtPlotHexagon.m b/6_rendering/gtPlotHexagon.m
new file mode 100755
index 0000000000000000000000000000000000000000..40e2155b4760fd1b27e55f20c18e4263077143ac
--- /dev/null
+++ b/6_rendering/gtPlotHexagon.m
@@ -0,0 +1,101 @@
+
+function gtPlotHexagon(grains, r_vectors, angle, cmap)
+
+%make a figure containing subplots of the unit cells of the selected grains
+%angle is the angle of the section plane, defined as in
+%gtShowSampleSurface
+%can pass in a colormap as well, so colours match the section
+
+%as in gtShowSampleSurface
+%Deal with coordinate systems.  R-vector orientation data in the instrument
+%system: x//beam, z upwards, y towards door.
+%In the reconstructed tomography/grain map data, z is downwards, y//x
+%instruments, x//y instrument.
+%Finally present all information in the frame of the tomo data.
+
+
+if ~exist('cmap', 'var')
+    %if no colourmap passed in, use red
+    cmap=zeros(size(r_vectors, 1), 3);
+    cmap(:,1)=1;
+end
+
+
+% patch object hexagonal prism
+%12 corners
+%[u v x w]
+corners4=[2 -1 -1 3;...
+    -1 2 -1 3;...
+    -1 -1 2 3;...
+    1 1 -2 3;...
+    1 -2 1 3;...
+    -2 1 1 3];
+corners4=[corners4; corners4];
+corners4(7:12, 4)=-3;%lower corners
+
+%turn these into 3 index coords
+corners3(:,3)=corners4(:,4);
+corners3(:,1)=(corners4(:,1)-corners4(:,3))*cosd(30);
+corners3(:,2)=corners4(:,2)-((corners4(:,1)+corners4(:,3))*sind(30));
+corners3=corners3./repmat(sqrt(sum((corners3.*corners3),2)), 1,3);
+
+id=figure;
+
+%apply the R-vector
+for i=1:length(grains)
+
+    grain=grains(i);
+    R=r_vectors(find(r_vectors(:,1)==grain),2:4);
+    g=Rod2g(R);
+    corners3a=(g*corners3')';
+
+    %allow for the two coordinate systems.  Transform from instrument to
+    %reconstructed tomo coordinates: x-->y y-->x z-->-z
+    corners3a=[corners3a(:,2) corners3a(:,1) -corners3a(:,3)]; 
+    
+    %do the rotate to follow the the section plane
+    corners3b = ([cosd(angle) sind(angle) 0; -sind(angle) cosd(angle) 0;0 0 1]*corners3a')';
+
+    %write these corners into the correct format for patch
+
+    %corners3a is "vertices"
+    hex_faces=[1 4 2 6 3 5; 7 11 9 12 8 10];
+    rec_faces=[1 7 10 4;...
+        4 2 8 10;...
+        2 6 12 8;...
+        6 3 9 12;...
+        3 5 11 9;...
+        5 1 7 11];
+
+    subplot(1, length(grains), i);
+    %reference hex
+    %patch('Vertices', corners3, 'Faces', hex_faces, 'FaceColor', 'b', 'FaceAlpha', 0.4)
+    %patch('Vertices', corners3, 'Faces', rec_faces, 'FaceColor', 'b', 'FaceAlpha', 0.4)
+    %reference background like the section plane
+    xpos=min(mean(corners3b([1 4 2 6 3 5], 1)), mean(corners3b([7 11 9 12 8 10], 1)));
+    section_plane_vertices=[xpos 1 1; xpos 1 -1; xpos -1 1; xpos -1 -1];
+    section_plane_face=[1 2 4 3];
+    patch('Vertices', section_plane_vertices, 'Faces', section_plane_face, 'FaceColor', 'k', 'FaceAlpha', 0.4)
+    %including the rotation for sectioning
+    patch('Vertices', corners3b, 'Faces', hex_faces, 'FaceColor', cmap(grain+1,:), 'FaceAlpha', 1)
+    patch('Vertices', corners3b, 'Faces', rec_faces, 'FaceColor', cmap(grain+1,:), 'FaceAlpha', 1)
+
+    set(get(get(id, 'CurrentAxes'), 'Title'), 'String', sprintf('grain %d unit cell', grain))
+    set(get(get(id, 'CurrentAxes'), 'xLabel'),'String', 'x axis')
+    set(get(get(id, 'CurrentAxes'), 'yLabel'),'String', 'y axis')
+    set(get(get(id, 'CurrentAxes'), 'zLabel'),'String', 'z axis')
+    set(get(id, 'CurrentAxes'), 'zdir','reverse')
+    set(get(id, 'CurrentAxes'), 'xdir','reverse')
+    %need to mirror twice to stay consistant with tomo
+    set(get(id, 'CurrentAxes'), 'view', [90 0])
+
+    axis tight
+    axis vis3d
+end
+
+
+
+
+
+
+
diff --git a/6_rendering/gtPlotOrientationCube.m b/6_rendering/gtPlotOrientationCube.m
new file mode 100755
index 0000000000000000000000000000000000000000..cf437db8ebc7a25cb8eadc2ece7f50e6a0aedf2e
--- /dev/null
+++ b/6_rendering/gtPlotOrientationCube.m
@@ -0,0 +1,18 @@
+function gtPlotOrientationCube(r_vector, colour)
+% plot a cube corresponding to the orientation of a grain
+%be careful regarding axes and coordinate systems!
+%should be that this cube is plotted in instrument coordinates
+% tomo reconstruction coordinates: x tomo//y inst ; y tomo // x inst ; z
+% tomo // negative z inst
+% AK - 9/2008
+
+corners=[0 0 0; 1 0 0; 0 1 0; 0 0 1; 1 1 0; 1 0 1; 0 1 1; 1 1 1 ];
+faces=[1 3 5 2; 1 4 6 2; 1 4 7 3; 4 6 8 7; 3 5 8 7; 2 5 8 6];
+
+g=rod2g(r_vector);
+cornersA=(g*corners')';
+
+figure
+patch('Vertices', cornersA, 'Faces', faces, 'FaceColor', colour, 'FaceAlpha', 1)
+
+axis equal
\ No newline at end of file
diff --git a/6_rendering/gtRenderGrains b/6_rendering/gtRenderGrains
new file mode 100755
index 0000000000000000000000000000000000000000..e0b558e3ccfddfac019c45f9fe9b7a6253f0ba20
--- /dev/null
+++ b/6_rendering/gtRenderGrains
@@ -0,0 +1,34 @@
+subvol=grains(1:2:end, 1:2:end, 30:2:250);
+
+
+map=gtRodriguezColormap(r_vectors);
+
+list=unique(subvol(:,:,50));
+
+
+list(find(list==0))=[];%don't render the background
+
+figure;
+%go through graini by grain
+for i=1:length(list)
+  disp(sprintf('rendering grain %d of %d...', i, length(list)))
+
+  voltest=zeros(size(subvol));
+
+  voltest(find(subvol==list(i)))=1;
+  %pad for smoothing
+  voltest2=zeros(size(voltest)+10);
+  voltest2(6:end-5, 6:end-5, 6:end-5)=voltest;
+  voltest2=smooth3(voltest2, 'box', 3);
+  p(i)=patch(isosurface(voltest2, 0.5));
+  %set colour according to map (note map(1,:)=[0 0 0] for background, so +1
+  set(p(i), 'FaceColor', map(list(i)+1, :), 'EdgeColor', 'none');
+
+end
+camlight
+lighting phong
+axis equal
+axis vis3d
+set(gca, 'xTick', []);
+set(gca, 'yTick', []);
+set(gca, 'zTick', []);
diff --git a/6_rendering/gtRenderGrains.m b/6_rendering/gtRenderGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..24f94ef6f5ef72941a70acbb984eedc57f5bcdcc
--- /dev/null
+++ b/6_rendering/gtRenderGrains.m
@@ -0,0 +1,42 @@
+function p=gtRenderGrains(grains,map,varargin);
+%
+
+if nargin==3
+  layer=varargin{1};
+  % pick out grains in a single layer
+  list=unique(grains(:,:,layer));
+else
+  list=unique(grains);
+end
+
+
+
+
+
+
+list(find(list==0))=[];%don't render the background
+
+figure;
+%go through graini by grain
+for i=1:length(list)
+  disp(sprintf('rendering grain %d of %d...', i, length(list)))
+
+  voltest=zeros(size(grains));
+
+  voltest(find(grains==list(i)))=1;
+  %pad for smoothing
+  voltest2=zeros(size(voltest)+10);
+  voltest2(6:end-5, 6:end-5, 6:end-5)=voltest;
+  voltest2=smooth3(voltest2, 'box', 3);
+  p(i)=patch(isosurface(voltest2, 0.5));
+  %set colour according to map (note map(1,:)=[0 0 0] for background, so +1
+  set(p(i), 'FaceColor', map(list(i)+1, :), 'EdgeColor', 'none');
+
+end
+camlight
+lighting phong
+axis equal
+axis vis3d
+set(gca, 'xTick', []);
+set(gca, 'yTick', []);
+set(gca, 'zTick', []);
diff --git a/6_rendering/gtSSTCmap.m b/6_rendering/gtSSTCmap.m
new file mode 100755
index 0000000000000000000000000000000000000000..37e3dbfac384de7971ffc62381f85abebb556bca
--- /dev/null
+++ b/6_rendering/gtSSTCmap.m
@@ -0,0 +1,140 @@
+
+function gtSSTCmap()
+%make a color space for the Standard Stereographic Triangle
+
+%analyse the pole data
+figure
+hold on
+inc=0.01;
+i=1;j=1;
+    phimax=pi/4;
+    psimax=atan(sqrt(2));
+for phi=[0:inc:(phimax-inc) (phimax-inc)] %around z-axis
+    j=1;
+    for psi=[0:inc:(psimax+inc) psimax+inc] % out from z-axis - go slightly further to avoid gaps at edge of triangle
+
+        z=cos(psi);
+        x=sin(psi)*cos(phi);
+        y=sin(psi)*sin(phi);
+        
+        %for a colour representation want two angles - phi (around z) and
+        % alpha (around y)
+        
+        alpha=atan(x/z); % in sst alpha 0->pi/4
+        
+        if alpha<=pi/4
+            rgb=[1-(alpha/(pi/4)) (alpha/(pi/4))*(1-(phi/(pi/4))) (alpha/(pi/4))*(phi/(pi/4))];
+            % rgb=rgb/max(rgb);
+        else
+            rgb=[1-(alpha/(pi/4)) (alpha/(pi/4))*(1-(phi/(pi/4))) (alpha/(pi/4))*(phi/(pi/4))];
+            rgb=rgb/max(rgb);
+            rgb(find(rgb<0))=0;
+            %rgb=[1 1 1];
+        end
+
+        test_normal=[x y z];
+
+%radius distorted for stereographic proj
+r_patch=tan([psi/2 (psi+inc)/2]);
+[phi_patch,r_patch]=meshgrid([phi phi+inc]',r_patch);
+[x_patch,y_patch]=pol2cart(phi_patch,r_patch);
+        
+
+         p=patch(x_patch([1 2 4 3]), y_patch([1 2 4 3]), rgb);
+        set(p, 'edgecolor', 'none')
+        j=j+1;
+    end
+    i=i+1;
+end
+
+%add poles and tart up like gtMakePoleFigure
+set(gca, 'XTickLabel','')
+set(gca, 'YTickLabel','')
+set(gca, 'GridLineStyle','none')
+set(gca, 'Ycolor', 'w')
+set(gca, 'Xcolor', 'w')
+
+set(gca, 'xlim', [-0.02 sqrt(2)-1+0.045])
+set(gca, 'ylim', [-0.025 0.3769])
+
+
+        uvw_poles=[0 0 1; 1 0 1; 1 1 1;...
+            2 0 1; 2 1 1; 2 2 1;...
+            3 0 1; 3 1 1; 3 2 0; 3 2 1; 3 2 2; 3 3 1; 3 3 2;...
+            4 0 1; 4 1 1; 4 2 1; 4 3 0; 4 3 1; 4 3 2; 4 3 3; 4 4 1; 4 4 3];
+
+            sym = gtGetCubicSymOp;
+    uvw_poles2=[];
+    for i=1:length(sym)
+        uvw_poles2=[uvw_poles2; uvw_poles*sym(i).g];
+    end
+    uvw_poles=[uvw_poles2; -uvw_poles2];
+        dum=find(uvw_poles(:,2)>=0 & uvw_poles(:,2)<=uvw_poles(:,1) & uvw_poles(:,3)>=uvw_poles(:,1));
+        uvw_poles=uvw_poles(dum, :);
+        
+            % plot these uvw/hkl poles
+    phi_uvw=atan2(uvw_poles(:,2), uvw_poles(:,1));
+    psi_uvw=acos(uvw_poles(:,3)./(sqrt(sum(uvw_poles.*uvw_poles, 2))));
+    r_uvw=tan(psi_uvw/2);
+    dummy=find(r_uvw>1);
+    r_uvw(dummy)=[];
+    phi_uvw(dummy)=[];
+    [x_uvw,y_uvw]=pol2cart(phi_uvw, r_uvw);
+    dummy=find(x_uvw<-1 | x_uvw>1 | y_uvw<-1 | y_uvw>1);
+    x_uvw(dummy)=[];
+    y_uvw(dummy)=[];
+
+    plot(x_uvw, y_uvw, 'k*')
+    
+    
+                text(0, 0-0.015, '(001)')
+        text(0.366+0.01, 0.366-0.005, '(111)')
+        text(0.4142-0.015, -0.015, '(101)')
+        
+        text(0.1213-0.04, 0.1213, '(114)')
+        text(0.1583-0.04, 0.1583, '(113)')
+        text(0.2247-0.04, 0.2247, '(112)')
+        text(0.2808-0.04, 0.2808, '(223)')
+        text(0.3052-0.045, 0.3052, '(334)')
+
+        text(0.3845+0.01, 0.2884, '(434)')
+        text(0.3901+0.01, 0.2601, '(323)')
+        text(0.4000+0.01, 0.2000, '(212)')
+        text(0.4077+0.01, 0.1359, '(313)')
+        text(0.4105+0.01, 0.1026, '(414)')
+
+        text(0.1231-0.02, -0.015, '(104)')
+        text(0.1623-0.01, -0.015, '(103)')
+        text(0.2361-0.015, -0.015, '(102)')
+        text(0.3028-0.02, -0.015, '(203)')
+        text(0.3333-0.01, -0.015, '(304)')
+
+        text(0.2967+0.01, 0.1483, '(213)')
+        text(0.2330+0.01, 0.1165, '(214)')
+        text(0.3297+0.01, 0.1099, '(314)')
+        text(0.3197+0.01, 0.2131, '(324)')
+
+        %add a black border
+       %line from 101 to 111 is z=x
+line_phi=[0:0.01:pi/4 pi/4];
+linex=cos(line_phi);
+linez=linex;
+liney=sin(line_phi);
+line_points=[linex' liney' linez'];
+%normalise
+line_points=line_points./repmat(sqrt(sum(line_points.*line_points, 2)), 1, 3);
+%convert to stereographic proj.
+line_psi=acos(line_points(:,3));
+line_r=tan(line_psi/2);
+%stereographic projection x-y
+[linex,liney]=pol2cart(line_phi', line_r);
+plot([linex; 0; linex(1)], [liney; 0; liney(1)], 'k-')
+
+
+%add a white patch to mask the rough outer edge of the triangle
+xp=[linex; linex(end); 0.55; 0.55; linex(1)];
+yp=[liney; 0.379; 0.379; 0; 0];
+p=patch(xp, yp, 'w');
+set(p, 'edgecolor', 'none')
+
+
diff --git a/6_rendering/gtShowSampleSurface.m b/6_rendering/gtShowSampleSurface.m
new file mode 100755
index 0000000000000000000000000000000000000000..a41130846dcc8c94561f78168bb5b901844cd0b7
--- /dev/null
+++ b/6_rendering/gtShowSampleSurface.m
@@ -0,0 +1,170 @@
+function gtShowSampleSurface(vol, angle, depth_orig, cmap, r_vectors, grains)
+%rotate volume by angle, remove layer depth pixels thick from surface
+%use volume with surface added (surface label is 800, grains 1-700)
+%show what's left
+%highlight grains of interest
+%show trace of basal planes on section, display inclination, using
+%gtPlotHexagon to display crystallographic orientation.
+
+%rotation convention for section: starting from 12-6 o'clock on grain map // y, angle
+%is measured clockwise.  Hence, first cut of interest is around 13.1
+%degrees.  Depth is removed from the left of the sample, after rotation
+
+%Deal with coordinate systems.  R-vector orientation data in the instrument 
+%system: x//beam, z upwards, y towards door.  
+%In the reconstructed tomography/grain map data, z is downwards, y//x
+%instruments, x//y instrument.
+%Finally present all information in the frame of the tomo data.
+
+vol=imrotate(vol, angle, 'nearest', 'crop');
+
+
+%find edge of sample
+outline_rot=sum(vol==800, 3);
+%calculate depth of section
+depth=depth_orig+find(sum(outline_rot, 1),1, 'first');
+if isempty(depth)
+  depth=depth_orig;
+  disp('no outline found - designed for outline==800 - guessing')
+end
+%get section, transpose for correct orientation and view direction
+section=squeeze(vol(:,depth,:))';
+
+%get surface grains not cut by section
+section_outline=outline_rot(:,depth)';
+
+%section is vertical as we look at plane through the sample.  Thus x, y in
+%the section correspond to y z in 3D
+if 0 %simple style
+    section_min=find(section_outline, 1, 'first');
+    section_max=find(section_outline, 1, 'last');
+    for x=[1:section_min section_max:size(section, 2)] %along the rows
+        for y=1:size(section, 1) %down the columns
+            tmp=vol(x,:,y); %get the line of voxels
+            tmp(find(tmp==800))=0;%remove outline
+            if any(tmp~=0)
+                [v,v,v]=find(tmp, 1, 'first');
+                section(y,x)=v;
+            end
+        end
+    end
+else %more difficult...
+    sample_dia=find(sum(outline_rot,1), 1, 'last')-find(sum(outline_rot,1), 1, 'first');
+    if isempty(sample_dia)
+      sample_dia=max(size(outline_rot));
+      disp('again, no outline (==800) found')
+    end
+    
+    
+    for x=[1:size(section, 2)] %along the rows
+
+        %estimate how thick a layer we should look at to get near surface
+        %grains
+        a=asin(x-(size(section,2)/2)/(sample_dia/2));
+        if ~isreal(a)
+            a=pi/2;
+        end
+        layer_thickness=5/cos(a);
+        layer_thickness=min(round(layer_thickness), 40);
+        for y=1:size(section, 1) %down the columns
+            %don't remove the edges of the section
+            if section(y,x)~=800
+            tmp=vol(x,:,y); %get the line of voxels
+            %at this point, is the surface the sample surface, or the section?
+            sam_edge=max(depth, find(tmp==800, 1, 'first'));
+            tmp=tmp(sam_edge:sam_edge+layer_thickness); %consider a 21 pixel zone
+            tmp(find(tmp==800))=0;%remove outline
+            if any(tmp~=0)
+                [v,v,v]=find(tmp, 1, 'first');
+                section(y,x)=v;
+            end
+            end
+        end
+    end
+end
+
+section_id=figure;
+imshow(section,[0 max(vol(:))])
+%in this image, y tomo is from left to right, z tomo is from top to bottom
+%(note this is after the rotation of the sample to display the right
+%section)
+colormap(cmap)
+hold on
+
+set(get(get(section_id, 'CurrentAxes'), 'Title'), 'String',sprintf('Section at angle %0.1f degrees, %d pixels depth',angle,depth_orig'))
+%set axis titles - note that because we are looking at a section, x->y,
+%y->z
+set(get(get(section_id, 'CurrentAxes'), 'yLabel'),'String', 'z axis')
+set(get(get(section_id, 'CurrentAxes'), 'xLabel'),'String', 'y axis')
+axis equal
+
+
+
+if 0
+dum=[];
+for i=1:length(grains)
+    if isempty(find(section==grains(i), 1))
+        dum(i)=1;
+    end
+end
+grains(find(dum))=[];
+end
+
+dum=[];
+%plot basal plane traces on the grains of interest
+
+disp('note that the section plane that we look at is y (--> left to right) z (--> top to bottom')
+disp('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
+
+for i=1:length(grains)
+    grain=grains(i);
+    R=r_vectors(find(r_vectors(:,1)==grain), 2:4);
+    g=Rod2g(R);
+    c_axis=(g*[0 0 1]')';
+    %this is in instrument coordinates... convert to tomo
+    c_axis=[c_axis(2) c_axis(1) -c_axis(3)];
+    
+    %test inclination: suitable for fatigue?
+    a=abs(90-acosd(c_axis(3)));
+    if 1%a>30 & a<60 % if the inclination is good
+    
+    %rotate c_axis by angle (same sense as imrotate
+    c_axis = [cosd(angle) sind(angle) 0; -sind(angle) cosd(angle) 0;0 0 1]*c_axis';
+    %section plane is yz, normal // x
+    section_norm=[1 0 0];
+    %cross product gives the intesection of these two planes
+    basal_trace=cross(c_axis, section_norm);
+    %basal trace: [x y z] in 3d --> x_section=y, y_section=z
+    [y,x]=ind2sub(size(section), find(section==grain));
+    point=[mean(x), mean(y)];
+    point=point+50*basal_trace(2:3);
+    point(2,:)=point-100*basal_trace(2:3);
+    plot(point(:,1), point(:,2), 'y')
+    %other component of this basal plane
+    %if we can tilt around the 3D y-axis?
+    %define positive rotation of sample to be anticlockwise about positive
+    %y-tilt - around the left-right axis of the image as we look at the
+    %section
+    y_tilt=atand(-c_axis(1)/c_axis(3));
+    %x_tilt - this is the one we can see plotted on the image - hence from
+    %basal trace
+    x_tilt=atand(-basal_trace(3)/basal_trace(2));
+    %display for user
+    disp(sprintf('c_axis of grain %d - in 3D coordinates, after sample rotation, is:', grain))
+    disp(sprintf('%0.2f %0.2f %0.2f', c_axis(1), c_axis(2), c_axis(3)))
+    disp(sprintf('x_tilt for grain %d should be %0.2f degrees', grain, x_tilt))
+    disp(sprintf('y_tilt for grain %d should be %0.2f degrees', grain, y_tilt))
+    disp('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
+    
+    else
+        dum(i)=1;
+    end
+end
+
+%again, remove grains with non-interesting inclinations
+grains(find(dum))=[];
+
+%plot the unit cell representations of the visible grains in second figure
+%change gtPlotHexagon to take the two coordinate systems into account
+gtPlotHexagon(grains, r_vectors, angle, cmap)
+
diff --git a/6_rendering/gtThinCrack2.m b/6_rendering/gtThinCrack2.m
new file mode 100755
index 0000000000000000000000000000000000000000..2dd28228b55260bff6c69916e02eccddfa2627d6
--- /dev/null
+++ b/6_rendering/gtThinCrack2.m
@@ -0,0 +1,39 @@
+
+function volout = gtThinCrack2(vol)
+
+%label only the centres of a crack
+
+
+
+
+%%%%%%  Close the crack   %%%%%%%
+volout=zeros(size(vol));
+vol=uint8(vol>0); %crack=1, material=0
+
+% vol(y,x,z)
+
+for y=1:size(vol,1)
+  for x=1:size(vol,2)
+
+       
+    tmp=squeeze(vol(y, x, :));
+    
+    if max(tmp(:))>0
+    
+    tmp=bwlabel(tmp);
+    
+    for i=1:max(tmp(:))
+        
+        z=find(tmp==i);
+        z=round(mean(z));
+        
+        volout(y,x,z)=255;
+        
+    end
+    
+    %test if we have some crack
+    end
+
+    %loop through the volume
+  end
+end
diff --git a/6_rendering/objwrite.m b/6_rendering/objwrite.m
new file mode 100755
index 0000000000000000000000000000000000000000..86c4b2a0e3214c13cd601fe98ca7318c9d7ce752
--- /dev/null
+++ b/6_rendering/objwrite.m
@@ -0,0 +1,46 @@
+function objwrite(pv,filename)
+% OBJWRITE.M A simple OBJ (Alias Wavefront) file writer (pv is the form of
+% output from isosurface)
+% Greg Johnson, August 2002 (November 2006)
+%
+%pv.faces=pv.faces(1:100:end,:);
+
+
+fid=fopen(filename,'w');
+
+for group=1:length(pv)
+  nvertices=size(pv{group}.vertices,1);
+  nfaces=size(pv{group}.faces,1);
+
+  verticesperface=size(pv{group}.faces,2);
+
+  for n=1:nvertices
+    fprintf(fid,'v %3.3f %3.3f %3.3f\n',pv{group}.vertices(n,:));
+  end
+
+  fprintf(fid,'g foo%d\n',group);
+
+  for n=1:nfaces
+    fprintf(fid,'f %d %d %d\n',pv{group}.faces(n,:));
+  end
+end
+
+fprintf(fid,'g\n');
+
+
+
+% 0 0 0                      { start of vertex list }
+% 0 0 1
+% 0 1 1
+% 0 1 0
+% 1 0 0
+% 1 0 1
+% 1 1 1
+% 1 1 0
+% 4 0 1 2 3                  { start of face list }
+% 4 7 6 5 4
+% 4 0 4 5 1
+% 4 1 5 6 2
+% 4 2 6 7 3
+% 4 3 7 4 0
+fclose(fid);
diff --git a/6_rendering/plyread.m b/6_rendering/plyread.m
new file mode 100755
index 0000000000000000000000000000000000000000..7ba81ee9fbe84baf24e6a9d861131c509e409cdb
--- /dev/null
+++ b/6_rendering/plyread.m
@@ -0,0 +1,107 @@
+% PLYREAD.M A simple PLY (Stanford polygon) file reader
+% Greg Johnson, August 2002
+%
+
+clear ply
+[filename,pathname]=uigetfile('*.ply','Pick a PLY file');
+
+
+fid=fopen(filename,'rt');
+
+l=upper(fgetl(fid));
+if ~strcmp(l,'PLY')
+  disp('I don''t think this is a PLY file...');
+  return
+end
+
+l=upper(fgetl(fid));
+[t,r]=strtok(l);
+if ~strcmp(t,'FORMAT')
+  disp('The file is not formatted correctly');
+  return
+else
+  [ply.filetype,r]=strtok(r);
+  [ply.fileversion,r]=strtok(r);
+end
+
+ply.comments=[];
+ply.elements=[];
+
+while (1)  % read header
+  l=upper(fgetl(fid));
+  [t,r]=strtok(l);
+  switch (t)
+    case 'COMMENT'
+      disp(['Comment: ' r])
+      ply.comments{end+1}=r;
+    case 'ELEMENT'
+      [t,r]=strtok(r);
+      ply.elements{end+1}.name=t;
+      ply.elements{end}.quantity=str2num(r);
+      ply.elements{end}.property=[];  % initialise properties to empty matrix
+      status=t;
+
+    case 'PROPERTY'
+      [t,r]=strtok(r);
+      if ~strcmp(t,'LIST')
+        ply.elements{end}.property{end+1}.name = r(2:end);
+        ply.elements{end}.property{end}.datatype=t;
+        ply.elements{end}.property{end}.dataset=[];
+      else
+
+        [t,r]=strtok(r);
+        ply.elements{end}.property
+        disp('Don''t know how to handle LIST properties yet...');
+      end
+
+    case 'END_HEADER'
+      break;
+  end
+end
+
+
+
+% ply
+% format ascii 1.0           { ascii/binary, format version number }
+% comment made by anonymous  { comments keyword specified, like all lines }
+% comment this file is a cube
+% element vertex 8           { define "vertex" element, 8 of them in file }
+% property float32 x         { vertex contains float "x" coordinate }
+% property float32 y         { y coordinate is also a vertex property }
+% property float32 z         { z coordinate, too }
+% element face 6             { there are 6 "face" elements in the file }
+% property list uint8 int32 vertex_index { "vertex_indices" is a list of ints }
+% end_header                 { delimits the end of the header }
+% 0 0 0                      { start of vertex list }
+% 0 0 1
+% 0 1 1
+% 0 1 0
+% 1 0 0
+% 1 0 1
+% 1 1 1
+% 1 1 0
+% 4 0 1 2 3                  { start of face list }
+% 4 7 6 5 4
+% 4 0 4 5 1
+% 4 1 5 6 2
+% 4 2 6 7 3
+% 4 3 7 4 0
+
+if strcmp(ply.filetype,'ASCII')
+  disp('Reading ASCII PLY file');
+  for element_ndx=1:length(ply.elements)
+    for item_ndx=1:ply.elements{element_ndx}.quantity
+      l=fgetl(fid);
+      values=strread(l,'%f');
+      for property_ndx=1:length(ply.elements{element_ndx}.property)
+        ply.elements{element_ndx}.property{property_ndx}.dataset(end+1)=...
+          values(property_ndx);
+      end
+    end
+  end
+else
+  disp('Reading binary PLY file')
+
+end
+fclose(fid);
+
diff --git a/6_rendering/plywrite.m b/6_rendering/plywrite.m
new file mode 100755
index 0000000000000000000000000000000000000000..9f01bcebb79459c1b009d75c345036181956c3a0
--- /dev/null
+++ b/6_rendering/plywrite.m
@@ -0,0 +1,63 @@
+function plywrite(pv,filename,isascii)
+% PLYWRITE.M A simple PLY (Stanford polygon) file writer (pv is the form of
+% output from isosurface)
+% Greg Johnson, August 2002 (November 2006)
+%
+%pv.faces=pv.faces(1:100:end,:);
+  
+nvertices=size(pv.vertices,1);
+nfaces=size(pv.faces,1);
+
+verticesperface=size(pv.faces,2);
+
+fid=fopen(filename,'w');
+fprintf(fid,'ply\n');
+if isascii
+  fprintf(fid,'format ascii 1.0\n');
+else
+  fprintf(fid,'format binary_little_endian\n');
+end
+fprintf(fid,'comment made by matlab\n');
+fprintf(fid,'element vertex %d\n',nvertices);
+fprintf(fid,'property float x\n');
+fprintf(fid,'property float y\n');
+fprintf(fid,'property float z\n');
+fprintf(fid,'element face %d\n',nfaces);
+fprintf(fid,'property list uint32 uint32 vertex_index\n');
+fprintf(fid,'end_header\n');
+
+if isascii % ascii format file
+  disp('ascii')
+  for n=1:nvertices
+    fprintf(fid,'%3.3f %3.3f %3.3f\n',pv.vertices(n,:));
+  end
+  for n=1:nfaces
+    fprintf(fid,'%d %d %d %d\n',[size(pv.vertices,2) pv.faces(n,:)-1]);
+  end
+else  % binary format file
+  disp('binary')
+  for n=1:nvertices
+    fwrite(fid,pv.vertices(n,:),'float32');
+  end
+  for n=1:nfaces
+    fwrite(fid,[size(pv.vertices,2) pv.faces(n,:)-1],'uint32');
+  end
+end
+
+
+
+% 0 0 0                      { start of vertex list }
+% 0 0 1
+% 0 1 1
+% 0 1 0
+% 1 0 0
+% 1 0 1
+% 1 1 1
+% 1 1 0
+% 4 0 1 2 3                  { start of face list }
+% 4 7 6 5 4
+% 4 0 4 5 1
+% 4 1 5 6 2
+% 4 2 6 7 3
+% 4 3 7 4 0
+fclose(fid);
diff --git a/6_rendering/plywrite_broken.m b/6_rendering/plywrite_broken.m
new file mode 100755
index 0000000000000000000000000000000000000000..d08d7f7da4649e421111d10abe693095facdb2a9
--- /dev/null
+++ b/6_rendering/plywrite_broken.m
@@ -0,0 +1,52 @@
+function objwrite(pv,filename,isascii)
+% OBJWRITE.M A simple OBJ (Alias Wavefront) file writer (pv is the form of
+% output from isosurface)
+% Greg Johnson, August 2002 (November 2006)
+%
+%pv.faces=pv.faces(1:100:end,:);
+
+nvertices=size(pv.vertices,1);
+nfaces=size(pv.faces,1);
+
+verticesperface=size(pv.faces,2);
+
+fid=fopen(filename,'w');
+fprintf(fid,'comment made by matlab\n');
+fprintf(fid,'element vertex %d\n',nvertices);
+fprintf(fid,'property float x\n');
+fprintf(fid,'property float y\n');
+fprintf(fid,'property float z\n');
+fprintf(fid,'element face %d\n',nfaces);
+fprintf(fid,'property list uint32 uint32 vertex_index\n');
+fprintf(fid,'end_header\n');
+
+
+for n=1:nvertices
+  fprintf(fid,'v %3.3f %3.3f %3.3f\n',pv.vertices(n,:));
+end
+
+fprintf(fid,'g foo\n');
+
+for n=1:nfaces
+  fprintf(fid,'f %d %d %d\n',pv.faces(n,:)-1);
+end
+
+fprintf(fid,'g\n');
+
+
+
+% 0 0 0                      { start of vertex list }
+% 0 0 1
+% 0 1 1
+% 0 1 0
+% 1 0 0
+% 1 0 1
+% 1 1 1
+% 1 1 0
+% 4 0 1 2 3                  { start of face list }
+% 4 7 6 5 4
+% 4 0 4 5 1
+% 4 1 5 6 2
+% 4 2 6 7 3
+% 4 3 7 4 0
+fclose(fid);
diff --git a/6_rendering/stlread.m b/6_rendering/stlread.m
new file mode 100755
index 0000000000000000000000000000000000000000..fca22d1fc985a1d3c052cb71c043842abad8f5fe
--- /dev/null
+++ b/6_rendering/stlread.m
@@ -0,0 +1,210 @@
+function stl=stlread(varargin)
+% STLREAD.M A simple STL (stereolithography) file reader
+% Greg Johnson, August 2002
+% greg.johnson@ieee.org
+%
+% Usage: stl=stlread            You will be asked to pick an STL file
+%        stl=stlread(filename)  The file specified will be used
+% The returned structure, stl, contains the name/comment (as taken from the
+% file header) along with three vertex lists.  These can be visualised
+% with:  
+%  
+%   hp=patch(stl.verticesX,stl.verticesY,stl.verticesZ,zeros(size(stl.verticesX)));
+% and the following, for additional coolness factor:
+%   axis image;axis vis3d; axis off
+%   cameratoolbar('setmode','orbit')
+%   camorbit(20,20)
+%   set(gcf,'color',[0 0 0])
+%   set(hp,'facecolor',[1 0 0])
+%   set(hp,'edgecolor',[0 0 1])
+%
+% and yes, stlread does automagically read both the ASCII and binary
+% variants of the file format.
+
+debug=0;
+
+if nargin==0
+  [filename,pathname]=uigetfile('*.stl','Pick an STL file');
+  filename=fullfile(pathname,filename);
+else
+  filename=varargin{1};
+end
+  
+%tic
+% test for ASCII or BINARYness
+
+fid=fopen(filename,'rb');
+tmp=fread(fid,80,'char');
+tmp_numfacets=fread(fid,1,'uint32');
+tmp_size=50*tmp_numfacets;
+tmp_current=ftell(fid);
+fseek(fid,0,'eof');
+tmp_end=ftell(fid);
+fclose(fid);
+
+if (tmp_end~=tmp_current+tmp_size)
+  % ASCII STL FILE
+  disp('Reading ASCII STL file');
+  fid=fopen(filename,'rt');
+  filelocation='started';
+  
+  stl.name=[];
+  stl.verticesX=[];
+  stl.verticesY=[];
+  stl.verticesZ=[];
+  
+  while (~feof(fid))
+    
+    l=upper(fgetl(fid));
+    [t,r]=strtok(l);
+    switch t
+      case 'SOLID'
+        if debug disp('SOLID'),end
+        if strcmp(filelocation,'started')
+          filelocation='solid';
+          stl.name=r;
+        else
+          disp('Somethings wrong...')
+          return
+        end
+        
+        
+      case 'FACET'
+        if debug disp('FACET'),end
+        if strcmp(filelocation,'solid')
+          filelocation='facet';
+          %disp('Not using STL Normal values')
+          currentfacetX=[];
+          currentfacetY=[];
+          currentfacetZ=[];
+        else
+          disp('Something wrong...')
+          return
+        end
+        
+      case 'OUTER'
+        if debug disp('OUTER'),end
+        if strcmp(filelocation,'facet')
+          filelocation='loop';
+          
+        else
+          disp('Something wrong...')
+          return
+        end
+        
+      case 'VERTEX'
+        if debug disp('VERTEX'),end
+        if strcmp(filelocation,'loop')
+          filelocation='loop';
+          [tmpX,r]=strtok(r);
+          [tmpY,r]=strtok(r);
+          [tmpZ,r]=strtok(r);
+          
+          currentfacetX=cat(1,currentfacetX,str2num(tmpX));
+          currentfacetY=cat(1,currentfacetY,str2num(tmpY));
+          currentfacetZ=cat(1,currentfacetZ,str2num(tmpZ));
+          
+        else
+          disp('Something wrong...')
+          return
+        end
+        
+      case 'ENDLOOP'
+        if debug disp('ENDLOOP'),end
+        filelocation='facet';
+      case 'ENDFACET'
+        if debug disp('ENDFACET'),end
+        filelocation='solid';
+        stl.verticesX=cat(2,stl.verticesX,currentfacetX);
+        stl.verticesY=cat(2,stl.verticesY,currentfacetY);
+        stl.verticesZ=cat(2,stl.verticesZ,currentfacetZ);
+        
+        
+      case 'ENDSOLID'
+        if debug disp('ENDSOLID'),end
+        filelocation='done';
+    end
+    
+    
+    
+  end
+  
+  fclose(fid);
+  
+  
+ 
+else
+  % BINARY STL FILE
+  fid=fopen(filename,'rb');
+  disp('Reading binary STL file');
+  stl.name=[];
+  
+  
+  stl.name=char(fread(fid,80,'char')');
+  
+  num_facets=fread(fid,1,'uint32');
+  stl.verticesX=zeros(3,num_facets);
+  stl.verticesY=zeros(3,num_facets);
+  stl.verticesZ=zeros(3,num_facets);
+  currentfacetX=zeros(3,1);
+  currentfacetY=zeros(3,1);
+  currentfacetZ=zeros(3,1);
+  
+  data=fread(fid,12*num_facets,'12*float',2);
+  for ndx=1:num_facets
+    data_facet=data(((ndx-1)*12)+1:((ndx-1)*12)+12);
+    normals=data_facet([1 2 3]);
+    
+  
+    
+    for vertex=1:3
+      currentfacetX(vertex)=data_facet((vertex*3)+1);
+      currentfacetY(vertex)=data_facet((vertex*3)+2);
+      currentfacetZ(vertex)=data_facet((vertex*3)+3);
+    end
+    
+    
+    stl.verticesX(:,ndx)=currentfacetX';
+    stl.verticesY(:,ndx)=currentfacetY';
+    stl.verticesZ(:,ndx)=currentfacetZ';
+  end
+  
+  fclose(fid);
+  
+end
+
+disp(sprintf('Number of facets: %d',size(stl.verticesX,2)))
+%toc;
+
+
+% An example of a simple ASCII STL file:
+% SOLID TRI 
+%    FACET NORMAL 0.0 0.0 -1.0 
+%      OUTER LOOP 
+%        VERTEX -1.5 -1.5 1.4 
+%        VERTEX 0.0 1.7 1.4 
+%        VERTEX 1.5 -1.5 1.4 
+%      ENDLOOP 
+%    ENDFACET 
+%    FACET NORMAL 0.0 0.88148 0.472221 
+%      OUTER LOOP 
+%        VERTEX -1.5 -1.5 1.4 
+%        VERTEX 1.5 -1.5 1.4 
+%        VERTEX 0.0 0.0 -1.4 
+%      ENDLOOP 
+%    ENDFACET 
+%    FACET NORMAL -0.876814 -0.411007 0.24954 
+%      OUTER LOOP 
+%        VERTEX 1.5 -1.5 1.4 
+%        VERTEX 0.0 1.7 1.4 
+%        VERTEX 0.0 0.0 -1.4 
+%      ENDLOOP 
+%    ENDFACET 
+%    FACET NORMAL 0.876814 -0.411007 0.24954 
+%      OUTER LOOP 
+%        VERTEX 0.0 1.7 1.4 
+%        VERTEX -1.5 -1.5 1.4 
+%        VERTEX 0.0 0.0 -1.4 
+%      ENDLOOP 
+%    ENDFACET 
+% ENDSOLID TRI 
\ No newline at end of file
diff --git a/6_rendering/stlwrite.m b/6_rendering/stlwrite.m
new file mode 100755
index 0000000000000000000000000000000000000000..83d44f2a1fd32f9d2b82a8f828aa7d0728606dad
--- /dev/null
+++ b/6_rendering/stlwrite.m
@@ -0,0 +1,55 @@
+function stlwrite(stl,filename,varargin)
+% STLWRITE.M A simple STL (stereolithography) file writer
+% Greg Johnson, August 2002
+% greg.johnson@ieee.org
+%
+% Usage: stlwrite(stl,filename,{'ascii'/'binary'}
+% where stl is the variable containing the mesh
+%       filename is the output filename
+% The file will be a binary STL unless the optional third argument is
+% 'ascii'
+%
+% The stl variable has the following components:
+% stl.verticesX (Y,Z) - the locations of the vertices - three per triangle
+%
+% See also: stlread
+
+if nargin==2
+  filetype='binary';
+elseif nargin==3
+  if strcmp(varargin{1},'ascii')
+    filetype='ascii';
+  else
+    filetype='binary';
+  end
+else
+  disp('Not quite sure what you''re asking...');
+  return
+end
+
+if strcmp(filetype,'ascii')
+  disp('Writing ASCII STL file');  
+  fid=fopen(filename,'wt');
+  fprintf(fid,'SOLID %s\n',stl.name);
+  for ndx_facet=1:length(stl.verticesX)
+    mat=[diff(stl.verticesX(:,ndx_facet)) diff(stl.verticesY(:,ndx_facet)) diff(stl.verticesZ(:,ndx_facet))];
+    normal=[det(mat(:,[2 3])) det(mat(:,[3 1])) det(mat(:,[1 2]))];
+    normal=normal/(norm(normal)+eps);
+    fprintf(fid,'  FACET NORMAL %1.1f %1.1f %1.1f\n',normal(1),normal(2),normal(3));
+    fprintf(fid,'    OUTER LOOP\n');
+    for ndx_vertex=1:3
+      fprintf(fid,'      VERTEX %1.1f %1.1f %1.1f\n',...
+        stl.verticesX(ndx_vertex,ndx_facet),...
+        stl.verticesY(ndx_vertex,ndx_facet),...
+        stl.verticesZ(ndx_vertex,ndx_facet));
+    end
+    fprintf(fid,'    ENDLOOP\n');
+    fprintf(fid,'  ENDFACET\n');
+  end
+  fprintf(fid,'ENDSOLID %s\n',stl.name);
+  fclose(fid);
+else
+  disp('Writing binary STL file');
+  disp('NOT YET!');
+end
+
diff --git a/6_rendering/stlwrite2.m b/6_rendering/stlwrite2.m
new file mode 100755
index 0000000000000000000000000000000000000000..754c2f147eb7cd18394df0856d45832618a2cecf
--- /dev/null
+++ b/6_rendering/stlwrite2.m
@@ -0,0 +1,55 @@
+function stlwrite(pv,filename,varargin)
+% STLWRITE.M A simple STL (stereolithography) file writer
+% Greg Johnson, August 2002
+% greg.johnson@ieee.org
+%
+% Usage: stlwrite(stl,filename,{'ascii'/'binary'}
+% where stl is the variable containing the mesh
+%       filename is the output filename
+% The file will be a binary STL unless the optional third argument is
+% 'ascii'
+%
+% The stl variable has the following components:
+% stl.verticesX (Y,Z) - the locations of the vertices - three per triangle
+%
+% See also: stlread
+
+if nargin==2
+  filetype='binary';
+elseif nargin==3
+  if strcmp(varargin{1},'ascii')
+    filetype='ascii';
+  else
+    filetype='binary';
+  end
+else
+  disp('Not quite sure what you''re asking...');
+  return
+end
+
+if strcmp(filetype,'ascii')
+  disp('Writing ASCII STL file');  
+  fid=fopen(filename,'wt');
+  fprintf(fid,'solid matlab\n');
+  for ndx_facet=1:size(pv.faces,1)
+    points=pv.vertices(pv.faces(ndx_facet,:),:);
+    normal = cross([points(2,:)-points(1,:)],[points(3,:)-points(1,:)]);
+    normal=normal./norm(normal);
+    fprintf(fid,'  facet normal %f %f %f\n',-normal);
+    fprintf(fid,'    outer loop\n');
+    for ndx_vertex=1:3
+      v1=pv.vertices(pv.faces(ndx_facet,ndx_vertex),1)/10;
+      v2=pv.vertices(pv.faces(ndx_facet,ndx_vertex),2)/10;
+      v3=pv.vertices(pv.faces(ndx_facet,ndx_vertex),3)/10;
+      fprintf(fid,'      vertex %1.2f %1.2f %1.2f\n',v1,v2,v3);
+    end
+    fprintf(fid,'    endloop\n');
+    fprintf(fid,'  endfacet\n');
+  end
+  fprintf(fid,'endsolid %s\n','MATLAB');
+  fclose(fid);
+else
+  disp('Writing binary STL file');
+  disp('NOT YET!');
+end
+
diff --git a/6_rendering/wrl_write_w_color_vertex.m b/6_rendering/wrl_write_w_color_vertex.m
new file mode 100755
index 0000000000000000000000000000000000000000..8cebd13db4d33178c67bc826dae551b3e4b85dfd
--- /dev/null
+++ b/6_rendering/wrl_write_w_color_vertex.m
@@ -0,0 +1,61 @@
+function wrl_write_w_color_vertex(fv, name)
+%fv is face vertex structure with
+% fv.vertices specified
+% fv.faces specified
+% fv.FaceVertexCData specified
+% name is the file name (string), either name or name.wrl
+lnm = length(name);
+if name((lnm-3):(lnm-1))=='wrl'
+  label = name(1:lnm-3);
+else
+  label = name;
+  name = sprintf('%s.wrl', name);
+end
+fid = fopen(name,'w');
+fprintf(fid,'#VRML V2.0 utf8 \n');
+fprintf(fid,'Viewpoint { description "Initial view" position 0.0 0.0 9.0} \n');
+fprintf(fid,'NavigationInfo { type "EXAMINE" }\n');
+fprintf(fid,'Transform {\n');
+fprintf(fid,' translation -1.5 0.0 0.0 \n');
+fprintf(fid,' children Shape {\n');
+fprintf(fid,' appearance DEF A Appearance { material Material { } } \n');
+fprintf(fid,' geometry DEF IFS IndexedFaceSet {\n');
+fprintf(fid,' coord Coordinate { \n');
+fprintf(fid,' point [ \n');
+
+%fprintf ... vertices 1 2 3, next line
+for k = 1:length(fv.vertices)
+  fprintf(fid,' %0.4f %0.4f %0.4f,\n',fv.vertices(k,1),fv.vertices(k,2),fv.vertices(k,3));
+end
+fprintf(fid,'] \n');
+fprintf(fid,'} \n');
+fprintf(fid,'coordIndex [ \n');
+%fprintf ... vert 1, 2, 3, -1, next line, if you need more then add
+%another vertex 1, 2, 3 ,4, 5, etc, -1
+for k = 1:length(fv.faces)
+  fprintf(fid,' %0.0f, %0.0f, %0.0f, -1,\n',fv.faces(k,1)-1,fv.faces(k,2)-1,fv.faces(k,3)-1);
+end
+fprintf(fid,'] \n');
+fprintf(fid,' colorPerVertex TRUE \n');
+fprintf(fid,' color Color {\n');
+fprintf(fid,' color [ \n');
+%fprintf ... color R G B, next line
+if size(fv.facevertexcdata,2)==3
+  disp('Colour')
+  for k = 1:length(fv.facevertexcdata)
+    fprintf(fid,' %0.4f %0.4f %0.4f,\n',fv.facevertexcdata(k,1),fv.facevertexcdata(k,2),fv.facevertexcdata(k,3));
+  end
+else
+  disp('grayscale')
+  for k = 1:length(fv.facevertexcdata)
+    fprintf(fid,' %0.4f %0.4f %0.4f,\n',fv.facevertexcdata(k,1),fv.facevertexcdata(k,1),fv.facevertexcdata(k,1));
+  end
+end
+fprintf(fid,'] \n');
+fprintf(fid,'} \n');
+fprintf(fid,'} \n');
+fprintf(fid,'} \n');
+fprintf(fid,'} \n');
+fclose(fid);
+
+
diff --git a/FigureManagement/Contents.m b/FigureManagement/Contents.m
new file mode 100755
index 0000000000000000000000000000000000000000..24f7674e7e8e52d4daa42e1d097608b27594a0fd
--- /dev/null
+++ b/FigureManagement/Contents.m
@@ -0,0 +1,9 @@
+% WINDOWS
+%
+% Files
+%   getmondim   - y = getmondim(monitornumber)  GET MONitor DIMensions.
+%   maxfig      - maxfig(fig,monitor,mode)  MAXimize a FIGure to fill the screen.
+%   newfig      - fighandle = newfig(numfigs,figname,monitor,aspect)  create NEW FIGures.
+%   screenxyabs - newxy = screenxyabs(monitor,xy)  SCREEN X-Y ABSolute coordinates.
+%   screenxymon - newxy = screenxymon(monitor,xy)  SCREEN X-Y MONitor coordinates.
+%   tilefig     - fighandle = tilefig(figs,figname,monitor,layout)  TILE 1 or more FIGures.
diff --git a/FigureManagement/Help/Contents.html b/FigureManagement/Help/Contents.html
new file mode 100755
index 0000000000000000000000000000000000000000..4a183b7ead34595b9fb093897c1c7a18321c4986
--- /dev/null
+++ b/FigureManagement/Help/Contents.html
@@ -0,0 +1,96 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>Contents</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="Contents"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content"><pre class="codeinput"><span class="comment">% FIGURE MANAGMENT</span>
+<span class="comment">%</span>
+<span class="comment">% Files</span>
+<span class="comment">%   dockfig   - fighandle=dockfig(figs)      DOCK one or more FIGures.</span>
+<span class="comment">%   getfigdim - [figsize,figborders]=getfigdim(figh)  GET FIGure DIMensions.</span>
+<span class="comment">%   newdfig   - fighandle = newdfig(numfigs,figname)  create NEW Docked FIGures.</span>
+<span class="comment">%   vf        - fighandle=vf(figs)      View one or more Figures.</span>
+</pre><p class="footer"><br>
+            Published with MATLAB&reg; 7.2<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+% FIGURE MANAGMENT
+%
+% Files
+%   dockfig   - fighandle=dockfig(figs)      DOCK one or more FIGures.
+%   getfigdim - [figsize,figborders]=getfigdim(figh)  GET FIGure DIMensions.
+%   newdfig   - fighandle = newdfig(numfigs,figname)  create NEW Docked FIGures.
+%   vf        - fighandle=vf(figs)      View one or more Figures.
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
\ No newline at end of file
diff --git a/FigureManagement/Help/Figure Tiling.gif b/FigureManagement/Help/Figure Tiling.gif
new file mode 100755
index 0000000000000000000000000000000000000000..9640b8fc71d7c4f80a73db07628d486254e7da23
Binary files /dev/null and b/FigureManagement/Help/Figure Tiling.gif differ
diff --git a/FigureManagement/Help/Platform Independent/Contents.html b/FigureManagement/Help/Platform Independent/Contents.html
new file mode 100755
index 0000000000000000000000000000000000000000..4b7d32b65eba53fd1d389e254fc8e460724eb1ec
--- /dev/null
+++ b/FigureManagement/Help/Platform Independent/Contents.html	
@@ -0,0 +1,94 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>Contents</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="Contents"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content"><pre class="codeinput"><span class="comment">% PLATFORM INDEPENDENT</span>
+<span class="comment">%</span>
+<span class="comment">% Files</span>
+<span class="comment">%   maxfig  - maxfig(fig,extend,mode)  MAXimize a FIGure to fill the screen.</span>
+<span class="comment">%   newfig  - fighandle = newfig(numfigs,figname,extend,aspect)  create NEW FIGures.</span>
+<span class="comment">%   tilefig - fighandle = tilefig(figs,figname,extend,layout)  TILE 1 or more FIGures.</span>
+</pre><p class="footer"><br>
+            Published with MATLAB&reg; 7.2<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+% PLATFORM INDEPENDENT
+%
+% Files
+%   maxfig  - maxfig(fig,extend,mode)  MAXimize a FIGure to fill the screen.
+%   newfig  - fighandle = newfig(numfigs,figname,extend,aspect)  create NEW FIGures.
+%   tilefig - fighandle = tilefig(figs,figname,extend,layout)  TILE 1 or more FIGures.
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
\ No newline at end of file
diff --git a/FigureManagement/Help/Platform Independent/maxfig.html b/FigureManagement/Help/Platform Independent/maxfig.html
new file mode 100755
index 0000000000000000000000000000000000000000..110f6cefdf0f8bb193c3bcfcb6272b11923a329b
--- /dev/null
+++ b/FigureManagement/Help/Platform Independent/maxfig.html	
@@ -0,0 +1,165 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>maxfig</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_maxfig"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>maxfig</h1>
+         <introduction>
+            <p>MAXimize a FIGure to fill the screen.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>maxfig(fig,extend,mode)</pre><h2>Description<a name="2"></a></h2>
+         <p>Maximize a figure to fill the screen. Subsequent calls will restore the maximized figure to its previous state.</p>
+			<p>"fig" (first numeric input) is the handle of the figure to maximize
+			(default is current figure).</p>
+			<p>"extend" (second numeric input) is a complex number specifying how
+			figures are to be created on the extended desktop.<br>
+&nbsp;&nbsp;&nbsp;       Examples: +1/-1 is one screen to the right/left,
+<br>
+&nbsp;&nbsp;&nbsp;                 0 is the primary screen (default),
+<br>
+&nbsp;&nbsp;&nbsp;                 +i is one screen up,
+<br>
+&nbsp;&nbsp;&nbsp;                 -1-0.5i is half a screen down and to the left, etc...</p>
+			<p>"mode" is a string specifying whether to fully maximize the figure       (borders extend beyond the monitor, menu and tool bars are removed)
+			or set to normal mode with borders, menu & toolbars displayed.
+			Value for maximize mode is any of {m,max,y,yes,t,true}(default).
+			Value for normal mode is any of {n,normal,no,f,false}.</p>
+			<p>Will work with docked figures. Inspired by MAXFIGSIZE (ID 3036) by Duane Hanselman. Extended monitors must have
+                  the same resolution as the primary monitor. The figure properties, TAG and USERDATA, are used to keep track of the maximized
+                  figure. </p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>maxfig<br>
+			maxfig(3,1+i)<br>
+			maxfig([],-1)<br>
+			maxfig('normal&#39;)
+         </p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 08/23/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a></li>
+            </ul>
+         </div>
+         <p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% maxfig
+% maxfig(fig,extend,mode)  MAXimize a FIGure to fill the screen.
+%% Syntax
+%  maxfig(varargin)
+%% Description
+% Subsequent calls will restore the maximized figure to its previous state.
+%% Examples:
+% maxfig, maxfig(3,1+i), maxfig([],-1), maxfig('normal')
+% "fig" (first numeric input) is the handle of the figure to maximize
+% (default is current figure).
+% "extend" (second numeric input) is a complex number specifying how
+% figures are to be created on the extended desktop.
+%% Examples: +1/-1 is one screen to the right/left,
+% 0 is the primary screen (default),
+% +i is one screen up,
+% -1-0.5i is half a screen down and to the left, etc...
+% "mode" is a string specifying whether to fully maximize the figure
+% (borders extend beyond the monitor, menu and tool bars are removed)
+% or set to normal mode with borders, menu & toolbars displayed.
+% Value for maximize mode is any of {m,max,y,yes,t,true}(default).
+% Value for normal mode is any of {n,normal,no,f,false}.
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 08/23/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.   email: mhrovat@email.com
+% More notes:
+% Will work with docked figures.
+% Inspired by MAXFIGSIZE (ID 3036) by Duane Hanselman.
+% Extended monitors must have the same resolution as the primary monitor.
+% The figure properties, TAG and USERDATA, are used to keep track of the
+% maximized figure.
+%%
+% REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH- Key Constants REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH-
+% To allow for user or OS borders set the appropriate value in pixels.
+% For example one might want to set the bottomborder for the windows
+% taskbar (try a value of 40).
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/Platform Independent/newfig.html b/FigureManagement/Help/Platform Independent/newfig.html
new file mode 100755
index 0000000000000000000000000000000000000000..b30a10d7a5c9fec5483aa9a4f75de8937dd31443
--- /dev/null
+++ b/FigureManagement/Help/Platform Independent/newfig.html	
@@ -0,0 +1,194 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>newfig</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_newfig"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>newfig</h1>
+         <introduction>
+            <p>create NEW FIGures.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>fighandle = newfig(numfigs,figname,extend,aspect)</pre><h2>Description<a name="2"></a></h2>
+         <p>Tiles the screen with multiple figures starting at the top left hand corner. If the specified layout only creates one row,
+            then the figure height is chosen to maintain the desired aspect ratio.
+         </p>
+			<p>"fighandle" output is an
+            array of handle numbers for the figures.</p>
+			<p>"numfigs" (first numeric argument) determines the number of figures to create. If
+            numfigs is a vector (rows,columns) then the layout is also specified. 
+         </p>
+			<p>"figname" (any argument position) is an optional string
+            for the figures' name. 
+         </p>
+			<p>"extend" (second numeric argument) is a complex number indicating how figures are to be created on
+            multiple monitors, (extended desktop). <br>
+&nbsp;&nbsp;&nbsp;       Examples: +1/-1 is one screen to the right/left,
+<br>
+&nbsp;&nbsp;&nbsp;                 0 is the primary screen (default),
+<br>
+&nbsp;&nbsp;&nbsp;                 +i is one screen up,
+<br>
+&nbsp;&nbsp;&nbsp;                 -1-0.5i is half a screen down and to the left, etc...</p>
+			<p>&quot;aspect&quot; (third numeric argument) is the desired aspect ratio 
+			(minimum horizontal/vertical size of the figure) used for 
+			determining the layout, it is ignored if the layout is specified by numfigs.
+         </p>
+         <p>Extended monitors must have the same resolution as the primary monitor. The size and layout of the figures is
+                  determined by the aspect ratio and the number of figure columns. For a large number of figures, the menubar 
+			and toolbar are removed to increase figure space. The figures are numbered within this group of figures and not by their figure handles. The figures are accessible by
+            their handles. Thus "figure(fighandle(4))" will make the 4th figure from this group of figures the current figure. To delete
+            the entire group of figures use "close(fighandle)".</p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>newfig(3,&#39;Title&#39;,1+i,2)<br>
+			newfig('Title&#39;)<br>
+			newfig <br>
+			figh=newfig(6); <br>
+			figh=newfig(4,i,1.5); <br>
+			newfig([1,5],-1); 
+         </p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a>
+               </li>
+            </ul>
+         </div>
+			<p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% newfig
+% fighandle = newfig(numfigs,figname,extend,aspect)  create NEW FIGures.
+%% Syntax
+%  fighandle=newfig(varargin)
+%% Description
+% Tiles the screen with multiple figures starting at the top left hand corner.
+% If the specified layout only creates one row, then the figure height is
+% chosen to maintain the desired aspect ratio.
+%% Examples:
+% newfig(3,'Title',1+i,2), newfig('Title'), newfig
+% figh=newfig(6); figh=newfig(4,i,1.5); newfig([1,5],-1);
+% "fighandle" is an array of handle numbers for the figures.
+% "numfigs" (first numeric argument) determines the number of figures to create.
+% If numfigs is a vector (rows,columns) then the layout is also specified.
+% "figname" (any argument position) is an optional string for the figures' name.
+% "extend" (second numeric argument) is a complex number indicating how
+% figures are to be created on multiple monitors, (extended desktop).
+%% Examples: +1/-1 is one screen to the right/left,
+% 0 is the primary screen (default),
+% +i is one screen up,
+% -1-0.5i is half a screen down and to the left, etc...
+% "aspect" (third numeric argument) is the desired aspect ratio (minimum
+% horizontal/vertical size of the figure) used for determining the
+% layout, it is ignored if the layout is specified by numfigs.
+%%
+% NOTES:
+% The figures are numbered within this group of figures and not by their
+% figure handles.
+% The figures are accessible by their handles. Thus "figure(fighandle(4))" will
+% make the 4th figure from this group of figures the current figure.
+% To delete the entire group of figures use "close(fighandle)".
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+% More notes:
+% Extended monitors must have the same resolution as the primary monitor.
+% The size and layout of the figures is determined by the aspect ratio and
+% the number of figure columns.
+% For a large number of figures, the menubar and toolbar are removed to
+% increase figure space.
+% Default properties for this particular group of figures may be coded into
+% the code below (near bottom). The following properties are currently set.
+% 'Units','pixels', ...
+% 'Colormap',gray(256),...
+% 'NumberTitle','off',...
+% 'MenuBar',menbar,...       (depends on number of figures)
+% 'ToolBar',tbar             (depends on number of figures)
+%%
+% REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH- Key Constants REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH-
+% To allow for user or OS borders set the appropriate value in pixels.
+% For example one might want to set the bottomborder for the taskbar.
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/Platform Independent/tilefig.html b/FigureManagement/Help/Platform Independent/tilefig.html
new file mode 100755
index 0000000000000000000000000000000000000000..834fa0d19d01654470bc72489f395d5df34101c5
--- /dev/null
+++ b/FigureManagement/Help/Platform Independent/tilefig.html	
@@ -0,0 +1,205 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html
+ xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+  <title>tilefig</title>
+  <meta name="generator" content="MATLAB 7.2">
+  <meta name="date" content="2006-10-10">
+  <meta name="m-file" content="script_tilefig">
+  <style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style>
+</head>
+<body>
+<div class="content">
+<h1>tilefig</h1>
+<introduction> </introduction>
+<p>TILE one or more FIGures.</p>
+<h2>Contents</h2>
+<div>
+<ul>
+  <li><a href="#1">Syntax</a></li>
+  <li><a href="#2">Description</a></li>
+  <li><a href="#3">Examples:</a></li>
+</ul>
+</div>
+<h2>Syntax<a name="1"></a></h2>
+<pre>fighandle = tilefig(figs,figname,extend,layout) </pre>
+<h2>Description<a name="2"></a></h2>
+<p>Tiles the screen for existing figures starting at the top left hand
+corner.</p>
+<p>"fighandle" is an output array of handle numbers for the figures.</p>
+<p>"figs" (first numeric input) is a vector of handles of the figures
+to be tiled. Default value is 0 or empty which tiles all open figures. </p>
+<p>"figname" (any input position) is an optional string for each
+figure's name. If not specified then figure names are retained, to
+erase names use the blank string ' '.</p>
+<p>"extend" (second numeric input) is a complex number indicating how
+figures are to be created on multiple monitors, (extended desktop). <br>
+&nbsp;&nbsp;&nbsp; Examples: +1/-1 is one screen to the right/left,
+<br>
+&nbsp;&nbsp;&nbsp; 0 is the primary screen (default),
+<br>
+&nbsp;&nbsp;&nbsp; +i is one screen up,
+<br>
+&nbsp;&nbsp;&nbsp; -1-0.5i is half a screen down and to the left, etc...</p>
+<p>"layout" (third numeric input) is a vector (rows,columns) specifying
+the screen layout or a single number specifying the aspect ratio. If
+not specified then the optimal layout will be determined. If the
+specified layout only creates one row, then the figure height is chosen
+to maintain the default aspect ratio. The aspect ratio is the minimum
+horizontal/vertical figure size. </p>
+<p>Figures are tiled in the order they are specified in "figs". The
+figures are numbered within this group of figures and not by their
+figure handle. The figures are accessible by their handles. Thus
+"figure(fighandle(4))" will make the 4th figure from this group of
+figures the current figure. To delete the entire group of figures use
+"close(fighandle)".</p>
+<p>Will work with docked figures, will ignore modal figures. Extended
+monitors must have the same resolution as the primary monitor. The size
+and layout of the figures is determined by the aspect ratio and the
+number of figure columns. For a large number of figures, the menubar
+and toolbar are removed to increase figure space. Inspired by
+"Tilefigs" by Charles Plum.</p>
+<h2>Examples:<a name="3"></a></h2>
+<p>tilefig <br>
+tilefig([1,2,3],'Title',1+i)<br>
+tilefig('Title')<br>
+figh=tilefig([2:12]);<br>
+figh=tilefig([3,4],i);<br>
+tilefig(5,-1,[2,3])</p>
+<div>
+<ul>
+  <li><b>Copyright</b> 2006 Mirtech, Inc. created 09/18/2006 by Mirko
+Hrovat on Matlab Ver. 7.2 <br>
+email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a> </li>
+</ul>
+</div>
+<p class="footer">Published with wg_publish; V1.0<br>
+</p>
+</div>
+<!--
+##### SOURCE BEGIN #####
+%% tilefig
+% fighandle = tilefig(figs,figname,extend,layout)  TILE 1 or more FIGures.
+%% Syntax
+%  fighandle=tilefig(varargin)  
+%% Description
+% Tiles the screen for existing figures starting at the top left hand corner.
+%% Examples:
+% tilefig, tilefig([1,2,3],'Title',1+i), tilefig('Title'),
+% figh=tilefig([2:12]); figh=tilefig([3,4],i); tilefig(5,-1,[2,3])
+% "fighandle" is an output array of handle numbers for the figures.
+% "figs" (first numeric input) is a vector of handles of the figures to be tiled.
+% Default value is 0 which tiles all open figures.
+% "figname" (any argument position) is an optional string for each figure's name.
+% If not specified then figure names are retained, to erase names use ' '.
+% "extend" (second numeric input)is a complex number specifying how figures
+% are to be created on the extended desktop.
+%% Examples: +1/-1 is one screen to the right/left,
+% 0 is the primary screen (default),
+% +i is one screen up,
+% -1-0.5i is half a screen down and to the left, etc...
+% "layout" (third numeric input) is a vector (rows,columns) specifying the
+% screen layout or a single number specifying the aspect ratio.
+% If not specified then the optimal layout will be determined.
+% If the specified layout only creates one row, then the figure
+% height is chosen to maintain the default aspect ratio.
+% The aspect ratio is the minimum horizontal/vertical figure size.
+% NOTES:
+% Figures are tiled in the order they are specified in "figs".
+% The figures are numbered within this group of figures and not by their
+% figure handle.
+% The figures are accessible by their handles. Thus "figure(fighandle(4))"
+% will make the 4th figure from this group of figures the current figure.
+% To delete the entire group of figures use "close(fighandle)".
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+% Inspired by "Tilefigs" by Charles Plum
+% More notes:
+% Will work with docked figures, will ignore modal figures.
+% Extended monitors must have the same resolution as the primary monitor.
+% The size and layout of the figures is determined by the aspect ratio and
+% the number of figure columns.
+% For a large number of figures, the menubar and toolbar are removed to
+% increase figure space.
+% Default properties for this group of figures may be coded into the code
+% below. The following properties are currently set.
+% 'Units','pixels', ...
+% 'NumberTitle','off',...
+% 'MenuBar',menbar,...       (depends on number of figures)
+% 'ToolBar',tbar             (depends on number of figures)
+%%
+% REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH- Key Constants REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH-
+% To allow for user or OS borders set the appropriate value in pixels.
+% For example one might want to set the bottomborder for the taskbar.
+
+##### SOURCE END #####
+-->
+</body>
+</html>
diff --git a/FigureManagement/Help/Windows/Contents.html b/FigureManagement/Help/Windows/Contents.html
new file mode 100755
index 0000000000000000000000000000000000000000..4af5c0510e50098b8684eb7bdcd5ff222fd2cc15
--- /dev/null
+++ b/FigureManagement/Help/Windows/Contents.html
@@ -0,0 +1,100 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>Contents</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="Contents"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content"><pre class="codeinput"><span class="comment">% WINDOWS</span>
+<span class="comment">%</span>
+<span class="comment">% Files</span>
+<span class="comment">%   getmondim   - y = getmondim(monitornumber)  GET MONitor DIMensions.</span>
+<span class="comment">%   maxfig      - maxfig(fig,monitor,mode)  MAXimize a FIGure to fill the screen.</span>
+<span class="comment">%   newfig      - fighandle = newfig(numfigs,figname,monitor,aspect)  create NEW FIGures.</span>
+<span class="comment">%   screenxyabs - newxy = screenxyabs(monitor,xy)  SCREEN X-Y ABSolute coordinates.</span>
+<span class="comment">%   screenxymon - newxy = screenxymon(monitor,xy)  SCREEN X-Y MONitor coordinates.</span>
+<span class="comment">%   tilefig     - fighandle = tilefig(figs,figname,monitor,layout)  TILE 1 or more FIGures.</span>
+</pre><p class="footer"><br>
+            Published with MATLAB&reg; 7.2<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+% WINDOWS
+%
+% Files
+%   getmondim   - y = getmondim(monitornumber)  GET MONitor DIMensions.
+%   maxfig      - maxfig(fig,monitor,mode)  MAXimize a FIGure to fill the screen.
+%   newfig      - fighandle = newfig(numfigs,figname,monitor,aspect)  create NEW FIGures.
+%   screenxyabs - newxy = screenxyabs(monitor,xy)  SCREEN X-Y ABSolute coordinates.
+%   screenxymon - newxy = screenxymon(monitor,xy)  SCREEN X-Y MONitor coordinates.
+%   tilefig     - fighandle = tilefig(figs,figname,monitor,layout)  TILE 1 or more FIGures.
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
\ No newline at end of file
diff --git a/FigureManagement/Help/Windows/getmondim.html b/FigureManagement/Help/Windows/getmondim.html
new file mode 100755
index 0000000000000000000000000000000000000000..43c4adbf6e9226e5d251a9dd2bf63c3c30bee480
--- /dev/null
+++ b/FigureManagement/Help/Windows/getmondim.html
@@ -0,0 +1,152 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>getmondim</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_getmondim"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>getmondim</h1>
+         <introduction>
+            <p>GET MONitor DIMensions.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>y = getmondim(monitornumber)</pre><h2>Description<a name="2"></a></h2>
+         <p>"y" is the dimensions of the specified monitor represented as [xstart,ystart,width,height] where values are in pixels. (xstart,ystart)
+            are the absolute coordinates of the lower left corner. 
+         </p>
+			<p>"monitornumber" is a number associated with each monitor (Default=1).
+            Monitor numbering is defined as the row number of the corresponding monitor in the root property 'MonitorPositions'.
+         </p>
+			<p>The primary monitor is always numbered 1 and always starts at (1,1). 'MonitorPositions' returns coordinates corresponding
+                  to the upper left corner and the bottom right corner (Windows convention). Matlab 'Help' on this property is incorrect. GETMONDIM
+                  converts these coordinates to the Matlab convention where the lower left corner starts at (1,1). There is a 
+			feature with the root
+                  property 'ScreenSize'. If the primary monitor's resolution is adjusted after Matlab has started, then the size parameters
+                  of 'ScreenSize' are not adjusted while the origin is adjusted. GETMONDIM fixes this by using the 'ScreenSize' origin to
+                  correct for the discrepancy. Note that on restarting Matlab the 'ScreenSize' property changes to the correct values!
+         </p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>y=getmondim; <br>
+			y=getmondim(2);</p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 09/26/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a>
+               </li>
+            </ul>
+         </div>
+         <p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% getmondim
+% y = getmondim(monitornumber)  GET MONitor DIMensions.
+%% Syntax
+%  y=getmondim(mnum)
+%% Description
+% "y" is the dimensions of the specified monitor represented as
+% [xstart,ystart,width,height] where values are in pixels.
+% (xstart,ystart) are the absolute coordinates of the lower left corner.
+% "monitornumber" is a number associated with each monitor (Default=1).
+% Monitor numbering is defined as the row number of the corresponding
+% monitor in the root property 'MonitorPositions'.
+%% Examples:
+% y=getmondim; y=getmondim(2);
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 09/26/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+% Notes:
+% The primary monitor is always numbered 1 and always starts at (1,1).
+% 'MonitorPositions' returns coordinates corresponding to the upper left
+% corner and the bottom right corner (Windows convention). Matlab 'Help'
+% on this property is incorrect. GETMONDIM converts these coordinates to
+% the Matlab convention where the lower left corner starts at (1,1).
+% There is a bug with the root property 'ScreenSize'. If the primary
+% monitor's resolution is adjusted after Matlab has started, then the
+% size parameters of 'ScreenSize' are not adjusted while the origin is
+% adjusted. GETMONDIM.M fixes this be using the 'ScreenSize' origin to
+% correct for the discrepancy. Note that on restarting Matlab the
+% 'ScreenSize' property changes to the correct values!
+%
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/Windows/maxfig.html b/FigureManagement/Help/Windows/maxfig.html
new file mode 100755
index 0000000000000000000000000000000000000000..c49e42f42f6cbf43edac2a3a0fa763ee2cc775d4
--- /dev/null
+++ b/FigureManagement/Help/Windows/maxfig.html
@@ -0,0 +1,163 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>maxfig</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_maxfig"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>maxfig</h1>
+         <introduction>
+            <p>MAXimize a FIGure to fill the screen.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>maxfig(fig,monitor,mode)</pre><h2>Description<a name="2"></a></h2>
+         <p>Subsequent calls will restore the maximized figure to its previous state. 
+         </p>
+			<p>"fig" (first numeric input) is the handle of the
+            figure to maximize (default is current figure). 
+         </p>
+			<p>"monitor" (second numeric input) (Default=1) is an integer corresponding to
+            a monitor. Monitor numbering is defined by the row number of the corresponding monitor in the root property 'MonitorPositions'.
+            </p>
+			<p>"mode" is a string specifying whether to fully maximize the figure (borders extend beyond the monitor, menu and tool bars
+            are removed) or set to normal mode with borders, menu &amp; toolbars displayed. Value for maximize mode is any of {m,max,y,yes,t,true}(default).
+            Value for normal mode is any of {n,normal,no,f,false}.
+         </p>
+			<p>Uses getmondim.m.<br>
+			Extended monitors can have a different resolution from the primary monitor. Placement and size
+                  of the taskbar on the primary monitor can be changed in the code, see commented sections. 
+         </p>
+			<p>Will work with docked figures. Inspired
+                  by MAXFIGSIZE (ID 3036) by Duane Hanselman. The figure properties, TAG and USERDATA, are used to keep track of the maximized
+                  figure.</p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>maxfig<br>
+			maxfig(3,2)<br>
+			maxfig([],3)<br>
+			maxfig('normal')</p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 08/23/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a>
+               </li>
+            </ul>
+         </div>
+         <p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% maxfig
+% maxfig(fig,monitor,mode)  MAXimize a FIGure to fill the screen.
+%% Syntax
+%  maxfig(varargin)
+%% Description
+% Subsequent calls will restore the maximized figure to its previous state.
+% "fig" (first numeric input) is the handle of the figure to maximize
+% (default is current figure).
+% "monitor" (second numeric input) (Default=1) is an integer corresponding
+% to a monitor. Monitor numbering is defined by the row number of the
+% corresponding monitor in the root property 'MonitorPositions'.
+% "mode" is a string specifying whether to fully maximize the figure
+% (borders extend beyond the monitor, menu and tool bars are removed)
+% or set to normal mode with borders, menu & toolbars displayed.
+% Value for maximize mode is any of {m,max,y,yes,t,true}(default).
+% Value for normal mode is any of {n,normal,no,f,false}.
+%% Examples:
+% maxfig, maxfig(3,2), maxfig([],3), maxfig('normal')
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 08/23/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.   email: mhrovat@email.com
+% Uses getmondim.m
+% More notes:
+% Extended monitors can have a different resolution from the primary monitor.
+% Placement and size of the taskbar on the primary monitor can be changed
+% in the code, see commented sections.
+% Will work with docked figures.
+% Inspired by MAXFIGSIZE (ID 3036) by Duane Hanselman.
+% The figure properties, TAG and USERDATA, are used to keep track of the
+% maximized figure.
+%%
+% REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH- Key Constants REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH-
+% To allow for user or OS borders set the appropriate value in pixels.
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/Windows/newfig.html b/FigureManagement/Help/Windows/newfig.html
new file mode 100755
index 0000000000000000000000000000000000000000..cadbdc5d962b4bc6680045f142836f43a0953134
--- /dev/null
+++ b/FigureManagement/Help/Windows/newfig.html
@@ -0,0 +1,190 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>newfig</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_newfig"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>newfig</h1>
+         <introduction>
+            <p>create NEW FIGures.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>fighandle = newfig(numfigs,figname,monitor,aspect)</pre><h2>Description<a name="2"></a></h2>
+         <p>Tiles the screen with multiple figures starting at the top left hand corner. If the specified layout only creates one row,
+            then the figure height is chosen to maintain the desired aspect ratio. 
+         </p>
+			<p>"fighandle" is an output array of handle numbers for the figures.
+            </p>
+			<p>"numfigs" (first numeric input) determines the number of figures to create. If numfigs is a vector (rows,columns) then the
+            layout is also specified. 
+         </p>
+			<p>"figname" (any argument position) is an optional string for the figures' name. 
+         </p>
+			<p>"monitor" (second
+            numeric input) (Default=1) is an integer corresponding to a monitor. Monitor numbering is defined by the row number of the
+            corresponding monitor in the root property 'MonitorPositions'. 
+         </p>
+			<p>"aspect" (third numeric input) is the desired aspect ratio
+            (minimum horizontal/vertical size of the figure) used for determining the layout, it is ignored if the layout is specified
+            by numfigs.
+         </p>
+         <div>
+			Uses getmondim.m.<p>The figures are numbered within this group of figures and not by their figure handles. The figures are accessible by
+            their handles. Thus "figure(fighandle(4))" will make the 4th figure from this group of figures the current figure. To delete
+            the entire group of figures use "close(fighandle)". </p>
+			<p>Extended monitors can have a different resolution from the primary monitor. Placement and size
+                  of the taskbar on the primary monitor can be changed in the code, see commented sections.</p>
+			<p>The size and layout of the figures
+                  is determined by the aspect ratio and the number of figure columns. For a large number of figures, the menubar and toolbar
+                  are removed to increase figure space. 
+         </div>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>newfig(3,&#39;Title&#39;,2,2)<br>
+			newfig('Title&#39;)<br>
+			newfig figh=newfig(6); <br>
+			figh=newfig(4,2,1.5); <br>
+			newfig([1,5],2);</p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a> 
+               </li>
+            </ul>
+         </div>
+			<p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% newfig
+% fighandle = newfig(numfigs,figname,monitor,aspect)  create NEW FIGures.
+%% Syntax
+%  fighandle=newfig(varargin)
+%% Description
+% Tiles the screen with multiple figures starting at the top left hand corner.
+% If the specified layout only creates one row, then the figure height is
+% chosen to maintain the desired aspect ratio.
+% "fighandle" is an array of handle numbers for the figures.
+% "numfigs" (first numeric input) determines the number of figures to create.
+% If numfigs is a vector (rows,columns) then the layout is also specified.
+% "figname" (any argument position) is an optional string for the figures' name.
+% "monitor" (second numeric input) (Default=1) is an integer corresponding
+% to a monitor. Monitor numbering is defined by the row number of the
+% corresponding monitor in the root property 'MonitorPositions'.
+% "aspect" (third numeric input) is the desired aspect ratio (minimum
+% horizontal/vertical size of the figure) used for determining the
+% layout, it is ignored if the layout is specified by numfigs.
+%% Examples:
+% newfig(3,'Title',2,2), newfig('Title'), newfig
+% figh=newfig(6); figh=newfig(4,2,1.5); newfig([1,5],2);
+%%
+% NOTES:
+% The figures are numbered within this group of figures and not by their
+% figure handles.
+% The figures are accessible by their handles. Thus "figure(fighandle(4))" will
+% make the 4th figure from this group of figures the current figure.
+% To delete the entire group of figures use "close(fighandle)".
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+% Uses getmondim.m
+% More notes:
+% Extended monitors can have a different resolution from the primary monitor.
+% Placement and size of the taskbar on the primary monitor can be changed
+% in the code, see commented sections.
+% The size and layout of the figures is determined by the aspect ratio and
+% the number of figure columns.
+% For a large number of figures, the menubar and toolbar are removed to
+% increase figure space.
+% Default properties for this particular group of figures may be coded into
+% the code below (near bottom). The following properties are currently set.
+% 'Units','pixels', ...
+% 'Colormap',gray(256),...
+% 'NumberTitle','off',...
+% 'MenuBar',menbar,...       (depends on number of figures)
+% 'ToolBar',tbar             (depends on number of figures)
+%%
+% REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH- Key Constants REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH-
+% To allow for user or OS borders, set the appropriate value in pixels.
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/Windows/screenxyabs.html b/FigureManagement/Help/Windows/screenxyabs.html
new file mode 100755
index 0000000000000000000000000000000000000000..63925253636fdbac24061b0db4dc38e62e201388
--- /dev/null
+++ b/FigureManagement/Help/Windows/screenxyabs.html
@@ -0,0 +1,144 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>screenxyabs</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_screenxyabs"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>screenxyabs</h1>
+         <introduction>
+            <p>SCREEN X-Y ABSolute coordinates.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>newxy = screenxyabs(monitor,xy) </pre><h2>Description<a name="2"></a></h2>
+         <p>Calculates absolute screen coordinates from the relative monitor screen coordinates. This function simplifies the use of multiple
+            monitors in Matlab through the use of relative coordinates for each monitor. 
+         </p>
+			<p>&quot;newxy" is a vector of xy pairs (pixels) calculated for each input xy 
+			pair.</p>
+			<p>"monitor" is a number associated
+            with each number (Default=1). Monitor numbering is defined as the row number of the corresponding monitor in the root property
+            'MonitorPositions'. "xy" is a vector of xy coordinate pairs (pixels) relative to the monitor's origin (1,1) which is the coordinate
+            of the monitor's lower left corner.
+         </p>
+			<p>See also SCREENXYMON.M for calculation of relative coordinates.&nbsp;
+         </p>
+			<p>Uses getmondim.m.</p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>y=screenxyabs(2,[1,1]);  <br>
+			y=screenxyabs(2,[1,1,1024,768]);</p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 09/25/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a>
+               </li>
+            </ul>
+         </div>
+         <p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% screenxyabs
+% newxy = screenxyabs(monitor,xy)  SCREEN X-Y ABSolute coordinates.
+%% Syntax
+%  newxy=screenxyabs(monitor,xy)
+%% Description
+% Calculates absolute screen coordinates from the relative monitor screen
+% coordinates. This function simplifies the use of multiple monitors
+% in Matlab through the use of relative coordinates for each monitor.
+% See also SCREENXYMON.M for calculation of relative coordinates.
+% "newxy" is a vector of xy pairs (pixels) calculated for each input xy pair.
+% "monitor" is a number associated with each number (Default=1).
+% Monitor numbering is defined as the row number of the corresponding
+% monitor in the root property 'MonitorPositions'.
+% "xy" is a vector of xy coordinate pairs (pixels) relative to the monitor's
+% origin (1,1) which is the coordinate of the monitor's lower left corner.
+%% Examples:
+% y=screenxyabs(2,[1,1]);  y=screenxyabs(2,[1,1,1024,768]);
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 09/25/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+% Uses getmondim.m
+%
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/Windows/screenxymon.html b/FigureManagement/Help/Windows/screenxymon.html
new file mode 100755
index 0000000000000000000000000000000000000000..53b87a538480b814e87b7dd99b537e4721ddf71b
--- /dev/null
+++ b/FigureManagement/Help/Windows/screenxymon.html
@@ -0,0 +1,142 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>screenxymon</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_screenxymon"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>screenxymon</h1>
+         <introduction>
+            <p>SCREEN X-Y MONitor coordinates.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>newxy = screenxymon(monitor,xy) </pre><h2>Description<a name="2"></a></h2>
+         <p>Calculates relative screen coordinates for the monitor from the absolute coordinates. This function simplifies the use of
+            multiple monitors in Matlab through the use of relative coordinates for each monitor. 
+         </p>
+			<p>&quot;newxy" is a vector of xy pairs (pixels) calculated for each input xy pair. 
+         </p>
+			<p>"monitor" is a number
+            associated with each number (Default=1). Monitor numbering is defined as the row number of the corresponding monitor in the
+            root property 'MonitorPositions'. "xy" is a vector of absolute xy coordinate pairs (pixels) which are relative to the lower
+            left corner of the primary monitor (1,1).
+         </p>
+			<p>See also SCREENXYABS.M for calculation of absolute coordinates.</p>
+			<p>Uses getmondim.m.</p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>y=screenxymon(2,[1,1]);  y=screenxymon(2,[1,1,1024,768]);</p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 09/27/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a>
+               </li>
+            </ul>
+         </div>
+			<p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% screenxymon
+% newxy = screenxymon(monitor,xy)  SCREEN X-Y MONitor coordinates.
+%% Syntax
+%  newxy=screenxymon(monitor,xy)
+%% Description
+% Calculates relative screen coordinates for the monitor from the
+% absolute coordinates. This function simplifies the use of multiple monitors
+% in Matlab through the use of relative coordinates for each monitor.
+% See also SCREENXYABS.M for calculation of absolute coordinates.
+% "newxy" is a vector of xy pairs (pixels) calculated for each input xy pair.
+% "monitor" is a number associated with each number (Default=1).
+% Monitor numbering is defined as the row number of the corresponding
+% monitor in the root property 'MonitorPositions'.
+% "xy" is a vector of absolute xy coordinate pairs (pixels) which are relative
+% to the lower left corner of the primary monitor (1,1).
+%% Examples:
+% y=screenxymon(2,[1,1]);  y=screenxymon(2,[1,1,1024,768]);
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 09/27/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+% Uses getmondim.m
+%
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/Windows/tilefig.html b/FigureManagement/Help/Windows/tilefig.html
new file mode 100755
index 0000000000000000000000000000000000000000..c258f41779669ccd9e8fab1974d7f43cebcfc4ab
--- /dev/null
+++ b/FigureManagement/Help/Windows/tilefig.html
@@ -0,0 +1,205 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html
+ xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+  <title>tilefig</title>
+  <meta name="generator" content="MATLAB 7.2">
+  <meta name="date" content="2006-10-10">
+  <meta name="m-file" content="script_tilefig">
+  <style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style>
+</head>
+<body>
+<div class="content">
+<h1>tilefig</h1>
+<introduction> </introduction>
+<p>TILE one or more FIGures.</p>
+<h2>Contents</h2>
+<div>
+<ul>
+  <li><a href="#1">Syntax</a></li>
+  <li><a href="#2">Description</a></li>
+  <li><a href="#3">Examples:</a></li>
+</ul>
+</div>
+<h2>Syntax<a name="1"></a></h2>
+<pre>fighandle = tilefig(figs,figname,monitor,layout)</pre>
+<h2>Description<a name="2"></a></h2>
+<p>Tiles the screen for existing figures starting at the top left hand
+corner. </p>
+<p>"fighandle" is an output array of handle numbers for the figures. </p>
+<p>"figs" (first numeric input) is a vector of handles of the figures
+to be tiled. Default value is 0 or empty which tiles all open figures. </p>
+<p>"figname" (any argument position) is an optional string for each
+figure's name. If not specified then figure names are retained, to
+erase names use ' '. </p>
+<p>"monitor" (second numeric input) (Default=1) is an integer
+corresponding to a monitor. Monitor numbering is defined by the row
+number of the corresponding monitor in the root property
+'MonitorPositions'. </p>
+<p>"layout" (third numeric input) is a vector (rows,columns) specifying
+the screen layout or a single number (aspect) specifying the aspect
+ratio. If not specified then the optimal layout will be determined. If
+the specified layout only creates one row, then the figure height is
+chosen to maintain the default aspect ratio. The aspect ratio is the
+minimum horizontal/vertical figure size. </p>
+<p>Figures are tiled in the order they are specified in "figs". The
+figures are numbered within this group of figures and not by their
+figure handle. The figures are accessible by their handles. Thus
+"figure(fighandle(4))" will make the 4th figure from this group of
+figures the current figure. To delete the entire group of figures use
+"close(fighandle)". </p>
+<p>&nbsp;Inspired by "Tilefigs" by Charles Plum. Will work with docked
+figures, will ignore modal figures. Extended monitors may have a
+different resolution from the primary monitor. Placement and size of
+the taskbar on the primary monitor can be changed in the code, see
+commented sections. The size and layout of the figures is determined by
+the aspect ratio and the number of figure columns. For a large number
+of figures, the menubar and toolbar are removed to increase figure
+space.</p>
+<p>Uses getmondim.m.</p>
+<h2>Examples:<a name="3"></a></h2>
+<p>tilefig<br>
+tilefig([1,2,3],'Title',2)<br>
+tilefig('Title')<br>
+figh=tilefig([2:12]); <br>
+figh=tilefig([3,4],2); <br>
+tilefig(5,2,[2,3])</p>
+<div>
+<ul>
+  <li><b>Copyright</b> 2006 Mirtech, Inc. created 09/18/2006 by Mirko
+Hrovat on Matlab Ver. 7.2 <br>
+email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a> </li>
+</ul>
+</div>
+<p class="footer"><br>
+Published with wg_publish; V1.0<br>
+</p>
+</div>
+<!--
+##### SOURCE BEGIN #####
+%% tilefig
+% fighandle = tilefig(figs,figname,monitor,layout)  TILE 1 or more FIGures.
+%% Syntax
+%  fighandle=tilefig(varargin)  
+%% Description
+% Tiles the screen for existing figures starting at the top left hand corner.
+% "fighandle" is an output array of handle numbers for the figures.
+% "figs" (first numeric input) is a vector of handles of the figures to be tiled.
+% Default value is 0 which tiles all open figures.
+% "figname" (any argument position) is an optional string for each figure's name.
+% If not specified then figure names are retained, to erase names use ' '.
+% "monitor" (second numeric input) (Default=1) is an integer corresponding
+% to a monitor. Monitor numbering is defined by the row number of the
+% corresponding monitor in the root property 'MonitorPositions'.
+% "layout" (third numeric input) is a vector (rows,columns) specifying the
+% screen layout or a single number specifying the aspect ratio.
+% If not specified then the optimal layout will be determined.
+% If the specified layout only creates one row, then the figure
+% height is chosen to maintain the default aspect ratio.
+% The aspect ratio is the minimum horizontal/vertical figure size.
+%% Examples:
+% tilefig, tilefig([1,2,3],'Title',2), tilefig('Title'),
+% figh=tilefig([2:12]); figh=tilefig([3,4],2);
+% tilefig(5,2,[2,3])
+%%
+% NOTES:
+% Figures are tiled in the order they are specified in "figs".
+% The figures are numbered within this group of figures and not by their
+% figure handle.
+% The figures are accessible by their handles. Thus "figure(fighandle(4))"
+% will make the 4th figure from this group of figures the current figure.
+% To delete the entire group of figures use "close(fighandle)".
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+% Inspired by "Tilefigs" by Charles Plum
+% Uses getmondim.m
+% More notes:
+% Will work with docked figures, will ignore modal figures.
+% Extended monitors may have a different resolution from the primary monitor.
+% Placement and size of the taskbar on the primary monitor can be changed
+% in the code, see commented sections.
+% The size and layout of the figures is determined by the aspect ratio and
+% the number of figure columns.
+% For a large number of figures, the menubar and toolbar are removed to
+% increase figure space.
+% Default properties for this group of figures may be coded into the code
+% below. The following properties are currently set.
+% 'Units','pixels', ...
+% 'NumberTitle','off',...
+% 'MenuBar',menbar,...       (depends on number of figures)
+% 'ToolBar',tbar             (depends on number of figures)
+%%
+% REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH- Key Constants REPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASHREPLACE_WITH_DASH_DASH-
+% To allow for user or OS borders set the appropriate value in pixels.
+
+##### SOURCE END #####
+-->
+</body>
+</html>
diff --git a/FigureManagement/Help/dockfig.html b/FigureManagement/Help/dockfig.html
new file mode 100755
index 0000000000000000000000000000000000000000..c52c85650869c991c1634ba3af219ed4feabca76
--- /dev/null
+++ b/FigureManagement/Help/dockfig.html
@@ -0,0 +1,129 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>dockfig</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_dockfig"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>dockfig</h1>
+         <introduction>
+            <p>DOCK one or more FIGures.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>fighandle=dockfig(figs)</pre><h2>Description<a name="2"></a></h2>
+         <p>"fighandle" is an array of handle numbers for the figures.<br>
+         "figs" is an array of figure handles.<br>
+          If "figs" is empty then all figures are docked.
+         </p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>figh=dockfig([4,3,5])&nbsp;&nbsp; - Dock figures with figure handles 
+			4, 3, and 5 and return the handles in figh. &nbsp;&nbsp;&nbsp; <br>
+			dockfig&nbsp;&nbsp; - Dock all figures.&nbsp; <br>
+			dockfig 4 3 5&nbsp;&nbsp; - Dock figures with figure handles 4, 3, 
+			and 5. <br>
+         Note that the command line format is supported.</p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 09/20/2006  by Mirko Hrovat on Matlab Ver. 7.2 <br>
+               email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a></li>
+            </ul>
+         </div>
+         <p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% dockfig
+% fighandle=dockfig(figs)      DOCK one or more FIGures.
+%% Syntax
+%  fighandle=dockfig(varargin)
+%% Description
+% "fighandle" is an array of handle numbers for the figures.
+% "figs" is an array of figure handles.
+% If "figs" is empty then all figures are docked.
+%% Examples:
+% figh=dockfig([4,3,5]), dockfig, dockfig 4 3 5
+% Note that the command line format is supported.
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 09/20/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/getfigdim.html b/FigureManagement/Help/getfigdim.html
new file mode 100755
index 0000000000000000000000000000000000000000..13f3db6fb762cae8bd38ce963761f6f0da311cbb
--- /dev/null
+++ b/FigureManagement/Help/getfigdim.html
@@ -0,0 +1,150 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>getfigdim</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_getfigdim"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>getfigdim</h1>
+         <introduction>
+            <p>GET FIGure DIMensions.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Example:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>[figsize,figborders]=getfigdim(figh)</pre><h2>Description<a name="2"></a></h2>
+         <p>Function creates a figure and then measures the appropriate values to obtain border widths and heights of the menu and tool
+            bars and other parameters. This can then be used to size and place figures more exactly.</p>
+			<p>"figh" is the handle of the figure
+            whose dimensions are measured. If "figh" is not specified or empty then a figure will be created. 
+         </p>
+			<p>"figsize" is a four element
+            row vector which specifies the figure. The vector is as follows:  [left bottom width height] These are the same values returned
+            by "OuterPosition" property. 
+         </p>
+			<p>"figborders" is a 6 element row vector which is defined as: [figureborder titlebarheight menubarheight toolbarheight minfigwidth minfigheight] The figureborder is defined 
+			as the border width for all four sides of the figure. The minfigwidth,
+            minfigheight are the minimum size of figures that Matlab produces without menu and tool bars.
+         </p>
+         <h2>Example:<a name="3"></a></h2>
+         <p>[fsize,fborder]=getfigdim; <br>
+			Results:&nbsp;&nbsp; fsize = [227   241   570   504] fborder = [5    26    21    27   125    37]</p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 08/20/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a></li>
+            </ul>
+         </div><pre class="codeinput"><span class="comment">%Create a figure if it doesn't exist</span>
+</pre><p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% getfigdim
+% [figsize,figborders]=getfigdim(figh)  GET FIGure DIMensions.
+%% Syntax
+%  [figsize,figborders]=getfigdim(figh)
+%% Description
+% Function creates a figure and then measures the appropriate values to
+% obtain border widths and heights of the menu and tool bars and other
+% parameters. This can then be used to size and place figures more exactly.
+% "figh" is the handle of the figure whose dimensions are measured.
+% If "figh" is not specified or empty then a figure will be created.
+% "figsize" is a four element row vector which specifies the figure.
+% The vector is as follows:  [left bottom width height]
+% These are the same values returned by "OuterPosition" property.
+% "figborders" is a 6 element row vector which is defined as:
+% [figureborder titlebarheight menubarheight ...
+% toolbarheight minfigwidth minfigheight]
+% The figureborder is defined for all four sides of the figure.
+% The minfigwidth, minfigheight are the minimum size of figures that
+% Matlab produces without menu and tool bars.
+%%
+%% Example:
+% [fsize,fborder]=getfigdim;
+% fsize = [227   241   570   504]
+% fborder = [5    26    21    27   125    37]
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 08/20/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+%%
+%Create a figure if it doesn't exist
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/help.html b/FigureManagement/Help/help.html
new file mode 100755
index 0000000000000000000000000000000000000000..a64a0798aa8507cb5a865ad29d78fac92ca1df77
--- /dev/null
+++ b/FigureManagement/Help/help.html
@@ -0,0 +1,57 @@
+<html>
+  <h1> Figure Management </h1>
+<p style="text-align: justify;">These M-files are a collection of utilities for
+managing groups of figures. The concept of a figure group is
+introduced as a collection of figures which may be treated
+as a single group. A figure group can be tiled on the screen with any 
+desired layout. New groups can be created or a group or can be formed from 
+figures already created. A figure group can also be simply brought to the front 
+of the display screen. Figure groups will work with multiple monitor displays, 
+also known<img border="2" src="Figure%20Tiling.gif" width="512" height="384" align="right" hspace="4" vspace="8"> as the extended desktop, though figure groups do not span more than 
+one monitor. Figure groups are defined and accessed by a variable which is an 
+array of the figure handles in the group. Thus for example to close the entire 
+figure group, use <i>close(a)</i> where <i>a</i> is the array of figure handles 
+(i.e. [1,3,4,6,7,9]).</p>
+<p style="text-align: justify;">Actions such as tiling, creating, and viewing 
+can create figure groups. At right is an example of 6 figures tiled on the 
+screen with room for the taskbar. The figures have their own numbering scheme 
+designated by <i>#N</i>. Thus if the figure group is referenced by the variable
+<i>a</i>, then <i>a(2)</i> refers to the second figure in the group irregardless 
+of the figure's handle number.</p>
+	<p style="text-align: justify;">Support is also provided for working with 
+	docked figures in the Matlab desktop using DOCKFIG and NEWDFIG. The utility MAXFIG will maximize a 
+	figure to fill the screen, remembering it's prior position and size. A 
+	subsequent call to MAXFIG will restore the figure. Two versions are provided 
+	for MAXFIG, NEWFIG, and TILEFIG in the folders &quot;Windows&quot; and &quot;Platform 
+	Independent&quot; to provide support for multiple monitors. The &quot;Windows&quot; 
+	versions use the root property &quot;MonitorPositions&quot; and thus may not work 
+	properly on all platforms and will not work for Matlab versions prior to 
+	version 7 (R14). The &quot;Platform Independent&quot; versions should work on earlier 
+	releases and all platforms.</p>
+<h2>Folder Contents</h2>
+	<p><a href="dockfig.html" source="blank">dockfig</a>  &nbsp;&nbsp; DOCK one or more FIGures.<br>
+	<a href="newdfig.html" source="blank">newdfig</a>  &nbsp;&nbsp; create NEW Docked FIGures.<br>
+<a href="vf.html" source="blank">vf</a>  &nbsp;&nbsp; View one or more Figures.<br>
+<a href="getfigdim.html" source="blank">getfigdim</a>  &nbsp;&nbsp; GET FIGure DIMensions.<br>
+	</p>
+<h3>&nbsp;&nbsp;&nbsp; Platform Independent Folder</h3>
+&nbsp;&nbsp;&nbsp;
+<a href="Platform Independent/maxfig.html">maxfig</a>  &nbsp;&nbsp; MAXimize a FIGure to fill the screen.<br>
+&nbsp;&nbsp;&nbsp;
+<a href="Platform Independent/newfig.html">newfig</a>  &nbsp;&nbsp; create NEW FIGures.<br>
+&nbsp;&nbsp;&nbsp;
+<a href="Platform Independent/tilefig.html">tilefig</a>  &nbsp;&nbsp; TILE 1 or more FIGures.<br>
+<h3>&nbsp;&nbsp;&nbsp; Windows Folder</h3>
+&nbsp;&nbsp;&nbsp;
+<a href="Windows/maxfig.html">maxfig</a>  &nbsp;&nbsp; MAXimize a FIGure to fill the screen.  <br>
+&nbsp;&nbsp;&nbsp;
+<a href="Windows/newfig.html">newfig</a>  &nbsp;&nbsp; create NEW FIGures.<br>
+&nbsp;&nbsp;&nbsp; <a href="Windows/tilefig.html">tilefig</a>  &nbsp;&nbsp; TILE 1 or more FIGures.<br>
+&nbsp;&nbsp;&nbsp;
+<a href="Windows/getmondim.html">getmondim</a>  &nbsp;&nbsp;  GET MONitor DIMensions.<br>
+&nbsp;&nbsp;&nbsp;
+<a href="Windows/screenxyabs.html">screenxyabs</a>  &nbsp;&nbsp; SCREEN X-Y ABSolute coordinates.<br>
+&nbsp;&nbsp;&nbsp;
+<a href="Windows/screenxymon.html">screenxymon</a>&nbsp; &nbsp; SCREEN X-Y MONitor coordinates.<br>
+	
+</html>
\ No newline at end of file
diff --git a/FigureManagement/Help/newdfig.html b/FigureManagement/Help/newdfig.html
new file mode 100755
index 0000000000000000000000000000000000000000..f6bb86963127605f899fc63e53ea90aa8fcd1969
--- /dev/null
+++ b/FigureManagement/Help/newdfig.html
@@ -0,0 +1,131 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>newdfig</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_newdfig"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>newdfig</h1>
+         <introduction>
+            <p>create NEW Docked FIGures.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>fighandle = newdfig(numfigs,figname) </pre><h2>Description<a name="2"></a></h2>
+         <p>"fighandle" is a vector of handle numbers for the figures. <br>
+			"numfigs" determines the number of figures to create. <br>
+			"figname"
+            is an optional string for each figure's name in the figure title.
+         </p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>newdfig('Title&#39;)<br>
+			newdfig Title<br>
+			newdfig <br>
+			figh=newdfig(3);&nbsp;&nbsp; - Opens 3 new docked figures<br>
+			figh=newfig(2,'Title');&nbsp;&nbsp; - Opens 2 new docked figures 
+			with the name &quot;Title&quot; in the title bar. </p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 08/27/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a></li>
+            </ul>
+         </div>
+         <p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% newdfig
+% fighandle = newdfig(numfigs,figname)  create NEW Docked FIGures.
+%% Syntax
+%  fighandle=newdfig(varargin)
+%% Description
+% "fighandle" is a vector of handle numbers for the figures.
+% "numfigs" determines the number of figures to create.
+% "figname" is an optional string for each figure's name.
+%% Examples:
+% newdfig('Title'), newdfig Title, newdfig
+% figh=newdfig(3); figh=newfig(2,'Title');
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 08/27/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Help/vf.html b/FigureManagement/Help/vf.html
new file mode 100755
index 0000000000000000000000000000000000000000..3c325a0de57ace3f5f351fdd941304ff2a989263
--- /dev/null
+++ b/FigureManagement/Help/vf.html
@@ -0,0 +1,137 @@
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>vf</title>
+      <meta name="generator" content="MATLAB 7.2">
+      <meta name="date" content="2006-10-10">
+      <meta name="m-file" content="script_vf"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows.  On Gecko-based browsers, the shrink-to-fit doesn't work. */ 
+p,h1,h2,div.content div {
+  /* for MATLAB's browser */
+  width: 600px;
+  /* for Mozilla, but the "width" tag overrides it anyway */
+  max-width: 600px;
+  /* for IE */
+  width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>vf</h1>
+         <introduction>
+            <p>View one or more Figures.</p>
+         </introduction>
+         <h2>Contents</h2>
+         <div>
+            <ul>
+               <li><a href="#1">Syntax</a></li>
+               <li><a href="#2">Description</a></li>
+               <li><a href="#3">Examples:</a></li>
+            </ul>
+         </div>
+         <h2>Syntax<a name="1"></a></h2><pre>fighandle=vf(figs)</pre><h2>Description<a name="2"></a></h2>
+         <p>This simple function brings the group of figures specified by "figs" to the front. No tiling or rearrangement of the figures
+            is done. If "figs" is empty then all of the figures are brought to the front. 
+			The output "fighandle" has the figure handles of the figures
+            brought forward.
+         </p>
+         <h2>Examples:<a name="3"></a></h2>
+         <p>vf(a) where "a" is a vector of figure handles. <br>
+			a=vf <br>
+			vf a<br>
+			vf [1,6,8]<br>
+			a=vf(1,6,8)<br>
+			vf 1 a 6</p>
+			<p>Note that the command line format
+            is supported.
+         </p>
+         <div>
+            <ul>
+               <li><b>Copyright</b> 2006 Mirtech, Inc. created 08/22/2006  by Mirko Hrovat on Matlab Ver. 7.2 
+				<br>
+				email: <a href="mailto:mhrovat@email.com">mhrovat@email.com</a></li>
+            </ul>
+         </div>
+         <p class="footer"><br>
+            Published with wg_publish; V1.0<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% vf
+% fighandle=vf(figs)      View one or more Figures.
+%% Syntax
+%  fighandle=vf(varargin)
+%% Description
+% This simple function brings the group of figures specified by "figs" to
+% the front. No tiling or rearrangment of the figures is done.
+% If "figs" is empty then all of the figures are brought to the front.
+% "fighandle" has the figure handles of the figures brought forward.
+%% Examples:
+% vf(a) where "a" is a vector of figure handles.
+% a=vf, vf a, vf [1,6,8], a=vf(1,6,8), vf 1 a 6
+% Note that the command line format is supported.
+%%
+%%
+% * *Copyright* 2006 Mirtech, Inc.
+% created 08/22/2006  by Mirko Hrovat on Matlab Ver. 7.2
+% Mirtech, Inc.       email: mhrovat@email.com
+%
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
diff --git a/FigureManagement/Platform Independent/Contents.m b/FigureManagement/Platform Independent/Contents.m
new file mode 100755
index 0000000000000000000000000000000000000000..c909c82c8fc2894de3e776a39da4df51d9891f37
--- /dev/null
+++ b/FigureManagement/Platform Independent/Contents.m	
@@ -0,0 +1,6 @@
+% PLATFORM INDEPENDENT
+%
+% Files
+%   maxfig  - maxfig(fig,extend,mode)  MAXimize a FIGure to fill the screen.
+%   newfig  - fighandle = newfig(numfigs,figname,extend,aspect)  create NEW FIGures.
+%   tilefig - fighandle = tilefig(figs,figname,extend,layout)  TILE 1 or more FIGures.
diff --git a/FigureManagement/Platform Independent/maxfig.m b/FigureManagement/Platform Independent/maxfig.m
new file mode 100755
index 0000000000000000000000000000000000000000..2eeffbf58ee3ea61712c10dc6e8d266994991b8d
--- /dev/null
+++ b/FigureManagement/Platform Independent/maxfig.m	
@@ -0,0 +1,137 @@
+function maxfig(varargin)
+% maxfig(fig,extend,mode)  MAXimize a FIGure to fill the screen.
+%   Subsequent calls will restore the maximized figure to its previous state.
+%   Examples:
+%       maxfig, maxfig(3,1+i), maxfig([],-1), maxfig('normal')
+%   "fig" (first numeric input) is the handle of the figure to maximize
+%       (default is current figure).
+%   "extend" (second numeric input) is a complex number specifying how
+%       figures are to be created on the extended desktop. 
+%       Examples: +1/-1 is one screen to the right/left,
+%                 0 is the primary screen (default),
+%                 +i is one screen up,
+%                 -1-0.5i is half a screen down and to the left, etc...
+%   "mode" is a string specifying whether to fully maximize the figure
+%       (borders extend beyond the monitor, menu and tool bars are removed)
+%       or set to normal mode with borders, menu & toolbars displayed.
+%       Value for maximize mode is any of {m,max,y,yes,t,true}(default).
+%       Value for normal mode is any of {n,normal,no,f,false}.
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 08/23/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.   email: mhrovat@email.com
+% More notes:
+% Will work with docked figures.
+% Inspired by MAXFIGSIZE (ID 3036) by Duane Hanselman.
+% Extended monitors must have the same resolution as the primary monitor.
+% The figure properties, TAG and USERDATA, are used to keep track of the
+% maximized figure. 
+
+% --------- Key Constants -----------
+% To allow for user or OS borders set the appropriate value in pixels.
+% For example one might want to set the bottomborder for the windows 
+% taskbar (try a value of 40).
+topborder       =0;
+bottomborder    =0;
+rightborder     =0;
+leftborder      =0;
+% Border properties for figures - Adjust if needed.
+% determined by the difference between OuterPosition and Position values.
+% GETFIGDIM can return these values for your system.  
+figureborder    =5;
+titleheight     =26;        %#ok
+% ----------------------------------
+
+fullflag=1;     % set default state for maximization choice
+extend=[];
+% just in case, check all figures for 'MaxFig' tag
+set(0,'ShowHiddenHandles','on')     
+fig= findobj('Tag','MaxFig');
+set(0,'ShowHiddenHandles','off')
+% If "MaxFig" figure is found then reset size to original values
+if ~isempty(fig),
+    set(fig,'Tag','')
+    userdata=get(fig,'UserData');
+    set(fig,'Units',userdata{1},'OuterPosition',userdata{2});
+    set(fig,'MenuBar',userdata{3},'ToolBar',userdata{4},...
+        'WindowStyle',userdata{5});
+    drawnow
+end    
+if nargin==0,
+    if ~isempty(fig),
+        return         
+    % return if no arguments, maxfig is only resetting the figure.
+    end
+else
+    count=0;
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if isnumeric(arg),      % note "empty" is also considered to be numeric!
+            count=count+1;
+            switch count
+                case 1
+                    fig=arg;
+                case 2
+                    extend=arg;
+            end  % switch count
+        elseif ischar(arg),
+            if any(strcmpi(arg,{'y','yes','t','true','m','max'})),
+                fullflag=1;
+            elseif any(strcmpi(arg,{'n','no','f','false','normal'})),
+                fullflag=0;
+            end
+        end
+    end  % for
+end  % if nargin
+if isempty(fig),        fig=gcf;    end
+if isempty(extend),     extend=0;   end
+
+% Check WindowStyle property
+winstyle=get(fig,'WindowStyle');
+if strcmpi(winstyle,'modal'),
+    error('  Cannot maximize this figure.')
+end
+    
+% Get screen dimensions. Note that multiple monitors are assumed to have
+% the same resolution.
+set(0,'Units','pixels');
+scnsize=get(0,'ScreenSize');
+scnwidth=scnsize(3)-leftborder-rightborder;
+scnheight=scnsize(4)-topborder-bottomborder;
+
+% Calculate offsets for multiple monitors.
+offx=scnsize(3)*real(extend)+leftborder;
+offy=scnsize(4)*imag(extend)+bottomborder;
+
+% Save properties for figure in UserData field
+set(fig,'Tag','MaxFig')
+menbar=get(fig,'MenuBar');
+tbar=get(fig,'ToolBar');
+set(fig,'UserData',{get(fig,'Units'), get(fig,'OuterPosition'),...
+    menbar,tbar,winstyle})
+
+if fullflag
+    tbar='none';
+    menbar='none';
+    offx=offx-figureborder;
+    offy=offy-figureborder;
+    scnwidth=scnwidth+2*figureborder;
+    scnheight=scnheight+2*figureborder;
+%    scnheight=scnheight+2*figureborder+titleheight;  
+% The above seems to create problems as results don't match settings.
+%   The values seem to wrap around. So it looks like there is no simple
+%   way to get rid of the title bar in Matlab.    
+end
+
+pos=[offx+1,offy+1,scnwidth,scnheight];
+% Move, size figure and modify properties as needed.
+if strcmpi(winstyle,'docked'),
+    set(fig,'WindowStyle','normal')
+    drawnow
+end
+set(fig,'Units','pixels', ...
+        'OuterPosition',pos,...
+        'MenuBar',menbar,...
+        'ToolBar',tbar);
+figure(fig)                 % bring figure to front.
+end
diff --git a/FigureManagement/Platform Independent/newfig.m b/FigureManagement/Platform Independent/newfig.m
new file mode 100755
index 0000000000000000000000000000000000000000..e85797d76ec07b8b6d987b63b1239160b68118ce
--- /dev/null
+++ b/FigureManagement/Platform Independent/newfig.m	
@@ -0,0 +1,202 @@
+function fighandle=newfig(varargin)
+% fighandle = newfig(numfigs,figname,extend,aspect)  create NEW FIGures.
+% Tiles the screen with multiple figures starting at the top left hand corner.
+% If the specified layout only creates one row, then the figure height is
+% chosen to maintain the desired aspect ratio.
+%   Examples: 
+%       newfig(3,'Title',1+i,2), newfig('Title'), newfig
+%       figh=newfig(6); figh=newfig(4,i,1.5); newfig([1,5],-1);
+%   "fighandle" is an array of handle numbers for the figures.
+%   "numfigs" (first numeric argument) determines the number of figures to create.
+%       If numfigs is a vector (rows,columns) then the layout is also specified.
+%   "figname" (any argument position) is an optional string for the figures' name.
+%   "extend" (second numeric argument) is a complex number indicating how 
+%       figures are to be created on multiple monitors, (extended desktop).
+%       Examples: +1/-1 is one screen to the right/left,
+%                 0 is the primary screen (default),
+%                 +i is one screen up,
+%                 -1-0.5i is half a screen down and to the left, etc...
+%   "aspect" (third numeric argument) is the desired aspect ratio (minimum 
+%       horizontal/vertical size of the figure) used for determining the 
+%       layout, it is ignored if the layout is specified by numfigs.
+%
+% NOTES:
+% The figures are numbered within this group of figures and not by their
+%   figure handles.
+% The figures are accessible by their handles. Thus "figure(fighandle(4))" will
+%   make the 4th figure from this group of figures the current figure.
+% To delete the entire group of figures use "close(fighandle)".
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+% More notes:
+% Extended monitors must have the same resolution as the primary monitor.
+% The size and layout of the figures is determined by the aspect ratio and
+%   the number of figure columns.
+% For a large number of figures, the menubar and toolbar are removed to
+%   increase figure space.
+% Default properties for this particular group of figures may be coded into
+%   the code below (near bottom). The following properties are currently set.
+%        'Units','pixels', ...
+%        'Colormap',gray(256),...
+%        'NumberTitle','off',...
+%        'MenuBar',menbar,...       (depends on number of figures)
+%        'ToolBar',tbar             (depends on number of figures)
+
+% --------- Key Constants -----------
+% To allow for user or OS borders set the appropriate value in pixels.
+% For example one might want to set the bottomborder for the taskbar.
+topborder       =0;
+bottomborder    =0;
+rightborder     =0;
+leftborder      =0;
+% Border properties for figures - Adjust if needed.
+% determined by the difference between OuterPosition and Position values.
+% GETFIGDIM can return these values for your system.  
+figureborder    =5;     %#ok
+titleheight     =26;
+menbarheight    =21;
+toolbarheight   =27;
+minfigwidth     =125;
+% Set the desired default aspect ratio (minimum horizontal/vertical size of the figure).
+def_aspect      =1.1;   
+
+menbarlimit     =3;     % no menubar if numrows > menbarlimit
+toolbarlimit    =3;     % no toolbar if numrows > toolbarlimit
+maxnumrows      =6;     % maximum number of figure rows to create
+% ----------------------------------
+
+extend=[];
+numfigs=[];  
+ftitle=[];
+aspect=[];
+if nargin~=0,
+    count=0;
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if isnumeric(arg),      % note "empty" is also considered to be numeric!
+            count=count+1;
+            switch count
+                case 1
+                    numfigs=arg;
+                case 2
+                    extend=arg;
+                case 3
+                    aspect=arg;
+            end  % switch count
+        elseif ischar(arg),
+            ftitle=arg;
+        end
+    end  % for
+end  % if nargin
+if isempty(numfigs),    numfigs=1;  end
+if isempty(ftitle),     ftitle='';  end
+if isempty(extend),     extend=0;   end
+if isempty(aspect),     aspect=def_aspect;  end
+    
+% Get screen dimensions. Note that multiple monitors are assumed to have
+% the same resolution.
+set(0,'Units','pixels');
+scnsize=get(0,'ScreenSize');
+scnwidth=scnsize(3)-leftborder-rightborder;
+scnheight=scnsize(4)-topborder-bottomborder;
+
+% Try to determine the best layout for the number of figures.
+% Calculate the number of figure columns for different number of rows
+% based upon the screen size to maintain square figures
+numfigcols=zeros(1,maxnumrows);
+for n=2:maxnumrows,
+    barheight=((menbarlimit-n)>=0)*menbarheight+((toolbarlimit-n)>=0)*toolbarheight;
+    numfigcols(n)=fix(scnwidth/((scnheight/n - barheight-titleheight)*aspect));
+% Note that the figure size is created with a minimum aspect ratio. 
+end
+% For one row of figures use the same size figure as for two rows.
+numfigcols(1)=numfigcols(2);
+maxnumfigs=(1:maxnumrows).*numfigcols;
+
+% Calculate offsets for multiple monitors.
+offx=scnsize(3)*real(extend)+leftborder;
+offy=scnsize(4)*imag(extend)+bottomborder;
+
+% Determine layout from numfigs
+switch numel(numfigs)
+    case 2
+        figrows=numfigs(1);
+        figcols=numfigs(2);
+        numfigs=figrows*figcols;
+        if figrows>maxnumrows,
+            error ('  Too many figure rows! Maximum is %3.0f',maxnumrows)
+        end 
+    case 1
+        % Determine a layout (figrows,figcols) for numfigs figures.
+        figrows=1;
+        while numfigs>maxnumfigs(figrows);
+            figrows=figrows+1;
+            if figrows>maxnumrows,
+                error ('  Too many figures are requested! Maximum is %3.0f',maxnumfigs(maxnumrows))
+            end    
+        end
+        figcols=numfigcols(figrows);
+    otherwise
+        error ('  Number of figures is specified incorrectly!')
+end     % switch numel(numfigs)
+    
+% For a large number of figures, the menu and tool bars are turned off to
+% conserve space.
+if figrows > toolbarlimit,
+    tbar='none';
+else
+    tbar='figure';
+end
+if figrows > menbarlimit,
+    menbar='none';
+else
+    menbar='figure';
+end
+
+figwidth=scnwidth/figcols;
+if figwidth < minfigwidth
+    figcols=fix(scnwidth/minfigwidth);
+    figrows=ceil(numfigs/figcols);
+    if figrows>maxnumrows,
+        error ('  Too many figure rows! Maximum is %3.0f',maxnumrows)
+    end 
+    figwidth=scnwidth/figcols;
+end
+
+% For a single row of figures calculate height based upon aspect ratio.
+if figrows==1,
+    figheight=figwidth/aspect + menbarheight + toolbarheight + titleheight;
+    figrows=scnheight/figheight;    % It's ok if figrows is not integer.
+else
+    figheight=scnheight/figrows;
+end
+
+% Now create the individual figures.
+% Note that the OuterPosition property is preferable to the Position property 
+% for setting the figure positions.
+figh=ones(1,numfigs);
+for n=1:numfigs,
+    r=fix((n-1)/figcols)+1;
+    c=mod(n-1,figcols)+1;
+    pos=[offx+(c-1)*figwidth+1,offy+(figrows-r)*figheight+1,figwidth,figheight];
+    if numfigs==1,
+        figtitle=ftitle;
+    else
+        figtitle=['#',int2str(n),'  ',ftitle];
+    end
+    % Add additional or modify properties as needed.
+    figh(n)=figure('Name',figtitle,...
+        'Units','pixels',...
+        'OuterPosition',pos,...
+        'Colormap',gray(256),...
+        'NumberTitle','off',...
+        'MenuBar',menbar,...
+        'ToolBar',tbar);
+end
+figure(figh(1))             % put focus back onto first figure
+
+if nargout==1,
+    fighandle=figh;
+end
diff --git a/FigureManagement/Platform Independent/tilefig.m b/FigureManagement/Platform Independent/tilefig.m
new file mode 100755
index 0000000000000000000000000000000000000000..595b3fd8cb68887c0d3ce240e8551a5fbd9b4d00
--- /dev/null
+++ b/FigureManagement/Platform Independent/tilefig.m	
@@ -0,0 +1,243 @@
+function fighandle=tilefig(varargin)  
+% fighandle = tilefig(figs,figname,extend,layout)  TILE 1 or more FIGures.
+% Tiles the screen for existing figures starting at the top left hand corner.
+%   Examples:
+%           tilefig, tilefig([1,2,3],'Title',1+i), tilefig('Title'), 
+%           figh=tilefig([2:12]); figh=tilefig([3,4],i); tilefig(5,-1,[2,3])
+%   "fighandle" is an output array of handle numbers for the figures.
+%   "figs" (first numeric input) is a vector of handles of the figures to be tiled. 
+%       Default value is 0 which tiles all open figures.
+%   "figname" (any argument position) is an optional string for each figure's name.
+%       If not specified then figure names are retained, to erase names use ' '.
+%   "extend" (second numeric input)is a complex number specifying how figures
+%       are to be created on the extended desktop. 
+%       Examples: +1/-1 is one screen to the right/left,
+%                 0 is the primary screen (default),
+%                 +i is one screen up,
+%                 -1-0.5i is half a screen down and to the left, etc...
+%   "layout" (third numeric input) is a vector (rows,columns) specifying the 
+%       screen layout or a single number specifying the aspect ratio.
+%       If not specified then the optimal layout will be determined.
+%       If the specified layout only creates one row, then the figure
+%       height is chosen to maintain the default aspect ratio.
+%       The aspect ratio is the minimum horizontal/vertical figure size. 
+% NOTES:
+% Figures are tiled in the order they are specified in "figs".
+% The figures are numbered within this group of figures and not by their
+%   figure handle.
+% The figures are accessible by their handles. Thus "figure(fighandle(4))" 
+%   will make the 4th figure from this group of figures the current figure.
+% To delete the entire group of figures use "close(fighandle)".
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+%   Inspired by "Tilefigs" by Charles Plum  
+% More notes:
+% Will work with docked figures, will ignore modal figures.
+% Extended monitors must have the same resolution as the primary monitor.
+% The size and layout of the figures is determined by the aspect ratio and
+%   the number of figure columns.
+% For a large number of figures, the menubar and toolbar are removed to
+%   increase figure space.
+% Default properties for this group of figures may be coded into the code
+%   below. The following properties are currently set.
+%        'Units','pixels', ...
+%        'NumberTitle','off',...
+%        'MenuBar',menbar,...       (depends on number of figures)
+%        'ToolBar',tbar             (depends on number of figures)
+
+% --------- Key Constants -----------
+% To allow for user or OS borders set the appropriate value in pixels.
+% For example one might want to set the bottomborder for the taskbar.
+topborder       =0;
+bottomborder    =0;
+rightborder     =0;
+leftborder      =0;
+% Border properties for figures - Adjust if needed.
+% determined by the difference between OuterPosition and Position values.
+% GETFIGDIM can return these values for your system.  
+figureborder    =5;     %#ok
+titleheight     =26;
+menbarheight    =21;
+toolbarheight   =27;
+minfigwidth     =125;
+% Set the default aspect ratio (minimum horizontal/vertical size of the figure).
+def_aspect      =1.1;   
+
+menbarlimit     =3;     % no menubar if numrows > menbarlimit
+toolbarlimit    =3;     % no toolbar if numrows > toolbarlimit
+maxnumrows      =6;     % maximum number of figure rows to create
+% ----------------------------------
+
+extend=[];
+figs=[];  
+ftitle=[];
+layout=[];
+getname=1;
+if nargin~=0,
+    count=0;
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if isnumeric(arg),      % note "empty" is also considered to be numeric!
+            count=count+1;
+            switch count
+                case 1
+                    figs=arg;
+                case 2
+                    extend=arg;
+                case 3
+                    layout=arg;
+            end  % switch count
+        elseif ischar(arg),
+            ftitle=arg;
+            getname=0;
+        end  % if ~isempty
+    end  % for
+end  % if nargin
+if isempty(figs),       figs=0;     end
+if isempty(ftitle),     ftitle='';  end
+if isempty(extend),     extend=0;   end
+if isempty(layout)||numel(layout)==2,     
+    aspect=def_aspect;
+elseif numel(layout)==1,
+    aspect=layout;
+    layout=[];
+else
+    error ('  Layout cannot have more than 2 elements!')
+end
+
+% alternative methods to find all of the figures.
+% Second method should be more foolproof.
+% allhands=get(0,'Children');
+allhands=findobj('Type','figure');
+% Note that figures without visible handles will not be tiled.
+if figs==0,
+    figs=sort(allhands);
+else
+    [tmp,indx]=intersect(figs,allhands);    %#ok  only tile figures that do exist
+    figs=figs(sort(indx));                  % this keeps the order of the figures
+end
+numfigs=numel(figs);
+% Check WindowStyle property on figures
+m=0;
+for n=1:numfigs,
+    m=m+1;
+    winstyle=get(figs(m),'WindowStyle');
+    if strcmpi(winstyle,'modal'),           % Cannot maximize this figure.
+        figs(m)=[];
+        m=m-1;
+    elseif strcmpi(winstyle,'docked'),      % Docked figures need to be undocked.
+        set(figs(m),'WindowStyle','normal');
+        drawnow
+    end
+end
+numfigs=numel(figs);
+
+% Get screen dimensions. Note that multiple monitors are assumed to have
+% the same resolution.
+set(0,'Units','pixels');
+scnsize=get(0,'ScreenSize');
+scnwidth=scnsize(3)-leftborder-rightborder;
+scnheight=scnsize(4)-topborder-bottomborder;
+
+% Try to determine the best layout for the number of figures.
+% Calculate the number of figure columns for different number of rows
+% based upon the screen size to maintain square figures
+numfigcols=zeros(1,maxnumrows);
+for n=2:maxnumrows,
+    barheight=((menbarlimit-n)>=0)*menbarheight+((toolbarlimit-n)>=0)*toolbarheight;
+    numfigcols(n)=fix(scnwidth/((scnheight/n - barheight-titleheight)*aspect));
+% Note that the figure size is created with a minimum aspect ratio. 
+end
+% For one row of figures use the same size figure as for two rows.
+numfigcols(1)=numfigcols(2);
+maxnumfigs=(1:maxnumrows).*numfigcols;
+
+% Calculate offsets for multiple monitors.
+offx=scnsize(3)*real(extend)+leftborder;
+offy=scnsize(4)*imag(extend)+bottomborder;
+
+% Determine layout from numfigs
+if isempty(layout),
+    % Determine a layout (figrows,figcols) for numfigs figures.
+    figrows=1;
+    while numfigs>maxnumfigs(figrows);
+        figrows=figrows+1;
+        if figrows>maxnumrows,
+            error ('  Too many figures are requested! Maximum is %3.0f',maxnumfigs(maxnumrows))
+        end    
+    end
+    figcols=numfigcols(figrows);
+else
+    figrows=layout(1);
+    figcols=layout(2);
+    if figrows>maxnumrows,
+        error ('  Too many figure rows! Maximum is %3.0f',maxnumrows)
+    end 
+end     % isempty(layout)
+    
+% For a large number of figures, the menu and tool bars are turned off to
+% conserve space.
+if figrows > toolbarlimit,
+    tbar='none';
+else
+    tbar='figure';
+end
+if figrows > menbarlimit,
+    menbar='none';
+else
+    menbar='figure';
+end
+
+figwidth=scnwidth/figcols;
+if figwidth < minfigwidth
+    figcols=fix(scnwidth/minfigwidth);
+    figrows=ceil(numfigs/figcols);
+    if figrows>maxnumrows,
+        error ('  Too many figure rows! Maximum is %3.0f',maxnumrows)
+    end 
+    figwidth=scnwidth/figcols;
+end
+
+% For a single row of figures calculate height based upon aspect ratio.
+if figrows==1,
+    figheight=figwidth/aspect + menbarheight + toolbarheight + titleheight;
+    figrows=scnheight/figheight;    % It's ok if figrows is not integer.
+else
+    figheight=scnheight/figrows;
+end
+
+% Now move the individual figures.
+% Note that the OuterPosition property is preferable to the Position property 
+% for setting the figure positions.
+for n=numfigs:-1:1,
+    r=fix((n-1)/figcols)+1;     % calculate row number
+    c=mod(n-1,figcols)+1;       % calculate column number
+    pos=[offx+(c-1)*figwidth+1,offy+(figrows-r)*figheight+1,figwidth,figheight];
+    if getname,
+        ftitle = get(figs(n),'Name');
+        % remove #xx if it exists
+        if ~isempty(ftitle) && ftitle(1)=='#',
+            [tmp,ftitle]=strtok(ftitle);    %#ok
+            ftitle=strtrim(ftitle);         
+        end
+    end
+    if numfigs==1,
+        figtitle=ftitle;
+    else
+        figtitle=['#',int2str(n),'  ',ftitle];
+    end
+    % Move figure and modify properties as needed.
+    set(figs(n),'Name',figtitle,...
+        'Units','pixels', ...
+        'OuterPosition',pos,...
+        'NumberTitle','off',...
+        'MenuBar',menbar,...
+        'ToolBar',tbar);
+    figure(figs(n))             % bring figure to front.
+end
+
+if nargout==1,
+    fighandle=figs;
+end
diff --git a/FigureManagement/dockfig.m b/FigureManagement/dockfig.m
new file mode 100755
index 0000000000000000000000000000000000000000..0ea846be974d85718bf06ef8238f6dc6db6551d2
--- /dev/null
+++ b/FigureManagement/dockfig.m
@@ -0,0 +1,59 @@
+function fighandle=dockfig(varargin)
+% fighandle=dockfig(figs)      DOCK one or more FIGures.
+%   "fighandle" is an array of handle numbers for the figures.
+%   "figs" is an array of figure handles.
+%       If "figs" is empty then all figures are docked.
+%   Examples: 
+%       figh=dockfig([4,3,5]), dockfig, dockfig 4 3 5
+% Note that the command line format is supported.
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 09/20/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+figs=[];  
+if nargin>0,
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if ischar(arg),
+            tmp=str2num(arg);   %#ok
+            if isempty(tmp),    % since it is empty then it may be a variable
+                tmp = evalin('base',arg);
+                if isempty(tmp),
+                    error ('  Syntax error in argument!'),
+                end
+            end  % isempty(tmp)
+        else
+            tmp=arg;
+        end  % ischar(arg)
+        figs=[figs,tmp];
+    end  % for
+end  % if nargin
+if isempty(figs),       figs=0;     end
+
+% set this to "on" so that all figures with "HandleVisibility" set to off can be seen.
+set(0,'ShowHiddenHandles','on')     
+% Below are two alternative methods to find all of the figures.
+% Second method should be more foolproof.
+% allhands=get(0,'Children');
+allhands=findobj('Type','figure');
+set(0,'ShowHiddenHandles','off')
+if figs==0,
+    figs=sort(allhands)';
+else
+    [tmp,indx]=intersect(figs,allhands);    %#ok tmp not used, view figures that exist
+    figs=figs(sort(indx));                  % order the figures as specified
+end
+numfigs=numel(figs);
+
+if isempty(figs),
+    warning('MATLAB:EmptyValue','There are no figures to dock.')
+else
+    for n=numfigs:-1:1,
+        set(figs(n),'WindowStyle','docked');
+        figure(figs(n))             % bring figure to front.
+    end
+end
+
+if nargout==1,
+    fighandle=figs;
+end
diff --git a/FigureManagement/getfigdim.m b/FigureManagement/getfigdim.m
new file mode 100755
index 0000000000000000000000000000000000000000..b4e57e935cfeada36432e5a22cb3b23dec7b86bd
--- /dev/null
+++ b/FigureManagement/getfigdim.m
@@ -0,0 +1,82 @@
+function [figsize,figborders]=getfigdim(figh)
+% [figsize,figborders]=getfigdim(figh)  GET FIGure DIMensions.
+%   Function creates a figure and then measures the appropriate values to
+%   obtain border widths and heights of the menu and tool bars and other 
+%   parameters. This can then be used to size and place figures more exactly.
+%   "figh" is the handle of the figure whose dimensions are measured.
+%       If "figh" is not specified or empty then a figure will be created.
+%   "figsize" is a four element row vector which specifies the figure. 
+%       The vector is as follows:  [left bottom width height]
+%       These are the same values returned by "OuterPosition" property.
+%   "figborders" is a 6 element row vector which is defined as:
+%       [figureborder titlebarheight menubarheight ...
+%                           toolbarheight minfigwidth minfigheight]
+%       The figureborder is defined for all four sides of the figure.
+%       The minfigwidth, minfigheight are the minimum size of figures that
+%       Matlab produces without menu and tool bars.
+%       
+%   Example: 
+%       [fsize,fborder]=getfigdim; 
+%       fsize = [227   241   570   504]
+%       fborder = [5    26    21    27   125    37]
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 08/20/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+
+%Create a figure if it doesn't exist
+if nargin==0 || isempty(figh),
+    figh=figure;
+    clrflg=1;
+else
+    figure(figh);
+    clrflg=0;
+end
+menbarstate=get(figh,'MenuBar');
+toolbarstate=get(figh,'ToolBar');
+unitsstate=get(figh,'Units');
+set(figh,'Units','pixels');
+drawnow
+figsize=get(figh,'OuterPosition');
+figpos=get(figh,'Position');
+if nargout==2,
+    set(figh,'MenuBar','none');
+    set(figh,'ToolBar','none');
+    drawnow
+    p1=get(figh,'OuterPosition');
+    p =get(figh,'Position');
+
+    set(figh,'MenuBar','figure');
+    set(figh,'ToolBar','none');
+    drawnow
+    p2=get(figh,'OuterPosition');
+
+    set(figh,'MenuBar','none');
+    set(figh,'ToolBar','figure');
+    drawnow
+    p3=get(figh,'OuterPosition');
+
+    set(figh,'MenuBar','none');
+    set(figh,'ToolBar','none');
+    set(figh,'OuterPosition',[figsize(1),figsize(2),10,10]);
+    drawnow
+    p4=get(figh,'OuterPosition');
+
+    figborders=zeros(1,6);
+    figborders(4)= p3(4)-p1(4);             % calculate height of Toolbar
+    figborders(3)= p2(4)-p1(4);             % calculate height of Menubar
+    figborders(1)= (p1(3)-p(3))/2;          % calculate width of figure border
+    figborders(2)= p1(4)-p(4)-2*figborders(1); % calculate height of title bar
+    figborders(5:6)=p4(3:4);                % get minimium figure sizes
+end %if nargout==2
+% close the figure if created, otherwise return to original state
+if clrflg,
+    close(figh);
+else
+    set(figh,'MenuBar',menbarstate);
+    set(figh,'ToolBar',toolbarstate);
+    set(figh,'Units',unitsstate);
+    set(figh,'Position',figpos);
+    drawnow
+end
+% ---------- END ----------
diff --git a/FigureManagement/getmondim.m b/FigureManagement/getmondim.m
new file mode 100755
index 0000000000000000000000000000000000000000..d59e3d1e7522042666809bada2332f4d5498ddf7
--- /dev/null
+++ b/FigureManagement/getmondim.m
@@ -0,0 +1,54 @@
+function y=getmondim(mnum)
+% y = getmondim(monitornumber)  GET MONitor DIMensions.
+%   "y" is the dimensions of the specified monitor represented as
+%   [xstart,ystart,width,height] where values are in pixels.
+%   (xstart,ystart) are the absolute coordinates of the lower left corner.
+%   "monitornumber" is a number associated with each monitor (Default=1).
+%       Monitor numbering is defined as the row number of the corresponding 
+%       monitor in the root property 'MonitorPositions'. 
+%   Examples: 
+%       y=getmondim; y=getmondim(2);
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 09/26/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+%  Notes:
+%       The primary monitor is always numbered 1 and always starts at (1,1).
+%   'MonitorPositions' returns coordinates corresponding to the upper left
+%   corner and the bottom right corner (Windows convention). Matlab 'Help'
+%   on this property is incorrect. GETMONDIM converts these coordinates to
+%   the Matlab convention where the lower left corner starts at (1,1).
+%       There is a bug with the root property 'ScreenSize'. If the primary
+%   monitor's resolution is adjusted after Matlab has started, then the
+%   size parameters of 'ScreenSize' are not adjusted while the origin is
+%   adjusted. GETMONDIM.M fixes this be using the 'ScreenSize' origin to 
+%   correct for the discrepancy. Note that on restarting Matlab the
+%   'ScreenSize' property changes to the correct values!
+
+if nargin==0,       mnum=[];    end        
+if isempty(mnum),   mnum=1;     end
+savedunits=get(0,'Units');
+set(0,'Units','pixels')         % make sure unit values are in pixels
+mpos=get(0,'MonitorPositions'); % get list of monitor positions
+% MonitorPositions are the coordinates for upper left & lower right corners.
+primaryhght=mpos(1,4)-mpos(1,2)+1;
+if any(mnum==1:size(mpos,1)),
+    % need to convert MonitorPositions to Matlab convention.
+    height=mpos(mnum,4)-mpos(mnum,2)+1;
+    width=mpos(mnum,3)-mpos(mnum,1)+1;
+    offset=1;       %#ok
+% NOTE!
+% Bugfix for the root property 'ScreenSize' in case the primary monitor's
+% resolution has changed. If bug is ever fixed then delete these lines.
+    screenxy=get(0,'ScreenSize');
+    offset=2-screenxy(2);
+% end bugfix
+    
+    % get lower left corner coordinates
+    llpt=[mpos(mnum,1),primaryhght-mpos(mnum,4)+offset];  
+    y=[llpt,width,height];
+else
+    warning('  Monitor does not exist!');   %#ok
+    y=[];
+end
+set(0,'Units',savedunits)
diff --git a/FigureManagement/maxfig.m b/FigureManagement/maxfig.m
new file mode 100755
index 0000000000000000000000000000000000000000..c94fadbf2d31e184d6a27e2bbfa6c99d92ba4fc1
--- /dev/null
+++ b/FigureManagement/maxfig.m
@@ -0,0 +1,143 @@
+function maxfig(varargin)
+% maxfig(fig,monitor,mode)  MAXimize a FIGure to fill the screen.
+%   Subsequent calls will restore the maximized figure to its previous state.
+%   "fig" (first numeric input) is the handle of the figure to maximize
+%       (default is current figure).
+%   "monitor" (second numeric input) (Default=1) is an integer corresponding
+%       to a monitor. Monitor numbering is defined by the row number of the
+%       corresponding monitor in the root property 'MonitorPositions'. 
+%   "mode" is a string specifying whether to fully maximize the figure
+%       (borders extend beyond the monitor, menu and tool bars are removed)
+%       or set to normal mode with borders, menu & toolbars displayed.
+%       Value for maximize mode is any of {m,max,y,yes,t,true}(default).
+%       Value for normal mode is any of {n,normal,no,f,false}.
+%   Examples:
+%       maxfig, maxfig(3,2), maxfig([],3), maxfig('normal')
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 08/23/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.   email: mhrovat@email.com
+%   Uses getmondim.m
+% More notes:
+% Extended monitors can have a different resolution from the primary monitor.
+% Placement and size of the taskbar on the primary monitor can be changed
+%   in the code, see commented sections.
+% Will work with docked figures.
+% Inspired by MAXFIGSIZE (ID 3036) by Duane Hanselman.
+% The figure properties, TAG and USERDATA, are used to keep track of the
+%   maximized figure. 
+
+% --------- Key Constants -----------
+% To allow for user or OS borders set the appropriate value in pixels.
+topborder       =0;
+bottomborder    =0;
+rightborder     =0;
+leftborder      =0;
+taskbarborder   =30;
+% Border properties for figures - Adjust if needed.
+% determined by the difference between OuterPosition and Position values.
+% GETFIGDIM can return these values for your system.  
+figureborder    =5;
+titleheight     =26;        %#ok
+% ----------------------------------
+
+fullflag=1;     % set default state for maximization choice
+monnum=[];
+% just in case, check all figures for 'MaxFig' tag
+set(0,'ShowHiddenHandles','on')     
+fig= findobj('Tag','MaxFig');
+set(0,'ShowHiddenHandles','off')
+% If "MaxFig" figure is found then reset size to original values
+if ~isempty(fig),
+    set(fig,'Tag','')
+    userdata=get(fig,'UserData');
+    set(fig,'Units',userdata{1},'OuterPosition',userdata{2});
+    set(fig,'MenuBar',userdata{3},'ToolBar',userdata{4},...
+        'WindowStyle',userdata{5});
+    drawnow
+end    
+if nargin==0,
+    if ~isempty(fig),
+        return         
+    % return if no arguments, maxfig is only resetting the figure.
+    end
+else
+    count=0;
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if isnumeric(arg),      % note "empty" is also considered to be numeric!
+            count=count+1;
+            switch count
+                case 1
+                    fig=arg;
+                case 2
+                    monnum=arg;
+            end  % switch count
+        elseif ischar(arg),
+            if any(strcmpi(arg,{'y','yes','t','true','m','max'})),
+                fullflag=1;
+            elseif any(strcmpi(arg,{'n','no','f','false','normal'})),
+                fullflag=0;
+            end
+        end
+    end  % for
+end  % if nargin
+if isempty(fig),        fig=gcf;    end
+if isempty(monnum),     monnum=1;   end
+
+% Check WindowStyle property
+winstyle=get(fig,'WindowStyle');
+if strcmpi(winstyle,'modal'),
+    error('  Cannot maximize this figure.')
+end
+    
+% Get screen dimensions. 
+scnsize=getmondim(monnum);
+if isempty(scnsize),
+    error ('  Monitor %g does not exist',monnum)
+end
+% ----------------------- TASKBAR PLACEMENT --------------------
+% adjust border for taskbar, edit appropriate line for position of taskbar
+if monnum==1,   
+    bottomborder=bottomborder+taskbarborder;
+end
+% ----------------------- TASKBAR PLACEMENT --------------------
+scnwidth=scnsize(3)-leftborder-rightborder;
+scnheight=scnsize(4)-topborder-bottomborder;
+
+% Calculate offsets for multiple monitors.
+offx=scnsize(1)+leftborder-1;
+offy=scnsize(2)+bottomborder-1;
+
+% Save properties for figure in UserData field
+set(fig,'Tag','MaxFig')
+menbar=get(fig,'MenuBar');
+tbar=get(fig,'ToolBar');
+set(fig,'UserData',{get(fig,'Units'), get(fig,'OuterPosition'),...
+    menbar,tbar,winstyle})
+
+if fullflag
+    tbar='none';
+    menbar='none';
+    offx=offx-figureborder;
+    offy=offy-figureborder;
+    scnwidth=scnwidth+2*figureborder;
+    scnheight=scnheight+2*figureborder;
+%    scnheight=scnheight+2*figureborder+titleheight;  
+% The above seems to create problems as results don't match settings.
+%   The values seem to wrap around. So it looks like there is no simple
+%   way to get rid of the title bar in Matlab.    
+end
+
+pos=[offx+1,offy+1,scnwidth,scnheight];
+% Move, size figure and modify properties as needed.
+if strcmpi(winstyle,'docked'),
+    set(fig,'WindowStyle','normal')
+    drawnow
+end
+set(fig,'Units','pixels', ...
+        'OuterPosition',pos,...
+        'MenuBar',menbar,...
+        'ToolBar',tbar);
+figure(fig)                 % bring figure to front.
+end
diff --git a/FigureManagement/newdfig.m b/FigureManagement/newdfig.m
new file mode 100755
index 0000000000000000000000000000000000000000..eb8a828b733a8035f8a65e0946a888710181cbfa
--- /dev/null
+++ b/FigureManagement/newdfig.m
@@ -0,0 +1,35 @@
+function fighandle=newdfig(varargin)
+% fighandle = newdfig(numfigs,figname)  create NEW Docked FIGures.
+%   "fighandle" is a vector of handle numbers for the figures.
+%   "numfigs" determines the number of figures to create.
+%   "figname" is an optional string for each figure's name.
+%   Examples: 
+%       newdfig('Title'), newdfig Title, newdfig
+%       figh=newdfig(3); figh=newfig(2,'Title');
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 08/27/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+numfigs=[];  
+ftitle=[];
+if nargin~=0,
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if isnumeric(arg),
+            numfigs=arg;
+        elseif ischar(arg),
+            ftitle=arg;
+        end
+    end  % for
+end  % if nargin
+if isempty(numfigs),    numfigs=1;  end
+if isempty(ftitle),     ftitle='';  end
+
+figh=zeros(1,numfigs);
+for n=1:numfigs,
+    figh(n)=figure('Name',ftitle,'WindowStyle','docked');
+end
+
+if nargout==1,
+    fighandle=figh;
+end
diff --git a/FigureManagement/newfig.m b/FigureManagement/newfig.m
new file mode 100755
index 0000000000000000000000000000000000000000..14faba2fd2904f5a9739ff1f62375f6652996ba1
--- /dev/null
+++ b/FigureManagement/newfig.m
@@ -0,0 +1,211 @@
+function fighandle=newfig(varargin)
+% fighandle = newfig(numfigs,figname,monitor,aspect)  create NEW FIGures.
+% Tiles the screen with multiple figures starting at the top left hand corner.
+% If the specified layout only creates one row, then the figure height is
+% chosen to maintain the desired aspect ratio.
+%   "fighandle" is an array of handle numbers for the figures.
+%   "numfigs" (first numeric input) determines the number of figures to create.
+%       If numfigs is a vector (rows,columns) then the layout is also specified.
+%   "figname" (any argument position) is an optional string for the figures' name.
+%   "monitor" (second numeric input) (Default=1) is an integer corresponding
+%       to a monitor. Monitor numbering is defined by the row number of the
+%       corresponding monitor in the root property 'MonitorPositions'. 
+%   "aspect" (third numeric input) is the desired aspect ratio (minimum 
+%       horizontal/vertical size of the figure) used for determining the 
+%       layout, it is ignored if the layout is specified by numfigs.
+%   Examples: 
+%       newfig(3,'Title',2,2), newfig('Title'), newfig
+%       figh=newfig(6); figh=newfig(4,2,1.5); newfig([1,5],2);
+%
+% NOTES:
+% The figures are numbered within this group of figures and not by their
+%   figure handles.
+% The figures are accessible by their handles. Thus "figure(fighandle(4))" will
+%   make the 4th figure from this group of figures the current figure.
+% To delete the entire group of figures use "close(fighandle)".
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+%   Uses getmondim.m
+% More notes:
+% Extended monitors can have a different resolution from the primary monitor.
+% Placement and size of the taskbar on the primary monitor can be changed
+%   in the code, see commented sections.
+% The size and layout of the figures is determined by the aspect ratio and
+%   the number of figure columns.
+% For a large number of figures, the menubar and toolbar are removed to
+%   increase figure space.
+% Default properties for this particular group of figures may be coded into
+%   the code below (near bottom). The following properties are currently set.
+%        'Units','pixels', ...
+%        'Colormap',gray(256),...
+%        'NumberTitle','off',...
+%        'MenuBar',menbar,...       (depends on number of figures)
+%        'ToolBar',tbar             (depends on number of figures)
+
+% --------- Key Constants -----------
+% To allow for user or OS borders, set the appropriate value in pixels.
+topborder       =0;
+bottomborder    =0;
+rightborder     =0;
+leftborder      =0;
+taskbarborder   =30;
+% Border properties for figures - Adjust if needed.
+% determined by the difference between OuterPosition and Position values.
+% GETFIGDIM can return these values for your system.  
+figureborder    =5;     %#ok
+titleheight     =26;
+menbarheight    =21;
+toolbarheight   =27;
+minfigwidth     =125;
+% Set the desired default aspect ratio (minimum horizontal/vertical size of the figure).
+def_aspect      =1.1;   
+
+menbarlimit     =3;     % no menubar if numrows > menbarlimit
+toolbarlimit    =3;     % no toolbar if numrows > toolbarlimit
+maxnumrows      =6;     % maximum number of figure rows to create
+% ----------------------------------
+
+monnum=[];
+numfigs=[];  
+ftitle=[];
+aspect=[];
+if nargin~=0,
+    count=0;
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if isnumeric(arg),      % note "empty" is also considered to be numeric!
+            count=count+1;
+            switch count
+                case 1
+                    numfigs=arg;
+                case 2
+                    monnum=arg;
+                case 3
+                    aspect=arg;
+            end  % switch count
+        elseif ischar(arg),
+            ftitle=arg;
+        end
+    end  % for
+end  % if nargin
+if isempty(numfigs),    numfigs=1;  end
+if isempty(ftitle),     ftitle='';  end
+if isempty(monnum),     monnum=1;   end
+if isempty(aspect),     aspect=def_aspect;  end
+    
+% Get screen dimensions. 
+scnsize=getmondim(monnum);
+if isempty(scnsize),
+    error ('  Monitor %g does not exist',monnum)
+end
+% ----------------------- TASKBAR PLACEMENT --------------------
+% adjust border for taskbar, edit appropriate line for position of taskbar
+if monnum==1,   
+    bottomborder=bottomborder+taskbarborder;
+end
+% ----------------------- TASKBAR PLACEMENT --------------------
+scnwidth=scnsize(3)-leftborder-rightborder;
+scnheight=scnsize(4)-topborder-bottomborder;
+
+% Try to determine the best layout for the number of figures.
+% Calculate the number of figure columns for different number of rows
+% based upon the screen size to maintain square figures
+numfigcols=zeros(1,maxnumrows);
+for n=2:maxnumrows,
+    barheight=((menbarlimit-n)>=0)*menbarheight+((toolbarlimit-n)>=0)*toolbarheight;
+    numfigcols(n)=fix(scnwidth/((scnheight/n - barheight-titleheight)*aspect));
+% Note that the figure size is created with a minimum aspect ratio. 
+end
+% For one row of figures use the same size figure as for two rows.
+numfigcols(1)=numfigcols(2);
+maxnumfigs=(1:maxnumrows).*numfigcols;
+
+% Calculate offsets for multiple monitors.
+offx=scnsize(1)+leftborder-1;
+offy=scnsize(2)+bottomborder-1;
+
+% Determine layout from numfigs
+switch numel(numfigs)
+    case 2
+        figrows=numfigs(1);
+        figcols=numfigs(2);
+        numfigs=figrows*figcols;
+        if figrows>maxnumrows,
+            error ('  Too many figure rows! Maximum is %3.0f',maxnumrows)
+        end 
+    case 1
+        % Determine a layout (figrows,figcols) for numfigs figures.
+        figrows=1;
+        while numfigs>maxnumfigs(figrows);
+            figrows=figrows+1;
+            if figrows>maxnumrows,
+                error ('  Too many figures are requested! Maximum is %3.0f',maxnumfigs(maxnumrows))
+            end    
+        end
+        figcols=numfigcols(figrows);
+    otherwise
+        error ('  Number of figures is specified incorrectly!')
+end     % switch numel(numfigs)
+    
+% For a large number of figures, the menu and tool bars are turned off to
+% conserve space.
+if figrows > toolbarlimit,
+    tbar='none';
+else
+    tbar='figure';
+end
+if figrows > menbarlimit,
+    menbar='none';
+else
+    menbar='figure';
+end
+
+figwidth=scnwidth/figcols;
+if figwidth < minfigwidth
+    figcols=fix(scnwidth/minfigwidth);
+    figrows=ceil(numfigs/figcols);
+    if figrows>maxnumrows,
+        error ('  Too many figure rows! Maximum is %3.0f',maxnumrows)
+    end 
+    figwidth=scnwidth/figcols;
+end
+
+% For a single row of figures calculate height based upon aspect ratio.
+if figrows==1,
+    figheight=figwidth/aspect + menbarheight + toolbarheight + titleheight;
+    figrows=scnheight/figheight;    % It's ok if figrows is not integer.
+else
+    figheight=scnheight/figrows;
+end
+
+% Now create the individual figures.
+% Note that the OuterPosition property is preferable to the Position property 
+% for setting the figure positions.
+figh=ones(1,numfigs);
+for n=1:numfigs,
+    r=fix((n-1)/figcols)+1;
+    c=mod(n-1,figcols)+1;
+    pos=[offx+(c-1)*figwidth+1,offy+(figrows-r)*figheight+1,figwidth,figheight];
+    if numfigs==1,
+        figtitle=ftitle;
+    else
+        figtitle=['#',int2str(n),'  ',ftitle];
+    end
+    % ------------------- MODIFY FIGURE PROPERTIES -----------------
+    % Add additional or modify properties as needed.
+    figh(n)=figure('Name',figtitle,...
+        'Units','pixels',...
+        'OuterPosition',pos,...
+        'Colormap',gray(256),...
+        'NumberTitle','off',...
+        'MenuBar',menbar,...
+        'ToolBar',tbar);
+    % ------------------- MODIFY FIGURE PROPERTIES -----------------
+end
+figure(figh(1))             % put focus back onto first figure
+
+if nargout==1,
+    fighandle=figh;
+end
diff --git a/FigureManagement/readme.txt b/FigureManagement/readme.txt
new file mode 100755
index 0000000000000000000000000000000000000000..8c5da9f6466db04cc75398a6bedf754a66071a65
--- /dev/null
+++ b/FigureManagement/readme.txt
@@ -0,0 +1,23 @@
+These M-files are a collection of utilities for managing groups of figures. The concept of a figure group is introduced as a collection of figures which may be treated as a single group. A figure group can be tiled on the screen with any desired layout. New groups can be created or a group or can be formed from figures already created. A figure group can also be simply brought to the front of the display screen. Figure groups will work with multiple monitor displays, also known as the extended desktop, though figure groups do not span more than one monitor. Figure groups are defined and accessed by a variable which is an array of the figure handles in the group. Thus for example to close the entire figure group, use close(a) where a is the array of figure handles (i.e. [1,3,4,6,7,9]). Actions such as tiling, creating, and viewing can create figure groups. 
+
+Two versions are provided for MAXFIG, NEWFIG, and TILEFIG in the folders "Windows" and "Platform Independent" to provide support for multiple monitors. The "Windows" versions use the root property "MonitorPositions" and thus may not work properly on all platforms and will not work for Matlab versions prior to version 7 (R14). The "Platform Independent" versions should work on earlier releases and all platforms.
+
+INSTALLATION:
+Combine or preferably copy the m-files in the root folder and the m-files in only ONE of the subfolders, "Platform Independent" or "Windows" to a new folder. For example these files might be copied to the folder "Figure_Management". Add this folder to your path in Matlab.
+
+I would recommend trying to use the "Windows" files first as this provides the greatest flexibility in working with multiple monitors.
+
+HELP:
+Help is available in html format. Switch to the help folder and view help.html.
+More details are available in the comments field of each m-file.
+
+Feel free to email me with your comments and/or suggestions. The files were developed in a Windows environment, so your experience on other platforms would be useful. In particular it would be useful to know whether the root property "MonitorPositions" behaves the same on other platforms (see GETMONDIM.M).
+
+mhrovat@email.com
+
+Acknowledgements:
+MAXFIG inspired by MAXFIGSIZE by Duane Hanselman.
+TILEFIG inspired by TILEFIGS by Charles Plum.
+Html HELP was created with initial help files generated by WG_PUBLISH by Wolfgang Garn.
+For a collection of utilities for working with cascaded folders, see "Useful Trivial Graphics Utilities" by Scott Hirsch.
+
diff --git a/FigureManagement/screenxyabs.m b/FigureManagement/screenxyabs.m
new file mode 100755
index 0000000000000000000000000000000000000000..78a12d661b94119ee9013de4407c0ba62b841a97
--- /dev/null
+++ b/FigureManagement/screenxyabs.m
@@ -0,0 +1,41 @@
+function newxy=screenxyabs(monitor,xy)
+% newxy = screenxyabs(monitor,xy)  SCREEN X-Y ABSolute coordinates.
+%   Calculates absolute screen coordinates from the relative monitor screen
+%   coordinates. This function simplifies the use of multiple monitors 
+%   in Matlab through the use of relative coordinates for each monitor.
+%   See also SCREENXYMON.M for calculation of relative coordinates.
+%   "newxy" is a vector of xy pairs (pixels) calculated for each input xy pair.
+%   "monitor" is a number associated with each number (Default=1).
+%       Monitor numbering is defined as the row number of the corresponding 
+%       monitor in the root property 'MonitorPositions'. 
+%   "xy" is a vector of xy coordinate pairs (pixels) relative to the monitor's
+%       origin (1,1) which is the coordinate of the monitor's lower left corner.
+%   Examples: 
+%       y=screenxyabs(2,[1,1]);  y=screenxyabs(2,[1,1,1024,768]);
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 09/25/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+%   Uses getmondim.m
+
+switch nargin
+    case 2
+    case 1
+        xy=[];
+    case 0
+        monitor=[];
+        xy=[];
+    otherwise
+        error ('  Too many arguments!')
+end  % switch
+if isempty(monitor),    monitor=1;  end
+if isempty(xy),         xy=[1,1];   end
+xypairs=fix(numel(xy)/2);
+xyformat=size(xy);
+xy=reshape(xy,[2,xypairs]);     % make each row correspond to a different xy pair
+mpos=getmondim(monitor);        % get monitor's origin
+if isempty(mpos),
+    error ('  Monitor %g does not exist',monitor)
+else
+    newxy=reshape(xy+repmat([mpos(1)-1;mpos(2)-1],[1,xypairs]),xyformat);
+end
diff --git a/FigureManagement/screenxymon.m b/FigureManagement/screenxymon.m
new file mode 100755
index 0000000000000000000000000000000000000000..30a72a26265c599fd7acd1f292087c2671d58a6b
--- /dev/null
+++ b/FigureManagement/screenxymon.m
@@ -0,0 +1,41 @@
+function newxy=screenxymon(monitor,xy)
+% newxy = screenxymon(monitor,xy)  SCREEN X-Y MONitor coordinates.
+%   Calculates relative screen coordinates for the monitor from the
+%   absolute coordinates. This function simplifies the use of multiple monitors 
+%   in Matlab through the use of relative coordinates for each monitor.
+%   See also SCREENXYABS.M for calculation of absolute coordinates.
+%   "newxy" is a vector of xy pairs (pixels) calculated for each input xy pair.
+%   "monitor" is a number associated with each number (Default=1).
+%       Monitor numbering is defined as the row number of the corresponding 
+%       monitor in the root property 'MonitorPositions'. 
+%   "xy" is a vector of absolute xy coordinate pairs (pixels) which are relative
+%       to the lower left corner of the primary monitor (1,1).
+%   Examples: 
+%       y=screenxymon(2,[1,1]);  y=screenxymon(2,[1,1,1024,768]);
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 09/27/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+%   Uses getmondim.m
+
+switch nargin
+    case 2
+    case 1
+        xy=[];
+    case 0
+        monitor=[];
+        xy=[];
+    otherwise
+        error ('  Too many arguments!')
+end  % switch
+if isempty(monitor),    monitor=1;  end
+if isempty(xy),         xy=[1,1];   end
+xypairs=fix(numel(xy)/2);
+xyformat=size(xy);
+xy=reshape(xy,[2,xypairs]);     % make each row correspond to a different xy pair
+mpos=getmondim(monitor);        % get monitor's origin
+if isempty(mpos),
+    error ('  Monitor %g does not exist',monitor)
+else
+    newxy=reshape(xy-repmat([mpos(1)-1;mpos(2)-1],[1,xypairs]),xyformat);
+end
diff --git a/FigureManagement/tilefig.m b/FigureManagement/tilefig.m
new file mode 100755
index 0000000000000000000000000000000000000000..010527f382f07bf58feb596e698b6fa5f8e7aef5
--- /dev/null
+++ b/FigureManagement/tilefig.m
@@ -0,0 +1,254 @@
+function fighandle=tilefig(varargin)  
+% fighandle = tilefig(figs,figname,monitor,layout)  TILE 1 or more FIGures.
+% Tiles the screen for existing figures starting at the top left hand corner.
+%   "fighandle" is an output array of handle numbers for the figures.
+%   "figs" (first numeric input) is a vector of handles of the figures to be tiled. 
+%       Default value is 0 which tiles all open figures.
+%   "figname" (any argument position) is an optional string for each figure's name.
+%       If not specified then figure names are retained, to erase names use ' '.
+%   "monitor" (second numeric input) (Default=1) is an integer corresponding
+%       to a monitor. Monitor numbering is defined by the row number of the
+%       corresponding monitor in the root property 'MonitorPositions'. 
+%   "layout" (third numeric input) is a vector (rows,columns) specifying the 
+%       screen layout or a single number specifying the aspect ratio.
+%       If not specified then the optimal layout will be determined.
+%       If the specified layout only creates one row, then the figure
+%       height is chosen to maintain the default aspect ratio.
+%       The aspect ratio is the minimum horizontal/vertical figure size. 
+%   Examples:
+%           tilefig, tilefig([1,2,3],'Title',2), tilefig('Title'), 
+%           figh=tilefig([2:12]); figh=tilefig([3,4],2);
+%           tilefig(5,2,[2,3])
+%
+% NOTES:
+% Figures are tiled in the order they are specified in "figs".
+% The figures are numbered within this group of figures and not by their
+%   figure handle.
+% The figures are accessible by their handles. Thus "figure(fighandle(4))" 
+%   will make the 4th figure from this group of figures the current figure.
+% To delete the entire group of figures use "close(fighandle)".
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 09/18/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+%   Inspired by "Tilefigs" by Charles Plum  
+%   Uses getmondim.m
+% More notes:
+% Will work with docked figures, will ignore modal figures.
+% Extended monitors may have a different resolution from the primary monitor.
+% Placement and size of the taskbar on the primary monitor can be changed
+%   in the code, see commented sections.
+% The size and layout of the figures is determined by the aspect ratio and
+%   the number of figure columns.
+% For a large number of figures, the menubar and toolbar are removed to
+%   increase figure space.
+% Default properties for this group of figures may be coded into the code
+%   below. The following properties are currently set.
+%        'Units','pixels', ...
+%        'NumberTitle','off',...
+%        'MenuBar',menbar,...       (depends on number of figures)
+%        'ToolBar',tbar             (depends on number of figures)
+
+% --------- Key Constants -----------
+% To allow for user or OS borders set the appropriate value in pixels.
+topborder       =0;
+bottomborder    =0;
+rightborder     =0;
+leftborder      =0;
+taskbarborder   =30;
+% Border properties for figures - Adjust if needed.
+% determined by the difference between OuterPosition and Position values.
+% GETFIGDIM can return these values for your system.  
+figureborder    =5;     %#ok
+titleheight     =26;
+menbarheight    =21;
+toolbarheight   =27;
+minfigwidth     =125;
+% Set the default aspect ratio (minimum horizontal/vertical size of the figure).
+def_aspect      =1.1;   
+
+menbarlimit     =3;     % no menubar if numrows > menbarlimit
+toolbarlimit    =3;     % no toolbar if numrows > toolbarlimit
+maxnumrows      =6;     % maximum number of figure rows to create
+% ----------------------------------
+
+monnum=[];
+figs=[];  
+ftitle=[];
+layout=[];
+getname=1;
+if nargin~=0,
+    count=0;
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if isnumeric(arg),      % note "empty" is also considered to be numeric!
+            count=count+1;
+            switch count
+                case 1
+                    figs=arg;
+                case 2
+                    monnum=arg;
+                case 3
+                    layout=arg;
+            end  % switch count
+        elseif ischar(arg),
+            ftitle=arg;
+            getname=0;
+        end  % if ~isempty
+    end  % for
+end  % if nargin
+if isempty(figs),       figs=0;     end
+if isempty(ftitle),     ftitle='';  end
+if isempty(monnum),     monnum=1;   end
+if isempty(layout)||numel(layout)==2,     
+    aspect=def_aspect;
+elseif numel(layout)==1,
+    aspect=layout;
+    layout=[];
+else
+    error ('  Layout cannot have more than 2 elements!')
+end
+
+% alternative methods to find all of the figures.
+% Second method should be more foolproof.
+% allhands=get(0,'Children');
+allhands=findobj('Type','figure');
+% Note that figures without visible handles will not be tiled.
+if figs==0,
+    figs=sort(allhands);
+else
+    [tmp,indx]=intersect(figs,allhands);    %#ok  only tile figures that do exist
+    figs=figs(sort(indx));                  % this keeps the order of the figures
+end
+numfigs=numel(figs);
+% Check WindowStyle property on figures
+m=0;
+for n=1:numfigs,
+    m=m+1;
+    winstyle=get(figs(m),'WindowStyle');
+    if strcmpi(winstyle,'modal'),           % Cannot maximize this figure.
+        figs(m)=[];
+        m=m-1;
+    elseif strcmpi(winstyle,'docked'),      % Docked figures need to be undocked.
+        set(figs(m),'WindowStyle','normal');
+        drawnow
+    end
+end
+numfigs=numel(figs);
+
+% Get screen dimensions.
+scnsize=getmondim(monnum);
+if isempty(scnsize),
+    error ('  Monitor %g does not exist',monnum)
+end
+% ----------------------- TASKBAR PLACEMENT --------------------
+% adjust border for taskbar, edit appropriate line for position of taskbar
+if monnum==1,   
+    bottomborder=bottomborder+taskbarborder;
+end
+% ----------------------- TASKBAR PLACEMENT --------------------
+scnwidth=scnsize(3)-leftborder-rightborder;
+scnheight=scnsize(4)-topborder-bottomborder;
+
+% Try to determine the best layout for the number of figures.
+% Calculate the number of figure columns for different number of rows
+% based upon the screen size to maintain square figures
+numfigcols=zeros(1,maxnumrows);
+for n=2:maxnumrows,
+    barheight=((menbarlimit-n)>=0)*menbarheight+((toolbarlimit-n)>=0)*toolbarheight;
+    numfigcols(n)=fix(scnwidth/((scnheight/n - barheight-titleheight)*aspect));
+% Note that the figure size is created with a minimum aspect ratio. 
+end
+% For one row of figures use the same size figure as for two rows.
+numfigcols(1)=numfigcols(2);
+maxnumfigs=(1:maxnumrows).*numfigcols;
+
+% Calculate offsets for multiple monitors.
+offx=scnsize(1)+leftborder-1;
+offy=scnsize(2)+bottomborder-1;
+
+% Determine layout from numfigs
+if isempty(layout),
+    % Determine a layout (figrows,figcols) for numfigs figures.
+    figrows=1;
+    while numfigs>maxnumfigs(figrows);
+        figrows=figrows+1;
+        if figrows>maxnumrows,
+            error ('  Too many figures are requested! Maximum is %3.0f',maxnumfigs(maxnumrows))
+        end    
+    end
+    figcols=numfigcols(figrows);
+else
+    figrows=layout(1);
+    figcols=layout(2);
+    if figrows>maxnumrows,
+        error ('  Too many figure rows! Maximum is %3.0f',maxnumrows)
+    end 
+end     % isempty(layout)
+    
+% For a large number of figures, the menu and tool bars are turned off to
+% conserve space.
+if figrows > toolbarlimit,
+    tbar='none';
+else
+    tbar='figure';
+end
+if figrows > menbarlimit,
+    menbar='none';
+else
+    menbar='figure';
+end
+
+figwidth=scnwidth/figcols;
+if figwidth < minfigwidth
+    figcols=fix(scnwidth/minfigwidth);
+    figrows=ceil(numfigs/figcols);
+    if figrows>maxnumrows,
+        error ('  Too many figure rows! Maximum is %3.0f',maxnumrows)
+    end 
+    figwidth=scnwidth/figcols;
+end
+
+% For a single row of figures calculate height based upon aspect ratio.
+if figrows==1,
+    figheight=figwidth/aspect + menbarheight + toolbarheight + titleheight;
+    figrows=scnheight/figheight;    % It's ok if figrows is not integer.
+else
+    figheight=scnheight/figrows;
+end
+
+% Now move the individual figures.
+% Note that the OuterPosition property is preferable to the Position property 
+% for setting the figure positions.
+for n=numfigs:-1:1,
+    r=fix((n-1)/figcols)+1;     % calculate row number
+    c=mod(n-1,figcols)+1;       % calculate column number
+    pos=[offx+(c-1)*figwidth+1,offy+(figrows-r)*figheight+1,figwidth,figheight];
+    if getname,
+        ftitle = get(figs(n),'Name');
+        % remove #xx if it exists
+        if ~isempty(ftitle) && ftitle(1)=='#',
+            [tmp,ftitle]=strtok(ftitle);    %#ok
+            ftitle=strtrim(ftitle);         
+        end
+    end
+    if numfigs==1,
+        figtitle=ftitle;
+    else
+        figtitle=['#',int2str(n),'  ',ftitle];
+    end
+     % ------------------- MODIFY FIGURE PROPERTIES -----------------
+    % Move figure and modify properties as needed.
+    set(figs(n),'Name',figtitle,...
+        'Units','pixels', ...
+        'OuterPosition',pos,...
+        'NumberTitle','off',...
+        'MenuBar',menbar,...
+        'ToolBar',tbar);
+    % ------------------- MODIFY FIGURE PROPERTIES -----------------
+    figure(figs(n))             % bring figure to front.
+end
+
+if nargout==1,
+    fighandle=figs;
+end
diff --git a/FigureManagement/vf.m b/FigureManagement/vf.m
new file mode 100755
index 0000000000000000000000000000000000000000..1619d68822f13bdb642b8eee25ddeb719b7e2cd8
--- /dev/null
+++ b/FigureManagement/vf.m
@@ -0,0 +1,58 @@
+function fighandle=vf(varargin)
+% fighandle=vf(figs)      View one or more Figures.
+% This simple function brings the group of figures specified by "figs" to 
+% the front. No tiling or rearrangment of the figures is done.
+% If "figs" is empty then all of the figures are brought to the front.
+%   "fighandle" has the figure handles of the figures brought forward.
+%   Examples:
+%       vf(a) where "a" is a vector of figure handles.
+%       a=vf, vf a, vf [1,6,8], a=vf(1,6,8), vf 1 a 6
+% Note that the command line format is supported.
+
+%   Copyright 2006 Mirtech, Inc.
+%   created 08/22/2006  by Mirko Hrovat on Matlab Ver. 7.2
+%   Mirtech, Inc.       email: mhrovat@email.com
+
+figs=[];    
+if nargin>0
+    for n=1:length(varargin),
+        arg=varargin{n};
+        if ischar(arg),
+            tmp=str2num(arg);   %#ok
+            if isempty(tmp),    % since it is empty then it may be a variable
+                tmp = evalin('base',arg);
+                if isempty(tmp),
+                    error ('  Syntax error in argument!'),
+                end
+            end  % isempty(tmp)
+        else
+            tmp=arg;
+        end  % ischar(arg)
+        figs=[figs,tmp];
+    end  % for
+end
+
+% set this to "on" so that all figures with "HandleVisibility" set to off can be seen.
+set(0,'ShowHiddenHandles','on')     
+% Below are two alternative methods to find all of the figures.
+% Second method should be more foolproof.
+% allhands=get(0,'Children');
+allhands=findobj('Type','figure');
+set(0,'ShowHiddenHandles','off')
+if isempty(figs),
+    figs=sort(allhands)';
+else
+    [tmp,indx]=intersect(figs,allhands);    %#ok tmp not used, view figures that exist
+    figs=figs(sort(indx));                  % order the figures as specified
+end
+if isempty(figs),
+    warning('MATLAB:EmptyValue','There are no figures to select.')
+else
+    for n=numel(figs):-1:1,
+        figure(figs(n))                         % bring figure to front.
+    end
+end
+
+if nargout==1,
+    fighandle=figs;
+end
diff --git a/alignment_test.m b/alignment_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..37e8837a240435995eb9e4021116b9d2f4310559
--- /dev/null
+++ b/alignment_test.m
@@ -0,0 +1,207 @@
+## Copyright (C) 2007 P. Cloetens
+## 
+## 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+## alignment
+## function [offset(,tilt)] = alignment(varargin)
+##      Tomography alignment
+##      determines offset (and tilt) of rotation axis
+##      uses two images acquired at 180 degrees apart, a reference image and a dark image
+##      assumptions:
+##      vertical rotation axis
+##      offset motor translates from left to right in the image
+##      images are manually given or stored in /data/beamline/inhouse/align
+##      with beamline either id19 or set by the global variable FT_BL
+##      align0000.edf: image at 0 degrees
+##      align0001.edf: image at 180 degrees
+##      align0002.edf: reference image
+##      align0002.edf: dark image
+##      tilt (degrees) is determined only when axisposition method is (choose)highlow
+##      offset (pixels) gives current axis position with respect to image middle
+##          corrections to be applied are given when possible
+##
+##      arguments:
+##      argument 1: axisposition method ( default: 'highlow' )
+##          possible values:
+##              highlow: line by line correlation, gives offset and tilt
+##              global: 2D correlation, gives offset only
+##              accurate: 2D correlation, followed by accurate real space determination
+##              choosehighlow: same as highlow, but top and bottom are chosen graphically
+##
+##      e.g.:   [offset,tilt] = alignment;
+##              [offset,tilt] = alignment('highlow');
+##              offset = alignment('global');
+##              offset = alignment('accurate');
+##              [offset,tilt] = alignment('choosehighlow');
+
+## Author: P. Cloetens <cloetens@esrf.fr>
+## 
+## 2007-07-13 P. Cloetens <cloetens@esrf.fr>
+## * Initial revision
+## * Based on alignment.m by Wolfgag and Peter
+
+function [offset,tilt] = alignment(axisposition);
+    global FT_BL
+
+    if isempty(FT_BL)
+        beamline = 'id19';
+    else
+        beamline = FT_BL;
+    end
+    if !nargin
+        axisposition = [];
+    endif
+    if isempty(axisposition)
+        axisposition = "highlow";    
+    endif
+
+    headerlength=1024;
+    # defaults if semi-automatic alignment
+    align_dir = ['/data/' beamline '/inhouse/align'];
+    align_prefix = 'align';
+    nbeg = 0; # image at 0 degrees
+    nend = 1; # image at 180 degrees
+    nref = 2; # reference image
+    ndark = 3; # dark image
+
+    #### message to check beamline is right
+    printf('You are working on beamline %s\n',beamline)
+
+    ####### semi-automatic acquisition ? ########
+    name=sprintf('%s/%s%4.4i.edf',align_dir,align_prefix,nend);
+    descript = dir(name);
+    if isempty(descript)
+        align_auto = 0;
+    elseif ((datenum(clock)-datenum(descript.date))*24 > 0.5)
+        # check if images for alignment are more than 30 minutes old
+        align_auto = 0;
+    else
+        align_auto = 1;
+    end	
+
+    ####### initialisation ########
+    if align_auto
+        n1 = align_dir;
+        n2 = align_prefix;
+    else
+        # manual initialisation 
+        # n1: directory, default is present directory
+        disp('You will have to enter values manually')
+        disp('Please use alignment in *tomo for semi-automatic alignment')
+        # n1: directory, default is present directory
+        n1=cleandirectoryname;
+        # prefix
+        n2 = input('prefix ?        : ','s');
+        ndark = input('number of dark image ?       : ');
+        nref = input('number of reference image ?  : ');
+        nbeg = input('number image 0 degrees?      : ');
+        nend = input('number image 180 degrees?    : ');
+    end # initialisation
+
+    ##########
+    # reading images
+    ##########
+
+    name=sprintf('%s/%s%4.4i.edf',n1,n2,ndark);
+    d=edfread(name);
+    name=sprintf('%s/%s%4.4i.edf',n1,n2,nref);
+    f=edfread(name);
+    name=sprintf('%s/%s%4.4i.edf',n1,n2,nbeg);
+    a0=edfread(name);
+    name=sprintf('%s/%s%4.4i.edf',n1,n2,nend);
+    a1=edfread(name);
+    fp=fopen(name,'rb');
+    hd=fscanf(fp,'%c',headerlength);
+    fclose(fp);
+    pixsize=findheader(hd,'pixel_size','float');
+    if isempty(pixsize)
+        pixsize=findheader(hd,'optic_used','float');
+        if isempty(pixsize)
+            disp('pixel_size and optic_used are not in header')
+            disp('Pixel size is unknown')
+        endif
+    endif
+
+    ##########
+    # selecting region, flatfield and mirror of image 180 degrees
+    ##########
+
+
+    if strcmp(axisposition,'choosehighlow')
+        [rb,re,cb,ce]=imagej_getcorners(a0,'Indicate top of region for alignment','Indicate bottom of region for alignment');
+    else
+        cb = 1;
+        ce = size(a0,2);
+    endif
+    a0=(a0(:,cb:ce)-d(:,cb:ce))./max((f(:,cb:ce)-d(:,cb:ce)),1);
+    a1=(a1(:,cb:ce)-d(:,cb:ce))./max((f(:,cb:ce)-d(:,cb:ce)),1);
+    a1=flipud(a1);
+
+    ##########
+    # determination tilt and offset
+    ##########
+
+    [n,m]=size(a0);
+    if strcmp(FT_BL,'id22')
+        offset_motor_name = 'ys';
+    else
+        offset_motor_name = 'pmy';
+    endif
+    limz=0.5; # maximum vertical drift before warning 
+    switch axisposition
+    case {'global','accurate'}
+        sizepow2=2^floor(log(m)/log(2)); # to use a good size for fft's
+        shift=correlate(cut(a0,n,sizepow2),cut(a1,n,sizepow2),0);
+        if strcmp(axisposition,'accurate')
+            if (abs(shift(2))>10*limz)
+                # this is suspicious, we don't trust result of correlate
+                printf('Pre-correlation yields %5.2f pixels vertical motion\n',shift(2))
+                printf('We do not consider this\n')
+                shift=[0 0];
+            endif                
+            # limit the size of region for comparison to cutsize in both directions
+            cutsize = 1024;
+            oldshift = round(shift);
+            if ((n>cutsize)|(m>cutsize))
+                shift = oldshift + findshift(cut(a0,min(n,cutsize),min(m,cutsize)),cut(circshift(a1,oldshift),min(n,cutsize),min(m,cutsize)));
+            else
+	        shift = findshift(a0,a1,[],oldshift);
+	    endif
+            if (norm(shift-oldshift)>2)
+                printf('Pre-correlation and accurate correlation are not consistent\n')
+                printf('!!!Please check or use manual!!!\n')
+            endif
+        endif
+        offset=shift(1)/2;
+        if abs(shift(2))>limz
+	    disp('Verify alignment or motion sample !!!')
+	    printf('Vertical motion: %5.2f pixels\n',shift(2))
+        end
+    case {'highlow','choosehighlow'}
+        c=correlate1(a0,a1);
+        plot(c);
+        y=1:m;
+        dec=polyfit(y,c,1);
+        tilt=-dec(1)/2*180/pi;
+        offset=(dec(2)+m/2*dec(1))/2;
+        printf('Tilt to apply (degrees): mvr rotc %5.3f\n',tilt)
+    endswitch
+    if !isempty(pixsize)
+        printf('Pixel size is %3.1f microns\n',pixsize)
+        printf('Offset to apply (mm) = %5.2f pixels: mvr %s %6.4f\n',-offset,offset_motor_name,-offset*pixsize/1000)
+    else
+        printf('Offset to apply = %5.2f pixels\n',-offset)
+    endif
+endfunction
diff --git a/assess_autofind.m b/assess_autofind.m
new file mode 100755
index 0000000000000000000000000000000000000000..40b7f6bf12d602a9dc0cf34066e1f5b168c007f0
--- /dev/null
+++ b/assess_autofind.m
@@ -0,0 +1,54 @@
+function results = assess_autofind
+
+global app;
+
+trial = load('../../tmp/21082006/random/autofind_extspot.mat');
+
+results=[];
+counter = 1;
+for i=1:4818
+
+if ~isempty(app.extspot(i).ExtCentroid)
+
+    results(counter,1) = i;
+
+  if isempty(trial.point(i).x)
+  
+    results(counter,2) = -1;
+  
+    for j=app.extspot(i).ExtStartImage:app.extspot(i).ExtEndImage
+      if ~exist(sprintf('full/full%04d.edf',j))
+        results(counter,2) = -2; %-2 indicates missing full image
+      end
+    end
+    
+  else   
+  difx = app.extspot(i).ExtCentroid(1) - trial.point(i).x;
+  dify = app.extspot(i).ExtCentroid(2) - trial.point(i).y - 50;
+  
+  %need to correct if roll has gone over edge of the image
+  if trial.point(i).x > app.bb.directbeam(3)
+    difx = app.extspot(i).ExtCentroid(1) - (trial.point(i).x - app.bb.directbeam(3));
+    disp('here - x roll')
+  end
+  
+  if trial.point(i).y > app.bb.directbeam(4)
+  dify = app.extspot(i).ExtCentroid(2) - (trial.point(i).y - app.bb.directbeam(4)) - 50;
+  disp('here - y roll')
+  end
+  
+  
+  dif = sqrt(difx^2 + dify^2);
+  results(counter,2) = dif;
+  end
+  
+  counter = counter +1;
+  
+end
+  
+  
+end
+
+
+
+
diff --git a/assess_autofind_interactive.m b/assess_autofind_interactive.m
new file mode 100755
index 0000000000000000000000000000000000000000..1beadd1462490048cb165b0d6b729b8bf8dca118
--- /dev/null
+++ b/assess_autofind_interactive.m
@@ -0,0 +1,119 @@
+function results = assess_autofind_interactive
+
+global app;
+
+trial = load('../../tmp/autofind_extspot.mat');
+
+results=[];
+counter = 1;
+for i=1:3500
+
+
+  if ~isempty(app.extspot(i).ExtCentroid)
+
+    results(counter,1) = i;
+
+    if isempty(trial.point(i).x)
+
+      results(counter,2) = -1;
+
+      for j=app.extspot(i).ExtStartImage:app.extspot(i).ExtEndImage
+        if ~exist(sprintf('full/full%04d.edf',j))
+          results(counter,2) = -2; %-2 indicates missing full image
+        end
+      end
+
+    else
+      difx = app.extspot(i).ExtCentroid(1) - trial.point(i).x;
+      dify = app.extspot(i).ExtCentroid(2) - trial.point(i).y - 50;
+
+      %need to correct if roll has gone over edge of the image
+      if trial.point(i).x > app.bb.directbeam(3)
+        difx = app.extspot(i).ExtCentroid(1) - (trial.point(i).x - app.bb.directbeam(3));
+       % disp('here - x roll')
+      end
+
+      if trial.point(i).y > app.bb.directbeam(4)
+        dify = app.extspot(i).ExtCentroid(2) - (trial.point(i).y - app.bb.directbeam(4)) - 50;
+        %disp('here - y roll')
+      end
+
+
+      
+      dif = sqrt(difx^2 + dify^2);
+      results(counter,2) = dif;
+    end
+
+    counter = counter +1;
+
+  end
+
+
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%interactive part
+dummy = find(results(:,2)>20);
+bads = results(dummy,1);
+
+
+if 0
+
+counter = 0
+for i=1:length(bads);
+  
+  struct_id = bads(i);
+  
+  if counter > 0
+    counter = counter - 1
+  else
+close all
+    im = imread(sprintf('../../tmp/correlate150906/blob%04d.jpg', struct_id));
+  imshow(im,[])
+ 
+disp(sprintf('replaced flag == %d', app.extspot(struct_id).Replaced));  
+  flag = input('type n for Next, s to Skip next 10, f to see Full image','s')
+  
+  if flag == 'n'
+    
+    %do nothing, go to next bad
+    
+  elseif flag == 's'
+    
+   counter = 10;
+   
+   
+  elseif flag == 'f'
+    figure
+    maxim = app.extspot(struct_id).MaxImage;
+    full = edf_read(sprintf('full/full%04d.edf',maxim));
+    imshow(full, []);
+    hold on;
+    
+    %blue difspot
+    dif = app.extspot(struct_id).Centroid;
+  plot(dif(1), dif(2), 'x');
+  
+  %green our guess
+  ourext = app.extspot(struct_id).ExtCentroid;
+  bb = app.bb.directbeam;
+  plot(ourext(1)+bb(1), ourext(2)+bb(2)-50, 'gx')
+  
+  %red auto_find guess
+  autoext_x = trial.point(struct_id).x;
+  autoext_y = trial.point(struct_id).y;  
+  plot(autoext_x+bb(1), autoext_y+bb(2), 'rx')
+  
+  k=waitforbuttonpress;
+  
+  hold off
+  end
+  
+  end
+end
+
+
+
+
+end
\ No newline at end of file
diff --git a/gjthesis/fit_spline_bivariant_mdf.m b/gjthesis/fit_spline_bivariant_mdf.m
new file mode 100755
index 0000000000000000000000000000000000000000..4fca12de5f88d00d81eb2392bbebf40ecff92164
--- /dev/null
+++ b/gjthesis/fit_spline_bivariant_mdf.m
@@ -0,0 +1,67 @@
+function [zi_upred,zi_npred]=fit_spline_bivariant_mdf(rawx,rawy,rawz,...
+    x_out,numberofgroups,numberofknots,numx)
+
+% cross validation of bivariant spline for different numberofknots
+% This is just one run to split data into numberofgroups groups
+% It is recommended to run many times for building up a meaningful statistics.
+% Yuan Xiong May 2008
+
+% rawx=rawx(:); rawy=rawy(:); rawz=rawz(:); 
+nomberpfpoints=length(rawx);
+[ind_i,ind_r]=pfDivideDataset(nomberpfpoints,numberofgroups);
+
+L_numberofknots=length(numberofknots); % number of knot sets
+spl_order_x=4; spl_order_y=4;
+
+%  zi_upred is predicted disp for uniform knots
+zi_upred=zeros(nomberpfpoints,L_numberofknots);  
+%  zi_npred is predicted disp for non_uniform knots
+zi_npred=zeros(nomberpfpoints,1);  
+
+for j=1:numberofgroups
+    fprintf('       group=%4d;\n',j);
+    % % ii is the training data, and ~ii is the test data
+    ii=true(nomberpfpoints,1); % all raw data points
+
+    ii(ind_r(ind_i(j):ind_i(j+1)))=false; % leave jth group out
+    
+%    fitX=rawx(ii); fitY=rawy(ii); fitZ=rawz(ii);
+%    testX=rawx(~ii); testY=rawy(~ii); testZ=rawz(~ii); 
+%    % end defining fit and test data points
+%     direct use of them to save mem
+
+    xunique=unique(rawx(ii)); yunique=unique(rawy(ii));
+    [x,y,z]=griddata(rawx(ii),rawy(ii),rawz(ii),xunique,yunique','nearest');
+    xmin=xunique(1); xmax=xunique(end); 
+    ymin=yunique(1); ymax=yunique(end); 
+    % fix the konts in x direction 
+    xu=linspace(xmin,xmax,numx);
+    xknots=augknt(xu,spl_order_x); 
+    for k=1:L_numberofknots
+        %fprintf('    j=%4d,  k=%4d;\n',j,k);
+        numy=numberofknots(k);
+        yu=linspace(ymin,ymax,numy);
+        yknots=augknt(yu,spl_order_y); 
+        spline_x=spap2_simple({xknots,yknots},...
+            [spl_order_x,spl_order_y],{xunique,yunique},z');
+        zi_upred(~ii,k)=fnval_bayes(spline_x,rawx(~ii),rawy(~ii));
+    end
+    
+
+%     spline_x=fit2_bivariant(x,y,z);
+%     zi_npred(~ii)=fnval_mdf(spline_x,rawx(~ii),rawy(~ii));
+end
+
+function [ind_i,ind_r]=pfDivideDataset(nomberpfpoints,numberofgroups)
+% the split is implemented by randomly select the index of the data points
+% ind_i defines the start and end positions of each group.
+%       for example ind_i=[1;100;200], 
+%       then index 1~100, 101~200 forms index of two groups
+% ind_r is a random permutation of (1:nomberpfpoints)',
+%      then, ind_r(1:100) is the index of the first group,
+%       ind_r(101:200) is the index of the second group.
+%       z(ind_r(1:100)) is the disp of the first group etc.
+%       (see the definition of ii in the main function).
+
+ind_i=round(linspace(1,nomberpfpoints,numberofgroups+1)'); 
+ind_r=(randperm(nomberpfpoints))'; 
diff --git a/gjthesis/optimise_uniform_knots.m b/gjthesis/optimise_uniform_knots.m
new file mode 100755
index 0000000000000000000000000000000000000000..cbe246ed5eec0781ec8e230f29fd4eed9117cf40
--- /dev/null
+++ b/gjthesis/optimise_uniform_knots.m
@@ -0,0 +1,55 @@
+function results=optimise_uniform_knots(first,last,wdir)
+if isdeployed
+    first=str2num(first);
+    last=str2num(last);
+end
+
+cd(wdir)
+
+
+% load the data and outline
+tmp=load('lsp_a_aligned.txt');
+rawx=tmp(:,1);rawy=tmp(:,2);rawz=tmp(:,3);
+x_out=load('lsp_outline.txt');
+numberofpoints=length(rawz);
+clear tmp;
+
+% set parameters
+numx=30; % numberofknots in the x-direction
+numberofiterations=3;
+numberofgroups=5;
+numberofknots=[20:1:170];
+
+numberofknots_local=numberofknots(first:last);
+
+L_numberofknots=length(numberofknots_local);
+
+% rms error for each iteration and for different numberofknots
+error_rms_i=zeros(numberofiterations,L_numberofknots);
+
+
+
+for i=1:numberofiterations
+    fprintf('  Iter=%4d;\n',i);
+
+    [zi_upred,zi_npred]=fit_spline_bivariant_mdf(rawx,rawy,rawz,x_out,...
+        numberofgroups,numberofknots_local,numx);
+    for j=1:L_numberofknots
+        e_temp=zi_upred(:,j)-rawz(:);
+        error_rms_i(i,j)=sqrt((e_temp'*e_temp)/numberofpoints);
+    end
+end
+
+% rms error averaged over all iterations
+error_rms=mean(error_rms_i,1)';
+knotspacings=(max(rawy)-min(rawy))./numberofknots_local(:);
+
+% save the results for later plot
+results.ynumberofknots=numberofknots_local;
+results.yknotspacings=knotspacings;
+results.error_rms=error_rms;
+save(sprintf('results_%04d',first),'results');
+
+end
+
+
diff --git a/gtARTSimulate.m b/gtARTSimulate.m
new file mode 100755
index 0000000000000000000000000000000000000000..269afeb511690341c8ae79624213755b99201d33
--- /dev/null
+++ b/gtARTSimulate.m
@@ -0,0 +1,295 @@
+function gtART3D(...
+  scanname,...
+  parfilename,...
+  p_numbers,...
+  psi_angles,...
+  xsi_angles,...
+  delta_angles,...
+  twotheta,...
+  eta,...
+  lambda,...
+  nbiter,...
+  pixsize,...
+  braggangle,...
+  np,nq,...
+  offset,...
+  z1,nz,...
+  x1,nx,...
+  y1,ny)
+% write .par file ready for rec_alg to use
+%
+%
+% function make_art_parfile(scanname,parfilename,p_numbers,psi_angles,xsi_angles,delta_angles,lambda,nbiter,pixsize,braggangle,np,nq,offset,z1,nz,x1,nx,y1,ny)
+% 
+% scanname  : name of scan
+% parfilenane: name of parameterfile (output)
+% p_numbers: vector containing the projections to be taken into account, e.g. [0:10:180]
+% p_angles : vector containing the correpsonding projection angles in degree e.g. [0:20:360]
+% lambda   : ART loop update parameter
+% nbiter   : number of ART iterations
+% pixsize  : pixelsize [mm]
+% braggangle: Bragg angle
+% np        : number of pixels in projections (hoizontal)
+% nq        : number of pixel in projections (vertical)
+% offset    : offset of the rotation axis with respect to the center of the image (in pixels) 
+% z1        : z start of reconstructed volume
+% nz        : number of reconstructed slices 
+% x1        : x start of reconstructed volume //andy 21/6/06
+% nx        : size of reconstructed volume in x
+% y1        : y start of reconstructed volume
+% ny        : size of reconstructed volume in y(attention: pixelsize in reconstructed image will be half
+% the pixel size in original projection images
+
+
+
+%% mods
+parfilename = 'test.par';
+scanname='testing';
+p_numbers=[1 2 3 4];
+psi_angles=[0 0 0 0];
+xsi_angles=[90 90 90 90];
+delta_angles=[0 0 0 0];
+nbiter=1;
+pixsize=0.001;
+braggangle=0;
+twotheta=[20 20 20 20];
+eta=[0 90 180 270];
+lambda=0;
+
+%%
+
+rec_alg='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/rec_alg';
+seg2view='/users/bleuet/postdoc/programmes/main/new_ART/AREMIS/v2.0/bin/seg2view';
+
+fid=fopen(parfilename,'w');
+nbradio=length(p_numbers);
+
+% Algorithm paramters
+
+nbiter_half_quadra = 1;
+nbsauv = nbiter;
+rec_gene_filename = scanname;
+ext_rec0 = 1;
+if nbiter>1
+   lambda_flag = 1;
+else
+   lambda_flag=0;
+end   	
+
+err_flag = 0;
+algo_type = 1;
+block_size = length(p_numbers);  % for straight back projection,
+%block_size should be = num projections
+% block_size=1;
+% if block_size=N it will forward project after each N projections
+proj_mng = 'A';
+nb_resol = 1;
+thresh_supp = 100;
+clip_supp = 4;
+clip_sphere = 0;
+histo_size = 100;
+maxvol = 1000.;
+minvol = -10.;
+vol_type = 3;
+param1 = 0.1;  % paramX not used for ART (algo_type=1 or =2)
+param2 = 0.00005;
+param3 = 0.00005;
+param4 = 0.05;
+param5 = 0.82;
+
+%geometry paramters
+fgd = 145000;         % Distance source detector [mm]  - put it far away, to approximate a parallel beam
+disp('*****************************')
+
+
+psi = psi_angles;     % first Euler angle (==omega)  [degrees]
+xsi = xsi_angles;     % second Euler angle
+delta = delta_angles; % third Euler angle
+np=2048;
+nq=2048;
+pepd= pixsize;        % horizontal Pixel size, [mm]
+peqd= pixsize;        % vertical Pixel size [mm]
+
+p1d=-1023.5;          % pixels
+q1d=-1023.5;          % pixels
+
+[alphap,alphaq]=gtGT2ARTangles(twotheta,eta);
+
+%ang=15;
+%alphap=[-ang+.1 -ang-.1 ang ang];
+%alphaq=[-ang ang ang -ang];
+
+pdisp=tan(deg2rad(alphap))*fgd;
+qdisp=tan(deg2rad(alphaq))*fgd;
+%pdisp=repmat(0,size(qdisp));
+%qdisp=repmat(0,size(pdisp));
+
+
+% at the moment, moving pgd and p0 in opposite directions, but equal
+% amounts.  Probably only works when VOI is centred over detector!!!
+pgd=-pdisp/pixsize;  % -
+qgd=-qdisp/pixsize;
+
+
+%%%%%%%%%%%%% m0,p0,q0 - coordinate of O in F
+m0=-(fgd-2000);  % reconstruction object is centred over detector!
+%m0=-fgd;                   % mm
+p0=pdisp;          % mm
+q0=qdisp;          % mm
+
+
+ipd = 0;              % ROI begin horizontal [pixels] 
+iqd = 0;              % ROI begin vertical [pixels]
+ipf=2047;
+iqf=2047;
+
+%Reconstruction paramters
+
+% THIS ONLY WORKS WITH PSI_ANGLES ALL ZERO.  OTHERWISE, VOI MUST BE CENTRED
+% ON O
+% x1=-(250*pixsize),
+%  y1=x1-900;   % -900  for synthetic, -2000 real
+%  z1=x1;
+%  pex=5*pixsize,pey=pex;pez=pex;
+%  nx=100;ny=nx;nz=nx;
+
+
+x1=-(200*pixsize);y1=x1;z1=x1;
+pex=5*pixsize;pey=pex;pez=pex;
+nx=80;ny=nx;nz=nx;
+
+
+
+
+
+
+
+
+
+%  x1=-512,
+%  y1=x1-400;
+%  z1=x1;
+%  pex=16,pey=pex;pez=pex;
+%  nx=2*abs(x1)/pex;ny=nx;nz=nx;
+
+% this is for object from -64:1:64
+%x1=-(.5);y1=x1;z1=x1;  % mm
+%nx=101;ny=nx;nz=nx;   % num pixels
+%pex=0.01;pey=pex;pez=pex;   % size of pixel in mm
+
+
+% approximate sample size
+%x1=-(256*pixsize),y1=x1;z1=x1;
+%pex=4*pixsize,pey=pex;pez=pex;
+%nx=128;ny=nx;nz=nx;
+
+% uncomment this for: object from -1024:4:1024
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  decimation=4;
+%  pex=decimation*pixsize;pey=pex;pez=pex;
+%  nx=2048/decimation;ny=nx;nz=nx;
+
+
+%if 0  % full resolution - voxel size in object = detector pixel size  REC_ALG FAILS - CANNOT ALLOCATE SO MUCH MEMORY!!
+%  x1=-1024*pixsize;y1=x1;z1=x1;
+%  pex=pixsize;pey=pex;pez=pex;
+%  nx=2048;ny=2048;nz=2048;
+%end
+
+
+% write out file
+
+
+fprintf(fid,'PAGBEGIN SYSTEMAL\n');
+fprintf(fid,'PROJ_GENE_FILENAME = %s\n',scanname);
+for i=1:nbradio
+  fprintf(fid,'EXT_PROJ%d = %d\n',i-1,p_numbers(i));
+end
+
+fprintf(fid,'NBITER = %d\n',nbiter);
+fprintf(fid,'NBITER_HALF_QUADRA = %d\n',nbiter_half_quadra);
+fprintf(fid,'NBSAUV = %d\n',nbsauv);
+fprintf(fid,'REC_GENE_FILENAME = %s\n',rec_gene_filename);
+for i=1:nbiter
+     fprintf(fid,'EXT_REC%d = %d\n',i-1,i);
+end 
+    
+fprintf(fid,'LAMBDA_FLAG = %d\n',lambda_flag);
+if lambda_flag
+  for i=1:nbiter
+     fprintf(fid,'LAMBDA%d = %f\n',i-1,lambda(i));
+   end
+else 
+  fprintf(fid,'LAMBDA = %f\n',lambda);
+end       
+fprintf(fid,'ERR_FLAG = %d\n',err_flag);
+fprintf(fid,'ALGO_TYPE = %d\n',algo_type);
+fprintf(fid,'BLOCK_SIZE = %d\n',block_size);
+fprintf(fid,'PROJ_MNG = %s\n',proj_mng);
+fprintf(fid,'NB_RESOL = %d\n',nb_resol);
+fprintf(fid,'THRESH_SUPP = %d\n',thresh_supp);
+fprintf(fid,'CLIP_SUPP = %d\n',clip_supp);
+fprintf(fid,'CLIP_SPHERE = %d\n',clip_sphere);
+fprintf(fid,'HISTO_SIZE = %d\n',histo_size);
+fprintf(fid,'MAXVOL = %f\n',maxvol);
+fprintf(fid,'MINVOL = %f\n',minvol);
+fprintf(fid,'VOL_TYPE = %d\n',vol_type);
+fprintf(fid,'PARAM1 = %f\n',param1);
+fprintf(fid,'PARAM2 = %f\n',param2);
+fprintf(fid,'PARAM3 = %f\n',param3);
+fprintf(fid,'PARAM4 = %f\n',param4);
+fprintf(fid,'PARAM5 = %f\n',param5);
+
+fprintf(fid,'PAGEND SYSTEMAL\n') ;
+fprintf(fid,'PAGBEGIN ACQGEO\n');
+fprintf(fid,'NBRADIO = %d\n',nbradio);
+
+for i=1:nbradio
+fprintf(fid,'#radio %d origine position\n',i);
+fprintf(fid,'POSITION = %d\n',i);
+fprintf(fid,'FGD = %f\n',fgd);
+fprintf(fid,'PGD = %f\n',pgd(mod(i-1,length(pgd))+1));
+fprintf(fid,'QGD = %f\n',qgd(mod(i-1,length(qgd))+1));	
+fprintf(fid,'PEPD = %f\n',pepd);	
+fprintf(fid,'PEQD = %f\n',peqd);	
+fprintf(fid,'P1D = %f\n',p1d(mod(i-1,length(p1d))+1));
+fprintf(fid,'Q1D = %f\n',q1d(mod(i-1,length(q1d))+1));
+fprintf(fid,'NP =  %d\n',np(mod(i-1,length(np))+1));
+fprintf(fid,'NQ =  %d\n',nq(mod(i-1,length(nq))+1));
+% this next line uses each value for the angles, if it exists.  Otherwise
+% it just repeats the single value over and over.  GJ
+fprintf(fid,'PSI = %f\n',psi(mod(i-1,length(psi))+1));
+fprintf(fid,'XSI = %f\n',xsi(mod(i-1,length(xsi))+1));
+fprintf(fid,'DELTA = %f\n',delta(mod(i-1,length(delta))+1));
+fprintf(fid,'PO = %f\n',p0(mod(i-1,length(p0))+1));	
+fprintf(fid,'QO = %f\n',q0(mod(i-1,length(q0))+1));
+fprintf(fid,'MO = %f\n',m0);
+fprintf(fid,'IPD = %d\n',ipd);
+fprintf(fid,'IQD = %d\n',iqd);
+fprintf(fid,'IPF = %d\n',ipf);
+fprintf(fid,'IQF = %d\n',iqf);
+end
+
+fprintf(fid,'PAGEND ACQGEO\n');
+fprintf(fid,'PAGBEGIN OBJET\n');
+fprintf(fid,'PEX = %f\n',pex);
+fprintf(fid,'PEY = %f\n',pey);
+fprintf(fid,'PEZ = %f\n',pez);
+fprintf(fid,'X1 = %f\n',x1);
+fprintf(fid,'Y1 = %f\n',y1);
+fprintf(fid,'Z1 = %f\n',z1);
+fprintf(fid,'NX = %d\n',nx);
+fprintf(fid,'NY = %d\n',ny);
+fprintf(fid,'NZ = %d\n',nz);
+fprintf(fid,'PAGEND OBJET\n');
+
+       
+fclose(fid);
+
+
+
+
+  system(sprintf('%s %s',rec_alg,whole_parfilename));
+  for n=1:nbiter
+    system(sprintf('%s %s_res0_%d\n\n',seg2view,scanname,n));
+  end
diff --git a/gtFindBoundingBox.m b/gtFindBoundingBox.m
new file mode 100755
index 0000000000000000000000000000000000000000..9455ddda91fa97a38ed9a19715ff1ca519d1d6c6
--- /dev/null
+++ b/gtFindBoundingBox.m
@@ -0,0 +1,77 @@
+function acq=gtFindBoundingBox(acq)
+  
+  name=sprintf('0_rawdata/%s/darkend0000.edf',acq.name);
+  d=edf_read(name)./acq.ndark;
+  name=sprintf('0_rawdata/%s/ref0001_0000.edf',acq.name);
+  ref0=edf_read(name)-d;
+  name=sprintf('0_rawdata/%s/ref0001_%04d.edf',acq.name,acq.nproj);
+  ref1=edf_read(name)-d;
+ 
+  
+  m=mean2(ref0(round(acq.ydet/2-127:acq.ydet/2+128),round(acq.xdet/2-127:acq.xdet/2+128)));
+  cen=double(ref0>(0.5*m));
+  
+  marker=zeros(acq.ydet,acq.xdet);
+  marker(round(acq.ydet/2),round(acq.xdet/2))=1;
+  cen=imreconstruct(marker,cen);
+  tmp=regionprops(cen,'BoundingBox');
+  bb=tmp.BoundingBox;
+  bb=[ceil(bb(1:2)),bb(3:4)+1];
+  
+ 
+
+  name=sprintf('0_rawdata/%s/%s0000.edf',acq.name,acq.name);
+  im0=(edf_read(name)-d)./ref0;
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,acq.nproj-1);
+  im1=(edf_read(name)-d)./ref1;
+  
+  a0=gtcrop(im0,bb);
+  a1=fliplr(gtcrop(im1,bb));
+  
+  shift=[];
+  assignin('base','shift',shift);
+  findshifts2(a0,a1);
+  while isempty(shift)
+    drawnow;
+    shift=evalin('base','shift');
+  end  
+    
+  shift=evalin('base','shift')
+  if mod(bb(3),2)
+    acq.rotx=bb(1)+bb(3)/2+shift(2)/2-0.5;
+  else
+    acq.rotx=bb(1)+bb(3)/2+shift(2)/2;
+  end
+  
+  % rotx will be forced to be either .0 or .5 
+  acq.rotx=round(acq.rotx*2)/2;
+  
+  %this vertical drift can't be easy found without zooming on a little
+  %feature
+  if shift(1)==0
+    acq.zdrift=zeros(acq.nproj+1,1);
+  else
+    acq.zdrift=[0:shift(1)/acq.nproj:shift(1)];
+  end
+  
+  %determine the limits of sample horizontally
+ disp('Trying to determine a tight BoundingBox around the sample and a region for intensity normalization');
+ [first,last,ims]=gtFindSampleEdges(acq,bb);
+ 
+ width=ceil(max(acq.rotx-first,last-acq.rotx));
+ 
+ if mod(acq.rotx,1)
+    sprintf('rotation axis is centered between pixels %d and %d',acq.rotx,acq.rotx+1)
+    %mindist=min(round(acq.rotx)-bb(1),bb(1)+bb(3)-round(acq.rotx));
+    acq.bb=[round(acq.rotx)-width,bb(2),2*width,bb(4)];
+  else  
+    sprintf('rotation axis is centered on pixel %d',acq.rotx)
+    %mindist=min(acq.rotx-bb(1),bb(1)+bb(3)-1-acq.rotx);
+    acq.bb=[acq.rotx-width,bb(2),2*width+1,bb(4)];
+  end
+  
+test0=gtcrop(im0,acq.bb);
+test1=gtCrop(im1,acq.bb);
+findshifts2(test0,fliplr(test1));
+ 
+end  
\ No newline at end of file
diff --git a/gtFindBoundingBox.m~ b/gtFindBoundingBox.m~
new file mode 100755
index 0000000000000000000000000000000000000000..5dc22a7101eb18eb7d0b3d04c6837b4c96e72f26
--- /dev/null
+++ b/gtFindBoundingBox.m~
@@ -0,0 +1,78 @@
+function acq=gtFindBoundingBox(acq)
+  
+  name=sprintf('0_rawdata/%s/darkend0000.edf',acq.name);
+  d=edf_read(name)./acq.ndark;
+  name=sprintf('0_rawdata/%s/ref0001_0000.edf',acq.name);
+  ref0=edf_read(name)-d;
+  name=sprintf('0_rawdata/%s/ref0001_%04d.edf',acq.name,acq.nproj);
+  ref1=edf_read(name)-d;
+ 
+  
+  m=mean2(ref0(round(acq.ydet/2-127:acq.ydet/2+128),round(acq.xdet/2-127:acq.xdet/2+128)));
+  cen=double(ref0>(0.5*m));
+  
+  marker=zeros(acq.ydet,acq.xdet);
+  marker(round(acq.ydet/2),round(acq.xdet/2))=1;
+  cen=imreconstruct(marker,cen);
+  tmp=regionprops(cen,'BoundingBox');
+  bb=tmp.BoundingBox;
+  bb=[ceil(bb(1:2)),bb(3:4)+1];
+  
+ 
+
+  name=sprintf('0_rawdata/%s/%s0000.edf',acq.name,acq.name);
+  im0=(edf_read(name)-d)./ref0;
+  name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,acq.nproj-1);
+  im1=(edf_read(name)-d)./ref1;
+  
+  a0=gtcrop(im0,bb);
+  a1=fliplr(gtcrop(im1,bb));
+  
+  shift=[];
+  assignin('base','shift',shift);
+  findshifts2(a0,a1);
+  while isempty(shift)
+    drawnow;
+    shift=evalin('base','shift');
+  end  
+    
+  shift=evalin('base','shift')
+  if mod(bb(3),2)
+    acq.rotx=bb(1)+bb(3)/2+shift(2)/2-0.5;
+  else
+    acq.rotx=bb(1)+bb(3)/2+shift(2)/2;
+  end
+  
+  % rotx will be forced to be either .0 or .5 
+  acq.rotx=round(acq.rotx*2)/2;
+  
+  %this vertical drift can't be easy found without zooming on a little
+  %feature: possible solution: put absorption markers on sample 
+  
+  if shift(1)==0
+    acq.zdrift=zeros(acq.nproj+1,1);
+  else
+    acq.zdrift=[0:shift(1)/acq.nproj:shift(1)];
+  end
+  
+  %determine the limits of sample horizontally
+ disp('Trying to determine a tight BoundingBox around the sample and a region for intensity normalization');
+ [first,last,ims]=gtFindSampleEdges(acq,bb);
+ 
+ width=ceil(max(acq.rotx-first,last-acq.rotx));
+ 
+ if mod(acq.rotx,1)
+    sprintf('rotation axis is centered between pixels %d and %d',acq.rotx,acq.rotx+1)
+    %mindist=min(round(acq.rotx)-bb(1),bb(1)+bb(3)-round(acq.rotx));
+    acq.bb=[round(acq.rotx)-width,bb(2),2*width,bb(4)];
+  else  
+    sprintf('rotation axis is centered on pixel %d',acq.rotx)
+    %mindist=min(acq.rotx-bb(1),bb(1)+bb(3)-1-acq.rotx);
+    acq.bb=[acq.rotx-width,bb(2),2*width+1,bb(4)];
+  end
+  
+test0=gtcrop(im0,acq.bb);
+test1=gtCrop(im1,acq.bb);
+findshifts2(test0,fliplr(test1));
+ 
+end  
\ No newline at end of file
diff --git a/gtFindBoundingBoxnew.m~ b/gtFindBoundingBoxnew.m~
new file mode 100755
index 0000000000000000000000000000000000000000..6b6cd5c1c43b43ae466b59215e2b000bf6b5bb80
--- /dev/null
+++ b/gtFindBoundingBoxnew.m~
@@ -0,0 +1,51 @@
+function acq=gtFindBoundingBoxnew(acq,dim)
+ % 01/08/2007
+ % Gives only approximate bounding box of direct beam to be used for
+ % calibration and to be refined as sample bounding box.
+  
+ %%%%%%%%%%%%%%%%%%%%
+ acq.nproj=3600
+ acq.calibration='images at end';
+ %%%%%%%%%%%%%%%%%%%%%
+ 
+ refarea=127;
+ 
+ if strcmpi(acq.type,'180degree')
+   totproj=acq.nproj;
+ elseif strcmpi(acq.type,'360degree');
+   totproj=acq.nproj*2;
+ else
+   disp('unknown scantype in gtFindBoundingBoxnew');
+   return;
+ end
+
+ d=edf_read(sprintf('0_rawdata/%s/dark.edf',acq.name));
+ name=sprintf('0_rawdata/%s/ref0000_0000.edf',acq.name);
+ ref0=edf_read(name)-d;
+ name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj);
+ ref1=edf_read(name)-d;
+
+ ref=(ref0+ref1)/2;
+ 
+ % calculate mean value m in central part of the image
+ m=mean2(ref(round(acq.ydet/2-refarea:acq.ydet/2+refarea+1),round(acq.xdet/2-refarea:acq.xdet/2+refarea+1)));
+ cen=double(ref>(0.5*m));  % should correspond to direct beam footprint
+
+ % find the direct beam region bb automatically (supposes fairly homogeneous
+ % beam profile - attention with ID11 data here... !
+
+ marker=zeros(acq.ydet,acq.xdet);
+ marker(round(acq.ydet/2),round(acq.xdet/2))=1;
+ cen=imreconstruct(marker,cen);
+ tmp=regionprops(cen,'BoundingBox');
+ bb=tmp.BoundingBox;
+ bb=[ceil(bb(1:2)),bb(3:4)-1];
+ 
+ % make sure the bbox width and height are even numbers (needed for correlation)
+ bb(3:4)=ceil(bb(3:4)/2)*2;
+ 
+ figure('name','Preliminary bounding box')
+ imshow(ref,[])
+ hold on
+ plot([bb(1),bb(1)+bb(3)-1,bb(1)+bb(3)-1,bb(1),bb(1)],[bb(2),bb(2),bb(2)+bb(4)-1,bb(2)+bb(4)-1,bb(2)],'r-') 
+ 
diff --git a/gtFindBoundingBoxnew_xxx.m b/gtFindBoundingBoxnew_xxx.m
new file mode 100755
index 0000000000000000000000000000000000000000..6be16085544eb2ef576feb5642f7a3f85c82defb
--- /dev/null
+++ b/gtFindBoundingBoxnew_xxx.m
@@ -0,0 +1,258 @@
+function acq=gtFindBoundingBoxnew(acq,dim)
+ % 24/07/2007:  switch to images at end of scan for rotation axis determination  
+ %              implement more precise determination of rotation axis based on findshift (octave)
+ %              possible use of callibration scan
+ 
+ 
+ 
+ 
+ 
+  %%%%%%%%%%%%%%%%%%%%
+ acq.nproj=3600
+ acq.calibration='images at end';
+ %%%%%%%%%%%%%%%%%%%%%
+ 
+ 
+ 
+ if strcmpi(acq.type,'180degree')
+   totproj=acq.nproj;
+ elseif strcmpi(acq.type,'360degree');
+   totproj=acq.nproj*2;
+ else
+   disp('unknown scantype in gtFindBoundingBoxnew');
+   return;
+ end
+
+ %name=sprintf('0_rawdata/%s/darkend0000.edf',acq.name);
+ %d=edf_read(name)./acq.ndark;
+ d=edf_read(sprintf('0_rawdata/%s/dark.edf',acq.name));
+ name=sprintf('0_rawdata/%s/ref0000_0000.edf',acq.name);
+ ref0=edf_read(name)-d;
+ name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj);
+ ref1=edf_read(name)-d;
+
+ ref=(ref0+ref1)/2;  %%% could use refHST instead
+ 
+ % calculate mean value m in central part of the image
+ m=mean2(ref(round(acq.ydet/2-127:acq.ydet/2+128),round(acq.xdet/2-127:acq.xdet/2+128)));
+ cen=double(ref>(0.5*m));  % should correspond to direct beam footprint
+
+
+ % find the direct beam region bb automatically (supposes fairly homogeneous
+ % beam profile - attention with ID11 data here... !
+
+ marker=zeros(acq.ydet,acq.xdet);
+ marker(round(acq.ydet/2),round(acq.xdet/2))=1;
+ cen=imreconstruct(marker,cen);
+ tmp=regionprops(cen,'BoundingBox');
+ bb=tmp.BoundingBox;
+ bb=[ceil(bb(1:2)),bb(3:4)-1];
+ % make sure the bbox width and height are even numbers (needed for correlation)
+ bb(3:4)=ceil(bb(3:4)/2)*2;
+ 
+ figure('name','Preliminary bounding box')
+ imshow(ref,[])
+ hold on
+ plot([bb(1),bb(1)+bb(3)-1,bb(1)+bb(3)-1,bb(1),bb(1)],[bb(2),bb(2),bb(2)+bb(4)-1,bb(2)+bb(4)-1,bb(2)],'r-') 
+ 
+
+ switch acq.calibration
+   case 'images at end'
+
+     name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj);  % changed from 0 to nproj
+     im0=(edf_read(name)-d)./ref1;
+
+     name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+2);  % changed from nproj-1 to nproj+2
+     im1=(edf_read(name)-d)./ref1;
+
+     a0=gtCrop(im0,bb);
+     a1=fliplr(gtCrop(im1,bb));
+
+     % calculate the rotation axis offset
+     %offset=-median(correlate1(a0',a1'));
+     if dim==0 || isempty(dim)
+       offset=-correlate(a0,a1);
+     elseif dim==1
+       offset=-[median(correlate1(a0,a1)), 0];
+     elseif dim==2
+       offset=-[0, median(correlate1(a0',a1'))];
+     else
+       error('Dimension (second input argument) should be [], 0, 1 or 2!')
+     end
+    
+     
+     % double check this result and modify if necessary by  user intervention...
+     a1c=interpolatef(a1,-offset(1),-offset(2));
+
+
+     shift=[];
+     assignin('base','shift',shift);
+     disp('Check result of image correlation with findshifts...')
+
+     findshifts2(a0,a1c);
+     while isempty(shift)
+       drawnow;
+       shift=evalin('base','shift');
+     end
+
+     shift=evalin('base','shift')
+     offset=shift(2)/2+offset/2;   %%% ???? check direction of shift and offset
+
+     acq.rotx=bb(1)+bb(3)/2+offset; %%% ????  % check if we should add + 0.5 here or not:  (does the pixel 1 start at 0 or at 0.5 ?)
+	 
+	  
+    % now check if there was a sample drift during the scan and correct for it 	  
+	  % for the moment we suppose a 360 degree scan with 4 images at the end...
+    if strcmpi(acq.type,'360degree');
+      
+      name=sprintf('0_rawdata/%s/dark.edf',acq.name);
+      d=edf_read(name,bb);
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj);
+      refend=edf_read(name,bb)-d;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj);
+      im_end_360=(edf_read(name,bb)-d)./refend;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+1);
+      im_end_270=(edf_read(name,bb)-d)./refend;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+2);
+      im_end_180=(edf_read(name,bb)-d)./refend;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+3);
+      im_end_90=(edf_read(name,bb)-d)./refend;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+4);
+      im_end_0=(edf_read(name,bb)-d)./refend;
+
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj*0.75); ???? ref0000
+      ref270=edf_read(name,bb)-d;
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.75);
+      im_270=(edf_read(name,bb)-d)./ref270;
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj*0.5);
+      ref180=edf_read(name,bb)-d;
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.5);
+      im_180=(edf_read(name,bb)-d)./ref180;
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj*0.25);
+      ref90=edf_read(name,bb)-d;
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.25);
+      im_90=(edf_read(name,bb)-d)./ref90;
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,0);
+      ref0=edf_read(name,bb)-d;
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,0);
+      im_0=(edf_read(name,bb)-d)./ref0;
+
+      % corr_0=correlate(im_end_0,im_0)
+      % corr_90=correlate(im_end_90,im_90)
+      % corr_180=correlate(im_end_180,im_180)
+      % corr_270=correlate(im_end_270,im_270)
+      
+      
+      if dim==0 || isempty(dim)
+        corr_0=correlate(im_end_0,im_0)
+        corr_90=correlate(im_end_90,im_90)
+        corr_180=correlate(im_end_180,im_180)
+        corr_270=correlate(im_end_270,im_270)
+        corr_360=correlate(im_end_360,im_360)
+      elseif dim==1
+        corr_0=-[median(correlate1(im_end_0,im_0)), 0]
+        corr_90=-[median(correlate1(im_end_90,im_90)), 0]
+        corr_180=-[median(correlate1(im_end_180,im_180)), 0]
+        corr_270=-[median(correlate1(im_end_270,im_270)), 0]
+        corr_360=-[median(correlate1(im_end_360,im_360)), 0]
+      elseif dim==2
+        corr_0=-[0, median(correlate1(im_end_0',im_0'))]
+        corr_90=-[0, median(correlate1(im_end_90',im_90'))]
+        corr_180=-[0, median(correlate1(im_end_180',im_180'))]
+        corr_270=-[0, median(correlate1(im_end_270',im_270'))]
+        corr_360=-[0, median(correlate1(im_end_360',im_360'))]
+      else
+        error('Dimension (second input argument) should be [], 0, 1 or 2!')
+      end
+
+    
+      check_drift=1;
+
+      while check_drift
+
+        % simple linear interpolation for the moment - not the most
+        % accurate - for higher accuracy one should acquire a small
+        % callibration scan !
+        
+%         nim=totproj/4;
+% 
+%         for i=0:nim
+%           drift(:,i+1)= corr_0.*(1-i/nim)+corr_90.*i/nim;
+%         end
+%         for i=nim:2*nim
+%           drift(:,i+1)= corr_90.*(1-(i-nim)/nim)+corr_180.*(i-nim)/nim;
+%         end
+%         for i=2*nim:3*nim
+%           drift(:,i+1)= corr_180.*(1-(i-2*nim)/nim)+ corr_270.*(i-2*nim)/nim;
+%         end
+%         for i=3*nim:4*nim
+%           drift(:,i+1)= corr_270.*(1-(i-3*nim)/nim);
+%         end
+        
+        acq.zdrift=interp1([0,totproj*0.25,totproj*0.5,totproj*0.75,totproj],[corr_0(1),corr_90(1),corr_180(1),corr_270(1),corr_360(1)],0:totproj);
+        acq.ydrift=interp1([0,totproj*0.25,totproj*0.5,totproj*0.75,totproj],[corr_0(2),corr_90(2),corr_180(2),corr_270(2),corr_360(2)],0:totproj);
+       
+        figure('name','Drifts according to images at end')
+        subplot(2,1,1);plot(acq.ydrift,'r.');title('horizontal drift');
+        subplot(2,1,2);plot(acq.zdrift,'b.');title('vertical drift');
+        accept=inputwdefault('accept values ?','y');
+
+        if ~strcmpi(accept,'y')
+          check_drift=0;
+        else
+          disp('run findshifts2 on pairs: corr_0=findshifts2(im_end_0, im_0), corr_90=findshifts(im_end_90, im_90), ...');
+          disp('when done set check_drift=0');
+          keyboard;
+        end
+      end
+
+    else
+      % to be done...
+      disp('correction not yet implemented for 180degree scans');
+      acq.zdrift=zeros(totproj+1,1);
+      acq.ydrift=zeros(totproj+1,1);
+    end
+
+
+   case {'calibration scan 180degree','calibration scan 360degree'}
+     % should become the standard way to calibrate a scan...
+     gtEvaluateCalibrationScan(acq)
+
+ end
+  
+ 
+ 
+ 			  
+	
+  
+  %determine the limits of sample horizontally
+ disp('Trying to determine a tight BoundingBox around the sample and a region for intensity normalization');
+ [first,last,ims]=gtFindSampleEdges(acq,bb);
+ 
+ width=ceil(max(acq.rotx-first,last-acq.rotx));
+ 
+ if mod(acq.rotx,1)
+    sprintf('rotation axis is centered between pixels %d and %d',acq.rotx,acq.rotx+1)
+    %mindist=min(round(acq.rotx)-bb(1),bb(1)+bb(3)-round(acq.rotx));
+    acq.bb=[round(acq.rotx)-width,bb(2),2*width,bb(4)];
+  else  
+    sprintf('rotation axis is centered on pixel %d',acq.rotx)
+    %mindist=min(acq.rotx-bb(1),bb(1)+bb(3)-1-acq.rotx);
+    acq.bb=[acq.rotx-width,bb(2),2*width+1,bb(4)];
+  end
+  
+test0=gtcrop(im0,acq.bb);
+test1=gtCrop(im1,acq.bb);
+findshifts2(test0,fliplr(test1));
+ 
+end  
diff --git a/gtFindBoundingBoxnew_xxx.m~ b/gtFindBoundingBoxnew_xxx.m~
new file mode 100755
index 0000000000000000000000000000000000000000..6be16085544eb2ef576feb5642f7a3f85c82defb
--- /dev/null
+++ b/gtFindBoundingBoxnew_xxx.m~
@@ -0,0 +1,258 @@
+function acq=gtFindBoundingBoxnew(acq,dim)
+ % 24/07/2007:  switch to images at end of scan for rotation axis determination  
+ %              implement more precise determination of rotation axis based on findshift (octave)
+ %              possible use of callibration scan
+ 
+ 
+ 
+ 
+ 
+  %%%%%%%%%%%%%%%%%%%%
+ acq.nproj=3600
+ acq.calibration='images at end';
+ %%%%%%%%%%%%%%%%%%%%%
+ 
+ 
+ 
+ if strcmpi(acq.type,'180degree')
+   totproj=acq.nproj;
+ elseif strcmpi(acq.type,'360degree');
+   totproj=acq.nproj*2;
+ else
+   disp('unknown scantype in gtFindBoundingBoxnew');
+   return;
+ end
+
+ %name=sprintf('0_rawdata/%s/darkend0000.edf',acq.name);
+ %d=edf_read(name)./acq.ndark;
+ d=edf_read(sprintf('0_rawdata/%s/dark.edf',acq.name));
+ name=sprintf('0_rawdata/%s/ref0000_0000.edf',acq.name);
+ ref0=edf_read(name)-d;
+ name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj);
+ ref1=edf_read(name)-d;
+
+ ref=(ref0+ref1)/2;  %%% could use refHST instead
+ 
+ % calculate mean value m in central part of the image
+ m=mean2(ref(round(acq.ydet/2-127:acq.ydet/2+128),round(acq.xdet/2-127:acq.xdet/2+128)));
+ cen=double(ref>(0.5*m));  % should correspond to direct beam footprint
+
+
+ % find the direct beam region bb automatically (supposes fairly homogeneous
+ % beam profile - attention with ID11 data here... !
+
+ marker=zeros(acq.ydet,acq.xdet);
+ marker(round(acq.ydet/2),round(acq.xdet/2))=1;
+ cen=imreconstruct(marker,cen);
+ tmp=regionprops(cen,'BoundingBox');
+ bb=tmp.BoundingBox;
+ bb=[ceil(bb(1:2)),bb(3:4)-1];
+ % make sure the bbox width and height are even numbers (needed for correlation)
+ bb(3:4)=ceil(bb(3:4)/2)*2;
+ 
+ figure('name','Preliminary bounding box')
+ imshow(ref,[])
+ hold on
+ plot([bb(1),bb(1)+bb(3)-1,bb(1)+bb(3)-1,bb(1),bb(1)],[bb(2),bb(2),bb(2)+bb(4)-1,bb(2)+bb(4)-1,bb(2)],'r-') 
+ 
+
+ switch acq.calibration
+   case 'images at end'
+
+     name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj);  % changed from 0 to nproj
+     im0=(edf_read(name)-d)./ref1;
+
+     name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+2);  % changed from nproj-1 to nproj+2
+     im1=(edf_read(name)-d)./ref1;
+
+     a0=gtCrop(im0,bb);
+     a1=fliplr(gtCrop(im1,bb));
+
+     % calculate the rotation axis offset
+     %offset=-median(correlate1(a0',a1'));
+     if dim==0 || isempty(dim)
+       offset=-correlate(a0,a1);
+     elseif dim==1
+       offset=-[median(correlate1(a0,a1)), 0];
+     elseif dim==2
+       offset=-[0, median(correlate1(a0',a1'))];
+     else
+       error('Dimension (second input argument) should be [], 0, 1 or 2!')
+     end
+    
+     
+     % double check this result and modify if necessary by  user intervention...
+     a1c=interpolatef(a1,-offset(1),-offset(2));
+
+
+     shift=[];
+     assignin('base','shift',shift);
+     disp('Check result of image correlation with findshifts...')
+
+     findshifts2(a0,a1c);
+     while isempty(shift)
+       drawnow;
+       shift=evalin('base','shift');
+     end
+
+     shift=evalin('base','shift')
+     offset=shift(2)/2+offset/2;   %%% ???? check direction of shift and offset
+
+     acq.rotx=bb(1)+bb(3)/2+offset; %%% ????  % check if we should add + 0.5 here or not:  (does the pixel 1 start at 0 or at 0.5 ?)
+	 
+	  
+    % now check if there was a sample drift during the scan and correct for it 	  
+	  % for the moment we suppose a 360 degree scan with 4 images at the end...
+    if strcmpi(acq.type,'360degree');
+      
+      name=sprintf('0_rawdata/%s/dark.edf',acq.name);
+      d=edf_read(name,bb);
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj);
+      refend=edf_read(name,bb)-d;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj);
+      im_end_360=(edf_read(name,bb)-d)./refend;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+1);
+      im_end_270=(edf_read(name,bb)-d)./refend;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+2);
+      im_end_180=(edf_read(name,bb)-d)./refend;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+3);
+      im_end_90=(edf_read(name,bb)-d)./refend;
+
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj+4);
+      im_end_0=(edf_read(name,bb)-d)./refend;
+
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj*0.75); ???? ref0000
+      ref270=edf_read(name,bb)-d;
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.75);
+      im_270=(edf_read(name,bb)-d)./ref270;
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj*0.5);
+      ref180=edf_read(name,bb)-d;
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.5);
+      im_180=(edf_read(name,bb)-d)./ref180;
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,totproj*0.25);
+      ref90=edf_read(name,bb)-d;
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,totproj*0.25);
+      im_90=(edf_read(name,bb)-d)./ref90;
+
+      name=sprintf('0_rawdata/%s/ref0000_%04d.edf',acq.name,0);
+      ref0=edf_read(name,bb)-d;
+      name=sprintf('0_rawdata/%s/%s%04d.edf',acq.name,acq.name,0);
+      im_0=(edf_read(name,bb)-d)./ref0;
+
+      % corr_0=correlate(im_end_0,im_0)
+      % corr_90=correlate(im_end_90,im_90)
+      % corr_180=correlate(im_end_180,im_180)
+      % corr_270=correlate(im_end_270,im_270)
+      
+      
+      if dim==0 || isempty(dim)
+        corr_0=correlate(im_end_0,im_0)
+        corr_90=correlate(im_end_90,im_90)
+        corr_180=correlate(im_end_180,im_180)
+        corr_270=correlate(im_end_270,im_270)
+        corr_360=correlate(im_end_360,im_360)
+      elseif dim==1
+        corr_0=-[median(correlate1(im_end_0,im_0)), 0]
+        corr_90=-[median(correlate1(im_end_90,im_90)), 0]
+        corr_180=-[median(correlate1(im_end_180,im_180)), 0]
+        corr_270=-[median(correlate1(im_end_270,im_270)), 0]
+        corr_360=-[median(correlate1(im_end_360,im_360)), 0]
+      elseif dim==2
+        corr_0=-[0, median(correlate1(im_end_0',im_0'))]
+        corr_90=-[0, median(correlate1(im_end_90',im_90'))]
+        corr_180=-[0, median(correlate1(im_end_180',im_180'))]
+        corr_270=-[0, median(correlate1(im_end_270',im_270'))]
+        corr_360=-[0, median(correlate1(im_end_360',im_360'))]
+      else
+        error('Dimension (second input argument) should be [], 0, 1 or 2!')
+      end
+
+    
+      check_drift=1;
+
+      while check_drift
+
+        % simple linear interpolation for the moment - not the most
+        % accurate - for higher accuracy one should acquire a small
+        % callibration scan !
+        
+%         nim=totproj/4;
+% 
+%         for i=0:nim
+%           drift(:,i+1)= corr_0.*(1-i/nim)+corr_90.*i/nim;
+%         end
+%         for i=nim:2*nim
+%           drift(:,i+1)= corr_90.*(1-(i-nim)/nim)+corr_180.*(i-nim)/nim;
+%         end
+%         for i=2*nim:3*nim
+%           drift(:,i+1)= corr_180.*(1-(i-2*nim)/nim)+ corr_270.*(i-2*nim)/nim;
+%         end
+%         for i=3*nim:4*nim
+%           drift(:,i+1)= corr_270.*(1-(i-3*nim)/nim);
+%         end
+        
+        acq.zdrift=interp1([0,totproj*0.25,totproj*0.5,totproj*0.75,totproj],[corr_0(1),corr_90(1),corr_180(1),corr_270(1),corr_360(1)],0:totproj);
+        acq.ydrift=interp1([0,totproj*0.25,totproj*0.5,totproj*0.75,totproj],[corr_0(2),corr_90(2),corr_180(2),corr_270(2),corr_360(2)],0:totproj);
+       
+        figure('name','Drifts according to images at end')
+        subplot(2,1,1);plot(acq.ydrift,'r.');title('horizontal drift');
+        subplot(2,1,2);plot(acq.zdrift,'b.');title('vertical drift');
+        accept=inputwdefault('accept values ?','y');
+
+        if ~strcmpi(accept,'y')
+          check_drift=0;
+        else
+          disp('run findshifts2 on pairs: corr_0=findshifts2(im_end_0, im_0), corr_90=findshifts(im_end_90, im_90), ...');
+          disp('when done set check_drift=0');
+          keyboard;
+        end
+      end
+
+    else
+      % to be done...
+      disp('correction not yet implemented for 180degree scans');
+      acq.zdrift=zeros(totproj+1,1);
+      acq.ydrift=zeros(totproj+1,1);
+    end
+
+
+   case {'calibration scan 180degree','calibration scan 360degree'}
+     % should become the standard way to calibrate a scan...
+     gtEvaluateCalibrationScan(acq)
+
+ end
+  
+ 
+ 
+ 			  
+	
+  
+  %determine the limits of sample horizontally
+ disp('Trying to determine a tight BoundingBox around the sample and a region for intensity normalization');
+ [first,last,ims]=gtFindSampleEdges(acq,bb);
+ 
+ width=ceil(max(acq.rotx-first,last-acq.rotx));
+ 
+ if mod(acq.rotx,1)
+    sprintf('rotation axis is centered between pixels %d and %d',acq.rotx,acq.rotx+1)
+    %mindist=min(round(acq.rotx)-bb(1),bb(1)+bb(3)-round(acq.rotx));
+    acq.bb=[round(acq.rotx)-width,bb(2),2*width,bb(4)];
+  else  
+    sprintf('rotation axis is centered on pixel %d',acq.rotx)
+    %mindist=min(acq.rotx-bb(1),bb(1)+bb(3)-1-acq.rotx);
+    acq.bb=[acq.rotx-width,bb(2),2*width+1,bb(4)];
+  end
+  
+test0=gtcrop(im0,acq.bb);
+test1=gtCrop(im1,acq.bb);
+findshifts2(test0,fliplr(test1));
+ 
+end  
diff --git a/gtSuper.m b/gtSuper.m
new file mode 100755
index 0000000000000000000000000000000000000000..a9e0be28b0b2ea6b45e3d0b9ebe9892a6ff70654
--- /dev/null
+++ b/gtSuper.m
@@ -0,0 +1,103 @@
+function gtSuper
+%for the latest 360 degree structure
+
+
+%%%%%%%    SETUP    %%%%%%%%%
+%create the parameters.mat and the directory structure
+gtSetup_ak
+%create all the databases
+gtDBCreateDifblobTable
+gtDBCreateDifspotTable
+gtDBCreateSpotPairTable
+gtDBCreateExtspotTable
+%%%%%%%    SETUP    %%%%%%%%%
+
+
+%%%%%%%    PREPROCESSING    %%%%%%%%%
+%preprocessing - copy (and correct) data to analysis location, filtering, make fulls,
+%abs, ext images.
+%parallelisation handled by the function
+gtPreProcessing_live
+%%%%%%%    PREPROCESSING    %%%%%%%%%
+
+
+%%%%%%%    FIND SAMPLE SHIFTS    %%%%%%%%
+%something in here if correcting sample shifts...  works on the ful/abs/ext
+%images
+%%%%%%%    FIND SAMPLE SHIFTS    %%%%%%%%
+
+
+
+%%%%%%%    SEGMENTATION OF DIFSPOTs    %%%%%%%%%
+%add parameters.seg thresholds, bounding box
+%segment blobs
+%condor over 30-40 machines
+
+gtSegmentDiffractionBlobs
+%eg:   condor_make('gtSegmentDiffractionBlobs', 0, 7198, 40, pwd, 1)
+%  7198 is total images in 360 degrees, minus one, because each job does
+%  one extra image to overlap.
+
+%when finished
+gtRemoveOverlappingDifblobs(parameters.acq.name)
+%fill difspot table
+%can condor, but pretty quick
+gtDBBlob2SpotTable(min(blobID), max(blobID), pwd)
+%match difspot pairs
+% add match field to parameters or as an input
+% can account for tilts and correlate difspots
+% speed shouldn't depend on the number of spots
+gtMatchDifspots_v3
+%%%%%%%    SEGMENTATION OF DIFSPOTs    %%%%%%%%%
+
+
+%%%%%%%    MATCH DIFSPOTS TO EXTSPOTS    %%%%%%%%%
+%add autofind parameters - height tolerance for extspot search, filter
+%sizes should also go here
+%condor over 40-50 machines
+gtBatchAutoFind_360
+%%%%%%%    MATCH DIFSPOTS TO EXTSPOTS    %%%%%%%%%
+
+
+%%%%%%%    SPOTS INTO GRAINS    %%%%%%%%%
+%add sort fields to parameters, should have a replace_all field to replace
+%all extspots in poor qualtity datasets
+%single job
+gtDoAll_360
+%%%%%%%    SPOTS INTO GRAINS    %%%%%%%%%
+
+
+%%%%%%%    TIDY GRAINS< MAKE VOLUME    %%%%%%%%%
+%run...
+!chmod 775 seg2view.sh
+!seg2view.sh
+
+%assemble the volume, have a look at the map - will probably be messy
+vol=gtnew_assemble_vol2(1)
+%have a look... 
+% e.g.  vol_view(vol, 'cmap', gtRandCmap(vol), 'clims', 0, 'plane', 'yz')
+
+%combine overlapping (ghost) grains
+[r_vectors, positions]=gtReadGrains
+combine_list=combine_grains2(r_vectors, positions, []) %bads)
+gtDoCombineGrains_360(combine_list)
+%rerun seg2view for these
+%rerun threshold_grain_auto for these
+
+vol2=gtnew_assemble_vol2(1)
+
+%this should be as good as you can get automatically, although a second iteration could be useful.  After that it's a
+%case of using gtReconstructionManager to manually tweak ART parameters and
+%chose which projections to use.
+
+gtReconstructionManager_360(grainid)
+
+
+
+
+
+
+
+
+
+
diff --git a/gtSuper.m~ b/gtSuper.m~
new file mode 100755
index 0000000000000000000000000000000000000000..0edbfba884049c0144796815e181ddfc293cae8b
--- /dev/null
+++ b/gtSuper.m~
@@ -0,0 +1,102 @@
+function gtSuper
+%for the latest 360 degree structure
+
+
+%%%%%%%    SETUP    %%%%%%%%%
+%create the parameters.mat and the directory structure
+gtSetup_ak
+%create all the databases
+gtDBCreateDifblobTable
+gtDBCreateDifspotTable
+gtDBCreateSpotPairTable
+gtDBCreateExtspotTable
+%%%%%%%    SETUP    %%%%%%%%%
+
+
+%%%%%%%    PREPROCESSING    %%%%%%%%%
+%preprocessing - copy (and correct) data to analysis location, filtering, make fulls,
+%abs, ext images.
+%parallelisation handled by the function
+gtPreProcessing_live
+%%%%%%%    PREPROCESSING    %%%%%%%%%
+
+
+%%%%%%%    FIND SAMPLE SHIFTS    %%%%%%%%
+%something in here if correcting sample shifts...  works on the ful/abs/ext
+%images
+%%%%%%%    FIND SAMPLE SHIFTS    %%%%%%%%
+
+
+
+%%%%%%%    SEGMENTATION OF DIFSPOTs    %%%%%%%%%
+%add parameters.seg thresholds, bounding box
+%segment blobs
+%condor over 30-40 machines
+
+gtSegmentDiffractionBlobs
+%eg:   condor_make('gtSegmentDiffractionBlobs', 0, 7198, 40, pwd, 1)
+%  7198 is total images in 360 degrees, minus one, because each job does
+%  one extra image to overlap.
+
+%when finished
+gtRemoveOverlappingDifblobs(parameters.acq.name)
+%fill difspot table
+%can condor, but pretty quick
+gtDBBlob2SpotTable(min(blobID), max(blobID), pwd)
+%match difspot pairs
+%add match field to parameters or as an input
+% ca
+gtMatchDifspots_v3
+%%%%%%%    SEGMENTATION OF DIFSPOTs    %%%%%%%%%
+
+
+%%%%%%%    MATCH DIFSPOTS TO EXTSPOTS    %%%%%%%%%
+%add autofind parameters - height tolerance for extspot search, filter
+%sizes should also go here
+%condor over 40-50 machines
+gtBatchAutoFind_360
+%%%%%%%    MATCH DIFSPOTS TO EXTSPOTS    %%%%%%%%%
+
+
+%%%%%%%    SPOTS INTO GRAINS    %%%%%%%%%
+%add sort fields to parameters, should have a replace_all field to replace
+%all extspots in poor qualtity datasets
+%single job
+gtDoAll_360
+%%%%%%%    SPOTS INTO GRAINS    %%%%%%%%%
+
+
+%%%%%%%    TIDY GRAINS< MAKE VOLUME    %%%%%%%%%
+%run...
+!chmod 775 seg2view.sh
+!seg2view.sh
+
+%assemble the volume, have a look at the map - will probably be messy
+vol=gtnew_assemble_vol2(1)
+%have a look... 
+% e.g.  vol_view(vol, 'cmap', gtRandCmap(vol), 'clims', 0, 'plane', 'yz')
+
+%combine overlapping (ghost) grains
+[r_vectors, positions]=gtReadGrains
+combine_list=combine_grains2(r_vectors, positions, []) %bads)
+gtDoCombineGrains_360(combine_list)
+%rerun seg2view for these
+%rerun threshold_grain_auto for these
+
+vol2=gtnew_assemble_vol2(1)
+
+%this should be as good as you can get automatically, although a second iteration could be useful.  After that it's a
+%case of using gtReconstructionManager to manually tweak ART parameters and
+%chose which projections to use.
+
+gtReconstructionManager_360(grainid)
+
+
+
+
+
+
+
+
+
+
diff --git a/gtSynchGrains.m b/gtSynchGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..142604ac3bf61db1ad1bce11cc4ce69612bbc88d
--- /dev/null
+++ b/gtSynchGrains.m
@@ -0,0 +1,26 @@
+function gtSynchGrains
+%reset databases using info from saved .mat files
+%restore...
+
+global parameters
+if isempty(parameters)
+  load parameters.mat
+end
+
+
+for i=130:3350
+  
+  try
+    tmp=load(sprintf('4_grains/grain%d_/grain%d_.mat',i,i));
+    
+    for j=1:length(tmp.struct_ids)
+      
+     mym(sprintf('update %sextspot set GrainID=%d where extspotID=%d',parameters.acq.name,i,tmp.struct_ids(j)));
+     mym(sprintf('update %sbb set GrainID=%d where extspotID=%d',parameters.acq.name,i,tmp.struct_ids(j)));
+     
+    end
+disp(sprintf('~~~~~~~~~   done grain %d    ~~~~~~~~~~~',i))
+  end
+
+ 
+end
diff --git a/html/grain_test.html b/html/grain_test.html
new file mode 100755
index 0000000000000000000000000000000000000000..251eb457f1ae9a9726fd9a2deb9a26e6e7f2ca8a
--- /dev/null
+++ b/html/grain_test.html
@@ -0,0 +1,132 @@
+
+<!DOCTYPE html
+  PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>grain_test</title>
+      <meta name="generator" content="MATLAB 7.4">
+      <meta name="date" content="2007-10-25">
+      <meta name="m-file" content="grain_test"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows. */ 
+p,h1,h2,div.content div {
+  max-width: 600px;
+  /* Hack for IE6 */
+  width: auto !important; width: 600px;
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <p class="footer"><br>
+            Published with MATLAB&reg; 7.4<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+function grain_test (grainID)
+%%GRAIN_TEST.M A display function of the diffraction spot and extinction
+%%spot of a given ID
+% to be run in the sample directory once you have done gtDoAll_360
+% g: diffraction spot
+% r: extinction spot
+% b: extinction spot with snake
+% grain_test (grainID)
+close all
+load('parameters.mat');
+samplename=parameters.acq.name;
+offsetx=parameters.acq.bb(1);
+offsety=parameters.acq.bb(2);
+gtDBConnect
+% recherche de la liste des spots d extinction
+issnakes=0;
+
+grainmat=load(sprintf('./4_grains/grain%d_/grain%d_.mat',grainID,grainID));
+
+for i=1:size(grainmat.struct_ids,2)
+    % lecture de l image principale
+    [debz,finz, bb_ds_debx, bb_ds_deby, bb_ds_sizex, bb_ds_sizey]=mym(...
+        sprintf('select ExtStartImage, ExtEndImage, BoundingBoxXorigin, BoundingBoxYorigin,BoundingBoxXsize, BoundingBoxYsize from %sdifspot where difspotID=%d', ...
+        samplename,grainmat.struct_ids(i)));
+    
+    zimage=floor((debz+finz)/2);
+    im=edf_read(sprintf('./1_preprocessing/full/full%04d.edf',zimage));
+    figure, imshow(im,[-20 20]);
+    titre=grainmat.struct_ids(i);
+    title(titre);
+    hold on;
+    data1=[bb_ds_debx:0.05:bb_ds_debx+bb_ds_sizex]; plot(data1,bb_ds_deby,'g'); plot(data1,bb_ds_deby+bb_ds_sizey,'g'); 
+    data2=[bb_ds_deby:0.05:bb_ds_deby+bb_ds_sizey]; plot(bb_ds_debx,data2,'g'); plot(bb_ds_debx+bb_ds_sizex,data2,'g'); 
+    
+    [bb_es_debx, bb_es_deby, bb_es_sizex, bb_es_sizey] = mym(...
+        sprintf('select Xorigin, Yorigin, Xsize, Ysize from %sbboxes where extspotID=%d',...
+        samplename,grainmat.struct_ids(i)));
+    bb_es_debx= bb_es_debx +offsetx; bb_es_deby= bb_es_deby +offsety;
+    
+    data1=[bb_es_debx(1):0.05:bb_es_debx(1)+bb_es_sizex(1)]; plot(data1,bb_es_deby(1),'r'); plot(data1,bb_es_deby(1)+bb_es_sizey(1),'r'); 
+    data2=[bb_es_deby(1):0.05:bb_es_deby(1)+bb_es_sizey(1)]; plot(bb_es_debx(1),data2,'r'); plot(bb_es_debx(1)+bb_es_sizex(1),data2,'r'); 
+
+if size(bb_es_debx,1)==2
+    issnakes=1
+    data1=[bb_es_debx(2):0.05:bb_es_debx(2)+bb_es_sizex(2)]; plot(data1,bb_es_deby(2),'b'); plot(data1,bb_es_deby(2)+bb_es_sizey(2),'b'); 
+    data2=[bb_es_deby(2):0.05:bb_es_deby(2)+bb_es_sizey(2)]; plot(bb_es_debx(2),data2,'b'); plot(bb_es_debx(2)+bb_es_sizex(2),data2,'b'); 
+end
+
+
+end % chaque diffbaction spot
+##### SOURCE END #####
+-->
+   </body>
+</html>
\ No newline at end of file
diff --git a/html/publish_gt.html b/html/publish_gt.html
new file mode 100755
index 0000000000000000000000000000000000000000..c13c3ebd46b5527103cb7f33bf7c50284c8ec577
--- /dev/null
+++ b/html/publish_gt.html
@@ -0,0 +1,99 @@
+
+<!DOCTYPE html
+  PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>PUBLISH_GT.M  Generates html documentation for Graintracking</title>
+      <meta name="generator" content="MATLAB 7.4">
+      <meta name="date" content="2007-10-24">
+      <meta name="m-file" content="publish_gt"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows. */ 
+p,h1,h2,div.content div {
+  max-width: 600px;
+  /* Hack for IE6 */
+  width: auto !important; width: 600px;
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>PUBLISH_GT.M  Generates html documentation for Graintracking</h1>
+         <p>There are some instructions somewhere...</p>
+         <p class="footer"><br>
+            Published with MATLAB&reg; 7.4<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+%% PUBLISH_GT.M  Generates html documentation for Graintracking
+% There are some instructions somewhere...
+function publish_gt(filename)
+  
+  opts.outputDir='/data/id19/graintracking/matlab/html';
+  opts.evalCode=false;
+opts.showCode=false;
+publish(filename,opts);
+
+if strcmp(filename(end-1:end),'.m')
+  htmlname = [filename(1:end-2) '.html'];
+else
+  htmlname = [filename '.html'];
+end
+web([opts.outputDir '/' htmlname])
+##### SOURCE END #####
+-->
+   </body>
+</html>
\ No newline at end of file
diff --git a/html/vol_view.html b/html/vol_view.html
new file mode 100755
index 0000000000000000000000000000000000000000..59da63527f61b378651713128019e9f3cb5f6d13
--- /dev/null
+++ b/html/vol_view.html
@@ -0,0 +1,516 @@
+
+<!DOCTYPE html
+  PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
+<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
+   <head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+   
+      <!--
+This HTML is auto-generated from an M-file.
+To make changes, update the M-file and republish this document.
+      -->
+      <title>VOL_VIEW.M  A simple viewer of 3D volumes,</title>
+      <meta name="generator" content="MATLAB 7.4">
+      <meta name="date" content="2007-10-24">
+      <meta name="m-file" content="vol_view"><style>
+
+body {
+  background-color: white;
+  margin:10px;
+}
+
+h1 {
+  color: #990000; 
+  font-size: x-large;
+}
+
+h2 {
+  color: #990000;
+  font-size: medium;
+}
+
+/* Make the text shrink to fit narrow windows, but not stretch too far in 
+wide windows. */ 
+p,h1,h2,div.content div {
+  max-width: 600px;
+  /* Hack for IE6 */
+  width: auto !important; width: 600px;
+}
+
+pre.codeinput {
+  background: #EEEEEE;
+  padding: 10px;
+}
+@media print {
+  pre.codeinput {word-wrap:break-word; width:100%;}
+} 
+
+span.keyword {color: #0000FF}
+span.comment {color: #228B22}
+span.string {color: #A020F0}
+span.untermstring {color: #B20000}
+span.syscmd {color: #B28C00}
+
+pre.codeoutput {
+  color: #666666;
+  padding: 10px;
+}
+
+pre.error {
+  color: red;
+}
+
+p.footer {
+  text-align: right;
+  font-size: xx-small;
+  font-weight: lighter;
+  font-style: italic;
+  color: gray;
+}
+
+  </style></head>
+   <body>
+      <div class="content">
+         <h1>VOL_VIEW.M  A simple viewer of 3D volumes,</h1>
+         <p><b>Usage:</b></p><pre>vol_view(vol)  Will show the simplest version of the viewer.  Try it!
+vol_view(vol,'parameter','value') - specify some optional parameters.</pre><pre>These are:
+'plane'  =  'xy','yz','zx'    &lt;&lt; viewing plane
+'slicendx'= 42                &lt;&lt; start viewing at slice index supplied
+'cmap'   =   gray,jet,etc     &lt;&lt; any colour map. See 'help graph3d'
+                                 The cmap_saturation colormap is quite
+                                 useful for determining which pixels
+                                 would be saturated for certain min/max
+'cbar'   =   true,false       &lt;&lt; show colourbar
+'clims'  =   2, [min max]     &lt;&lt; either a single value (percentile) or two
+                                 absolute values
+'hordisplay' = [hmin hmax]    &lt;&lt; use the hmin,hmax values to map the volume
+                                 to the horizontal-axis
+'verdisplay'                  &lt;&lt; as for hordisplay
+'ij'     =   true,false       &lt;&lt; use ImageJ for viewing
+'whichfigure'='new','current' &lt;&lt; create a new figure (default) or
+                                 reuse the
+'linkname' = something        &lt;&lt; if you run vol_view multiple times,
+                                 using the same linkname, the sliders
+                                 are linked together in the different
+                                 viewers.  What fun!</pre><p><b>Examples:</b></p><pre>vol_view(vol,'cbar',true,'plane','yz','slicendx',43,'cmap',jet,'clims',3)</pre><pre>You can use vol=HSTVolReader to load your ESRF HST volumes.</pre><p class="footer"><br>
+            Published with MATLAB&reg; 7.4<br></p>
+      </div>
+      <!--
+##### SOURCE BEGIN #####
+
+%% VOL_VIEW.M  A simple viewer of 3D volumes, 
+% *Usage:*
+%
+%  vol_view(vol)  Will show the simplest version of the viewer.  Try it!
+%  vol_view(vol,'parameter','value') - specify some optional parameters.
+% 
+%  These are:
+%  'plane'  =  'xy','yz','zx'    << viewing plane
+%  'slicendx'= 42                << start viewing at slice index supplied
+%  'cmap'   =   gray,jet,etc     << any colour map. See 'help graph3d'
+%                                   The cmap_saturation colormap is quite
+%                                   useful for determining which pixels
+%                                   would be saturated for certain min/max
+%  'cbar'   =   true,false       << show colourbar
+%  'clims'  =   2, [min max]     << either a single value (percentile) or two
+%                                   absolute values
+%  'hordisplay' = [hmin hmax]    << use the hmin,hmax values to map the volume
+%                                   to the horizontal-axis
+%  'verdisplay'                  << as for hordisplay
+%  'ij'     =   true,false       << use ImageJ for viewing
+%  'whichfigure'='new','current' << create a new figure (default) or
+%                                   reuse the
+%  'linkname' = something        << if you run vol_view multiple times,
+%                                   using the same linkname, the sliders
+%                                   are linked together in the different
+%                                   viewers.  What fun!
+%
+% *Examples:*
+%
+%  vol_view(vol,'cbar',true,'plane','yz','slicendx',43,'cmap',jet,'clims',3)
+%
+%  You can use vol=HSTVolReader to load your ESRF HST volumes.
+
+
+function vol_view(vol,varargin)
+
+  app=[];
+  firsttime=true;
+  ok=sfInitialise(varargin);
+
+  if (~ok)
+    return
+  end
+  if app.ij
+    % use ImageJ instead of Matlab figure
+    ij_imshow(vol)
+    disp('ImageJ version does not support plane,cmap, or cbar yet');
+  else
+
+    sfSetupFigure
+    sfUpdateDisplay
+  end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function ok=sfInitialise(arguments)
+    warning('off','Images:initSize:adjustingMag');
+    warning('off','Images:imshow:magnificationMustBeFitForDockedFigure');
+    warning('off','MATLAB:divideByZero')
+
+    if isa(vol,'char') % user has specified a filename
+      d=dir(vol);
+      if ~isempty(d)
+        if d.bytes<1e6
+          disp('Small volume - reading entirely')
+          vol=HSTVolReader(vol);
+        else
+          disp('Large volume - using a memory map to read');
+          vol=vol_mmap(vol);
+        end
+      else % if d was empty, might be a wildcard
+        try
+          vol=vol_mmap(vol);
+        catch
+          disp('Could not find the file')
+          ok=false;
+          return
+        end
+      end
+    end
+    if isstruct(vol)
+      % probably a memory map - treat it differently
+      appdefaults.ismap=true;
+      appdefaults.map=vol.mmap{1};
+      if length(vol.mmap)>1
+        % iterate over all chunks to find size in z
+        volz=0;
+        appdefaults.chunklimits=[];
+        for q=1:length(vol.mmap)
+          sz=size(vol.mmap{q}.Data.vol,3);
+          appdefaults.chunklimits=[appdefaults.chunklimits sz];
+          volz=volz+sz;
+        end
+        appdefaults.dim=size(vol.mmap{1}.Data.vol);
+        appdefaults.dim(3)=volz;
+      else
+        % just a single chunk - use the size as-is
+        appdefaults.dim=size(vol.mmap{1}.Data.vol);
+        appdefaults.chunklimits=appdefaults.dim(3);
+      end
+
+    else
+      appdefaults.ismap=false;
+      appdefaults.dim=size(vol);
+    end
+
+    appdefaults.slicendx=1;
+    appdefaults.clims=2;
+    appdefaults.cbar=false;
+    appdefaults.cmap=gray(64);
+    appdefaults.plane='xy';
+    appdefaults.ij=false;
+    appdefaults.whichfigure='new';
+
+    appdefaults.hordisplay=[1 appdefaults.dim(2)];
+    appdefaults.verdisplay=[1 appdefaults.dim(1)];
+    appdefaults.linkname=[];
+    app=parse_pv_pairs(appdefaults,arguments);
+
+
+    % now validate the arguments
+    if ~strcmp(app.plane,{'xy','yz','zx'})
+      disp('Plane must be one of ''xy'',''yz'',''zx''')
+      disp(' ')
+      help(mfilename)
+      ok=false;
+      return;
+    end
+
+    % only permit xy slice if using a memorymapped file
+    % otherwise speed will drop swiftly towards zero
+    if app.ismap && ~strcmp(app.plane,'xy')
+      disp('Sorry, can only view xy slices with memory mapped volumes')
+      ok=false;
+      return;
+    end
+    % ensure slice is possible for a given orientation
+    switch app.plane
+      case 'xy'
+        tmpdim=3;
+      case 'yz'
+        tmpdim=1;
+        if app.hordisplay==appdefaults.hordisplay % user did not change the display scale
+          app.hordisplay=[1 app.dim(1)];
+        end
+        if app.verdisplay==appdefaults.verdisplay % user did not change the display scale
+          app.verdisplay=[1 app.dim(3)];
+        end
+      case 'zx'
+        tmpdim=2;
+        if app.hordisplay==appdefaults.hordisplay % user did not change the display scale
+          app.hordisplay=[1 app.dim(3)];
+        end
+        if app.verdisplay==appdefaults.verdisplay % user did not change the display scale
+          app.verdisplay=[1 app.dim(3)];
+        end
+    end
+    if app.ismap==false
+      slicendx=min(app.slicendx,app.dim(tmpdim));
+    else
+      slicendx=min(app.slicendx,vol.dim(tmpdim));
+    end
+    ok=true;
+    return
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function sfSetupFigure
+    if strcmp(app.whichfigure,'new')
+      app.h_figure=figure;
+      iptaddcallback(app.h_figure,'closerequestfcn',@sfQuit);
+    else
+      app.h_figure=gcf;
+    end
+    zoom off
+    %app.h_axes = axes('parent', app.h_figure)
+    app.h_slider=uicontrol('style','slider');
+    iptaddcallback(app.h_slider,'callback',@sfUpdateDisplay);
+    set(app.h_slider,'units','normalized');
+    set(app.h_slider,'position',[0 0 1 0.05])
+    switch app.plane
+      case 'xy'
+        set(app.h_slider,'min',1,'max',app.dim(3),'sliderstep',[1/app.dim(3) 1/app.dim(3)]);
+      case 'yz'
+        set(app.h_slider,'min',1,'max',app.dim(1),'sliderstep',[1/app.dim(1) 1/app.dim(1)]);
+      case 'zx'
+        set(app.h_slider,'min',1,'max',app.dim(2),'sliderstep',[1/app.dim(2) 1/app.dim(1)]);
+    end
+
+    set(app.h_slider,'value',app.slicendx);
+    set(app.h_slider,'tag','slider');
+
+    if app.dim(3)==1
+      set(app.h_slider,'visible','off')
+    end
+    iptaddcallback(app.h_figure,'windowbuttonmotionfcn',@sfUpdateDisplay);
+    iptaddcallback(app.h_figure,'windowbuttondownfcn',@sfUpdateDisplay);
+    set(app.h_figure,'currentobject',app.h_slider); % pretned the user has already clicked on the slider
+
+    set(app.h_figure,'menuBar','none')
+    %set(gcf,'handlevisibility','callback')  % protect the window from being accidentall reused
+
+    % modify the colour limits if a percentile is requested
+
+    if app.ismap
+      %      disp('Warning: Setting clims using just one slice (big volume)')
+      app.refresh_clims=app.clims;  % store the initial clims for refreshing later
+      % as we read more slices
+      app.clims=pfSetColourLimits(vol.mmap{1}.Data.vol(:,:,1),app.clims,'verbose',true);
+      app.data.lims=app.clims;
+    else
+      app.clims=pfSetColourLimits(vol,app.clims,'verbose',true);
+    end
+    zoom on
+
+    app.setsliderlimits=pfBrightnessContrast(gca,app.clims);
+
+    % write the app variable to a shared location (appending if necessary)
+    if ~isempty(app.linkname)
+      if isappdata(0,app.linkname)
+        appdata=getappdata(0,app.linkname);
+        % check that sliders have same maximum values
+        if get(appdata(end).app.h_slider,'max')==get(app.h_slider,'max')
+          disp(['Adding instance ' num2str(length(appdata)+1)])
+          appdata(end+1).app=app;
+        else
+          disp('Cannot add using this linkname - the volumes do not have the same')
+          disp('number of slices')
+          app.linkname=[];
+        end
+      else
+        disp('First instance')
+        appdata(1).app=app;
+      end
+      setappdata(0,app.linkname,appdata)
+    end
+  end
+
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function sfUpdateDisplay(varargin)
+    if (isequal(gco,app.h_slider) || firsttime)
+
+      tmp=round(get(app.h_slider,'value'));
+      set(app.h_slider,'value',tmp);
+      if (tmp~=app.slicendx || firsttime)  % slice change
+        app.slicendx=tmp;
+        set(app.h_slider,'value',app.slicendx);
+        if firsttime
+          if app.ismap
+            switch app.plane
+              case 'xy'
+                slice=vol.mmap{1}.Data.vol(:,:,1);
+              case 'yz'  % NOT SUPPORTED
+                disp('Hmm...')
+                slice=[];
+                for n=1:length(vol.mmap)
+                  slice=[slice squeeze(vol.mmap{n}.Data.vol(1,:,:))];
+                end
+              case 'zx' % NOT SUPPORTED
+                disp('Um?')
+                slice=squeeze(vol.mmap{3}.Data.vol(:,1,:));
+            end
+          else
+            switch app.plane
+              case 'xy'
+                slice=vol(:,:,1);
+              case 'yz'
+                slice=squeeze(vol(1,:,:));
+              case 'zx'
+                slice=squeeze(vol(:,1,:));
+            end
+
+          end
+          xtmp=[0.5 size(slice,2)+0.5];
+          ytmp=[0.5 size(slice,1)+0.5];
+        else
+          xtmp=get(gca,'xlim');
+          ytmp=get(gca,'ylim');
+        end
+        if app.ismap
+          chunk_ndx=find(app.slicendx<cumsum(app.chunklimits)+1,1,'first');
+          slice_offset=sum(app.chunklimits(1:chunk_ndx-1));
+          if isempty(slice_offset)
+            slice_offset=0;
+          end
+
+          switch app.plane
+            case 'xy'
+              h_im=imshow(vol.mmap{chunk_ndx}.Data.vol(:,:,app.slicendx-slice_offset),app.clims);
+            case 'yz' % NOT SUPPORTED
+              h_im=imshow(squeeze(vol.mmap{1}.Data.vol(app.slicendx,:,:)),app.clims);
+            case 'zx' % NOT SUPPORTED
+              h_im=imshow(squeeze(vol.mmap{1}.Data.vol(:,app.slicendx,:)),app.clims);
+          end
+
+
+        else
+
+          switch app.plane
+            case 'xy'
+              h_im=imshow(vol(:,:,app.slicendx),app.clims);
+            case 'yz'
+              h_im=imshow(squeeze(vol(app.slicendx,:,:)),app.clims);
+            case 'zx'
+              h_im=imshow(squeeze(vol(:,app.slicendx,:)),app.clims);
+          end
+        end
+        app.h_axes = ancestor(h_im,'axes');
+
+        if  app.ismap
+          if isfield(app,'refresh_clims')  % get the new min and max and update the slider limits
+            %            disp('Adjusting sliders');
+            slims=pfSetColourLimits(vol.mmap{chunk_ndx}.Data.vol(:,:,app.slicendx-slice_offset),0,'verbose',false);
+            app.data.lims(1)=min(app.data.lims(1),slims(1));
+            app.data.lims(2)=max(app.data.lims(2),slims(2));
+            app.setsliderlimits(app.data.lims);
+          end
+        end
+        %        axis image
+        axis on
+        if 1
+          switch(app.plane)
+            case 'xy'
+              xlabel('X');
+              ylabel('Y');
+              set(h_im,'xdata',linspace(app.hordisplay(1),app.hordisplay(2),app.dim(2)))
+              set(h_im,'ydata',linspace(app.verdisplay(1),app.verdisplay(2),app.dim(1)))
+            case 'yz'
+              xlabel('Y');
+              ylabel('Z');
+              set(h_im,'xdata',linspace(app.hordisplay(1),app.hordisplay(2),app.dim(1)))
+              set(h_im,'ydata',linspace(app.verdisplay(1),app.verdisplay(2),app.dim(3)))
+            case 'zx'
+              xlabel('Z');
+              ylabel('X');
+              set(h_im,'xdata',linspace(app.hordisplay(1),app.hordisplay(2),app.dim(3)))
+              set(h_im,'ydata',linspace(app.verdisplay(1),app.verdisplay(2),app.dim(2)))
+          end
+        end
+
+        set(app.h_axes,'xlim',xtmp); % reset the axis limits to those of the previous image (possibly zoomed in)
+        set(app.h_axes,'ylim',ytmp);
+
+        %        set(app.h_axes,'xlim',app.hordisplay);
+        %        set(app.h_axes,'ylim',app.verdisplay);
+
+        % axis image
+
+        colormap(app.cmap)
+        if app.cbar
+          colorbar
+        end
+        title(sprintf('Slice: %3d',app.slicendx))
+        if 1 %firsttime
+          app.h_pixelinfo = impixelinfoval(app.h_figure,h_im);
+          set(app.h_pixelinfo,'unit','normalized','position',[0.62 0.93 0.35 0.03]);
+        end
+        firsttime=false;
+        %figure(app.h_figure)
+
+        if ~isempty(app.linkname)
+
+          apps=getappdata(0,app.linkname);
+          % disp('Something to tweak')
+          % length(apps)
+          for n=1:length(apps)
+            tmp_slider=apps(n).app.h_slider;
+            if tmp_slider~=app.h_slider
+              currentobject=gco;
+              set(tmp_slider,'value',app.slicendx);
+              tmp_cb=get(tmp_slider,'callback');
+              uicontrol(tmp_slider) % focus on the other slider
+              tmp_cb()  % fire the callback to update the other display
+              uicontrol(currentobject) % return the focus to the original object
+            end
+          end
+          drawnow
+        end
+        % drawnow
+      end
+      %drawnow
+    end
+
+    %drawnow;
+  end
+  function sfQuit(varargin)
+    %disp('Quitting')
+    if ~isempty(app.linkname)
+      apps=getappdata(0,app.linkname);
+      for n=1:length(apps)
+        if apps(n).app.h_figure==app.h_figure
+          apps(n)=[];
+          % disp('Removing this instance from links')
+          break
+        end
+      end
+      if isempty(apps)
+        rmappdata(0,app.linkname)
+      else
+        setappdata(0,app.linkname,apps)
+      end
+
+    end
+    try
+      delete(app.h_figure)
+    catch
+    end
+  end
+
+end
+
+##### SOURCE END #####
+-->
+   </body>
+</html>
\ No newline at end of file
diff --git a/initialise_gt.m b/initialise_gt.m
new file mode 100755
index 0000000000000000000000000000000000000000..1c093cb34ee258445b8dd4fc24b488b5c05b86fe
--- /dev/null
+++ b/initialise_gt.m
@@ -0,0 +1,40 @@
+disp('Adding graintracking folders to the path')
+if strcmp(computer,'MAC')|strcmp(computer,'MACI')
+  GT_MATLAB_HOME='~/matlab/graintracking/';
+else
+  if exist('/mntdirect/_data_id19_graintracking/matlab/initialise_gt.m','file')
+    GT_MATLAB_HOME='/mntdirect/_data_id19_graintracking/matlab/';
+  else
+    GT_MATLAB_HOME='/data/id19/graintracking/matlab/';
+  end
+end
+addpath([GT_MATLAB_HOME '1_preprocessing']);
+addpath([GT_MATLAB_HOME '2_segment_difspot']);
+addpath([GT_MATLAB_HOME '3_match_extspot']);
+addpath([GT_MATLAB_HOME '4_spot_sorting']);
+addpath([GT_MATLAB_HOME '5_reconstruction']);
+addpath([GT_MATLAB_HOME '6_rendering']);
+addpath([GT_MATLAB_HOME 'zUtil_GVF']);
+addpath([GT_MATLAB_HOME 'zUtil_Maths']);
+addpath([GT_MATLAB_HOME 'zUtil_Drawing']);
+addpath([GT_MATLAB_HOME 'zUtil_Imaging']);
+addpath([GT_MATLAB_HOME 'zUtil_Index']);
+addpath([GT_MATLAB_HOME 'zUtil_Help']);
+addpath([GT_MATLAB_HOME 'zUtil_Condor']);
+addpath([GT_MATLAB_HOME 'zUtil_DB']);
+addpath([GT_MATLAB_HOME 'zUtil_ART']);
+addpath([GT_MATLAB_HOME 'zUtil_ForwardProjection']);
+addpath([GT_MATLAB_HOME 'zUtil_Strain']);
+addpath([GT_MATLAB_HOME 'zUtil_ICP']);
+addpath([GT_MATLAB_HOME 'FigureManagement']);
+addpath([GT_MATLAB_HOME 'orthogonal_slicer']);
+
+d=pwd;
+cd('/data/id19/graintracking/GJ/contourmethod_development')
+initialise_contourmethod_development
+cd(d)
+
+%addpath([GT_MATLAB_HOME 'zUtil_ImageJ']);
+
+clear GT_MATLAB_HOME d
+
diff --git a/pdfprint.m b/pdfprint.m
new file mode 100755
index 0000000000000000000000000000000000000000..a7ae8f385ab93274d89b70d518351be960a1ad52
--- /dev/null
+++ b/pdfprint.m
@@ -0,0 +1,90 @@
+%
+% FUNCTION pdfprint(fname,xlab,ylab,lw,fs)
+%
+% USAGE    pdfprint('test1','\theta','\eta',2,14)
+%
+% Prints current figure into pdf file. Sets papersize, fontsize, linewidth.
+% See hardcoded settings.
+% 
+
+function pdfprint(fname,xlab,ylab,lw,fs,res)
+
+% Directory
+fdir=[fname '.pdf'];
+%fdir=['/Users/reischig/thesis/figures/' fname '.pdf'];
+
+
+if ~exist('xlab','var')
+  xlab=[];
+end
+if ~exist('ylab','var')
+  ylab=[];
+end
+if ~exist('lw','var')
+  lw=[];
+end
+if ~exist('fs','var')
+  fs=[];
+end
+if ~exist('res','var')
+  res=[];
+end
+if isempty(res)
+  res=100;
+end
+
+
+% Fontsize
+if ~isempty(fs)
+  set(gca,'fontunits', 'points','fontsize',fs)
+   
+  textobj = findobj('type', 'text');
+  set(textobj, 'fontunits', 'points');
+  set(textobj, 'fontsize', fs);
+else
+  fs=14;
+end
+
+% Labels
+if ~isempty(xlab)
+  xlabel(xlab,'fontunits', 'points','fontsize',fs)
+end
+
+if ~isempty(ylab)
+  ylabel(ylab,'fontunits', 'points','fontsize',fs)
+end
+
+% Linewidth
+if ~isempty(lw)
+  lineobj = findobj('type', 'line');
+  set(lineobj, 'linewidth', lw);
+end
+
+
+% Papersize
+set(gcf,'units','centimeters','paperunits','centimeters','paperpositionmode','manual')
+fpos=get(gcf,'position');
+
+%%%%%%
+papersize=[fpos(3) fpos(4)]; % width and height of figure
+paperpos=[0 0 fpos(3) fpos(4)];
+%%%%%%
+
+%%%%%%
+%papersize=[fpos(3)-2 fpos(4)];
+%paperpos=[-1 0 fpos(3) fpos(4)];
+%%%%%%
+
+
+set(gcf,'paperposition',paperpos,'papersize',papersize)
+
+% Resolution, fileformat
+resin=sprintf('-r%d',res);
+%print('-r200','-dpdf',fdir)
+print(resin,'-dpdf',fdir)
+
+disp(['Figure saved in ' fdir])
+
+system(['acroread ' fdir ' &'])
+
+end
diff --git a/pdfprint.m~ b/pdfprint.m~
new file mode 100755
index 0000000000000000000000000000000000000000..0d38362d95c857c90e6fbfcb291cb50520cb3c22
--- /dev/null
+++ b/pdfprint.m~
@@ -0,0 +1,81 @@
+%
+% FUNCTION pdfprint(fname,xlab,ylab,lw,fs)
+%
+% USAGE    pdfprint('test1','\theta','\eta',2,14)
+%
+% Prints current figure into pdf file. Sets papersize, fontsize, linewidth.
+% See hardcoded settings.
+% 
+
+function pdfprint(fname,xlab,ylab,lw,fs)
+
+% Directory
+fdir=[fname '.pdf'];
+%fdir=['/Users/reischig/thesis/figures/' fname '.pdf'];
+
+
+if ~exist('xlab','var')
+  xlab=[];
+end
+if ~exist('ylab','var')
+  ylab=[];
+end
+if ~exist('lw','var')
+  lw=[];
+end
+if ~exist('fs','var')
+  fs=[];
+end
+
+% Fontsize
+if ~isempty(fs)
+  set(gca,'fontunits', 'points','fontsize',fs)
+   
+  textobj = findobj('type', 'text');
+  set(textobj, 'fontunits', 'points');
+  set(textobj, 'fontsize', fs);
+else
+  fs=14;
+end
+
+% Labels
+if ~isempty(xlab)
+  xlabel(xlab,'fontunits', 'points','fontsize',fs)
+end
+
+if ~isempty(ylab)
+  ylabel(ylab,'fontunits', 'points','fontsize',fs)
+end
+
+% Linewidth
+if ~isempty(lw)
+  lineobj = findobj('type', 'line');
+  set(lineobj, 'linewidth', lw);
+end
+
+
+% Papersize
+set(gcf,'units','centimeters','paperunits','centimeters','paperpositionmode','manual')
+fpos=get(gcf,'position');
+
+%%%%%%
+papersize=[fpos(3) fpos(4)]; % width and height of figure
+paperpos=[0 0 fpos(3) fpos(4)];
+%%%%%%
+
+%%%%%%
+%papersize=[fpos(3)-2 fpos(4)];
+%paperpos=[-1 0 fpos(3) fpos(4)];
+%%%%%%
+
+
+set(gcf,'paperposition',paperpos,'papersize',papersize)
+
+% Resolution, fileformat
+print('-r100','-dpdf',fdir)
+
+disp(['Figure saved in ' fdir])
+
+system(['open ' fdir ' &'])
+
+end
diff --git a/quali_calib_spheres.m b/quali_calib_spheres.m
new file mode 100755
index 0000000000000000000000000000000000000000..ef4e6f75e4bbad2a1e34437e5acef694b0749f2b
--- /dev/null
+++ b/quali_calib_spheres.m
@@ -0,0 +1,373 @@
+%
+% Tool that helps the direct, manual correlation of a marker object when
+% comparing a calibration and a scan. Gives magnified subtracted images 
+% in a bounding box (findshifts) that follows the turn of the sample. 
+%
+% OUTPUT vector of drifts: [vertical, horizontal]
+%          signs: [positive vertical, positive horizontal] meaning that
+%          scan image has moved upwards and to the left relative to the 
+%          calibration scan; thus this output should be directly used as an
+%          input for the translation of full,abs,... images (in addition,
+%          the location of rotation axis during calibration should be taken
+%          into account!)
+%
+%
+
+
+function corr=quali_calib_spheres(corrfile)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% x0=133.6
+% x90=379.5
+% x180=556.4
+% x270=310.5
+% y00=1759.1
+% bbb=[96 96]
+
+% 150N lower sphere Sept2007
+% x0=176.2
+% x90=422.5
+% x180=596.8
+% x270=353.5
+% y00=1778.2
+% bbb=[111 93]
+qualiname='quali_';
+qualirefname='quali_ref_';
+
+% 5N upper sphere Sept2007; no quali_ref-s
+% x0=227
+% x90=554
+% x180=542
+% x270=212
+% y00=216
+% bbb=[105 93]
+% qualiname='quali_';
+% qualirefname=[];
+
+% 5N lower sphere Sept2007; no quali_ref-s
+% x0=185
+% x90=428
+% x180=581
+% x270=338
+% y00=1776
+% bbb=[105 105]
+% qualiname='quali_';
+% qualirefname=[];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+load parameters
+
+acq=parameters.acq;
+calib=parameters.calib;
+calibtotproj=calib.totproj;
+
+bbox=calib.bb;  % contains the whole sphere trajectory
+xrot=calib.rotx-bbox(1)+1; % location of the rotation axis during calibration 
+% (used only for following the bounding box)
+
+if strcmpi(acq.type,'360degree')
+  scantotproj=acq.nproj*2;
+elseif strcmpi(acq.type,'180degree')
+  scantotproj=acq.nproj;
+else
+  error('Unknown type of scan. Check acq.type!');
+end
+
+calibfreq=scantotproj/calibtotproj;
+
+close all
+
+tomo_N=calib.totproj; % =xml.acquisition.tomo_N
+scanname=acq.name;
+scanfolder=sprintf('%s/0_rawdata/%s',acq.dir,scanname);
+
+if exist('corrfile','var')
+  load(corrfile)
+  istart=find(isnan(corr(:,1)),1,'first');
+else
+  istart=1;
+  corr=NaN(calibtotproj+1,2);
+end
+
+%% Determine BB trajectory
+
+%detcenter_abs=acq.xdet/2+0.5;
+%bboxcenter_abs=(2*bbox(1)+bbox(3)-1)/2;
+
+% Darks and ref-s
+calibdark=edf_read(sprintf('%s/dark.edf',calib.dir),bbox,'nodisp');
+calibrefstart=edf_read(sprintf('%s/refHST0000.edf',calib.dir),bbox,'nodisp')-calibdark;
+calibrefend=edf_read(sprintf('%s/refHST%0.4d.edf',calib.dir,tomo_N),bbox,'nodisp')-calibdark;
+
+%calibdarkbb=calibdark(1+frame:end-frame,1+frame:end-frame);
+%calibrefstartbb=calibrefstart(1+frame:end-frame,1+frame:end-frame);
+%calibrefendbb=calibrefend(1+frame:end-frame,1+frame:end-frame);
+calibdarkbb=calibdark;
+calibrefendbb=calibrefend;
+calibrefstartbb=calibrefstart;
+
+% Determine sphere trajectory
+%imend0=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N+4),bbox,'nodisp')-calibdarkbb)./calibrefendbb;
+%imend90=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N+3),bbox,'nodisp')-calibdarkbb)./calibrefendbb;
+%imend180=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N+2),bbox,'nodisp')-calibdarkbb)./calibrefendbb;
+%imend270=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N+1),bbox,'nodisp')-calibdarkbb)./calibrefendbb;
+imend0=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,0),bbox,'nodisp')-calibdarkbb)./calibrefendbb;
+imend90=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N/4),bbox,'nodisp')-calibdarkbb)./calibrefendbb;
+imend180=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N/2),bbox,'nodisp')-calibdarkbb)./calibrefendbb;
+imend270=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,tomo_N/4*3),bbox,'nodisp')-calibdarkbb)./calibrefendbb;
+
+% Input marker locations during the turn
+if ~exist('x0','var')
+
+  disp('Choose bounding box around marker...')
+  imshow(imend0,[])
+  [tmp,bbb]=imcrop;
+  bbb=[bbb(3) bbb(4)];
+  bbb=round(bbb);  % width and height of bb to contain the sphere
+
+  disp('Point out the marker centre...')
+  x0=ginput(1);
+  y0=x0(2);
+  x0=x0(1);
+
+  imshow(imend90,[])
+  x90=ginput(1);
+  y90=x90(2);
+  x90=x90(1);
+
+  imshow(imend180,[])
+  x180=ginput(1);
+  y180=x180(2);
+  x180=x180(1);
+
+  imshow(imend270,[])
+  x270=ginput(1);
+  y270=x270(2);
+  x270=x270(1);
+
+  y00=mean([y0 y90 y180 y270]);
+  
+end
+
+disp('Marker bbox:')
+disp(bbb)
+disp('Marker positions:')
+disp([x0 x90 x180 x270 y00])
+
+%keyboard
+
+b0=(x0-x180)/2; 
+b90=(x90-x270)/2;
+r=sqrt(b0^2+b90^2); % radius of motion
+%xrot=(x180+x0)/2;
+
+alpha0=-acosd(b0/r); % offset angle at calib image 0
+
+% Positions:
+% alpha=imi/calibtotproj*360+alpha0;
+% cpos=r*cosd(alpha)+xrot;   % sphere center position in bbox
+
+% Feedback for calculated positions
+figure
+imshow(imend0,[0 1])
+hold on
+alpha=0/calibtotproj*360+alpha0;
+plot(r*cosd(alpha)+xrot,y00,'g*')
+drawnow
+
+imshow(imend90,[0 1])
+hold on
+alpha=90/calibtotproj*360+alpha0;
+plot(r*cosd(alpha)+xrot,y00,'g*')
+drawnow
+
+imshow(imend180,[0 1])
+hold on
+alpha=180/calibtotproj*360+alpha0;
+plot(r*cosd(alpha)+xrot,y00,'g*')
+drawnow
+
+imshow(imend270,[0 1])
+hold on
+alpha=270/calibtotproj*360+alpha0;
+plot(r*cosd(alpha)+xrot,y00,'g*')
+drawnow
+
+
+%% Display for finding shifts
+
+disp(' ')
+disp('Reading edf-s...')
+disp(' ')
+
+calibblob=zeros(bbb(2),bbb(1),tomo_N+1,'double');
+imblob=zeros(bbb(2),bbb(1),tomo_N+1,'double');
+cmimi=NaN(calibtotproj+1,2);
+
+scandark=edf_read(sprintf('%s/dark.edf',scanfolder),[],'nodisp');
+calibdark=edf_read(sprintf('%s/dark.edf',calib.dir),[],'nodisp');
+calibrefstart=edf_read(sprintf('%s/refHST0000.edf',calib.dir),[],'nodisp')-calibdark;
+calibrefend=edf_read(sprintf('%s/refHST%0.4d.edf',calib.dir,tomo_N),[],'nodisp')-calibdark;
+
+for i=0:tomo_N
+  alpha=i/tomo_N*360+alpha0;
+  cpos=r*cosd(alpha)+xrot; % used only for following the bounding box
+  
+  % bb around marker for readout from whole edf:
+  bbmarker=[floor(bbox(1)-1+cpos-bbb(1)/2) floor(bbox(2)-1+y00-bbb(2)/2) bbb(1) bbb(2)]; 
+
+  if isempty(qualirefname)
+    calibref=ones(bbmarker(4),bbmarker(3));
+  else
+    calibref=(tomo_N-i)/tomo_N*gtCrop(calibrefstart,bbmarker)+i/tomo_N*gtCrop(calibrefend,bbmarker);
+  end
+  
+  calibblob(:,:,i+1)=(edf_read(sprintf('%s/%s%0.4d.edf',calib.dir,calib.name,i),bbmarker,'nodisp')-gtCrop(calibdark,bbmarker))./calibref;
+
+  imi=i*calibfreq;
+  cmimi(i+1,:)=[i imi];
+  
+  scandark_bbmarker=gtCrop(scandark,bbmarker);
+  
+  if isempty(qualirefname)
+    imref=ones(size(scandark_bbmarker));
+  else
+    imrefa=edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,qualirefname,floor(imi/acq.refon)*acq.refon),bbmarker,'nodisp')-scandark_bbmarker;
+    imrefb=edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,qualirefname,ceil((imi-eps)/acq.refon)*acq.refon),bbmarker,'nodisp')-scandark_bbmarker;
+    imref=(acq.refon-mod(imi,acq.refon))/acq.refon*imrefa+mod(imi,acq.refon)/acq.refon*imrefb;
+  end
+  
+  imblob(:,:,i+1)=(edf_read(sprintf('%s/%s%0.4d.edf',scanfolder,qualiname,imi),bbmarker,'nodisp')-scandark_bbmarker)./imref;
+end
+
+disp('Correlate calibration and scan...')
+
+wdefault=warning;
+warning('off','all');
+
+figure
+for i=istart:tomo_N+1
+  if i==1
+    voff=0;
+    hoff=0;
+  else
+    voff=corr(i-1,1);
+    hoff=corr(i-1,2);
+  end
+  disp(sprintf('Calib #%d and Scan #%0.4d',cmimi(i,1),cmimi(i,2)))
+  shifts=sfQualiFish(calibblob(:,:,i),imblob(:,:,i),voff,hoff);
+  corr(i,1:2)=[voff hoff]+shifts;
+%  if mod(i-istart,5)==0
+    save('quali_calib_spheres_last.mat','corr','bbb','x0','x90','x180','x270','y00')
+%  end
+end
+
+warning(wdefault);
+
+save('quali_calib_spheres_last.mat','corr','bbb','x0','x90','x180','x270','y00')
+
+disp('End of quali_calib_spheres.')
+%keyboard
+
+
+end % of function
+
+
+%% Sub-functions
+
+
+function shift_output=sfQualiFish(baseim,imforfs,voff,hoff)
+
+  shift_output=[];
+  assignin('base','shift_output',shift_output);
+
+  clims=pfSetColourLimits(baseim-imforfs,5);
+  climt=pfSetColourLimits(imforfs,5);
+  disp(sprintf('  Clims: %f %f   Climt: %f %f',clims,climt))
+  
+  quali_fish(baseim,imforfs,'vroll',voff,'hroll',hoff,'clims',clims,'climt',climt);
+  set(gcf,'name','Correlate calibration and scan...')
+  while isempty(shift_output)
+    drawnow;
+    shift_output=evalin('base','shift_output');
+  end
+
+  shift_output=evalin('base','shift_output');
+
+end % of sfQualiFish
+
+
+
+%% Unused sub-functions 
+
+function [ydrift_pol,zdrift_pol,ydrift_int,zdrift_int]=nfComputePolynomials(lower_sphere_ver,lower_sphere_hor,upper_sphere_ver,upper_sphere_hor,tomo_N,calibfreq,totproj)
+
+  tol_pol=2;
+
+  corr_ver_calib=NaN(totproj+1,1);
+  for i=0:tomo_N
+    corr_ver_calib(i*calibfreq+1)=(lower_sphere_ver(i+1)+upper_sphere_ver(i+1))/2;
+  end
+
+  corr_hor_calib=NaN(totproj+1,1);
+  for i=0:tomo_N
+    corr_hor_calib(i*calibfreq+1)=(lower_sphere_hor(i+1)+upper_sphere_hor(i+1))/2;
+  end
+
+
+    % Polynomial of vertical drift
+    corr_ver=corr_ver_calib;
+  
+    figure('name','Vertical drift of scan from calibration')
+    hold on
+    plot(corr_ver,'r.')
+
+    %[pol_ver,s_ver,mu_ver]=polyfit(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),polyorder_outliers);
+    %corrp_ver=polyval(pol_ver,((1:totproj+1)-mu_ver(1))/mu_ver(2))';
+    %err_ver=corrp_ver-corr_ver;
+    err_ver=0; % no outliers considered
+    
+    corr_ver(abs(err_ver)>tol_pol*std(err_ver(~isnan(err_ver))))=NaN;
+    plot(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),'g.')
+    plot(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),'g-')
+    [pol_ver,s_ver,mu_ver]=polyfit(find(~isnan(corr_ver)),corr_ver(~isnan(corr_ver)),polyorder_driftcurve);
+    corrp_ver=polyval(pol_ver,((1:totproj+1)-mu_ver(1))/mu_ver(2))'; % vector of drifts
+    plot(corrp_ver,'r.','markersize',3)
+
+
+    % Polynomial of horizontal drift
+
+    corr_hor=corr_hor_calib+(parameters.acq.xdet/2+0.5-parameters.calib.rotx);
+
+    figure('name','Horizontal drift of scan from calibration')
+    hold on
+    plot(corr_hor,'r.')
+
+    %[pol_hor,s_hor,mu_hor]=polyfit(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),polyorder_outliers);
+    %corrp_hor=polyval(pol_hor,((1:totproj+1)-mu_hor(1))/mu_hor(2))';
+    %err_hor=corrp_hor-corr_hor;
+    err_hor=0; % no outliers considered
+
+    corr_hor(abs(err_hor)>tol_pol*std(err_hor(~isnan(err_hor))))=NaN;
+    plot(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),'g.')
+    plot(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),'g-')
+    [pol_hor,s_hor,mu_hor]=polyfit(find(~isnan(corr_hor)),corr_hor(~isnan(corr_hor)),polyorder_driftcurve);
+    corrp_hor=polyval(pol_hor,((1:totproj+1)-mu_hor(1))/mu_hor(2))'; % vector of drifts
+    plot(corrp_hor,'r.','markersize',3)
+
+    % The resulting drift polynomials
+    ydrift_pol=corrp_hor;
+    zdrift_pol=corrp_ver;
+
+    % Interpolated drifts
+    zdrift_int=corr_ver;
+    zdrift_int(isnan(zdrift_int))=interp1(find(~isnan(zdrift_int)),zdrift_int(~isnan(zdrift_int)),find(isnan(zdrift_int)));
+
+    ydrift_int=corr_hor;
+    ydrift_int(isnan(ydrift_int))=interp1(find(~isnan(ydrift_int)),ydrift_int(~isnan(ydrift_int)),find(isnan(ydrift_int)));
+
+end % of nfComputePolynomials
+
+
+  
diff --git a/quali_fish.m b/quali_fish.m
new file mode 100755
index 0000000000000000000000000000000000000000..ec0b20f6d498124e61f8a6326c7af2cfab293860
--- /dev/null
+++ b/quali_fish.m
@@ -0,0 +1,317 @@
+function quali_fish(varargin)
+
+% Originally: function findshifts2(varargin)
+% Changed for treating quali images manually: sets zoom level right away.
+%
+% function shift=findshifts(im1,im2)
+% allows to to determine visually the relative shift between two images
+% KEYS:
+% arrows (cursor keys) - one pixel shift
+% shift-arrows - ten pixel shift
+% 1 (2)  - increase (decrease) image contrast
+% 3 (4)  - increase (decrease) image brightness
+%
+% press    t       to toggle between images
+% press    s       to return to to image subtraction mode
+% press    z       to select graphically a region of interest (4 times oversampling)
+% press    r       to return to full image')
+% press  enter     to accept current value')
+% 
+% OTHER STARTUP OPTIONS
+% findshifts2(im1,im1,parameter,value)
+% where parameter and value pairs can be:
+%   'roix',[minimum maximum]  - set the horizontal region of interest
+%   'roiy',[minimum maximum]  - vertical ROI
+%   'clims',[minimum maximum] - preset the colour limits
+%   'precorrelate','yes'      - attempt to correlate the images before
+%                               interaction
+
+% origin: Wolfgang  12/05
+
+  %% startup
+  app=[];
+  app.view.h=gcf; % create a new figure
+  app.mode='subtract';
+  app.togglestate=true;
+  app.vshift=0;
+  app.hshift=0;
+  app.voffset=0;
+  app.hoffset=0;
+  app.zoom=1;
+  app.view.h=gcf;
+  app.clims=[-0.1 0.1];
+  app.climt=[0 1];
+  app.clima=[0 2];
+  app.im0=varargin{1};
+  app.im1=varargin{2};
+  app.roix=[1 size(app.im0,2)];
+  app.roiy=[1 size(app.im0,1)];
+  app.precorrelate='off';
+  app.block='off';
+  app.quit=0;
+
+  %%%%%%%%%%%%%%%%
+  app.vroll=0;
+  app.hroll=0;
+  %%%%%%%%%%%%%%%%
+  
+  if nargin>2
+    if iscell(varargin{3})
+      app=parse_pv_pairs(app,varargin{3});
+    else
+      app=parse_pv_pairs(app,{varargin{3:end}});
+    end
+  end
+
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  app.orig0=app.im0;
+  app.orig1=app.im1;
+
+  app.zoom=10;
+  roi=[1 1 app.roix(2)-app.roix(1)+1 app.roiy(2)-app.roiy(1)+1];
+  app.im0=imresize(imcrop(app.im0,roi),app.zoom,'bicubic');
+  app.im1=imresize(imcrop(app.im1,[roi(1)-app.hshift,roi(2)-app.vshift,roi(3),roi(4)]),app.zoom,'bicubic');
+  
+  app.im1=roll(app.im1,round(app.vroll*app.zoom),round(app.hroll*app.zoom));
+  
+  assignin('base','updaterunning',false)
+  
+  
+%   % precrop the image
+%   app.im0=app.im0(app.roiy(1):app.roiy(2),app.roix(1):app.roix(2));
+%   app.im1=app.im1(app.roiy(1):app.roiy(2),app.roix(1):app.roix(2));
+ 
+%   % then pre-correlate if requested
+%   if strcmpi(app.precorrelate,'yes') || strcmpi(app.precorrelate,'on')
+%     fprintf('Pre-correlating images\n')
+% 
+%     tmp=correlate(app.im0,app.im1);
+%     app.voffset = tmp(1);app.hoffset=tmp(2);
+%   end
+% 
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  
+  
+  set(app.view.h,'KeyPressFcn',@sfKeyPress)
+  %  help(mfilename)
+  iptsetpref('imtoolinitialmagnification','fit')
+  
+  %keyboard
+  
+  sfUpdateFigure;
+   
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+  %r=[1 1 app.roix(2)-app.roix(1)+1 app.roiy(2)-app.roiy(1)+1];
+  %sfZoom(r)
+  %sfUpdateFigure;
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  
+  if strcmp(app.block,'on')
+    % if user wants nothing to return until findshift is finished
+    while 1
+      drawnow
+      if app.quit==1
+        break
+      end
+    end
+  end
+  
+function sfKeyPress(varargin)
+   if evalin('base','updaterunning')
+    %disp('too fast')
+    return
+   else
+    assignin('base','updaterunning',true)
+   end
+
+  c=varargin{2};
+  switch c.Key
+    case 'uparrow'    
+      if strcmp(c.Modifier,'shift')
+        app.vshift=app.vshift-10/app.zoom;
+      else
+        app.vshift=app.vshift-1/app.zoom;
+      end
+      sfUpdateFigure;
+
+    case 'downarrow'
+      if strcmp(c.Modifier,'shift')
+        app.vshift=app.vshift+10/app.zoom;
+      else
+        app.vshift=app.vshift+1/app.zoom;
+      end
+      sfUpdateFigure;
+    
+    case 'rightarrow'
+      if strcmp(c.Modifier,'shift')
+        app.hshift=app.hshift+10/app.zoom;
+      else
+        app.hshift=app.hshift+1/app.zoom;
+      end
+      sfUpdateFigure;
+
+    case 'leftarrow'
+      if strcmp(c.Modifier,'shift')
+        app.hshift=app.hshift-10/app.zoom;
+      else
+        app.hshift=app.hshift-1/app.zoom;
+      end
+      sfUpdateFigure;
+    
+    case 'return'
+      %exit interactive mode and return current shift
+      set(app.view.h,'KeyPressFcn','');
+      assignin('base','shift_output',[app.vshift+app.voffset app.hshift+app.hoffset]);
+      fprintf('Shift is: [%.2fv %.2fh]\n',app.vshift+app.voffset,app.hshift+app.hoffset);
+      app.quit=1;
+      return;
+
+    case 'a'
+      disp('changing to adding mode');
+      app.mode='add';
+      sfUpdateFigure;
+
+    case '1'
+      disp('Increasing contrast')
+      switch app.mode
+        case 'subtract'
+          app.clims=app.clims*0.9;
+          disp(sprintf('clim is %f %f',app.clims(1),app.clims(2)));
+        case 'toggle'
+          app.climt=app.climt*0.95;
+          disp(sprintf('clim is %f %f',app.climt(1),app.climt(2)));
+        case 'add'
+          app.clima=app.clima*0.9;
+          disp(sprintf('clim is %f %f',app.clima(1),app.clima(2)));
+      end
+      sfUpdateFigure;
+      
+    case '2'
+      disp('Decreasing contrast')
+      switch app.mode
+        case 'subtract'
+          app.clims=app.clims*1.1;
+          disp(sprintf('clim is %f %f',app.clims(1),app.clims(2)));
+        case 'toggle'
+          app.climt=app.climt*1.05;
+          disp(sprintf('clim is %f %f',app.climt(1),app.climt(2)));
+        case 'add'
+          app.clima=app.clima*1.1;
+          disp(sprintf('clim is %f %f',app.clima(1),app.clima(2)));
+      end
+      sfUpdateFigure;
+    case '3'
+      disp('Colormap brighter')
+      switch app.mode
+        case 'subtract'
+          app.clims=app.clims-max(app.clims)*0.1;
+          disp(sprintf('clim is %f %f',app.clims(1),app.clims(2)));
+        case 'toggle'
+          app.climt=app.climt-mean(app.climt)*0.05;
+          disp(sprintf('clim is %f %f',app.climt(1),app.climt(2)));
+        case 'add'
+          app.clima=app.clima-mean(app.clima)*0.1;
+          disp(sprintf('clim is %f %f',app.clima(1),app.clima(2)));
+      end
+      sfUpdateFigure;
+    case '4'
+      disp('Colormap darker')
+      switch app.mode
+        case 'subtract'
+          app.clims=app.clims+max(app.clims)*0.1;
+          disp(sprintf('clim is %f %f',app.clims(1),app.clims(2)));
+        case 'toggle'
+          app.climt=app.climt+mean(app.climt)*0.05;
+          disp(sprintf('clim is %f %f',app.climt(1),app.climt(2)));
+        case 'add'
+          app.clima=app.clima+mean(app.clima)*0.1;
+          disp(sprintf('clim is %f %f',app.clima(1),app.clima(2)));
+      end
+      sfUpdateFigure;
+    case 's'
+      disp('changing to subtraction mode');
+      app.mode='subtract';
+      app.clim=app.clims;
+      sfUpdateFigure;
+    case 'z'
+      disp('Select region of interest');
+      title('Select region of interest');
+      [toto,r]=imcrop;
+      disp('Zooming...')
+      title('Zooming...')
+      r=round(r);
+      sfZoom(r)
+      sfUpdateFigure;
+    case 'r'
+      disp('reset full image');
+      app.zoom=1;
+      app.im0=app.orig0;
+      app.im1=app.orig1;
+      app.vshift=round(app.vshift+app.voffset);
+      app.hshift=round(app.hshift+app.hoffset);
+      app.voffset=0;
+      app.hoffset=0;
+      sfUpdateFigure;
+    case 't'
+      app.mode='toggle';
+      app.togglestate= not(app.togglestate);
+      app.clim=app.climt;
+      sfUpdateFigure;
+    case 'h'
+      help(mfilename)
+  end
+
+  assignin('base','updaterunning',false)
+
+end
+
+
+
+% function sfZoom(roi)
+%   
+%   app.orig0=app.im0;
+%   app.orig1=app.im1;
+%   app.zoom=10;
+%   app.im0=imresize(imcrop(app.im0,roi),app.zoom,'bicubic');
+%   app.im1=imresize(imcrop(app.im1,[roi(1)-app.hshift,roi(2)-app.vshift,roi(3),roi(4)]),app.zoom,'bicubic');
+%   app.voffset=app.vshift;
+%   app.hoffset=app.hshift;
+%   app.vshift=0;
+%   app.hshift=0;
+% end
+
+function sfUpdateFigure
+  colormap gray;
+  im_tmp=[];
+  im_tmp=roll(app.im1,round(app.vshift*app.zoom),round(app.hshift*app.zoom));
+  switch app.mode
+    case 'add'
+      imshow(app.im0+im_tmp,app.clima);
+      title(sprintf('vertical shift: %.2f\t horizontal shift: %.2f',app.vshift+app.voffset,app.hshift+app.hoffset));
+    case 'subtract'
+      %imagesc(app.im0-im_tmp,app.clims);
+     imshow(app.im0-im_tmp,app.clims);
+%      keyboard
+%      axis image
+      title(sprintf('vertical shift: %.2f\t horizontal shift: %.2f',app.vshift+app.voffset,app.hshift+app.hoffset));
+    case 'toggle'
+      if app.togglestate == true
+        imagesc(app.im0,app.climt);
+        axis image
+        title('first image (fixed position)');
+      else
+        imagesc(im_tmp,app.climt);
+        axis image
+        title(sprintf('second image: vertical shift: %.2f\t horizontal shift: %.2f',app.vshift+app.voffset,app.hshift+app.hoffset));
+      end
+  end
+  drawnow
+end
+
+
+
+end
diff --git a/zUtil_ART/drawproj.m b/zUtil_ART/drawproj.m
new file mode 100755
index 0000000000000000000000000000000000000000..e34fc48954a1b0f9b374f460e2d7211209f6f822
--- /dev/null
+++ b/zUtil_ART/drawproj.m
@@ -0,0 +1,217 @@
+d='/data/id19/graintracking/graingrowth/s5_dct8_';
+tname='s5_dct8_';
+
+cd(d)
+load('4_grains/grain2_/grain2_.mat')
+
+recon_dir='tmpGJ/';
+
+Aspots=struct_ids(pair_vector==1);
+thetarange =[];
+etarange=[];
+omegarange=[];
+spotndx=[];
+for n=Aspots
+  sql=sprintf('select theta,eta,omega from %sspotpairs where difAID=%d',tname,n);
+  [t,e,o]=mym(sql);
+  if isempty(t)
+    continue
+  end
+  thetarange=[thetarange t];
+  etarange=[etarange e];
+  omegarange=[omegarange o*2];  % spot fudge factor here
+  spotndx=[spotndx n];
+
+end
+
+numproj=length(thetarange);
+%numproj=4;
+thetarange = thetarange(1:numproj);
+etarange=etarange(1:numproj);
+omegarange=omegarange(1:numproj);
+ndx=0;
+
+radius = 5; % of warped difspot images
+[x,z]=meshgrid(1:2048);
+y=zeros(size(x));
+
+
+clf
+hold on
+try
+  mkdir(recon_dir)
+catch,end
+try
+  system(['rm ' recon_dir '*']);
+catch,end
+
+clear xorigin yorigin xdir ydir xc yc wA wB pA pB
+for n=spotndx(1:numproj)
+  ndx=ndx+1;
+  imA=gtGetSummedDifSpot(n);
+  [xoriginA(ndx),yoriginA(ndx),xcenA(ndx),ycenA(ndx)]=...
+    mym(sprintf('select BoundingBoxXOrigin,BoundingBoxYOrigin,CentroidX,CentroidY from %sdifspot where difspotID=%d',tname,n));
+
+  [imAx,imAz]=meshgrid(...
+    xoriginA(ndx):xoriginA(ndx)+size(imA,2),...
+    yoriginA(ndx):yoriginA(ndx)+size(imA,1));
+
+  imAx=imAx-1024.5;
+  imAz=imAz-1024.5;
+  xcenA=xcenA-1024.5;
+  ycenA=ycenA-1024.5;
+
+
+
+  n2=mym(sprintf('select difBID from %sspotpairs where difAID=%d',tname,n));
+
+
+  imB=gtGetSummedDifSpot(n2);
+  % used to be B table
+  [xoriginB(ndx),yoriginB(ndx),xcenB(ndx),ycenB(ndx)]=...
+    mym(sprintf('select BoundingBoxXOrigin,BoundingBoxYOrigin,CentroidX,CentroidY from %sdifspot where difspotID=%d',tname,n2));
+
+  [imBx,imBz]=meshgrid(...
+    xoriginB(ndx):xoriginB(ndx)+size(imB,2),...
+    yoriginB(ndx):yoriginB(ndx)+size(imB,1));
+
+  imBx=imBx-1024.5;
+  imBz=imBz-1024.5;
+  xcenB=xcenB-1024.5;
+  ycenB=ycenB-1024.5;
+
+  gradient_image=zeros(2048); %repmat(linspace(0,1,2048)',1,2048);
+  % write projections to disk in form that suits AREMIS
+  imAART=gtPlaceSubImage(imA,zeros(2048),xoriginA(ndx),yoriginA(ndx));
+  %  imAART=gtPlaceSubImage(ones(100),gradient_image,1024-50,1024-50);
+  %  imAART=gtPlaceSubImage(ones(100),gradient_image,xoriginA(ndx),yoriginA(ndx));
+  fname=sprintf('%sscanname%d',recon_dir,ndx);
+  sdt_write(fname,imAART,'float32');
+
+
+  detradius=11660/2.4;
+  imAy=detradius*ones(size(imAx));
+  imBy=detradius*ones(size(imBx));
+
+  pA(ndx)=patch([-1024.5 -1024.5 1024.5 1024.5 -1024.5],repmat(imAy(1),1,5),[-1024.5 1024.5 1024.5 -1024.5 -1024.5],[1 0 0]);
+  wA(ndx)=warp(imAx,imAy,imAz,imA./max(imA(:)));
+  cA(ndx)=plot3(xcenA(ndx),detradius,ycenA(ndx),'ro');
+
+  rotate(wA(ndx),[0 90],-omegarange(ndx),[0 0 0]);
+  rotate(pA(ndx),[0 90],-omegarange(ndx),[0 0 0]);
+  rotate(cA(ndx),[0 90],-omegarange(ndx),[0 0 0]);
+
+  pB(ndx)=patch([-1024.5 -1024.5 1024.5 1024.5 -1024.5],repmat(imBy(1),1,5),[-1024.5 1024.5 1024.5 -1024.5 -1024.5],[0 1 0]);
+  wB(ndx)=warp(imBx,imBy,imBz,imB./max(imB(:)));
+  cB(ndx)=plot3(xcenB(ndx),detradius,ycenB(ndx),'go');
+
+  rotate(wB(ndx),[0 90],-(omegarange(ndx)+180),[0 0 0]);
+  rotate(pB(ndx),[0 90],-(omegarange(ndx)+180),[0 0 0]);
+  rotate(cB(ndx),[0 90],-(omegarange(ndx)+180),[0 0 0]);
+
+  % fake a line between the spots
+  x1=get(cA(ndx),'xdata');x1=mean(x1(:));
+  y1=get(cA(ndx),'ydata');y1=mean(y1(:));
+  z1=get(cA(ndx),'zdata');z1=z1(1);
+
+  x2=get(cB(ndx),'xdata');x2=mean(x2(:));
+  y2=get(cB(ndx),'ydata');y2=mean(y2(:));
+  z2=get(cB(ndx),'zdata');z2=mean(z2(:));
+
+  l(ndx)=plot3([x1 x2],[y1 y2],[z1 z2],'-');
+  %drawnow
+end
+set(pA,'facealpha',0.1);
+set(pB,'facealpha',0.1);
+set(gca,'projection','perspective')
+axis equal
+axis vis3d
+xlabel('x'),ylabel('y'),zlabel('z')
+shg
+cameramenu,cameratoolbar
+
+drawnow
+%%%%%%%%%%%%%%%%%%%%%%%%%%   ART
+
+%%
+proj.eta=etarange;
+proj.theta=thetarange;
+proj.omega=omegarange;
+
+proj.indices=1:length(etarange);
+
+zdet=-11.6610;
+lambda=[1] ; % 0.6 0.2 0.1
+
+numpixels=2048;
+np=numpixels;nq=numpixels;
+xsi_angles= [90];
+delta_angles=[0];
+pixsize=0.01;
+scanname='scanname';
+parfilename='parfile.par';
+testing=false;
+disp('should theta = 2theta?')
+if 1 % 3D reconstruction
+  % reconstructed volume
+  % centre of sphere seems to be at y=-2???
+  if testing==true
+    x1=-.25;x2=.25;  % second horizontal dimenion
+    y1=-.25;y2=.25;  % distance from sample to detector of detector (omega 0)
+    z1=-.25;z2=.25;  % vertical dimension of detector
+  else
+    x1=-5;x2=5;  % second horizontal dimenion
+    y1=-5;y2=5;  % distance from sample to detector of detector (omega 0)
+    z1=-5;z2=5;  % vertical dimension of detector
+  end
+
+
+  voxsize=0.10;
+
+  % make these odd so the center voxel is really centred.
+  nx=((x2-x1)/voxsize)+1;
+  ny=((y2-y1)/voxsize)+1;
+  nz=((z2-z1)/voxsize)+1;
+
+  disp('3D reconstruction')
+  gtART3D(scanname,[recon_dir parfilename],proj.indices,proj.omega,xsi_angles,delta_angles,proj.theta,proj.eta,...
+    lambda,length(lambda),pixsize,0,np,nq,0, ...
+    zdet+0,voxsize,z1,nz,x1,nx,y1,ny); %min(yy(:)),nz,min(xx(:)),np,min(xx(:)),nq);
+
+  disp('ART volume probably needs rotating')
+
+else
+  disp('Parallel beam reconstruction')
+  % working parallel reconstruction
+  gtMakeARTJob(scanname,parfilename,proj.indices,proj.omega,lambda,length(lambda),1,0,np,nq,0,z1-0,nz,1,np,1,nq)
+end
+
+%% run ART
+cd(recon_dir)
+cmd=sprintf('rm %s_res*',scanname);
+system(cmd)
+
+cmd_rec_alg=gtGetARTCommand('rec_alg');
+cmd_seg2view=gtGetARTCommand('seg2view');
+
+
+cmd=sprintf('%s %s',cmd_rec_alg,parfilename);
+system(cmd);
+
+for n=1:length(lambda)
+  system(sprintf('%s %s_res0_%d',cmd_seg2view,scanname,n));
+end
+
+
+%% display the results
+vol=sdt_read(sprintf('%s_res0_%d',scanname,1));
+
+fprintf('Pixel size: %3.3f Voxel size: %3.3f \n',pixsize,voxsize);
+%orthogonalslicer(vol,[1 1 1],gray,min(vol(:)),max(vol(:))+eps);
+vol_view(vol,'clims',0)
+fprintf('Volume min: %3.3f max: %3.3f\n',min(vol(:)),max(vol(:)));
+
+axis on
+
+
+
diff --git a/zUtil_ART/gtBackProject3D.m b/zUtil_ART/gtBackProject3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..d847604c0b9c6c976d25f063ef8af1b9522ce577
--- /dev/null
+++ b/zUtil_ART/gtBackProject3D.m
@@ -0,0 +1,112 @@
+function varargout=gtBackProject3D(proj)
+  testing=true;
+  graphics=true;
+  zdet=proj.zdet;
+  np=proj.numpixels;nq=np;
+  nz=nq;
+  parfilename='parfile.par';
+  scanname='scanname';
+
+
+  if testing==true
+    % write projections to disk
+    for n=proj.indices
+      fname=sprintf('%s%d',scanname,n);
+      sdt_write(fname,proj.projections(:,:,n),'float32');
+    end
+    disp('Written projections to disk');
+  end
+  lambda=[1] ; % 0.6 0.2 0.1
+
+
+  xsi_angles= [90];
+  delta_angles=[0];
+  pixsize=proj.sizepixels;
+  disp('should theta = 2theta?')
+
+  % reconstructed volume
+  % centre of sphere seems to be at y=-2???
+
+  x1=-.5;x2=.5;  % second horizontal dimenion
+  y1=-.5;y2=.5;  % distance from sample to detector of detector (omega 0) (x in lab space)
+  z1=-.5;z2=.5;  % vertical dimension of detector
+
+  if 0 % keep volume centered around centre of test sphere
+    
+    xoff=proj.xsc;
+    yoff=-proj.ysc;
+    zoff=proj.zsc;
+    x1=x1+xoff;x2=x2+xoff;
+    y1=y1+yoff;y2=y2+yoff;  % for omega=0, this is x-ray axis
+    z1=z1+zoff;z2=z2+zoff;
+  end
+
+
+  if testing==true
+    voxsize=0.010;
+  else
+    voxsize=0.10;
+  end
+  % make these odd so the center voxel is really centred.
+  nx=((x2-x1)/voxsize)+1;
+  ny=((y2-y1)/voxsize)+1;
+  nz=((z2-z1)/voxsize)+1;
+
+  if graphics
+    figure
+    % draw the reconstructed volume
+    h_reconvol(1)=patch([x1 x2 x2 x1],[y1 y1 y2 y2],[z1 z1 z1 z1],'r');
+    h_reconvol(2)=patch([x1 x2 x2 x1],[y1 y1 y2 y2],[z2 z2 z2 z2],'r');
+    h_reconvol(3)=patch([x1 x1 x1 x1],[y1 y2 y2 y1],[z1 z1 z2 z2],'r');
+    h_reconvol(4)=patch([x2 x2 x2 x2],[y1 y2 y2 y1],[z1 z1 z2 z2],'r');
+    h_reconvol(5)=patch([x1 x2 x2 x1],[y1 y1 y1 y1],[z1 z1 z2 z2],'r');
+    h_reconvol(6)=patch([x1 x2 x2 x1],[y2 y2 y2 y2],[z1 z1 z2 z2],'r');
+    set(h_reconvol,'facealpha',.5)
+    view(3)
+    xlabel('x');ylabel('y');zlabel('z')
+  end
+
+  disp('3D reconstruction')
+  gtART3D(scanname,parfilename,proj.indices,proj.omega,xsi_angles,delta_angles,proj.theta,proj.eta,...
+    lambda,length(lambda),pixsize,0,np,nq,0, ...
+    zdet+0,voxsize,z1,nz,x1,nx,y1,ny); %min(yy(:)),nz,min(xx(:)),np,min(xx(:)),nq);
+
+
+
+
+  %% run ART
+  cmd=sprintf('rm %s_res*',scanname);
+  system(cmd);
+  %%
+  cmd_rec_alg=gtGetARTCommand('rec_alg');
+  cmd_seg2view=gtGetARTCommand('seg2view');
+
+
+  %  cmd=sprintf('%s %s > /dev/null 2>&1',cmd_rec_alg,parfilename);
+  cmd=sprintf('%s %s',cmd_rec_alg,parfilename);
+  system(cmd);
+
+  for n=1:length(lambda)
+    %    system(sprintf('%s %s_res0_%d > /dev/null 2>&1',cmd_seg2view,scanname,n))
+    system(sprintf('%s %s_res0_%d ',cmd_seg2view,scanname,n));
+  end
+
+
+  %% display the results
+  vol=sdt_read(sprintf('%s_res0_%d',scanname,1));
+
+  fprintf('X: %2.2f %2.2f Y: %2.2f %2.2f Z: %2.2f %2.2f\n',x1,x2,y1,y2,z1,z2);
+  fprintf('Pixel size: %3.3f Voxel size: %3.3f \n',pixsize,voxsize);
+
+  fprintf('NX: %3d NY: %3d NZ: %3d\n\n',nx,ny,nz);
+
+  fprintf('Volume grayscale min: %3.3f max: %3.3f\n\n',min(vol(:)),max(vol(:)));
+
+  % volume needs rotating to align with lab conventions
+  vol=permute(vol,[2 1 3]);
+  vol=flipdim(vol,2);
+
+  vol_view(vol);
+  if nargout==1
+    varargout{1}=vol;
+  end
diff --git a/zUtil_ART/gtFlipProjections.m b/zUtil_ART/gtFlipProjections.m
new file mode 100755
index 0000000000000000000000000000000000000000..a9225427060cac8c56effc5c01c2d5d91ff9da52
--- /dev/null
+++ b/zUtil_ART/gtFlipProjections.m
@@ -0,0 +1,23 @@
+function grflip=gtFlipProjections(gr,index)
+  
+  grflip=gr;
+  grflip.omega=-gr.omega;
+  grflip.omegashear=-gr.omegashear;
+  grflip.eta=-gr.eta;
+ 
+  for i=index
+	name=sprintf('difspot%d',i);
+	tmp=sdt_read(name);
+	name=sprintf('difspot_flip%d',i);
+	sdt_write(name,fliplr(tmp),'float32');
+	
+	name=sprintf('shearspot%d',i);
+	tmp=sdt_read(name);
+	name=sprintf('shearspot_flip%d',i);
+	sdt_write(name,fliplr(tmp),'float32');
+	
+	name=sprintf('extspot%d',i);
+	tmp=sdt_read(name);
+	name=sprintf('extspot_flip%d',i);
+	sdt_write(name,fliplr(tmp),'float32');
+  end	
\ No newline at end of file
diff --git a/zUtil_ART/gtGetARTCommand.m b/zUtil_ART/gtGetARTCommand.m
new file mode 100755
index 0000000000000000000000000000000000000000..831b9a62e92124bc12bfadba5a251e3d1f9a985b
--- /dev/null
+++ b/zUtil_ART/gtGetARTCommand.m
@@ -0,0 +1,44 @@
+function cmd=gtGetARTCommand(executable)
+% gtGetARTCommand(executable)
+% returns the full path to the executable requested.
+% executable can be with "rec_alg" or "seg2view"
+%
+% Usage:
+% cmd=gtGetARTCommand('rec_alg')
+% system(cmd)
+%
+% This runs rec_alg...
+%
+% This supports Linux on Athlons (corals etc) and Mac Intel machines
+% using 'computer' to determine machine type
+  switch lower(executable)
+    case 'rec_alg'
+      switch lower(computer)
+        case 'glnxa64'
+          cmd='/data/id19/graintracking/matlab/zUtil_ART/rec_alg_GLNXA64';
+        case 'maci'
+          cmd ='~/matlab_graintracking/zUtil_ART/rec_alg_MACI';
+        otherwise
+          disp('Computer not recognised')
+          cmd=[];
+          help(mfilename)
+      end
+    case 'seg2view'
+      switch lower(computer)
+        case 'glnxa64'
+          cmd='/data/id19/graintracking/matlab/zUtil_ART/seg2view_GLNXA64';
+        case 'maci'
+          cmd ='~/matlab_graintracking/zUtil_ART/seg2view_MACI';
+        otherwise
+          disp('Computer not recognised')
+          cmd=[];
+          help(mfilename)
+      end
+    otherwise
+      disp('Command not recognised')
+      cmd=[];
+      help(mfilename)
+  end
+
+end
+
diff --git a/zUtil_ART/gtMakeLinks.m b/zUtil_ART/gtMakeLinks.m
new file mode 100755
index 0000000000000000000000000000000000000000..999b1695235be052e2e6935a76137205f7c5b047
--- /dev/null
+++ b/zUtil_ART/gtMakeLinks.m
@@ -0,0 +1,18 @@
+function gtMakeLinks3D(grainid,dif,ext)
+
+  j=1;
+ 
+  for i=1:length(dif)
+	unix(sprintf('ln -sf difspot%d.sdt grain%d_%d.sdt',grainid,dif(i),j));
+	unix(sprintf('ln -sf difspot%d.spr grain%d_%d.spr',grainid,dif(i),j));
+	j=j+1;
+  end
+  
+  
+  for i=1:length(ext)
+	unix(sprintf('ln -sf extspot%d.sdt grain%d_%d.sdt',grainid,ext(i),j));
+	unix(sprintf('ln -sf extspot%d.spr grain%d_%d.spr',grainid,ext(i),j));
+	j=j+1;
+  end	
+  
+  disp(sprintf('%d links have been created',j-1));
\ No newline at end of file
diff --git a/zUtil_ART/gtMakeLinksflip.m b/zUtil_ART/gtMakeLinksflip.m
new file mode 100755
index 0000000000000000000000000000000000000000..c9164ace0eaf60210312d9a9c90544fd0910625b
--- /dev/null
+++ b/zUtil_ART/gtMakeLinksflip.m
@@ -0,0 +1,23 @@
+function gtMakeLinksflip(dif,shear,ext)
+
+  j=1;
+ 
+  for i=1:length(dif)
+	unix(sprintf('ln -sf difspot_flip%d.sdt proj_flip%d.sdt',dif(i),j));
+	unix(sprintf('ln -sf difspot_flip%d.spr proj_flip%d.spr',dif(i),j));
+	j=j+1;
+  end
+  
+  for i=1:length(shear)
+	unix(sprintf('ln -sf shearspot_flip%d.sdt proj_flip%d.sdt',shear(i),j));
+	unix(sprintf('ln -sf shearspot_flip%d.spr proj_flip%d.spr',shear(i),j));
+	j=j+1;
+  end	
+  
+  for i=1:length(ext)
+	unix(sprintf('ln -sf extspot_flip%d.sdt proj_flip%d.sdt',ext(i),j));
+	unix(sprintf('ln -sf extspot_flip%d.spr proj_flip%d.spr',ext(i),j));
+	j=j+1;
+  end	
+  
+  disp(sprintf('%d links have been created',j-1));
\ No newline at end of file
diff --git a/zUtil_ART/gtShowProjections.m b/zUtil_ART/gtShowProjections.m
new file mode 100755
index 0000000000000000000000000000000000000000..ab7bcf3d6efaa5c42d9f538275362610a5a39b60
--- /dev/null
+++ b/zUtil_ART/gtShowProjections.m
@@ -0,0 +1,15 @@
+function gtShowProjections(proj)
+  stack=proj.projections;
+  stacksize=size(stack,3);
+  figure
+  ax=[];
+  for n=1:stacksize
+    subplot(1,stacksize,n)
+    imshow(stack(:,:,n),[])
+    title(sprintf('Omega %.0f Theta %.2f Eta %.2f',proj.omega(n),proj.theta(n),proj.eta(n)))
+    ax=[ax gca];
+    axis on
+  end
+  linkaxes(ax,'xy')
+  zoom on
+end
diff --git a/zUtil_ART/gtSimulateProjections.m b/zUtil_ART/gtSimulateProjections.m
new file mode 100755
index 0000000000000000000000000000000000000000..cfdf39dbb642b8db0e8bd2b50fe8ce1be2466088
--- /dev/null
+++ b/zUtil_ART/gtSimulateProjections.m
@@ -0,0 +1,269 @@
+function proj=gtSimulateProjections(xsc,ysc,zsc,thetarange,etarange,omegarange)
+  test=true;
+
+  if exist('thetarange','var') && any(thetarange<0)
+    error('All theta should be >= 0')
+  end
+  draw_graphics=true;
+
+
+  if (test)
+    disp('Ignoring parameters - running example')
+    close all
+    %proj=gtSimulateProjections(1,2,3,[10,10,10,10],[0 90 180 270],[0 30 60
+    %90]);
+    xsc=0;ysc=0;zsc=0;
+    thetarange=[0 10 20 30];
+    %    thetarange=[0 0 0 0 ];
+    etarange=[0 0 0 0];
+    omegarange=[0 45 90 0];
+  end
+   xdet=1;  % CCD at xc=10mm (in spec terms)
+  %zdet=-11.6610;
+
+  numpixels=1001;
+  sizepixels=0.01;
+  %numpixels=11;
+  %sizepixels=1;
+  
+  
+  if ~(all(size(thetarange)==size(etarange)) && all(size(thetarange)==size(omegarange)))
+    error('All angle ranges should be the same length')
+  end
+
+  if ~mod(numpixels,2)
+    warning('Odd pixel number are easier...')
+  end
+
+  xdetsize=numpixels*sizepixels;
+  ydetsize=xdetsize;
+
+  np=numpixels;nq=np;
+  [uu,vv]=meshgrid(...
+    linspace(-floor(numpixels/2)*sizepixels,floor(numpixels/2)*sizepixels,numpixels),...
+    linspace(floor(numpixels/2)*sizepixels,-floor(numpixels/2)*sizepixels,numpixels));
+
+  rsphere=0.3;  % 0.01 only works for 0,45,90 etc +-1
+  %%%%%%%%%%%%%%%%%%%
+  % xsc and ysc are horiztonal in the plane of the detector
+  % zsc is vertical in the plane of the detector
+  %  xsc=1;
+  %  ysc=0;
+  %  zsc=0;
+  fprintf('Sample centred at (%d,%d,%d)\n',xsc,ysc,zsc)
+  if draw_graphics
+    %% draw sphere
+    [xs,ys,zs]=sphere;
+    figure
+
+    clf
+    xs=(xs*rsphere)+xsc;
+    ys=(ys*rsphere)+ysc;
+    zs=(zs*rsphere)+zsc;
+    draw_sphere
+    xr=1;yr=xr;zr=xr;
+    vertices=[...
+      xsc-xr/2 ysc-yr/2 zsc-zr/2;...
+      xsc+xr/2 ysc-yr/2 zsc-zr/2;...
+      xsc-xr/2 ysc+yr/2 zsc-zr/2;...
+      xsc+xr/2 ysc+yr/2 zsc-zr/2;...
+      xsc-xr/2 ysc-yr/2 zsc+zr/2;...
+      xsc+xr/2 ysc-yr/2 zsc+zr/2;...
+      xsc-xr/2 ysc+yr/2 zsc+zr/2;...
+      xsc+xr/2 ysc+yr/2 zsc+zr/2];
+
+    faces=[1 2 4 3;...
+      5 6 8 7;...
+      1 2 6 5 ;...
+      4 3 7 8;...
+      2 4 8 6;...
+      1 3 7 5;...
+      ];
+    colors=[...
+      1 0 0;...
+      1 0 0;...
+      0 1 0;...
+      0 1 0;...
+      0 0 1;...
+      0 0 1];
+
+    if 0
+      patch('faces',faces,'vertices',vertices,'facevertexcdata',colors,'facecolor','flat');
+      alpha(0.1);
+      %light('position',[1 3 2])
+      %light('position',[-3 -1 -3]);
+    else % draw lines - opacity not working
+      vx=vertices(:,1);vy=vertices(:,2);vz=vertices(:,3);
+      lx=[vx(1) vx(1);vx(1) vx(end); vx(end) vx(end); vx(end) vx(1);...
+        vx(1) vx(1);vx(1) vx(end); vx(end) vx(end); vx(end) vx(1);...
+        vx(1) vx(1);vx(end) vx(end);vx(1) vx(1);vx(end) vx(end)];
+
+      ly=[vy(1) vy(end);vy(1) vy(1); vy(end) vy(1); vy(end) vy(end);...
+        vy(1) vy(end);vy(1) vy(1); vy(end) vy(1); vy(end) vy(end);...
+        vy(1) vy(1); vy(1) vy(1);vy(end) vy(end);vy(end) vy(end)];
+
+      lz=[vz(1) vz(1);vz(1) vz(1);vz(1) vz(1); vz(1) vz(1);...
+        vz(end) vz(end);vz(end) vz(end);vz(end) vz(end); vz(end) vz(end);...
+        vz(1) vz(end);vz(1) vz(end);vz(1) vz(end);vz(1) vz(end)];
+
+      line(lx',ly',lz')
+    end
+    view(90,0) % view like the frelon - into the x-ray beam (omega 0)
+  end
+
+  %%
+  %%%%%%%%%%%%%%%%%%%%%
+
+  % setup projection geometries
+  %  numproj=3;
+  %  thetarange=[0 0 0];
+  %  etarange=[0 0 0];
+  %  omegarange=[0 45 90 ];
+  numproj=length(thetarange);
+  etarange=etarange-90;
+
+
+  ip=zeros([size(uu) length(thetarange)]);
+
+
+  for n=1:length(thetarange) % each projection
+    theta=thetarange(n);
+    eta=etarange(n);
+    omega=omegarange(n);
+
+    % create unit cylinder
+
+    [yc,zc,xc]=cylinder;
+
+    xc(2,:)=xdet-xsc;  % move bottom of cylinder to detector plane (xsc correction will be applied as last step)
+    xc(1,:)=xc(1,:)-5*rsphere;
+
+    ydist=(rsphere/cosd(theta))-rsphere;
+    %ydist=(rsphere/cos(etarad))-rsphere;
+
+    yc(1,:)=(yc(1,:)*rsphere/cosd(theta))+(xc(1,:)*sind(theta));
+    yc(2,:)=(yc(2,:)*(rsphere/cosd(theta))+(xc(2,:)*sind(theta))); %(-rsphere*tan(thetarad));
+
+    zc=zc*rsphere;
+
+    % now do the rotation around eta
+    T=[cosd(eta) sind(eta);-sind(eta) cosd(eta)];
+
+    for q=1:2
+      yorig=yc(q,:);
+      zorig=zc(q,:);
+      transformed=T*[yorig;zorig];
+      yc(q,:)=transformed(1,:);
+      zc(q,:)=transformed(2,:);
+    end
+
+    xc=xc+xsc;
+    zc=zc+zsc;
+    draw_detector(xdet,uu,vv,omega)
+    draw_cylinder  % draw before we do a projection correction for yc
+    yc=yc+(ysc*cosd(omega) - xsc*sind(omega));
+
+    a=yc(2,:);b=zc(2,:);
+    ip(:,:,n)=inpolygon(uu,vv,a,b)*n;
+  end
+
+  %% generate ART projection files
+
+  proj.eta=etarange;  % removed +90
+  proj.theta=thetarange;
+  proj.omega=omegarange;
+  proj.projections=ip*100;
+  proj.indices=1:size(proj.projections,3);
+  proj.numpixels=numpixels;
+  proj.sizepixels=sizepixels;
+  disp('Possibly change these???')
+  proj.xsc=ysc;
+  proj.ysc=xsc;  % for omega=0. this is x-ray direction (x in lab space)
+  proj.zsc=-zsc;
+  disp('zdet?')
+  proj.zdet=xdet;
+
+
+  if 0  % originals before coordinate reassertment...
+    proj.eta=etarange+90;
+    proj.theta=thetarange;
+    proj.omega=omegarange;
+    proj.projections=ip*100;
+    proj.indices=1:size(proj.projections,3);
+    proj.numpixels=numpixels;
+    proj.sizepixels=sizepixels;
+    disp('Possibly change these???')
+    proj.xsc=0;
+    proj.ysc=0;
+    proj.zsc=zsc;
+    disp('zdet?')
+    proj.zdet=xdet;
+  end
+  disp('Eta needs eta=eta-90 for ART')
+
+  gtShowProjections(proj)
+
+
+
+  function draw_sphere
+    for q=1:4
+      subplot(2,2,q)
+      surface(xs,ys,zs)
+      xlabel('x');ylabel('y');zlabel('z')
+      axis equal
+      %    axis([-2 2 -2 2 -2 2])
+      %    axis vis3d
+      grid on
+
+    end
+
+  end
+  function draw_cylinder
+    viewaz=[0 90 0 -37.5];
+    viewel=[0 0 90 30];
+    for q=1:4
+      subplot(2,2,q)
+
+      hs=surface(xc,yc+ysc,zc,xc);
+      set(hs,'facecolor','interp','edgecolor','k')
+
+      rotate(hs,[0 0 1],omega,[xsc ysc zsc])
+
+      axis equal
+      xlabel('x');ylabel('y');zlabel('z')
+      view(viewaz(q),viewel(q))
+    end
+    axis vis3d
+    rotate3d on
+  end
+end
+
+function draw_detector(dist,uu,vv,omega)  % NOT a subfunction to avoid changing all the names!
+  x1=dist;x2=dist;y1=min(uu(:));y2=max(uu(:));z1=min(vv(:));z2=max(vv(:));
+
+  vertices=[...
+    x1 y1 z1;...
+    x2 y1 z1;...
+    x1 y2 z1;...
+    x2 y2 z1;...
+    x1 y1 z2;...
+    x2 y1 z2;...
+    x1 y2 z2;...
+    x2 y2 z2];
+
+  vx=vertices(:,1);vy=vertices(:,2);vz=vertices(:,3);
+  lx=[vx(1) vx(1);vx(1) vx(end); vx(end) vx(end); vx(end) vx(1);...
+    vx(1) vx(1);vx(1) vx(end); vx(end) vx(end); vx(end) vx(1);...
+    vx(1) vx(1);vx(end) vx(end);vx(1) vx(1);vx(end) vx(end)];
+
+  ly=[vy(1) vy(end);vy(1) vy(1); vy(end) vy(1); vy(end) vy(end);...
+    vy(1) vy(end);vy(1) vy(1); vy(end) vy(1); vy(end) vy(end);...
+    vy(1) vy(1); vy(1) vy(1);vy(end) vy(end);vy(end) vy(end)];
+
+  lz=[vz(1) vz(1);vz(1) vz(1);vz(1) vz(1); vz(1) vz(1);...
+    vz(end) vz(end);vz(end) vz(end);vz(end) vz(end); vz(end) vz(end);...
+    vz(1) vz(end);vz(1) vz(end);vz(1) vz(end);vz(1) vz(end)];
+
+  hline=line(lx',ly',lz');
+  rotate(hline,[0 0 1],omega,[0 0 0])
+end
\ No newline at end of file
diff --git a/zUtil_ART/parfile.par b/zUtil_ART/parfile.par
new file mode 100755
index 0000000000000000000000000000000000000000..81b1bfce49ea72a7c6c08eadc38ca9a843839d2d
--- /dev/null
+++ b/zUtil_ART/parfile.par
@@ -0,0 +1,129 @@
+PAGBEGIN SYSTEMAL
+PROJ_GENE_FILENAME = scanname
+EXT_PROJ0 = 1
+EXT_PROJ1 = 2
+EXT_PROJ2 = 3
+EXT_PROJ3 = 4
+NBITER = 1
+NBITER_HALF_QUADRA = 1
+NBSAUV = 1
+REC_GENE_FILENAME = scanname
+EXT_REC0 = 1
+LAMBDA_FLAG = 0
+LAMBDA = 1.000000
+ERR_FLAG = 0
+ALGO_TYPE = 1
+BLOCK_SIZE = 4
+PROJ_MNG = A
+NB_RESOL = 1
+THRESH_SUPP = 100
+CLIP_SUPP = 4
+CLIP_SPHERE = 0
+HISTO_SIZE = 100
+MAXVOL = 1000.000000
+MINVOL = -10.000000
+VOL_TYPE = 3
+PARAM1 = 0.100000
+PARAM2 = 0.000050
+PARAM3 = 0.000050
+PARAM4 = 0.050000
+PARAM5 = 0.820000
+PAGEND SYSTEMAL
+PAGBEGIN ACQGEO
+NBRADIO = 4
+#radio 1 origine position
+POSITION = 1
+FGD = 145000.000000
+PGD = 0.000000
+QGD = 0.000000
+PEPD = 0.010000
+PEQD = 0.010000
+P1D = -500.000000
+Q1D = -500.000000
+NP =  1001
+NQ =  1001
+PSI = 0.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = -0.000000
+QO = -0.000000
+MO = -144999.000000
+IPD = 0
+IQD = 0
+IPF = 1000
+IQF = 1000
+#radio 2 origine position
+POSITION = 2
+FGD = 145000.000000
+PGD = 0.000000
+QGD = 0.000000
+PEPD = 0.010000
+PEQD = 0.010000
+P1D = -500.000000
+Q1D = -500.000000
+NP =  1001
+NQ =  1001
+PSI = 45.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = -0.000000
+QO = -0.000000
+MO = -144999.000000
+IPD = 0
+IQD = 0
+IPF = 1000
+IQF = 1000
+#radio 3 origine position
+POSITION = 3
+FGD = 145000.000000
+PGD = 0.000000
+QGD = 0.000000
+PEPD = 0.010000
+PEQD = 0.010000
+P1D = -500.000000
+Q1D = -500.000000
+NP =  1001
+NQ =  1001
+PSI = 90.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = -0.000000
+QO = -0.000000
+MO = -144999.000000
+IPD = 0
+IQD = 0
+IPF = 1000
+IQF = 1000
+#radio 4 origine position
+POSITION = 4
+FGD = 145000.000000
+PGD = 0.000000
+QGD = 0.000000
+PEPD = 0.010000
+PEQD = 0.010000
+P1D = -500.000000
+Q1D = -500.000000
+NP =  1001
+NQ =  1001
+PSI = 0.000000
+XSI = 90.000000
+DELTA = 0.000000
+PO = -0.000000
+QO = -0.000000
+MO = -144999.000000
+IPD = 0
+IQD = 0
+IPF = 1000
+IQF = 1000
+PAGEND ACQGEO
+PAGBEGIN OBJET
+PEX = 0.010000
+PEY = 0.010000
+PEZ = 0.010000
+X1 = -0.500000
+Y1 = -0.500000
+Z1 = -0.500000
+NX = 101
+NY = 101
+NZ = 101
+PAGEND OBJET
diff --git a/zUtil_ART/spr_write.m b/zUtil_ART/spr_write.m
new file mode 100755
index 0000000000000000000000000000000000000000..8daee36c32e5c74a12759cfdc4b20d449010e3c7
--- /dev/null
+++ b/zUtil_ART/spr_write.m
@@ -0,0 +1,19 @@
+function stat=write_spr(name,dims,dim1,dim2,type)
+% helper function only - should not be called directly
+fid=fopen(name,'w');
+if fid
+  stat=1;
+else
+  stat=0;
+  disp('error opening file');
+  return; 
+end   
+fprintf(fid,'%d\n',dims);
+fprintf(fid,'%d\n',dim1);
+fprintf(fid,'0\n1\n');
+fprintf(fid,'%d\n',dim2);
+fprintf(fid,'0\n1\n');
+fprintf(fid,'%d\n',type);
+fprintf(fid,'0\n1\n');
+
+fclose(fid);
diff --git a/zUtil_ART/testobject.m b/zUtil_ART/testobject.m
new file mode 100755
index 0000000000000000000000000000000000000000..43c6812f9dd73bbf1039974115a052f451ee5d4c
--- /dev/null
+++ b/zUtil_ART/testobject.m
@@ -0,0 +1,15 @@
+gv=zeros(parameters.acq.bb(3),parameters.acq.bb(3),parameters.acq.bb(4));
+
+
+
+tmp=zeros(parameters.acq.bb(3),parameters.acq.bb(3));
+tmp(249,106)=1;
+%tmp(151,151)=1;
+
+for i=310:390
+  if mod(i,3)==0
+	tmp=bwmorph(tmp,'dilate');
+  end
+  gv(:,:,i)=tmp;
+end  
+	
diff --git a/zUtil_DB/LICENSE.txt b/zUtil_DB/LICENSE.txt
new file mode 100755
index 0000000000000000000000000000000000000000..3912109b5cd65a68039d473c11c9f7ac2303e06d
--- /dev/null
+++ b/zUtil_DB/LICENSE.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/zUtil_DB/compile_mym.m b/zUtil_DB/compile_mym.m
new file mode 100755
index 0000000000000000000000000000000000000000..ac08e887ed9589f242824f5bc080a7384e04e182
--- /dev/null
+++ b/zUtil_DB/compile_mym.m
@@ -0,0 +1,25 @@
+if 1
+  disp('First compile - coral')
+  mex -I/data/id19/graintracking/code/include -I/data/id19/graintracking/code/mysql/include ...
+    -L/data/id19/graintracking/code/lib  ...
+    -lmysqlclient -lz ...
+    /data/id19/graintracking/matlab/zUtil_DB/mym.cpp
+else
+  disp('First compile - esrflinux')
+  mex -I/data/id19/graintracking/code/include -I/data/id19/graintracking/code/mysql/include ...
+    -L/data/id19/graintracking/code/lib64  ...
+    -lmysqlclient -lz ...
+    /data/id19/graintracking/matlab/zUtil_DB/mym.cpp
+end
+try
+  disp('Then check it runs')
+  mym
+  disp('Then try a connection')
+
+  mym('open','mysql','gtadmin','gtadmin')
+  disp('Seemed to work')
+catch
+  lasterr
+  disp('Did not work - probably the library problem')
+  !ldd mym.mexa64 |grep mysql
+end
diff --git a/zUtil_DB/dbInsert.m b/zUtil_DB/dbInsert.m
new file mode 100755
index 0000000000000000000000000000000000000000..01491ec73dc1f7de0396633b55565702f4ca59b6
--- /dev/null
+++ b/zUtil_DB/dbInsert.m
@@ -0,0 +1,20 @@
+ function cmd=dbInsert(table,varargin)
+ % modified 10/12/2007 to use mantissa/exponent (%g) for double precision
+ % modified 13/12/2007 to use mantissa/exponent (%0.20g) for double precision /Peter/
+
+ beginning=sprintf('insert into %s (',table);
+ middle1=[];
+ for n=1:2:nargin-1
+   middle1=[middle1 sprintf('%s,',varargin{n})];
+ end
+ middle1=[middle1(1:end-1) ') values ('];
+ middle2=[];
+
+ for n=2:2:nargin-1
+   middle2=[middle2 sprintf('"%0.20g",',varargin{n})];
+ end
+ 
+ middle2(end)=')';
+ 
+ cmd=[beginning middle1 middle2];
+
diff --git a/zUtil_DB/dbInsertMultiple.m b/zUtil_DB/dbInsertMultiple.m
new file mode 100755
index 0000000000000000000000000000000000000000..28ed4026714722ec5f200acdec9c912cda3b9e47
--- /dev/null
+++ b/zUtil_DB/dbInsertMultiple.m
@@ -0,0 +1,103 @@
+function dbInsertMultiple(table,varargin)
+% NOW DOES THE INSERTION AS WELL
+% to insert many rows at once do:
+% dbInsertMultiple(...
+%  tablename,'colA',[valA1 valA2 valA3],'colB',[valB1 valB2 valB3])
+
+% modified 10/12/2007 to use mantissa/exponent (%g) for double precision
+% modified 13/12/2007 to use mantissa/exponent (%0.20g) for double
+%   precision /Peter/
+
+
+numitems=length(varargin{2});
+
+% do a maximum of 500 rows at a time
+maxitems=500;
+
+for itemndx=1:maxitems:numitems
+  for q=1:2:nargin-1
+    first=itemndx;
+    if (first+maxitems>numitems)
+      last=numitems;
+    else
+      last=first+maxitems-1;
+    end
+    current_varargin{q}=varargin{q};
+    current_varargin{q+1}=varargin{q+1}(first:last);
+  end
+
+  beginning=sprintf('insert into %s (',table);
+  middle1=[];
+  for n=1:2:nargin-1
+    middle1=[middle1 sprintf('%s,',current_varargin{n})];
+  end
+  middle1=[middle1(1:end-1) ') values '];
+  middle2=[];
+
+  % error check that all arguments have same length
+  firsttime=true;
+  for n=2:2:length(current_varargin)
+    if firsttime
+      l=length(current_varargin{n});
+      firsttime=false;
+    else
+      if length(current_varargin{n})~=l
+        error('All columns need same number of items')
+      end
+    end
+  end
+
+  % preallocate blank string
+
+  middle3=repmat(' ',1,((7*n+4)*l)-1);
+
+  if 1
+    ndx=1;
+    q=length(current_varargin{2});
+    for m=1:q
+      middle3(ndx)='(';
+      ndx=ndx+1;
+      for n=2:2:length(current_varargin)
+        tmp=sprintf('%0.20g,',current_varargin{n}(m));
+        lentmp=length(tmp);
+        middle3(ndx:ndx+lentmp-1)=tmp;
+        ndx=ndx+lentmp;
+      end
+      middle3(ndx-1:ndx)='),';
+      ndx=ndx+1;
+
+    end
+%    middle3(end)=[];
+% ak 13/12/2007
+% if data are not doubles, then the preallocated string is too long!
+% Instead, delete everything after the last (unnececssary) comma:
+dum=find(middle3==',', 1, 'last');
+middle3(dum:end)=[];
+
+    cmd=[beginning middle1 middle3];
+  else
+    q=length(current_varargin{2});
+    for m=1:q
+      middle2 = [middle2 '('];
+      for n=2:2:length(current_varargin)
+        middle2=[middle2 sprintf('%0.20g,',current_varargin{n}(m))];
+      end
+      middle2=[middle2(1:end-1) '),'];
+    end
+
+    middle2=[middle2(1:end-1)];
+
+    cmd=[beginning middle1 middle2];
+  end
+
+  if (length(current_varargin)==2)
+    if (maxitems==q)
+      cmd=cmd(1:end-2);
+    else
+      cmd=cmd(1:end-1);
+    end
+  end
+%  fprintf('%d: %s\n',itemndx);
+  mym(cmd)
+
+end
diff --git a/zUtil_DB/dbUpdate.m b/zUtil_DB/dbUpdate.m
new file mode 100755
index 0000000000000000000000000000000000000000..f510048f9b2fdbe2b727c7642c11a18846ac60cc
--- /dev/null
+++ b/zUtil_DB/dbUpdate.m
@@ -0,0 +1,11 @@
+ function cmd=dbUpdate(table,whereparam,wherevalue,varargin)
+ 
+ beginning=sprintf('update %s set ',table);
+ middle=[];
+ for n=1:2:nargin-3
+   middle=[middle sprintf('%s="%f",',varargin{n},varargin{n+1})];
+ end
+ middle(end)=[' ']; % suppress last comma
+ ending=sprintf('where %s="%f"',whereparam,wherevalue);
+ cmd=[beginning middle ending];
+
diff --git a/zUtil_DB/flex_charter.m b/zUtil_DB/flex_charter.m
new file mode 100755
index 0000000000000000000000000000000000000000..d311314822ac87afd5d51ea13ddc812e09db21d9
--- /dev/null
+++ b/zUtil_DB/flex_charter.m
@@ -0,0 +1,190 @@
+if isempty(import)
+  javaaddpath(which('jdom.jar'))
+
+
+  import org.jdom.*
+  import org.jdom.input.*
+  import org.jdom.output.*
+  import java.lang.*
+  import java.io.File.*
+end
+
+
+% create data
+mym('open','mysql','gtadmin','gtadmin');
+mym('use graintracking');
+
+
+products=mym('select distinct product from matlab');
+
+for q=1:length(products)
+  fprintf('Graphing %s\n',products{q});
+
+  doc=Document;
+  chart=Element('chart');
+  doc.setRootElement(chart);
+
+
+  axis_category=Element('axis_category');
+  axis_category.setAttribute('size','12');
+  axis_category.setAttribute('orientation','diagonal_down');
+%  axis_category.setAttribute('skip','120');% num2str(skipval));
+
+  axis_ticks=Element('axis_ticks');
+  axis_ticks.setAttribute('value_ticks','false');
+  axis_ticks.setAttribute('category_ticks','false');
+
+
+  chart_border=Element('chart_border');
+  chart_data=Element('chart_data');
+
+  timestamp=mym(sprintf('select distinct timestamp from matlab where product="%s" order by timestamp',products{q}));
+  times=1:length(timestamp);
+%  skipval=floor((length(times)/10)-1);
+  [used,total]=mym(sprintf('select used,total from matlab where product="%s"',products{q}));
+
+  axis_value=Element('axis_value');
+  axis_value.setAttribute('min','0');
+  axis_value.setAttribute('max',num2str(total(1)));
+
+  values=used';
+  %values=used(1:10:end)';
+
+  row=Element('row');
+  row.addContent(Element('null'));
+  for n=1:size(values,2)
+   
+    dnum=datenum(timestamp{n},'yyyy-mm-dd HH:MM:SS');
+    [y,m,d,h,mi,s]=datevec(dnum);    
+    if mi==0 && (mod(h,3)==0)
+      tmp=Element('string');
+      tmp.setText(datestr(dnum,'HH:MM (dd mmm)'));
+      %      datestr(dnum,'HH:MM')
+      row.addContent(tmp);
+
+    elseif n==size(values,2)
+      tmp=Element('string');
+      tmp.setText(datestr(dnum,'HH:MM'));
+      row.addContent(tmp);
+    else
+      tmp=Element('string');
+      tmp.setText('');
+      row.addContent(tmp);
+    end
+
+  end
+  chart_data.addContent(row);
+
+  row=Element('row');
+  tmp=Element('string');
+  tmp.setText(products{q});
+  row.addContent(tmp);
+  for m=1:size(values,2)
+    tmp=Element('number');
+    tmp.setText(num2str(values(m)));
+    row.addContent(tmp);
+  end
+  chart_data.addContent(row);
+
+
+
+  chart_grid_h=Element('chart_grid_h');
+  chart_grid_v=Element('chart_grid_v');
+  chart_pref=Element('chart_pref');
+  chart_pref.setAttribute('point_shape','none');
+  chart_rect=Element('chart_rect');
+  chart_rect.setAttribute('x','80');
+  chart_rect.setAttribute('y','55');
+  chart_rect.setAttribute('width','650');
+  chart_rect.setAttribute('height','360');
+
+  
+  
+  chart_type=Element('chart_type');
+  tmp=Element('string');
+  tmp.setText('line');
+  chart_type.addContent(tmp);
+
+  chart_value=Element('chart_value');
+  chart_value.setAttribute('position','cursor');
+
+  chart_transition=Element('chart_transition');
+%  chart_transition.setAttribute('type','drop');
+%  chart_transition.setAttribute('delay','1');
+%  chart_transition.setAttribute('duration','3');
+%  chart_transition.setAttribute('order','series');
+  draw=Element('draw');
+
+  text=Element('text');
+  text.setAttribute('color','ffffff');
+  text.setAttribute('alpha','20');
+  text.setAttribute('rotation','0');
+  text.setAttribute('bold','true');
+  text.setAttribute('x','80');
+  text.setAttribute('y','375');
+  text.setAttribute('height','60');
+  text.setAttribute('h_align','left');
+  text.setAttribute('v_align','bottom');
+  if length(products{q})>10
+  text.setAttribute('size','50');
+  else
+  text.setAttribute('size','80');
+  end
+  text.setText(sprintf('%s',products{q}));
+
+  draw.addContent(text);
+
+  %  image=Element('image');
+  %  image.setAttribute('url','charts.swf?library_path=charts_library&xml_source=temp2.xml');
+  %  draw.addContent(image);
+
+
+  legend_label=Element('legend_label');
+  legend_label.setAttribute('alpha','0');
+  legend_label.setAttribute('layout','vertical');
+
+  legend_rect=Element('legend_rect');
+  legend_rect.setAttribute('x','5000');
+  legend_rect.setAttribute('y','5000');
+  
+  legend_rect.setAttribute('width','0');
+  legend_rect.setAttribute('height','0');
+  legend_rect.setAttribute('fillalpha','0');
+  legend_rect.setAttribute('linealpha','0');
+  
+  
+
+  series_color=Element('series_color');
+
+  chart.addContent(axis_category);
+  chart.addContent(axis_ticks);
+  chart.addContent(axis_value);
+  chart.addContent(chart_border);
+  chart.addContent(chart_data);
+  chart.addContent(chart_grid_h);
+  chart.addContent(chart_grid_v);
+  chart.addContent(chart_pref);
+  chart.addContent(chart_rect);
+  chart.addContent(chart_type);
+  chart.addContent(chart_value);
+  chart.addContent(draw);
+  chart.addContent(legend_label);
+  chart.addContent(legend_rect);
+  chart.addContent(series_color);
+  chart.addContent(chart_transition);
+
+
+
+
+  stream=java.io.FileOutputStream(sprintf('/data/id19/graintracking/www/matlablicense/flex_%02d.xml',q));
+
+  outputter = XMLOutputter(Format.getPrettyFormat);
+
+  outputter.output(doc,stream)
+
+end
+
+mym('close')
+
+
+
diff --git a/zUtil_DB/flex_watcher.m b/zUtil_DB/flex_watcher.m
new file mode 100755
index 0000000000000000000000000000000000000000..a2110cb6ea66bad6d24756591f30a4eb2c10ac4b
--- /dev/null
+++ b/zUtil_DB/flex_watcher.m
@@ -0,0 +1,36 @@
+function flex_watcher
+% adds entrys to the database with matlab flex license vales
+
+% mym('create table matlab (timestamp datetime,product char(40), total
+% int,used int)')
+if 1
+if mym('status')
+mym('open','mysql.esrf.fr','gtadmin','gtadmin');
+mym('use graintracking')
+end
+timestamp=datestr(now,31);
+
+fname=tempname;
+[tmp,msg]=system(['/sware/com/matlab_2006b/etc/lmstat -a > ' fname]);
+%[tmp,msg]=system(['/sware/com/matlab_2006b/etc/lmstat -a']);
+
+pattern='Users\s+of\s+(?<product>\S+):.*\(Total\s+of\s+(?<total>\d+).*Total of (?<used>\d+).*$';
+results=[];
+fid=fopen(fname,'rt');
+while ~feof(fid)
+  l=fgetl(fid);
+  tmp=regexp(l,pattern,'names');
+  if ~isempty(tmp)
+    mysqlcmd=sprintf('insert into matlab (timestamp,product,total,used) values ("%s","%s",%d,%d)',timestamp,tmp.product,str2num(tmp.total),str2num(tmp.used));
+    mym(mysqlcmd);
+    
+  end
+end
+
+fclose(fid);
+mym('close')
+flex_charter
+end
+
+
+end
diff --git a/zUtil_DB/gtDBConnect.m b/zUtil_DB/gtDBConnect.m
new file mode 100755
index 0000000000000000000000000000000000000000..047ac27542562edd924fccd7b222e915094fb795
--- /dev/null
+++ b/zUtil_DB/gtDBConnect.m
@@ -0,0 +1,30 @@
+%function gtDBConnect(host,username,password,database)
+function gtDBConnect(varargin)
+  % modified 30/11/2007 GJ
+  % no longer accepts gtadmin as a user - gtuser has all rights.
+
+
+  if nargin==4
+    host=varargin{1};
+    username=varargin{2};
+    password=varargin{3};
+    database=varargin{4};
+    mym('close'); % will fail without a problem if no connection exists.
+    mym('open',host,username,password)
+    mym(sprintf('use %s',database))
+  elseif nargin==0
+    if mym('status') % connection is already open
+      fprintf('Connecting\n')
+      mym('open', 'graindb.esrf.fr', 'gtadmin', 'gtadmin')
+      mym('use graintracking')
+    else
+      disp('Using previous connection')
+    end
+  elseif strcmp(varargin{1},'admin')
+    fprintf('PLEASE CORRECT YOUR CODE - JUST CALL gtDBConnect\n\n')
+    gtDBConnect;
+  else
+    disp('Sorry - not understood')
+  end
+
+
diff --git a/zUtil_DB/gtDBCreateCalibrationTable_v3.m b/zUtil_DB/gtDBCreateCalibrationTable_v3.m
new file mode 100755
index 0000000000000000000000000000000000000000..a60914fe995ca063c7b3d0cb35a476197b5febdc
--- /dev/null
+++ b/zUtil_DB/gtDBCreateCalibrationTable_v3.m
@@ -0,0 +1,24 @@
+% CalibrationTable is used for geometry correction (rotation axis to detector distance,
+% detector tilts), contains pairs of perfectly matching diffraction spots.
+% Should have exactly the same structure as SpotPairTable-s.
+%
+% 
+% Used by:  gtMatchDifspotsForCalibration.m  - loads data
+%           gtCorrectGeo.m  - reading data
+%
+
+function gtDBCreateCalibrationTable_v3(name)
+
+fprintf('Working on %s\n',name);
+
+mym('close')
+mym('open','mysql.esrf.fr','gtadmin','gtadmin')
+mym('use graintracking')
+
+tablename_calibration=sprintf('%scalibration',name);
+
+mym(sprintf('drop table if exists %s',tablename_calibration));
+mysqlcmd=sprintf('create table %s (pairID int not null auto_increment, difAID int, difBID int, theta double, eta double, omega double, avintint double, avbbXsize double, avbbYsize double, samcentXA double, samcentYA double, samcentZA double, samcentXB double, samcentYB double, samcentZB double, ldirX double, ldirY double, ldirZ double, plX double, plY double, plZ double, thetatype int, grainID int, primary key (pairID))',tablename_calibration);
+mym(mysqlcmd)
+
+end
diff --git a/zUtil_DB/gtDBCreateDifblobTable.m b/zUtil_DB/gtDBCreateDifblobTable.m
new file mode 100755
index 0000000000000000000000000000000000000000..61c09c73cf556a16bbd3a605d572de378395e333
--- /dev/null
+++ b/zUtil_DB/gtDBCreateDifblobTable.m
@@ -0,0 +1,79 @@
+function gtDBCreateDifblobTable(expname,overwriteflag)
+
+fprintf('Working on %s\n',expname);
+
+gtDBConnect
+
+tablename_difblob=sprintf('%sdifblob',expname);
+tablename_difblobinfo = sprintf('%sdifblobinfo',expname);
+tablename_difblobdetails=sprintf('%sdifblobdetails',expname);
+
+tablename_cracked_difblob=sprintf('%scracked_difblob',expname);
+tablename_cracked_difblobinfo = sprintf('%scracked_difblobinfo',expname);
+tablename_cracked_difblobdetails=sprintf('%scracked_difblobdetails',expname);
+
+
+
+
+if ~exist('overwriteflag','var') | ~overwriteflag
+  check1=mym(sprintf('show tables like "%s"',tablename_difblob));
+  check2=mym(sprintf('show tables like "%s"',tablename_difblobinfo));
+  check3=mym(sprintf('show tables like "%s"',tablename_difblobdetails));
+
+  check4=mym(sprintf('show tables like "%s"',tablename_cracked_difblob));
+  check5=mym(sprintf('show tables like "%s"',tablename_cracked_difblobinfo));
+  check6=mym(sprintf('show tables like "%s"',tablename_cracked_difblobdetails));
+
+
+  if (~isempty(check1) | ~isempty(check2) | ~isempty(check3) | ~isempty(check4) | ~isempty(check5) | ~isempty(check6))
+    error(sprintf('At least one of the tables exists already!\nRun again using the overwriteflag=true\n'));
+    return
+  end
+end
+mym(sprintf('drop table if exists %s',tablename_difblob));
+mym(sprintf('drop table if exists %s',tablename_difblobinfo));
+mym(sprintf('drop table if exists %s',tablename_difblobdetails));
+
+mym(sprintf('drop table if exists %s',tablename_cracked_difblob));
+mym(sprintf('drop table if exists %s',tablename_cracked_difblobinfo));
+mym(sprintf('drop table if exists %s',tablename_cracked_difblobdetails));
+
+mysqlcmd=sprintf(...
+  'create table %s (difblobID int unsigned not null auto_increment, primary key (difblobID)) ENGINE=MyISAM',...
+  tablename_difblob);
+mym(mysqlcmd)
+
+mysqlcmd=sprintf(...
+  'create table %s (difblobID int unsigned not null, xIndex smallint unsigned not null, yIndex smallint unsigned not null, zIndex smallint unsigned not null, graylevel double, index (difblobID),index (zIndex)) ENGINE=MyISAM',...
+  tablename_difblobdetails);
+%mysqlcmd=sprintf(...
+%  'create table %s (difblobID int unsigned not null, xIndex smallint unsigned not null, yIndex smallint unsigned not null, zIndex smallint unsigned not null, graylevel double) ENGINE=MyISAM',...
+%  tablename_difblobdetails);
+mym(mysqlcmd)
+
+
+mysqlcmd = sprintf(...
+  'create table %s (chunkID int not null auto_increment, startIndex smallint unsigned not null, endIndex smallint unsigned not null, primary key (chunkID)) ENGINE=MyISAM',...
+  tablename_difblobinfo);
+mym(mysqlcmd);
+
+
+
+mysqlcmd=sprintf(...
+  'create table %s (difblobID int unsigned not null auto_increment, primary key (difblobID)) ENGINE=MyISAM',...
+  tablename_cracked_difblob);
+mym(mysqlcmd)
+
+mysqlcmd=sprintf(...
+  'create table %s (difblobID int unsigned not null, xIndex smallint unsigned not null, yIndex smallint unsigned not null, zIndex smallint unsigned not null, graylevel double, index (difblobID),index (zIndex)) ENGINE=MyISAM',...
+  tablename_cracked_difblobdetails);
+mym(mysqlcmd)
+
+mysqlcmd = sprintf(...
+  'create table %s (chunkID int not null auto_increment, startIndex smallint unsigned not null, endIndex smallint unsigned not null, primary key (chunkID)) ENGINE=MyISAM',...
+  tablename_cracked_difblobinfo);
+mym(mysqlcmd);
+
+fprintf('\nMade tables: %s, %s, %s and %s, %s, %s\n',tablename_difblob,tablename_difblobdetails,tablename_difblobinfo,...
+  tablename_cracked_difblob,tablename_cracked_difblobdetails,tablename_cracked_difblobinfo);
+end
diff --git a/zUtil_DB/gtDBCreateDifspotTable.m b/zUtil_DB/gtDBCreateDifspotTable.m
new file mode 100755
index 0000000000000000000000000000000000000000..4fbb8afe2275811bf21633eea909b50233b2714e
--- /dev/null
+++ b/zUtil_DB/gtDBCreateDifspotTable.m
@@ -0,0 +1,70 @@
+function gtDBCreateDifspotTable(expname, overwriteflag)
+
+fprintf('Working on %s\n',expname);
+
+gtDBConnect
+
+tablename_difspot=sprintf('%sdifspot',expname);
+
+
+
+
+
+if ~exist('overwriteflag','var') | ~overwriteflag
+  check1=mym(sprintf('show tables like "%s"',tablename_difspot));
+  if ~isempty(check1) 
+    error(sprintf('At least one of the tables exists already!\nRun again using the overwriteflag=true\n'));
+    return
+  end
+end
+
+
+
+% difspot
+mym(sprintf('drop table if exists %s',tablename_difspot));
+mysqlcmd=sprintf('create table %s (difspotID int not null auto_increment, StartImage int, EndImage int, MaxImage int, ExtStartImage int, ExtEndImage int, Area double, CentroidX double, CentroidY double, CentroidImage double, BoundingBoxXorigin int, BoundingBoxYorigin int, BoundingBoxXsize int, BoundingBoxYsize int, Integral double, primary key (difspotID))',tablename_difspot);
+mym(mysqlcmd)
+
+end
+
+
+
+
+
+%
+% if 0  % PROBABLY NEVER NEEDED ANYMORE!
+%   % Import existing difspot data
+%   disp('Importing data into difspot table')
+%   if ~exist('difspot','var')
+%     disp('Loading difspot')
+%     load 2_difspot/difspot.mat
+%   end
+%
+%   for n=1:length(difspot)
+%     if mod(n,2000)==0
+%       fprintf('%3d%% complete\r',round(100*n/length(difspot)))
+%     end
+%     cmd=sprintf('INSERT INTO %s ( StartImage, EndImage, MaxImage, ExtStartImage, ',tablename_difspot);
+%     cmd=[cmd 'ExtEndImage, Area, CentroidX, CentroidY, '];
+%     cmd=[cmd 'BoundingBoxXorigin, BoundingBoxYorigin, BoundingBoxXsize, BoundingBoxYsize, Integral ) VALUES '];
+%     cmd=[cmd sprintf('("%d", "%d", "%d", "%d", "%d", "%d", "%f", "%f", "%d", "%d", "%d", "%d","%d")',...
+%       difspot(n).StartImage,...
+%       difspot(n).EndImage,...
+%       difspot(n).MaxImage(1),...
+%       difspot(n).ExtStartImage,...
+%       difspot(n).ExtEndImage,...
+%       difspot(n).Area,...
+%       difspot(n).Centroid(1),...
+%       difspot(n).Centroid(2),...
+%       difspot(n).BoundingBox(1),...
+%       difspot(n).BoundingBox(2),...
+%       difspot(n).BoundingBox(3),...
+%       difspot(n).BoundingBox(4),...
+%       difspot(n).Integral...
+%       )];
+%     mym(cmd)
+%
+%   end
+%
+%   fprintf('\n');
+% end
diff --git a/zUtil_DB/gtDBCreateExtspotTable.m b/zUtil_DB/gtDBCreateExtspotTable.m
new file mode 100755
index 0000000000000000000000000000000000000000..b58f801dc2dedf44fb03f213eece83ed277c3225
--- /dev/null
+++ b/zUtil_DB/gtDBCreateExtspotTable.m
@@ -0,0 +1,41 @@
+function gtDBCreateExtspotTable(expname)
+
+fprintf('Working on %s\n',expname);
+
+gtDBConnect
+
+tablename_extspot=sprintf('%sextspot',expname);
+tablename_snakes=sprintf('%ssnakes',expname);
+tablename_bboxes=sprintf('%sbboxes',expname);
+tablename_grainid=sprintf('%sgrainid',expname);
+viewname_bb=sprintf('%sbb',expname);
+%tablename_centroids=sprintf('%scentroids',expname);
+
+% create all tables necessary
+
+% extspot
+mym(sprintf('drop table if exists %s',tablename_extspot));
+mysqlcmd=sprintf('create table %s (extspotID int not null,bbID int, searchbbID int, Area int, SnakeID int, GrainID int, primary key (extspotID))',tablename_extspot);
+mym(mysqlcmd)
+
+% snakes
+mym(sprintf('drop table if exists %s',tablename_snakes));
+mysqlcmd=sprintf('create table %s (snakeID int, x double, y double)',tablename_snakes);
+mym(mysqlcmd);
+
+%% centroids
+%mym(sprintf('drop table if exists %s',tablename_centroids));
+%mysqlcmd=sprintf('create table %s (centroidID int not null auto_increment, x double, y double, primary key (centroidID))',tablename_centroids);
+%mym(mysqlcmd);
+
+% boundingboxes
+mym(sprintf('drop table if exists %s',tablename_bboxes));
+mysqlcmd=sprintf('create table %s (bboxID int not null auto_increment, extspotID int,Xorigin int, Yorigin int, Xsize int, Ysize int, Xcentroid double, Ycentroid double,primary key (bboxID))',tablename_bboxes);
+mym(mysqlcmd);
+
+mym(sprintf('drop view if exists %s',viewname_bb));
+mym(sprintf('create view %sbb as select extspotID,grainID,ifnull(bbID,searchbbID) as bbID from %sextspot',expname,expname));
+
+
+
+
diff --git a/zUtil_DB/gtDBCreateSpotPairTable.m b/zUtil_DB/gtDBCreateSpotPairTable.m
new file mode 100755
index 0000000000000000000000000000000000000000..c2e86d2ca25e9bd5296f2cd81ab28a6178b0a3a8
--- /dev/null
+++ b/zUtil_DB/gtDBCreateSpotPairTable.m
@@ -0,0 +1,35 @@
+function gtDBCreateSpotPairTable(fullname,overwriteflag)
+
+if ~exist('fullname','var')
+  fullname=[];
+end
+
+if ~exist('overwriteflag','var')
+  overwriteflag=false;
+end
+
+
+if isempty(fullname)
+  load parameters
+  tablename_spotpairs=parameters.acq.pair_tablename;
+else
+  tablename_spotpairs=fullname;
+end
+
+fprintf('Working on %s\n',tablename_spotpairs);
+
+gtDBConnect
+
+if ~overwriteflag
+  check=mym(sprintf('show tables like "%s"',tablename_spotpairs));
+  if ~isempty(check) 
+    error(sprintf('Table exists already!\nRun again using the overwriteflag=true\n'));
+    return
+  end
+end
+
+mym(sprintf('drop table if exists %s',tablename_spotpairs));
+mysqlcmd=sprintf('create table %s (pairID int not null auto_increment, difAID int, difBID int, theta double, eta double, omega double, avintint double, avbbXsize double, avbbYsize double, samcentXA double, samcentYA double, samcentZA double, samcentXB double, samcentYB double, samcentZB double, ldirX double, ldirY double, ldirZ double, plX double, plY double, plZ double, thetatype int, grainID int, primary key (pairID))',tablename_spotpairs);
+mym(mysqlcmd)
+
+end
diff --git a/zUtil_DB/gtDBGetBigBlobs.m b/zUtil_DB/gtDBGetBigBlobs.m
new file mode 100755
index 0000000000000000000000000000000000000000..e7b7ad491cba6f8a1b66766068498ce00777275d
--- /dev/null
+++ b/zUtil_DB/gtDBGetBigBlobs.m
@@ -0,0 +1,36 @@
+clear all
+close all
+gtDBConnect
+table='strain_june_6N_difblobdetails';
+mysqlcmd=sprintf('select difblobID,count(difblobID) as c1 from %s group by difblobID order by c1 desc limit 30',table);
+
+[id,count]=mym(mysqlcmd)
+return
+%id=[2550 3113 55 2212 1074 303 30 3362 1688];
+% wide
+%id = [2550 3113 2212 1074];
+% narrow
+%id = [303 3362];
+% interesting
+id =  1688;
+
+for n=1:length(id)
+  close all
+  t=gtPlasticViewer(id(n),3);
+  for q=1:4
+  fwhm{n}(q)=t(q).fwhm;
+  end
+  
+%pause(5)
+end
+%%
+return
+p1=[];p2=[];p3=[];p4=[];
+for n=1:length(fwhm)
+  a=fwhm{n};
+  p1=[p1 a(1)];  
+  p2=[p2 a(2)];  
+  p3=[p3 a(3)];  
+  p4=[p4 a(4)];
+  
+end
diff --git a/zUtil_DB/gtDBProgressMonitor.m b/zUtil_DB/gtDBProgressMonitor.m
new file mode 100755
index 0000000000000000000000000000000000000000..4b1e9467e3b2ea59b155ca4e49b61b801d20eca6
--- /dev/null
+++ b/zUtil_DB/gtDBProgressMonitor.m
@@ -0,0 +1,21 @@
+function [first,last,current,ts]=gtDBProgressMonitor(varargin)
+
+param.function='';
+param.scanname='';
+param.first=1;
+param=parse_pv_pairs(param,varargin);
+
+
+gtDBConnect;
+mysqlcmd=sprintf('select first,last,current,ts from condorprogress where function="%s" and scanname="%s"',param.function,param.scanname);
+%
+[first,last,current,ts]=mym(mysqlcmd);
+
+hold off
+plot(datenum(ts,'yyyy-mm-dd HH:MM:SS'),[current first last])
+title(sprintf('Last point: %d @ %s',current(end),char(ts(end))))
+datetick
+shg
+
+end
+
diff --git a/zUtil_DB/gtDBProgressUpdate.m b/zUtil_DB/gtDBProgressUpdate.m
new file mode 100755
index 0000000000000000000000000000000000000000..dc6b86a31b90d7d8d86ad912a6869d2a5bae4a9d
--- /dev/null
+++ b/zUtil_DB/gtDBProgressUpdate.m
@@ -0,0 +1,40 @@
+function gtDBProgressUpdate(funcname,scanname,first,last,current)
+% makes a mark in the condorprogress table so you can track your condor
+% jobs...
+% Usage:
+% Open the database BEFORE the main loop, and call gtDBProgressUpdate
+% inside the loop.  The parameters to gtDBProgressUpdate are:
+%  mfilename - use this always
+%  acq.name  - or some string to identify the dataset
+%  first, last - two integers indicating beginning and end of the
+%  processing loop
+%  i - the index of the current position
+%
+% Example:
+%  gtDBConnect
+%  for i=first:last
+%    gtDBProgressUpdate(mfilename,acq.name,first,last,i);
+%    do_some_work
+%  end
+%
+% Monitoring progress
+%   See gtDBProgressMonitor
+  
+  
+  
+if false
+  % change this to true to create the table for the first time
+  gtDBConnect('admin')
+  mym('create table condorprogress (function varchar(60),scanname varchar(30),first int,last int, current int, ts timestamp default now())');
+end
+
+mysqlcmd=sprintf(...
+  'insert into condorprogress (function,scanname,first,last,current) values ("%s","%s",%d,%d,%d)',...
+  funcname,scanname,first,last,current);
+
+mym(mysqlcmd)
+
+
+
+
+end
diff --git a/zUtil_DB/mym.cpp b/zUtil_DB/mym.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..24c0ea66e0326120286a297ad8d8fb9936a675f5
--- /dev/null
+++ b/zUtil_DB/mym.cpp
@@ -0,0 +1,1183 @@
+/*  mYm is a Matlab interface to MySQL server that support BLOB object
+*   Copyright (C) 2005 Swiss Federal Institute of technology (EPFL), Lausanne, CH
+*
+*   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
+*
+*   Author:                     Yannick Maret
+*   e-mail:                     yannick.maret@a3.epfl.ch
+*   old fashioned paper mail:   EPFL-STI-ITS-LTS1
+*                               Yannick MARET
+*                               ELD241
+*                               Station 11
+*                               CH-1015 Lausanne
+*
+*   Notice: some parts of this code (server connection, fancy print) is based  
+*   on an original code by Robert Almgren (http://www.mmf.utoronto.ca/resrchres/mysql/).
+*   The present code is under GPL license with the express agreement of Mr. Almgren.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <algorithm> // for max
+#include "mym.h"
+#define CLIENT_MULTI_STATEMENTS 65536
+/**********************************************************************
+*typestr(s):  Readable translation of MySQL field type specifier
+*       as listed in   mysql_com.h
+**********************************************************************/
+static const char*typestr(enum_field_types t) {
+	switch(t) {
+		//  These are considered numeric by IS_NUM() macro
+		case FIELD_TYPE_DECIMAL:    
+      return "decimal";
+		case FIELD_TYPE_TINY:     
+      return "tiny";
+		case FIELD_TYPE_SHORT:    
+      return "short";
+		case FIELD_TYPE_LONG:     
+      return "long";
+		case FIELD_TYPE_FLOAT:    
+      return "float";
+		case FIELD_TYPE_DOUBLE:    
+      return "double";
+		case FIELD_TYPE_NULL:     
+      return "null";
+		case FIELD_TYPE_LONGLONG:   
+      return "longlong";
+		case FIELD_TYPE_INT24:    
+      return "int24";
+		case FIELD_TYPE_YEAR:     
+      return "year";
+		case FIELD_TYPE_TIMESTAMP:  
+      return "timestamp";
+		//  These are not considered numeric by IS_NUM()
+		case FIELD_TYPE_DATE:     
+      return "date";
+		case FIELD_TYPE_TIME:     
+      return "time";
+		case FIELD_TYPE_DATETIME:   
+      return "datetime";
+		case FIELD_TYPE_NEWDATE:    
+      return "newdate";   // not in manual
+		case FIELD_TYPE_ENUM:     
+      return "enum";
+		case FIELD_TYPE_SET:      
+      return "set";
+		case FIELD_TYPE_TINY_BLOB:  
+      return "tiny_blob";
+		case FIELD_TYPE_MEDIUM_BLOB:  
+      return "medium_blob";
+		case FIELD_TYPE_LONG_BLOB:  
+      return "long_blob";
+		case FIELD_TYPE_BLOB:     
+      return "blob";
+		case FIELD_TYPE_VAR_STRING:   
+      return "var_string";
+		case FIELD_TYPE_STRING:     
+      return "string";
+//		case FIELD_TYPE_GEOMETRY:   
+//      return "geometry";   // not in manual 4.0
+		default:            
+      return "unknown";
+	}
+}
+/**********************************************************************
+*fancyprint():  Print a nice display of a query result
+*  We assume the whole output set is already stored in memory, 
+*  as from mysql_store_result(), just so that we can get the
+*  number of rows in case we need to clip the printing.
+*   In any case, we make only one pass through the data.
+*  If the number of rows in the result is greater than NROWMAX, 
+*  then we print only the first NHEAD and the last NTAIL.
+*  NROWMAX must be greater than NHEAD+NTAIL, normally at least
+*  2 greater to allow the the extra information
+*  lines printed when we clip (ellipses and total lines).
+*   Display null elements as empty
+**********************************************************************/
+const char*contstr = "...";   //  representation of missing rows
+const int contstrlen = 3;     //  length of above string
+const int NROWMAX = 50;       //  max number of rows to print w/o clipping
+const int NHEAD = 10;         //  number of rows to print at top if we clip
+const int NTAIL = 10;         //  number of rows to print at end if we clip
+static void fancyprint(MYSQL_RES*res) {
+	const ulong nrow = (ulong)mysql_num_rows(res);
+	const ulong nfield = mysql_num_fields(res);
+	bool clip = (nrow > NROWMAX);
+	MYSQL_FIELD*f = mysql_fetch_fields(res);
+	/************************************************************************/
+	//  Determine column widths, and format strings for printing
+	//  Find the longest entry in each column header, 
+	//  and over the rows, using MySQL's max_length
+	ulong*len = (ulong*) mxMalloc(nfield*sizeof(ulong));
+	for (ulong j = 0; j<nfield; j++) {
+    len[j] = (int)strlen(f[j].name);
+    if (f[j].max_length > len[j]) 
+      len[j] = f[j].max_length;
+  }
+	//  Compare to the continuation string length if we will clip
+	if (clip) { 
+    for (ulong j = 0; j<nfield; j++)
+      if (contstrlen > len[j])  
+        len[j] = contstrlen; 
+  }
+	//  Construct the format specification for printing the strings
+	char**fmt = (char**) mxMalloc(nfield*sizeof(char*));
+	for (ulong j = 0; j<nfield; j++) {
+    fmt[j] = (char*) mxCalloc(10, sizeof(char));
+    sprintf(fmt[j], "  %%-%ds ", len[j]); 
+  }
+	/************************************************************************/
+	//  Now print the actual data
+	mexPrintf("\n");
+	//  Column headers
+	for (ulong j = 0; j<nfield; j++) 
+    mexPrintf(fmt[j], f[j].name);
+	mexPrintf("\n");
+	//  Fancy underlines
+	for (ulong j = 0; j<nfield; j++) {
+    mexPrintf(" +");
+    for (ulong k = 0; k<len[j]; k++)  
+      mexPrintf("-");
+    mexPrintf("+"); 
+  }
+	mexPrintf("\n");
+	//  Print the table entries
+	if (nrow<=0) 
+    mexPrintf("(zero rows in result set)\n");
+	else {
+    if (!clip) { 
+      //  print the entire table
+      mysql_data_seek(res, 0);
+      for (ulong i = 0; i<nrow; i++) { 
+        MYSQL_ROW row = mysql_fetch_row(res);
+        if (!row) { 
+          mexPrintf("Printing full table data from row %d\n", i+1);
+          mexErrMsgTxt("Internal error:  Failed to get a row"); 
+        }
+        for (ulong j = 0; j<nfield; j++)
+          mexPrintf(fmt[j], (row[j] ? row[j] : ""));
+        mexPrintf("\n"); }
+    }
+    else {
+      //  print half at beginning, half at end
+      mysql_data_seek(res, 0);
+      for (int i = 0; i<NHEAD; i++) { 
+        MYSQL_ROW row = mysql_fetch_row(res);
+        if (!row) {
+          mexPrintf("Printing head table data from row %d\n", i+1);
+          mexErrMsgTxt("Internal error:  Failed to get a row"); 
+        }
+        for (ulong j = 0; j<nfield; j++)
+          mexPrintf(fmt[j], (row[j] ? row[j] : ""));
+        mexPrintf("\n");
+      }
+      for (ulong j = 0; j<nfield; j++) 
+        mexPrintf(fmt[j], contstr);
+      mexPrintf("\n");
+      mysql_data_seek(res, nrow-NTAIL);
+      for (int i = 0; i<NTAIL; i++) { 
+        MYSQL_ROW row = mysql_fetch_row(res);
+        if (!row) {
+          mexPrintf("Printing tail table data from row %d", nrow-NTAIL+i+1);
+          mexErrMsgTxt("Internal error:  Failed to get a row");
+        }
+        for (ulong j = 0; j<nfield; j++)
+          mexPrintf(fmt[j], (row[j] ? row[j] : ""));
+        mexPrintf("\n"); 
+      }
+      mexPrintf("(%d rows total)\n", nrow);
+    }
+  }
+	mexPrintf("\n");
+	// These should be automatically freed when we return to Matlab, 
+	//  but just in case ...
+	mxFree(len);  
+  mxFree(fmt);
+}
+/**********************************************************************
+*field2num():  Convert field in string format to double number
+**********************************************************************/
+const double NaN = mxGetNaN();				//  Matlab NaN for null values
+static bool can_convert(enum_field_types t) {
+	return (IS_NUM(t)&&
+		(t!=FIELD_TYPE_DATE)&&
+		(t!=FIELD_TYPE_TIME)&&
+		(t!=FIELD_TYPE_DATETIME)&&
+		(t!=FIELD_TYPE_TIMESTAMP));
+}
+static double field2num(const char*s, enum_field_types t) {
+	if (!s) return NaN;  // MySQL null -- nothing there
+	if (IS_NUM(t)) {
+    double val = NaN;
+    char* charend = 0;
+    val = std::strtod(s, &charend);
+    if (charend==s) {
+		//if (sscanf(s, "%lf", &val)!=1) {
+      mexPrintf("Unreadable value \"%s\" of type %s\n", s, typestr(t));
+      return NaN; 
+    }
+    return val;
+  }
+	else {
+    mexPrintf("Tried to convert \"%s\" of type %s to numeric\n", s, typestr(t));
+    mexErrMsgTxt("Internal inconsistency");
+  }
+  return 0;
+}
+/**********************************************************************
+*getstring():   Extract string from a Matlab array
+*   (Space allocated by mxCalloc() should be freed by Matlab
+*  when control returns out of the MEX-function.)
+*  This is based on an original by Kimmo Uutela
+**********************************************************************/
+static char* getstring(const mxArray*a) {
+	int llen = mxGetM(a)*mxGetN(a)*sizeof(mxChar)+1;
+	char*c = (char*) mxCalloc(llen, sizeof(char));
+	if (mxGetString(a, c, llen))
+		mexErrMsgTxt("Can\'t copy string in getstring()");
+	return c;
+}
+/**********************************************************************
+*mysql():  Execute the actual action
+* Which action we perform is based on the first input argument, 
+* which must be present and must be a character string:
+*   'open', 'close', 'use', 'status', or a legitimate MySQL query.
+*  This version does not permit binary characters in query string, 
+* since the query is converted to a C null-terminated string.
+*  If no output argument is given, then information is displayed.
+* If an output argument is given, then we operate silently, and
+* return status information.
+**********************************************************************/
+void mexFunction(int nlhs, mxArray*plhs[], int nrhs, const mxArray*prhs[]) {
+	int cid = 0;   // ID number of the current connection
+	int jarg = 0;  // Number of first string arg: becomes 1 if id is specified
+	/*********************************************************************/
+  // show GPL license
+  if (!runonce) {
+    runonce = true;
+    mexPrintf("mYm v1.0.9, Copyright (C) 2006, Swiss Federal Institute of technology, Lausanne, CH\n");
+    mexPrintf("mYm comes with ABSOLUTELY NO WARRANTY. This is free software,\n");
+    mexPrintf("and you are welcome to redistribute it under certain conditions.\n");
+    mexPrintf("For details read the GPL license included with this distribution.\n\n");
+  }
+	// Parse the first argument to see if it is a specific id number
+	if (nrhs!=0&&mxIsNumeric(prhs[0]))	{ 
+    if (mxGetM(prhs[0])!=1||mxGetN(prhs[0])!=1) {
+      mexPrintf("Usage:  %s([id], command, [ host, user, password ])\n", mexFunctionName());
+      mexPrintf("First argument is array %d x %d\n", mxGetM(prhs[0]), mxGetN(prhs[0]));
+      mexErrMsgTxt("Invalid connection ID"); 
+    }
+    double xid = *mxGetPr(prhs[0]);
+    cid = int(xid);
+    if (double(cid)!=xid||cid<-1||cid>=MAXCONN) {
+      mexPrintf("Usage:  %s([id], command, [ host, user, password ])\n", mexFunctionName());
+      mexPrintf("id = %g -- Must be integer between 0 and %d\n", xid, MAXCONN-1);
+      mexErrMsgTxt("Invalid connection ID"); 
+    }
+    jarg++; 
+  }
+	if (debug) 
+    mexPrintf("cid = %d  jarg = %d\n", cid, jarg);
+	/*********************************************************************/
+	//  Parse the result based on the first argument
+	enum querytype { OPEN, CLOSE, CLOSE_ALL, USE, STATUS, CMD } q;
+	char*query = NULL;
+	if (nrhs<=jarg)   
+    q = STATUS;
+	else{ 
+    if (!mxIsChar(prhs[jarg]))
+			mexErrMsgTxt("The command string is missing!");
+    query = getstring(prhs[jarg]);
+    if (!strcasecmp(query, "open"))
+      q = OPEN;
+    else if (!strcasecmp(query, "close"))  
+      q = CLOSE;
+    else if (!strcasecmp(query, "closeall"))
+      q = CLOSE_ALL;
+    else if (!strcasecmp(query, "use")||!strncasecmp(query, "use ", 4)) 
+      q = USE;
+    else if (!strcasecmp(query, "status")) 
+      q = STATUS;
+    else q = CMD; 
+  }
+	//  Check that the arguments are all character strings
+	if (q!=CMD)
+		for (int j = jarg; j<nrhs; j++) { 
+			if (!mxIsChar(prhs[j])) { 
+				mexPrintf("Usage:  %s([id], command, [ host, user, password ])\n", mexFunctionName());
+				mexErrMsgTxt("All args must be strings, except id"); 
+			}
+		}
+	if (debug){ 
+    if (q==OPEN)   
+      mexPrintf("q = OPEN\n");
+    if (q==CLOSE)  
+      mexPrintf("q = CLOSE\n");
+    if (q==USE)  
+      mexPrintf("q = USE\n");
+    if (q==STATUS) 
+      mexPrintf("q = STATUS\n");
+    if (q==CMD)  
+      mexPrintf("q = CMD\n"); 
+  }
+  // found the correct cid, if automatic scan is requested
+  if (cid==-1) {
+    if (q!=OPEN)
+      mexErrMsgTxt("automatic free connection scan, only when issuing a mYm open command!");
+    cid = 1;
+    while (cid<MAXCONN&&c[cid].isopen)
+      cid++;
+    if (cid==MAXCONN)
+      mexErrMsgTxt("no free connection ID"); 
+  }
+    // Shorthand notation now that we know which id we have
+  typedef MYSQL*mp;
+	mp &conn = c[cid].conn;
+	bool &isopen = c[cid].isopen;
+  if (q==OPEN) {
+    // OPEN A NEW CONNECTION
+    ////////////////////////
+		//  Close connection if it is open
+		if (isopen) {
+      mysql_close(conn);   
+      isopen = false;  
+      conn = NULL; 
+    }
+		//  Extract information from input arguments
+		char*host = NULL;   
+    if (nrhs>=jarg+2)  
+      host = getstring(prhs[jarg+1]);
+		char*user = NULL;   
+    if (nrhs>=jarg+3)  
+      user = getstring(prhs[jarg+2]);
+		char*pass = NULL;   
+    if (nrhs>=jarg+4)  
+      pass = getstring(prhs[jarg+3]);
+		int port = hostport(host);  // returns zero if there is no port
+		if (nlhs<1) { 
+      mexPrintf("Connecting to  host = %s", (host) ? host : "localhost");
+			if (port) 
+        mexPrintf("  port = %d", port);
+			if (user) 
+        mexPrintf("  user = %s", user);
+			if (pass) 
+        mexPrintf("  password = %s", pass);
+      mexPrintf("\n"); 
+    }
+		//  Establish and test the connection
+		//  If this fails, then conn is still set, but isopen stays false
+		if (!(conn = mysql_init(conn)))
+			mexErrMsgTxt("Couldn\'t initialize MySQL connection object");
+    //my_bool  my_true = true;
+    //mysql_options(conn, MYSQL_OPT_RECONNECT, &my_true);
+		if (!mysql_real_connect(conn, host, user, pass, NULL, port, NULL, CLIENT_MULTI_STATEMENTS))
+			mexErrMsgTxt(mysql_error(conn));
+		const char*c = mysql_stat(conn);
+    if (c) { 
+      if (nlhs<1) 
+        mexPrintf("%s\n", c); 
+    }
+    else   
+      mexErrMsgTxt(mysql_error(conn));
+		isopen = true;
+
+		//  Now we are OK -- if he wants output, give him the cid
+    if (nlhs>=1) { 
+      if (!(plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL)))
+        mexErrMsgTxt("Unable to create matrix for output");
+      *mxGetPr(plhs[0]) = cid; 
+    }
+  }
+  else if (q==CLOSE) {
+    // CLOSE CONNECTION
+    ////////////////////////
+    if (isopen) { 
+      // only if open
+      mysql_close(conn); 
+      isopen = false;  
+      conn = NULL;
+    }
+  }
+  else if (q==CLOSE_ALL) {
+    // CLOSE ALL CONNECTIONS
+    ////////////////////////
+    for (int i = 0; i<MAXCONN; i++)
+        if (c[i].isopen) {
+          mysql_close(c[i].conn); 
+          c[i].conn = NULL;
+          c[i].isopen = false;
+        }
+  }
+	else if (q==USE) {
+    // SPECIFY DATABASE
+    ////////////////////////
+    if (!isopen)
+      mexErrMsgTxt("Not connected");
+    if (mysql_ping(conn)) {
+      isopen = false;  
+      mexErrMsgTxt(mysql_error(conn)); 
+    }
+    char*db = NULL;
+    if (!strcasecmp(query, "use")) { 
+      if (nrhs>=2) 
+        db = getstring(prhs[jarg+1]);
+      else
+        mexErrMsgTxt("Must specify a database to use"); 
+    }
+    else if (!strncasecmp(query, "use ", 4)) { 
+      db = query+4;
+      while (*db==' ' ||*db=='\t') 
+        db++; 
+    }
+    else
+      mexErrMsgTxt("How did we get here?  Internal logic error!");
+    if (mysql_select_db(conn, db))  
+      mexErrMsgTxt(mysql_error(conn));
+    if (nlhs<1) 
+      mexPrintf("Current database is \"%s\"\n", db);
+    else {
+      // he wants some output, give him a 1
+      if (!(plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL)))
+        mexErrMsgTxt("Unable to create matrix for output");
+      *mxGetPr(plhs[0]) = 1.; 
+    } 
+  }
+	else if (q==STATUS)	{
+    // GET CONNECTION STATUS
+    ////////////////////////
+		if (nlhs<1) {
+      //  He just wants a report
+      if (jarg>0) {
+        //  mysql(cid, 'status')  Give status of the specified id				
+				if (!isopen) { 
+          mexPrintf("%2d: Not connected\n", cid);  
+          return; 
+        }
+				if (mysql_ping(conn)) {
+          isopen = false;   
+          mexErrMsgTxt(mysql_error(conn)); 
+        }
+        mexPrintf("%2d:  %-30s   Server version %s\n", cid, mysql_get_host_info(conn), mysql_get_server_info(conn));
+      }
+			else { 
+        //  mysql('status') with no specified connection
+				int nconn = 0;
+				for (int j = 0; j<MAXCONN; j++)
+          if (c[j].isopen) 
+            nconn++; 
+				if (debug)
+          mexPrintf("%d connections open\n", nconn);
+				if (nconn==0) {
+          mexPrintf("No connections open\n");  
+          return; 
+        }
+				if (nconn==1&&c[0].isopen) {
+          // Only connection number zero is open
+          // Give simple report with no connection id #
+					if (mysql_ping(conn)) { 
+            isopen = false;   
+            mexErrMsgTxt(mysql_error(conn)); 
+          }
+					mexPrintf("Connected to %s Server version %s Client %s\n", mysql_get_host_info(conn), mysql_get_server_info(conn), mysql_get_client_info());
+        }
+				else { 
+          // More than one connection is open
+          // Give a detailed report of all open connections
+					for (int j = 0; j<MAXCONN; j++) { 
+            if (c[j].isopen) { 
+              if (mysql_ping(c[j].conn)) {
+                c[j].isopen = false;
+                mexPrintf("%2d:  %s\n", mysql_error(c[j].conn));
+                continue; 
+              }
+							mexPrintf("%2d: %-30s Server version %s\n", j, mysql_get_host_info(c[j].conn), mysql_get_server_info(c[j].conn));
+            }
+          }
+        }
+      }
+    }
+		else {
+      //  He wants a return value for this connection
+			if (!(plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL)))
+				mexErrMsgTxt("Unable to create matrix for output");
+			double *pr = mxGetPr(plhs[0]);  
+      *pr = 0.;
+			if (!isopen)
+        *pr = 1.; 
+        //return; 
+			else if (mysql_ping(conn)) { 
+        isopen = false; 
+        *pr = 2.; 
+        //return; 
+      }
+			else if (!mysql_stat(conn)) { 
+        isopen = false; 
+        *pr = 3.; 
+        //return; 
+      }
+    }
+  }
+	else if (q==CMD) {
+    // ISSUE A MYSQL COMMAND
+    ////////////////////////
+    //  Check that we have a valid connection
+    if (!isopen)
+      mexErrMsgTxt("Not connected");
+    if (mysql_ping(conn)) {
+      isopen = false;  
+      mexErrMsgTxt(mysql_error(conn)); 
+    }
+		//******************PLACEHOLDER PROCESSING******************
+		// global placeholders variables and constant
+    const unsigned nex = nrhs-jarg-1;	// expected number of placeholders
+		unsigned nac = 0;									// actual number
+		ulong lq = (ulong)strlen(query);	// original query length, needed at some point
+		if (nex) {
+			// local placeholders variables and constant
+			char** po = 0;								// pointer to placeholders openning symbols
+			char** pc = 0;								// pointer to placeholders closing symbols
+      bool*  pec = 0;               // pointer to 'enable compression field'
+			char** pa = 0;								// pointer to placeholder in-string argument
+			unsigned* ps = 0;							// pointer to placeholders size (in bytes)
+			pfserial* pf = 0;							// pointer to serialization function
+			// LOOK FOR THE PLACEHOLDERS
+			po = (char**)mxCalloc(nex+1, sizeof(char*));
+			pc = (char**)mxCalloc(nex+1, sizeof(char*));
+			if (po[nac++] = strstr(query, PH_OPEN))
+				while (po[nac-1]&&nac<=nex) {
+					pc[nac-1] = strstr(po[nac-1]+1, PH_CLOSE);
+					if (pc[nac-1]==0)
+						mexErrMsgTxt("Placeholders are not correctly closed!");
+					po[nac] = strstr(pc[nac-1]+1, PH_OPEN);
+					nac++;
+			}
+			nac--;
+			// some error checks
+			if (nac!=nex)
+				mexErrMsgTxt("The number of placeholders differs from that of additional arguments!");
+			// now we have the correct number of placeholders
+			// read the types and in-string arguments
+			ps = (unsigned*)mxCalloc(nac, sizeof(unsigned));
+			pa = (char**)mxCalloc(nac, sizeof(char*));
+      pec = (bool*)mxCalloc(nac, sizeof(bool));
+			pf = (pfserial*)mxCalloc(nac, sizeof(pfserial));
+			for (unsigned i = 0; i<nac; i++) {
+				// placeholder function+control ph type+control arg type
+				getSerialFct(po[i]+strlen(PH_OPEN), prhs[jarg+i+1], pf[i], pec[i]);
+				// placeholder size in bytes
+				ps[i] = (unsigned)(pc[i]-po[i]+strlen(PH_OPEN));
+				// placeholder in-string argument
+				pa[i] = po[i]+strlen(PH_OPEN)+1;								
+				*(pc[i]) = 0;
+				// we can add a termination character in the query, 
+				// it will be processed anyway and we already have the original query length
+			}
+			// BUILD THE NEW QUERY
+      // serialize
+			char** pd = (char**)mxCalloc(nac, sizeof(char*));
+			ulong* plen = (ulong*)mxCalloc(nac, sizeof(ulong));
+      uLongf cmp_buf_len = 10000;
+      Bytef* pcmp = (Bytef*)mxCalloc(cmp_buf_len, sizeof(Bytef));
+			ulong nb = 0;
+			for (unsigned i = 0; i<nac; i++) {
+        // serialize individual field
+				pd[i] = pf[i](plen[i], prhs[jarg+i+1], pa[i], true);
+        if (pec[i]&&plen[i]>MIN_LEN_ZLIB) {
+          // compress field
+          const uLongf max_len = 1;//compressBound(plen[i]); *** GJ
+          if (max_len>cmp_buf_len){
+            pcmp = (Bytef*)mxRealloc(pcmp, max_len);
+            cmp_buf_len = max_len;
+          }
+          uLongf len = cmp_buf_len;
+          if (compress(pcmp, &len, (Bytef*)pd[i], plen[i])!=Z_OK)
+            mexErrMsgTxt("Compression failed");
+          const float cmp_rate = plen[i]/(LEN_ZLIB_ID+1.f+sizeof(ulong)+len);
+          if (cmp_rate>MIN_CMP_RATE_ZLIB) {
+            const ulong len_old = plen[i];
+            plen[i] = (ulong)LEN_ZLIB_ID+1+sizeof(ulong)+len;
+            pd[i] = (char*)mxRealloc(pd[i], plen[i]);
+            memcpy(pd[i], (const char*)ZLIB_ID, LEN_ZLIB_ID);
+            *(pd[i]+LEN_ZLIB_ID) = 0;
+            memcpy(pd[i]+LEN_ZLIB_ID+1, (const char*)&len_old, sizeof(ulong));
+            memcpy(pd[i]+LEN_ZLIB_ID+1+sizeof(ulong), pcmp, len);
+          }
+        }
+				nb += plen[i];
+			}
+      // create new query
+			char* nq = (char*)mxCalloc(2*nb+lq+1, sizeof(char));  // new query
+			char* pnq = nq; // running pointer to new query
+			const char* poq = query; // running pointer to old query
+			for (unsigned i = 0; i<nac; i++) {
+				memcpy(pnq, poq, po[i]-poq);
+				pnq += po[i]-poq;
+				poq = po[i]+ps[i];
+        pnq += mysql_real_escape_string(conn, pnq, pd[i], plen[i]);
+				mxFree(pd[i]);
+			}
+			memcpy(pnq, poq, lq-(poq-query)+1);
+      // replace the old query by the new one
+			pnq += lq-(poq-query)+1;
+			mxFree(query);
+			query = nq;
+			lq = (ulong)(pnq-nq);
+			mxFree(po);
+			mxFree(pc);
+      mxFree(pec);
+			mxFree(ps);
+			mxFree(pa);
+			mxFree(pd);
+			mxFree(plen);
+      if (pcmp!=NULL)
+        mxFree(pcmp);
+		}
+		else {
+			// check that no placeholders are present in the query
+			char*p_tmp_o = strstr(query, PH_OPEN);
+			char*p_tmp_c = strstr(query, PH_CLOSE);
+      if (p_tmp_o||p_tmp_c)
+				mexErrMsgTxt("The query contains placeholders, but no additional arguments!");
+		}
+		//  Execute the query (data stays on server)
+		if (nac!=0) {
+			if (mysql_real_query(conn, query, lq))
+				mexErrMsgTxt(mysql_error(conn));
+			}
+		else if (mysql_query(conn, query))  
+			mexErrMsgTxt(mysql_error(conn));
+		//  Download the data from server into our memory
+		//  We need to be careful to deallocate res before returning.
+		//  Matlab's allocation routines return instantly if there is not
+		//  enough free space, without giving us time to dealloc res.
+		//  This is a potential memory leak but I don't see how to fix it.
+		MYSQL_RES*res = mysql_store_result(conn);
+		//  As recommended in Paul DuBois' MySQL book (New Riders, 1999):
+		//  A NULL result set after the query can indicate either
+		//  (1) the query was an INSERT, DELETE, REPLACE, or UPDATE, that
+		//    affect rows in the table but do not return a result set; or
+		//  (2) an error, if the query was a SELECT, SHOW, or EXPLAIN
+		//    that should return a result set but didn't.
+		//  Distinguish between the two by checking mysql_field_count()
+		//  We return in either case, either correctly or with an error
+		if (!res) {
+			if (!mysql_field_count(conn)) {
+        ulong nrows = (ulong)mysql_affected_rows(conn);
+        if (nlhs<1)
+          return;
+        else {
+          plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
+          if (plhs[0]==0)
+            mexErrMsgTxt("Unable to create numeric matrix for output");
+          *mxGetPr(plhs[0]) = (double) nrows;
+          return; 
+        }
+      }
+			else
+        mexErrMsgTxt(mysql_error(conn));
+    }
+		ulong nrow = (ulong)mysql_num_rows(res), nfield = mysql_num_fields(res);
+		//  If he didn't ask for any output (nlhs = 0), 
+		//     then display the output and return
+		if (nlhs<1) { 
+      fancyprint(res);
+      mysql_free_result(res);
+      return; 
+    }
+		//  If we are here, he wants output
+		//  He must give exactly the right number of output arguments
+		if (nlhs!=nfield)	{ 
+      mysql_free_result(res);
+      mexPrintf("You specified %d output arguments, and got %d columns of data\n", nlhs, nfield);
+      mexErrMsgTxt("Must give one output argument for each column"); 
+    }
+		//  Fix the column types to fix MySQL C API sloppiness
+		MYSQL_FIELD*f = mysql_fetch_fields(res);
+		//fix_types(f, res);
+		//  Create the Matlab arrays for output
+		double**pr = (double**) mxMalloc(nfield*sizeof(double*));
+		for (ulong j = 0; j<nfield; j++) { 
+      if (can_convert(f[j].type)) { 
+        if (!(plhs[j] = mxCreateDoubleMatrix(nrow, 1, mxREAL))) { 
+          mysql_free_result(res);
+          mexErrMsgTxt("Unable to create numeric matrix for output"); 
+        }
+        pr[j] = mxGetPr(plhs[j]); 
+      }
+      else if (f[j].type==FIELD_TYPE_BLOB) {
+        if (!(plhs[j] = mxCreateCellMatrix(nrow, 1))) {
+          mysql_free_result(res);
+          mexErrMsgTxt("Unable to create cell matrix for output"); 
+        }
+        pr[j] = NULL;
+      }
+      else { 
+        if (!(plhs[j] = mxCreateCellMatrix(nrow, 1))) { 
+          mysql_free_result(res);
+          mexErrMsgTxt("Unable to create cell matrix for output"); 
+        }
+        pr[j] = NULL; 
+      }
+    }
+		//  Load the data into the cells
+		mysql_data_seek(res, 0);
+		for (ulong i = 0; i<nrow; i++) {
+      MYSQL_ROW row = mysql_fetch_row(res);
+      if (!row) { 
+        mexPrintf("Scanning row %d for data extraction\n", i+1);
+        mexErrMsgTxt("Internal error:  Failed to get a row"); 
+      }
+      ulong*p_lengths = mysql_fetch_lengths(res);
+      for (ulong j = 0; j<nfield; j++) { 
+        if (can_convert(f[j].type)) { 
+          pr[j][i] = field2num(row[j], f[j].type); 
+        }
+        else if (f[j].type==FIELD_TYPE_BLOB) {
+					mxSetCell(plhs[j], i, deserialize(row[j], p_lengths[j]));
+				}
+        else { 
+          mxArray*c = mxCreateString(row[j]);
+          mxSetCell(plhs[j], i, c); 
+        }
+      }
+    }
+		mysql_free_result(res);
+  }
+	else { 
+    mexPrintf("Unknown query type q = %d\n", q);
+    mexErrMsgTxt("Internal code error"); 
+  }
+}
+/*************************************SERIALIZE******************************************/
+// Serialize a structure array
+char* serializeStruct(ulong &rnBytes, const mxArray* rpArray, const char* rpArg, const bool rhead) {
+  // number of dimensions
+  int ndims = mxGetNumberOfDimensions(rpArray);
+  rnBytes = 1+(1+ndims)*sizeof(int);
+  if (rhead)
+    rnBytes += (ulong)LEN_ID_MATLAB+1;
+  // get number of fields and their names
+  const int nfields = mxGetNumberOfFields(rpArray);
+  rnBytes += sizeof(int); 
+  const char** pname = (const char**)mxCalloc(nfields, sizeof(char*));
+  int* fnl = (int*)mxCalloc(nfields, sizeof(int));
+  for (int i = 0; i<nfields; i++) {
+    pname[i] = mxGetFieldNameByNumber(rpArray, i);
+    fnl[i] = (int)strlen(pname[i]);
+    rnBytes += fnl[i]+1;
+  }
+  // loop through each element of the array and serialize it
+  const int nelts = mxGetNumberOfElements(rpArray);
+  char** pser = (char**)mxCalloc(nelts*nfields, sizeof(char*));
+  ulong* plen = (ulong*)mxCalloc(nelts*nfields, sizeof(ulong));
+  const mxArray* pf;
+  unsigned li = 0;
+  for (int i = 0; i<nelts; i++)
+    for (int j = 0; j<nfields; j++) {
+      pf = mxGetFieldByNumber(rpArray, i, j); 
+      if (mxIsNumeric(pf)||mxIsLogical(pf)||mxIsChar(pf))
+        pser[li] = serializeArray(plen[li], pf, rpArg, false);
+      else if (mxIsStruct(pf))
+        pser[li] = serializeStruct(plen[li], pf, rpArg, false);
+      else if (mxIsCell(pf))
+        pser[li] = serializeCell(plen[li], pf, rpArg, false);
+      else
+		    mexErrMsgTxt("Unknow type");
+      rnBytes += plen[li]+sizeof(int);
+      li++;
+    }
+  // put together the partial serializations
+  char* p_serial = (char*)mxCalloc(rnBytes, sizeof(char));
+  char* p_work = p_serial;
+  if (rhead) {
+    memcpy(p_work, ID_MATLAB, sizeof(char)*LEN_ID_MATLAB);
+    p_work += LEN_ID_MATLAB;
+    *(p_work++) = 0;
+  }
+  *(p_work++) = ID_STRUCT;
+	// number of dimensions
+	memcpy(p_work, (const char*)&ndims, sizeof(int));
+	p_work += sizeof(int);
+	// length of each dimension
+  const int* pdims = mxGetDimensions(rpArray);
+	memcpy(p_work, (const char*)pdims, sizeof(const int)*ndims);
+	p_work += sizeof(const int)*ndims;
+  // number of field
+	memcpy(p_work, (const char*)&nfields, sizeof(const int));
+	p_work += sizeof(const int);
+  // field names
+  for (int i = 0; i<nfields; i++) {
+    memcpy(p_work, (const char*)pname[i], fnl[i]);
+    p_work += fnl[i];
+    *(p_work++) = 0;
+  }
+  // partial serialization
+  for (int i = 0; i<nfields*nelts; i++) {
+    memcpy(p_work, (const char*)&plen[i], sizeof(ulong));
+    p_work  +=  sizeof(ulong);
+    memcpy(p_work, (const char*)pser[i], plen[i]);
+    p_work  +=  plen[i];
+  }
+  if (p_work-p_serial!=rnBytes)
+		// should never arrives here
+		mexErrMsgTxt("Oups, I haven't allocated enough memory, BEWARE");
+  // free unused memory
+  mxFree(pname);
+  mxFree(fnl);
+  for (int i = 1; i<nelts; i++)
+    mxFree(pser[i]);
+  mxFree(plen);
+  return p_serial;
+}
+// Serialize a cell
+char* serializeCell(ulong &rnBytes, const mxArray* rpArray, const char* rpArg, const bool rhead) {
+  // number of dimensions
+  const int ndims = mxGetNumberOfDimensions(rpArray);
+  rnBytes = 1+(1+ndims)*sizeof(int);
+  if (rhead)
+    rnBytes += (u_long)LEN_ID_MATLAB+1;
+  // loop through each element of the cell array and serialize it
+  const int nelts = mxGetNumberOfElements(rpArray);
+  char** pser = (char**)mxCalloc(nelts, sizeof(char*));
+  ulong* plen = (ulong*)mxCalloc(nelts, sizeof(ulong));
+  const mxArray* pf;
+  for (int i = 0; i<nelts; i++){
+    pf = mxGetCell(rpArray, i); 
+    if (mxIsNumeric(pf)||mxIsLogical(pf)||mxIsChar(pf))
+      pser[i] = serializeArray(plen[i], pf, rpArg, false);
+    else if (mxIsStruct(pf))
+      pser[i] = serializeStruct(plen[i], pf, rpArg, false);
+    else if (mxIsCell(pf))
+      pser[i] = serializeCell(plen[i], pf, rpArg, false);
+    else
+		  mexErrMsgTxt("unsupported type");
+    rnBytes += plen[i]+sizeof(int);
+  }
+  // put together the partial serializations
+  char* p_serial = (char*)mxCalloc(rnBytes, sizeof(char));
+  char* p_work = p_serial;
+  if (rhead) {
+    memcpy(p_work, ID_MATLAB, sizeof(char)*LEN_ID_MATLAB);
+    p_work += LEN_ID_MATLAB;
+    *(p_work++) = 0;
+  }
+  *(p_work++) = ID_CELL;
+	// number of dimensions
+	memcpy(p_work, (const char*)&ndims, sizeof(int));
+	p_work += sizeof(int);
+	// length of each dimension
+  const int* pdims = mxGetDimensions(rpArray);
+	memcpy(p_work, (const char*)pdims, sizeof(const int)*ndims);
+	p_work += sizeof(const int)*ndims;
+  // partial serialization
+  for (int i = 0; i<nelts; i++) {
+    memcpy(p_work, (const char*)&plen[i], sizeof(ulong));
+    p_work  +=  sizeof(ulong);
+    memcpy(p_work, (const char*)pser[i], plen[i]);
+    p_work  +=  plen[i];
+  }
+  if (p_work-p_serial!=rnBytes)
+		// should never arrives here
+		mexErrMsgTxt("Oups, I haven't allocated enough memory, BEWARE");
+  // free unused memory
+  for (int i = 1; i<nelts; i++)
+    mxFree(pser[i]);
+  mxFree(plen);
+  return p_serial;
+}
+// Serialize a numeric or a character array
+char* serializeArray(ulong &rnBytes, const mxArray*rpArray, const char*rpArg, const bool rhead) {
+	// compute number of bytes and allocate memory
+	int ndims = mxGetNumberOfDimensions(rpArray);
+	mxComplexity complexity = mxIsComplex(rpArray)? mxCOMPLEX : mxREAL;
+	ulong n_bytes_data;
+	if (complexity!=mxCOMPLEX)
+		n_bytes_data = mxGetElementSize(rpArray)*mxGetNumberOfElements(rpArray);
+	else
+		n_bytes_data = mxGetElementSize(rpArray)*mxGetNumberOfElements(rpArray)*2;
+	ulong nb = 1+sizeof(int)+ndims*sizeof(int)+sizeof(mxClassID)+sizeof(mxComplexity)+n_bytes_data;
+  if (rhead)
+    nb += (u_long)LEN_ID_MATLAB+1;
+	char*p_serial = (char*)mxCalloc(nb, sizeof(char));
+	char*p_work = p_serial;
+	if (!p_serial)
+		mexErrMsgTxt("Not enough memory");
+	/***SERIALIZE***/
+	// the first byte is set to 'A' for Array
+  if (rhead) {
+    memcpy(p_work, ID_MATLAB, sizeof(char)*LEN_ID_MATLAB);
+    p_work += LEN_ID_MATLAB;
+    *(p_work++) = 0;
+  }
+	*(p_work++) = ID_ARRAY;
+	// number of dimensions
+	memcpy(p_work, (const char*)&ndims, sizeof(int));
+	p_work += sizeof(int);
+	// length of each dimension
+	const int*pdims = mxGetDimensions(rpArray);
+	memcpy(p_work, (const char*)pdims, sizeof(const int)*ndims);
+	p_work += sizeof(const int)*ndims;
+	// classID
+	mxClassID class_id = mxGetClassID(rpArray);
+	memcpy(p_work, (const char*)&class_id, sizeof(mxClassID));
+	p_work += sizeof(mxClassID);
+	// complexity
+	memcpy(p_work, (const char*)&complexity, sizeof(mxComplexity));
+	p_work += sizeof(mxComplexity);
+  // data
+	if (complexity==mxCOMPLEX) {
+    // real part data
+    const char*pdata = (const char*)mxGetData(rpArray);
+	  memcpy(p_work, pdata, n_bytes_data/2);
+	  p_work += n_bytes_data/2;
+    // imaginary part data (if exists)
+		pdata = (const char*)mxGetImagData(rpArray);
+		memcpy(p_work, pdata, n_bytes_data/2);
+		p_work += n_bytes_data/2;
+	}
+  else{
+    // real part data
+    const char*pdata = (const char*)mxGetData(rpArray);
+	  memcpy(p_work, pdata, n_bytes_data);
+	  p_work += n_bytes_data;
+  }
+	rnBytes = (ulong)(p_work-p_serial);
+	if (rnBytes > nb)
+		// should never arrives here
+		mexErrMsgTxt("Oups, I haven't allocated enough memory, BEWARE");
+	return p_serial;
+}
+// Serialize a matlab string
+char* serializeString(ulong &rnBytes, const mxArray*rpArray, const char*rpArg, const bool) {
+  const int* pdims = mxGetDimensions(rpArray);
+  const unsigned length = std::max<int>(pdims[0], pdims[1]);
+  const unsigned n_dims = mxGetNumberOfDimensions(rpArray);
+  char* p_buf = NULL;
+  if (mxIsEmpty(rpArray)) {
+    p_buf = (char*)mxCalloc(2, sizeof(char));
+    p_buf[0] = ' ';
+    p_buf[1] = 0;
+    rnBytes = 1;
+  }
+  else if (mxIsChar(rpArray)) {
+    if (n_dims!=2||!(pdims[0]==1||pdims[1]==1))
+      mexErrMsgTxt("String placeholders only accept CHAR 1-by-M arrays or M-by-1!");
+    // matlab string
+	  p_buf = (char*)mxCalloc(length+1, sizeof(char));
+	  mxGetString(rpArray, p_buf, length+1);
+	  rnBytes = length;
+  }
+  else if (mxIsNumeric(rpArray)||mxIsLogical(rpArray)) {
+    // matlab scalar
+    p_buf = (char*)mxCalloc(512, sizeof(char));
+    if (length!=1)
+      mexErrMsgTxt("Only scalars are accepted!");
+	  if (mxIsComplex(rpArray))
+		  mexErrMsgTxt("Complex scalars are not supported");
+    double value;
+    bool conv_to_int = true;
+    if (mxIsDouble(rpArray)) {
+      value = *((double*)mxGetData(rpArray));
+      conv_to_int = false;
+    }
+    else if (mxIsSingle(rpArray)) {
+      value = *((float*)mxGetData(rpArray));   
+      conv_to_int = false;
+    }	  
+	  else if (mxIsInt8(rpArray))
+		  value = *((char*)mxGetData(rpArray));	 
+	  else if (mxIsInt32(rpArray))
+		  value = *((int*)mxGetData(rpArray));	 
+	  else if (mxIsUint8(rpArray))
+		  value = *((unsigned char*)mxGetData(rpArray));	 
+	  else if (mxIsUint32(rpArray))
+		  value = *((unsigned*)mxGetData(rpArray));
+    else if (mxIsLogical(rpArray))
+		  value = *(char*)mxGetData(rpArray)!=0;	
+	  else
+		  mexErrMsgTxt("Unsupported type, the supported types are (U)INT 8 and 32, FLOAT and DOUBLE");
+    if (*rpArg=='i') {
+      conv_to_int = true;
+      value = floor(value);
+    }
+    if (conv_to_int)
+      rnBytes = sprintf(p_buf, "%d", (int)value);
+    else {
+      int n = atoi(rpArg);
+      if (n==0)
+        rnBytes = sprintf(p_buf, "%.6f", value);
+      else
+        rnBytes = sprintf(p_buf, "%.*f", n, value);
+    }
+  }
+  else
+    mexErrMsgTxt("Only char string and non-complex scalar are supported");
+  return p_buf;
+}
+// serialize binary data, given as a UINT8 vector
+char* serializeBinary(ulong &rnBytes, const mxArray*rpArray, const char*rpArg, const bool) {
+	rnBytes = mxGetNumberOfElements(rpArray);
+  char*p_buf = (char*)mxCalloc(rnBytes, sizeof(char));
+  memcpy(p_buf, (const char*)mxGetData(rpArray), rnBytes);
+	return p_buf;
+}
+// Serialize a file, the filename is given
+char* serializeFile(ulong &rnBytes, const mxArray*rpArray, const char*rpArg, const bool) {
+	const int*pdims = mxGetDimensions(rpArray);
+	const unsigned length = std::max<int>(pdims[0], pdims[1]);
+	// filename provided
+	char*p_name = (char*)mxCalloc(length+1, sizeof(char));
+	mxGetString(rpArray, p_name, length+1);
+	FILE*pf = fopen(p_name, "rb");
+	mxFree(p_name);
+	if (!pf)
+		mexErrMsgTxt("Could not open file");
+	rnBytes = file_length(pf);
+	char*p_buf = (char*)mxCalloc(rnBytes, sizeof(char));
+	fread(p_buf, sizeof(char), rnBytes, pf);
+	fclose(pf);
+	return p_buf;
+}
+/*************************************DESERIALIZE******************************************/
+// deserialize a numeric or char Array
+mxArray* deserializeArray(const char*rpSerial, const ulong rlength) {
+	const char*p_serial = rpSerial;
+	// number of dimensions
+	int ndims;
+	memcpy((char*)&ndims, p_serial, sizeof(int));
+	p_serial += sizeof(int);
+	// length of each dimension
+	int*pdims = (int*)mxCalloc(ndims, sizeof(int));
+	memcpy((char*)pdims, p_serial, sizeof(int)*ndims);
+	p_serial += sizeof(int)*ndims;
+	// classID
+	mxClassID class_id;
+	memcpy((char*)&class_id, p_serial, sizeof(mxClassID));
+	p_serial += sizeof(mxClassID);
+	// complexity
+	mxComplexity complexity;
+	memcpy((char*)&complexity, p_serial, sizeof(mxComplexity));
+	p_serial += sizeof(mxComplexity);
+	// create the numerice array
+	mxArray*p_array = mxCreateNumericArray(ndims, pdims, class_id, complexity);
+	mxFree(pdims);
+	// real part data
+	char*pdata = (char*)mxGetData(p_array);
+	size_t nbytes_data_data = mxGetElementSize(p_array)*mxGetNumberOfElements(p_array);
+	memcpy((char*)pdata, p_serial, nbytes_data_data);
+	p_serial += nbytes_data_data;
+	// imaginary part data (if exists)
+	if (complexity==mxCOMPLEX) {
+		pdata = (char*)mxGetImagData(p_array);
+		memcpy((char*)pdata, p_serial, nbytes_data_data);
+	}
+	return p_array;
+}
+// deserialize struct Array
+mxArray* deserializeStruct(const char* rpSerial, const ulong rlength){
+	const char*p_serial = rpSerial;
+	// number of dimensions
+	int ndims;
+	memcpy((char*)&ndims, p_serial, sizeof(int));
+	p_serial += sizeof(int);
+	// length of each dimension
+	int* pdims = (int*)mxCalloc(ndims, sizeof(int));
+	memcpy((char*)pdims, p_serial, sizeof(int)*ndims);
+	p_serial += sizeof(int)*ndims;
+  int nelts = 1;
+  for (int i = 0; i<ndims; i++)
+    nelts *= pdims[i];
+  // number of field
+  int nfields;
+	memcpy(&nfields, (const char*)p_serial, sizeof(const int));
+	p_serial += sizeof(const int);
+  // field names
+  const char** field_names = (const char**)mxCalloc(nfields, sizeof(char*));
+  for (int i = 0; i<nfields; i++) {
+    field_names[i] = p_serial;
+    p_serial += strlen(p_serial)+1;
+  }
+  // create structure array
+  mxArray* ps = mxCreateStructArray(ndims, pdims, nfields, field_names);
+  // partial serialization
+  for (int i = 0; i<nelts; i++)
+    for (int j = 0; j<nfields; j++) {
+      ulong nbytes; 
+      memcpy(&nbytes, p_serial, sizeof(ulong));
+      p_serial  +=  sizeof(ulong);
+      mxArray* pf;
+      if (*p_serial==ID_ARRAY)
+        pf = deserializeArray(p_serial+1, nbytes);
+      else if (*p_serial==ID_STRUCT)
+        pf = deserializeStruct(p_serial+1, nbytes);
+      else if (*p_serial==ID_CELL)
+        pf = deserializeCell(p_serial+1, nbytes);
+      else
+		    mexErrMsgTxt("Unknow type");
+      mxSetFieldByNumber(ps, i, j, pf);
+      p_serial += nbytes;
+    }
+  // free unused memory
+  mxFree(field_names);
+  return ps;
+}
+// deserialize cell array
+mxArray* deserializeCell(const char* rpSerial, const ulong rlength){
+	const char* p_serial = rpSerial;
+	// number of dimensions
+	int ndims;
+	memcpy((char*)&ndims, p_serial, sizeof(int));
+	p_serial += sizeof(int);
+	// length of each dimension
+	int* pdims = (int*)mxCalloc(ndims, sizeof(int));
+	memcpy((char*)pdims, p_serial, sizeof(int)*ndims);
+	p_serial += sizeof(int)*ndims;
+  int nelts = 1;
+  for (int i = 0; i<ndims; i++)
+    nelts *= pdims[i];
+  // create structure array
+  mxArray* ps = mxCreateCellArray(ndims, pdims);
+  // partial serialization
+  for (int i = 0; i<nelts; i++){
+    ulong nbytes; 
+    memcpy(&nbytes, p_serial, sizeof(ulong));
+    p_serial += sizeof(ulong);
+    mxArray* pf;
+    if (*p_serial==ID_ARRAY)
+      pf = deserializeArray(p_serial+1, nbytes);
+    else if (*p_serial==ID_STRUCT)
+      pf = deserializeStruct(p_serial+1, nbytes);
+    else if (*p_serial==ID_CELL)
+      pf = deserializeCell(p_serial+1, nbytes);
+    else
+		  mexErrMsgTxt("Unknow type");
+    mxSetCell(ps, i, pf);
+    p_serial += nbytes;
+  }
+  return ps;
+}
+/*
+*   returns the length of a file in bytes, and replace the file pointer to its state before calling
+*/
+int file_length(FILE*f) {
+	int pos;
+	int end;
+	pos = ftell(f);
+	fseek(f, 0, SEEK_END);
+	end = ftell(f);
+	fseek(f, pos, SEEK_SET);
+	return end;
+}
diff --git a/zUtil_DB/mym.h b/zUtil_DB/mym.h
new file mode 100755
index 0000000000000000000000000000000000000000..95736a8bdff97e80769a5dca2f7f37ad999a09d0
--- /dev/null
+++ b/zUtil_DB/mym.h
@@ -0,0 +1,262 @@
+/*  mYm is a Matlab interface to MySQL server that support BLOB object
+*   Copyright (C) 2005 Swiss Federal Institute of technology (EPFL), Lausanne, CH
+*
+*   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
+*
+*   Author:                     Yannick Maret
+*   e-mail:                     yannick.maret@a3.epfl.ch
+*   old fashioned paper mail:   EPFL-STI-ITS-LTS1
+*                               Yannick MARET
+*                               ELD241
+*                               Station 11
+*                               CH-1015 Lausanne
+*
+*   Notice: some parts of this code (server connection, fancy print) is based  
+*   on an original code by Robert Almgren (http://www.mmf.utoronto.ca/resrchres/mysql/).
+*   The present code is under GPL license with the express agreement of Mr. Almgren.
+*/
+
+#ifndef MY_MAT_H
+#define MY_MAT H
+
+// some local defintion
+#ifndef ulong
+typedef unsigned long ulong;
+#endif
+#ifndef uchar
+typedef unsigned char uchar;
+#endif
+
+#include <mex.h>  //  Definitions for Matlab API
+
+#define ZLIB_WINAPI 
+#include <zlib.h>
+
+#include <math.h>
+
+const bool debug = false;  //  turn on information messages
+
+#if (defined(_WIN32)||defined(_WIN64))&&!defined(__WIN__)
+#include <windows.h>
+#include <winsock.h> // to overcome a bug in mysql.h
+/* We use case-insensitive string comparison functions strcasecmp(), strncasecmp().
+   These are a BSD addition and are also defined on Linux, but not on every OS, 
+   in particular Windows. The two "inline" declarations below fix this problem. If
+   you get errors on other platforms, move the declarations outside the WIN32 block */
+inline int strcasecmp(const char *s1, const char *s2) { return strcmp(s1, s2); }
+inline int strncasecmp(const char *s1, const char *s2, size_t n) { return strncmp(s1, s2, n); }
+#endif
+#include <mysql.h>  //  Definitions for MySQL client API
+
+// DLL entry point
+void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
+/*************** serializing functions ***************/
+// matlab objects
+char* serializeArray(unsigned long &rnBytes, const mxArray* rpArray, const char* rpArg, const bool);
+char* serializeStruct(unsigned long &rnBytes, const mxArray* rpArray, const char* rpArg, const bool);
+char* serializeCell(unsigned long &rnBytes, const mxArray* rpArray, const char* rpArg, const bool);
+char* serializeScalar(unsigned long &rnBytes, const mxArray* rpArray, const char* rpArg, const bool);
+char* serializeString(unsigned long &rnBytes, const mxArray* rpArray, const char* rpArg, const bool);
+// generic object
+char* serializeBinary(unsigned long &rnBytes, const mxArray* rpArray, const char* rpArg, const bool);
+char* serializeFile(unsigned long &rnBytes, const mxArray* rpArray, const char* rpArg, const bool);
+// deserilaizing functions
+mxArray* deserialize(const char* rpSerial, const unsigned long rlength);
+mxArray* deserializeArray(const char* rpSerial, const unsigned long rlength);
+mxArray* deserializeStruct(const char* rpSerial, const unsigned long rlength);
+mxArray* deserializeCell(const char* rpSerial, const unsigned long rlength);
+// utility functioms
+int file_length(FILE *f); // get the size of a file in byte
+unsigned long min_mysql_escape(char* rpout, const char* rpin, const unsigned long nin);
+/**********************************************************************
+ *
+ * hostport(s):  Given a host name s, possibly containing a port number
+ *  separated by the port separation character (normally ':').
+ * Modify the input string by putting a null at the end of
+ * the host string, and return the integer of the port number.
+ * Return zero in most special cases and error cases.
+ * Modified string will not contain the port separation character.
+ * Examples:  s = "myhost:2515" modifies s to "myhost" and returns 2515.
+ *      s = "myhost"    leaves s unchanged and returns 0.
+ *
+ **********************************************************************/
+const char portsep = ':';   //  separates host name from port number
+static int hostport(char *s) {
+	//   Look for first portsep in s; return 0 if null or can't find
+	if (!s||!(s = strchr(s, portsep))) 
+    return 0;
+	//  If s points to portsep, then truncate and convert tail
+	*s += 0;
+	return atoi(s);   // Returns zero in most special cases
+}
+/*********************************************************************/
+//  Static variables that contain connection state
+/*
+ *  isopen gets set to true when we execute an "open"
+ *  isopen gets set to false when either we execute a "close"
+ *            or when a ping or status fails
+ *   We do not set it to false when a normal query fails;
+ *   this might be due to the server having died, but is much
+ *   more likely to be caused by an incorrect query.
+ */
+class conninfo {
+public:
+	MYSQL *conn;   //  MySQL connection information structure
+	bool isopen;   //  whether we believe that connection is open
+	conninfo() { 
+    conn = NULL; 
+    isopen = false; 
+  }
+};
+const int MAXCONN = 20;
+static conninfo c[MAXCONN];   //  preserve state for MAXCONN different connections
+// for GPL license
+static bool runonce = false;
+/*********************************************************************/
+const char ID_MATLAB[] = "mYm";
+const size_t LEN_ID_MATLAB = strlen(ID_MATLAB);
+const char ID_ARRAY   = 'A';
+const char ID_CELL    = 'C';
+const char ID_STRUCT  = 'S';
+// Placeholder related constants
+const char PH_OPEN[]   = "{";  // placeholder openning symbols						
+const char PH_CLOSE[]  = "}";  // placeholder closing symbols					
+const char PH_BINARY   = 'B';
+const char PH_FILE     = 'F';
+const char PH_MATLAB   = 'M';
+const char PH_STRING   = 'S';
+// Preamble argument
+const char PRE_NO_COMPRESSION = 'u';
+// Compression
+const ulong MIN_LEN_ZLIB = 1000;        // minimum number of byte for trying compressiom
+const float MIN_CMP_RATE_ZLIB = 1.1f;   // minimum compression ratio
+const char ZLIB_ID[] = "ZL123";
+const size_t LEN_ZLIB_ID = strlen(ZLIB_ID);
+typedef char* (*pfserial)(unsigned long&, const mxArray*, const char*, const bool);
+
+static void getSerialFct(const char* rpt, const mxArray* rparg, pfserial& rpf, bool& rpec) {
+	const unsigned n_dims = mxGetNumberOfDimensions(rparg);
+	const int* p_dim = mxGetDimensions(rparg);
+  bool no_compression = false;
+  const char* pt = rpt;
+  // first check for preamble
+  if (*pt==PRE_NO_COMPRESSION) {
+    no_compression = true;
+    pt++;
+  }
+  if (*pt==PH_MATLAB) {
+    // this placeholder results in a serialized version of array, cell or structure 
+    rpec = true;
+    if (mxIsNumeric(rparg)||mxIsChar(rparg))
+      rpf = &serializeArray;
+    else if (mxIsCell(rparg))
+      rpf = &serializeCell;
+    else if (mxIsStruct(rparg))
+      rpf = &serializeStruct;
+    else
+      mexErrMsgTxt("Matlab placeholder only support array, structure, or cell");
+  }
+  else if (*pt==PH_BINARY||*pt==PH_FILE) {
+    // this placeholder results in a binary dump of the corresponding data
+    rpec = true;
+    if (*pt==PH_BINARY)
+      if (n_dims!=2||!(p_dim[0]==1||p_dim[1]==1)||!mxIsUint8(rparg))
+				mexErrMsgTxt("Binary placeholders only accept UINT8 1-by-M or M-by-1 arrays!");
+      else
+        rpf = &serializeBinary;
+    else
+      if (n_dims!=2||!(p_dim[0]==1||p_dim[1]==1)||!mxIsChar(rparg))
+        mexErrMsgTxt("String placeholders only accept CHAR 1-by-M or M-by-1 arrays!");
+      else
+        rpf = &serializeFile;
+  }
+  else if (*pt==PH_STRING) {
+    // this placeholder results in a text version of the data
+    rpec = false;
+    rpf = &serializeString;
+  }
+  else
+    mexErrMsgTxt("Unknow placeholders!");
+  if (no_compression)
+    rpec = false;
+}
+// entry point
+mxArray* deserialize(const char* rpSerial, const unsigned long rlength) {
+	mxArray* p_res = NULL;
+	bool could_not_deserialize = true;
+  bool used_compression = false;
+  char* p_cmp = NULL;
+  const char* p_serial = rpSerial;
+  unsigned long length = rlength;
+  if (p_serial==0) {
+		// the row is empty: return an empty array
+		p_res = mxCreateNumericArray(0, 0, mxCHAR_CLASS, mxREAL);
+    return p_res;
+  }
+  if (strcmp(p_serial, ZLIB_ID)==0) {
+    p_serial = p_serial+LEN_ZLIB_ID+1;
+    // read the length in bytes
+    ulong len;
+    memcpy((char*)&len, p_serial, sizeof(ulong));
+    p_serial = p_serial+sizeof(ulong);
+    char* p_cmp = (char*)mxCalloc(len, sizeof(char));
+    try {
+      int res = uncompress((Bytef*)p_cmp, &len, (const Bytef*)p_serial, length);
+      if (res==Z_OK) {
+        used_compression = true;
+        p_serial = p_cmp;
+        length = len;
+      }
+      else
+        p_serial = rpSerial;
+    }
+    catch(...) {
+      p_serial = rpSerial;
+    }
+  }
+  if (strcmp(p_serial, ID_MATLAB)==0) {
+    p_serial = p_serial+LEN_ID_MATLAB+1;
+    try {
+      could_not_deserialize = false;
+      if (*p_serial==ID_ARRAY)
+			  // the blob contains an array
+			  p_res = deserializeArray(p_serial+1, length);
+      else if (*p_serial==ID_STRUCT)
+        // the blob contains a struct
+        p_res = deserializeStruct(p_serial+1, length);
+      else if (*p_serial==ID_CELL)
+        // the blob contains a struct
+        p_res = deserializeCell(p_serial+1, length);
+      else
+        // the blob contains an unknow object
+        could_not_deserialize = true;
+    }
+    catch(...) {
+      could_not_deserialize = true;
+      p_serial = rpSerial;
+    }
+  }
+	if (could_not_deserialize) {
+		// we don't know what to do with the stuff in the database
+		// we return a memory dump in UINT8 format
+		int p_dim[2] = {length, 1};
+		p_res = mxCreateNumericArray(2, p_dim, mxUINT8_CLASS, mxREAL);
+		memcpy((char*)mxGetData(p_res), p_serial, length);
+	}
+  if (used_compression)
+    mxFree(p_cmp);
+	return p_res;
+}
+#endif // MY_MAT_H
diff --git a/zUtil_DB/mym2.m b/zUtil_DB/mym2.m
new file mode 100755
index 0000000000000000000000000000000000000000..bd6f05b43f6febecf7410f323e743f3fdb740f8d
--- /dev/null
+++ b/zUtil_DB/mym2.m
@@ -0,0 +1,92 @@
+% MYM - Interact with a MySQL database server 
+%       Copyright 2005, EPFL (Yannick Maret)
+%
+% Copyright notice: this code is a heavily modified version of the original
+% work of Robert Almgren from University of Toronto.
+%
+% If no output arguments are given, then display results. Otherwise returns
+% requested data silently.
+% mym() or mym
+% ------------
+%   shows status of all open connections (returns nothing).
+% mym('open', host, user, password)
+% ---------------------------------
+%   Open a connection with specified parameters, or defaults if none
+%     host:     default is local host. Use colon for port number
+%     user:     default is Unix login name.
+%     password: default says connect without password.
+%   Examples: mym('open','arkiv')     %  connect on default port
+%             mym('open','arkiv:2215')
+%   If successful, open returns 0 if successful, and throw an error
+%   otherwise. The program can maintain up to 20 independent connections.
+%   Any command may be preceded by a connection handle -- an integer from 0
+%   to 10 -- to apply the command to that connection.
+%   Examples: mym(5,'open','host2')  %  connection 5 to host 2
+%             mym                    %  status of all connections
+%   When no connection handle is given, mym use 0 by default. If the
+%   corresponding connection is open, it is closed and opened again.
+%   It is possible to ask mym to look for an available connection
+%   handle by using -1. The used connection handle is then returned.
+%   Example:  cid = mym(-1, 'open', 'host2')  %  cid contains the used
+%                                                connection handle
+% mym('close')
+% ------------
+%   Close the current connection. Use mym('closeall') to closes all open 
+%   connections.
+% mym('use',db)  or   mym('use db')
+% ---------------------------------
+%   Set the current database to db   
+%   Example:  mym('use cme')
+% mym('status')
+% -------------
+%   Display information about the connection and the server.
+%   Return  0  if connection is open and functioning
+%           1  if connection is closed
+%           2  if should be open but we cannot ping the server
+% mym(query)
+% ----------
+%   Send the given query or command to the MySQL server. If arguments are
+%   given on the left, then each argument is set to the column of the
+%   returned query. Dates and times in result are converted to Matlab 
+%   format: dates are serial day number, and times are fraction of day. 
+%   String variables are returned as cell arrays.
+%   Example: p = mym('select price from contract where date="1997-04-30"');
+%            % Returns price for contract that occured on April 30, 1997.
+%   Note: All string comparisons are case-insensitive
+%   Placeholders: in a query the following placeholders can be used: {S}, 
+%   {Si}, {M}, {F}, and {B}.
+%   Example: i = 1000;
+%            B = [1 2; 3 4];
+%            mym('INSERT INTO test(id,value) VALUES("{Si}","{M}")',i,B);
+%            A = mym('SELECT value FROM test WHERE id ="{Si}")', 1000);
+%            % Insert the array B into table test with id=1000. Then the 
+%            % value is retrieved and put into A.
+%   {S}  is remplaced by a string given by the corresponding argument arg. 
+%        Arg can be a matlab string or a scalar. The format of the string
+%        for double scalars is [sign]d.ddddddEddd; for integers the format 
+%        is [sign]dddddd.
+%   {Sn} is the same as {S} but for double scalar only. The format of the
+%        string is [sign]d.ddddEddd, where the number of decimal after the 
+%        dot is given by n.
+%   {Si} is the same as {S} but for double scalar only. The corresponding 
+%        double is first converted to an integer (using floor).
+%   {M}  is replaced by the binary representation of the corresponding
+%        argument (it can be a scalar, cell, numeric or cell array, or a 
+%        structure).
+%   {B}  is replaced by the binary representation of the uint8 vector
+%        given in the corresponding argument.
+%   {F}  is the same as {B} but for the file whose name is given in the
+%        corresponding argument.
+%   Note: 1) {M}, {B} and {F} need to be put in fields of type BLOB
+%         2) {M}, {B} and {F} binary representations are compressed -- only 
+%            if the space gain is larger than 10% --. We use zlib v1.2.3!
+%            The compression can be switched off by using  {uM}, {uB} and
+%            {uF}, instead.
+%         3) {M} does not work if the endian of the client used to store
+%            the BLOB is different than that used to fetch it.
+%         4) time fields are returned as string dump
+%         5) this kind of insert does not work properly:
+%             mym(INSERT INTO tbl(id,txt) VALUES(1000,"abc{dfg}h")');
+%            as the "abc{dfg}h" is mistaken for a mYm command. A possible
+%            solution is to use the following command:
+%             mym(INSERT INTO tbl(id,txt) VALUES(1000,"{S}")','abc{dfg}h');
\ No newline at end of file
diff --git a/zUtil_DB/readme.txt b/zUtil_DB/readme.txt
new file mode 100755
index 0000000000000000000000000000000000000000..fc1bf3f2adfb0ed5b6f604d60ee0e4dbd2699bad
--- /dev/null
+++ b/zUtil_DB/readme.txt
@@ -0,0 +1,81 @@
+mYm v1.0.9 readme.txt
+Updated March 30, 2006 by Yannick Maret
+
+All feedback appreciated to yannick.maret@epfl.ch
+
+GPL
+---
+mYm is a Matlab interface to MySQL server that support BLOB object
+Copyright (C) 2005 Swiss Federal Institute of technology (EPFL), Lausanne, CH
+
+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
+
+author:                   yannick MARET
+e-mail:                   yannick.maret@a3.epfl.ch
+old fashioned paper mail: EPFL-STI-ITS-LTS1 
+                          Yannick MARET
+                          ELD241
+                          Station 11
+                          CH-1015 Lausanne    
+
+Copyright notice: some parts of this code (server connection, fancy print) is based on an original code by Robert Almgren (http://www.mmf.utoronto.ca/resrchres/mysql/). The present code is under GPL license with express agreement of Mr. Almgren.
+ 
+WHAT IS MYM?
+------------
+mYm is a Matlab interface to MySQL server. It is based on the original 'MySQL and Matlab' by Robert Almgren and adds the support for Binary Large Object (BLOB). That is, it can insert matlab objects (e.g. array, structure, cell) into BLOB fields, as well retrieve from them. To save space, the matlab objects is first compressed (using zlib) before storing it into a BLOB field. Like Almgren's original, mYm supports multiple connections to MySQL server.
+
+INSTALLATION
+------------
+-Windows run setup.msi
+-Matlab  the source can be compiled using the following command (thanks to Jeffrey Elrich)
+         mex -I[mysql_include_dir] -I[zlib_include_dir] -L[mysql_lib_dir] -L[zlib_lib_dir] -lz -lmysqlclient mym.cpp
+	 (on Mac OS X you might also need the -lSystemStubs switch to avoid namespace clashes)
+         Note: to compile, the zlib library should be installed on the system (including the headers).
+               for more information, cf. http://www.zlib.net/
+
+HOW TO USE IT
+-------------
+see mym.m
+
+HISTORY
+-------
+v1.0.9	- a space is now used when the variable corresponding to a string placeholder is empty
+        - we now use strtod instead of sscanf(s, "%lf")
+	- add support for stored procedure
+v1.0.8	- corrected a problem occurring with MySQL commands that do not return results
+        - the M$ Windows binary now use the correct runtime DLL (MSVC80.DLL insteaLd of MSVC80D.DL)
+v1.0.7  - logical values are now correctly considered as numerical value when using placeholder {Si}
+        - corrected a bug occuring when closing a connection that was not openned
+        - added the possibility to get the next free connection ID when oppening a connection
+v1.0.6  - corrected a bug where mym('use', 'a_schema') worked fine while mym(conn, 'use', 'a_schema') did not work
+        - corrected a segmentation violation that happened when issuing a MySQL command when not connected
+        - corrected the mex command (this file)
+        - corrected a bug where it was impossible to open a connection silently
+        - use std::max<int>(a, b) instead of max(a, b)
+v1.0.5  - added the preamble 'u', permitting to save binary fields without using compression
+        - corrected a bug in mym('closeall')
+        - corrected various mistakes in the help file (thanks to Jörg Buchholz)
+v1.0.4  corrected the behaviour of mYm with time fields, now return a string dump of the field
+v1.0.3 	minor corrections
+v1.0.2  put mYm under GPL license, official release
+v1.0.1  corrected a bug where non-matlab binary objects were not returned
+v1.0.0  initial release
+
+
+
+
+
+
+
diff --git a/zUtil_Drawing/circlepoints.m b/zUtil_Drawing/circlepoints.m
new file mode 100755
index 0000000000000000000000000000000000000000..67678f48e49896f4b66cd90cf8a486f9b67a0ba6
--- /dev/null
+++ b/zUtil_Drawing/circlepoints.m
@@ -0,0 +1,18 @@
+function [xpoints,ypoints]=circlepoints(x,y,r,nseg)
+% CIRCLEPOINTS.M Produces points lying on a circle
+% Usage: [x,y]=circlepoints(xc,yc,radius)
+%        uses a default (40) number of line segments to produces points for a circle centred at xc,yc with radius 'radius'
+%        [x,y]=circlepoints(xc,yc,radius,nseg)
+%        as for previous case, with user-specified number of line segments
+
+% Greg Johnson, September 2006
+
+if ~exist('nseg','var')  % if user didn't specify number of line segments
+  nseg=40;               % make default
+end
+
+theta = 0 : (2 * pi / nseg) : (2 * pi);
+xpoints = r * cos(theta) + x;
+ypoints = r * sin(theta) + y;
+
+% last point is the same as first point
\ No newline at end of file
diff --git a/zUtil_Drawing/ellipsepoints.m b/zUtil_Drawing/ellipsepoints.m
new file mode 100755
index 0000000000000000000000000000000000000000..c90c45242b9ca77eb4fbb8c01e2ca462d2689a75
--- /dev/null
+++ b/zUtil_Drawing/ellipsepoints.m
@@ -0,0 +1,20 @@
+function [xpoints,ypoints]=ellipsepoints(xc,yc,semiaxisx,semiaxisy,nseg)
+% ELLIPSEPOINTS.M Produces points lying on a ellipse
+% Usage: [x,y]=ellipsepoints(xc,yc,major,minor)
+%        uses a default (40) number of line segments to produces points for
+%        an ellipse centred at xc,yc with major axis and minor axis as
+%        specified
+%        [x,y]=ellipsepoints(xc,yc,major,minor,nseg)
+%        as for previous case, with user-specified number of line segments
+
+% Greg Johnson, February 2007
+
+if ~exist('nseg','var')  % if user didn't specify number of line segments
+  nseg=40;               % make default
+end
+
+theta = 0 : (2 * pi / nseg) : (2 * pi);
+xpoints = semiaxisx * cos(theta) + xc;
+ypoints = semiaxisy * sin(theta) + yc;
+
+% last point is the same as first point
\ No newline at end of file
diff --git a/zUtil_Drawing/fig2jpg.m b/zUtil_Drawing/fig2jpg.m
new file mode 100755
index 0000000000000000000000000000000000000000..727c25bc07c236ae1e8dd6ca5af34be0114fcafc
--- /dev/null
+++ b/zUtil_Drawing/fig2jpg.m
@@ -0,0 +1,13 @@
+function fig2jpg(fname);
+% FIG2JPG.M Converts Matlab figure to a JPEG
+% Usage:
+%       fig2jpg(filename)
+%       filename is every EXCEPT the extension - .fig and .jpg will be
+%       appended automatically
+
+% Greg Johnson, September 2006
+
+  hgload([fname '.fig']);
+  print('-djpeg',[fname '.jpg']);
+  close(gcf)
+end
diff --git a/zUtil_ForwardProjection/AREMIS_view.m b/zUtil_ForwardProjection/AREMIS_view.m
new file mode 100755
index 0000000000000000000000000000000000000000..eb08f1bc416c54f058d88b542ccc43dae2225aed
--- /dev/null
+++ b/zUtil_ForwardProjection/AREMIS_view.m
@@ -0,0 +1,162 @@
+fid=fopen('grain99_whole.par');
+tokens=textscan(fid,'%s%s','delimiter','=');
+fclose(fid);
+keys=deblank(tokens{1});
+values=deblank(tokens{2});
+clear art
+
+for n=1:length(keys)
+  str=upper(char(keys(n)));
+  if (strfind(str,'EXT_PROJ'))
+    extprojndx=str2num(str(9:end));
+    art.radio(extprojndx+1).extprojndx=str2double(values(n));
+  else
+    k=upper(char(keys(n)));
+    switch(k) % can't handle EXT_PROJx lines...
+      case 'PAGBEGIN SYSTEMAL'
+      case 'PROJ_GENE_FILENAME'
+        art.proj_fname_prefix=char(values(n));
+      case 'NBITER'
+        art.nbiter = str2double(values(n));
+      case 'NBITER_HALF_QUADRA'
+      case 'NBSAUV'
+      case 'REC_GENE_FILENAME'
+      case 'LAMBDA_FLAG'
+      case 'LAMBDA'
+      case 'ERR_FLAG'
+      case 'ALGO_TYPE'
+      case 'BLOCK_SIZE'
+      case 'PROJ_MNG'
+      case 'NB_RESOL'
+      case 'THRESH_SUPP'
+      case 'CLIP_SUPP'
+      case 'CLIP_SPHERE'
+      case 'HISTO_SIZE'
+      case 'MAXVOL'
+      case 'MINVOL'
+      case 'VOL_TYPE'
+      case 'PAGEND SYSTEMAL'
+      case 'PAGBEGIN ACQGEO'
+      case 'NBRADIO'
+      case 'POSITION'
+        radio_ndx=str2double(values(n));
+      case {'FGD','PGD','QGD','PEPD','PEQD','P1D','Q1D','NP','NQ'...
+          'PSI','XSI','DELTA','PO','QO','MO','IPD','IQD','IPF','IQF'}
+        art.radio(radio_ndx).(lower(char((keys(n)))))=str2double(values(n));
+      case 'PAGBEGIN OBJET'
+        radio_ndx=NaN; % finished with radios
+      case {'PEX','PEY','PEZ','X1','Y1','Z1','NX','NY','NZ'}
+        art.geometry.(lower(char((keys(n)))))=str2double(values(n));
+
+    end
+  end
+end
+
+%%
+  clear x y z
+
+  % make VOI bounding box
+  x1=art.geometry.x1;
+  y1=art.geometry.y1;
+  z1=art.geometry.z1;
+  pex=art.geometry.pex;
+  pey=art.geometry.pey;
+  pez=art.geometry.pez;
+  nx=art.geometry.nx;
+  ny=art.geometry.ny;
+  nz=art.geometry.nz;
+
+  u1 = x1;
+  u2 = x1 + (pex*nx);
+  v1 = y1;
+  v2 = y1 + (pey*ny);
+  w1 = z1;
+  w2 = z1 + (pez*nz);
+
+  x=[u1 u2 u2 u1 u1 u1;...
+    u2 u2 u1 u1 u2 u2;...
+    u2 u2 u1 u1 u2 u2;...
+    u1 u2 u2 u1 u1 u1];
+
+  y=[v1 v1 v2 v2 v1 v1;...
+    v1 v2 v2 v1 v1 v1;...
+    v1 v2 v2 v1 v2 v2;...
+    v1 v1 v2 v2 v2 v2;];
+
+  z=[w1 w1 w1 w1 w1 w2;...
+    w1 w1 w1 w1 w1 w2;...
+    w2 w2 w2 w2 w1 w2;...
+    w2 w2 w2 w2 w1 w2];
+
+  c=[0.5 0 0];
+  %close all
+  clf
+  p_sample=patch(x,y,z,c);
+  set(p_sample,'facealpha',0.2);
+
+ % projndx=5;
+
+  hold on
+  fgd=art.radio(projndx).fgd;
+  mo=art.radio(projndx).mo;
+
+  if 0
+    l1=line([0 mo],[0 0],[0 0])  % sample origin to source
+    set(l1,'color','r');
+    l2=line([mo mo+fgd],[0 0],[0 0]);
+    set(l2,'color','g')
+  end
+
+  % detector
+  np=art.radio(projndx).np;
+  nq=art.radio(projndx).nq;
+  pepd=art.radio(projndx).pepd;
+  peqd=art.radio(projndx).peqd;
+
+  wdet=mo+fgd;
+  udetsize=np*pepd;
+  vdetsize=nq*peqd;
+
+  udetorigin=art.radio(projndx).po;
+  vdetorigin=art.radio(projndx).qo;
+  vdetmin=vdetorigin-(vdetsize/2);
+  vdetmax=vdetorigin+(vdetsize/2);
+  udetmin=udetorigin-(udetsize/2);
+  udetmax=udetorigin+(udetsize/2);
+  fname=sprintf('%s%d',art.proj_fname_prefix,art.radio(projndx).extprojndx)
+art.radio(projndx).extprojndx
+  projim=sdt_read(fname);
+  projim=-(projim./max(projim(:)))+1;
+  [uu,vv]=meshgrid(udetmin:udetmax,vdetmin:vdetmax);
+  hw=warp(zeros(size(uu)),uu,vv,projim);
+  %hs=surface(zeros(size(uu)),uu,vv,ones(size(uu)));
+  %set(hs,'facecolor','texturemap','edgecolor','none','cdatamapping','direct');
+  %set(hs,'facealpha',0.2);
+  %p_det=patch(...
+  %  [wdet;wdet;wdet;wdet],...
+  %  [udetmin;udetmin;udetmax;udetmax],...
+  %  [vdetmin;vdetmax;vdetmax;vdetmin],.5*ones(4,1))
+
+  %% line projection
+
+  axis image
+  axis vis3d
+  view(3)
+  shg
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_ForwardProjection/fp.m b/zUtil_ForwardProjection/fp.m
new file mode 100755
index 0000000000000000000000000000000000000000..dbc9be478a555b5d835cbee35049816c333f08f3
--- /dev/null
+++ b/zUtil_ForwardProjection/fp.m
@@ -0,0 +1,291 @@
+testing=true;
+if testing==true
+  clear all
+  close all
+  testing=true;
+else
+  cd ~/gt/data/june2007/strain_june_6N_
+  load('~/gt/data/june2007/strain_june_6N_/old_4_grains/grain2_/grain2_.mat')
+
+  numproj=15;
+  thetarange = Theta(1:numproj);
+  etarange=Eta(1:numproj);
+  omegarange=Omega(1:numproj);
+  ndx=0;
+  for n=struct_ids(1:numproj)
+    ndx=ndx+1;
+    im=gtGetSummedDifSpot_pair(n,1);
+    [xorigin,yorigin]=mym(sprintf('select BoundingBoxXOrigin,BoundingBoxYOrigin from strain_june_6N_difspot where difspotID=%d',n));
+    im=gtPlaceSubImage(im,zeros(2048),xorigin,yorigin);
+    % now write the projection to disk
+    scanname='scanname';
+    % write projections to disk
+    fname=sprintf('/tmp_14_days/art/scanname%d',ndx);
+    sdt_write(fname,im,'float32');
+  end
+end
+cd /tmp_14_days/art
+
+%% produce phantom sphere
+zdet=-11.6610;
+
+if testing==true
+  numpixels=1001;
+  sizepixels=0.01;
+else
+  numpixels=2048;
+  sizepixels=0.01;
+end
+
+
+if ~mod(numpixels,2)
+  warning('Odd pixel number are easier...')
+end
+
+xdetsize=numpixels*sizepixels;
+ydetsize=xdetsize;
+p=patch(...
+  [-floor(numpixels/2)*sizepixels -floor(numpixels/2)*sizepixels floor(numpixels/2)*sizepixels floor(numpixels/2)*sizepixels],...
+  [-floor(numpixels/2)*sizepixels floor(numpixels/2)*sizepixels floor(numpixels/2)*sizepixels -floor(numpixels/2)*sizepixels],[zdet zdet zdet zdet],'r');
+set(p,'facealpha',.1)
+
+np=numpixels;nq=np;
+[xx,yy]=meshgrid(linspace(-floor(numpixels/2)*sizepixels,floor(numpixels/2)*sizepixels,numpixels));
+
+hold on
+rsphere=0.1;  % 0.01 only works for 0,45,90 etc +-1
+%%%%%%%%%%%%%%%%%%%
+% xsc and ysc are horiztonal in the plane of the detector
+% zsc is vertical in the plane of the detector
+xsc=0;
+ysc=1;
+zsc=1;
+%%%%%%%%%%%%%%%%%%%%%
+
+
+
+[xs,ys,zs]=sphere(20);
+xs=(xs*rsphere)+xsc;
+ys=(ys*rsphere)-ysc;
+zs=(zs*rsphere)+zsc;
+ss=surf(xs,ys,zs,ones(size(zs)));
+set(ss,'faceColor','r')
+
+axis equal
+view(3)
+shg
+
+%% calculate projections
+
+% manual setup
+if testing==true
+  % setup projection geometries
+  numproj=3;
+
+  % omega rotation only
+ 
+  thetarange=[-5 0 5];
+  etarange=0*ones(1,numproj);
+  %omegarange=linspace(0,360,numproj+1);omegarange(end)=[];
+  omegarange=[0 90 180 ];
+  
+  numproj=3;
+  thetarange=[0 0 0];
+  etarange=[0 0 0];
+  omegarange=[0 45 90 ];
+ 
+ etarange=etarange-90;% eta is 0 when HORIZONTAL on the detector!!!
+
+end
+ip=zeros([size(xx) length(thetarange)]);
+
+hold on
+for n=1:length(thetarange) % each projection
+  theta=thetarange(n);
+  eta=etarange(n);
+  thetarad=theta*pi/180;
+  etarad=eta*pi/180;
+  omegarad=omegarange(n)*pi/180;
+
+  % create unit cylinder
+  [xc,yc,zc]=cylinder;
+  
+  zc(2,:)=zdet;  % move bottom of cylinder to detector plane
+  zc(1,:)=zc(1,:)+rsphere;
+
+  xdist=(rsphere/cos(thetarad))-rsphere;
+  %ydist=(rsphere/cos(etarad))-rsphere;
+
+  xc(1,:)=(xc(1,:)*rsphere/cos(thetarad))+(zc(1,:)*sin(thetarad));
+  xc(2,:)=(xc(2,:)*(rsphere/cos(thetarad))+(zc(2,:)*sin(thetarad))); %(-rsphere*tan(thetarad));
+
+  yc=yc*rsphere;
+  %yc(1,:)=(yc(1,:)*rsphere/cos(thetarad))+(zc(1,:)*sin(thetarad));
+  %yc(2,:)=(yc(2,:)*(rsphere/cos(thetarad))+(zc(2,:)*sin(thetarad))); %(-rsphere*tan(thetarad));
+
+
+  %    plot3(xc(2,:),yc(2,:),zc(2,:),'b')
+  %    sc=surf(xc,yc,zc);
+  %    set(sc,'facealpha',0.2,'edgealpha',0.1)
+
+  % now do the rotation around eta
+  T=[cos(etarad) sin(etarad);-sin(etarad) cos(etarad)];
+
+  for q=1:2
+    xtmp=xc(q,:);
+    ytmp=yc(q,:);
+    transformed=T*[xtmp;ytmp];
+    xc2(q,:)=transformed(1,:);
+    yc2(q,:)=transformed(2,:);
+  end
+  
+  
+  % finally do displacement
+  xc2=xc2+(xsc*cos(omegarad) - ysc*sin(omegarad));
+  yc2=yc2+zsc;
+  
+  sc2=surf(xc2,yc2,zc);
+  set(sc2,'facealpha',0.1,'edgealpha',0.2,'facecolor','g')
+  fill3(xc2(2,:),yc2(2,:),zc(2,:),'b')
+  a=xc2(2,:);b=yc2(2,:);
+  ip(:,:,n)=inpolygon(xx,yy,a,b)*n;
+  if 0
+    figure,clf
+    plot(a,b)
+    figure
+  end
+  i=imagesc(sort(unique(xx)),sort(unique(yy)),ip(:,:,n));
+  % drawnow
+
+end
+
+axis tight
+cameratoolbar
+shg
+
+
+%% generate ART projection files
+
+proj.eta=etarange;
+proj.theta=thetarange;
+proj.omega=omegarange;
+proj.projections=ip*100;
+proj.indices=1:size(proj.projections,3);
+
+% show the user the projections
+
+%vol_view(proj.projections,'clims',0,'plane','xy',...
+%  'hordisplay',[-floor(xdetsize/2),floor(xdetsize/2)],...
+%  'verdisplay',[-floor(xdetsize/2),floor(xdetsize/2)])
+
+
+%vol_view(vol,'clims',0,'plane','yz','hordisplay',[y1 y1+ny*pixsize],'verdisplay',[z1 z1+nz*pixsize])
+%vol_view(vol,'clims',0,'plane','zx','hordisplay',[z1 z1+nz*pixsize],'verdisplay',[x1 x1 + nx*pixsize])
+
+% now write out the projections:
+% omega - negative?
+
+nz=nq;
+parfilename='parfile.par';
+scanname='scanname';
+if testing==true
+  % write projections to disk
+  for n=proj.indices
+    fname=sprintf('%s%d',scanname,n);
+    sdt_write(fname,proj.projections(:,:,n),'float32');
+  end
+end
+lambda=[1] ; % 0.6 0.2 0.1
+
+
+xsi_angles= [90];
+delta_angles=[0];
+pixsize=sizepixels;
+disp('should theta = 2theta?')
+if 1
+  % reconstructed volume
+  % centre of sphere seems to be at y=-2???
+  if testing==true
+  x1=-.5;x2=.5;  % second horizontal dimenion
+  y1=-.5;y2=.5;  % distance from sample to detector of detector (omega 0)
+  z1=-.5;z2=.5;  % vertical dimension of detector
+  
+  %x1=x1+xsc; y1=y1+ysc;
+  %x2=x2+xsc; y2=y2+ysc;
+  xoff=xsc;
+  yoff=-ysc;
+  zoff=zsc;
+  x1=x1+xoff;x2=x2+xoff;
+  y1=y1+yoff;y2=y2+yoff;
+  z1=z1+zoff;z2=z2+zoff;
+  else
+  x1=-5;x2=5;  % second horizontal dimension
+  y1=-5;y2=5;  % distance from sample to detector of detector (omega 0)
+  z1=-5;z2=5;  % vertical dimension of detector
+  end
+
+if testing==true
+  voxsize=0.010;
+else
+  voxsize=0.10;
+end
+  % make these odd so the center voxel is really centred.
+  nx=((x2-x1)/voxsize)+1;
+  ny=((y2-y1)/voxsize)+1;
+  nz=((z2-z1)/voxsize)+1;
+
+  if testing==true
+    % draw the reconstructed volume
+    h_reconvol(1)=patch([x1 x2 x2 x1],[y1 y1 y2 y2],[z1 z1 z1 z1],'r');
+    h_reconvol(2)=patch([x1 x2 x2 x1],[y1 y1 y2 y2],[z2 z2 z2 z2],'r');
+    h_reconvol(3)=patch([x1 x1 x1 x1],[y1 y2 y2 y1],[z1 z1 z2 z2],'r');
+    h_reconvol(4)=patch([x2 x2 x2 x2],[y1 y2 y2 y1],[z1 z1 z2 z2],'r');
+    h_reconvol(5)=patch([x1 x2 x2 x1],[y1 y1 y1 y1],[z1 z1 z2 z2],'r');
+    h_reconvol(6)=patch([x1 x2 x2 x1],[y2 y2 y2 y2],[z1 z1 z2 z2],'r');
+    set(h_reconvol,'facealpha',.5)
+  end
+
+  disp('3D reconstruction')
+  gtART3D(scanname,parfilename,proj.indices,proj.omega,xsi_angles,delta_angles,proj.theta,proj.eta,...
+    lambda,length(lambda),pixsize,0,np,nq,0, ...
+    zdet+0,voxsize,z1,nz,x1,nx,y1,ny); %min(yy(:)),nz,min(xx(:)),np,min(xx(:)),nq);
+
+  disp('ART volume probably needs rotating')
+
+  %parameters.acq.bb(2)-1024,parameters.acq.bb(4),...
+  %  parameters.acq.bb(1)-1024,parameters.acq.bb(3),...
+  %  parameters.acq.bb(1)-1024,parameters.acq.bb(3));
+else
+  disp('Parallel beam reconstruction')
+  % working parallel reconstruction
+  gtMakeARTJob(scanname,parfilename,proj.indices,proj.omega,lambda,length(lambda),1,0,np,nq,0,z1-0,nz,1,np,1,nq)
+end
+
+%% run ART
+cmd=sprintf('rm %s_res*',scanname);
+system(cmd)
+%%
+cmd_rec_alg=gtGetARTCommand('rec_alg');
+cmd_seg2view=gtGetARTCommand('seg2view');
+
+
+cmd=sprintf('%s %s',cmd_rec_alg,parfilename);
+system(cmd);
+
+for n=1:length(lambda)
+  system(sprintf('%s %s_res0_%d',cmd_seg2view,scanname,n));
+end
+
+
+%% display the results
+vol=sdt_read(sprintf('%s_res0_%d',scanname,1));
+
+fprintf('Pixel size: %3.3f Voxel size: %3.3f \n',pixsize,voxsize);
+orthogonalslicer(vol,[1 1 1],gray,min(vol(:)),max(vol(:))+eps);
+fprintf('Volumen min: %3.3f max: %3.3f\n',min(vol(:)),max(vol(:)));
+figure(2)
+axis on
+figure(3)
+axis on
+figure(4)
+axis on
diff --git a/zUtil_ForwardProjection/fp_prepare.m b/zUtil_ForwardProjection/fp_prepare.m
new file mode 100755
index 0000000000000000000000000000000000000000..9d5eac66d3b64623f7ae0b85f11394c97fc574c3
--- /dev/null
+++ b/zUtil_ForwardProjection/fp_prepare.m
@@ -0,0 +1,8 @@
+ % load a grain.mat to get struct_ids
+ 
+ thetarange = Theta;
+ etarange = Eta;
+ omegarange = Omega;
+ 
+ numproj=length(thetarange)
+ fp
\ No newline at end of file
diff --git a/zUtil_ForwardProjection/gtForwardProject.m b/zUtil_ForwardProjection/gtForwardProject.m
new file mode 100755
index 0000000000000000000000000000000000000000..74bae2730d6c29f98dd474da2ad85c01632d32f2
--- /dev/null
+++ b/zUtil_ForwardProjection/gtForwardProject.m
@@ -0,0 +1,137 @@
+function [proj,difspot,bb]=gtForwardProject(gv,grain,parameters,index)
+% INPUTS:  
+% gv         binary 3D grain volume
+% grain      grain structure of the grain
+% parameters parameters structure
+% index      projection indices to be calculated
+% OUTPUTS:  
+% proj       2D projection on the detector...
+
+proj=zeros(parameters.acq.ydet,parameters.acq.xdet,max(index));
+
+dist=parameters.acq.dist/parameters.acq.pixelsize;   %rotation axis to detector distance
+
+for nr=index   %
+
+  
+  o=grain.omega(nr)+90;  % 
+  t=grain.theta(nr);
+  
+  e=-grain.eta(nr);   
+  
+  % step 1: rotate the grain volume 
+  gvr=zeros(size(gv));
+  for nz=1:size(gv,3)
+	if mean2(gv(:,:,nz))>0
+	  gvr(:,:,nz)=imrotate(gv(:,:,nz),-o,'crop');
+	end
+  end
+
+s=regionprops(bwlabeln(gvr));
+cen=s.Centroid;
+% step 2: forward project each pixel onto the detector
+voxind=find(gvr>0);
+n=[sind(2*t)*sind(e);sind(2*t)*cosd(e); -cosd(2*t)];  % direction of the diffracted beam in AREMIS coordinates (u,v,w)
+
+  for nv=1:length(voxind)
+	% transform voxel coordinates into the detector system - assuming the center of
+	% rotation in the center of the sample volume
+
+	%[y,x,z]=ind2sub(size(gvr),voxind(nv));   % sample system x and y axis are perpendicular to the z-rotation axis 
+	% u=  x-size(gvr,2)/2-0.5;
+	% v=  size(gvr,3)/2-z+0.5;
+	% w=  dist+y-size(gvr,1)/2-0.5;
+	
+	[x,y,z]=ind2sub(size(gvr),voxind(nv));   % sample BB system x and y axis are perpendicular to the z-rotation axis 
+	
+	u=  y-size(gvr,2)/2-0.5;
+	v=  size(gvr,3)/2-z+0.5;
+	w=  dist+x-size(gvr,1)/2-0.5; % old&reconstructable:  +x-size, data in /test
+	
+	
+	
+	% direct beam image
+	if 1
+	  Imx=u+parameters.acq.xdet/2+0.5;
+	  Imy=parameters.acq.ydet/2+0.5-v;
+
+	  fracx=Imx-floor(Imx);
+	  fracy=Imy-floor(Imy);
+
+	  Ix=floor(Imx);
+	  Iy=floor(Imy);
+
+	  proj(Iy,Ix,nr)=proj(Iy,Ix,nr)-(1-fracx)*(1-fracy);
+	  proj(Iy,Ix+1,nr)=proj(Iy,Ix+1,nr)-fracx*(1-fracy);
+	  proj(Iy+1,Ix,nr)=proj(Iy+1,Ix,nr)-(1-fracx)*fracy;
+	  proj(Iy+1,Ix+1,nr)=proj(Iy+1,Ix+1,nr)-fracx*fracy;
+	end % if
+	%now solve  w+ f*n(3)  = 0 and calculate intersection point on the detector
+
+	f=-w/n(3);
+	Pd=u+f*n(1);
+	Qd=v+f*n(2);
+
+	Imx=Pd+parameters.acq.rotx;
+	Imy=parameters.acq.ydet/2+0.5-Qd;
+
+	fracx=Imx-floor(Imx);
+	fracy=Imy-floor(Imy);
+
+	Ix=floor(Imx);
+	Iy=floor(Imy);
+	
+	if Ix<0 | Iy<0 | Ix>size(proj,2) | Iy>size(proj,1)
+	  disp('projection out of detector');
+	else
+	  proj(Iy,Ix,nr)=proj(Iy,Ix,nr)+(1-fracx)*(1-fracy);
+	  proj(Iy,Ix+1,nr)=proj(Iy,Ix+1,nr)+fracx*(1-fracy);
+	  proj(Iy+1,Ix,nr)=proj(Iy+1,Ix,nr)+(1-fracx)*fracy;
+	  proj(Iy+1,Ix+1,nr)=proj(Iy+1,Ix+1,nr)+fracx*fracy;
+	end % if
+  end  % for nv
+  
+% locate direct beam spot  
+%   u=  cen(1)-size(gvr,2)/2-0.5;
+%   v=  size(gvr,3)/2-cen(3)+0.5;
+%   Imx=u+parameters.acq.xdet/2+0.5;
+%   Imy=parameters.acq.ydet/2+0.5-v;
+%   
+%   marker=zeros(parameters.acq.ydet,parameters.acq.xdet);
+%   marker(round(Imy),round(Imx))=1;
+%   dir=imreconstruct(marker,proj(:,:,nr));
+%   
+%  a=regionprops(bwlabel(dir));
+  
+
+  %proj(:,:,nr)=fliplr(proj(:,:,nr));
+  
+  extspot=gtCrop(proj(:,:,nr),parameters.acq.bb);
+  name=sprintf('extspot%d',nr);
+  %sdt_write(name,extspot,'float32');
+  
+  
+  %remove direct beam spot
+  tmp=zeros(parameters.acq.bb(4),parameters.acq.bb(3));
+  difspot=gtPlaceSubImage(tmp,proj(:,:,nr),parameters.acq.bb(1), parameters.acq.bb(2));
+  
+  a=regionprops(bwlabel(difspot)); 
+ 
+  bb(nr,1)=ceil(a.BoundingBox(1));
+  bb(nr,2)=ceil(a.BoundingBox(2));
+  bb(nr,3)=a.BoundingBox(3);
+  bb(nr,4)=a.BoundingBox(4);
+
+  bb(nr,5)=round(a.Centroid(1));
+  bb(nr,6)=round(a.Centroid(2));
+
+  difspot=gtCrop(proj(:,:,nr),bb(nr,1:4));
+  
+  name=sprintf('test3/difspot%d',nr);
+  tmp=zeros(size(difspot)+200);
+  difspot=gtPlaceSubImage(difspot,tmp,101,101);
+  sdt_write(name,difspot,'float32');
+  
+end % for nr
+
+save test3/lastrun gv proj bb grain parameters
diff --git a/zUtil_ForwardProjection/gtForwardProject2.m b/zUtil_ForwardProjection/gtForwardProject2.m
new file mode 100755
index 0000000000000000000000000000000000000000..db3f3407f393e03a22412639a6c32627548349a6
--- /dev/null
+++ b/zUtil_ForwardProjection/gtForwardProject2.m
@@ -0,0 +1,140 @@
+function [proj,difspot,bb]=gtForwardProject2(gv,grain,parameters,index)
+% INPUTS:  
+% gv         binary 3D grain volume
+% grain      grain structure of the grain
+% parameters parameters structure
+% index      projection indices to be calculated
+% OUTPUTS:  
+% proj       2D projection on the detector...
+
+proj=zeros(parameters.acq.ydet,parameters.acq.xdet,max(index));
+
+dist=parameters.acq.dist/parameters.acq.pixelsize;   %rotation axis to detector distance
+
+for nr=index   %
+  
+
+  o=grain.omega(nr);  % changed to -
+  t=grain.theta(nr);
+  e=grain.eta(nr);   % changed to -
+
+  % step 1: rotate the grain volume
+  gvr=zeros(size(gv));
+  for nz=1:size(gv,3)
+    if mean2(gv(:,:,nz))>0
+      gvr(:,:,nz)=imrotate(gv(:,:,nz),-o,'crop');
+    end
+  end
+
+  s=regionprops(bwlabeln(gvr));
+  cen=s.Centroid;
+  % step 2: forward project each pixel onto the detector
+  voxind=find(gvr>0);
+  n=[sind(2*t)*sind(-e);sind(2*t)*cosd(e); -cosd(2*t)];  % direction of the diffracted beam in AREMIS coordinates (u,v,w)
+
+  for nv=1:length(voxind)
+    % transform voxel coordinates into the detector system - assuming the center of
+    % rotation in the center of the sample volume
+
+    %[y,x,z]=ind2sub(size(gvr),voxind(nv));   % sample system x and y axis are perpendicular to the z-rotation axis
+    % u=  x-size(gvr,2)/2-0.5;
+    % v=  size(gvr,3)/2-z+0.5;
+    % w=  dist+y-size(gvr,1)/2-0.5;
+
+%     [x,y,z]=ind2sub(size(gvr),voxind(nv));   % sample BB system x and y axis are perpendicular to the z-rotation axis
+% 
+%     u=  y-size(gvr,2)/2-0.5;
+%     v=  size(gvr,3)/2-z+0.5;
+%     w=  dist+x-size(gvr,1)/2-0.5;
+
+    [y,x,z]=ind2sub(size(gvr),voxind(nv));   % sample system x and y axis are perpendicular to the z-rotation axis
+      u=  -(x-size(gvr,2)/2-0.5);
+      v=  -(z-size(gvr,3)/2-0.5);
+      w=  -(y-size(gvr,1)/2-0.5)+dist;
+
+
+    % direct beam image
+    if 1
+      Imx= u+parameters.acq.xdet/2+0.5;
+      Imy=-v+parameters.acq.ydet/2+0.5;
+
+      fracx=Imx-floor(Imx);
+      fracy=Imy-floor(Imy);
+
+      Ix=floor(Imx);
+      Iy=floor(Imy);
+
+      proj(Iy,Ix,nr)=proj(Iy,Ix,nr)-(1-fracx)*(1-fracy);
+      proj(Iy,Ix+1,nr)=proj(Iy,Ix+1,nr)-fracx*(1-fracy);
+      proj(Iy+1,Ix,nr)=proj(Iy+1,Ix,nr)-(1-fracx)*fracy;
+      proj(Iy+1,Ix+1,nr)=proj(Iy+1,Ix+1,nr)-fracx*fracy;
+    end % if
+    %now solve  w+ f*n(3)  = 0 and calculate intersection point on the detector
+
+    f=-w/n(3); %Dw=0=w+f*n(3)
+    Du=u+f*n(1);
+    Dv=v+f*n(2);
+
+    Imx= Du+parameters.acq.xdet/2+0.5;
+    Imy=-Dv+parameters.acq.ydet/2+0.5;
+
+    fracx=Imx-floor(Imx);
+    fracy=Imy-floor(Imy);
+
+    Ix=floor(Imx);
+    Iy=floor(Imy);
+
+    if Ix<0 || Iy<0 || Ix>size(proj,2) || Iy>size(proj,1)
+      disp('projection out of detector');
+    else
+      proj(Iy,Ix,nr)=proj(Iy,Ix,nr)+(1-fracx)*(1-fracy);
+      proj(Iy,Ix+1,nr)=proj(Iy,Ix+1,nr)+fracx*(1-fracy);
+      proj(Iy+1,Ix,nr)=proj(Iy+1,Ix,nr)+(1-fracx)*fracy;
+      proj(Iy+1,Ix+1,nr)=proj(Iy+1,Ix+1,nr)+fracx*fracy;
+    end % if
+  end  % for nv
+
+  %proj(:,:,nr)=fliplr(proj(:,:,nr));  %  in order to compare to experimental images...
+  
+  % locate direct beam spot
+  %   u=  cen(1)-size(gvr,2)/2-0.5;
+  %   v=  size(gvr,3)/2-cen(3)+0.5;
+  %   Imx=u+parameters.acq.xdet/2+0.5;
+  %   Imy=parameters.acq.ydet/2+0.5-v;
+  %
+  %   marker=zeros(parameters.acq.ydet,parameters.acq.xdet);
+  %   marker(round(Imy),round(Imx))=1;
+  %   dir=imreconstruct(marker,proj(:,:,nr));
+  %
+  %  a=regionprops(bwlabel(dir));
+
+  extspot=gtCrop(proj(:,:,nr),parameters.acq.bb);
+  name=sprintf('extspot%d',nr);
+  sdt_write(name,extspot,'float32');
+
+
+  %remove direct beam spot
+  tmp=zeros(parameters.acq.bb(4),parameters.acq.bb(3));
+  difspot=gtPlaceSubImage(tmp,proj(:,:,nr),parameters.acq.bb(1), parameters.acq.bb(2));
+  % remove flip - just a test:
+  % difspot=fliplr(difspot);
+  a=regionprops(bwlabel(difspot));
+
+  bb(nr,1)=ceil(a.BoundingBox(1));
+  bb(nr,2)=ceil(a.BoundingBox(2));
+  bb(nr,3)=a.BoundingBox(3);
+  bb(nr,4)=a.BoundingBox(4);
+
+  bb(nr,5)=round(a.Centroid(1));
+  bb(nr,6)=round(a.Centroid(2));
+
+  difspot=gtCrop(proj(:,:,nr),bb(nr,1:4));
+
+  name=sprintf('test2/difspot%d',nr);
+  tmp=zeros(size(difspot)+200);
+  difspot=gtPlaceSubImage(difspot,tmp,101,101);
+  sdt_write(name,difspot,'float32');
+
+end % for nr
+
+save test2/lastrun gv proj bb grain parameters
diff --git a/zUtil_ForwardProjection/gtGenFP.m b/zUtil_ForwardProjection/gtGenFP.m
new file mode 100755
index 0000000000000000000000000000000000000000..52af6c7e7caa6bd5f37ff532622817a68e57baf6
--- /dev/null
+++ b/zUtil_ForwardProjection/gtGenFP.m
@@ -0,0 +1,48 @@
+function im=gtGenFP(theta,eta)
+
+
+  zdet=-5;
+  xdetsize=11;
+  ydetsize=11;
+
+  range=linspace(-floor(xdetsize/2),floor(xdetsize/2),2048);
+  [xx,yy]=meshgrid(range);
+
+
+  rsphere=1;
+  xsc=0;ysc=0;zsc=0;
+
+
+  [xs,ys,zs]=sphere(20);
+  xs=(xs*rsphere)+xsc;
+  ys=(ys*rsphere)+ysc;
+  zs=(zs*rsphere)+zsc;
+
+  thetarad=theta*pi/180;
+  etarad=eta*pi/180;
+
+  % create unit cylinder
+  [xc,yc,zc]=cylinder;
+  zc(2,:)=zdet;  % move bottom of cylinder to detector plane
+  zc(1,:)=zc(1,:)+rsphere;
+
+  xdist=(rsphere/cos(thetarad))-rsphere;
+
+  xc(1,:)=(xc(1,:)*rsphere/cos(thetarad))+(zc(1,:)*sin(thetarad));
+  xc(2,:)=(xc(2,:)*(rsphere/cos(thetarad))+(zc(2,:)*sin(thetarad))); %(-rsphere*tan(thetarad));
+
+  % now do the rotation around eta
+  T=[cos(etarad) sin(etarad);-sin(etarad) cos(etarad)];
+
+  for n=1:2
+    xtmp=xc(n,:);
+    ytmp=yc(n,:);
+    transformed=T*[xtmp;ytmp];
+    xc2(n,:)=transformed(1,:);
+    yc2(n,:)=transformed(2,:);
+  end
+  a=xc2(2,:);b=yc2(2,:);
+  im=inpolygon(xx,yy,a,b);
+
+
+imagesc(range,range,im)
diff --git a/zUtil_ForwardProjection/gtTrLabToSamBB.m b/zUtil_ForwardProjection/gtTrLabToSamBB.m
new file mode 100755
index 0000000000000000000000000000000000000000..9a2af60f51b3e97e20e1411d9fafc5ccd002cbb4
--- /dev/null
+++ b/zUtil_ForwardProjection/gtTrLabToSamBB.m
@@ -0,0 +1,9 @@
+% function [sambbX,sambbY,sambbZ]=gtTrLabToSamBB(sambbX, sambbY,sambbZ,parameters)
+% Transform from the SampleBoundingBoxCooridinates (i,j,k) coordinates of
+% a voxel into the Laboratory coordinatesystem
+
+function [sambbX,sambbY,sambbZ]=gtTrLabToSamBB(labX, labY, labZ,parameters)
+  sambbX=parameters.acq.bb(3)/2-labX+0.5;
+  sambbY=parameters.acq.bb(3)/2-labY+0.5;
+  sambbZ=parameters.acq.bb(4)/2-labZ+0.5;
+end
diff --git a/zUtil_ForwardProjection/gtTrSamBBToLab.m b/zUtil_ForwardProjection/gtTrSamBBToLab.m
new file mode 100755
index 0000000000000000000000000000000000000000..798f4f05f9d2e8d31ab2ddc100607f82752f0067
--- /dev/null
+++ b/zUtil_ForwardProjection/gtTrSamBBToLab.m
@@ -0,0 +1,9 @@
+% function [labX,labY,labZ]=gtTrSamBBToLab(sambbX, sambbY,sambbZ,parameters)
+% Transform from the SampleBoundingBoxCooridinates (i,j,k) coordinates of
+% a voxel into the Laboratory coordinatesystem
+
+function [labX,labY,labZ]=gtTrSamBBToLab(sambbX, sambbY, sambbZ,parameters)
+  labX=parameters.acq.bb(3)/2-sambbx+0.5;
+  labY=parameters.acq.bb(3)/2-sambby+0.5;
+  labZ=parameters.acq.bb(4)/2-sambbz+0.5;
+end
diff --git a/zUtil_ForwardProjection/jacobs_ray3d.m b/zUtil_ForwardProjection/jacobs_ray3d.m
new file mode 100755
index 0000000000000000000000000000000000000000..160fe17bd4c8cff8931172ae5d11ad48c5980d1e
--- /dev/null
+++ b/zUtil_ForwardProjection/jacobs_ray3d.m
@@ -0,0 +1,39 @@
+function jacobs_ray3d = jacobs_ray3d(im_size, p1_x, p1_y, p1_z, p2_x, p2_y, p2_z, voxel_size)
+%JACOBS_RAY3D   Ray tracing through voxel grid
+%   J = JACOBS_RAY3D( im_size, p1_x, p1_y, p1_z, p2_x, p2_y, p2_z,
+%   voxel_size) returns a sparse vector with entries in positions
+%   corresponding to weighted intersections of a line, with the grid. The
+%   positions in the vector corresponds to a 3d matlab array reshaped to a
+%   vector using RESHAPE( ARRAY, [], 1)
+%
+%   im_size is the number of voxels along one dimension of the 3d array.
+%   p1 and p2 contain coordinates of the starting and end point,
+%   respectively.
+%   relative a coordinate system with its origin in the centre of the voxel
+%   grid.
+%   voxel size is the size (length units) of each voxel in the grid.
+%
+%   the weights are fractions of the total line length
+%
+%   to calculate radiographs, calculate the inner product of J with a
+%   vector containing the volume elements. ( DOT(J, X_VEC), where X_VEC =
+%   RESHAPE(X, [], 1)  )
+
+
+% jacobs_ray3d
+% Calculates intersection lengths of a line with a voxel grid
+% Implementation of algorithm described by F. Jacobs et.al.
+% 
+% F. Jacobs, E. Sundermann, B. De Sutter, M. Christiaens and I. Lemahieu, ["A Fast
+% Algorithm to Calculate the Exact Radiological Path through a Pixel or Voxel
+% Space"
+% Journal of Computing and Information Technology - CIT 6 1998, 1, pp 89-94]
+% 
+% Written by David Szotten 2005-2006
+% D.Szotten@student.manchester.ac.uk
+% 
+% Copyright (c) The University of Manchester 2006
+
+jacobs_ray3d = jacobs_ray3d_c( im_size, p1_x, p1_y, p1_z, p2_x, p2_y, p2_z, voxel_size );
+
+end
diff --git a/zUtil_ForwardProjection/jacobs_ray3d_c.c b/zUtil_ForwardProjection/jacobs_ray3d_c.c
new file mode 100755
index 0000000000000000000000000000000000000000..431f074ec8707f091126c88443e463095e8e220c
--- /dev/null
+++ b/zUtil_ForwardProjection/jacobs_ray3d_c.c
@@ -0,0 +1,203 @@
+/* jacobs_ray3d
+ Calculates intersection lengths of a line with a voxel grid
+ Implementation of algorithm described by F. Jacobs et.al.
+ 
+ F. Jacobs, E. Sundermann, B. De Sutter, M. Christiaens and I. Lemahieu, ["A Fast
+ Algorithm to Calculate the Exact Radiological Path through a Pixel or Voxel
+ Space"
+ Journal of Computing and Information Technology - CIT 6 1998, 1, pp 89-94]
+ 
+ Written by David Szotten 2005-2006
+ D.Szotten@student.manchester.ac.uk
+ 
+ Copyright (c) The University of Manchester 2006 */
+
+
+#include <mex.h>
+#include <math.h>
+#include <matrix.h>
+#include <stdlib.h>
+
+
+void jacobs_ray_3d(int im_size, double *start, double *end, int *ray_index, double *ray_data, int *n_entries, 
+		  double voxel_size);
+
+
+
+
+#define MINX(x,y) ((x) < (y) ? (x) : (y))
+#define MAXX(x,y) ((x) > (y) ? (x) : (y))
+
+#define PRECISION 0.00000001
+
+void sort_and_set(int *tmp_arr_index, double *tmp_arr_data, int n_entries, double *pr ,mwIndex *ir, mwIndex *jc);
+void qsort_indexed_list(int *index, double *values, int l, int r);
+void swop_dbl(double *a, double *b);
+void swop_int(int *a, int *b);
+
+void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+	/*check number of arguments */
+	if(nrhs != 8) {
+		mexWarnMsgTxt("Eight inputs required. Aborting");
+		return;
+		}
+	else if(nlhs > 1) {
+		mexWarnMsgTxt("Too many output arguments. Aborting");
+		return;
+	}
+
+	/*check the arguments */
+	if(!(mxIsDouble(prhs[0]) && mxGetScalar(prhs[0]) > 0)) {
+		mexWarnMsgTxt("Side length must be a positive integer");
+		return;
+		}
+
+
+	int im_size;
+	double p1_x, p1_y, p1_z, p2_x, p2_y, p2_z, voxel_size;
+	double start[3], end[3];
+
+
+
+
+
+	/*read variables */
+	im_size=(int) mxGetScalar(prhs[0]);
+	start[0]=p1_x=mxGetScalar(prhs[1]);
+	start[1]=p1_y=mxGetScalar(prhs[2]);
+	start[2]=p1_z=mxGetScalar(prhs[3]);
+	end[0]=p2_x=mxGetScalar(prhs[4]);
+	end[1]=p2_y=mxGetScalar(prhs[5]);
+	end[2]=p2_z=mxGetScalar(prhs[6]);
+	voxel_size = mxGetScalar(prhs[7]);
+
+	/*allocate memory for the matrix. 3*im_size entries should be enough */
+	/* storing as column vector uses less space (due to implementation of sparse) */
+/*	plhs[0] = mxCreateSparse(im_size*im_size*im_size, 1, 3*im_size ,mxREAL); */
+  plhs[0] = mxCreateSparse((mwSize)(im_size*im_size*im_size),1,3*im_size,mxREAL);
+
+	double *output_matrix_pr;
+	mwIndex *output_matrix_ir, *output_matrix_jc;
+
+	output_matrix_pr = mxGetPr(plhs[0]);
+    	output_matrix_ir = mxGetIr(plhs[0]);
+    	output_matrix_jc = mxGetJc(plhs[0]);
+
+
+	/* to store data before sorting (for sparse matrix) */
+	int *tmp_arr_index;
+	double *tmp_arr_data;
+	int tmp_counter;
+
+	tmp_arr_index=mxCalloc(im_size*im_size*im_size,sizeof(int));
+	tmp_arr_data=mxCalloc(im_size*im_size*im_size,sizeof(double));
+
+	if (tmp_arr_index == NULL || tmp_arr_data == NULL ) {
+		mexWarnMsgTxt("Not enough memory!");
+		return;
+	}
+
+
+	jacobs_ray_3d(im_size, start, end, tmp_arr_index, tmp_arr_data, &tmp_counter, voxel_size);
+	/*coor_to_voxel(im_size, tmp_arr_index_i, tmp_arr_index_j, tmp_arr_index, &tmp_counter);*/
+	
+	/*int tmp;
+	for(tmp=0;tmp<tmp_counter;tmp++)
+		mexPrintf("%d: %f\n", tmp_arr_index[tmp], tmp_arr_data[tmp]);*/
+
+	sort_and_set(tmp_arr_index, tmp_arr_data, tmp_counter, output_matrix_pr, output_matrix_ir, output_matrix_jc);
+}
+
+
+void sort_and_set(int *tmp_arr_index, double *tmp_arr_data, int n_entries, double *pr ,mwIndex *ir, mwIndex *jc)
+{
+	 /* if n_entries == 0, store empty matrix */
+	 /*mexPrintf("sorted, entries: %d\n", n_entries);/**/
+
+	if(n_entries != 0)
+		qsort_indexed_list(tmp_arr_index, tmp_arr_data, 1, n_entries);
+
+	int n, pos;
+
+	jc[0]=0;
+	jc[1]=n_entries-1*0;
+	pos=0;
+	for(n=0; n<n_entries-1*0; n++) {
+		if(tmp_arr_data[n] != 0) {
+			ir[pos]=tmp_arr_index[n];
+			pr[pos++]=tmp_arr_data[n];
+			/*mexPrintf("n: %d, ir: %d, pr: %f\n", n, ir[n], pr[n]);/**/
+		}
+		else
+			jc[1]--;
+	}
+
+/*	int m;
+	int o=0;
+	for(n=0; n<36; n++) {
+		jc[n]=o;
+		for(m=0; m<n_entries-1;m++)
+			if(n==tmp_arr_index[m]) {
+				ir[o]=0*n;
+				pr[o++]=tmp_arr_data[m];
+				mexPrintf("n: %d, m: %d, o: %d, ir: %d, pr: %f\n", n, m, o, ir[o-1], pr[o-1]);
+				}
+		}
+	jc[36]=o;
+*/
+
+}
+
+
+void qsort_indexed_list(int *index, double *values, int l, int r)
+/* to sort the entries in index ascending, and entries in values to match
+[1 3 2                  [1 2 3
+   a b c]    becomes     a c b] */
+{
+    /*mexPrintf("qsort, left: %d, right: %d \n", l, r);*/
+
+    int l1, r1;
+
+    if (l < r) {
+	l1=l;
+	r1=r;
+
+	do {
+	    while (l1 < r && index[l1-1] <= index[l-1])
+		l1++;
+	    while(l < r1 && index[r1-1] >= index[l-1])
+		r1--;
+	    if (l1 < r1) {
+		swop_int( &index[l1-1], &index[r1-1]);
+		swop_dbl( &values[l1-1], &values[r1-1]);
+	    }
+	} while (l1 < r1);
+
+	swop_int( &index[l-1], &index[r1-1]);
+	swop_dbl( &values[l-1], &values[r1-1]);
+
+	qsort_indexed_list(index, values, l, r1-1);
+	qsort_indexed_list(index, values, r1+1, r);
+    }
+}
+
+
+void swop_int(int *a, int *b)
+/* swops the values of a and b */
+{
+    double t;
+    t=*a;
+    *a=*b;
+    *b=t;
+}
+
+void swop_dbl(double *a, double *b)
+/* swops the values of a and b */
+{
+    double t;
+    t=*a;
+    *a=*b;
+    *b=t;
+}
+
diff --git a/zUtil_ForwardProjection/jacobs_rays.c b/zUtil_ForwardProjection/jacobs_rays.c
new file mode 100755
index 0000000000000000000000000000000000000000..828e196e9b6d19460fec47e1cebc37a15cf2ff84
--- /dev/null
+++ b/zUtil_ForwardProjection/jacobs_rays.c
@@ -0,0 +1,817 @@
+/* jacobs_ray_3d
+% void jacobs_ray_3d(int im_size, double *start, double *end, int *ray_index, double *ray_data, int *n_entries)
+%
+% implementation of algorithm by Jacobs et.al (modification of Siddon's)
+%
+% int im_size: size of grid
+% double start[3]: x,y,z coordinates for starting point of ray
+% double end[3]
+% int ray_index[n_entries]: stores voxel numbers hit by ray
+% double ray_data[n_entries]: stores weights corresponding to relative length of ray in a given voxel
+% int n_entries: counts number of voxels hit by ray
+%
+%
+% takes coordinates of points relative origin in centre of grid, and
+% translates to correspond to algorithm
+%
+%
+% david szotten
+% august 2005
+*/
+
+#include <math.h>
+#include <matrix.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "reconstruct_phototom.h"
+
+
+/*#ifndef MIN3X
+	#define MIN3X(x,y,z) ((x) < (y) ? MINX((x),(z)) : MINX((y),(z)) )
+	#define MAX3X(x,y,z) ((x) > (y) ? MAXX((x),(z)) : MAXX((y),(z)) )
+#endif*/
+
+
+int equal_to_precision(double x, double y, double precision);
+double alpha_fn(int n, double p1, double p2, double b, double d);
+double p(double alpha, double p1, double p2);
+double phi(double alpha, double p1, double p2, double b, double d);
+
+double min_dbl(double a, double b) { return a < b ? a : b; };
+double max_dbl(double a, double b) { return a > b ? a : b; };
+
+double min3_dbl(double a, double b, double c) { return a < b ? min_dbl(a,c) : min_dbl(b,c); };
+double max3_dbl(double a, double b, double c) { return a > b ? max_dbl(a,c) : max_dbl(b,c); };
+
+
+
+void jacobs_ray_3d(int im_size, double *start, double *end, int *ray_index, double *ray_data, int *n_entries,
+		   double voxel_size)
+{
+
+  int testing = 0;
+/*  if((*n_entries)==830530) {
+	  printf(":jacobs_ray_3d");fflush(NULL);
+	  testing = 0*1;
+  }
+*/
+
+	int N_x, N_y, N_z, N_p;
+	double b_x, b_y, b_z, d_x, d_y, d_z, d_conv; /*, d_conv_alpha; */
+	double p1_x, p1_y, p1_z, p2_x, p2_y, p2_z;
+
+	int i,j,k;
+
+	double alpha_x_min, alpha_y_min, alpha_z_min, alpha_x_max, alpha_y_max, 
+alpha_z_max, alpha_min, alpha_max, alpha_x, alpha_y, alpha_z, alpha_c;
+	double alpha_x_u, alpha_y_u, alpha_z_u;
+	double l_ij;
+	int i_min, j_min, k_min, i_max, j_max, k_max, n_count, i_u, j_u, k_u;
+
+	*n_entries=0;
+	
+	p1_x = start[0];
+	p1_y = start[1];
+	p1_z = start[2];
+	p2_x = end[0];
+	p2_y = end[1];
+	p2_z = end[2];
+
+	b_x=-im_size*voxel_size/2;
+	b_y=-im_size*voxel_size/2;
+	b_z=-im_size*voxel_size/2;
+
+	d_x=voxel_size;
+	d_y=voxel_size;
+	d_z=voxel_size;
+
+	/* use total lengh=alpha_max-alpha_min instead, to get everage, not sum. */
+	/* moving back to original d_conv*/
+	d_conv=sqrt( (p1_x-p2_x)*(p1_x-p2_x) + (p1_y-p2_y)*(p1_y-p2_y) +
+(p1_z-p2_z)*(p1_z-p2_z));/**/
+
+	N_x=im_size+1;
+	N_y=im_size+1;
+	N_z=im_size+1;
+
+	/* rewrite in terms of jacob2d*/
+	if (equal_to_precision(p1_x,p2_x,PRECISION)==1) {
+    		i=(int) floor( phi(0, p1_x, p2_x, b_x, d_x));
+    		/* or ceil? */
+
+    		/*may as well assume ray starts and ends outside grid as this will be
+    		the case whenever this is used */
+		if (0 <= i && i <= im_size-1) {
+
+			int *ray2d_index_j;
+			int *ray2d_index_k;
+			double *ray2d_data;
+			int ray2d_n_entries;
+			
+			/*ray2d_index_j=mxCalloc( im_size*3, sizeof(int));
+			ray2d_index_k=mxCalloc( im_size*3, sizeof(int));
+			ray2d_data=mxCalloc( im_size*3,sizeof(double));/**/
+			
+			ray2d_index_j=malloc( im_size*3* sizeof(int));
+			ray2d_index_k=malloc( im_size*3* sizeof(int));			
+			ray2d_data=calloc( im_size*3, sizeof(double));/**/
+			if(testing == 1)
+			  printf(".");fflush(NULL);
+			
+			if (ray2d_index_j == NULL || ray2d_index_k == NULL || ray2d_data == NULL ) {
+				/*mexWarnMsgTxt("Not enough memory!");*/
+				printf("Error");fflush(NULL);/**/
+				return;
+			}
+
+			if(testing == 1)
+			  printf("running 2d...");fflush(NULL);
+
+			jacobs_ray_2d(im_size, p1_y, p1_z, p2_y, p2_z, ray2d_index_j, ray2d_index_k,
+				      ray2d_data, &ray2d_n_entries, voxel_size);
+			
+			if(testing == 1)
+			  printf("putting in place...");fflush(NULL);
+			
+			/* loop through entries in ray */
+			while (ray2d_n_entries > 0) {
+			  ray_index[(*n_entries)] = ray2d_index_k[ray2d_n_entries-1]*im_size*im_size +
+			    ray2d_index_j[ray2d_n_entries-1]*im_size + i;
+			  ray_data[(*n_entries)++] = ray2d_data[(ray2d_n_entries--) -1];
+			}
+			
+			if(ray2d_index_j != NULL)
+			  /*mxFree(ray2d_index_j);/**/
+			  free(ray2d_index_j);/**/
+			if(ray2d_index_k != NULL)
+			  /*mxFree(ray2d_index_k);/**/
+			  free(ray2d_index_k);/**/
+			if(ray2d_data != NULL)
+			  /*mxFree(ray2d_data);/**/
+			  free(ray2d_data);/**/
+			
+		}
+		/* else  leave empty */
+
+		/*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, jacobs_ray);*/
+
+		if(testing == 1)
+		  printf("returns here (3)");fflush(NULL);		
+		return;
+	}
+
+	else if (equal_to_precision(p1_y,p2_y,PRECISION)==1) {
+		j=(int) floor( phi(0, p1_y, p2_y, b_y, d_y));
+		/* or ceil? */
+
+		/*may as well assume ray starts and ends outside grid as this will be
+    		%the case whenever this is used */
+		if (0 <= j && j <= im_size-1) {
+
+			int *ray2d_index_i;
+			int *ray2d_index_k;
+			double *ray2d_data;
+			int ray2d_n_entries;
+
+/*			ray2d_index_i=mxCalloc( im_size*3, sizeof(int));
+			ray2d_index_k=mxCalloc( im_size*3, sizeof(int));
+			ray2d_data=mxCalloc( im_size*3,sizeof(double));*/
+
+			ray2d_index_i=calloc( im_size*3, sizeof(int));
+			ray2d_index_k=calloc( im_size*3, sizeof(int));
+			ray2d_data=calloc( im_size*3,sizeof(double));
+
+
+			if (ray2d_index_i == NULL || ray2d_index_k == NULL || ray2d_data == NULL ) {
+				/*mexWarnMsgTxt("Not enough memory!");/**/
+				printf("Error");
+				return;
+			}
+
+			jacobs_ray_2d(im_size, p1_x, p1_z, p2_x, p2_z, ray2d_index_i, ray2d_index_k,
+				      ray2d_data, &ray2d_n_entries, voxel_size);
+
+			/* loop through entries in ray */
+			while (ray2d_n_entries > 0) {
+				ray_index[(*n_entries)] = ray2d_index_k[ray2d_n_entries-1]*im_size*im_size + 
+				  j*im_size + ray2d_index_i[ray2d_n_entries-1];
+				ray_data[(*n_entries)++] = ray2d_data[(ray2d_n_entries--)-1];
+			}
+
+			if(ray2d_index_i != NULL)
+			  free(ray2d_index_i);
+			if(ray2d_index_k != NULL)
+			  free(ray2d_index_k);
+			if(ray2d_data != NULL)
+			  free(ray2d_data);
+		}
+
+		/* else  leave empty */
+
+
+		/*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, jacobs_ray);*/
+		if(testing == 1)
+		  printf("returns here (4)");fflush(NULL);
+		return;
+	}
+
+	else if (equal_to_precision(p1_z,p2_z,PRECISION)==1) {
+		k=(int) floor( phi(0, p1_z, p2_z, b_z, d_z));
+		
+		/* or ceil? */
+
+		/*may as well assume ray starts and ends outside grid as this will be
+	    	%the case whenever this is used */
+		if (0 <= k && k <= im_size-1) {
+
+			int *ray2d_index_i;
+			int *ray2d_index_j;
+			double *ray2d_data;
+			int ray2d_n_entries;
+
+			ray2d_index_i=calloc( im_size*3, sizeof(int));
+			ray2d_index_j=calloc( im_size*3, sizeof(int));
+			ray2d_data=calloc( im_size*3,sizeof(double));
+
+			if (ray2d_index_i == NULL || ray2d_index_j == NULL || ray2d_data == NULL ) {
+				/*mexWarnMsgTxt("Not enough memory!");*/
+				printf("Error");
+				return;
+			}
+
+			jacobs_ray_2d(im_size, p1_x, p1_y, p2_x, p2_y, ray2d_index_i, ray2d_index_j, 
+				      ray2d_data, &ray2d_n_entries, voxel_size);
+
+			/* loop through entries in ray */
+			while (ray2d_n_entries > 0) {
+				ray_index[(*n_entries)] = k*im_size*im_size + 
+ray2d_index_j[ray2d_n_entries-1]*im_size + ray2d_index_i[ray2d_n_entries-1];
+				ray_data[(*n_entries)++] = ray2d_data[(ray2d_n_entries--) -1];
+			}
+
+			if(ray2d_index_i != NULL)
+			  free(ray2d_index_i);
+			if(ray2d_index_j != NULL)
+			  free(ray2d_index_j);
+			if(ray2d_data != NULL)
+			  free(ray2d_data);		
+}
+		
+		/* else leave empty */
+
+		/*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, jacobs_ray);*/
+		if(testing == 1)
+		  printf("returns here");fflush(NULL);
+
+		return;
+	}
+
+	/* x,y,z all different 1-2 */
+	else {
+	/*mexWarnMsgTxt("Not using 2d");/**/
+
+		alpha_x_min=min_dbl(alpha_fn(0, p1_x, p2_x, b_x, d_x), alpha_fn(N_x-1, p1_x, 
+p2_x, b_x, d_x));
+    		alpha_x_max=max_dbl(alpha_fn(0, p1_x, p2_x, b_x, d_x), alpha_fn(N_x-1, p1_x, 
+p2_x, b_x, d_x));
+
+    		alpha_y_min=min_dbl(alpha_fn(0, p1_y, p2_y, b_y, d_y), alpha_fn(N_y-1, p1_y, 
+p2_y, b_y, d_y));
+    		alpha_y_max=max_dbl(alpha_fn(0, p1_y, p2_y, b_y, d_y), alpha_fn(N_y-1, p1_y, 
+p2_y, b_y, d_y));
+
+    		alpha_z_min=min_dbl(alpha_fn(0, p1_z, p2_z, b_z, d_z), alpha_fn(N_z-1, p1_z, 
+p2_z, b_z, d_z));
+    		alpha_z_max=max_dbl(alpha_fn(0, p1_z, p2_z, b_z, d_z), alpha_fn(N_z-1, p1_z, 
+p2_z, b_z, d_z));
+
+    		alpha_min=max3_dbl(alpha_x_min, alpha_y_min, alpha_z_min);
+    		alpha_max=min3_dbl(alpha_x_max, alpha_y_max, alpha_z_max);
+
+		if(testing == 1)
+		  printf("get here");fflush(NULL);
+
+		if (alpha_min < alpha_max) {
+
+			/* use total lengh=alpha_max-alpha_min instead, to get everage, not sum. */
+			/* d_conv_alpha=alpha_max-alpha_min;/**/
+
+    			if (p1_x < p2_x) {
+        			if (equal_to_precision(alpha_min,alpha_x_min,PRECISION)==1)
+            				i_min=1;
+        			else
+            				i_min = (int) ceil(phi(alpha_min, p1_x, p2_x, b_x, d_x));
+
+			        if (equal_to_precision(alpha_max,alpha_x_max,PRECISION)==1)
+			            i_max = N_x - 1;
+        			else
+            				i_max = (int) floor( phi(alpha_max, p1_x, p2_x, b_x, d_x));
+
+				alpha_x=alpha_fn(i_min, p1_x, p2_x, b_x, d_x);
+	    		}
+
+    			else {
+        			if (equal_to_precision(alpha_min,alpha_x_min,PRECISION)==1)
+	            			i_max=N_x-2;
+        			else
+	            			i_max = (int) floor(phi(alpha_min, p1_x, p2_x, b_x, d_x));
+
+		        	if (equal_to_precision(alpha_max,alpha_x_max,PRECISION)==1)
+	            			i_min = 0;
+        			else
+	            			i_min = (int) ceil( phi(alpha_max, p1_x, p2_x, b_x, d_x));
+
+				alpha_x=alpha_fn(i_max, p1_x, p2_x, b_x, d_x);
+			}
+
+
+    			if (p1_y < p2_y) {
+        			if (equal_to_precision(alpha_min,alpha_y_min,PRECISION)==1)
+            				j_min=1;
+        			else
+            				j_min = (int) ceil(phi(alpha_min, p1_y, p2_y, b_y, d_y));
+
+
+        			if (equal_to_precision(alpha_max, alpha_y_max,PRECISION)==1)
+        				j_max = N_y - 1;
+        			else
+            				j_max = (int) floor( phi(alpha_max, p1_y, p2_y, b_y, d_y));
+
+				alpha_y=alpha_fn(j_min, p1_y, p2_y, b_y, d_y);
+			}
+
+    			else {
+
+        			if (equal_to_precision(alpha_min,alpha_y_min,PRECISION)==1)
+            				j_max=N_y-2;
+        			else
+            				j_max = (int) floor(phi(alpha_min, p1_y, p2_y, b_y, d_y));
+
+
+			        if (equal_to_precision(alpha_max, alpha_y_max, PRECISION)==1)
+            				j_min = 0;
+        			else
+            				j_min = (int) ceil( phi(alpha_max, p1_y, p2_y, b_y, d_y));
+
+				alpha_y=alpha_fn(j_max, p1_y, p2_y, b_y, d_y);
+			}
+
+
+
+    			if (p1_z < p2_z) {
+        			if (equal_to_precision(alpha_min,alpha_z_min,PRECISION)==1)
+            				k_min=1;
+        			else
+            				k_min = (int) ceil(phi(alpha_min, p1_z, p2_z, b_z, d_z));
+
+
+        			if (equal_to_precision(alpha_max, alpha_z_max,PRECISION)==1)
+            				k_max = N_z - 1;
+        			else
+            				k_max = (int) floor( phi(alpha_max, p1_z, p2_z, b_z, d_z));
+
+				alpha_z=alpha_fn(k_min, p1_z, p2_z, b_z, d_z);
+			}
+
+    			else {
+
+        			if (equal_to_precision(alpha_min,alpha_z_min,PRECISION)==1)
+            				k_max=N_z-2;
+        			else
+            				k_max = (int) floor(phi(alpha_min, p1_z, p2_z, b_z, d_z));
+
+
+        			if (equal_to_precision(alpha_max, alpha_z_max, PRECISION)==1)
+        	    			k_min = 0;
+        			else
+            				k_min = (int) ceil( phi(alpha_max, p1_z, p2_z, b_z, d_z));
+
+				alpha_z=alpha_fn(k_max, p1_z, p2_z, b_z, d_z);
+			}
+
+
+			N_p=(i_max - i_min +1) + (j_max - j_min + 1) + (k_max - k_min + 1);
+
+
+    			i=(int) floor( phi( (min3_dbl(alpha_x, alpha_y, alpha_z) + alpha_min)/2, p1_x, 
+p2_x, b_x, d_x) );
+    			j=(int) floor( phi( (min3_dbl(alpha_x, alpha_y, alpha_z) + alpha_min)/2, p1_y, 
+p2_y, b_y, d_y) );
+    			k=(int) floor( phi( (min3_dbl(alpha_x, alpha_y, alpha_z) + alpha_min)/2, p1_z, 
+p2_z, b_z, d_z) );
+
+    			alpha_x_u = d_x/fabs(p2_x-p1_x);
+			if (p1_x < p2_x)
+        			i_u=1;
+    			else
+        			i_u=-1;
+
+    			alpha_y_u = d_y/fabs(p2_y-p1_y);
+    			if (p1_y < p2_y)
+        			j_u=1;
+    			else
+        			j_u=-1;
+
+			alpha_z_u = d_z/fabs(p2_z-p1_z);
+    			if (p1_z < p2_z)
+        			k_u=1;
+    			else
+        			k_u=-1;
+
+
+    			alpha_c=alpha_min;
+
+    			/* should possibly use N_v here*/
+    			for (n_count=1; n_count<N_p+1;n_count++) {
+
+
+    				/*%PROBLEM. sometimes i or j increase too much. fix!
+    				%this seems to work. stills seems odd tho */
+				if (0>i || i>im_size-1 || 0>j || j>im_size-1 || 0>k || k>im_size-1) {
+     				/*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, 
+jacobs_ray);*/
+		if(testing == 1)
+		  printf("returns here (2)");fflush(NULL);
+    					return;
+    				}
+
+
+        			/* x smallest*/
+				if (alpha_x <= alpha_y && alpha_x <= alpha_z) {
+             				/* ray intersects pixel(i,j) with length l_ij */
+
+				    	ray_index[(*n_entries)] = k*im_size*im_size + j*im_size + i;
+					ray_data[(*n_entries)++] = (alpha_x-alpha_c);
+
+            				i=i+i_u;
+            				alpha_c=alpha_x;
+            				alpha_x = alpha_x + alpha_x_u;
+	    			}
+
+				/* y smallest*/
+				else if (alpha_y <= alpha_y && alpha_y <= alpha_z) {
+            				/* ray intersects pixel(i,j) with length l_ij */
+
+					ray_index[(*n_entries)] = k*im_size*im_size + j*im_size + i;
+					ray_data[(*n_entries)++] = (alpha_y-alpha_c);
+
+            				j=j+j_u;
+            				alpha_c=alpha_y;
+            				alpha_y = alpha_y + alpha_y_u;
+	    			}
+
+				/* z smallest*/
+				else {
+            				/* ray intersects pixel(i,j) with length l_ij */
+
+				    	ray_index[(*n_entries)] = k*im_size*im_size + j*im_size + i;
+					ray_data[(*n_entries)++] = (alpha_z-alpha_c);
+
+            				k=k+k_u;
+			        	alpha_c=alpha_z;
+            				alpha_z = alpha_z + alpha_z_u;
+	    			}
+
+
+ 			} /* end of for loop though N_p */
+
+		} /* of alpha_min < alpha_max */
+
+ /*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, jacobs_ray);*/
+	if(testing == 1)
+	  printf(":jacobs_ray_3d done:");fflush(NULL);
+
+	return;
+
+	} /* of points px!=px && py!=py */
+
+}
+
+
+
+/***********************************************************************/
+
+
+
+void jacobs_ray_2d(int im_size, double p1_x, double p1_y, double p2_x, double
+		p2_y, int *ray_index_i, int *ray_index_j, double *ray_data, int *n_entries, double voxel_size)
+{
+
+	int N_x, N_y, N_p;
+	double b_x, b_y, d_x, d_y, d_conv; /*, d_conv_alpha; */
+
+	int i,j;
+
+	double alpha_x_min, alpha_y_min, alpha_x_max, alpha_y_max, alpha_min, 
+alpha_max, alpha_x, alpha_y, alpha_c;
+	double alpha_x_u, alpha_y_u;
+	double l_ij;
+	int i_min, j_min, i_max, j_max, n_count, i_u, j_u;
+
+	*n_entries=0;
+
+		
+	b_x=-im_size*voxel_size/2;
+	b_y=-im_size*voxel_size/2;
+
+	d_x=voxel_size;
+	d_y=voxel_size;
+
+	/* use total lengh=alpha_max-alpha_min instead, to get everage, not sum. */
+	d_conv=sqrt( (p1_x-p2_x)*(p1_x-p2_x) + (p1_y-p2_y)*(p1_y-p2_y) );/**/
+
+	N_x=im_size+1;
+	N_y=im_size+1;
+
+if (equal_to_precision(p1_x,p2_x,PRECISION)==1) {
+    i=(int)floor( phi(0, p1_x, p2_x, b_x, d_x));
+    /* or ceil? */
+
+    /*may as well assume ray starts and ends outside grid as this will be
+    the case whenever this is used */
+	if (0 <= i && i <= im_size-1)
+    		for (j=0; j< im_size; j++) {
+			/*ray_index[(*n_entries)] = j* im_size + i;*/
+			ray_index_i[(*n_entries)] = i;
+			ray_index_j[(*n_entries)] = j;
+			ray_data[(*n_entries)++] = 1.0 * voxel_size / d_conv;
+		}
+	else {
+		/* leave empty */
+	}
+
+	/*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, jacobs_ray);*/
+	return;
+}
+
+else if (equal_to_precision(p1_y,p2_y,PRECISION)==1) {
+	j=(int)floor( phi(0, p1_y, p2_y, b_y, d_y));
+	/* or ceil? */
+
+	/*may as well assume ray starts and ends outside grid as this will be
+    	%the case whenever this is used */
+	if (0 <= j && j <= im_size-1)
+    		for (i=0; i< im_size; i++) {
+			/*ray_index[(*n_entries)] = j* im_size + i;*/
+			ray_index_i[(*n_entries)] = i;
+			ray_index_j[(*n_entries)] = j;
+			ray_data[(*n_entries)++] = 1.0 * voxel_size / d_conv;
+		}
+	else {
+		/* leave as zero */
+	}
+
+	/*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, jacobs_ray);*/
+	return;
+}
+
+else {
+    alpha_x_min=min_dbl(alpha_fn(0, p1_x, p2_x, b_x, d_x), alpha_fn(N_x-1, p1_x, 
+p2_x, b_x, d_x));
+    alpha_x_max=max_dbl(alpha_fn(0, p1_x, p2_x, b_x, d_x), alpha_fn(N_x-1, p1_x, 
+p2_x, b_x, d_x));
+
+
+    alpha_y_min=min_dbl(alpha_fn(0, p1_y, p2_y, b_y, d_y), alpha_fn(N_y-1, p1_y, 
+p2_y, b_y, d_y));
+    alpha_y_max=max_dbl(alpha_fn(0, p1_y, p2_y, b_y, d_y), alpha_fn(N_y-1, p1_y, 
+p2_y, b_y, d_y));
+
+    alpha_min=max_dbl(alpha_x_min, alpha_y_min);
+    alpha_max=min_dbl(alpha_x_max, alpha_y_max);
+
+if (alpha_min < alpha_max) {
+
+    /* use total lengh=alpha_max-alpha_min instead, to get everage, not sum. */
+    /* d_conv_alpha=alpha_max-alpha_min; /**/
+
+
+
+
+    if (p1_x < p2_x) {
+        if (equal_to_precision(alpha_min,alpha_x_min,PRECISION)==1)
+            i_min=1;
+        else
+            i_min = (int)ceil(phi(alpha_min, p1_x, p2_x, b_x, d_x));
+
+
+        if (equal_to_precision(alpha_max,alpha_x_max,PRECISION)==1)
+            i_max = N_x - 1;
+        else
+            i_max = (int)floor( phi(alpha_max, p1_x, p2_x, b_x, d_x));
+
+	alpha_x=alpha_fn(i_min, p1_x, p2_x, b_x, d_x);
+	    }
+
+    else {
+        if (equal_to_precision(alpha_min,alpha_x_min,PRECISION)==1)
+            i_max=N_x-2;
+        else
+            i_max = (int)floor(phi(alpha_min, p1_x, p2_x, b_x, d_x));
+
+
+        if (equal_to_precision(alpha_max,alpha_x_max,PRECISION)==1)
+            i_min = 0;
+        else
+            i_min = (int)ceil( phi(alpha_max, p1_x, p2_x, b_x, d_x));
+
+	alpha_x=alpha_fn(i_max, p1_x, p2_x, b_x, d_x);
+	}
+
+
+    if (p1_y < p2_y) {
+        if (equal_to_precision(alpha_min,alpha_y_min,PRECISION)==1)
+            j_min=1;
+        else
+            j_min = (int)ceil(phi(alpha_min, p1_y, p2_y, b_y, d_y));
+
+
+        if (equal_to_precision(alpha_max, alpha_y_max,PRECISION)==1)
+            j_max = N_y - 1;
+        else
+            j_max = (int)floor( phi(alpha_max, p1_y, p2_y, b_y, d_y));
+
+	alpha_y=alpha_fn(j_min, p1_y, p2_y, b_y, d_y);
+	}
+
+    else {
+
+        if (equal_to_precision(alpha_min,alpha_y_min,PRECISION)==1)
+            j_max=N_y-2;
+        else
+            j_max = (int)floor(phi(alpha_min, p1_y, p2_y, b_y, d_y));
+
+
+        if (equal_to_precision(alpha_max, alpha_y_max, PRECISION)==1)
+            j_min = 0;
+        else
+            j_min = (int)ceil( phi(alpha_max, p1_y, p2_y, b_y, d_y));
+
+	alpha_y=alpha_fn(j_max, p1_y, p2_y, b_y, d_y);
+	}
+
+
+    N_p=(i_max - i_min +1) + (j_max - j_min + 1);
+
+
+    i=(int)floor( phi( (min_dbl(alpha_x, alpha_y) + alpha_min)/2, p1_x, p2_x, b_x, d_x) 
+);
+    j=(int)floor( phi( (min_dbl(alpha_x, alpha_y) + alpha_min)/2, p1_y, p2_y, b_y, d_y) 
+);
+
+    alpha_x_u = d_x/fabs(p2_x-p1_x);
+    if (p1_x < p2_x)
+        i_u=1;
+    else
+        i_u=-1;
+
+    alpha_y_u = d_y/fabs(p2_y-p1_y);
+    if (p1_y < p2_y)
+        j_u=1;
+    else
+        j_u=-1;
+
+
+    alpha_c=alpha_min;
+
+    /* should possibly use N_v here*/
+    for (n_count=1; n_count<N_p+1;n_count++)
+    {
+
+
+    /*%PROBLEM. sometimes i or j increase too much. fix!
+    %this seems to work. stills seems odd tho */
+if (0>i || i>im_size-1 || 0>j || j>im_size-1) {
+     /*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, jacobs_ray);*/
+    return;
+    }
+
+
+        if (alpha_x < alpha_y) {
+             /* ray intersects pixel(i,j) with length l_ij */
+             l_ij=(alpha_x-alpha_c); 
+
+            /* remove tiny rounding errors by rounding to 8 d.p.
+            l_ij=round(l_ij*10^8)/10^8;*/
+
+
+	    	/*ray_index[(*n_entries)] = j* im_size + i;*/
+		ray_index_i[(*n_entries)] = i;
+		ray_index_j[(*n_entries)] = j;
+
+		ray_data[(*n_entries)++] = l_ij; /* * d_conv_alpha / d_conv; /**/
+
+            i=i+i_u;
+            alpha_c=alpha_x;
+            alpha_x = alpha_x + alpha_x_u;
+	    }
+        else {
+            /* ray intersects pixel(i,j) with length l_ij */
+            l_ij=(alpha_y-alpha_c); 
+
+            /* remove tiny rounding errors by rounding to 8 d.p.
+            l_ij=round(l_ij*10^8)/10^8; */
+
+
+	    	/*ray_index[(*n_entries)] = j* im_size + i;*/
+		ray_index_i[(*n_entries)] = i;
+		ray_index_j[(*n_entries)] = j;
+		ray_data[(*n_entries)++] = l_ij; /* * d_conv_alpha / d_conv; /**/
+
+            j=j+j_u;
+            alpha_c=alpha_y;
+            alpha_y = alpha_y + alpha_y_u;
+	    }
+
+	    } /* of loop through N_p*/
+ } /* of alpha_min < alpha_max */
+
+ /*sort_and_set(tmp_arr_index, tmp_arr_data, &tmp_counter, jacobs_ray);*/
+return;
+
+} /* of points px!=px && py!=py */
+
+}
+
+
+
+
+double alpha_fn(int n, double p1, double p2, double b, double d)
+{
+    return ( (b+n*d) - p1)/(p2-p1);
+}
+
+
+double phi(double alpha, double p1, double p2, double b, double d)
+{
+    return ( p(alpha, p1, p2)-b)/d;
+}
+
+
+double p(double alpha, double p1, double p2)
+{
+    return p1+alpha*(p2-p1);
+}
+
+
+
+int equal_to_precision(double x, double y, double prec)
+{
+   return fabs(x-y) < prec;
+}
+
+
+
+#if 0 == 1
+void qsort_indexed_list(int *index, double *values, int l, int r)
+/* to sort the entries in index ascending, and entries in values to match
+[1 3 2			[1 2 3
+   a b c]    becomes	 a c b] */
+{
+	/*mexPrintf("qsort, left: %d, right: %d \n", l, r);*/
+
+	int l1, r1;
+
+	if (l < r) {
+		l1=l;
+		r1=r;
+
+		do {
+		while (l1 < r && index[l1-1] <= index[l-1])
+			l1++;
+		while(l < r1 && index[r1-1] >= index[l-1])
+			r1--;
+		if (l1 < r1) {
+			swop_int( &index[l1-1], &index[r1-1]);
+			swop_dbl( &values[l1-1], &values[r1-1]);
+			}
+		} while (l1 < r1);
+
+		swop_int( &index[l-1], &index[r1-1]);
+		swop_dbl( &values[l-1], &values[r1-1]);
+
+		qsort_indexed_list(index, values, l, r1-1);
+		qsort_indexed_list(index, values, r1+1, r);
+	}
+}
+
+void swop_int(int *a, int *b)
+/* swops the values of a and b */
+{
+	double t;
+	t=*a;
+	*a=*b;
+	*b=t;
+}
+
+void swop_dbl(double *a, double *b)
+/* swops the values of a and b */
+{
+	double t;
+	t=*a;
+	*a=*b;
+	*b=t;
+}
+
+#endif
+
diff --git a/zUtil_ForwardProjection/reconstruct_phototom.h b/zUtil_ForwardProjection/reconstruct_phototom.h
new file mode 100755
index 0000000000000000000000000000000000000000..e4bc3d2e564b73201feeee7088cdb87e442266ec
--- /dev/null
+++ b/zUtil_ForwardProjection/reconstruct_phototom.h
@@ -0,0 +1,179 @@
+/* An MPI implementation for solving the equations for photoelastic tomography 
+   using a conjugate gradient least squares method. functions are implemented 
+   for matrix and matrix transpose times vector.
+
+
+   David Szotten
+   March 2006
+*/
+
+
+#ifndef _RECPT_HEADER_
+#define _RECPT_HEADER_
+
+
+/* ************** OPTIONS ************** */
+
+#define _RECPT_USE_MPI_ 0 
+
+/*	defined through precompiler argument, -D _RECPT_MAKE_MEX_ = 0/1 
+	decides if making mex file or exe file. */
+#ifndef _RECPT_MAKE_MEX_
+	#define _RECPT_MAKE_MEX_ 0
+#endif
+
+/* from the 2x2 symmetric matrices. if traceless, they only have 2 independent data values */
+#define DATA_TO_STORE 3
+#define MAX_SEND_BUFFER_BYTES 400000/*4194304;*/
+#ifndef REMOVE_TRACE
+	#define REMOVE_TRACE 1
+#endif
+
+#define COMPATIBILITY_SCALE_FACTOR 0.01
+#define EQUILIBRIUM_SCALE_FACTOR 0.01
+#define LAMBDA 1.9
+#define MU 0.9
+
+#define PRECISION 0.00000001 /* for calculating rays intersecting voxels*/
+
+/* ************************************* */
+
+
+/* ************** NOTES ****************** 
+
+decided to allocate im_size*3 elements for storing voxels being intersected
+by each ray. not fully tested, but should work
+
+
+
+ *************************************** */
+
+#include <matrix.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <mat.h>
+
+#if _RECPT_MAKE_MEX_ == 1
+	#include <mex.h>
+#endif
+
+#define jacobs_PI 3.14159265358979
+
+#define TAG_DATA 99
+#define TAG_REQUEST_SEND 98
+#define TAG_SEND_NOW 97
+#define TAG_FINISH 96
+#define TAG_ORDER 94
+#define TAG_SENDING 93
+#define TAG_INPUT_DATA 92
+
+#define ORDER_START 79
+#define ORDER_SEND_INPUT 78
+#define ORDER_SEND_INPUT_SIZES 77
+#define ORDER_SEND_INPUT_DATA 76
+#define ORDER_START_TIMESX 75
+#define ORDER_START_TRANSPOSE 74
+#define ORDER_STOP 73
+
+#define OPTION_GENERATE 10
+#define OPTION_RECONSTRUCT 11
+#define OPTION_GENERATE_AND_RECONSTRUCT 12
+#define OPTION_CALCULATE_COMP 13
+#define OPTION_CALCULATE_LINEL 14
+#define OPTION_TEST 15
+#define OPTION_CALCULATE_SMOOTH 16
+
+/* display_progress */
+#define OPTION_DISPLAY_NOTHING 0
+#define OPTION_DISPLAY_DOTS 1
+#define OPTION_DISPLAY_NUMBERS 2
+#define OPTION_DISPLAY_MORENUMBERS 3
+#define OPTION_DISPLAY_IMAGES 4
+
+
+
+struct option_list {
+    int height, width, angle_increment, printing_on, side_length, side_length_voxels, smooth, display_progress;
+    double pixels_per_meter, side_length_meter, *origin;
+    double option_compatibility, option_equilibrium, option_lambda, option_mu;
+    mxArray *augmented_R;
+
+};
+	
+
+#if _RECPT_USE_MPI_ == 1
+	#include <mpi.h>
+	int send_in_parts(double *buffer, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); 
+	int receive_in_parts(double* buffer, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status);
+#else
+	int MPI_Finalize(void);
+#endif
+
+int print_array(mxArray *array);
+double time_in_seconds(struct timeval *time_val_struct);
+
+#if (_RECPT_MAKE_MEX_ != 1)
+	int load_vars_from_file(const char *file, const int n_vars, const char **var_names, mxArray **data, int print_progress);
+	int write_vars_to_file(const char *outputfile, const int n_vars, const char **var_names, mxArray **data);
+#endif
+
+double dbl_abs(double num);
+
+int cgls(struct option_list *options, mxArray *image, int max_iterations, double tolerance, mxArray **return_value);
+int photoelasticity_afun(mxArray *x, struct option_list *options, int transpose, mxArray **return_value);
+
+int jacobs_timesx(struct option_list *options, mxArray *x, mxArray **result);
+int jacobs_transpose_timesy(struct option_list *options, mxArray *y, mxArray **return_value);
+int calculate_mypart(struct option_list *options, int my_start, int my_end, mxArray *vector, double *my_partial_result, int calculate_transpose);
+int process_input(struct option_list *options, int *p_n_angles, int *p_n_tilts, int *p_im_size, int *p_width);
+int im_size_from_height(int height);
+
+
+int get_matrix_from_array_of_matrices(mxArray *array, int n, mxArray **result);
+int transpose(mxArray *a, mxArray **result);
+int separate_augmented(mxArray *augmented, mxArray **rotation, mxArray **translation);
+int matrix_times_vector(mxArray *a, double *x, double *result);
+int matrix_mult(mxArray *A, mxArray *B, mxArray **result);
+/*int extract_adapt_for_symmetric_tensor(mxArray *tensor_projection_operator, mxArray **result);*/
+int kron_eye_on_right(mxArray *A, int n, mxArray **result);
+int kron_eye_on_left(mxArray *A, int n, mxArray **result);
+
+void jacobs_ray_2d(int im_size, double p1_x, double p1_y, double p2_x, double p2_y, int *ray_index_i, int *ray_index_j, double *ray_data, int *n_entries, double voxel_size);
+void jacobs_ray_3d(int im_size, double *start, double *end, int *ray_index, double *ray_data, int *n_entries, double voxel_size);
+void jacobs_tensorise_and_dot(int *jra_index, double *jra_data, int jra_n_entries, double *total_tensor_ptr, mxArray *x_ptr, double *output_ptr);
+int jacobs_tensorise_and_dot_transpose(int *jra_index, double *jra_data, int jra_n_entries, double *total_tensor_ptr, mxArray *x_ptr, int tensor_start, double *arr_to_set_ptr);
+
+int compatibility_timesx(struct option_list *options, mxArray *x, mxArray **result);
+int compatibility_transpose_timesy(struct option_list *options, double *p_y, mxArray **result);
+int second_derivative(int i, int j, int k, int l, int derivative_array[5][4]);
+int compatibility_equation(int i, int j, int k, int l, int equation_derivative_array[5][16], int weight_factor);
+
+
+int equilibrium_timesx(struct option_list *options, mxArray *x, mxArray **result);
+int equilibrium_transpose_timesy(struct option_list *options, double *p_y, mxArray **result);
+int first_derivative(int i, int j, int m, int derivative_array[5][2]);
+int equilibrium_equation(struct option_list *options, int j, int equation_derivative_array[5][24]);
+
+
+void jacobs_tensorise_and_dot(int *jra_index, double *jra_data, int jra_n_entries, double *total_tensor_ptr, mxArray *x_ptr, double *output_ptr);
+int jacobs_tensorise_and_dot_transpose(int *jra_index, double *jra_data, int jra_n_entries, double *total_tensor_ptr, mxArray *x_ptr, int tensor_start, double *arr_to_set_ptr);
+
+int vector_linear_combination(double lambda1, mxArray *vector1, double lambda2, mxArray *vector2, mxArray **return_value);
+double norm_square(mxArray *vector);
+int cross_product(double *a, double *b, double *result);
+int scalar_mult(double scalar, double *vector, double *result);
+int append(mxArray *vector1, mxArray *vector2, mxArray **result);
+
+/*mxArray *recpt_mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag);
+void recpt_mxDestroyArray(mxArray *array_ptr);
+mxArray *recpt_mxDuplicateArray(mxArray *array_ptr);*/
+void add_noise(mxArray *images, double noise_level);
+bool file_exists(char *FileName);
+int get_options(int argc, char **argv, char **filename, int *option_method, struct option_list *options, 
+			int *option_n_iterations, double *option_tolerance);
+
+int smooth_timesx(int im_size, mxArray *x, mxArray **result);
+int smooth_transpose_timesy(int im_size, double *p_y, mxArray **result);
+
+#endif
diff --git a/zUtil_ForwardProjection/try1.m b/zUtil_ForwardProjection/try1.m
new file mode 100755
index 0000000000000000000000000000000000000000..9419f0b64ef1eb7a0c5d5c4c31bd4865dc55ea72
--- /dev/null
+++ b/zUtil_ForwardProjection/try1.m
@@ -0,0 +1,19 @@
+
+ph=phantom(101);
+vol=repmat(ph,[1,1,101]);
+vol_view(vol);
+
+[x,y]=meshgrid(-50:50);
+
+im=zeros(101,101);
+for xndx=-5:5;
+  for yndx=-5:5;
+    sp_ray=jacobs_ray3d(101,...
+      -1e6,0,0,...
+      0,yndx,xndx,...
+    1);
+  
+    im(yndx+51,xndx+51)=full(dot(sp_ray,reshape(vol,[],1)));
+  end
+end
+imagesc(im)
\ No newline at end of file
diff --git a/zUtil_ForwardProjection/work.m b/zUtil_ForwardProjection/work.m
new file mode 100755
index 0000000000000000000000000000000000000000..55ef83c9751b5bad12f128d9b8b6857a9e942db2
--- /dev/null
+++ b/zUtil_ForwardProjection/work.m
@@ -0,0 +1,48 @@
+load('/data/id19/graintracking/data/sept2007/strain_sept07_5N_/parameters.mat');
+load('/data/id19/graintracking/data/sept2007/strain_sept07_5N_/sort_grains_lastrun.mat');
+cd /data/id19/graintracking/data/sept2007/strain_sept07_5N_/test
+
+if 1  % use real grain data 
+  gr=grain{2};
+  gr.Omega=gr.omega;
+  gr.Theta=gr.theta;
+  gr.Eta=gr.eta;
+  
+  % create a pyramid
+  gv=zeros(parameters.acq.bb(3),parameters.acq.bb(3),parameters.acq.bb(4));
+  tmp=zeros(parameters.acq.bb(3));
+  [x,y,z]=gtTrLabToSamBB(gr.center(1),gr.center(2),gr.center(3),parameters)
+  x=floor(x);y=floor(y);z=floor(z);
+  tmp(x,y)=1;
+  
+  for i= z-30:z+30
+	if mod(i,3)==0
+	  tmp=bwmorph(tmp,'dilate');
+	end
+	gv(:,:,i)=tmp;
+  end
+
+else  % use some testdata
+	gr.Omega=[0 90 30];gr.omega=gr.Omega;
+	gr.Theta=[5 5 5];gr.theta=gr.Theta;
+	gr.Eta=[0 60 30];gr.eta=gr.Eta;
+	gr.center=[49.5 49.5 0.5];
+	[x,y,z]=gtTrLabToSamBB(gr.center(1),gr.center(2),gr.center(3),parameters)
+	x=round(x);y=round(y);z=round(z);
+	gv=zeros(parameters.acq.bb(3),parameters.acq.bb(3),parameters.acq.bb(4));
+	gv(x-30:x+30,y-30:y+30,z)=1;
+end
+
+
+index=[1:length(gr.Omega)];	
+
+[proj,difspot,bb]=gtForwardProject(gv,gr,parameters,index);
+
+parameters.bb=bb;
+
+[dif,gr]=gtShearDifspots_wl(gr,parameters,index);
+
+grflip=gtFlipProjections(gr,index);
+
+vol2=tryARTflip('proj','test.par',[index],[],[],gr,[1],parameters,z);impixelinfo
+%s=regionprops(bwlabel(vol2(:,:,2)))
\ No newline at end of file
diff --git a/zUtil_GVF/BoundMirrorEnsure.m b/zUtil_GVF/BoundMirrorEnsure.m
new file mode 100755
index 0000000000000000000000000000000000000000..6afbd600d0b5901caa5e7cf3ede337107698f298
--- /dev/null
+++ b/zUtil_GVF/BoundMirrorEnsure.m
@@ -0,0 +1,39 @@
+function B = BoundMirrorEnsure(A)
+% Ensure mirror boundary condition
+%
+% The number of rows and columns of A must be greater than 2
+%
+% for example (X means value that is not of interest)
+% 
+% A = [
+%     X  X  X  X  X   X
+%     X  1  2  3  11  X
+%     X  4  5  6  12  X 
+%     X  7  8  9  13  X 
+%     X  X  X  X  X   X
+%     ]
+%
+% B = BoundMirrorEnsure(A) will yield
+%
+%     5  4  5  6  12  6
+%     2  1  2  3  11  3
+%     5  4  5  6  12  6 
+%     8  7  8  9  13  9 
+%     5  4  5  6  12  6
+%
+
+% Chenyang Xu and Jerry L. Prince, 9/9/1999
+% http://iacl.ece.jhu.edu/projects/gvf
+
+[m,n] = size(A);
+
+if (m<3 | n<3) 
+    error('either the number of rows or columns is smaller than 3');
+end
+
+yi = 2:m-1;
+xi = 2:n-1;
+B = A;
+B([1 m],[1 n]) = B([3 m-2],[3 n-2]);  % mirror corners
+B([1 m],xi) = B([3 m-2],xi);          % mirror left and right boundary
+B(yi,[1 n]) = B(yi,[3 n-2]);          % mirror top and bottom boundary
diff --git a/zUtil_GVF/BoundMirrorExpand.m b/zUtil_GVF/BoundMirrorExpand.m
new file mode 100755
index 0000000000000000000000000000000000000000..a226c6b10fb6d2d32d18435d47b4f5df8791ee94
--- /dev/null
+++ b/zUtil_GVF/BoundMirrorExpand.m
@@ -0,0 +1,31 @@
+function B = BoundMirrorExpand(A)
+% Expand the matrix using mirror boundary condition
+% 
+% for example 
+%
+% A = [
+%     1  2  3  11
+%     4  5  6  12
+%     7  8  9  13
+%     ]
+%
+% B = BoundMirrorExpand(A) will yield
+%
+%     5  4  5  6  12  6
+%     2  1  2  3  11  3
+%     5  4  5  6  12  6 
+%     8  7  8  9  13  9 
+%     5  4  5  6  12  6
+%
+
+% Chenyang Xu and Jerry L. Prince, 9/9/1999
+% http://iacl.ece.jhu.edu/projects/gvf
+
+[m,n] = size(A);
+yi = 2:m+1;
+xi = 2:n+1;
+B = zeros(m+2,n+2);
+B(yi,xi) = A;
+B([1 m+2],[1 n+2]) = B([3 m],[3 n]);  % mirror corners
+B([1 m+2],xi) = B([3 m],xi);          % mirror left and right boundary
+B(yi,[1 n+2]) = B(yi,[3 n]);          % mirror top and bottom boundary
diff --git a/zUtil_GVF/BoundMirrorShrink.m b/zUtil_GVF/BoundMirrorShrink.m
new file mode 100755
index 0000000000000000000000000000000000000000..519d2c912d7e488e35d2be890a47f312cff52ca7
--- /dev/null
+++ b/zUtil_GVF/BoundMirrorShrink.m
@@ -0,0 +1,27 @@
+function B = BoundMirrorShrink(A)
+% Shrink the matrix to remove the padded mirror boundaries
+%
+% for example 
+%
+% A = [
+%     5  4  5  6  12  6
+%     2  1  2  3  11  3
+%     5  4  5  6  12  6 
+%     8  7  8  9  13  9 
+%     5  4  5  6  12  6
+%     ]
+% 
+% B = BoundMirrorShrink(A) will yield
+%
+%     1  2  3  11
+%     4  5  6  12
+%     7  8  9  13
+
+% Chenyang Xu and Jerry L. Prince, 9/9/1999
+% http://iacl.ece.jhu.edu/projects/gvf
+
+[m,n] = size(A);
+yi = 2:m-1;
+xi = 2:n-1;
+B = A(yi,xi);
+
diff --git a/zUtil_GVF/Contents.m b/zUtil_GVF/Contents.m
new file mode 100755
index 0000000000000000000000000000000000000000..2823bf3aa5a7841a8afdd4419d129824444cc05f
--- /dev/null
+++ b/zUtil_GVF/Contents.m
@@ -0,0 +1,30 @@
+% GVF snake (active contour) toolbox
+% Version 1.0 17-June-1997
+% Copyright (c) 1996-1997 by Chenyang Xu and Jerry L. Prince 
+%
+%
+%  Image input/output
+%    rawread       - Read a Portable Bitmap file, or a raw file
+%    rawwrite      - Write a Portable Bitmap file, or a raw file
+% 
+%  Image Display
+%    imdisp        - Display an image
+% 
+%  Active Contour
+%    snakeinit     - Initialize the snake manually
+%    snakedeform   - Deform snake in the given external force field
+%    snakedeform2  - Deform snake in the given external force field with
+%                    pressure force
+%    snakedisp     - Display a snake
+%    snakeinterp   - Interpolate the snake adaptively
+%    snakeinterp1  - Interpolate the snake at a fixed resolution
+%                    (better implemented than snakeinterp)
+% 
+%  Gradient Vector Flow
+%    GVF           - Compute the gradient vector flow field
+% 
+%  Other
+%    dt            - Simple distance transform
+%    gaussianBlur  - Blurring an image using gaussian kernel   
+%    gaussianMask  - Generate a discrete gaussian mask
+
diff --git a/zUtil_GVF/GVF.m b/zUtil_GVF/GVF.m
new file mode 100755
index 0000000000000000000000000000000000000000..66e7c41c8c4686dc874c8f861f66c5244780ddc8
--- /dev/null
+++ b/zUtil_GVF/GVF.m
@@ -0,0 +1,49 @@
+function [u,v] = GVF(f, mu, ITER)
+%GVF Compute gradient vector flow.
+%   [u,v] = GVF(f, mu, ITER) computes the
+%   GVF of an edge map f.  mu is the GVF regularization coefficient
+%   and ITER is the number of iterations that will be computed.  
+
+%   Chenyang Xu and Jerry L. Prince 6/17/97
+%   Copyright (c) 1996-99 by Chenyang Xu and Jerry L. Prince
+%   Image Analysis and Communications Lab, Johns Hopkins University
+
+%   modified on 9/9/99 by Chenyang Xu
+%   MATLAB do not implement the boundary condition for gradient and del2 
+%   consistently between MATLAB 4.2 and MATLAB 5. Hence I modify
+%   the function to take care of this issue by the code itself.
+%   Also, in the previous version, the input "f" is assumed to have been
+%   normalized to the range [0,1] before the function is called. 
+%   In this version, "f" is normalized inside the function to avoid 
+%   potential error of inputing an unnormalized "f".
+
+[m,n] = size(f);
+fmin  = min(f(:));
+fmax  = max(f(:));
+f = (f-fmin)/(fmax-fmin);  % Normalize f to the range [0,1]
+
+f = BoundMirrorExpand(f);  % Take care of boundary condition
+[fx,fy] = gradient(f);     % Calculate the gradient of the edge map
+u = fx; v = fy;            % Initialize GVF to the gradient
+SqrMagf = fx.*fx + fy.*fy; % Squared magnitude of the gradient field
+
+% Iteratively solve for the GVF u,v
+
+for i=1:ITER,
+  u = BoundMirrorEnsure(u);
+  v = BoundMirrorEnsure(v);
+  u = u + mu*4*del2(u) - SqrMagf.*(u-fx);
+  v = v + mu*4*del2(v) - SqrMagf.*(v-fy);
+  if 0
+    fprintf(1, '%3d', i);
+    if (rem(i,20) == 0)
+      fprintf(1, '\n');
+    end
+  end
+end
+if 0
+  fprintf(1, '\n');
+end
+u = BoundMirrorShrink(u);
+v = BoundMirrorShrink(v);
+
diff --git a/zUtil_GVF/dt.m b/zUtil_GVF/dt.m
new file mode 100755
index 0000000000000000000000000000000000000000..ffcabe8e6c9b822ebc643e2306c452ee06dedb82
--- /dev/null
+++ b/zUtil_GVF/dt.m
@@ -0,0 +1,23 @@
+function D = dt(B)
+% DT apply Eucledian distance transform
+%    D = dt(B) compute the Eucledian distance transform of B
+%    B must be a binary map. 
+%
+% NOTE: this is not an efficient way to implement distance transform. 
+%    If one is interested in using DT, one may want to implement its
+%    own DT. 
+
+%    Chenyang Xu and Jerry L. Prince 6/17/97
+%    Copyright (c) 1996-97 by Chenyang Xu and Jerry L. Prince
+
+[i,j] = find(B);
+
+[n,m] = size(B);
+for x = 1:n,
+    for y = 1:m,
+        dx = i-x;
+        dy = j-y;
+        dmag = sqrt(dx.*dx+dy.*dy);
+	D(x,y) = min(dmag);
+    end
+end
diff --git a/zUtil_GVF/gaussianBlur.m b/zUtil_GVF/gaussianBlur.m
new file mode 100755
index 0000000000000000000000000000000000000000..d453cf21e798ceb4d070770239be29d995401822
--- /dev/null
+++ b/zUtil_GVF/gaussianBlur.m
@@ -0,0 +1,13 @@
+function GI = gaussianBlur(I,s)
+% GAUSSIANBLUR blur the image with a gaussian kernel
+%     GI = gaussianBlur(I,s) 
+%     I is the image, s is the standard deviation of the gaussian
+%     kernel, and GI is the gaussian blurred image.
+
+%    Chenyang Xu and Jerry L. Prince 6/17/97
+%    Copyright (c) 1996-97 by Chenyang Xu and Jerry L. Prince
+
+M = gaussianMask(1,s);
+M = M/sum(sum(M));   % normalize the gaussian mask so that the sum is
+                     % equal to 1
+GI = xconv2(I,M);
diff --git a/zUtil_GVF/gaussianMask.m b/zUtil_GVF/gaussianMask.m
new file mode 100755
index 0000000000000000000000000000000000000000..2792d9787da6387d4841de7e5b4e266de900381d
--- /dev/null
+++ b/zUtil_GVF/gaussianMask.m
@@ -0,0 +1,11 @@
+function M = gaussianMask(k,s)
+% k: the scaling factor
+% s: standard variance
+
+R = ceil(3*s); % cutoff radius of the gaussian kernal  
+for i = -R:R,
+    for j = -R:R,
+        M(i+ R+1,j+R+1) = k * exp(-(i*i+j*j)/2/s/s)/(2*pi*s*s);
+    end
+end
+
diff --git a/zUtil_GVF/gtSnakeBW.m b/zUtil_GVF/gtSnakeBW.m
new file mode 100755
index 0000000000000000000000000000000000000000..fa054db688e7fda3f9bdfde347dd87c6eb305e93
--- /dev/null
+++ b/zUtil_GVF/gtSnakeBW.m
@@ -0,0 +1,195 @@
+function snaked=gtSnakeBW(im, varargin)
+
+%pass in snakeoptions, else use defaults
+snakeoptions=[];
+if ~isempty(varargin)
+  snakeoptions=varargin{1};
+else
+  snakeoptions.elasticity=.5; %3;
+  snakeoptions.rigidity=15;  % keep this high to prevent spurs from local features
+  snakeoptions.viscosity=5;
+  snakeoptions.forcefactor=5;
+  snakeoptions.iterations=5;
+end
+
+
+  val=max(im(:));  % store input image value
+
+  im(im==val)=1;
+  % polarity of image not important because only magnitude of gradient is used
+  [fx,fy]=gradient(im);
+  fmag=sqrt(fx.^2+fy.^2);
+
+  % use a small part of the image to find the starting snake
+  [roffset,coffset]=find(im);
+  if length(roffset) > 10  % need AT LEAST 10 points to be reasonable
+    % TODO should this be replace with a convex hull? might be quicker?
+    [x_orig,y_orig]=gtMask2Poly(...
+      im(...
+      min(roffset):max(roffset),...
+      min(coffset):max(coffset)));
+
+    % adjust back to original coordinates
+    x_orig=x_orig+min(coffset)-1;
+    y_orig=y_orig+min(roffset)-1;
+
+    x=x_orig;y=y_orig;
+
+
+    %%%%%%%%%%%%%%
+    % make some measures of the spot we are considering:
+    defaultmaskarea=29000;
+    maskarea=numel(im);
+    arearatio=maskarea/defaultmaskarea;
+    %fprintf('Area ratio: %3.6f\n',arearatio);
+
+    defaultmaskperim=575;
+    tmp=regionprops(double(im),'perimeter');
+    maskperim=round(tmp.Perimeter);
+    perimratio=maskperim/defaultmaskperim;
+    %fprintf('Perimeter ratio: %3.2f\n',perimratio);
+
+
+    % snakeoptions.elasticity=snakeoptions.elasticity*arearatio.^2;
+    %    snakeoptions.forcefactor=snakeoptions.forcefactor*perimratio;
+    snakeoptions;
+
+    %%%%%%%%%%%%%%%
+
+    pad=25;
+   % tmp_bbox=round([min(x(:))-pad min(y(:))-pad gtRange(x)+(2*pad) gtRange(y)+(2*pad)]);
+   tmp_bbox=[1 1 size(im,2) size(im,1)];
+   
+   h_gvf=figure(1);
+   % clf
+   imagesc(gtCrop(im,tmp_bbox))
+    hold on
+    axis image
+
+    %    keyboard
+    [u,v] = GVF(gtExtract(fmag,tmp_bbox), 0.05, 15);  % 0.2,80 % 0.3 15
+    % Normalizing the GVF external force
+    mag = sqrt(u.^2+v.^2);
+    pxnorm = u./(mag+1e-10);pynorm = v./(mag+1e-10);
+
+    forcefield.x=pxnorm;
+    forcefield.y=pynorm;
+
+    x=x-(tmp_bbox(1));
+    y=y-(tmp_bbox(2));
+
+
+
+
+    [x,y]=snakeinterp(x,y,20,1);
+    origlength=length(x);
+    clear hp
+    converged=false;
+    snakecollapse=false;
+    sfConverged([]); % reset sfConverged
+    i=0;
+    while not(converged)
+      i=i+1;
+      if i>50 % *** CHANGED
+        break % get out of loop - we've taken too long
+      end
+      if length(x)<origlength/2
+        %      disp('Snake is too short!')
+        % break
+      end
+      if length(x)<10
+        disp('Snake has collapsed')
+        snakecollapse=true;
+        break
+      end
+
+
+
+
+      [x2,y2]=snakedeform(x,y,forcefield,snakeoptions);
+      tmp=poly2mask(x,y,round(max(x)+5),round(max(y)+5));
+      area=sum(tmp(:));
+      converged=sfConverged(area);
+      if length(x2)<15 % snake has collapsed
+        disp('Snake has collapsed')
+        snakecollapse=true;
+        break
+      end
+      if false
+
+        if exist('hp','var')
+          delete(hp)
+        end
+        hp=snakedisp(x,y,'g.-');
+        axis image
+        title(['Deformation in progress,  iter = ' num2str(i*snakeoptions.iterations)])
+ %       drawnow
+
+        % print('-dtiff',sprintf('perrin_%03d.tif',i));
+      end
+
+      [x,y]=snakeinterp(x2,y2,20,1);
+
+    end
+    if converged
+      disp('Converged')
+    else
+      disp('Did NOT converge')
+    end
+
+
+    figure(h_gvf);
+
+    snakedisp(x+tmp_bbox(1)-1,y+tmp_bbox(2)-1,'g.-');
+
+    [xgrid,ygrid]=meshgrid(1:size(im,2),1:size(im,1));
+    snaked=inpolygon(xgrid,ygrid,x+(tmp_bbox(1))-1,y+(tmp_bbox(2))-1);
+
+
+    snaked_area=regionprops(double(snaked),'area');
+    im_area=regionprops(double(im),'area');
+    try
+      if 0 %snaked_area.Area>2*im_area.Area
+        disp('********PROBABLY A BAD SNAKE')
+        snaked=im;
+      end
+    catch
+      snaked=im;
+    end
+
+    if snakecollapse
+      snaked=im;
+    end
+  else
+    % not enough points to be sensible
+    snaked=zeros(size(im));
+  end
+  % restore value used in input image
+  snaked=double(snaked)*val;
+%waitforbuttonpress
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  function flag=sfConverged(data1)
+    persistent diffdata data h_history
+    if isempty(data1)
+      clear data diffdata h_history
+      return
+    end
+    if numel(data)==0
+      data=[data1];
+      flag=false;
+      %   disp('*******************************************STARTING')
+
+    else
+      data=[data;data1];
+      diffdata=diff(data);
+
+      if abs(diffdata(end))<1
+        flag=true;
+      else
+        flag=false;
+      end
+
+    end
+  end
+end
diff --git a/zUtil_GVF/gvf_gj.m b/zUtil_GVF/gvf_gj.m
new file mode 100755
index 0000000000000000000000000000000000000000..29992fc06a532a8b8435e710b458abfff644c8b5
--- /dev/null
+++ b/zUtil_GVF/gvf_gj.m
@@ -0,0 +1,117 @@
+% EXAMPLE     GVF snake examples on two simulated object boundaries.
+%
+% NOTE: 
+% 
+% traditional snake and distance snake differed from GVF snake only 
+%   by using different external force field. In order to produce the
+%   corresponding external force field, use the following (all
+%   assuming edge map f is in memory).
+%
+% traditional snake:
+%   f0 = gaussianBlur(f,1);
+%   [px,py] = gradient(f0);
+%
+% distance snake:
+%   D = dt(f>0.5);  % distance transform (dt) require binary edge map
+%   [px,py] = gradient(-D);
+%
+% [px,py] is the external force field in both cases
+%
+% balloon model using a different matlab function "snakedeform2"
+% instead of "snakedeform". The external force could be any force
+% field generated above.
+%
+% an example of using it is as follows
+%       [x,y] = snakedeform2(x,y, alpha, beta, gamma, kappa, kappap, px,py,2);
+% do a "help snakedeform2" for more details
+% 
+
+  
+   if 1
+     [I,map] = rawread('/data/id19/archive/matlab/greg/gvf_dist_v4.2c/images/U64.pgm'); 
+      f = 1 - I/255; 
+   else
+     I=ones(64)*256;
+     I(20:50,20:50)=1;
+     I(22:48,22:48)=256;
+     I=double(imread('test.tif'));
+     I=I(50:220,210:330);
+     I=I-min(I(:));
+     I=I./max(I(:));
+     I=I(1:1:end,1:1:end);
+     blur=gaussianBlur(I,0.8);
+     clf
+     [e,thresh]=edge(I,'canny',0.1,3);
+     thresh
+     figure(2)
+     colormap(gray)
+     e=imfill(e,'holes');
+     q=imdilate(imerode(e,strel(ones(2))),strel(ones(2)));
+     e=bwperim(q);
+     imagesc(e)
+     f=double(e);
+     drawnow
+     keyboard
+   end
+     
+   % Compute the GVF of the edge map f
+     disp(' Compute GVF ...');
+     [u,v] = GVF(f, 0.2, 80);  % 0.2,80
+%     [u2,v2]=GVF(f,0.2,40);
+     disp(' Nomalizing the GVF external force ...');
+     mag = sqrt(u.*u+v.*v);
+     px = u./(mag+1e-10); py = v./(mag+1e-10); 
+
+     % display the gradient of the edge map
+     [fx,fy] = gradient(f); 
+%     subplot(223); quiver(fx,fy); 
+%     axis off; axis equal; axis 'ij';     % fix the axis 
+%     title('edge map gradient');
+
+     % display the GVF 
+     figure(3); quiver(px,py);
+%     axis off; axis equal; axis 'ij';     % fix the axis 
+ %    title('normalized GVF field');
+%%
+   % snake deformation
+     figure(1); clf
+     colormap(gray); 
+     a=imagesc(I);
+     set(a,'alphadata',0.5)
+     hold on
+     b=imagesc(e);
+     set(b,'alphadata',0.5);
+     t = 0:0.05:6.28;
+     t=0:0.5:2*pi;
+     x = 32 + 30*cos(t);
+     y = 32 + 30*sin(t);
+     borderx=0.1*size(I,2);
+     bordery=0.1*size(I,1);
+     x=[borderx size(I,2)-borderx size(I,2)-borderx borderx];
+     y=[bordery bordery size(I,1)-bordery size(I,1)-bordery];
+     
+     [x,y] = snakeinterp(x,y,20,0.5);
+     snakedisp(x,y,'r.-') 
+
+pause(1);
+
+     elastic=0.15;
+     rigid=0.01;
+     viscous=0.3;
+     force=.3;
+     iter=5;
+     for i=1:25,
+       [x,y] = snakedeform(x,y,elastic,rigid,viscous,force,px,py,iter);
+       [x,y] = snakeinterp(x,y,5,0.5);
+       snakedisp(x,y,'r.-') 
+       title(['Deformation in progress,  iter = ' num2str(i*iter)])
+       drawnow
+     end
+pause(1)
+clf
+     colormap(gray); 
+     a=imagesc(I);
+     hold on
+     b=imagesc(e);
+     set(b,'alphadata',0.5)
+     snakedisp(x,y,'g.-')
diff --git a/zUtil_GVF/imdisp.m b/zUtil_GVF/imdisp.m
new file mode 100755
index 0000000000000000000000000000000000000000..4c9e36e1699889ec5015307ae07144e1fed52350
--- /dev/null
+++ b/zUtil_GVF/imdisp.m
@@ -0,0 +1,12 @@
+function imdisp(I)
+% imdisp(I) - scale the dynamic range of an image and display it.
+
+x = (0:255)./255;
+grey = [x;x;x]';
+minI = min(min(I));
+maxI = max(max(I));
+I = (I-minI)/(maxI-minI)*255;
+image(I);
+axis('square','off');
+colormap(grey);
+
diff --git a/zUtil_GVF/rawread.m b/zUtil_GVF/rawread.m
new file mode 100755
index 0000000000000000000000000000000000000000..cd6643d04fd8872030bae061f6fd95435030f18c
--- /dev/null
+++ b/zUtil_GVF/rawread.m
@@ -0,0 +1,106 @@
+function [X,map] = rawread(filename,n,m);
+% RAWREAD Read a Portable Bitmap file, or a raw file.
+%       RAWREAD('imagefile.raw', xsize, ysize) reads a "raw" image file
+%       RAWREAD('imagefile.pgm') reads a "pgm" (portable gray map) image
+%       [X,map] = RAWREAD('imagefile.raw') returns both the image and a
+%       color map, so that
+%               [X,map] = rawread('imagefile.raw',sx,sy);
+%       or      [X,map] = rawread('imagefile.pgm');
+%               image(X)
+%               colormap(map)
+%       will display the result with the proper colors.
+%
+%       NOTE : map is optional and could be replaced during the display by
+%              the "colormap('gray')" command
+%
+%       See also IMWRITE, IMREAD, IMAGE, COLORMAP.
+
+dot = max(find(filename == '.'));
+suffix = filename(dot+1:dot+3);
+
+if strcmp(suffix,'pgm') | strcmp(suffix,'raw')
+
+   disp(sprintf('\nopens %s file\n',filename));
+   fp = fopen(filename,'rb','b');  % "Big-endian" byte order.
+   
+   if (fp<0)
+      error(['Cannot open ' filename '.']);
+   end
+
+   if strcmp(suffix,'pgm')
+   % Read and crack the header
+   
+      head = fread(fp,2,'uchar'); % pgm magic number : P5
+      if ~strcmp(head,'P5'),
+         fprintf(1,'\n Magic Number : %s\n',head);
+      else
+         fprintf(1,'\n Bad Magic Number : %s\n',head);
+         error('cannot continue this way, good bye cruel world');
+      end
+
+      c = fread(fp,1,'uchar'); %reads the carriage return separating P5 from the creator
+
+      precreator = fread(fp,1,'uchar'); % look for a '#' character preceeding a creator signature
+      if precreator == '#',
+         c = setstr(20);  % any character except carriage return
+         cr = setstr(10); % defines a carriage return
+         while c ~= cr,
+               c = fread(fp,1,'uchar');
+               creator = [creator,c];
+         end;
+         fprintf(1,'\n creator : %s\n',creator);
+      else
+         fprintf('\n No creator signature\n');
+         fseek(fp,-1,'cof'); % return one char before
+      end;
+
+end
+
+   if nargin <2,
+      if strcmp(suffix,'raw')
+      % assume image size is 256x256
+         disp('RAW file without size : assume image size is 256x256');
+         n = 256;
+         m = 256;
+      else % for PGM files
+      % reads the size and depth
+          disp(' reads sizes');
+          n = fscanf(fp,'%d',1);
+          tn = num2str(n);
+          disp(['  xsize = ' tn]);
+          m = fscanf(fp,'%d',1);
+          tm = num2str(m);
+          disp(['  ysize = ' tm]);
+          p = fscanf(fp,'%d',1);
+          tp = num2str(p);
+          disp(['  depth = ' tp]);
+          c = fread(fp,1,'uchar'); %reads the last carriage return
+      end;
+   end
+
+
+   % Creates a gray palette and scale it to [0,1].
+   disp(' create gray palette');
+   for i=1:256,
+       map(i,[1:3])=[i/256,i/256,i/256];
+   end;
+   
+  
+   % Read the image
+   disp(' Reads image data ...');
+   [X,l] = fread(fp,[n,m],'uchar');
+   if l ~= m*n, l, error('HSI image file is wrong length'), end
+   % Image elements are colormap indices, so start at 1.
+   X = X'+1;
+   
+   fclose(fp);
+   
+   disp('end');
+
+else
+   error('Image file name must end in ''raw'' or ''pgm''.')
+end
+
+
+
+
diff --git a/zUtil_GVF/rawwrite.m b/zUtil_GVF/rawwrite.m
new file mode 100755
index 0000000000000000000000000000000000000000..0bc07e0f8ed0053927ebadc7658aad7ebc5fcc6a
--- /dev/null
+++ b/zUtil_GVF/rawwrite.m
@@ -0,0 +1,54 @@
+function rawwrite(X,MAX,filename);
+% RAWWRITE Write a Portable Bitmap file, or a raw file.
+%       RAWWRITE(X,MAX,'imagefile.raw') writes a "raw" image file
+%       RAWWRITE(X,MAX,'imagefile.pgm') writes a "pgm" (portable gray map) image
+%       MAX is the maximum intensity value used, must be smaller or
+%       equal to 255. If bigger, 255 is automatically used. 
+%
+%       See also RAWREAD, IMWRITE, IMREAD, IMAGE, COLORMAP.
+
+%      Chenyang Xu and Jerry L. Prince, 4/1/95, 6/17/97
+%      Copyright (c) 1995-97 by Chenyang Xu and Jerry L. Prince
+%      Image Analysis and Communications Lab, Johns Hopkins University
+
+disp('RawWrite');
+dot = max(find(filename == '.'));
+suffix = filename(dot+1:dot+3);
+
+if strcmp(suffix,'pgm') | strcmp(suffix,'raw')
+
+   disp(sprintf('\nopens %s file\n',filename));
+   fp = fopen(filename,'wb','b');  % "Big-endian" byte order.
+   
+   if (fp<0)
+      error(['Cannot open ' filename '.']);
+   end
+
+   [height,width] = size(X);
+
+   if strcmp(suffix,'pgm')
+   % Write and crack the header
+   
+      fprintf(fp,'P5\n'); % pgm magic number : P5
+
+      fprintf(fp, '%d %d\n', [height width]);
+      if (MAX>255)
+	MAX = 255;
+      end
+      fprintf(fp, '%d\n', MAX);
+   end
+
+   % Read the image
+   disp(' Writes image data ...');
+   l = fwrite(fp,X,'uchar');
+   if l ~= height*width, l, error('HSI image file is wrong length'), end
+   
+   fclose(fp);
+   
+   disp('end');
+
+else
+   error('Image file name must end in ''raw'' or ''pgm''.')
+end
+
+
diff --git a/zUtil_GVF/snakedeform.m b/zUtil_GVF/snakedeform.m
new file mode 100755
index 0000000000000000000000000000000000000000..beb26e43d9e5104fd4fe12ef98dd9b41148e0088
--- /dev/null
+++ b/zUtil_GVF/snakedeform.m
@@ -0,0 +1,74 @@
+function [x,y] = snakedeform(x,y,forcefield,options)
+alpha=options.elasticity;
+beta=options.rigidity;
+gamma=options.viscosity;
+kappa=options.forcefactor;
+ITER=options.iterations;
+fx=forcefield.x;
+fy=forcefield.y;
+
+% modified by GJ to use extrapolation value when snake is outside image
+% border
+
+
+%alpha,beta,gamma,kappa,fx,fy,ITER)
+% SNAKEDEFORM  Deform snake in the given external force field
+%     [x,y] = snakedeform(x,y,alpha,beta,gamma,kappa,fx,fy,ITER)
+%
+%     alpha:   elasticity parameter
+%     beta:    rigidity parameter
+%     gamma:   viscosity parameter
+%     kappa:   external force weight
+%     fx,fy:   external force field
+
+%      Chenyang Xu and Jerry L. Prince, 4/1/95, 6/17/97
+%      Copyright (c) 1995-97 by Chenyang Xu and Jerry L. Prince
+%      Image Analysis and Communications Lab, Johns Hopkins University
+
+% generates the parameters for snake
+
+N = length(x);
+
+alpha = alpha* ones(1,N); 
+beta = beta*ones(1,N);
+
+% produce the five diagnal vectors
+alpham1 = [alpha(2:N) alpha(1)];
+alphap1 = [alpha(N) alpha(1:N-1)];
+betam1 = [beta(2:N) beta(1)];
+betap1 = [beta(N) beta(1:N-1)];
+
+a = betam1;
+b = -alpha - 2*beta - 2*betam1;
+c = alpha + alphap1 +betam1 + 4*beta + betap1;
+d = -alphap1 - 2*beta - 2*betap1;
+e = betap1;
+
+% generate the parameters matrix
+A = diag(a(1:N-2),-2) + diag(a(N-1:N),N-2);
+A = A + diag(b(1:N-1),-1) + diag(b(N), N-1);
+A = A + diag(c);
+A = A + diag(d(1:N-1),1) + diag(d(N),-(N-1));
+A = A + diag(e(1:N-2),2) + diag(e(N-1:N),-(N-2));
+
+invAI = inv(A + gamma * diag(ones(1,N)));
+
+for count = 1:ITER,
+  % *** modified by GJ for extrapolation value (when snake is at border of
+  % image
+   vfx = interp2(fx,x,y,'linear',0);
+   vfy = interp2(fy,x,y,'linear',0);
+
+   % deform snake
+   x = invAI * (gamma* x + kappa*vfx);
+   y = invAI * (gamma* y + kappa*vfy);
+end
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_GVF/snakedeform2.m b/zUtil_GVF/snakedeform2.m
new file mode 100755
index 0000000000000000000000000000000000000000..42cdd8297a4091c36f5ecce88dc301fbfd2b0880
--- /dev/null
+++ b/zUtil_GVF/snakedeform2.m
@@ -0,0 +1,70 @@
+function [x,y] = snakedeform(x,y,alpha,beta,gamma,kappa, kappap, fx,fy,ITER)
+% SNAKEDEFORM2  Deform snake in the given external force field with
+%     pressure force added
+%     [x,y] = snakedeform(x,y,alpha,beta,gamma,kappa,kappap,fx,fy,ITER)
+%
+%     alpha:   elasticity parameter
+%     beta:    rigidity parameter
+%     gamma:   viscosity parameter
+%     kappa:   external force weight
+%     kappap:  pressure force weight
+%     fx,fy:   external force field
+
+%      Chenyang Xu and Jerry L. Prince, 4/1/95, 6/17/97
+%      Copyright (c) 1995-97 by Chenyang Xu and Jerry L. Prince
+%      Image Analysis and Communications Lab, Johns Hopkins University
+
+
+% generates the parameters for snake
+
+N = length(x);
+
+alpha = alpha* ones(1,N); 
+beta = beta*ones(1,N);
+
+% produce the five diagnal vectors
+alpham1 = [alpha(2:N) alpha(1)];
+alphap1 = [alpha(N) alpha(1:N-1)];
+betam1 = [beta(2:N) beta(1)];
+betap1 = [beta(N) beta(1:N-1)];
+
+a = betam1;
+b = -alpha - 2*beta - 2*betam1;
+c = alpha + alphap1 +betam1 + 4*beta + betap1;
+d = -alphap1 - 2*beta - 2*betap1;
+e = betap1;
+
+% generate the parameters matrix
+A = diag(a(1:N-2),-2) + diag(a(N-1:N),N-2);
+A = A + diag(b(1:N-1),-1) + diag(b(N), N-1);
+A = A + diag(c);
+A = A + diag(d(1:N-1),1) + diag(d(N),-(N-1));
+A = A + diag(e(1:N-2),2) + diag(e(N-1:N),-(N-2));
+
+invAI = inv(A + gamma * diag(ones(1,N)));
+
+for count = 1:ITER,
+  vfx = interp2(fx,x,y);
+   vfy = interp2(fy,x,y);
+  
+   % adding the pressure force 	
+   xp = [x(2:N);x(1)];    yp = [y(2:N);y(1)]; 
+   xm = [x(N);x(1:N-1)];  ym = [y(N);y(1:N-1)]; 
+   
+   qx = xp-xm;  qy = yp-ym;
+   pmag = sqrt(qx.*qx+qy.*qy);
+   px = qy./pmag;     py = -qx./pmag;
+
+   % deform snake
+   x = invAI * (gamma* x + kappa*vfx + kappap.*px);
+   y = invAI * (gamma* y + kappa*vfy + kappap.*py);
+end
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_GVF/snakedisp.m b/zUtil_GVF/snakedisp.m
new file mode 100755
index 0000000000000000000000000000000000000000..7ea429169ce1bdccd25292979adba6872ab2376c
--- /dev/null
+++ b/zUtil_GVF/snakedisp.m
@@ -0,0 +1,24 @@
+function [vargout]=snakedisp(x,y,style)
+% SNAKEDISP  Initialize the snake 
+%      snakedisp(x,y,line)
+%       
+%      style is same as the string for plot
+
+%      Chenyang Xu and Jerry L. Prince, 5/15/95, 6/17/97
+%      Copyright (c) 1995-97 by Chenyang Xu and Jerry L. Prince
+%      Image Analysis and Communications Lab, Johns Hopkins University
+
+hold on
+
+% convert to column data
+x = x(:); y = y(:);
+
+if nargin == 3
+   hp=plot([x;x(1,1)],[y;y(1,1)],style);
+   hold off
+else
+   disp('snakedisp.m: The input parameter is not correct!'); 
+end
+if nargout==1 
+  vargout(1)=hp;
+end
diff --git a/zUtil_GVF/snakeindex.m b/zUtil_GVF/snakeindex.m
new file mode 100755
index 0000000000000000000000000000000000000000..f497c8b9c309138394ed53c86fc1d678328b4d61
--- /dev/null
+++ b/zUtil_GVF/snakeindex.m
@@ -0,0 +1,12 @@
+function y = snakeindex(IDX)
+% SNAKEINDEX  Create index for adpative interpolating the snake 
+%     y = snakeindex(IDX)
+%
+
+N = length(IDX);
+y=1:0.5:N+0.5;
+x=1:N;
+y(2*x(IDX==0))=[];
+
+
+
diff --git a/zUtil_GVF/snakeinit.m b/zUtil_GVF/snakeinit.m
new file mode 100755
index 0000000000000000000000000000000000000000..b2785ef5dbc4f4aa9f3e4f5cf973062db2219e98
--- /dev/null
+++ b/zUtil_GVF/snakeinit.m
@@ -0,0 +1,46 @@
+function [x,y] = snakeinit(delta)
+%SNAKEINIT  Manually initialize a 2-D, closed snake 
+%   [x,y] = SNAKEINIT(delta)
+%
+%   delta: interpolation step
+
+%   Chenyang Xu and Jerry L. Prince, 4/1/95, 6/17/97
+%   Copyright (c) 1995-97 by Chenyang Xu and Jerry L. Prince
+%   Image Analysis and Communications Lab, Johns Hopkins University
+
+hold on
+
+x = [];
+y = [];
+n =0;
+
+% Loop, picking up the points
+disp('Left mouse button picks points.')
+disp('Right mouse button picks last point.')
+
+but = 1;
+while but == 1
+      [s, t, but] = ginput(1);
+      n = n + 1;
+      x(n,1) = s;
+      y(n,1) = t;
+      plot(x, y, 'r-');
+end   
+
+plot([x;x(1,1)],[y;y(1,1)],'r-');
+hold off
+
+% sampling and record number to N
+x = [x;x(1,1)];
+y = [y;y(1,1)];
+t = 1:n+1;
+ts = [1:delta:n+1]';
+xi = interp1(t,x,ts);
+yi = interp1(t,y,ts);
+n = length(xi);
+x = xi(1:n-1);
+y = yi(1:n-1);
+
+
+
+
diff --git a/zUtil_GVF/snakeinterp.m b/zUtil_GVF/snakeinterp.m
new file mode 100755
index 0000000000000000000000000000000000000000..a28916cd9adf6eec6ee8465fd936b5363336da11
--- /dev/null
+++ b/zUtil_GVF/snakeinterp.m
@@ -0,0 +1,69 @@
+function [xi,yi] = snakeinterp(x,y,dmax,dmin)
+  %SNAKEINTERP  Interpolate the snake adaptively
+  %   [xi,yi] = snakeinterp(x,y,dmax,dmin)
+  %
+  %   dmax: the maximum distance between two snake points
+  %   dmin: the maximum distance between two snake points
+  %   d(i,i+1)>dmax, then a new point is added between i and i+1
+  %   d(i,i+1)<dmin, then either i or i+1 is removed
+  %
+  %   NOTE: the spacing of original curve must be close to the
+  %         range defined by dmax and dmin. For arbitrary spacing,
+  %         try snakeinterp1.
+  %
+  %   See also SNAKEINTERP1
+
+  %    there is a bug in the program for points removal
+
+  %   Chenyang Xu and Jerry L. Prince, 4/1/95, 6/17/97
+  %   Copyright (c) 1995-97 by Chenyang Xu and Jerry L. Prince
+  %   Image Analysis and Communications Lab, Johns Hopkins University
+
+  % convert to column vector
+  x = x(:); y = y(:);
+
+  N = length(x);
+
+  d = abs(x([2:N 1])- x(:)) + abs(y([2:N 1])- y(:));
+
+  % remove the points which distance to neighbor points is shorter than dmin
+  IDX = (d<dmin);
+
+  idx = find(IDX==0);
+  if ~isempty(idx)  % added by Greg to fix point removal bug
+    x = x(idx);
+    y = y(idx);
+  end
+
+  N = length(x);
+  d = abs(x([2:N 1])- x(:)) + abs(y([2:N 1])- y(:));
+
+  IDX = (d>dmax);
+
+  z = snakeindex(IDX);
+
+  p = 1:N+1;
+
+  xi = interp1(p,[x;x(1)],z');
+  yi = interp1(p,[y;y(1)],z');
+
+  N = length(xi);
+  d = abs(xi([2:N 1])- xi(:)) + abs(yi([2:N 1])- yi(:));
+
+  while (max(d)>dmax),
+
+    IDX = (d>dmax);
+    z = snakeindex(IDX);
+
+    p = 1:N+1;
+
+    xi = interp1(p,[xi;xi(1)],z');
+    yi = interp1(p,[yi;yi(1)],z');
+
+    N = length(xi);
+    d = abs(xi([2:N 1])- xi(:)) + abs(yi([2:N 1])- yi(:));
+  end
+
+
+
+
diff --git a/zUtil_GVF/snakeinterp1.m b/zUtil_GVF/snakeinterp1.m
new file mode 100755
index 0000000000000000000000000000000000000000..ac857f07432c017636d88e8209b147e434c15f9c
--- /dev/null
+++ b/zUtil_GVF/snakeinterp1.m
@@ -0,0 +1,50 @@
+function [xi,yi] = snakeinterp1(x,y,RES)
+% SNAKEINTERP1  Interpolate the snake to have equal distance RES
+%     [xi,yi] = snakeinterp(x,y,RES)
+%
+%     RES: resolution desired
+
+%     update on snakeinterp after finding a bug
+
+%      Chenyang Xu and Jerry L. Prince, 3/8/96, 6/17/97
+%      Copyright (c) 1996-97 by Chenyang Xu and Jerry L. Prince
+%      Image Analysis and Communications Lab, Johns Hopkins University
+
+% convert to column vector
+x = x(:); y = y(:);
+
+N = length(x);  
+
+% make it a circular list since we are dealing with closed contour
+x = [x;x(1)];
+y = [y;y(1)];
+
+dx = x([2:N+1])- x(1:N);
+dy = y([2:N+1])- y(1:N);
+d = sqrt(dx.*dx+dy.*dy);  % compute the distance from previous node for point 2:N+1
+
+d = [0;d];   % point 1 to point 1 is 0 
+
+% now compute the arc length of all the points to point 1
+% we use matrix multiply to achieve summing 
+M = length(d);
+d = (d'*uppertri(M,M))';
+
+% now ready to reparametrize the closed curve in terms of arc length
+maxd = d(M);
+
+if (maxd/RES<3)
+   error('RES too big compare to the length of original curve');
+end
+
+di = 0:RES:maxd;
+
+xi = interp1(d,x,di);
+yi = interp1(d,y,di);
+
+N = length(xi);
+
+if (maxd - di(length(di)) <RES/2)  % deal with end boundary condition
+   xi = xi(1:N-1);
+   yi = yi(1:N-1);
+end
diff --git a/zUtil_GVF/xconv2.m b/zUtil_GVF/xconv2.m
new file mode 100755
index 0000000000000000000000000000000000000000..bc1ef0890ea82e23b0b923221be4d05842e57ea2
--- /dev/null
+++ b/zUtil_GVF/xconv2.m
@@ -0,0 +1,26 @@
+function Y = xconv2(I,G)
+% function Y = xconv2(I,G)
+%   I: the original image
+%   G: the mask to be convoluted
+%   Y: the convoluted result (by taking fft2, multiply and ifft2)
+% 
+%   a similar version of the MATLAB conv2(I,G,'same'),  7/10/95
+%   implemented by fft instead of doing direct convolution as in conv2
+%   the result is almost same , differences are under 1e-10.
+%   However, the speed of xconv2 is much faster than conv2 when
+%   gaussian kernel has large standard variation.
+
+%   Chenyang Xu and Jerry L. Prince, 7/10/95, 6/17/97
+%   Copyright (c) 1995-97 by Chenyang Xu and Jerry L. Prince
+%   Image Analysis and Communications Lab, Johns Hopkins University
+%
+
+[n,m] = size(I);
+[n1,m1] = size(G);
+FI = fft2(I,n+n1-1,m+m1-1);  % avoid aliasing
+FG = fft2(G,n+n1-1,m+m1-1);
+FY = FI.*FG;
+YT = real(ifft2(FY));
+nl = floor(n1/2);
+ml = floor(m1/2);
+Y = YT(1+nl:n+nl,1+ml:m+ml);
\ No newline at end of file
diff --git a/zUtil_Help/makehtmldoc.html b/zUtil_Help/makehtmldoc.html
new file mode 100755
index 0000000000000000000000000000000000000000..66a6b46d48c940cf9125047ba0d753df8a0cc22e
--- /dev/null
+++ b/zUtil_Help/makehtmldoc.html
@@ -0,0 +1,76 @@
+<html><head><title>makehtmldoc</title>
+<!-- Help file for makehtmldoc.m generated by makehtmldoc 1.20, 13-Sep-2006 14:21:13 -->
+<!-- makehtmldoc (F. Moisy, 2005), see http://www.fast.u-psud.fr/~moisy/ml/ -->
+ 
+<link rel=stylesheet href="docstyle1.css" type="text/css">
+</head>
+<body bgcolor=#ffffff>
+<table width="100%" border=0 cellpadding=0 cellspacing=0><tr><td valign=baseline bgcolor="#e7ebf7"><b><a href="Contents.html">Contents</a></b></td><td valign=baseline bgcolor="#e7ebf7" align=right><a href="._makehtmldoc.html"><b>&lt;&lt; Prev</b></a>&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td></tr></table>
+<font size=+3 color="#990000">makehtmldoc</font><br>
+Create HTML help files from a set of M-Files<br>
+<br>
+ 
+<font size=+1 color="#990000"><b>Description</b></font>
+<code><pre>
+<b>makehtmldoc</b>(FILENAME) creates an html help file for each M-File 
+matching FILENAME. This help file contains the header of the M-File 
+(the first block of contiguous comment lines, see HELP for details), 
+with links between each M-File matching FILENAME referencing each 
+other. 
+ 
+If no input argument specified, works with all the M-files of the 
+current directory (ie, <b>makehtmldoc</b>('*.m')). 
+ 
+<b>makehtmldoc</b>(FILENAME, 'Property1', 'Property2'...) where 'Property.' 
+may be: 
+ 
+  'code'               adds a link to the source code (except for the 
+                       file 'Contents.m'); 
+  'upper'              makes a link only for words in upper case. 
+  'quiet'              does not display informations during the 
+                       processing. 
+  'color', string      any HTML color code for the upper and lower 
+                       panels. Default = '#e7ebf7'. 
+  'title', string      title of the web window. Default = '\f'. 
+  'firstline', string  text at the top of the page. Default = 
+                       'Contents'. 
+  'lastline', string   text at the bottom of the page. Default = ''. 
+ 
+Note: In the string of the last three properties, '\f' will be replaced 
+by the name of the current M-file. Web links may be used, e.g. 
+string = '\f (&lt;a href="MyToolbox.html"&gt;MyToolbox&lt;/a&gt;)' 
+ 
+<b>makehtmldoc</b> works essentially as Matlab's DOC function, except that the 
+links are only established between the set of files matching FILENAME. 
+So the resulting set of HTML pages only have link between themselves, 
+and will not have broken links when consulted from an external web 
+site. 
+ 
+Examples: 
+   <b>makehtmldoc</b>('*.m','code')  produces a set of *.html help files for 
+   all the *.m files of the current directory, with a link to the 
+   corresponding source code. 
+ 
+   <b>makehtmldoc</b>('*.m','title','\f (MyToolbox)','lastline','(c) 2006'); 
+ 
+   <b>makehtmldoc</b>('*.m', ... 
+               'color', '#ffff00', ... 
+               'title', 'Help for \f', ... 
+               'firstline', '&lt;a href="Contents.html"&gt;Back&lt;/a&gt;', ... 
+               'lastline', '&lt;a href="www.mytoolbox.com"&gt;MyToolBox&lt;/a&gt;', ... 
+               'upper', 'code'); 
+ 
+F. Moisy 
+Revision: 1.20,  Date: 2006/09/06. 
+ 
+</pre>
+<font size=+1 color="#990000"><b>See Also</b></font>
+<pre>
+HELP, DOC, WEB. 
+</pre></code>
+ 
+<br>
+<table width="100%" border=0 cellspacing=0 bgcolor="#e7ebf7"><tr><td>&nbsp;<a href="._makehtmldoc.html"><b>Previous: ._makehtmldoc</b></a></td><td align=right>&nbsp;</td></tr></table><br>
+<br>
+<font size=-1>Help file generated by <a href="http://www.fast.u-psud.fr/~moisy/ml" target="_blank">makehtmldoc 1.20</a></font><br>
+</body></html>
diff --git a/zUtil_Help/makehtmldoc.m b/zUtil_Help/makehtmldoc.m
new file mode 100755
index 0000000000000000000000000000000000000000..000ca75a34caff02a0e40b43b032c27b6b384015
--- /dev/null
+++ b/zUtil_Help/makehtmldoc.m
@@ -0,0 +1,303 @@
+function makehtmldoc(filename,varargin)
+%MAKEHTMLDOC Create HTML help files from a set of M-Files
+%   MAKEHTMLDOC(FILENAME) creates an html help file for each M-File
+%   matching FILENAME. This help file contains the header of the M-File
+%   (the first block of contiguous comment lines, see HELP for details),
+%   with links between each M-File matching FILENAME referencing each
+%   other.
+%
+%   If no input argument specified, works with all the M-files of the
+%   current directory (ie, MAKEHTMLDOC('*.m')).
+%
+%   MAKEHTMLDOC(FILENAME, 'Property1', 'Property2'...) where 'Property.'
+%   may be:
+%
+%     'code'               adds a link to the source code (except for the
+%                          file 'Contents.m');
+%     'upper'              makes a link only for words in upper case.
+%     'quiet'              does not display informations during the
+%                          processing.
+%     'color', string      any HTML color code for the upper and lower
+%                          panels. Default = '#e7ebf7'.
+%     'title', string      title of the web window. Default = '\f'.
+%     'firstline', string  text at the top of the page. Default =
+%                          'Contents'.
+%     'lastline', string   text at the bottom of the page. Default = ''.
+%
+%   Note: In the string of the last three properties, '\f' will be replaced
+%   by the name of the current M-file. Web links may be used, e.g.
+%   string = '\f (<a href="MyToolbox.html">MyToolbox</a>)'
+%
+%   MAKEHTMLDOC works essentially as Matlab's DOC function, except that the
+%   links are only established between the set of files matching FILENAME.
+%   So the resulting set of HTML pages only have link between themselves,
+%   and will not have broken links when consulted from an external web
+%   site.
+%
+%   Examples:
+%      makehtmldoc('*.m','code')  produces a set of *.html help files for
+%      all the *.m files of the current directory, with a link to the
+%      corresponding source code.
+%
+%      makehtmldoc('*.m','title','\f (MyToolbox)','lastline','(c) 2006');
+%
+%      makehtmldoc('*.m', ...
+%                  'color', '#ffff00', ...
+%                  'title', 'Help for \f', ...
+%                  'firstline', '<a href="Contents.html">Back</a>', ...
+%                  'lastline', '<a href="www.mytoolbox.com">MyToolBox</a>', ...
+%                  'upper', 'code');
+%
+%   F. Moisy
+%   Revision: 1.20,  Date: 2006/09/06.
+%
+%   See also HELP, DOC, WEB.
+
+% History:
+% 2005/10/18: v1.00, first version.
+% 2005/10/19: v1.02, process the 'See Also' section.
+% 2005/10/20: v1.03, option 'quiet' added.
+% 2005/10/22: v1.04, prev and next in the upper menu bar added
+% 2005/10/28: v1.05, prev and next instead of < and >.
+% 2005/11/01: v1.06, <pre> mode (keeps normal white spaces instead of &nbsp;)
+% 2006/06/02: v1.10, works with varargin input arguments
+% 2006/06/16: v1.11, minor bug fixed with docstyle.css
+% 2006/07/21: v1.12, option 'lastline' added
+% 2006/09/04: v1.13, options 'title' and 'contentspage' added
+% 2006/09/06: v1.20, renamed 'makehtmldoc' (was named m2html before).
+%                    upper table modified (options 'firstline' and 'color'
+%                    added)                
+
+
+if nargin==0,
+    filename='*.m';
+end;
+
+listefilename=dir(filename);
+listefilename={listefilename.name};
+
+if ~length(listefilename)
+    error('No file match.');
+end;
+
+% iscontents is 1 if the file 'Contents.m' is present, 0 otherwise:
+iscontents=any(strcmp(listefilename,'Contents.m'));
+
+% color of upper and lower table (new v1.20)
+if any(strncmpi(varargin,'color',3)),
+    colortable = varargin{1+find(strncmpi(varargin,'color',3),1,'last')};
+else
+    colortable = '#e7ebf7';
+end;
+
+for f=1:length(listefilename),
+    nbrelink=0;
+    filename=listefilename{f};
+    [pathstr,name,ext] = fileparts(filename);
+    if ~strcmp(ext,'.m'),
+        error([filename ' is not an M-file.']);
+    end;
+    htmlfilename=fullfile(pathstr,[name '.html']);
+    fid=fopen(htmlfilename,'w');
+    if fid==-1
+        error(['Can''t create ' htmlfilename]);
+    end;
+
+    % title of the html page (new v1.13):
+    if any(strncmpi(varargin,'title',3)),
+        titlehtmlpage = varargin{1+find(strncmpi(varargin,'title',3),1,'last')};
+    else
+        titlehtmlpage = '\f';
+    end;
+    titlehtmlpage = strrep(titlehtmlpage,'\f',name);
+    
+    % head of the html page:
+    fprintf(fid,'%s\n',['<html><head><title>' titlehtmlpage '</title>']);
+    fprintf(fid,'%s\n',['<!-- Help file for ' name '.m generated by makehtmldoc 1.20, ' datestr(now) ' -->']);
+    fprintf(fid,'%s\n','<!-- makehtmldoc (F. Moisy, 2005), see http://www.fast.u-psud.fr/~moisy/ml/ -->');
+    fprintf(fid,'%s\n',' ');
+    fprintf(fid,'%s\n','<link rel=stylesheet href="docstyle1.css" type="text/css">');
+    fprintf(fid,'%s\n','</head>');
+    fprintf(fid,'%s\n','<body bgcolor=#ffffff>');
+
+    % upper table: links to the code source (if option 'code') and to the
+    % Contents file (if present), except for the Contents.m file itself:
+    if ~strcmpi(name,'contents'),
+        headfline='<table width="100%" border=0 cellpadding=0 cellspacing=0><tr>';
+        tailfline='</tr></table>';
+        firstlinetext='<a href="Contents.html">Contents</a>';
+        if iscontents,
+            if any(strncmpi(varargin,'firstline',4)),
+                firstlinetext = varargin{1+find(strncmpi(varargin,'firstline',4),1,'last')};
+                firstlinetext = strrep(firstlinetext,'\f',name);
+            end;
+        end;
+        fline1=['<td valign=baseline bgcolor="' colortable '"><b>' firstlinetext '</b></td>'];
+
+        if any(strncmpi(varargin,'code',3))
+            fline2=['<td valign=baseline bgcolor="' colortable '" align=center>&nbsp;<a href="matlab:open ''' name '.m''"><b>View code</b></a></td>'];
+        else
+            fline2='';
+        end;
+        
+        if length(listefilename)>1,
+            fline3=['<td valign=baseline bgcolor="' colortable '" align=right>'];
+            if f>1,
+                [pathstr prevfname ext]=fileparts(listefilename{f-1});
+                fline3=[fline3 '<a href="' prevfname '.html"><b>&lt;&lt; Prev</b></a>&nbsp;'];
+            else
+                fline3=[fline3 '<b>&lt;</b>&nbsp;'];
+            end;
+            if f<length(listefilename),
+                [pathstr nextfname ext]=fileparts(listefilename{f+1});
+                fline3=[fline3 '|&nbsp;<a href="' nextfname '.html"><b>Next &gt;&gt;</b></a>&nbsp;'];
+            else
+                fline3=[fline3 '|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'];
+            end;
+            fline3=[fline3 '</td>'];
+        else
+            fline3='';
+        end;
+        fprintf(fid,'%s\n',[headfline fline1 fline2 fline3 tailfline]);
+    end;
+
+    helptext=help(filename);
+
+    % suppress the 'overloaded ...' part (for Contents.m file)
+    pover=strfind(helptext,'Overloaded');
+    if length(pover),
+        helptext=[helptext(1:(pover-1)) char(10)];
+    end;
+
+    % number of initial spaces to jump at each line
+    % (this value may be overestimated):
+    firstchar=6;
+
+    remhelptext=helptext; % initialize the remainder of the help text
+    firstline = true;
+    while length(remhelptext),
+        %extracts the first line of the remainder of the help text:
+        pnextenter=strfind(remhelptext,10); pnextenter=pnextenter(1);
+        curline=remhelptext(1:(pnextenter-1)); % current line
+
+        % removes the < and > signs (confusion with html syntax):
+        curline=strrep(curline,'<','&lt;');
+        curline=strrep(curline,'>','&gt;');
+
+        if firstline, % the first line of the help text is the name of the function
+            if ~strcmpi(name,'contents'),
+                fprintf(fid,'%s\n',['<font size=+3 color="#990000">' lower(name) '</font><br>']);
+                [token,remline]=strtok(curline);
+                fprintf(fid,'%s\n',[strtrim(remline) '<br>']);
+            else
+                fprintf(fid,'%s\n',['<font size=+3 color="#990000">' curline '</font><br>']);
+            end;
+            fprintf(fid,'%s\n','<br>');
+            fprintf(fid,'%s\n',' ');
+            if ~strcmpi(name,'contents'),
+                fprintf(fid,'%s\n','<font size=+1 color="#990000"><b>Description</b></font>');
+            end;
+            fprintf(fid,'%s\n','<code><pre>');
+            firstline = false;
+        else
+            % removes the first white spaces:
+            curline=[curline '           '];
+            while ~isequal(curline(firstchar-1),' '),
+                firstchar=firstchar-1; %
+            end;
+            curline=deblank(curline(firstchar:end));
+
+            % detects the 'See Also' section  (v1.01)
+            pseealso=strfind(lower(curline),'see also');
+            if ((length(pseealso))&&(length(curline)>2)),
+                pseealso=pseealso(1);
+                fprintf(fid,'%s\n','</pre>');
+                fprintf(fid,'%s\n','<font size=+1 color="#990000"><b>See Also</b></font>');
+                fprintf(fid,'%s\n','<pre>');
+                curline=curline((pseealso+9):end);
+                seealsotoken=strtok(curline);
+                pp=strfind(curline,seealsotoken); pp=pp(1); % position of the first character of the "see also" words
+                curline=curline(pp:end);
+            end;
+
+            remline=curline; % remainder of the current line
+
+            while length(remline),
+                [token, newremline] = strtok(remline,' ,.;:!?()[]{}"''=+-*/'); % next word
+                if length(token)
+                    pnextword=strfind(remline,token); pnextword=pnextword(1); % position of the next word
+                    fprintf(fid,'%s',remline(1:(pnextword-1))); % writes the characters before % changed v1.06
+                    makelink=0;
+                    if strcmpi(token,name)
+                        makelink=-1; % if the word is the filename itself, displays it in bold
+                    else
+                        if logical(sum(ismember(listefilename,lower([token '.m'])))),
+                            if any(strncmpi(varargin,'upper',1))
+                                makelink=strcmp(token,upper(token)); % makes a link only if the word is in upper case
+                            else
+                                makelink=1;
+                            end;
+                        end;
+                    end;
+                    if makelink==1
+                        fprintf(fid,'%s',['<a href="' lower(token) '.html">' lower(token) '</a>']);
+                        nbrelink=nbrelink+1;
+                    elseif makelink==-1,
+                        fprintf(fid,'%s',['<b>' lower(token) '</b>']);
+                    else
+                        fprintf(fid,'%s',token);   % no link for this word
+                    end;
+                else  % if no word found until the end of the line, simply writes the end of the line:
+                    fprintf(fid,'%s',remline);
+                end;
+                remline=newremline;
+            end;
+            fprintf(fid,'%s\n',' '); % end of the line
+        end;
+        remhelptext=remhelptext((pnextenter+1):end); % new remainder
+    end;
+    fprintf(fid,'%s\n','</pre></code>');  % end of "code" section
+
+    fprintf(fid,'%s\n',' ');
+
+    % lower table (links to the previous and next filenames):
+    if ~strcmpi(name,'contents'),
+        if length(listefilename)>1,
+            headfline=['<table width="100%" border=0 cellspacing=0 bgcolor="' colortable '"><tr>'];
+            tailfline='</tr></table><br>';
+            if f==1,
+                fline1='<td>&nbsp;</td>';
+            else
+                [pathstr prevfname ext]=fileparts(listefilename{f-1});
+                fline1=['<td>&nbsp;<a href="' prevfname '.html"><b>Previous: ' prevfname '</b></a></td>'];
+            end;
+            if f==length(listefilename),
+                fline2='<td align=right>&nbsp;</td>';
+            else
+                [pathstr nextfname ext]=fileparts(listefilename{f+1});
+                fline2=['<td align=right><a href="' nextfname '.html"><b>Next: ' nextfname '</b></a>&nbsp;</td>'];
+            end;
+            fprintf(fid,'%s\n','<br>');
+            fprintf(fid,'%s\n',[headfline fline1 fline2 tailfline]);
+        end;
+    end;
+
+    % foot of the html page:
+    if any(strncmpi(varargin,'lastline',4)),
+        lastline = varargin{1+find(strncmpi(varargin,'lastline',4),1,'last')};
+        lastline = strrep(lastline,'\f',name);
+        fprintf(fid,'%s\n',[lastline '<br>']);
+    end;
+    
+    fprintf(fid,'%s\n','<br>');
+    if ~any(strncmpi(varargin,'noadver',4)),  % hidden option: 'noad'
+        fprintf(fid,'%s\n','<font size=-1>Help file generated by <a href="http://www.fast.u-psud.fr/~moisy/ml" target="_blank">makehtmldoc 1.20</a></font><br>');
+    end;
+    fprintf(fid,'%s\n','</body></html>');
+    fclose(fid);
+
+    % new v1.02
+    if ~any(strncmpi(varargin,'quiet',1)),
+        disp([name '.m --> ' name '.html  [' num2str(nbrelink) ' links]']);
+    end;
+end;
diff --git a/zUtil_Help/publish_gt.m b/zUtil_Help/publish_gt.m
new file mode 100755
index 0000000000000000000000000000000000000000..d1a1b2b7a77be169ea9c2b55fbe854bc0c2cd61f
--- /dev/null
+++ b/zUtil_Help/publish_gt.m
@@ -0,0 +1,15 @@
+%% PUBLISH_GT.M  Generates html documentation for Graintracking
+% There are some instructions somewhere...
+function publish_gt(filename)
+  
+  opts.outputDir='/data/id19/graintracking/matlab/html';
+  opts.evalCode=false;
+opts.showCode=false;
+publish(filename,opts);
+
+if strcmp(filename(end-1:end),'.m')
+  htmlname = [filename(1:end-2) '.html'];
+else
+  htmlname = [filename '.html'];
+end
+web([opts.outputDir '/' htmlname])
\ No newline at end of file
diff --git a/zUtil_ICP/README.txt b/zUtil_ICP/README.txt
new file mode 100755
index 0000000000000000000000000000000000000000..2a3c137468fff1de3c4e6d088a71122dd3c70c97
--- /dev/null
+++ b/zUtil_ICP/README.txt
@@ -0,0 +1,61 @@
+
+
+This Matlab implementation of the ICP (Iterative Closest Point) algorithm 
+is licensed under the GNU General Public License version 2 or later. 
+
+Before starting using and/or changing any of the files included here, please
+take a moment and reade the included "gpl.txt" file or get it at:
+
+http://www.gnu.org/licenses/gpl.html
+
+
+All Matlab files included here must contain the following text, which should
+be also visible from Matlab's help:
+%
+%/***************************************************************************
+% *                                                                         *
+% *   This program is not free software. It is distributed under the        *
+% *   GNU General Public License version 2 or later. See the included       *
+% *   "gpl.txt" file or get it at http://www.gnu.org/licenses/gpl.html      *
+% *                                                                         *
+% *   This program is the property of ETH (Swiss Federal Institute of       * 
+% *   Technology) and the author. For feedback and comments please contact  *
+% *   pirnog@vision.ee.ethz.ch                                              *
+% *                                                                         *
+% ***************************************************************************/
+%
+
+
+This directory should contain at least the following files:
+
+  closestPoint.m           - implements one iteration of the ICP
+  iterativeClosestPoint.m  - performs the actual ICP
+  testICP.m                - test file for the algorithm
+  gpl.txt                  - GNU General Public License version 2
+
+
+If any of this files is missig, please contact Cristian Pirnog at:
+pirnog@vision.ee.ethz.ch.
+
+
+The directory may also contain any of these sample data files:
+
+  data1.txt
+  data1_isotropic.txt
+  data2.txt
+  data2_isotropic.txt
+
+The sample data files can be used directly with "testICP.m", to give you
+an ideea of how these programs work.
+
+Best regards,
+Cristian Pirnog
+
+
+
+ ---------------------------------------------
+| Cristian Pirnog - pirnog@vision.ee.ethz.ch  |
+| ETZ F 71, Gloriastrasse 35                  |
+| ETH Zentrum, 8092 Zurich,  Tel. 01 632 7948 |
+| Web Page: www.vision.ee.ethz.ch/~pirnog     |
+ ---------------------------------------------
\ No newline at end of file
diff --git a/zUtil_ICP/closestPoint.m b/zUtil_ICP/closestPoint.m
new file mode 100755
index 0000000000000000000000000000000000000000..fe6a28640fad09a37a35e18789f0815b4e334f1f
--- /dev/null
+++ b/zUtil_ICP/closestPoint.m
@@ -0,0 +1,212 @@
+% CLOSESTPOINT Compute one step of the Iterative Closest Point (ICP) algorithm.
+%
+% [TR, ROT] = closestPoint(REF, FLT) returns the translation vector
+%   TR and the rotation matrix ROT that lead to the minimization of
+%   the total distance from the floating points FLT to their
+%   corresponding closest reference points REF. The vectors FLT and
+%   REF must have size either Mx3 and Nx3 or 3xM and 3xN (where M
+%   and N are the number of reference and floating points
+%   respectively).
+%
+%   Important: THIS ALGORITHM WORKS ONLY FOR THREE DIMENSIONAL POINTS.
+%
+%   Each floating point has a CLOSEST_DISTANCE, which is the
+%   distance from it to its closest reference point.
+%
+% [TR, ROT] = closestPoint(REF, FLT, THR) will use the supplied
+%   threshold THR for leaving out possible outliers. A floating
+%   point is considered outlier if its CLOSEST_DISTANCE is outside
+%   the domain [0, AVG_DIST+THR], where AVG_DIST is the average
+%   distance of all the floating points.
+%
+% [TR, ROT, AVG_DIST] = closestPoint(REF, FLT) will also return the
+%   average CLOSEST_DISTANCE, which can be used to stop the ICP
+%   algorithm if early convergence was achieved.
+%
+%   If no threshold is supplied, CLOSESTPOINT will use the
+%   default threshold, which is 2*DIST_ST_DEV, where DIST_ST_DEV
+%   is the standard deviation of the floating points
+%   CLOSEST_DISTANCEs.
+%
+%   Example:
+%
+%   See also: ITERATIVECLOSESTPOINT
+%
+%
+% Author:  Cristian Pirnog
+%          Computer Vision Laboratory - ETH Zurich
+%          pirnog@vision.ee.ethz.ch
+%
+% Created: 12 May 2004
+%
+%/***************************************************************************
+% *                                                                         *
+% *   This program is not free software. It is distributed under the        *
+% *   GNU General Public License version 2 or later. See the included       *
+% *   "gpl.txt" file or get it at http://www.gnu.org/licenses/gpl.html      *
+% *                                                                         *
+% *   This program is the property of ETH (Swiss Federal Institute of       * 
+% *   Technology) and the author. For feedback and comments please contact  *
+% *   pirnog@vision.ee.ethz.ch                                              *
+% *                                                                         *
+% ***************************************************************************/
+%
+
+function [translation, rotation, varargout] = closestPoint(referencePoints, ...
+						  floatingPoints, varargin)
+
+
+%===============================================================
+% Check that the data is given in a 2D matrix
+%===============================================================
+if ndims(referencePoints)~=2
+  error('The reference matrix must be two dimensional.')
+end
+
+if ndims(floatingPoints)~=2
+  error('The floating matrix must be two dimensional.')
+end
+
+
+%===============================================================
+% Check that the data is 3-dimensional
+%===============================================================
+noOfDims = 3;
+if ~(size(referencePoints)==noOfDims) | ~sum(size(floatingPoints)==noOfDims)
+  error('This algorithm works only for 3D points.')
+end
+
+%===============================================================
+% Check for 3X3 matrices (where you cannot differenciate the 
+% dimension from the number of points)
+%===============================================================
+if size(referencePoints)==[noOfDims, noOfDims]
+  error( ['Te reference data matrix has size [', ...
+	  int2str(noOfDims), ', ', int2str(noOfDims), ...
+	  '].', ...
+	  'Cannot differenciate between the coordinates and the', ...
+	  ' actual points.']);
+end
+
+
+
+% Make the floating data points have the coordinates on columns
+%
+% floatingPoints = [ x1, y1, z1;
+%                    x2, y2, z2;
+%                    x3, y3, z3;
+%                    x4, y4, z4;
+%                       ...
+%                    xN, yN, zN];
+%
+if size(floatingPoints, 1)==noOfDims
+  floatingPoints=floatingPoints.';
+end
+
+% Same for the reference data points
+if size(referencePoints, 1)==noOfDims
+  referencePoints=referencePoints.';
+end
+
+% The number of original floating and reference points
+floatingPointsNo=size(floatingPoints, 1);
+referencePointsNo=size(referencePoints, 1);
+
+
+%----------------------------------------------------------
+%           Start closest point computation
+%----------------------------------------------------------
+
+% 1. Find the reference points the that are closest to each floating
+% point
+closestPoints=[];
+minDistances=[];
+for i=1:floatingPointsNo
+  distances = sum((referencePoints - repmat(floatingPoints(i, :), ...
+					    referencePointsNo, 1)).^2, 2);
+  
+  [dist, index]=min(distances);
+  minDistances(i)=sqrt(dist);
+  
+  closestPoints(i, :)=referencePoints(index, :);
+end
+
+
+% 2. Elliminate the possible outliers
+meanDist=mean(minDistances);
+if nargin==3
+  threshold=varargin{:, 1};
+else
+  stdDev=std(minDistances, 1);
+  threshold=2*stdDev;
+end
+
+
+% 3. Keep the good floating points...
+goodFloatingPoints = floatingPoints(minDistances-meanDist<threshold, :);
+% ... and their corresponding closest points
+closestPoints = closestPoints(minDistances-meanDist<threshold, :);
+
+if isempty(closestPoints)
+  error(['The closest points vector is empty. You probably set a' ...
+	 ' too big threshold']);
+end
+
+drawnow
+% 4. Compute the center of the floating and reference (closest) points
+centerOfMass_flt = mean(goodFloatingPoints, 1);
+centerOfMass_ref = mean(closestPoints, 1);
+
+drawnow
+% 5. Compute the cross-covariance matrix
+goodPointsNo=size(closestPoints, 1);
+C = closestPoints.'*goodFloatingPoints/goodPointsNo;
+C = (C - centerOfMass_ref.'*centerOfMass_flt).';
+
+drawnow
+% 6. Compute "delta"
+delta = [C(2, 3) - C(3, 2),
+	 C(3, 1) - C(1, 3),
+	 C(1, 2) - C(2, 1)].';
+
+% ... and cross-covariance matrix trace
+traceC=trace(C);
+
+drawnow
+% 7. Compute matrix "Q"
+tmp = (C + C.') - diag(ones(noOfDims, 1))*traceC;
+Q = [ traceC, delta;
+      delta.', tmp];
+
+    
+drawnow
+% 8. Compute the eigenvectors and eigenvalues
+[V, D] = eig(Q);
+
+drawnow
+% 9. Compute the rotation matrix...
+v=V(:, 4).';
+v2=v.^2;
+rotation(1, :) = [ v2(1) + v2(2) - v2(3) - v2(4), ...
+		   2*(v(2)*v(3) - v(1)*v(4)), ...
+		   2*(v(2)*v(4)+v(1)*v(3))];
+
+rotation(2, :) = [ 2*(v(2)*v(3) + v(1)*v(4)), ...
+		   v2(1) + v2(3) - v2(2) - v2(4), ...
+		   2*(v(3)*v(4) - v(1)*v(2))];
+
+rotation(3, :) = [ 2*(v(2)*v(4)-v(1)*v(3)), ...
+		   2*(v(3)*v(4) + v(1)*v(2)), ...
+		   v2(1) + v2(4) - v2(2) - v2(3)];
+
+% ... and the translation vector
+translation = centerOfMass_ref - centerOfMass_flt*rotation.';
+
+
+%===============================================================
+% Assign the output values
+%===============================================================
+if nargout==3
+  varargout(1) = {meanDist};
+end
+
diff --git a/zUtil_ICP/data1.txt b/zUtil_ICP/data1.txt
new file mode 100755
index 0000000000000000000000000000000000000000..b1924ff964e00f4f91b6e9181c590bfa95b86b20
--- /dev/null
+++ b/zUtil_ICP/data1.txt
@@ -0,0 +1,578 @@
+	265.900696	151.604187	20.511370
+	250.944626	120.633949	38.147240
+	197.442093	152.685806	31.460543
+	189.484039	159.684357	17.190521
+	259.711792	153.457901	11.447582
+	289.883179	107.066261	15.955608
+	301.882294	104.767067	26.498569
+	269.354248	150.424942	29.678827
+	229.258942	110.826721	16.455971
+	225.739243	101.207397	22.945721
+	234.420425	101.839088	32.572224
+	227.604767	158.816925	18.756153
+	183.217667	162.479889	24.595573
+	231.223816	156.386749	25.985083
+	264.094574	154.733826	15.806349
+	223.357040	161.647049	13.140743
+	284.997528	133.698532	17.731302
+	278.273865	131.218964	12.735267
+	291.032379	131.859619	23.221125
+	300.378265	103.671852	21.066399
+	268.339630	152.384689	25.036438
+	294.178467	131.835602	28.409758
+	233.372971	154.570068	30.711481
+	279.307495	110.437355	33.085884
+	261.580963	137.265671	34.398323
+	222.873398	137.165237	35.521427
+	243.856659	131.577957	12.811918
+	205.029556	133.588730	16.120073
+	260.001770	102.987175	15.254725
+	199.300995	120.353020	28.132120
+	196.538239	123.957550	20.125826
+	225.931824	103.131897	19.578951
+	259.519653	91.205017	19.223961
+	266.206451	86.755615	25.300749
+	270.048004	90.637871	30.503614
+	229.559570	100.413193	27.824375
+	208.257416	122.582779	33.067352
+	241.481110	107.260590	36.176197
+	247.061661	156.699387	19.606184
+	184.179321	162.939911	20.766939
+	213.891556	157.978012	28.777536
+	265.051849	153.306519	18.156878
+	241.605392	159.424805	11.837105
+	276.686371	144.062271	19.044594
+	284.630768	119.128387	14.227038
+	279.060303	142.493988	21.807713
+	302.893921	103.473877	23.768167
+	266.996857	151.663391	22.788511
+	283.040192	142.545975	29.109114
+	215.136078	155.290314	31.170244
+	266.999542	114.373428	36.205284
+	265.757416	144.437836	32.094990
+	209.897903	145.175613	33.594860
+	251.775009	142.737823	11.442513
+	216.884659	121.924393	16.226192
+	275.968658	102.741844	15.106169
+	212.010178	110.054825	25.571808
+	189.437469	141.162338	18.456789
+	226.933456	105.932770	17.917444
+	276.987732	93.338745	17.180548
+	287.352417	89.461983	26.146420
+	287.832611	94.892822	28.767588
+	231.770157	100.705536	30.233521
+	220.721832	111.377495	32.920876
+	237.667496	103.870552	34.459145
+	208.145538	161.121994	17.892883
+	188.279938	159.277649	28.263401
+	248.812164	155.230484	23.189148
+	262.724792	155.487961	13.478592
+	205.727921	162.002762	14.923501
+	290.004089	121.147034	16.596853
+	270.084900	143.014587	11.737191
+	301.142853	119.762680	24.677448
+	296.240082	104.881180	18.411144
+	269.153168	152.139893	27.334087
+	300.863770	118.801514	27.553001
+	251.617233	153.833267	30.244577
+	292.011383	106.785255	30.006500
+	257.335236	130.061920	36.697632
+	236.225403	129.305817	37.359215
+	236.328461	120.897835	14.518364
+	194.718491	146.452667	16.172731
+	244.334488	106.254501	15.732143
+	192.057999	134.955322	30.459179
+	210.106537	111.206795	21.576773
+	225.573822	101.670860	21.268583
+	242.010895	94.498146	21.125870
+	245.322906	92.057396	24.199741
+	251.577301	93.300392	31.786022
+	227.608337	100.734528	25.385893
+	199.693237	136.869980	32.773411
+	245.942642	112.802925	37.508244
+	205.230484	160.017319	21.723299
+	207.058060	159.240448	25.286461
+	229.234772	156.473129	22.409899
+	244.102570	160.133743	14.396890
+	225.495819	160.703705	15.923950
+	246.157043	158.350845	17.247620
+	283.182770	133.383270	15.023169
+	274.461182	145.559998	13.902966
+	275.719543	145.402756	16.669704
+	297.748688	118.650002	22.040976
+	293.786682	119.050514	19.318153
+	287.365173	132.287720	20.530560
+	282.843170	143.921707	26.639740
+	294.028687	132.769928	25.755268
+	280.755280	143.429108	24.034714
+	232.328445	156.486008	28.327335
+	251.195297	155.935730	27.799816
+	250.054230	156.169235	25.439812
+	288.547455	121.402992	30.991360
+	279.014008	135.125275	31.583336
+	273.123840	124.541039	34.264210
+	247.867111	148.654282	32.909023
+	228.231766	148.393677	33.474442
+	242.499878	140.233521	35.484539
+	231.354202	147.781464	11.893736
+	223.702942	132.208755	14.118413
+	212.161270	148.769562	13.313443
+	251.887833	117.086006	13.944885
+	261.444244	130.880356	12.221214
+	269.612701	116.409775	13.476233
+	182.178665	139.977081	26.756897
+	180.514130	141.837631	22.633532
+	195.958496	120.655052	24.200817
+	199.787750	128.103775	17.994852
+	213.649231	116.277733	17.618223
+	210.382126	112.444511	19.800737
+	242.059433	100.543350	17.203230
+	259.696808	95.285004	17.052938
+	242.317337	96.070061	19.366076
+	284.688568	88.372398	20.000814
+	287.970703	87.436958	23.087124
+	262.882660	88.009804	22.260408
+	268.167877	87.718559	27.963825
+	248.717422	91.337944	29.466230
+	247.029907	90.993195	26.725960
+	217.751511	109.877388	30.614058
+	203.357834	121.116791	30.659910
+	214.172958	109.932343	28.012375
+	229.508255	120.590858	36.738110
+	213.462952	129.002579	34.945255
+	224.123123	114.085434	34.838905
+	275.801941	98.417862	32.210163
+	261.974182	104.366997	35.540264
+	255.842422	96.704666	33.687862
+	256.678619	154.957794	20.040941
+	186.344574	161.773880	18.926243
+	205.301361	157.760818	30.212831
+	265.435577	152.361694	19.336187
+	250.814972	157.111465	11.474970
+	271.606873	148.256424	19.759871
+	287.508972	113.090874	15.042538
+	272.730774	147.409561	21.138971
+	302.978546	103.905144	25.143166
+	266.348541	151.486160	21.668642
+	276.613831	146.797867	29.490486
+	206.044266	155.202454	31.401157
+	259.179047	117.153130	37.560970
+	267.907928	147.794754	31.023294
+	203.464783	149.174988	32.610981
+	255.847321	148.633118	11.083726
+	222.954987	116.319145	16.312061
+	283.519989	104.341560	15.345088
+	218.578339	105.416794	24.254694
+	187.603531	151.040039	17.638115
+	227.916733	108.122932	17.146782
+	284.625916	99.079369	16.280214
+	296.697510	95.527672	26.427744
+	295.970856	98.745171	27.773577
+	232.936035	101.030960	31.460331
+	227.418640	106.459496	32.800030
+	235.997955	102.771606	33.525337
+	217.986282	159.892563	18.340761
+	184.985992	161.238831	26.459911
+	240.016983	155.687408	24.593758
+	263.473083	155.244293	14.593701
+	214.406967	161.947159	13.995060
+	287.913055	127.637726	17.134949
+	274.336761	137.167847	12.155858
+	296.998993	125.772217	23.941389
+	298.408752	104.256203	19.732273
+	268.859772	152.391998	26.199217
+	298.305023	125.265800	28.048458
+	242.493042	154.185745	30.479462
+	285.543304	108.664780	31.519588
+	259.495422	133.695770	35.618591
+	229.484421	133.252213	36.463516
+	240.029633	126.212852	13.616938
+	199.440536	140.105423	16.080736
+	252.118958	104.491325	15.460382
+	194.955643	127.085114	29.374331
+	202.854050	117.034111	20.859930
+	225.667984	102.235260	20.423491
+	250.672577	92.513626	20.176287
+	255.583923	88.645798	24.773924
+	260.754028	91.092628	31.219856
+	228.484253	100.393692	26.614138
+	203.464447	129.408600	33.005894
+	243.634933	109.809807	36.892284
+	216.388290	159.176819	20.247889
+	195.169403	161.969864	24.921337
+	230.191025	155.975647	24.215647
+	254.362808	158.399429	15.074641
+	224.444580	161.688232	14.505827
+	236.875092	158.575760	18.006657
+	284.165070	133.591461	16.372679
+	277.691101	139.087067	13.124576
+	270.291901	150.569321	16.212065
+	294.982971	125.620590	22.575031
+	297.461578	111.478920	20.161800
+	286.130768	132.968460	19.135118
+	275.864044	148.624420	25.810083
+	294.808075	132.788681	27.067751
+	286.029083	137.780518	23.613457
+	231.780151	156.630936	27.150318
+	242.280655	155.445221	29.257545
+	259.380585	155.137772	25.194754
+	284.083344	115.882629	32.071987
+	287.453308	133.892853	30.112032
+	268.013275	131.379822	34.458145
+	254.899017	143.497177	33.729179
+	230.872223	152.291138	32.146900
+	232.526810	139.334244	35.653137
+	226.452927	156.400513	11.908130
+	233.688049	131.770645	13.405252
+	208.199585	140.895508	14.602714
+	255.909073	109.931808	14.553690
+	252.616928	131.142380	12.462929
+	274.355377	123.620621	12.867888
+	189.662033	129.263779	27.544338
+	177.132095	153.314194	23.701197
+	195.705414	121.791725	22.168371
+	197.833069	125.773048	19.028776
+	209.143066	124.762840	16.829393
+	218.042603	107.600639	19.684477
+	233.717636	101.236893	18.367825
+	259.777161	98.673500	16.079401
+	250.843735	93.384438	19.289143
+	272.064880	88.582428	19.599064
+	297.582336	92.719475	21.941038
+	264.527283	87.140961	23.787153
+	267.176208	87.012909	26.645638
+	259.246521	89.433937	30.107351
+	238.040802	95.212830	27.304100
+	223.629227	105.060944	29.223480
+	205.639847	121.660446	31.891695
+	206.610229	114.967659	28.086817
+	235.010880	113.277908	36.626652
+	217.596115	133.127274	35.441853
+	216.001770	118.144951	33.991287
+	273.119965	93.962662	31.441034
+	271.346649	106.649124	34.498722
+	248.542847	101.294304	35.040546
+	237.342056	157.770630	19.184864
+	183.380753	163.123001	22.665663
+	222.550262	157.281342	27.382954
+	264.609467	154.117722	16.979744
+	232.459854	160.830322	12.439198
+	281.178284	139.176498	18.370739
+	281.623444	125.169418	13.440564
+	285.074371	137.216827	22.512465
+	301.952362	103.494614	22.405678
+	267.675507	152.045792	23.910530
+	288.953827	137.431946	28.777855
+	224.252518	154.856415	30.940639
+	273.223022	112.371399	34.660007
+	263.548950	140.716095	33.220234
+	216.398331	141.152252	34.551048
+	247.783798	137.090485	12.066599
+	210.883804	127.695740	16.153025
+	268.000000	102.520966	15.090909
+	205.280731	114.661064	26.887642
+	192.328293	132.160980	19.250578
+	226.291504	104.309822	18.737572
+	268.232452	91.344383	18.167658
+	276.878448	87.023766	25.784737
+	279.128448	92.167831	29.694939
+	230.596848	100.435516	29.036747
+	214.212570	116.650032	33.039627
+	239.464279	105.306290	35.357693
+	198.460571	162.280487	17.440281
+	192.399292	156.466492	29.931057
+	257.540588	154.227600	21.818783
+	261.659637	155.229553	12.356516
+	197.232666	161.516602	15.959793
+	291.090240	114.305641	16.143616
+	265.220001	148.550659	11.473481
+	303.328064	112.436073	25.571836
+	293.539154	105.821053	17.128162
+	269.386902	151.618256	28.502916
+	302.181061	111.740509	27.068878
+	260.663940	152.828293	29.989506
+	297.718719	105.370934	28.363705
+	254.564621	125.707947	37.653133
+	243.381210	125.086601	38.009346
+	232.684723	115.721710	15.439696
+	190.831863	153.313217	16.465904
+	236.736038	108.431534	16.069441
+	192.458710	143.825409	31.278139
+	217.784485	105.995964	22.270079
+	225.619522	101.383408	22.107552
+	233.669861	97.400421	22.050842
+	235.369720	96.268242	23.583723
+	242.770477	97.005386	32.231731
+	226.621643	100.853378	24.172384
+	197.590210	144.841400	32.311153
+	248.376205	116.326256	37.985485
+	194.257614	162.291260	23.139429
+	219.077530	157.355240	25.652674
+	228.429993	157.676239	20.581442
+	233.739731	161.285339	13.747381
+	226.541840	159.741989	17.340286
+	255.391479	157.593262	16.500595
+	281.747711	132.738861	13.727147
+	269.821808	150.827103	14.814862
+	280.544556	139.689316	17.189381
+	299.520935	111.294403	21.522955
+	289.681091	126.496979	18.503731
+	289.063965	131.964172	21.890308
+	289.317932	138.583969	27.512026
+	292.597290	132.358643	24.480453
+	274.901642	148.466476	24.496239
+	232.864410	155.832123	29.517153
+	259.985870	155.176804	26.376022
+	240.639648	156.182312	25.716215
+	292.395233	126.991707	29.827005
+	270.315613	136.233521	33.006657
+	276.915619	117.430542	33.793659
+	240.694870	152.266647	31.855091
+	225.425476	143.265518	34.611008
+	252.319351	139.454865	35.045052
+	237.525558	139.573975	12.281969
+	214.065216	132.634674	15.017386
+	216.845383	157.028870	12.577399
+	247.857803	124.296478	13.366530
+	270.272797	130.848587	12.189893
+	264.776337	109.497871	14.277525
+	178.399796	152.328278	25.807381
+	187.422638	132.166916	21.360689
+	197.291962	120.121941	26.195427
+	202.264999	130.745178	17.033520
+	219.250671	108.967522	18.556786
+	203.211060	117.927338	19.952244
+	250.862366	101.245987	16.143858
+	259.541718	92.859215	18.119089
+	233.968048	99.274124	19.467215
+	295.892853	93.205444	20.369011
+	277.131042	86.355522	24.219034
+	261.125641	89.151665	20.742908
+	269.139618	88.789207	29.262995
+	238.859909	95.339737	28.678459
+	256.452423	88.181396	26.045403
+	212.473953	115.552071	31.925108
+	201.315521	120.741989	29.395086
+	221.846542	105.151413	27.915831
+	225.397812	128.822464	36.405178
+	210.436691	125.500061	34.099297
+	232.501999	110.223717	35.602726
+	277.986176	103.990074	32.760403
+	251.654312	104.583374	36.080273
+	262.992798	93.217087	32.152966
+	206.110153	159.427917	23.514118
+	218.092606	157.479477	23.864098
+	217.222641	158.171143	22.068813
+	234.799957	160.446289	15.161760
+	235.829788	159.530380	16.588564
+	245.137039	159.287155	15.821692
+	279.080963	139.636337	14.437664
+	275.178406	145.567307	15.280006
+	279.885834	139.714249	15.816251
+	295.664215	118.795059	20.690916
+	291.228363	126.054779	19.875189
+	292.948700	125.667274	21.252689
+	288.710541	138.620743	26.181576
+	287.478149	138.189423	24.884878
+	281.883911	143.780426	25.328972
+	241.762436	156.187439	28.063286
+	250.654922	156.299072	26.610241
+	241.194687	156.429108	26.879223
+	284.324707	128.500748	31.365866
+	275.980652	129.804581	32.910740
+	280.605927	122.934349	32.590965
+	238.084122	148.967758	33.235600
+	235.333908	144.533096	34.521152
+	245.223999	144.648499	34.222542
+	227.390411	139.845169	12.909532
+	217.776474	140.344666	13.647850
+	221.635040	148.310196	12.518001
+	256.639160	123.889076	13.028921
+	265.547455	123.593208	12.812339
+	260.719818	116.595039	13.631588
+	180.288727	140.590790	24.723841
+	186.657455	130.064209	23.459469
+	187.614243	129.174011	25.562897
+	206.467270	121.959679	17.775482
+	211.648315	113.917351	18.673653
+	204.393097	119.576263	18.836126
+	250.798935	97.645042	17.103251
+	250.805283	95.011200	18.177900
+	242.000229	97.814400	18.260931
+	286.515472	87.459076	21.540819
+	275.446533	86.465965	22.703678
+	273.771088	87.202400	21.140337
+	258.286621	88.585655	28.779133
+	247.840988	91.108818	28.094431
+	257.403809	88.327408	27.399660
+	210.401749	115.287956	30.661098
+	208.558472	115.248093	29.361465
+	215.971634	109.896515	29.311749
+	221.387543	124.714973	35.869553
+	218.196243	121.023048	35.040665
+	226.494461	116.975639	35.885761
+	268.991119	101.154228	33.917206
+	258.941528	100.033470	34.695061
+	266.067688	96.452141	33.111034
+	206.669388	160.447342	19.813025
+	196.148285	162.356155	19.317413
+	194.758972	162.448883	21.212460
+	253.675339	158.837158	13.885874
+	252.514999	158.910263	12.532644
+	242.969131	160.601349	13.048182
+	286.733917	127.315376	15.794681
+	288.195648	120.329422	15.298635
+	285.109985	126.577499	14.470731
+	299.592041	119.267036	23.346682
+	302.767639	111.779724	24.194416
+	301.342438	111.312828	22.839203
+	276.306396	148.559906	26.968994
+	276.622192	148.160950	28.207430
+	283.305756	143.672897	27.865150
+	223.084793	156.953476	28.559704
+	214.501129	157.043610	29.978031
+	223.735870	156.201294	29.751192
+	290.831573	114.009369	30.584764
+	297.466644	112.640762	28.917370
+	295.648865	120.158646	29.391821
+	257.013306	147.105011	32.559929
+	259.158112	150.524384	31.294416
+	249.858688	151.725296	31.610407
+	236.283890	154.561096	11.394081
+	246.570068	151.975677	11.089912
+	241.530869	145.275314	11.553299
+	248.042267	111.552376	14.792503
+	240.280258	113.496681	15.096352
+	244.052689	118.899597	14.191870
+	186.821991	137.367035	28.643312
+	187.068008	147.356216	29.722616
+	182.098816	150.086334	27.825293
+	194.287613	134.453339	18.192385
+	191.873398	143.754272	17.291296
+	196.991180	137.137390	17.051840
+	234.397964	103.052299	17.542017
+	235.351746	105.583031	16.741270
+	243.064056	103.112732	16.417160
+	281.114441	90.130951	18.534792
+	289.212097	96.500648	17.465273
+	293.112610	94.312149	18.917778
+	277.821289	88.184250	27.087273
+	287.782715	91.812050	27.495749
+	278.341248	89.994911	28.481136
+	224.728806	105.213196	30.432379
+	225.964279	105.565758	31.625860
+	219.097076	110.444359	31.788656
+	237.351471	116.273415	37.309349
+	240.276947	120.445160	37.877850
+	232.424347	124.780960	37.240047
+	282.004333	96.321404	30.540983
+	290.583527	100.178856	29.515253
+	284.224701	102.233658	31.188692
+	197.639816	161.232391	26.773588
+	200.988342	159.991669	28.532753
+	210.484421	158.830627	27.029310
+	215.613495	161.841690	15.403819
+	206.913483	162.014297	16.388134
+	216.810394	160.780807	16.910046
+	273.178497	145.033432	12.649105
+	267.844299	150.719498	12.355936
+	269.086853	151.105545	13.628664
+	295.465118	112.115349	18.827633
+	293.460358	113.087715	17.473326
+	291.832550	120.068001	17.962185
+	299.072662	126.549118	26.622690
+	302.028076	119.560600	26.103718
+	298.244568	126.610832	25.183876
+	251.446915	155.173721	29.022060
+	260.638000	154.144440	28.778425
+	260.363495	154.854874	27.547318
+	281.641144	139.329514	30.435299
+	275.121246	144.235001	30.716450
+	272.680725	140.082458	31.895008
+	221.687881	152.086166	32.346523
+	212.308594	151.402496	32.556816
+	218.978180	147.127106	33.601089
+	229.999969	126.527290	14.312738
+	226.468536	121.245316	15.310293
+	220.232437	126.998268	15.146286
+	256.607880	136.800079	11.820617
+	261.189362	142.915237	11.344917
+	266.080658	136.876556	11.713465
+	178.639297	153.466537	21.488646
+	182.535934	152.705353	19.423626
+	183.987549	141.274796	20.486374
+	215.129562	118.952423	16.885056
+	221.462814	113.381584	16.968300
+	220.125137	110.876869	17.741781
+	267.819641	98.021225	15.912049
+	276.624817	97.579842	16.060030
+	268.333374	93.853569	17.065701
+	298.142883	92.938423	23.466309
+	297.679230	94.004128	25.068571
+	287.846100	88.071991	24.644770
+	250.052963	91.962761	30.657267
+	241.147598	95.799500	31.118029
+	239.908524	95.335770	29.907156
+	200.402725	128.147552	31.901747
+	195.467667	135.720901	31.687349
+	197.234283	127.631279	30.633640
+	210.957947	137.205811	34.493149
+	203.939972	141.173447	33.437534
+	206.381485	132.921478	33.902298
+	264.842255	108.822678	36.025513
+	257.080994	111.967590	37.329876
+	254.067490	107.665298	36.741295
+	239.002121	155.505783	22.810591
+	247.857452	155.489365	21.410294
+	238.152237	156.502075	21.009253
+	246.608231	157.545563	18.427414
+	256.271240	155.867859	18.865292
+	255.848083	156.803452	17.682755
+	270.826416	149.945709	17.391569
+	271.222565	149.148315	18.582325
+	276.250122	144.789963	17.855896
+	282.097626	138.253601	19.780924
+	277.658752	143.036865	20.440094
+	283.312195	137.494476	21.160423
+	279.907959	142.950562	22.920959
+	273.380859	147.595795	22.261776
+	274.168640	148.002960	23.377954
+	258.696442	154.776962	24.060711
+	258.081207	154.359375	22.938374
+	249.425766	155.666550	24.316725
+	265.918793	127.617012	35.615677
+	263.419403	122.469772	36.777008
+	270.642975	119.493484	35.342781
+	239.284103	135.373489	36.596066
+	246.908279	130.750854	37.384308
+	250.047363	135.665894	36.207661
+	202.698257	147.638275	14.558609
+	197.980133	155.959427	14.800883
+	207.050156	157.179504	13.517823
+	277.713989	117.439072	13.581683
+	280.878571	110.629654	14.413619
+	272.875061	109.441673	14.218801
+	202.948563	115.809258	22.891277
+	210.781586	110.230186	23.588980
+	203.749313	115.027763	24.903547
+	217.804520	106.773773	20.537306
+	217.763840	106.322235	21.426193
+	210.106644	111.638725	20.691011
+	242.140213	95.230370	20.245504
+	233.675873	97.845795	21.200373
+	233.769302	98.512733	20.318996
+	253.993637	89.649933	23.242298
+	243.571259	92.975105	22.667080
+	252.305679	90.739716	21.699766
+	237.018768	95.230103	26.086182
+	236.252945	95.954865	24.809652
+	246.105423	91.302193	25.469654
+	212.909409	109.710167	26.813105
+	219.806976	105.407486	25.478842
+	220.746689	105.092087	26.712645
+	222.293564	112.551788	33.904015
+	229.007156	107.317596	33.729786
+	230.667725	108.622681	34.703949
+	246.551224	99.531265	34.173981
+	244.468994	98.156693	33.172855
+	253.678787	94.800446	32.761700
\ No newline at end of file
diff --git a/zUtil_ICP/data1_isotropic.txt b/zUtil_ICP/data1_isotropic.txt
new file mode 100755
index 0000000000000000000000000000000000000000..91a918010e6dd695d40cbed490f0b0d0833e4e32
--- /dev/null
+++ b/zUtil_ICP/data1_isotropic.txt
@@ -0,0 +1,578 @@
+83.093967	47.376308	30.767055
+78.420196	37.698109	57.220860
+61.700654	47.714314	47.190815
+59.213762	49.901362	25.785781
+81.159935	47.955594	17.171373
+90.588493	33.458207	23.933412
+94.338217	32.739708	39.747853
+84.173203	47.007794	44.518240
+71.643419	34.633350	24.683957
+70.543513	31.627312	34.418582
+73.256383	31.824715	48.858336
+71.126490	49.630289	28.134230
+57.255521	50.774965	36.893360
+72.257442	48.870859	38.977624
+82.529554	48.354321	23.709524
+69.799075	50.514703	19.711115
+89.061727	41.780791	26.596953
+86.960583	41.005926	19.102901
+90.947618	41.206131	34.831688
+93.868208	32.397454	31.599598
+83.856134	47.620215	37.554657
+91.930771	41.198626	42.614637
+72.929053	48.303146	46.067222
+87.283592	34.511673	49.628826
+81.744051	42.895522	51.597484
+69.647937	42.864137	53.282141
+76.205206	41.118112	19.217877
+64.071736	41.746478	24.180110
+81.250553	32.183492	22.882088
+62.281561	37.610319	42.198180
+61.418200	38.736734	30.188739
+70.603695	32.228718	29.368426
+81.099892	28.501568	28.835941
+83.189516	27.111130	37.951124
+84.390001	28.324335	45.755421
+71.737366	31.379123	41.736562
+65.080443	38.307118	49.601028
+75.462847	33.518934	54.264296
+77.206769	48.968558	29.409276
+57.556038	50.918722	31.150409
+66.841111	49.368129	43.166304
+82.828703	47.908287	27.235317
+75.501685	49.820252	17.755657
+86.464491	45.019460	28.566891
+88.947115	37.227621	21.340557
+87.206345	44.529371	32.711569
+94.654350	32.335587	35.652250
+83.436518	47.394810	34.182766
+88.450060	44.545617	43.663671
+67.230024	48.528223	46.755366
+83.437357	35.741696	54.307926
+83.049192	45.136824	48.142485
+65.593095	45.367379	50.392290
+78.679690	44.605570	17.163770
+67.776456	38.101373	24.339288
+86.240206	32.106826	22.659253
+66.253181	34.392133	38.357712
+59.199209	44.113231	27.685184
+70.916705	33.103991	26.876166
+86.558666	29.168358	25.770822
+89.797630	27.956870	39.219630
+89.947691	29.654007	43.151382
+72.428174	31.470480	45.350282
+68.975572	34.805467	49.381314
+74.271092	32.459547	51.688717
+65.045481	50.350623	26.839325
+58.837481	49.774265	42.395102
+77.753801	48.509526	34.783722
+82.101497	48.589988	20.217888
+64.289975	50.625863	22.385251
+90.626278	37.858448	24.895280
+84.401531	44.692058	17.605787
+94.107142	37.425838	37.016172
+92.575026	32.775369	27.616716
+84.110365	47.543717	41.001131
+94.019928	37.125473	41.329501
+78.630385	48.072896	45.366866
+91.253557	33.370392	45.009750
+80.417261	40.644350	55.046448
+73.820438	40.408068	56.038822
+73.852644	37.780573	21.777546
+60.849528	45.766458	24.259096
+76.354528	33.204532	23.598215
+60.018125	42.173538	45.688768
+65.658293	34.752123	32.365159
+70.491819	31.772144	31.902874
+75.628405	29.530671	31.688805
+76.663408	28.767936	36.299611
+78.617907	29.156372	47.679033
+71.127605	31.479540	38.078840
+62.404137	42.771869	49.160117
+76.857076	35.250914	56.262366
+64.134526	50.005412	32.584949
+64.705644	49.762640	37.929691
+71.635866	48.897853	33.614849
+76.282053	50.041795	21.595335
+70.467443	50.219908	23.885925
+76.924076	49.484639	25.871430
+88.494616	41.682272	22.534754
+85.769119	45.487499	20.854449
+86.162357	45.438361	25.004556
+93.046465	37.078126	33.061464
+91.808338	37.203286	28.977229
+89.801617	41.339913	30.795840
+88.388491	44.975533	39.959610
+91.883965	41.490602	38.632902
+87.736025	44.821596	36.052071
+72.602639	48.901877	42.491003
+78.498530	48.729916	41.699724
+78.141947	48.802886	38.159718
+90.171080	37.938435	46.487040
+87.191878	42.226648	47.375004
+85.351200	38.919075	51.396315
+77.458472	46.454463	49.363535
+71.322427	46.373024	50.211663
+75.781212	43.822975	53.226808
+72.298188	46.181708	17.840604
+69.907169	41.315236	21.177619
+66.300397	46.490488	19.970164
+78.714948	36.589377	20.917327
+81.701326	40.900111	18.331821
+84.253969	36.378055	20.214350
+56.930833	43.742838	40.135345
+56.410666	44.324260	33.950298
+61.237030	37.704704	36.301226
+62.433672	40.032430	26.992278
+66.765385	36.336792	26.427335
+65.744414	35.138910	29.701106
+75.643573	31.419797	25.804845
+81.155252	29.776564	25.579407
+75.724168	30.021894	29.049114
+88.965177	27.616374	30.001221
+89.990845	27.324049	34.630686
+82.150831	27.503064	33.390612
+83.802462	27.412050	41.945737
+77.724194	28.543107	44.199345
+77.196846	28.435373	40.088940
+68.047347	34.336684	45.921087
+63.549323	37.848997	45.989865
+66.929049	34.353857	42.018563
+71.721330	37.684643	55.107165
+66.707172	40.313306	52.417883
+70.038476	35.651698	52.258357
+86.188107	30.755582	48.315245
+81.866932	32.614687	53.310396
+79.950757	30.220208	50.531793
+80.212068	48.424311	30.061411
+58.232679	50.554337	28.389364
+64.156675	49.300256	45.319247
+82.948618	47.613029	29.004281
+78.379679	49.097333	17.212455
+84.877148	46.330133	29.639806
+89.846554	35.340898	22.563807
+85.228367	46.065488	31.708457
+94.680796	32.470358	37.714749
+83.233919	47.339425	32.502963
+86.441822	45.874333	44.235729
+64.388833	48.500767	47.101736
+80.993452	36.610353	56.341455
+83.721228	46.185861	46.534941
+63.582745	46.617184	48.916472
+79.952288	46.447849	16.625589
+69.673433	36.349733	24.468091
+88.599997	32.606738	23.017632
+68.305731	32.942748	36.382041
+58.626103	47.200012	26.457172
+71.223979	33.788416	25.720173
+88.945599	30.962303	24.420321
+92.717972	29.852397	39.641616
+92.490893	30.857866	41.660365
+72.792511	31.572175	47.190497
+71.068325	33.268592	49.200045
+73.749361	32.116127	50.288005
+68.120713	49.966426	27.511142
+57.808123	50.387135	39.689867
+75.005307	48.652315	36.890637
+82.335338	48.513842	21.890552
+67.002177	50.608487	20.992590
+89.972830	39.886789	25.702423
+85.730238	42.864952	18.233787
+92.812185	39.303818	35.912084
+93.252735	32.580063	29.598409
+84.018679	47.622499	39.298825
+93.220320	39.145562	42.072687
+75.779076	48.183045	45.719193
+89.232282	33.957744	47.279382
+81.092319	41.779928	53.427886
+71.713882	41.641317	54.695274
+75.009260	39.441516	20.425407
+62.325168	43.782945	24.121104
+78.787174	32.653539	23.190573
+60.923638	39.714098	44.061497
+63.391891	36.573160	31.289895
+70.521245	31.948519	30.635236
+78.335180	28.910508	30.264430
+79.869976	27.701812	37.160886
+81.485634	28.466446	46.829784
+71.401329	31.373029	39.921207
+63.582640	40.440188	49.508841
+76.135917	34.315565	55.338426
+67.621341	49.742756	30.371834
+60.990438	50.615583	37.382006
+71.934695	48.742390	36.323470
+79.488377	49.499822	22.611961
+70.138931	50.527572	21.758741
+74.023466	49.554925	27.009985
+88.801584	41.747332	24.559019
+86.778469	43.464708	19.686864
+84.466219	47.052913	24.318098
+92.182178	39.256434	33.862547
+92.956743	34.837162	30.242700
+89.415865	41.552644	28.702677
+86.207514	46.445131	38.715125
+92.127523	41.496463	40.601627
+89.384088	43.056412	35.420186
+72.431297	48.947167	40.725477
+75.712705	48.576632	43.886318
+81.056433	48.480554	37.792131
+88.776045	36.213322	48.107980
+89.829159	41.841517	45.168048
+83.754148	41.056194	51.687218
+79.655943	44.842868	50.593769
+72.147570	47.590981	48.220350
+72.664628	43.541951	53.479706
+70.766540	48.875160	17.862195
+73.027515	41.178327	20.107878
+65.062370	44.029846	21.904071
+79.971585	34.353690	21.830535
+78.942790	40.981994	18.694394
+85.736055	38.631444	19.301832
+59.269385	40.394931	41.316507
+55.353780	47.910686	35.551795
+61.157942	38.059914	33.252556
+61.822834	39.304077	28.543164
+65.357208	38.988388	25.244090
+68.138313	33.625200	29.526716
+73.036761	31.636529	27.551738
+81.180363	30.835469	24.119101
+78.388667	29.182637	28.933715
+85.020275	27.682009	29.398596
+92.994480	28.974836	32.911557
+82.664776	27.231550	35.680729
+83.492565	27.191534	39.968457
+81.014538	27.948105	45.161027
+74.387751	29.754009	40.956150
+69.884133	32.831545	43.835220
+64.262452	38.018889	47.837542
+64.565697	35.927393	42.130226
+73.440900	35.399346	54.939978
+67.998786	41.602273	53.162779
+67.500553	36.920297	50.986930
+85.349989	29.363332	47.161551
+84.795828	33.327851	51.748083
+77.669640	31.654470	52.560819
+74.169393	49.303322	28.777296
+57.306485	50.975938	33.998494
+69.546957	49.150419	41.074431
+82.690458	48.161788	25.469616
+72.643704	50.259476	18.658797
+87.868214	43.492656	27.556109
+88.007326	39.115443	20.160846
+89.085741	42.880258	33.768698
+94.360113	32.342067	33.608517
+83.648596	47.514310	35.865795
+90.298071	42.947483	43.166782
+70.078912	48.392630	46.410958
+85.382194	35.116062	51.990010
+82.359047	43.973780	49.830351
+67.624478	44.110079	51.826572
+77.432437	42.840777	18.099899
+65.901189	39.904919	24.229537
+83.750000	32.037802	22.636364
+64.150228	35.831582	40.331463
+60.102592	41.300306	28.875867
+70.716095	32.596819	28.106358
+83.822641	28.545120	27.251487
+86.524515	27.194927	38.677105
+87.227640	28.802447	44.542409
+72.061515	31.386099	43.555121
+66.941428	36.453135	49.559441
+74.832587	32.908216	53.036539
+62.018928	50.712652	26.160421
+60.124779	48.895779	44.896586
+80.481434	48.196125	32.728175
+81.768637	48.509235	18.534774
+61.635208	50.473938	23.939690
+90.965700	35.720513	24.215424
+82.881250	46.422081	17.210221
+94.790020	35.136273	38.357754
+91.730986	33.069079	25.692243
+84.183407	47.380705	42.754374
+94.431582	34.918909	40.603317
+81.457481	47.758842	44.984259
+93.037100	32.928417	42.545558
+79.551444	39.283733	56.479699
+76.056628	39.089563	57.014019
+72.713976	36.163034	23.159544
+59.634957	47.910380	24.698856
+73.980012	33.884854	24.104162
+60.143347	44.945440	46.917209
+68.057652	33.123739	33.405119
+70.506101	31.682315	33.161328
+73.021832	30.437632	33.076263
+73.553038	30.083826	35.375585
+75.865774	30.314183	48.347597
+70.819263	31.516681	36.258576
+61.746941	45.262937	48.466729
+77.617564	36.351955	56.978227
+60.705504	50.716019	34.709143
+68.461728	49.173513	38.479011
+71.384373	49.273825	30.872163
+73.043666	50.401668	20.621071
+70.794325	49.919372	26.010429
+79.809837	49.247894	24.750892
+88.046160	41.480894	20.590720
+84.319315	47.133470	22.222293
+87.670174	43.652911	25.784072
+93.600292	34.779501	32.284433
+90.525341	39.530306	27.755596
+90.332489	41.238804	32.835462
+90.411854	43.307490	41.268039
+91.436653	41.362076	36.720680
+85.906763	46.395774	36.744358
+72.770128	48.697538	44.275729
+81.245584	48.492751	39.564033
+75.199890	48.806973	38.574322
+91.373510	39.684908	44.740507
+84.473629	42.572975	49.509985
+86.536131	36.697044	50.690489
+75.217147	47.583327	47.782637
+70.445461	44.770474	51.916512
+78.849797	43.579645	52.567578
+74.226737	43.616867	18.422953
+66.895380	41.448336	22.526079
+67.764182	49.071522	18.866098
+77.455563	38.842649	20.049795
+84.460249	40.890183	18.284840
+82.742605	34.218085	21.416288
+55.749936	47.602587	38.711072
+58.569574	41.302161	32.041033
+61.653738	37.538107	39.293140
+63.207812	40.857868	25.550280
+68.515835	34.052351	27.835179
+63.503456	36.852293	29.928366
+78.394489	31.639371	24.215787
+81.106787	29.018505	27.178633
+73.115015	31.023164	29.200823
+92.466517	29.126701	30.553517
+86.603451	26.986101	36.328551
+81.601763	27.859895	31.114362
+84.106131	27.746627	43.894492
+74.643722	29.793668	43.017688
+80.141382	27.556686	39.068105
+66.398110	36.110022	47.887662
+62.911100	37.731872	44.092629
+69.327044	32.859817	41.873747
+70.436816	40.257020	54.607767
+65.761466	39.218769	51.148945
+72.656875	34.444912	53.404089
+86.870680	32.496898	49.140604
+78.641973	32.682304	54.120409
+82.185249	29.130340	48.229449
+64.409423	49.821224	35.271177
+68.153939	49.212337	35.796147
+67.882075	49.428482	33.103219
+73.374987	50.139465	22.742640
+73.696809	49.853244	24.882846
+76.605325	49.777236	23.732538
+87.212801	43.636355	21.656496
+85.993252	45.489783	22.920009
+87.464323	43.660703	23.724376
+92.395067	37.123456	31.036374
+91.008863	39.392118	29.812783
+91.546469	39.271023	31.879033
+90.222044	43.318982	39.272364
+89.836922	43.184195	37.327317
+88.088722	44.931383	37.993458
+75.550761	48.808575	42.094929
+78.329663	48.843460	39.915361
+75.373340	48.884096	40.318835
+88.851471	40.156484	47.048799
+86.243954	40.563932	49.366110
+87.689352	38.416984	48.886447
+74.401288	46.552424	49.853400
+73.541846	45.166593	51.781728
+76.632500	45.202656	51.333813
+71.059503	43.701615	19.364298
+68.055148	43.857708	20.471775
+69.260950	46.346936	18.777002
+80.199737	38.715336	19.543382
+82.983580	38.622878	19.218508
+81.474943	36.435950	20.447382
+56.340227	43.934622	37.085762
+58.330455	40.645065	35.189203
+58.629451	40.366878	38.344346
+64.521022	38.112400	26.663223
+66.140098	35.599172	28.010480
+63.872843	37.367582	28.254189
+78.374667	30.514076	25.654877
+78.376651	29.691000	27.266850
+75.625072	30.567000	27.391396
+89.536085	27.330961	32.311228
+86.077042	27.020614	34.055517
+85.553465	27.250750	31.710505
+80.714569	27.683017	43.168700
+77.450309	28.471506	42.141647
+80.438690	27.602315	41.099490
+65.750547	36.027486	45.991647
+65.174522	36.015029	44.042198
+67.491136	34.342661	43.967624
+69.183607	38.973429	53.804330
+68.186326	37.819702	52.560997
+70.779519	36.554887	53.828642
+84.059725	31.610696	50.875809
+80.919228	31.260459	52.042592
+83.146152	30.141294	49.666551
+64.584184	50.139794	29.719538
+61.296339	50.736298	28.976119
+60.862179	50.765276	31.818690
+79.273543	49.636612	20.828811
+78.910937	49.659457	18.798966
+75.927853	50.187922	19.572273
+89.604349	39.786055	23.692022
+90.061140	37.602944	22.947952
+89.096870	39.555468	21.706097
+93.622513	37.270949	35.020023
+94.614887	34.931164	36.291624
+94.169512	34.785259	34.258805
+86.345749	46.424971	40.453491
+86.444435	46.300297	42.311145
+88.533049	44.897780	41.797725
+69.713998	49.047961	42.839556
+67.031603	49.076128	44.967047
+69.917459	48.812904	44.626788
+90.884867	35.627928	45.877146
+92.958326	35.200238	43.376055
+92.390270	37.549577	44.087732
+80.316658	45.970316	48.839893
+80.986910	47.038870	46.941624
+78.080840	47.414155	47.415610
+73.838716	48.300342	17.091121
+77.053146	47.492399	16.634868
+75.478397	45.398536	17.329949
+77.513208	34.860118	22.188755
+75.087581	35.467713	22.644528
+76.266465	37.156124	21.287805
+58.381872	42.927198	42.964968
+58.458752	46.048817	44.583924
+56.905880	46.901979	41.737939
+60.714879	42.016668	27.288578
+59.960437	44.923210	25.936944
+61.559744	42.855434	25.577760
+73.249364	32.203843	26.313026
+73.547421	32.994697	25.111905
+75.957517	32.222729	24.625740
+87.848263	28.165922	27.802188
+90.378780	30.156453	26.197910
+91.597691	29.472547	28.376667
+86.819153	27.557578	40.630910
+89.932098	28.691266	41.243623
+86.981640	28.123410	42.721704
+70.227752	32.879124	45.648569
+70.613837	32.989299	47.438790
+68.467836	34.513862	47.682984
+74.172335	36.335442	55.964023
+75.086546	37.639113	56.816775
+72.632608	38.994050	55.860070
+88.126354	30.100439	45.811475
+90.807352	31.305892	44.272880
+88.820219	31.948018	46.783038
+61.762442	50.385122	40.160382
+62.808857	49.997397	42.799129
+65.776382	49.634571	40.543965
+67.379217	50.575528	23.105729
+64.660463	50.629468	24.582201
+67.753248	50.244002	25.365069
+85.368280	45.322947	18.973658
+83.701343	47.099843	18.533904
+84.089642	47.220483	20.442996
+92.332849	35.036047	28.241449
+91.706362	35.339911	26.209989
+91.197672	37.521250	26.943278
+93.460207	39.546599	39.934035
+94.383774	37.362687	39.155577
+93.201428	39.565885	37.775814
+78.577161	48.491788	43.533090
+81.449375	48.170138	43.167637
+81.363592	48.392148	41.320977
+88.012857	43.540473	45.652949
+85.975389	45.073438	46.074675
+85.212727	43.775768	47.842512
+69.277463	47.526927	48.519785
+66.346436	47.313280	48.835224
+68.430681	45.977221	50.401634
+71.874990	39.539778	21.469107
+70.771417	37.889161	22.965439
+68.822637	39.686959	22.719429
+80.189963	42.750025	17.730926
+81.621676	44.661012	17.017375
+83.150206	42.773924	17.570197
+55.824780	47.958293	32.232969
+57.042479	47.720423	29.135439
+57.496109	44.148374	30.729561
+67.227988	37.172632	25.327584
+69.207129	35.431745	25.452450
+68.789105	34.649022	26.612671
+83.693638	30.631633	23.868074
+86.445255	30.493701	24.090045
+83.854179	29.329240	25.598551
+93.169651	29.043257	35.199464
+93.024759	29.376290	37.602857
+89.951906	27.522497	36.967155
+78.141551	28.738363	45.985900
+75.358624	29.937344	46.677043
+74.971414	29.792428	44.860734
+62.625852	40.046110	47.852621
+61.083646	42.412782	47.531024
+61.635713	39.884775	45.950460
+65.924358	42.876816	51.739724
+63.731241	44.116702	50.156301
+64.494214	41.537962	50.853447
+82.763205	34.007087	54.038269
+80.337811	34.989872	55.994814
+79.396091	33.645406	55.111942
+74.688163	48.595557	34.215886
+77.455454	48.590427	32.115441
+74.422574	48.906898	31.513880
+77.065072	49.232988	27.641121
+80.084762	48.708706	28.297938
+79.952526	49.001079	26.524133
+84.633255	46.858034	26.087353
+84.757052	46.608848	27.873488
+86.328163	45.246863	26.783844
+88.155508	43.204250	29.671386
+86.768360	44.699020	30.660141
+88.535061	42.967024	31.740635
+87.471237	44.672051	34.381439
+85.431518	46.123686	33.392664
+85.677700	46.250925	35.066931
+80.842638	48.367801	36.091067
+80.650377	48.237305	34.407561
+77.945552	48.645797	36.475088
+83.099623	39.880316	53.423515
+82.318563	38.271804	55.165512
+84.575930	37.341714	53.014172
+74.776282	42.304215	54.894099
+77.158837	40.859642	56.076462
+78.139801	42.395592	54.311492
+63.343205	46.136961	21.837913
+61.868792	48.737321	22.201325
+64.703174	49.118595	20.276734
+86.785622	36.699710	20.372525
+87.774553	34.571767	21.620429
+85.273457	34.200523	21.328201
+63.421426	36.190393	34.336915
+65.869246	34.446933	35.383470
+63.671660	35.946176	37.355320
+68.063913	33.366804	30.805959
+68.051200	33.225698	32.139290
+65.658326	34.887102	31.036516
+75.668817	29.759491	30.368256
+73.023710	30.576811	31.800559
+73.052907	30.785229	30.478494
+79.373012	28.015604	34.863447
+76.116018	29.054720	34.000620
+78.845525	28.356161	32.549649
+74.068365	29.759407	39.129273
+73.829045	29.985895	37.214478
+76.907945	28.531935	38.204481
+66.534190	34.284427	40.219657
+68.689680	32.939839	38.218263
+68.983340	32.841277	40.068967
+69.466739	35.172434	50.856023
+71.564736	33.536749	50.594679
+72.083664	33.944588	52.055924
+77.047258	31.103520	51.260971
+76.396561	30.673967	49.759282
+79.274621	29.625139	49.142550
diff --git a/zUtil_ICP/data2.txt b/zUtil_ICP/data2.txt
new file mode 100755
index 0000000000000000000000000000000000000000..f7cee7b3426fca801330f2751f69ddabc81be65a
--- /dev/null
+++ b/zUtil_ICP/data2.txt
@@ -0,0 +1,87 @@
+   2.5951965e+02   9.1205017e+01   1.9223961e+01
+   2.6620645e+02   8.6755615e+01   2.5300749e+01
+   2.7004800e+02   9.0637871e+01   3.0503614e+01
+   2.7698773e+02   9.3338745e+01   1.7180548e+01
+   2.8735242e+02   8.9461983e+01   2.6146420e+01
+   2.8783261e+02   9.4892822e+01   2.8767588e+01
+   2.4201090e+02   9.4498146e+01   2.1125870e+01
+   2.4532291e+02   9.2057396e+01   2.4199741e+01
+   2.5157730e+02   9.3300392e+01   3.1786022e+01
+   2.5969681e+02   9.5285004e+01   1.7052938e+01
+   2.4231734e+02   9.6070061e+01   1.9366076e+01
+   2.8468857e+02   8.8372398e+01   2.0000814e+01
+   2.8797070e+02   8.7436958e+01   2.3087124e+01
+   2.6288266e+02   8.8009804e+01   2.2260408e+01
+   2.6816788e+02   8.7718559e+01   2.7963825e+01
+   2.4871742e+02   9.1337944e+01   2.9466230e+01
+   2.4702991e+02   9.0993195e+01   2.6725960e+01
+   2.7580194e+02   9.8417862e+01   3.2210163e+01
+   2.5584242e+02   9.6704666e+01   3.3687862e+01
+   2.8462592e+02   9.9079369e+01   1.6280214e+01
+   2.9669751e+02   9.5527672e+01   2.6427744e+01
+   2.9597086e+02   9.8745171e+01   2.7773577e+01
+   2.5067258e+02   9.2513626e+01   2.0176287e+01
+   2.5558392e+02   8.8645798e+01   2.4773924e+01
+   2.6075403e+02   9.1092628e+01   3.1219856e+01
+   2.5977716e+02   9.8673500e+01   1.6079401e+01
+   2.5084374e+02   9.3384438e+01   1.9289143e+01
+   2.7206488e+02   8.8582428e+01   1.9599064e+01
+   2.9758234e+02   9.2719475e+01   2.1941038e+01
+   2.6452728e+02   8.7140961e+01   2.3787153e+01
+   2.6717621e+02   8.7012909e+01   2.6645638e+01
+   2.5924652e+02   8.9433937e+01   3.0107351e+01
+   2.3804080e+02   9.5212830e+01   2.7304100e+01
+   2.7311996e+02   9.3962662e+01   3.1441034e+01
+   2.6823245e+02   9.1344383e+01   1.8167658e+01
+   2.7687845e+02   8.7023766e+01   2.5784737e+01
+   2.7912845e+02   9.2167831e+01   2.9694939e+01
+   2.3366986e+02   9.7400421e+01   2.2050842e+01
+   2.3536972e+02   9.6268242e+01   2.3583723e+01
+   2.4277048e+02   9.7005386e+01   3.2231731e+01
+   2.5954172e+02   9.2859215e+01   1.8119089e+01
+   2.3396805e+02   9.9274124e+01   1.9467215e+01
+   2.9589285e+02   9.3205444e+01   2.0369011e+01
+   2.7713104e+02   8.6355522e+01   2.4219034e+01
+   2.6112564e+02   8.9151665e+01   2.0742908e+01
+   2.6913962e+02   8.8789207e+01   2.9262995e+01
+   2.3885991e+02   9.5339737e+01   2.8678459e+01
+   2.5645242e+02   8.8181396e+01   2.6045403e+01
+   2.6299280e+02   9.3217087e+01   3.2152966e+01
+   2.5079894e+02   9.7645042e+01   1.7103251e+01
+   2.5080528e+02   9.5011200e+01   1.8177900e+01
+   2.4200023e+02   9.7814400e+01   1.8260931e+01
+   2.8651547e+02   8.7459076e+01   2.1540819e+01
+   2.7544653e+02   8.6465965e+01   2.2703678e+01
+   2.7377109e+02   8.7202400e+01   2.1140337e+01
+   2.5828662e+02   8.8585655e+01   2.8779133e+01
+   2.4784099e+02   9.1108818e+01   2.8094431e+01
+   2.5740381e+02   8.8327408e+01   2.7399660e+01
+   2.6606769e+02   9.6452141e+01   3.3111034e+01
+   2.8111444e+02   9.0130951e+01   1.8534792e+01
+   2.8921210e+02   9.6500648e+01   1.7465273e+01
+   2.9311261e+02   9.4312149e+01   1.8917778e+01
+   2.7782129e+02   8.8184250e+01   2.7087273e+01
+   2.8778271e+02   9.1812050e+01   2.7495749e+01
+   2.7834125e+02   8.9994911e+01   2.8481136e+01
+   2.8200433e+02   9.6321404e+01   3.0540983e+01
+   2.6781964e+02   9.8021225e+01   1.5912049e+01
+   2.7662482e+02   9.7579842e+01   1.6060030e+01
+   2.6833337e+02   9.3853569e+01   1.7065701e+01
+   2.9814288e+02   9.2938423e+01   2.3466309e+01
+   2.9767923e+02   9.4004128e+01   2.5068571e+01
+   2.8784610e+02   8.8071991e+01   2.4644770e+01
+   2.5005296e+02   9.1962761e+01   3.0657267e+01
+   2.4114760e+02   9.5799500e+01   3.1118029e+01
+   2.3990852e+02   9.5335770e+01   2.9907156e+01
+   2.4214021e+02   9.5230370e+01   2.0245504e+01
+   2.3367587e+02   9.7845795e+01   2.1200373e+01
+   2.3376930e+02   9.8512733e+01   2.0318996e+01
+   2.5399364e+02   8.9649933e+01   2.3242298e+01
+   2.4357126e+02   9.2975105e+01   2.2667080e+01
+   2.5230568e+02   9.0739716e+01   2.1699766e+01
+   2.3701877e+02   9.5230103e+01   2.6086182e+01
+   2.3625295e+02   9.5954865e+01   2.4809652e+01
+   2.4610542e+02   9.1302193e+01   2.5469654e+01
+   2.4655122e+02   9.9531265e+01   3.4173981e+01
+   2.4446899e+02   9.8156693e+01   3.3172855e+01
+   2.5367879e+02   9.4800446e+01   3.2761700e+01
diff --git a/zUtil_ICP/data2_isotropic.txt b/zUtil_ICP/data2_isotropic.txt
new file mode 100755
index 0000000000000000000000000000000000000000..67fe44f81f4d25dd6946cef74fb5f36631f459fc
--- /dev/null
+++ b/zUtil_ICP/data2_isotropic.txt
@@ -0,0 +1,87 @@
+81.099891	28.501568	28.835941
+83.189516	27.111130	37.951124
+84.390000	28.324335	45.755421
+86.558666	29.168358	25.770822
+89.797631	27.956870	39.219630
+89.947691	29.654007	43.151382
+75.628406	29.530671	31.688805
+76.663409	28.767936	36.299611
+78.617906	29.156372	47.679033
+81.155253	29.776564	25.579407
+75.724169	30.021894	29.049114
+88.965178	27.616374	30.001221
+89.990844	27.324049	34.630686
+82.150831	27.503064	33.390612
+83.802463	27.412050	41.945737
+77.724194	28.543107	44.199345
+77.196847	28.435373	40.088940
+86.188106	30.755582	48.315245
+79.950756	30.220208	50.531793
+88.945600	30.962303	24.420321
+92.717972	29.852397	39.641616
+92.490894	30.857866	41.660365
+78.335181	28.910508	30.264430
+79.869975	27.701812	37.160886
+81.485634	28.466446	46.829784
+81.180363	30.835469	24.119101
+78.388669	29.182637	28.933715
+85.020275	27.682009	29.398596
+92.994481	28.974836	32.911557
+82.664775	27.231550	35.680729
+83.492566	27.191534	39.968457
+81.014537	27.948105	45.161027
+74.387750	29.754009	40.956150
+85.349987	29.363332	47.161551
+83.822641	28.545120	27.251487
+86.524516	27.194927	38.677105
+87.227641	28.802447	44.542409
+73.021831	30.437632	33.076263
+73.553038	30.083826	35.375585
+75.865775	30.314183	48.347597
+81.106787	29.018505	27.178633
+73.115016	31.023164	29.200823
+92.466516	29.126701	30.553517
+86.603450	26.986101	36.328551
+81.601762	27.859895	31.114362
+84.106131	27.746627	43.894492
+74.643722	29.793668	43.017688
+80.141381	27.556686	39.068105
+82.185250	29.130340	48.229449
+78.374669	30.514076	25.654877
+78.376650	29.691000	27.266850
+75.625072	30.567000	27.391396
+89.536084	27.330961	32.311228
+86.077041	27.020614	34.055517
+85.553466	27.250750	31.710505
+80.714569	27.683017	43.168700
+77.450309	28.471506	42.141647
+80.438691	27.602315	41.099490
+83.146153	30.141294	49.666551
+87.848263	28.165922	27.802188
+90.378781	30.156453	26.197910
+91.597691	29.472547	28.376667
+86.819153	27.557578	40.630910
+89.932097	28.691266	41.243623
+86.981641	28.123410	42.721704
+88.126353	30.100439	45.811475
+83.693637	30.631633	23.868074
+86.445256	30.493701	24.090045
+83.854178	29.329240	25.598551
+93.169650	29.043257	35.199464
+93.024759	29.376290	37.602857
+89.951906	27.522497	36.967155
+78.141550	28.738363	45.985900
+75.358625	29.937344	46.677043
+74.971412	29.792428	44.860734
+75.668816	29.759491	30.368256
+73.023709	30.576811	31.800559
+73.052906	30.785229	30.478494
+79.373013	28.015604	34.863447
+76.116019	29.054720	34.000620
+78.845525	28.356161	32.549649
+74.068366	29.759407	39.129273
+73.829047	29.985895	37.214478
+76.907944	28.531935	38.204481
+77.047256	31.103520	51.260971
+76.396559	30.673967	49.759282
+79.274622	29.625139	49.142550
diff --git a/zUtil_ICP/gpl.txt b/zUtil_ICP/gpl.txt
new file mode 100755
index 0000000000000000000000000000000000000000..ce257d4b0a32e3d0683d49c7ec750d54676b45bb
--- /dev/null
+++ b/zUtil_ICP/gpl.txt
@@ -0,0 +1,252 @@
+GNU GENERAL PUBLIC LICENSE
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, 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.
+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 an idea of what it does.
+Copyright (C) yyyy  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 Lesser General Public License instead of this License. 
\ No newline at end of file
diff --git a/zUtil_ICP/iterativeClosestPoint.m b/zUtil_ICP/iterativeClosestPoint.m
new file mode 100755
index 0000000000000000000000000000000000000000..b81729f50ffdcc587f51b581db45bc24b6d2161b
--- /dev/null
+++ b/zUtil_ICP/iterativeClosestPoint.m
@@ -0,0 +1,152 @@
+% ITERATIVECLOSESTPOINT Perform the Iterative Closest Point (ICP) algorithm.
+%
+% [TR_FLT] = iterativeClosestPoint(REF, FLT, STEPS) will return the
+%   transformed floating points TR_FLT that have minimal distance
+%   to the reference points REF. The number of iteration steps will
+%   be STEPS.
+%
+%   Important: THIS ALGORITHM WORKS ONLY FOR THREE DIMENSIONAL POINTS.
+%
+% [TR, ROT] = iterativeClosestPoint(REF, FLT, STEPS) returns the
+%   translation vector TR and the rotation matrix ROT that lead to
+%   the minimization of the total distance from the floating points
+%   FLT to their corresponding closest reference points REF.
+%
+% [TR, ROT] = iterativeClosestPoint(REF, FLT, STEPS, MIN_DIST) will
+%   stop the optimization if the average CLOSEST_DISTANCE is smaller
+%   than MIN_DIST. See CLOSESTPOINT, for details about
+%   CLOSEST_DISTANCE. In this case, STEPS represents the maximum
+%   number of iterations performed.
+%
+% [TR, ROT] = iterativeClosestPoint(REF, FLT, STEPS, MIN_DIST, THR)
+%   will use the supplied threshold THR for leaving out possible
+%   outliers during optimization. See CLOSESTPOINT, for more
+%   details.
+%
+% [TR_FLT, TR, ROT] = iterativeClosestPoint(REF, FLT, STEPS, ...)
+%   will return the transformed floating points and also the
+%   translation vector and the rotation matrix.
+%
+%   If no threshold is supplied, ITERATIVECLOSESTPOINT will use the
+%   default threshold from CLOSESTPOINT.
+%
+%   Example:
+%
+%   See also: CLOSESTPOINT
+%
+%
+% Author:  Cristian Pirnog
+%          Computer Vision Laboratory - ETH Zurich
+%          pirnog@vision.ee.ethz.ch
+%
+% Created: 12 May 2004
+%
+%/***************************************************************************
+% *                                                                         *
+% *   This program is not free software. It is distributed under the        *
+% *   GNU General Public License version 2 or later. See the included       *
+% *   "gpl.txt" file or get it at http://www.gnu.org/licenses/gpl.html      *
+% *                                                                         *
+% *   This program is the property of ETH (Swiss Federal Institute of       * 
+% *   Technology) and the author. For feedback and comments please contact  *
+% *   pirnog@vision.ee.ethz.ch                                              *
+% *                                                                         *
+% ***************************************************************************/
+%
+
+
+function varargout = iterativeClosestPoint(referencePoints, ...
+					   floatingPoints, steps, ...
+					   varargin) 
+
+
+%===============================================================
+% Check that 'steps' is a scalar
+%===============================================================
+if ndims(steps)~=2 || min(size(steps))~=1
+  error('The number of steps must be a scalar')
+end
+
+
+%===============================================================
+% Check for 'threshold'
+%===============================================================
+minDist=0;
+closestPointCall='closestPoint(referencePoints, floatingPoints)';
+if nargin>3
+  minDist=varargin{:, 1};
+  if nargin==5
+    threshold=varargin{:, 2};
+    closestPointCall=['closestPoint(referencePoints, floatingPoints,' ...
+		      ' threshold)'];
+  end
+end
+
+
+%===============================================================
+% Make the floating data points have the coordinates on columns
+%===============================================================
+% floatingPoints = [ x1, y1, z1;
+%                    x2, y2, z2;
+%                    x3, y3, z3;
+%                    x4, y4, z4;
+%                       ...
+%                    xN, yN, zN];
+%
+noOfDims = 3;
+if size(floatingPoints, 2)==noOfDims
+  floatingPoints=floatingPoints.';
+end
+
+% Same for the reference data points
+if size(referencePoints, 2)==noOfDims
+  referencePoints=referencePoints.';
+end
+
+
+%===============================================================
+% Initialize translation and rotation
+%===============================================================
+rotation=eye(3);
+translation=zeros(1, 3);
+
+
+%===============================================================
+% Perform the ICP
+%===============================================================
+for i=1:steps
+  % Compute the new translation and rotation
+  [newTranslation, newRotation, d]=eval(closestPointCall);
+  fprintf('Distance: %f\n',d);
+  drawnow % let user trying to interact with figures get _some_ chance!  GJ
+  
+  % Transform the floating points
+  floatingPoints = newRotation*floatingPoints + repmat(newTranslation.', 1, size(floatingPoints, 2));
+
+  % Update the total rotation and translation
+  rotation = newRotation*rotation;
+  translation = translation + newTranslation*newRotation;
+    
+  % Check for early convergence
+  if minDist>d
+    fprintf('Converged to %f after %d steps\n',d,i)
+    break
+  end
+end
+if i==steps
+  fprintf('Converged only to %f after %d steps \n',d,steps)
+end
+%===============================================================
+% Assign the output values
+%===============================================================
+switch nargout
+ case 1
+  varargout(1) = {floatingPoints};
+ case 2
+  varargout(1) = {translation};
+  varargout(2) = {rotation};
+ otherwise
+  varargout(1) = {floatingPoints};
+  varargout(2) = {translation};
+  varargout(3) = {rotation};
+end
\ No newline at end of file
diff --git a/zUtil_ICP/testICP.m b/zUtil_ICP/testICP.m
new file mode 100755
index 0000000000000000000000000000000000000000..3b0068dcaf432b55efead94e33ccfc896836322e
--- /dev/null
+++ b/zUtil_ICP/testICP.m
@@ -0,0 +1,176 @@
+% Test program for the ITERATIVECLOSESTPOINT algorithm.
+%
+% This program:
+%      - reads the reference data from an ASCII file;
+%      - creates the floating data by rotating and translating the
+%   reference data;
+%      - plots the two initial data-sets as point clouds in the same
+%   figure;
+%      - asks you to hit any key
+%      - performs ICP;
+%      - plots the two final data-sets as point clouds in the same
+%   figure;
+%
+% The reference data file must be an ASCII file with the points
+% coordinates written on three columns:
+%
+%        P1_x    P1_y   P1_z
+%        P2_x    P2_y   P2_z
+%        P3_x    P3_y   P3_z
+%              ........
+%        Pn_x    Pn_y   Pn_z
+%
+%
+% Author:  Cristian Pirnog
+%          Computer Vision Laboratory - ETH Zurich
+%          pirnog@vision.ee.ethz.ch
+%
+% Created: 12 May 2004
+%
+%/***************************************************************************
+% *                                                                         *
+% *   This program is not free software. It is distributed under the        *
+% *   GNU General Public License version 2 or later. See the included       *
+% *   "gpl.txt" file or get it at http://www.gnu.org/licenses/gpl.html      *
+% *                                                                         *
+% *   This program is the property of ETH (Swiss Federal Institute of       * 
+% *   Technology) and the author. For feedback and comments please contact  *
+% *   pirnog@vision.ee.ethz.ch                                              *
+% *                                                                         *
+% ***************************************************************************/
+%
+
+clear all
+
+%+++++++++++++++++++++++++++++++++++++++++++++++++++++++
+%    
+%+++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+%The reference data file
+referenceDataFileName = 'data2_isotropic.txt';
+
+% Use the default matlab axis (if useDefaultAxis~=0).
+% If you use the default matlab axis is very difficult
+% to compare the initial and final plots.
+useDefaultAxis=0;
+
+% Translation
+deltaT = [0 0 0]; % [1, -2, 1];
+
+% Rotation angles (degrees)
+alphaX=17;
+alphaY=-8;
+alphaZ=14;
+
+% The maximum number of steps for ICP
+Nsteps=250;
+
+% The maximum CLOSEST_DISTANCE for which the two 
+% data-sets are considered alligned (this depends
+% strongly on the data). If you don't want to use 
+% it, just comment it.
+maxICPDist=1e-5;
+
+% Plot the data (if doPlot~=0).
+doPlot=1;
+
+%+++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+close all
+clc
+
+% Read the reference data
+r=load(referenceDataFileName, 'ascii').';
+
+
+%Transform the angles in radians
+alphaX = alphaX*pi/180;
+alphaY = alphaY*pi/180;
+alphaZ = alphaZ*pi/180;
+
+
+% Compute the rotation matrix
+Rx=[1, 0, 0;
+    0, cos(alphaX), sin(alphaX);
+    0, -sin(alphaX), cos(alphaX)];
+
+Ry=[cos(alphaY), 0, -sin(alphaY);
+    0, 1, 0;
+    sin(alphaY), 0, cos(alphaY)];
+
+Rz=[cos(alphaZ), sin(alphaZ), 0;
+    -sin(alphaZ), cos(alphaZ), 0;
+    0, 0, 1];
+
+R=Rx*Ry*Rz
+clear Rx Ry Rz
+
+
+% fprintf(' {');
+% fprintf('Point3D(%f, %f, %f),\n', R(1, 1), R(1, 2), R(1, 3));
+% fprintf('Point3D(%f, %f, %f),\n', R(2, 1), R(2, 2), R(2, 3));
+% fprintf('Point3D(%f, %f, %f)', R(3, 1), R(3, 2), R(3, 3));
+% fprintf('};');
+
+% Apply the transformation
+% Rotate the floating data...
+f=r-repmat(mean(r, 2), 1, size(r, 2));
+f= R*f;
+f=f+repmat(mean(r, 2), 1, size(r, 2));
+
+% ... and then translate it
+f = f + repmat(deltaT.', 1, size(r, 2));
+
+
+% Plot the two initial data-sets
+mX=min([min(f(1, :)) min(r(1, :))]);
+mY=min([min(f(2, :)) min(r(2, :))]);
+mZ=min([min(f(3, :)) min(r(3, :))]);
+
+MX=max([max(f(1, :)) max(r(1, :))]);
+MY=max([max(f(2, :)) max(r(2, :))]);
+MZ=max([max(f(3, :)) max(r(3, :))]);
+
+axisSize=max([MX-mX, MY-mY, MZ-mZ]);
+if doPlot
+  figure(1)
+  hold off
+  plot3(r(1, :), r(2, :), r(3, :), 'bo');
+  grid on, hold on
+  plot3(f(1, :), f(2, :), f(3, :), 'ro');
+  title('Initial')
+  legend('Ref', 'Flt')
+  xlabel('x'), ylabel('y'), zlabel('z')
+  if ~useDefaultAxis
+    axis([mX mX+axisSize mY mY+axisSize mZ mZ+axisSize])
+  end
+  fprintf('Hit any key...\n')
+  pause
+end
+
+
+% Perform ICP  
+fprintf('Performing ICP...\t\t')
+if ~exist('maxICPDist')
+  [f1, tr, rot] = iterativeClosestPoint(r, f, Nsteps);
+else
+  [f1, tr, rot] = iterativeClosestPoint(r, f, Nsteps, maxICPDist);
+end
+fprintf('[Done]')
+
+
+% Plot the two final data-sets
+if doPlot
+  figure(2)
+  hold off
+  plot3(r(1, :), r(2, :), r(3, :), 'bo');
+  hold on, grid on
+  plot3(f1(1, :), f1(2, :), f1(3, :), 'k*');
+  title('After ICP')
+  legend('Ref', 'Flt')
+  xlabel('x'), ylabel('y'), zlabel('z')
+  if ~useDefaultAxis
+    axis([mX mX+axisSize mY mY+axisSize mZ mZ+axisSize])  
+  end
+end
diff --git a/zUtil_Imaging/gtAdjustThreshold.m b/zUtil_Imaging/gtAdjustThreshold.m
new file mode 100755
index 0000000000000000000000000000000000000000..79c44c8db3f6548e1d178840a910992a26f2ae17
--- /dev/null
+++ b/zUtil_Imaging/gtAdjustThreshold.m
@@ -0,0 +1,51 @@
+function [thresh_val,mask]=gtAdjustThreshold(thresh_val,img,h)
+
+
+   %if ~exist('h','var')
+   %  h=figure; 
+   %	 state=uisuspend(h,false);  %create a new figure
+   %end
+  
+  quit=0;
+  
+  subplot(1,2,1);
+  imshow(img,[])
+  subplot(1,2,2);
+  colormap(gray)
+ 
+  set(h,'KeyPressFcn',@sfKeyPress)
+  
+  while 1
+      sfUpdateFigure
+      if quit==1
+		
+        break
+      end
+  end
+   
+function sfKeyPress(varargin)
+  c=varargin{2};
+  switch c.Key
+	case 'rightarrow'
+      thresh_val=thresh_val+thresh_val/10;
+	  sfUpdateFigure;
+    case 'leftarrow' 
+      thresh_val=thresh_val-thresh_val/10;
+	  sfUpdateFigure;
+    case 'return'
+      %exit interactive mode and return current shift
+      set(h,'KeyPressFcn','');
+	  
+	  mask=double(img>thresh_val);
+	  quit=1;
+  end      
+end
+
+function sfUpdateFigure
+  %thresh_val
+  imshow(img>thresh_val,[]);
+  drawnow;
+end
+
+
+end
\ No newline at end of file
diff --git a/zUtil_Imaging/gtAlphaAdjust.m b/zUtil_Imaging/gtAlphaAdjust.m
new file mode 100755
index 0000000000000000000000000000000000000000..2c77826ce598966816c2a7ad909b9b607ed19e35
--- /dev/null
+++ b/zUtil_Imaging/gtAlphaAdjust.m
@@ -0,0 +1,58 @@
+function gtAlphaAdjust(h1,h2)
+% GTALPHAADJUST.M Adds a GUI slider to adjust opacity of two overlaid images
+% Usage:
+%      gtAlphaAdjust(h1,h2)
+%      h1 and h2 are the handles to the two images
+%
+% Example:
+% im1=rand(100);
+% im2=rand(100);
+% clf
+% h1=imagesc(im1)
+% hold on
+% h2=imagesc(im2)
+% gtAlphaAdjust(h1,h2)
+
+% GJ September 2006
+h_fig=get(get(h1,'parent'),'parent');  % find the figure that has the objects in it
+
+h_gui=figure;  % create a new figure for the sliders
+tmp=get(h_gui,'position');
+ss=get(0,'screensize');
+set(h_gui,'position',[tmp(1) tmp(2) 200 200])
+set(h_gui,'toolbar','none','menubar','none','name','AlphaControl','numbertitle','off')
+
+
+
+  h_slider1=uicontrol('style','slider');
+  set(h_slider1,'callback',@sfUpdateDisplay)
+  set(h_slider1,'units','normalized');
+  set(h_slider1,'position',[0.1 0.5 0.9 0.3])
+  set(h_slider1,'min',0,'max',1,'sliderstep',[0.01 0.01]);
+  set(h_slider1,'value',1);
+  set(h_slider1,'tag','slider');
+  
+
+  h_slider2=uicontrol('style','slider');
+  set(h_slider2,'callback',@sfUpdateDisplay)
+  set(h_slider2,'units','normalized');
+  set(h_slider2,'position',[0.1 0.1 0.9 0.3])
+  set(h_slider2,'min',0,'max',1,'sliderstep',[0.01 0.01]);
+  set(h_slider2,'value',1);
+  set(h_slider2,'tag','slider');
+  set(h_gui,'handlevisibility','callback')
+  
+  function sfUpdateDisplay(varargin)
+
+    switch varargin{1}
+      case h_slider1
+        set(h1,'alphadata',get(gcbo,'value'));
+      case h_slider2
+        set(h2,'alphadata',get(gcbo,'value'));
+      otherwise
+        
+        disp('Empty')
+    end
+    drawnow
+  end
+end
diff --git a/zUtil_Imaging/gtBboxSizeMat.m b/zUtil_Imaging/gtBboxSizeMat.m
new file mode 100755
index 0000000000000000000000000000000000000000..e6b6b30c24404ed4988f5eb10b4806254838e1c6
--- /dev/null
+++ b/zUtil_Imaging/gtBboxSizeMat.m
@@ -0,0 +1,3 @@
+function dim=gtBboxSizeMat(bbox)
+% GTBBOXSIZEMAT returns size of gtbbox in matrix convention (rows, columns)
+dim=[bbox(4) bbox(3)];
\ No newline at end of file
diff --git a/zUtil_Imaging/gtCrop.m b/zUtil_Imaging/gtCrop.m
new file mode 100755
index 0000000000000000000000000000000000000000..cc7a3a8f671677b8f680262023afefab503f5a80
--- /dev/null
+++ b/zUtil_Imaging/gtCrop.m
@@ -0,0 +1,43 @@
+function im=gtCrop(im,gtbbox)
+% GTCROP.M Crops an image given a bounding box
+% Usage:
+%       im=gtCrop(imorig,bbox)
+%       The input image, imorig, is cropped by bbox, and the result is im
+%       bbox has a format [x1 y1 xsize ysize] where x1 and y1 are the top
+%       left pixel to be INCLUDED and x/y sizes are the dimensions of the
+%       resulting image.
+% 
+%       If the bounding box is bigger than the original image, it is
+%       reduced to fit.
+%
+% Example:
+%   imorig=reshape(1:25,5,5)   % produce a 10x10 matrix
+%   bbox=[3 2 2 3];
+%   im=gtCrop(imorig,bbox)
+%
+%   imorig = 
+%     1     6    11    16    21
+%     2     7    12    17    22
+%     3     8    13    18    23
+%     4     9    14    19    24
+%     5    10    15    20    25
+%  im =
+%    12    17
+%    13    18
+%    14    19
+
+
+% Greg Johnson, September 2006
+     x1=gtbbox(1);
+     y1=gtbbox(2);
+     x2=x1+gtbbox(3)-1;
+     y2=y1+gtbbox(4)-1;
+     
+     % if bbox is too large, crop to image extent
+     if x1<1, x1=1;end
+     if y1<1, y1=1;end
+     
+     if x2>size(im,2), x2=size(im,2);end
+     if y2>size(im,1), y2=size(im,1);end
+
+     im=im(y1:y2,x1:x2);
diff --git a/zUtil_Imaging/gtCropContour.m b/zUtil_Imaging/gtCropContour.m
new file mode 100755
index 0000000000000000000000000000000000000000..e7a8de611088714790b13c90e2ce222ff34cbfdc
--- /dev/null
+++ b/zUtil_Imaging/gtCropContour.m
@@ -0,0 +1,36 @@
+function [x,y]=gtCropContour(x,y,gtbbox)
+% GTCROPCONTOUR.M Crops a contour given a bounding box
+% Usage:
+%       [x,y]=gtCropContour(x,y,bbox)
+%       The input contour, contained as a series of points in x and y, is 
+%       cropped by bbox, and the result is returned
+%       bbox has a format [x1 y1 xsize ysize] where x1 and y1 are the top
+%       left pixel to be INCLUDED and x/y sizes are the dimensions of the
+%       resulting image.
+% 
+%
+% Example:
+%   [x,y]=circlepoints(10,10,15);
+%   bbox=[1 1 40 40];
+%   [x2,y2]=gtCropContour(x,y,bbox);
+%   figure
+%   plot(x,y,'r.-');
+%   hold on 
+%   plot(x2,y2,'g.-')
+
+% Greg Johnson, September 2006
+     x1=gtbbox(1);
+     y1=gtbbox(2);
+     x2=x1+gtbbox(3)-1;
+     y2=y1+gtbbox(4)-1;
+     
+     % if bbox is too large, crop to image extent
+     minx=(x<gtbbox(1));
+     maxx=(x>gtbbox(1)+gtbbox(3)-1);
+     miny=(y<gtbbox(2));
+     maxy=(y>gtbbox(2)+gtbbox(4)-1);
+
+     x(minx|maxx|miny|maxy)=[];
+     y(minx|maxx|miny|maxy)=[];
+     
+     
\ No newline at end of file
diff --git a/zUtil_Imaging/gtExtract b/zUtil_Imaging/gtExtract
new file mode 100755
index 0000000000000000000000000000000000000000..584c782a4fa1a19f5bb58cc646bc262a0c7d4195
--- /dev/null
+++ b/zUtil_Imaging/gtExtract
@@ -0,0 +1,44 @@
+function im=gtCrop(im,gtbbox)
+% GTCROP.M Crops an image given a bounding box
+% Usage:
+%       im=gtCrop(imorig,bbox)
+%       The input image, imorig, is cropped by bbox, and the result is im
+%       bbox has a format [x1 y1 xsize ysize] where x1 and y1 are the top
+%       left pixel to be INCLUDED and x/y sizes are the dimensions of the
+%       resulting image.
+% 
+%       If the bounding box is bigger than the original image, it is
+%       reduced to fit.
+%
+% Example:
+%   imorig=reshape(1:25,5,5)   % produce a 10x10 matrix
+%   bbox=[3 2 2 3];
+%   im=gtCrop(imorig,bbox)
+%
+%   imorig = 
+%     1     6    11    16    21
+%     2     7    12    17    22
+%     3     8    13    18    23
+%     4     9    14    19    24
+%     5    10    15    20    25
+%  im =
+%    12    17
+%    13    18
+%    14    19
+
+
+% Greg Johnson, September 2006
+     x1=gtbbox(1);
+     y1=gtbbox(2);
+     x2=x1+gtbbox(3)-1;
+     y2=y1+gtbbox(4)-1;
+     
+     % if bbox is too large, crop to image extent
+     if x1<1, xa=1;else xa=x1;end 
+     if y1<1, ya=1;else ya=y1;end
+     
+     if x2>size(im,2), xb=size(im,2);else xb=x2;end
+     if y2>size(im,1), yb=size(im,1);else yb=y2;end
+
+     im=im(ya:yb,xa:xb);
+im=gtPlaceSubImage(im,zeros(gtbbox(4),gtbbox(3)),gtbbox(3)-xb,gtbbox(4)-yb);
diff --git a/zUtil_Imaging/gtExtract.m b/zUtil_Imaging/gtExtract.m
new file mode 100755
index 0000000000000000000000000000000000000000..8a57fc339e24ccd74ddcade8ddb6d0c73647e173
--- /dev/null
+++ b/zUtil_Imaging/gtExtract.m
@@ -0,0 +1,35 @@
+function im=gtExtract(imorig,gtbbox)
+% GTEXTRACT.M Extracts an subimage, possibly padded with zeros,given a bounding box
+% Usage:
+%       im=gtExtract(imorig,bbox)
+%       The input image, imorig, is cropped by bbox, and the result is im
+%       bbox has a format [x1 y1 xsize ysize] where x1 and y1 are the top
+%       left pixel to be INCLUDED and x/y sizes are the dimensions of the
+%       resulting image.
+%
+%       The bounding box CAN be larger than the supplied image - see
+%       examples.
+%
+% Examples:
+% TO BE WRITTEN!!
+
+% Greg Johnson, September 2006
+x1=gtbbox(1);
+y1=gtbbox(2);
+x2=x1+gtbbox(3)-1;
+y2=y1+gtbbox(4)-1;
+
+% get necessary portion of image
+subim=gtCrop(imorig,gtbbox);
+if numel(subim)==0  % nothing left!
+  im=zeros(gtbbox(4),gtbbox(3));
+  return
+end
+if x1>1
+  x1=1;
+end
+if y1>1
+  y1=1;
+end
+
+im=gtPlaceSubImage(subim,zeros(gtbbox(4),gtbbox(3)),(-x1)+2,(-y1)+2);
diff --git a/zUtil_Imaging/gtMask2Poly.m b/zUtil_Imaging/gtMask2Poly.m
new file mode 100755
index 0000000000000000000000000000000000000000..eac8ebafb3a847840aa8202b5695d1026b7b4bb2
--- /dev/null
+++ b/zUtil_Imaging/gtMask2Poly.m
@@ -0,0 +1,90 @@
+function [x,y]=gtMask2Poly(mask)
+% GTMASK2POLY.M Converts a black and white outline to a series of points.
+% Usage:
+%    [x,y]=gtMask2Poly(mask);
+%
+% Example:
+% %create a simple outline image
+% im=zeros(10,10);
+% im(3,3:7)=1;im(7,3:7)=1; im(3:7,3)=1;im(3:7,7)=1;
+% im = not(im);
+% % convert to polygon
+% [x,y]=gtMask2Poly(im);
+% % display results
+% figure
+% imagesc(im)
+% colormap(gray)
+% hold on
+% plot(x,y,'ro');
+% hold off
+%
+%
+% THIS CODE IS NOT ROBUST!
+debug=false;
+
+% some details
+fprintf('Image size: %d x %d\n',size(mask)')
+% put 10% padding around it
+pad=max(1,round(0.1*max(size(mask))));
+mask_padded=gtPlaceSubImage(mask,zeros(size(mask)+(2*pad)),pad,pad);
+if debug
+  imagesc(mask_padded);colormap(gray),axis image
+end
+[fx,fy]=gradient(double(mask_padded));
+fmag=sqrt(fx.^2+fy.^2);
+
+[u,v]=GVF(fmag,0.2,15);
+gvfmag=sqrt(u.^2+v.^2);
+% normalise gvf
+unorm=u./(gvfmag+eps);
+vnorm=v./(gvfmag+eps);
+
+% for image with area 5000
+defaultmaskarea=5000;
+defaultsnakeoptions.elasticity=5;
+defaultsnakeoptions.rigidity=0.1;
+defaultsnakeoptions.viscosity=1;
+defaultsnakeoptions.forcefactor=1;
+defaultsnakeoptions.iterations=5;
+% perhaps make variation here?
+
+maskarea=prod(size(mask))
+arearatio=maskarea/defaultmaskarea;
+
+snakeoptions=defaultsnakeoptions;
+%fprintf('Scaling parameters to take account of image size (area ratio: %d)\n',round(arearatio));
+
+%snakeoptions.forcefactor=snakeoptions.forcefactor*arearatio;
+%snakeoptions.elasticity=snakeoptions.elasticity*arearatio;
+%snakeoptions.viscosity=snakeoptions.viscosity/arearatio;
+snakeoptions.iterations=snakeoptions.iterations*arearatio;
+snakeforcefield.x=unorm;
+snakeforcefield.y=vnorm;
+
+
+x=[5 size(fmag,2)-5 size(fmag,2)-5 5];
+y=[5 5 size(fmag,1)-5 size(fmag,1)-5];
+
+[x,y]=snakeinterp(x,y,2,1);
+if debug
+  figure(99)
+  imagesc(mask_padded),colormap(gray),axis image
+  hold on
+  quiver(u,v)
+  drawnow
+end
+for i=1:10,
+  if debug
+    hp=snakedisp(x,y,'g.-');
+    title(['Deformation in progress,  iter = ' num2str(i*snakeoptions.iterations)])
+    drawnow
+  end
+  [x,y]=snakedeform(x,y,snakeforcefield,snakeoptions);
+  [x,y]=snakeinterp(x,y,2,1);
+end
+if debug
+  snakedisp(x,y,'r-')
+end
+x=x-pad;
+y=y-pad;
+
diff --git a/zUtil_Imaging/gtPlaceSubImage.m b/zUtil_Imaging/gtPlaceSubImage.m
new file mode 100755
index 0000000000000000000000000000000000000000..ee38d7151d31a3b165e887ef77caf7cfb8a69472
--- /dev/null
+++ b/zUtil_Imaging/gtPlaceSubImage.m
@@ -0,0 +1,17 @@
+function im_big=gtPlaceSubImage(im_small,im_big,topleftx,toplefty)
+% GTPLACESUBIMAGE Place a small image within a larger one
+% Usage:
+%     imbig=gtPlaceSubImage(imsmall,imbig,topleftx,toplefty)
+%     imsmall is the image to place
+%     imbig is the image to place it into
+%     topleftx/y is the location of the top left corner of the placement
+% 
+%  The final image is the same size as imbig, no matter where the imsmall
+%  is placed
+
+% Greg Johnson, September 2006
+
+sz_big=size(im_big);
+sz_small=size(im_small);
+im_big(toplefty:toplefty+sz_small(1)-1,topleftx:topleftx+sz_small(2)-1)=im_small;
+im_big=im_big(1:sz_big(1),1:sz_big(2));
diff --git a/zUtil_Imaging/gtPlaceSubVolume.m b/zUtil_Imaging/gtPlaceSubVolume.m
new file mode 100755
index 0000000000000000000000000000000000000000..c6e9cc1c918008216b4ca656c2e5d0937e31ee73
--- /dev/null
+++ b/zUtil_Imaging/gtPlaceSubVolume.m
@@ -0,0 +1,36 @@
+function output=gtPlaceSubVolume(output, input, shift)
+% output=gtPlaceSubVolume(output, input, shift)
+% ~analogous to gtPlaceSubImage
+% places the input volume in the output vol, with the origin of the input
+% volume at point defined by shift=[y x z] in the output volume.  Any part of the
+% input volume falling outside of the output volume is cropped.  Origin
+% can contain negative coordinates, again anything outside the output
+% volume is cropped.
+% so...  shift=[0 0 0] means that the voxel (a,b,c) in input will be at
+% point (a,b,c) in the output.
+%shift=[2 -2 0] means that voxel (a,b,c) will be at (a+2, b-2, c) in
+%output.
+
+[sizeYi, sizeXi, sizeZi]=size(input);
+[sizeYo, sizeXo, sizeZo]=size(output);
+
+%output(y1o:y2o, x1o:x2o, z1o:z2o)=output(y1o:y2o, x1o:x2o, z1o:z2o)+input(y1i:y2i, x1i:x2i, z1i:z2i);
+y=shift(1);x=shift(2);z=shift(3);
+
+%output volume limits
+y1o=max(1, y+1);
+y2o=min(sizeYo, y+sizeYi);
+x1o=max(1, x+1);
+x2o=min(sizeXo, x+sizeXi);
+z1o=max(1, z+1);
+z2o=min(sizeZo, z+sizeZi);
+
+%input volume limits
+y1i=max(1, -y+1);
+y2i=min(sizeYi, sizeYo-y);
+x1i=max(1, -x+1);
+x2i=min(sizeXi, sizeXo-x);
+z1i=max(1, -z+1);
+z2i=min(sizeZi, sizeZo-z);
+
+output(y1o:y2o, x1o:x2o, z1o:z2o)=output(y1o:y2o, x1o:x2o,z1o:z2o)+input(y1i:y2i, x1i:x2i, z1i:z2i);
\ No newline at end of file
diff --git a/zUtil_Imaging/gtShift.m b/zUtil_Imaging/gtShift.m
new file mode 100755
index 0000000000000000000000000000000000000000..a58d8828a9ba130f3b5fb7c9322c68bc8f84ec11
--- /dev/null
+++ b/zUtil_Imaging/gtShift.m
@@ -0,0 +1,69 @@
+function im=gtShift(imorig,x,y,pad)
+% Shifts an image with x (horizontal right) and y (vertical downwards), and zero pads on edges. In case of 
+% non-integer x or y, 'interpolatef' is used.
+
+xr=ceil(abs(x));
+yr=ceil(abs(y));
+
+if exist('pad','var')
+  if strcmpi(pad,'av')
+    padleft=mean(imorig(:,1));
+    padright=mean(imorig(:,end));
+    padtop=mean(imorig(1,:));
+    padbottom=mean(imorig(end,:));
+  else
+    padleft=pad;
+    padright=pad;
+    padtop=pad;
+    padbottom=pad;
+  end
+else
+  padleft=0;
+  padright=0;
+  padtop=0;
+  padbottom=0;
+end
+
+
+if round(x)==x && round(y)==y
+  xpad=zeros(size(imorig,1),abs(xr));
+  ypad=zeros(abs(yr),size(imorig,2));
+  
+  if x>0
+    xpad(:,:)=padleft;
+    tmp=[xpad imorig];
+    im=tmp(:,1:size(imorig,2));
+  else
+    xpad(:,:)=padright;
+    tmp=[imorig xpad];
+    im=tmp(:,abs(xr)+1:end);
+  end
+
+  if y>0
+    ypad(:,:)=padtop;
+    tmp=[ypad;im];
+    im=tmp(1:size(imorig,1),:);
+  else
+    ypad(:,:)=padbottom;
+    tmp=[im;ypad];
+    im=tmp(abs(yr)+1:end,:);
+  end
+
+else
+  im=interpolatef(imorig,y,x); % !! interpolatef(im,vertical_down,horizontal_right)
+
+  if x>0
+    im(:,1:xr)=padleft;
+  else
+    im(:,end-xr+1:end)=padright;
+  end
+
+  if y>0
+    im(1:yr,:)=padtop;
+  else
+    im(end-yr+1:end,:)=padbottom;
+  end
+
+end
+
+end % of function
diff --git a/zUtil_Imaging/gtShiftContour.m b/zUtil_Imaging/gtShiftContour.m
new file mode 100755
index 0000000000000000000000000000000000000000..7cf0c88d2f6825ec15ecaac274211a97ea8c6de4
--- /dev/null
+++ b/zUtil_Imaging/gtShiftContour.m
@@ -0,0 +1,16 @@
+function [x,y]=gtShiftContour(x,y,shiftx,shifty,sizex,sizey)
+
+if (x<1) | (y<1)
+  error('X and Y must be inside the sizex,sizey pair')
+end
+x=mod(x+shiftx-1,sizex)+1;
+y=mod(y+shifty-1,sizey)+1;
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Imaging/gtShift_subp.m b/zUtil_Imaging/gtShift_subp.m
new file mode 100755
index 0000000000000000000000000000000000000000..a2b5bba59571a3c31d045ae47d8dbff1a6cf2b3d
--- /dev/null
+++ b/zUtil_Imaging/gtShift_subp.m
@@ -0,0 +1,45 @@
+function im=gtShift_subp(imorig,x,y,varargin)
+% Shifts an image with x and y, and zero pads on edges. In case of 
+% non-integer x or y, 'interpolatef' is used.
+
+xr=ceil(abs(x));
+yr=ceil(abs(y));
+
+if round(x)==x && round(y)==y
+  xpad=zeros(size(imorig,1),abs(xr));
+  ypad=zeros(abs(yr),size(imorig,2));
+
+  if x>0
+    tmp=[xpad imorig];
+    im=tmp(:,1:size(imorig,2));
+  else
+    tmp=[imorig xpad];
+    im=tmp(:,abs(xr)+1:end);
+  end
+
+  if y>0
+    tmp=[ypad;im];
+    im=tmp(1:size(imorig,1),:);
+  else
+    tmp=[im;ypad];
+    im=tmp(abs(yr)+1:end,:);
+  end
+
+else
+  im=interpolatef(imorig,x,y);
+
+  if x>0
+    im(:,1:xr)=0;
+  else
+    im(:,end-xr+1:end)=0;
+  end
+
+  if y>0
+    im(1:yr,:)=0;
+  else
+    im(end-yr+1:end,:)=0;
+  end
+
+end
+
+end % of function
diff --git a/zUtil_Imaging/gtShift_xxx.m b/zUtil_Imaging/gtShift_xxx.m
new file mode 100755
index 0000000000000000000000000000000000000000..b9cead1cd0baa7f66b1d33a57781a2ae28a4919e
--- /dev/null
+++ b/zUtil_Imaging/gtShift_xxx.m
@@ -0,0 +1,31 @@
+function im=gtShift(imorig,x,y)
+
+xpad=zeros(size(imorig,1),abs(x));
+ypad=zeros(abs(y),size(imorig,2));
+
+if x>0
+ 
+  tmp=[xpad imorig];
+  im=tmp(:,1:size(imorig,2));
+else
+  tmp=[imorig xpad];
+  im=tmp(:,abs(x)+1:end);
+
+end
+
+if y>0
+  tmp=[ypad;im];
+  im=tmp(1:size(imorig,1),:);
+else
+  tmp=[im;ypad];
+  im=tmp(abs(y)+1:end,:);
+end
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Imaging/hsl2rgb.m b/zUtil_Imaging/hsl2rgb.m
new file mode 100755
index 0000000000000000000000000000000000000000..cfd6304b84e5f5192c91098f33d2979a71e3fd1f
--- /dev/null
+++ b/zUtil_Imaging/hsl2rgb.m
@@ -0,0 +1,72 @@
+function rgb=hsl2rgb(hsl)
+
+%Converts Hue-Saturation-Luminance Color value to Red-Green-Blue Color value
+%
+%Usage
+%       RGB = hsl2rgb(HSL)
+%
+%   converts HSL, a M X 3 color matrix with values between 0 and 1
+%   into RGB, a M X 3 color matrix with values between 0 and 1
+%
+%See also rgb2hsl, rgb2hsv, hsv2rgb
+
+%Suresh E Joel, April 26,2003
+
+if nargin<1,
+    error('Too few arguements for hsl2rgb');
+    return;
+elseif nargin>1,
+    error('Too many arguements for hsl2rgb');
+    return;
+end;
+
+if max(max(hsl))>1 | min(min(hsl))<0,
+    error('HSL values have to be between 0 and 1');
+    return;
+end;
+
+todo=size(hsl, 1);
+%preallocate rgb
+rgb=zeros(size(hsl));
+
+for i=1:size(hsl,1),
+    if hsl(i,2)==0,%when sat is 0
+        rgb(i,1:3)=hsl(i,3);% all values are same as luminance
+    end;
+    if hsl(i,3)<0.5,
+        temp2=hsl(i,3)*(1+hsl(i,2));
+    else
+        temp2=hsl(i,3)+hsl(i,2)-hsl(i,3)*hsl(i,2);
+    end;
+    temp1=2*hsl(i,3)-temp2;
+    temp3(1)=hsl(i,1)+1/3;
+    temp3(2)=hsl(i,1);
+    temp3(3)=hsl(i,1)-1/3;
+    for j=1:3,
+        if temp3(j)>1, 
+            temp3(j)=temp3(j)-1; 
+        elseif temp3(j)<0, 
+            temp3(j)=temp3(j)+1; 
+        end;
+        if 6*temp3(j)<1,
+            rgb(i,j)=temp1+(temp2-temp1)*6*temp3(j);
+        elseif 2*temp3(j)<1,
+            rgb(i,j)=temp2;
+        elseif 3*temp3(j)<2,
+            rgb(i,j)=temp1+(temp2-temp1)*(2/3-temp3(j))*6;
+        else
+            rgb(i,j)=temp1;
+        end;
+    end;
+    
+    %give a progress report for long lists
+    if todo>1000
+        if mod(i, 1000)==0
+          100*i/todo
+        end
+    end
+
+    
+end;
+
+rgb=round(rgb.*100000)./100000; %Sometimes the result is 1+eps instead of 1 or 0-eps instead of 0 ... so to get rid of this I am rounding to 5 decimal places)
\ No newline at end of file
diff --git a/zUtil_Imaging/rgb2hsl.m b/zUtil_Imaging/rgb2hsl.m
new file mode 100755
index 0000000000000000000000000000000000000000..19978b1024c6445d1aaf345a6531281ff5c92551
--- /dev/null
+++ b/zUtil_Imaging/rgb2hsl.m
@@ -0,0 +1,54 @@
+function hsl=rgb2hsl(rgb)
+
+%Converts Red-Green-Blue Color value to Hue-Saturation-Luminance Color value
+%
+%Usage
+%       HSL = rgb2hsl(RGB)
+%
+%   converts RGB, a M X 3 color matrix with values between 0 and 1
+%   into HSL, a M X 3 color matrix with values between 0 and 1
+%
+%See also hsl2rgb, rgb2hsv, hsv2rgb
+
+%Suresh E Joel, April 26,2003
+
+if nargin<1,
+    error('Too few arguements for rgb2hsl');
+    return;
+elseif nargin>1,
+    error('Too many arguements for rgb2hsl');
+    return;
+end;
+
+if max(max(rgb))>1 | min(min(rgb))<0,
+    error('RGB values have to be between 0 and 1');
+    return;
+end;
+
+for i=1:size(rgb,1),
+    mx=max(rgb(i,:));%max of the 3 colors
+    mn=min(rgb(i,:));%min of the 3 colors
+    imx=find(rgb(i,:)==mx);%which color has the max
+    hsl(i,3)=(mx+mn)/2;%luminance is half of max value + min value
+    if(mx-mn)==0,%if all three colors have same value, 
+        hsl(i,2)=0;%then s=0 and 
+        hsl(i,1)=0;%h is undefined but for practical reasons 0
+        return;
+    end;
+    if hsl(i,3)<0.5,
+        hsl(i,2)=(mx-mn)/(mx+mn);
+    else
+        hsl(i,2)=(mx-mn)/(2-(mx+mn));
+    end;
+    switch(imx(1))%if two colors have same value and be the maximum, use the first color
+    case 1 %Red is the max color
+        hsl(i,1)=((rgb(i,2)-rgb(i,3))/(mx-mn))/6;
+    case 2 %Green is the max color
+        hsl(i,1)=(2+(rgb(i,3)-rgb(i,1))/(mx-mn))/6;
+    case 3 %Blue is the max color
+        hsl(i,1)=(4+(rgb(i,1)-rgb(i,2))/(mx-mn))/6;
+    end;
+    if hsl(i,1)<0,hsl(i,1)=hsl(i,1)+1;end;%if hue is negative, add 1 to get it within 0 and 1
+end;
+
+hsl=round(hsl*100000)/100000; %Sometimes the result is 1+eps instead of 1 or 0-eps instead of 0 ... so to get rid of this I am rounding to 5 decimal places)
\ No newline at end of file
diff --git a/zUtil_Index/gtDrawGrainCubes2.m b/zUtil_Index/gtDrawGrainCubes2.m
new file mode 100755
index 0000000000000000000000000000000000000000..129c11a6d535866705d78228878882ee4ee1ad92
--- /dev/null
+++ b/zUtil_Index/gtDrawGrainCubes2.m
@@ -0,0 +1,185 @@
+% function gtDrawGrainCubes(grains,sample,numbered,hlight)
+%
+% Draws a figure representing grain size and orientation by cubes 
+% (unit cells in a cubic lattice) based on the Rodrigues vectors.
+%
+% USAGE  gtDrawGrainCubes(grains,sample)
+%        gtDrawGrainCubes(grains([1:10]),sample,1,[1,3,5])  
+%
+% INPUT  grains:   grain structure from indexing
+%        sample:   parameters and definition of the sample reference system  
+%                   (sample=gtSampleGeoInSampleSystem)
+%        numbered: if true, grain id-s are shown
+%        hlight:   grain id-s to be highlighted
+%
+
+
+function gtDrawGrainCubes2(grains,sample,numbered,hlight)
+
+
+if ~exist('hlight','var')
+  hlight=[];
+end
+if ~exist('numbered','var')
+  numbered=[];
+end
+
+nof_grains=length(grains);
+
+% cube_vertices=[0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1]-0.5*repmat([1 1 1],8,1);
+% cube_faces=[1 2 6 5; 2 3 7 6; 3 4 8 7; 4 1 5 8; 1 2 3 4; 5 6 7 8];
+
+strainscale=50; % 50
+fs=14;
+
+figure
+
+colormap(jet(1000))
+caxis([-0.01 0.01])
+cb=colorbar('FontSize',fs,'ytick',-0.01:0.005:0.01);
+%cb=colorbar('ytick',-0.01:0.002:0.01);
+%cbpos=get(cb,'Position');
+cbpos=[0.8 0.2 0.03 0.6];
+set(cb,'Position',cbpos);
+
+set(gca,'xtick',[],'xcolor','w')
+set(gca,'ytick',[],'ycolor','w')
+set(gca,'ztick',[],'zcolor','w')
+
+view(3);
+
+axhor=10*floor((sample.rad+30)/10);
+axver=10*floor((max(sample.top,sample.bot)+50)/10);
+axis([-axhor axhor -axhor axhor -axver axver])
+axis equal;
+%xlabel('X')
+%ylabel('Y')
+%zlabel('Z')
+hold on
+
+get(gca,'CameraPosition');
+get(gca,'CameraViewAngle');
+%camviewangle=
+%campos=
+
+t=1:360;
+circx=cosd(t)*sample.rad;
+circy=sind(t)*sample.rad;
+circbotz(1:360)=sample.bot;
+circtopz(1:360)=sample.top;
+plot3(circx,circy,circbotz,'k-','Linewidth',1)
+plot3(circx,circy,circtopz,'k-','Linewidth',1)
+plot3([0 0],[0 0],[sample.bot sample.top],'k.-.','Linewidth',1)
+plot3([-sample.rad -sample.rad],[0 0],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([0 0],[-sample.rad -sample.rad],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([sample.rad sample.rad],[0 0],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([0 0],[sample.rad sample.rad],[sample.bot sample.top],'k.-','Linewidth',1)
+
+% beam direction: 
+%plot3([-170 170],[0 0],[0 0],'r-','Linewidth',2)
+
+
+cube_vertices=[0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1]-0.5*repmat([1 1 1],8,1);
+cube_faces=[2 3 7 6; 4 1 5 8; 1 2 6 5;  3 4 8 7;  5 6 7 8; 1 2 3 4];
+% directions: +yz      -yz      -xz       +xz       +xy      -xy       
+%             +x       -x       -y        +y        +z       -z
+cube_planes=[1 0 0; -1 0 0; 0 -1 0; 0 1 0; 0 0 1; 0 0 -1];
+
+ for i=1:nof_grains
+   if ismember(i,hlight)
+     hl=1;
+   else
+     hl=false;
+   end
+   sfPlotGrainCube(grains{i},cube_vertices,cube_faces,cube_planes,hl,strainscale)
+   if numbered
+    text(grains{i}.center(1),-axhor,grains{i}.center(3),num2str(i),'Color','c')
+    text(axhor,grains{i}.center(2),grains{i}.center(3),num2str(i),'Color','c')
+   end
+ end
+ 
+end
+
+
+    
+function sfPlotGrainCube(grain,cube_vertices,cube_faces,cube_planes,hl,strainscale)
+
+ga=grain.stat.bbysmean/2;
+gc=grain.center;
+
+% if hl
+%   facecolors=cool(8);
+%   facecolors=facecolors(end-5:end,:);
+% else
+%   facecolors=copper(8);
+%   facecolors=facecolors(end-5:end,:);
+% end  
+
+
+% ELONGATION ALONG LOADING AXIS
+% 
+ggrain=Rod2g(grain.R_vector);
+grain_vertices=ga*cube_vertices*ggrain';
+grain_vertices_st=repmat(gc,8,1)+((eye(3)+grain.strain.ST*strainscale)*grain_vertices')';
+
+facecolor=grain.strain.Eps(3);
+
+facecolor=repmat(facecolor,6,1);
+%facecolor=facecolor.*repmat([1.0; 0.98; 0.96; 0.94; 0.92; 0.90],1,3);
+
+
+
+% SHEAR STRAIN ON THE CUBE CELL FACES
+
+% T=Rod2g(grain.R_vector); % T rotation tensor in lab system (align the axes with the crystal axes); 
+% 
+% ECRYST=T'*grain.strain.ST*T;  % strain tensor in the crystal reference
+% 
+% facecolor=zeros(6,1);
+% facecolor([1,2])=sqrt(ECRYST(1,2)^2+ECRYST(1,3)^2); % xy & xz
+% facecolor([3,4])=sqrt(ECRYST(2,1)^2+ECRYST(2,3)^2); % yx & yz
+% facecolor([5,6])=sqrt(ECRYST(3,1)^2+ECRYST(3,2)^2); % zx & zy
+% 
+% ST=grain.strain.ST;
+% 
+% grain_vertices=ga*cube_vertices*T';
+% grain_vertices_st=repmat(gc,8,1)+((eye(3)+ST*strainscale)*grain_vertices')';
+% 
+
+
+
+patch('Vertices',grain_vertices_st,'Faces',cube_faces,...
+      'FaceVertexCData',facecolor,'FaceColor','flat');
+
+
+% x0=[1 0 0];
+% y0=[0 1 0];
+% z0=[0 0 1];
+% 
+% xcr=T*x0';
+% ycr=T*y0';
+% zcr=T*z0';
+% 
+% 
+%  quiver3(gc(1),gc(2),gc(3),xcr(1),xcr(2),xcr(3),200,'r')
+%  quiver3(gc(1),gc(2),gc(3),ycr(1),ycr(2),ycr(3),200,'b')
+%  quiver3(gc(1),gc(2),gc(3),zcr(1),zcr(2),zcr(3),200,'k')
+%  
+%  grain_vertices=ga*cube_vertices*T';
+%  grain_vertices_st=repmat(gc,8,1)+((eye(3))*grain_vertices')';
+%  		
+%  patch('Vertices',grain_vertices_st,'Faces',cube_faces,...
+%       'FaceVertexCData',facecolor,'FaceColor','flat');
+%  	
+% 		
+%    edgevec=[0 1 0];
+%    facepos=[1 0 0];
+%    edgevec_g=edgevec*T';
+%    facepos_g=gc+ga/2*facepos*T';
+%    quiver3(facepos_g(1),facepos_g(2),facepos(3),edgevec_g(1),edgevec_g(2),edgevec_g(3),100,'c');
+ 
+  
+      
+end
+
+
diff --git a/zUtil_Index/gtINDEXTER.m b/zUtil_Index/gtINDEXTER.m
new file mode 100755
index 0000000000000000000000000000000000000000..334b580d61b88c179cce9d283ec9c1c831cec4c3
--- /dev/null
+++ b/zUtil_Index/gtINDEXTER.m
@@ -0,0 +1,278 @@
+%
+% INPUT:    Two data series of segmented and paired diffraction spots 180 degrees
+%           offset from Spotpair or Calibration tables.
+%
+%
+%   
+% OUTPUT:   Diffraction spots grouped into grains. Location, orientation
+%           and volume of grains are determined. 
+%
+%           
+%           
+
+function [grain,allgrainstat,probl,singlesfit,errest]=gtINDEXTER(strategy,flag_update,grain)
+
+load parameters.mat
+
+if ~exist('strategy','var')
+	strategy=[];
+end
+if ~exist('grain','var')
+	grain=[];
+end
+% if ~exist('flag_cont','var')
+%   flag_cont=false;
+% end
+if ~exist('flag_update','var')
+  flag_update=false;
+end
+
+tic
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SET PARAMETERS
+
+% Sample coordinate system defined in pixels by:
+sample=gtSampleGeoInSampleSystem(parameters);
+
+spacegroup=parameters.acq.spacegroup;
+latticepar=parameters.acq.latticepar;
+
+% allowed angles and their multiplicity according of plane families
+[ACM,ACMU]=gtAngConsMat(spacegroup);  % (in degrees)
+
+% vector of all valid 2theta angles in degrees
+[tmp,reflections]=gtnew_calculate_twotheta;
+reflections=reflections.reflections;
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Load data from database
+
+pairtable=parameters.acq.pair_tablename ;
+
+gtDBConnect ;
+
+
+% All the pair data are loaded in 'tot':
+
+% if flag_cont  % continue indexing
+%   mymcmd=sprintf(['SELECT pairID, difAID, difBID, theta, eta, omega, '...
+%   'avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, '...
+%   'samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, '...
+%   'thetatype FROM %s WHERE isnull(grainid) ORDER BY avbbYsize desc'],pairtable);
+%   disp('Continuation does not work yet...')
+% 	return
+% else          % (re)start indexing
+	mymcmd=sprintf(['SELECT pairID, difAID, difBID, theta, eta, omega, '...
+  'avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, '...
+  'samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, '...
+  'thetatype FROM %s ORDER BY avbbYsize desc'],pairtable);
+%end
+
+[tot.pairid,tot.aid,tot.bid,tot.theta,tot.eta,tot.omega,...
+	tot.int,tot.bbxs,tot.bbys, ...
+  tot.ca(:,1),tot.ca(:,2),tot.ca(:,3),tot.cb(:,1),tot.cb(:,2),tot.cb(:,3),...
+	tot.dir(:,1),tot.dir(:,2),tot.dir(:,3), ...
+  tot.pl(:,1),tot.pl(:,2),tot.pl(:,3),tot.thetatype]=mym(mymcmd);
+
+nof_lines=length(tot.pairid) ;
+
+% these line id-s will not correspond to pairID-s !!!
+tot.id=(1:nof_lines)';
+
+% Make sure directions are normalized 
+%  (e.g. acosd function after rounding errors from database)
+pllength=sqrt(tot.pl(:,1).^2 + tot.pl(:,2).^2 + tot.pl(:,3).^2) ;
+tot.pl=[tot.pl(:,1)./pllength tot.pl(:,2)./pllength tot.pl(:,3)./pllength] ;
+
+dirlength=sqrt(tot.dir(:,1).^2 + tot.dir(:,2).^2 + tot.dir(:,3).^2) ;
+tot.dir=[tot.dir(:,1)./dirlength tot.dir(:,2)./dirlength tot.dir(:,3)./dirlength] ;
+
+for i=1:nof_lines
+  tot.hkl(i,:)=reflections(tot.thetatype(i),:);
+end
+
+% Exclude Friedel pairs which are discarded
+if isfield(parameters.index,'discard')
+	consider=true(nof_lines,1);
+	discard=[];
+	for i=1:length(parameters.index.discard)
+		tmp=find(parameters.index.discard(i)==tot.pairid);
+		if ~isempty(tmp)
+			discard=[discard, tmp];    % line ID belonging to pair ID
+		end
+	end
+
+	consider(discard)=false;
+
+	tot=gtIndexSelectLines(consider,tot);
+	nof_lines=length(tot.pairid) ;
+	tot.id=(1:nof_lines)';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Execute strategy and create output
+
+if isempty(strategy)
+	if isfield(parameters,'index')
+		if isfield(parameters.index,'strategy')
+  		strategy=parameters.index.strategy;
+		else
+			strategy=gtIndexDefaultStrategy;
+		end
+	else
+		strategy=gtIndexDefaultStrategy;
+	end
+end
+
+[grain,singleids]=gtIndexExecuteStrategy(strategy,grain,tot,sample,ACM,spacegroup,latticepar);
+
+if isempty(grain)
+  disp(' ')
+  disp(' No grain has been found.')
+  return
+end
+
+singles=gtIndexSelectLines(singleids,tot);
+
+nof_grains=length(grain);
+
+% Create final grain output
+disp(' ')
+disp('CREATING OUTPUT...')
+tic
+
+if flag_update  %  && ~flag_cont
+  mym(sprintf('UPDATE %s SET grainID=null', pairtable)) ;
+end
+
+grain=gtIndexCreateOutput(grain,(1:nof_grains),tot,strategy.r,spacegroup,ACM,latticepar,pairtable,flag_update);
+
+% Intermediate saving before singles 
+fname=sfLatestFileName('new');
+save(fname,'grain','singles','strategy');
+disp(' ')
+disp(['Results have been saved in ', fname])
+toc
+
+% Deal with singles
+singlesfit=[];
+if ~isempty(strategy.s)
+	if ~isempty(singles.id) %if no singles, then skip
+		disp(' ')
+		disp('TREATING SINGLES...')
+		tic
+		[grain,changedg,singlesfit]=gtIndexFitSinglesToGrains(singles,grain,strategy.s,spacegroup,latticepar);
+		toc
+
+		disp(' ')
+		disp('RECREATING OUTPUT...')
+		disp(' ')
+		tic
+		grain=gtIndexCreateOutput(grain,changedg,tot,strategy.r,spacegroup,ACM,latticepar,pairtable,flag_update);
+		toc
+	end
+else
+	singlesfit.pairid=[];
+end
+
+
+% Collect lines which have been assigned
+% grouped=false(nof_lines,1);
+% for i=1:nof_grains
+% 	grouped(grain{i}.lid)=true;
+% end
+% sum(grouped)
+
+grouped=[];
+for i=1:nof_grains
+	grouped=[grouped; [grain{i}.lid', grain{i}.pairid', repmat(i,length(grain{i}.lid),1)]];
+end
+%size(grouped,1)
+%length(unique(grouped(:,1)))
+
+grouped=sortrows(grouped,1);
+group=gtIndexSelectLines(grouped(:,1),tot);
+
+sfpairid=[];
+for i=1:length(singlesfit.pairid)
+	pid=singlesfit.pairid(i);
+  sfpairid(i,:)=[pid, grouped((grouped(:,2)==pid),3)];
+end
+
+if ~isempty(sfpairid)
+	singlesfit.pairid=sortrows(sfpairid,1);
+	%singlesfit.pairid=[singlesfit.pairid', grouped(singlesfit.pairid',2)];
+else
+	singlesfit.pairid=[];
+end
+
+% Determine unique planes
+disp(' ')
+grain=gtIndexUniquePlaneNormals(grain,ACM);
+unipl=gtAllGrainValues(grain,'uni','nof_unipl',1);
+
+% Grain statistics
+[allgrainstat,probl]=gtIndexAllGrainStat(grain);
+
+% Estimate errors:
+errest=gtEstimateErrors(grain);
+
+% Save results
+disp(' ')
+save(fname,'grain','group','singles','singlesfit','allgrainstat','probl','errest','strategy');
+disp(['Results have been saved in ', fname])
+disp(' ')
+
+
+disp(' ')
+disp('Number of Friedel pairs:'), disp(length(tot.id)) ;
+disp('Number of pairs indexed:'), disp(length(group.id)) ;
+disp('Number of pairs left unassigned:'), disp(length(tot.id)-length(group.id)) ;
+disp('Number of single pairs:'), disp(length(singles.id)) ;
+disp('Number of grains found:'), disp(length(grain)) ;
+disp('Average number of pairs per grain:'), disp(length(group.id)/length(grain)) ;
+disp('Average number of unique pairs per grain:'), disp(mean(unipl)) ;
+disp(' ')
+
+figure('name','Eta vs theta from grouped pairs')
+ plot(group.theta,group.eta,'b.')
+
+
+
+end % of function
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SUB-FUNCTIONS
+
+function lname=sfLatestFileName(w)
+
+  fnames=dir('indexter_lastrun*.mat');
+	nmb=[];
+
+	for i=1:length(fnames)
+		tmp=str2double(fnames(i).name(17:end-4));
+		if isempty(tmp)
+			nmb(i)=0;
+		else
+			nmb(i)=tmp;
+		end
+	end
+	
+	[maxval,maxloc]=max(nmb);
+	
+	switch w
+		case 'existing'
+			lname=fnames(maxloc).name;
+		case 'new'
+			lname=sprintf('indexter_lastrun%d.mat',maxval+1);
+	end
+	
+end 
+
+
+
+
diff --git a/zUtil_Index/gtINDEXTER_sab.m b/zUtil_Index/gtINDEXTER_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..8b97e2cd8e8c49bb057d8a859b5a1ce2db4c0f1e
--- /dev/null
+++ b/zUtil_Index/gtINDEXTER_sab.m
@@ -0,0 +1,273 @@
+%
+% INPUT:    Two data series of segmented and paired diffraction spots 180 degrees
+%           offset from Spotpair or Calibration tables.
+%
+%
+%   
+% OUTPUT:   Diffraction spots grouped into grains. Location, orientation
+%           and volume of grains are determined. 
+%
+%           
+%           
+
+function [grain,allgrainstat,probl,singlesfit,errest]=gtINDEXTER_sab(strategy,flag_update,grain)
+
+load parameters.mat
+
+if ~exist('strategy','var')
+	strategy=[];
+end
+if ~exist('grain','var')
+	grain=[];
+end
+% if ~exist('flag_cont','var')
+%   flag_cont=false;
+% end
+if ~exist('flag_update','var')
+  flag_update=false;
+end
+
+tic
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SET PARAMETERS
+
+% Sample coordinate system defined in pixels by:
+sample=gtSampleGeoInSampleSystem(parameters);
+
+spacegroup=parameters.acq.spacegroup;
+latticepar=parameters.acq.latticepar;
+
+% allowed angles and their multiplicity according of plane families
+[ACM,ACMU]=gtAngConsMat(spacegroup);  % (in degrees)
+
+% vector of all valid 2theta angles in degrees
+[tmp,reflections]=gtnew_calculate_twotheta;
+reflections=reflections.reflections;
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Load data from database
+
+pairtable=parameters.acq.pair_tablename ;
+
+gtDBConnect ;
+
+
+% All the pair data are loaded in 'tot':
+
+if flag_cont  % continue indexing
+  mymcmd=sprintf(['SELECT pairID, difAID, difBID, theta, eta, omega, '...
+  'avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, '...
+  'samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, '...
+  'thetatype FROM %s WHERE isnull(grainid) ORDER BY avbbYsize desc'],pairtable);
+  %disp('Continuation does not work yet...')
+%	return
+else          % (re)start indexing
+	mymcmd=sprintf(['SELECT pairID, difAID, difBID, theta, eta, omega, '...
+  'avintint, avbbXsize, avbbYsize, samcentXA, samcentYA, samcentZA, '...
+  'samcentXB, samcentYB, samcentZB, ldirX, ldirY, ldirZ, plX, plY, plZ, '...
+  'thetatype FROM %s ORDER BY avbbYsize desc'],pairtable);
+%end
+
+[tot.pairid,tot.aid,tot.bid,tot.theta,tot.eta,tot.omega,...
+	tot.int,tot.bbxs,tot.bbys, ...
+  tot.ca(:,1),tot.ca(:,2),tot.ca(:,3),tot.cb(:,1),tot.cb(:,2),tot.cb(:,3),...
+	tot.dir(:,1),tot.dir(:,2),tot.dir(:,3), ...
+  tot.pl(:,1),tot.pl(:,2),tot.pl(:,3),tot.thetatype]=mym(mymcmd);
+
+nof_lines=length(tot.pairid) ;
+
+% these line id-s will not correspond to pairID-s !!!
+tot.id=(1:nof_lines)';
+
+% Make sure directions are normalized 
+%  (e.g. acosd function after rounding errors from database)
+pllength=sqrt(tot.pl(:,1).^2 + tot.pl(:,2).^2 + tot.pl(:,3).^2) ;
+tot.pl=[tot.pl(:,1)./pllength tot.pl(:,2)./pllength tot.pl(:,3)./pllength] ;
+
+dirlength=sqrt(tot.dir(:,1).^2 + tot.dir(:,2).^2 + tot.dir(:,3).^2) ;
+tot.dir=[tot.dir(:,1)./dirlength tot.dir(:,2)./dirlength tot.dir(:,3)./dirlength] ;
+
+for i=1:nof_lines
+  tot.hkl(i,:)=reflections(tot.thetatype(i),:);
+end
+
+% Exclude Friedel pairs which are discarded
+if isfield(parameters.index,'discard')
+	consider=true(nof_lines,1);
+	discard=[];
+	for i=1:length(parameters.index.discard)
+		tmp=find(parameters.index.discard(i)==tot.pairid);
+		if ~isempty(tmp)
+			discard=[discard, tmp];    % line ID belonging to pair ID
+		end
+	end
+
+	consider(discard)=false;
+
+	tot=gtIndexSelectLines(consider,tot);
+	nof_lines=length(tot.pairid) ;
+	tot.id=(1:nof_lines)';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Execute strategy and create output
+
+if isempty(strategy)
+	if isfield(parameters,'index')
+		if isfield(parameters.index,'strategy')
+  		strategy=parameters.index.strategy;
+		else
+			strategy=gtIndexDefaultStrategy;
+		end
+	else
+		strategy=gtIndexDefaultStrategy;
+	end
+end
+
+[grain,singleids]=gtIndexExecuteStrategy(strategy,grain,tot,sample,ACM,spacegroup,latticepar);
+
+if isempty(grain)
+  disp(' ')
+  disp(' No grain has been found.')
+  return
+end
+
+singles=gtIndexSelectLines(singleids,tot);
+
+nof_grains=length(grain);
+
+% Create final grain output
+disp(' ')
+disp('CREATING OUTPUT...')
+tic
+
+if flag_update  %  && ~flag_cont
+  mym(sprintf('UPDATE %s SET grainID=null', pairtable)) ;
+end
+
+grain=gtIndexCreateOutput(grain,(1:nof_grains),tot,strategy.r,spacegroup,ACM,latticepar,pairtable,flag_update);
+
+% Intermediate saving before singles 
+fname=sfLatestFileName('new');
+save(fname,'grain','singles','strategy');
+disp(' ')
+disp(['Results have been saved in ', fname])
+toc
+
+% Deal with singles
+singlesfit=[];
+if ~isempty(strategy.s)
+	if ~isempty(singles.id) %if no singles, then skip
+		disp(' ')
+		disp('TREATING SINGLES...')
+		tic
+		[grain,changedg,singlesfit]=gtIndexFitSinglesToGrains(singles,grain,strategy.s,spacegroup,latticepar);
+		toc
+
+		disp(' ')
+		disp('RECREATING OUTPUT...')
+		disp(' ')
+		tic
+		grain=gtIndexCreateOutput(grain,changedg,tot,strategy.r,spacegroup,ACM,latticepar,pairtable,flag_update);
+		toc
+	end
+end
+
+
+% Collect lines which have been assigned
+% grouped=false(nof_lines,1);
+% for i=1:nof_grains
+% 	grouped(grain{i}.lid)=true;
+% end
+% sum(grouped)
+
+grouped=[];
+for i=1:nof_grains
+	grouped=[grouped; [grain{i}.lid', grain{i}.pairid', repmat(i,length(grain{i}.lid),1)]];
+end
+%size(grouped,1)
+%length(unique(grouped(:,1)))
+
+grouped=sortrows(grouped,1);
+group=gtIndexSelectLines(grouped(:,1),tot);
+
+
+for i=1:length(singlesfit.pairid)
+	pid=singlesfit.pairid(i);
+  sfpairid(i,:)=[pid, grouped((grouped(:,2)==pid),3)];
+end
+	
+singlesfit.pairid=sortrows(sfpairid,1);
+%singlesfit.pairid=[singlesfit.pairid', grouped(singlesfit.pairid',2)];
+
+
+% Determine unique planes
+disp(' ')
+grain=gtIndexUniquePlaneNormals(grain,ACM);
+unipl=gtAllGrainValues(grain,'uni','nof_unipl',1);
+
+% Grain statistics
+[allgrainstat,probl]=gtIndexAllGrainStat(grain);
+
+% Estimate errors:
+errest=gtEstimateErrors(grain);
+
+% Save results
+disp(' ')
+save(fname,'grain','group','singles','singlesfit','allgrainstat','probl','errest','strategy');
+disp(['Results have been saved in ', fname])
+disp(' ')
+
+
+disp(' ')
+disp('Number of Friedel pairs:'), disp(length(tot.id)) ;
+disp('Number of pairs indexed:'), disp(length(group.id)) ;
+disp('Number of pairs left unassigned:'), disp(length(tot.id)-length(group.id)) ;
+disp('Number of single pairs:'), disp(length(singles.id)) ;
+disp('Number of grains found:'), disp(length(grain)) ;
+disp('Average number of pairs per grain:'), disp(length(group.id)/length(grain)) ;
+disp('Average number of unique pairs per grain:'), disp(mean(unipl)) ;
+disp(' ')
+
+figure('name','Eta vs theta from grouped pairs')
+ plot(group.theta,group.eta,'b.')
+
+
+
+end % of function
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SUB-FUNCTIONS
+
+function lname=sfLatestFileName(w)
+
+  fnames=dir('indexter_lastrun*.mat');
+	nmb=[];
+
+	for i=1:length(fnames)
+		tmp=str2double(fnames(i).name(17:end-4));
+		if isempty(tmp)
+			nmb(i)=0;
+		else
+			nmb(i)=tmp;
+		end
+	end
+	
+	[maxval,maxloc]=max(nmb);
+	
+	switch w
+		case 'existing'
+			lname=fnames(maxloc).name;
+		case 'new'
+			lname=sprintf('indexter_lastrun%d.mat',maxval+1);
+	end
+	
+end 
+
+
+
+
diff --git a/zUtil_Index/gtIndexAddToGrains.m b/zUtil_Index/gtIndexAddToGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..e2effe83681d9242e9e55b91d50df153c570c872
--- /dev/null
+++ b/zUtil_Index/gtIndexAddToGrains.m
@@ -0,0 +1,59 @@
+function [newgrain,remaining]=gtIndexAddToGrains(remaining,grain,tot,...
+				                                sample,ACM,tol_b)
+
+disp(' ')
+disp(' ADDING PAIRS TO GRAINS...')
+disp(' ')
+disp(tol_b)
+tic
+
+nof_grains=length(grain);
+newgrain=grain;
+	
+for i=1:nof_grains
+	nof_lines=length(grain{i}.lid);
+	
+	pgood=true(nof_lines+1,1);
+	pgood(nof_lines+1)=false;
+	ptry=nof_lines+1;
+	goodfit=false(length(remaining),1);
+	
+	% Distance tolerance
+	if grain{i}.merged
+		tol_b.dist=max(max(grain{i}.stat.distlines),tol_b.distmax);
+	else
+		tol_b.dist=tol_b.distmax;
+	end
+
+	glines=gtIndexSelectLines(grain{i}.lid,tot);
+	
+	for j=1:length(remaining)
+		%cand=gtIndexSelectLines([grain{i}.lid,remaining(j)],tot);
+		%goodfit(j)=gtIndexTryAddLineToGroup(ptry,pgood,cand,tol_b,sample,ACM);
+		
+		tryline=gtIndexSelectLines(remaining(j),tot);
+		goodfit(j)=gtIndexCheckGroupCons(tryline,glines,grain{i}.center,tol_b,sample,ACM);
+	end	
+	
+	if any(goodfit)
+		lineids=[grain{i}.lid'; remaining(goodfit)];
+
+		newlines=gtIndexSelectLines(lineids,tot); % reload original lines in the new grain
+		newgrain{i}=gtIndexCreateGrainOutputAdd(newlines);
+		newgrain{i}.id=i;
+		newgrain{i}.merged=grain{i}.merged;
+		
+		disp(['Pairs added to grain #' num2str(i) ':'])
+		disp(remaining(goodfit))
+	end
+		
+  remaining(goodfit)=[];
+	
+end
+
+disp(' ')
+toc
+
+end
+																			
+																			
diff --git a/zUtil_Index/gtIndexAllGrainStat.m b/zUtil_Index/gtIndexAllGrainStat.m
new file mode 100755
index 0000000000000000000000000000000000000000..8523a68cdb88d4704b9b1e70148b993e81e4bacb
--- /dev/null
+++ b/zUtil_Index/gtIndexAllGrainStat.m
@@ -0,0 +1,98 @@
+% Grain statistics for output and check
+
+function [allgrainstat,probl]=gtIndexAllGrainStat(grain)
+
+nof_grains=length(grain);
+
+allgrainstat.intrel=[];
+allgrainstat.intrat=[];
+allgrainstat.bbxsrel=[];
+allgrainstat.bbysrel=[];
+allgrainstat.bbxsrat=[];
+allgrainstat.bbysrat=[];
+allgrainstat.distcom=[];
+allgrainstat.distlines=[];
+allgrainstat.angplanes=[];
+allgrainstat.Rdist=[];
+
+%grouped=false(nof_lines,1);
+
+% Detected problems:
+probl.distcom=[];
+probl.Rdist=[];
+probl.int=[];
+probl.bbxs=[];
+probl.bbys=[];
+
+
+for i=1:nof_grains
+  allgrainstat.distcom=[allgrainstat.distcom, grain{i}.stat.distcom];
+  allgrainstat.distlines=[allgrainstat.distlines, grain{i}.stat.distlines];
+  allgrainstat.angplanes=[allgrainstat.angplanes, grain{i}.stat.angplanes];
+  allgrainstat.Rdist=[allgrainstat.Rdist, grain{i}.stat.Rdist];
+  allgrainstat.intrel=[allgrainstat.intrel, grain{i}.stat.intrel];
+  allgrainstat.intrat=[allgrainstat.intrat, grain{i}.stat.intrat];
+  allgrainstat.bbxsrel=[allgrainstat.bbxsrel, grain{i}.stat.bbxsrel];
+  allgrainstat.bbysrel=[allgrainstat.bbysrel, grain{i}.stat.bbysrel];
+  allgrainstat.bbxsrat=[allgrainstat.bbxsrat, grain{i}.stat.bbxsrat];
+  allgrainstat.bbysrat=[allgrainstat.bbysrat, grain{i}.stat.bbysrat];
+	
+  
+	% Mark outliers 
+  if ~isempty(grain{i}.stat.outl.int)
+		tmp=[repmat(i,length(grain{i}.stat.outl.int),1) grain{i}.stat.outl.int'];
+    probl.int=[probl.int; tmp]; % mark as problem
+  end
+  if ~isempty(grain{i}.stat.outl.bbxs)
+		tmp=[repmat(i,length(grain{i}.stat.outl.bbxs),1) grain{i}.stat.outl.bbxs'];
+    probl.bbxs=[probl.bbxs; tmp]; % mark as problem
+  end
+  if ~isempty(grain{i}.stat.outl.bbys)
+		tmp=[repmat(i,length(grain{i}.stat.outl.bbys),1) grain{i}.stat.outl.bbys'];
+    probl.bbys=[probl.bbys; tmp]; % mark as problem
+	end
+	if ~isempty(grain{i}.stat.outl.distcom)
+ 	  tmp=[repmat(i,length(grain{i}.stat.outl.distcom),1) grain{i}.stat.outl.distcom'];
+    probl.distcom=[probl.distcom; tmp]; % mark as problem
+  end
+	if ~isempty(grain{i}.stat.outl.Rdist)
+ 		tmp=[repmat(i,length(grain{i}.stat.outl.Rdist),1) grain{i}.stat.outl.Rdist'];
+    probl.Rdist=[probl.Rdist; tmp]; % mark as problem
+  end
+
+end
+
+nof_bins=nof_grains;
+
+figure('name','Relative intensities in the grains')
+ hist(allgrainstat.intrel,nof_bins)
+
+figure('name','Relative bbox X size in the grains')
+ hist(allgrainstat.bbxsrel,nof_bins)
+ 
+figure('name','Relative bbox Y size in the grains')
+ hist(allgrainstat.bbysrel,nof_bins)
+
+figure('name','Max. intensity ratio in the grains')
+ hist(allgrainstat.intrat,round(nof_bins/10))
+ 
+figure('name','Max. bbox X size ratio in the grains')
+ hist(allgrainstat.bbxsrat,round(nof_bins/10))
+ 
+figure('name','Max. bbox Y size ratio in the grains')
+ hist(allgrainstat.bbysrat,round(nof_bins/10))
+ 
+figure('name','Angular deviation of planes')
+ hist(allgrainstat.angplanes,nof_bins)
+
+figure('name','Difference between planes and grain orientation in Rodrigues space')
+ hist(allgrainstat.Rdist,nof_bins)
+
+figure('name','Distance between diffraction paths')
+ hist(allgrainstat.distlines,nof_bins)
+
+figure('name','Distance of diffraction paths to grain center of mass')
+ hist(allgrainstat.distcom,nof_bins)
+ 
+ 
+end
diff --git a/zUtil_Index/gtIndexBuildGrains.m b/zUtil_Index/gtIndexBuildGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..37c29946f763f5a08f1053cf12b6d395690c1992
--- /dev/null
+++ b/zUtil_Index/gtIndexBuildGrains.m
@@ -0,0 +1,57 @@
+function [grain,singles]=gtIndexBuildGrains(remaining_in,tot,sample,ACM,tol_b)
+
+disp(' ')
+disp(' BUILDING GRAINS...')
+disp(' ')
+disp(tol_b)
+tic
+
+remaining=remaining_in;
+nof_grains=0;
+singles=[];
+grain=[];
+
+
+while length(remaining)>=1
+  
+  act=gtIndexSelectLines(remaining(1),tot);
+  cand_rem=gtIndexSelectLines(remaining(2:end),tot);
+
+	
+	tol_b.dist=min(act.bbys/tol_b.distsf,tol_b.distmax);
+	
+	
+  [paircons,cand0,isecs]=gtIndexCheckPairCons(act,cand_rem,tol_b,sample,ACM);
+  
+  if length(paircons)>3
+    cand_paircons=gtIndexSelectLines([act.id; cand0.id],tot);
+    %[pgroup1,grainoutput1]=gtIndexFindGroupInCand(cand_paircons,tol_b,sample,ACM);
+
+		[pgroup,grainoutput]=gtIndexFindGroupInCand(cand_paircons,isecs,tol_b,sample,ACM);
+	
+    if sum(pgroup)>1
+      nof_grains=nof_grains+1;
+      grain{nof_grains}=grainoutput;
+      grain{nof_grains}.id=nof_grains;
+      disp(['Found new grain #' num2str(nof_grains)])
+      disp(grain{nof_grains}.pairid)
+      todel=cand_paircons.id(pgroup);
+    else
+      singles=[singles; act.id];
+      todel=act.id;
+    end
+  else
+    singles=[singles; act.id];
+    todel=act.id;
+  end
+
+  for i=1:length(todel)
+    remaining(remaining==todel(i))=[];
+  end
+
+end
+
+disp(' ')
+toc
+
+end
diff --git a/zUtil_Index/gtIndexCheckAllPairCons.m b/zUtil_Index/gtIndexCheckAllPairCons.m
new file mode 100755
index 0000000000000000000000000000000000000000..00c90db8036cccdb19459b67725ac2ea7eefdfa4
--- /dev/null
+++ b/zUtil_Index/gtIndexCheckAllPairCons.m
@@ -0,0 +1,88 @@
+%
+% Gives OK, if all the lines are pair consistent with a given line. 
+%
+% act:  the actual line (structure)
+% cand: candidates (structure) to be tested for pair consistency with 'act'
+% tol:  tolerances (structure)
+% sample: sample geometry parameters (structure)
+% ACM:  angular consistency matrix
+
+function ok=gtIndexCheckAllPairCons(act,cand,tol,sample,ACM)
+
+ok=false;
+
+%paircons=(1:length(cand.id))';  % initial indices of consistent lines 
+%progress=length(cand.id);
+
+% bbox y size close enough?
+cons=(act.bbys/tol.bbys<cand.bbys) & (act.bbys*tol.bbys>cand.bbys);
+if ~all(cons)
+	return
+end
+%cand=gtIndexSelectLines(cons,cand);
+%paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+% bbox x size close enough?
+cons=(act.bbxs/tol.bbxs<cand.bbxs) & (act.bbxs*tol.bbxs>cand.bbxs);
+if ~all(cons)
+	return
+end
+%cand=gtIndexSelectLines(cons,cand);
+%paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+% integrated intensities close enough?
+cons=(act.int/tol.int<cand.int) & (act.int*tol.int>cand.int);
+if ~all(cons)
+	return
+end
+%cand=gtIndexSelectLines(cons,cand);
+%paircons(~cons)=[];
+%progress=[progress; length(cand.id)];
+
+% spatial distance small enough?
+cons=gt2LinesDist([act.ca act.dir],[cand.ca cand.dir])<tol.dist;
+if ~all(cons)
+	return
+end
+%cand=gtIndexSelectLines(cons,cand);
+%paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+% is intersection in the sample volume?%
+% NOTE: intersection of 2 lines might actually be far from the grain center
+% if they are near being parallel. This could be taken into account here...
+% On the other hand, there should be no parallel lines in a grain set.
+pofinters=gt2LinesIntersection([act.ca act.dir],[cand.ca cand.dir]);
+cons=gtIsPointInSample(pofinters,sample,tol);
+if ~all(cons)
+	return
+end
+%cand=gtIndexSelectLines(cons,cand);
+%pofinters(~cons,:)=[];
+%paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+% plane angles consistent?
+cons=false(length(cand.id),1);
+angle=zeros(length(cand.id),1);
+for i=1:length(cand.id)
+  ACV=ACM{act.thetatype,cand.thetatype(i)};
+  ang=gt2PlanesAngle(act.pl,cand.pl(i,:));
+  angle(i)=ang;
+  cons(i)=min(abs(ACV-ang))<tol.ang;
+end
+if ~all(cons)
+	return
+end
+%cand=gtIndexSelectLines(cons,cand);
+%pofinters(~cons,:)=[];
+%angle(~cons)=[];
+%paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+ok=true;
+
+end
+
diff --git a/zUtil_Index/gtIndexCheckGroupCons.m b/zUtil_Index/gtIndexCheckGroupCons.m
new file mode 100755
index 0000000000000000000000000000000000000000..b510ccf497b37bf49b64ed133ff96642d0143829
--- /dev/null
+++ b/zUtil_Index/gtIndexCheckGroupCons.m
@@ -0,0 +1,14 @@
+
+function groupcons=gtIndexCheckGroupCons(tryline,goodl,goodpofinters,tol,sample,ACM)
+
+groupcons=false;
+
+paircons=gtIndexCheckAllPairCons(tryline,goodl,tol,sample,ACM);
+
+if paircons
+  if pointtolinedist(goodpofinters,[tryline.ca tryline.dir])<tol.dist;
+    groupcons=true;
+  end
+end
+
+end
diff --git a/zUtil_Index/gtIndexCheckPairCons.m b/zUtil_Index/gtIndexCheckPairCons.m
new file mode 100755
index 0000000000000000000000000000000000000000..8ac72b1a0c19d595641f5c61dac3c409ca668dcd
--- /dev/null
+++ b/zUtil_Index/gtIndexCheckPairCons.m
@@ -0,0 +1,67 @@
+%
+% Checks pair consistency in a set of lines. 
+%
+% act:  the actual line (structure)
+% cand: candidates (structure) to be pair consistent with it
+% tol:  tolerances (structure)
+% sample: sample geometry parameters (structure)
+% ACM:  angular consistency matrix
+
+function [paircons,cand,pofinters]=gtIndexCheckPairCons(act,cand,tol,sample,ACM)
+
+paircons=(1:length(cand.id))';  % initial indices of consistent lines 
+%progress=length(cand.id);
+
+% integrated intensities close enough?
+cons=(act.int/tol.int<cand.int) & (act.int*tol.int>cand.int);
+cand=gtIndexSelectLines(cons,cand);
+paircons(~cons)=[];
+%progress=[progress; length(cand.id)];
+
+% bbox x size close enough?
+cons=(act.bbxs/tol.bbxs<cand.bbxs) & (act.bbxs*tol.bbxs>cand.bbxs);
+cand=gtIndexSelectLines(cons,cand);
+paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+% bbox y size close enough?
+cons=(act.bbys/tol.bbys<cand.bbys) & (act.bbys*tol.bbys>cand.bbys);
+cand=gtIndexSelectLines(cons,cand);
+paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+% spatial distance small enough?
+cons=gt2LinesDist([act.ca act.dir],[cand.ca cand.dir])<tol.dist;
+cand=gtIndexSelectLines(cons,cand);
+paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+% is intersection in the sample volume?%
+% NOTE: intersection of 2 lines might actually be far from the grain center
+% if they are near being parallel. This could be taken into account here...
+% On the other hand, there should be no parallel lines in a grain set.
+pofinters=gt2LinesIntersection([act.ca act.dir],[cand.ca cand.dir]);
+cons=gtIsPointInSample(pofinters,sample,tol);
+cand=gtIndexSelectLines(cons,cand);
+pofinters(~cons,:)=[];
+paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+% plane angles consistent?
+cons=false(length(cand.id),1);
+angle=zeros(length(cand.id),1);
+for i=1:length(cand.id)
+  ACV=ACM{act.thetatype,cand.thetatype(i)};
+  ang=gt2PlanesAngle(act.pl,cand.pl(i,:));
+  angle(i)=ang;
+  cons(i)=min(abs(ACV-ang))<tol.ang;
+end
+cand=gtIndexSelectLines(cons,cand);
+pofinters(~cons,:)=[];
+%angle(~cons)=[];
+paircons(~cons)=[]; 
+%progress=[progress; length(cand.id)];
+
+
+end
+
diff --git a/zUtil_Index/gtIndexCreateGrainOutputAdd.m b/zUtil_Index/gtIndexCreateGrainOutputAdd.m
new file mode 100755
index 0000000000000000000000000000000000000000..2a46aea6764ad0e35967786575b04337dd7b33b0
--- /dev/null
+++ b/zUtil_Index/gtIndexCreateGrainOutputAdd.m
@@ -0,0 +1,46 @@
+% Creates 'grain' output structure from indexed (grouped) pair-lines.
+%
+
+function grain=gtIndexCreateGrainOutputAdd(grainl) % ,spacegroup)
+
+grain.id=[];
+
+% Pair ID
+grain.pairid=grainl.pairid';
+
+% Line ID-s in the indexing (normally the pairs ordered by intensities)
+% i.e. NOT the pairID-s!
+grain.lid=grainl.id';
+
+grain.center=pofintersectexp([grainl.ca grainl.dir])'; % center of mass
+grain.stat.intmean=mean(grainl.int); % mean intensity value
+
+grain.stat.bbxsmean=mean(grainl.bbxs); % mean
+grain.stat.bbysmean=mean(grainl.bbys); % mean
+
+ grain.stat.distlines=[];
+% grain.stat.angplanes=[];
+ for gi=1:length(grainl.id)
+   for gj=gi+1:length(grainl.id)
+     grain.stat.distlines=[grain.stat.distlines,...
+       gt2LinesDist([grainl.ca(gi,:) grainl.dir(gi,:)],...
+                    [grainl.ca(gj,:) grainl.dir(gj,:)])];
+% 
+%     ACV=ACM{grainl.thetatype(gi),grainl.thetatype(gj)};
+%     ang=gt2PlanesAngle(grainl.pl(gi,:),grainl.pl(gj,:));
+%     ang=min(abs(ACV-ang));
+%     grain.stat.angplanes=[grain.stat.angplanes, ang];
+   end
+ end
+
+
+
+
+%grain.R_vector=[0, 0, 0];
+
+%grain.merged=false;
+
+end
+
+
+
diff --git a/zUtil_Index/gtIndexCreateGrainOutputBuild.m b/zUtil_Index/gtIndexCreateGrainOutputBuild.m
new file mode 100755
index 0000000000000000000000000000000000000000..774dfddc202f08501a539c19e16e4a190d2bf0fa
--- /dev/null
+++ b/zUtil_Index/gtIndexCreateGrainOutputBuild.m
@@ -0,0 +1,28 @@
+% Creates 'grain' output structure from indexed (grouped) pair-lines.
+%
+
+function grain=gtIndexCreateGrainOutputBuild(grainl) % ,spacegroup)
+
+grain.id=[];
+
+% Pair ID
+grain.pairid=grainl.pairid';
+
+% Line ID-s in the indexing (normally the pairs ordered by intensities)
+% i.e. NOT the pairID-s!
+grain.lid=grainl.id';
+
+grain.center=pofintersectexp([grainl.ca grainl.dir])'; % center of mass
+grain.stat.intmean=mean(grainl.int); % mean intensity value
+
+grain.stat.bbxsmean=mean(grainl.bbxs); % mean
+grain.stat.bbysmean=mean(grainl.bbys); % mean
+
+grain.R_vector=[0, 0, 0];
+
+grain.merged=false;
+
+end
+
+
+
diff --git a/zUtil_Index/gtIndexCreateGrainOutputFinal.m b/zUtil_Index/gtIndexCreateGrainOutputFinal.m
new file mode 100755
index 0000000000000000000000000000000000000000..2b90327502070de8d16a2c642cbe6469955120d9
--- /dev/null
+++ b/zUtil_Index/gtIndexCreateGrainOutputFinal.m
@@ -0,0 +1,121 @@
+% Creates 'grain' output structure from indexed (grouped) pair-lines.
+%
+
+function grain=gtIndexCreateGrainOutputFinal(grainl,ACM,spacegroup,latticepar,tol_outl)
+
+nof_lines=length(grainl.id);
+
+% Tolerance factor for marking outliers (*std)
+%tol_outl=3;
+
+% Order lines by thetatype and plane normal
+sortM(:,1)=grainl.thetatype';
+sortM(:,2)=grainl.pl(:,3);
+sortM(:,3)=(1:nof_lines)';
+
+sortM=sortrows(sortM,[1 -2]);
+
+grainl=gtIndexSelectLines(sortM(:,3),grainl);
+
+% ID and Rodrigues vector
+grain.id=[];
+
+% Center of mass in sample system; for coordinate definition, look at
+%  gtSampleGeoInSampleSystem
+grain.center=pofintersectexp([grainl.ca grainl.dir])'; % center of mass
+
+grain.R_vector=gtRodriguesTest(grainl.pl,grainl.hkl,spacegroup,latticepar);
+
+% Pair ID
+grain.nof_pairs=length(grainl.pairid);
+grain.pairid=grainl.pairid';
+
+% Thetatype, hkl vectors and plane normals
+grain.thetatype=grainl.thetatype';
+grain.hkl=grainl.hkl; 
+grain.pl=grainl.pl;
+grain.pla=NaN(1,nof_lines);
+
+% Diffraction angles
+grain.theta=grainl.theta';
+grain.eta=grainl.eta';
+grain.omega=grainl.omega';
+
+% Line ID-s in the indexing (normally the pairs ordered by intensities)
+%  i.e. these are NOT the pairID-s!
+grain.lid=grainl.id';
+
+
+
+% Grain statistics for tolerances
+
+% Difference of each plane and the average grain orientation in Rodrigues space:
+for i=1:length(grainl.id)
+  Rv=gtRodriguesVectors2(grainl.pl(i,:),grainl.hkl(i,:),spacegroup,latticepar);
+  grain.stat.Rdist(i)=min(pointtolinedist(grain.R_vector,Rv));
+end
+  
+% Mean and standard deviation of distance in Rodrigues space
+grain.stat.Rdistmean=mean(grain.stat.Rdist);
+grain.stat.Rdiststd=std(grain.stat.Rdist);
+
+% Line distances to the center of mass
+grain.stat.distcom=pointtolinedist(grain.center,[grainl.ca grainl.dir])';
+grain.stat.distcommean=mean(grain.stat.distcom);
+grain.stat.distcomstd=std(grain.stat.distcom);
+
+% Line distances and plane angles pair-wise
+grain.stat.distlines=[];
+grain.stat.angplanes=[];
+for gi=1:length(grainl.id)
+  for gj=gi+1:length(grainl.id)
+    grain.stat.distlines=[grain.stat.distlines,...
+      gt2LinesDist([grainl.ca(gi,:) grainl.dir(gi,:)],...
+                   [grainl.ca(gj,:) grainl.dir(gj,:)])];
+
+    ACV=ACM{grainl.thetatype(gi),grainl.thetatype(gj)};
+    ang=gt2PlanesAngle(grainl.pl(gi,:),grainl.pl(gj,:));
+    ang=min(abs(ACV-ang));
+    grain.stat.angplanes=[grain.stat.angplanes, ang];
+  end
+end
+
+% Intensity
+grain.stat.int=grainl.int';
+grain.stat.intmean=mean(grainl.int); % mean intensity value
+grain.stat.intstd=std(grainl.int); % std intensity
+grain.stat.intrel=(grainl.int/grain.stat.intmean)'; % relative intensity
+grain.stat.intrat=max(grainl.int)/min(grainl.int); % extreme intensity ratio
+
+% Bounding box x size
+grain.stat.bbxs=grainl.bbxs';
+grain.stat.bbxsmean=mean(grainl.bbxs); % mean
+grain.stat.bbxsstd=std(grainl.bbxs); % std
+grain.stat.bbxsrel=(grainl.bbxs/grain.stat.bbxsmean)'; % relative bbox size
+grain.stat.bbxsrat=max(grainl.bbxs)/min(grainl.bbxs); % extreme ratio
+
+% Bounding box y size
+grain.stat.bbys=grainl.bbys';
+grain.stat.bbysmean=mean(grainl.bbys); % mean
+grain.stat.bbysstd=std(grainl.bbys); % std
+grain.stat.bbysrel=(grainl.bbys/grain.stat.bbysmean)'; % relative bbox size
+grain.stat.bbysrat=max(grainl.bbys)/min(grainl.bbys); % extreme ratio
+
+% Mark outliers
+grain.stat.outl.int=gtOutliers(grainl.int', tol_outl, grain.stat.intmean, grain.stat.intstd);
+grain.stat.outl.bbxs=gtOutliers(grainl.bbxs', tol_outl, grain.stat.bbxsmean, grain.stat.bbxsstd);
+grain.stat.outl.bbys=gtOutliers(grainl.bbys', tol_outl, grain.stat.bbysmean, grain.stat.bbysstd);
+grain.stat.outl.distcom=gtOutliers(grain.stat.distcom, tol_outl, grain.stat.distcommean, grain.stat.distcomstd);
+grain.stat.outl.Rdist=gtOutliers(grain.stat.Rdist, tol_outl, grain.stat.Rdistmean, grain.stat.Rdiststd);
+
+grain.stat.outl.int=grain.pairid(grain.stat.outl.int);
+grain.stat.outl.bbxs=grain.pairid(grain.stat.outl.bbxs);
+grain.stat.outl.bbys=grain.pairid(grain.stat.outl.bbys);
+grain.stat.outl.distcom=grain.pairid(grain.stat.outl.distcom);
+grain.stat.outl.Rdist=grain.pairid(grain.stat.outl.Rdist);
+
+
+end % of function   
+
+
+
diff --git a/zUtil_Index/gtIndexCreateGrainOutputMerge.m b/zUtil_Index/gtIndexCreateGrainOutputMerge.m
new file mode 100755
index 0000000000000000000000000000000000000000..cbfdefae48294be2388bad444a61008ef41644f3
--- /dev/null
+++ b/zUtil_Index/gtIndexCreateGrainOutputMerge.m
@@ -0,0 +1,126 @@
+% Creates 'grain' output structure from indexed (grouped) pair-lines.
+%
+
+function grain=gtIndexCreateGrainOutputMerge(grainl)
+
+% nof_lines=length(grainl.id);
+% 
+% % Tolerance factor for marking outliers (*std)
+% tol_outl=3;
+% % modif sabine
+% 
+% %ACM
+% 
+% % fin modif sabine
+% % Order lines by thetatype and plane normal
+% sortM(:,1)=grainl.thetatype';
+% sortM(:,2)=grainl.pl(:,3);
+% sortM(:,3)=(1:nof_lines)';
+% 
+% sortM=sortrows(sortM,[1 -2]);
+% 
+% grainl=gtIndexSelectLines(sortM(:,3),grainl);
+
+% ID and Rodrigues vector
+grain.id=[];
+grain.merged=true;
+
+% Center of mass in sample system; for coordinate definition, look at
+%  gtSampleGeoInSampleSystem
+grain.center=pofintersectexp([grainl.ca grainl.dir])'; % center of mass
+
+%grain.R_vector=NaN(1,3);
+
+% Line ID-s in the indexing (normally the pairs ordered by intensities)
+% i.e. NOT the pairID-s!
+grain.lid=grainl.id';
+
+% % Pair ID
+% grain.pairid=grainl.pairid';
+% 
+% % Thetatype, hkl vectors and plane normals
+% grain.thetatype=grainl.thetatype';
+
+%grain.hkl=grainl.hkl; 
+%grain.pl=grainl.pl;
+
+ % grain.pla=NaN(1,nof_lines);
+
+% Unique plane normals (multiples are averaged)
+%grain=gtINUniquePlaneNormals(grainl,ACM);
+
+% Rodrigues vectors (multiple) of the plane normals of a line
+%for i=1:length(grainl.id)
+%  Rv=gtRodriguesVectors(grainl.pl(i,:),grainl.hkl(i,:),spacegroup);
+%  grain.lRv(1:size(Rv,1),1:size(Rv,2),i)=Rv;
+%end
+%grain.lRv=grainl.lRv;
+
+% grain.theta=grainl.theta';
+% grain.eta=grainl.eta';
+% grain.omega=grainl.omega';
+% 
+% % Grain statistics for tolerances
+% grain.stat.int=grainl.int;
+
+grain.stat.intmean=mean(grainl.int); % mean intensity value
+
+% grain.stat.intstd=std(grainl.int); % std intensity
+% grain.stat.intrel=(grainl.int/grain.stat.intmean)'; % relative intensity
+% grain.stat.intrat=max(grainl.int)/min(grainl.int); % extreme intensity ratio
+
+% grain.stat.bbxs=grainl.bbxs;
+
+grain.stat.bbxsmean=mean(grainl.bbxs); % mean
+
+% grain.stat.bbxsstd=std(grainl.bbxs); % std
+% grain.stat.bbxsrel=(grainl.bbxs/grain.stat.bbxsmean)'; % relative bbox size
+% grain.stat.bbxsrat=max(grainl.bbxs)/min(grainl.bbxs); % extreme ratio
+
+% grain.stat.bbys=grainl.bbys;
+
+grain.stat.bbysmean=mean(grainl.bbys); % mean
+
+% grain.stat.bbysstd=std(grainl.bbys); % std
+% grain.stat.bbysrel=(grainl.bbys/grain.stat.bbysmean)'; % relative bbox size
+% grain.stat.bbysrat=max(grainl.bbys)/min(grainl.bbys); % extreme ratio
+
+
+% Line distances to the center of mass
+% grain.stat.distcom=pointtolinedist(grain.center,[grainl.ca grainl.dir])';
+% grain.stat.distcommean=mean(grain.stat.distcom);
+% grain.stat.distcomstd=std(grain.stat.distcom);
+% 
+% % Line distances and plane angles pair-wise
+ grain.stat.distlines=[];
+% grain.stat.angplanes=[];
+ for gi=1:length(grainl.id)
+   for gj=gi+1:length(grainl.id)
+     grain.stat.distlines=[grain.stat.distlines,...
+       gt2LinesDist([grainl.ca(gi,:) grainl.dir(gi,:)],...
+                    [grainl.ca(gj,:) grainl.dir(gj,:)])];
+% 
+%     ACV=ACM{grainl.thetatype(gi),grainl.thetatype(gj)};
+%     ang=gt2PlanesAngle(grainl.pl(gi,:),grainl.pl(gj,:));
+%     ang=min(abs(ACV-ang));
+%     grain.stat.angplanes=[grain.stat.angplanes, ang];
+   end
+ end
+% 
+% % Outliers
+% grain.stat.outl.int=gtOutliers(grainl.int', tol_outl, grain.stat.intmean, grain.stat.intstd);
+% grain.stat.outl.bbxs=gtOutliers(grainl.bbxs', tol_outl, grain.stat.bbxsmean, grain.stat.bbxsstd);
+% grain.stat.outl.bbys=gtOutliers(grainl.bbys', tol_outl, grain.stat.bbysmean, grain.stat.bbysstd);
+% grain.stat.outl.distcom=gtOutliers(grain.stat.distcom, tol_outl, grain.stat.distcommean, grain.stat.distcomstd);
+% 
+% grain.stat.outl.int=grain.pairid(grain.stat.outl.int);
+% grain.stat.outl.bbxs=grain.pairid(grain.stat.outl.bbxs);
+% grain.stat.outl.bbys=grain.pairid(grain.stat.outl.bbys);
+% grain.stat.outl.distcom=grain.pairid(grain.stat.outl.distcom);
+
+
+
+end % of function   
+
+
+
diff --git a/zUtil_Index/gtIndexCreateOutput.m b/zUtil_Index/gtIndexCreateOutput.m
new file mode 100755
index 0000000000000000000000000000000000000000..d9b9b00208915f7f0a84a477be3c7fca72e0c3d1
--- /dev/null
+++ b/zUtil_Index/gtIndexCreateOutput.m
@@ -0,0 +1,53 @@
+function newgrain=gtIndexCreateOutput(grain,whichg,tot,strategy_r,spacegroup,ACM,latticepar,pairtable,flag_update)
+
+
+for i=whichg
+	% Create grain structure
+	glines=gtIndexSelectLines(grain{i}.lid,tot);
+	grain{i}=gtIndexCreateGrainOutputFinal(glines,ACM,spacegroup,latticepar,strategy_r);
+	grain{i}.id=i;
+	
+	% Get difspot ID-s 
+	difAID=[];
+	difBID=[];
+  
+	for j=1:length(grain{i}.pairid)
+    mysqlcmd=sprintf('SELECT difAID,difBID FROM %s WHERE pairID=%d',pairtable,grain{i}.pairid(j));
+    [difAID(j),difBID(j)]=mym(mysqlcmd);
+  end	
+	
+  grain{i}.difspots=[difAID, difBID];
+		
+end
+	
+
+% Order grains by approximate volume
+bbys=gtAllGrainValues(grain,'stat','bbysmean',1);
+bbxs=gtAllGrainValues(grain,'stat','bbxsmean',1);
+
+M(:,1)=gtAllGrainValues(grain,'id',[],1);
+M(:,2)=bbys.*bbxs;
+
+M=sortrows(M,-2);
+
+for i=1:length(grain)
+	newgrain{i}=grain{M(i,1)};
+	newgrain{i}.id=i;
+end
+
+
+% Update database table
+if flag_update
+	for i=1:length(newgrain)
+		for j=1:length(newgrain{i}.pairid)
+      mysqlcmd=sprintf('UPDATE %s SET grainID=%d WHERE pairID=%d',pairtable,i,newgrain{i}.pairid(j));
+      mym(mysqlcmd);
+		end
+	end
+end
+
+end
+
+
+
+
diff --git a/zUtil_Index/gtIndexDefaultStrategy.m b/zUtil_Index/gtIndexDefaultStrategy.m
new file mode 100755
index 0000000000000000000000000000000000000000..ec195677cbc4bbea3fa146349a473c445c1729cf
--- /dev/null
+++ b/zUtil_Index/gtIndexDefaultStrategy.m
@@ -0,0 +1,46 @@
+function strategy=gtIndexDefaultStrategy
+
+% No. of iterations (linear extension of tolerances from 'beg' to 'end'):
+strategy.iter=5;
+
+% Tolerances for building grains in the first iteration:
+strategy.b.beg.ang=0.2;     % angular difference in degrees
+strategy.b.beg.int=100;     % max. intensity ratio
+strategy.b.beg.bbxs=5;      % max. bbox x size ratio
+strategy.b.beg.bbys=1.4;    % max. bbox y size ratio
+strategy.b.beg.distsf=3;    % size factor for maximum distance
+strategy.b.beg.distmax=2;   % max. absolut distance
+strategy.b.beg.ming=4;      % min. no. of Friedel pairs in a grain  
+strategy.b.beg.geo=10;      % safety margin around sample volume
+
+% Tolerances for building grains in the last iteration:
+strategy.b.end.ang=1.2;
+strategy.b.end.int=100;
+strategy.b.end.bbxs=5;
+strategy.b.end.bbys=1.4;
+strategy.b.end.distsf=3;
+strategy.b.end.distmax=20;
+strategy.b.end.ming=4;  
+strategy.b.end.geo=10;
+
+% Tolerances for merging grains in the first iteration:
+strategy.m.beg.bbxs=strategy.b.beg.bbxs;   % max. bbox x size ratio 
+strategy.m.beg.bbys=strategy.b.beg.bbys;   % max. bbox y size ratio
+strategy.m.beg.distsf=2;                   % size factor for maximum distance
+strategy.m.beg.int=strategy.b.beg.int;     % max. intensity ratio
+
+% Tolerances for merging grains in the last iteration:
+strategy.m.end.bbxs=strategy.b.end.bbxs;
+strategy.m.end.bbys=strategy.b.end.bbys;
+strategy.m.end.distsf=2; 
+strategy.m.end.int=strategy.b.end.int;
+
+% Tolerances for assigning Friedel pairs to existing grains:
+%strategy.a=strategy.b;
+
+% Tolerance for marking outliers in final grain sets (in std):
+strategy.r=3;
+
+strategy.s=3
+
+
diff --git a/zUtil_Index/gtIndexExecuteStrategy.m b/zUtil_Index/gtIndexExecuteStrategy.m
new file mode 100755
index 0000000000000000000000000000000000000000..3874af9f60f693fca1de9baacaab6faefc7b32e8
--- /dev/null
+++ b/zUtil_Index/gtIndexExecuteStrategy.m
@@ -0,0 +1,102 @@
+function [grain,remaining]=gtIndexExecuteStrategy(strategy,grain,tot,sample,ACM,spacegroup,latticepar)
+
+
+% Define indexing strategy:
+% b = build
+% m = merge
+% l = loosen
+% a = add
+% f = fit singles
+
+if ~isfield(strategy,'proc')
+	strategy.proc=[];
+end
+
+% Creat strategy.proc () if not given
+if isempty(strategy.proc)
+
+	if strategy.iter<=1
+		strategy.iter=1;
+		strategy.proc{1,1}='b';
+		strategy.proc{2,1}='m';
+		strategy.proc{3,1}='a';
+	else
+		strfields=fieldnames(strategy.b.beg);
+		for i=1:length(strfields)
+			dif=strategy.b.end.(strfields{i})-strategy.b.beg.(strfields{i});
+			strategy.l.b.(strfields{i})=dif/(strategy.iter-1);
+		end
+
+		strfields=fieldnames(strategy.m.beg);
+		for i=1:length(strfields)
+			dif=strategy.m.end.(strfields{i})-strategy.m.beg.(strfields{i});
+			strategy.l.m.(strfields{i})=dif/(strategy.iter-1);
+		end
+	
+		sp{1,1}='b';
+		sp{2,1}='m';
+		sp{3,1}='l';
+		sp{4,1}='a';
+
+		for i=1:strategy.iter-1
+			strategy.proc=[strategy.proc; sp];
+		end
+
+		strategy.proc{end+1}='b';
+		strategy.proc{end+1}='m';
+		strategy.proc{end+1}='a';
+	
+	end
+	
+end
+
+
+tol.b=strategy.b.beg;
+tol.a=strategy.b.beg;
+tol.m=strategy.m.beg;
+%tol.r=strategy.r.beg;
+%tol.f=strategy.f.beg;
+
+remaining=1:length(tot.pairid); % list of all lines not yet grouped
+
+for i=1:length(strategy.proc)
+  step=strategy.proc{i};
+	action=step(1);
+
+	switch action
+
+	  case 'l'  % Loosen tolerance values
+			strfields=fieldnames(strategy.b.beg);
+			for j=1:length(strfields)
+				tol.b.(strfields{j})=tol.b.(strfields{j})+strategy.(step).b.(strfields{j});
+			end
+			tol.a=tol.b;
+			
+			strfields=fieldnames(strategy.m.beg);
+			for j=1:length(strfields)
+				tol.m.(strfields{j})=tol.m.(strfields{j})+strategy.(step).m.(strfields{j});
+			end
+
+ 
+		case 'b'  % Build grains
+			[grainB,remaining]=gtIndexBuildGrains(remaining,tot,sample,ACM,tol.(step));
+      grain=[grain,grainB];
+			for j=1:length(grain)
+				grain{j}.id=j;
+			end
+			
+		case 'm'  % Merge grains
+      if ~isempty(grain)
+        grain=gtIndexMergeGrains(grain,tot,tol.(step),spacegroup,latticepar);
+      end
+      
+		case 'a'  % Add lines to grains
+			if ~isempty(grain)
+        [grain,remaining]=gtIndexAddToGrains(remaining,grain,tot,sample,ACM,tol.(step));
+      end
+      
+	end
+	
+end
+
+end % of function
diff --git a/zUtil_Index/gtIndexFindGroupInCand.m b/zUtil_Index/gtIndexFindGroupInCand.m
new file mode 100755
index 0000000000000000000000000000000000000000..e0c3c3354fae99587a06fb7fbe84e47a227446d1
--- /dev/null
+++ b/zUtil_Index/gtIndexFindGroupInCand.m
@@ -0,0 +1,93 @@
+function [goods,grainoutput]=gtIndexFindGroupInCand(cand,isecs,tol,sample,ACM)
+% cand: all the lines that possibly belong to the same grain as the 1st line 
+%        (they are pair-consistent)
+%       1st line in "cand" is the actual line investigated
+% isecs: intersections (length(cand)-1))
+
+nof_cand=length(cand.id); 
+grainoutput=[];
+goods=false(nof_cand,1);
+goods(1)=true;
+
+
+for c1=2:nof_cand % loop to find a 2nd line of the grain
+
+	basel=gtIndexSelectLines([1,c1],cand);
+
+	for c2=c1+1:nof_cand % loop to find a 3rd line of the grain
+	
+		tryl=gtIndexSelectLines(c2,cand);
+
+		ok=gtIndexCheckGroupCons(tryl,basel,isecs(c1-1,:),tol,sample,ACM);
+
+		if ok
+			% loop to find a 4th,5th,6th,... line of the grain recursively
+			cs=sfAddLineToGroup([1,c1,c2],cand,nof_cand,tol,sample,ACM,1);
+
+			if length(cs)>=tol.ming  % grain was found and cs output contains all lines
+				csf=sfCheckRest(cs,cand,nof_cand,tol,sample,ACM);
+				goods(csf)=true;
+				grainl=gtIndexSelectLines(csf,cand); % lines in the grain
+				grainoutput=gtIndexCreateGrainOutputBuild(grainl);
+				return
+			end
+			
+		end
+		
+	end
+	
+end
+
+
+end
+
+
+
+
+function csnew=sfAddLineToGroup(cs,cand,nof_cand,tol,sample,ACM,mylevel)
+  
+	basel=gtIndexSelectLines(cs,cand);
+	baseisec=pofintersectexp([basel.ca basel.dir])';
+	csnew=cs;
+	
+	for i=cs(end)+1:nof_cand
+		tryl=gtIndexSelectLines(i,cand);
+		ok=gtIndexCheckGroupCons(tryl,basel,baseisec,tol,sample,ACM);
+
+		if ok
+			
+			if (length(cs)+1)>=tol.ming
+				csnew=[cs,i];
+				return
+			else
+				csext=sfAddLineToGroup([cs,i],cand,nof_cand,tol,sample,ACM,mylevel+1);
+				if length(csext)>=tol.ming
+					csnew=csext;
+					return
+				end
+			end
+		
+		end
+		
+	end
+	
+end
+
+
+function csf=sfCheckRest(cs,cand,nof_cand,tol,sample,ACM)
+	basel=gtIndexSelectLines(cs,cand);
+	baseisec=pofintersectexp([basel.ca basel.dir])';
+	csf=cs;
+	for i=max(cs):nof_cand
+		tryl=gtIndexSelectLines(i,cand);
+		ok=gtIndexCheckGroupCons(tryl,basel,baseisec,tol,sample,ACM);
+		if ok
+			csf=[csf,i];
+			basel=gtIndexSelectLines(csf,cand);
+			baseisec=pofintersectexp([basel.ca basel.dir])';
+		end
+	end
+end
+
+		
+
diff --git a/zUtil_Index/gtIndexMatchGrains.m b/zUtil_Index/gtIndexMatchGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..d60218a57bdb505db646b7e3a64d0a3fe0c69e0d
--- /dev/null
+++ b/zUtil_Index/gtIndexMatchGrains.m
@@ -0,0 +1,240 @@
+function [match,d]=gtIndexMatchGrains(grain1,grain2,cent,tol_matchgrains)
+
+% Relative position: vectorfrom pos. 1 to pos. 2
+
+dc=[0 0 0]
+%dc=[9.2443, -13.7827, 16.2131]
+
+
+% bug: uniqueness is not fulfilled
+
+
+
+if ~exist('tol_matchgrains','var')
+  tol_matchgrains.dist=20;           % 50
+  tol_matchgrains.Rdist=0.05;         % 0.05
+  tol_matchgrains.bbxs=3;            % 3 
+  tol_matchgrains.bbys=2;            % 3   
+  tol_matchgrains.int=1e10;          % 1e10
+end
+
+nof_grains1=length(grain1);
+%nof_grains2=length(grain2);
+
+
+if cent
+	cz1=gtAllGrainValues(grain1,'center',[],3);
+	ids1=(1:length(grain1))';
+
+	S=sortrows([ids1,cz1],2);
+
+	cgrain1=[];
+	for i=floor(nof_grains1/3):nof_grains1*2/3
+		cgrain1=[cgrain1,grain1(S(i,1))];
+	end
+
+	grain1=cgrain1;
+	nof_grains1=length(grain1);
+end
+
+
+
+match=NaN(nof_grains1,2);
+match(:,1)=(1:nof_grains1)';
+
+% Load relevant info into the gr1 structure (vectors and matrices):
+gr1.id=gtAllGrainValues(grain1,'id',[],1);
+
+gr1.center(:,1)=gtAllGrainValues(grain1,'center',[],1);
+gr1.center(:,2)=gtAllGrainValues(grain1,'center',[],2);
+gr1.center(:,3)=gtAllGrainValues(grain1,'center',[],3);
+
+gr1.R_vector(:,1)=gtAllGrainValues(grain1,'R_vector',[],1);
+gr1.R_vector(:,2)=gtAllGrainValues(grain1,'R_vector',[],2);
+gr1.R_vector(:,3)=gtAllGrainValues(grain1,'R_vector',[],3);
+
+gr1.bbxs(:,1)=gtAllGrainValues(grain1,'stat','bbxsmean',1);
+gr1.bbys(:,1)=gtAllGrainValues(grain1,'stat','bbysmean',1);
+gr1.int(:,1)=gtAllGrainValues(grain1,'stat','intmean',1);
+
+% Load relevant info into the gr2 structure (vectors and matrices):
+gr2.id=gtAllGrainValues(grain2,'id',[],1);
+
+gr2.center(:,1)=gtAllGrainValues(grain2,'center',[],1);
+gr2.center(:,2)=gtAllGrainValues(grain2,'center',[],2);
+gr2.center(:,3)=gtAllGrainValues(grain2,'center',[],3);
+
+gr2.R_vector(:,1)=gtAllGrainValues(grain2,'R_vector',[],1);
+gr2.R_vector(:,2)=gtAllGrainValues(grain2,'R_vector',[],2);
+gr2.R_vector(:,3)=gtAllGrainValues(grain2,'R_vector',[],3);
+
+gr2.bbxs(:,1)=gtAllGrainValues(grain2,'stat','bbxsmean',1);
+gr2.bbys(:,1)=gtAllGrainValues(grain2,'stat','bbysmean',1);
+gr2.int(:,1)=gtAllGrainValues(grain2,'stat','intmean',1);
+
+
+for i=1:nof_grains1
+
+	if i==85
+		%keyboard
+	end
+	
+	act=sfSelectGrains(i,gr1);      % actual grain
+
+	%tol_matchgrains.dist=min([act.bbxs, act.bbys])/2;
+
+	tomatch=sfCheckMatching(act,gr2,dc,tol_matchgrains); % grains to be matched
+
+	if ~isempty(tomatch)
+
+		ltm=length(tomatch);
+		
+		if ltm>1
+
+			%actminsize=min([act.bbxs, act.bbys]);
+			%dcenter=sum((repmat(act.center,ltm,1)-gr2.center(tomatch,:)).^2,2)/(actminsize^2);
+			dR_vector=sum((repmat(act.center+dc,ltm,1)-gr2.R_vector(tomatch,:)).^2,2);
+			%dbbxs=sum((act.bbxs-gr2.bbxs(tomatch,:)).^2,2)/(act.bbxs^2);
+			%dbbys=sum((act.bbys-gr2.bbys(tomatch,:)).^2,2)/(act.bbys^2);
+			%dint=sum((act.int-gr2.int(tomatch,:)).^2,2)/(act.int^2);
+
+			%dd=dcenter+dR_vector+dbbxs+dbbys+dint;
+			dd=dR_vector;
+			
+			sortM=[];
+
+			sortM(:,1)=dd;
+			sortM(:,2)=tomatch;
+			sortM(:,3)=gr2.id(tomatch);
+			
+			sortM=sortrows(sortM,1);
+
+			tomatch=sortM(:,2);
+
+			disp(['Multiple matches found for grain #' num2str(i) ':'])
+			disp(tomatch)
+		end
+
+		match(i,2)=tomatch(1);
+
+	end
+
+end
+
+
+
+
+
+for i=1:nof_grains1
+	
+	if isnan(match(i,2))
+		d.dist(i,:)=NaN(1,3);
+		d.Rdist(i,:)=NaN(1,3);
+		d.int(i,1)=NaN;
+		d.bbys(i,1)=NaN;
+		d.bbxs(i,1)=NaN;
+	else
+		d.dist(i,:)=gr2.center(match(i,2),:)-gr1.center(i,:)-dc;
+		d.Rdist(i,:)=gr2.R_vector(match(i,2),:)-gr1.R_vector(i,:);
+		d.bbxs(i,1)=gr2.bbxs(match(i,2))/gr1.bbxs(i);
+		d.bbys(i,1)=gr2.bbys(match(i,2))/gr1.bbys(i);
+		d.int(i,1)=gr2.int(match(i,2))/gr1.int(i);
+	end
+	
+end
+
+
+mean(d.dist(~isnan(d.dist(:,1)),:))
+
+disp('Matches found:')
+disp(sum(~isnan(match(:,2))));
+
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SUB_FUNCTIONS
+
+function grk=sfSelectGrains(keeplist,gr)
+
+grk.id=gr.id(keeplist);
+grk.int=gr.int(keeplist);
+grk.center=gr.center(keeplist,:);
+grk.R_vector=gr.R_vector(keeplist,:);
+grk.bbys=gr.bbys(keeplist);
+grk.bbxs=gr.bbxs(keeplist);
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function tomatch=sfCheckMatching(act,cand,dc,tol_matchgrains)
+
+if act.id==38
+	%keyboard
+end
+
+
+tomatch=(1:length(cand.id))';  % initial indices of grain candidates to be merged 
+
+% Delete those indices that don't meet the following constraints:
+
+% Bounding box Y size close enough?
+cons=(cand.bbys>act.bbys/tol_matchgrains.bbys) & ...
+     (cand.bbys<tol_matchgrains.bbys*act.bbys);
+cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% Spatial distance of centers close enough?
+dvec=repmat(act.center+dc,length(cand.id),1)-cand.center;
+dist=sqrt(sum(dvec.*dvec,2));
+cons=dist<tol_matchgrains.dist;
+cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% Bounding box X size close enough?
+cons=(cand.bbxs>act.bbxs/tol_matchgrains.bbxs) & ...
+	   (cand.bbxs<tol_matchgrains.bbxs*act.bbxs);
+cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% Intensity close enough?
+cons=(cand.int>act.int/tol_matchgrains.int) & ...
+	   (cand.int<tol_matchgrains.int*act.int);
+cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% Rodriguez vector close enough?
+dRvec=repmat(act.R_vector,length(cand.id),1)-cand.R_vector;
+Rdist=sqrt(sum(dRvec.*dRvec,2));
+cons=Rdist<tol_matchgrains.Rdist;
+%cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% cons=false(length(cand.id),1);
+% for i=1:length(cand.id)
+% 
+%   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 	
+% %	[pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test([l1.pl;l2.pl],[l1.hkl;l2.hkl],0);
+%   [Rvec, good_plnorms]=gtRodriguesTest([act.pl;grain{cand.id(i)}.pl],[act.hkl;grain{cand.id(i)}.hkl],0,spacegroup,0);
+% 
+%   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 
+%   cons(i)=all(good_plnorms);
+% end
+% tomatch(~cons)=[];
+
+
+
+end
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Index/gtIndexMatchGrains_sab.m b/zUtil_Index/gtIndexMatchGrains_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..d12daafa7b0a0403807c0ecfbccb5bef467259b9
--- /dev/null
+++ b/zUtil_Index/gtIndexMatchGrains_sab.m
@@ -0,0 +1,241 @@
+function [match,d]=gtIndexMatchGrains_sab(grain1,grain2,cent,tol_matchgrains)
+
+% Relative position: vectorfrom pos. 1 to pos. 2
+
+dc=[10 10 10]
+%dc =[0 0 0]
+%dc=[9.2443, -13.7827, 16.2131]
+
+
+% bug: uniqueness is not fulfilled
+
+
+
+if ~exist('tol_matchgrains','var')
+  tol_matchgrains.dist=50;           % 50
+  tol_matchgrains.Rdist=0.25;         % 0.05
+  tol_matchgrains.bbxs=50;            % 3 
+  tol_matchgrains.bbys=50;            % 3   
+  tol_matchgrains.int=100e10;          % 1e10
+end
+
+nof_grains1=length(grain1);
+%nof_grains2=length(grain2);
+
+
+if cent
+	cz1=gtAllGrainValues(grain1,'center',[],3);
+	ids1=(1:length(grain1))';
+
+	S=sortrows([ids1,cz1],2);
+
+	cgrain1=[];
+	for i=floor(nof_grains1/3):nof_grains1*2/3
+		cgrain1=[cgrain1,grain1(S(i,1))];
+	end
+
+	grain1=cgrain1;
+	nof_grains1=length(grain1);
+end
+
+
+
+match=NaN(nof_grains1,2);
+match(:,1)=(1:nof_grains1)';
+
+% Load relevant info into the gr1 structure (vectors and matrices):
+gr1.id=gtAllGrainValues(grain1,'id',[],1);
+
+gr1.center(:,1)=gtAllGrainValues(grain1,'center',[],1);
+gr1.center(:,2)=gtAllGrainValues(grain1,'center',[],2);
+gr1.center(:,3)=gtAllGrainValues(grain1,'center',[],3);
+
+gr1.R_vector(:,1)=gtAllGrainValues(grain1,'R_vector',[],1);
+gr1.R_vector(:,2)=gtAllGrainValues(grain1,'R_vector',[],2);
+gr1.R_vector(:,3)=gtAllGrainValues(grain1,'R_vector',[],3);
+
+gr1.bbxs(:,1)=gtAllGrainValues(grain1,'stat','bbxsmean',1);
+gr1.bbys(:,1)=gtAllGrainValues(grain1,'stat','bbysmean',1);
+gr1.int(:,1)=gtAllGrainValues(grain1,'stat','intmean',1);
+
+% Load relevant info into the gr2 structure (vectors and matrices):
+gr2.id=gtAllGrainValues(grain2,'id',[],1);
+
+gr2.center(:,1)=gtAllGrainValues(grain2,'center',[],1);
+gr2.center(:,2)=gtAllGrainValues(grain2,'center',[],2);
+gr2.center(:,3)=gtAllGrainValues(grain2,'center',[],3);
+
+gr2.R_vector(:,1)=gtAllGrainValues(grain2,'R_vector',[],1);
+gr2.R_vector(:,2)=gtAllGrainValues(grain2,'R_vector',[],2);
+gr2.R_vector(:,3)=gtAllGrainValues(grain2,'R_vector',[],3);
+
+gr2.bbxs(:,1)=gtAllGrainValues(grain2,'stat','bbxsmean',1);
+gr2.bbys(:,1)=gtAllGrainValues(grain2,'stat','bbysmean',1);
+gr2.int(:,1)=gtAllGrainValues(grain2,'stat','intmean',1);
+
+
+for i=1:nof_grains1
+
+	if i==85
+		%keyboard
+	end
+	
+	act=sfSelectGrains(i,gr1);      % actual grain
+
+	%tol_matchgrains.dist=min([act.bbxs, act.bbys])/2;
+
+	tomatch=sfCheckMatching(act,gr2,dc,tol_matchgrains); % grains to be matched
+
+	if ~isempty(tomatch)
+
+		ltm=length(tomatch);
+		
+		if ltm>1
+
+			%actminsize=min([act.bbxs, act.bbys]);
+			%dcenter=sum((repmat(act.center,ltm,1)-gr2.center(tomatch,:)).^2,2)/(actminsize^2);
+			dR_vector=sum((repmat(act.center+dc,ltm,1)-gr2.R_vector(tomatch,:)).^2,2);
+			%dbbxs=sum((act.bbxs-gr2.bbxs(tomatch,:)).^2,2)/(act.bbxs^2);
+			%dbbys=sum((act.bbys-gr2.bbys(tomatch,:)).^2,2)/(act.bbys^2);
+			%dint=sum((act.int-gr2.int(tomatch,:)).^2,2)/(act.int^2);
+
+			%dd=dcenter+dR_vector+dbbxs+dbbys+dint;
+			dd=dR_vector;
+			
+			sortM=[];
+
+			sortM(:,1)=dd;
+			sortM(:,2)=tomatch;
+			sortM(:,3)=gr2.id(tomatch);
+			
+			sortM=sortrows(sortM,1);
+
+			tomatch=sortM(:,2);
+
+			disp(['Multiple matches found for grain #' num2str(i) ':'])
+			disp(tomatch)
+		end
+
+		match(i,2)=tomatch(1);
+
+	end
+
+end
+
+
+
+
+
+for i=1:nof_grains1
+	
+	if isnan(match(i,2))
+		d.dist(i,:)=NaN(1,3);
+		d.Rdist(i,:)=NaN(1,3);
+		d.int(i,1)=NaN;
+		d.bbys(i,1)=NaN;
+		d.bbxs(i,1)=NaN;
+	else
+		d.dist(i,:)=gr2.center(match(i,2),:)-gr1.center(i,:)-dc;
+		d.Rdist(i,:)=gr2.R_vector(match(i,2),:)-gr1.R_vector(i,:);
+		d.bbxs(i,1)=gr2.bbxs(match(i,2))/gr1.bbxs(i);
+		d.bbys(i,1)=gr2.bbys(match(i,2))/gr1.bbys(i);
+		d.int(i,1)=gr2.int(match(i,2))/gr1.int(i);
+	end
+	
+end
+
+
+mean(d.dist(~isnan(d.dist(:,1)),:))
+
+disp('Matches found:')
+disp(sum(~isnan(match(:,2))));
+
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SUB_FUNCTIONS
+
+function grk=sfSelectGrains(keeplist,gr)
+
+grk.id=gr.id(keeplist);
+grk.int=gr.int(keeplist);
+grk.center=gr.center(keeplist,:);
+grk.R_vector=gr.R_vector(keeplist,:);
+grk.bbys=gr.bbys(keeplist);
+grk.bbxs=gr.bbxs(keeplist);
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function tomatch=sfCheckMatching(act,cand,dc,tol_matchgrains)
+
+if act.id==38
+	%keyboard
+end
+
+
+tomatch=(1:length(cand.id))';  % initial indices of grain candidates to be merged 
+
+% Delete those indices that don't meet the following constraints:
+
+% Bounding box Y size close enough?
+cons=(cand.bbys>act.bbys/tol_matchgrains.bbys) & ...
+     (cand.bbys<tol_matchgrains.bbys*act.bbys);
+cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% Spatial distance of centers close enough?
+dvec=repmat(act.center+dc,length(cand.id),1)-cand.center;
+dist=sqrt(sum(dvec.*dvec,2));
+cons=dist<tol_matchgrains.dist;
+cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% Bounding box X size close enough?
+cons=(cand.bbxs>act.bbxs/tol_matchgrains.bbxs) & ...
+	   (cand.bbxs<tol_matchgrains.bbxs*act.bbxs);
+cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% Intensity close enough?
+cons=(cand.int>act.int/tol_matchgrains.int) & ...
+	   (cand.int<tol_matchgrains.int*act.int);
+cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% Rodriguez vector close enough?
+dRvec=repmat(act.R_vector,length(cand.id),1)-cand.R_vector;
+Rdist=sqrt(sum(dRvec.*dRvec,2));
+cons=Rdist<tol_matchgrains.Rdist;
+%cand=sfSelectGrains(cons,cand);
+tomatch(~cons)=[];
+
+% cons=false(length(cand.id),1);
+% for i=1:length(cand.id)
+% 
+%   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 	
+% %	[pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test([l1.pl;l2.pl],[l1.hkl;l2.hkl],0);
+%   [Rvec, good_plnorms]=gtRodriguesTest([act.pl;grain{cand.id(i)}.pl],[act.hkl;grain{cand.id(i)}.hkl],0,spacegroup,0);
+% 
+%   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 
+%   cons(i)=all(good_plnorms);
+% end
+% tomatch(~cons)=[];
+
+
+
+end
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Index/gtIndexMergeGrains.m b/zUtil_Index/gtIndexMergeGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..57dbc49a0b6b583a081b243fa426d18b429dd056
--- /dev/null
+++ b/zUtil_Index/gtIndexMergeGrains.m
@@ -0,0 +1,162 @@
+function newgrain=gtIndexMergeGrains(grain,tot,tol_merge,spacegroup,latticepar)
+
+disp(' ')
+disp(' MERGING GRAINS...')
+disp(' ')
+disp(tol_merge)
+tic
+
+nof_newgrains=0;
+nof_grains=length(grain);
+
+remaining=1:nof_grains;
+
+% Load relevant info into the gr structure (vectors and matrices):
+gr.id=gtAllGrainValues(grain,'id',[],1);
+
+gr.center(:,1)=gtAllGrainValues(grain,'center',[],1);
+gr.center(:,2)=gtAllGrainValues(grain,'center',[],2);
+gr.center(:,3)=gtAllGrainValues(grain,'center',[],3);
+
+%gr.R_vector(:,1)=gtAllGrainValues(grain,'R_vector',[],1);
+%gr.R_vector(:,2)=gtAllGrainValues(grain,'R_vector',[],2);
+%gr.R_vector(:,3)=gtAllGrainValues(grain,'R_vector',[],3);
+
+gr.bbxs(:,1)=gtAllGrainValues(grain,'stat','bbxsmean',1);
+gr.bbys(:,1)=gtAllGrainValues(grain,'stat','bbysmean',1);
+gr.int(:,1)=gtAllGrainValues(grain,'stat','intmean',1);
+
+
+
+while length(remaining)>=1
+  
+  act=sfSelectGrains(remaining(1),gr);      % actual grain
+  cand=sfSelectGrains(remaining(2:end),gr); % remaining candidates for merge 
+	
+	tol_merge.dist=min([act.bbxs, act.bbys])/tol_merge.distsf;
+	
+  tomerge=sfCheckMerge(act,cand,grain,tot,tol_merge,spacegroup,latticepar); % grains to be merged
+
+	nof_newgrains=nof_newgrains+1;
+  	
+  if isempty(tomerge)
+	  newgrain{nof_newgrains}=grain{act.id};    % grain is unchanged
+	  newgrain{nof_newgrains}.id=nof_newgrains; 
+	else
+		lineids=grain{act.id}.lid;
+		for i=1:length(tomerge)
+			lineids=[lineids, grain{cand.id(tomerge(i))}.lid];
+		end
+		lineids=lineids';
+			
+		newglines=gtIndexSelectLines(lineids,tot); % reload original lines in the new grain
+				
+		newgrain{nof_newgrains}=gtIndexCreateGrainOutputMerge(newglines);
+
+		newgrain{nof_newgrains}.id=nof_newgrains; 
+
+		%newgrain{nof_newgrains}.merged=true; 
+		
+		disp(['Grains merged as new grain #' num2str(nof_newgrains) ':'])
+		disp(act.id)
+		disp(cand.id(tomerge(:)))
+	end
+
+	remaining(1)=[];
+	remaining(tomerge)=[];
+
+% 	for i=1:length(todel)
+%     remaining(remaining==todel(i))=[];
+%   end
+%   
+%   if nof_grains>=dongrains
+%     break
+%   end
+
+end
+
+disp(' ')
+toc
+
+end
+
+
+function grk=sfSelectGrains(keeplist,gr)
+
+grk.id=gr.id(keeplist);
+grk.int=gr.int(keeplist);
+grk.center=gr.center(keeplist,:);
+%grk.R_vector=gr.R_vector(keeplist,:);
+grk.bbys=gr.bbys(keeplist);
+grk.bbxs=gr.bbxs(keeplist);
+
+end
+
+
+
+function tomerge=sfCheckMerge(act,cand,grain,tot,tol_merge,spacegroup,latticepar)
+
+tomerge=(1:length(cand.id))';  % initial indices of grain candidates to be merged 
+
+% Delete those indices that don't meet the following constraints:
+
+% Bounding box Y size close enough?
+cons=(cand.bbys>act.bbys/tol_merge.bbys) & ...
+     (cand.bbys<tol_merge.bbys*act.bbys);
+cand=sfSelectGrains(cons,cand);
+tomerge(~cons)=[];
+
+% Spatial distance of centres close enough?
+dvec=repmat(act.center,length(cand.id),1)-cand.center;
+dist=sqrt(sum(dvec.*dvec,2));
+cons=dist<tol_merge.dist;
+cand=sfSelectGrains(cons,cand);
+tomerge(~cons)=[];
+
+% Bounding box X size close enough?
+cons=(cand.bbxs>act.bbxs/tol_merge.bbxs) & ...
+	   (cand.bbxs<tol_merge.bbxs*act.bbxs);
+cand=sfSelectGrains(cons,cand);
+tomerge(~cons)=[];
+
+% Intensity close enough?
+cons=(cand.int>act.int/tol_merge.int) & ...
+	   (cand.int<tol_merge.int*act.int);
+cand=sfSelectGrains(cons,cand);
+tomerge(~cons)=[];
+
+% Rodriguez vector close enough?
+% dRvec=repmat(act.R_vector,length(cand.id),1)-cand.R_vector;
+% Rdist=sqrt(sum(dRvec.*dRvec,2));
+% cons=Rdist<tol_merge.Rdist;
+% cand=sfSelectGrains(cons,cand);
+% tomerge(~cons)=[];
+
+l1=gtIndexSelectLines(grain{act.id}.lid,tot);
+cons=false(length(cand.id),1);
+for i=1:length(cand.id)
+	l2=gtIndexSelectLines(grain{cand.id(i)}.lid,tot);
+	
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+	
+%	[pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test([l1.pl;l2.pl],[l1.hkl;l2.hkl],0);
+  [Rvec, good_plnorms]=gtRodriguesTest([l1.pl;l2.pl],[l1.hkl;l2.hkl],spacegroup,latticepar);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  cons(i)=all(good_plnorms);
+end
+%cand=sfSelectGrains(cons,cand);
+tomerge(~cons)=[];
+
+end
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Index/gtIndexSelectLines.m b/zUtil_Index/gtIndexSelectLines.m
new file mode 100755
index 0000000000000000000000000000000000000000..cbb448134fc7e195fc6466160fff0cefe8dc7647
--- /dev/null
+++ b/zUtil_Index/gtIndexSelectLines.m
@@ -0,0 +1,26 @@
+% to be deleted
+% new macro: gtIndexSelectLines
+
+function linekept=gtIndexSelectLines(keeplist,line)
+
+  linekept.id=line.id(keeplist);
+  linekept.pairid=line.pairid(keeplist);
+  linekept.aid=line.aid(keeplist);
+  linekept.bid=line.bid(keeplist);
+  linekept.theta=line.theta(keeplist);
+  linekept.eta=line.eta(keeplist);
+  linekept.omega=line.omega(keeplist);
+  linekept.int=line.int(keeplist);
+  linekept.bbxs=line.bbxs(keeplist);
+  linekept.bbys=line.bbys(keeplist);
+
+  linekept.ca=line.ca(keeplist,:);
+  linekept.cb=line.cb(keeplist,:);
+  linekept.dir=line.dir(keeplist,:);
+  linekept.pl=line.pl(keeplist,:);
+
+  linekept.thetatype=line.thetatype(keeplist);
+  linekept.hkl=line.hkl(keeplist,:);
+  %linekept.lRv=line.lRv(:,:,keeplist);
+
+end
diff --git a/zUtil_Index/gtIndexStrategyExample.m b/zUtil_Index/gtIndexStrategyExample.m
new file mode 100755
index 0000000000000000000000000000000000000000..c401a1057ef44a46c557e4dd9a4005aeed66bd05
--- /dev/null
+++ b/zUtil_Index/gtIndexStrategyExample.m
@@ -0,0 +1,47 @@
+% function strategy=gtIndexStrategyExample
+
+function strategy=gtIndexStrategyExample
+
+% No. of iterations (linear extension of tolerances from 'beg' to 'end'):
+strategy.iter=5;
+
+% Tolerances for building grains in the first iteration:
+strategy.b.beg.ang=0.2;     % angular difference in degrees
+strategy.b.beg.int=60;     % max. intensity ratio
+strategy.b.beg.bbxs=5;      % max. bbox x size ratio
+strategy.b.beg.bbys=1.4;    % max. bbox y size ratio
+strategy.b.beg.distsf=3;    % size factor for maximum distance
+strategy.b.beg.distmax=2;   % max. absolut distance
+strategy.b.beg.ming=4;      % min. no. of Friedel pairs in a grain  
+strategy.b.beg.geo=10;      % safety margin around sample volume
+
+% Tolerances for building grains in the last iteration:
+strategy.b.end.ang=0.8;
+strategy.b.end.int=60;
+strategy.b.end.bbxs=5;
+strategy.b.end.bbys=1.4;
+strategy.b.end.distsf=3;
+strategy.b.end.distmax=10;
+strategy.b.end.ming=4;  
+strategy.b.end.geo=10;
+
+% Tolerances for merging grains in the first iteration:
+strategy.m.beg.bbxs=strategy.b.beg.bbxs;   % max. bbox x size ratio 
+strategy.m.beg.bbys=strategy.b.beg.bbys;   % max. bbox y size ratio
+strategy.m.beg.distsf=2;                   % size factor for maximum distance
+strategy.m.beg.int=1e10;                   % max. intensity ratio
+
+% Tolerances for merging grains in the last iteration:
+strategy.m.end.bbxs=strategy.b.end.bbxs;
+strategy.m.end.bbys=strategy.b.end.bbys;
+strategy.m.end.distsf=2;
+strategy.m.end.int=1e10;
+
+% Tolerances for assigning Friedel pairs to existing grains:
+%strategy.a=strategy.b;
+
+% Tolerance for marking outliers in final grain sets (in std):
+strategy.r=3;
+
+strategy.s=3;
+
diff --git a/zUtil_Index/gtIndexTryAddLineToGroup.m b/zUtil_Index/gtIndexTryAddLineToGroup.m
new file mode 100755
index 0000000000000000000000000000000000000000..d4011d12887a75fb443d7c23beb8f30439c7382e
--- /dev/null
+++ b/zUtil_Index/gtIndexTryAddLineToGroup.m
@@ -0,0 +1,12 @@
+% Given some pair-lines among which 'pgood' are accepted, it checks if 'ptry'
+% fits to the group.
+%
+% NOTE: p2 and p3 intersection might be far from the actual grain center if
+% they are near being parallel
+
+function ok=gtIndexTryAddLineToGroup(ptry,pgood,cand,tol,sample,ACM)
+  tryline=gtIndexSelectLines(ptry,cand);
+  goodl=gtIndexSelectLines(pgood,cand);
+  goodpofinters=pofintersectexp([goodl.ca goodl.dir])';
+  ok=gtIndexCheckGroupCons(tryline,goodl,goodpofinters,tol,sample,ACM);
+end
diff --git a/zUtil_Index/gtIndexUniquePlaneNormals.m b/zUtil_Index/gtIndexUniquePlaneNormals.m
new file mode 100755
index 0000000000000000000000000000000000000000..b71d1fed7e2353a99aa15e1356ea57595e4d87bd
--- /dev/null
+++ b/zUtil_Index/gtIndexUniquePlaneNormals.m
@@ -0,0 +1,396 @@
+% former gtINUniquePlaneNormals
+
+function grainsout=gtIndexUniquePlaneNormals(grainsinp,ACM)
+
+if ~exist('ACM','var')
+  load parameters.mat
+  ACM=gtAngConsMat(parameters.acq.spacegroup);
+end
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+% Loop through grains
+for i=1:nof_grains
+  nof_pl=size(grains{i}.pl,1);
+
+  % Load grain info into 'remaining' (these remain to be dealt with)
+  remainingl.pl=grains{i}.pl;
+  remainingl.thetatype=grains{i}.thetatype;
+  remainingl.theta=grains{i}.theta;
+  remainingl.eta=grains{i}.eta;
+  remainingl.hkl=grains{i}.hkl;
+  remainingl.omega=grains{i}.omega;
+
+  remainings=1:nof_pl; % ; modif sabine
+
+  nof_unipl=0;
+
+  grains{i}.uni.nof_unipl=NaN;
+  grains{i}.uni.nof_dbpl=NaN;
+
+  % Process all the planes in the grain
+  while length(remainings)>=1
+
+    nof_unipl=nof_unipl+1;
+
+    merge=1;
+
+    % Take the first in remaining and compare with all other remaining,
+    % look for possible identical planes.
+    for j=2:length(remainings)
+      if remainingl.thetatype(1)==remainingl.thetatype(j)
+        ACV=ACM{remainingl.thetatype(1),remainingl.thetatype(j)};
+        ang=gt2PlanesAngle(remainingl.pl(1,:),remainingl.pl(j,:));
+        [minval,minloc]=min(abs(ACV-ang));
+
+        if ACV(minloc)==0 % the same planes
+          merge=[merge, j];
+        end
+      end
+    end
+
+    % Merge identical planes, its new direction is the mean of the constituting
+    %  planes.
+
+    if length(merge)>1
+      % here, it's assumed that merge=2 always
+      % in case of wrong indexing merge might be >2
+      if length(merge)>2
+        disp(sprintf('Warning! Segmentation or indexing error in grain %d.',i))
+        disp('  Dubious plane normals are:')
+        disp(grains{i}.pairid(remainings(merge)))
+      end
+
+      % sign: if spl=-1 they are of opposite direction
+     
+      spl=sign(remainingl.pl(merge(2),:)*remainingl.pl(merge(1),:)'); % direction same or opposite
+      spl=repmat(spl,1,3);
+
+      n1=remainingl.pl(merge(1),:);
+      n2=remainingl.pl(merge(2),:).*spl;
+
+      unipl=(n1+n2)/2;
+      
+      theta1=remainingl.theta(merge(1)); % in degrees
+      theta2=remainingl.theta(merge(2));
+      
+      eta1=remainingl.eta(merge(1)); % in degrees
+      eta2=remainingl.eta(merge(2));
+
+      omega1=remainingl.omega(merge(1)); % in degrees
+      %omega2=remainingl.omega(merge(2));
+
+      % Average eta,theta and their error
+      unieta1=eta1;  
+      if spl(1)<0
+        unieta2=mod((eta2+180),360);
+      else
+        unieta2=360-eta2;
+      end
+      unieta=(unieta1+unieta2)/2;
+      deta_deg=unieta1-unieta2;
+      deta=deg2rad(deta_deg);
+      
+      unitheta=(theta1+theta2)/2;
+      dtheta_deg=theta1-theta2;
+      dtheta=deg2rad(dtheta_deg);
+      
+      % Error in the plane normal coordinates
+      dn=n1-n2;
+      nn=n1*n2';
+      
+      dang_deg=acosd(nn); % angle between the two normals
+      dang=acos(nn);
+ 
+      nnhor=n1(1:2)*n2(1:2)'/norm(n1(1:2))/norm(n2(1:2));
+      %dazhd_deg=acosd(nnhor); % azimuth
+      %dazh=acos(nnhor);    
+      
+      % Azimuth
+      az1=atan2(n1(2),n1(1)); % in rad
+      az2=atan2(n2(2),n2(1)); % in rad
+      
+      if az1<0
+        az1=az1+2*pi; % set between 0..2pi
+      end
+      
+      if az2<0
+        az2=az2+2*pi; % set between 0..2pi
+      end
+     
+      % Corner case around 0 deg (X axis)
+      if az1-az2<-pi
+        az1=az1+2*pi;
+      elseif az1-az2>pi
+        az2=az2+2*pi;
+      end
+      
+      uniaz=(az1+az2)/2;
+      daz=az1-az2; % error in azimuth in rad
+      daz_deg=rad2deg(daz); % in deg
+      
+      dy1=sind(2*theta1)*sind(eta1);
+      dz1=sind(2*theta1)*cosd(eta1);
+
+      dy2=sind(2*theta2)*sind(eta2); % should be around -dy1
+      dz2=sind(2*theta2)*cosd(eta2);
+
+      if dy1*dy2>0
+        disp('Warning! dy1*dy2>0 ')
+        disp(sprintf('   Possible segmentation or indexing error in grain %d ',i))
+        disp('   Dubious plane normals are:')
+        disp(grains{i}.pairid(remainings(merge)))
+				%keyboard
+      end
+      
+%       azd1=-atan(dy1/2/sind(theta1)^2); % azimuth term from the diffr. condition dy,dz 
+%       azd2o=-atan(dy2/2/sind(theta2)^2);
+%       azd2=azd2o;
+      
+      if spl(1)<0
+        %azd2=azd2+pi;     % if n2 opposite to n1, n2 should be turned 180 degrees
+        dz=(dz1-dz2)/2;   % average dz
+        ddz=dz1+dz2;      % error in dz
+      else
+        dz=(dz1+dz2)/2;
+        ddz=dz1-dz2;
+      end
+      
+      dy=(dy1-dy2)/2; % !!!  average dy
+      ddy=dy1+dy2;    % error in dy
+
+%       dazd=azd1+azd2o; % !!!
+%       
+%       azd1_deg=rad2deg(azd1)
+%       azd2o_deg=rad2deg(azd2o)
+%       azd2_deg=rad2deg(azd2)
+%       dazd_deg=rad2deg(dazd)
+%       
+%       az1c_deg=mod(180+azd1_deg+omega1,360)
+%       az2c_deg=mod(180+azd2_deg+omega2,360)
+%       dazc_deg=az1c_deg-az2c_deg
+%       daz_deg
+%             
+%       dom_deg=dazc_deg-dazd_deg
+%       dom_deg=daz_deg-dazd_deg
+      
+     
+%       % Derivatives      
+%       dth_ddy=1/2*sind(unieta)/cosd(2*unitheta);
+%       dth_ddz=1/2*cosd(unieta)/cosd(2*unitheta);
+%       
+%       term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+%       term2=1/2*(1/sind(unitheta)^2-2*dy*cosd(unitheta)/sind(unitheta)^3*dth_ddy);
+%       daz_ddy=term1*term2;
+%       
+%       term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+%       term2=-dy*cosd(unitheta)/sind(unitheta)^3*dth_ddz;
+%       daz_ddz=term1*term2;
+%       
+%       % Error in azimuth from dy,dz:
+%       dazd=daz_ddy*ddy+daz_ddz*ddz;
+%       dazd_deg=rad2deg(dazd); % in deg
+%      
+%       % Error in azimuth from omega
+%       domega=daz-dazd;
+%       domega_deg=rad2deg(domega); % in deg
+    
+
+      
+      
+      errvernorm=abs(ddz/cosd(2*unitheta)/sqrt(2)); % vertical detection error normalized
+                                                    % by sp/(2r)     
+      errhornorm=abs(ddy/cosd(2*unitheta)/sqrt(2)); % horizontal detection error normalized
+                                                    % by sp/(2r)     
+     
+      %pixerrvernorm=abs(dn(3)*2*sind(unitheta)/cosd(2*unitheta));
+      ddfrometa=deta*2*sind(unitheta);  %/cosd(2*unitheta);
+      %omfactor=(1/(1+(sind(2*unitheta)*sind(unieta)/(2*sind(unitheta)^2))^2)/...
+      %         (2*sind(unitheta)^2))^2*cosd(2*unitheta)^2;
+      
+    else % if length(merge)<=1
+      unipl=remainingl.pl(1,:);
+      unitheta=remainingl.theta(1);
+      unieta=remainingl.eta(1); % in degrees
+      omega1=remainingl.omega(1);
+			
+      % Azimuth
+      uniaz=atan2(unipl(2),unipl(1)); % in rad
+      if uniaz<0
+        uniaz=uniaz+2*pi; % set between 0..2pi
+      end
+      
+      dy=sind(2*unitheta)*sind(unieta);
+      dz=sind(2*unitheta)*cosd(unieta);
+
+      % Discrepancy: not known
+      dn=NaN(1,3);
+      nn=NaN;
+      ddy=NaN;
+      ddz=NaN;
+
+      errvernorm=NaN;
+      errhornorm=NaN;
+      %pixerrvernorm=NaN;
+      ddfrometa=NaN;
+      dang=NaN;
+      dang_deg=NaN;
+      daz_deg=NaN;
+      dtheta_deg=NaN;
+      deta_deg=NaN;
+            
+      nnhor=NaN;
+      daz=NaN;
+      dtheta=NaN;
+      deta=NaN;
+      %omfactor=NaN;
+    end
+
+
+    % Eta in first quadrant (between 0..90deg)
+     %  Set eta between 0<eta<180
+    if unieta>180
+      etaq=360-unieta; % in degrees
+    else
+      etaq=unieta; % in degrees
+    end
+
+     %  Set eta between 0<eta<90
+    if etaq>90
+      etaq=180-etaq;
+    end
+
+   
+    % Derivatives
+    dth_ddy=1/2*sind(unieta)/cosd(2*unitheta);
+    dth_ddz=1/2*cosd(unieta)/cosd(2*unitheta);
+ 
+    deta_ddy=cosd(unieta)/sind(2*unitheta);
+    deta_ddz=-sind(unieta)/sind(2*unitheta);
+
+    dnz_ddy=-dz/2*cosd(unitheta)/sind(unitheta)^2*dth_ddy;
+    dnz_ddz=1/2/sind(unitheta)-dz*cosd(unitheta)/2/sind(unitheta)^2*dth_ddz;
+
+    % azimuth
+    term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+    term2=1/2*(1/sind(unitheta)^2-2*dy*cosd(unitheta)/sind(unitheta)^3*dth_ddy);
+    daz_ddy=term1*term2;
+
+    term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+    term2=-dy*cosd(unitheta)/sind(unitheta)^3*dth_ddz;
+    daz_ddz=term1*term2;
+
+    % Error in azimuth from dy,dz:
+    dazd=daz_ddy*ddy+daz_ddz*ddz;
+    dazd_deg=rad2deg(dazd); % in deg
+
+    % Error in azimuth from omega
+    dom=daz-dazd;
+    dom_deg=rad2deg(dom); % in deg
+    
+    if isnan(dom_deg)
+      uniomega=omega1; % no correction 
+    else
+      uniomega=omega1-dom_deg/2; % double detection; corrected by half the difference
+    end
+    
+    % Save unique planes under grains.uni 
+    grains{i}.uni.plid(nof_unipl,:)=false(1,nof_pl);
+    grains{i}.uni.plid(nof_unipl,remainings(merge))=true; % which pair-lines are used
+    
+    % Coordinates
+    grains{i}.uni.pl(nof_unipl,:)=unipl;
+    grains{i}.uni.thetatype(nof_unipl)=remainingl.thetatype(1);
+    grains{i}.uni.hkl(nof_unipl,:)=remainingl.hkl(1,:);
+    %grains{i}.uni.pla(nof_unipl)=NaN;
+    
+    grains{i}.uni.theta(nof_unipl)=unitheta; % in deg
+    grains{i}.uni.eta(nof_unipl)=unieta; % in deg 
+    grains{i}.uni.etaq(nof_unipl)=etaq; % in deg
+    grains{i}.uni.omega(nof_unipl)=uniomega; % refers to n1; in deg
+    
+    grains{i}.uni.dy(nof_unipl)=dy;
+    grains{i}.uni.dz(nof_unipl)=dz;   
+    grains{i}.uni.az(nof_unipl)=uniaz; % azimuth in rad   
+    
+    % Errors
+    grains{i}.uni.ddy(nof_unipl)=ddy;    
+    %grains{i}.uni.ddy_az(nof_unipl)=ddy_az;
+    grains{i}.uni.ddz(nof_unipl)=ddz;
+    grains{i}.uni.dom(nof_unipl)=dom;
+    
+    grains{i}.uni.ddfrometa(nof_unipl)=ddfrometa;
+
+    grains{i}.uni.errvernorm(nof_unipl)=errvernorm;
+    grains{i}.uni.errhornorm(nof_unipl)=errhornorm;
+    
+    grains{i}.uni.dn(nof_unipl,:)=dn;    
+    grains{i}.uni.nn(nof_unipl)=nn;
+    grains{i}.uni.nnhor(nof_unipl)=nnhor;    
+    
+    grains{i}.uni.dang(nof_unipl)=dang;    
+    grains{i}.uni.daz(nof_unipl)=daz;    
+    grains{i}.uni.dazd(nof_unipl)=dazd;    
+    grains{i}.uni.dtheta(nof_unipl)=dtheta;    
+    grains{i}.uni.deta(nof_unipl)=deta;    
+
+    grains{i}.uni.dom_deg(nof_unipl)=dom_deg;
+    grains{i}.uni.dang_deg(nof_unipl)=dang_deg;    
+    grains{i}.uni.daz_deg(nof_unipl)=daz_deg;    
+    grains{i}.uni.dazd_deg(nof_unipl)=dazd_deg;    
+    grains{i}.uni.dtheta_deg(nof_unipl)=dtheta_deg;
+    grains{i}.uni.deta_deg(nof_unipl)=deta_deg;
+
+    % Derivatives
+    grains{i}.uni.dth_ddy(nof_unipl)=dth_ddy;
+    grains{i}.uni.dth_ddz(nof_unipl)=dth_ddz;
+    grains{i}.uni.dth_dom(nof_unipl)=0;
+    
+    grains{i}.uni.deta_ddy(nof_unipl)=deta_ddy;
+    grains{i}.uni.deta_ddz(nof_unipl)=deta_ddz;
+    grains{i}.uni.deta_dom(nof_unipl)=0;
+
+    grains{i}.uni.dnz_ddy(nof_unipl)=dnz_ddy;
+    grains{i}.uni.dnz_ddz(nof_unipl)=dnz_ddz;
+    grains{i}.uni.dnz_dom(nof_unipl)=0;
+    
+    grains{i}.uni.daz_ddy(nof_unipl)=daz_ddy;
+    grains{i}.uni.daz_ddz(nof_unipl)=daz_ddz;
+    grains{i}.uni.daz_dom(nof_unipl)=1;
+   
+    % Other
+
+    %grains{i}.uni.pixerrvernorm(nof_unipl)=pixerrvernorm;
+    %grains{i}.uni.omfactor(nof_unipl)=omfactor;    
+
+    
+    remainingl.pl(merge,:)=[];
+    remainingl.thetatype(merge)=[];
+    remainingl.theta(merge)=[];
+    remainingl.eta(merge)=[];
+    remainingl.hkl(merge,:)=[];
+    remainingl.omega(merge)=[];
+
+    remainings(merge)=[];
+
+  end % of planes
+
+  grains{i}.uni.nof_unipl=nof_unipl;
+  grains{i}.uni.nof_dbpl=nof_pl-nof_unipl;
+
+end % of grains
+
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+end % of function
diff --git a/zUtil_Index/helpers.m b/zUtil_Index/helpers.m
new file mode 100755
index 0000000000000000000000000000000000000000..39c8c7853a78503bb5a72724062cd53e76d6c022
--- /dev/null
+++ b/zUtil_Index/helpers.m
@@ -0,0 +1,55 @@
+
+D=NaN(length(grain));
+for ii=1:length(grain)
+	for jj=1:length(grain)
+		dvec=grain{ii}.center-grain{jj}.center;
+		dist=sqrt(sum(dvec.*dvec,2));
+		D(ii,jj)=dist;
+	end
+end
+m=D<40;
+figure, imagesc(m)
+
+
+% 39-125; 
+
+l1=gtIndexSelectLines(grain{83}.lid,tot);
+l2=gtIndexSelectLines(grain{87}.lid,tot);
+
+close([2,3,4])
+i=121 ;
+j=122 ;
+[Rout, good_plnorms]=gtRodriguesTest([grain{i}.pl;grain{j}.pl],[grain{i}.hkl;grain{j}.hkl],229,0,1)
+
+[Rout, good_plnorms]=gtRodriguesTest(grain{i}.pl,grain{i}.hkl,229,0,1)
+[Rout, good_plnorms]=gtRodriguesTest(grain{j}.pl,grain{j}.hkl,229,0,1)
+
+
+
+
+close([1,2,3])
+i=115 ;
+j=117 ;
+[Rout, good_plnorms]=gtRodriguesTest([grain1{i}.pl;grain2{j}.pl],[grain1{i}.hkl;grain2{j}.hkl],229,0,1)
+
+[Rout, good_plnorms]=gtRodriguesTest(grain1{i}.pl,grain1{i}.hkl,229,0,1)
+[Rout, good_plnorms]=gtRodriguesTest(grain2{j}.pl,grain2{j}.hkl,229,0,1)
+
+
+
+
+
+
+[pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test(l1.pl,l1.hkl,1)
+[pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test(l2.pl,l2.hkl,1)
+
+[pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test([l1.pl;l2.pl],[l1.hkl;l2.hkl],1)
+
+
+
+l1=gtIndexSelectLines(grain{22}.lid,tot);
+l2=gtIndexSelectLines(grain{66}.lid,tot);
+l3=gtIndexSelectLines(grain{76}.lid,tot);
+
+[pof, good_plnorms, dsqr]=plot_rodrigues_consistancy_test([l1.pl;l2.pl;l3.pl],[l1.hkl;l2.hkl;l3.hkl],1)
+
diff --git a/zUtil_Maths/3dtrans.txt b/zUtil_Maths/3dtrans.txt
new file mode 100755
index 0000000000000000000000000000000000000000..3e3ac174ee84e2fd5ec2cdb4b5fa6de0f0467316
--- /dev/null
+++ b/zUtil_Maths/3dtrans.txt
@@ -0,0 +1,32 @@
+==========================================================================
+ftp://ftp.mathworks.com/pub/contrib/v5/math/3Dtrans
+
+3D Space Coordinate Transformations
+
+This folder contains 3 files (m-functions) :
+
+- t2x.m Transformation Matrix to Generalized Position Vector.
+- x2t.m Generalized Position Vector to Transformation Matrix.
+- m2m.m Mass/Inertia Tensor transformation with coordinate change.
+
+In the Generalized Position Vector the orientation can be expressed with:
+  -  unit quaternion, 
+  -  Euler angles xyz (roll, pitch, and yaw),
+  -  Euler angles zyz (rotation, precession, and mutation),
+  -  unit vector and rotation angle,
+  -  Denavitt-Hartemberg parameters.
+Conversion between the above orientation systems can be easily achieved.
+
+The three files work independently on each other, but since they work
+on the same objects it is somewhat useful to keep them in the same folder. 
+
+For more detailed information see the help texts of the three functions.
+
+
+January 2001
+
+Giampiero Campa, PhD, Research Assistant Professor
+West Virginia University, Aerospace Engineering Dept.
+Morgantown, WV, 26506-6106, USA
+campa@cemr.wvu.edu; gcampa@supereva.it
+==========================================================================
\ No newline at end of file
diff --git a/zUtil_Maths/deg2rad.m b/zUtil_Maths/deg2rad.m
new file mode 100755
index 0000000000000000000000000000000000000000..7eccd19ee37e00d748d5c33db6d118ef1f727ee0
--- /dev/null
+++ b/zUtil_Maths/deg2rad.m
@@ -0,0 +1,2 @@
+function rad=deg2rad(deg)
+rad=deg*pi/180;
diff --git a/zUtil_Maths/fit_ellipse.m b/zUtil_Maths/fit_ellipse.m
new file mode 100755
index 0000000000000000000000000000000000000000..95e1e21247f0bd6e887725d01391d426033dd5ef
--- /dev/null
+++ b/zUtil_Maths/fit_ellipse.m
@@ -0,0 +1,412 @@
+
+
+
+function fit_ellipse(thetatype,tol)
+
+p=load('parameters.mat');
+parameters=p.parameters;
+
+if ~exist('tol','var')
+  tol=1;
+end
+
+disp(' ')
+disp(['Dataset: ' parameters.acq.name])
+disp(sprintf('Reflection type: %d',thetatype))
+disp(' ')
+
+[eta,theta]=mym(sprintf('select eta,theta from %s where thetatype=%d',parameters.acq.pair_tablename,thetatype));
+
+x=sind(eta).*tand(2*theta);
+y=cosd(eta).*tand(2*theta);
+
+x0=sind(0).*tand(2*theta(1));
+y0=cosd(0).*tand(2*theta(1));
+
+x90=sind(90).*tand(2*theta(1));
+y90=cosd(90).*tand(2*theta(1));
+
+A=[x.^2 y.^2 x y x.*y];
+B=-ones(size(x));
+
+%lsqr(A,B)
+pf=A\B;
+
+% reject outliers
+useit=abs(A*pf+1)<tol*std(A*pf+1);
+
+A=[x(useit).^2 y(useit).^2 x(useit) y(useit) x(useit).*y(useit)];
+B=-ones(size(x(useit)));
+
+disp('Fitted parameters:')
+%lsqr(A,B)
+pf=A\B
+
+
+% for plotting
+xte=(-1:0.000001:1)';
+[yt1 yt2 xte]=Yxe(pf,xte);
+ 
+% etane=gtEtaOfPoint(xte,yt2);
+% etane=[etane; gtEtaOfPoint(xte,yt1)];
+% 
+% thetane=atand(sqrt(xte.^2+yt2.^2))/2;
+% thetane=[thetane; atand(sqrt(xte.^2+yt1.^2))/2];
+
+etane=(0.1:0.1:359.9)';
+thetane=zeros(size(etane));
+for i=1:length(etane)
+  thetane(i)=theta_fit(etane(i),pf);
+end
+
+%close all
+
+f1=figure;
+ plot(x(useit),y(useit),'b.')
+ axis equal
+ hold on
+ plot(x(~useit),y(~useit),'r.')
+ plot(x0,y0,'mo')
+ plot(x90,y90,'mo')
+ plot(xte,yt1,'g')
+ plot(xte,yt2,'g')
+
+f2=figure;
+ plot(theta(useit),eta(useit),'b.')
+ hold on
+ plot(theta(~useit),eta(~useit),'r.')
+ plot(thetane,etane,'g.')
+
+
+%% From Matrix representations of conic sections, Wikipedia
+
+% General equation of a conic section: 
+%  A*x^2+B*y^2+C*x+D*y+E*x*y+F=0
+
+A=pf(1);
+B=pf(2);
+C=pf(3);
+D=pf(4);
+E=pf(5);
+F=1;
+
+% The asssociated matrix
+% M=[F C/2 D/2 ; C/2 A E/2 ; D/2 E/2 B];
+
+% Classification
+Mq=[ A E/2 ; E/2 B ];
+cl=det(Mq);
+if cl<0
+  disp('Curve is a hyperbola.')
+elseif cl==0
+  disp('Curve is a parabola.')
+else
+  disp('Curve is an ellipse.')
+end
+
+% Center
+x0=Mq\[-C/2 ; -D/2];
+
+disp('Center of curve:')
+y0=x0(2)
+x0=x0(1)
+
+[eigvec,eigval]=eig(Mq);
+
+disp('Direction of axes:')
+v1=eigvec([1 2],1)
+v2=eigvec([1 2],2)
+
+l1=eigval(1,1);
+l2=eigval(2,2);
+
+% Reduced equation
+% xx^2/aa^2+yy^2/bb^2=1
+
+% Semi-major and semi-minor axes
+
+disp('Stretch:')
+st=sqrt(l1/l2)
+
+disp('Vertices:')
+vertices=intersect_line_ellipse(x0,y0,v1,pf);
+ver1a=vertices(1,:)
+ver1b=vertices(2,:)
+
+vertices=intersect_line_ellipse(x0,y0,v2,pf);
+ver2a=vertices(1,:)
+ver2b=vertices(2,:)
+
+disp('Length of semi-axes:')
+r1=norm(ver1a-ver1b)/2
+r2=norm(ver2a-ver2b)/2
+
+disp('r1/r2=')
+disp(r1/r2)
+disp('r2/r1=')
+disp(r2/r1)
+
+
+disp('Fitted eta angles at the vertices:')
+% eta1a=gtEtaOfPoint(ver1a(1)-x0,ver1a(2)-y0)
+% eta1b=gtEtaOfPoint(ver1b(1)-x0,ver1b(2)-y0)
+% eta2a=gtEtaOfPoint(ver2a(1)-x0,ver2a(2)-y0)
+% eta2b=gtEtaOfPoint(ver2b(1)-x0,ver2b(2)-y0)
+% 
+% theta1=atand(sqrt((ver1a(1)-x0)^2+(ver1a(2)-y0)^2))/2
+% theta2=atand(sqrt((ver2a(1)-x0)^2+(ver2a(2)-y0)^2))/2
+
+
+
+etaver1a=gtEtaOfPoint(ver1a(1),ver1a(2))
+etaver1b=gtEtaOfPoint(ver1b(1),ver1b(2))
+etaver2a=gtEtaOfPoint(ver2a(1),ver2a(2))
+etaver2b=gtEtaOfPoint(ver2b(1),ver2b(2))
+
+thetaver1a=atand(sqrt((ver1a(1))^2+(ver1a(2))^2))/2
+thetaver1b=atand(sqrt((ver1b(1))^2+(ver1b(2))^2))/2
+thetaver2a=atand(sqrt((ver2a(1))^2+(ver2a(2))^2))/2
+thetaver2b=atand(sqrt((ver2b(1))^2+(ver2b(2))^2))/2
+
+[etaex(1),thetaex(1)]=theta_extremes(etane,thetane,etaver1a);
+[etaex(2),thetaex(2)]=theta_extremes(etane,thetane,etaver1b);
+[etaex(3),thetaex(3)]=theta_extremes(etane,thetane,etaver2a);
+[etaex(4),thetaex(4)]=theta_extremes(etane,thetane,etaver2b)
+
+disp('Difference in theta extreme value:')
+disp(' Around vertex 1:') 
+disp(thetaex(1)-thetaex(2))
+disp(' Around vertex 2:') 
+disp(thetaex(3)-thetaex(4))
+
+
+%% Correction curve %%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cctheta1=@(eta,fr,A)A*sind(eta*fr);
+%cctheta2=@(eta,fr,A)A*sind(eta*fr);
+
+cc1A=(thetaex(3)-thetaex(4))/2; % amplitude
+cc1fr=1; % frequency
+ 
+% cc2A=-(thetaex(1)-thetaex(2))*0; % amplitude
+% cc2fr=0.5;
+
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+et=1:360;
+for i=1:length(et)
+   th(i)=theta_fit(et(i),pf);
+end
+
+ccbase=min(thetaex);
+
+figure(f1)
+plot([ver1a(1) ver1b(1)],[ver1a(2) ver1b(2)],'ko-')
+plot([ver2a(1) ver2b(1)],[ver2a(2) ver2b(2)],'ko-')
+% plot([ver1a(1) ver1a(1)],Yxe(pf,ver1a(1)),'kx')
+% plot([ver1b(1) ver1b(1)],Yxe(pf,ver1b(1)),'kx')
+% plot([ver2a(1) ver2a(1)],Yxe(pf,ver2a(1)),'kx')
+% plot([ver2b(1) ver2b(1)],Yxe(pf,ver2b(1)),'kx')
+plot([ver2a(1) ver2b(1)],[ver2a(2) ver2b(2)],'ko-')
+quiver(x0,y0,v1(1),v1(2),r1*0.5,'b-','LineWidth',3)
+quiver(x0,y0,v2(1),v2(2),r1*0.5*(1+(1-st)*100),'c-','LineWidth',3)
+text(ver1a(1)*0.8,ver1a(2)*0.8,'Axis 1')
+text(ver2a(1)*0.8,ver2a(2)*0.8,'Axis 2')
+plot(0,0,'k+')
+
+figure(f2)
+ plot(thetaver1a,etaver1a,'ko')
+ plot(thetaver1b,etaver1b,'ko')
+ plot(thetaver2a,etaver2a,'ko')
+ plot(thetaver2b,etaver2b,'ko')
+ plot(thetaex,etaex,'k*')
+
+ plot(cctheta1(et,cc1fr,cc1A)+ccbase,et,'y.')
+ %plot(cctheta2(et,cc2fr,cc2A)+ccbase,et,'y.')
+ %plot(cctheta1(et,cc1fr,cc1A)+cctheta2(et,cc2fr,cc2A)+th,et,'m.')
+
+ plot(cctheta1(et,cc1fr,cc1A)+th,et,'m.')
+
+ 
+ 
+end % of function
+ 
+ 
+
+%% Sub-functions
+
+function Mxy=intersect_line_ellipse(x0,y0,v,pf)
+  % intersection in xy coord.
+  % eq_ellipse='A*x^2+B*y^2+C*x+D*y+E*x*y+F=0';
+  % eq_axis1='y=y0+(x-x0)*f';
+
+  A=pf(1);
+  B=pf(2);
+  C=pf(3);
+  D=pf(4);
+  E=pf(5);
+  F=1;
+  
+  f=v(2)/v(1); % tangent of axis
+
+  % Solve x^2*a+x*b+c=0
+  a=A+B*f^2+E*f;
+  b=B*(-2*x0*f^2+2*y0*f)+E*(y0-x0*f)+C+D*f;
+  c=B*(y0^2+x0^2*f^2-2*y0*x0*f)+D*(y0-x0*f)+F;
+
+  x1=(-b+sqrt(b^2-4*a*c))/2/a;
+  x2=(-b-sqrt(b^2-4*a*c))/2/a;
+
+  y1=y0+(x1-x0)*f;
+  y2=y0+(x2-x0)*f;
+
+  Mxy=[x1 y1; x2 y2];
+
+  % eq_ellipse='A*x^2+B*y^2+C*x+D*y+E*x*y+F=0';
+  % eq_axis1='y=y0+(x-x0)*f';
+  % syms x y
+  % [ver1x,ver1y]=solve(eq_ellipse,eq_axis1)
+end
+
+
+function theta=theta_fit(eta,pf)
+  v=[sind(eta) cosd(eta)];
+  m=intersect_line_ellipse(0,0,v,pf);
+  x1=m(1,1);
+  y1=m(1,2);
+  x2=m(2,1);
+  y2=m(2,2);
+ 
+  if (x1*v(1)+y1*v(2))>0
+    theta=atand(sqrt(x1^2+y1^2))/2;
+  else
+    theta=atand(sqrt(x2^2+y2^2))/2;
+  end
+end
+
+
+function [y1 y2 x]=Yxe(pf,x,sol)
+  A=pf(1);
+  B=pf(2);
+  C=pf(3);
+  D=pf(4);
+  E=pf(5);
+
+  y1=(-(E*x+D)+sqrt((E*x+D).^2-4*B*(A*x.^2+C*x+1)))/2/B;
+  y2=(-(E*x+D)-sqrt((E*x+D).^2-4*B*(A*x.^2+C*x+1)))/2/B;
+
+  if y1<y2
+    tmp=y1;
+    y1=y2;
+    y2=tmp;
+  end
+  
+  if exist('sol','var')
+    if sol<=0
+      tmp=y1;
+      y1=y2;
+      y2=tmp;
+    end
+  end
+  
+  todel=false(size(y1));
+  for i=1:length(y1)
+    if ~isreal(y1(i))
+      todel(i)=true;
+    end
+  end
+
+  y1(todel)=[];
+  y2(todel)=[];
+  x(todel)=[];
+end
+
+
+
+function [etaex,thetaex]=theta_extremes(etane,thetane,etaver)
+  
+  range=30;
+  
+  eta_sub=etane((etane>etaver-range) & (etane<etaver+range));
+  theta_sub=thetane((etane>etaver-range) & (etane<etaver+range));
+  
+  [thetaex exloc]=max(theta_sub);
+  if exloc==1 || exloc==length(eta_sub)  % should look at other extreme
+    [thetaex exloc]=min(theta_sub);
+  end
+  
+  etaex=eta_sub(exloc);
+  
+  
+%   etaex(1)=etane(etaex(1));
+%   [thetaex(3) etaex(3)]=max(thetane((etane>etaver1b-45) & (etane<etaver1b+45)));
+%   etaex(3)=etane(etaex(3));
+%   [thetaex(2) etaex(2)]=max(thetane((etane>etaver2a-45) & (etane<etaver2a+45)));
+%   etaex(2)=etane(etaex(2));
+%   [thetaex(4) etaex(4)]=max(thetane((etane>etaver2b-45) & (etane<etaver2b+45)));
+%   etaex(4)=etane(etaex(4));
+
+end
+
+
+function [eta,theta]=xxx_theta_extremes(pf,y0)
+  A=pf(1);
+  B=pf(2);
+  C=pf(3);
+  D=pf(4);
+  E=pf(5);
+  
+  % X coords of tangent locations
+  %Fx=E*x^2+x(2*(B-A)*y+D)-C*y-E*y^2
+  Fx_p=@(x)E*x^2+x*(2*(B-A)*Yxe(pf,x,1)+D)-C*Yxe(pf,x,1)-E*Yxe(pf,x,1)^2; % positive y
+  Fx_n=@(x)E*x^2+x*(2*(B-A)*Yxe(pf,x,-1)+D)-C*Yxe(pf,x,-1)-E*Yxe(pf,x,-1)^2; % negative y
+    
+  x1=fzero(Fx_p,0); % about eta=0
+  y1=Yxe(pf,x1,1);
+  eta(1,1)=gtEtaOfPoint(x1,y1);
+  theta(1,1)=atand(sqrt(x1^2+y1^2))/2;
+
+  x3=fzero(Fx_n,0); % about eta=180
+  y3=Yxe(pf,x3,-1);
+  eta(3,1)=gtEtaOfPoint(x3,y3);
+  theta(3,1)=atand(sqrt(x3^2+y3^2))/2;
+ 
+  rguess=min(r1,r2);
+  
+  if y0>=0
+    x2=fzero(Fx_p,x0+rguess); % about eta=90
+    y2=Yxe(pf,x2,1);
+    eta(2,1)=gtEtaOfPoint(x2,y2);
+    theta(2,1)=atand(sqrt(x2^2+y2^2))/2;
+
+    x4=fzero(Fx_p,x0-rguess); % about eta=270
+    y4=Yxe(pf,x4,1);
+    eta(4,1)=gtEtaOfPoint(x4,y4);
+    theta(4,1)=atand(sqrt(x4^2+y4^2))/2;
+    
+  else
+    x2=fzero(Fx_n,x0+rguess); % about eta=90
+    y2=Yxe(pf,x2,-1);
+    eta(2,1)=gtEtaOfPoint(x2,y2);
+    theta(2,1)=atand(sqrt(x2^2+y2^2))/2;
+
+    x4=fzero(Fx_n,x0-rguess); % about eta=270
+    y4=Yxe(pf,x4,-1);
+    eta(4,1)=gtEtaOfPoint(x4,y4);
+    theta(4,1)=atand(sqrt(x4^2+y4^2))/2;
+  end
+
+  
+
+end
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Maths/gtIsPointInPolyhedron.m b/zUtil_Maths/gtIsPointInPolyhedron.m
new file mode 100755
index 0000000000000000000000000000000000000000..7e8dba854871a61f34f09f1cf07585bd4390c9c6
--- /dev/null
+++ b/zUtil_Maths/gtIsPointInPolyhedron.m
@@ -0,0 +1,9 @@
+% Tells if a point is inside a convex polygon, defined by its face planes.
+
+function ok=gtIsPointInPolyhedron(p,faces)
+% 
+% ok = all( (p-f0)*fdir<=0 )
+%
+
+ok=all(sum((repmat(p,size(faces,1),1)-faces(:,1:3)).*faces(:,4:6),2)<=1e-10);
+
diff --git a/zUtil_Maths/gtLinePlaneIntersection.m b/zUtil_Maths/gtLinePlaneIntersection.m
new file mode 100755
index 0000000000000000000000000000000000000000..16da6cc962c4d7c4804cd7c7622678084241fe2a
--- /dev/null
+++ b/zUtil_Maths/gtLinePlaneIntersection.m
@@ -0,0 +1,33 @@
+function isec=gtLinePlaneIntersection(l,p)
+%
+% FUNCTION is=gtLinePlaneIntersection(l,p)
+%
+% Computes the intersection of a line with several planes.
+%
+% INPUT:  l:  line parameters   (1x6) [l0x l0y l0z ldirx ldiry ldirz]
+%         p:  planes parameters (nx6) [p0x p0y p0z pnormx pnormy pnormz]
+%    
+%   ,where ldir and pnorm do not need to be normalized.
+%
+% OUTPUT: isec: intersection points respectively (nx3) [X Y Z]
+%
+
+
+% Equations:
+% t  = (plane_0-line_0)*plane_dir/(plane_dir*line_dir)
+% isec = line_0+line_dir*t
+
+% For one plane only:
+%  t=((p(1)-l(1))*p(4)+(p(2)-l(2))*p(5)+(p(3)-l(3))*p(6))/...
+%	   (l(4)*p(4)+l(5)*p(5)+l(6)*p(6));
+%  isec=l(1:3)+l(4:6)*t;
+%
+
+l0=repmat(l(1:3),size(p,1),1);
+ld=repmat(l(4:6),size(p,1),1);
+
+t=sum((p(:,1:3)-l0).*p(:,4:6),2)./(p(:,4:6)*l(4:6)');
+
+isec=l0+ld.*[t t t];
+
+end
diff --git a/zUtil_Maths/gtLinePolyhedronIntersection.m b/zUtil_Maths/gtLinePolyhedronIntersection.m
new file mode 100755
index 0000000000000000000000000000000000000000..1edf9d5df9a4adb602f729266a8e874a19577403
--- /dev/null
+++ b/zUtil_Maths/gtLinePolyhedronIntersection.m
@@ -0,0 +1,26 @@
+function isec=gtLinePolyhedronIntersection(l,p)
+%
+% FUNCTION is=gtLinePolygonIntersection(l,p)
+%
+% Computes the intersection of a line and the surface of a convex polygon,
+%  defined by its face planes.
+%
+% INPUT:  l:  line parameters   (1x6) [l0x l0y l0z ldirx ldiry ldirz]
+%         p:  planes parameters (nx6) [p0x p0y p0z pnormx pnormy pnormz]
+%    
+%   ,where ldir and pnorm do not need to be normalized.
+%
+% OUTPUT: isec: the intersection points (2x3) [X1 Y1 Z1; X2 Y2 Z2]
+%
+
+isecs_lp=gtLinePlaneIntersection(l,p);
+
+ok=false(size(isecs_lp,1),1);
+
+for i=1:size(isecs_lp,1)
+	ok(i)=gtIsPointInPolyhedron(isecs_lp(i,:),p);
+end
+
+isec=isecs_lp(ok,:);
+
+end
\ No newline at end of file
diff --git a/zUtil_Maths/gtOutliers.m b/zUtil_Maths/gtOutliers.m
new file mode 100755
index 0000000000000000000000000000000000000000..e7e354c4b8493eb091a2a457ffe2da0c1459b0e7
--- /dev/null
+++ b/zUtil_Maths/gtOutliers.m
@@ -0,0 +1,12 @@
+% Gives outliers in a set of values.
+
+function out=gtOutliers(values,tolfact,meanv,stdv)
+
+if nargin<3
+  meanv=mean(values);
+  stdv=std(values);
+end
+  
+  out=(values>meanv+tolfact*stdv) | (values<meanv-tolfact*stdv);
+
+end
diff --git a/zUtil_Maths/gtRange.m b/zUtil_Maths/gtRange.m
new file mode 100755
index 0000000000000000000000000000000000000000..f9d56faba8c71ebdfd12fb23988e0d4080771928
--- /dev/null
+++ b/zUtil_Maths/gtRange.m
@@ -0,0 +1,2 @@
+function range=gtRange(data)
+range=max(data(:))-min(data(:));
diff --git a/zUtil_Maths/lsplane.m b/zUtil_Maths/lsplane.m
new file mode 100755
index 0000000000000000000000000000000000000000..becff48617fda8c8cceb9da9e33dde4c4b3d9a2a
--- /dev/null
+++ b/zUtil_Maths/lsplane.m
@@ -0,0 +1,61 @@
+  function [x0, a, d, normd] = lsplane(X)
+% ---------------------------------------------------------------------
+% LSPLANE.M   Least-squares plane (orthogonal distance
+%             regression).
+%
+% Version 1.0   
+% Last amended   I M Smith 27 May 2002.
+% Created        I M Smith 08 Mar 2002
+% ---------------------------------------------------------------------
+% Input   
+% X        Array [x y z] where x = vector of x-coordinates,
+%          y = vector of y-coordinates and z = vector of
+%          z-coordinates.
+%          Dimension: m x 3.
+%
+% Output  
+% x0       Centroid of the data = point on the best-fit plane.
+%          Dimension: 3 x 1.
+%
+% a        Direction cosines of the normal to the best-fit
+%          plane.
+%          Dimension: 3 x 1.
+%
+% <Optional...
+% d        Residuals.
+%          Dimension: m x 1.
+%
+% normd    Norm of residual errors.
+%          Dimension: 1 x 1.
+% ...>
+%
+% [x0, a <, d, normd >] = lsplane(X)
+% ---------------------------------------------------------------------
+
+% check number of data points
+  m = size(X, 1);
+  if m < 3
+    error('At least 3 data points required: ' )
+  end
+%
+% calculate centroid
+  x0 = mean(X)';
+%
+% form matrix A of translated points
+  A = [(X(:, 1) - x0(1)) (X(:, 2) - x0(2)) (X(:, 3) - x0(3))];
+%
+% calculate the SVD of A
+  [U, S, V] = svd(A, 0);
+%
+% find the smallest singular value in S and extract from V the
+% corresponding right singular vector
+  [s, i] = min(diag(S));
+  a = V(:, i);
+%
+% calculate residual distances, if required 
+  if nargout > 2
+    d = U(:, i)*s;
+    normd = norm(d);
+  end
+% ---------------------------------------------------------------------
+% End of LSPLANE.M.
\ No newline at end of file
diff --git a/zUtil_Maths/m2m.m b/zUtil_Maths/m2m.m
new file mode 100755
index 0000000000000000000000000000000000000000..0cf4227daaa23d8cacf4d75b2e4944691dc15163
--- /dev/null
+++ b/zUtil_Maths/m2m.m
@@ -0,0 +1,78 @@
+function Mb=m2m(Ma,T)
+
+% Mb=m2m(Ma,T) generalized mass transformation.
+% Trasforms generalized mass with respect to coordinate frame a,
+% in the generalized mass with respect to coordinate frame b.
+% 
+% Generalized mass with respect to coordinate frame x, 
+% is a 6 by 6 matrix defined like this : 
+% 
+%      [ eye(3,3)*m , -S(cx)*m ] 
+% Mx = [                       ] 
+%      [    S(cx)*m ,       Ix ] 
+% 
+% Where m is the mass of the body, cx its center of mass,
+% and Ix its inertia tensor (both with respect to x).
+% S(v) = [0 -v3 v2; v3 0 -v1; -v2 v1 0] is the cross 
+% product matrix of v. 
+% 
+% The transformation matrix T between b and a coordinate
+% frames is a 4 by 4 matrix such that:
+% T(1:3,1:3) = Orientation matrix between b and a = unit vectors
+%              of x,y,z axes of b expressed in the a coordinates.
+% T(1:3,4)   = Origin of b expressed in a coordinates.
+% T(4,1:3)   = zeros(1,3)
+% T(4,4)     = 1
+% 
+% Example (see also x2t and t2x):
+% m1=rand*eye(3);m2=rand(3);m3=rand(3);
+% M=[m1 (m2-m2')/2;(m2'-m2)/2 (m3+m3')/2];
+% x=[rand(3,1);1;rand(3,1);0];m=m2m(M,x2t(x,'rpy'));
+% M-m2m(m,inv(x2t(x,'rpy')))
+% 
+% 
+% Giampiero Campa 06/11/96
+
+if [ size(Ma)==[6 6] size(T)==[4 4] ],
+
+m=trace(Ma(1:3,1:3))/3;
+ca=[Ma(2,6)+Ma(6,2)-Ma(5,3)-Ma(3,5); Ma(4,3)+Ma(3,4)-Ma(1,6)-Ma(6,1); Ma(1,5)+Ma(5,1)-Ma(2,4)-Ma(4,2)]/4/m;
+Ia=Ma(4:6,4:6);
+
+cb=inv(T)*[ca;1];
+
+if norm(Ia-Ia')>1e-10
+    disp('   ');
+    disp('M2M warning: non symmetrical Ia tensor');
+    disp('   ');
+end
+
+Ia=(Ia+Ia')/2;
+R=T(1:3,1:3);
+Ob=T(1:3,4);
+
+Ib=R'*(Ia+m*((Ob-2*ca)'*Ob*eye(3,3)+Ob*(ca-Ob)'+ca*Ob'))*R;
+
+Mb=[eye(3,3)*m,-vp(cb,m);vp(cb,m),Ib];
+
+else
+
+disp('   ');
+disp('   Mb=m2m(Ma,T)');
+disp('   where Ma is 6 by 6 and T is 4 by 4, (see help for details)');
+disp('   ');
+
+end
+
+function z=vp(x,y)
+
+% z=vp(x,y); z = 3d cross product of x and y
+% vp(x) is the 3d cross product matrix : vp(x)*y=vp(x,y).
+%
+% by Giampiero Campa.  
+
+z=[  0    -x(3)   x(2);
+    x(3)    0    -x(1);
+   -x(2)   x(1)    0   ];
+
+if nargin>1, z=z*y; end
diff --git a/zUtil_Maths/ordfilt3D.m b/zUtil_Maths/ordfilt3D.m
new file mode 100755
index 0000000000000000000000000000000000000000..3e8ff5ab396ab8156eadf4be28f7ab7fdb6ac2fd
--- /dev/null
+++ b/zUtil_Maths/ordfilt3D.m
@@ -0,0 +1,100 @@
+function [Vr] = ordfilt3D(V0,ord,padoption);
+% ordfilt3D:    Perform 3-D order-statistic filtering on 26 neighbors
+%
+%   [Vr] = ordfilt3D(V0,ord,padoption)
+%          use 26 neighbors
+%       ord = 14 <=> median filtering
+%       ord = 1 <=> min
+%       ord = [1 27] <=> [min max]
+%       padoption: same as in padarray
+%
+% Olivier Salvado, Case Western Reserve University, 16Aug04
+
+
+
+if ~exist('padoption','var')
+    padoption = 'replicate';
+end
+
+
+%%
+% special care for uint8
+if isa(V0,'uint8')
+    V = uint8(padarray(V0,[1 1 1],padoption));
+    S = size(V);
+    Vn = uint8(zeros(S(1),S(2),S(3),26));  % all the neighbor
+else
+    V = single(padarray(V0,[1 1 1],padoption));
+    S = size(V);
+    Vn = single(zeros(S(1),S(2),S(3),26));  % all the neighbor
+end
+
+%%
+% build the neighboord
+Vn(:,:,:,1) = V;
+i = 1:S(1); ip1 = [i(2:end) i(end)]; im1 = [i(1) i(1:end-1)];
+j = 1:S(2); jp1 = [j(2:end) j(end)]; jm1 = [j(1) j(1:end-1)];
+k = 1:S(3); kp1 = [k(2:end) k(end)]; km1 = [k(1) k(1:end-1)];
+
+%%
+% left
+Vn(:,:,:,2)     = V(im1    ,jm1    ,km1);
+Vn(:,:,:,3)     = V(im1    ,j      ,km1);
+Vn(:,:,:,4)     = V(im1    ,jp1    ,km1);
+
+Vn(:,:,:,5)     = V(im1    ,jm1    ,k);
+Vn(:,:,:,6)     = V(im1    ,j      ,k);
+Vn(:,:,:,7)     = V(im1    ,jp1    ,k);
+
+Vn(:,:,:,8)     = V(im1    ,jm1    ,kp1);
+Vn(:,:,:,9)     = V(im1    ,j      ,kp1);
+Vn(:,:,:,10)    = V(im1    ,jp1    ,kp1);
+
+%%
+% right
+Vn(:,:,:,11)    = V(ip1    ,jm1    ,km1);
+Vn(:,:,:,12)    = V(ip1    ,j      ,km1);
+Vn(:,:,:,13)    = V(ip1    ,jp1    ,km1);
+
+Vn(:,:,:,14)    = V(ip1    ,jm1    ,k);
+Vn(:,:,:,15)    = V(ip1    ,j      ,k);
+Vn(:,:,:,16)    = V(ip1    ,jp1    ,k);
+
+Vn(:,:,:,17)    = V(ip1    ,jm1    ,kp1);
+Vn(:,:,:,18)    = V(ip1    ,j      ,kp1);
+Vn(:,:,:,19)    = V(ip1    ,jp1    ,kp1);
+
+%%
+% top
+Vn(:,:,:,20)    = V(i       ,jm1    ,kp1);
+Vn(:,:,:,21)    = V(i       ,j      ,kp1);
+Vn(:,:,:,22)    = V(i       ,jp1    ,kp1);
+
+%%
+% bottom
+Vn(:,:,:,23)    = V(i       ,jm1    ,km1);
+Vn(:,:,:,24)    = V(i       ,j      ,km1);
+Vn(:,:,:,25)    = V(i       ,jp1    ,km1);
+
+%%
+% front
+Vn(:,:,:,26)    = V(i       ,jp1    ,k);
+
+%%
+% back
+Vn(:,:,:,27)    = V(i       ,jm1    ,k);
+
+%%
+% perform the processing
+Vn = sort(Vn,4);
+Vr = Vn(:,:,:,ord);
+
+
+%%
+% remove padding on the 3 first dimensions
+Vr = Vr(2:end-1,2:end-1,2:end-1,:);
+
+
+
+
+
diff --git a/zUtil_Maths/rad2deg.m b/zUtil_Maths/rad2deg.m
new file mode 100755
index 0000000000000000000000000000000000000000..94b0cb249406826363545fe797c40fea84f745e7
--- /dev/null
+++ b/zUtil_Maths/rad2deg.m
@@ -0,0 +1,2 @@
+function deg=rad2deg(rad)
+deg=rad*180/pi;
diff --git a/zUtil_Maths/t2x.m b/zUtil_Maths/t2x.m
new file mode 100755
index 0000000000000000000000000000000000000000..ccf37e1691cf929e9bfba6913b93a002216fb557
--- /dev/null
+++ b/zUtil_Maths/t2x.m
@@ -0,0 +1,415 @@
+function x=t2x(T,str)
+
+% x=t2x(T,str);
+% 
+% Converts transformation matrix T between B and A coordinate
+% frames into a generalized position vector x, which contains
+% position and orientation vectors of B with respect to A.
+% Orientation can be expressed with quaternions, euler angles
+% (xyz or zxz convention), unit vector and rotation angle.
+% Also both orientation and position can be expressed with
+% Denavitt-Hartemberg parameters.
+% 
+% ---------------------------------------------------------------------------
+% 
+% The transformation matrix T between B and A coordinate
+% frames is a 4 by 4 matrix such that:
+% T(1:3,1:3) = Orientation matrix between B and A = unit vectors
+%              of x,y,z axes of B expressed in the A coordinates.
+% T(1:3,4)   = Origin of B expressed in A coordinates.
+% T(4,1:3)   = zeros(1,3)
+% T(4,4)     = 1
+%
+% ---------------------------------------------------------------------------
+% 
+% The generalized position vector x contains the origin of B
+% expressed in the A coordinates in the first four entries,
+% and orientation of B with respect to A in the last four entries.
+% In more detail, its shape depends on the value of str as 
+% specified below :
+% 
+% ---------------------------------------------------------------------------
+% 
+% str='van' : UNIT VECTOR AND ROTATION ANGLE 
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%           [ Vx ]     Vx,Vy,Vz = unit vector respect to A, 
+%  x(5:8) = [ Vy ]     which B is rotated about.
+%           [ Vz ]     
+%           [ Th ]     Th = angle which B is rotated (-pi,pi].
+% ---------------------------------------------------------------------------
+% 
+% str='qua' : UNIT QUATERNION 
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%           [ q1 ]     q1,q2,q3 = V*sin(Th/2)
+%  x(5:8) = [ q2 ]     q0 = cos(Th/2) where :
+%           [ q3 ]     V = unit vector respect to A, which B is 
+%           [ q0 ]     rotated about, Th = angle which B is rotated (-pi,pi].
+% ---------------------------------------------------------------------------
+% 
+% str='erp' : EULER-RODRIGUEZ PARAMETERS
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%           [ r1 ]     r1,r2,r3 = V*tan(Th/2), where :
+%  x(5:8) = [ r2 ]     V = unit vector with respect to A, which B is 
+%           [ r3 ]     rotated about.
+%           [  0 ]     Th = angle which B is rotated (-pi,pi) (<> pi).
+% ---------------------------------------------------------------------------
+% 
+% str='rpy' : ROLL, PITCH, YAW ANGLES (euler x-y-z convention) 
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%            [ r ]     r = roll angle  ( fi    (-pi,pi], about x,          )
+%  x(5:8) =  [ p ]     p = pitch angle ( theta (-pi,pi], about y, <> +-pi/2)
+%            [ y ]     y = yaw angle   ( psi   (-pi,pi], about z,          )
+%            [ 0 ]     
+% ---------------------------------------------------------------------------
+% 
+% str='rpm' : ROTATION, PRECESSION, MUTATION ANGLES (euler z-x-z convention) 
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%            [ r ]     r = rotation angle   ( (-pi,pi] ,about z           )
+%  x(5:8) =  [ p ]     p = precession angle ( (-pi,pi] ,about x , <> 0,pi )
+%            [ y ]     y = mutation angle   ( (-pi,pi] ,about z           )
+%            [ 0 ]     
+% ---------------------------------------------------------------------------
+% 
+% str='dht' : DENAVITT-HARTEMBERG PARAMETERS 
+% 
+%            [ b ]                [ a ]     this four-parameter 
+%  x(1:4) =  [ d ] ,   x(5:8) =   [ t ] ,   description does not involve
+%            [ 0 ]                [ 0 ]     a loss of information if and 
+%            [ 0 ]                [ 0 ]     only if T has this shape:
+% 
+%           [    ct   -st     0     b ]     where : 
+%  T =      [ ca*st ca*ct   -sa -d*sa ]     
+%           [ sa*st sa*ct    ca  d*ca ]     sa = sin(a), ca = cos(a)
+%           [     0     0     0     1 ]     st = sin(t), ct = cos(t)
+% ---------------------------------------------------------------------------
+% 
+% Example (see also x2t):
+% x=[rand(3,1);1;rand(3,1);0];x-t2x(x2t(x,'rpm'),'rpm')
+% 
+%
+% Giampiero Campa 1/11/96
+% 
+
+% ---------------------------------------------------------------------------
+% UNIT VECTOR AND ROTATION ANGLE 
+
+if [ str=='van' size(T)==[4 4] ],
+
+O=T(1:3,4);
+R=T(1:3,1:3);
+d=round(.5*(trace(R)-1)*1e12)/1e12;
+
+if d==1,
+   v=[0 0 1]';
+   th=0;
+
+elseif d==-1,
+    v0=sum(R'+eye(3,3))';
+
+    if v0 == 0 
+	 v0=R(:,2)+R(:,3)+[0 1 1]';
+    end;
+
+    if v0 == 0 
+	 v0=R(:,3)+[0 0 1]';
+    end;
+
+    v=v0/norm(v0);
+    th=pi;
+
+else 
+
+   sg=(vp([1 0 0]',R(:,1))+vp([0 1 0]',R(:,2))+vp([0 0 1]',R(:,3)));
+
+    if norm(sg) < 1e-12
+        disp(' ');
+        disp('T2x warning: det(R)<>1, unit vector assumed to be [0 0 1]''.');
+        disp(' ');
+        sg=[0 0 1]';
+    end
+
+   v=sg/norm(sg);
+   th=atan2(norm(sg)/2,d);
+
+end
+
+x=[O;1;v;th];
+
+% ---------------------------------------------------------------------------
+% UNIT QUATERNION 
+
+elseif [ str=='qua' size(T)==[4 4] ],
+
+O=T(1:3,4);
+R=T(1:3,1:3);
+d=round(.5*(trace(R)-1)*1e12)/1e12;
+
+if d==1,
+   v=[0 0 1]';
+   th=0;
+
+elseif d==-1,
+    v0=sum(R'+eye(3,3))';
+
+    if v0 == 0 
+	v0=R(:,2)+R(:,3)+[0 1 1]';
+    end;
+
+    if v0 == 0 
+	v0=R(:,3)+[0 0 1]';
+    end;
+
+    v=v0/norm(v0);
+    th=pi;
+
+else 
+
+   sg=(vp([1 0 0]',R(:,1))+vp([0 1 0]',R(:,2))+vp([0 0 1]',R(:,3)));
+
+    if norm(sg) < 1e-12
+        disp(' ');
+        disp('T2x warning: det(R)<>1, unit vector assumed to be [0 0 1]''.');
+        disp(' ');
+        sg=[0 0 1]';
+    end
+
+   v=sg/norm(sg);
+   th=atan2(norm(sg)/2,d);
+   
+end
+
+q=v*sin(th/2);
+q0=cos(th/2);
+
+x=[O;1;q;q0];
+
+% ---------------------------------------------------------------------------
+% EULER-RODRIGUEZ PARAMETERS
+
+elseif [ str=='erp' size(T)==[4 4] ],
+
+O=T(1:3,4);
+R=T(1:3,1:3);
+d=round(.5*(trace(R)-1)*1e12)/1e12;
+
+if d==1,
+   v=[0 0 1]';
+   th=0;
+
+elseif d==-1,
+    v0=sum(R'+eye(3,3))';
+
+    if v0 == 0 
+	v0=R(:,2)+R(:,3)+[0 1 1]';
+    end;
+
+    if v0 == 0 
+	v0=R(:,3)+[0 0 1]';
+    end;
+
+    v=v0/norm(v0);
+    th=pi;
+
+else 
+
+   sg=(vp([1 0 0]',R(:,1))+vp([0 1 0]',R(:,2))+vp([0 0 1]',R(:,3)));
+
+    if norm(sg) < 1e-12
+        disp(' ');
+        disp('T2x warning: det(R)<>1, unit vector assumed to be [0 0 1]''.');
+        disp(' ');
+        sg=[0 0 1]';
+    end
+
+   v=sg/norm(sg);
+   th=atan2(norm(sg)/2,d);
+   
+end
+
+p=v*tan(th/2);
+x=[O;1;p;0];
+
+% ---------------------------------------------------------------------------
+% ROLL, PITCH, YAW ANGLES (euler x-y-z convention) 
+
+elseif [ str=='rpy' size(T)==[4 4] ],
+
+O=T(1:3,4);
+R=T(1:3,1:3);
+d=round([0 0 1]*R(:,1)*1e12)/1e12;
+
+if d==1,
+   y=atan2([0 1 0]*R(:,2),[1 0 0]*R(:,2));
+   p=-pi/2;
+   r=-pi/2;
+
+elseif d==-1
+   y=atan2([0 1 0]*R(:,2),[1 0 0]*R(:,2));
+   p=pi/2;
+   r=pi/2;
+
+else 
+   sg=vp([0 0 1]',R(:,1));
+   j2=sg/sqrt(sg'*sg);
+   k2=vp(R(:,1),j2);
+
+   r=atan2(k2'*R(:,2),j2'*R(:,2));
+   p=atan2(-[0 0 1]*R(:,1),[0 0 1]*k2);
+   y=atan2(-[1 0 0]*j2,[0 1 0]*j2);
+end
+
+y1=y+(1-sign(y)-sign(y)^2)*pi;
+p1=p+(1-sign(p)-sign(p)^2)*pi;
+r1=r+(1-sign(r)-sign(r)^2)*pi;
+
+% takes smaller values of angles
+
+if norm([y1 p1 r1]) < norm([y p r])
+    x=[O;1;r1;-p1;y1;0];
+else
+    x=[O;1;r;p;y;0];
+end
+
+% ---------------------------------------------------------------------------
+% ROTATION, PRECESSION, MUTATION ANGLES (euler z-x-z convention) 
+
+elseif [ str=='rpm' size(T)==[4 4] ],
+
+O=T(1:3,4);
+R=T(1:3,1:3);
+d=round([0 0 1]*R(:,3)*1e12)/1e12;
+
+if d==1,
+   m=0;
+   p=0;
+   r=atan2([0 1 0]*R(:,1),[1 0 0]*R(:,1));
+
+elseif d==-1
+   m=0;
+   p=pi;
+   r=atan2([0 1 0]*R(:,1),[1 0 0]*R(:,1));
+
+else 
+   sg=vp([0 0 1]',R(:,3));
+   i2=sg/norm(sg);
+   j2=vp(R(:,3),i2);
+
+   m=atan2(j2'*R(:,1),i2'*R(:,1));
+   p=atan2([0 0 1]*j2,[0 0 1]*R(:,3));
+   r=atan2([0 1 0]*i2,[1 0 0]*i2);
+   
+end
+
+r1=r+(1-sign(r)-sign(r)^2)*pi;
+p1=p;
+m1=m+(1-sign(m)-sign(m)^2)*pi;
+
+% takes the smaller values of angles
+
+if norm([r1 p1 m1]) < norm([r p m])
+    x=[O;1;r1;-p1;m1;0];
+else
+    x=[O;1;r;p;m;0];
+end
+
+% ---------------------------------------------------------------------------
+% DENAVITT-HARTEMBERG PARAMETERS 
+
+elseif [ str=='dht' size(T)==[4 4] ],
+
+% b calculation
+b=T(1,4);
+
+% d calculation
+if norm(T(3,3)) > norm(T(2,3))
+    d=T(3,4)/T(3,3);
+else
+    d=T(2,4)/T(2,3);
+end
+
+% alfa and theta computation by mean of euler-zxz angles
+R=T(1:3,1:3);
+dl=round([0 0 1]*R(:,3)*1e12)/1e12;
+
+if dl==1,
+   th=0;
+   alfa=0;
+   n=atan2([0 1 0]*R(:,1),[1 0 0]*R(:,1));
+elseif dl==-1
+   th=0;
+   alfa=pi;
+   n=atan2([0 1 0]*R(:,1),[1 0 0]*R(:,1));
+else 
+   sg=vp([0 0 1]',R(:,3));
+   i2=sg/norm(sg);
+   j2=vp(R(:,3),i2);
+
+   th=atan2(j2'*R(:,1),i2'*R(:,1));
+   alfa=atan2([0 0 1]*j2,[0 0 1]*R(:,3));
+   n=atan2([0 1 0]*i2,[1 0 0]*i2);
+end
+
+th1=th+(1-sign(th)-sign(th)^2)*pi;
+alfa1=alfa;
+n1=n+(1-sign(n)-sign(n)^2)*pi;
+
+% takes the smaller values of angles
+
+if norm([th1 alfa1 n1]) < norm([th alfa n])
+   x=[b;d;0;0;-alfa1;th1;0;0];
+else
+   x=[b;d;0;0;alfa;th;0;0];
+end
+
+% ---------------------------------------------------------------------------
+% OTHER STRING
+
+else
+
+disp('   ');
+disp('   x=T2x(T,str)');
+disp('   where T is a 4 by 4 matrix (see help for details)');
+disp('   and str can be : ''van'',''qua'',''erp'',''rpy'',''rpm'',''dht''. ');
+disp('   ');
+
+end
+
+
+function z=vp(x,y)
+
+% z=vp(x,y); z = 3d cross product of x and y
+% vp(x) is the 3d cross product matrix : vp(x)*y=vp(x,y).
+%
+% by Giampiero Campa.  
+
+z=[  0    -x(3)   x(2);
+    x(3)    0    -x(1);
+   -x(2)   x(1)    0   ];
+
+if nargin>1, z=z*y; end
+
diff --git a/zUtil_Maths/x2t.m b/zUtil_Maths/x2t.m
new file mode 100755
index 0000000000000000000000000000000000000000..4278f547a5bac26e90177b8b29e0c7649dc38d95
--- /dev/null
+++ b/zUtil_Maths/x2t.m
@@ -0,0 +1,252 @@
+function T=x2t(x,str)
+
+% T=x2t(x,str)
+% 
+% Converts a generalized position vector x, which contains
+% position and orientation vectors of B with respect to A,
+% into transformation matrix T between B and A coordinate frames.
+% Orientation can be expressed with quaternions, euler angles
+% (xyz or zxz convention), unit vector and rotation angle.
+% Also both orientation and position can be expressed with
+% Denavitt-Hartemberg parameters.
+% 
+% ---------------------------------------------------------------------------
+% 
+% The transformation matrix T between B and A coordinate
+% frames is a 4 by 4 matrix such that:
+% T(1:3,1:3) = Orientation matrix between B and A = unit vectors
+%              of x,y,z axes of B expressed in the A coordinates.
+% T(1:3,4)   = Origin of B expressed in A coordinates.
+% T(4,1:3)   = zeros(1,3)
+% T(4,4)     = 1
+%
+% ---------------------------------------------------------------------------
+% 
+% The generalized position vector x contains the origin of B
+% expressed in the A coordinates in the first four entries,
+% and orientation of B with respect to A in the last four entries.
+% In more detail, its shape depends on the value of str as 
+% specified below :
+% 
+% ---------------------------------------------------------------------------
+% 
+% str='van' : UNIT VECTOR AND ROTATION ANGLE 
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%           [ Vx ]     Vx,Vy,Vz = unit vector respect to A, 
+%  x(5:8) = [ Vy ]     which B is rotated about.
+%           [ Vz ]     
+%           [ Th ]     Th = angle which B is rotated (-pi,pi].
+% ---------------------------------------------------------------------------
+% 
+% str='qua' : UNIT QUATERNION 
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%           [ q1 ]     q1,q2,q3 = V*sin(Th/2)
+%  x(5:8) = [ q2 ]     q0 = cos(Th/2) where :
+%           [ q3 ]     V = unit vector respect to A, which B is 
+%           [ q0 ]     rotated about, Th = angle which B is rotated (-pi,pi].
+% ---------------------------------------------------------------------------
+% 
+% str='erp' : EULER-RODRIGUEZ PARAMETERS
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%           [ r1 ]     r1,r2,r3 = V*tan(Th/2), where :
+%  x(5:8) = [ r2 ]     V = unit vector with respect to A, which B is 
+%           [ r3 ]     rotated about.
+%           [  0 ]     Th = angle which B is rotated (-pi,pi) (<> pi).
+% ---------------------------------------------------------------------------
+% 
+% str='rpy' : ROLL, PITCH, YAW ANGLES (euler x-y-z convention) 
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%            [ r ]     r = roll angle  ( fi    (-pi,pi], about x,          )
+%  x(5:8) =  [ p ]     p = pitch angle ( theta (-pi,pi], about y, <> +-pi/2)
+%            [ y ]     y = yaw angle   ( psi   (-pi,pi], about z,          )
+%            [ 0 ]     
+% ---------------------------------------------------------------------------
+% 
+% str='rpm' : ROTATION, PRECESSION, MUTATION ANGLES (euler z-x-z convention) 
+% 
+%           [ Ox ]     origin of the B coordinate frame    
+%  x(1:4) = [ Oy ]     with respect to A.
+%           [ Oz ]     
+%           [  1 ]     
+% 
+%            [ r ]     r = rotation angle   ( (-pi,pi] ,about z           )
+%  x(5:8) =  [ p ]     p = precession angle ( (-pi,pi] ,about x , <> 0,pi )
+%            [ y ]     y = mutation angle   ( (-pi,pi] ,about z           )
+%            [ 0 ]     
+% ---------------------------------------------------------------------------
+% 
+% str='dht' : DENAVITT-HARTEMBERG PARAMETERS 
+% 
+%            [ b ]                [ a ]     this four-parameter 
+%  x(1:4) =  [ d ] ,   x(5:8) =   [ t ] ,   description does not involve
+%            [ 0 ]                [ 0 ]     a loss of information if and 
+%            [ 0 ]                [ 0 ]     only if T has this shape:
+% 
+%           [    ct   -st     0     b ]     where : 
+%  T =      [ ca*st ca*ct   -sa -d*sa ]     
+%           [ sa*st sa*ct    ca  d*ca ]     sa = sin(a), ca = cos(a)
+%           [     0     0     0     1 ]     st = sin(t), ct = cos(t)
+% ---------------------------------------------------------------------------
+% 
+% Example (see also t2x):
+% x=[rand(3,1);1;rand(3,1);0];x-t2x(x2t(x,'rpm'),'rpm')
+% 
+% Giampiero Campa 1/11/96
+% 
+
+rnd=0;
+
+if [ str=='van' size(x)==[8 1] ],
+
+th=x(8);
+v=x(5:7);
+O=x(1:3);
+
+if norm(v) < 1e-10
+    disp(' ');
+    disp('x2T warning: zero lenght vector, direction assumed to be [0 0 1]''.');
+    disp(' ');
+    v=[0 0 1]';
+end
+
+v=v/norm(v);
+R=(cos(th)*eye(3,3)+(1-cos(th))*v*v'-sin(th)*vp(v))';
+
+% This was simpler but a little bit slower
+% R=expm(vp(v,th));
+
+T=[ R, O; 0 0 0 1 ];
+if rnd,T=round(T*1e14)/1e14;end
+
+% ---------------------------------------------------------------------------
+% UNIT QUATERNION 
+
+elseif [ str=='qua' size(x)==[8 1] ],
+
+q=x(5:8);
+O=x(1:3);
+
+if norm(q) < 1e-10
+    disp(' ');
+    disp('x2T warning: zero lenght vector, direction assumed to be [0 0 0 1]''.');
+    disp(' ');
+    q=[0 0 0 1]';
+end
+
+q=q/norm(q);
+
+qv=q(1:3);
+q0=q(4);
+
+R=((q0'*q0-qv'*qv)*eye(3,3)+2*(qv*qv'-q0*vp(qv)))';
+
+T=[ R, O; 0 0 0 1 ];
+if rnd,T=round(T*1e14)/1e14;end
+
+% ---------------------------------------------------------------------------
+% EULER-RODRIGUEZ PARAMETERS
+
+elseif [ str=='erp' size(x)==[8 1] ],
+
+r=x(5:7);
+O=x(1:3);
+
+S=vp(r);
+R=(eye(3,3)+2/(1+r'*r)*S*(S-eye(3,3)))';
+
+T=[ R, O; 0 0 0 1 ];
+if rnd,T=round(T*1e14)/1e14;end
+
+% ---------------------------------------------------------------------------
+% ROLL, PITCH, YAW ANGLES (euler x-y-z convention) 
+
+elseif [ str=='rpy' size(x)==[8 1] ],
+
+O=x(1:3);
+r=x(5);
+p=x(6);
+y=x(7);
+
+R=expm(vp([0 0 1]',y))*expm(vp([0 1 0]',p))*expm(vp([1 0 0]',r));
+
+T=[ R, O; 0 0 0 1 ];
+if rnd,T=round(T*1e14)/1e14;end
+
+% ---------------------------------------------------------------------------
+% ROTATION, PRECESSION, MUTATION ANGLES (euler z-x-z convention) 
+
+elseif [ str=='rpm' size(x)==[8 1] ],
+
+O=x(1:3);
+r=x(5);
+p=x(6);
+m=x(7);
+
+R=expm(vp([0 0 1]',r))*expm(vp([1 0 0]',p))*expm(vp([0 0 1]',m));
+
+T=[ R, O; 0 0 0 1 ];
+if rnd,T=round(T*1e14)/1e14;end
+
+% ---------------------------------------------------------------------------
+% DENAVITT-HARTEMBERG PARAMETERS 
+
+elseif [ str=='dht' size(x)==[8 1] ],
+
+ca=cos(x(5));
+sa=sin(x(5));
+ct=cos(x(6));
+st=sin(x(6));
+b=x(1);
+d=x(2);
+
+T=[    ct   -st   0     b
+    ca*st ca*ct -sa -d*sa
+    sa*st sa*ct  ca  d*ca
+        0     0   0     1];
+if rnd,T=round(T*1e14)/1e14;end
+
+% ---------------------------------------------------------------------------
+% OTHER STRING
+
+else
+
+disp('   ');
+disp('   T=x2T(x,str)');
+disp('   where x is an 8 by 1 vector (see help for details)');
+disp('   and str can be : ''van'',''qua'',''erp'',''rpy'',''rpm'',''dht''. ');
+disp('   ');
+
+end
+
+function z=vp(x,y)
+
+% z=vp(x,y); z = 3d cross product of x and y
+% vp(x) is the 3d cross product matrix : vp(x)*y=vp(x,y).
+%
+% by Giampiero Campa.  
+
+z=[  0    -x(3)   x(2);
+    x(3)    0    -x(1);
+   -x(2)   x(1)    0   ];
+
+if nargin>1, z=z*y; end
diff --git a/zUtil_Strain/TestRodriguesOp.m b/zUtil_Strain/TestRodriguesOp.m
new file mode 100755
index 0000000000000000000000000000000000000000..84725dd39029b59c1b26a1c110c174f00c49502c
--- /dev/null
+++ b/zUtil_Strain/TestRodriguesOp.m
@@ -0,0 +1,58 @@
+
+% Euler angles in degrees
+gamma=10
+beta=20
+alpha=30
+
+
+RG=[cosd(gamma) -sind(gamma) 0;
+    sind(gamma) cosd(gamma)  0;
+    0                      0 1]
+
+RB=[1 0 0;
+    0 cosd(beta) -sind(beta);
+    0 sind(beta) cosd(beta)]
+
+RA=[cosd(alpha) -sind(alpha) 0;
+    sind(alpha) cosd(alpha) 0;
+    0 0 1]
+
+% Rotation matrix
+RR=RG*RB*RA
+
+% {100} planes aligned with the reference
+v0=gtGetReflections([1 0 0])'
+hkl0=repmat([1 0 0],6,1)
+
+% Rotated {100] planes:
+vRR=RR*v0
+
+% R vector from rotated planes by the macro:
+[R_vector,rodr_goods]=plot_rodrigues_consistancy_test(vRR',hkl0,1)
+
+% Results
+disp(' ')
+disp('Input rotation matrix:')
+RR
+disp('Rotation matrix from Rodrigues vector:')
+Rg=Rod2g(R_vector)
+disp('Difference')
+Rg-RR
+
+% I.e. plot_rodrigues_consistancy_test and Rod2g together gives the 
+% transformation tensor from the lab into the crystal reference.
+
+% Fixing the sign problem in Rod2g gives the inverse of g:
+% mRg=myRod2g(R_vector)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Strain/grainorientations.m b/zUtil_Strain/grainorientations.m
new file mode 100755
index 0000000000000000000000000000000000000000..e89408b2e26d7f4e33ce78d6664c310ed3b2c5eb
--- /dev/null
+++ b/zUtil_Strain/grainorientations.m
@@ -0,0 +1,33 @@
+
+
+r1=gtAllGrainValues(grain,'R_vector',[],1);
+r2=gtAllGrainValues(grain,'R_vector',[],2);
+r3=gtAllGrainValues(grain,'R_vector',[],3);
+
+R=[];
+RR=[];
+
+
+for i=1:length(grain)
+RR=Rod2g([r1(i) r2(i) r3(i)]);
+R(i,:)=RR(:,1)';
+end
+
+Z=zeros(length(grain),1);
+
+figure
+quiver3(Z,Z,Z,R(:,1),R(:,2),R(:,3))
+
+axis equal
+
+
+figure
+hist(R(:,1))
+
+
+
+
+
+
+
+
diff --git a/zUtil_Strain/gtAddGrainLatticePar.m b/zUtil_Strain/gtAddGrainLatticePar.m
new file mode 100755
index 0000000000000000000000000000000000000000..0e473534daded88e2643289f3870f8215c383945
--- /dev/null
+++ b/zUtil_Strain/gtAddGrainLatticePar.m
@@ -0,0 +1,78 @@
+function [grainsout,allpla_mean,allpla_med]=gtAddGrainLatticePar(grainsinp,parameters)
+
+% Applies Bragg's law to each plane in the grain structure(s).
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+spacegroup=parameters.acq.spacegroup;
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy);   % in angstroms
+
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or a single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+allpla=[]; % will contain all plane normals
+
+for i=1:nof_grains
+  nof_pl=size(grains{i}.pl,1); % number of planes in grain
+
+	switch spacegroup
+	
+		case {225, 229}  % Cubic lattice
+		
+			% Factor to get interplanar distance from lattice parameter for each plane: d=a*v
+			for j=1:nof_pl
+				plv= 1/norm(grains{i}.hkl(j,:)); % dimensionless v
+				pld= lambda / (2*sind(grains{i}.theta(j))); % d in angstroms
+				pla= pld/plv ; % lattice parameter resulting from this measurement
+
+				%grain{i}.plv(j)=plv;
+				grains{i}.pld(j)=pld;
+				grains{i}.pla(j)=pla;
+
+				allpla=[allpla, pla];
+			end
+
+			% Same for unified planes
+			nof_unipl=size(grains{i}.uni.pl,1); % number of planes in grain
+
+			for j=1:nof_unipl
+				plv= 1/norm(grains{i}.uni.hkl(j,:));
+				pld= lambda / (2*sind(grains{i}.uni.theta(j))); % in angstroms
+				pla= pld/plv ;
+
+				%grain{i}.uni.plv(j)=plv;
+				grains{i}.uni.pld(j)=pld;
+				grains{i}.uni.pla(j)=pla;
+
+			end
+
+			
+			
+		otherwise
+			error('Only spacegroups 225,229 are recognised. Please, modify gtAddGrainLatticePar.')
+			
+	end
+	
+end
+
+allpla_mean=mean(allpla);
+allpla_med=median(allpla);
+
+% Handle cell arrays or a single one as output
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+end
diff --git a/zUtil_Strain/gtAddGrainLatticePar_sab.m b/zUtil_Strain/gtAddGrainLatticePar_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..0f0e6524f0bd6b128e16c555bd7bcb2c2a9b2361
--- /dev/null
+++ b/zUtil_Strain/gtAddGrainLatticePar_sab.m
@@ -0,0 +1,66 @@
+function [grainsout,allpla_mean,allpla_med]=gtAddGrainLatticePar(grainsinp,parameters)
+
+% Applies Bragg's law to each plane in the grain structure(s).
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+lambda=gtConvEnergyToWavelength(parameters.acq.energy);   % in angstroms
+
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or a single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+allpla=[]; % will contain all plane normals
+
+for i=1:nof_grains
+  nof_pl=size(grains{i}.pl,1); % number of planes in grain
+
+  % Factor to get interplanar distance from lattice parameter for each plane: d=a*v 
+  for j=1:nof_pl
+    plv= 1/norm(grains{i}.hkl(j,:)); % dimensionless v
+    pld= lambda / (2*sind(grains{i}.theta(j))); % d in angstroms
+    pla= pld/plv ; % lattice parameter resulting from this measurement
+    
+    %grain{i}.plv(j)=plv;
+    grains{i}.pld(j)=pld;
+    grains{i}.pla(j)=pla;
+    
+    allpla=[allpla, pla];
+  end
+ 
+  % Same for unified planes
+  if isfield(grains{i},'uni')
+  nof_unipl=size(grains{i}.uni.pl,1); % number of planes in grain
+  
+  for j=1:nof_unipl
+    plv= 1/norm(grains{i}.uni.hkl(j,:));
+    pld= lambda / (2*sind(grains{i}.uni.theta(j))); % in angstroms
+    pla= pld/plv ;
+    
+    %grain{i}.uni.plv(j)=plv;
+    grains{i}.uni.pld(j)=pld;
+    grains{i}.uni.pla(j)=pla;
+    
+  end
+  end 
+end
+
+allpla_mean=mean(allpla);
+allpla_med=median(allpla);
+
+% Handle cell arrays or a single one as output
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+end
diff --git a/zUtil_Strain/gtAllGrainValues.m b/zUtil_Strain/gtAllGrainValues.m
new file mode 100755
index 0000000000000000000000000000000000000000..254a448b3d1f51f70d531bb9238b2e3dd5068018
--- /dev/null
+++ b/zUtil_Strain/gtAllGrainValues.m
@@ -0,0 +1,43 @@
+function val=gtAllGrainValues(grain,par1,par2,co1,co2)
+
+% Gives a coloumn vector of the 'comp'-th component of a specified
+% parameter in all the grains.
+
+nof_grains=length(grain);
+
+if exist('co2','var')
+  scomp=false;
+else
+  scomp=true;
+end
+
+%val=zeros(nof_grains,length(comp));
+
+if isempty(par2)
+  if scomp
+    for i=1:nof_grains
+      tmp=grain{i}.(par1);
+      val(i,:)=tmp(co1);
+    end
+  else
+    for i=1:nof_grains
+      tmp=grain{i}.(par1);
+      val(i,:)=tmp(co1,co2);
+    end
+  end
+else
+  if scomp
+    for i=1:nof_grains
+      tmp=grain{i}.(par1).(par2);
+      val(i,:)=tmp(co1);
+    end
+  else
+    for i=1:nof_grains
+      tmp=grain{i}.(par1).(par2);
+      val(i,:)=tmp(co1,co2);
+    end
+  end
+end
+
+
+end
diff --git a/zUtil_Strain/gtDrawGrainCubes.m b/zUtil_Strain/gtDrawGrainCubes.m
new file mode 100755
index 0000000000000000000000000000000000000000..3d7458ccdee57cc732b05aeea28795663d727113
--- /dev/null
+++ b/zUtil_Strain/gtDrawGrainCubes.m
@@ -0,0 +1,116 @@
+% function gtDrawGrainCubes(grains,sample,numbered,hlight,noaxis)
+%
+% Draws a figure representing grain size and orientation by cubes 
+% (unit cells in a cubic lattice) based on the Rodrigues vectors in the
+% grain variable output from indexing.
+%
+% USAGE  gtDrawGrainCubes(grains,sample)
+%        gtDrawGrainCubes(grains([1:10]),sample,1,[1,3,5],1)  
+%
+% INPUT  grains:   grain structure from indexing
+%        sample:   parameters and definition of the sample reference system  
+%                   (sample=gtSampleGeoInSampleSystem)
+%        numbered: if true, grain id-s are shown
+%        hlight:   ID-s of grains to be highlighted
+%        noaxis:   if true, axes and beam direction are not shown
+%
+
+
+function gtDrawGrainCubes(grains,sample,numbered,hlight,noaxis)
+
+
+if ~exist('hlight','var')
+  hlight=[];
+end
+if ~exist('numbered','var')
+  numbered=[];
+end
+if ~exist('noaxis','var')
+  noaxis=false;
+end
+
+nof_grains=length(grains);
+
+figure
+view(3);
+
+axhor=10*floor((sample.rad+30)/10);
+axver=10*floor((max(sample.top,sample.bot)+50)/10);
+
+axis([-axhor axhor -axhor axhor -axver axver])
+axis equal;
+hold on
+
+if ~noaxis
+	xlabel('X')
+	ylabel('Y')
+	zlabel('Z')
+	plot3([-axhor axhor],[0 0],[0 0],'r-','Linewidth',2)
+end
+
+if noaxis
+	set(gca,'xtick',[],'xcolor','w')
+	set(gca,'ytick',[],'ycolor','w')
+	set(gca,'ztick',[],'zcolor','w')
+end
+
+t=1:360;
+circx=cosd(t)*sample.rad;
+circy=sind(t)*sample.rad;
+circbotz(1:360)=sample.bot;
+circtopz(1:360)=sample.top;
+plot3(circx,circy,circbotz,'k-','Linewidth',1)
+plot3(circx,circy,circtopz,'k-','Linewidth',1)
+plot3([0 0],[0 0],[sample.bot sample.top],'k.-.','Linewidth',1)
+plot3([-sample.rad -sample.rad],[0 0],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([0 0],[-sample.rad -sample.rad],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([sample.rad sample.rad],[0 0],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([0 0],[sample.rad sample.rad],[sample.bot sample.top],'k.-','Linewidth',1)
+
+
+cube_vertices=[0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1]-0.5*repmat([1 1 1],8,1);
+cube_faces=[2 3 7 6; 4 1 5 8; 1 2 6 5;  3 4 8 7;  5 6 7 8; 1 2 3 4];
+% directions: +yz      -yz      -xz       +xz       +xy      -xy       
+
+
+for i=1:nof_grains
+	if ismember(i,hlight)
+		hl=1;
+	else
+		hl=false;
+	end
+	sfPlotGrainCube(grains{i},cube_vertices,cube_faces,hl)
+	if numbered
+		text(grains{i}.center(1),-axhor,grains{i}.center(3),num2str(i),'Color','c')
+		text(axhor,grains{i}.center(2),grains{i}.center(3),num2str(i),'Color','c')
+	end
+end
+
+end
+
+
+    
+function sfPlotGrainCube(grain,cube_vertices,cube_faces,hl)
+
+ga=grain.stat.bbysmean/2;
+gc=grain.center;
+
+ggrain=Rod2g(grain.R_vector);
+grain_vertices=repmat(gc,8,1)+ga*cube_vertices*ggrain';
+
+if hl
+	facecolors=cool(8);
+	facecolors=facecolors(end-5:end,:);
+else
+	facecolors=copper(12);
+	facecolors=facecolors(end-1-5:end-1,:);
+	%facecolors=gray(12);
+	%facecolors=facecolors(end-1-5:end-1,:);
+end
+
+patch('Vertices',grain_vertices,'Faces',cube_faces,...
+	'FaceVertexCData',facecolors,'FaceColor','flat');
+      
+end
+
+
diff --git a/zUtil_Strain/gtEstimateErrors.m b/zUtil_Strain/gtEstimateErrors.m
new file mode 100755
index 0000000000000000000000000000000000000000..97bfbe82b15d91f0ee5f021cc7c504bb2762732c
--- /dev/null
+++ b/zUtil_Strain/gtEstimateErrors.m
@@ -0,0 +1,190 @@
+% FUNCTION [angprec_hor,angprec_ver]=gtEstimateAngularPrecision
+% 
+% Estimates the average angular precision in the whole scan, based on plane
+% normals that were detected twice (2 pairs, 2x2 difspots). It looks in all
+% the grains.
+%
+
+function errest=gtEstimateErrors(grainsinp)
+
+load parameters.mat
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or a single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+dang=[]; % will contain all the angular discrepancies
+daz=[]; % will contain all the azimuth
+dazd=[];
+errver_pix=[]; % 
+errvernorm=[]; % all the vertical coordinate discrepancies
+errhor_pix=[]; % 
+errhornorm=[]; % all the horizontal coordinate discrepancies
+ddfrometa=[];
+dnz=[];
+dtheta=[];
+deta=[];
+dom=[];
+%omfactor=[];
+thetatype=[];
+theta=[];
+eta=[];
+etaq=[];
+%pla=[];
+
+ddy=[];
+%ddy_az=[];
+ddz=[];
+
+% Loop through grains
+for i=1:nof_grains
+  
+  % Loop through unique planes and fetch the errors
+  for j=1:size(grains{i}.uni.plid,1)
+    if ~isnan(grains{i}.uni.ddy(j)) % those that have been detected twice
+      ddy=[ddy; grains{i}.uni.ddy(j)];
+      %ddy_az=[ddy_az; grains{i}.uni.ddy_az(j)];
+      ddz=[ddz; grains{i}.uni.ddz(j)];
+      dom=[dom; grains{i}.uni.dom(j)];
+      
+      dang=[dang; grains{i}.uni.dang(j)];
+      daz=[daz; grains{i}.uni.daz(j)];
+      dazd=[dazd; grains{i}.uni.dazd(j)];
+      errvernorm=[errvernorm; grains{i}.uni.errvernorm(j)];
+      errver_pix=[errver_pix; grains{i}.uni.errvernorm(j)*2*parameters.acq.dist/parameters.acq.pixelsize];
+      errhornorm=[errhornorm; grains{i}.uni.errhornorm(j)];
+      errhor_pix=[errhor_pix; grains{i}.uni.errhornorm(j)*2*parameters.acq.dist/parameters.acq.pixelsize];
+      ddfrometa=[ddfrometa; grains{i}.uni.ddfrometa(j)];
+      dnz=[dnz; grains{i}.uni.dn(j,3)];
+
+      dtheta=[dtheta; grains{i}.uni.dtheta(j)];
+      deta=[deta; grains{i}.uni.deta(j)];
+      %omfactor=[omfactor; grains{i}.uni.omfactor(j)];
+
+      thetatype=[thetatype; grains{i}.uni.thetatype(j)];
+      theta=[theta; grains{i}.uni.theta(j)];
+      eta=[eta; grains{i}.uni.eta(j)];
+      etaq=[etaq; grains{i}.uni.etaq(j)];
+      %pla=[pla; grains{i}.uni.pla(j)];
+    end
+  end
+
+end % of grain
+
+% Average errors of all
+load parameters.mat
+
+errest.std_dy=mean(abs(ddy))/sqrt(2);
+%errest.std_dy_az=mean(sqrt(2)*ddy_az);
+errest.std_dz=mean(abs(ddz))/sqrt(2);
+
+%errest.std_om=sqrt(mean(errest.std_dy^2-errest.std_dz^2)/2);
+errest.std_om=mean(abs(dom))/sqrt(2);
+
+errest.std_ddfrometa=mean(abs(ddfrometa))/sqrt(2);
+
+errest.std_errvernorm=mean(abs(errvernorm))/sqrt(2);
+errest.std_errver_pix=mean(abs(errver_pix))/sqrt(2);
+errest.std_errhornorm=mean(abs(errhornorm))/sqrt(2);
+errest.std_errhor_pix=mean(abs(errhor_pix))/sqrt(2);
+
+
+errest.std_ang=mean(abs(dang))/sqrt(2);
+errest.std_az=mean(abs(daz))/sqrt(2);
+errest.std_azd=mean(abs(dazd))/sqrt(2);
+errest.std_theta=mean(abs(dtheta))/sqrt(2);
+errest.std_eta=mean(abs(deta))/sqrt(2);
+
+errest.std_om_deg=rad2deg(errest.std_om);
+errest.std_ang_deg=rad2deg(errest.std_ang);
+errest.std_az_deg=rad2deg(errest.std_az);
+errest.std_azd_deg=rad2deg(errest.std_azd);
+errest.std_theta_deg=rad2deg(errest.std_theta);
+errest.std_eta_deg=rad2deg(errest.std_eta);
+
+% Error for each thetatype
+for j=1:max(thetatype)
+%   N=sum(thetatype==j);
+%   errest.std_dang_tht(j)=sqrt(sum((dang(thetatype==j)/2).^2)/N);
+%   errest.std_danghor_tht(j)=sqrt(sum((danghor(thetatype==j)/2).^2)/N);
+%   errest.std_pixerrvernorm_tht(j)=sqrt(sum((pixerrvernorm(thetatype==j)/2).^2)/N);
+%   errest.std_ddfrometa_tht(j)=sqrt(sum((ddfrometa(thetatype==j)/2).^2)/N);
+%   errest.std_dtheta_tht(j)=sqrt(sum((dtheta(thetatype==j)/2).^2)/N);
+%   errest.std_deta_tht(j)=sqrt(sum((deta(thetatype==j)/2).^2)/N);
+
+  %errest.std_pixerrvernorm_thetat(j)=mean(pixerrvernorm(thetatype==j))/2;
+  
+  
+  errest.std_dy_thetat(j)=mean(abs(ddy(thetatype==j)))/sqrt(2);
+ % errest.std_dy_az_thetat(j)=mean(sqrt(2)*ddy_az(thetatype==j));
+  errest.std_dz_thetat(j)=mean(abs(ddz(thetatype==j)))/sqrt(2);
+  errest.std_om_thetat(j)=mean(abs(dom(thetatype==j)))/sqrt(2);
+   
+  errest.std_ddfrometa_thetat(j)=mean(abs(ddfrometa(thetatype==j)))/sqrt(2);
+
+  %errest.std_om_thetat(j)=sqrt(mean(ddy(thetatype==j).^2-ddz(thetatype==j).^2)/2);
+  
+  errest.std_errvernorm_thetat(j)=mean(abs(errvernorm(thetatype==j)))/sqrt(2);
+  errest.std_errver_pix_thetat(j)=mean(abs(errver_pix(thetatype==j)))/sqrt(2);
+  errest.std_errhornorm_thetat(j)=mean(abs(errhornorm(thetatype==j)))/sqrt(2);
+  errest.std_errhor_pix_thetat(j)=mean(abs(errhor_pix(thetatype==j)))/sqrt(2);
+  
+  errest.std_nz_thetat(j)=mean(abs(dnz(thetatype==j)))/sqrt(2);
+  errest.std_ang_thetat(j)=mean(abs(dang(thetatype==j)))/sqrt(2);
+  errest.std_az_thetat(j)=mean(abs(daz(thetatype==j)))/sqrt(2);
+  errest.std_azd_thetat(j)=mean(abs(dazd(thetatype==j)))/sqrt(2);
+  errest.std_theta_thetat(j)=mean(abs(dtheta(thetatype==j)))/sqrt(2);
+  errest.std_eta_thetat(j)=mean(abs(deta(thetatype==j)))/sqrt(2);
+  
+  %errest.std_om_thetat(j)=sqrt(errest.std_anghor_thetat(j)^2-mean(omfactor(thetatype==j))*errest.std_pixerrvernorm_thetat(j)^2);
+
+  errest.nofinput_thetat(j)=sum(thetatype==j);
+
+end
+
+% Store data
+errest.data.ddy=ddy;
+%errest.data.ddy_az=ddy_az;
+errest.data.ddz=ddz;
+errest.data.dom=dom;
+
+errest.data.ddfrometa=ddfrometa;
+
+errest.data.errvernorm=errvernorm;
+errest.data.errver_pix=errver_pix;
+errest.data.errhornorm=errhornorm;
+errest.data.errhor_pix=errhor_pix;
+
+errest.data.dang=dang;
+errest.data.daz=daz;
+errest.data.dazd=dazd;
+
+%errest.data.pixerrvernorm=pixerrvernorm;
+errest.data.dtheta=dtheta;
+errest.data.deta=deta;
+%errest.data.omfactor=omfactor;
+errest.data.thetatype=thetatype;
+errest.data.theta=theta;
+errest.data.eta=eta;
+errest.data.etaq=etaq;
+%errest.data.pla=pla;
+
+
+end % of function
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Strain/gtGeoSim.m b/zUtil_Strain/gtGeoSim.m
new file mode 100755
index 0000000000000000000000000000000000000000..3a807c604a0f7c23de5068271cf10b948d841707
--- /dev/null
+++ b/zUtil_Strain/gtGeoSim.m
@@ -0,0 +1,163 @@
+% FUNCTION gtGeoSim(rtiltY,rtiltZ,astiltY,astiltZ,hordist,thetatype,rottodet_r,parameters)
+%
+% Tilt simulator to see possible effects from scintilator tilts on 
+% diffraction spot pairs. Shows the result what gtMatchDifspots would give.
+%
+% X,Y,Z are the lab coordinates.
+%
+% INPUT
+%
+%   rtiltY:     real tilt around Y' (i.e. Y turned around Z by tiltZ)
+%   rtiltZ:     real tilt around Z (in degrees)
+%   astiltY:    assumed tilt around Y'
+%   astiltZ:    assumed tilt around Z
+%
+%  Optional
+%   hordist:    horizontal distortion in images (stretch relative to vertical)
+%   thetatype:  which plane families to show (1,[2 3],...)
+%   rottodet_r: real rotation-axis to detector distance (in mm)
+%   parameters: assumed rotx,rottodet,pixelsize,(thetas) are taken from
+%               here
+%
+
+function gtGeoSim(rtiltY,rtiltZ,astiltY,astiltZ,hordist,thetatype,rottodet_r,parameters)
+
+if ~exist('parameters','var')
+  load parameters.mat
+end
+
+if ~exist('hordist','var')
+  hordist=1;
+end
+
+if ~exist('thetatype','var')
+  thetatype=1;
+end
+
+[tmp,results]=gtnew_calculate_twotheta ;
+valid_2thetas=results.centre ; % coloumn vector of all valid 2theta angles in degrees
+
+rottodet_as=parameters.acq.dist/parameters.acq.pixelsize;
+rotx=parameters.acq.rotx;
+
+if ~exist('rottodet_r','var')
+  rottodet_r=rottodet_as;
+else
+  rottodet_r=rottodet_r/parameters.acq.pixelsize;
+end
+
+% Set sample coordinate system
+% sorX = on the rotation axis by definition 
+% sorY = on the rotation axis by definition
+sorZ=parameters.acq.ydet/2+0.5;
+
+eta=(0:1:360)';
+
+%figure
+ hold on
+ xlabel('theta (deg)') ;
+ ylabel('eta (deg)') ;
+ title('eta - theta') ;
+
+ 
+for i=1:length(thetatype)
+  theta=valid_2thetas(thetatype(i))/2;
+
+  % Generate fictitious data:
+  
+  [x1,y1,z1]=line_plane_sect(eta,rottodet_r,theta,rtiltZ,rtiltY);
+  [x2,y2,z2]=line_plane_sect(180-eta,rottodet_r,theta,rtiltZ,rtiltY);
+
+  plotrange=max(abs([y1;y2;z1;z2]));
+  
+  % unit vectors of image in the lab system:
+  imj=[-sind(rtiltY)*cosd(rtiltZ) -sind(rtiltY)*sind(rtiltZ) -cosd(rtiltY)]/hordist;
+  imi=[-sind(rtiltZ) cosd(rtiltZ) 0];
+
+  centXimA=[x1-rottodet_r y1 z1]*imi'+rotx;
+  centYimA=[x1-rottodet_r y1 z1]*imj'+sorZ;
+  centXimB=[x2-rottodet_r y2 z2]*imi'+rotx;
+  centYimB=[x2-rottodet_r y2 z2]*imj'+sorZ;
+
+  
+  % Detected data:
+
+  theta_s=gtThetaOfPairs(centXimA,centYimA,centXimB,centYimB,rottodet_as,astiltY,astiltZ,rotx,sorZ);
+
+  eta_s=gtEtaOfPairs(centXimA,centYimA,centXimB,centYimB,astiltY,astiltZ,rotx,sorZ);
+
+  plot(theta_s,eta_s,'.r','MarkerSize',6);
+  plot([theta theta],[0 360],'-.k','LineWidth',1);
+
+end  
+
+
+%For checking
+%dvec_s=gtDiffVecInLab(centXimA,centYimA,centXimB,centYimB,rottodet_as,astiltY,astiltZ,rotx,sorZ);
+%dvec_c=[x1+x2 y1+y2 z1-z2]./repmat(sqrt((x1+x2).^2+(y1+y2).^2+(z2-z1).^2),1,3);
+% eta_s2=gtEtaOfPoint(dvec_s(:,2),dvec_s(:,3));
+% eta_c=gtEtaOfPoint(dvec_c(:,2),dvec_c(:,3));
+%
+% [dvec_s dvec_c]
+% [eta_s eta_s2 eta_c]
+
+% figure
+%   hold on
+%   plot(centXimA,centYimA,'b.')
+%   plot(centXimB,centYimB,'ro')
+% 
+%   plot([rotx rotx],[sorZ-plotrange sorZ+plotrange],'k.-.')
+%   plot([rotx-plotrange rotx+plotrange],[sorZ sorZ],'k.--')
+%   axis equal
+%   set(gca,'YDir','reverse')
+% 
+ 
+  
+end % of function
+
+
+%% Sub-functions
+
+
+function [z1,z2]=cone_plane_sectZ(y,r,theta,rtiltZ,rtiltY)
+  % r = real rottodet
+  nx=-cosd(rtiltY).*cosd(rtiltZ);
+  ny=-cosd(rtiltY).*sind(rtiltZ);
+  nz=sind(rtiltY);
+
+  a=nx^2./tand(2*theta)-nz.^2;
+  b=2*nx*ny*y-2*nx*r*nz;
+  c=ny^2*y.^2+nx^2*r^2-2*ny*nx*r*y-nx^2/tand(2*theta)*y^2;
+
+  z1=(-b+sqrt(b.^2-4.*a.*c))/2/a;
+  z2=(-b-sqrt(b.^2-4.*a.*c))/2/a;
+end
+
+
+function [x,y,z]=line_plane_sect(eta,r,theta,rtiltZ,rtiltY)
+  % r = real rottodet
+  nx=-cosd(rtiltY).*cosd(rtiltZ);
+  ny=-cosd(rtiltY).*sind(rtiltZ);
+  nz=sind(rtiltY);
+
+  x=zeros(size(eta));
+  y=zeros(size(eta));
+  z=zeros(size(eta));
+  
+  for i=1:length(eta)
+    % 3 equations for X Y Z
+    A=[-tand(2*theta)*sind(eta(i)) 1 0; ...  % diffraction line y-x
+      -tand(2*theta)*cosd(eta(i)) 0 1; ... % diffraction line z-x
+      nx ny nz];                          % plane
+
+    B=[0; 0; nx*r];
+
+    C=A\B;
+
+    x(i,1)=C(1);
+    y(i,1)=C(2);
+    z(i,1)=C(3);
+  end
+  
+end
+
diff --git a/zUtil_Strain/gtINUniquePlaneNormals.m b/zUtil_Strain/gtINUniquePlaneNormals.m
new file mode 100755
index 0000000000000000000000000000000000000000..ca5f2c8ec1772322b79dbc2b5a4d3d46affc897f
--- /dev/null
+++ b/zUtil_Strain/gtINUniquePlaneNormals.m
@@ -0,0 +1,390 @@
+function grainsout=gtINUniquePlaneNormals(grainsinp,ACM)
+
+if ~exist('ACM','var')
+  load parameters.mat
+  ACM=gtAngConsMat(parameters.acq.spacegroup);
+end
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+% Loop through grains
+for i=1:nof_grains
+  nof_pl=size(grains{i}.pl,1);
+
+  % Load grain info into 'remaining' (these remain to be dealt with)
+  remainingl.pl=grains{i}.pl;
+  remainingl.thetatype=grains{i}.thetatype;
+  remainingl.theta=grains{i}.theta;
+  remainingl.eta=grains{i}.eta;
+  remainingl.hkl=grains{i}.hkl;
+  remainingl.omega=grains{i}.omega;
+
+  remainings=1:nof_pl; % ; modif sabine
+
+  nof_unipl=0;
+
+  grains{i}.uni.nof_unipl=NaN;
+  grains{i}.uni.nof_dbpl=NaN;
+
+  % Process all the planes in the grain
+  while length(remainings)>=1
+
+    nof_unipl=nof_unipl+1;
+
+    merge=1;
+
+    % Take the first in remaining and compare with all other remaining,
+    % look for possible identical planes.
+    for j=2:length(remainings)
+      if remainingl.thetatype(1)==remainingl.thetatype(j)
+        ACV=ACM{remainingl.thetatype(1),remainingl.thetatype(j)};
+        ang=gt2PlanesAngle(remainingl.pl(1,:),remainingl.pl(j,:));
+        [minval,minloc]=min(abs(ACV-ang));
+
+        if ACV(minloc)==0 % the same planes
+          merge=[merge, j];
+        end
+      end
+    end
+
+    % Merge identical planes, its new direction is the mean of the constituting
+    %  planes.
+
+    if length(merge)>1
+      % here, it's assumed that merge=2 always
+      % in case of wrong indexing merge might be >2
+      if length(merge)>2
+        disp(sprintf('Warning! Indexing error in grain %d, dubious plane normals are:',i))
+        disp(remainings(merge))
+      end
+
+      % sign: if spl=-1 they are of opposite direction
+     
+      spl=sign(remainingl.pl(merge(2),:)*remainingl.pl(merge(1),:)'); % direction same or opposite
+      spl=repmat(spl,1,3);
+
+      n1=remainingl.pl(merge(1),:);
+      n2=remainingl.pl(merge(2),:).*spl;
+
+      unipl=(n1+n2)/2;
+      
+      theta1=remainingl.theta(merge(1)); % in degrees
+      theta2=remainingl.theta(merge(2));
+      
+      eta1=remainingl.eta(merge(1)); % in degrees
+      eta2=remainingl.eta(merge(2));
+
+      omega1=remainingl.omega(merge(1)); % in degrees
+      omega2=remainingl.omega(merge(2));
+
+      % Average eta,theta and their error
+      unieta1=eta1;  
+      if spl(1)<0
+        unieta2=mod((eta2+180),360);
+      else
+        unieta2=360-eta2;
+      end
+      unieta=(unieta1+unieta2)/2;
+      deta_deg=unieta1-unieta2;
+      deta=deg2rad(deta_deg);
+      
+      unitheta=(theta1+theta2)/2;
+      dtheta_deg=theta1-theta2;
+      dtheta=deg2rad(dtheta_deg);
+      
+      % Error in the plane normal coordinates
+      dn=n1-n2;
+      nn=n1*n2';
+      
+      dang_deg=acosd(nn); % angle between the two normals
+      dang=acos(nn);
+ 
+      nnhor=n1(1:2)*n2(1:2)'/norm(n1(1:2))/norm(n2(1:2));
+      %dazhd_deg=acosd(nnhor); % azimuth
+      %dazh=acos(nnhor);    
+      
+      % Azimuth
+      az1=atan2(n1(2),n1(1)); % in rad
+      az2=atan2(n2(2),n2(1)); % in rad
+      
+      if az1<0
+        az1=az1+2*pi; % set between 0..2pi
+      end
+      
+      if az2<0
+        az2=az2+2*pi; % set between 0..2pi
+      end
+     
+      % Corner case around 0 deg (X axis)
+      if az1-az2<-pi
+        az1=az1+2*pi;
+      elseif az1-az2>pi
+        az2=az2+2*pi;
+      end
+      
+      uniaz=(az1+az2)/2;
+      daz=az1-az2; % error in azimuth in rad
+      daz_deg=rad2deg(daz); % in deg
+      
+      dy1=sind(2*theta1)*sind(eta1);
+      dz1=sind(2*theta1)*cosd(eta1);
+
+      dy2=sind(2*theta2)*sind(eta2); % should be around -dy1
+      dz2=sind(2*theta2)*cosd(eta2);
+
+      if dy1*dy2>0
+        disp(' Warning! dy1*dy2>0 ')
+        disp(sprintf('   Possible indexing error in grain %d ',i))
+        %keyboard
+      end
+      
+%       azd1=-atan(dy1/2/sind(theta1)^2); % azimuth term from the diffr. condition dy,dz 
+%       azd2o=-atan(dy2/2/sind(theta2)^2);
+%       azd2=azd2o;
+      
+      if spl(1)<0
+        %azd2=azd2+pi;     % if n2 opposite to n1, n2 should be turned 180 degrees
+        dz=(dz1-dz2)/2;   % average dz
+        ddz=dz1+dz2;      % error in dz
+      else
+        dz=(dz1+dz2)/2;
+        ddz=dz1-dz2;
+      end
+      
+      dy=(dy1-dy2)/2; % !!!  average dy
+      ddy=dy1+dy2;    % error in dy
+
+%       dazd=azd1+azd2o; % !!!
+%       
+%       azd1_deg=rad2deg(azd1)
+%       azd2o_deg=rad2deg(azd2o)
+%       azd2_deg=rad2deg(azd2)
+%       dazd_deg=rad2deg(dazd)
+%       
+%       az1c_deg=mod(180+azd1_deg+omega1,360)
+%       az2c_deg=mod(180+azd2_deg+omega2,360)
+%       dazc_deg=az1c_deg-az2c_deg
+%       daz_deg
+%             
+%       dom_deg=dazc_deg-dazd_deg
+%       dom_deg=daz_deg-dazd_deg
+      
+     
+%       % Derivatives      
+%       dth_ddy=1/2*sind(unieta)/cosd(2*unitheta);
+%       dth_ddz=1/2*cosd(unieta)/cosd(2*unitheta);
+%       
+%       term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+%       term2=1/2*(1/sind(unitheta)^2-2*dy*cosd(unitheta)/sind(unitheta)^3*dth_ddy);
+%       daz_ddy=term1*term2;
+%       
+%       term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+%       term2=-dy*cosd(unitheta)/sind(unitheta)^3*dth_ddz;
+%       daz_ddz=term1*term2;
+%       
+%       % Error in azimuth from dy,dz:
+%       dazd=daz_ddy*ddy+daz_ddz*ddz;
+%       dazd_deg=rad2deg(dazd); % in deg
+%      
+%       % Error in azimuth from omega
+%       domega=daz-dazd;
+%       domega_deg=rad2deg(domega); % in deg
+    
+
+      
+      
+      errvernorm=abs(ddz/cosd(2*unitheta)/sqrt(2)); % vertical detection error normalized
+                                                    % by sp/(2r)     
+      errhornorm=abs(ddy/cosd(2*unitheta)/sqrt(2)); % horizontal detection error normalized
+                                                    % by sp/(2r)     
+     
+      %pixerrvernorm=abs(dn(3)*2*sind(unitheta)/cosd(2*unitheta));
+      ddfrometa=deta*2*sind(unitheta);  %/cosd(2*unitheta);
+      %omfactor=(1/(1+(sind(2*unitheta)*sind(unieta)/(2*sind(unitheta)^2))^2)/...
+      %         (2*sind(unitheta)^2))^2*cosd(2*unitheta)^2;
+      
+    else % if length(merge)<=1
+      unipl=remainingl.pl(1,:);
+      unitheta=remainingl.theta(1);
+      unieta=remainingl.eta(1); % in degrees
+      
+      % Azimuth
+      uniaz=atan2(unipl(2),unipl(1)); % in rad
+      if uniaz<0
+        uniaz=uniaz+2*pi; % set between 0..2pi
+      end
+      
+      dy=sind(2*unitheta)*sind(unieta);
+      dz=sind(2*unitheta)*cosd(unieta);
+
+      % Discrepancy: not known
+      dn=NaN(1,3);
+      nn=NaN;
+      ddy=NaN;
+      ddz=NaN;
+
+      errvernorm=NaN;
+      errhornorm=NaN;
+      %pixerrvernorm=NaN;
+      ddfrometa=NaN;
+      dang=NaN;
+      dang_deg=NaN;
+      daz_deg=NaN;
+      dtheta_deg=NaN;
+      deta_deg=NaN;
+            
+      nnhor=NaN;
+      daz=NaN;
+      dtheta=NaN;
+      deta=NaN;
+      %omfactor=NaN;
+    end
+
+
+    % Eta in first quadrant (between 0..90deg)
+     %  Set eta between 0<eta<180
+    if unieta>180
+      etaq=360-unieta; % in degrees
+    else
+      etaq=unieta; % in degrees
+    end
+
+     %  Set eta between 0<eta<90
+    if etaq>90
+      etaq=180-etaq;
+    end
+
+   
+    % Derivatives
+    dth_ddy=1/2*sind(unieta)/cosd(2*unitheta);
+    dth_ddz=1/2*cosd(unieta)/cosd(2*unitheta);
+ 
+    deta_ddy=cosd(unieta)/sind(2*unitheta);
+    deta_ddz=-sind(unieta)/sind(2*unitheta);
+
+    dnz_ddy=-dz/2*cosd(unitheta)/sind(unitheta)^2*dth_ddy;
+    dnz_ddz=1/2/sind(unitheta)-dz*cosd(unitheta)/2/sind(unitheta)^2*dth_ddz;
+
+    % azimuth
+    term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+    term2=1/2*(1/sind(unitheta)^2-2*dy*cosd(unitheta)/sind(unitheta)^3*dth_ddy);
+    daz_ddy=term1*term2;
+
+    term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+    term2=-dy*cosd(unitheta)/sind(unitheta)^3*dth_ddz;
+    daz_ddz=term1*term2;
+
+    % Error in azimuth from dy,dz:
+    dazd=daz_ddy*ddy+daz_ddz*ddz;
+    dazd_deg=rad2deg(dazd); % in deg
+
+    % Error in azimuth from omega
+    dom=daz-dazd;
+    dom_deg=rad2deg(dom); % in deg
+    
+    if isnan(dom_deg)
+      uniomega=omega1; % no correction 
+    else
+      uniomega=omega1-dom_deg/2; % double detection; corrected by half the difference
+    end
+    
+    % Save unique planes under grains.uni 
+    grains{i}.uni.plid(nof_unipl,:)=false(1,nof_pl);
+    grains{i}.uni.plid(nof_unipl,remainings(merge))=true; % which pair-lines are used
+    
+    % Coordinates
+    grains{i}.uni.pl(nof_unipl,:)=unipl;
+    grains{i}.uni.thetatype(nof_unipl)=remainingl.thetatype(1);
+    grains{i}.uni.hkl(nof_unipl,:)=remainingl.hkl(1,:);
+    %grains{i}.uni.pla(nof_unipl)=NaN;
+    
+    grains{i}.uni.theta(nof_unipl)=unitheta; % in deg
+    grains{i}.uni.eta(nof_unipl)=unieta; % in deg 
+    grains{i}.uni.etaq(nof_unipl)=etaq; % in deg
+    grains{i}.uni.omega(nof_unipl)=uniomega; % refers to n1; in deg
+    
+    grains{i}.uni.dy(nof_unipl)=dy;
+    grains{i}.uni.dz(nof_unipl)=dz;   
+    grains{i}.uni.az(nof_unipl)=uniaz; % azimuth in rad   
+    
+    % Errors
+    grains{i}.uni.ddy(nof_unipl)=ddy;    
+    %grains{i}.uni.ddy_az(nof_unipl)=ddy_az;
+    grains{i}.uni.ddz(nof_unipl)=ddz;
+    grains{i}.uni.dom(nof_unipl)=dom;
+    
+    grains{i}.uni.ddfrometa(nof_unipl)=ddfrometa;
+
+    grains{i}.uni.errvernorm(nof_unipl)=errvernorm;
+    grains{i}.uni.errhornorm(nof_unipl)=errhornorm;
+    
+    grains{i}.uni.dn(nof_unipl,:)=dn;    
+    grains{i}.uni.nn(nof_unipl)=nn;
+    grains{i}.uni.nnhor(nof_unipl)=nnhor;    
+    
+    grains{i}.uni.dang(nof_unipl)=dang;    
+    grains{i}.uni.daz(nof_unipl)=daz;    
+    grains{i}.uni.dazd(nof_unipl)=dazd;    
+    grains{i}.uni.dtheta(nof_unipl)=dtheta;    
+    grains{i}.uni.deta(nof_unipl)=deta;    
+
+    grains{i}.uni.dom_deg(nof_unipl)=dom_deg;
+    grains{i}.uni.dang_deg(nof_unipl)=dang_deg;    
+    grains{i}.uni.daz_deg(nof_unipl)=daz_deg;    
+    grains{i}.uni.dazd_deg(nof_unipl)=dazd_deg;    
+    grains{i}.uni.dtheta_deg(nof_unipl)=dtheta_deg;
+    grains{i}.uni.deta_deg(nof_unipl)=deta_deg;
+
+    % Derivatives
+    grains{i}.uni.dth_ddy(nof_unipl)=dth_ddy;
+    grains{i}.uni.dth_ddz(nof_unipl)=dth_ddz;
+    grains{i}.uni.dth_dom(nof_unipl)=0;
+    
+    grains{i}.uni.deta_ddy(nof_unipl)=deta_ddy;
+    grains{i}.uni.deta_ddz(nof_unipl)=deta_ddz;
+    grains{i}.uni.deta_dom(nof_unipl)=0;
+
+    grains{i}.uni.dnz_ddy(nof_unipl)=dnz_ddy;
+    grains{i}.uni.dnz_ddz(nof_unipl)=dnz_ddz;
+    grains{i}.uni.dnz_dom(nof_unipl)=0;
+    
+    grains{i}.uni.daz_ddy(nof_unipl)=daz_ddy;
+    grains{i}.uni.daz_ddz(nof_unipl)=daz_ddz;
+    grains{i}.uni.daz_dom(nof_unipl)=1;
+   
+    % Other
+
+    %grains{i}.uni.pixerrvernorm(nof_unipl)=pixerrvernorm;
+    %grains{i}.uni.omfactor(nof_unipl)=omfactor;    
+
+    
+    remainingl.pl(merge,:)=[];
+    remainingl.thetatype(merge)=[];
+    remainingl.theta(merge)=[];
+    remainingl.eta(merge)=[];
+    remainingl.hkl(merge,:)=[];
+    remainingl.omega(merge)=[];
+
+    remainings(merge)=[];
+
+  end % of planes
+
+  grains{i}.uni.nof_unipl=nof_unipl;
+  grains{i}.uni.nof_dbpl=nof_pl-nof_unipl;
+
+end % of grains
+
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+end % of function
diff --git a/zUtil_Strain/gtINUniquePlaneNormals_sab.m b/zUtil_Strain/gtINUniquePlaneNormals_sab.m
new file mode 100755
index 0000000000000000000000000000000000000000..f80370728ad262a1aa11c6e7d0ad5ce2e61601f4
--- /dev/null
+++ b/zUtil_Strain/gtINUniquePlaneNormals_sab.m
@@ -0,0 +1,347 @@
+function grainsout=gtINUniquePlaneNormals_sab(grainsinp,ACM)
+
+if ~exist('ACM','var')
+    load parameters.mat
+    ACM=gtAngConsMat(parameters.acq.spacegroup);
+end
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or single one
+if nof_grains==1
+    grains{1}=grainsinp;
+else
+    grains=grainsinp;
+end
+
+% Loop through grains
+for i=1:nof_grains
+    nof_pl=size(grains{i}.pl,1);
+
+    % Load grain info into 'remaining' (these remain to be dealt with)
+    remainingl.pl=grains{i}.pl;
+    remainingl.thetatype=grains{i}.thetatype;
+    remainingl.theta=grains{i}.theta;
+    remainingl.eta=grains{i}.eta;
+    remainingl.hkl=grains{i}.hkl;
+    remainingl.omega=grains{i}.omega;
+
+    remainings=1:nof_pl; % ; modif sabine
+
+    nof_unipl=0;
+
+    grains{i}.uni.nof_unipl=NaN;
+    grains{i}.uni.nof_dbpl=NaN;
+
+    % Process all the planes in the grain
+    while length(remainings)>=1
+
+        nof_unipl=nof_unipl+1;
+
+        merge=1;
+
+        % Take the first in remaining and compare with all other remaining,
+        % look for possible identical planes.
+        for j=2:length(remainings)
+            if remainingl.thetatype(1)==remainingl.thetatype(j)
+                ACV=ACM{remainingl.thetatype(1),remainingl.thetatype(j)};
+                ang=gt2PlanesAngle(remainingl.pl(1,:),remainingl.pl(j,:));
+                [minval,minloc]=min(abs(ACV-ang));
+
+                if ACV(minloc)==0 % the same planes
+                    merge=[merge, j];
+                end
+            end
+        end
+
+        % Merge identical planes, its new direction is the mean of the constituting
+        %  planes.
+
+        if length(merge)>1
+            % here, it's assumed that merge=2 always
+            % in case of wrong indexing merge might be >2
+            if length(merge)>2
+                disp(sprintf('Warning! Indexing error in grain %d, dubious plane normals are:',i))
+                disp(merge)
+            end
+
+            % sign: if spl=-1 they are of opposite direction
+
+            spl=sign(remainingl.pl(merge(2),:)*remainingl.pl(merge(1),:)'); % direction same or opposite
+            spl=repmat(spl,1,3);
+
+            n1=remainingl.pl(merge(1),:);
+            n2=remainingl.pl(merge(2),:).*spl;
+
+            unipl=(n1+n2)/2;
+
+            theta1=remainingl.theta(merge(1)); % in degrees
+            theta2=remainingl.theta(merge(2));
+
+            eta1=remainingl.eta(merge(1)); % in degrees
+            eta2=remainingl.eta(merge(2));
+
+            omega1=remainingl.omega(merge(1)); % in degrees
+            omega2=remainingl.omega(merge(2));
+
+            % Average eta,theta and their error
+            unieta1=eta1;
+            if spl(1)<0
+                unieta2=mod((eta2+180),360);
+            else
+                unieta2=360-eta2;
+            end
+            unieta=(unieta1+unieta2)/2;
+            deta_deg=unieta1-unieta2;
+            deta=deg2rad(deta_deg);
+
+            unitheta=(theta1+theta2)/2;
+            dtheta_deg=theta1-theta2;
+            dtheta=deg2rad(dtheta_deg);
+
+            % Error in the plane normal coordinates
+            dn=n1-n2;
+            nn=n1*n2';
+
+            dang_deg=acosd(nn); % angle between the two normals
+            dang=acos(nn);
+
+            nnhor=n1(1:2)*n2(1:2)'/norm(n1(1:2))/norm(n2(1:2));
+            %dazhd_deg=acosd(nnhor); % azimuth
+            %dazh=acos(nnhor);
+
+            % Azimuth
+            az1=atan2(n1(2),n1(1)); % in rad
+            az2=atan2(n2(2),n2(1)); % in rad
+
+            if az1<0
+                az1=az1+2*pi; % set between 0..2pi
+            end
+
+            if az2<0
+                az2=az2+2*pi; % set between 0..2pi
+            end
+
+            % Corner case around 0 deg (X axis)
+            if az1-az2<-pi
+                az1=az1+2*pi;
+            elseif az1-az2>pi
+                az2=az2+2*pi;
+            end
+
+            uniaz=(az1+az2)/2;
+            daz=az1-az2; % error in azimuth in rad
+            daz_deg=rad2deg(daz); % in deg
+
+            dy1=sind(2*theta1)*sind(eta1);
+            dz1=sind(2*theta1)*cosd(eta1);
+
+            dy2=sind(2*theta2)*sind(eta2); % should be around -dy1
+            dz2=sind(2*theta2)*cosd(eta2);
+
+            if dy1*dy2>0
+                disp(' Warning! dy1*dy2>0 ')
+                disp(sprintf('   Possible indexing error in grain %d ',i))
+                %keyboard
+            end
+
+            %       azd1=-atan(dy1/2/sind(theta1)^2); % azimuth term from the diffr. condition dy,dz
+            %       azd2o=-atan(dy2/2/sind(theta2)^2);
+            %       azd2=azd2o;
+
+            if spl(1)<0
+                %azd2=azd2+pi;     % if n2 opposite to n1, n2 should be turned 180 degrees
+                dz=(dz1-dz2)/2;   % average dz
+                ddz=dz1+dz2;      % error in dz
+            else
+                dz=(dz1+dz2)/2;
+                ddz=dz1-dz2;
+            end
+
+            dy=(dy1-dy2)/2; % !!!  average dy
+            ddy=dy1+dy2;    % error in dy
+
+            errvernorm=abs(ddz/cosd(2*unitheta)/sqrt(2)); % vertical detection error normalized
+            % by sp/(2r)
+            errhornorm=abs(ddy/cosd(2*unitheta)/sqrt(2)); % horizontal detection error normalized
+            % by sp/(2r)
+
+            %pixerrvernorm=abs(dn(3)*2*sind(unitheta)/cosd(2*unitheta));
+            ddfrometa=deta*2*sind(unitheta);  %/cosd(2*unitheta);
+            %omfactor=(1/(1+(sind(2*unitheta)*sind(unieta)/(2*sind(unitheta)^2))^2)/...
+            %         (2*sind(unitheta)^2))^2*cosd(2*unitheta)^2;
+
+        else % if length(merge)<=1
+            unipl=remainingl.pl(1,:);
+            unitheta=remainingl.theta(1);
+            unieta=remainingl.eta(1); % in degrees
+            omega1=remainingl.omega(1);
+            
+            % Azimuth
+            uniaz=atan2(unipl(2),unipl(1)); % in rad
+            if uniaz<0
+                uniaz=uniaz+2*pi; % set between 0..2pi
+            end
+
+            dy=sind(2*unitheta)*sind(unieta);
+            dz=sind(2*unitheta)*cosd(unieta);
+
+            % Discrepancy: not known
+            dn=NaN(1,3);
+            nn=NaN;
+            ddy=NaN;
+            ddz=NaN;
+
+            errvernorm=NaN;
+            errhornorm=NaN;
+            %pixerrvernorm=NaN;
+            ddfrometa=NaN;
+            dang=NaN;
+            dang_deg=NaN;
+            daz_deg=NaN;
+            dtheta_deg=NaN;
+            deta_deg=NaN;
+
+            nnhor=NaN;
+            daz=NaN;
+            dtheta=NaN;
+            deta=NaN;
+            %omfactor=NaN;
+        end % end if merge>1
+
+
+        % Eta in first quadrant (between 0..90deg)
+        %  Set eta between 0<eta<180
+        if unieta>180
+            etaq=360-unieta; % in degrees
+        else
+            etaq=unieta; % in degrees
+        end
+
+        %  Set eta between 0<eta<90
+        if etaq>90
+            etaq=180-etaq;
+        end
+
+
+        % Derivatives
+        dth_ddy=1/2*sind(unieta)/cosd(2*unitheta);
+        dth_ddz=1/2*cosd(unieta)/cosd(2*unitheta);
+
+        deta_ddy=cosd(unieta)/sind(2*unitheta);
+        deta_ddz=-sind(unieta)/sind(2*unitheta);
+
+        dnz_ddy=-dz/2*cosd(unitheta)/sind(unitheta)^2*dth_ddy;
+        dnz_ddz=1/2/sind(unitheta)-dz*cosd(unitheta)/2/sind(unitheta)^2*dth_ddz;
+
+        % azimuth
+        term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+        term2=1/2*(1/sind(unitheta)^2-2*dy*cosd(unitheta)/sind(unitheta)^3*dth_ddy);
+        daz_ddy=term1*term2;
+
+        term1=-1/(1+(dy/2/sind(unitheta)^2)^2);
+        term2=-dy*cosd(unitheta)/sind(unitheta)^3*dth_ddz;
+        daz_ddz=term1*term2;
+
+        % Error in azimuth from dy,dz:
+        dazd=daz_ddy*ddy+daz_ddz*ddz;
+        dazd_deg=rad2deg(dazd); % in deg
+
+        % Error in azimuth from omega
+        dom=daz-dazd;
+        dom_deg=rad2deg(dom); % in deg
+
+        if isnan(dom_deg)
+            uniomega=omega1; % no correction
+        else
+            uniomega=omega1-dom_deg/2; % double detection; corrected by half the difference
+        end
+
+        % Save unique planes under grains.uni
+        grains{i}.uni.plid(nof_unipl,:)=false(1,nof_pl);
+        grains{i}.uni.plid(nof_unipl,remainings(merge))=true; % which pair-lines are used
+
+        % Coordinates
+        grains{i}.uni.pl(nof_unipl,:)=unipl;
+        grains{i}.uni.thetatype(nof_unipl)=remainingl.thetatype(1);
+        grains{i}.uni.hkl(nof_unipl,:)=remainingl.hkl(1,:);
+        %grains{i}.uni.pla(nof_unipl)=NaN;
+
+        grains{i}.uni.theta(nof_unipl)=unitheta; % in deg
+        grains{i}.uni.eta(nof_unipl)=unieta; % in deg
+        grains{i}.uni.etaq(nof_unipl)=etaq; % in deg
+        grains{i}.uni.omega(nof_unipl)=uniomega; % refers to n1; in deg
+
+        grains{i}.uni.dy(nof_unipl)=dy;
+        grains{i}.uni.dz(nof_unipl)=dz;
+        grains{i}.uni.az(nof_unipl)=uniaz; % azimuth in rad
+
+        % Errors
+        grains{i}.uni.ddy(nof_unipl)=ddy;
+        %grains{i}.uni.ddy_az(nof_unipl)=ddy_az;
+        grains{i}.uni.ddz(nof_unipl)=ddz;
+        grains{i}.uni.dom(nof_unipl)=dom;
+
+        grains{i}.uni.ddfrometa(nof_unipl)=ddfrometa;
+
+        grains{i}.uni.errvernorm(nof_unipl)=errvernorm;
+        grains{i}.uni.errhornorm(nof_unipl)=errhornorm;
+
+        grains{i}.uni.dn(nof_unipl,:)=dn;
+        grains{i}.uni.nn(nof_unipl)=nn;
+        grains{i}.uni.nnhor(nof_unipl)=nnhor;
+
+        grains{i}.uni.dang(nof_unipl)=dang;
+        grains{i}.uni.daz(nof_unipl)=daz;
+        grains{i}.uni.dazd(nof_unipl)=dazd;
+        grains{i}.uni.dtheta(nof_unipl)=dtheta;
+        grains{i}.uni.deta(nof_unipl)=deta;
+
+        grains{i}.uni.dom_deg(nof_unipl)=dom_deg;
+        grains{i}.uni.dang_deg(nof_unipl)=dang_deg;
+        grains{i}.uni.daz_deg(nof_unipl)=daz_deg;
+        grains{i}.uni.dazd_deg(nof_unipl)=dazd_deg;
+        grains{i}.uni.dtheta_deg(nof_unipl)=dtheta_deg;
+        grains{i}.uni.deta_deg(nof_unipl)=deta_deg;
+
+        % Derivatives
+        grains{i}.uni.dth_ddy(nof_unipl)=dth_ddy;
+        grains{i}.uni.dth_ddz(nof_unipl)=dth_ddz;
+        grains{i}.uni.dth_dom(nof_unipl)=0;
+
+        grains{i}.uni.deta_ddy(nof_unipl)=deta_ddy;
+        grains{i}.uni.deta_ddz(nof_unipl)=deta_ddz;
+        grains{i}.uni.deta_dom(nof_unipl)=0;
+
+        grains{i}.uni.dnz_ddy(nof_unipl)=dnz_ddy;
+        grains{i}.uni.dnz_ddz(nof_unipl)=dnz_ddz;
+        grains{i}.uni.dnz_dom(nof_unipl)=0;
+
+        grains{i}.uni.daz_ddy(nof_unipl)=daz_ddy;
+        grains{i}.uni.daz_ddz(nof_unipl)=daz_ddz;
+        grains{i}.uni.daz_dom(nof_unipl)=1;
+
+ 
+        remainingl.pl(merge,:)=[];
+        remainingl.thetatype(merge)=[];
+        remainingl.theta(merge)=[];
+        remainingl.eta(merge)=[];
+        remainingl.hkl(merge,:)=[];
+        remainingl.omega(merge)=[];
+
+        remainings(merge)=[];
+
+    end % of planes
+
+    grains{i}.uni.nof_unipl=nof_unipl;
+    grains{i}.uni.nof_dbpl=nof_pl-nof_unipl;
+
+end % of grains
+
+if nof_grains==1
+    grainsout=grains{1};
+else
+    grainsout=grains;
+end
+
+end % of function
diff --git a/zUtil_Strain/gtKeepLine.m b/zUtil_Strain/gtKeepLine.m
new file mode 100755
index 0000000000000000000000000000000000000000..dff6ca51cb913ed04d777aba6cfde67e21040778
--- /dev/null
+++ b/zUtil_Strain/gtKeepLine.m
@@ -0,0 +1,26 @@
+% to be deleted
+% new macro: gtIndexSelectLines
+
+function linekept=gtKeepLine(keeplist,line)
+
+  linekept.id=line.id(keeplist);
+  linekept.pairid=line.pairid(keeplist);
+  linekept.aid=line.aid(keeplist);
+  linekept.bid=line.bid(keeplist);
+  linekept.theta=line.theta(keeplist);
+  linekept.eta=line.eta(keeplist);
+  linekept.omega=line.omega(keeplist);
+  linekept.int=line.int(keeplist);
+  linekept.bbxs=line.bbxs(keeplist);
+  linekept.bbys=line.bbys(keeplist);
+
+  linekept.ca=line.ca(keeplist,:);
+  linekept.cb=line.cb(keeplist,:);
+  linekept.dir=line.dir(keeplist,:);
+  linekept.pl=line.pl(keeplist,:);
+
+  linekept.thetatype=line.thetatype(keeplist);
+  linekept.hkl=line.hkl(keeplist,:);
+  %linekept.lRv=line.lRv(:,:,keeplist);
+
+end
diff --git a/zUtil_Strain/gtMatrix2Vector.m b/zUtil_Strain/gtMatrix2Vector.m
new file mode 100755
index 0000000000000000000000000000000000000000..7a25a6c9437238455df7de5067da4c9e3e4863a4
--- /dev/null
+++ b/zUtil_Strain/gtMatrix2Vector.m
@@ -0,0 +1,4 @@
+function v=Matrix2Vector(m)
+
+           v=[m(1,1),m(2,2),m(3,3),m(3,2),m(1,3),m(1,2)]';
+end			
\ No newline at end of file
diff --git a/zUtil_Strain/gtPlotSampleEnv.m b/zUtil_Strain/gtPlotSampleEnv.m
new file mode 100755
index 0000000000000000000000000000000000000000..a7c579549fb640874afe30e87cf6c7e6863e5051
--- /dev/null
+++ b/zUtil_Strain/gtPlotSampleEnv.m
@@ -0,0 +1,34 @@
+function gtPlotSampleEnv(fig_no,sample,rottodet)
+    figure(fig_no) ;
+    t=0:20:360 ;
+    vec(1:19,1)=1 ;
+    hold on ;
+   
+    for i= 0.01: 0.05: 1 % sample top and bottom plane
+      plot3(i*sample.rad*sind(t),i*sample.rad*cosd(t),-sample.top*vec,'b') ;
+      plot3(i*sample.rad*sind(t),i*sample.rad*cosd(t),-sample.bot*vec,'b') ;
+    end
+
+    for i=0: 0.05: 1 % sample cylinder
+      plot3(sample.rad*sind(t),sample.rad*cosd(t),(i*(-sample.top+sample.bot)-sample.bot)*vec,'b') ;
+    end
+
+    plot3(sample.rad*sind(t),sample.rad*cosd(t),-sample.top*vec,'k','LineWidth',1) ; % sample edge
+    plot3(sample.rad*sind(t),sample.rad*cosd(t),-sample.bot*vec,'k','LineWidth',1) ; % sample edge
+        
+    for i=0:-20:-2048 % detector cylinder
+      plot3(rottodet*sind(t),rottodet*cosd(t),i*vec,'c') ;
+    end
+   
+    plot3(rottodet*sind(t),rottodet*cosd(t),0*vec,'k','LineWidth',1) ; % detector edge
+    plot3(rottodet*sind(t),rottodet*cosd(t),-2048*vec,'k','LineWidth',1) ; % detector edge
+    
+    plot3([rottodet,rottodet],[0,0],[0,-2048],'r','LineWidth',2) ; % beam direction
+    plot3(rottodet,0,0,'rx','LineWidth',2) ;
+    
+    plot3([0,0],[0,0],[0,-2048],'-.b','LineWidth',2) ; % rotation axis
+    plot3(0,0,0,'bx','LineWidth',2) ;
+    
+    axis square; grid on
+    drawnow ;
+end
diff --git a/zUtil_Strain/gtPlotUniErrors.m b/zUtil_Strain/gtPlotUniErrors.m
new file mode 100755
index 0000000000000000000000000000000000000000..773bf3fd109fa458e5bd86b62c980465e9342f55
--- /dev/null
+++ b/zUtil_Strain/gtPlotUniErrors.m
@@ -0,0 +1,158 @@
+% function gtPlotUniErrors(errest,write_flag)
+
+function gtPlotUniErrors(errest,write_flag)
+
+%sdir='/Users/reischig/thesis/figures';
+fs=16;
+
+close all
+
+d=errest.data;
+
+
+binw.etaq=10;
+edges_st.etaq=10;
+edges_end.etaq=90;
+
+binw.ddy=0.00002;
+edges_st.ddy=-0.0005;
+edges_end.ddy=0.0005;
+
+binw.ddz=binw.ddy;
+edges_st.ddz=edges_st.ddy;
+edges_end.ddz=edges_end.ddy;
+
+binw.dom=0.0001;
+edges_st.dom=-0.002;
+edges_end.dom=0.002;
+
+binw.dazd=0.00002;
+edges_st.dazd=-0.0005;
+edges_end.dazd=0.0005;
+
+binw.daz=0.0001;
+edges_st.daz=-0.002;
+edges_end.daz=0.002;
+
+binw.deta=0.0001;
+edges_st.deta=-0.002;
+edges_end.deta=0.002;
+
+binw.dtheta=0.00002;
+edges_st.dtheta=-0.0005;
+edges_end.dtheta=0.0005;
+
+binw.dang=0.0001;
+edges_st.dang=0;
+edges_end.dang=0.005;
+
+
+cfPlotHistNo('etaq','No. of inputs','\eta [deg]')
+
+cfPlotHistVs('ddy','etaq','Mean \Delta d_{y}','\eta [deg]')
+cfPlotHistVs('ddz','etaq','Mean \Delta d_{z}','\eta [deg]')
+cfPlotHistVs('dom','etaq','Mean \Delta \omega [rad]','\eta [deg]')
+cfPlotHistVs('dazd','etaq','Mean \Delta \vartheta_{d} [rad]','\eta [deg]')
+cfPlotHistVs('deta','etaq','Mean \Delta \eta [rad]','\eta [deg]')
+cfPlotHistVs('dtheta','etaq','Mean \Delta \theta [rad]','\eta [deg]')
+cfPlotHistVs('daz','etaq','Mean \Delta \vartheta [rad]','\eta [deg]')
+cfPlotHistVs('dang','etaq','Mean \Delta \beta [rad]','\eta [deg]')
+
+
+cfPlotHist('ddy','Histogram of \Delta d_{y}','\Delta d_{y}')
+cfPlotHist('ddz','Histogram of \Delta d_{z}','\Delta d_{z}')
+cfPlotHist('dom','Histogram of \Delta \omega [rad]','\Delta \omega [rad]')
+cfPlotHist('dtheta','Histogram of \Delta \theta [rad]','\Delta \theta [rad]')
+cfPlotHist('deta','Histogram of \Delta \eta [rad]','\Delta \eta [rad]')
+cfPlotHist('daz','Histogram of \Delta \vartheta [rad]','\Delta \vartheta [rad]')
+cfPlotHist('dazd','Histogram of \Delta \vartheta_{d} [rad]','\Delta \vartheta_{d} [rad]')
+cfPlotHist('dang','Histogram of \Delta \beta [rad]','\Delta \beta [rad]')
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function cfPlotHistVs(dv,vs,ylab,xlab)
+
+edges_act=edges_st.(vs):binw.(vs):edges_end.(vs);
+bins_act=(edges_st.(vs)+binw.(vs)/2):binw.(vs):edges_end.(vs);
+  
+[no,b]=histc(d.(vs),edges_act);
+no(end)=[];
+
+for ii=1:length(bins_act)
+  m1(ii,1)=mean(abs(d.(dv)(b==ii & d.thetatype==1)));
+  m2(ii,1)=mean(abs(d.(dv)(b==ii & d.thetatype==2)));
+end
+
+figure
+set(gca,'fontunits', 'points','fontsize',fs)
+bar(bins_act,[m1,m2],'group')
+legend('\{110\}','\{200\}') % ,'fontsize',fs)
+%xlabel(xlab,'fontunits', 'points','fontsize',fs)
+%ylabel(ylab,'fontunits', 'points','fontsize',fs)
+xlabel(xlab,'fontsize',fs)
+ylabel(ylab,'fontsize',fs)
+
+if write_flag
+	fname=['ch5-HistUniErrors_',dv,'_vs_',vs];
+	pdfprint(fname)
+end
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function cfPlotHistNo(vs,ylab,xlab)
+
+edges_act=edges_st.(vs):binw.(vs):edges_end.(vs);
+bins_act=(edges_st.(vs)+binw.(vs)/2):binw.(vs):edges_end.(vs);
+
+no1=histc(d.(vs)(d.thetatype==1),edges_act);
+no2=histc(d.(vs)(d.thetatype==2),edges_act);
+no1(end)=[];
+no2(end)=[];
+
+figure
+set(gca,'fontunits', 'points','fontsize',fs)
+bar(bins_act,[no1,no2],'group')
+legend('\{110\}','\{200\}')% ,'fontsize',fs)
+xlabel(xlab,'fontsize',fs)
+ylabel(ylab,'fontsize',fs)
+
+if write_flag
+	fname=['ch5-HistNofErrorInputs_vs_',vs];
+	pdfprint(fname)
+end
+
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function cfPlotHist(dv,ylab,xlab)
+
+edges_act=edges_st.(dv):binw.(dv):edges_end.(dv);
+bins_act=(edges_st.(dv)+binw.(dv)/2):binw.(dv):edges_end.(dv);
+
+no1=histc(d.(dv)(d.thetatype==1),edges_act);
+no2=histc(d.(dv)(d.thetatype==2),edges_act);
+no1(end)=[];
+no2(end)=[];
+
+figure
+set(gca,'fontunits', 'points','fontsize',fs)
+bar(bins_act,[no1,no2],'group')
+legend('\{110\}','\{200\}','Location','Best')% ,'fontsize',fs)
+
+xlabel(xlab,'fontsize',fs)
+ylabel(ylab,'fontsize',fs)
+
+set(gca,'XTick',edges_act*5)
+
+if write_flag
+	fname=['ch5-HistUniErrors_',dv];
+	pdfprint(fname)
+end
+
+end
+
+end
\ No newline at end of file
diff --git a/zUtil_Strain/gtPlotUniPlanes.m b/zUtil_Strain/gtPlotUniPlanes.m
new file mode 100755
index 0000000000000000000000000000000000000000..af7f3c2f053ca64722896b2dd1175bcf5bae4fbd
--- /dev/null
+++ b/zUtil_Strain/gtPlotUniPlanes.m
@@ -0,0 +1,36 @@
+% function gtPlotUniPlanes(grain)
+
+
+function gtPlotUniPlanes(grain)
+
+z=zeros(grain.uni.nof_unipl,1);
+
+figure
+quiver3(z,z,z,grain.uni.pl(:,1),grain.uni.pl(:,2),grain.uni.pl(:,3))
+
+end
+
+
+% 
+% figure
+% hold on
+% 
+% xlabel('X')
+% ylabel('Y')
+% zlabel('Z')
+% axis equal
+% grid
+% 
+% tmp=summer(4);
+% c1=tmp(1,:);
+% c2=tmp(3,:);
+% 
+% i=1; quiver3(0,0,0,g.uni.pl(i,1),g.uni.pl(i,2),g.uni.pl(i,3),'color',c1,'linewidth',2);
+% i=2; quiver3(0,0,0,g.uni.pl(i,1),g.uni.pl(i,2),g.uni.pl(i,3),'color',c1,'linewidth',2);
+% i=3; quiver3(0,0,0,g.uni.pl(i,1),g.uni.pl(i,2),g.uni.pl(i,3),'color',c1,'linewidth',2);
+% i=4; quiver3(0,0,0,g.uni.pl(i,1),g.uni.pl(i,2),g.uni.pl(i,3),'color',c1,'linewidth',2);
+% i=5; quiver3(0,0,0,-g.uni.pl(i,1),-g.uni.pl(i,2),-g.uni.pl(i,3),'color',c1,'linewidth',2);
+% i=6; quiver3(0,0,0,g.uni.pl(i,1),g.uni.pl(i,2),g.uni.pl(i,3),'color',c2,'linewidth',2);
+% i=7; quiver3(0,0,0,g.uni.pl(i,1),g.uni.pl(i,2),g.uni.pl(i,3),'color',c2,'linewidth',2);
+% 
+
diff --git a/zUtil_Strain/gtSTRDeleteStrainInGrains.m b/zUtil_Strain/gtSTRDeleteStrainInGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..f3de57484b1738f6dbac35dae287c9ef7e5565c0
--- /dev/null
+++ b/zUtil_Strain/gtSTRDeleteStrainInGrains.m
@@ -0,0 +1,41 @@
+function grainsout=gtSTRDeleteStrainInGrains(grainsinp,grainids)
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+
+for i=grainids
+
+    grains{i}.pstrain1=NaN;
+    grains{i}.pstrain2=NaN;
+    grains{i}.pstrain3=NaN;
+  
+    % Principal strain directions in order
+    grains{i}.pstrainvec1=NaN;
+    grains{i}.pstrainvec2=NaN;
+    grains{i}.pstrainvec3=NaN;
+
+    % Strain in directions of the lab system
+    grains{i}.strainnormX=NaN;
+    grains{i}.strainnormY=NaN;
+    grains{i}.strainnormZ=NaN;
+    
+    grains{i}.straintensor=NaN;
+
+end
+
+
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+
+end
diff --git a/zUtil_Strain/gtStrainDoAll.m b/zUtil_Strain/gtStrainDoAll.m
new file mode 100755
index 0000000000000000000000000000000000000000..92d16b60a5e7acca13f6e40c416e7cd44820c820
--- /dev/null
+++ b/zUtil_Strain/gtStrainDoAll.m
@@ -0,0 +1,7 @@
+function grain=gtStrainDoAll
+
+load grain.mat
+
+grain=gtINUniquePlaneNormals(grain);
+grain=gtAddGrainLatticePar(grain);
+grain=gtStrainGrains(grain);
diff --git a/zUtil_Strain/gtStrainDrawPrincipalStrainVectors.m b/zUtil_Strain/gtStrainDrawPrincipalStrainVectors.m
new file mode 100755
index 0000000000000000000000000000000000000000..15435aaa2f79b2b83da37d69b29cd047de6f92f0
--- /dev/null
+++ b/zUtil_Strain/gtStrainDrawPrincipalStrainVectors.m
@@ -0,0 +1,94 @@
+function gtStrainDrawPrincipalStrainVectors(grainsinp)
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+
+% strainscale=0.01;
+
+
+
+for i=1:nof_grains
+  psvec(i,:)=grains{i}.strain.pstrainmaxdir;
+end
+
+figure
+set(gca,'fontunits', 'points','fontsize',14)
+compass(psvec(:,1),psvec(:,2))
+axis([-1 1 -1 1])
+%axis equal;
+xlabel('X axis','Fontsize',14)
+ylabel('Y axis','Fontsize',14)
+
+h = findobj(gca,'Type','line');
+set(h,'Color','b','Linewidth',1.5)
+
+
+
+
+
+figure
+for i=1:nof_grains
+  pseta(i)=gtEtaOfPoint(psvec(i,2),psvec(i,1));
+end
+set(gca,'fontunits', 'points','fontsize',14)
+rose(pseta,24)
+xlabel('X axis','Fontsize',14)
+ylabel('Y axis','Fontsize',14)
+
+h = findobj(gca,'Type','patch');
+set(h,'FaceColor','b','EdgeColor','w')
+
+h = findobj(gca,'Type','line');
+set(h,'Color','b','Linewidth',2)
+
+
+
+figure('name','Hist grain orientation')
+for i=1:nof_grains
+  R=Rod2g(grains{i}.R_vector);
+  v1=R(1,3);
+  v2=R(2,3);
+  oeta(i)=gtEtaOfPoint(v1,v2);
+end
+set(gca,'fontunits', 'points','fontsize',14)
+rose(oeta,24)
+xlabel('X axis','Fontsize',14)
+ylabel('Y axis','Fontsize',14)
+
+h = findobj(gca,'Type','patch');
+set(h,'FaceColor','b','EdgeColor','w')
+
+h = findobj(gca,'Type','line');
+set(h,'Color','b','Linewidth',2)
+
+
+
+figure('name','Grain Orientation')
+set(gca,'fontunits', 'points','fontsize',14)
+for i=1:nof_grains
+  R=Rod2g(grains{i}.R_vector);
+  v1(i)=R(1,3);
+  v2(i)=R(2,3);
+end
+plot(v1,v2,'.')
+axis([-1 1 -1 1])
+%axis equal;
+xlabel('X axis','Fontsize',14)
+ylabel('Y axis','Fontsize',14)
+
+h = findobj(gca,'Type','line');
+set(h,'Color','b','Linewidth',1.5)
+
+
+
+end
+
+
+    
diff --git a/zUtil_Strain/gtStrainErrors.m b/zUtil_Strain/gtStrainErrors.m
new file mode 100755
index 0000000000000000000000000000000000000000..7cee6b055f8a23bb56f497eac13586747a244769
--- /dev/null
+++ b/zUtil_Strain/gtStrainErrors.m
@@ -0,0 +1,81 @@
+
+function [std_Bragg_plstrain_abs,std_Bragg_plstrain_rel,std_ang_pl,...
+  bboxarea,std_distcom,std_lRdist,nof_pairids,nof_uniids]=gtStrainErrors(grain)
+
+nof_grains=length(grain);
+
+for i=1:nof_grains
+  if any(isnan(grain{i}.straintensor))
+    continue
+  end
+    
+    
+    
+  std_Bragg_plstrain_abs(i)=std(grain{i}.stat.err.plstrain_abs);
+  std_Bragg_plstrain_rel(i)=std(grain{i}.stat.err.plstrain_rel);
+
+  std_ang_pl(i)=std(grain{i}.stat.strainerror_abs(3:4:end));
+
+  bboxarea(i)=grain{i}.stat.bbxsmean*grain{i}.stat.bbysmean;
+  
+  std_distcom(i)=grain{i}.stat.distcomstd;
+  
+  std_lRdist(i)=grain{i}.stat.lRdiststd;
+  
+  nof_pairids(i)=length(grain{i}.pairid);
+
+  nof_uniids(i)=size(grain{i}.uni.plid,1);
+  
+end
+
+% out=[std_Bragg_plstrain_abs' std_Bragg_plstrain_rel' ...
+%      std_ang_plstrain' std_distcom' std_lRdist'];
+
+figure('name','nof_pairids - std_Bragg_plstrain_abs')
+plot(nof_pairids,std_Bragg_plstrain_abs,'b.')
+
+figure('name','nof_uniids - std_Bragg_plstrain_abs')
+plot(nof_uniids,std_Bragg_plstrain_abs,'b.')
+
+figure('name','bboxarea - std_Bragg_plstrain_abs')
+plot(bboxarea,std_Bragg_plstrain_abs,'b.')
+
+figure('name','std_distcom - std_Bragg_plstrain_abs')
+plot(std_distcom,std_Bragg_plstrain_abs,'b.')
+
+figure('name','std_lRdist - std_Bragg_plstrain_abs')
+plot(std_lRdist,std_Bragg_plstrain_abs,'b.')
+
+
+figure('name','nof_pairids - std_ang_pl')
+plot(nof_pairids,std_ang_pl,'b.')
+
+figure('name','nof_uniids - std_ang_pl')
+plot(nof_uniids,std_ang_pl,'b.')
+
+figure('name','bboxarea - std_ang_pl')
+plot(bboxarea,std_ang_pl,'b.')
+
+figure('name','std_distcom - std_ang_pl')
+plot(std_distcom,std_ang_pl,'b.')
+
+figure('name','std_lRdist - std_ang_pl')
+plot(std_lRdist,std_ang_pl,'b.')
+
+
+
+
+
+
+end
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Strain/gtStrainFitElasticConstants.m b/zUtil_Strain/gtStrainFitElasticConstants.m
new file mode 100755
index 0000000000000000000000000000000000000000..56fffad3d95cf68d370ad844adbd365b2a2675f7
--- /dev/null
+++ b/zUtil_Strain/gtStrainFitElasticConstants.m
@@ -0,0 +1,159 @@
+volfull=edf_read('5_reconstruction/grains.edf');
+load grain
+load parameters
+
+vol=volfull(:,:,50:500);
+%vol=volfull(:,:,170:200);
+%vol=volfull(:,:,320:340);
+%vol=volfull(:,:,211:500); % the right one
+%vol=vol(:,:,160:180);  % minimum region
+%vol=vol(:,:,120:140);  % max region
+
+%vol=volfull;
+ 
+Fg_measured=149.9;
+
+%Lop=@(a,b) [a(1)*b(1), a(2)*b(2), a(3)*b(3), a(1)*b(2)+a(2)*b(1), ...
+%     a(1)*b(3)+a(3)*b(1), a(2)*b(3)+a(3)*b(2)];
+
+Lop=@(a,b) [a(1)*b(1), a(2)*b(2), a(3)*b(3), a(2)*b(3)+a(3)*b(2), ...
+     a(1)*b(3)+a(3)*b(1), a(1)*b(2)+a(2)*b(1)];
+
+Bop=@(a,b) [a(1)*b(1)+a(2)*b(2)+a(3)*b(3), ...
+            a(1)*(b(2)+b(3))+a(2)*(b(1)+b(3))+a(3)*(b(1)+b(2)), ... 
+            a(4)*b(4)+a(5)*b(5)+a(6)*b(6)];
+
+ng=length(grain); % number of grains
+nl=size(vol,3);    % number of layers        
+
+ps=(parameters.acq.pixelsize.^2)*1e-6;  % pixel area in m2 (pixelsize is in mm)
+
+AI=zeros(nl,ng);  % cross-section of each grain in each layer  
+BI=zeros(ng,3);
+zlab=[0 0 1]';    % loading direction in the LAB system
+Fg=zeros(nl,1);
+gidused=(1:ng)';
+
+
+Fg(:)=Fg_measured;
+
+% Cross-sectional area of each grain in each layer
+for i=1:nl      %  # actual layer
+  slice=vol(:,:,i);
+  indb=zeros(ng+1,1);
+  for k=1:length(slice(:))
+    indb(slice(k)+1)=indb(slice(k)+1)+1;
+  end
+  AI(i,:)=indb(2:end)';  
+end
+AI=AI*ps;
+
+% tic
+% for i=1:nl      %  # actual layer
+%     slice=vol(:,:,i);
+%   for j=1:ng    %  # actual grain
+%     ind=find(slice==j);
+%     AI(i,j)=length(ind)*ps;   
+%   end  
+% end
+% toc
+
+
+for j=1:ng
+  elab = grain{j}.strain.Eps([1 2 3 6 5 4])';   % rearrange the vector to agree with definition in Noyen and Cohen
+  
+  %if any(isnan())
+  
+  ELAB = gtVector2Matrix(elab);
+  
+  %g=Rod2g(grain{j}.R_vector)';  % transform from LAB to CRYSTAL
+  g=Rod2g(grain{j}.R_vector); % check how it is done in gtDrawGrainCubes2 !!!
+  
+  %ECRYST=g*ELAB*g';
+  ECRYST=g*ELAB*g'; % check how it's done gtDrawGrainCubes2 !!!!
+  ecryst=gtMatrix2Vector(ECRYST);
+  
+  %zcryst=g*zlab;
+  zcryst=g*zlab;
+    
+  BI(j,:)=Bop(Lop(zcryst,zcryst),ecryst);
+end
+
+% Delete grain data where strain couldn'e be measured (-> NaN)
+
+todel=any(isnan(BI),2);
+
+BI(todel,:)=[];
+AI(:,todel)=[];
+gidused(todel)=[];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% MAXIMUM LIKELIHOOD FIT OF THE SYSTEM
+
+% Singular Value Decomposition (SVD)
+%   see e.g. Numerical Recipes
+% Gives maximum likelihood fit when the uncertainties of the b 
+%   vector components are normalized (the rows of b and A are divided with 
+%   the corresponding variances).
+%
+% System to solve: b=A*x  , where x is to be fitted
+%
+% Decompose the A matrix: A=U*S*V'
+%   [U,S,V]=svd(A,0) ;
+% The inverse of A is given by:
+%   omega=diag(S) ;
+%   inv_A=V*diag(1./diag(S))*U' ;
+% So the maximum likelihood fit of x is:   
+%   x=V*diag(1./diag(S))*U'*b ;
+%
+% Covariance matrix of the fitted solution vector from the SVD output: 
+%   (not correct for dependent x variables !)
+%   for j=1:6
+%     for k=1:6
+%       Cov(j,k)=(V(j,:).*V(k,:))*(1./omega.^2) ;
+%     end
+%   end
+% Note that in general Cov_x=inv(A'*A);
+%
+% Standard deviation of the fitted x vector:
+%   std_x=sqrt(diag(Cov)) ;
+
+% System to solve: Fg=AI*BI*c=M*c , where c contains the elastic constants
+
+% System matrix:
+M=AI*BI;
+
+[U,S,V]=svd(M,0);
+%omega=diag(S);
+c=V*diag(1./diag(S))*U'*Fg
+
+% Fitted force:
+Ff=M*c;
+
+bar(Ff)
+
+
+
+return
+
+ctest=[152e9; 124e9; 38e9]
+ctest=[250.2e9; 19.0e9; 115.3e9]
+
+
+ctest=[56e9; 25e9; 121e9];
+
+Ff=M*ctest;
+figure('name','Test')
+bar(Ff)
+
+
+
+
+%cout=c;
+%cout(2)=-cout(2);
+% C=[c11 c12 c12   0   0   0;...
+%    c12 c11 c12   0   0   0;...
+%    c12 c12 c11   0   0   0;...
+%      0   0   0 c44   0   0;...
+%      0   0   0   0 c44   0;...
+%  	   0   0   0   0   0 c44];
diff --git a/zUtil_Strain/gtStrainFitElasticConstants_test.m b/zUtil_Strain/gtStrainFitElasticConstants_test.m
new file mode 100755
index 0000000000000000000000000000000000000000..7996e4a1b6866b2e15e0b4cfbb45e878d7d7dc8b
--- /dev/null
+++ b/zUtil_Strain/gtStrainFitElasticConstants_test.m
@@ -0,0 +1,149 @@
+%volfull=edf_read('5_reconstruction/grains.edf');
+%load grain
+%load parameters
+
+vol=volfull(:,:,50:500);
+%vol=volfull;
+ 
+Fg_measured=149.9;
+
+%Lop=@(a,b) [a(1)*b(1), a(2)*b(2), a(3)*b(3), a(1)*b(2)+a(2)*b(1), ...
+%     a(1)*b(3)+a(3)*b(1), a(2)*b(3)+a(3)*b(2)];
+
+Lop=@(a,b) [a(1)*b(1), a(2)*b(2), a(3)*b(3), a(2)*b(3)+a(3)*b(2), ...
+     a(1)*b(3)+a(3)*b(1), a(1)*b(2)+a(2)*b(1)];
+
+Bop=@(a,b) [a(1)*b(1)+a(2)*b(2)+a(3)*b(3), ...
+            a(1)*(b(2)+b(3))+a(2)*(b(1)+b(3))+a(3)*(b(1)+b(2)), ... 
+            a(4)*b(4)+a(5)*b(5)+a(6)*b(6)];
+
+ng=length(grain); % number of grains
+nl=size(vol,3);    % number of layers        
+
+ps=(parameters.acq.pixelsize.^2)*1e-6;  % pixel area in m2 (pixelsize is in mm)
+
+AI=zeros(nl,ng);  % cross-section of each grain in each layer  
+BI=zeros(ng,3);
+zlab=[0 0 1]';    % loading direction in the LAB system
+Fg=zeros(nl,1);
+gidused=(1:ng)';
+
+
+Fg(:)=Fg_measured;
+
+% Cross-sectional area of each grain in each layer
+for i=1:nl      %  # actual layer
+  slice=vol(:,:,i);
+  indb=zeros(ng+1,1);
+  for k=1:length(slice(:))
+    indb(slice(k)+1)=indb(slice(k)+1)+1;
+  end
+  AI(i,:)=indb(2:end)';  
+end
+AI=AI*ps;
+
+% tic
+% for i=1:nl      %  # actual layer
+%     slice=vol(:,:,i);
+%   for j=1:ng    %  # actual grain
+%     ind=find(slice==j);
+%     AI(i,j)=length(ind)*ps;   
+%   end  
+% end
+% toc
+
+
+for j=1:ng
+  elab = confgrain{j}.strain.Eps([1 2 3 6 5 4])';   % rearrange the vector to agree with definition in Noyen and Cohen
+  
+  %if any(isnan())
+  
+  ELAB = gtVector2Matrix(elab);
+  
+  g=Rod2g(confgrain{j}.R_vector)';  % transform from LAB to CRYSTAL
+  
+  ECRYST=g*ELAB*g';
+  ecryst=gtMatrix2Vector(ECRYST);
+  
+  zcryst=g*zlab;
+    
+  BI(j,:)=Bop(Lop(zcryst,zcryst),ecryst);
+end
+
+% Delete grain data where strain couldn'e be measured (-> NaN)
+
+todel=any(isnan(BI),2);
+
+BI(todel,:)=[];
+AI(:,todel)=[];
+gidused(todel)=[];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% MAXIMUM LIKELIHOOD FIT OF THE SYSTEM
+
+% Singular Value Decomposition (SVD)
+%   see e.g. Numerical Recipes
+% Gives maximum likelihood fit when the uncertainties of the b 
+%   vector components are normalized (the rows of b and A are divided with 
+%   the corresponding variances).
+%
+% System to solve: b=A*x  , where x is to be fitted
+%
+% Decompose the A matrix: A=U*S*V'
+%   [U,S,V]=svd(A,0) ;
+% The inverse of A is given by:
+%   omega=diag(S) ;
+%   inv_A=V*diag(1./diag(S))*U' ;
+% So the maximum likelihood fit of x is:   
+%   x=V*diag(1./diag(S))*U'*b ;
+%
+% Covariance matrix of the fitted solution vector from the SVD output: 
+%   (not correct for dependent x variables !)
+%   for j=1:6
+%     for k=1:6
+%       Cov(j,k)=(V(j,:).*V(k,:))*(1./omega.^2) ;
+%     end
+%   end
+% Note that in general Cov_x=inv(A'*A);
+%
+% Standard deviation of the fitted x vector:
+%   std_x=sqrt(diag(Cov)) ;
+
+% System to solve: Fg=AI*BI*c=M*c , where c contains the elastic constants
+
+% System matrix:
+M=AI*BI;
+
+[U,S,V]=svd(M,0);
+%omega=diag(S);
+c=V*diag(1./diag(S))*U'*Fg
+
+% Fitted force:
+Ff=M*c;
+
+bar(Ff)
+
+
+
+return
+
+ctest=[152e9; 124e9; 38e9]
+ctest=[250.2e9; 19.0e9; 115.3e9]
+
+ctest=[7e10; 0e10; 7.4e10];
+
+Ff=M*ctest;
+figure('name','Test')
+bar(Ff)
+
+
+
+
+%cout=c;
+%cout(2)=-cout(2);
+% C=[c11 c12 c12   0   0   0;...
+%    c12 c11 c12   0   0   0;...
+%    c12 c12 c11   0   0   0;...
+%      0   0   0 c44   0   0;...
+%      0   0   0   0 c44   0;...
+%  	   0   0   0   0   0 c44];
diff --git a/zUtil_Strain/gtStrainGrains.m b/zUtil_Strain/gtStrainGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..f137dda8c7d83c3184828a2046a2c195ef9939ce
--- /dev/null
+++ b/zUtil_Strain/gtStrainGrains.m
@@ -0,0 +1,78 @@
+% FUNCTION grainsout=gtStrainGrains(grainsinp,ACM,latticeparref)
+%
+% INPUT
+% grainsinp: grain structure
+% ACM: angular consistency matrix  ( ACM=gtAngConsMat(spacegroup) )
+% latticeparref (optional): lattice parameter, reference at zero strain
+%                            if not specified, parameters.acq.latticepar(1)
+
+function grainsout=gtStrainGrains(grainsinp,limiterr_flag,ACM,latticeparref)
+
+if ~exist('limiterr_flag','var')
+  limiterr_flag=false;
+end
+
+if ~exist('ACM','var')
+  ACM=[];
+end
+
+if ~exist('latticeparref','var')
+  load parameters.mat
+  latticeparref=parameters.acq.latticepar(1);
+end
+
+if isempty(ACM)
+  load parameters.mat
+  ACM=gtAngConsMat(parameters.acq.spacegroup);
+end
+
+tic
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or a single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+faults=[];
+comments=[];
+
+errest=gtEstimateErrors(grainsinp);
+
+for i=1:nof_grains
+
+  grains{i}=gtStrainPlanes(grains{i},latticeparref);
+  
+  grains{i}=gtStrainTensorFit(grains{i},ACM,errest,limiterr_flag);
+ 
+  if ~isnan(grains{i}.strain.comment)
+    faults=[faults; grains{i}.id];
+    comments=[comments; grains{i}.strain.comment];
+  end
+  
+end
+
+disp(' ')
+disp(sprintf('Strain tensor determination failed in %d grains with the following ID-s:',length(faults)))
+for j=1:length(faults)
+  disp(sprintf('   %4d   %s',faults(j), comments(j,:)))
+end
+    
+
+% Handle cell arrays or a single one as output
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+grain=grainsout;
+
+save('straingrains_lastrun.mat','grain');
+
+toc
+
+end
diff --git a/zUtil_Strain/gtStrainNormalProductSTD.m b/zUtil_Strain/gtStrainNormalProductSTD.m
new file mode 100755
index 0000000000000000000000000000000000000000..2a6418b8d2480a39bfd866d8c55c382d71dc6d7b
--- /dev/null
+++ b/zUtil_Strain/gtStrainNormalProductSTD.m
@@ -0,0 +1,138 @@
+function stdnn=gtStrainNormalProductSTD(n1,n2,dn1z,dn2z,da1,da2,...
+                                        std_allnz1,std_allnz2,std_alla1,std_alla2)
+
+% Expected std of dot product n1*n2.
+%
+% INPUT  n1,n2             normal vectors
+%        dn1z,dn2z         measured error of the variables (~2std); or NaN; 
+%        da1,da2             z components of n and the azimuth in radians (!)
+%        std_avnz,std_ava  computed std (1 and not 2 std); 
+%                            used if the ones above are unknown
+%
+
+% STD to be used; known or the average
+if isnan(dn1z)
+  stdn1z=std_allnz1;
+else
+  stdn1z=dn1z/2;
+end
+if isnan(da1)
+  stda1=std_alla1;
+else
+  stda1=da1/2;
+end
+
+if isnan(dn2z)
+  stdn2z=std_allnz2;
+else
+  stdn2z=dn2z/2;
+end
+if isnan(da2)
+  stda2=std_alla2;
+else
+  stda2=da2/2;
+end
+
+n1z=n1(3);
+n2z=n2(3);
+a1=atan2(n1(2),n1(1)); % azimuth angle
+a2=atan2(n2(2),n2(1));
+
+% Normal product:
+% F=n1*n2=n1x*n2x+n1y*n2y+n1z*n2z
+% F=Fx+Fy+Fz
+
+% Derivatives of Fx:
+% Fx=sqrt(1-n1z^2)*cosd(a1)*sqrt(1-n2z^2)*cosd(a2)
+dFxdn1z=-n1z/sqrt(1-n1z^2)*cos(a1)*sqrt(1-n2z^2)*cos(a2);
+dFxdn2z=sqrt(1-n1z^2)*cos(a1)*(-n2z)/sqrt(1-n2z^2)*cos(a2);
+dFxda1=sqrt(1-n1z^2)*(-sin(a1))*sqrt(1-n2z^2)*cos(a2);
+dFxda2=sqrt(1-n1z^2)*cos(a1)*sqrt(1-n2z^2)*(-sin(a2));
+
+% Derivatives of Fy:
+% Fx=sqrt(1-n1z^2)*sind(a1)*sqrt(1-n2z^2)*sind(a2)
+dFydn1z=-n1z/sqrt(1-n1z^2)*sin(a1)*sqrt(1-n2z^2)*sin(a2);
+dFydn2z=sqrt(1-n1z^2)*sin(a1)*(-n2z)/sqrt(1-n2z^2)*sin(a2);
+dFyda1=sqrt(1-n1z^2)*cos(a1)*sqrt(1-n2z^2)*sin(a2);
+dFyda2=sqrt(1-n1z^2)*sin(a1)*sqrt(1-n2z^2)*cos(a2);
+
+% Derivatives of Fz:
+% Fz=n1z*n2z
+dFzdn1z=n2z;
+dFzdn2z=n1z;
+dFzda1=0;
+dFzda2=0;
+
+termn1z=dFxdn1z^2 + dFydn1z^2 + dFzdn1z^2 + ...
+  2*dFxdn1z*dFydn1z + 2*dFxdn1z*dFzdn1z + 2*dFydn1z*dFzdn1z ;
+termn2z=dFxdn2z^2 + dFydn2z^2 + dFzdn2z^2 + ...
+  2*dFxdn2z*dFydn2z + 2*dFxdn2z*dFzdn2z + 2*dFydn2z*dFzdn2z ;
+terma1=dFxda1^2 + dFyda1^2 + dFzda1^2 + ...
+  2*dFxda1*dFyda1 + 2*dFxda1*dFzda1 + 2*dFyda1*dFzda1 ;
+terma2=dFxda2^2 + dFyda2^2 + dFzda2^2 + ...
+  2*dFxda2*dFyda2 + 2*dFxda2*dFzda2 + 2*dFyda2*dFzda2 ;
+
+varnn= termn1z*stdn1z^2 + termn2z*stdn2z^2 + terma1*stda1^2 + terma2*stda2^2;
+
+stdnn=sqrt(varnn);
+
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zUtil_Strain/gtStrainPlanes.m b/zUtil_Strain/gtStrainPlanes.m
new file mode 100755
index 0000000000000000000000000000000000000000..3943bccb84807de51ffea11f3e2c732ee67afdce
--- /dev/null
+++ b/zUtil_Strain/gtStrainPlanes.m
@@ -0,0 +1,42 @@
+% Adds strain values to each plane in a grain structure, given a reference lattice
+% parameter.
+% If not a fix reference lattice parameter, but relative measurements between 
+% two datasets are to be used, this is the macro to be extended.
+
+function grainsout=gtStrainPlanes(grainsinp,latticeparref)
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or a single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+for i=1:nof_grains
+
+  % Strain in each plane
+  nof_pl=size(grains{i}.pl,1); % number of planes in grain
+  for j=1:nof_pl
+    grains{i}.plstrain(j)= (grains{i}.pla(j) / latticeparref) - 1 ;
+  end
+
+  % Same for unique planes
+  nof_unipl=size(grains{i}.uni.pl,1); % number of unique planes in grain
+  for j=1:nof_unipl
+    grains{i}.uni.plstrain(j)= (grains{i}.uni.pla(j) / latticeparref) - 1 ;
+  end
+
+  grains{i}.latticeparref=latticeparref;
+
+end
+  
+% Handle cell arrays or a single one as output
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+end
diff --git a/zUtil_Strain/gtStrainPlotResults.m b/zUtil_Strain/gtStrainPlotResults.m
new file mode 100755
index 0000000000000000000000000000000000000000..2b542651f67730f70be28e1b937c21d3306a4b83
--- /dev/null
+++ b/zUtil_Strain/gtStrainPlotResults.m
@@ -0,0 +1,329 @@
+% function gtPlotStrainResults(grainsinp,write_flag)
+
+function gtStrainPlotResults(grainsinp,write_flag,prefix)
+
+
+if ~exist('write_flag','var')
+  write_flag=false;
+end
+
+if ~exist('prefix','var')
+  prefix=[];
+end
+
+ds=dir('strainresults');
+if isempty(ds)
+  mkdir('strainresults');
+end
+
+fdir='strainresults/';
+fs=16;
+c=[ 0.2778    0.1736    0.1106];
+
+%close all
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or a single one
+if nof_grains==1
+  grain{1}=grainsinp;
+else
+  grain=grainsinp;
+end
+
+cfBarEstdEcompFittype
+
+cfBarErrfactEcompFitALL
+
+%return
+
+cfBarEstdAllgrains(1)
+cfBarEstdAllgrains(2)
+cfBarEstdAllgrains(3)
+cfBarEstdAllgrains(4)
+cfBarEstdAllgrains(5)
+cfBarEstdAllgrains(6)
+
+cfBarEAllgrains(1)
+cfBarEAllgrains(2)
+cfBarEAllgrains(3)
+cfBarEAllgrains(4)
+cfBarEAllgrains(5)
+cfBarEAllgrains(6)
+
+% binw.E12=0.0002;
+% edges_st.E12=-0.004;
+% edges_end.E12=0.004;
+% 
+% binw.E33=0.0005;
+% edges_st.E33=-0.005;
+% edges_end.E33=0.01;
+% 
+% binw.E11=0.0005;
+% edges_st.E11=-0.007;
+% edges_end.E11=0.007;
+
+binw.E12=0.0005;
+edges_st.E12=-0.01;
+edges_end.E12=0.01;
+
+binw.E33=0.0005;
+edges_st.E33=-0.01;
+edges_end.E33=0.01;
+
+binw.E11=0.0005;
+edges_st.E11=-0.01;
+edges_end.E11=0.01;
+
+%keyboard
+pause(10)
+
+cfHistE(1,'E11')
+cfHistE(2,'E11')
+cfHistE(3,'E33')
+cfHistE(4,'E12')
+cfHistE(5,'E12')
+cfHistE(6,'E12')
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function cfBarEstdEcompFittype
+
+name=[prefix, 'BarEStdEcompFittype'];
+%xlab='\epsilon_{11}  \epsilon_{22}  \epsilon_{33}  \epsilon_{12}  \epsilon_{13}  \epsilon_{23}';
+ylab='Mean error of \epsilon components [std]';
+
+for ii=1:6
+  m1=gtAllGrainValues(grain,'strain','std_sp',ii);
+  m2=gtAllGrainValues(grain,'strain','std_dev',ii);
+  m3=gtAllGrainValues(grain,'strain','std',ii);
+  m(ii,1)=mean(m1(~isnan(m1)));
+  m(ii,2)=mean(m2(~isnan(m2)));
+  m(ii,3)=mean(m3(~isnan(m3)));
+end
+
+disp('Grand average of Std(epsilon) vs. fit type:')
+mean(m,1)
+
+figure('name',name)
+bar(m,'group')
+
+set(gca,'xtick',[])
+text(1,0,'\epsilon_{11}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(2,0,'\epsilon_{22}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(3,0,'\epsilon_{33}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(4,0,'\epsilon_{12}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(5,0,'\epsilon_{13}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(6,0,'\epsilon_{23}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+
+set(gca,'fontunits', 'points','fontsize',fs)
+legend('Fit d-spacings','Fit angles','Fit both','Location','best') % ,'fontsize',fs)
+%xlabel(xlab,'fontunits', 'points','fontsize',fs)
+%ylabel(ylab,'fontunits', 'points','fontsize',fs)
+%xlabel(xlab,'fontsize',fs)
+ylabel(ylab,'fontsize',fs)
+colormap autumn
+
+if write_flag
+  pdfprint([fdir, name])
+end
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function cfBarErrfactEcompFitALL
+
+name=[prefix, 'BarErrfactEcompFitALL'];
+%xlab='\epsilon_{11}  \epsilon_{22}  \epsilon_{33}  \epsilon_{12}  \epsilon_{13}  \epsilon_{23}';
+ylab='Mean error factors of \epsilon components';
+
+% xlab{1}=' \epsilon_{11}';
+% xlab{2}=' \epsilon_{12}';
+% xlab{3}=' \epsilon_{13}';
+% xlab{4}=' \epsilon_{12}';
+% xlab{5}=' \epsilon_{13}';
+% xlab{6}=' \epsilon_{23}';
+
+
+for ii=1:6
+  m1=gtAllGrainValues(grain,'strain','errfact',ii,1); % dy
+  m2=gtAllGrainValues(grain,'strain','errfact',ii,2); % dz
+  m3=gtAllGrainValues(grain,'strain','errfact',ii,3); % om
+  m(ii,1)=mean(m1(~isnan(m1)));
+  m(ii,2)=mean(m2(~isnan(m2)));
+  m(ii,3)=mean(m3(~isnan(m3)));
+end
+
+figure('name',name)
+bar(m,'group')
+
+set(gca,'xtick',[])
+text(1,0,'\epsilon_{11}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(2,0,'\epsilon_{22}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(3,0,'\epsilon_{33}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(4,0,'\epsilon_{12}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(5,0,'\epsilon_{13}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+text(6,0,'\epsilon_{23}','VerticalAlignment','top','HorizontalAlignment','center','FontSize',fs)
+
+set(gca,'fontunits', 'points','fontsize',fs)
+legend('d_{y}','d_{z}','\omega','Location','best') % ,'fontsize',fs)
+%xlabel(xlab,'fontsize',fs)
+ylabel(ylab,'fontsize',fs)
+%set(gca,'XTicklabel',xlab,'fontsize',fs)
+colormap winter
+
+if write_flag
+  pdfprint([fdir, name])
+end
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function cfBarEstdAllgrains(E)
+
+name=[prefix, 'BarEStdAllGrains'];
+
+switch E
+  case 1
+    E_string='Error in \epsilon_{11} [std]';
+    fname=[name '11'];
+  case 2
+    E_string='Error in \epsilon_{22} [std]';
+    fname=[name '22'];
+  case 3
+    E_string='Error in \epsilon_{33} [std]';
+    fname=[name '33'];
+  case 4
+    E_string='Error in \epsilon_{12} [std]';
+    fname=[name '12'];
+  case 5
+    E_string='Error in \epsilon_{13} [std]';
+    fname=[name '13'];
+  case 6
+    E_string='Error in \epsilon_{23} [std]';
+    fname=[name '23'];
+end
+
+xlab='Grain ID';
+ylab=E_string;
+
+m=gtAllGrainValues(grain,'strain','std',E); % E11, Fit ALL
+
+figure('name',fname)
+%bar(m,'group')
+bar(m,'b')
+set(gcf,'units','centimeters','paperunits','centimeters','paperpositionmode','manual');
+set(gcf,'Position',[0 0 40 15])
+set(gca,'Position',[0.06 0.12 0.92 0.8])
+set(gca,'fontunits', 'points','fontsize',fs)
+xlabel(xlab,'fontsize',fs)
+ylabel(ylab,'fontsize',fs)
+set(gca,'XTick',0:10:length(m))
+
+if write_flag
+  pdfprint([fdir, fname])
+end
+
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function cfBarEAllgrains(E)
+
+name=[prefix, 'BarEAllGrains'];
+
+switch E
+  case 1
+    E_string='\epsilon_{11}';
+    fname=[name '11'];
+  case 2
+    E_string='\epsilon_{22}';
+    fname=[name '22'];
+  case 3
+    E_string='\epsilon_{33}';
+    fname=[name '33'];
+  case 4
+    E_string='\epsilon_{12}';
+    fname=[name '12'];
+  case 5
+    E_string='\epsilon_{13}';
+    fname=[name '13'];
+  case 6
+    E_string='\epsilon_{23}';
+    fname=[name '23'];
+end
+
+xlab='Grain ID';
+ylab=E_string;
+
+m=gtAllGrainValues(grain,'strain','Eps',E);
+
+figure('name',fname)
+%bar(m,'group')
+bar(m,'FaceColor',c)
+set(gcf,'units','centimeters','paperunits','centimeters','paperpositionmode','manual');
+set(gcf,'Position',[0 0 40 15])
+set(gca,'Position',[0.06 0.12 0.92 0.8])
+set(gca,'fontunits', 'points','fontsize',fs)
+xlabel(xlab,'fontsize',fs)
+ylabel(ylab,'fontsize',fs)
+set(gca,'XTick',0:10:length(m))
+
+if write_flag
+  pdfprint([fdir, fname])
+end
+
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function cfHistE(E,b)
+
+name=[prefix, 'Histogram of ',cfEString(E)];
+xlab=cfEString(E);
+ylab=[prefix, 'Frequency of ',cfEString(E)];
+
+edges_act=edges_st.(b):binw.(b):edges_end.(b);
+bins_act=(edges_st.(b)+binw.(b)/2):binw.(b):edges_end.(b);
+
+m=gtAllGrainValues(grain,'strain','Eps',E); % E11, Fit ALL
+
+m=histc(m,edges_act);
+m(end)=[];
+
+figure('name',name)
+bar(bins_act,m,'FaceColor',c,'EdgeColor','w')
+set(gca,'fontunits', 'points','fontsize',fs)
+xlabel(xlab,'fontsize',fs)
+ylabel(ylab,'fontsize',fs)
+
+fname=[prefix, 'HistE',num2str(E)];
+
+if write_flag
+  pdfprint([fdir, fname])
+end
+
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function E_string=cfEString(E)
+
+switch E
+  case 1
+    E_string='\epsilon_{11}';
+  case 2
+    E_string='\epsilon_{22}';
+  case 3
+    E_string='\epsilon_{33}';
+  case 4
+    E_string='\epsilon_{12}';
+  case 5
+    E_string='\epsilon_{13}';
+  case 6
+    E_string='\epsilon_{23}';
+end
+
+end
+
+
+end
diff --git a/zUtil_Strain/gtStrainSpotSpread.m b/zUtil_Strain/gtStrainSpotSpread.m
new file mode 100755
index 0000000000000000000000000000000000000000..d406cd9db4c76ec5f411ea3fec0ae1b4d80ca2b0
--- /dev/null
+++ b/zUtil_Strain/gtStrainSpotSpread.m
@@ -0,0 +1,75 @@
+function grainsout=gtStrainSpotSpread(grainsinp,thetatype)
+
+% if ~exist('difspottable','var')
+ 	load parameters.mat
+ 	difspottable=[parameters.acq.name 'difspot'];
+% end
+
+if ~exist('thetatype','var')
+	thetatype=[];
+end
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or a single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+gtDBConnect;
+
+figure('name','Average spot spread vs. principal strain')
+hold on
+xlabel('Maximum principal strain')
+ylabel('Normalised extension')
+
+for i=1:nof_grains
+
+	normext=[];
+	ext=[];
+	lf=[];
+	
+	for j=1:grains{i}.nof_pairs
+
+		mycmd=sprintf('SELECT (EndImage-StartImage+1) FROM %s WHERE difspotID=%d',...
+			    difspottable,grains{i}.difspots(j));
+		ext1=mym(mycmd);
+		
+		mycmd=sprintf('SELECT (EndImage-StartImage+1) FROM %s WHERE difspotID=%d',...
+			    difspottable,grains{i}.difspots(j+grains{i}.nof_pairs));
+		ext2=mym(mycmd);
+
+		lf(j)=1/sind(2*grains{i}.theta(j))/abs(sind(grains{i}.eta(j)));
+  	%lf(j)=1/abs(sind(grains{i}.eta(j)));
+
+		normext(j)=(ext1+ext2)/2/lf(j);
+		ext(j)=(ext1+ext2)/2;
+	
+	end
+	
+	grains{i}.Lorentzfactor=lf;
+	grains{i}.normext=normext;
+	grains{i}.ext=ext;
+
+	if isempty(thetatype)
+		m=mean(normext);
+	else
+		m=mean(normext(ismember(grains{i}.thetatype,thetatype)));
+	end
+	
+	%plot(grains{i}.strain.Eps(3),mean(ext),'.')
+	plot(grains{i}.strain.pstrainmax,m,'.')
+	
+end
+
+
+% Handle cell arrays or a single one as output
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+end
\ No newline at end of file
diff --git a/zUtil_Strain/gtStrainSpotSpreadDiff.m b/zUtil_Strain/gtStrainSpotSpreadDiff.m
new file mode 100755
index 0000000000000000000000000000000000000000..0dba139e61c86082648268d4f481bb22d0442da2
--- /dev/null
+++ b/zUtil_Strain/gtStrainSpotSpreadDiff.m
@@ -0,0 +1,28 @@
+function [dpstrain,dnormext]=gtStrainSpotSpreadDiff(grainb,grainc,matchg)
+
+nof_grainsb=length(grainb);
+
+
+figure('name','Diff in average spot spread vs. diff. in principal strain')
+hold on
+xlabel('Diff. in absolut maximum principal strain')
+ylabel('Diff. in normalised extension')
+
+for i=1:nof_grainsb
+
+	if ~isnan(matchg(i,2))
+		dnormext(i)=mean(grainc{matchg(i,2)}.normext)-mean(grainb{i}.normext);
+%		dpstrain(i)=abs(grainc{matchg(i,2)}.strain.pstrainmax)-abs(grainb{i}.strain.pstrainmax);
+		dpstrain(i)=grainc{matchg(i,2)}.strain.pstrainmax-grainb{i}.strain.pstrainmax;
+%		dpstrain(i)=grainc{matchg(i,2)}.strain.Eps(3)-grainb{i}.strain.Eps(3);
+		
+		plot(dpstrain(i),dnormext(i),'.')
+	else
+		dnormext(i)=NaN;
+		dpstrain(i)=NaN;
+	end
+	
+	
+end
+
+end
\ No newline at end of file
diff --git a/zUtil_Strain/gtStrainSpotSpreadDiff_B.m b/zUtil_Strain/gtStrainSpotSpreadDiff_B.m
new file mode 100755
index 0000000000000000000000000000000000000000..d77bc1d84d2216e44b157bb9c0544555bb5bfc6c
--- /dev/null
+++ b/zUtil_Strain/gtStrainSpotSpreadDiff_B.m
@@ -0,0 +1,44 @@
+function [dpstrain,dnormext]=gtStrainSpotSpreadDiff_B(grainb,grainc,matchg)
+
+nof_grainsb=length(grainb);
+
+
+figure('name','Diff in average spot spread vs. diff. in principal strain')
+hold on
+xlabel('Diff. in absolut maximum principal strain')
+ylabel('Diff. in normalised extension')
+
+for i=1:nof_grainsb
+
+	if ~isnan(matchg(i,2))
+
+		[ab,bb]=sort(grainb{i}.uni.etaq,'ascend');
+		nb=bb(1:3);
+		mb=[];
+		for ii=1:length(nb)
+			mb=[mb, find(grainb{i}.uni.plid(nb(ii),:))];
+		end
+
+		[ac,bc]=sort(grainc{matchg(i,2)}.uni.etaq,'ascend');
+		nc=bc(1:3);
+		mc=[];
+		for ii=1:length(nc)
+			mc=[mc, find(grainc{matchg(i,2)}.uni.plid(nc(ii),:))];
+		end
+	
+		
+		dnormext(i)=mean(grainc{matchg(i,2)}.normext(mc))-mean(grainb{i}.normext(mb));
+%		dpstrain(i)=abs(grainc{matchg(i,2)}.strain.pstrainmax)-abs(grainb{i}.strain.pstrainmax);
+		dpstrain(i)=grainc{matchg(i,2)}.strain.pstrainmax-grainb{i}.strain.pstrainmax;
+%		dpstrain(i)=grainc{matchg(i,2)}.strain.Eps(3)-grainb{i}.strain.Eps(3);
+		
+		plot(dpstrain(i),dnormext(i),'.')
+	else
+		dnormext(i)=NaN;
+		dpstrain(i)=NaN;
+	end
+	
+	
+end
+
+end
\ No newline at end of file
diff --git a/zUtil_Strain/gtStrainTensor.m b/zUtil_Strain/gtStrainTensor.m
new file mode 100755
index 0000000000000000000000000000000000000000..c5eef8edabfbb161b0b3916cc3f83ba9e3d423f7
--- /dev/null
+++ b/zUtil_Strain/gtStrainTensor.m
@@ -0,0 +1,272 @@
+% Least squares fit of the strain tensor in a grain.
+% Uses  grain.pl, .uni.plid, .thetatype, .plstrain  values.
+
+
+function [ST,res,Mplid]=gtStrainTensor(grain,ACM,mode_flag)
+
+if mode_flag==2
+  disp(' ')
+  disp('Infinite number of solutions....')
+  disp(' ')
+  ST=NaN(3);
+  totressqr=NaN;
+  res=NaN;
+  Mplid=[NaN NaN];
+  return
+end
+
+
+
+if size(grain.uni.plid,1)<3 % not enough input data; strain tensor undetermined
+  ST=NaN(3);
+  totressqr=NaN;
+  res=NaN;
+  Mplid=[NaN NaN];
+  return
+end
+
+
+nof_pl=size(grain.pl,1);  
+
+STINP=[];
+
+% Different projections of the strain values (relative displacement vector)
+for i=1:nof_pl
+  for j=(i+1):nof_pl
+
+    if find(grain.uni.plid(:,i))~=find(grain.uni.plid(:,j))
+      % they don't come from the same plane normal
+
+      n1=grain.pl(i,:);
+      n2=grain.pl(j,:);
+
+      % find original (unstrained) angle between those plane normals
+      ACV=ACM{grain.thetatype(i),grain.thetatype(j)};
+      ang=gt2PlanesAngle(n1,n2);
+      [minval,minloc]=min(abs(ACV-ang));
+      origdotpro=cosd(ACV(minloc));
+
+      if n1*n2'<0 % plane normals direction opposite
+        origdotpro=-origdotpro; % set the sign of original dot product correctly
+      end
+
+      STINP=[STINP; [i j origdotpro]];
+
+    end
+
+  end
+end
+
+Sg0=gtStrainTensor_allplBragg(grain);
+if any(isnan(Sg0))
+  Sg0=zeros(1,6);
+else
+  Sg0=[Sg0(1,1) Sg0(2,2) Sg0(3,3) Sg0(1,2) Sg0(1,3) Sg0(2,3)] ;
+end
+
+[Dopt,fval,exitflag]=fminsearch(@(Sg) ...
+  sfLSQresidual(Sg,grain,STINP,mode_flag),Sg0,...
+  optimset('TolX',1e-10,'MaxIter',5000,'MaxFunEvals',5000)); %,'Display','iter'));
+
+if exitflag~=1
+  disp(' ')
+  disp('No optimized values for correction were found.')
+  disp(' ')
+  ST=NaN(3);
+  totressqr=NaN;
+  res=NaN;
+  Mplid=[NaN NaN];
+  return
+end
+
+
+% aaa=evalin('base','ST0')';aaa=[aaa(1,1) aaa(2,2) aaa(3,3)  aaa(1,2) aaa(1,3) aaa(2,3)];
+% [totressqr2,DT2,res2,Mplid2]=sfLSQresidual(aaa,grain,STINP,mode_flag);
+
+[totressqr,ST,res,Mplid]=sfLSQresidual(Dopt,grain,STINP,mode_flag);
+
+
+ 
+end 
+
+
+
+
+
+
+%% Function to be optimized - sum of residual squares (LSQM)
+
+
+function [totressqr,ST,res,Mplid]=sfLSQresidual(Sg,grain,STINP,mode_flag)
+
+switch mode_flag
+  case 2
+    ST=[Sg(1) Sg(3) Sg(4);...
+        Sg(3) Sg(2) Sg(5);...
+        Sg(4) Sg(5) 0 ];
+  case {0,1}
+    ST=[Sg(1) Sg(4) Sg(5);...
+        Sg(4) Sg(2) Sg(6);...
+        Sg(5) Sg(6) Sg(3)];
+end 
+  
+nof_pl=size(grain.pl,1);  
+res=[];
+Mplid=[];
+
+
+I=eye(3); % identity matrix
+
+B=inv(I+ST);
+
+% Changes in the interplanar angles
+for i=1:size(STINP,1)
+  plid1=STINP(i,1);
+  plid2=STINP(i,2);
+  origdotpro=STINP(i,3);
+  
+  n1=grain.pl(plid1,:);
+  n2=grain.pl(plid2,:);
+  
+  e12=cross(n1,n2);
+  e1=cross(n1,e12);
+  e2=cross(n2,e12);
+  
+  e12=e12/norm(e12);
+  e1=e1/norm(e1);
+  e2=e2/norm(e2);
+
+  e12o=(B*e12')'; 
+  e1o=(B*e1')';
+  e2o=(B*e2')';
+
+  A1o=norm(cross(e12o,e1o));
+  A2o=norm(cross(e12o,e2o));
+  
+  e12o=e12o/norm(e12o);
+  e1o=e1o/norm(e1o);
+  e2o=e2o/norm(e2o);
+  
+  n1o=cross(e12o,e1o);
+  n1o=n1o/norm(n1o);
+
+  n2o=cross(e12o,e2o);
+  n2o=n2o/norm(n2o);
+  
+  switch mode_flag
+    case 0
+      resnew1=grain.plstrain(plid1)-(det(ST+I)*A1o-1);
+      resnew2=grain.plstrain(plid2)-(det(ST+I)*A2o-1);
+      resnew3=n1o*n2o'-origdotpro;
+      resnew4=n1o*n2o'-origdotpro;
+      resnew=[resnew1; resnew2; resnew3; resnew4];
+      Mplidnew=[STINP(i,1:2); STINP(i,1:2); STINP(i,1:2); STINP(i,1:2)];
+    case 1
+      resnew1=grain.plstrain(plid1)-(det(ST+I)*A1o-1);
+      resnew2=grain.plstrain(plid2)-(det(ST+I)*A2o-1);
+      resnew=[resnew1; resnew2];
+      Mplidnew=[STINP(i,1:2); STINP(i,1:2)];
+    case 2
+      resnew=n1o*n2o'-origdotpro;
+      Mplidnew=STINP(i,1:2);
+  end
+  
+  res=[res; resnew]; 
+  Mplid=[Mplid; Mplidnew];  
+  
+end
+
+totressqr=sum((res).^2);
+
+end
+
+
+
+
+
+
+
+% function [totressqr,ST,res,Mplid]=sfLSQresidual(Sg,grain,STINP,mode_flag)
+% 
+% switch mode_flag
+%   case 2
+%     ST=[Sg(1) Sg(3) Sg(4);...
+%         Sg(3) Sg(2) Sg(5);...
+%         Sg(4) Sg(5) 0 ];
+%   case {0,1}
+%     ST=[Sg(1) Sg(4) Sg(5);...
+%         Sg(4) Sg(2) Sg(6);...
+%         Sg(5) Sg(6) Sg(3)];
+% end 
+%   
+% nof_pl=size(grain.pl,1);  
+% res=[];
+% Mplid=[];
+% 
+% 
+% I=eye(3); % identity matrix
+% 
+% B=inv(I+ST);
+% 
+% % Changes in the interplanar angles
+% for i=1:size(STINP,1)
+%   plid1=STINP(i,1);
+%   plid2=STINP(i,2);
+%   origdotpro=STINP(i,3);
+%   
+%   n1=grain.pl(plid1,:);
+%   n2=grain.pl(plid2,:);
+%   
+%   e12=cross(n1,n2);
+%   e1=cross(n1,e12);
+%   e2=cross(n2,e12);
+%   
+%   e12=e12/norm(e12);
+%   e1=e1/norm(e1);
+%   e2=e2/norm(e2);
+% 
+%   e12o=(B*e12')'; 
+%   e1o=(B*e1')';
+%   e2o=(B*e2')';
+% 
+%   A1o=norm(cross(e12o,e1o));
+%   A2o=norm(cross(e12o,e2o));
+%   
+%   e12o=e12o/norm(e12o);
+%   e1o=e1o/norm(e1o);
+%   e2o=e2o/norm(e2o);
+%   
+%   n1o=cross(e12o,e1o);
+%   n1o=n1o/norm(n1o);
+% 
+%   n2o=cross(e12o,e2o);
+%   n2o=n2o/norm(n2o);
+%   
+%   switch mode_flag
+%     case 0
+%       resnew1=grain.plstrain(plid1)-(det(ST+I)*A1o-1);
+%       resnew2=grain.plstrain(plid2)-(det(ST+I)*A2o-1);
+%       resnew3=n1o*n2o'-origdotpro;
+%       resnew4=n1o*n2o'-origdotpro;
+%       resnew=[resnew1; resnew2; resnew3; resnew4];
+%       Mplidnew=[STINP(i,1:2); STINP(i,1:2); STINP(i,1:2); STINP(i,1:2)];
+%     case 1
+%       resnew1=grain.plstrain(plid1)-(det(ST+I)*A1o-1);
+%       resnew2=grain.plstrain(plid2)-(det(ST+I)*A2o-1);
+%       resnew=[resnew1; resnew2];
+%       Mplidnew=[STINP(i,1:2); STINP(i,1:2)];
+%     case 2
+%       resnew=n1o*n2o'-origdotpro;
+%       Mplidnew=STINP(i,1:2);
+%   end
+%   
+%   res=[res; resnew]; 
+%   Mplid=[Mplid; Mplidnew];  
+%   
+% end
+% 
+% totressqr=sum((res*1e5).^2);
+% 
+% end
+
+
diff --git a/zUtil_Strain/gtStrainTensorFit.m b/zUtil_Strain/gtStrainTensorFit.m
new file mode 100755
index 0000000000000000000000000000000000000000..a1208caa527476970ef8696536cc9428c10d9209
--- /dev/null
+++ b/zUtil_Strain/gtStrainTensorFit.m
@@ -0,0 +1,536 @@
+% Linear solution (or least squares fit) of the strain tensor in a grain.
+% Uses  grain.uni.pl  and  grain.uni.plstrain  values.
+
+
+function grain=gtStrainTensorFit(grain,ACM,errest,limiterr_flag)
+
+nof_unipl=size(grain.uni.pl,1);
+
+% Set output
+grain.strain.ST=NaN(3);
+grain.strain.ST_sp=NaN(3);
+grain.strain.ST_dev=NaN(3);
+
+grain.strain.Eps=NaN(1,6);
+
+grain.strain.std=NaN(1,6);
+grain.strain.std_sp=NaN(1,6);
+grain.strain.std_dev=NaN(1,6);
+
+grain.strain.stdy_sp=NaN;
+grain.strain.stdy_dev=NaN;
+
+grain.strain.errfact=NaN(6,3);
+grain.strain.errfact_sp=NaN(6,3);
+grain.strain.errfact_dev=NaN(6,3);
+
+grain.strain.straininlab=NaN(1,3);
+
+grain.strain.pstrain=NaN(1,3);
+grain.strain.pstraindir=NaN(3); % principal dirs are in columns
+grain.strain.pstrainmax=NaN;
+grain.strain.pstrainmaxdir=NaN(1,3);
+
+grain.strain.comment=NaN;
+
+if size(grain.uni.pl,1)<3
+  grain.strain.comment='Not enough unique planes.';
+  return
+end
+
+%% Prepare input values %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Linear operators to create the system of equations
+Lop5=@(a,b) [a(1)*b(1)-a(3)*b(3), a(2)*b(2)-a(3)*b(3), a(1)*b(2)+a(2)*b(1), ...
+     a(1)*b(3)+a(3)*b(1), a(2)*b(3)+a(3)*b(2)];
+Xop5=@(a,b) (a*b')*Lop5(a,a)+(a*b')*Lop5(b,b)-2*Lop5(a,b);
+   
+Lop6=@(a,b) [a(1)*b(1), a(2)*b(2), a(3)*b(3), a(1)*b(2)+a(2)*b(1), ...
+     a(1)*b(3)+a(3)*b(1), a(2)*b(3)+a(3)*b(2)];
+Xop6=@(a,b) (a*b')*Lop6(a,a)+(a*b')*Lop6(b,b)-2*Lop6(a,b);
+
+% System of equation
+%  number of equations:
+Ns_dev=nof_unipl*(nof_unipl-1)/2; % deviatoric (angles)
+Ns_sp=nof_unipl;                  % spacing
+Ns=Ns_dev+Ns_sp;                  % all
+
+% Left side:
+y_dev=zeros(Ns_dev,1); % vector
+y_sp=zeros(Ns_sp,1); % vector
+y=zeros(Ns,1); % vector
+
+N10n20_dev=zeros(Ns_dev,1); % vector
+
+% Derivatives of the plane normal coordinates wrt.
+% the base parameters. Diagonal matrices.
+Nz_dy=zeros(nof_unipl); % dnz/d(dy)
+Nz_dz=zeros(nof_unipl); % dnz/d(dz)
+Nz_om=zeros(nof_unipl); % dnz/d(om)
+Az_dy=zeros(nof_unipl); % daz/d(dy)
+Az_dz=zeros(nof_unipl); % daz/d(dz)
+Az_om=zeros(nof_unipl); % daz/d(om)
+Th_dy=zeros(nof_unipl); % dth/d(dy)
+Th_dz=zeros(nof_unipl); % dth/d(dz)
+Th_om=zeros(nof_unipl); % dth/d(om)
+
+% Derivatives of y wrt. the (plane) normal coordinates
+Y_nz_dev=zeros(Ns_dev,nof_unipl); % dy/nz
+Y_az_dev=zeros(Ns_dev,nof_unipl); % dy/az
+Y_th_dev=zeros(Ns_dev,nof_unipl); % dy/th
+
+Y_nz_sp=zeros(Ns_sp,nof_unipl); % dy/nz
+Y_az_sp=zeros(Ns_sp,nof_unipl); % dy/az
+Y_th_sp=zeros(Ns_sp,nof_unipl); % dy/th
+Y_nz=zeros(Ns,nof_unipl); % dy/nz
+Y_az=zeros(Ns,nof_unipl); % dy/az
+Y_th=zeros(Ns,nof_unipl); % dy/th
+
+% Derivatives of y wrt. the base coordinates
+Y_dy_dev=zeros(Ns_dev,nof_unipl); % dy/d(dy)
+Y_dz_dev=zeros(Ns_dev,nof_unipl); % dy/d(dz)
+Y_om_dev=zeros(Ns_dev,nof_unipl); % dy/d(om)
+
+Y_dy_sp=zeros(Ns_sp,nof_unipl); % dy/d(dy)
+Y_dz_sp=zeros(Ns_sp,nof_unipl); % dy/d(dz)
+Y_om_sp=zeros(Ns_sp,nof_unipl); % dy/d(om)
+
+Y_dy=zeros(Ns,nof_unipl); % dy/d(dy)
+Y_dz=zeros(Ns,nof_unipl); % dy/d(dz)
+Y_om=zeros(Ns,nof_unipl); % dy/d(om)
+
+% Standard deviation and variance of y-s and the base coordinates
+Std_y_dev=zeros(Ns_dev,1);
+Std_y_sp=zeros(Ns_sp,1);
+Std_y=zeros(Ns,1);
+Var_y_dev=zeros(Ns_dev,1);
+Var_y_sp=zeros(Ns_sp,1);
+Var_y=zeros(Ns,1);
+
+Std_dy=zeros(nof_unipl,1);
+Std_dz=zeros(nof_unipl,1); 
+Std_om=zeros(nof_unipl,1); 
+Var_dy=zeros(nof_unipl,1);
+Var_dz=zeros(nof_unipl,1);
+Var_om=zeros(nof_unipl,1);
+
+% Derivatives of epsilon wrt. the y-s
+E_dev=zeros(5,Ns_dev);
+E_sp=zeros(6,Ns_sp);
+E=zeros(6,Ns);
+
+Eb_dev=zeros(5,Ns_dev);
+Eb_sp=zeros(6,Ns_sp);
+Eb=zeros(6,Ns);
+
+% Derivatives of epsilon wrt. the base coordinates
+Gdy_devo=zeros(5,nof_unipl);
+Gdz_devo=zeros(5,nof_unipl);
+Gom_devo=zeros(5,nof_unipl);
+
+Gdy_dev=zeros(6,nof_unipl);
+Gdz_dev=zeros(6,nof_unipl);
+Gom_dev=zeros(6,nof_unipl);
+
+Gdy_sp=zeros(6,nof_unipl);
+Gdz_sp=zeros(6,nof_unipl);
+Gom_sp=zeros(6,nof_unipl);
+
+Gdy=zeros(6,nof_unipl);
+Gdz=zeros(6,nof_unipl);
+Gom=zeros(6,nof_unipl);
+
+% Right side: model matrix
+X_dev=zeros(Ns_dev,5);
+X_sp=zeros(Ns_sp,6);
+X=zeros(Ns,6);
+
+% Plane indices used for a given equation
+Plid_dev=zeros(Ns_dev,2);
+Plid_sp=zeros(Ns_sp,2);
+Plid=zeros(Ns,2);
+
+%% Variance of dy,dz and Nz,Az,Th matrices
+for i=1:nof_unipl
+
+%   if isnan(grain.uni.ddy(i))
+%     Std_dy(i)=errest.std_dy;
+%   else
+%     Std_dy(i)=sqrt(2)*grain.uni.ddy(i);
+%   end
+%   Var_dy(i)=Std_dy(i)^2;
+%   
+%   if isnan(grain.uni.ddz(i))
+%     Std_dz(i)=errest.std_dz;
+%   else
+%     Std_dz(i)=sqrt(2)*grain.uni.ddz(i);
+%   end
+%   Var_dz(i)=Std_dz(i)^2;
+ 
+  if isnan(grain.uni.ddy(i)) 
+    if length(errest.std_dy_thetat) >= grain.uni.thetatype(i)
+      Std_dy(i)=errest.std_dy_thetat(grain.uni.thetatype(i));
+      Std_dz(i)=errest.std_dz_thetat(grain.uni.thetatype(i));
+      Std_om(i)=errest.std_om_thetat(grain.uni.thetatype(i));
+    else
+      Std_dy(i)=errest.std_dy_thetat(grain.uni.thetatype(end));
+      Std_dz(i)=errest.std_dz_thetat(grain.uni.thetatype(end));
+      Std_om(i)=errest.std_om_thetat(grain.uni.thetatype(end));
+    end
+  else
+    Std_dy(i)=sqrt(2)*abs(grain.uni.ddy(i));
+    Std_dz(i)=sqrt(2)*abs(grain.uni.ddz(i));
+    Std_om(i)=sqrt(2)*abs(grain.uni.dom(i));
+  end
+  Var_dy(i)=Std_dy(i)^2;
+  Var_dz(i)=Std_dz(i)^2;
+  Var_om(i)=Std_om(i)^2;
+
+  
+  Nz_dy(i,i)=grain.uni.dnz_ddy(i); % dnz/d(dy); diagonal
+  Nz_dz(i,i)=grain.uni.dnz_ddz(i); % dnz/d(dz); diagonal
+  Nz_om(i,i)=grain.uni.dnz_dom(i); % dnz/d(om); diagonal
+  
+  Az_dy(i,i)=grain.uni.daz_ddy(i); % daz/d(dy); diagonal
+  Az_dz(i,i)=grain.uni.daz_ddz(i); % daz/d(dz); diagonal
+  Az_om(i,i)=grain.uni.daz_dom(i); % daz/d(om); diagonal
+
+  Th_dy(i,i)=grain.uni.dth_ddy(i); % dth/d(dy); diagonal
+  Th_dz(i,i)=grain.uni.dth_ddz(i); % dth/d(dz); diagonal
+  Th_om(i,i)=grain.uni.dth_dom(i); % dth/d(om); diagonal
+
+end
+
+%% Equations - angles
+
+i=0;
+
+for ii=1:nof_unipl-1
+  for jj=ii+1:nof_unipl
+
+  i=i+1;
+    
+  n1=grain.uni.pl(ii,:); % plane normal
+  n2=grain.uni.pl(jj,:);
+  
+  a1=grain.uni.az(ii); % azimuth
+  a2=grain.uni.az(jj);
+  
+  Plid_dev(i,1:2)=[ii,jj];
+  Plid(i,1:2)=[ii,jj];
+ 
+  % LEFT SIDE - measurements of change in n1*n2
+  
+  % find original (unstrained) angle between those plane normals
+  ACV=ACM{grain.uni.thetatype(ii),grain.uni.thetatype(jj)};
+  ang=gt2PlanesAngle(n1,n2);
+  [minval,minloc]=min(abs(ACV-ang));
+  n10n20=abs(cosd(ACV(minloc))); % the original dot product (undeformed)
+
+  % Note: ACV should contain 0<= angles <=90. Two different
+  % unique planes can't have 0 deg between them.
+
+  if n1*n2'<0 % if plane normals direction opposite,
+    n10n20=-n10n20; % the original dot product should be negative as well
+  end
+
+  N10n20_dev(i)=n10n20;
+  y_dev(i)=n10n20-n1*n2'; % change in dot product
+  y(i)=n10n20-n1*n2'; % change in dot product
+  
+  % Y MATRICES
+  n1z=n1(3);
+  n2z=n2(3);
+%   a1=atan2(n1(2),n1(1)); % azimuth angle
+%   a2=atan2(n2(2),n2(1));
+
+  % Normal product:
+  % y=n1*n2=n1x*n2x+n1y*n2y+n1z*n2z
+  % y=Yx+Yy+Yz
+
+  % Derivatives of Yx:
+  %   Yx=sqrt(1-n1z^2)*cosd(a1)*sqrt(1-n2z^2)*cosd(a2)
+  dYx_dn1z=-n1z/sqrt(1-n1z^2)*cos(a1)*sqrt(1-n2z^2)*cos(a2);
+  dYx_dn2z=sqrt(1-n1z^2)*cos(a1)*(-n2z)/sqrt(1-n2z^2)*cos(a2);
+  dYx_da1=sqrt(1-n1z^2)*(-sin(a1))*sqrt(1-n2z^2)*cos(a2);
+  dYx_da2=sqrt(1-n1z^2)*cos(a1)*sqrt(1-n2z^2)*(-sin(a2));
+
+  % Derivatives of Yy:
+  %   Yy=sqrt(1-n1z^2)*sind(a1)*sqrt(1-n2z^2)*sind(a2)
+  dYy_dn1z=-n1z/sqrt(1-n1z^2)*sin(a1)*sqrt(1-n2z^2)*sin(a2);
+  dYy_dn2z=sqrt(1-n1z^2)*sin(a1)*(-n2z)/sqrt(1-n2z^2)*sin(a2);
+  dYy_da1=sqrt(1-n1z^2)*cos(a1)*sqrt(1-n2z^2)*sin(a2);
+  dYy_da2=sqrt(1-n1z^2)*sin(a1)*sqrt(1-n2z^2)*cos(a2);
+
+  % Derivatives of Yz:
+  %   Yz=n1z*n2z
+  dYz_dn1z=n2z;
+  dYz_dn2z=n1z;
+  dYz_da1=0;
+  dYz_da2=0;
+
+  % Derivatives of y:
+  dY_dn1z=dYx_dn1z+dYy_dn1z+dYz_dn1z;
+  dY_dn2z=dYx_dn2z+dYy_dn2z+dYz_dn2z;
+  
+  dY_da1=dYx_da1+dYy_da1+dYz_da1;
+  dY_da2=dYx_da2+dYy_da2+dYz_da2;
+  
+  % Y matrices
+  Y_nz(i,ii)=dY_dn1z; % dy/nz
+  Y_az(i,ii)=dY_da1; % dy/az
+
+  Y_nz(i,jj)=dY_dn2z; % dy/nz
+  Y_az(i,jj)=dY_da2; % dy/az
+
+  Y_nz_dev(i,ii)=dY_dn1z; % dy/nz
+  Y_az_dev(i,ii)=dY_da1; % dy/az
+
+  Y_nz_dev(i,jj)=dY_dn2z; % dy/nz
+  Y_az_dev(i,jj)=dY_da2; % dy/az
+
+  
+  % MODEL MATRIX
+  X_dev(i,1:5)=Xop5(n1,n2);
+  X(i,1:6)=Xop6(n1,n2);
+  
+  end
+end
+
+
+%% Equations - d-spacing
+
+for ii=1:nof_unipl
+
+  i=i+1;
+    
+  n1=grain.uni.pl(ii,:);
+  
+  Plid_sp(ii,1:2)=[ii,ii];
+  Plid(i,1:2)=[ii,ii];
+  
+  % LEFT SIDE - measurements of d-spacing (Bragg's law)
+  
+  % y=reverse strain in each plane
+  y_sp(ii)=-grain.uni.plstrain(ii);
+  y(i)=-grain.uni.plstrain(ii);
+
+  % Derivatives of y:
+  % Y matrices
+  Y_th(i,ii)=-(grain.uni.plstrain(ii)+1)/tand(grain.uni.theta(ii)); % dy/dth
+  Y_th_sp(ii,ii)=Y_th(i,ii);
+  
+  % MODEL MATRIX
+  X_sp(ii,1:6)=Lop6(n1,n1);
+  X(i,1:6)=Lop6(n1,n1);
+end
+
+%% Main stuff
+
+% Derivative of y wrt. the base parameters
+Y_dy_dev = Y_nz_dev*Nz_dy + Y_az_dev*Az_dy + Y_th_dev*Th_dy ; % d(y)/d(dy); N_dev*n
+Y_dz_dev = Y_nz_dev*Nz_dz + Y_az_dev*Az_dz + Y_th_dev*Th_dz ; % d(y)/d(dz); N_dev*n
+Y_om_dev = Y_nz_dev*Nz_om + Y_az_dev*Az_om + Y_th_dev*Th_om ; % d(y)/d(om); N_dev*n
+
+Var_y_dev= Y_dy_dev.^2*Var_dy + Y_dz_dev.^2*Var_dz + Y_om_dev.^2*Var_om;
+Std_y_dev=sqrt(Var_y_dev);
+
+Y_dy_sp = Y_nz_sp*Nz_dy + Y_az_sp*Az_dy + Y_th_sp*Th_dy ; % d(y)/d(dy); N_sp*n
+Y_dz_sp = Y_nz_sp*Nz_dz + Y_az_sp*Az_dz + Y_th_sp*Th_dz ; % d(y)/d(dz); N_sp*n
+Y_om_sp = Y_nz_sp*Nz_om + Y_az_sp*Az_om + Y_th_sp*Th_om ; % d(y)/d(om); N_sp*n
+
+Var_y_sp= Y_dy_sp.^2*Var_dy + Y_dz_sp.^2*Var_dz + Y_om_sp.^2*Var_om;
+Std_y_sp=sqrt(Var_y_sp);
+
+Y_dy = Y_nz*Nz_dy + Y_az*Az_dy + Y_th*Th_dy ; % d(y)/d(dy); N*n
+Y_dz = Y_nz*Nz_dz + Y_az*Az_dz + Y_th*Th_dz ; % d(y)/d(dz); N*n
+Y_om = Y_nz*Nz_om + Y_az*Az_om + Y_th*Th_om ; % d(y)/d(om); N*n
+
+Var_y= Y_dy.^2*Var_dy + Y_dz.^2*Var_dz + Y_om.^2*Var_om;
+Std_y=sqrt(Var_y);
+
+% System matrices
+A_dev=X_dev./repmat(Std_y_dev,1,5);
+A_sp=X_sp./repmat(Std_y_sp,1,6);
+A=X./repmat(Std_y,1,6);
+
+b_dev=y_dev./Std_y_dev;
+b_sp=y_sp./Std_y_sp;
+b=y./Std_y;
+
+% Solution
+if grain.uni.nof_unipl>=4
+  Eb_dev=inv(A_dev'*A_dev)*A_dev';
+else
+  Eb_dev(:,:)=NaN;
+end
+
+if grain.uni.nof_unipl>=6
+  Eb_sp=inv(A_sp'*A_sp)*A_sp';
+else
+  Eb_sp(:,:)=NaN;
+end
+
+if grain.uni.nof_unipl>=3
+ Eb=inv(A'*A)*A';
+else
+ Eb(:,:)=NaN;
+end
+
+
+E_dev=Eb_dev*diag(1./Std_y_dev);
+E_sp=Eb_sp*diag(1./Std_y_sp);
+E=Eb*diag(1./Std_y);
+
+% Epsilon derivative matrices
+%  for 5 epsilon components from fit
+Gdy_devo = E_dev*Y_dy_dev;
+Gdz_devo = E_dev*Y_dz_dev;
+Gom_devo = E_dev*Y_om_dev;
+%  extended to 6 components, including epsilon_dev33
+Gdy_dev = [Gdy_devo(1:2,:); -Gdy_devo(1,:)-Gdy_devo(2,:); Gdy_devo(3:5,:)];
+Gdz_dev = [Gdz_devo(1:2,:); -Gdz_devo(1,:)-Gdz_devo(2,:); Gdz_devo(3:5,:)];
+Gom_dev = [Gom_devo(1:2,:); -Gom_devo(1,:)-Gom_devo(2,:); Gom_devo(3:5,:)];
+
+Gdy_sp = E_sp*Y_dy_sp;
+Gdz_sp = E_sp*Y_dz_sp;
+Gom_sp = E_sp*Y_om_sp;
+
+Gdy = E*Y_dy;
+Gdz = E*Y_dz;
+Gom = E*Y_om;
+
+Errfact_eps_dev=[Gdy_dev.^2*Var_dy , Gdz_dev.^2*Var_dz , Gom_dev.^2*Var_om];
+Var_eps_dev=sum(Errfact_eps_dev,2);
+Errfact_eps_dev=Errfact_eps_dev./repmat(Var_eps_dev,1,3);
+Std_eps_dev=sqrt(Var_eps_dev);
+
+Errfact_eps_sp=[Gdy_sp.^2*Var_dy , Gdz_sp.^2*Var_dz , Gom_sp.^2*Var_om];
+Var_eps_sp=sum(Errfact_eps_sp,2);
+Errfact_eps_sp=Errfact_eps_sp./repmat(Var_eps_sp,1,3);
+Std_eps_sp=sqrt(Var_eps_sp);
+
+Errfact_eps=[Gdy.^2*Var_dy , Gdz.^2*Var_dz , Gom.^2*Var_om];
+Var_eps=sum(Errfact_eps,2);
+Errfact_eps=Errfact_eps./repmat(Var_eps,1,3);
+Std_eps=sqrt(Var_eps);
+
+%% Solution 
+
+% Singular Value Decomposition (SVD)
+%   see e.g. Numerical Recipes
+% Gives maximum likelihood fit when including the uncertainty of each
+% measurement.
+% A=U*S*V'
+% inv(A)=V*diag(1./diag(S))*U'
+% [U,S,V]=svd(A,0);
+% omega=diag(S);
+% erev_svd=V*diag(1./diag(S))*U'*b
+% Covariance matrix of the fitted vector EDrev_vec
+% from the SVD output: not correct for dependent x variables !
+% for j=1:6
+%   for k=1:6
+%     Cov_erev(j,k)=(V(j,:).*V(k,:))*(1./omega.^2);
+%   end
+% end
+% Note that in general Cov_erev=inv(A'*A);
+% std_erev=sqrt(diag(Cov_erev));
+
+% Strain components - normal equations
+%   this could be done by avoiding the matrix inversion in Eb 
+Epsrev_dev=Eb_dev*b_dev;
+Epsrev_sp=Eb_sp*b_sp;
+Epsrev=Eb*b;
+
+% Strain tensors
+Trev_dev=[Epsrev_dev(1) , Epsrev_dev(3) , Epsrev_dev(4) ;...
+          Epsrev_dev(3) , Epsrev_dev(2) , Epsrev_dev(5) ;...
+          Epsrev_dev(4) , Epsrev_dev(5) , -Epsrev_dev(1)-Epsrev_dev(2) ];
+Trev_sp=[Epsrev_sp(1) , Epsrev_sp(4) , Epsrev_sp(5) ;...
+         Epsrev_sp(4) , Epsrev_sp(2) , Epsrev_sp(6) ;...
+         Epsrev_sp(5) , Epsrev_sp(6) , Epsrev_sp(3) ];
+Trev=[Epsrev(1) , Epsrev(4) , Epsrev(5) ;...
+      Epsrev(4) , Epsrev(2) , Epsrev(6) ;...
+      Epsrev(5) , Epsrev(6) , Epsrev(3) ];
+
+I=eye(3);    
+
+if isnan(Trev_dev(1,1))
+  T_dev=NaN(3);
+else
+  T_dev=inv(I+Trev_dev)-I;
+end
+
+if isnan(Trev_sp(1,1))
+  T_sp=NaN(3);
+else
+  T_sp=inv(I+Trev_sp)-I;
+end
+
+if isnan(Trev(1,1))
+  T=NaN(3);
+else
+  T=inv(I+Trev)-I;
+end
+
+% Principal strains        
+[eigvecTmat,eigvalTmat]=eig(T);
+eigvalT=[eigvalTmat(1,1) eigvalTmat(2,2) eigvalTmat(3,3)];
+
+[maxval,maxloc]=max(abs(eigvalT));
+
+
+% Solution output
+
+if limiterr_flag
+
+	if max(Std_eps)>maxval % errors are too large
+		grain.strain.comment='Errors are too large.    ';
+		return
+	end
+
+	if max(Std_eps_dev)>maxval % errors are too large
+		%grain.strain.comment='Errors are too large.    ';
+		T_dev=NaN(3);
+		Std_eps_dev=NaN(6,1);
+		Errfact_eps_dev=NaN(6,3);
+	end
+
+	if max(Std_eps_sp)>maxval % errors are too large
+		%grain.strain.comment='Errors are too large.    ';
+		T_sp=NaN(3);
+		Std_eps_sp=NaN(6,1);
+		Errfact_eps_sp=NaN(6,3);
+	end
+
+end
+
+grain.strain.ST=T;
+grain.strain.ST_sp=T_sp;
+grain.strain.ST_dev=T_dev;
+
+grain.strain.Eps=[T(1,1), T(2,2), T(3,3), T(1,2), T(1,3), T(2,3)];
+
+grain.strain.std=Std_eps';
+grain.strain.std_sp=Std_eps_sp';
+grain.strain.std_dev=Std_eps_dev';
+
+grain.strain.stdy_sp=mean(Std_y_sp);
+grain.strain.stdy_dev=mean(Std_y_dev);
+
+grain.strain.errfact=Errfact_eps;
+grain.strain.errfact_sp=Errfact_eps_sp;
+grain.strain.errfact_dev=Errfact_eps_dev;
+
+grain.strain.straininlab=diag(T)';
+
+grain.strain.pstrain=eigvalT;
+grain.strain.pstraindir=eigvecTmat; % principal dirs are in columns
+grain.strain.pstrainmax=eigvalT(maxloc);
+grain.strain.pstrainmaxdir=eigvecTmat(:,maxloc)';
+
+  
+end
+
+
+
diff --git a/zUtil_Strain/gtStrainTensorFitDev.m b/zUtil_Strain/gtStrainTensorFitDev.m
new file mode 100755
index 0000000000000000000000000000000000000000..100967241f4049bd1d48eb3d8fec48ed36c57f1f
--- /dev/null
+++ b/zUtil_Strain/gtStrainTensorFitDev.m
@@ -0,0 +1,184 @@
+% Linear solution (or least squares fit) of the strain tensor in a grain.
+% Uses  grain.uni.pl  and  grain.uni.plstrain  values.
+
+
+function grain=gtStrainTensorFitDev(grain,ACM,errest)
+
+nof_unipl=size(grain.uni.pl,1);
+
+if size(grain.uni.pl,1)<3
+  return
+end
+
+%% Fit Dev %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Linear operators to create the system of equations
+Lop=@(a,b) [a(1)*b(1)-a(3)*b(3), a(2)*b(2)-a(3)*b(3), a(1)*b(2)+a(2)*b(1), ...
+     a(1)*b(3)+a(3)*b(1), a(2)*b(3)+a(3)*b(2)];
+
+Aop=@(a,b) (a*b')*Lop(a,a)+(a*b')*Lop(b,b)-2*Lop(a,b);
+
+
+sigma_n1n2=[];
+n10n20=[];
+Dn1n2o=[];
+Adevo=[];
+
+% System of equation
+
+for i=1:nof_unipl
+  for j=i+1:nof_unipl
+
+  n1=grain.uni.pl(i,:);
+  n2=grain.uni.pl(j,:);
+
+  % EXPECTED STD-s (measurement error in n1*n2 of the given n1,n2)
+  
+  if length(errest.std_anghor_thetat) >= grain.uni.thetatype(i)
+    std_alla1=errest.std_anghor_thetat(grain.uni.thetatype(i));
+    std_allnz1=errest.std_nz_thetat(grain.uni.thetatype(i));
+  else
+    std_alla1=errest.std_anghor_thetat(end);
+    std_allnz1=errest.std_nz_thetat(end);
+  end
+
+  if length(errest.std_anghor_thetat) >= grain.uni.thetatype(j)
+    std_alla2=errest.std_anghor_thetat(grain.uni.thetatype(j));
+    std_allnz2=errest.std_nz_thetat(grain.uni.thetatype(j));
+  else
+    std_alla2=errest.std_anghor_thetat(end);
+    std_allnz2=errest.std_nz_thetat(end);
+  end
+
+  sigmaij=gtStrainNormalProductSTD(n1,n2,...
+    grain.uni.dn(i,3),grain.uni.dn(j,3),...
+    grain.uni.danghor(i),grain.uni.danghor(j),...
+    std_allnz1,std_allnz2,std_alla1,std_alla2);
+
+  sigma_n1n2=[sigma_n1n2; sigmaij];
+
+  
+  % LEFT SIDE - measurements of change in n1*n2
+  
+  % find original (unstrained) angle between those plane normals
+  ACV=ACM{grain.uni.thetatype(i),grain.uni.thetatype(j)};
+  ang=gt2PlanesAngle(n1,n2);
+  [minval,minloc]=min(abs(ACV-ang));
+  n10n20=abs(cosd(ACV(minloc))); % the original dot product (undeformed)
+
+  % Note: ACV should contain 0<= angles <=90. Two different
+  % unique planes can't have 0 deg between them.
+
+  if n1*n2'<0 % if plane normals direction opposite,
+    n10n20=-n10n20; % the original dot product should be negative as well
+  end
+
+  Dn1n2o=[Dn1n2o; n10n20-n1*n2']; % change in dot product
+
+
+  % RIGHT SIDE - model prediction for change in n1*n2
+  Adevo=[Adevo; Aop(n1,n2)];
+
+  end
+end
+
+m=size(Adevo,2);
+
+Dn1n2=Dn1n2o./sigma_n1n2;
+Adev=Adevo./repmat(sigma_n1n2,1,m);
+
+% Test
+%Adev=Adev(end-14:end,:);
+%Dn1n2=Dn1n2(end-14:end);
+%Adev=Adev(end-10:end,:);
+%Dn1n2=Dn1n2(end-10:end);
+%Adev=[Adev(1:6,:);Adev(1:6,:)];
+%Dn1n2=[Dn1n2(1:6);Dn1n2(1:6)];
+%Adev=Adev(1:5,:);
+%Dn1n2=Dn1n2(1:5);
+
+
+[U,S,V]=svd(Adev,0);
+
+% Singular Value Decomposition (SVD)
+% see e.g. Numerical Recipes
+% Gives maximum likelihood fit when including the uncertainty of each
+% measurement.
+% A=U*S*V'
+% inv(A)=V*diag(1./diag(S))*U'
+omega=diag(S);
+EDrev_vec=V*diag(1./diag(S))*U'*Dn1n2
+
+% Covariance matrix of the fitted vector EDrev_vec
+% from the SVD output:
+for j=1:m
+  for k=1:m
+    Cov_EDrev(j,k)=(V(j,:).*V(k,:))*(1./omega.^2);
+  end
+end
+% Note that in general Cov_EDrev=inv(Adev'*Adev);
+
+std_EDrev=sqrt(diag(Cov_EDrev))
+
+
+
+
+
+
+
+% %Test
+% A=repmat(Adev,100,1);
+% b=repmat(Dn1n2,100,1);
+% [U,S,V]=svd(A,0);
+% omega=diag(S);
+% E=V*diag(1./diag(S))*U'*b;
+% for j=1:m
+%   for k=1:m
+%     Covt(j,k)=(V(j,:).*V(k,:))*(1./omega.^2);
+%   end
+% end
+% stdt=sqrt(diag(Covt));
+% 
+% %Test
+% A=Adev(1:5,1:5);
+% b=Dn1n2(1:5);
+% [U,S,V]=svd(A,0);
+% omega=diag(S);
+% E=V*diag(1./diag(S))*U'*b;
+% for j=1:m
+%   for k=1:m
+%     Covt(j,k)=(V(j,:).*V(k,:))*(1./omega.^2);
+%   end
+% end
+% stdt=sqrt(diag(Covt))
+
+
+  
+  
+  
+        
+%     [eigvecSTmat,eigvalSTmat]=eig(ST);
+%     eigvalST=[eigvalSTmat(1,1) eigvalSTmat(2,2) eigvalSTmat(3,3)];
+%     [STeigval,ordeigval]=sort(eigvalST,'descend');
+%     STeigvec1=eigvecSTmat(:,ordeigval(1));
+%     STeigvec2=eigvecSTmat(:,ordeigval(2));
+%     STeigvec3=eigvecSTmat(:,ordeigval(3));
+%     % Principal strain values in order
+%     grains{i}.pstrain1=STeigval(1);
+%     grains{i}.pstrain2=STeigval(2);
+%     grains{i}.pstrain3=STeigval(3);   
+
+
+
+
+%    
+%     grains{i}.strainGT.pstrainvalues=[NaN NaN NaN];
+%     grains{i}.strainGT.pstrainvalues=[NaN NaN NaN];
+%     grains{i}.strainGT.pstraindir=NaN(3);
+%   
+%     % Strain in directions of the lab system
+%     grains{i}.strainGT.straininlab=[NaN NaN NaN]  
+%     grains{i}.strainGT.straintensor=NaN(3);
+%     grains{i}.strainGT.errors.variance
+  
+end
diff --git a/zUtil_Strain/gtVector2Matrix.m b/zUtil_Strain/gtVector2Matrix.m
new file mode 100755
index 0000000000000000000000000000000000000000..2da62edc66f78103b02f87a6ea036da5f7c2a0bb
--- /dev/null
+++ b/zUtil_Strain/gtVector2Matrix.m
@@ -0,0 +1,7 @@
+function m=gtVector2Matrix(v)
+
+
+           m=[v(1) v(6) v(5);...
+			  v(6) v(2) v(4);...
+			  v(5) v(4) v(3)];
+end			
\ No newline at end of file
diff --git a/zUtil_Strain/myRod2g.m b/zUtil_Strain/myRod2g.m
new file mode 100755
index 0000000000000000000000000000000000000000..46e92711828fb35b4a4c5ed44c25078bc2613297
--- /dev/null
+++ b/zUtil_Strain/myRod2g.m
@@ -0,0 +1,56 @@
+function g = myRod2g(r)
+% function g = Rod2g(r)
+% This function calculates the orientation matrix g given a Rodrigues
+% vector r. 
+% See e.g. equation 3.13 in Three-Dimensional X-Ray Diffraction Microscopy
+% by H.F. Poulsen
+%
+% Written by EML Sept. 04
+
+g=zeros(3,3);   % Initialise the orientation matrix
+%initialise the permutation tensor
+e=calc_perm_tensor;
+
+% Loop over the elements of the orientation matrix
+for i=1:3
+    for j=1:3
+        
+        g(i,j)= (1-dot(r,r))*delta(i,j) + 2*r(i)*r(j);
+       
+        % Summing over the remaining component   
+        for k=1:3
+          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+          %    g(i,j) = g(i,j) - 2*e(i,j,k)*r(k);
+          % changed into:
+          g(i,j) = g(i,j) + 2*e(i,j,k)*r(k);
+          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+          % this just gives the inverse of g! 
+          
+          
+       end
+        g(i,j) = g(i,j)/(1+dot(r,r));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Helper function %%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function  e=calc_perm_tensor
+% Calculates the permutation tensor
+%e_ijk(i,j,k)=(x_i dot (x_j cross x_k))
+I=eye(3);   % Identity matrix
+for i=1:3
+    for j=1:3
+        for k=1:3
+            e(i,j,k) = dot(I(:,i),cross(I(:,j),I(:,k)));
+        end
+    end
+end
+
+function res=delta(i,j)
+% Calculates the Kronecker delta
+if i==j
+    res = 1;
+else
+    res= 0;
+end
+
+    
\ No newline at end of file
diff --git a/zUtil_Strain/untitled.m b/zUtil_Strain/untitled.m
new file mode 100755
index 0000000000000000000000000000000000000000..48f5a0e5e02dd9e8ab08c7da0c2a20652af9debe
--- /dev/null
+++ b/zUtil_Strain/untitled.m
@@ -0,0 +1,26 @@
+[aid,bid,t]=mym('select difAID,difBID,thetatype from strain_sept07_150N_spotpairs');
+
+[s,e,a,id]=mym('select ExtStartImage,ExtEndImage,Area,difspotID from strain_sept07_150N_difspot');
+
+d1=[];
+d2=[];
+
+for i=1:length(aid)
+  if t(i)==1 
+    d1=[d1; e(id==aid(i))-s(id==aid(i))];
+    d1=[d1; e(id==bid(i))-s(id==bid(i))];    
+  end
+  if t(i)==2 
+    d2=[d2; e(id==aid(i))-s(id==aid(i))];
+    d2=[d2; e(id==bid(i))-s(id==bid(i))];    
+  end
+end
+
+mean(d1)
+mean(d2)
+
+
+
+
+
+
diff --git a/zUtil_Strain/xxx2_gtDrawGrainCubes.m b/zUtil_Strain/xxx2_gtDrawGrainCubes.m
new file mode 100755
index 0000000000000000000000000000000000000000..5781bbbee31f81bdee69ae660d74a3092de04e78
--- /dev/null
+++ b/zUtil_Strain/xxx2_gtDrawGrainCubes.m
@@ -0,0 +1,132 @@
+% function gtDrawGrainCubes(grains,sample,numbered,hlight)
+%
+% Draws a figure representing grain size and orientation by cubes 
+% (unit cells in a cubic lattice) based on the Rodrigues vectors.
+%
+% USAGE  gtDrawGrainCubes(grains,sample)
+%        gtDrawGrainCubes(grains([1:10]),sample,1,[1,3,5])  
+%
+% INPUT  grains:   grain structure from indexing
+%        sample:   parameters and definition of the sample reference system  
+%                   (sample=gtSampleGeoInSampleSystem)
+%        numbered: if true, grain id-s are shown
+%        hlight:   grain id-s to be highlighted
+%
+
+
+function gtDrawGrainCubes(grains,sample,numbered,hlight,noaxis)
+
+
+if ~exist('hlight','var')
+  hlight=[];
+end
+if ~exist('numbered','var')
+  numbered=[];
+end
+if ~exist('noaxis','var')
+  noaxis=false;
+end
+
+nof_grains=length(grains);
+
+% cube_vertices=[0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1]-0.5*repmat([1 1 1],8,1);
+% cube_faces=[1 2 6 5; 2 3 7 6; 3 4 8 7; 4 1 5 8; 1 2 3 4; 5 6 7 8];
+
+strainscale=0.01;
+
+figure
+
+
+view(3);
+
+axhor=10*floor((sample.rad+30)/10);
+axver=10*floor((max(sample.top,sample.bot)+50)/10);
+axis([-axhor axhor -axhor axhor -axver axver])
+
+if ~noaxis
+	xlabel('X')
+	ylabel('Y')
+	zlabel('Z')
+	plot3([-170 170],[0 0],[0 0],'r-','Linewidth',2)
+end
+if noaxis
+	set(gca,'xtick',[],'xcolor','w')
+	set(gca,'ytick',[],'ycolor','w')
+	set(gca,'ztick',[],'zcolor','w')
+end
+
+axis equal;
+hold on
+
+t=1:360;
+circx=cosd(t)*sample.rad;
+circy=sind(t)*sample.rad;
+circbotz(1:360)=sample.bot;
+circtopz(1:360)=sample.top;
+plot3(circx,circy,circbotz,'k-','Linewidth',1)
+plot3(circx,circy,circtopz,'k-','Linewidth',1)
+plot3([0 0],[0 0],[sample.bot sample.top],'k.-.','Linewidth',1)
+plot3([-sample.rad -sample.rad],[0 0],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([0 0],[-sample.rad -sample.rad],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([sample.rad sample.rad],[0 0],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([0 0],[sample.rad sample.rad],[sample.bot sample.top],'k.-','Linewidth',1)
+
+
+
+
+cube_vertices=[0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1]-0.5*repmat([1 1 1],8,1);
+cube_faces=[2 3 7 6; 4 1 5 8; 1 2 6 5;  3 4 8 7;  5 6 7 8; 1 2 3 4];
+% directions: +yz      -yz      -xz       +xz       +xy      -xy       
+
+
+ for i=1:nof_grains
+   if ismember(i,hlight)
+     hl=1;
+   else
+     hl=false;
+   end
+   sfPlotGrainCube(grains{i},cube_vertices,cube_faces,hl,strainscale)
+   if numbered
+    text(grains{i}.center(1),-axhor,grains{i}.center(3),num2str(i),'Color','c')
+    text(axhor,grains{i}.center(2),grains{i}.center(3),num2str(i),'Color','c')
+   end
+ end
+ 
+end
+
+
+    
+function sfPlotGrainCube(grain,cube_vertices,cube_faces,hl,strainscale)
+
+  strainbar=jet(1000);
+
+  ga=grain.stat.bbysmean/2;
+  gc=grain.center;
+  
+  ggrain=Rod2g(grain.R_vector);
+  grain_vertices=repmat(gc,8,1)+ga*cube_vertices*ggrain';
+
+if hl
+  facecolors=cool(8);
+  facecolors=facecolors(end-5:end,:);
+else
+	%facecolors=copper(12);
+  %facecolors=facecolors(end-5:end,:);
+	facecolors=gray(12);
+  facecolors=facecolors(end-1-5:end-1,:);
+end  
+  
+  patch('Vertices',grain_vertices,'Faces',cube_faces,...
+      'FaceVertexCData',facecolors,'FaceColor','flat');
+  
+%   edgevec=[0 1 0];
+%   facepos=[1 0 0];
+%   edgevec_g=edgevec*ggrain';
+%   facepos_g=gc+ga/2*facepos*ggrain';
+%   quiver3(facepos_g(1),facepos_g(2),facepos(3),edgevec_g(1),edgevec_g(2),edgevec_g(3),100);
+ 
+  
+      
+end
+
+
diff --git a/zUtil_Strain/xxx2_gtStrainGrains.m b/zUtil_Strain/xxx2_gtStrainGrains.m
new file mode 100755
index 0000000000000000000000000000000000000000..810b03728379994f8c824c49d252aeef3218fd8f
--- /dev/null
+++ b/zUtil_Strain/xxx2_gtStrainGrains.m
@@ -0,0 +1,101 @@
+% FUNCTION [grainsout,allstrainZ_mean,allstrainZ_med]=gtStrainGrains(grainsinp,ACM,flag_mode,latticeparref)
+%
+% INPUT
+% grainsinp: grain structure
+% ACM: angular consistency matrix  ( ACM=gtAngConsMat(spacegroup) )
+% mode_flag: relative displacement and strain tensor calculated from: 
+%              0 - Bragg's measurement
+%              1 - using changes in interplanar angles
+%              2 - using both
+% latticeparref (optional): lattice parameter, reference at zero strain
+%                            if not specified, parameters.acq.latticepar(1)
+
+function [grainsout,allstrainZ_mean,allstrainZ_med]=gtStrainGrains(grainsinp,ACM,latticeparref)
+
+
+if ~exist('latticeparref','var')
+  load parameters.mat
+  latticeparref=parameters.acq.latticepar(1);
+end
+
+tic
+
+nof_grains=length(grainsinp);
+
+% Handle cell arrays or a single one
+if nof_grains==1
+  grains{1}=grainsinp;
+else
+  grains=grainsinp;
+end
+
+allstrainZ=[]; % will collect all the strain values in Z (normally the load axis)
+
+errest=gtEstimateErrors(grainsinp);
+
+for i=1:nof_grains
+
+  grains{i}=gtStrainPlanes(grains{i},latticeparref);
+  
+  grains{i}.strainDev=gtStrainTensorFitDev(grains{i},ACM,errest,mode_flag);
+  grains{i}.strainBragg=gtStrainTensorFitBragg(grains{i},ACM,errest,mode_flag);
+  grains{i}.strainAll=gtStrainTensorFitAll(grains{i},ACM,errest,mode_flag);
+
+end
+
+
+  
+
+    
+%     % Errors
+%     for j=1:nof_pl
+%       strain_computed=grains{i}.pl(j,:)*(ST*grains{i}.pl(j,:)'); % normal component of displacement
+%       strain_measured=grains{i}.plstrain(j);
+%       grains{i}.stat.err.plstrain_abs(j)=strain_measured-strain_computed;
+%       grains{i}.stat.err.plstrain_rel(j)=grains{i}.stat.err.plstrain_abs(j)/grains{i}.pstrain1;
+%     end
+%     
+%     for j=1:nof_unipl
+%       strain_computed=grains{i}.uni.pl(j,:)*(ST*grains{i}.uni.pl(j,:)'); % normal component of displacement
+%       strain_measured=grains{i}.uni.plstrain(j);
+%       grains{i}.stat.err.uniplstrain_abs(j)=strain_measured-strain_computed;
+%       grains{i}.stat.err.uniplstrain_rel(j)=grains{i}.stat.err.uniplstrain_abs(j)/grains{i}.pstrain1;
+%     end
+
+
+
+
+%     % Errors
+%     for j=1:nof_pl
+%       errj=res(find(inputids(:,1)==j,1));
+%       if isempty(errj)
+%         errj=res(find(inputids(:,2)==j,1)+1);
+%       end
+%       grains{i}.stat.err.plstrain_abs(j)=errj;
+%       grains{i}.stat.err.plstrain_rel(j)=grains{i}.stat.err.plstrain_abs(j)/grains{i}.pstrain1;
+%     end
+
+    
+      
+    allstrainZ=[allstrainZ, grains{i}.strainnormZ];
+
+  end
+  
+
+allstrainZ_mean=mean(allstrainZ);
+allstrainZ_med=median(allstrainZ);
+
+% Handle cell arrays or a single one as output
+if nof_grains==1
+  grainsout=grains{1};
+else
+  grainsout=grains;
+end
+
+grain=grainsout;
+
+save('straingrains_lastrun.mat','grain','allstrainZ_mean','allstrainZ_med')
+
+toc
+
+end
diff --git a/zUtil_Strain/xxx3_gtDrawGrainCubes.m b/zUtil_Strain/xxx3_gtDrawGrainCubes.m
new file mode 100755
index 0000000000000000000000000000000000000000..0fc3b2519abc9b8cacc0c6d7424c5834ef562f5f
--- /dev/null
+++ b/zUtil_Strain/xxx3_gtDrawGrainCubes.m
@@ -0,0 +1,134 @@
+% function gtDrawGrainCubes(grains,sample,numbered,hlight)
+%
+% Draws a figure representing grain size and orientation by cubes 
+% (unit cells in a cubic lattice) based on the Rodrigues vectors.
+%
+% USAGE  gtDrawGrainCubes(grains,sample)
+%        gtDrawGrainCubes(grains([1:10]),sample,1,[1,3,5])  
+%
+% INPUT  grains:   grain structure from indexing
+%        sample:   parameters and definition of the sample reference system  
+%                   (sample=gtSampleGeoInSampleSystem)
+%        numbered: if true, grain id-s are shown
+%        hlight:   grain id-s to be highlighted
+%
+
+
+function gtDrawGrainCubes(grains,sample,numbered,hlight,noaxis)
+
+
+if ~exist('hlight','var')
+  hlight=[];
+end
+if ~exist('numbered','var')
+  numbered=[];
+end
+if ~exist('noaxis','var')
+  noaxis=false;
+end
+
+nof_grains=length(grains);
+
+% cube_vertices=[0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1]-0.5*repmat([1 1 1],8,1);
+% cube_faces=[1 2 6 5; 2 3 7 6; 3 4 8 7; 4 1 5 8; 1 2 3 4; 5 6 7 8];
+
+strainscale=0.01;
+
+figure
+
+
+view(3);
+
+
+axhor=10*floor((sample.rad+30)/10);
+axver=10*floor((max(sample.top,sample.bot)+50)/10);
+
+axis([-axhor axhor -axhor axhor -axver axver])
+axis equal;
+hold on
+
+if ~noaxis
+	xlabel('X')
+	ylabel('Y')
+	zlabel('Z')
+	plot3([-170 170],[0 0],[0 0],'r-','Linewidth',2)
+end
+if noaxis
+	set(gca,'xtick',[],'xcolor','w')
+	set(gca,'ytick',[],'ycolor','w')
+	set(gca,'ztick',[],'zcolor','w')
+end
+
+
+t=1:360;
+circx=cosd(t)*sample.rad;
+circy=sind(t)*sample.rad;
+circbotz(1:360)=sample.bot;
+circtopz(1:360)=sample.top;
+plot3(circx,circy,circbotz,'k-','Linewidth',1)
+plot3(circx,circy,circtopz,'k-','Linewidth',1)
+plot3([0 0],[0 0],[sample.bot sample.top],'k.-.','Linewidth',1)
+plot3([-sample.rad -sample.rad],[0 0],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([0 0],[-sample.rad -sample.rad],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([sample.rad sample.rad],[0 0],[sample.bot sample.top],'k.-','Linewidth',1)
+plot3([0 0],[sample.rad sample.rad],[sample.bot sample.top],'k.-','Linewidth',1)
+
+
+
+
+cube_vertices=[0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1]-0.5*repmat([1 1 1],8,1);
+cube_faces=[2 3 7 6; 4 1 5 8; 1 2 6 5;  3 4 8 7;  5 6 7 8; 1 2 3 4];
+% directions: +yz      -yz      -xz       +xz       +xy      -xy       
+
+
+ for i=1:nof_grains
+   if ismember(i,hlight)
+     hl=1;
+   else
+     hl=false;
+   end
+   sfPlotGrainCube(grains{i},cube_vertices,cube_faces,hl,strainscale)
+   if numbered
+    text(grains{i}.center(1),-axhor,grains{i}.center(3),num2str(i),'Color','c')
+    text(axhor,grains{i}.center(2),grains{i}.center(3),num2str(i),'Color','c')
+   end
+ end
+ 
+end
+
+
+    
+function sfPlotGrainCube(grain,cube_vertices,cube_faces,hl,strainscale)
+
+  strainbar=jet(1000);
+
+  ga=grain.stat.bbysmean/2;
+  gc=grain.center;
+  
+  ggrain=Rod2g(grain.R_vector);
+  grain_vertices=repmat(gc,8,1)+ga*cube_vertices*ggrain';
+
+if hl
+  facecolors=cool(8);
+  facecolors=facecolors(end-5:end,:);
+else
+	%facecolors=copper(12);
+  %facecolors=facecolors(end-5:end,:);
+	facecolors=gray(12);
+  facecolors=facecolors(end-1-5:end-1,:);
+end  
+  
+  patch('Vertices',grain_vertices,'Faces',cube_faces,...
+      'FaceVertexCData',facecolors,'FaceColor','flat');
+  
+%   edgevec=[0 1 0];
+%   facepos=[1 0 0];
+%   edgevec_g=edgevec*ggrain';
+%   facepos_g=gc+ga/2*facepos*ggrain';
+%   quiver3(facepos_g(1),facepos_g(2),facepos(3),edgevec_g(1),edgevec_g(2),edgevec_g(3),100);
+ 
+  
+      
+end
+
+