diff --git a/4_grains/GtThreshold.m b/4_grains/GtThreshold.m
index f051a1a9c84d7f610135f0acbc97aedad30660fe..3cc170a36a6a3fe482d02512d50c4e739f71829c 100644
--- a/4_grains/GtThreshold.m
+++ b/4_grains/GtThreshold.m
@@ -449,7 +449,7 @@ classdef GtThreshold < handle
                 % for bb start values
                 grain.seg       = gtCrop(segvol, ceil(segbb));
                 grain.Area      = regprop.Area;
-                segbb(1:3)      = grain.proj.shift + floor(segbb(1:3));
+                segbb(1:3)      = grain.proj.shift + ceil(segbb(1:3)) - 1;
                 grain.segbb     = segbb;
             end
             grain.threshold = threshold;
diff --git a/5_reconstruction/GtAssembleVol3D.m b/5_reconstruction/GtAssembleVol3D.m
index af7e861ee55ed9e749eff9d6776fa127207aa0fb..2657a034f17d8b0b7ce41829ecb5ec886952536f 100644
--- a/5_reconstruction/GtAssembleVol3D.m
+++ b/5_reconstruction/GtAssembleVol3D.m
@@ -125,6 +125,10 @@ classdef GtAssembleVol3D < handle
                 grainDirsModel = fullfile('4_grains', 'phase_%02d', 'grain_%04d.mat');
                 obj.localPar.cache.createModel(grainDirsModel, 'grain');
             end
+            if (~obj.localPar.cache.isModel('grain_details'))
+                grainDirsModel = fullfile('4_grains', 'phase_%02d', 'grain_details_%04d.mat');
+                obj.localPar.cache.createModel(grainDirsModel, 'grain_details');
+            end
 
             if (obj.localPar.deal_with_twins)
                 disp('dealing with twins')
@@ -153,19 +157,28 @@ classdef GtAssembleVol3D < handle
             end
 
             % Let's initialize the volume
-            volume = zeros(obj.parameters.acq.bb(3), ...
-                           obj.parameters.acq.bb(3), ...
-                           obj.parameters.acq.bb(4));
+            grain_ids = zeros(obj.parameters.acq.bb([3, 3, 4]), 'int16');
 
             if (obj.localPar.deal_with_twins)
-                volume = obj.calculatePhaseVolumeTwins(volume, sampleInfo, phaseID, list);
+                grain_ids = obj.calculatePhaseVolumeTwins(grain_ids, sampleInfo, phaseID, list);
                 obj.savePhaseTwinOutput(phaseID);
             else
-                volume = obj.doAssemblePhaseVolume(volume, sampleInfo, phaseID, list);
+                grain_ids = obj.doAssemblePhaseVolume(grain_ids, sampleInfo, phaseID, list);
             end
-
             % store volume
-            obj.volumes.phases{phaseID} = volume;
+            obj.volumes.phases{phaseID}.grains = grain_ids;
+
+            if (strcmpi(obj.parameters.rec.grains.algorithm(1:2), '6D'))
+                dmvol = zeros([obj.parameters.acq.bb([3, 3, 4]), 3]);
+                dmvol = obj.doAssemblePhaseDmVolume(dmvol, sampleInfo, phaseID, list);
+
+                if (ismember(obj.localPar.overlaps, {'zero', 'conflict'}))
+                    % set overlapping regions to zero - this could be another label colour
+                    dmvol(grain_ids == -1 | grain_ids == 0) = 0;
+                end
+
+                obj.volumes.phases{phaseID}.dmvol = dmvol;
+            end
 
             if (obj.localPar.autosave)
                 obj.savePhaseVolume(phaseID);
@@ -184,54 +197,6 @@ classdef GtAssembleVol3D < handle
             end
         end % end function assembleAllPhases
 
-        function assembleInExistingVolume(obj, phaseID, filename)
-        % GTASSEMBLEVOL3D/ASSEMBLEINEXISTINGVOLUME Discouraged function to write
-        % a new grain map, to a previously existing grain map.
-
-            if (~exist('phaseID', 'var'))
-                phaseID = 1;
-            end
-
-            [sampleInfo, list] = obj.initialiseAssembling(phaseID);
-
-            % look for the file
-            if (~exist('filename', 'var'))
-                filename = obj.localPar.add_to_filename;
-            end
-            absolute_file_path = fullfile(obj.parameters.acq.dir, ...
-                                          '5_reconstruction', filename);
-
-            if exist(filename, 'file')
-                volume = edf_read(filename);
-                % check if it's in the 5_reconstruction directory
-            elseif exist( absolute_file_path, 'file')
-                volume = edf_read(absolute_file_path);
-                % otherwise, complain
-            else
-                error('ASSEMBLE:wrong_argument', ...
-                      ['Cannot find the volume to add to: %s\ncheck the' ...
-                       ' filename / path\n'], ...
-                       filename)
-            end
-
-            % if we want to add grains to an existing volume, this is loaded
-            % in. Then labels in the list are set to zero, before the grains
-            % are "re-added" to the volume. I don't think this will deal
-            % with overlapping grains correctly.
-            if (max(volume(:)) > 0)
-                for ii = 1:length(list)
-                    volume(obj.volume == list(ii)) = 0;
-                end
-            end
-
-            volume = obj.doAssemblePhaseVolume(volume, sampleInfo, phaseID, list);
-
-            % Dumb saving.
-            name = fullfile('5_reconstruction', filename);
-            fprintf('writing volume %s\n', name);
-            edf_write(volume, name, 'uint16');
-        end % end function assembleInExistingVolume
-
         function assembleCompleteVolume(obj)
         % GTASSEMBLEVOL3D/ASSEMBLEFINALVOLUME
 
@@ -239,20 +204,30 @@ classdef GtAssembleVol3D < handle
             sampleInfo = obj.localPar.cache.get('sample', {}, 'sample');
 
             % Let's initialize the phase IDs volumes
-            volumePIDs = zeros( obj.parameters.acq.bb(3), ...
-                                obj.parameters.acq.bb(3), ...
-                                obj.parameters.acq.bb(4), 'int16' );
+            volumePIDs = zeros(obj.parameters.acq.bb([3, 3, 4]), 'int16');
             % Let's initialize the grains IDs volumes
-            volumeGIDs = zeros( obj.parameters.acq.bb(3), ...
-                                obj.parameters.acq.bb(3), ...
-                                obj.parameters.acq.bb(4), 'int16' );
+            volumeGIDs = zeros(obj.parameters.acq.bb([3, 3, 4]), 'int16');
+
+            assemble_6D = strcmpi(obj.parameters.rec.grains.algorithm(1:2), '6D');
+            if (assemble_6D)
+                volumeDM = zeros([obj.parameters.acq.bb([3, 3, 4]), 3]);
+            end
 
             phasesNum = length(sampleInfo.phases);
             gauge = GtGauge(phasesNum, 'Processing phases: ');
             for ii = 1:phasesNum
                 gauge.incrementAndDisplay();
                 % no real need to cache phase volumes
-                phaseVol = gtMATVolReader(sampleInfo.phases{ii}.volumeFile);
+                phase_file_name = sampleInfo.phases{ii}.volumeFile;
+                phase_file_name = regexp(phase_file_name, ':', 'split');
+                phase_file = matfile(phase_file_name{1});
+                phaseVol = phase_file.vol;
+
+                assemble_phase_6D = assemble_6D ...
+                    && ismember('dmvol', fieldnames(phase_file));
+                if (assemble_phase_6D)
+                    phaseDmVol = phase_file.dmvol;
+                end
                 grainMap = phaseVol;
                 phaseVol = int16(phaseVol ~= 0) * ii;
 
@@ -262,6 +237,9 @@ classdef GtAssembleVol3D < handle
                     maskVol = gtMATVolReader([maskFile ':mask']);
                     phaseVol = phaseVol .* int16(maskVol);
                     grainMap = grainMap .* int16(maskVol);
+                    if (assemble_phase_6D)
+                        phaseDmVol(~maskVol) = 0;
+                    end
                 end
 
                 switch (obj.localPar.overlaps)
@@ -272,10 +250,18 @@ classdef GtAssembleVol3D < handle
 
                         volumeGIDs = volumeGIDs + grainMap;
                         volumeGIDs(overlappingPoints) = -1;
+
+                        if (assemble_phase_6D)
+                            volumeDM = volumeDM + phaseDmVol;
+                            volumeDM(overlappingPoints) = -1;
+                        end
                     case {'summed'}
                         volumePIDs = volumePIDs + phaseVol;
                         volumeGIDs = volumeGIDs + grainMap;
 
+                        if (assemble_phase_6D)
+                            volumeDM = volumeDM + phaseDmVol;
+                        end
                 end
             end
             gauge.delete();
@@ -295,6 +281,7 @@ classdef GtAssembleVol3D < handle
 
             obj.volumes.complete.phases = volumePIDs;
             obj.volumes.complete.grains = volumeGIDs;
+            obj.volumes.complete.dmvol = volumeDM;
 
             % Autosaving
             if (obj.localPar.autosave)
@@ -314,9 +301,11 @@ classdef GtAssembleVol3D < handle
             name = obj.checkAndSaveExistingFile(fileName);
 
             % Small trick to keep consistency in field name in the written file.
-            outStruct = [];
-            volField = 'vol';
-            outStruct.(volField) = int16(obj.volumes.phases{phaseID});
+            outStruct = struct( ...
+                'vol', int16(obj.volumes.phases{phaseID}.grains) );
+            if (isfield(obj.volumes.phases{phaseID}, 'dmvol'))
+                outStruct.dmvol = obj.volumes.phases{phaseID}.dmvol; %#ok<STRNU>
+            end
 
             % We lock, to avoid other processes to write to this file:
             % Actually this is commented out because it should happen
@@ -330,7 +319,7 @@ classdef GtAssembleVol3D < handle
             obj.checkSampleInfo(sampleInfo, phaseID);
 
             % Store info about volume in the metadata
-            sampleInfo.phases{phaseID}.volumeFile = [name ':' volField];
+            sampleInfo.phases{phaseID}.volumeFile = [name ':vol'];
             obj.localPar.cache.set('sample', {}, sampleInfo, 'sample');
             % Flush metadata
             fprintf('Flushing sample.mat\n');
@@ -341,7 +330,7 @@ classdef GtAssembleVol3D < handle
 
             % Saving the data
             fprintf('Writing phase %02d volume to: %s\n', phaseID, name);
-            save(name, '-struct', 'outStruct', volField, '-v7.3');
+            save(name, '-struct', 'outStruct', '-v7.3');
 
         end % end function savePhaseVolume
 
@@ -373,8 +362,8 @@ classdef GtAssembleVol3D < handle
 
             % Saving the data
             fprintf('Writing complete volume to: %s\n', name);
-            outStruct = obj.volumes.complete;
-            save(name, '-struct', 'outStruct', 'phases', 'grains', '-v7.3');
+            outStruct = obj.volumes.complete; %#ok<NASGU>
+            save(name, '-struct', 'outStruct', '-v7.3');
 
         end % end function saveCompleteVolume
 
@@ -495,7 +484,7 @@ classdef GtAssembleVol3D < handle
 
         function volume = doAssemblePhaseVolume(obj, volume, sampleInfo, phaseID, list)
         % GTASSEMBLEVOL3D/DOASSEMBLEPHASEVOLUME  Function that effectively assembles phase volume
-        
+
             grainsNum = length(list);
             gauge = GtGauge(grainsNum, sprintf('Phase %02d: ', phaseID));
 
@@ -530,6 +519,49 @@ classdef GtAssembleVol3D < handle
             gauge.delete();
         end % end function doAssemblePhaseVolume
 
+        function dmvol = doAssemblePhaseDmVolume(obj, dmvol, sampleInfo, phaseID, list)
+        % GTASSEMBLEVOL3D/DOASSEMBLEPHASEVOLUME  Function that effectively assembles phase volume
+
+            grainsNum = length(list);
+            gauge = GtGauge(grainsNum, sprintf('Phase %02d: ', phaseID));
+
+            for ii = list;
+                gauge.setExtraText(sprintf('(grain %04d)', ii));
+                gauge.incrementAndDisplay();
+
+                if (~sampleInfo.phases{phaseID}.getSelected(ii))
+                    fprintf('\nSkipping deselected grain: %04d\n', ii);
+                    gauge.rePrint();
+                    continue;
+                end
+
+                try
+                    volBBox = sampleInfo.phases{phaseID}.getBoundingBox(ii);
+                    seg_vol = obj.localPar.cache.get('grain', {phaseID, ii}, 'seg');
+                    odf6d = obj.localPar.cache.get('grain_details', {phaseID, ii}, 'ODF6D');
+                    segbb = [volBBox(1:3) - odf6d.shift + 1, volBBox(4:6)];
+                    for ii_dim = 1:3
+                        single_dim_dmvol = odf6d.voxels_avg_R_vectors(:, :, :, ii_dim);
+                        single_dim_dmvol = gtCrop(single_dim_dmvol, segbb);
+                        single_dim_dmvol(~seg_vol) = 0;
+
+                        dmvol(:, :, :, ii_dim) = gtPlaceSubVolume( ...
+                            dmvol(:, :, :, ii_dim), single_dim_dmvol, ...
+                            volBBox(1:3), [], obj.localPar.overlaps, false);
+                    end
+                catch mexc
+                    gtPrintException(mexc, sprintf('\nGrain %d failed!!\n', ii));
+                    gauge.rePrint();
+                    obj.redo = [obj.redo ii];
+                end % end try catch loop
+
+                % Trigger callback (usually used in graphical applications)
+                gtTriggerUpdateCallback(obj.localPar.update_status_cb);
+            end  % for loop through all grains
+
+            gauge.delete();
+        end % end function doAssemblePhaseVolume
+
         function volumeUpdate = calculatePhaseVolumeTwins(obj, volume, sampleInfo, phaseID, list)
         % GTASSEMBLEVOL3D/CALCULATEPHASEVOLUMETWINS
         % obj has the sigma as a property - not sure if useful like this