def get(self, cycle_list, dataitem=None, isotope=None, sparse=1):
        '''
        Get Data from HDF5 files.

        There are three ways to call this function

        1. get(dataitem)

            Fetches the datatiem for all cycles. If dataitem is a header
            attribute or list of attributes then the data is retured.
            If detaitem an individulal or list of column attributes,
            data columns or isotopes/elements the data is returned for
            all cycles.

        2. get(cycle_list, dataitem)

            Fetches the dataitem or list of dataitems for the cycle
            or list of cycles. The variable dataitems can contain column
            attributes, data columns, and isotopes/elemnts.

        3. get(cycle_list, dataitem, isotope)

            Fetches the dataitems like the seccond method except that
            one of the dataitems must be either "iso_massf" or "yps",
            and in the data returned "iso_massf" and "yps" are replaced
            with the data from the isotopes.  The isotopes must be in
            the form given by se.isotopes or se.elements.

        Parameters
        ----------
        cycle_list : list, integer or string
            If cycle_list is a list or string and all of the entries
            are header attributes then the attributes are returned.

            If cycle_list is a list or string of dataitems then the
            dataitems are fetched for all cycles.

            If cycle_list is a list, integer or string of cycle numbers
            then data is returned for those cycles.
        dataitem: list or string, optional
            If dataitem is not None then the data for each item is
            returned for the cycle or list of cycles. dataitem may be an
            individual or a mixed list of column attributes, column
            data or isotopes/elements. If dataitem is None then
            cycle_list must be a string.  The default is None.
        isotope: list or string, optional
            If one of the dataitems is "iso_massf" or "yps" then it is
            replaced with the data from the individual isotopes/elements
            listed in isotope.  The default is None.
        sparse : int
            Implements a sparsity factor on the fetched data i.e. only
            the i th cycle in cycle_list data is returned,
            where i = sparse.

        '''

#    Check out the inputs
        t1=time.time()
        isotopes_of_interest = []

        nested_list = False
        # if one of cycle_list, dataitem or isotope is given as a string convert it to a list
        if isinstance(cycle_list, basestring):
            cycle_list = [cycle_list]
        else:
            try:
                if len(cycle_list) == 1:
                    nested_list = True
            except TypeError:
                pass #leave nested_list as false
        if isinstance(dataitem, basestring):
            dataitem = [dataitem]
        if isinstance(isotope, basestring):
            isotope = [isotope]



        if dataitem==None and isotope==None:
            option_ind = 1
            dataitem = cycle_list

            if not any([item in self.hattrs for item in dataitem]):
                cycle_list = self.cycles
            else:
                first_file = mrT.File(self.h5s[0].filename,'r')
                dat = []
                # get all dataitems from header attributes
                for item in dataitem:
                    tmp = first_file.attrs.get(item, None)
                    try:
                        if len(tmp) == 1:
                            tmp = tmp[0]
                    except TypeError: #if a scaler is returned do nothing
                        pass
                    dat.append(tmp)
                # if only one header attribute is required dont return as a list
                if (len(dat) == 1) and (not nested_list):
                    dat = dat[0]
                first_file.close()
                return dat
            if any([item.split('-')[0] in self.isos for item in dataitem]):
                return self.get(cycle_list,dataitem,sparse=sparse)
        elif isotope==None:
            option_ind = 2
            cycle_list = cycle_list
            dataitem = dataitem
            # if one dataitem is given as a string convert it to a list
            if isinstance(dataitem, basestring):
                dataitem = [dataitem]
            new_dataitem = []
            new_isotopes = []
            for item in dataitem:
                if item.split('-')[0] in self.isos:
                    new_isotopes.append(item)
                else:
                    new_dataitem.append(item)
            if len(new_isotopes) != 0:
                tmp = []
                try:
                    tmp = self.get(cycle_list,new_dataitem + ['iso_massf'],new_isotopes,sparse=sparse)
                except: # in some old se files there maybe still yps as the name for the abundance arrays
                    tmp =  self.get(cycle_list,new_dataitem + ['yps'],new_isotopes,sparse=sparse)
                # modify the dat list so dat is structured like dataitems
                dat = []
                #make sure tmp containes the data as a list of cycles
                if isinstance(cycle_list, basestring):
                    tmp = [tmp]
                else:
                    try:
                        if len(cycle_list) == 1:
                            tmp = [tmp]
                    except TypeError:
                        tmp = [tmp]
                for cyc in tmp:
                    temp_dataitem = []
                    for item in dataitem:
                        if item in new_dataitem:
                            temp_dataitem.append(cyc[new_dataitem.index(item)])
                        else:
                            if len(new_dataitem) == 0:
                                temp_dataitem = cyc
                            else:
                                if len(new_isotopes) == 1:
                                    temp_dataitem.append(cyc[-1])
                                else:
                                    temp_dataitem.append(cyc[-1][new_isotopes.index(item)])
                    dat.append(temp_dataitem)
                if (len(dat) == 1) and (not nested_list):
                    dat = dat[0]
                return dat
        else:
# there is an implicite rule here that if you want 2D arrays you have
# to give 3 args, or, in other words you have to give a cycle or cycle
# array; there is no good reason for that, except the programmers
# laziness
            option_ind = 3
            cycle_list = cycle_list
            dataitem = dataitem
            isotopes_of_interest = isotope
# we need to find out the shellnb to know if any yps array may just be
# a one row array, as - for example- in the surf.h5 files
            # SJONES: I think here we only need to look at the first shellnb(!)
            #shellnb=self.get(cycle_list,'shellnb')
            try: #check if cycle_list is not a list
                cycle_list[0]
            except (TypeError,IndexError):
                cycle_list = [cycle_list]
            shellnb=self.get(cycle_list[0],'shellnb')

        if sparse <1:
            sparse=1

        #    Just in case the user inputs integers
        try:
            for x in range(len(cycle_list)):
                cycle_list[x] = str(cycle_list[x])
        except TypeError:
            cycle_list = [str(cycle_list)]

        if option_ind != 1:

            try: #if it is a single cycle make sure its formatted correctly
                if cycle_list.isdigit():
                    cycle_list = [cycle_list]
                    for cycle in cycle_list:
                        if len(cycle) != len(self.cycles[0]):
                                #print "a"
                            diff = len(self.cycles[0])-len(cycle)
                            OO = ''
                            while diff >=1:
                                OO+='0'

                            cycle = OO+cycle

            except AttributeError: ##if it is a list of cycles make sure its formatted correctly
                if cycle_list[0].isdigit():

                    for x in range(len(cycle_list)):
                        if len(str(cycle_list[x])) != len(str(self.cycles[0])):
                            #print "b"
                            diff = len(str(self.cycles[0]))-len(str(cycle_list[x]))

                            OO = ''
                            while diff >=1:
                                OO+='0'
                                diff-=1

                            try:
                                cycle_list[x] = OO+cycle_list[x]
                            except TypeError:
                                cycle_list[0] = OO+cycle_list[0]

        dat = []
        cycle_list.sort()

        cyclelist=np.array(list(map(int, cycle_list)))

        # cycles_requested is a list of indices from cyclelist
        # The index of the larges and smallest indices should be stored
        # in sorted order. As new requests are made if the requests
        # border or over lap then only keep the index of the larges and
        # smallest indices.
        cycles_requested = []

        # Sometimes bad data or last restart.h5 files contain no cycles,
        # causing the code to crash. Do a simple try/except here:
        file_min=[]
        file_max=[]
        try:
            for h5 in self.h5s:
                file_min.append(int(h5.cycle[0]))
                file_max.append(int(h5.cycle[-1]))
        except IndexError:
            print('File '+h5.filename+' contains no data, please remove or rename it')
            print('Once the file has been removed or renamed, the preprocessor file must be re-written. Do this by either removing the file h5Preproc.txt from the data directory or by invoking the se instance with rewrite=True')
            print('At present, h5T cannot check for empty files since the overhead using the mounted VOSpace would be too great.')
            raise IOError('Cycle-less file encountered')
        file_min.sort()
        file_max.sort()

        for h5 in self.h5s:
            #initalize file metadata
            min_file = int(h5.cycle[0])
            max_file = int(h5.cycle[-1])
            min_list = int(cyclelist[0])
            max_list = int(cyclelist[-1])
            index_min = None #if None start at begining
            index_max = None #if None finish at end

            # SJONES Now we need to add the case that the set only contains one file:
            if len(file_min) == 1:
                min_file = min_list - 1
                max_file = max_list + 1
            else:
                file_index = file_min.index(min_file)
                if file_index == 0:
                    if min_list - 1 < min_file:
                        min_file = min_list - 1
                    max_file = (file_min[file_index + 1] + max_file)//2
                elif file_index == len(file_min) - 1:
                    min_file = (file_max[file_index - 1] + min_file)//2 + 1
                    if max_list + 1 > max_file:
                        max_file = max_list + 1
                else:
                    min_file = (file_max[file_index - 1] + min_file)//2 + 1
                    max_file = (file_min[file_index + 1] + max_file)//2

            # calculate the left and right limits of the intersection
            # of the lists h5.cycle and cyclelist
            if (max_list < min_file) or (max_file < min_list):
            # the lists do not intersect
                continue
            elif (min_list <= min_file) and (max_file <= max_list):
                # all of h5.cycle is within cyclelist
                index_min = bisect.bisect_left(cyclelist, min_file)
                index_max = bisect.bisect_right(cyclelist, max_file)
            elif (min_file <= min_list) and (max_list <= max_file):
                # all of cyclelist is within h5.cycle
                index_min = None
                index_max = None
            else:
                if min_list > min_file:
                # cyclelist overlaps the right edge of h5.cycle
                    index_min = None
                    index_max = bisect.bisect_right(cyclelist, max_file)
                else:
                    # cyclelist overlaps the left edge of h5.cylce
                    index_min = bisect.bisect_left(cyclelist, min_file)
                    index_max = None

            # maintin list of all requested cycles by keeping trak of
            # the maximum and minimum indices
            imin = index_min
            if index_min == None:
                imin = 0

            imax = index_max
            if index_max == None:
                imax = len(cyclelist)

            request_min = bisect.bisect_left(cycles_requested, imin)
            request_max = bisect.bisect_right(cycles_requested, imax)

            # if the new request overlabs older request remove them
            del cycles_requested[request_min:request_max]
            if ((request_max-request_min) % 2) ==1:
                # new and old request overlaped on one edge only
                if request_min % 2 == 0:
                    # add new starting index
                    cycles_requested.insert(request_min, imin)
                else:
                    # add new ending index
                    cycles_requested.insert(request_min, imax)
            else:
                # new and old requests overlaped on two edges
                if request_min % 2 == 0:
                    # old request was contained with in new request
                    cycles_requested.insert(request_min, imin)
                    cycles_requested.insert(request_min + 1, imax)
                else:
                    # new request wat contained within old request
                    pass

            if not self.h5sStarted[self.h5s.index(h5)]:
                h5.start()
                h5.join()
                temp = h5.fetch_data_sam(dataitem,cycle_list[index_min:index_max],len(cycle_list),len(dat))
                self.h5sStarted[self.h5s.index(h5)]=True
            else:
                temp = h5.fetch_data_sam(dataitem,cycle_list[index_min:index_max],len(cycle_list),len(dat))

            temp_dat = []
            for temp_num, temp_cycle in enumerate(temp):
                temp_dataforcycle = []
                for dataitem_num, temp_dataitem in enumerate(temp_cycle):
                    # identify what cycle the temp data was collected from
                    temp_dataitem=self.red_dim(temp_dataitem)
#                    if option_ind == 3 and isotopes_of_interest != []:
                    if (dataitem[dataitem_num] == 'iso_massf' or dataitem[dataitem_num] == 'yps') and isotopes_of_interest != []:
                    #    Figure out the index
                        index = []
                        iso_tmp = []

                        if 'iso' in dataitem[dataitem_num]: #if we are looking at an isotope
                            iso_tmp = self.isotopes
                        else:
                            iso_tmp = self.elements

                        for iso in isotopes_of_interest: #finds the location of the isotope
                            x = iso_tmp.index(iso)
                            index.append(x)

                        if index == []:
                            # if none of the isotopes of interest are found
                            # then the index defaults to [0], so that the loop
                            # will still try to acess the data in t.
                            index = [0]
                        islist=True

                        if len(cycle_list)==1:
                            islist=False

#                        shellnb_index = 0
#                        if index_min == None:
#                            shellnb_index = temp_num
#                        else:
#                            shellnb_index = index_min + temp_num
                        temp_multicyc = []
                        for i in index:
#                            if islist:
#                                if shellnb[shellnb_index] == 1:    # again take care of 1-row 2D arrays
                                if shellnb == 1:    # again take care of 1-row 2D arrays
                                    temp_multicyc.append(temp_dataitem[i])
                                else:
                                    temp_multicyc.append(temp_dataitem[:,i])
#                            else:
#                                if shellnb == 1:    # again take care of 1-row 2D arrays
#                                    temp_multicyc.append(temp_dataitem[i])
#                                else:
#                                    temp_multicyc.append(temp_dataitem[:,i])
                        if len(temp_multicyc) == 1: # agian take care of 1-row arrays
                            temp_multicyc = temp_multicyc[0]
                        temp_dataitem = temp_multicyc
                    temp_dataforcycle.append(temp_dataitem)
                if len(temp_dataforcycle) == 1: # agian take care of 1-row arrays
                    temp_dataforcycle = temp_dataforcycle[0]
                # Now add the information to the list we pass back
                temp_dat.append(temp_dataforcycle)
            # calculate the proper insertion point for the data colected from
            # the file h5 in self.h5s
            insert_pnt = 0
            if index_min is not None: #alex: in py2: x < None == False
                for i in range(len(cycles_requested)):
                    if i % 2 == 1:
                        if cycles_requested[i] < index_min:
                            insert_pnt += cycles_requested[i] - cycles_requested[i-1]
                        elif cycles_requested[i - 1] < index_min:
                            insert_pnt += index_min - cycles_requested[i - 1]
            # insert the cycle data from the current file into the apropiat place
            # in the output data.
            dat[insert_pnt:insert_pnt] = temp_dat

        #check if cycles were not requested from the file
# SJONES comment
#        missing_cycles = np.array([])
#        if len(cycles_requested) != 2:
#            if len(cycles_requested) == 0:
#                missing_cycles = np.array([cycle_list])
#            else:
#                cycles_requested = [None] + cycles_requested + [None]
#                for i in xrange(0, len(cycles_requested), 2):
#                    min = cycles_requested[i]
#                    max = cycles_requested[i + 1]
#                    missing_cycles = np.append(missing_cycles, cycle_list[min:max])
#            print "The requested cycles: " + str(missing_cycles) + " are not available in this data set"
#        elif (cycles_requested[0] != 0) or (cycles_requested[1] != len(cyclelist)):
#            min = cycles_requested[0]
#            max = cycles_requested[1]
#            missing_cycles = np.append(missing_cycles, cycle_list[0:min])
#            missing_cycles = np.append(missing_cycles, cycle_list[max:])
#            print "The requested cycles: " + str(missing_cycles) + " are not available in this data set"

        if len(dat) < 2 and option_ind != 3 and (not nested_list):
            try:
                dat = dat[0]
            except IndexError:
                None
            except TypeError:
                None
        try:
            if len(dat) < 2 and isotopes_of_interest != []:
                dat = dat[0]
        except TypeError:
            None
        except IndexError:
            None
        t2=time.time()
        return dat