def postProcessing(self): ''' update the user product and product metadata, copy the logfile to QI data as a report, Check if at target product is present. ''' self.updateProductMetadata() xp = L3_XmlParser(self.config, 'UP03') auxdata = xp.getTree('L3_Auxiliary_Data_Info', 'Aux_Data') auxdata.clear() dirname, basename = os.path.split(self.config.L3_TILE_MTD_XML) fn1r = basename.replace('_MTD_', '_GIP_') fn2r = fn1r.replace('.xml', '') gippFn = etree.Element('GIPP_FILENAME', type='GIP_Level-3p', version=self.config.processorVersion) gippFn.text = fn2r gippList = objectify.Element('L3_GIPP_LIST') gippList.append(gippFn) auxdata.append(gippList) xp.export() dirname, basename = os.path.split(self.config.L3_TILE_MTD_XML) report = basename.replace('.xml', '_Report.xml') report = os.path.join(dirname, 'QI_DATA', report) if ((os.path.isfile(self.config.fnLog)) == False): self.logger.fatal('Missing file: ' + self.config.fnLog) self.config.exitError() f = open(self.config.fnLog, 'a') f.write('</Sen2Three_Level-3_Report_File>') f.flush() f.close() copy_file(self.config.fnLog, report) return
#!/usr/bin/env python
def exportBandList(self, productLevel): ''' Export all bands of current tile. converts all bands from hdf5 to JPEG-2000. :param productLevel: [ L2A | L3]. :type productLevel: str :return: false if error occurred during export. :rtype: boolean ''' bandDir = self._L3_bandDir # converts all bands from hdf5 to JPEG 2000 if (os.path.exists(bandDir) == False): self.config.logger.fatal('missing directory %s:' % bandDir) self.config.exitError() return False os.chdir(bandDir) self.config.timestamp(productLevel + '_Tables: start export') if (self._resolution == 10): bandIndex = [1, 2, 3, 7, 14, 34] elif (self._resolution == 20): bandIndex = [1, 2, 3, 4, 5, 6, 8, 11, 12, 14, 34] elif (self._resolution == 60): bandIndex = [0, 1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 14, 34] xp = L3_XmlParser(self.config, 'UP2A') if self.config.productVersion < 14.5: pi = xp.getTree('General_Info', 'L2A_Product_Info') try: # 14.2: gr2a = pi.L2A_Product_Organisation.Granule_List.Granule except: # 13.1: gr2a = pi.L2A_Product_Organisation.Granule_List.Granules else: # 14.5: pi = xp.getTree('General_Info', 'Product_Info') gr2a = pi.Product_Organisation.Granule_List.Granule gi2a = gr2a.attrib['granuleIdentifier'] ds2a = gr2a.attrib['datastripIdentifier'] l3TileId_split = self.config.L3_TILE_ID.split('_') gi3 = gi2a.replace('_L2A_', '_L03_') ds3 = ds2a.replace('_L2A_', '_L03_') if self.config.productVersion < 14.5: gi3 = gi3[:41] + l3TileId_split[2] + '_' + l3TileId_split[1] + gi3[ -7:] else: gi3 = gi3[:41] + l3TileId_split[2] + '_' + l3TileId_split[1] + gi3[ -7:] gi3 = gi3.replace('USER', 'OPER') ds3 = ds3.replace('USER', 'OPER') Granule = objectify.Element('Granule') Granule.attrib['granuleIdentifier'] = gi3 Granule.attrib['datastripIdentifier'] = ds3 Granule.attrib['imageFormat'] = 'JPEG2000' gl = objectify.Element('Granule_List') gl.append(Granule) for index in bandIndex: bandName = self.getBandNameFromIndex(index) if index == self.SCL: filename = self._L3_Tile_SCL_File elif index == self.MSC: filename = self._L3_Tile_MSC_File else: filename = self._L3_Tile_BND_File.replace('BXX', bandName) if self.testBand(productLevel, index): band = self.getBand(productLevel, index) else: # create mosaic map if first tile: scl = self.getBand(productLevel, self.SCL) scl[scl > 0] = 1 self.setBand(productLevel, self.MSC) # Median Filter: mf = self.config.medianFilter if (mf > 0): band = ndimage.filters.median_filter(band, (mf, mf)) if (index == self.SCL) or (index == self.MSC): self.glymurWrapper(filename, band.astype(uint8)) else: self.glymurWrapper(filename, band.astype(uint16)) self.config.logger.info('Band ' + bandName + ' exported') self.config.timestamp('L3_Tables: band ' + bandName + ' exported') filename = os.path.basename(filename.strip('.jp2')) imageFile3 = etree.Element('IMAGE_FILE') # by intention os.path.join is not used here, as otherwise validation on windows fails: resolution = 'R' + str(self.config.resolution) + 'm/' imageFile3.text = 'GRANULE/' + self.config.L3_TILE_ID + '/IMG_DATA/' + resolution + filename Granule.append(imageFile3) self.createTci('L3') xp = L3_XmlParser(self.config, 'UP03') pi = xp.getTree('General_Info', 'Product_Info') po = pi.Product_Organisation po.append(gl) xp.export() #update on tile level xp = L3_XmlParser(self.config, 'T03') ti3 = xp.getTree('General_Info', 'TILE_ID') ti3._setText(gi3) di3 = xp.getTree('General_Info', 'DATASTRIP_ID') di3._setText(ds3) # clean up and post processing actions: pxlQI = objectify.Element('Pixel_Level_QI') pxlQI.attrib['resolution'] = str(self.config.resolution) pxlQI.append(objectify.Element('TILE_CLASSIFICATION_MASK')) pxlQI.append(objectify.Element('TILE_MOSAIC_MASK')) pxlQI.TILE_CLASSIFICATION_MASK = os.path.basename( self._L3_Tile_SCL_File).replace('.jp2', '') pxlQI.TILE_MOSAIC_MASK = os.path.basename( self._L3_Tile_MSC_File).replace('.jp2', '') qiiL3 = xp.getTree('Quality_Indicators_Info', 'Pixel_Level_QI') qiiL3Len = len(qiiL3) for i in range(qiiL3Len): if int(qiiL3[i].attrib['resolution']) == self.config.resolution: qiiL3[i] = pxlQI break xp.export() self.config.timestamp(productLevel + '_Tables: stop export') return True
def updateProductMetadata(self): ''' Update the product metadata for each new synthesis. ''' dbname = os.path.join(self.config.L3_TARGET_DIR, '.database.h5') h5file = tables.open_file(dbname, mode='a') table = h5file.root.group1.classes totalPixelCount = 0 dataPixelCount = 0 nodataPixelCount = 0 goodPixelCount = 0 badPixelCount = 0 satDefPixelCount = 0 darkFeaturesCount = 0 cloudShadowsCount = 0 vegetationCount = 0 bareSoilsCount = 0 waterCount = 0 lowProbaCloudsCount = 0 medProbaCloudsCount = 0 hiProbaCloudsCount = 0 thinCirrusCount = 0 snowIceCount = 0 for row in table.iterrows(): if row['RESOLUTION'] == self.config.resolution: totalPixelCount += row['TOTAL_PIXELS'] dataPixelCount += row['DATA_PIXELS'] nodataPixelCount += row['NODATA_PIXELS'] goodPixelCount += row['GOOD_PIXELS'] badPixelCount += row['BAD_PIXELS'] satDefPixelCount += row['SAT_DEF_PIXELS'] darkFeaturesCount += row['DARK_PIXELS'] cloudShadowsCount += row['CLOUD_SHADOWS'] vegetationCount += row['VEGETATION'] bareSoilsCount += row['NOT_VEGETATED'] waterCount += row['WATER'] lowProbaCloudsCount += row['UNCLASSIFIED'] medProbaCloudsCount += row['MED_PROBA_CLOUDS'] hiProbaCloudsCount += row['HIGH_PROBA_CLOUDS'] thinCirrusCount += row['THIN_CIRRUS'] snowIceCount += row['SNOW_ICE'] table.flush() h5file.close() totalPixelCount = float(totalPixelCount) * 0.01 dataPixelCount = float(dataPixelCount) * 0.01 dataPixelPercentage = float32(dataPixelCount) / totalPixelCount * 100 nodataPixelPercentage = float32(nodataPixelCount) / totalPixelCount goodPixelPercentage = float32(goodPixelCount) / dataPixelCount badPixelPercentage = float32(badPixelCount) / dataPixelCount satDefPixelPercentage = float32(satDefPixelCount) / dataPixelCount darkFeaturesPercentage = float32(darkFeaturesCount) / dataPixelCount cloudShadowsPercentage = float32(cloudShadowsCount) / dataPixelCount vegetationPercentage = float32(vegetationCount) / dataPixelCount bareSoilsPercentage = float32(bareSoilsCount) / dataPixelCount waterPercentage = float32(waterCount) / dataPixelCount lowProbaCloudsPercentage = float32( lowProbaCloudsCount) / dataPixelCount medProbaCloudsPercentage = float32( medProbaCloudsCount) / dataPixelCount hiProbaCloudsPercentage = float32(hiProbaCloudsCount) / dataPixelCount thinCirrusPercentage = float32(thinCirrusCount) / dataPixelCount snowIcePercentage = float32(snowIceCount) / dataPixelCount classificationQI = objectify.Element('Classification_QI') classificationQI.attrib['resolution'] = str(self.config.resolution) classificationQI.append(objectify.Element('TOTAL_PIXEL_COUNT')) classificationQI.append(objectify.Element('DATA_PIXEL_COUNT')) classificationQI.append(objectify.Element('DATA_PIXEL_PERCENTAGE')) classificationQI.append(objectify.Element('NODATA_PIXEL_COUNT')) classificationQI.append(objectify.Element('NODATA_PIXEL_PERCENTAGE')) classificationQI.append(objectify.Element('GOOD_PIXEL_COUNT')) classificationQI.append(objectify.Element('GOOD_PIXEL_PERCENTAGE')) classificationQI.append(objectify.Element('BAD_PIXEL_COUNT')) classificationQI.append(objectify.Element('BAD_PIXEL_PERCENTAGE')) classificationQI.append( objectify.Element('SATURATED_DEFECTIVE_PIXEL_COUNT')) classificationQI.append( objectify.Element('SATURATED_DEFECTIVE_PIXEL_PERCENTAGE')) classificationQI.append(objectify.Element('DARK_FEATURES_COUNT')) classificationQI.append(objectify.Element('DARK_FEATURES_PERCENTAGE')) classificationQI.append(objectify.Element('CLOUD_SHADOWS_COUNT')) classificationQI.append(objectify.Element('CLOUD_SHADOWS_PERCENTAGE')) classificationQI.append(objectify.Element('VEGETATION_COUNT')) classificationQI.append(objectify.Element('VEGETATION_PERCENTAGE')) classificationQI.append(objectify.Element('NOT_VEGETATED_COUNT')) classificationQI.append(objectify.Element('NOT_VEGETATED_PERCENTAGE')) classificationQI.append(objectify.Element('WATER_COUNT')) classificationQI.append(objectify.Element('WATER_PERCENTAGE')) classificationQI.append(objectify.Element('UNCLASSIFIED_COUNT')) classificationQI.append(objectify.Element('UNCLASSIFIED_PERCENTAGE')) classificationQI.append(objectify.Element('MEDIUM_PROBA_CLOUDS_COUNT')) classificationQI.append( objectify.Element('MEDIUM_PROBA_CLOUDS_PERCENTAGE')) classificationQI.append(objectify.Element('HIGH_PROBA_CLOUDS_COUNT')) classificationQI.append( objectify.Element('HIGH_PROBA_CLOUDS_PERCENTAGE')) classificationQI.append(objectify.Element('THIN_CIRRUS_COUNT')) classificationQI.append(objectify.Element('THIN_CIRRUS_PERCENTAGE')) classificationQI.append(objectify.Element('SNOW_ICE_COUNT')) classificationQI.append(objectify.Element('SNOW_ICE_PERCENTAGE')) classificationQI.TOTAL_PIXEL_COUNT = int(totalPixelCount * 100) classificationQI.DATA_PIXEL_COUNT = int(dataPixelCount * 100) classificationQI.DATA_PIXEL_PERCENTAGE = dataPixelPercentage classificationQI.NODATA_PIXEL_COUNT = nodataPixelCount classificationQI.NODATA_PIXEL_PERCENTAGE = nodataPixelPercentage classificationQI.GOOD_PIXEL_COUNT = goodPixelCount classificationQI.GOOD_PIXEL_PERCENTAGE = goodPixelPercentage classificationQI.BAD_PIXEL_COUNT = badPixelCount classificationQI.BAD_PIXEL_PERCENTAGE = badPixelPercentage classificationQI.SATURATED_DEFECTIVE_PIXEL_COUNT = satDefPixelCount classificationQI.SATURATED_DEFECTIVE_PIXEL_PERCENTAGE = satDefPixelPercentage classificationQI.DARK_FEATURES_COUNT = darkFeaturesCount classificationQI.DARK_FEATURES_PERCENTAGE = darkFeaturesPercentage classificationQI.CLOUD_SHADOWS_COUNT = cloudShadowsCount classificationQI.CLOUD_SHADOWS_PERCENTAGE = cloudShadowsPercentage classificationQI.VEGETATION_COUNT = vegetationCount classificationQI.VEGETATION_PERCENTAGE = vegetationPercentage classificationQI.NOT_VEGETATED_COUNT = bareSoilsCount classificationQI.NOT_VEGETATED_PERCENTAGE = bareSoilsPercentage classificationQI.WATER_COUNT = waterCount classificationQI.WATER_PERCENTAGE = waterPercentage classificationQI.UNCLASSIFIED_COUNT = lowProbaCloudsCount classificationQI.UNCLASSIFIED_PERCENTAGE = lowProbaCloudsPercentage classificationQI.MEDIUM_PROBA_CLOUDS_COUNT = medProbaCloudsCount classificationQI.MEDIUM_PROBA_CLOUDS_PERCENTAGE = medProbaCloudsPercentage classificationQI.HIGH_PROBA_CLOUDS_COUNT = hiProbaCloudsCount classificationQI.HIGH_PROBA_CLOUDS_PERCENTAGE = hiProbaCloudsPercentage classificationQI.THIN_CIRRUS_COUNT = thinCirrusCount classificationQI.THIN_CIRRUS_PERCENTAGE = thinCirrusPercentage classificationQI.SNOW_ICE_COUNT = snowIceCount classificationQI.SNOW_ICE_PERCENTAGE = snowIcePercentage xp = L3_XmlParser(self.config, 'UP03') l3qi = xp.getTree('Quality_Indicators_Info', 'Classification_QI') l3qiLen = len(l3qi) for i in range(l3qiLen): if int(l3qi[i].attrib['resolution']) == self.config.resolution: l3qi[i].clear() l3qi[i] = classificationQI xp.export() break return True
def createL3_Tile(self, tileId): ''' Create an L3 tile :param tileId: the tile ID :type tileId: string ''' L2A_TILE_ID = tileId if self.config.namingConvention == 'SAFE_STANDARD': strList = L2A_TILE_ID.split('_') L3_TILE_ID = 'L03_' + strList[-2] + '_' + strList[ -3] + '_' + strList[-4] else: L3_TILE_ID = L2A_TILE_ID.replace('L2A_', 'L03_') L3_TILE_ID = L3_TILE_ID.replace('USER', 'OPER') self.config.L3_TILE_ID = L3_TILE_ID sourceDir = self.config.sourceDir L2A_UP_ID = self.config.L2A_UP_ID L3_TARGET_DIR = self.config.L3_TARGET_DIR GRANULE = 'GRANULE' QI_DATA = 'QI_DATA' L2A_TILE_ID = os.path.join(sourceDir, L2A_UP_ID, GRANULE, L2A_TILE_ID) L3_TILE_ID = os.path.join(L3_TARGET_DIR, GRANULE, L3_TILE_ID) try: os.mkdir(L3_TILE_ID) os.mkdir(os.path.join(L3_TILE_ID, QI_DATA)) self.config.logger.info('new working directory is: ' + L3_TILE_ID) except: pass filelist = sorted(os.listdir(L2A_TILE_ID)) found = False if self.config.namingConvention == 'SAFE_STANDARD': L2A_UP_MASK = '*_MTD_L2A_TL_*.xml' else: L2A_UP_MASK = 'MTD_TL.xml' for filename in filelist: if (fnmatch.fnmatch(filename, L2A_UP_MASK) == True): found = True break if found == False: self.config.logger.fatal('No metadata in tile') self.config.exitError() assert isinstance(filename, object) L2A_TILE_MTD_XML = os.path.join(L2A_TILE_ID, filename) L3_TILE_MTD_XML = 'MTD_TL.xml' L3_TILE_MTD_XML = os.path.join(L3_TILE_ID, L3_TILE_MTD_XML) copy_file(L2A_TILE_MTD_XML, L3_TILE_MTD_XML) self.config.L2A_TILE_MTD_XML = L2A_TILE_MTD_XML xp = L3_XmlParser(self.config, 'T2A') TILE_ID_2A = xp.getTree('General_Info', 'TILE_ID') if TILE_ID_2A == False: # it's a version 14.2 metadata: TILE_ID_2A = xp.getTree('General_Info', 'TILE_ID_2A') self.config.TILE_ID_2A = TILE_ID_2A.text if xp.convert() != 0: xp = L3_XmlParser(self.config, 'T2A') xp.validate() self.config.L3_TILE_MTD_XML = L3_TILE_MTD_XML #update tile and datastrip id in metadata file. xp = L3_XmlParser(self.config, 'T03') if (xp.convert() == False): self.logger.fatal('error in converting tile metadata to level 3') self.exitError() xp = L3_XmlParser(self.config, 'T03') try: tree = xp.getTree('General_Info', 'L1C_TILE_ID') del tree[:] except: pass try: # remove all QI items from the past, as they will be calculated # directly from contents of images tree = xp.getTree('Quality_Indicators_Info', 'L1C_Image_Content_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'L2A_Image_Content_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'L1C_Pixel_Level_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'L2A_Pixel_Level_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'PVI_FILENAME') del tree[:] except: try: # test on version 14.5 data: tree = xp.getTree('Quality_Indicators_Info', 'Image_Content_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'Pixel_Level_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'PVI_FILENAME') del tree[:] except: pass xp.export() # read updated file and append new items: # create the first three enties of the Quality Measures: xp = L3_XmlParser(self.config, 'T03') root = xp.getRoot('Quality_Indicators_Info') tree = objectify.Element('Pixel_Level_QI') tree.attrib['resolution'] = str(self.config.resolution) root.append(tree) tree = objectify.Element('Classification_QI') tree.attrib['resolution'] = str(self.config.resolution) root.append(tree) tree = objectify.Element('Mosaic_QI') tree.attrib['resolution'] = str(self.config.resolution) root.append(tree) xp.export() #update tile id in ds metadata file. xp = L3_XmlParser(self.config, 'UP2A') if self.config.productVersion > 14.2: pi = xp.getTree('General_Info', 'Product_Info') gr2a = pi.Product_Organisation.Granule_List.Granule else: pi = xp.getTree('General_Info', 'L2A_Product_Info') try: gr2a = pi.L2A_Product_Organisation.Granule_List.Granule except: # it's a boring old 13.1 product: gr2a = pi.L2A_Product_Organisation.Granule_List.Granules gi2a = gr2a.attrib['granuleIdentifier'] gi03 = gi2a.replace('L2A_', 'L03_') xp = L3_XmlParser(self.config, 'DS03') ti = xp.getTree('Image_Data_Info', 'Tiles_Information') ti.Tile_List.append(objectify.Element('Tile', tileId=gi03)) xp.export() return
def createL3_TargetProduct(self): ''' Create the L3 target product. :return: true if succesful :rtype: bool ''' self.config.logger.info('Creating L3 target product ...') L2A_UP_MASK = '*L2A_*' #L2A_UP_DIR = os.path.join(self.config.sourceDir, self.config.L2A_UP_ID) L2A_UP_DIR = self.config.L2A_UP_DIR # detect the filename for the datastrip metadata: L2A_DS_DIR = os.path.join(L2A_UP_DIR, 'DATASTRIP') if os.path.exists(L2A_DS_DIR) == False: stderrWrite('directory "%s" does not exist.\n' % L2A_DS_DIR) self.config.exitError() return False if self.config.namingConvention == 'SAFE_STANDARD': L2A_DS_MASK = 'S2?_USER_MSI_L2A_DS_*' else: L2A_DS_MASK = 'DS_*' dirlist = sorted(os.listdir(L2A_DS_DIR)) found = False for dirname in dirlist: if (fnmatch.fnmatch(dirname, L2A_DS_MASK) == True): found = True break L2A_DS_DIR = os.path.join(L2A_DS_DIR, dirname) if self.config.namingConvention == 'SAFE_STANDARD': L2A_DS_MTD_XML = (dirname[:-7] + '.xml').replace('_MSI_', '_MTD_') else: L2A_DS_MTD_XML = 'MTD_DS.xml' L2A_DS_MTD_XML = os.path.join(L2A_DS_DIR, L2A_DS_MTD_XML) if found == False: stderrWrite('No metadata in datastrip\n.') self.config.exitError() dirname, basename = os.path.split(L2A_UP_DIR) if (fnmatch.fnmatch(basename, L2A_UP_MASK) == False): stderrWrite(basename + ': identifier "%s" is missing.' % L2A_UP_MASK) self.config.exitError() return False GRANULE = os.path.join(L2A_UP_DIR, 'GRANULE') if os.path.exists(GRANULE) == False: stderrWrite('directory "' + GRANULE + '" does not exist.') self.config.exitError() return False # # the product (directory) structure: #------------------------------------------------------- L3_TARGET_ID = basename L3_TARGET_ID = L3_TARGET_ID.replace('L2A_', 'L03_') strList = L3_TARGET_ID.split('_') if self.config.namingConvention == 'SAFE_STANDARD': L3_TARGET_ID = strList[0] + '_' + strList[3] + '_' + strList[ 5] + '_' + 'N0000_R000_T00XXX_' + self.config.minTime + '.SAFE' else: L3_TARGET_ID = L3_TARGET_ID.replace(strList[6], self.config.minTime + '.SAFE') if self.config.targetDir != 'DEFAULT': targetDir = self.config.targetDir if os.name == 'nt' and not '\\\\?\\' in targetDir: targetDir = u'\\'.join([u'\\\\?', targetDir]) if (os.path.exists(targetDir) == False): os.mkdir(targetDir) else: targetDir = dirname self.config.targetDir = targetDir L3_TARGET_DIR = os.path.join(targetDir, L3_TARGET_ID) self.config.L3_TARGET_DIR = L3_TARGET_DIR self.config.L3_TARGET_ID = L3_TARGET_ID L2A_INSPIRE_XML = os.path.join(L2A_UP_DIR, 'INSPIRE.xml') L2A_MANIFEST_SAFE = os.path.join(L2A_UP_DIR, 'manifest.safe') L3_INSPIRE_XML = os.path.join(L3_TARGET_DIR, 'INSPIRE.xml') L3_MANIFEST_SAFE = os.path.join(L3_TARGET_DIR, 'manifest.safe') AUX_DATA = 'AUX_DATA' DATASTRIP = 'DATASTRIP' GRANULE = 'GRANULE' HTML = 'HTML' REP_INFO = 'rep_info' self.config.L2A_DS_MTD_XML = L2A_DS_MTD_XML xp = L3_XmlParser(self.config, 'DS2A') xp.export() xp.validate() copy_tree(os.path.join(L2A_UP_DIR, AUX_DATA), os.path.join(L3_TARGET_DIR, AUX_DATA)) copy_tree(os.path.join(L2A_UP_DIR, DATASTRIP), os.path.join(L3_TARGET_DIR, DATASTRIP)) copy_tree(os.path.join(L2A_UP_DIR, HTML), os.path.join(L3_TARGET_DIR, HTML)) copy_tree(os.path.join(L2A_UP_DIR, REP_INFO), os.path.join(L3_TARGET_DIR, REP_INFO)) copy_file(L2A_INSPIRE_XML, L3_INSPIRE_XML) copy_file(L2A_MANIFEST_SAFE, L3_MANIFEST_SAFE) if not os.path.exists(os.path.join(L3_TARGET_DIR, GRANULE)): os.mkdir(os.path.join(L3_TARGET_DIR, GRANULE)) self.config.L3_INSPIRE_XML = L2A_INSPIRE_XML self.config.L3_MANIFEST_SAFE = L2A_MANIFEST_SAFE self.config.L3_TARGET_DIR = L3_TARGET_DIR #create user product: if self.config.namingConvention == 'SAFE_STANDARD': S2A_mask = 'S2?_USER_MTD_SAFL2A_*.xml' else: S2A_mask = 'MTD_MSIL2A.xml' filelist = sorted(os.listdir(L2A_UP_DIR)) found = False for filename in filelist: if (fnmatch.fnmatch(filename, S2A_mask) == True): found = True break if found == False: stderrWrite('No metadata for user product') self.config.exitError() # prepare L3 User Product metadata file fn_L2A = os.path.join(L2A_UP_DIR, filename) fn_L3 = 'MTD_MSIL03.xml' fn_L3 = os.path.join(L3_TARGET_DIR, fn_L3) self.config.L2A_UP_MTD_XML = fn_L2A xp = L3_XmlParser(self.config, 'UP2A') if xp.convert() != 0: xp = L3_XmlParser(self.config, 'UP2A') xp.validate() self.config.L3_TARGET_MTD_XML = fn_L3 # copy L2A schemes from config_dir into rep_info: upScheme3 = self.config.upScheme3 basename = os.path.basename(upScheme3) copy_file(os.path.join(self.config.configDir, upScheme3), os.path.join(L3_TARGET_DIR, REP_INFO, basename)) tileScheme3 = self.config.tileScheme3 basename = os.path.basename(tileScheme3) copy_file(os.path.join(self.config.configDir, tileScheme3), os.path.join(L3_TARGET_DIR, REP_INFO, basename)) dsScheme3 = self.config.dsScheme3 basename = os.path.basename(dsScheme3) copy_file(os.path.join(self.config.configDir, dsScheme3), os.path.join(L3_TARGET_DIR, REP_INFO, basename)) # copy L3 User Product metadata file: copy_file(fn_L2A, fn_L3) # remove old L2A entries from L3_TARGET_MTD_XML: xp = L3_XmlParser(self.config, 'UP03') if (xp.convert() == False): self.logger.fatal( 'error in converting user product metadata to level 3') stderrWrite('Error in converting user product metadata to level 3') self.config.exitError() xp = L3_XmlParser(self.config, 'UP03') pi = xp.getTree('General_Info', 'Product_Info') # update L2A entries from L2A_UP_MTD_XML: tmin = self.config.minTime tmax = self.config.maxTime pi.PRODUCT_START_TIME = tmin[:4] + '-' + tmin[4:6] + '-' + tmin[ 6:11] + ':' + tmin[11:13] + ':' + tmin[13:15] + '.000Z' pi.PRODUCT_STOP_TIME = tmax[:4] + '-' + tmax[4:6] + '-' + tmax[ 6:11] + '-' + tmax[11:13] + ':' + tmax[13:15] + '.000Z' # update L2A and L3 entries from L2A_UP_MTD_XML: try: del pi.PRODUCT_URI_1C except: pass pi.PRODUCT_URI = self.config.L3_TARGET_ID pi.PROCESSING_LEVEL = 'Level-3p' pi.PRODUCT_TYPE = 'S2MSI3p' pi.PROCESSING_ALGORITHM = self.config.algorithm pi.RADIOMETRIC_PREFERENCE = self.config.radiometricPreference dt = datetime.utcnow() pi.GENERATION_TIME = strftime('%Y-%m-%dT%H:%M:%SZ', dt.timetuple()) if self.config.namingConvention == 'SAFE_STANDARD': try: qo = pi.Query_Options del qo[:] qo = objectify.Element('Query_Options') qo.attrib['completeSingleTile'] = "false" qo.append(objectify.Element('PRODUCT_FORMAT')) qo.PRODUCT_FORMAT = 'SAFE_COMPACT' pi.append(qo) except: pass try: gl = pi.Product_Organisation.Granule_List del gl[:] except: pass try: pic = xp.getTree('General_Info', 'Product_Image_Characteristics') del pic.QUANTIFICATION_VALUES_LIST.L1C_TOA_QUANTIFICATION_VALUE except: pass try: aux = xp.getRoot('L2A_Auxiliary_Data_Info') del aux[:] except: pass try: aux = xp.getRoot('Auxiliary_Data_Info') aux.clear() node = objectify.Element('GIPP_LIST') aux.append(node) except: pass try: qii = xp.getRoot('L2A_Quality_Indicators_Info') del qii[:] except: pass try: qii = xp.getRoot('Quality_Indicators_Info') qii.clear() node = objectify.Element('Classification_QI') node.attrib['resolution'] = str(self.config.resolution) qii.append(node) except: pass xp.export() #create datastrip ID: L3_DS_DIR = os.path.join(L3_TARGET_DIR, DATASTRIP) dirlist = sorted(os.listdir(L3_DS_DIR)) found = False for dirname in dirlist: if (fnmatch.fnmatch(dirname, L2A_DS_MASK) == True): found = True break if found == False: stderrWrite('No subdirectory in datastrip') self.config.exitError() if self.config.namingConvention == 'SAFE_STANDARD': L3_DS_ID = dirname[17:-7] L3_DS_OLD = os.path.join(L3_DS_DIR, dirname) L3_DS_DIR = os.path.join(L3_DS_DIR, L3_DS_ID) os.rename(L3_DS_OLD, L3_DS_DIR) else: L3_DS_ID = dirname L3_DS_DIR = os.path.join(L3_DS_DIR, L3_DS_ID) self.config.L3_DS_ID = L3_DS_ID filelist = sorted(os.listdir(L3_DS_DIR)) found = False L2A_DS_MTD_MSK = 'S2?_USER_MTD_L2A_DS_*.xml' for filename in filelist: if (fnmatch.fnmatch(filename, L2A_DS_MTD_MSK) == True): L3_DS_OLD = os.path.join(L3_DS_DIR, filename) L3_DS_MTD = os.path.join(L3_DS_DIR, 'MTD_DS.xml') os.rename(L3_DS_OLD, L3_DS_MTD) filename = 'MTD_DS.xml' found = True elif (fnmatch.fnmatch(filename, 'MTD_DS.xml') == True): found = True break if found == False: stderrWrite('No metadata in datastrip') self.config.exitError() self.config.L3_DS_MTD_XML = os.path.join(L3_DS_DIR, filename) xp = L3_XmlParser(self.config, 'DS03') if (xp.convert() == False): stderrWrite('Error in converting datastrip metadata to level 3.') self.logger.fatal( 'error in converting datastrip metadata to level 3.') self.config.exitError() xp = L3_XmlParser(self.config, 'DS03') ti = xp.getTree('Image_Data_Info', 'Tiles_Information') del ti.Tile_List.Tile[:] ri = xp.getTree('Image_Data_Info', 'Radiometric_Info') qvl = objectify.Element('QUANTIFICATION_VALUES_LIST') qvl.BOA_QUANTIFICATION_VALUE = str(int(self.config.dnScale)) qvl.BOA_QUANTIFICATION_VALUE.attrib['unit'] = 'none' qvl.AOT_QUANTIFICATION_VALUE = str( self.config.L2A_AOT_QUANTIFICATION_VALUE) qvl.AOT_QUANTIFICATION_VALUE.attrib['unit'] = 'none' qvl.WVP_QUANTIFICATION_VALUE = str( self.config.L2A_WVP_QUANTIFICATION_VALUE) qvl.WVP_QUANTIFICATION_VALUE.attrib['unit'] = 'cm' ri.QUANTIFICATION_VALUES_LIST = qvl auxinfo = xp.getRoot('Auxiliary_Data_Info') if (xp.getTree('Auxiliary_Data_Info', 'GRI_List')) == False: gfn = xp.getTree('Auxiliary_Data_Info', 'GRI_FILENAME') del gfn[:] gl = etree.Element('GRI_List') gl.append(gfn) auxinfo.append(gl) if (xp.getTree('Auxiliary_Data_Info', 'LUT_List')) == False: ll = etree.Element('LUT_List') auxinfo.append(ll) if (xp.getTree('Auxiliary_Data_Info', 'SNOW_CLIMATOLOGY_MAP')) == False: ll = etree.Element('SNOW_CLIMATOLOGY_MAP') ll.text = 'None' auxinfo.append(ll) if (xp.getTree('Auxiliary_Data_Info', 'ESACCI_WaterBodies_Map')) == False: ll = etree.Element('ESACCI_WaterBodies_Map') ll.text = 'None' auxinfo.append(ll) if (xp.getTree('Auxiliary_Data_Info', 'ESACCI_LandCover_Map')) == False: ll = etree.Element('ESACCI_LandCover_Map') ll.text = 'None' auxinfo.append(ll) if (xp.getTree('Auxiliary_Data_Info', 'ESACCI_SnowCondition_Map_Dir')) == False: ll = etree.Element('ESACCI_SnowCondition_Map_Dir') ll.text = 'None' auxinfo.append(ll) xp.export() self.createTable() return True
def exportBandList(self, productLevel): ''' Export all bands of current tile. converts all bands from hdf5 to JPEG-2000. :param productLevel: [L1C | L2A | L3]. :type productLevel: str :return: false if error occurred during export. :rtype: boolean ''' bandDir = self._L3_bandDir # converts all bands from hdf5 to JPEG 2000 if (os.path.exists(bandDir) == False): self.config.logger.fatal('missing directory %s:' % bandDir) self.config.exitError() return False os.chdir(bandDir) self.config.timestamp(productLevel + '_Tables: start export') if (self._resolution == 10): bandIndex = [1, 2, 3, 7, 14, 30] elif (self._resolution == 20): bandIndex = [1, 2, 3, 4, 5, 6, 8, 11, 12, 14, 30] elif (self._resolution == 60): bandIndex = [0, 1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 14, 30] #prepare the xml export Granules = objectify.Element('Granules') Granules.attrib['granuleIdentifier'] = self.config.L3_TILE_ID Granules.attrib['datastripIdentifier'] = self.config.L3_DS_ID Granules.attrib['imageFormat'] = 'JPEG2000' gl = objectify.Element('Granule_List') gl.append(Granules) for index in bandIndex: bandName = self.getBandNameFromIndex(index) if index == 14: filename = self._L3_Tile_SCL_File elif index == 30: filename = self._L3_Tile_MSC_File else: filename = self._L3_Tile_BND_File.replace('BXX', bandName) band = self.getBand(productLevel, index) # Median Filter: mf = self.config.medianFilter if (mf > 0): band = ndimage.filters.median_filter(band, (mf, mf)) kwargs = {"tilesize": (2048, 2048), "prog": "RPCL"} glymur.Jp2k(filename, band.astype(uint16), **kwargs) self.config.logger.info('Band ' + bandName + ' exported') self.config.timestamp('L3_Tables: band ' + bandName + ' exported') filename = os.path.basename(filename.strip('.jp2')) imageId = etree.Element('IMAGE_ID_3') imageId.text = filename Granules.append(imageId) xp = L3_XmlParser(self.config, 'UP03') pi = xp.getTree('General_Info', 'L3_Product_Info') po = pi.L3_Product_Organisation po.append(gl) xp.export() # update on tile level xp = L3_XmlParser(self.config, 'T03') gi = xp.getRoot('General_Info') tiOld = xp.getTree('General_Info', 'TILE_ID_3') tiNew = etree.Element('TILE_ID_3') tiNew.text = self.config.L3_TILE_ID gi.replace(tiOld, tiNew) dsOld = xp.getTree('General_Info', 'DATASTRIP_ID_3') dsNew = etree.Element('DATASTRIP_ID_3') dsNew.text = self.config.L3_DS_ID gi.replace(dsOld, dsNew) # clean up and post processing actions: pxlQI = objectify.Element('L3_Mosaic_QI') pxlQI.attrib['resolution'] = str(self.config.resolution) pxlQI.append(objectify.Element('PVI_FILENAME')) pxlQI.append(objectify.Element('L3_TILE_CLASSIFICATION_MASK')) pxlQI.append(objectify.Element('L3_TILE_MOSAIC_MASK')) pxlQI.PVI_FILENAME = os.path.basename(self._L3_Tile_PVI_File).replace( '.jp2', '') pxlQI.L3_TILE_CLASSIFICATION_MASK = os.path.basename( self._L3_Tile_SCL_File).replace('.jp2', '') pxlQI.L3_TILE_MOSAIC_MASK = os.path.basename( self._L3_Tile_MSC_File).replace('.jp2', '') qiiL3 = xp.getTree('Quality_Indicators_Info', 'L3_Pixel_Level_QI') qiiL3Len = len(qiiL3) for i in range(qiiL3Len): if int(qiiL3[i].attrib['resolution']) == self.config.resolution: qiiL3[i].clear() qiiL3[i] = pxlQI break xp.export() # globdir = self.config.L3_TARGET_ID + '/GRANULE/' + self.config.L3_TILE_ID + '/*/*.jp2.aux.xml' # for filename in glob.glob(globdir): # os.remove(filename) # globdir = self.config.L3_TARGET_ID + '/GRANULE/' + self.config.L3_TILE_ID + '/*/*/*.jp2.aux.xml' # for filename in glob.glob(globdir): # os.remove(filename) self.config.timestamp(productLevel + '_Tables: stop export') return True
def createL3_Tile(self, tileId): ''' Create an L3 tile :param tileId: the tile ID :type tileId: string ''' L2A_TILE_ID = tileId L3_TILE_ID = L2A_TILE_ID.replace('L2A_', 'L03_') self.config.L3_TILE_ID = L3_TILE_ID sourceDir = self.config.sourceDir L2A_UP_ID = self.config.L2A_UP_ID L3_TARGET_DIR = self.config.L3_TARGET_DIR GRANULE = 'GRANULE' QI_DATA = 'QI_DATA' L2A_TILE_ID = os.path.join(sourceDir, L2A_UP_ID, GRANULE, L2A_TILE_ID) L3_TILE_ID = os.path.join(L3_TARGET_DIR, GRANULE, L3_TILE_ID) try: os.mkdir(L3_TILE_ID) os.mkdir(os.path.join(L3_TILE_ID, QI_DATA)) self.config.logger.info('new working directory is: ' + L3_TILE_ID) except: pass filelist = sorted(os.listdir(L2A_TILE_ID)) found = False L2A_UP_MASK = '*_L2A_*' for filename in filelist: if (fnmatch.fnmatch(filename, L2A_UP_MASK) == True): found = True break if found == False: self.config.logger.fatal('No metadata in tile') self.config.exitError() assert isinstance(filename, object) L2A_TILE_MTD_XML = os.path.join(L2A_TILE_ID, filename) L3_TILE_MTD_XML = filename L3_TILE_MTD_XML = L3_TILE_MTD_XML.replace('L2A_', 'L03_') L3_TILE_MTD_XML = os.path.join(L3_TILE_ID, L3_TILE_MTD_XML) copy_file(L2A_TILE_MTD_XML, L3_TILE_MTD_XML) self.config.L2A_TILE_MTD_XML = L2A_TILE_MTD_XML xp = L3_XmlParser(self.config, 'T2A') xp.export() xp.validate() self.config.L3_TILE_MTD_XML = L3_TILE_MTD_XML #update tile and datastrip id in metadata file. if (self.config.resolution == 20) or (self.config.resolution == 60): copy_file(L2A_TILE_MTD_XML, L3_TILE_MTD_XML) xp = L3_XmlParser(self.config, 'T03') if (xp.convert() == False): self.logger.fatal( 'error in converting tile metadata to level 3') self.exitError() xp = L3_XmlParser(self.config, 'T03') try: # remove all QI items from the past, as they will be calculated # directly from contents of images tree = xp.getTree('Quality_Indicators_Info', 'L1C_Image_Content_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'L2A_Image_Content_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'L1C_Pixel_Level_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'L2A_Pixel_Level_QI') del tree[:] tree = xp.getTree('Quality_Indicators_Info', 'PVI_FILENAME') del tree[:] except: pass xp.export() # read updated file and append new items: # create the first three enties of the Quality Measures: xp = L3_XmlParser(self.config, 'T03') root = xp.getRoot('Quality_Indicators_Info') tree = objectify.Element('L3_Pixel_Level_QI') tree.attrib['resolution'] = str(self.config.resolution) root.append(tree) tree = objectify.Element('L3_Classification_QI') tree.attrib['resolution'] = str(self.config.resolution) root.append(tree) tree = objectify.Element('L3_Mosaic_QI') tree.attrib['resolution'] = str(self.config.resolution) root.append(tree) xp.export() #update tile id in ds metadata file. xp = L3_XmlParser(self.config, 'DS03') ti = xp.getTree('Image_Data_Info', 'Tiles_Information') ti.Tile_List.append( objectify.Element('Tile', tileId=os.path.basename(L3_TILE_ID))) xp.export() return
def createL3_TargetProduct(self): ''' Create the L3 target product. :return: true if succesful :rtype: bool ''' self.config.logger.info('Creating L3 target product ...') L2A_UP_MASK = '*2A_*' L2A_UP_DIR = os.path.join(self.config.sourceDir, self.config.L2A_UP_ID) # detect the filename for the datastrip metadata: L2A_DS_DIR = os.path.join(L2A_UP_DIR, 'DATASTRIP') if os.path.exists(L2A_DS_DIR) == False: stderrWrite('directory "%s" does not exist.\n' % L2A_DS_DIR) self.config.exitError() return False L2A_DS_MASK = '*_L2A_*' dirlist = sorted(os.listdir(L2A_DS_DIR)) found = False for dirname in dirlist: if (fnmatch.fnmatch(dirname, L2A_DS_MASK) == True): found = True break L2A_DS_DIR = os.path.join(L2A_DS_DIR, dirname) L2A_DS_MTD_XML = (dirname[:-7] + '.xml').replace('_MSI_', '_MTD_') L2A_DS_MTD_XML = os.path.join(L2A_DS_DIR, L2A_DS_MTD_XML) if found == False: stderrWrite('No metadata in datastrip\n.') self.config.exitError() dirname, basename = os.path.split(L2A_UP_DIR) if (fnmatch.fnmatch(basename, L2A_UP_MASK) == False): stderrWrite(basename + ': identifier "*2A_*" is missing.') self.config.exitError() return False GRANULE = os.path.join(L2A_UP_DIR, 'GRANULE') if os.path.exists(GRANULE) == False: stderrWrite('directory "' + GRANULE + '" does not exist.') self.config.exitError() return False # # the product (directory) structure: #------------------------------------------------------- L3_TARGET_ID = basename L3_TARGET_ID = L3_TARGET_ID.replace('L2A_', 'L03_') L3_TARGET_ID = L3_TARGET_ID.replace(L3_TARGET_ID[47:62], self.config.minTime) L3_TARGET_ID = L3_TARGET_ID.replace(L3_TARGET_ID[63:78], self.config.maxTime) if self.config.targetDir != 'DEFAULT': targetDir = self.config.targetDir if os.name == 'nt' and not '\\\\?\\' in targetDir: targetDir = u'\\'.join([u'\\\\?', targetDir]) if (os.path.exists(targetDir) == False): os.mkdir(targetDir) else: targetDir = dirname self.config.targetDir = targetDir L3_TARGET_DIR = os.path.join(targetDir, L3_TARGET_ID) self.config.L3_TARGET_DIR = L3_TARGET_DIR self.config.L3_TARGET_ID = L3_TARGET_ID L2A_INSPIRE_XML = os.path.join(L2A_UP_DIR, 'INSPIRE.xml') L2A_MANIFEST_SAFE = os.path.join(L2A_UP_DIR, 'manifest.safe') L3_INSPIRE_XML = os.path.join(L3_TARGET_DIR, 'INSPIRE.xml') L3_MANIFEST_SAFE = os.path.join(L3_TARGET_DIR, 'manifest.safe') AUX_DATA = 'AUX_DATA' DATASTRIP = 'DATASTRIP' GRANULE = 'GRANULE' HTML = 'HTML' REP_INFO = 'rep_info' self.config.L2A_DS_MTD_XML = L2A_DS_MTD_XML xp = L3_XmlParser(self.config, 'DS2A') xp.export() xp.validate() copy_tree(os.path.join(L2A_UP_DIR, AUX_DATA), os.path.join(L3_TARGET_DIR, AUX_DATA)) copy_tree(os.path.join(L2A_UP_DIR, DATASTRIP), os.path.join(L3_TARGET_DIR, DATASTRIP)) copy_tree(os.path.join(L2A_UP_DIR, HTML), os.path.join(L3_TARGET_DIR, HTML)) copy_tree(os.path.join(L2A_UP_DIR, REP_INFO), os.path.join(L3_TARGET_DIR, REP_INFO)) copy_file(L2A_INSPIRE_XML, L3_INSPIRE_XML) copy_file(L2A_MANIFEST_SAFE, L3_MANIFEST_SAFE) if not os.path.exists(os.path.join(L3_TARGET_DIR, GRANULE)): os.mkdir(os.path.join(L3_TARGET_DIR, GRANULE)) self.config.L3_INSPIRE_XML = L2A_INSPIRE_XML self.config.L3_MANIFEST_SAFE = L2A_MANIFEST_SAFE self.config.L3_TARGET_DIR = L3_TARGET_DIR #create user product: S2A_mask = 'S2A_*' filelist = sorted(os.listdir(L2A_UP_DIR)) found = False for filename in filelist: if (fnmatch.fnmatch(filename, S2A_mask) == True): found = True break if found == False: stderrWrite('No metadata for user product') self.config.exitError() # prepare L3 User Product metadata file fn_L2A = os.path.join(L2A_UP_DIR, filename) fn_L3 = filename[:4] + 'USER' + filename[8:] fn_L3 = fn_L3.replace('L2A_', 'L03_') fn_L3 = os.path.join(L3_TARGET_DIR, fn_L3) self.config.L2A_UP_MTD_XML = fn_L2A xp = L3_XmlParser(self.config, 'UP2A') xp.export() xp.validate() self.config.L3_TARGET_MTD_XML = fn_L3 # copy L2A schemes from config_dir into rep_info: xp = L3_XmlParser(self.config, 'GIPP') cs = xp.getRoot('Common_Section') upScheme2a = cs.UP_Scheme_2A.text basename = os.path.basename(upScheme2a) copy_file(os.path.join(self.config.configDir, upScheme2a), os.path.join(L3_TARGET_DIR, REP_INFO, basename)) tileScheme2a = cs.Tile_Scheme_2A.text basename = os.path.basename(tileScheme2a) copy_file(os.path.join(self.config.configDir, tileScheme2a), os.path.join(L3_TARGET_DIR, REP_INFO, basename)) dsScheme2a = cs.DS_Scheme_2A.text basename = os.path.basename(dsScheme2a) copy_file(os.path.join(self.config.configDir, dsScheme2a), os.path.join(L3_TARGET_DIR, REP_INFO, basename)) # copy L3 User Product metadata file: copy_file(fn_L2A, fn_L3) # remove old L2A entries from L3_TARGET_MTD_XML: xp = L3_XmlParser(self.config, 'UP03') if (xp.convert() == False): self.logger.fatal( 'error in converting user product metadata to level 3') stderrWrite('Error in converting user product metadata to level 3') self.config.exitError() xp = L3_XmlParser(self.config, 'UP03') pi = xp.getTree('General_Info', 'L3_Product_Info') # update L2A entries from L2A_UP_MTD_XML: # 2015-07-30T10:39:14.021Z tmin = self.config.minTime tmax = self.config.maxTime pi.PRODUCT_START_TIME = tmin[:4] + '-' + tmin[4:6] + '-' + tmin[ 6:11] + ':' + tmin[11:13] + ':' + tmin[13:15] + '.000Z' pi.PRODUCT_STOP_TIME = tmax[:4] + '-' + tmax[4:6] + '-' + tmax[ 6:11] + '-' + tmax[11:13] + ':' + tmax[13:15] + '.000Z' pi.PROCESSING_LEVEL = 'Level-3p' pi.PRODUCT_TYPE = 'S2MSI3p' pi.PROCESSING_ALGORITHM = self.config.algorithm pi.RADIOMETRIC_PREFERENCE = self.config.radiometricPreference dt = datetime.utcnow() pi.GENERATION_TIME = strftime('%Y-%m-%dT%H:%M:%SZ', dt.timetuple()) qo = pi.Query_Options del qo[:] del pi.L3_Product_Organisation.Granule_List[:] aux = xp.getRoot('Auxiliary_Data_Info') del aux[:] l3auxData = xp.getTree('L3_Auxiliary_Data_Info', 'Aux_Data') l3auxData.clear() qii = xp.getRoot('Quality_Indicators_Info') del qii[:] l3icqi = xp.getTree('L3_Quality_Indicators_Info', 'Image_Content_QI') del l3icqi[:] l3qii = xp.getRoot('L3_Quality_Indicators_Info') tree = objectify.Element('L3_Classification_QI') tree.attrib['resolution'] = str(self.config.resolution) l3qii.append(tree) xp.export() #create datastrip ID: L3_DS_DIR = os.path.join(L3_TARGET_DIR, DATASTRIP) dirlist = sorted(os.listdir(L3_DS_DIR)) found = False for dirname in dirlist: if (fnmatch.fnmatch(dirname, S2A_mask) == True): found = True break if found == False: stderrWrite('No subdirectory in datastrip') self.config.exitError() L2A_DS_ID = dirname L3_DS_ID = L2A_DS_ID[:4] + 'USER' + L2A_DS_ID[8:] L3_DS_ID = L3_DS_ID.replace('L2A_', 'L03_') self.config.L3_DS_ID = L3_DS_ID olddir = os.path.join(L3_DS_DIR, L2A_DS_ID) newdir = os.path.join(L3_DS_DIR, L3_DS_ID) os.rename(olddir, newdir) #find datastrip metadada, rename and change it: L3_DS_DIR = newdir filelist = sorted(os.listdir(L3_DS_DIR)) found = False for filename in filelist: if (fnmatch.fnmatch(filename, S2A_mask) == True): found = True break if found == False: stderrWrite('No metadata in datastrip') self.config.exitError() LXX_DS_MTD_XML = filename L3_DS_MTD_XML = LXX_DS_MTD_XML[:4] + 'USER' + LXX_DS_MTD_XML[8:] L3_DS_MTD_XML = L3_DS_MTD_XML.replace('L2A_', 'L03_') oldfile = os.path.join(L3_DS_DIR, LXX_DS_MTD_XML) newfile = os.path.join(L3_DS_DIR, L3_DS_MTD_XML) self.config.L3_DS_MTD_XML = newfile os.rename(oldfile, newfile) xp = L3_XmlParser(self.config, 'DS03') if (xp.convert() == False): stderrWrite('Error in converting datastrip metadata to level 3.') self.logger.fatal( 'error in converting datastrip metadata to level 3.') self.config.exitError() xp = L3_XmlParser(self.config, 'DS03') ti = xp.getTree('Image_Data_Info', 'Tiles_Information') del ti.Tile_List.Tile[:] xp.export() self.createTable() return True