diff --git a/Modules/DICOMReader/include/mitkDICOMITKSeriesGDCMReader.h b/Modules/DICOMReader/include/mitkDICOMITKSeriesGDCMReader.h
index 44337e0974..803b07f91e 100644
--- a/Modules/DICOMReader/include/mitkDICOMITKSeriesGDCMReader.h
+++ b/Modules/DICOMReader/include/mitkDICOMITKSeriesGDCMReader.h
@@ -1,349 +1,350 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #ifndef mitkDICOMITKSeriesGDCMReader_h
 #define mitkDICOMITKSeriesGDCMReader_h
 
 #include <stack>
 #include "itkMutexLock.h"
 #include "mitkDICOMFileReader.h"
 #include "mitkDICOMDatasetSorter.h"
 #include "mitkDICOMGDCMImageFrameInfo.h"
 #include "mitkEquiDistantBlocksSorter.h"
 #include "mitkNormalDirectionConsistencySorter.h"
 #include "MitkDICOMReaderExports.h"
 
 
 namespace itk
 {
   class TimeProbesCollectorBase;
 }
 
 namespace mitk
 {
 
 /**
   \ingroup DICOMReaderModule
   \brief Flexible reader based on itk::ImageSeriesReader and GDCM, for single-slice modalities like CT, MR, PET, CR, etc.
 
   Implements the loading processed as structured by DICOMFileReader offers configuration
   of its loading strategy.
 
   Documentation sections:
    - \ref DICOMITKSeriesGDCMReader_LoadingStrategy
    - \ref DICOMITKSeriesGDCMReader_ForcedConfiguration
    - \ref DICOMITKSeriesGDCMReader_UserConfiguration
    - \ref DICOMITKSeriesGDCMReader_GantryTilt
    - \ref DICOMITKSeriesGDCMReader_Testing
    - \ref DICOMITKSeriesGDCMReader_Internals
      - \ref DICOMITKSeriesGDCMReader_RelatedClasses
      - \ref DICOMITKSeriesGDCMReader_TiltInternals
      - \ref DICOMITKSeriesGDCMReader_Condensing
 
 
   \section DICOMITKSeriesGDCMReader_LoadingStrategy Loading strategy
 
   The set of input files is processed by a number of DICOMDatasetSorter objects which may do two sort of things:
    1. split a list of input frames into multiple lists, based on DICOM tags such as "Rows", "Columns", which cannot be mixed within a single mitk::Image
    2. sort the frames within the input lists, based on the values of DICOM tags such as "Image Position Patient"
 
   When the DICOMITKSeriesGDCMReader is configured with DICOMDatasetSorter%s, the list of input files is processed
   as follows:
    1. build an initial set of output groups, simply by grouping all input files.
    2. for each configured DICOMDatasetSorter, process:
      - for each output group:
        1. set this group's files as input to the sorter
        2. let the sorter sort (and split)
        3. integrate the sorter's output groups with our own output groups
 
   \section DICOMITKSeriesGDCMReader_ForcedConfiguration Forced Configuration
 
   In all cases, the reader will add two DICOMDatasetSorter objects that are required to load
   mitk::Images properly via itk::ImageSeriesReader:
    1. As a \b first step, the input files will be split into groups that are not compatible because they differ in essential aspects:
      - (0028,0010) Number of Rows
      - (0028,0011) Number of Columns
      - (0028,0030) Pixel Spacing
      - (0018,1164) Imager Pixel Spacing
      - (0020,0037) %Image Orientation (Patient)
      - (0018,0050) Slice Thickness
      - (0028,0008) Number of Frames
     2. As are two forced \b last steps:
       1. There will always be an instance of EquiDistantBlocksSorter,
          which ensures that there is an equal distance between all the frames of an Image.
          This is required to achieve correct geometrical positions in the mitk::Image,
          i.e. it is essential to be able to make measurements in images.
          - whether or not the distance is required to be orthogonal to the image planes is configured by SetFixTiltByShearing().
          - during this check, we need to tolerate some minor errors in documented vs. calculated image origins.
            The amount of tolerance can be adjusted by SetToleratedOriginOffset() and SetToleratedOriginOffsetToAdaptive().
            Please see EquiDistantBlocksSorter for more details. The default should be good for most cases.
       2. There is always an instance of NormalDirectionConsistencySorter,
          which makes the order of images go along the image normals (see NormalDirectionConsistencySorter)
 
   \section DICOMITKSeriesGDCMReader_UserConfiguration User Configuration
 
   The user of this class can add more sorting steps (similar to the one described in above section) by calling AddSortingElement().
 
   Usually, an application will add sorting by "Image Position Patient", by "Instance Number", and by other relevant tags here.
 
   \section DICOMITKSeriesGDCMReader_GantryTilt Gantry tilt handling
 
   When CT gantry tilt is used, the gantry plane (= X-Ray source and detector ring) and the vertical plane do not align
   anymore. This scanner feature is used for example to reduce metal artifacs (e.g. <i>Lee C , Evaluation of Using CT
   Gantry Tilt Scan on Head and Neck Cancer Patients with Dental Structure: Scans Show Less Metal Artifacts. Presented
   at: Radiological Society of North America 2011 Scientific Assembly and Annual Meeting; November 27- December 2,
   2011 Chicago IL.</i>).
 
   The acquired planes of such CT series do not match the expectations of a orthogonal geometry in mitk::Image: if you
   stack the slices, they show a small shift along the Y axis:
 \verbatim
 
     without tilt       with tilt
 
       ||||||             //////
       ||||||            //////
   --  |||||| --------- ////// -------- table orientation
       ||||||          //////
       ||||||         //////
 
   Stacked slices:
 
     without tilt       with tilt
 
    --------------    --------------
    --------------     --------------
    --------------      --------------
    --------------       --------------
    --------------        --------------
 
 \endverbatim
 
 
    As such gemetries do not "work" in conjunction with mitk::Image, DICOMITKSeriesGDCMReader is able to perform a correction for such series.
    Whether or not such correction should be attempted is controlled by SetFixTiltByShearing(), the default being correction.
    For details, see "Internals" below.
   \section DICOMITKSeriesGDCMReader_Testing Testing
 
   A number of tests is implemented in module DICOMTesting, which is documented at \ref DICOMTesting.
 
   \section DICOMITKSeriesGDCMReader_Internals Class internals
 
   Internally, the class is based on GDCM and it depends heavily on the gdcm::Scanner class.
 
   Since the sorting elements (see DICOMDatasetSorter and DICOMSortCriterion) can access tags only via the DICOMDatasetAccess interface,
   BUT DICOMITKSeriesGDCMReader holds a list of more specific classes DICOMGDCMImageFrameInfo, we must convert between the two
   types sometimes. This explains the methods ToDICOMDatasetList(), FromDICOMDatasetList().
 
   The intermediate result of all the sorting efforts is held in m_SortingResultInProgress,
   which is modified through InternalExecuteSortingStep().
 
   \subsection DICOMITKSeriesGDCMReader_RelatedClasses Overview of related classes
 
   The following diagram gives an overview of the related classes:
 
   \image html implementeditkseriesgdcmreader.jpg
 
   \subsection DICOMITKSeriesGDCMReader_TiltInternals Details about the tilt correction
 
   The gantry tilt "correction" algorithm fixes two errors introduced by ITK's ImageSeriesReader:
     - the plane shift that is ignored by ITK's reader is recreated by applying a shearing transformation using itk::ResampleFilter.
     - the spacing is corrected (it is calculated by ITK's reader from the distance between two origins, which is NOT the slice distance in this special case)
 
   Both errors are introduced in
   itkImageSeriesReader.txx (ImageSeriesReader<TOutputImage>::GenerateOutputInformation(void)), lines 176 to 245 (as of ITK 3.20)
 
   For the correction, we examine two consecutive slices of a series, both described as a pair (origin/orientation):
     - we calculate if the first origin is on a line along the normal of the second slice
       - if this is not the case, the geometry will not fit a normal mitk::Image/mitk::Geometry3D
       - we then project the second origin into the first slice's coordinate system to quantify the shift
       - both is done in class GantryTiltInformation with quite some comments.
 
   The geometry of image stacks with tilted geometries is illustrated below:
     - green: the DICOM images as described by their tags: origin as a point with the line indicating the orientation
     - red: the output of ITK ImageSeriesReader: wrong, larger spacing, no tilt
     - blue: how much a shear must correct
 
   \image html tilt-correction.jpg
 
   \subsection DICOMITKSeriesGDCMReader_Condensing Sub-classes can condense multiple blocks into a single larger block
 
   The sorting/splitting process described above is helpful for at least two more DICOM readers, which either try to load 3D+t images or which load diffusion data.
 
   In both cases, a single pixel of the mitk::Image is made up of multiple values, in one case values over time, in the other case multiple measurements of a single point.
 
   The specialized readers for these cases (e.g. ThreeDnTDICOMSeriesReader) can reuse most of the methods in DICOMITKSeriesGDCMReader,
   except that they need an extra step after the usual sorting, in which they can merge already grouped 3D blocks. What blocks are merged
   depends on the specialized reader's understanding of these images. To allow for such merging, a method Condense3DBlocks() is called
   as an absolute last step of AnalyzeInputFiles(). Given this, a sub-class could implement only LoadImages() and Condense3DBlocks() instead
   repeating most of AnalyzeInputFiles().
 
 */
 class MITKDICOMREADER_EXPORT DICOMITKSeriesGDCMReader : public DICOMFileReader
 {
   public:
 
     mitkClassMacro( DICOMITKSeriesGDCMReader, DICOMFileReader );
     mitkCloneMacro( DICOMITKSeriesGDCMReader );
     itkFactorylessNewMacro( DICOMITKSeriesGDCMReader );
     mitkNewMacro1Param( DICOMITKSeriesGDCMReader, unsigned int );
 
     /**
       \brief Runs the sorting / splitting process described in \ref DICOMITKSeriesGDCMReader_LoadingStrategy.
       Method required by DICOMFileReader.
     */
     virtual void AnalyzeInputFiles() override;
 
     // void AllocateOutputImages();
     /**
       \brief Loads images using itk::ImageSeriesReader, potentially applies shearing to correct gantry tilt.
     */
     virtual bool LoadImages() override;
 
     // re-implemented from super-class
     virtual bool CanHandleFile(const std::string& filename) override;
 
     /**
       \brief Add an element to the sorting procedure described in \ref DICOMITKSeriesGDCMReader_LoadingStrategy.
     */
     virtual void AddSortingElement(DICOMDatasetSorter* sorter, bool atFront = false);
 
     typedef const std::list<DICOMDatasetSorter::ConstPointer> ConstSorterList;
     ConstSorterList GetFreelyConfiguredSortingElements() const;
 
     /**
       \brief Controls whether to "fix" tilted acquisitions by shearing the output (see \ref DICOMITKSeriesGDCMReader_GantryTilt).
     */
     void SetFixTiltByShearing(bool on);
 
     bool GetFixTiltByShearing() const;
 
     /**
       \brief Controls whether groups of only two images are accepted when ensuring consecutive slices via EquiDistantBlocksSorter.
     */
     void SetAcceptTwoSlicesGroups(bool accept) const;
     bool GetAcceptTwoSlicesGroups() const;
 
     /**
       \brief See \ref DICOMITKSeriesGDCMReader_ForcedConfiguration.
     */
     void SetToleratedOriginOffsetToAdaptive(double fractionOfInterSliceDistanct = 0.3) const;
 
     /**
       \brief See \ref DICOMITKSeriesGDCMReader_ForcedConfiguration.
     */
     void SetToleratedOriginOffset(double millimeters = 0.005) const;
 
     double GetToleratedOriginError() const;
     bool IsToleratedOriginOffsetAbsolute() const;
 
     double GetDecimalPlacesForOrientation() const;
 
     virtual bool operator==(const DICOMFileReader& other) const override;
 
     virtual DICOMTagList GetTagsOfInterest() const override;
 
   protected:
 
     virtual void InternalPrintConfiguration(std::ostream& os) const override;
 
     /// \brief Return active C locale
   static std::string GetActiveLocale();
     /**
       \brief Remember current locale on stack, activate "C" locale.
       "C" locale is required for correct parsing of numbers by itk::ImageSeriesReader
     */
     void PushLocale() const;
     /**
       \brief Activate last remembered locale from locale stack
       "C" locale is required for correct parsing of numbers by itk::ImageSeriesReader
     */
     void PopLocale() const;
 
     DICOMITKSeriesGDCMReader(unsigned int decimalPlacesForOrientation = 5);
     virtual ~DICOMITKSeriesGDCMReader();
 
     DICOMITKSeriesGDCMReader(const DICOMITKSeriesGDCMReader& other);
     DICOMITKSeriesGDCMReader& operator=(const DICOMITKSeriesGDCMReader& other);
 
     /// \brief See \ref DICOMITKSeriesGDCMReader_Internals
   static DICOMDatasetList ToDICOMDatasetList(const DICOMGDCMImageFrameList& input);
     /// \brief See \ref DICOMITKSeriesGDCMReader_Internals
   static DICOMGDCMImageFrameList FromDICOMDatasetList(const DICOMDatasetList& input);
     /// \brief See \ref DICOMITKSeriesGDCMReader_Internals
   static DICOMImageFrameList ToDICOMImageFrameList(const DICOMGDCMImageFrameList& input);
 
     typedef std::vector<DICOMGDCMImageFrameList> SortingBlockList;
     /**
       \brief "Hook" for sub-classes, see \ref DICOMITKSeriesGDCMReader_Condensing
       \return REMAINING blocks
     */
     virtual SortingBlockList Condense3DBlocks(SortingBlockList& resultOf3DGrouping);
 
     virtual DICOMTagCache::Pointer GetTagCache() const;
     void SetTagCache( const DICOMTagCache::Pointer& ) override;
 
     /// \brief Sorting step as described in \ref DICOMITKSeriesGDCMReader_LoadingStrategy
   static SortingBlockList InternalExecuteSortingStep(
         unsigned int sortingStepIndex,
         const DICOMDatasetSorter::Pointer& sorter,
         const SortingBlockList& input);
 
     /// \brief Loads the mitk::Image by means of an itk::ImageSeriesReader
     virtual bool LoadMitkImageForOutput(unsigned int o);
 
     virtual bool LoadMitkImageForImageBlockDescriptor(DICOMImageBlockDescriptor& block) const;
 
     /// \brief Describe this reader's confidence for given SOP class UID
   static ReaderImplementationLevel GetReaderImplementationLevel(const std::string sopClassUID);
   private:
 
     /// \brief Creates the required sorting steps described in \ref DICOMITKSeriesGDCMReader_ForcedConfiguration
     void EnsureMandatorySortersArePresent(unsigned int decimalPlacesForOrientation);
 
   protected:
 
     // NOT nice, made available to ThreeDnTDICOMSeriesReader due to lack of time
     bool m_FixTiltByShearing; // could be removed by ITKDICOMSeriesReader NOT flagging tilt unless requested to fix it!
 
   private:
 
     SortingBlockList m_SortingResultInProgress;
 
     typedef std::list<DICOMDatasetSorter::Pointer> SorterList;
     SorterList m_Sorter;
 
   protected:
 
     // NOT nice, made available to ThreeDnTDICOMSeriesReader and ClassicDICOMSeriesReader due to lack of time
     mitk::EquiDistantBlocksSorter::Pointer m_EquiDistantBlocksSorter;
 
     mitk::NormalDirectionConsistencySorter::Pointer m_NormalDirectionConsistencySorter;
 
   private:
 
     static itk::MutexLock::Pointer s_LocaleMutex;
 
     mutable std::stack<std::string> m_ReplacedCLocales;
     mutable std::stack<std::locale> m_ReplacedCinLocales;
 
     double m_DecimalPlacesForOrientation;
 
     DICOMTagCache::Pointer m_TagCache;
+    bool m_ExternalCache;
 };
 
 }
 
 #endif
diff --git a/Modules/DICOMReader/src/mitkDICOMFileReader.cpp b/Modules/DICOMReader/src/mitkDICOMFileReader.cpp
index 7f506d1033..0c5be7bbe9 100644
--- a/Modules/DICOMReader/src/mitkDICOMFileReader.cpp
+++ b/Modules/DICOMReader/src/mitkDICOMFileReader.cpp
@@ -1,224 +1,229 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #include "mitkDICOMFileReader.h"
 
 #include <itkGDCMImageIO.h>
 
 mitk::DICOMFileReader
 ::DICOMFileReader()
 :itk::Object()
 {
 }
 
 mitk::DICOMFileReader
 ::~DICOMFileReader()
 {
 }
 
 mitk::DICOMFileReader
 ::DICOMFileReader(const DICOMFileReader& other )
 :itk::Object()
 ,m_InputFilenames( other.m_InputFilenames )
 ,m_Outputs( other.m_Outputs )
 ,m_ConfigLabel( other.m_ConfigLabel )
 ,m_ConfigDescription( other.m_ConfigDescription )
 {
 }
 
 mitk::DICOMFileReader&
 mitk::DICOMFileReader
 ::operator=(const DICOMFileReader& other)
 {
   if (this != &other)
   {
     m_InputFilenames = other.m_InputFilenames;
     m_Outputs = other.m_Outputs;
     m_ConfigLabel = other.m_ConfigLabel;
     m_ConfigDescription = other.m_ConfigDescription;
   }
   return *this;
 }
 
 void
 mitk::DICOMFileReader
 ::SetConfigurationLabel(const std::string& label)
 {
   m_ConfigLabel = label;
+  this->Modified();
 }
 
 std::string
 mitk::DICOMFileReader
 ::GetConfigurationLabel() const
 {
   return m_ConfigLabel;
 }
 
 void
 mitk::DICOMFileReader
 ::SetConfigurationDescription(const std::string& desc)
 {
   m_ConfigDescription = desc;
+  this->Modified();
 }
 
 std::string
 mitk::DICOMFileReader
 ::GetConfigurationDescription() const
 {
   return m_ConfigDescription;
 }
 
 void
 mitk::DICOMFileReader
 ::SetInputFiles( const StringList& filenames)
 {
   m_InputFilenames = filenames;
+  this->Modified();
 }
 
 const mitk::StringList&
 mitk::DICOMFileReader
 ::GetInputFiles() const
 {
   return m_InputFilenames;
 }
 
 unsigned int
 mitk::DICOMFileReader
 ::GetNumberOfOutputs() const
 {
   return m_Outputs.size();
 }
 
 void
 mitk::DICOMFileReader
 ::ClearOutputs()
 {
   m_Outputs.clear();
 }
 
 void
 mitk::DICOMFileReader
 ::SetNumberOfOutputs(unsigned int numberOfOutputs)
 {
   m_Outputs.resize(numberOfOutputs);
 }
 
 void
 mitk::DICOMFileReader
 ::SetOutput(unsigned int index, const mitk::DICOMImageBlockDescriptor& output)
 {
   if (index < m_Outputs.size())
   {
     m_Outputs[index] = output;
   }
   else
   {
     std::stringstream ss;
     ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)";
     throw std::invalid_argument( ss.str() );
   }
 }
 
 void
 mitk::DICOMFileReader
 ::PrintConfiguration(std::ostream& os) const
 {
   os << "---- Configuration of " << this->GetNameOfClass() <<" " << (void*)this << " ----"<< std::endl;
   this->InternalPrintConfiguration(os);
   os << "---- End of configuration ----" << std::endl;
 }
 
 
 void
 mitk::DICOMFileReader
 ::PrintOutputs(std::ostream& os, bool filenameDetails) const
 {
   os << "---- Outputs of DICOMFilereader " << (void*)this << " ----"<< std::endl;
 
   for (unsigned int o = 0; o < m_Outputs.size(); ++o)
   {
     os << "-- Output " << o << std::endl;
     const DICOMImageBlockDescriptor& block = m_Outputs[o];
     block.Print(os, filenameDetails);
   }
   os << "---- End of output list ----" << std::endl;
 }
 
 
 const mitk::DICOMImageBlockDescriptor&
 mitk::DICOMFileReader
 ::GetOutput(unsigned int index) const
 {
   if (index < m_Outputs.size())
   {
     return m_Outputs[index];
   }
   else
   {
     std::stringstream ss;
     ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)";
     throw std::invalid_argument( ss.str() );
   }
 }
 mitk::DICOMImageBlockDescriptor&
 mitk::DICOMFileReader
 ::InternalGetOutput(unsigned int index)
 {
   if (index < m_Outputs.size())
   {
     return m_Outputs[index];
   }
   else
   {
     std::stringstream ss;
     ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)";
     throw std::invalid_argument( ss.str() );
   }
 }
 
 bool
 mitk::DICOMFileReader
 ::IsDICOM(const std::string& filename)
 {
   itk::GDCMImageIO::Pointer io = itk::GDCMImageIO::New();
   return io->CanReadFile( filename.c_str() );
 }
 
 
 std::unordered_map<const char*, mitk::DICOMTag> mitk::DICOMFileReader::GetAdditionalTagsOfInterest() const
 {
   return m_AdditionalTagsOfInterest;
 }
 
 
 void mitk::DICOMFileReader::SetAdditionalTagsOfInterest(
   const std::unordered_map<const char*, mitk::DICOMTag>& tagList )
 {
   m_AdditionalTagsOfInterest = tagList;
+  this->Modified();
 }
 
 
 void mitk::DICOMFileReader::SetTagLookupTableToPropertyFunctor(
   mitk::DICOMImageBlockDescriptor::TagLookupTableToPropertyFunctor functor )
 {
   m_TagLookupTableToPropertyFunctor = functor;
+  this->Modified();
 }
 
 mitk::DICOMImageBlockDescriptor::TagLookupTableToPropertyFunctor
   mitk::DICOMFileReader::GetTagLookupTableToPropertyFunctor() const
 {
   return m_TagLookupTableToPropertyFunctor;
 }
diff --git a/Modules/DICOMReader/src/mitkDICOMITKSeriesGDCMReader.cpp b/Modules/DICOMReader/src/mitkDICOMITKSeriesGDCMReader.cpp
index 9be0df209e..40124a8e1d 100644
--- a/Modules/DICOMReader/src/mitkDICOMITKSeriesGDCMReader.cpp
+++ b/Modules/DICOMReader/src/mitkDICOMITKSeriesGDCMReader.cpp
@@ -1,677 +1,685 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 //#define MBILOG_ENABLE_DEBUG
 #define ENABLE_TIMING
 
 #include <itkTimeProbesCollectorBase.h>
 #include <gdcmUIDs.h>
 #include "mitkDICOMITKSeriesGDCMReader.h"
 #include "mitkITKDICOMSeriesReaderHelper.h"
 #include "mitkGantryTiltInformation.h"
 #include "mitkDICOMTagBasedSorter.h"
 #include "mitkDICOMGDCMTagScanner.h"
 
 itk::MutexLock::Pointer mitk::DICOMITKSeriesGDCMReader::s_LocaleMutex = itk::MutexLock::New();
 
 
 mitk::DICOMITKSeriesGDCMReader::DICOMITKSeriesGDCMReader( unsigned int decimalPlacesForOrientation )
 : DICOMFileReader()
 , m_FixTiltByShearing( true )
 , m_DecimalPlacesForOrientation( decimalPlacesForOrientation )
+, m_ExternalCache(false)
 {
   this->EnsureMandatorySortersArePresent( decimalPlacesForOrientation );
 }
 
 
 mitk::DICOMITKSeriesGDCMReader::DICOMITKSeriesGDCMReader( const DICOMITKSeriesGDCMReader& other )
 : DICOMFileReader( other )
 , m_FixTiltByShearing( false )
 , m_SortingResultInProgress( other.m_SortingResultInProgress )
 , m_Sorter( other.m_Sorter )
 , m_EquiDistantBlocksSorter( other.m_EquiDistantBlocksSorter->Clone() )
 , m_NormalDirectionConsistencySorter( other.m_NormalDirectionConsistencySorter->Clone() )
 , m_ReplacedCLocales( other.m_ReplacedCLocales )
 , m_ReplacedCinLocales( other.m_ReplacedCinLocales )
 , m_DecimalPlacesForOrientation( other.m_DecimalPlacesForOrientation )
 , m_TagCache( other.m_TagCache )
+, m_ExternalCache(other.m_ExternalCache)
 {
 }
 
 mitk::DICOMITKSeriesGDCMReader::~DICOMITKSeriesGDCMReader()
 {
 }
 
 mitk::DICOMITKSeriesGDCMReader& mitk::DICOMITKSeriesGDCMReader::
   operator=( const DICOMITKSeriesGDCMReader& other )
 {
   if ( this != &other )
   {
     DICOMFileReader::operator                =( other );
     this->m_FixTiltByShearing                = other.m_FixTiltByShearing;
     this->m_SortingResultInProgress          = other.m_SortingResultInProgress;
     this->m_Sorter                           = other.m_Sorter; // TODO should clone the list items
     this->m_EquiDistantBlocksSorter          = other.m_EquiDistantBlocksSorter->Clone();
     this->m_NormalDirectionConsistencySorter = other.m_NormalDirectionConsistencySorter->Clone();
     this->m_ReplacedCLocales                 = other.m_ReplacedCLocales;
     this->m_ReplacedCinLocales               = other.m_ReplacedCinLocales;
     this->m_DecimalPlacesForOrientation      = other.m_DecimalPlacesForOrientation;
     this->m_TagCache                         = other.m_TagCache;
   }
   return *this;
 }
 
 bool mitk::DICOMITKSeriesGDCMReader::operator==( const DICOMFileReader& other ) const
 {
   if ( const Self* otherSelf = dynamic_cast<const Self*>( &other ) )
   {
     if ( this->m_FixTiltByShearing == otherSelf->m_FixTiltByShearing
          && *( this->m_EquiDistantBlocksSorter ) == *( otherSelf->m_EquiDistantBlocksSorter )
          && ( fabs( this->m_DecimalPlacesForOrientation - otherSelf->m_DecimalPlacesForOrientation ) < eps ) )
     {
       // test sorters for equality
       if ( this->m_Sorter.size() != otherSelf->m_Sorter.size() )
         return false;
 
       auto mySorterIter = this->m_Sorter.cbegin();
       auto oSorterIter  = otherSelf->m_Sorter.cbegin();
       for ( ; mySorterIter != this->m_Sorter.cend() && oSorterIter != otherSelf->m_Sorter.cend();
             ++mySorterIter, ++oSorterIter )
       {
         if ( !( **mySorterIter == **oSorterIter ) )
           return false; // this sorter differs
       }
 
       // nothing differs ==> all is equal
       return true;
     }
     else
     {
       return false;
     }
   }
   else
   {
     return false;
   }
 }
 
 void mitk::DICOMITKSeriesGDCMReader::SetFixTiltByShearing( bool on )
 {
+  this->Modified();
   m_FixTiltByShearing = on;
 }
 
 bool mitk::DICOMITKSeriesGDCMReader::GetFixTiltByShearing() const
 {
   return m_FixTiltByShearing;
 }
 
 void mitk::DICOMITKSeriesGDCMReader::SetAcceptTwoSlicesGroups( bool accept ) const
 {
+  this->Modified();
   m_EquiDistantBlocksSorter->SetAcceptTwoSlicesGroups( accept );
 }
 
 bool mitk::DICOMITKSeriesGDCMReader::GetAcceptTwoSlicesGroups() const
 {
   return m_EquiDistantBlocksSorter->GetAcceptTwoSlicesGroups();
 }
 
 
 mitk::DICOMGDCMImageFrameList
   mitk::DICOMITKSeriesGDCMReader::FromDICOMDatasetList( const DICOMDatasetList& input )
 {
   DICOMGDCMImageFrameList output;
   output.reserve( input.size() );
 
   for ( auto inputIter = input.cbegin(); inputIter != input.cend(); ++inputIter )
   {
     DICOMGDCMImageFrameInfo* gfi = dynamic_cast<DICOMGDCMImageFrameInfo*>( *inputIter );
     assert( gfi );
     output.push_back( gfi );
   }
 
   return output;
 }
 
 mitk::DICOMDatasetList
   mitk::DICOMITKSeriesGDCMReader::ToDICOMDatasetList( const DICOMGDCMImageFrameList& input )
 {
   DICOMDatasetList output;
   output.reserve( input.size() );
 
   for ( auto inputIter = input.cbegin(); inputIter != input.cend(); ++inputIter )
   {
     DICOMDatasetAccess* da = inputIter->GetPointer();
     assert( da );
     output.push_back( da );
   }
 
   return output;
 }
 
 mitk::DICOMImageFrameList
   mitk::DICOMITKSeriesGDCMReader::ToDICOMImageFrameList( const DICOMGDCMImageFrameList& input )
 {
   DICOMImageFrameList output;
   output.reserve( input.size() );
 
   for ( auto inputIter = input.cbegin(); inputIter != input.cend(); ++inputIter )
   {
     DICOMImageFrameInfo::Pointer fi = ( *inputIter )->GetFrameInfo();
     assert( fi.IsNotNull() );
     output.push_back( fi );
   }
 
   return output;
 }
 
 void mitk::DICOMITKSeriesGDCMReader::InternalPrintConfiguration( std::ostream& os ) const
 {
   unsigned int sortIndex( 1 );
   for ( auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sortIndex, ++sorterIter )
   {
     os << "Sorting step " << sortIndex << ":" << std::endl;
     ( *sorterIter )->PrintConfiguration( os, "  " );
   }
 
   os << "Sorting step " << sortIndex << ":" << std::endl;
   m_EquiDistantBlocksSorter->PrintConfiguration( os, "  " );
 }
 
 
 std::string mitk::DICOMITKSeriesGDCMReader::GetActiveLocale()
 {
   return setlocale( LC_NUMERIC, nullptr );
 }
 
 void mitk::DICOMITKSeriesGDCMReader::PushLocale() const
 {
   s_LocaleMutex->Lock();
 
   std::string currentCLocale = setlocale( LC_NUMERIC, nullptr );
   m_ReplacedCLocales.push( currentCLocale );
   setlocale( LC_NUMERIC, "C" );
 
   std::locale currentCinLocale( std::cin.getloc() );
   m_ReplacedCinLocales.push( currentCinLocale );
   std::locale l( "C" );
   std::cin.imbue( l );
 
   s_LocaleMutex->Unlock();
 }
 
 void mitk::DICOMITKSeriesGDCMReader::PopLocale() const
 {
   s_LocaleMutex->Lock();
 
   if ( !m_ReplacedCLocales.empty() )
   {
     setlocale( LC_NUMERIC, m_ReplacedCLocales.top().c_str() );
     m_ReplacedCLocales.pop();
   }
   else
   {
     MITK_WARN << "Mismatched PopLocale on DICOMITKSeriesGDCMReader.";
   }
 
   if ( !m_ReplacedCinLocales.empty() )
   {
     std::cin.imbue( m_ReplacedCinLocales.top() );
     m_ReplacedCinLocales.pop();
   }
   else
   {
     MITK_WARN << "Mismatched PopLocale on DICOMITKSeriesGDCMReader.";
   }
 
   s_LocaleMutex->Unlock();
 }
 
 mitk::DICOMITKSeriesGDCMReader::SortingBlockList
   mitk::DICOMITKSeriesGDCMReader::Condense3DBlocks( SortingBlockList& input )
 {
   return input; // to be implemented differently by sub-classes
 }
 
 #if defined( MBILOG_ENABLE_DEBUG ) || defined( ENABLE_TIMING )
 #define timeStart( part ) timer.Start( part );
 #define timeStop( part ) timer.Stop( part );
 #else
 #define timeStart( part )
 #define timeStop( part )
 #endif
 
 void mitk::DICOMITKSeriesGDCMReader::AnalyzeInputFiles()
 {
   itk::TimeProbesCollectorBase timer;
 
   timeStart( "Reset" );
   this->ClearOutputs();
   timeStop( "Reset" );
 
   // prepare initial sorting (== list of input files)
   const StringList inputFilenames = this->GetInputFiles();
   timeStart( "Check input for DCM" );
   if ( inputFilenames.empty() || !this->CanHandleFile( inputFilenames.front() ) // first
        || !this->CanHandleFile( inputFilenames.back() )                         // last
        || !this->CanHandleFile( inputFilenames[inputFilenames.size() / 2] )     // roughly central file
        )
   {
     // TODO a read-as-many-as-possible fallback could be implemented here
     MITK_DEBUG << "Reader unable to process files..";
     return;
   }
 
   timeStop( "Check input for DCM" );
 
   // scan files for sorting-relevant tags
-  if ( m_TagCache.IsNull() )
+  if ( m_TagCache.IsNull() || ( m_TagCache->GetMTime()<this->GetMTime() && !m_ExternalCache ))
   {
     timeStart( "Tag scanning" );
     DICOMGDCMTagScanner::Pointer filescanner = DICOMGDCMTagScanner::New();
     m_TagCache = filescanner.GetPointer(); // keep alive and make accessible to sub-classes
 
     filescanner->SetInputFiles( inputFilenames );
     filescanner->AddTags( this->GetTagsOfInterest() );
 
     PushLocale();
     filescanner->Scan();
     PopLocale();
 
     timeStop( "Tag scanning" );
   }
   else
   {
     // ensure that the tag cache contains our required tags AND files and has scanned!
   }
 
   m_SortingResultInProgress.clear();
   // TODO We should remove the following cast
   // DICOMImageFrameInfo would need to inherit DICOMDatasetAccess!
   // - then the DICOMGDCMTagScanner class could create a DICOMGDCMImageFrameList internally
   //   - and return it as a DICOMImageFrameList
   // - like this, DICOMITKSeriesGDCMReader could use the DICOMImageFrameInfoList to feed its sorters
   // - problem:
   //   - DICOMImageFrameInfo is also part of DICOMImageBlockDescriptor, which is meant
   //     to describe the scanner output, even after the reader (and its scanner) is deleted.
   //   - if DICOMImageFrameInfo now inherits DICOMDatasetAccess, it would also need to implement
   //     GetTagValueAsString().
   //     - so this could all work if we implement a default response in
   //     DICOMImageFrameInfo::GetTagValueAsString() (like in GetFilenameIfAvailable)
   //       and overwrite it in DICOMGDCMImageFrameInfo, which also knows about a specific GDCM scanner result
   //       (which again COULD (no need to?) be hidden as a point to a DICOMGDCMTagScanner class)
   //
   if ( DICOMGDCMTagScanner* tagCache = dynamic_cast<DICOMGDCMTagScanner*>( m_TagCache.GetPointer() ) )
   {
     m_SortingResultInProgress.push_back( tagCache->GetFrameInfoList() );
   }
   else
   {
     throw std::logic_error( "Bad implementation error: DICOMITKSeriesGDCMReader now unable to find "
                             "dataset/tag information for its input." );
   }
 
   // sort and split blocks as configured
 
   timeStart( "Sorting frames" );
   unsigned int sorterIndex = 0;
   for ( auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sorterIndex, ++sorterIter )
   {
     std::stringstream ss;
     ss << "Sorting step " << sorterIndex;
     timeStart( ss.str().c_str() );
     m_SortingResultInProgress =
       this->InternalExecuteSortingStep( sorterIndex, *sorterIter, m_SortingResultInProgress );
     timeStop( ss.str().c_str() );
   }
 
   // a last extra-sorting step: ensure equidistant slices
   timeStart( "EquiDistantBlocksSorter" );
   m_SortingResultInProgress = this->InternalExecuteSortingStep(
     sorterIndex++, m_EquiDistantBlocksSorter.GetPointer(), m_SortingResultInProgress );
   timeStop( "EquiDistantBlocksSorter" );
 
   timeStop( "Sorting frames" );
 
   timeStart( "Condensing 3D blocks" );
   m_SortingResultInProgress = this->Condense3DBlocks( m_SortingResultInProgress );
   timeStop( "Condensing 3D blocks" );
 
   // provide final result as output
 
   timeStart( "Output" );
   unsigned int o = this->GetNumberOfOutputs();
   this->SetNumberOfOutputs(
     o + m_SortingResultInProgress.size() ); // Condense3DBlocks may already have added outputs!
   for ( auto blockIter = m_SortingResultInProgress.cbegin(); blockIter != m_SortingResultInProgress.cend();
         ++o, ++blockIter )
   {
     const DICOMGDCMImageFrameList& gdcmFrameInfoList = *blockIter;
     assert( !gdcmFrameInfoList.empty() );
 
     // reverse frames if necessary
     // update tilt information from absolute last sorting
     const DICOMDatasetList datasetList = ToDICOMDatasetList( gdcmFrameInfoList );
     m_NormalDirectionConsistencySorter->SetInput( datasetList );
     m_NormalDirectionConsistencySorter->Sort();
     const DICOMGDCMImageFrameList sortedGdcmInfoFrameList =
       FromDICOMDatasetList( m_NormalDirectionConsistencySorter->GetOutput( 0 ) );
     const GantryTiltInformation& tiltInfo = m_NormalDirectionConsistencySorter->GetTiltInformation();
 
     // set frame list for current block
     const DICOMImageFrameList frameList = ToDICOMImageFrameList( sortedGdcmInfoFrameList );
     assert( !frameList.empty() );
 
     DICOMImageBlockDescriptor block;
     block.SetTagCache( this->GetTagCache() ); // important: this must be before SetImageFrameList(), because
                                               // SetImageFrameList will trigger reading of lots of interesting
                                               // tags!
     block.SetAdditionalTagsOfInterest( GetAdditionalTagsOfInterest() );
     block.SetTagLookupTableToPropertyFunctor( GetTagLookupTableToPropertyFunctor() );
     block.SetImageFrameList( frameList );
     block.SetTiltInformation( tiltInfo );
 
     block.SetReaderImplementationLevel( this->GetReaderImplementationLevel( block.GetSOPClassUID() ) );
 
     this->SetOutput( o, block );
   }
   timeStop( "Output" );
 
 #if defined( MBILOG_ENABLE_DEBUG ) || defined( ENABLE_TIMING )
   std::cout << "---------------------------------------------------------------" << std::endl;
   timer.Report( std::cout );
   std::cout << "---------------------------------------------------------------" << std::endl;
 #endif
 }
 
 mitk::DICOMITKSeriesGDCMReader::SortingBlockList mitk::DICOMITKSeriesGDCMReader::InternalExecuteSortingStep(
   unsigned int sortingStepIndex, const DICOMDatasetSorter::Pointer& sorter, const SortingBlockList& input )
 {
   SortingBlockList nextStepSorting; // we should not modify our input list while processing it
   std::stringstream ss;
   ss << "Sorting step " << sortingStepIndex << " '";
 #if defined( MBILOG_ENABLE_DEBUG )
   sorter->PrintConfiguration( ss );
 #endif
   ss << "'";
   nextStepSorting.clear();
 
   MITK_DEBUG << "================================================================================";
   MITK_DEBUG << "DICOMITKSeriesGDCMReader: " << ss.str() << ": " << input.size() << " groups input";
   unsigned int groupIndex = 0;
 
   for ( auto blockIter = input.cbegin(); blockIter != input.cend(); ++groupIndex, ++blockIter )
   {
     const DICOMGDCMImageFrameList& gdcmInfoFrameList = *blockIter;
     const DICOMDatasetList datasetList               = ToDICOMDatasetList( gdcmInfoFrameList );
 
 #if defined( MBILOG_ENABLE_DEBUG )
     MITK_DEBUG << "--------------------------------------------------------------------------------";
     MITK_DEBUG << "DICOMITKSeriesGDCMReader: " << ss.str() << ", dataset group " << groupIndex << " ("
                << datasetList.size() << " datasets): ";
     for ( auto oi = datasetList.cbegin(); oi != datasetList.cend(); ++oi )
     {
       MITK_DEBUG << "  INPUT     : " << ( *oi )->GetFilenameIfAvailable();
     }
 #endif
 
     sorter->SetInput( datasetList );
     sorter->Sort();
     unsigned int numberOfResultingBlocks = sorter->GetNumberOfOutputs();
 
     for ( unsigned int b = 0; b < numberOfResultingBlocks; ++b )
     {
       const DICOMDatasetList blockResult = sorter->GetOutput( b );
 
       for ( auto oi = blockResult.cbegin(); oi != blockResult.cend(); ++oi )
       {
         MITK_DEBUG << "  OUTPUT(" << b << ") :" << ( *oi )->GetFilenameIfAvailable();
       }
 
       DICOMGDCMImageFrameList sortedGdcmInfoFrameList = FromDICOMDatasetList( blockResult );
       nextStepSorting.push_back( sortedGdcmInfoFrameList );
     }
   }
 
   return nextStepSorting;
 }
 
 mitk::ReaderImplementationLevel
   mitk::DICOMITKSeriesGDCMReader::GetReaderImplementationLevel( const std::string sopClassUID )
 {
   if ( sopClassUID.empty() )
   {
     return SOPClassUnknown;
   }
 
   gdcm::UIDs uidKnowledge;
   uidKnowledge.SetFromUID( sopClassUID.c_str() );
 
   gdcm::UIDs::TSType gdcmType = uidKnowledge;
 
   switch ( gdcmType )
   {
     case gdcm::UIDs::CTImageStorage:
     case gdcm::UIDs::MRImageStorage:
     case gdcm::UIDs::PositronEmissionTomographyImageStorage:
     case gdcm::UIDs::ComputedRadiographyImageStorage:
     case gdcm::UIDs::DigitalXRayImageStorageForPresentation:
     case gdcm::UIDs::DigitalXRayImageStorageForProcessing:
       return SOPClassSupported;
 
     case gdcm::UIDs::NuclearMedicineImageStorage:
       return SOPClassPartlySupported;
 
     case gdcm::UIDs::SecondaryCaptureImageStorage:
       return SOPClassImplemented;
 
     default:
       return SOPClassUnsupported;
   }
 }
 
 // void AllocateOutputImages();
 
 bool mitk::DICOMITKSeriesGDCMReader::LoadImages()
 {
   bool success = true;
 
   unsigned int numberOfOutputs = this->GetNumberOfOutputs();
   for ( unsigned int o = 0; o < numberOfOutputs; ++o )
   {
     success &= this->LoadMitkImageForOutput( o );
   }
 
   return success;
 }
 
 bool mitk::DICOMITKSeriesGDCMReader::LoadMitkImageForImageBlockDescriptor(
   DICOMImageBlockDescriptor& block ) const
 {
   PushLocale();
   const DICOMImageFrameList& frames    = block.GetImageFrameList();
   const GantryTiltInformation tiltInfo = block.GetTiltInformation();
   bool hasTilt                         = tiltInfo.IsRegularGantryTilt();
 
   ITKDICOMSeriesReaderHelper::StringContainer filenames;
   filenames.reserve( frames.size() );
   for ( auto frameIter = frames.cbegin(); frameIter != frames.cend(); ++frameIter )
   {
     filenames.push_back( ( *frameIter )->Filename );
   }
 
   mitk::ITKDICOMSeriesReaderHelper helper;
   bool success( true );
   try
   {
     mitk::Image::Pointer mitkImage = helper.Load( filenames, m_FixTiltByShearing && hasTilt, tiltInfo );
     block.SetMitkImage( mitkImage );
   }
   catch ( const std::exception& e )
   {
     success = false;
     MITK_ERROR << "Exception during image loading: " << e.what();
   }
 
   PopLocale();
 
   return success;
 }
 
 
 bool mitk::DICOMITKSeriesGDCMReader::LoadMitkImageForOutput( unsigned int o )
 {
   DICOMImageBlockDescriptor& block = this->InternalGetOutput( o );
   return this->LoadMitkImageForImageBlockDescriptor( block );
 }
 
 
 bool mitk::DICOMITKSeriesGDCMReader::CanHandleFile( const std::string& filename )
 {
   return ITKDICOMSeriesReaderHelper::CanHandleFile( filename );
 }
 
 void mitk::DICOMITKSeriesGDCMReader::AddSortingElement( DICOMDatasetSorter* sorter, bool atFront )
 {
   assert( sorter );
 
   if ( atFront )
   {
     m_Sorter.push_front( sorter );
   }
   else
   {
     m_Sorter.push_back( sorter );
   }
+  this->Modified();
 }
 
 mitk::DICOMITKSeriesGDCMReader::ConstSorterList
   mitk::DICOMITKSeriesGDCMReader::GetFreelyConfiguredSortingElements() const
 {
   std::list<DICOMDatasetSorter::ConstPointer> result;
 
   unsigned int sortIndex( 0 );
   for ( auto sorterIter = m_Sorter.begin(); sorterIter != m_Sorter.end(); ++sortIndex, ++sorterIter )
   {
     if ( sortIndex > 0 ) // ignore first element (see EnsureMandatorySortersArePresent)
     {
       result.push_back( ( *sorterIter ).GetPointer() );
     }
   }
 
   return result;
 }
 
 void mitk::DICOMITKSeriesGDCMReader::EnsureMandatorySortersArePresent(
   unsigned int decimalPlacesForOrientation )
 {
   DICOMTagBasedSorter::Pointer splitter = DICOMTagBasedSorter::New();
   splitter->AddDistinguishingTag( DICOMTag(0x0028, 0x0010) ); // Number of Rows
   splitter->AddDistinguishingTag( DICOMTag(0x0028, 0x0011) ); // Number of Columns
   splitter->AddDistinguishingTag( DICOMTag(0x0028, 0x0030) ); // Pixel Spacing
   splitter->AddDistinguishingTag( DICOMTag(0x0018, 0x1164) ); // Imager Pixel Spacing
   splitter->AddDistinguishingTag( DICOMTag(0x0020, 0x0037), new mitk::DICOMTagBasedSorter::CutDecimalPlaces(decimalPlacesForOrientation) ); // Image Orientation (Patient)
   splitter->AddDistinguishingTag( DICOMTag(0x0018, 0x0050) ); // Slice Thickness
   splitter->AddDistinguishingTag( DICOMTag(0x0028, 0x0008) ); // Number of Frames
   this->AddSortingElement( splitter, true ); // true = at front
 
   if ( m_EquiDistantBlocksSorter.IsNull() )
   {
     m_EquiDistantBlocksSorter = mitk::EquiDistantBlocksSorter::New();
   }
   m_EquiDistantBlocksSorter->SetAcceptTilt( m_FixTiltByShearing );
 
   if ( m_NormalDirectionConsistencySorter.IsNull() )
   {
     m_NormalDirectionConsistencySorter = mitk::NormalDirectionConsistencySorter::New();
   }
 }
 
 void mitk::DICOMITKSeriesGDCMReader::SetToleratedOriginOffsetToAdaptive( double fractionOfInterSliceDistance ) const
 {
   assert( m_EquiDistantBlocksSorter.IsNotNull() );
   m_EquiDistantBlocksSorter->SetToleratedOriginOffsetToAdaptive( fractionOfInterSliceDistance );
+  this->Modified();
 }
 
 void mitk::DICOMITKSeriesGDCMReader::SetToleratedOriginOffset( double millimeters ) const
 {
   assert( m_EquiDistantBlocksSorter.IsNotNull() );
   m_EquiDistantBlocksSorter->SetToleratedOriginOffset( millimeters );
+  this->Modified();
 }
 
 double mitk::DICOMITKSeriesGDCMReader::GetToleratedOriginError() const
 {
   assert( m_EquiDistantBlocksSorter.IsNotNull() );
   return m_EquiDistantBlocksSorter->GetToleratedOriginOffset();
 }
 
 bool mitk::DICOMITKSeriesGDCMReader::IsToleratedOriginOffsetAbsolute() const
 {
   assert( m_EquiDistantBlocksSorter.IsNotNull() );
   return m_EquiDistantBlocksSorter->IsToleratedOriginOffsetAbsolute();
 }
 
 double mitk::DICOMITKSeriesGDCMReader::GetDecimalPlacesForOrientation() const
 {
   return m_DecimalPlacesForOrientation;
 }
 
 mitk::DICOMTagCache::Pointer mitk::DICOMITKSeriesGDCMReader::GetTagCache() const
 {
   return m_TagCache;
 }
 
 void mitk::DICOMITKSeriesGDCMReader::SetTagCache( const DICOMTagCache::Pointer& tagCache )
 {
   m_TagCache = tagCache;
+  m_ExternalCache = tagCache.IsNotNull();
 }
 
 mitk::DICOMTagList mitk::DICOMITKSeriesGDCMReader::GetTagsOfInterest() const
 {
   DICOMTagList completeList;
 
   // check all configured sorters
   for ( auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sorterIter )
   {
     assert( sorterIter->IsNotNull() );
 
     const DICOMTagList tags = ( *sorterIter )->GetTagsOfInterest();
     completeList.insert( completeList.end(), tags.cbegin(), tags.cend() );
   }
 
   // check our own forced sorters
   DICOMTagList tags = m_EquiDistantBlocksSorter->GetTagsOfInterest();
   completeList.insert( completeList.end(), tags.cbegin(), tags.cend() );
 
   tags = m_NormalDirectionConsistencySorter->GetTagsOfInterest();
   completeList.insert( completeList.end(), tags.cbegin(), tags.cend() );
 
   // add the tags for DICOMImageBlockDescriptor
   tags = DICOMImageBlockDescriptor::GetTagsOfInterest();
   completeList.insert( completeList.end(), tags.cbegin(), tags.cend() );
 
 
   const std::unordered_map<const char*, mitk::DICOMTag> tagList = GetAdditionalTagsOfInterest();
   for ( auto iter = tagList.cbegin();
         iter != tagList.cend();
         ++iter
       )
   {
    completeList.push_back( iter->second ) ;
   }
 
   return completeList;
 }
diff --git a/Modules/DICOMReaderServices/src/mitkAutoSelectingDICOMReaderService.cpp b/Modules/DICOMReaderServices/src/mitkAutoSelectingDICOMReaderService.cpp
index a466232708..71f13e278e 100644
--- a/Modules/DICOMReaderServices/src/mitkAutoSelectingDICOMReaderService.cpp
+++ b/Modules/DICOMReaderServices/src/mitkAutoSelectingDICOMReaderService.cpp
@@ -1,46 +1,49 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #include "mitkAutoSelectingDICOMReaderService.h"
 
 #include <mitkDICOMFileReaderSelector.h>
 
 namespace mitk {
 
 AutoSelectingDICOMReaderService::AutoSelectingDICOMReaderService()
   : BaseDICOMReaderService("MITK DICOM Reader v2 (autoselect)")
 {
   this->RegisterService();
 }
 
 DICOMFileReader::Pointer AutoSelectingDICOMReaderService::GetReader(const mitk::StringList& relevantFiles) const
 {
   mitk::DICOMFileReaderSelector::Pointer selector = mitk::DICOMFileReaderSelector::New();
 
   selector->LoadBuiltIn3DConfigs();
   selector->LoadBuiltIn3DnTConfigs();
   selector->SetInputFiles(relevantFiles);
 
   mitk::DICOMFileReader::Pointer reader = selector->GetFirstReaderWithMinimumNumberOfOutputImages();
+  //reset tag cache to ensure that additional tags of interest
+  //will be regarded by the reader if set later on.
+  reader->SetTagCache(nullptr);
   return reader;
 };
 
 AutoSelectingDICOMReaderService* AutoSelectingDICOMReaderService::Clone() const
 {
   return new AutoSelectingDICOMReaderService(*this);
 }
 
 }
diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp b/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp
index 5601e03f5d..fbdd3053ca 100644
--- a/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp
+++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp
@@ -1,373 +1,375 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #include "mitkPluginActivator.h"
 #include "DicomEventHandler.h"
 #include <service/event/ctkEventConstants.h>
 #include <ctkDictionary.h>
 #include <mitkLogMacros.h>
 #include <mitkDataNode.h>
 #include <mitkIDataStorageService.h>
 #include <service/event/ctkEventAdmin.h>
 #include <ctkServiceReference.h>
 #include <mitkRenderingManager.h>
 #include <QVector>
 #include "mitkImage.h"
 #include <mitkContourModelSet.h>
 
 #include <mitkDICOMFileReaderSelector.h>
 #include <mitkDICOMEnums.h>
 #include <mitkDICOMTagHelper.h>
 #include <mitkDICOMProperty.h>
 #include <mitkStringProperty.h>
 
 #include <mitkRTDoseReader.h>
 #include <mitkRTStructureSetReader.h>
 #include <mitkRTConstants.h>
 #include <mitkIsoDoseLevelCollections.h>
 #include <mitkIsoDoseLevelSetProperty.h>
 #include <mitkIsoDoseLevelVectorProperty.h>
 #include <mitkDoseImageVtkMapper2D.h>
 #include <mitkRTUIConstants.h>
 #include <mitkIsoLevelsGenerator.h>
 
 #include <vtkSmartPointer.h>
 #include <vtkMath.h>
 #include <mitkTransferFunction.h>
 #include <mitkTransferFunctionProperty.h>
 #include <mitkRenderingModeProperty.h>
 
 #include <berryIPreferencesService.h>
 #include <berryIPreferences.h>
 #include <berryPlatform.h>
 
 DicomEventHandler::DicomEventHandler()
 {
 }
 
 DicomEventHandler::~DicomEventHandler()
 {
 }
 
 void DicomEventHandler::OnSignalAddSeriesToDataManager(const ctkEvent& ctkEvent)
 {
   QStringList listOfFilesForSeries;
   listOfFilesForSeries = ctkEvent.getProperty("FilesForSeries").toStringList();
 
   if (!listOfFilesForSeries.isEmpty())
   {
     //for rt data, if the modality tag isnt defined or is "CT" the image is handled like before
     if(ctkEvent.containsProperty("Modality") &&
        (ctkEvent.getProperty("Modality").toString().compare("RTDOSE",Qt::CaseInsensitive) == 0 ||
         ctkEvent.getProperty("Modality").toString().compare("RTSTRUCT",Qt::CaseInsensitive) == 0))
     {
       QString modality = ctkEvent.getProperty("Modality").toString();
 
       if(modality.compare("RTDOSE",Qt::CaseInsensitive) == 0)
       {
         mitk::RTDoseReader::Pointer doseReader = mitk::RTDoseReader::New();
 
         mitk::DataNode::Pointer doseImageNode = mitk::DataNode::New();
         mitk::DataNode::Pointer doseOutlineNode = mitk::DataNode::New();
 
         doseImageNode = doseReader->LoadRTDose(listOfFilesForSeries.at(0).toStdString().c_str());
         doseOutlineNode->SetData(doseImageNode->GetData());
         if (doseImageNode.IsNotNull() && doseOutlineNode->GetData() != nullptr)
         {
           berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService();
           berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_ISO_PRESETS_PREFERENCE_NODE_ID.c_str());
 
           typedef QStringList NamesType;
           NamesType names = prefNode->ChildrenNames();
 
           std::map<std::string, mitk::IsoDoseLevelSet::Pointer> presetMap;
 
           for (NamesType::const_iterator pos = names.begin(); pos != names.end(); ++pos)
           {
             berry::IPreferences::Pointer aPresetNode = prefNode->Node(*pos);
 
             if (aPresetNode.IsNull())
             {
               mitkThrow() << "Error in preference interface. Cannot find preset node under given name. Name: " << (*pos).toStdString();
             }
 
             mitk::IsoDoseLevelSet::Pointer levelSet = mitk::IsoDoseLevelSet::New();
 
             NamesType levelNames = aPresetNode->ChildrenNames();
             for (NamesType::const_iterator levelName = levelNames.begin(); levelName != levelNames.end(); ++levelName)
             {
               berry::IPreferences::Pointer levelNode = aPresetNode->Node(*levelName);
               if (aPresetNode.IsNull())
               {
                 mitkThrow() << "Error in preference interface. Cannot find level node under given preset name. Name: " << (*pos).toStdString() << "; Level id: " << (*levelName).toStdString();
               }
 
               mitk::IsoDoseLevel::Pointer isoLevel = mitk::IsoDoseLevel::New();
 
               isoLevel->SetDoseValue(levelNode->GetDouble(mitk::RTUIConstants::ISO_LEVEL_DOSE_VALUE_ID.c_str(), 0.0));
               mitk::IsoDoseLevel::ColorType color;
               color.SetRed(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_RED_ID.c_str(), 1.0));
               color.SetGreen(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_GREEN_ID.c_str(), 1.0));
               color.SetBlue(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_BLUE_ID.c_str(), 1.0));
               isoLevel->SetColor(color);
               isoLevel->SetVisibleIsoLine(levelNode->GetBool(mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_ISOLINES_ID.c_str(), true));
               isoLevel->SetVisibleColorWash(levelNode->GetBool(mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_COLORWASH_ID.c_str(), true));
 
               levelSet->SetIsoDoseLevel(isoLevel);
             }
 
             presetMap.insert(std::make_pair((*pos).toStdString(), levelSet));
           }
 
           if (presetMap.size() == 0)
           {
             presetMap.insert(std::make_pair(std::string("Virtuos"), mitk::GeneratIsoLevels_Virtuos()));
           }
 
 
           prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str());
 
           if (prefNode.IsNull())
           {
             mitkThrow() << "Error in preference interface. Cannot find preset node under given name. Name: " << prefNode->ToString().toStdString();
           }
 
           //set some specific colorwash and isoline properties
           bool showColorWashGlobal = prefNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_COLORWASH_ID.c_str(), true);
           doseImageNode->SetBoolProperty(mitk::RTConstants::DOSE_SHOW_COLORWASH_PROPERTY_NAME.c_str(), showColorWashGlobal);
 
           bool showIsolinesGlobal = prefNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_ISOLINES_ID.c_str(), true);
           doseOutlineNode->SetBoolProperty(mitk::RTConstants::DOSE_SHOW_ISOLINES_PROPERTY_NAME.c_str(), showIsolinesGlobal);
 
           //Set reference dose property
           double referenceDose = prefNode->GetDouble(mitk::RTUIConstants::REFERENCE_DOSE_ID.c_str(), mitk::RTUIConstants::DEFAULT_REFERENCE_DOSE_VALUE);
           doseImageNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), referenceDose);
           doseOutlineNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), referenceDose);
 
 
           QString presetName = prefNode->Get(mitk::RTUIConstants::SELECTED_ISO_PRESET_ID.c_str(), "Virtuos");
 
           mitk::IsoDoseLevelSet::Pointer isoDoseLevelPreset = presetMap[presetName.toStdString()];
           mitk::IsoDoseLevelSetProperty::Pointer levelSetProp = mitk::IsoDoseLevelSetProperty::New(isoDoseLevelPreset);
 
           doseImageNode->SetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str(), levelSetProp);
           doseOutlineNode->SetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str(), levelSetProp);
 
           mitk::IsoDoseLevelVector::Pointer levelVector = mitk::IsoDoseLevelVector::New();
           mitk::IsoDoseLevelVectorProperty::Pointer levelVecProp = mitk::IsoDoseLevelVectorProperty::New(levelVector);
           doseImageNode->SetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str(), levelVecProp);
           doseOutlineNode->SetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str(), levelVecProp);
 
           mitk::RenderingModeProperty::Pointer renderingModeProp = mitk::RenderingModeProperty::New();
 
           if (showColorWashGlobal)
           {
             //Generating the Colorwash
             vtkSmartPointer<vtkColorTransferFunction> transferFunction = vtkSmartPointer<vtkColorTransferFunction>::New();
 
             for (mitk::IsoDoseLevelSet::ConstIterator itIsoDoseLevel = isoDoseLevelPreset->Begin(); itIsoDoseLevel != isoDoseLevelPreset->End(); ++itIsoDoseLevel)
             {
               float *hsv = new float[3];
               //used for transfer rgb to hsv
               vtkSmartPointer<vtkMath> cCalc = vtkSmartPointer<vtkMath>::New();
               if (itIsoDoseLevel->GetVisibleColorWash()){
                 cCalc->RGBToHSV(itIsoDoseLevel->GetColor()[0], itIsoDoseLevel->GetColor()[1], itIsoDoseLevel->GetColor()[2], &hsv[0], &hsv[1], &hsv[2]);
                 transferFunction->AddHSVPoint(itIsoDoseLevel->GetDoseValue()*referenceDose, hsv[0], hsv[1], hsv[2], 1.0, 1.0);
               }
             }
 
             mitk::TransferFunction::Pointer mitkTransFunc = mitk::TransferFunction::New();
             mitk::TransferFunctionProperty::Pointer mitkTransFuncProp = mitk::TransferFunctionProperty::New();
             mitkTransFunc->SetColorTransferFunction(transferFunction);
             mitkTransFuncProp->SetValue(mitkTransFunc);
             doseImageNode->SetProperty("Image Rendering.Transfer Function", mitkTransFuncProp);
 
 
             renderingModeProp->SetValue(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR);
           }
           else
           {
             //Set rendering mode to levelwindow color mode
             renderingModeProp->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR);
           }
 
           doseImageNode->SetProperty("Image Rendering.Mode", renderingModeProp);
           doseImageNode->SetProperty("opacity", mitk::FloatProperty::New(0.5));
 
           //set the outline properties
           doseOutlineNode->SetBoolProperty("outline binary", true);
           doseOutlineNode->SetProperty("helper object", mitk::BoolProperty::New(true));
           doseOutlineNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false));
 
           ctkServiceReference serviceReference = mitk::PluginActivator::getContext()->getServiceReference<mitk::IDataStorageService>();
           mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService<mitk::IDataStorageService>(serviceReference);
           mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage();
 
           dataStorage->Add(doseImageNode);
           dataStorage->Add(doseOutlineNode, doseImageNode);
 
           //set the dose mapper for outline drawing; the colorwash is realized by the imagevtkmapper2D
           mitk::DoseImageVtkMapper2D::Pointer contourMapper = mitk::DoseImageVtkMapper2D::New();
           doseOutlineNode->SetMapper(1, contourMapper);
 
           mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage);
         }//END DOSE
       }
       else if(modality.compare("RTSTRUCT",Qt::CaseInsensitive) == 0)
       {
         mitk::RTStructureSetReader::Pointer structreader = mitk::RTStructureSetReader::New();
         std::deque<mitk::DataNode::Pointer> modelVector = structreader->ReadStructureSet(listOfFilesForSeries.at(0).toStdString().c_str());
 
         if(modelVector.empty())
         {
           MITK_ERROR << "No structuresets were created" << endl;
         }
         else
         {
           ctkServiceReference serviceReference =mitk::PluginActivator::getContext()->getServiceReference<mitk::IDataStorageService>();
           mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService<mitk::IDataStorageService>(serviceReference);
           mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage();
 
           for(int i=0; i<modelVector.size();i++)
           {
             dataStorage->Add(modelVector.at(i));
           }
           mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage);
         }
       }
     }
     else
     {
       mitk::StringList seriesToLoad;
       QStringListIterator it(listOfFilesForSeries);
 
       while (it.hasNext())
       {
         seriesToLoad.push_back(it.next().toStdString());
       }
 
       //Get Reference for default data storage.
       ctkServiceReference serviceReference = mitk::PluginActivator::getContext()->getServiceReference<mitk::IDataStorageService>();
       mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService<mitk::IDataStorageService>(serviceReference);
       mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage();
 
       //special handling of Philips 3D US DICOM.
       //Copied from DICOMSeriesReaderService
       if (!seriesToLoad.empty() && mitk::DicomSeriesReader::IsPhilips3DDicom(seriesToLoad.front()))
       {
           MITK_INFO << "it is a Philips3D US Dicom file" << std::endl;
           const char* previousCLocale = setlocale(LC_NUMERIC, NULL);
           setlocale(LC_NUMERIC, "C");
           std::locale previousCppLocale(std::cin.getloc());
           std::locale l("C");
           std::cin.imbue(l);
 
           mitk::DataNode::Pointer node = mitk::DataNode::New();
           mitk::DicomSeriesReader::StringContainer stringvec;
           stringvec.push_back(seriesToLoad.front());
           if (mitk::DicomSeriesReader::LoadDicomSeries(stringvec, *node))
           {
               mitk::BaseData::Pointer data = node->GetData();
               mitk::StringProperty::Pointer nameProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenameName(seriesToLoad.front()));
               data->GetPropertyList()->SetProperty("name", nameProp);
               node->SetProperty("name", nameProp);
               dataStorage->Add(node);
           }
           setlocale(LC_NUMERIC, previousCLocale);
           std::cin.imbue(previousCppLocale);
           return;
       }
 
       //Normal DICOM handling (It wasn't a Philips 3D US)
       mitk::DICOMFileReaderSelector::Pointer selector = mitk::DICOMFileReaderSelector::New();
 
       selector->LoadBuiltIn3DConfigs();
       selector->LoadBuiltIn3DnTConfigs();
       selector->SetInputFiles(seriesToLoad);
 
       mitk::DICOMFileReader::Pointer reader = selector->GetFirstReaderWithMinimumNumberOfOutputImages();
-
+      //reset tag cache to ensure that additional tags of interest
+      //will be regarded by the reader if set later on.
+      reader->SetTagCache(nullptr);
       reader->SetAdditionalTagsOfInterest(mitk::GetCurrentDICOMTagsOfInterest());
       reader->SetTagLookupTableToPropertyFunctor(mitk::GetDICOMPropertyForDICOMValuesFunctor);
       reader->SetInputFiles(seriesToLoad);
       reader->AnalyzeInputFiles();
       reader->LoadImages();
 
       for (unsigned int i = 0; i < reader->GetNumberOfOutputs(); ++i)
       {
           const mitk::DICOMImageBlockDescriptor& desc = reader->GetOutput(i);
           mitk::BaseData::Pointer data = desc.GetMitkImage().GetPointer();
 
           std::string nodeName = "Unnamed_DICOM";
 
           std::string studyDescription = desc.GetPropertyAsString("studyDescription");
           std::string seriesDescription = desc.GetPropertyAsString("seriesDescription");
 
           if (!studyDescription.empty())
           {
               nodeName = studyDescription;
           }
 
           if (!seriesDescription.empty())
           {
               if (!studyDescription.empty())
               {
                   nodeName += "/";
               }
               nodeName += seriesDescription;
           }
 
           mitk::StringProperty::Pointer nameProp = mitk::StringProperty::New(nodeName);
           data->SetProperty("name", nameProp);
 
           mitk::DataNode::Pointer node = mitk::DataNode::New();
           node->SetData(data);
           nameProp = mitk::StringProperty::New(nodeName);
           node->SetProperty("name", nameProp);
 
           dataStorage->Add(node);
       }
 
       if (reader->GetNumberOfOutputs() < 1)
       {
           MITK_ERROR << "Error loading series: " << ctkEvent.getProperty("SeriesName").toString().toStdString()
               << " id: " << ctkEvent.getProperty("SeriesUID").toString().toStdString();
       }
     }
   }
   else
   {
     MITK_INFO << "There are no files for the current series";
   }
 }
 
 void DicomEventHandler::OnSignalRemoveSeriesFromStorage(const ctkEvent& /*ctkEvent*/)
 {
 }
 
 void DicomEventHandler::SubscribeSlots()
 {
   ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference<ctkEventAdmin>();
   if (ref)
   {
     ctkEventAdmin* eventAdmin = mitk::PluginActivator::getContext()->getService<ctkEventAdmin>(ref);
     ctkDictionary properties;
     properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/ADD";
     eventAdmin->subscribeSlot(this, SLOT(OnSignalAddSeriesToDataManager(ctkEvent)), properties);
     properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/DELETED";
     eventAdmin->subscribeSlot(this, SLOT(OnSignalRemoveSeriesFromStorage(ctkEvent)), properties);
   }
 }