def derive_datasets(self, input_dataset_dict, stack_output_info, tile_type_info):
        assert type(input_dataset_dict) == dict, 'input_dataset_dict must be a dict'
        
        log_multiline(logger.debug, input_dataset_dict, 'input_dataset_dict', '\t')    
       
        # Test function to copy ORTHO & NBAR band datasets with pixel quality mask applied
        # to an output directory for stacking

        output_dataset_dict = {}
        nbar_dataset_info = input_dataset_dict.get('NBAR') # Only need NBAR data for NDVI
        if nbar_dataset_info is None:
            return

        #thermal_dataset_info = input_dataset_dict['ORTHO'] # Could have one or two thermal bands
        
        # Instantiate band lookup object with all required lookup parameters
        lookup = BandLookup(data_cube=self,
                            lookup_scheme_name='LANDSAT-LS5/7',
                            tile_type_id=tile_type_info['tile_type_id'],
                            satellite_tag=nbar_dataset_info['satellite_tag'],
                            sensor_name=nbar_dataset_info['sensor_name'],
                            level_name=nbar_dataset_info['level_name']
                            )

        nbar_dataset_path = nbar_dataset_info['tile_pathname']
        
        #=======================================================================
        # # Generate sorted list of band info for this tile type, satellite and sensor
        # band_dict = self.bands[tile_type_info['tile_type_id']][(nbar_dataset_info['satellite_tag'], nbar_dataset_info['sensor_name'])]
        # band_info_list = [band_dict[tile_layer] for tile_layer in sorted(band_dict.keys()) if band_dict[tile_layer]['level_name'] == 'NBAR']
        #=======================================================================

        # Get a boolean mask from the PQA dataset (use default parameters for mask and dilation)
        pqa_mask = self.get_pqa_mask(input_dataset_dict['PQA']['tile_pathname']) 
        
        nbar_dataset = gdal.Open(nbar_dataset_path)
        assert nbar_dataset, 'Unable to open dataset %s' % nbar_dataset
        logger.debug('Opened NBAR dataset %s', nbar_dataset_path)
        
        #no_data_value = nbar_dataset_info['nodata_value']
        no_data_value = -32767 # Need a value outside the scaled range -10000 - +10000
        
        for output_tag in ['NDVI']: # List of outputs to generate from each file - just NDVI at this stage.
                                
            output_stack_path = os.path.join(self.output_dir, '%s_pqa_masked.vrt' % output_tag)
                    
            output_tile_path = os.path.join(self.output_dir, re.sub('\.\w+$', 
                                                                   '_%s%s' % (output_tag,
                                                                                tile_type_info['file_extension']),
                                                                   os.path.basename(nbar_dataset_path)
                                                                   )
                                           )
                
            # Copy metadata for eventual inclusion in stack file output
            # This could also be written to the output tile if required
            output_dataset_info = dict(nbar_dataset_info)
            output_dataset_info['tile_pathname'] = output_tile_path # This is the most important modification - used to find 
            output_dataset_info['band_name'] = '%s with PQA mask applied' % output_tag
            output_dataset_info['band_tag'] = '%s-PQA' % output_tag
            output_dataset_info['tile_layer'] = 1
    
            # Check for existing, valid file
            if self.refresh or not os.path.exists(output_tile_path) or not gdal.Open(output_tile_path):
                gdal_driver = gdal.GetDriverByName(tile_type_info['file_format'])
                output_dataset = gdal_driver.Create(output_tile_path, 
                                                    nbar_dataset.RasterXSize, nbar_dataset.RasterYSize,
                                                    1, nbar_dataset.GetRasterBand(1).DataType,
                                                    tile_type_info['format_options'].split(','))
                assert output_dataset, 'Unable to open output dataset %s'% output_dataset                                   
                output_dataset.SetGeoTransform(nbar_dataset.GetGeoTransform())
                output_dataset.SetProjection(nbar_dataset.GetProjection()) 
    
                output_band = output_dataset.GetRasterBand(1)
    
                # Calculate NDVI here
                # Remember band indices are one-based
                try:
                    # Read and adjust arrays for NIR and R
                    NIR_array = nbar_dataset.GetRasterBand(lookup.band_no['NIR']).ReadAsArray() * lookup.adjustment_multiplier['NIR'] + lookup.adjustment_offset['NIR'] * SCALE_FACTOR
                    R_array = nbar_dataset.GetRasterBand(lookup.band_no['R']).ReadAsArray() * lookup.adjustment_multiplier['R'] + lookup.adjustment_offset['R'] * SCALE_FACTOR
                except TypeError:   
                    return
                  
                data_array = numpy.true_divide(NIR_array - R_array, NIR_array + R_array) * SCALE_FACTOR
                
                self.apply_pqa_mask(data_array, pqa_mask, no_data_value)
                
                output_band.WriteArray(data_array)
                output_band.SetNoDataValue(no_data_value)
                output_band.FlushCache()
                
                # This is not strictly necessary - copy metadata to output dataset
                output_dataset_metadata = nbar_dataset.GetMetadata()
                if output_dataset_metadata:
                    output_dataset.SetMetadata(output_dataset_metadata) 
                    log_multiline(logger.debug, output_dataset_metadata, 'output_dataset_metadata', '\t')    
                
                output_dataset.FlushCache()
                logger.info('Finished writing %s', output_tile_path)
            else:
                logger.info('Skipped existing, valid dataset %s', output_tile_path)
            
            output_dataset_dict[output_stack_path] = output_dataset_info
#                    log_multiline(logger.debug, output_dataset_info, 'output_dataset_info', '\t')    

        log_multiline(logger.debug, output_dataset_dict, 'output_dataset_dict', '\t')    
        # NDVI dataset processed - return info
        return output_dataset_dict
Overrides abstract function in stacker class. Called in Stacker.stack_derived() function. 
dataset/ETHPy150Open GeoscienceAustralia/agdc/examples/ndvi_stacker.py/NDVIStacker.derive_datasets