diff --git a/Code/Mantid/scripts/Inelastic/Direct/CommonFunctions.py b/Code/Mantid/scripts/Inelastic/Direct/CommonFunctions.py
index 68fb32d6294f9173f68202f381ffecbcb03d71ce..07458064372fb08135657ec1982f887cfa3f6bfd 100644
--- a/Code/Mantid/scripts/Inelastic/Direct/CommonFunctions.py
+++ b/Code/Mantid/scripts/Inelastic/Direct/CommonFunctions.py
@@ -4,16 +4,6 @@ from mantid import api
 import os
 import string
 
-def find_file(run_number):
-    """Use Mantid to search for the given run.
-    """
-    file_hint = str(run_number)
-    try:
-        return FileFinder.findRuns(file_hint)[0]
-    except RuntimeError:
-        message = 'Cannot find file matching hint "%s" on current search paths ' + \
-                  'for instrument "%s"'
-        raise ValueError( message % (file_hint, config['default.instrument']))
 
 def create_resultname(run_number, prefix='', suffix=''):
     """Create a string based on the run number and optional prefix and
@@ -106,80 +96,6 @@ def load_runs(inst_name, runs, sum=True, calibration=None,load_with_workspace=Fa
         # Try a single run
         return load_run(inst_name, runs, calibration,False,load_with_workspace)
 
-def load_run(inst_name, run_number, calibration=None, force=False, load_with_workspace=False):
-    """Loads run into the given workspace.
-
-    If force is true then the file is loaded regardless of whether
-    its workspace exists already.
-    """
-    # If a workspace with this name exists, then assume it is to be used in place of a file
-    if str(run_number) in mtd:
-        logger.notice("%s already loaded as workspace." % str(run_number))
-        if type(run_number) == str:
-            loaded_ws = mtd[run_number]
-        else:
-            loaded_ws = run_number
-    else:
-        # If it doesn't exists as a workspace assume we have to try and load a file
-        if type(run_number) == int:
-            filename = find_file(run_number)
-        elif type(run_number) == list:
-            raise TypeError('load_run() cannot handle run lists')
-        else:
-            # Check if it exists, else tell Mantid to try and
-            # find it
-            if os.path.exists(run_number):
-                filename = run_number
-            else:
-                filename = find_file(run_number)
-        # The output name
-        output_name = create_dataname(filename)
-        if (not force) and (output_name in mtd):
-            logger.notice("%s already loaded" % filename)
-            return mtd[output_name]
-
-        args={};
-        ext = os.path.splitext(filename)[1].lower();
-        wrong_monitors_name = False;
-        if ext.endswith("raw"):
-            if load_with_workspace:
-                args['LoadMonitors']='Include'
-            else:
-                args['LoadMonitors']='Separate'
-
-        elif ext.endswith('nxs'):
-            args['LoadMonitors'] = '1'
-
-        loaded_ws = Load(Filename=filename, OutputWorkspace=output_name,**args)
-        if isinstance(loaded_ws,tuple) and len(loaded_ws)>1:
-            mon_ws = loaded_ws[1];
-            loaded_ws=loaded_ws[0];
-
-        logger.notice("Loaded %s" % filename)
-
-    ######## Now we have the workspace
-    apply_calibration(inst_name, loaded_ws, calibration)
-    return loaded_ws
-
-def apply_calibration(inst_name, loaded_ws, calibration):
-    """
-    """
-    if loaded_ws.run().hasProperty("calibrated"):
-        return
-
-    if type(calibration) == str or type(calibration) == int:
-        logger.debug('load_data: Moving detectors to positions specified in cal file "%s"' % str(calibration))
-        filename = calibration
-        skip_lines = None
-        if type(filename) == int: # assume run number
-            filename = inst_name + str(filename)
-        # Pull in pressures, thicknesses & update from cal file
-        LoadDetectorInfo(Workspace=loaded_ws, DataFilename=filename, RelocateDets=True)
-        AddSampleLog(Workspace=loaded_ws,LogName="calibrated",LogText=str(calibration))
-    elif isinstance(calibration, mantid.api.Workspace):
-        logger.debug('load_data: Copying detectors positions from workspace "%s": ' % calibration.name())
-        CopyInstrumentParameters(InputWorkspace=calibration,OutputWorkspace=loaded_ws)
-        AddSampleLog(Workspace=loaded_ws,LogName="calibrated",LogText=str(calibration))
 
 def sum_files(accumulator, files, file_type):
     """
diff --git a/Code/Mantid/scripts/Inelastic/Direct/NonIDF_Properties.py b/Code/Mantid/scripts/Inelastic/Direct/NonIDF_Properties.py
index 64db72478b2c74507463b5ad2e01272155e201f0..c9d6b6adb25d0d9efeeb39d47d92fa30b5388745 100644
--- a/Code/Mantid/scripts/Inelastic/Direct/NonIDF_Properties.py
+++ b/Code/Mantid/scripts/Inelastic/Direct/NonIDF_Properties.py
@@ -44,21 +44,12 @@ class NonIDF_Properties(object):
         object.__setattr__(self,'_save_file_name',None)
  
         self._set_instrument_and_facility(Instrument,run_workspace)
+
+        # set up descriptors holder class reference
+        RunDescriptor.__holder_class__ = self
+        RunDescriptor.logger   = self.log
   
     #end
-    def get_sample_ws_name(self):
-        """ build and return sample workspace name 
-
-            See similar property save_file_name TODO: (leave only one)
-        """ 
-        if not self.sum_runs:
-            return common.create_resultname(self.sample_run,self.instr_name)
-        else:
-            return common.create_resultname(self.sample_run,self.instr_name,'-sum')
-
-    def getDefaultParameterValue(self,par_name):
-        """ method to get default parameter value, specified in IDF """
-        return prop_helpers.get_default_parameter(self.instrument,par_name)
     #-----------------------------------------------------------------------------
     # Complex properties with personal descriptors
     #-----------------------------------------------------------------------------
@@ -74,14 +65,17 @@ class NonIDF_Properties(object):
     #
     van_rmm = VanadiumRMM()
     # Run descriptors
-    sample_run = RunDescriptor("Run ID (number) to convert to energy or list of the such run numbers")
-    wb_run     = RunDescriptor("Run ID (number) for vanadium run used in detectors calibration")
-    monovan_run = RunDescriptor("Run ID (number) for monochromatic vanadium used in absolute units normalization ")
-    wb_for_monovan_run = RunDescriptorDependent(wb_run,""" white beam run used To calculating monovanadium integrals.\n If not explicitly set, white beam for processing run is used instead """)
+    sample_run = RunDescriptor("_RUN","Run ID (number) to convert to energy or list of the such run numbers")
+    wb_run     = RunDescriptor("_WB","Run ID (number) for vanadium run used in detectors calibration")
+    monovan_run = RunDescriptor("_MONO","Run ID (number) for monochromatic vanadium used in absolute units normalization ")
+    wb_for_monovan_run = RunDescriptorDependent(wb_run,"_MONOWB",""" white beam run used to calculate monovanadium integrals.\n If not explicitly set, white beam for processing run is used instead """)
     # TODO: do something about it.  Second white is explicitly used in
-    # diagnostics.
+    # diagnostics but not accessed at all
     seclond_white  = RunDescriptor("Second white beam currently unused in the  workflow. Should it be used for Monovan Diagnostics?") 
     #-----------------------------------------------------------------------------------
+    def getDefaultParameterValue(self,par_name):
+        """ method to get default parameter value, specified in IDF """
+        return prop_helpers.get_default_parameter(self.instrument,par_name)
     @property
     def instrument(self):
         if self._pInstrument is None:
diff --git a/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py b/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py
index 72a8f29e938e17d3090a3e4d155999a27445fd82..b2beb5402bb3b74a56c1198b7253fa4970ba5954 100644
--- a/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py
+++ b/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py
@@ -54,6 +54,9 @@ class PropertyManager(NonIDF_Properties):
            This is why any new descriptor should never place a key with its name in __dict__. Current design automatically remove IDF name 
            from __dict__ if a descriptor with such name exist, so further development should support this behavior.
 
+        5) In many places (descriptors, RunDescriptor itself), PropertyManager assumed to be a singleton. 
+           If this changes, careful refactoring may be needed
+
 
     Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
 
diff --git a/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py b/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py
index 86fe1a8dc4ef4944069b94645c30564794a59b80..27390b3a704ff11051ea3f1f9a5e2aa04ed4d78b 100644
--- a/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py
+++ b/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py
@@ -1,17 +1,36 @@
 """ File contains Descriptors used describe run for direct inelastic reduction """ 
 
+
 from mantid.simpleapi import *
 from PropertiesDescriptors import *
 
 
 class RunDescriptor(PropDescriptor):
-    """ descriptor for property energy or range of incident energies to be processed """
-    def __init__(self,DocString=None): 
+    """ descriptor supporting a run and a workspace  """
+
+    # the host class referencing contained all instantiated descriptors. 
+    # Descriptors methods rely on it to work (e.g. to extract file loader preferences) 
+    # so it has to be set up manually by PropertyManager __init__ method
+    __holder_class__=None
+    logger = None
+
+    def __init__(self,ws_preffix,DocString=None): 
+        """ """
+        # Run number 
         self._run_number  = None
+        # Extension of the file to load data from
+        self._run_ext     = None
+        # Workspace name which corresponds to the run 
         self._run_ws_name = None
+        # String used to identify the workspace related to this property w.r.t. other workspaces
+        self._ws_preffix  = ws_preffix
+        #
         if not DocString is None:
             self.__doc__ = DocString
 
+        if RunDescriptor.__holder_class__:
+            logger = RunDescriptor.__holder_class__.log()
+
     def __get__(self,instance,owner=None):
         """ return current run number""" 
         if instance is None:
@@ -23,6 +42,11 @@ class RunDescriptor(PropDescriptor):
        if value == None: # clear current run number
            self._run_number = None
            self._run_ws_name = None
+           self._run_ext     = None
+           return
+       if isinstance(value, api.Workspace):
+           self._run_number = value.getRunNuber()
+           self._run_ws_name= value.name()
            return
 
        if isinstance(value,str): # it may be run number as string or it may be a workspace name
@@ -30,30 +54,150 @@ class RunDescriptor(PropDescriptor):
               self._run_ws_name = value
               ws = mtd[value]
               self._run_number = ws.getRunNumber()
-          elif [',',':'] in value: # range of runs provided # TODO: parser
-              raise NotImplementedError('Range of run numbers is not yet implemented')
-          else:  #  filename or run number is provided
-              self._run_number = value # TODO: parser      
+              return 
+          else:
+              self._run_number = parse_run_number_string(value) # TODO: parser      
        elif isinstance(value,list):
            self._run_number = value
        else:
            self._run_number = int(value)
 
+       self._run_ws_name = None
+       self._run_ws_name = self.get_ws_name()
+
+
+    def get_file_ext(self):
+        """ Method returns current file extension for file to load workspace from 
+            e.g. .raw or .nxs extension
+        """ 
+        if self._run_ext:
+            return self._run_ext
+        else: # return IDF default
+            return RunDescriptor.__holder_class__.data_file_ext
+
+    def set_file_ext(self,val):
+        """ set non-default file extension """
+        if isinstance(val,str):
+            if val[0] != '.':
+                value = '.' + val
+            else:
+                value = val
+            self._run_ext = value
+        else:
+            raise AttributeError('Source file extension can be only a string')
+
+    def find_file(self,run_num = None):
+        """Use Mantid to search for the given run. """
+
+        inst_name = RunDescriptor.__holder_class__.short_inst_name
+        if run_num:
+            run_num_str = str(run_num)
+        else:
+            run_num_str = str(self.__get__(RunDescriptor.__holder_class__))
+        #
+        file_hint =inst_name + run_num_str + self.get_file_ext()
+        try:
+            return FileFinder.findRuns(file_hint)[0]
+        except RuntimeError:
+            message = 'Cannot find file matching hint {0} on current search paths ' \
+                      'for instrument {1}'.format(file_hint,inst_name)
+
+            logger(message,'warning')
+            return 'ERROR:find_file '+message
+
     def get_workspace(self):
-        """ Method returns workspace correspondent to current run number(s) """ 
-        if self._run_ws_name:
+        """ Method returns workspace correspondent to current run number(s)
+            and loads this workspace if necessary 
+        """ 
+        if not self._run_ws_name:
+           return None
+
+        if self._run_ws_name in mtd:
            return mtd[self._run_ws_name]
         else:
            if self._run_number:
-              raise  NotImplementedError('Load is not yet implemented')
+               inst_name   = RunDescriptor.__holder_class__.short_inst_name
+               calibration = RunDescriptor.__holder_class__.det_cal_file
+               return self.load_run(inst_name, calibration,False, RunDescriptor.__holder_class__.load_monitors_with_workspace)
            else:
               return None
-             
+
+    def get_ws_name(self):
+        """ return workspace name. If ws name is not defined, build it first and set up as target ws name
+
+        """ 
+
+        if self._run_ws_name:
+            return self._run_ws_name
+
+        if RunDescriptor.__holder_class__:
+            instr_name = RunDescriptor.__holder_class__.short_inst_name
+        else:
+            instr_name = '_test_instrument'
+
+        if not RunDescriptor.__holder_class__.sum_runs:
+            ws_name = common.create_resultname(self._run_number,instr_name+self._ws_preffix)
+        else:
+            ws_name = common.create_resultname(self._run_number,instr_name+self._ws_preffix,'-sum')
+        self._run_ws_name = ws_name
+
+        return ws_name
+
+
+    def load_run(self,inst_name, calibration=None, force=False, load_with_workspace=False):
+        """Loads run into the given workspace.
+
+           If force is true then the file is loaded regardless of whether  its workspace exists already
+        """
+        # If a workspace with this name exists, then assume it is to be used in place of a file
+        ws_name = self.get_ws_name()
+
+        if ws_name in mtd and not(force):
+            RunDescriptor.logger("{0} already loaded as workspace.".format(self._run_ws_name),'notice')
+            loaded_ws = mtd[ws_name]
+        else:
+            # If it doesn't exists as a workspace assume we have to try and load a file
+            data_file = self.find_file()
+            if data_file[0:4] == 'ERROR':
+                raise IOError(data_file)           
+
+
+            Load(Filename=data_file, OutputWorkspace=ws_name,LoadMonitors = str(int(load_with_workspace)))
+            RunDescriptor.logger("Loaded {0}".format(data_file),'notice')
+            loaded_ws = mtd[ws_name]
+
+        ######## Now we have the workspace
+        self.apply_calibration(loaded_ws,calibration)
+        return loaded_ws
+
+    def apply_calibration(self,loaded_ws,calibration=None):
+        """  If calibration is present, apply it to the workspace """
+
+        if not calibration:
+            return
+        if not isinstance(loaded_ws, api.Workspace):
+           raise RuntimeError(' Calibration can be applied to a workspace only and got object of type {0}'.format(type(loaded_ws)))
+        
+        if loaded_ws.run().hasProperty("calibrated"):
+            return # already calibrated
+
+        if type(calibration) == str : # It can be only a file (got it from calibration property)
+            RunDescriptor.logger('load_data: Moving detectors to positions specified in cal file {0}'.format(calibration),'debug')
+            # Pull in pressures, thicknesses & update from cal file
+            LoadDetectorInfo(Workspace=loaded_ws, DataFilename=calibration, RelocateDets=True)
+            AddSampleLog(Workspace=loaded_ws,LogName="calibrated",LogText=str(calibration))
+        elif isinstance(calibration, api.Workspace):
+            logger('load_data: Copying detectors positions from workspace {0}: '.format(calibration.name()),'debug')
+            CopyInstrumentParameters(InputWorkspace=calibration,OutputWorkspace=loaded_ws)
+            AddSampleLog(Workspace=loaded_ws,LogName="calibrated",LogText=str(calibration))
+  
 #-------------------------------------------------------------------------------------------------------------------------------
 class RunDescriptorDependent(RunDescriptor):
-    def __init__(self,host_run,DocString=None):
+    def __init__(self,host_run,ws_preffix,DocString=None):
+        RunDescriptor.__init__(self,ws_preffix,DocString)
         self._host = host_run
         self._this_run_defined=False
+
     def __get__(self,instance,owner=None):
        """ return dependent run number which is host run number if this one has not been set or this run number if it was""" 
        if instance is None:
@@ -69,3 +213,10 @@ class RunDescriptorDependent(RunDescriptor):
             return
         self._this_run_defined = True
         super(RunDescriptorDependent,self).__set__(instance,value)
+
+    def get_workspace(self):
+        """ overloaded get workspace method """ 
+        if self._this_run_defined:
+            self.get_workspace()
+        else:
+            self._host.get_workspace()
\ No newline at end of file
diff --git a/Code/Mantid/scripts/test/RunDescriptorTest.py b/Code/Mantid/scripts/test/RunDescriptorTest.py
index a9db9d629b12f1cf526c5276a6859ec6b7bc3e35..071f65aebf05764c369cb856c417ea800de954c7 100644
--- a/Code/Mantid/scripts/test/RunDescriptorTest.py
+++ b/Code/Mantid/scripts/test/RunDescriptorTest.py
@@ -34,11 +34,11 @@ class RunDescriptorTest(unittest.TestCase):
         tmp_ws_name = '__empty_' + InstrumentName
         if not mtd.doesExist(tmp_ws_name):
                LoadEmptyInstrument(Filename=idf_file,OutputWorkspace=tmp_ws_name)
-        return mtd[tmp_ws_name].getInstrument();
+        return mtd[tmp_ws_name].getInstrument()
 
  
-    def test_basic_descr(self):
-        propman  = self.prop_man;
+    def test_descr_basic(self):
+        propman  = self.prop_man
 
         self.assertTrue(propman.sample_run is None)
         self.assertTrue(PropertyManager.sample_run.get_workspace() is None)
@@ -55,8 +55,69 @@ class RunDescriptorTest(unittest.TestCase):
 
         self.assertEqual(rez,'Success!')
 
+    def test_descr_dependend(self):
+        propman  = self.prop_man
+        propman.wb_run = 100
+        self.assertEqual(propman.wb_run,100)
+        self.assertEqual(propman.wb_for_monovan_run,100)
+
+        propman.wb_for_monovan_run = 200
+        self.assertEqual(propman.wb_for_monovan_run,200)
+        self.assertEqual(propman.wb_run,100)
+
+    def test_find_file(self):
+        propman  = self.prop_man
+        propman.sample_run = 11001
+
+        file=PropertyManager.sample_run.find_file()
+        self.assertTrue(len(file)>0)
+
+        ext = PropertyManager.sample_run.get_file_ext()
+        self.assertEqual(ext,'.raw')
+
+        PropertyManager.sample_run.set_file_ext('nxs')
+        ext = PropertyManager.sample_run.get_file_ext()
+        self.assertEqual(ext,'.nxs')
+
+        test_dir = config.getString('defaultsave.directory')
+
+        testFile1=os.path.normpath(test_dir+'MAR101111.nxs')
+        testFile2=os.path.normpath(test_dir+'MAR101111.raw')
+
+        f=open(testFile1,'w')
+        f.write('aaaaaa');
+        f.close()
+
+        f=open(testFile2,'w')
+        f.write('bbbb')
+        f.close()
+
+
+        propman.sample_run = 101111
+        file=PropertyManager.sample_run.find_file()
+        self.assertEqual(testFile1,os.path.normpath(file))
+        PropertyManager.sample_run.set_file_ext('.raw')
+        file=PropertyManager.sample_run.find_file()
+        self.assertEqual(testFile2,os.path.normpath(file))
+
+        os.remove(testFile1)
+        os.remove(testFile2)
+
+    def test_load_workspace(self):
+        propman  = self.prop_man
+
+        # MARI run with number 11001 and extension raw must among unit test files
+        propman.sample_run = 11001
+        PropertyManager.sample_run.set_file_ext('raw')
+
+        ws = PropertyManager.sample_run.get_workspace()
+
+        self.assertTrue(isinstance(ws, api.Workspace))
+        self.assertEqual(ws.name(), PropertyManager.sample_run.get_ws_name())
+
 
     
 
+
 if __name__=="__main__":
     unittest.main()