Commit b4f39a7b authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

Continued implementation of error array config options.

parent 746f8c06
......@@ -487,9 +487,9 @@ class AtmCorr(object):
@property
def options(self):
# type: () -> dict
"""Returns a dictionary containing AC options.
"""
# type: -> dict
if self._options:
return self._options
else:
......@@ -827,7 +827,8 @@ class AtmCorr(object):
self._check_or_download_ECMWF_data()
# validate SNR
self._validate_snr_source()
if CFG.ac_estimate_accuracy:
self._validate_snr_source()
# create an instance of RSImage
rs_image = RSImage(**rs_data)
......@@ -850,6 +851,12 @@ class AtmCorr(object):
self.results = ac_gms(rs_image, self.options, logger=self.logger, script=script)
except Exception as e:
self.logger.error('\nAn error occurred during atmospheric correction. BE AWARE THAT THE SCENE %s '
'(ENTITY ID %s) HAS NOT BEEN ATMOSPHERICALLY CORRECTED! Error message was: \n%s\n'
% (self.inObjs[0].scene_ID, self.inObjs[0].entity_ID, repr(e)))
self.logger.error(traceback.format_exc())
# TODO include that in the job summary
# serialialize AC input
if dump_ac_input:
path_dump = self.inObjs[0].pathGen.get_path_ac_input_dump()
......@@ -863,16 +870,10 @@ class AtmCorr(object):
for inObj in self.inObjs: # type: L1C_object
inObj.delete_ac_input_arrays()
self.logger.error('\nAn error occurred during atmospheric correction. BE AWARE THAT THE SCENE %s '
'(ENTITY ID %s) HAS NOT BEEN ATMOSPHERICALLY CORRECTED! Error message was: \n%s\n'
% (self.inObjs[0].scene_ID, self.inObjs[0].entity_ID, repr(e)))
self.logger.error(traceback.format_exc())
# TODO include that in the job summary
return list(self.inObjs)
# get processing infos
self.proc_info = self.ac_input['options']['processing'] # FIXME this is not appended to GMS objects
self.proc_info = self.ac_input['options']['processing']
# join results
self._join_results_to_inObjs() # sets self.outObjs
......@@ -900,6 +901,9 @@ class AtmCorr(object):
# update masks (always do that because masks can also only contain one layer)
[inObj.build_combined_masks_array() for inObj in self.inObjs]
# update AC processing info
[inObj.ac_options['processing'].update(self.proc_info) for inObj in self.inObjs]
self.outObjs = self.inObjs
def _join_data_ac(self):
......@@ -964,6 +968,9 @@ class AtmCorr(object):
ac_errors = ac_errors.astype(out_dtype)
inObj.ac_errors = ac_errors # setter generates a GeoArray with the same bandnames like inObj.arr
# TODO how to handle nans?
elif not CFG.ac_estimate_accuracy:
self.logger.warning("Atmospheric correction did not provide a 'data_errors' array because "
"'ac_estimate_accuracy' was set to False in the job configuration.")
else:
self.logger.warning("Atmospheric correction did not provide a 'data_errors' array. Maybe due to "
"missing SNR model? GMS_object.ac_errors kept None.")
......@@ -1016,8 +1023,7 @@ class AtmCorr(object):
"""
Join confidence array for mask_clouds.
"""
if self.results.mask_clouds.mask_confidence_array is not None:
if self.results.mask_clouds.mask_confidence_array is not None and CFG.ac_estimate_accuracy:
cfd_arr = self.results.mask_clouds.mask_confidence_array # float32 2D array, scaled [0-1, nodata 255]
cfd_arr[cfd_arr == self.ac_input['options']['cld_mask']['nodata_value_mask']] = -1
cfd_arr = (cfd_arr * CFG.scale_factor_BOARef).astype(np.int16)
......@@ -1036,7 +1042,9 @@ class AtmCorr(object):
if not joined:
self.logger.warning('Cloud mask confidence array has not been appended to one of the AC inputs because '
'there was no input GMS object with the same dimensions.')
elif not CFG.ac_estimate_accuracy:
self.logger.warning("Cloud mask confidence array is not appended to AC outputs because "
"'ac_estimate_accuracy' was set to False in the job configuration.")
else:
self.logger.warning("Atmospheric correction did not provide a 'mask_confidence_array' array for "
"attribute 'mask_clouds. GMS_object.mask_clouds_confidence kept None.")
......@@ -103,6 +103,7 @@ class L2B_object(L2A_object):
tgt_sensor=tgt_sen,
tgt_LBA=tgt_LBA,
nodataVal=self.arr.nodata,
compute_errors=CFG.spechomo_estimate_accuracy,
fallback_argskwargs=dict(
args=dict(source_CWLs=src_cwls, target_CWLs=tgt_cwls,),
kwargs=dict(kind='linear')
......@@ -118,7 +119,7 @@ class L2B_object(L2A_object):
del self.meta_odict['band names'] # TODO
self.arr = im # type: GeoArray
self.spec_homo_errors = errs # type: np.ndarray # int16
self.spec_homo_errors = errs # type: Union[np.ndarray, None] # int16, None if ~CFG.spechomo_estimate_accuracy
class SpectralHomogenizer(object):
......@@ -160,7 +161,8 @@ class SpectralHomogenizer(object):
return outarr
def predict_by_machine_learner(self, arrcube, method, src_satellite, src_sensor, src_LBA,
tgt_satellite, tgt_sensor, tgt_LBA, nodataVal=None, **fallback_argskwargs):
tgt_satellite, tgt_sensor, tgt_LBA, nodataVal=None, compute_errors=False,
**fallback_argskwargs):
# type: (Union[np.ndarray, GeoArray], str, str, str, list, str, str, list, int, dict) -> tuple
"""Predict spectral bands of target sensor by applying a machine learning approach.
......@@ -175,9 +177,11 @@ class SpectralHomogenizer(object):
:param tgt_sensor: target sensor, e.g., 'OLI_TIRS'
:param tgt_LBA: target LayerBandsAssignment
:param nodataVal: no data value
:param compute_errors: whether to compute pixel- / bandwise model errors for estimated pixel values
(default: false)
:param fallback_argskwargs: arguments and keyword arguments for fallback algorithm ({'args':{}, 'kwargs': {}}
:return: predicted array (rows x columns x bands)
:rtype: Tuple[np.ndarray, np.ndarray]
:rtype: Tuple[np.ndarray, Union[np.ndarray, None]]
"""
# TODO: add LBA validation to .predict()
PR = RSImage_Predictor(method=method, classifier_rootDir=self.classifier_rootDir)
......@@ -207,16 +211,19 @@ class SpectralHomogenizer(object):
# run prediction #
##################
errors = None
if cls:
self.logger.info('Performing spectral homogenization using %s. Target is %s %s %s.'
% (method, tgt_satellite, tgt_sensor, tgt_LBA))
im_homo = PR.predict(arrcube, classifier=cls, nodataVal=nodataVal)
errors = PR.compute_prediction_errors(im_homo, cls, nodataVal=nodataVal)
if compute_errors:
errors = PR.compute_prediction_errors(im_homo, cls, nodataVal=nodataVal)
elif fallback_argskwargs:
# fallback: use linear interpolation and set errors to an array of zeros
im_homo = self.interpolate_cube(arrcube, *fallback_argskwargs['args'], **fallback_argskwargs['kwargs'])
errors = np.zeros_like(im_homo, dtype=np.int16)
if compute_errors:
errors = np.zeros_like(im_homo, dtype=np.int16)
else:
raise exc
......
......@@ -339,6 +339,7 @@ class GMS_object(Dataset):
@property
def ac_options(self):
# type: () -> dict
"""
Returns the options dictionary needed as input for atmospheric correction. If an empty dictionary is returned,
atmospheric correction is not yet available for the current sensor and will later be skipped.
......@@ -359,7 +360,10 @@ class GMS_object(Dataset):
opt_dict['output'] = [] # outputs are not needed for GMS -> so
opt_dict['report']['report_path'] = os.path.join(self.pathGen.get_path_procdata(), '[TYPE]')
if 'uncertainties' in opt_dict:
opt_dict['uncertainties']['snr_model'] = PG.get_path_snr_model(self.GMS_identifier)
if CFG.ac_estimate_accuracy:
opt_dict['uncertainties']['snr_model'] = PG.get_path_snr_model(self.GMS_identifier)
else:
del opt_dict['uncertainties'] # SICOR will not compute uncertainties if that key is missing
# apply custom configuration
opt_dict["logger"]['level'] = CFG.log_level
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment